1 //===--- A platform independent file data structure -------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #ifndef LLVM_LIBC_SRC_SUPPORT_OSUTIL_FILE_H 10 #define LLVM_LIBC_SRC_SUPPORT_OSUTIL_FILE_H 11 12 #include <stddef.h> 13 #include <stdint.h> 14 15 namespace __llvm_libc { 16 17 // This a generic base class to encapsulate a platform independent file data 18 // structure. Platform specific specializations should create a subclass as 19 // suitable for their platform. 20 class File { 21 public: 22 using LockFunc = void(File *); 23 using UnlockFunc = void(File *); 24 25 using WriteFunc = size_t(File *, const void *, size_t); 26 using ReadFunc = size_t(File *, void *, size_t); 27 using SeekFunc = int(File *, long, int); 28 using CloseFunc = int(File *); 29 using FlushFunc = int(File *); 30 31 using ModeFlags = uint32_t; 32 33 // The three different types of flags below are to be used with '|' operator. 34 // Their values correspond to mutually exclusive bits in a 32-bit unsigned 35 // integer value. A flag set can include both READ and WRITE if the file 36 // is opened in update mode (ie. if the file was opened with a '+' the mode 37 // string.) 38 enum class OpenMode : ModeFlags { 39 READ = 0x1, 40 WRITE = 0x2, 41 APPEND = 0x4, 42 }; 43 44 // Denotes a file opened in binary mode (which is specified by including 45 // the 'b' character in teh mode string.) 46 enum class ContentType : ModeFlags { 47 BINARY = 0x10, 48 }; 49 50 // Denotes a file to be created for writing. 51 enum class CreateType : ModeFlags { 52 EXCLUSIVE = 0x100, 53 }; 54 55 private: 56 enum class FileOp : uint8_t { NONE, READ, WRITE, SEEK }; 57 58 // Platfrom specific functions which create new file objects should initialize 59 // these fields suitably via the constructor. Typically, they should be simple 60 // syscall wrappers for the corresponding functionality. 61 WriteFunc *platform_write; 62 ReadFunc *platform_read; 63 SeekFunc *platform_seek; 64 CloseFunc *platform_close; 65 FlushFunc *platform_flush; 66 67 // Platform specific functions to lock and unlock file for mutually exclusive 68 // access from threads in a multi-threaded application. 69 LockFunc *platform_lock; 70 UnlockFunc *platform_unlock; 71 72 void *buf; // Pointer to the stream buffer for buffered streams 73 size_t bufsize; // Size of the buffer pointed to by |buf|. 74 75 // Buffering mode to used to buffer. 76 int bufmode; 77 78 // If own_buf is true, the |buf| is owned by the stream and will be 79 // free-ed when close method is called on the stream. 80 bool own_buf; 81 82 // The mode in which the file was opened. 83 ModeFlags mode; 84 85 // Current read or write pointer. 86 size_t pos; 87 88 // Represents the previous operation that was performed. 89 FileOp prev_op; 90 91 // When the buffer is used as a read buffer, read_limit is the upper limit 92 // of the index to which the buffer can be read until. 93 size_t read_limit; 94 95 bool eof; 96 bool err; 97 98 protected: 99 bool write_allowed() const { 100 return mode & (static_cast<ModeFlags>(OpenMode::WRITE) | 101 static_cast<ModeFlags>(OpenMode::APPEND)); 102 } 103 104 bool read_allowed() const { 105 return mode & static_cast<ModeFlags>(OpenMode::READ); 106 } 107 108 public: 109 // We want this constructor to be constexpr so that global file objects 110 // like stdout do not require invocation of the constructor which can 111 // potentially lead to static initialization order fiasco. 112 constexpr File(WriteFunc *wf, ReadFunc *rf, SeekFunc *sf, CloseFunc *cf, 113 FlushFunc *ff, LockFunc *lf, UnlockFunc *ulf, void *buffer, 114 size_t buffer_size, int buffer_mode, bool owned, 115 ModeFlags modeflags) 116 : platform_write(wf), platform_read(rf), platform_seek(sf), 117 platform_close(cf), platform_flush(ff), platform_lock(lf), 118 platform_unlock(ulf), buf(buffer), bufsize(buffer_size), 119 bufmode(buffer_mode), own_buf(owned), mode(modeflags), pos(0), 120 prev_op(FileOp::NONE), read_limit(0), eof(false), err(false) {} 121 122 // This function helps initialize the various fields of the File data 123 // structure after a allocating memory for it via a call to malloc. 124 static void init(File *f, WriteFunc *wf, ReadFunc *rf, SeekFunc *sf, 125 CloseFunc *cf, FlushFunc *ff, LockFunc *lf, UnlockFunc *ulf, 126 void *buffer, size_t buffer_size, int buffer_mode, 127 bool owned, ModeFlags modeflags) { 128 f->platform_write = wf; 129 f->platform_read = rf; 130 f->platform_seek = sf; 131 f->platform_close = cf; 132 f->platform_flush = ff; 133 f->platform_lock = lf; 134 f->platform_unlock = ulf; 135 f->buf = reinterpret_cast<uint8_t *>(buffer); 136 f->bufsize = buffer_size; 137 f->bufmode = buffer_mode; 138 f->own_buf = owned; 139 f->mode = modeflags; 140 141 f->prev_op = FileOp::NONE; 142 f->read_limit = f->pos = 0; 143 f->eof = f->err = false; 144 } 145 146 // Buffered write of |len| bytes from |data|. 147 size_t write(const void *data, size_t len); 148 149 // Buffered read of |len| bytes into |data|. 150 size_t read(void *data, size_t len); 151 152 int seek(long offset, int whence); 153 154 // If buffer has data written to it, flush it out. Does nothing if the 155 // buffer is currently being used as a read buffer. 156 int flush(); 157 158 // Sets the internal buffer to |buffer| with buffering mode |mode|. 159 // |size| is the size of |buffer|. This new |buffer| is owned by the 160 // stream only if |owned| is true. 161 void set_buffer(void *buffer, size_t size, bool owned); 162 163 // Closes the file stream and frees up all resources owned by it. 164 int close(); 165 166 void lock() { platform_lock(this); } 167 void unlock() { platform_unlock(this); } 168 169 bool error() const { return err; } 170 void clearerr() { err = false; } 171 bool iseof() const { return eof; } 172 173 // Returns an bit map of flags corresponding to enumerations of 174 // OpenMode, ContentType and CreateType. 175 static ModeFlags mode_flags(const char *mode); 176 }; 177 178 // This is a convenience RAII class to lock and unlock file objects. 179 class FileLock { 180 File *file; 181 182 public: 183 explicit FileLock(File *f) : file(f) { file->lock(); } 184 185 ~FileLock() { file->unlock(); } 186 187 FileLock(const FileLock &) = delete; 188 FileLock(FileLock &&) = delete; 189 }; 190 191 } // namespace __llvm_libc 192 193 #endif // LLVM_LIBC_SRC_SUPPORT_OSUTIL_FILE_H 194