/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include <sys/stat.h> #include <sys/types.h> #include <cassert> #include <limits> #include <folly/Portability.h> #include <folly/Range.h> #include <folly/ScopeGuard.h> #include <folly/net/NetworkSocket.h> #include <folly/portability/Fcntl.h> #include <folly/portability/SysUio.h> #include <folly/portability/Unistd.h> namespace folly { /** * Convenience wrappers around some commonly used system calls. The *NoInt * wrappers retry on EINTR. The *Full wrappers retry on EINTR and also loop * 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 = 0666); // Two overloads, as we may be closing either a file or a socket. int closeNoInt(int fd); int closeNoInt(NetworkSocket 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(NetworkSocket fd, int how); ssize_t readNoInt(int fd, void* buf, size_t count); ssize_t preadNoInt(int fd, void* buf, size_t count, off_t offset); ssize_t readvNoInt(int fd, const iovec* iov, int count); ssize_t preadvNoInt(int fd, const iovec* iov, int count, off_t offset); ssize_t writeNoInt(int fd, const void* buf, size_t count); ssize_t pwriteNoInt(int fd, const void* buf, size_t count, off_t offset); ssize_t writevNoInt(int fd, const iovec* iov, int count); ssize_t pwritevNoInt(int fd, const iovec* iov, int count, off_t offset); /** * Wrapper around read() (and pread()) that, in addition to retrying on * EINTR, will loop until all data is read. * * This wrapper is only useful for blocking file descriptors (for non-blocking * file descriptors, you have to be prepared to deal with incomplete reads * anyway), and only exists because POSIX allows read() to return an incomplete * read if interrupted by a signal (instead of returning -1 and setting errno * to EINTR). * * Note that this wrapper weakens the thread safety of read(): the file pointer * is shared between threads, but the system call is atomic. If multiple * threads are reading from a file at the same time, you don't know where your * data came from in the file, but you do know that the returned bytes were * contiguous. You can no longer make this assumption if using readFull(). * You should probably use pread() when reading from the same file descriptor * from multiple threads simultaneously, anyway. * * Note that readvFull and preadvFull require iov to be non-const, unlike * readv and preadv. The contents of iov after these functions return * is unspecified. */ FOLLY_NODISCARD ssize_t readFull(int fd, void* buf, size_t count); FOLLY_NODISCARD ssize_t preadFull(int fd, void* buf, size_t count, off_t offset); FOLLY_NODISCARD ssize_t readvFull(int fd, iovec* iov, int count); FOLLY_NODISCARD ssize_t preadvFull(int fd, iovec* iov, int count, off_t offset); /** * Similar to readFull and preadFull above, wrappers around write() and * pwrite() that loop until all data is written. * * Generally, the write() / pwrite() system call may always write fewer bytes * than requested, just like read(). In certain cases (such as when writing to * a pipe), POSIX provides stronger guarantees, but not in the general case. * For example, Linux (even on a 64-bit platform) won't write more than 2GB in * one write() system call. * * 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 count); ssize_t pwriteFull(int fd, const void* buf, size_t count, off_t offset); ssize_t writevFull(int fd, iovec* iov, int count); ssize_t pwritevFull(int fd, iovec* iov, int count, off_t offset); /** * 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<char>, 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 <class Container> bool readFile( int fd, Container& out, size_t num_bytes = std::numeric_limits<size_t>::max()) { … } /** * 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()) { … } /** * 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. * * 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, int flags = O_WRONLY | O_CREAT | O_TRUNC, mode_t mode = 0666) { … } /* For atomic writes, do we sync to guarantee ordering or not? */ enum class SyncType { … }; class WriteFileAtomicOptions { … }; /* * writeFileAtomic() does not currently work on Windows. * Windows does not provide atomic file renames, which makes implementing this * tricky. Windows does have a MoveFileTransactedA() API which could * potentially be used, but according to the Microsoft documentation this API is * discouraged and may be removed in a future version. * * In order to implement this properly on Windows we would probably need a pair * of functions: one for writing the file, and one for reading the contents, * where the two functions synchronize with each other. We can probably only * provide atomic update behavior with cooperation from the reader. */ #ifndef _WIN32 /** * 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 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. * * The default implementation does not sync the data to storage before the * rename. Therefore, the write is *not* atomic in the event of a power failure * or OS crash. To guarantee atomicity in these cases, specify syncType = * WITH_SYNC, which will incur a performance cost of waiting for the data to be * persisted to storage. Note that the return of the function does not * guarantee the directory modifications have been written to disk; a further * sync of the directory after the function returns is required to ensure the * modification is durable. */ void writeFileAtomic( StringPiece filePath, iovec* iov, int count, mode_t permissions = 0644, SyncType syncType = SyncType::WITHOUT_SYNC); void writeFileAtomic( StringPiece filePath, ByteRange data, mode_t permissions = 0644, SyncType syncType = SyncType::WITHOUT_SYNC); void writeFileAtomic( StringPiece filePath, StringPiece data, mode_t permissions = 0644, SyncType syncType = SyncType::WITHOUT_SYNC); void writeFileAtomic( StringPiece filePath, StringPiece data, const WriteFileAtomicOptions&); /** * 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 filePath, iovec* iov, int count, mode_t permissions = 0644, SyncType syncType = SyncType::WITHOUT_SYNC); int writeFileAtomicNoThrow( StringPiece filePath, StringPiece data, const WriteFileAtomicOptions&); #endif // !_WIN32 } // namespace folly