LogCabin
Storage/FilesystemUtil.h
Go to the documentation of this file.
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 */
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines