LogCabin
|
00001 /* Copyright (c) 2011-2012 Stanford University 00002 * 00003 * Permission to use, copy, modify, and distribute this software for any 00004 * purpose with or without fee is hereby granted, provided that the above 00005 * copyright notice and this permission notice appear in all copies. 00006 * 00007 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR(S) DISCLAIM ALL WARRANTIES 00008 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 00009 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHORS BE LIABLE FOR 00010 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 00011 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 00012 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 00013 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 00014 */ 00015 00016 /** 00017 * \file 00018 * Contains utilities for working with the filesystem. 00019 */ 00020 00021 #include <cinttypes> 00022 #include <string> 00023 #include <vector> 00024 00025 #ifndef LOGCABIN_STORAGE_FILESYSTEMUTIL_H 00026 #define LOGCABIN_STORAGE_FILESYSTEMUTIL_H 00027 00028 namespace LogCabin { 00029 namespace Storage { 00030 namespace FilesystemUtil { 00031 00032 /** 00033 * Set to true in some unit tests to skip fsync() and fdatasync(), which can 00034 * speeds up some tests significantly. 00035 */ 00036 extern bool skipFsync; 00037 00038 /** 00039 * A File object is just a wrapper around a file descriptor; it represents 00040 * either an open file, an open directory, or an empty placeholder. It takes 00041 * charge of closing the file descriptor when it is done and tracks the path 00042 * used to open the file descriptor in order to provide useful error messages. 00043 */ 00044 class File { 00045 public: 00046 /// Default constructor. 00047 File(); 00048 /// Move constructor. 00049 File(File&& other); 00050 /** 00051 * Constructor. 00052 * \param fd 00053 * An open file descriptor. 00054 * \param path 00055 * The path used to open fd; used for error messages. 00056 */ 00057 File(int fd, std::string path); 00058 00059 /** 00060 * Destructor. Closes file unless it's already been closed. 00061 */ 00062 ~File(); 00063 00064 /// Move assignment. 00065 File& operator=(File&& other); 00066 00067 /** 00068 * Close the file. 00069 * This object's fd and path are cleared. 00070 */ 00071 void close(); 00072 00073 /** 00074 * Disassociate the file descriptor from this object. 00075 * The caller is in charge of closing the file descriptor. This object's fd 00076 * and path are cleared. 00077 * \return 00078 * The file descriptor. 00079 */ 00080 int release(); 00081 00082 /** 00083 * The open file descriptor, or -1 otherwise. 00084 */ 00085 int fd; 00086 /** 00087 * The path used to open fd, or empty. Used for error messages. 00088 */ 00089 std::string path; 00090 00091 // File is not copyable. 00092 File(const File&) = delete; 00093 File& operator=(const File&) = delete; 00094 }; 00095 00096 /** 00097 * Allocate a contiguous range of a file, padding with zeros if necessary. 00098 * See man 3 posix_fallocate. Does not fsync the file. 00099 */ 00100 void allocate(const File& file, uint64_t offset, uint64_t bytes); 00101 00102 /** 00103 * Clones a file descriptor. See man 2 dup. 00104 * \param file 00105 * An open file descriptor. 00106 * \return 00107 * A copy of 'file' with a new file descriptor. 00108 */ 00109 File dup(const File& file); 00110 00111 /** 00112 * Flush changes to a File to its underlying storage device. 00113 * See #skipFsync. 00114 * \param file 00115 * An open file descriptor. 00116 */ 00117 void fsync(const File& file); 00118 00119 /** 00120 * Flush changes to a File to its underlying storage device, except for 00121 * atime/mtime. See fdatasync man page. 00122 * \param file 00123 * An open file descriptor. 00124 * See #skipFsync. 00125 */ 00126 void fdatasync(const File& file); 00127 00128 /** 00129 * Apply or remove an advisory lock on a file or directory. 00130 * See man 2 flock. 00131 * PANICs if any errors are encountered, even EWOULDBLOCK (see tryFlock). 00132 */ 00133 void flock(const File& file, int operation); 00134 00135 /** 00136 * Apply or remove an advisory lock on a file or directory. 00137 * See man 2 flock. 00138 * \param file 00139 * File or directory to lock. 00140 * \param operation 00141 * LOCK_SH, LOCK_EX, or LOCK_UN, usually ORed with LOCK_NB. 00142 * \return 00143 * If successful, returns the empty string. 00144 * If the operation would have blocked, returns a non-empty string with 00145 * detailed information. 00146 */ 00147 std::string 00148 tryFlock(const File& file, int operation); 00149 00150 /** 00151 * Returns the size of the file in bytes. 00152 */ 00153 uint64_t getSize(const File& file); 00154 00155 /** 00156 * List the contents of a directory by path. 00157 * Panics if the 'path' is not a directory. 00158 * \param path 00159 * The path to the directory whose contents to list. 00160 * \return 00161 * The names of the directory entries in the order returned by readdir. 00162 * The caller will often want to prepend 'path' and a slash to these to 00163 * form a path. 00164 */ 00165 std::vector<std::string> ls(const std::string& path); 00166 00167 /** 00168 * List the contents of an open directory. 00169 * Panics if 'dir' is not a directory. 00170 * \param dir 00171 * An open file descriptor to the directory whose contents to list. 00172 * \return 00173 * The names of the directory entries in the order returned by readdir. 00174 */ 00175 std::vector<std::string> ls(const File& dir); 00176 00177 /** 00178 * Open a directory, creating it if it doesn't exist. 00179 */ 00180 File openDir(const std::string& path); 00181 00182 /** 00183 * Open a directory relative to an already open directory, creating it if it 00184 * doesn't exist. 00185 */ 00186 File openDir(const File& dir, const std::string& child); 00187 00188 /** 00189 * Open a file. See man 2 openat. 00190 * 00191 * Panics if the file could not be opened; see #tryOpenFile() if this isn't 00192 * what you want. 00193 */ 00194 File openFile(const File& dir, const std::string& child, int flags); 00195 00196 /** 00197 * Open a file. See man 2 openat. 00198 * 00199 * Returns a default-constructed File object if the file could not be opened 00200 * due to EEXIST or ENOENT; see #openFile() if this isn't what you want. 00201 */ 00202 File tryOpenFile(const File& dir, const std::string& child, int flags); 00203 00204 /** 00205 * Remove the file or directory at path. 00206 * If path is a directory, its contents will also be removed. 00207 * If path does not exist, this returns without an error. 00208 * This operation is not atomic but is idempotent. 00209 */ 00210 void remove(const std::string& path); 00211 00212 /** 00213 * Remove the file relative to an open directory. 00214 * If path does not exist, this returns without an error. 00215 * This does not fsync the directory. 00216 * \param dir 00217 * An open file descriptor to the directory containing path. 00218 * \param path 00219 * The path of the file to remove, relative to dirFd. 00220 * This must be a file; it may not be a directory. 00221 */ 00222 void 00223 removeFile(const File& dir, const std::string& path); 00224 00225 /** 00226 * Rename a file. See man 2 renameat. 00227 * This does not fsync the directories. 00228 */ 00229 void rename(const File& oldDir, const std::string& oldChild, 00230 const File& newDir, const std::string& newChild); 00231 00232 /** 00233 * Open a directory, fsync it, and close it. This is useful to fsync a 00234 * directory after creating a file or directory within it. 00235 * See #skipFsync. 00236 */ 00237 void syncDir(const std::string& path); 00238 00239 /** 00240 * Shrink or grow a file to the specified length, padding with zeros if 00241 * necessary. See man 2 ftruncate. Does not fsync the file. 00242 */ 00243 void truncate(const File& file, uint64_t bytes); 00244 00245 /** 00246 * Return a path to a temporary directory. 00247 */ 00248 std::string mkdtemp(); 00249 00250 /** 00251 * A wrapper around write that retries interrupted calls. 00252 * \param fildes 00253 * The file handle on which to write data. 00254 * \param data 00255 * A pointer to the data to write. 00256 * \param dataLen 00257 * The number of bytes of 'data' to write. 00258 * \return 00259 * Either -1 with errno set, or the number of bytes requested to write. 00260 * This wrapper will never return -1 with errno set to EINTR. 00261 */ 00262 ssize_t 00263 write(int fildes, const void* data, uint64_t dataLen); 00264 00265 /** 00266 * A wrapper around write that retries interrupted calls. 00267 * \param fildes 00268 * The file handle on which to write data. 00269 * \param data 00270 * An I/O vector of data to write (pointer, length pairs). 00271 * \return 00272 * Either -1 with errno set, or the number of bytes requested to write. 00273 * This wrapper will never return -1 with errno set to EINTR. 00274 */ 00275 ssize_t 00276 write(int fildes, 00277 std::initializer_list<std::pair<const void*, uint64_t>> data); 00278 00279 /** 00280 * Provides random access to a file. 00281 * This implementation currently works by mmaping the file and working from the 00282 * in-memory copy. 00283 */ 00284 class FileContents { 00285 public: 00286 /** 00287 * Constructor. 00288 * \param file 00289 * An open file descriptor for the file to read. 00290 */ 00291 explicit FileContents(const File& file); 00292 /// Destructor. 00293 ~FileContents(); 00294 /** 00295 * Return the length of the file. 00296 */ 00297 uint64_t getFileLength() { return fileLen; } 00298 00299 /** 00300 * Copy some number of bytes of the file into a user-supplied buffer. 00301 * 00302 * If there are not enough bytes in the file, this will PANIC. See 00303 * copyPartial if that's not what you want. 00304 * 00305 * \param offset 00306 * The number of bytes into the file at which to start copying. 00307 * \param[out] buf 00308 * The destination buffer to copy into. 00309 * \param length 00310 * The number of bytes to copy. 00311 */ 00312 void copy(uint64_t offset, void* buf, uint64_t length); 00313 00314 /** 00315 * Copy up to some number of bytes of the file into a user-supplied buffer. 00316 * 00317 * \param offset 00318 * The number of bytes into the file at which to start copying. 00319 * \param[out] buf 00320 * The destination buffer to copy into. 00321 * \param maxLength 00322 * The maximum number of bytes to copy. 00323 * \return 00324 * The number of bytes copied. This can be fewer than maxLength if the 00325 * file ended first. 00326 */ 00327 uint64_t copyPartial(uint64_t offset, void* buf, uint64_t maxLength); 00328 00329 /** 00330 * Get a pointer to a region of the file. 00331 * 00332 * If there are not enough bytes in the file, this will PANIC. 00333 * 00334 * \tparam T 00335 * The return type is casted to a pointer of T. 00336 * \param offset 00337 * The number of bytes into the file at which to return the pointer. 00338 * \param length 00339 * The number of bytes that must be valid after the offset. 00340 * \return 00341 * A pointer to a buffer containing the 'length' bytes starting at 00342 * 'offset' in the file. The caller may not modify this buffer. The 00343 * returned buffer will remain valid until this object is destroyed. 00344 */ 00345 template<typename T = void> 00346 const T* 00347 get(uint64_t offset, uint64_t length) { 00348 return reinterpret_cast<const T*>(getHelper(offset, length)); 00349 } 00350 00351 private: 00352 /// Used internally by get(). 00353 const void* getHelper(uint64_t offset, uint64_t length); 00354 /// An open file descriptor for the file to read. 00355 File file; 00356 /// The number of bytes in the file. 00357 uint64_t fileLen; 00358 /// The value returned by mmap(), or NULL for empty files. 00359 const void* map; 00360 FileContents(const FileContents&) = delete; 00361 FileContents& operator=(const FileContents&) = delete; 00362 }; 00363 00364 } // namespace LogCabin::Storage::FilesystemUtil 00365 } // namespace LogCabin::Storage 00366 } // namespace LogCabin 00367 00368 #endif /* LOGCABIN_STORAGE_FILESYSTEMUTIL_H */