Fix incorrect usages of folly::Synchronized
[folly.git] / folly / File.cpp
index 4998ec1fa1113067d94f3566121b2ec32d1c8ce7..9fb755a8468e37a2c212f18f8369ef3faa211803 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2013 Facebook, Inc.
+ * Copyright 2017 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>
 
 
 namespace folly {
 
-File::File()
-  : fd_(-1)
-  , ownsFd_(false)
-{}
+File::File() noexcept : fd_(-1), ownsFd_(false) {}
 
-File::File(int fd, bool ownsFd)
-  : fd_(fd)
-  , ownsFd_(ownsFd)
-{}
+File::File(int fd, bool ownsFd) noexcept : fd_(fd), 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();
 }
 
@@ -60,38 +67,30 @@ File& File::operator=(File&& other) {
 }
 
 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);
 }
 
-/* static */ File File::tryOpen(const char* name,
-                                int flags,
-                                mode_t mode) {
-  try {
-    return File(name, flags, mode);
-  } catch (const std::system_error&) {
-    return File();
-  }
-}
-
-void File::release() {
+int File::release() noexcept {
+  int released = fd_;
   fd_ = -1;
   ownsFd_ = false;
+  return released;
 }
 
 void File::swap(File& other) {
@@ -104,9 +103,20 @@ void swap(File& a, File& b) {
   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");
   }
 }
 
@@ -116,4 +126,28 @@ bool File::closeNoThrow() {
   return r == 0;
 }
 
-}  // namespace folly
+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