X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=folly%2FFileUtil.h;h=063fa2385c110d888ba8e07abc5a09f0b8b33529;hb=1672380910a8c21cd36095661eb1360f43c93332;hp=71d8e2551274089e9cf1cec503557790ccaf3168;hpb=c182b25f363bd80a8043d8616dec9dff8cf8736b;p=folly.git diff --git a/folly/FileUtil.h b/folly/FileUtil.h index 71d8e255..063fa238 100644 --- a/folly/FileUtil.h +++ b/folly/FileUtil.h @@ -1,5 +1,5 @@ /* - * Copyright 2014 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. @@ -14,20 +14,19 @@ * limitations under the License. */ -#ifndef FOLLY_FILEUTIL_H_ -#define FOLLY_FILEUTIL_H_ +#pragma once #include #include #include +#include +#include +#include #include #include #include #include -#include -#include -#include namespace folly { @@ -81,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 @@ -98,13 +95,14 @@ 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); 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 @@ -117,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 -bool readFile(const char* file_name, Container& out, - size_t num_bytes = std::numeric_limits::max()) { +bool readFile( + int fd, + 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 + DCHECK(out.size() >= soFar); // resize better doesn't throw out.resize(soFar); - // Ignore errors when closing the file - closeNoInt(fd); }; // Obtain file size: @@ -166,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 +bool readFile( + const char* file_name, + Container& out, + size_t num_bytes = std::numeric_limits::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 @@ -177,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 bool writeFile(const Container& data, const char* filename, @@ -188,10 +209,45 @@ bool writeFile(const Container& data, const char* filename, return false; } bool ok = data.empty() || - writeFull(fd, &data[0], data.size()) == data.size(); + writeFull(fd, &data[0], data.size()) == static_cast(data.size()); return closeNoInt(fd) == 0 && ok; } -} // namespaces +/** + * 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); -#endif /* FOLLY_FILEUTIL_H_ */ +} // namespaces