Open Model Railroad Network (OpenMRN)
Loading...
Searching...
No Matches
SPIFFS.cxx
Go to the documentation of this file.
1
34#include "SPIFFS.hxx"
35
36#include <fcntl.h>
37
38#include "spiffs.h"
39#include "spiffs_nucleus.h"
40
41#ifndef _FDIRECT
42#define _FDIRECT 0x80000
43#endif
44
45#ifndef O_DIRECT
46#define O_DIRECT _FDIRECT
47#endif
48
49void SPIFFS::extern_lock(struct spiffs_t *fs)
50{
51 static_cast<SPIFFS *>(fs->user_data)->lock_.lock();
52}
53
54void SPIFFS::extern_unlock(struct spiffs_t *fs)
55{
56 static_cast<SPIFFS *>(fs->user_data)->lock_.unlock();
57}
58
59extern "C"
60{
63
66void extern_spiffs_lock(struct spiffs_t *fs)
67{
69}
70
73void extern_spiffs_unlock(struct spiffs_t *fs)
74{
76}
77} // extern "C"
78
79// static
81 struct spiffs_t *fs, unsigned addr, unsigned size, uint8_t *dst)
82{
83 return static_cast<SPIFFS *>(fs->user_data)->flash_read(addr, size, dst);
84}
85
86// static
88 struct spiffs_t *fs, unsigned addr, unsigned size, uint8_t *src)
89{
90 return static_cast<SPIFFS *>(fs->user_data)->flash_write(addr, size, src);
91}
92
93// static
94int SPIFFS::flash_erase(struct spiffs_t *fs, unsigned addr, unsigned size)
95{
96 return static_cast<SPIFFS *>(fs->user_data)->flash_erase(addr, size);
97}
98
99//
100// SPIFFS::SPIFFS()
101//
102SPIFFS::SPIFFS(size_t physical_address, size_t size_on_disk,
103 size_t erase_block_size, size_t logical_block_size,
104 size_t logical_page_size, size_t max_num_open_descriptors,
105 size_t cache_pages,
106 std::function<void()> post_format_hook)
107 : FileSystem()
108 , postFormatHook_(std::move(post_format_hook))
109 , lock_()
110 , workBuffer_(new uint8_t[logical_page_size * 2])
111 , fdSpaceSize_(max_num_open_descriptors * sizeof(spiffs_fd))
112 , fdSpace_(new uint8_t[fdSpaceSize_])
113 , cacheSize_(sizeof(spiffs_cache) +
114 cache_pages * (sizeof(spiffs_cache_page) + logical_page_size))
115 , cache_(new uint8_t[cacheSize_])
116 , formatted_(false)
117 , anyDirty_(false)
118{
119 fs_ = new spiffs;
120 memset(fs_, 0, sizeof(spiffs));
121 fs_->user_data = this;
122 spiffs_config tmp{ //
123 .hal_read_f = flash_read,
124 .hal_write_f = flash_write,
125 .hal_erase_f = flash_erase,
126 .phys_size = size_on_disk,
127 .phys_addr = physical_address,
128 .phys_erase_block = erase_block_size,
129 .log_block_size = logical_block_size,
130 .log_page_size = logical_page_size};
131 memcpy(&fs_->cfg, &tmp, sizeof(fs_->cfg));
132}
133
134//
135// Destructor
136//
138{
139 // Performing unmount in the destructor of the base class is not
140 // possible, because the virtual functions for reading and writing the
141 // flash cannot be called anymore.
142 HASSERT(SPIFFS_mounted(fs_) == 0);
143 delete[] fdSpace_;
144 delete[] workBuffer_;
145 delete fs_;
146}
147
148//
149// SPIFFS::unmount
150//
152{
153 if (name)
154 {
155 SPIFFS_unmount(fs_);
156 name = nullptr;
157 }
158}
159
164{
165 spiffs_DIR dir_;
167};
168
169//
170// SPIFFS::format()
171//
173{
174 HASSERT(SPIFFS_mounted(fs_) == 0);
175
176 // formatting requires at least one mounting, so mount then unmount
177 if (do_mount() == 0)
178 {
179 SPIFFS_unmount(fs_);
180 }
181
182 HASSERT(SPIFFS_format(fs_) == 0);
183 formatted_ = true;
184}
185
186//
187// SPIFFS::do_mount()
188//
190{
191 spiffs_config tmp;
192 memcpy(&tmp, &fs_->cfg, sizeof(tmp));
193 return SPIFFS_mount(fs_, &tmp, workBuffer_, fdSpace_,
194 fdSpaceSize_, cache_, cacheSize_, nullptr);
195}
196
197//
198// SPIFFS::open()
199//
200int SPIFFS::open(File *file, const char *path, int flags, int mode)
201{
202 spiffs_flags ffs_flags = 0;
203 if (flags & O_APPEND)
204 {
205 ffs_flags |= SPIFFS_O_APPEND;
206 }
207 if (flags & O_TRUNC)
208 {
209 ffs_flags |= SPIFFS_O_TRUNC;
210 }
211 if (flags & O_CREAT)
212 {
213 ffs_flags |= SPIFFS_O_CREAT;
214 }
215 if ((flags & O_ACCMODE) == O_RDONLY)
216 {
217 ffs_flags |= SPIFFS_O_RDONLY;
218 }
219 if ((flags & O_ACCMODE) == O_WRONLY)
220 {
221 ffs_flags |= SPIFFS_O_WRONLY;
222 }
223 if ((flags & O_ACCMODE) == O_RDWR)
224 {
225 ffs_flags |= SPIFFS_O_RDWR;
226 }
227 if (flags & O_DIRECT)
228 {
229 ffs_flags |= SPIFFS_O_DIRECT;
230 }
231 if (flags & O_EXCL)
232 {
233 ffs_flags |= SPIFFS_O_EXCL;
234 }
235
236 spiffs_file fd = ::SPIFFS_open(fs_, path, ffs_flags, 0);
237
238 if (fd < 0)
239 {
240 return -errno_translate(fd);
241 }
242 else
243 {
244 // no error occured
245 file->privInt = fd;
246 return 0;
247 }
248}
249
250//
251// SPIFFS::close()
252//
254{
255 spiffs_file fd = file->privInt;
256
257 file->dirty = false;
258 int result = SPIFFS_close(fs_, fd);
259
260 if (result != SPIFFS_OK)
261 {
262 return -errno_translate(result);
263 }
264
265 return 0;
266}
267
268//
269// SPIFFS::unlink()
270//
271int SPIFFS::unlink(const char *path)
272{
273 int result = SPIFFS_remove(fs_, path);
274
275 if (result < 0)
276 {
277 return -errno_translate(result);
278 }
279
280 return 0;
281}
282
283//
284// SPIFFS::read()
285//
286ssize_t SPIFFS::read(File *file, void *buf, size_t count)
287{
288 spiffs_file fd = file->privInt;
289
290 ssize_t result = SPIFFS_read(fs_, fd, buf, count);
291
292 if (result < 0)
293 {
294 return -errno_translate(result);
295 }
296
297 return result;
298}
299
300//
301// SPIFFS::write()
302//
303ssize_t SPIFFS::write(File *file, const void *buf, size_t count)
304{
305 spiffs_file fd = file->privInt;
306
307 ssize_t result = SPIFFS_write(fs_, fd, (void *)buf, count);
308
309 if (result < 0)
310 {
311 return -errno_translate(result);
312 }
313
314 {
315 AtomicHolder h(this);
316 file->dirty = true;
317 anyDirty_ = true;
318 }
319
320 return result;
321}
322
323//
324// SPIFFS::lseek()
325//
326off_t SPIFFS::lseek(File* file, off_t offset, int whence)
327{
328 spiffs_file fd = file->privInt;
329 int spiffs_whence;
330
331 switch (whence)
332 {
333 default:
334 return (off_t)-EINVAL;
335 case SEEK_SET:
336 spiffs_whence = SPIFFS_SEEK_SET;
337 break;
338 case SEEK_CUR:
339 spiffs_whence = SPIFFS_SEEK_CUR;
340 break;
341 case SEEK_END:
342 spiffs_whence = SPIFFS_SEEK_END;
343 break;
344 }
345
346 off_t result = SPIFFS_lseek(fs_, fd, offset, spiffs_whence);
347
348 if (result < 0)
349 {
350 return -errno_translate(result);
351 }
352
353 return result;
354}
355
359static void stat_post_process(struct stat *stat, spiffs_stat *ffs_stat)
360{
361 memset(stat, 0, sizeof(*stat));
362 stat->st_ino = ffs_stat->obj_id;
363 stat->st_size = ffs_stat->size;
364 switch (ffs_stat->type)
365 {
366 default:
367 break;
368 case SPIFFS_TYPE_FILE:
369 stat->st_mode = S_IFREG;
370 break;
371 case SPIFFS_TYPE_DIR:
372 stat->st_mode = S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
373 break;
374 case SPIFFS_TYPE_HARD_LINK:
375 stat->st_mode = S_IFLNK | S_IXUSR | S_IXGRP | S_IXOTH;
376 break;
377 case SPIFFS_TYPE_SOFT_LINK:
378 stat->st_mode = S_IFLNK | S_IXUSR | S_IXGRP | S_IXOTH;
379 break;
380 }
381
382 stat->st_mode |= S_IRUSR | S_IRGRP | S_IROTH |
383 S_IWUSR | S_IWGRP | S_IWOTH;
384
385}
386
387//
388// SPIFFS::fstat()
389//
390int SPIFFS::fstat(File* file, struct stat *stat)
391{
392 spiffs_file fd = file->privInt;
393 spiffs_stat ffs_stat;
394
395 ssize_t result = SPIFFS_fstat(fs_, fd, &ffs_stat);
396
397 if (result < 0)
398 {
399 return -errno_translate(result);
400 }
401
402 stat_post_process(stat, &ffs_stat);
403
404 return 0;
405}
406
407//
408// SPIFFS::stat()
409//
410int SPIFFS::stat(const char *path, struct stat *stat)
411{
412 spiffs_stat ffs_stat;
413
414 if (!strcmp(path, "") || !strcmp(path, "/"))
415 {
416 // this is the root directory, which cannot be stat
417 ffs_stat.type = SPIFFS_TYPE_DIR;
418 ffs_stat.obj_id = 0;
419 ffs_stat.size = 0;
420 }
421 else
422 {
423 ssize_t result = SPIFFS_stat(fs_, path, &ffs_stat);
424
425 if (result < 0)
426 {
427 return -errno_translate(result);
428 }
429 }
430
431 stat_post_process(stat, &ffs_stat);
432
433 return 0;
434}
435
436//
437// SPIFFS::fsync()
438//
440{
441 spiffs_file fd = file->privInt;
442 file->dirty = false;
443 int result = SPIFFS_fflush(fs_, fd);
444 if (result < 0)
445 {
446 file->dirty = true;
447 return -errno_translate(result);
448 }
449 return 0;
450}
451
452//
453// SPIFFS::closedir()
454//
456{
457 OpenDir *dir = static_cast<OpenDir*>(file->priv);
458 int result = SPIFFS_closedir(&dir->dir_);
459
460 if (result == 0)
461 {
462 free(dir);
463 return 0;
464 }
465 else
466 {
467 return -errno_translate(result);
468 }
469}
470
471//
472// SPIFFS::opendir()
473//
474File *SPIFFS::opendir(File *file, const char *name)
475{
476 // special malloc is to reserve space for the full path name
477 OpenDir *dir = static_cast<OpenDir*>(malloc(sizeof(OpenDir) +
478 SPIFFS_OBJ_NAME_LEN +
479 strlen(this->name) + 1));
480
482 spiffs_DIR *result = SPIFFS_opendir(fs_, name, &dir->dir_);
483 if (!result)
484 {
485 free(dir);
486 errno = errno_translate(fs_->err_code);
487 }
488 else
489 {
490 // no error occured
491 file->priv = dir;
492 file->dir = true;
493 }
495
496 return file;
497}
498
499//
500// SPIFFS::readdir()
501//
503{
504 OpenDir *dir = static_cast<OpenDir*>(file->priv);
505 spiffs_dirent dirent;
506
507 spiffs_dirent *result = SPIFFS_readdir(&dir->dir_, &dirent);
508
509 if (!result)
510 {
511 return nullptr;
512 }
513 else
514 {
515 dir->dirent_.d_ino = dirent.obj_id;
516 strcpy(dir->dirent_.d_name, this->name);
517 strcat(dir->dirent_.d_name, "/");
518 strcat(dir->dirent_.d_name, (char*)dirent.name);
519 return &dir->dirent_;
520 }
521}
522
523//
524// SPIFFS::errno_translate()
525//
526int SPIFFS::errno_translate(int spiffs_error)
527{
528 globalLastSPIFFSError = spiffs_error;
529
530 switch (spiffs_error)
531 {
532 default:
533 // unknown error
534 HASSERT(0);
535 break;
536 case SPIFFS_OK:
537 return 0;
538 case SPIFFS_ERR_NOT_MOUNTED:
539 // should never get here
540 HASSERT(0);
541 break;
542 case SPIFFS_ERR_FULL:
543 return ENOSPC;
544 case SPIFFS_ERR_NOT_FOUND:
545 return ENOENT;
546 case SPIFFS_ERR_END_OF_OBJECT:
547 return EOVERFLOW;
548 case SPIFFS_ERR_DELETED:
549 return EFAULT;
550 case SPIFFS_ERR_NOT_FINALIZED:
551 return EBUSY;
552 case SPIFFS_ERR_NOT_INDEX:
553 return EINVAL;
554 case SPIFFS_ERR_OUT_OF_FILE_DESCS:
555 return EMFILE;
556 case SPIFFS_ERR_FILE_CLOSED:
557 return EBADF;
558 case SPIFFS_ERR_FILE_DELETED:
559 return EFAULT;
560 case SPIFFS_ERR_BAD_DESCRIPTOR:
561 return EBADF;
562 case SPIFFS_ERR_IS_INDEX:
563 break;
564 case SPIFFS_ERR_IS_FREE:
565 return EBUSY;
566 case SPIFFS_ERR_INDEX_SPAN_MISMATCH:
567 break;
568 case SPIFFS_ERR_DATA_SPAN_MISMATCH:
569 break;
570 case SPIFFS_ERR_INDEX_REF_FREE:
571 break;
572 case SPIFFS_ERR_INDEX_REF_LU:
573 break;
574 case SPIFFS_ERR_INDEX_REF_INVALID:
575 break;
576 case SPIFFS_ERR_INDEX_FREE:
577 break;
578 case SPIFFS_ERR_INDEX_LU:
579 break;
580 case SPIFFS_ERR_INDEX_INVALID:
581 return EINVAL;
582 case SPIFFS_ERR_NOT_WRITABLE:
583 return EACCES;
584 case SPIFFS_ERR_NOT_READABLE:
585 return EACCES;
586 case SPIFFS_ERR_CONFLICTING_NAME:
587 break;
588 case SPIFFS_ERR_NOT_CONFIGURED:
589 break;
590
591 case SPIFFS_ERR_NOT_A_FS:
592 break;
593 case SPIFFS_ERR_MOUNTED:
594 break;
595 case SPIFFS_ERR_ERASE_FAIL:
596 break;
597 case SPIFFS_ERR_MAGIC_NOT_POSSIBLE:
598 break;
599
600 case SPIFFS_ERR_NO_DELETED_BLOCKS:
601 break;
602
603 case SPIFFS_ERR_FILE_EXISTS:
604 return EEXIST;
605
606 case SPIFFS_ERR_NOT_A_FILE:
607 return ENOENT;
608 case SPIFFS_ERR_RO_NOT_IMPL:
609 break;
610 case SPIFFS_ERR_RO_ABORTED_OPERATION:
611 return EAGAIN;
612 case SPIFFS_ERR_PROBE_TOO_FEW_BLOCKS:
613 return ENOSPC;
614 case SPIFFS_ERR_PROBE_NOT_A_FS:
615 break;
616 case SPIFFS_ERR_NAME_TOO_LONG:
617 return ENAMETOOLONG;
618
619 case SPIFFS_ERR_IX_MAP_UNMAPPED:
620 break;
621 case SPIFFS_ERR_IX_MAP_MAPPED:
622 break;
623 case SPIFFS_ERR_IX_MAP_BAD_RANGE:
624 break;
625 case SPIFFS_ERR_SEEK_BOUNDS:
626 return EINVAL;
627
628 case SPIFFS_ERR_INTERNAL:
629 break;
630
631 case SPIFFS_ERR_TEST:
632 break;
633 }
634
635 return EINVAL;
636}
void extern_spiffs_unlock(struct spiffs_t *fs)
Provide mutex unlock.
Definition SPIFFS.cxx:73
void extern_spiffs_lock(struct spiffs_t *fs)
Provide mutex lock.
Definition SPIFFS.cxx:66
int globalLastSPIFFSError
global error number for the last SPIFFS error
Definition SPIFFS.cxx:62
static void stat_post_process(struct stat *stat, spiffs_stat *ffs_stat)
Common post processing for SPIFFS::stat() and SPIFFS::fstat().
Definition SPIFFS.cxx:359
See OSMutexLock in os/OS.hxx.
Definition Atomic.hxx:153
const char * name
device name
Definition Devtab.hxx:266
Base class for all File systems.
Definition Devtab.hxx:280
void lock()
Lock a mutex.
Definition OS.hxx:446
void unlock()
Unlock a mutex.
Definition OS.hxx:453
Generic SPIFFS base class.
Definition SPIFFS.hxx:49
OSMutex lock_
whole file system lock
Definition SPIFFS.hxx:281
static void extern_unlock(struct spiffs_t *fs)
Provide mutex unlock.
Definition SPIFFS.cxx:54
ssize_t read(File *file, void *buf, size_t count) override
Read from a file or device.
Definition SPIFFS.cxx:286
int errno_translate(int spiffs_error)
Translate a SPIFFS specific error number to a standard POSIX errno.
Definition SPIFFS.cxx:526
ssize_t write(File *file, const void *buf, size_t count) override
Write to a file or device.
Definition SPIFFS.cxx:303
File * opendir(File *file, const char *name) override
Open a directory.
Definition SPIFFS.cxx:474
int fsync(File *file) override
Synchronize (flush) a file to disk.
Definition SPIFFS.cxx:439
int open(File *file, const char *path, int flags, int mode) override
Open a file or device.
Definition SPIFFS.cxx:200
off_t lseek(File *f, off_t offset, int whence) override
Seek method.
Definition SPIFFS.cxx:326
int fstat(File *file, struct stat *stat) override
Get the status information of a file or device.
Definition SPIFFS.cxx:390
int close(File *file) override
Close a file or device.
Definition SPIFFS.cxx:253
static int flash_read(struct spiffs_t *fs, unsigned addr, unsigned size, uint8_t *dst)
SPIFFS callback to read flash.
Definition SPIFFS.cxx:80
int closedir(File *file) override
Close a directory.
Definition SPIFFS.cxx:455
void unmount()
Flushes caches and unmounts the filesystem.
Definition SPIFFS.cxx:151
spiffs * fs_
file system instance metadata
Definition SPIFFS.hxx:182
int stat(const char *path, struct stat *stat) override
Get the status information of a file or device.
Definition SPIFFS.cxx:410
int unlink(const char *path) override
Remove a file.
Definition SPIFFS.cxx:271
static int flash_write(struct spiffs_t *fs, unsigned addr, unsigned size, uint8_t *src)
SPIFFS callback to write flash.
Definition SPIFFS.cxx:87
uint32_t fdSpaceSize_
size in bytes of the fdSpace_
Definition SPIFFS.hxx:287
static void extern_lock(struct spiffs_t *fs)
Provide mutex lock.
Definition SPIFFS.cxx:49
uint8_t * fdSpace_
file descriptor metadata
Definition SPIFFS.hxx:290
void * cache_
memory for cache
Definition SPIFFS.hxx:296
static int flash_erase(struct spiffs_t *fs, unsigned addr, unsigned size)
SPIFFS callback to erase flash.
Definition SPIFFS.cxx:94
struct dirent * readdir(File *file) override
Read the next entry in a directory.
Definition SPIFFS.cxx:502
~SPIFFS()
Destructor.
Definition SPIFFS.cxx:137
void format() override
Format the file system, all data will be lost.
Definition SPIFFS.cxx:172
uint32_t cacheSize_
size in bytes of cache_
Definition SPIFFS.hxx:293
SPIFFS(size_t physical_address, size_t size_on_disk, size_t erase_block_size, size_t logical_block_size, size_t logical_page_size, size_t max_num_open_descriptors=16, size_t cache_pages=8, std::function< void()> post_format_hook=nullptr)
Constructor.
Definition SPIFFS.cxx:102
uint8_t * workBuffer_
work buffer for the file system
Definition SPIFFS.hxx:284
bool formatted_
has the file system been formatted since last reboot?
Definition SPIFFS.hxx:299
bool anyDirty_
Bit that is set to 1 when any write operation happens to this FS.
Definition SPIFFS.hxx:302
int do_mount()
Helper to mount the file system.
Definition SPIFFS.cxx:189
#define HASSERT(x)
Checks that the value of expression x is true, else terminates the current process.
Definition macros.h:138
File information.
Definition Devtab.hxx:52
uint8_t dirty
true if this file is dirty and needs flush
Definition Devtab.hxx:68
uint8_t dir
true if this is a directory, else false
Definition Devtab.hxx:67
int privInt
file reference specific data "int"
Definition Devtab.hxx:60
void * priv
file reference specific data "pointer"
Definition Devtab.hxx:57
Open directory metadata structure.
Definition SPIFFS.cxx:164
struct dirent dirent_
directory entry
Definition SPIFFS.cxx:166
spiffs_DIR dir_
directory object
Definition SPIFFS.cxx:165
Directory entry structure.
Definition dirent.h:49
char d_name[]
filename string of entry
Definition dirent.h:51
ino_t d_ino
file serial number
Definition dirent.h:50