Fix the last issues with exception_wrapper under MSVC
[folly.git] / folly / File.cpp
1 /*
2  * Copyright 2017 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 #include <folly/File.h>
18
19
20 #include <folly/Exception.h>
21 #include <folly/FileUtil.h>
22 #include <folly/Format.h>
23 #include <folly/ScopeGuard.h>
24 #include <folly/portability/Fcntl.h>
25 #include <folly/portability/SysFile.h>
26 #include <folly/portability/Unistd.h>
27
28 #include <system_error>
29
30 #include <glog/logging.h>
31
32 namespace folly {
33
34 File::File()
35   : fd_(-1)
36   , ownsFd_(false)
37 {}
38
39 File::File(int fd, bool ownsFd)
40   : fd_(fd)
41   , ownsFd_(ownsFd) {
42   CHECK_GE(fd, -1) << "fd must be -1 or non-negative";
43   CHECK(fd != -1 || !ownsFd) << "cannot own -1";
44 }
45
46 File::File(const char* name, int flags, mode_t mode)
47   : fd_(::open(name, flags, mode))
48   , ownsFd_(false) {
49   if (fd_ == -1) {
50     throwSystemError(folly::format("open(\"{}\", {:#o}, 0{:#o}) failed",
51                                    name, flags, mode).fbstr());
52   }
53   ownsFd_ = true;
54 }
55
56 File::File(const std::string& name, int flags, mode_t mode)
57   : File(name.c_str(), flags, mode) {}
58
59 File::File(StringPiece name, int flags, mode_t mode)
60   : File(name.str(), flags, mode) {}
61
62 File::File(File&& other) noexcept
63   : fd_(other.fd_)
64   , ownsFd_(other.ownsFd_) {
65   other.release();
66 }
67
68 File& File::operator=(File&& other) {
69   closeNoThrow();
70   swap(other);
71   return *this;
72 }
73
74 File::~File() {
75   auto fd = fd_;
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.";
79   }
80 }
81
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); };
87
88   int fd = ::dup(fileno(tmpFile));
89   checkUnixError(fd, "dup() failed");
90
91   return File(fd, true);
92 }
93
94 int File::release() noexcept {
95   int released = fd_;
96   fd_ = -1;
97   ownsFd_ = false;
98   return released;
99 }
100
101 void File::swap(File& other) {
102   using std::swap;
103   swap(fd_, other.fd_);
104   swap(ownsFd_, other.ownsFd_);
105 }
106
107 void swap(File& a, File& b) {
108   a.swap(b);
109 }
110
111 File File::dup() const {
112   if (fd_ != -1) {
113     int fd = ::dup(fd_);
114     checkUnixError(fd, "dup() failed");
115
116     return File(fd, true);
117   }
118
119   return File();
120 }
121
122 void File::close() {
123   if (!closeNoThrow()) {
124     throwSystemError("close() failed");
125   }
126 }
127
128 bool File::closeNoThrow() {
129   int r = ownsFd_ ? ::close(fd_) : 0;
130   release();
131   return r == 0;
132 }
133
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); }
138
139 void File::doLock(int op) {
140   checkUnixError(flockNoInt(fd_, op), "flock() failed (lock)");
141 }
142
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)");
148   return true;
149 }
150
151 void File::unlock() {
152   checkUnixError(flockNoInt(fd_, LOCK_UN), "flock() failed (unlock)");
153 }
154 void File::unlock_shared() { unlock(); }
155
156 }  // namespace folly