blob: d747a7f71139520f76c8d5a103262f593128a405 [file] [log] [blame]
Roman Stratiienko0fade372021-02-20 13:59:55 +02001/*
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
Roman Stratiienkodd214942022-05-03 18:24:49 +030020#include <fcntl.h>
Roman Stratiienko0fade372021-02-20 13:59:55 +020021#include <unistd.h>
22
23#include <memory>
24
25namespace 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
62constexpr int kEmptyFd = -1;
63
64class UniqueFd {
65 public:
66 UniqueFd() = default;
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
Roman Stratiienkodd214942022-05-03 18:24:49 +030077 static auto Dup(int fd) {
78 // NOLINTNEXTLINE(android-cloexec-dup): fcntl has issue (see issue #63)
79 return UniqueFd(dup(fd));
80 }
81
Roman Stratiienko0fade372021-02-20 13:59:55 +020082 explicit operator bool() const {
83 return fd_ != kEmptyFd;
84 }
85
86 ~UniqueFd() {
87 Set(kEmptyFd);
88 }
89
90 /* Allow move semantics */
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:
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