/
FS.h
317 lines (295 loc) · 9.63 KB
/
FS.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
/* Teensyduino Core Library - File base class
* http://www.pjrc.com/teensy/
* Copyright (c) 2021 PJRC.COM, LLC.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* 1. The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* 2. If the Software is incorporated into a build system that allows
* selection among a list of target devices, then similar target
* devices manufactured by PJRC.COM must be included in the list of
* target devices and selectable in the same manner.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef FS_H
#define FS_H
#ifdef __cplusplus
#include <Arduino.h>
#define FILE_READ 0
#define FILE_WRITE 1
#define FILE_WRITE_BEGIN 2
enum SeekMode {
SeekSet = 0,
SeekCur = 1,
SeekEnd = 2
};
class File;
// FileImpl is the actual implementation of access to files stored on media.
// Libraries providing access to files must inherit FileImpl. Instances of
// FileImpl are always created with "new". When a FileImpl instance is
// created, it is usually wrapped in a File instance: File(new myFileImpl(...));
// FileImpl instances are automatically deleted when the last referencing
// File is closed or goes out of scope. The refcount variable is meant to
// be maintained by File class instances, never access by FileImpl functions.
// The FileImpl functions are meant to be called only by use of File instances.
//
class FileImpl {
protected:
virtual ~FileImpl() { }
virtual size_t read(void *buf, size_t nbyte) = 0;
virtual size_t write(const void *buf, size_t size) = 0;
virtual int available() = 0;
virtual int peek() = 0;
virtual void flush() = 0;
virtual bool truncate(uint64_t size=0) = 0;
virtual bool seek(uint64_t pos, int mode) = 0;
virtual uint64_t position() = 0;
virtual uint64_t size() = 0;
virtual void close() = 0;
virtual bool isOpen() = 0;
virtual const char* name() = 0;
virtual bool isDirectory() = 0;
virtual File openNextFile(uint8_t mode=0) = 0;
virtual void rewindDirectory(void) = 0;
virtual bool getCreateTime(DateTimeFields &tm) { return false; }
virtual bool getModifyTime(DateTimeFields &tm) { return false; }
virtual bool setCreateTime(const DateTimeFields &tm) { return false; }
virtual bool setModifyTime(const DateTimeFields &tm) { return false; }
private:
friend class File;
unsigned int refcount = 0; // number of File instances referencing this FileImpl
};
// Libraries known to inherit from FileImpl (will need testing if FileImpl changes)
// https://github.com/PaulStoffregen/SD
// https://github.com/PaulStoffregen/LittleFS
// https://github.com/PaulStoffregen/USBHost_t36
// https://github.com/FrankBoesing/MemFile
// File move semantics require rvalue references, introduced in C++11.
#define FILE_USE_MOVE
// Programs and libraries using files do so with instances of File.
// File is merely a pointer to a FileImpl instance. More than one
// instance of File may reference the same FileImpl. File may also
// reference nothing (the pointer is NULL), as a result of having
// closed the file or the File instance created without referencing
// anything.
//
class File final : public Stream {
public:
// Empty constructor, used when a program creates a File variable
// but does not immediately assign or initialize it.
constexpr File() : f(nullptr) { }
// Explicit FileImpl constructor. Used by libraries which provide
// access to files stored on media. Normally this is used within
// functions derived from FS::open() and FileImpl::openNextFile().
// Not normally called used from ordinary programs or libraries
// which only access files.
File(FileImpl *file) {
f = file;
if (f) f->refcount++;
//Serial.printf("File ctor %x, refcount=%d\n", (int)f, get_refcount());
}
// Copy constructor. Typically used when a File is passed by value
// into a function. The File instance within the called function is
// a copy of the original. Also used when a File instance is created
// and assigned a value (eg, "File f =
File(const File& file) {
f = file.f;
if (f) f->refcount++;
//Serial.printf("File copy ctor %x, refcount=%d\n", (int)f, get_refcount());
}
#ifdef FILE_USE_MOVE
// Move constructor. Typically used when a File is passed by rvalue
// reference into a function, such as when using std::move(). The
// original file is closed, and the refcount of the underlying
// FileImpl is unchanged.
File(File&& file) {
f = file.f;
file.f = nullptr;
//Serial.printf("File move ctor %x, refcount=%d\n", (int)f, get_refcount());
}
#endif
// Copy assignment.
File& operator = (const File& file) {
//Serial.println("File copy assignment");
if (file.f) file.f->refcount++;
if (f) { dec_refcount(); /*Serial.println("File copy assignment autoclose");*/ }
f = file.f;
return *this;
}
#ifdef FILE_USE_MOVE
// Move assignment.
File& operator = (File&& file) {
//Serial.println("File move assignment");
if (f) { dec_refcount(); /*Serial.println("File move assignment autoclose");*/ }
f = file.f;
file.f = nullptr;
return *this;
}
#endif
virtual ~File() {
//Serial.printf("File dtor %x, refcount=%d\n", (int)f, get_refcount());
if (f) dec_refcount();
}
size_t read(void *buf, size_t nbyte) {
return (f) ? f->read(buf, nbyte) : 0;
}
// override print version
virtual size_t write(const uint8_t *buf, size_t size) {
return (f) ? f->write((void*)buf, size) : 0;
}
size_t write(const void *buf, size_t size) {
return (f) ? f->write(buf, size) : 0;
}
int available() {
return (f) ? f->available() : 0;
}
int peek() {
return (f) ? f->peek() : -1;
}
void flush() {
if (f) f->flush();
}
bool truncate(uint64_t size=0) {
return (f) ? f->truncate(size) : false;
}
bool seek(uint64_t pos, int mode) {
return (f) ? f->seek(pos, mode) : false;
}
uint64_t position() {
return (f) ? f->position() : 0;
}
uint64_t size() {
return (f) ? f->size() : 0;
}
void close() {
if (f) {
f->close();
dec_refcount();
}
}
operator bool() {
return (f) ? f->isOpen() : false;
}
const char* name() {
return (f) ? f->name() : "";
}
bool isDirectory() {
return (f) ? f->isDirectory() : false;
}
File openNextFile(uint8_t mode=0) {
return (f) ? f->openNextFile(mode) : *this;
}
void rewindDirectory(void) {
if (f) f->rewindDirectory();
}
bool getCreateTime(DateTimeFields &tm) {
return (f) ? f->getCreateTime(tm) : false;
}
bool getModifyTime(DateTimeFields &tm) {
return (f) ? f->getModifyTime(tm) : false;
}
bool setCreateTime(const DateTimeFields &tm) {
return (f) ? f->setCreateTime(tm) : false;
}
bool setModifyTime(const DateTimeFields &tm) {
return (f) ? f->setModifyTime(tm) : false;
}
bool seek(uint64_t pos) {
return seek(pos, SeekSet);
}
int read() {
if (!f) return -1;
unsigned char b;
if (f->read(&b, 1) < 1) return -1;
return b;
}
size_t write(uint8_t b) {
return (f) ? f->write(&b, 1) : 0;
}
size_t write(const char *str) {
return (f) ? f->write(str, strlen(str)) : 0;
}
size_t readBytes(char *buffer, size_t length) {
return read(buffer, length);
}
size_t write(unsigned long n) { return write((uint8_t)n); }
size_t write(long n) { return write((uint8_t)n); }
size_t write(unsigned int n) { return write((uint8_t)n); }
size_t write(int n) { return write((uint8_t)n); }
using Print::write;
private:
void dec_refcount() {
if (--(f->refcount) == 0) {
f->close();
delete f;
}
f = nullptr;
}
int get_refcount() {
if (f == nullptr) return -1;
return f->refcount;
}
FileImpl *f;
};
class FS
{
public:
FS() {}
virtual File open(const char *filename, uint8_t mode = FILE_READ) = 0;
virtual bool exists(const char *filepath) = 0;
virtual bool mkdir(const char *filepath) = 0;
virtual bool rename(const char *oldfilepath, const char *newfilepath) = 0;
virtual bool remove(const char *filepath) = 0;
virtual bool rmdir(const char *filepath) = 0;
virtual uint64_t usedSize() = 0;
virtual uint64_t totalSize() = 0;
virtual bool format(int type=0, char progressChar=0, Print& pr=Serial) {
return false;
}
virtual bool mediaPresent() {
return true;
}
// for compatibility with String input
File open(const String &filepath, uint8_t mode = FILE_READ) {
return open(filepath.c_str(), mode);
}
bool exists(const String &filepath) {
return exists(filepath.c_str());
}
bool mkdir(const String &filepath) {
return mkdir(filepath.c_str());
}
bool rename(const String &oldfilepath, const char *newfilepath) {
return rename(oldfilepath.c_str(), newfilepath);
}
bool rename(const char *oldfilepath, const String &newfilepath) {
return rename(oldfilepath, newfilepath.c_str());
}
bool rename(const String &oldfilepath, const String &newfilepath) {
return rename(oldfilepath.c_str(), newfilepath.c_str());
}
bool remove(const String &filepath) {
return remove(filepath.c_str());
}
bool rmdir(const String &filepath) {
return rmdir(filepath.c_str());
}
};
#endif // __cplusplus
#endif // FS_H