Add a SIGSEGV signal handler which detects stack overflow
[folly.git] / folly / FileUtil.h
index 4939803341215fa78816a593ff56e15d3deffb97..704a4969fc58d1cfff8780b13bf63a85d35a663d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2014 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.
  */
 
-#ifndef FOLLY_FILEUTIL_H_
-#define FOLLY_FILEUTIL_H_
+#pragma once
 
-#include "folly/Portability.h"
-#include "folly/ScopeGuard.h"
+#include <folly/Conv.h>
+#include <folly/Portability.h>
+#include <folly/ScopeGuard.h>
+#include <folly/portability/SysUio.h>
+#include <folly/portability/Unistd.h>
 
 #include <cassert>
 #include <limits>
 #include <sys/stat.h>
 #include <sys/types.h>
-#include <sys/uio.h>
 #include <fcntl.h>
-#include <unistd.h>
 
 namespace folly {
 
@@ -36,7 +36,7 @@ namespace folly {
  * until all data is written.  Note that *Full wrappers weaken the thread
  * semantics of underlying system calls.
  */
-int openNoInt(const char* name, int flags, mode_t mode=0644);
+int openNoInt(const char* name, int flags, mode_t mode = 0666);
 int closeNoInt(int fd);
 int dupNoInt(int fd);
 int dup2NoInt(int oldfd, int newfd);
@@ -80,9 +80,7 @@ ssize_t writevNoInt(int fd, const iovec* iov, int count);
 ssize_t readFull(int fd, void* buf, size_t n);
 ssize_t preadFull(int fd, void* buf, size_t n, off_t offset);
 ssize_t readvFull(int fd, iovec* iov, int count);
-#if FOLLY_HAVE_PREADV
 ssize_t preadvFull(int fd, iovec* iov, int count, off_t offset);
-#endif
 
 /**
  * Similar to readFull and preadFull above, wrappers around write() and
@@ -101,9 +99,7 @@ ssize_t preadvFull(int fd, iovec* iov, int count, off_t offset);
 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);
 ssize_t writevFull(int fd, iovec* iov, int count);
-#if FOLLY_HAVE_PWRITEV
 ssize_t pwritevFull(int fd, iovec* iov, int count, off_t offset);
-#endif
 
 /**
  * Read entire file (if num_bytes is defaulted) or no more than
@@ -122,7 +118,7 @@ bool readFile(const char* file_name, Container& out,
                 "readFile: only containers with byte-sized elements accepted");
   assert(file_name);
 
-  const auto fd = open(file_name, O_RDONLY);
+  const auto fd = openNoInt(file_name, O_RDONLY);
   if (fd == -1) return false;
 
   size_t soFar = 0; // amount of bytes successfully read
@@ -130,7 +126,7 @@ bool readFile(const char* file_name, Container& out,
     assert(out.size() >= soFar); // resize better doesn't throw
     out.resize(soFar);
     // Ignore errors when closing the file
-    close(fd);
+    closeNoInt(fd);
   };
 
   // Obtain file size:
@@ -144,7 +140,7 @@ bool readFile(const char* file_name, Container& out,
   constexpr size_t initialAlloc = 1024 * 4;
   out.resize(
     std::min(
-      buf.st_size ? buf.st_size + 1 : initialAlloc,
+      buf.st_size > 0 ? folly::to<size_t>(buf.st_size + 1) : initialAlloc,
       num_bytes));
 
   while (soFar < out.size()) {
@@ -165,6 +161,30 @@ bool readFile(const char* file_name, Container& out,
   return true;
 }
 
-}  // namespaces
+/**
+ * Writes container to file. The container is assumed to be
+ * contiguous, with element size equal to 1, and offering STL-like
+ * methods empty(), size(), and indexed access
+ * (e.g. std::vector<char>, std::string, fbstring, StringPiece).
+ *
+ * "flags" dictates the open flags to use. Default is to create file
+ * if it doesn't exist and truncate it.
+ *
+ * Returns: true on success or false on failure. In the latter case
+ * errno will be set appropriately by the failing system primitive.
+ */
+template <class Container>
+bool writeFile(const Container& data, const char* filename,
+              int flags = O_WRONLY | O_CREAT | O_TRUNC) {
+  static_assert(sizeof(data[0]) == 1,
+                "writeFile works with element size equal to 1");
+  int fd = open(filename, flags, 0666);
+  if (fd == -1) {
+    return false;
+  }
+  bool ok = data.empty() ||
+    writeFull(fd, &data[0], data.size()) == static_cast<ssize_t>(data.size());
+  return closeNoInt(fd) == 0 && ok;
+}
 
-#endif /* FOLLY_FILEUTIL_H_ */
+}  // namespaces