Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
FATFileSystem.cpp
00001 /* mbed Microcontroller Library 00002 * Copyright (c) 2006-2012 ARM Limited 00003 * 00004 * Permission is hereby granted, free of charge, to any person obtaining a copy 00005 * of this software and associated documentation files (the "Software"), to deal 00006 * in the Software without restriction, including without limitation the rights 00007 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 00008 * copies of the Software, and to permit persons to whom the Software is 00009 * furnished to do so, subject to the following conditions: 00010 * 00011 * The above copyright notice and this permission notice shall be included in 00012 * all copies or substantial portions of the Software. 00013 * 00014 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 00015 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 00016 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 00017 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 00018 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 00019 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 00020 * SOFTWARE. 00021 */ 00022 #include "mbed.h" 00023 00024 #include "diskio.h" 00025 #include "ffconf.h" 00026 #include "mbed_debug.h" 00027 #include "mbed_critical.h" 00028 #include <errno.h> 00029 00030 #include "FATFileSystem.h" 00031 00032 00033 ////// Error handling ///// 00034 00035 static int fat_error_remap(FRESULT res) 00036 { 00037 switch(res) { 00038 case FR_OK: /* (0) Succeeded */ 00039 return 0; /* no error */ 00040 case FR_DISK_ERR: /* (1) A hard error occurred in the low level disk I/O layer */ 00041 case FR_NOT_READY: /* (3) The physical drive cannot work */ 00042 return -EIO; /* I/O error */ 00043 case FR_NO_FILE: /* (4) Could not find the file */ 00044 case FR_NO_PATH: /* (5) Could not find the path */ 00045 case FR_INVALID_NAME: /* (6) The path name format is invalid */ 00046 case FR_INVALID_DRIVE: /* (11) The logical drive number is invalid */ 00047 case FR_NO_FILESYSTEM: /* (13) There is no valid FAT volume */ 00048 return -ENOENT; /* No such file or directory */ 00049 case FR_DENIED: /* (7) Access denied due to prohibited access or directory full */ 00050 return -EACCES; /* Permission denied */ 00051 case FR_EXIST: /* (8) Access denied due to prohibited access */ 00052 return -EEXIST; /* File exists */ 00053 case FR_WRITE_PROTECTED: /* (10) The physical drive is write protected */ 00054 case FR_LOCKED: /* (16) The operation is rejected according to the file sharing policy */ 00055 return -EACCES; /* Permission denied */ 00056 case FR_INVALID_OBJECT: /* (9) The file/directory object is invalid */ 00057 return -EFAULT; /* Bad address */ 00058 case FR_NOT_ENABLED: /* (12) The volume has no work area */ 00059 return -ENXIO; /* No such device or address */ 00060 case FR_NOT_ENOUGH_CORE: /* (17) LFN working buffer could not be allocated */ 00061 return -ENOMEM; /* Not enough space */ 00062 case FR_TOO_MANY_OPEN_FILES: /* (18) Number of open files > _FS_LOCK */ 00063 return -ENFILE; /* Too many open files in system */ 00064 case FR_INVALID_PARAMETER: /* (19) Given parameter is invalid */ 00065 return -ENOEXEC; /* Exec format error */ 00066 case FR_INT_ERR: /* (2) Assertion failed */ 00067 case FR_MKFS_ABORTED: /* (14) The f_mkfs() aborted due to any parameter error */ 00068 case FR_TIMEOUT: /* (15) Could not get a grant to access the volume within defined period */ 00069 default: /* Bad file number */ 00070 return -EBADF; 00071 } 00072 } 00073 00074 // Helper class for deferring operations when variable falls out of scope 00075 template <typename T> 00076 class Deferred { 00077 public: 00078 T _t; 00079 Callback<void(T)> _ondefer; 00080 00081 Deferred(const Deferred&); 00082 Deferred &operator=(const Deferred&); 00083 00084 public: 00085 Deferred(T t, Callback<void(T)> ondefer = NULL) 00086 : _t(t), _ondefer(ondefer) 00087 { 00088 } 00089 00090 operator T() 00091 { 00092 return _t; 00093 } 00094 00095 ~Deferred() 00096 { 00097 if (_ondefer) { 00098 _ondefer(_t); 00099 } 00100 } 00101 }; 00102 00103 static void dodelete(const char *data) 00104 { 00105 delete[] data; 00106 } 00107 00108 // Adds prefix needed internally by fatfs, this can be avoided for the first fatfs 00109 // (id 0) otherwise a prefix of "id:/" is inserted in front of the string. 00110 static Deferred<const char*> fat_path_prefix(int id, const char *path) 00111 { 00112 // We can avoid dynamic allocation when only on fatfs is in use 00113 if (id == 0) { 00114 return path; 00115 } 00116 00117 // Prefix path with id, will look something like 2:/hi/hello/filehere.txt 00118 char *buffer = new char[strlen("0:/") + strlen(path) + 1]; 00119 if (!buffer) { 00120 return NULL; 00121 } 00122 00123 buffer[0] = '0' + id; 00124 buffer[1] = ':'; 00125 buffer[2] = '/'; 00126 strcpy(buffer + strlen("0:/"), path); 00127 return Deferred<const char*>(buffer, dodelete); 00128 } 00129 00130 00131 ////// Disk operations ////// 00132 00133 // Global access to block device from FAT driver 00134 static BlockDevice *_ffs[_VOLUMES] = {0}; 00135 static SingletonPtr<PlatformMutex> _ffs_mutex; 00136 00137 00138 // FAT driver functions 00139 DWORD get_fattime(void) 00140 { 00141 time_t rawtime; 00142 time(&rawtime); 00143 struct tm *ptm = localtime(&rawtime); 00144 return (DWORD)(ptm->tm_year - 80) << 25 00145 | (DWORD)(ptm->tm_mon + 1 ) << 21 00146 | (DWORD)(ptm->tm_mday ) << 16 00147 | (DWORD)(ptm->tm_hour ) << 11 00148 | (DWORD)(ptm->tm_min ) << 5 00149 | (DWORD)(ptm->tm_sec/2 ); 00150 } 00151 00152 void *ff_memalloc(UINT size) 00153 { 00154 return malloc(size); 00155 } 00156 00157 void ff_memfree(void *p) 00158 { 00159 free(p); 00160 } 00161 00162 // Implementation of diskio functions (see ChaN/diskio.h) 00163 static WORD disk_get_sector_size(BYTE pdrv) 00164 { 00165 WORD ssize = _ffs[pdrv]->get_erase_size(); 00166 if (ssize < 512) { 00167 ssize = 512; 00168 } 00169 00170 MBED_ASSERT(ssize >= _MIN_SS && ssize <= _MAX_SS); 00171 MBED_ASSERT(_ffs[pdrv]->get_read_size() <= _ffs[pdrv]->get_erase_size()); 00172 MBED_ASSERT(_ffs[pdrv]->get_program_size() <= _ffs[pdrv]->get_erase_size()); 00173 return ssize; 00174 } 00175 00176 static DWORD disk_get_sector_count(BYTE pdrv) 00177 { 00178 DWORD scount = _ffs[pdrv]->size() / disk_get_sector_size(pdrv); 00179 MBED_ASSERT(scount >= 64); 00180 return scount; 00181 } 00182 00183 DSTATUS disk_status(BYTE pdrv) 00184 { 00185 debug_if(FFS_DBG, "disk_status on pdrv [%d]\n", pdrv); 00186 return RES_OK; 00187 } 00188 00189 DSTATUS disk_initialize(BYTE pdrv) 00190 { 00191 debug_if(FFS_DBG, "disk_initialize on pdrv [%d]\n", pdrv); 00192 return (DSTATUS)_ffs[pdrv]->init(); 00193 } 00194 00195 DRESULT disk_read(BYTE pdrv, BYTE *buff, DWORD sector, UINT count) 00196 { 00197 debug_if(FFS_DBG, "disk_read(sector %d, count %d) on pdrv [%d]\n", sector, count, pdrv); 00198 DWORD ssize = disk_get_sector_size(pdrv); 00199 int err = _ffs[pdrv]->read(buff, sector*ssize, count*ssize); 00200 return err ? RES_PARERR : RES_OK; 00201 } 00202 00203 DRESULT disk_write(BYTE pdrv, const BYTE *buff, DWORD sector, UINT count) 00204 { 00205 debug_if(FFS_DBG, "disk_write(sector %d, count %d) on pdrv [%d]\n", sector, count, pdrv); 00206 DWORD ssize = disk_get_sector_size(pdrv); 00207 int err = _ffs[pdrv]->erase(sector*ssize, count*ssize); 00208 if (err) { 00209 return RES_PARERR; 00210 } 00211 00212 err = _ffs[pdrv]->program(buff, sector*ssize, count*ssize); 00213 if (err) { 00214 return RES_PARERR; 00215 } 00216 00217 return RES_OK; 00218 } 00219 00220 DRESULT disk_ioctl(BYTE pdrv, BYTE cmd, void *buff) 00221 { 00222 debug_if(FFS_DBG, "disk_ioctl(%d)\n", cmd); 00223 switch (cmd) { 00224 case CTRL_SYNC: 00225 if (_ffs[pdrv] == NULL) { 00226 return RES_NOTRDY; 00227 } else { 00228 return RES_OK; 00229 } 00230 case GET_SECTOR_COUNT: 00231 if (_ffs[pdrv] == NULL) { 00232 return RES_NOTRDY; 00233 } else { 00234 *((DWORD*)buff) = disk_get_sector_count(pdrv); 00235 return RES_OK; 00236 } 00237 case GET_SECTOR_SIZE: 00238 if (_ffs[pdrv] == NULL) { 00239 return RES_NOTRDY; 00240 } else { 00241 *((WORD*)buff) = disk_get_sector_size(pdrv); 00242 return RES_OK; 00243 } 00244 case GET_BLOCK_SIZE: 00245 *((DWORD*)buff) = 1; // default when not known 00246 return RES_OK; 00247 case CTRL_TRIM: 00248 if (_ffs[pdrv] == NULL) { 00249 return RES_NOTRDY; 00250 } else { 00251 DWORD *sectors = (DWORD*)buff; 00252 DWORD ssize = disk_get_sector_size(pdrv); 00253 int err = _ffs[pdrv]->trim(sectors[0]*ssize, (sectors[1]-sectors[0]+1)*ssize); 00254 return err ? RES_PARERR : RES_OK; 00255 } 00256 } 00257 00258 return RES_PARERR; 00259 } 00260 00261 00262 ////// Generic filesystem operations ////// 00263 00264 // Filesystem implementation (See FATFilySystem.h) 00265 FATFileSystem::FATFileSystem(const char *name, BlockDevice *bd) 00266 : FileSystem(name), _id(-1) { 00267 if (bd) { 00268 mount(bd); 00269 } 00270 } 00271 00272 FATFileSystem::~FATFileSystem() 00273 { 00274 // nop if unmounted 00275 unmount(); 00276 } 00277 00278 int FATFileSystem::mount(BlockDevice *bd) { 00279 // requires duplicate definition to allow virtual overload to work 00280 return mount(bd, true); 00281 } 00282 00283 int FATFileSystem::mount(BlockDevice *bd, bool mount) { 00284 lock(); 00285 if (_id != -1) { 00286 unlock(); 00287 return -EINVAL; 00288 } 00289 00290 for (int i = 0; i < _VOLUMES; i++) { 00291 if (!_ffs[i]) { 00292 _id = i; 00293 _ffs[_id] = bd; 00294 _fsid[0] = '0' + _id; 00295 _fsid[1] = ':'; 00296 _fsid[2] = '\0'; 00297 debug_if(FFS_DBG, "Mounting [%s] on ffs drive [%s]\n", getName(), _fsid); 00298 FRESULT res = f_mount(&_fs, _fsid, mount); 00299 unlock(); 00300 return fat_error_remap(res); 00301 } 00302 } 00303 00304 unlock(); 00305 return -ENOMEM; 00306 } 00307 00308 int FATFileSystem::unmount() 00309 { 00310 lock(); 00311 if (_id == -1) { 00312 unlock(); 00313 return -EINVAL; 00314 } 00315 00316 FRESULT res = f_mount(NULL, _fsid, 0); 00317 _ffs[_id] = NULL; 00318 _id = -1; 00319 unlock(); 00320 return fat_error_remap(res); 00321 } 00322 00323 /* See http://elm-chan.org/fsw/ff/en/mkfs.html for details of f_mkfs() and 00324 * associated arguments. */ 00325 int FATFileSystem::format(BlockDevice *bd, bd_size_t cluster_size) { 00326 FATFileSystem fs; 00327 int err = fs.mount(bd, false); 00328 if (err) { 00329 return err; 00330 } 00331 00332 // Logical drive number, Partitioning rule, Allocation unit size (bytes per cluster) 00333 fs.lock(); 00334 FRESULT res = f_mkfs(fs._fsid, 1, cluster_size); 00335 fs.unlock(); 00336 if (res != FR_OK) { 00337 return fat_error_remap(res); 00338 } 00339 00340 err = fs.unmount(); 00341 if (err) { 00342 return err; 00343 } 00344 00345 return 0; 00346 } 00347 00348 int FATFileSystem::reformat(BlockDevice *bd, int allocation_unit) { 00349 lock(); 00350 if (_id != -1) { 00351 if (!bd) { 00352 bd = _ffs[_id]; 00353 } 00354 00355 int err = unmount(); 00356 if (err) { 00357 unlock(); 00358 return err; 00359 } 00360 } 00361 00362 if (!bd) { 00363 unlock(); 00364 return -ENODEV; 00365 } 00366 00367 int err = FATFileSystem::format(bd, allocation_unit); 00368 if (err) { 00369 unlock(); 00370 return err; 00371 } 00372 00373 err = mount(bd); 00374 unlock(); 00375 return err; 00376 } 00377 00378 int FATFileSystem::remove(const char *path) { 00379 Deferred<const char*> fpath = fat_path_prefix(_id, path); 00380 00381 lock(); 00382 FRESULT res = f_unlink(fpath); 00383 unlock(); 00384 00385 if (res != FR_OK) { 00386 debug_if(FFS_DBG, "f_unlink() failed: %d\n", res); 00387 } 00388 return fat_error_remap(res); 00389 } 00390 00391 int FATFileSystem::rename(const char *oldpath, const char *newpath) { 00392 Deferred<const char*> oldfpath = fat_path_prefix(_id, oldpath); 00393 Deferred<const char*> newfpath = fat_path_prefix(_id, newpath); 00394 00395 lock(); 00396 FRESULT res = f_rename(oldfpath, newfpath); 00397 unlock(); 00398 00399 if (res != FR_OK) { 00400 debug_if(FFS_DBG, "f_rename() failed: %d\n", res); 00401 } 00402 return fat_error_remap(res); 00403 } 00404 00405 int FATFileSystem::mkdir(const char *path, mode_t mode) { 00406 Deferred<const char*> fpath = fat_path_prefix(_id, path); 00407 00408 lock(); 00409 FRESULT res = f_mkdir(fpath); 00410 unlock(); 00411 00412 if (res != FR_OK) { 00413 debug_if(FFS_DBG, "f_mkdir() failed: %d\n", res); 00414 } 00415 return fat_error_remap(res); 00416 } 00417 00418 int FATFileSystem::stat(const char *path, struct stat *st) { 00419 Deferred<const char*> fpath = fat_path_prefix(_id, path); 00420 00421 lock(); 00422 FILINFO f; 00423 memset(&f, 0, sizeof(f)); 00424 00425 FRESULT res = f_stat(fpath, &f); 00426 if (res != FR_OK) { 00427 unlock(); 00428 return fat_error_remap(res); 00429 } 00430 00431 /* ARMCC doesnt support stat(), and these symbols are not defined by the toolchain. */ 00432 #ifdef TOOLCHAIN_GCC 00433 st->st_size = f.fsize; 00434 st->st_mode = 0; 00435 st->st_mode |= (f.fattrib & AM_DIR) ? S_IFDIR : S_IFREG; 00436 st->st_mode |= (f.fattrib & AM_RDO) ? 00437 (S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) : 00438 (S_IRWXU | S_IRWXG | S_IRWXO); 00439 #endif /* TOOLCHAIN_GCC */ 00440 unlock(); 00441 00442 return 0; 00443 } 00444 00445 void FATFileSystem::lock() { 00446 _ffs_mutex->lock(); 00447 } 00448 00449 void FATFileSystem::unlock() { 00450 _ffs_mutex->unlock(); 00451 } 00452 00453 00454 ////// File operations ////// 00455 int FATFileSystem::file_open(fs_file_t *file, const char *path, int flags) { 00456 debug_if(FFS_DBG, "open(%s) on filesystem [%s], drv [%s]\n", path, getName(), _id); 00457 00458 FIL *fh = new FIL; 00459 Deferred<const char*> fpath = fat_path_prefix(_id, path); 00460 00461 /* POSIX flags -> FatFS open mode */ 00462 BYTE openmode; 00463 if (flags & O_RDWR) { 00464 openmode = FA_READ | FA_WRITE; 00465 } else if (flags & O_WRONLY) { 00466 openmode = FA_WRITE; 00467 } else { 00468 openmode = FA_READ; 00469 } 00470 if (flags & O_CREAT) { 00471 if (flags & O_TRUNC) { 00472 openmode |= FA_CREATE_ALWAYS; 00473 } else { 00474 openmode |= FA_OPEN_ALWAYS; 00475 } 00476 } 00477 00478 lock(); 00479 FRESULT res = f_open(fh, fpath, openmode); 00480 00481 if (res != FR_OK) { 00482 unlock(); 00483 debug_if(FFS_DBG, "f_open('w') failed: %d\n", res); 00484 delete fh; 00485 return fat_error_remap(res); 00486 } 00487 00488 if (flags & O_APPEND) { 00489 f_lseek(fh, fh->fsize); 00490 } 00491 unlock(); 00492 00493 *file = fh; 00494 return 0; 00495 } 00496 00497 int FATFileSystem::file_close(fs_file_t file) { 00498 FIL *fh = static_cast<FIL*>(file); 00499 00500 lock(); 00501 FRESULT res = f_close(fh); 00502 unlock(); 00503 00504 delete fh; 00505 return fat_error_remap(res); 00506 } 00507 00508 ssize_t FATFileSystem::file_read(fs_file_t file, void *buffer, size_t len) { 00509 FIL *fh = static_cast<FIL*>(file); 00510 00511 lock(); 00512 UINT n; 00513 FRESULT res = f_read(fh, buffer, len, &n); 00514 unlock(); 00515 00516 if (res != FR_OK) { 00517 debug_if(FFS_DBG, "f_read() failed: %d\n", res); 00518 return fat_error_remap(res); 00519 } else { 00520 return n; 00521 } 00522 } 00523 00524 ssize_t FATFileSystem::file_write(fs_file_t file, const void *buffer, size_t len) { 00525 FIL *fh = static_cast<FIL*>(file); 00526 00527 lock(); 00528 UINT n; 00529 FRESULT res = f_write(fh, buffer, len, &n); 00530 unlock(); 00531 00532 if (res != FR_OK) { 00533 debug_if(FFS_DBG, "f_write() failed: %d", res); 00534 return fat_error_remap(res); 00535 } else { 00536 return n; 00537 } 00538 } 00539 00540 int FATFileSystem::file_sync(fs_file_t file) { 00541 FIL *fh = static_cast<FIL*>(file); 00542 00543 lock(); 00544 FRESULT res = f_sync(fh); 00545 unlock(); 00546 00547 if (res != FR_OK) { 00548 debug_if(FFS_DBG, "f_sync() failed: %d\n", res); 00549 } 00550 return fat_error_remap(res); 00551 } 00552 00553 off_t FATFileSystem::file_seek(fs_file_t file, off_t offset, int whence) { 00554 FIL *fh = static_cast<FIL*>(file); 00555 00556 lock(); 00557 if (whence == SEEK_END) { 00558 offset += fh->fsize; 00559 } else if(whence==SEEK_CUR) { 00560 offset += fh->fptr; 00561 } 00562 00563 FRESULT res = f_lseek(fh, offset); 00564 off_t noffset = fh->fptr; 00565 unlock(); 00566 00567 if (res != FR_OK) { 00568 debug_if(FFS_DBG, "lseek failed: %d\n", res); 00569 return fat_error_remap(res); 00570 } else { 00571 return noffset; 00572 } 00573 } 00574 00575 off_t FATFileSystem::file_tell(fs_file_t file) { 00576 FIL *fh = static_cast<FIL*>(file); 00577 00578 lock(); 00579 off_t res = fh->fptr; 00580 unlock(); 00581 00582 return res; 00583 } 00584 00585 off_t FATFileSystem::file_size(fs_file_t file) { 00586 FIL *fh = static_cast<FIL*>(file); 00587 00588 lock(); 00589 off_t res = fh->fsize; 00590 unlock(); 00591 00592 return res; 00593 } 00594 00595 00596 ////// Dir operations ////// 00597 int FATFileSystem::dir_open(fs_dir_t *dir, const char *path) { 00598 FATFS_DIR *dh = new FATFS_DIR; 00599 Deferred<const char*> fpath = fat_path_prefix(_id, path); 00600 00601 lock(); 00602 FRESULT res = f_opendir(dh, fpath); 00603 unlock(); 00604 00605 if (res != FR_OK) { 00606 debug_if(FFS_DBG, "f_opendir() failed: %d\n", res); 00607 delete dh; 00608 return fat_error_remap(res); 00609 } 00610 00611 *dir = dh; 00612 return 0; 00613 } 00614 00615 int FATFileSystem::dir_close(fs_dir_t dir) { 00616 FATFS_DIR *dh = static_cast<FATFS_DIR*>(dir); 00617 00618 lock(); 00619 FRESULT res = f_closedir(dh); 00620 unlock(); 00621 00622 delete dh; 00623 return fat_error_remap(res); 00624 } 00625 00626 ssize_t FATFileSystem::dir_read(fs_dir_t dir, struct dirent *ent) { 00627 FATFS_DIR *dh = static_cast<FATFS_DIR*>(dir); 00628 FILINFO finfo; 00629 00630 #if _USE_LFN 00631 finfo.lfname = ent->d_name; 00632 finfo.lfsize = NAME_MAX; 00633 #endif // _USE_LFN 00634 00635 lock(); 00636 FRESULT res = f_readdir(dh, &finfo); 00637 unlock(); 00638 00639 if (res != FR_OK) { 00640 return fat_error_remap(res); 00641 } else if (finfo.fname[0] == 0) { 00642 return 0; 00643 } 00644 00645 ent->d_type = (finfo.fattrib & AM_DIR) ? DT_DIR : DT_REG; 00646 00647 #if _USE_LFN 00648 if (ent->d_name[0] == 0) { 00649 // No long filename so use short filename. 00650 strncpy(ent->d_name, finfo.fname, NAME_MAX); 00651 } 00652 #else 00653 strncpy(end->d_name, finfo.fname, len); 00654 #endif 00655 00656 return 1; 00657 } 00658 00659 void FATFileSystem::dir_seek(fs_dir_t dir, off_t offset) { 00660 FATFS_DIR *dh = static_cast<FATFS_DIR*>(dir); 00661 00662 lock(); 00663 if (offset < dh->index) { 00664 f_rewinddir(dh); 00665 } 00666 while (dh->index < offset) { 00667 FILINFO finfo; 00668 FRESULT res; 00669 #if _USE_LFN 00670 char lfname[NAME_MAX]; 00671 finfo.lfname = lfname; 00672 finfo.lfsize = NAME_MAX; 00673 #endif // _USE_LFN 00674 res = f_readdir(dh, &finfo); 00675 if (res != FR_OK) { 00676 break; 00677 } else if (finfo.fname[0] == 0) { 00678 break; 00679 } 00680 } 00681 unlock(); 00682 } 00683 00684 off_t FATFileSystem::dir_tell(fs_dir_t dir) { 00685 FATFS_DIR *dh = static_cast<FATFS_DIR*>(dir); 00686 00687 lock(); 00688 off_t offset = dh->index; 00689 unlock(); 00690 00691 return offset; 00692 } 00693 00694 void FATFileSystem::dir_rewind(fs_dir_t dir) { 00695 FATFS_DIR *dh = static_cast<FATFS_DIR*>(dir); 00696 00697 lock(); 00698 f_rewinddir(dh); 00699 unlock(); 00700 } 00701
Generated on Thu Jul 14 2022 14:36:15 by
