2 * Copyright 2015 Facebook, Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include <folly/File.h>
23 #include <folly/Exception.h>
24 #include <folly/FileUtil.h>
25 #include <folly/Format.h>
26 #include <folly/ScopeGuard.h>
28 #include <system_error>
30 #include <glog/logging.h>
39 File::File(int fd, bool ownsFd)
42 CHECK_GE(fd, -1) << "fd must be -1 or non-negative";
43 CHECK(fd != -1 || !ownsFd) << "cannot own -1";
46 File::File(const char* name, int flags, mode_t mode)
47 : fd_(::open(name, flags, mode))
50 throwSystemError(folly::format("open(\"{}\", {:#o}, 0{:#o}) failed",
51 name, flags, mode).fbstr());
56 File::File(const std::string& name, int flags, mode_t mode)
57 : File(name.c_str(), flags, mode) {}
59 File::File(StringPiece name, int flags, mode_t mode)
60 : File(name.str(), flags, mode) {}
62 File::File(File&& other) noexcept
64 , ownsFd_(other.ownsFd_) {
68 File& File::operator=(File&& other) {
76 if (!closeNoThrow()) { // ignore most errors
77 DCHECK_NE(errno, EBADF) << "closing fd " << fd << ", it may already "
78 << "have been closed. Another time, this might close the wrong FD.";
82 /* static */ File File::temporary() {
83 // make a temp file with tmpfile(), dup the fd, then return it in a File.
84 FILE* tmpFile = tmpfile();
85 checkFopenError(tmpFile, "tmpfile() failed");
86 SCOPE_EXIT { fclose(tmpFile); };
88 int fd = ::dup(fileno(tmpFile));
89 checkUnixError(fd, "dup() failed");
91 return File(fd, true);
94 int File::release() noexcept {
101 void File::swap(File& other) {
103 swap(fd_, other.fd_);
104 swap(ownsFd_, other.ownsFd_);
107 void swap(File& a, File& b) {
111 File File::dup() const {
114 checkUnixError(fd, "dup() failed");
116 return File(fd, true);
123 if (!closeNoThrow()) {
124 throwSystemError("close() failed");
128 bool File::closeNoThrow() {
129 int r = ownsFd_ ? ::close(fd_) : 0;
134 void File::lock() { doLock(LOCK_EX); }
135 bool File::try_lock() { return doTryLock(LOCK_EX); }
136 void File::lock_shared() { doLock(LOCK_SH); }
137 bool File::try_lock_shared() { return doTryLock(LOCK_SH); }
139 void File::doLock(int op) {
140 checkUnixError(flockNoInt(fd_, op), "flock() failed (lock)");
143 bool File::doTryLock(int op) {
144 int r = flockNoInt(fd_, op | LOCK_NB);
145 // flock returns EWOULDBLOCK if already locked
146 if (r == -1 && errno == EWOULDBLOCK) return false;
147 checkUnixError(r, "flock() failed (try_lock)");
151 void File::unlock() {
152 checkUnixError(flockNoInt(fd_, LOCK_UN), "flock() failed (unlock)");
154 void File::unlock_shared() { unlock(); }