1 | /* |
2 | * Copyright (c) Facebook, Inc. and its affiliates. |
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 | #pragma once |
18 | |
19 | #include <fcntl.h> |
20 | #include <sys/stat.h> |
21 | #include <sys/types.h> |
22 | |
23 | #include <string> |
24 | #include <system_error> |
25 | |
26 | #include <folly/ExceptionWrapper.h> |
27 | #include <folly/Expected.h> |
28 | #include <folly/Portability.h> |
29 | #include <folly/Range.h> |
30 | #include <folly/portability/Unistd.h> |
31 | |
32 | namespace folly { |
33 | |
34 | /** |
35 | * A File represents an open file. |
36 | */ |
37 | class File { |
38 | public: |
39 | /** |
40 | * Creates an empty File object, for late initialization. |
41 | */ |
42 | File() noexcept; |
43 | |
44 | /** |
45 | * Create a File object from an existing file descriptor. |
46 | * Takes ownership of the file descriptor if ownsFd is true. |
47 | */ |
48 | explicit File(int fd, bool ownsFd = false) noexcept; |
49 | |
50 | /** |
51 | * Open and create a file object. Throws on error. |
52 | * Owns the file descriptor implicitly. |
53 | */ |
54 | explicit File(const char* name, int flags = O_RDONLY, mode_t mode = 0666); |
55 | explicit File( |
56 | const std::string& name, |
57 | int flags = O_RDONLY, |
58 | mode_t mode = 0666); |
59 | explicit File(StringPiece name, int flags = O_RDONLY, mode_t mode = 0666); |
60 | |
61 | /** |
62 | * All the constructors that are not noexcept can throw std::system_error. |
63 | * This is a helper method to use folly::Expected to chain a file open event |
64 | * to something else you want to do with the open fd. |
65 | */ |
66 | template <typename... Args> |
67 | static Expected<File, exception_wrapper> makeFile(Args&&... args) noexcept { |
68 | try { |
69 | return File(std::forward<Args>(args)...); |
70 | } catch (const std::system_error& se) { |
71 | return makeUnexpected(exception_wrapper(std::current_exception(), se)); |
72 | } |
73 | } |
74 | |
75 | ~File(); |
76 | |
77 | /** |
78 | * Create and return a temporary, owned file (uses tmpfile()). |
79 | */ |
80 | static File temporary(); |
81 | |
82 | /** |
83 | * Return the file descriptor, or -1 if the file was closed. |
84 | */ |
85 | int fd() const { |
86 | return fd_; |
87 | } |
88 | |
89 | /** |
90 | * Returns 'true' iff the file was successfully opened. |
91 | */ |
92 | explicit operator bool() const { |
93 | return fd_ != -1; |
94 | } |
95 | |
96 | /** |
97 | * Duplicate file descriptor and return File that owns it. |
98 | */ |
99 | File dup() const; |
100 | |
101 | /** |
102 | * If we own the file descriptor, close the file and throw on error. |
103 | * Otherwise, do nothing. |
104 | */ |
105 | void close(); |
106 | |
107 | /** |
108 | * Closes the file (if owned). Returns true on success, false (and sets |
109 | * errno) on error. |
110 | */ |
111 | bool closeNoThrow(); |
112 | |
113 | /** |
114 | * Returns and releases the file descriptor; no longer owned by this File. |
115 | * Returns -1 if the File object didn't wrap a file. |
116 | */ |
117 | int release() noexcept; |
118 | |
119 | /** |
120 | * Swap this File with another. |
121 | */ |
122 | void swap(File& other) noexcept; |
123 | |
124 | // movable |
125 | File(File&&) noexcept; |
126 | File& operator=(File&&); |
127 | |
128 | // FLOCK (INTERPROCESS) LOCKS |
129 | // |
130 | // NOTE THAT THESE LOCKS ARE flock() LOCKS. That is, they may only be used |
131 | // for inter-process synchronization -- an attempt to acquire a second lock |
132 | // on the same file descriptor from the same process may succeed. Attempting |
133 | // to acquire a second lock on a different file descriptor for the same file |
134 | // should fail, but some systems might implement flock() using fcntl() locks, |
135 | // in which case it will succeed. |
136 | void lock(); |
137 | bool try_lock(); |
138 | void unlock(); |
139 | |
140 | void lock_shared(); |
141 | bool try_lock_shared(); |
142 | void unlock_shared(); |
143 | |
144 | private: |
145 | void doLock(int op); |
146 | bool doTryLock(int op); |
147 | |
148 | // unique |
149 | File(const File&) = delete; |
150 | File& operator=(const File&) = delete; |
151 | |
152 | int fd_; |
153 | bool ownsFd_; |
154 | }; |
155 | |
156 | void swap(File& a, File& b) noexcept; |
157 | |
158 | } // namespace folly |
159 | |