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