1*6e36587aSZane Shelley #pragma once
2*6e36587aSZane Shelley 
3*6e36587aSZane Shelley #include <unistd.h> // for close()
4*6e36587aSZane Shelley 
5*6e36587aSZane Shelley namespace util
6*6e36587aSZane Shelley {
7*6e36587aSZane Shelley 
8*6e36587aSZane Shelley /**
9*6e36587aSZane Shelley  * @class FileDescriptor
10*6e36587aSZane Shelley  *
11*6e36587aSZane Shelley  * This class manages an open file descriptor.
12*6e36587aSZane Shelley  *
13*6e36587aSZane Shelley  * The file descriptor can be closed by calling close().  Otherwise it will be
14*6e36587aSZane Shelley  * closed by the destructor.
15*6e36587aSZane Shelley  *
16*6e36587aSZane Shelley  * FileDescriptor objects cannot be copied, but they can be moved.  This enables
17*6e36587aSZane Shelley  * them to be stored in containers like std::vector.
18*6e36587aSZane Shelley  */
19*6e36587aSZane Shelley class FileDescriptor
20*6e36587aSZane Shelley {
21*6e36587aSZane Shelley   public:
22*6e36587aSZane Shelley     FileDescriptor()                      = default;
23*6e36587aSZane Shelley     FileDescriptor(const FileDescriptor&) = delete;
24*6e36587aSZane Shelley     FileDescriptor& operator=(const FileDescriptor&) = delete;
25*6e36587aSZane Shelley 
26*6e36587aSZane Shelley     /**
27*6e36587aSZane Shelley      * Constructor.
28*6e36587aSZane Shelley      *
29*6e36587aSZane Shelley      * @param[in] fd - File descriptor
30*6e36587aSZane Shelley      */
31*6e36587aSZane Shelley     explicit FileDescriptor(int fd) : fd(fd) {}
32*6e36587aSZane Shelley 
33*6e36587aSZane Shelley     /**
34*6e36587aSZane Shelley      * Move constructor.
35*6e36587aSZane Shelley      *
36*6e36587aSZane Shelley      * Transfers ownership of a file descriptor.
37*6e36587aSZane Shelley      *
38*6e36587aSZane Shelley      * @param other - FileDescriptor object being moved
39*6e36587aSZane Shelley      */
40*6e36587aSZane Shelley     FileDescriptor(FileDescriptor&& other) : fd(other.fd)
41*6e36587aSZane Shelley     {
42*6e36587aSZane Shelley         other.fd = -1;
43*6e36587aSZane Shelley     }
44*6e36587aSZane Shelley 
45*6e36587aSZane Shelley     /**
46*6e36587aSZane Shelley      * Move assignment operator.
47*6e36587aSZane Shelley      *
48*6e36587aSZane Shelley      * Closes the file descriptor owned by this object, if any.  Then transfers
49*6e36587aSZane Shelley      * ownership of the file descriptor owned by the other object.
50*6e36587aSZane Shelley      *
51*6e36587aSZane Shelley      * @param other - FileDescriptor object being moved
52*6e36587aSZane Shelley      */
53*6e36587aSZane Shelley     FileDescriptor& operator=(FileDescriptor&& other)
54*6e36587aSZane Shelley     {
55*6e36587aSZane Shelley         // Verify not assigning object to itself (a = std::move(a))
56*6e36587aSZane Shelley         if (this != &other)
57*6e36587aSZane Shelley         {
58*6e36587aSZane Shelley             set(other.fd);
59*6e36587aSZane Shelley             other.fd = -1;
60*6e36587aSZane Shelley         }
61*6e36587aSZane Shelley         return *this;
62*6e36587aSZane Shelley     }
63*6e36587aSZane Shelley 
64*6e36587aSZane Shelley     /**
65*6e36587aSZane Shelley      * Destructor.
66*6e36587aSZane Shelley      *
67*6e36587aSZane Shelley      * Closes the file descriptor if necessary.
68*6e36587aSZane Shelley      */
69*6e36587aSZane Shelley     ~FileDescriptor()
70*6e36587aSZane Shelley     {
71*6e36587aSZane Shelley         close();
72*6e36587aSZane Shelley     }
73*6e36587aSZane Shelley 
74*6e36587aSZane Shelley     /**
75*6e36587aSZane Shelley      * Returns the file descriptor.
76*6e36587aSZane Shelley      *
77*6e36587aSZane Shelley      * @return File descriptor.  Returns -1 if this object does not contain an
78*6e36587aSZane Shelley      *         open file descriptor.
79*6e36587aSZane Shelley      */
80*6e36587aSZane Shelley     int operator()()
81*6e36587aSZane Shelley     {
82*6e36587aSZane Shelley         return fd;
83*6e36587aSZane Shelley     }
84*6e36587aSZane Shelley 
85*6e36587aSZane Shelley     /**
86*6e36587aSZane Shelley      * Returns whether this object contains an open file descriptor.
87*6e36587aSZane Shelley      *
88*6e36587aSZane Shelley      * @return true if object contains an open file descriptor, false otherwise.
89*6e36587aSZane Shelley      */
90*6e36587aSZane Shelley     operator bool() const
91*6e36587aSZane Shelley     {
92*6e36587aSZane Shelley         return fd != -1;
93*6e36587aSZane Shelley     }
94*6e36587aSZane Shelley 
95*6e36587aSZane Shelley     /**
96*6e36587aSZane Shelley      * Closes the file descriptor.
97*6e36587aSZane Shelley      *
98*6e36587aSZane Shelley      * Does nothing if the file descriptor was not set or was already closed.
99*6e36587aSZane Shelley      *
100*6e36587aSZane Shelley      * @return 0 if descriptor was successfully closed.  Returns -1 if an error
101*6e36587aSZane Shelley      *         occurred; errno will be set appropriately.
102*6e36587aSZane Shelley      */
103*6e36587aSZane Shelley     int close()
104*6e36587aSZane Shelley     {
105*6e36587aSZane Shelley         int rc = 0;
106*6e36587aSZane Shelley         if (fd >= 0)
107*6e36587aSZane Shelley         {
108*6e36587aSZane Shelley             rc = ::close(fd);
109*6e36587aSZane Shelley             fd = -1;
110*6e36587aSZane Shelley         }
111*6e36587aSZane Shelley         return rc;
112*6e36587aSZane Shelley     }
113*6e36587aSZane Shelley 
114*6e36587aSZane Shelley     /**
115*6e36587aSZane Shelley      * Sets the file descriptor.
116*6e36587aSZane Shelley      *
117*6e36587aSZane Shelley      * Closes the previous file descriptor if necessary.
118*6e36587aSZane Shelley      *
119*6e36587aSZane Shelley      * @param[in] descriptor - File descriptor
120*6e36587aSZane Shelley      */
121*6e36587aSZane Shelley     void set(int descriptor)
122*6e36587aSZane Shelley     {
123*6e36587aSZane Shelley         close();
124*6e36587aSZane Shelley         fd = descriptor;
125*6e36587aSZane Shelley     }
126*6e36587aSZane Shelley 
127*6e36587aSZane Shelley   private:
128*6e36587aSZane Shelley     /**
129*6e36587aSZane Shelley      * File descriptor.
130*6e36587aSZane Shelley      */
131*6e36587aSZane Shelley     int fd = -1;
132*6e36587aSZane Shelley };
133*6e36587aSZane Shelley 
134*6e36587aSZane Shelley } // namespace util
135