X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=folly%2FFileUtil.h;h=5adcd62d6c0df6a869c1d8aecb37a6fca3833132;hb=4e5cb0efba9454e3abb2dd203116ed8e9a056468;hp=81974871fc8866493958782b98af54bdfc5ebad2;hpb=a896ed3944ade052af5ab68167cf21505b55286d;p=folly.git diff --git a/folly/FileUtil.h b/folly/FileUtil.h index 81974871..5adcd62d 100644 --- a/folly/FileUtil.h +++ b/folly/FileUtil.h @@ -1,5 +1,5 @@ /* - * Copyright 2013 Facebook, Inc. + * Copyright 2015 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,8 +17,12 @@ #ifndef FOLLY_FILEUTIL_H_ #define FOLLY_FILEUTIL_H_ -#include "folly/Portability.h" +#include +#include +#include +#include +#include #include #include #include @@ -33,12 +37,16 @@ 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); int fsyncNoInt(int fd); int fdatasyncNoInt(int fd); int ftruncateNoInt(int fd, off_t len); int truncateNoInt(const char* path, off_t len); +int flockNoInt(int fd, int operation); +int shutdownNoInt(int fd, int how); ssize_t readNoInt(int fd, void* buf, size_t n); ssize_t preadNoInt(int fd, void* buf, size_t n, off_t offset); @@ -73,7 +81,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); -#ifdef FOLLY_HAVE_PREADV +#if FOLLY_HAVE_PREADV ssize_t preadvFull(int fd, iovec* iov, int count, off_t offset); #endif @@ -94,11 +102,96 @@ 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); -#ifdef FOLLY_HAVE_PWRITEV +#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 + * num_bytes (otherwise) into container *out. The container is assumed + * to be contiguous, with element size equal to 1, and offer size(), + * reserve(), and random access (e.g. std::vector, std::string, + * fbstring). + * + * Returns: true on success or false on failure. In the latter case + * errno will be set appropriately by the failing system primitive. + */ +template +bool readFile(const char* file_name, Container& out, + size_t num_bytes = std::numeric_limits::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 + out.resize(soFar); + // Ignore errors when closing the file + closeNoInt(fd); + }; + + // Obtain file size: + struct stat buf; + if (fstat(fd, &buf) == -1) return false; + // Some files (notably under /proc and /sys on Linux) lie about + // their size, so treat the size advertised by fstat under advise + // but don't rely on it. In particular, if the size is zero, we + // should attempt to read stuff. If not zero, we'll attempt to read + // one extra byte. + constexpr size_t initialAlloc = 1024 * 4; + out.resize( + std::min( + buf.st_size > 0 ? folly::to(buf.st_size + 1) : initialAlloc, + num_bytes)); + + while (soFar < out.size()) { + const auto actual = readFull(fd, &out[soFar], out.size() - soFar); + if (actual == -1) { + return false; + } + soFar += actual; + if (soFar < out.size()) { + // File exhausted + break; + } + // Ew, allocate more memory. Use exponential growth to avoid + // quadratic behavior. Cap size to num_bytes. + out.resize(std::min(out.size() * 3 / 2, num_bytes)); + } + + return true; +} + +/** + * 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, 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 +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(data.size()); + return closeNoInt(fd) == 0 && ok; +} + } // namespaces #endif /* FOLLY_FILEUTIL_H_ */ -