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 protected: 101 bool write_allowed() const { 102 return mode & (static_cast<ModeFlags>(OpenMode::WRITE) | 103 static_cast<ModeFlags>(OpenMode::APPEND) | 104 static_cast<ModeFlags>(OpenMode::PLUS)); 105 } 106 107 bool read_allowed() const { 108 return mode & (static_cast<ModeFlags>(OpenMode::READ) | 109 static_cast<ModeFlags>(OpenMode::PLUS)); 110 } 111 112 public: 113 // We want this constructor to be constexpr so that global file objects 114 // like stdout do not require invocation of the constructor which can 115 // potentially lead to static initialization order fiasco. 116 constexpr File(WriteFunc *wf, ReadFunc *rf, SeekFunc *sf, CloseFunc *cf, 117 FlushFunc *ff, void *buffer, size_t buffer_size, 118 int buffer_mode, bool owned, ModeFlags modeflags) 119 : platform_write(wf), platform_read(rf), platform_seek(sf), 120 platform_close(cf), platform_flush(ff), mutex(false, false, false), 121 buf(buffer), bufsize(buffer_size), bufmode(buffer_mode), own_buf(owned), 122 mode(modeflags), pos(0), prev_op(FileOp::NONE), read_limit(0), 123 eof(false), err(false) {} 124 125 // This function helps initialize the various fields of the File data 126 // structure after a allocating memory for it via a call to malloc. 127 static void init(File *f, WriteFunc *wf, ReadFunc *rf, SeekFunc *sf, 128 CloseFunc *cf, FlushFunc *ff, void *buffer, 129 size_t buffer_size, int buffer_mode, bool owned, 130 ModeFlags modeflags) { 131 Mutex::init(&f->mutex, false, false, false); 132 f->platform_write = wf; 133 f->platform_read = rf; 134 f->platform_seek = sf; 135 f->platform_close = cf; 136 f->platform_flush = ff; 137 f->buf = reinterpret_cast<uint8_t *>(buffer); 138 f->bufsize = buffer_size; 139 f->bufmode = buffer_mode; 140 f->own_buf = owned; 141 f->mode = modeflags; 142 143 f->prev_op = FileOp::NONE; 144 f->read_limit = f->pos = 0; 145 f->eof = f->err = false; 146 } 147 148 // Buffered write of |len| bytes from |data| without the file lock. 149 size_t write_unlocked(const void *data, size_t len); 150 151 // Buffered write of |len| bytes from |data| under the file lock. 152 size_t write(const void *data, size_t len) { 153 lock(); 154 size_t ret = write_unlocked(data, len); 155 unlock(); 156 return ret; 157 } 158 159 // Buffered read of |len| bytes into |data| without the file lock. 160 size_t read_unlocked(void *data, size_t len); 161 162 // Buffered read of |len| bytes into |data| under the file lock. 163 size_t read(void *data, size_t len) { 164 lock(); 165 size_t ret = read_unlocked(data, len); 166 unlock(); 167 return ret; 168 } 169 170 int seek(long offset, int whence); 171 172 // If buffer has data written to it, flush it out. Does nothing if the 173 // buffer is currently being used as a read buffer. 174 int flush(); 175 176 // Sets the internal buffer to |buffer| with buffering mode |mode|. 177 // |size| is the size of |buffer|. This new |buffer| is owned by the 178 // stream only if |owned| is true. 179 void set_buffer(void *buffer, size_t size, bool owned); 180 181 // Closes the file stream and frees up all resources owned by it. 182 int close(); 183 184 void lock() { mutex.lock(); } 185 void unlock() { mutex.unlock(); } 186 187 bool error() const { return err; } 188 void clearerr() { err = false; } 189 bool iseof() const { return eof; } 190 191 // Returns an bit map of flags corresponding to enumerations of 192 // OpenMode, ContentType and CreateType. 193 static ModeFlags mode_flags(const char *mode); 194 }; 195 196 // This is a convenience RAII class to lock and unlock file objects. 197 class FileLock { 198 File *file; 199 200 public: 201 explicit FileLock(File *f) : file(f) { file->lock(); } 202 203 ~FileLock() { file->unlock(); } 204 205 FileLock(const FileLock &) = delete; 206 FileLock(FileLock &&) = delete; 207 }; 208 209 // The implementaiton of this function is provided by the platfrom_file 210 // library. 211 File *openfile(const char *path, const char *mode); 212 213 } // namespace __llvm_libc 214 215 #endif // LLVM_LIBC_SRC_SUPPORT_OSUTIL_FILE_H 216