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