/*
- * Copyright 2013 Facebook, Inc.
+ * Copyright 2016 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* limitations under the License.
*/
-#include "folly/File.h"
-#include "folly/Format.h"
-#include "folly/ScopeGuard.h"
+#include <folly/File.h>
+
+
+#include <folly/Exception.h>
+#include <folly/FileUtil.h>
+#include <folly/Format.h>
+#include <folly/ScopeGuard.h>
+#include <folly/portability/Fcntl.h>
+#include <folly/portability/SysFile.h>
+#include <folly/portability/Unistd.h>
#include <system_error>
File::File(int fd, bool ownsFd)
: fd_(fd)
- , ownsFd_(ownsFd)
-{}
+ , ownsFd_(ownsFd) {
+ CHECK_GE(fd, -1) << "fd must be -1 or non-negative";
+ CHECK(fd != -1 || !ownsFd) << "cannot own -1";
+}
File::File(const char* name, int flags, mode_t mode)
: fd_(::open(name, flags, mode))
, ownsFd_(false) {
-
- if (fd_ < 0) {
- throw std::system_error(errno, std::system_category(),
- folly::format("open(\"{}\", {:#o}, 0{:#o}) failed",
- name, flags, mode).str());
+ if (fd_ == -1) {
+ throwSystemError(folly::format("open(\"{}\", {:#o}, 0{:#o}) failed",
+ name, flags, mode).fbstr());
}
ownsFd_ = true;
}
-File::File(File&& other)
+File::File(const std::string& name, int flags, mode_t mode)
+ : File(name.c_str(), flags, mode) {}
+
+File::File(StringPiece name, int flags, mode_t mode)
+ : File(name.str(), flags, mode) {}
+
+File::File(File&& other) noexcept
: fd_(other.fd_)
, ownsFd_(other.ownsFd_) {
-
other.release();
}
}
File::~File() {
- closeNoThrow(); // ignore error
+ auto fd = fd_;
+ if (!closeNoThrow()) { // ignore most errors
+ DCHECK_NE(errno, EBADF) << "closing fd " << fd << ", it may already "
+ << "have been closed. Another time, this might close the wrong FD.";
+ }
}
/* static */ File File::temporary() {
// make a temp file with tmpfile(), dup the fd, then return it in a File.
FILE* tmpFile = tmpfile();
- if (!tmpFile) {
- throw std::system_error(errno, std::system_category(), "tmpfile() failed");
- }
+ checkFopenError(tmpFile, "tmpfile() failed");
SCOPE_EXIT { fclose(tmpFile); };
- int fd = dup(fileno(tmpFile));
- if (fd < 0) {
- throw std::system_error(errno, std::system_category(), "dup() failed");
- }
+ int fd = ::dup(fileno(tmpFile));
+ checkUnixError(fd, "dup() failed");
return File(fd, true);
}
-void File::release() {
+int File::release() noexcept {
+ int released = fd_;
fd_ = -1;
ownsFd_ = false;
+ return released;
}
void File::swap(File& other) {
a.swap(b);
}
+File File::dup() const {
+ if (fd_ != -1) {
+ int fd = ::dup(fd_);
+ checkUnixError(fd, "dup() failed");
+
+ return File(fd, true);
+ }
+
+ return File();
+}
+
void File::close() {
if (!closeNoThrow()) {
- throw std::system_error(errno, std::system_category(), "close() failed");
+ throwSystemError("close() failed");
}
}
return r == 0;
}
+void File::lock() { doLock(LOCK_EX); }
+bool File::try_lock() { return doTryLock(LOCK_EX); }
+void File::lock_shared() { doLock(LOCK_SH); }
+bool File::try_lock_shared() { return doTryLock(LOCK_SH); }
+
+void File::doLock(int op) {
+ checkUnixError(flockNoInt(fd_, op), "flock() failed (lock)");
+}
+
+bool File::doTryLock(int op) {
+ int r = flockNoInt(fd_, op | LOCK_NB);
+ // flock returns EWOULDBLOCK if already locked
+ if (r == -1 && errno == EWOULDBLOCK) return false;
+ checkUnixError(r, "flock() failed (try_lock)");
+ return true;
+}
+
+void File::unlock() {
+ checkUnixError(flockNoInt(fd_, LOCK_UN), "flock() failed (unlock)");
+}
+void File::unlock_shared() { unlock(); }
+
} // namespace folly