• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015, 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef UNIQUEFD_H_
18 #define UNIQUEFD_H_
19 
20 #include <fcntl.h>
21 #include <unistd.h>
22 
23 #include <memory>
24 
25 namespace android {
26 
27 /*
28  * Using UniqueFd:
29  * 1. Create UniqueFd object:
30  *    auto fd_obj = UniqueFd(open("SomeFile", xxx));
31  *
32  * 2. Check whether the fd_obj is empty:
33  *    if (!fd_obj) { return -errno; }
34  *
35  * 3. Accessing the file descriptor:
36  *    int ret = read(fd_obj.Get(), buf, buf_size);
37  *
38  * 4. Closing the file:
39  *    FD will be closed once execution leaves fd_obj scope (on any return,
40  *    exception, destruction of class/struct where object is member, etc.).
41  *    User can also force closing the fd_obj by calling:
42  *      fd_obj = UniqueFd();
43  *      // fd is closed and fd_obj is empty now.
44  *
45  * 5. File descriptor may be transferred to the code, which will close it after
46  *    using. This can be done in 2 ways:
47  *    a. Duplicate the fd, in this case both fds should be closed separately:
48  *      int out_fd = dup(fd_obj.Get();
49  *      ...
50  *      close(out_fd);
51  *    b. Transfer ownership, use this method if you do not need the fd anymore.
52  *      int out_fd = fd_obj.Release();
53  *      // fd_obj is empty now.
54  *      ...
55  *      close(out_fd);
56  *
57  * 6. Transferring fd into another UniqueFD object:
58  *    UniqueFd fd_obj_2 = std::move(fd_obj);
59  *    // fd_obj empty now
60  */
61 
62 constexpr int kEmptyFd = -1;
63 
64 class UniqueFd {
65  public:
66   UniqueFd() = default;
UniqueFd(int fd)67   explicit UniqueFd(int fd) : fd_(fd){};
68 
69   auto Release [[nodiscard]] () -> int {
70     return std::exchange(fd_, kEmptyFd);
71   }
72 
73   auto Get [[nodiscard]] () const -> int {
74     return fd_;
75   }
76 
Dup(int fd)77   static auto Dup(int fd) {
78     // NOLINTNEXTLINE(android-cloexec-dup): fcntl has issue (see issue #63)
79     return UniqueFd(dup(fd));
80   }
81 
82   explicit operator bool() const {
83     return fd_ != kEmptyFd;
84   }
85 
~UniqueFd()86   ~UniqueFd() {
87     Set(kEmptyFd);
88   }
89 
90   /* Allow move semantics */
UniqueFd(UniqueFd && rhs)91   UniqueFd(UniqueFd &&rhs) noexcept {
92     Set(rhs.Release());
93   }
94 
95   auto operator=(UniqueFd &&rhs) noexcept -> UniqueFd & {
96     Set(rhs.Release());
97     return *this;
98   }
99 
100   /* Disable copy semantics */
101   UniqueFd(const UniqueFd &) = delete;
102   auto operator=(const UniqueFd &) = delete;
103 
104  private:
Set(int new_fd)105   void Set(int new_fd) {
106     if (fd_ != kEmptyFd) {
107       close(fd_);
108     }
109     fd_ = new_fd;
110   }
111 
112   int fd_ = kEmptyFd;
113 };
114 
115 }  // namespace android
116 
117 #endif
118