FileDescriptor: Add move and close methods

Made the following enhancements to the FileDescriptor class:
* Moved header file from file.hpp to file_descriptor.hpp to match naming
  convention used in other files.
* Added move constructor and move assignment operator so FileDescriptor
  objects can be put in containers like std::vector.
* Added close() method so users of class can optionally close the
  descriptor explicitly and check the return code for errors.  If not
  explicitly closed, the descriptor will still be closed by the destructor
  which ignores errors.
* Added automated tests
* Added doxygen comments

Signed-off-by: Shawn McCarney <shawnmm@us.ibm.com>
Change-Id: I1e05bbb232443ed1a79728768aaaa1efac8707ec
diff --git a/file_descriptor.hpp b/file_descriptor.hpp
new file mode 100644
index 0000000..7929aa6
--- /dev/null
+++ b/file_descriptor.hpp
@@ -0,0 +1,136 @@
+#pragma once
+
+#include <unistd.h> // for close()
+
+namespace phosphor::power::util
+{
+
+/**
+ * @class FileDescriptor
+ *
+ * This class manages an open file descriptor.
+ *
+ * The file descriptor can be closed by calling close().  Otherwise it will be
+ * closed by the destructor.
+ *
+ * FileDescriptor objects cannot be copied, but they can be moved.  This enables
+ * them to be stored in containers like std::vector.
+ */
+class FileDescriptor
+{
+  public:
+    FileDescriptor() = default;
+    FileDescriptor(const FileDescriptor&) = delete;
+    FileDescriptor& operator=(const FileDescriptor&) = delete;
+
+    /**
+     * Constructor.
+     *
+     * @param[in] fd - File descriptor
+     */
+    FileDescriptor(int fd) : fd(fd)
+    {
+    }
+
+    /**
+     * Move constructor.
+     *
+     * Transfers ownership of a file descriptor.
+     *
+     * @param other - FileDescriptor object being moved
+     */
+    FileDescriptor(FileDescriptor&& other) : fd(other.fd)
+    {
+        other.fd = -1;
+    }
+
+    /**
+     * Move assignment operator.
+     *
+     * Closes the file descriptor owned by this object, if any.  Then transfers
+     * ownership of the file descriptor owned by the other object.
+     *
+     * @param other - FileDescriptor object being moved
+     */
+    FileDescriptor& operator=(FileDescriptor&& other)
+    {
+        // Verify not assigning object to itself (a = std::move(a))
+        if (this != &other)
+        {
+            set(other.fd);
+            other.fd = -1;
+        }
+        return *this;
+    }
+
+    /**
+     * Destructor.
+     *
+     * Closes the file descriptor if necessary.
+     */
+    ~FileDescriptor()
+    {
+        close();
+    }
+
+    /**
+     * Returns the file descriptor.
+     *
+     * @return File descriptor.  Returns -1 if this object does not contain an
+     *         open file descriptor.
+     */
+    int operator()()
+    {
+        return fd;
+    }
+
+    /**
+     * Returns whether this object contains an open file descriptor.
+     *
+     * @return true if object contains an open file descriptor, false otherwise.
+     */
+    operator bool() const
+    {
+        return fd != -1;
+    }
+
+    /**
+     * Closes the file descriptor.
+     *
+     * Does nothing if the file descriptor was not set or was already closed.
+     *
+     * @return 0 if descriptor was successfully closed.  Returns -1 if an error
+     *         occurred; errno will be set appropriately.
+     */
+    int close()
+    {
+        int rc = 0;
+        if (fd >= 0)
+        {
+            rc = ::close(fd);
+            fd = -1;
+        }
+        return rc;
+    }
+
+    /**
+     * Sets the file descriptor.
+     *
+     * Closes the previous file descriptor if necessary.
+     *
+     * @param[in] descriptor - File descriptor
+     */
+    void set(int descriptor)
+    {
+        close();
+        fd = descriptor;
+    }
+
+  private:
+    /**
+     * File descriptor.
+     */
+    int fd = -1;
+};
+
+} // namespace phosphor::power::util