1/*
2 * Copyright 2013-present Facebook, Inc.
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
32namespace folly {
33
34/**
35 * A File represents an open file.
36 */
37class 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
156void swap(File& a, File& b) noexcept;
157
158} // namespace folly
159