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 "src/__support/threads/mutex.h" 13 14 #include <stddef.h> 15 #include <stdint.h> 16 17 namespace __llvm_libc { 18 19 // This a generic base class to encapsulate a platform independent file data 20 // structure. Platform specific specializations should create a subclass as 21 // suitable for their platform. 22 class File { 23 public: 24 static constexpr size_t DEFAULT_BUFFER_SIZE = 1024; 25 26 using LockFunc = void(File *); 27 using UnlockFunc = void(File *); 28 29 using WriteFunc = size_t(File *, const void *, size_t); 30 using ReadFunc = size_t(File *, void *, size_t); 31 using SeekFunc = int(File *, long, int); 32 using CloseFunc = int(File *); 33 using FlushFunc = int(File *); 34 35 using ModeFlags = uint32_t; 36 37 // The three different types of flags below are to be used with '|' operator. 38 // Their values correspond to mutually exclusive bits in a 32-bit unsigned 39 // integer value. A flag set can include both READ and WRITE if the file 40 // is opened in update mode (ie. if the file was opened with a '+' the mode 41 // string.) 42 enum class OpenMode : ModeFlags { 43 READ = 0x1, 44 WRITE = 0x2, 45 APPEND = 0x4, 46 PLUS = 0x8, 47 }; 48 49 // Denotes a file opened in binary mode (which is specified by including 50 // the 'b' character in teh mode string.) 51 enum class ContentType : ModeFlags { 52 BINARY = 0x10, 53 }; 54 55 // Denotes a file to be created for writing. 56 enum class CreateType : ModeFlags { 57 EXCLUSIVE = 0x100, 58 }; 59 60 private: 61 enum class FileOp : uint8_t { NONE, READ, WRITE, SEEK }; 62 63 // Platfrom specific functions which create new file objects should initialize 64 // these fields suitably via the constructor. Typically, they should be simple 65 // syscall wrappers for the corresponding functionality. 66 WriteFunc *platform_write; 67 ReadFunc *platform_read; 68 SeekFunc *platform_seek; 69 CloseFunc *platform_close; 70 FlushFunc *platform_flush; 71 72 Mutex mutex; 73 74 void *buf; // Pointer to the stream buffer for buffered streams 75 size_t bufsize; // Size of the buffer pointed to by |buf|. 76 77 // Buffering mode to used to buffer. 78 int bufmode; 79 80 // If own_buf is true, the |buf| is owned by the stream and will be 81 // free-ed when close method is called on the stream. 82 bool own_buf; 83 84 // The mode in which the file was opened. 85 ModeFlags mode; 86 87 // Current read or write pointer. 88 size_t pos; 89 90 // Represents the previous operation that was performed. 91 FileOp prev_op; 92 93 // When the buffer is used as a read buffer, read_limit is the upper limit 94 // of the index to which the buffer can be read until. 95 size_t read_limit; 96 97 bool eof; 98 bool err; 99 100 // This is a convenience RAII class to lock and unlock file objects. 101 class FileLock { 102 File *file; 103 104 public: FileLock(File * f)105 explicit FileLock(File *f) : file(f) { file->lock(); } 106 ~FileLock()107 ~FileLock() { file->unlock(); } 108 109 FileLock(const FileLock &) = delete; 110 FileLock(FileLock &&) = delete; 111 }; 112 113 protected: write_allowed()114 bool write_allowed() const { 115 return mode & (static_cast<ModeFlags>(OpenMode::WRITE) | 116 static_cast<ModeFlags>(OpenMode::APPEND) | 117 static_cast<ModeFlags>(OpenMode::PLUS)); 118 } 119 read_allowed()120 bool read_allowed() const { 121 return mode & (static_cast<ModeFlags>(OpenMode::READ) | 122 static_cast<ModeFlags>(OpenMode::PLUS)); 123 } 124 125 public: 126 // We want this constructor to be constexpr so that global file objects 127 // like stdout do not require invocation of the constructor which can 128 // potentially lead to static initialization order fiasco. File(WriteFunc * wf,ReadFunc * rf,SeekFunc * sf,CloseFunc * cf,FlushFunc * ff,void * buffer,size_t buffer_size,int buffer_mode,bool owned,ModeFlags modeflags)129 constexpr File(WriteFunc *wf, ReadFunc *rf, SeekFunc *sf, CloseFunc *cf, 130 FlushFunc *ff, void *buffer, size_t buffer_size, 131 int buffer_mode, bool owned, ModeFlags modeflags) 132 : platform_write(wf), platform_read(rf), platform_seek(sf), 133 platform_close(cf), platform_flush(ff), mutex(false, false, false), 134 buf(buffer), bufsize(buffer_size), bufmode(buffer_mode), own_buf(owned), 135 mode(modeflags), pos(0), prev_op(FileOp::NONE), read_limit(0), 136 eof(false), err(false) {} 137 138 // This function helps initialize the various fields of the File data 139 // structure after a allocating memory for it via a call to malloc. init(File * f,WriteFunc * wf,ReadFunc * rf,SeekFunc * sf,CloseFunc * cf,FlushFunc * ff,void * buffer,size_t buffer_size,int buffer_mode,bool owned,ModeFlags modeflags)140 static void init(File *f, WriteFunc *wf, ReadFunc *rf, SeekFunc *sf, 141 CloseFunc *cf, FlushFunc *ff, void *buffer, 142 size_t buffer_size, int buffer_mode, bool owned, 143 ModeFlags modeflags) { 144 Mutex::init(&f->mutex, false, false, false); 145 f->platform_write = wf; 146 f->platform_read = rf; 147 f->platform_seek = sf; 148 f->platform_close = cf; 149 f->platform_flush = ff; 150 f->buf = reinterpret_cast<uint8_t *>(buffer); 151 f->bufsize = buffer_size; 152 f->bufmode = buffer_mode; 153 f->own_buf = owned; 154 f->mode = modeflags; 155 156 f->prev_op = FileOp::NONE; 157 f->read_limit = f->pos = 0; 158 f->eof = f->err = false; 159 } 160 161 // Buffered write of |len| bytes from |data| without the file lock. 162 size_t write_unlocked(const void *data, size_t len); 163 164 // Buffered write of |len| bytes from |data| under the file lock. write(const void * data,size_t len)165 size_t write(const void *data, size_t len) { 166 FileLock l(this); 167 return write_unlocked(data, len); 168 } 169 170 // Buffered read of |len| bytes into |data| without the file lock. 171 size_t read_unlocked(void *data, size_t len); 172 173 // Buffered read of |len| bytes into |data| under the file lock. read(void * data,size_t len)174 size_t read(void *data, size_t len) { 175 FileLock l(this); 176 return read_unlocked(data, len); 177 } 178 179 int seek(long offset, int whence); 180 181 // If buffer has data written to it, flush it out. Does nothing if the 182 // buffer is currently being used as a read buffer. flush()183 int flush() { 184 FileLock lock(this); 185 return flush_unlocked(); 186 } 187 188 int flush_unlocked(); 189 190 // Sets the internal buffer to |buffer| with buffering mode |mode|. 191 // |size| is the size of |buffer|. This new |buffer| is owned by the 192 // stream only if |owned| is true. 193 void set_buffer(void *buffer, size_t size, bool owned); 194 195 // Closes the file stream and frees up all resources owned by it. 196 int close(); 197 lock()198 void lock() { mutex.lock(); } unlock()199 void unlock() { mutex.unlock(); } 200 error_unlocked()201 bool error_unlocked() const { return err; } 202 error()203 bool error() { 204 FileLock l(this); 205 return error_unlocked(); 206 } 207 clearerr_unlocked()208 void clearerr_unlocked() { err = false; } 209 clearerr()210 void clearerr() { 211 FileLock l(this); 212 clearerr_unlocked(); 213 } 214 iseof_unlocked()215 bool iseof_unlocked() { return eof; } 216 iseof()217 bool iseof() { 218 FileLock l(this); 219 return iseof_unlocked(); 220 } 221 222 // Returns an bit map of flags corresponding to enumerations of 223 // OpenMode, ContentType and CreateType. 224 static ModeFlags mode_flags(const char *mode); 225 226 private: 227 size_t write_unlocked_lbf(const void *data, size_t len); 228 size_t write_unlocked_fbf(const void *data, size_t len); 229 size_t write_unlocked_nbf(const void *data, size_t len); 230 }; 231 232 // The implementaiton of this function is provided by the platfrom_file 233 // library. 234 File *openfile(const char *path, const char *mode); 235 236 extern File *stdout; 237 extern File *stderr; 238 239 } // namespace __llvm_libc 240 241 #endif // LLVM_LIBC_SRC_SUPPORT_OSUTIL_FILE_H 242