• 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 <unistd.h>
21 
22 #include <memory>
23 
24 namespace android {
25 
26 /*
27  * Using UniqueFd:
28  * 1. Create UniqueFd object:
29  *    auto fd_obj = UniqueFd(open("SomeFile", xxx));
30  *
31  * 2. Check whether the fd_obj is empty:
32  *    if (!fd_obj) { return -errno; }
33  *
34  * 3. Accessing the file descriptor:
35  *    int ret = read(fd_obj.Get(), buf, buf_size);
36  *
37  * 4. Closing the file:
38  *    FD will be closed once execution leaves fd_obj scope (on any return,
39  *    exception, destruction of class/struct where object is member, etc.).
40  *    User can also force closing the fd_obj by calling:
41  *      fd_obj = UniqueFd();
42  *      // fd is closed and fd_obj is empty now.
43  *
44  * 5. File descriptor may be transferred to the code, which will close it after
45  *    using. This can be done in 2 ways:
46  *    a. Duplicate the fd, in this case both fds should be closed separately:
47  *      int out_fd = dup(fd_obj.Get();
48  *      ...
49  *      close(out_fd);
50  *    b. Transfer ownership, use this method if you do not need the fd anymore.
51  *      int out_fd = fd_obj.Release();
52  *      // fd_obj is empty now.
53  *      ...
54  *      close(out_fd);
55  *
56  * 6. Transferring fd into another UniqueFD object:
57  *    UniqueFd fd_obj_2 = std::move(fd_obj);
58  *    // fd_obj empty now
59  */
60 
61 constexpr int kEmptyFd = -1;
62 
63 class UniqueFd {
64  public:
65   UniqueFd() = default;
UniqueFd(int fd)66   explicit UniqueFd(int fd) : fd_(fd){};
67 
68   auto Release [[nodiscard]] () -> int {
69     return std::exchange(fd_, kEmptyFd);
70   }
71 
72   auto Get [[nodiscard]] () const -> int {
73     return fd_;
74   }
75 
76   explicit operator bool() const {
77     return fd_ != kEmptyFd;
78   }
79 
~UniqueFd()80   ~UniqueFd() {
81     Set(kEmptyFd);
82   }
83 
84   /* Allow move semantics */
UniqueFd(UniqueFd && rhs)85   UniqueFd(UniqueFd &&rhs) noexcept {
86     Set(rhs.Release());
87   }
88 
89   auto operator=(UniqueFd &&rhs) noexcept -> UniqueFd & {
90     Set(rhs.Release());
91     return *this;
92   }
93 
94   /* Disable copy semantics */
95   UniqueFd(const UniqueFd &) = delete;
96   auto operator=(const UniqueFd &) = delete;
97 
98  private:
Set(int new_fd)99   void Set(int new_fd) {
100     if (fd_ != kEmptyFd) {
101       close(fd_);
102     }
103     fd_ = new_fd;
104   }
105 
106   int fd_ = kEmptyFd;
107 };
108 
109 }  // namespace android
110 
111 #endif
112