apply clang-tidy modernize-use-override
[folly.git] / folly / FileUtil.h
index 704a4969fc58d1cfff8780b13bf63a85d35a663d..063fa2385c110d888ba8e07abc5a09f0b8b33529 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016 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.
@@ -19,6 +19,7 @@
 #include <folly/Conv.h>
 #include <folly/Portability.h>
 #include <folly/ScopeGuard.h>
+#include <folly/portability/Fcntl.h>
 #include <folly/portability/SysUio.h>
 #include <folly/portability/Unistd.h>
 
@@ -26,7 +27,6 @@
 #include <limits>
 #include <sys/stat.h>
 #include <sys/types.h>
-#include <fcntl.h>
 
 namespace folly {
 
@@ -95,6 +95,9 @@ ssize_t preadvFull(int fd, iovec* iov, int count, off_t offset);
  * Note that writevFull and pwritevFull require iov to be non-const, unlike
  * writev and pwritev.  The contents of iov after these functions return
  * is unspecified.
+ *
+ * These functions return -1 on error, or the total number of bytes written
+ * (which is always the same as the number of requested bytes) on success.
  */
 ssize_t writeFull(int fd, const void* buf, size_t n);
 ssize_t pwriteFull(int fd, const void* buf, size_t n, off_t offset);
@@ -112,21 +115,17 @@ ssize_t pwritevFull(int fd, iovec* iov, int count, off_t offset);
  * errno will be set appropriately by the failing system primitive.
  */
 template <class Container>
-bool readFile(const char* file_name, Container& out,
-              size_t num_bytes = std::numeric_limits<size_t>::max()) {
+bool readFile(
+    int fd,
+    Container& out,
+    size_t num_bytes = std::numeric_limits<size_t>::max()) {
   static_assert(sizeof(out[0]) == 1,
                 "readFile: only containers with byte-sized elements accepted");
-  assert(file_name);
-
-  const auto fd = openNoInt(file_name, O_RDONLY);
-  if (fd == -1) return false;
 
   size_t soFar = 0; // amount of bytes successfully read
   SCOPE_EXIT {
-    assert(out.size() >= soFar); // resize better doesn't throw
+    DCHECK(out.size() >= soFar); // resize better doesn't throw
     out.resize(soFar);
-    // Ignore errors when closing the file
-    closeNoInt(fd);
   };
 
   // Obtain file size:
@@ -161,6 +160,29 @@ bool readFile(const char* file_name, Container& out,
   return true;
 }
 
+/**
+ * Same as above, but takes in a file name instead of fd
+ */
+template <class Container>
+bool readFile(
+    const char* file_name,
+    Container& out,
+    size_t num_bytes = std::numeric_limits<size_t>::max()) {
+  DCHECK(file_name);
+
+  const auto fd = openNoInt(file_name, O_RDONLY);
+  if (fd == -1) {
+    return false;
+  }
+
+  SCOPE_EXIT {
+    // Ignore errors when closing the file
+    closeNoInt(fd);
+  };
+
+  return readFile(fd, out, num_bytes);
+}
+
 /**
  * Writes container to file. The container is assumed to be
  * contiguous, with element size equal to 1, and offering STL-like
@@ -172,6 +194,10 @@ bool readFile(const char* file_name, Container& out,
  *
  * Returns: true on success or false on failure. In the latter case
  * errno will be set appropriately by the failing system primitive.
+ *
+ * Note that this function may leave the file in a partially written state on
+ * failure.  Use writeFileAtomic() if you want to ensure that the existing file
+ * state will be unchanged on error.
  */
 template <class Container>
 bool writeFile(const Container& data, const char* filename,
@@ -187,4 +213,41 @@ bool writeFile(const Container& data, const char* filename,
   return closeNoInt(fd) == 0 && ok;
 }
 
+/**
+ * Write file contents "atomically".
+ *
+ * This writes the data to a temporary file in the destination directory, and
+ * then renames it to the specified path.  This guarantees that the specified
+ * file will be replaced the the specified contents on success, or will not be
+ * modified on failure.
+ *
+ * Note that on platforms that do not provide atomic filesystem rename
+ * functionality (e.g., Windows) this behavior may not be truly atomic.
+ */
+void writeFileAtomic(
+    StringPiece filename,
+    iovec* iov,
+    int count,
+    mode_t permissions = 0644);
+void writeFileAtomic(
+    StringPiece filename,
+    ByteRange data,
+    mode_t permissions = 0644);
+void writeFileAtomic(
+    StringPiece filename,
+    StringPiece data,
+    mode_t permissions = 0644);
+
+/**
+ * A version of writeFileAtomic() that returns an errno value instead of
+ * throwing on error.
+ *
+ * Returns 0 on success or an errno value on error.
+ */
+int writeFileAtomicNoThrow(
+    StringPiece filename,
+    iovec* iov,
+    int count,
+    mode_t permissions = 0644);
+
 }  // namespaces