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; 00040 case FR_DISK_ERR: // (1) A hard error occurred in the low level disk I/O layer 00041 return -EIO; 00042 case FR_INT_ERR: // (2) Assertion failed 00043 return -1; 00044 case FR_NOT_READY: // (3) The physical drive cannot work 00045 return -EIO; 00046 case FR_NO_FILE: // (4) Could not find the file 00047 return -ENOENT; 00048 case FR_NO_PATH: // (5) Could not find the path 00049 return -ENOTDIR; 00050 case FR_INVALID_NAME: // (6) The path name format is invalid 00051 return -EINVAL; 00052 case FR_DENIED: // (7) Access denied due to prohibited access or directory full 00053 return -EACCES; 00054 case FR_EXIST: // (8) Access denied due to prohibited access 00055 return -EEXIST; 00056 case FR_INVALID_OBJECT: // (9) The file/directory object is invalid 00057 return -EBADF; 00058 case FR_WRITE_PROTECTED: // (10) The physical drive is write protected 00059 return -EACCES; 00060 case FR_INVALID_DRIVE: // (11) The logical drive number is invalid 00061 return -ENODEV; 00062 case FR_NOT_ENABLED: // (12) The volume has no work area 00063 return -ENODEV; 00064 case FR_NO_FILESYSTEM: // (13) There is no valid FAT volume 00065 return -EINVAL; 00066 case FR_MKFS_ABORTED: // (14) The f_mkfs() aborted due to any problem 00067 return -EIO; 00068 case FR_TIMEOUT: // (15) Could not get a grant to access the volume within defined period 00069 return -ETIMEDOUT; 00070 case FR_LOCKED: // (16) The operation is rejected according to the file sharing policy 00071 return -EBUSY; 00072 case FR_NOT_ENOUGH_CORE: // (17) LFN working buffer could not be allocated 00073 return -ENOMEM; 00074 case FR_TOO_MANY_OPEN_FILES: // (18) Number of open files > FF_FS_LOCK 00075 return -ENFILE; 00076 case FR_INVALID_PARAMETER: // (19) Given parameter is invalid 00077 return -EINVAL; 00078 default: 00079 return -res; 00080 } 00081 } 00082 00083 // Helper class for deferring operations when variable falls out of scope 00084 template <typename T> 00085 class Deferred { 00086 public: 00087 T _t; 00088 Callback<void(T)> _ondefer; 00089 00090 Deferred(const Deferred&); 00091 Deferred &operator=(const Deferred&); 00092 00093 public: 00094 Deferred(T t, Callback<void(T)> ondefer = NULL) 00095 : _t(t), _ondefer(ondefer) 00096 { 00097 } 00098 00099 operator T() 00100 { 00101 return _t; 00102 } 00103 00104 ~Deferred() 00105 { 00106 if (_ondefer) { 00107 _ondefer(_t); 00108 } 00109 } 00110 }; 00111 00112 static void dodelete(const char *data) 00113 { 00114 delete[] data; 00115 } 00116 00117 // Adds prefix needed internally by fatfs, this can be avoided for the first fatfs 00118 // (id 0) otherwise a prefix of "id:/" is inserted in front of the string. 00119 static Deferred<const char*> fat_path_prefix(int id, const char *path) 00120 { 00121 // We can avoid dynamic allocation when only on fatfs is in use 00122 if (id == 0) { 00123 return path; 00124 } 00125 00126 // Prefix path with id, will look something like 2:/hi/hello/filehere.txt 00127 char *buffer = new char[strlen("0:/") + strlen(path) + 1]; 00128 if (!buffer) { 00129 return NULL; 00130 } 00131 00132 buffer[0] = '0' + id; 00133 buffer[1] = ':'; 00134 buffer[2] = '/'; 00135 strcpy(buffer + strlen("0:/"), path); 00136 return Deferred<const char*>(buffer, dodelete); 00137 } 00138 00139 00140 ////// Disk operations ////// 00141 00142 // Global access to block device from FAT driver 00143 static BlockDevice *_ffs[FF_VOLUMES] = {0}; 00144 static SingletonPtr<PlatformMutex> _ffs_mutex; 00145 00146 00147 // FAT driver functions 00148 DWORD get_fattime(void) 00149 { 00150 time_t rawtime; 00151 time(&rawtime); 00152 struct tm *ptm = localtime(&rawtime); 00153 return (DWORD)(ptm->tm_year - 80) << 25 00154 | (DWORD)(ptm->tm_mon + 1 ) << 21 00155 | (DWORD)(ptm->tm_mday ) << 16 00156 | (DWORD)(ptm->tm_hour ) << 11 00157 | (DWORD)(ptm->tm_min ) << 5 00158 | (DWORD)(ptm->tm_sec/2 ); 00159 } 00160 00161 void *ff_memalloc(UINT size) 00162 { 00163 return malloc(size); 00164 } 00165 00166 void ff_memfree(void *p) 00167 { 00168 free(p); 00169 } 00170 00171 // Implementation of diskio functions (see ChaN/diskio.h) 00172 static WORD disk_get_sector_size(BYTE pdrv) 00173 { 00174 WORD ssize = _ffs[pdrv]->get_erase_size(); 00175 if (ssize < 512) { 00176 ssize = 512; 00177 } 00178 00179 MBED_ASSERT(ssize >= FF_MIN_SS && ssize <= FF_MAX_SS); 00180 MBED_ASSERT(_ffs[pdrv]->get_read_size() <= _ffs[pdrv]->get_erase_size()); 00181 MBED_ASSERT(_ffs[pdrv]->get_program_size() <= _ffs[pdrv]->get_erase_size()); 00182 return ssize; 00183 } 00184 00185 static DWORD disk_get_sector_count(BYTE pdrv) 00186 { 00187 DWORD scount = _ffs[pdrv]->size() / disk_get_sector_size(pdrv); 00188 MBED_ASSERT(scount >= 64); 00189 return scount; 00190 } 00191 00192 DSTATUS disk_status(BYTE pdrv) 00193 { 00194 debug_if(FFS_DBG, "disk_status on pdrv [%d]\n", pdrv); 00195 return RES_OK; 00196 } 00197 00198 DSTATUS disk_initialize(BYTE pdrv) 00199 { 00200 debug_if(FFS_DBG, "disk_initialize on pdrv [%d]\n", pdrv); 00201 return (DSTATUS)_ffs[pdrv]->init(); 00202 } 00203 00204 DRESULT disk_read(BYTE pdrv, BYTE *buff, DWORD sector, UINT count) 00205 { 00206 debug_if(FFS_DBG, "disk_read(sector %d, count %d) on pdrv [%d]\n", sector, count, pdrv); 00207 DWORD ssize = disk_get_sector_size(pdrv); 00208 bd_addr_t addr = (bd_addr_t)sector*ssize; 00209 bd_size_t size = (bd_size_t)count*ssize; 00210 int err = _ffs[pdrv]->read(buff, addr, size); 00211 return err ? RES_PARERR : RES_OK; 00212 } 00213 00214 DRESULT disk_write(BYTE pdrv, const BYTE *buff, DWORD sector, UINT count) 00215 { 00216 debug_if(FFS_DBG, "disk_write(sector %d, count %d) on pdrv [%d]\n", sector, count, pdrv); 00217 DWORD ssize = disk_get_sector_size(pdrv); 00218 bd_addr_t addr = (bd_addr_t)sector*ssize; 00219 bd_size_t size = (bd_size_t)count*ssize; 00220 int err = _ffs[pdrv]->erase(addr, size); 00221 if (err) { 00222 return RES_PARERR; 00223 } 00224 00225 err = _ffs[pdrv]->program(buff, addr, size); 00226 if (err) { 00227 return RES_PARERR; 00228 } 00229 00230 return RES_OK; 00231 } 00232 00233 DRESULT disk_ioctl(BYTE pdrv, BYTE cmd, void *buff) 00234 { 00235 debug_if(FFS_DBG, "disk_ioctl(%d)\n", cmd); 00236 switch (cmd) { 00237 case CTRL_SYNC: 00238 if (_ffs[pdrv] == NULL) { 00239 return RES_NOTRDY; 00240 } else { 00241 return RES_OK; 00242 } 00243 case GET_SECTOR_COUNT: 00244 if (_ffs[pdrv] == NULL) { 00245 return RES_NOTRDY; 00246 } else { 00247 *((DWORD*)buff) = disk_get_sector_count(pdrv); 00248 return RES_OK; 00249 } 00250 case GET_SECTOR_SIZE: 00251 if (_ffs[pdrv] == NULL) { 00252 return RES_NOTRDY; 00253 } else { 00254 *((WORD*)buff) = disk_get_sector_size(pdrv); 00255 return RES_OK; 00256 } 00257 case GET_BLOCK_SIZE: 00258 *((DWORD*)buff) = 1; // default when not known 00259 return RES_OK; 00260 case CTRL_TRIM: 00261 if (_ffs[pdrv] == NULL) { 00262 return RES_NOTRDY; 00263 } else { 00264 DWORD *sectors = (DWORD*)buff; 00265 DWORD ssize = disk_get_sector_size(pdrv); 00266 bd_addr_t addr = (bd_addr_t)sectors[0]*ssize; 00267 bd_size_t size = (bd_size_t)(sectors[1]-sectors[0]+1)*ssize; 00268 int err = _ffs[pdrv]->trim(addr, size); 00269 return err ? RES_PARERR : RES_OK; 00270 } 00271 } 00272 00273 return RES_PARERR; 00274 } 00275 00276 00277 ////// Generic filesystem operations ////// 00278 00279 // Filesystem implementation (See FATFilySystem.h) 00280 FATFileSystem::FATFileSystem(const char *name, BlockDevice *bd) 00281 : FileSystem(name), _id(-1) { 00282 if (bd) { 00283 mount(bd); 00284 } 00285 } 00286 00287 FATFileSystem::~FATFileSystem() 00288 { 00289 // nop if unmounted 00290 unmount(); 00291 } 00292 00293 int FATFileSystem::mount(BlockDevice *bd) 00294 { 00295 // requires duplicate definition to allow virtual overload to work 00296 return mount(bd, true); 00297 } 00298 00299 int FATFileSystem::mount(BlockDevice *bd, bool mount) 00300 { 00301 lock(); 00302 if (_id != -1) { 00303 unlock(); 00304 return -EINVAL; 00305 } 00306 00307 for (int i = 0; i < FF_VOLUMES; i++) { 00308 if (!_ffs[i]) { 00309 _id = i; 00310 _ffs[_id] = bd; 00311 _fsid[0] = '0' + _id; 00312 _fsid[1] = ':'; 00313 _fsid[2] = '\0'; 00314 debug_if(FFS_DBG, "Mounting [%s] on ffs drive [%s]\n", getName(), _fsid); 00315 FRESULT res = f_mount(&_fs, _fsid, mount); 00316 unlock(); 00317 return fat_error_remap(res); 00318 } 00319 } 00320 00321 unlock(); 00322 return -ENOMEM; 00323 } 00324 00325 int FATFileSystem::unmount() 00326 { 00327 lock(); 00328 if (_id == -1) { 00329 unlock(); 00330 return -EINVAL; 00331 } 00332 00333 FRESULT res = f_mount(NULL, _fsid, 0); 00334 _ffs[_id] = NULL; 00335 _id = -1; 00336 unlock(); 00337 return fat_error_remap(res); 00338 } 00339 00340 /* See http://elm-chan.org/fsw/ff/en/mkfs.html for details of f_mkfs() and 00341 * associated arguments. */ 00342 int FATFileSystem::format(BlockDevice *bd, bd_size_t cluster_size) 00343 { 00344 FATFileSystem fs; 00345 fs.lock(); 00346 00347 int err = bd->init(); 00348 if (err) { 00349 fs.unlock(); 00350 return err; 00351 } 00352 00353 // erase first handful of blocks 00354 bd_size_t header = 2*bd->get_erase_size(); 00355 err = bd->erase(0, header); 00356 if (err) { 00357 bd->deinit(); 00358 fs.unlock(); 00359 return err; 00360 } 00361 00362 if (bd->get_erase_value() < 0) { 00363 // erase is unknown, need to write 1s 00364 bd_size_t program_size = bd->get_program_size(); 00365 void *buf = malloc(program_size); 00366 if (!buf) { 00367 bd->deinit(); 00368 fs.unlock(); 00369 return -ENOMEM; 00370 } 00371 00372 memset(buf, 0xff, program_size); 00373 00374 for (bd_addr_t i = 0; i < header; i += program_size) { 00375 err = bd->program(buf, i, program_size); 00376 if (err) { 00377 free(buf); 00378 bd->deinit(); 00379 fs.unlock(); 00380 return err; 00381 } 00382 } 00383 00384 free(buf); 00385 } 00386 00387 // trim entire device to indicate it is unneeded 00388 err = bd->trim(0, bd->size()); 00389 if (err) { 00390 bd->deinit(); 00391 fs.unlock(); 00392 return err; 00393 } 00394 00395 err = bd->deinit(); 00396 if (err) { 00397 fs.unlock(); 00398 return err; 00399 } 00400 00401 err = fs.mount(bd, false); 00402 if (err) { 00403 fs.unlock(); 00404 return err; 00405 } 00406 00407 // Logical drive number, Partitioning rule, Allocation unit size (bytes per cluster) 00408 FRESULT res = f_mkfs(fs._fsid, FM_ANY | FM_SFD, cluster_size, NULL, 0); 00409 if (res != FR_OK) { 00410 fs.unmount(); 00411 fs.unlock(); 00412 return fat_error_remap(res); 00413 } 00414 00415 err = fs.unmount(); 00416 if (err) { 00417 fs.unlock(); 00418 return err; 00419 } 00420 00421 fs.unlock(); 00422 return 0; 00423 } 00424 00425 int FATFileSystem::reformat(BlockDevice *bd, int allocation_unit) 00426 { 00427 lock(); 00428 if (_id != -1) { 00429 if (!bd) { 00430 bd = _ffs[_id]; 00431 } 00432 00433 int err = unmount(); 00434 if (err) { 00435 unlock(); 00436 return err; 00437 } 00438 } 00439 00440 if (!bd) { 00441 unlock(); 00442 return -ENODEV; 00443 } 00444 00445 int err = FATFileSystem::format(bd, allocation_unit); 00446 if (err) { 00447 unlock(); 00448 return err; 00449 } 00450 00451 err = mount(bd); 00452 unlock(); 00453 return err; 00454 } 00455 00456 int FATFileSystem::remove(const char *path) 00457 { 00458 Deferred<const char*> fpath = fat_path_prefix(_id, path); 00459 00460 lock(); 00461 FRESULT res = f_unlink(fpath); 00462 unlock(); 00463 00464 if (res != FR_OK) { 00465 debug_if(FFS_DBG, "f_unlink() failed: %d\n", res); 00466 if (res == FR_DENIED) { 00467 printf("hi %d -> %d\n", FR_DENIED, -ENOTEMPTY); 00468 return -ENOTEMPTY; 00469 } 00470 } 00471 return fat_error_remap(res); 00472 } 00473 00474 int FATFileSystem::rename(const char *oldpath, const char *newpath) 00475 { 00476 Deferred<const char*> oldfpath = fat_path_prefix(_id, oldpath); 00477 Deferred<const char*> newfpath = fat_path_prefix(_id, newpath); 00478 00479 lock(); 00480 FRESULT res = f_rename(oldfpath, newfpath); 00481 unlock(); 00482 00483 if (res != FR_OK) { 00484 debug_if(FFS_DBG, "f_rename() failed: %d\n", res); 00485 } 00486 return fat_error_remap(res); 00487 } 00488 00489 int FATFileSystem::mkdir(const char *path, mode_t mode) 00490 { 00491 Deferred<const char*> fpath = fat_path_prefix(_id, path); 00492 00493 lock(); 00494 FRESULT res = f_mkdir(fpath); 00495 unlock(); 00496 00497 if (res != FR_OK) { 00498 debug_if(FFS_DBG, "f_mkdir() failed: %d\n", res); 00499 } 00500 return fat_error_remap(res); 00501 } 00502 00503 int FATFileSystem::stat(const char *path, struct stat *st) 00504 { 00505 Deferred<const char*> fpath = fat_path_prefix(_id, path); 00506 00507 lock(); 00508 FILINFO f; 00509 memset(&f, 0, sizeof(f)); 00510 00511 FRESULT res = f_stat(fpath, &f); 00512 if (res != FR_OK) { 00513 unlock(); 00514 return fat_error_remap(res); 00515 } 00516 00517 /* ARMCC doesnt support stat(), and these symbols are not defined by the toolchain. */ 00518 #ifdef TOOLCHAIN_GCC 00519 st->st_size = f.fsize; 00520 st->st_mode = 0; 00521 st->st_mode |= (f.fattrib & AM_DIR) ? S_IFDIR : S_IFREG; 00522 st->st_mode |= (f.fattrib & AM_RDO) ? 00523 (S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) : 00524 (S_IRWXU | S_IRWXG | S_IRWXO); 00525 #endif /* TOOLCHAIN_GCC */ 00526 unlock(); 00527 00528 return 0; 00529 } 00530 00531 int FATFileSystem::statvfs(const char *path, struct statvfs *buf) 00532 { 00533 00534 memset(buf, 0, sizeof(struct statvfs)); 00535 FATFS *fs; 00536 DWORD fre_clust; 00537 00538 lock(); 00539 FRESULT res = f_getfree(_fsid, &fre_clust, &fs); 00540 if (res != FR_OK) { 00541 unlock(); 00542 return fat_error_remap(res); 00543 } 00544 00545 buf->f_bsize = fs->ssize; 00546 buf->f_frsize = fs->ssize; 00547 buf->f_blocks = (fs->n_fatent - 2) * fs->csize; 00548 buf->f_bfree = fre_clust * fs->csize; 00549 buf->f_bavail = buf->f_bfree; 00550 #if FF_USE_LFN 00551 buf->f_namemax = FF_LFN_BUF; 00552 #else 00553 buf->f_namemax = FF_SFN_BUF; 00554 #endif 00555 00556 unlock(); 00557 return 0; 00558 } 00559 00560 void FATFileSystem::lock() 00561 { 00562 _ffs_mutex->lock(); 00563 } 00564 00565 void FATFileSystem::unlock() 00566 { 00567 _ffs_mutex->unlock(); 00568 } 00569 00570 00571 ////// File operations ////// 00572 int FATFileSystem::file_open(fs_file_t *file, const char *path, int flags) 00573 { 00574 debug_if(FFS_DBG, "open(%s) on filesystem [%s], drv [%s]\n", path, getName(), _id); 00575 00576 FIL *fh = new FIL; 00577 Deferred<const char*> fpath = fat_path_prefix(_id, path); 00578 00579 /* POSIX flags -> FatFS open mode */ 00580 BYTE openmode; 00581 if (flags & O_RDWR) { 00582 openmode = FA_READ | FA_WRITE; 00583 } else if (flags & O_WRONLY) { 00584 openmode = FA_WRITE; 00585 } else { 00586 openmode = FA_READ; 00587 } 00588 00589 if (flags & O_CREAT) { 00590 if (flags & O_TRUNC) { 00591 openmode |= FA_CREATE_ALWAYS; 00592 } else { 00593 openmode |= FA_OPEN_ALWAYS; 00594 } 00595 } 00596 00597 if (flags & O_APPEND) { 00598 openmode |= FA_OPEN_APPEND; 00599 } 00600 00601 lock(); 00602 FRESULT res = f_open(fh, fpath, openmode); 00603 00604 if (res != FR_OK) { 00605 unlock(); 00606 debug_if(FFS_DBG, "f_open('w') failed: %d\n", res); 00607 delete fh; 00608 return fat_error_remap(res); 00609 } 00610 00611 unlock(); 00612 00613 *file = fh; 00614 return 0; 00615 } 00616 00617 int FATFileSystem::file_close(fs_file_t file) 00618 { 00619 FIL *fh = static_cast<FIL*>(file); 00620 00621 lock(); 00622 FRESULT res = f_close(fh); 00623 unlock(); 00624 00625 delete fh; 00626 return fat_error_remap(res); 00627 } 00628 00629 ssize_t FATFileSystem::file_read(fs_file_t file, void *buffer, size_t len) 00630 { 00631 FIL *fh = static_cast<FIL*>(file); 00632 00633 lock(); 00634 UINT n; 00635 FRESULT res = f_read(fh, buffer, len, &n); 00636 unlock(); 00637 00638 if (res != FR_OK) { 00639 debug_if(FFS_DBG, "f_read() failed: %d\n", res); 00640 return fat_error_remap(res); 00641 } else { 00642 return n; 00643 } 00644 } 00645 00646 ssize_t FATFileSystem::file_write(fs_file_t file, const void *buffer, size_t len) 00647 { 00648 FIL *fh = static_cast<FIL*>(file); 00649 00650 lock(); 00651 UINT n; 00652 FRESULT res = f_write(fh, buffer, len, &n); 00653 unlock(); 00654 00655 if (res != FR_OK) { 00656 debug_if(FFS_DBG, "f_write() failed: %d", res); 00657 return fat_error_remap(res); 00658 } else { 00659 return n; 00660 } 00661 } 00662 00663 int FATFileSystem::file_sync(fs_file_t file) 00664 { 00665 FIL *fh = static_cast<FIL*>(file); 00666 00667 lock(); 00668 FRESULT res = f_sync(fh); 00669 unlock(); 00670 00671 if (res != FR_OK) { 00672 debug_if(FFS_DBG, "f_sync() failed: %d\n", res); 00673 } 00674 return fat_error_remap(res); 00675 } 00676 00677 off_t FATFileSystem::file_seek(fs_file_t file, off_t offset, int whence) 00678 { 00679 FIL *fh = static_cast<FIL*>(file); 00680 00681 lock(); 00682 if (whence == SEEK_END) { 00683 offset += f_size(fh); 00684 } else if(whence==SEEK_CUR) { 00685 offset += f_tell(fh); 00686 } 00687 00688 FRESULT res = f_lseek(fh, offset); 00689 off_t noffset = fh->fptr; 00690 unlock(); 00691 00692 if (res != FR_OK) { 00693 debug_if(FFS_DBG, "lseek failed: %d\n", res); 00694 return fat_error_remap(res); 00695 } else { 00696 return noffset; 00697 } 00698 } 00699 00700 off_t FATFileSystem::file_tell(fs_file_t file) 00701 { 00702 FIL *fh = static_cast<FIL*>(file); 00703 00704 lock(); 00705 off_t res = f_tell(fh); 00706 unlock(); 00707 00708 return res; 00709 } 00710 00711 off_t FATFileSystem::file_size(fs_file_t file) 00712 { 00713 FIL *fh = static_cast<FIL*>(file); 00714 00715 lock(); 00716 off_t res = f_size(fh); 00717 unlock(); 00718 00719 return res; 00720 } 00721 00722 00723 ////// Dir operations ////// 00724 int FATFileSystem::dir_open(fs_dir_t *dir, const char *path) 00725 { 00726 FATFS_DIR *dh = new FATFS_DIR; 00727 Deferred<const char*> fpath = fat_path_prefix(_id, path); 00728 00729 lock(); 00730 FRESULT res = f_opendir(dh, fpath); 00731 unlock(); 00732 00733 if (res != FR_OK) { 00734 debug_if(FFS_DBG, "f_opendir() failed: %d\n", res); 00735 delete dh; 00736 return fat_error_remap(res); 00737 } 00738 00739 *dir = dh; 00740 return 0; 00741 } 00742 00743 int FATFileSystem::dir_close(fs_dir_t dir) 00744 { 00745 FATFS_DIR *dh = static_cast<FATFS_DIR*>(dir); 00746 00747 lock(); 00748 FRESULT res = f_closedir(dh); 00749 unlock(); 00750 00751 delete dh; 00752 return fat_error_remap(res); 00753 } 00754 00755 ssize_t FATFileSystem::dir_read(fs_dir_t dir, struct dirent *ent) 00756 { 00757 FATFS_DIR *dh = static_cast<FATFS_DIR*>(dir); 00758 FILINFO finfo; 00759 00760 lock(); 00761 FRESULT res = f_readdir(dh, &finfo); 00762 unlock(); 00763 00764 if (res != FR_OK) { 00765 return fat_error_remap(res); 00766 } else if (finfo.fname[0] == 0) { 00767 return 0; 00768 } 00769 00770 ent->d_type = (finfo.fattrib & AM_DIR) ? DT_DIR : DT_REG; 00771 00772 #if FF_USE_LFN 00773 if (ent->d_name[0] == 0) { 00774 // No long filename so use short filename. 00775 strncpy(ent->d_name, finfo.fname, FF_LFN_BUF); 00776 } 00777 #else 00778 strncpy(ent->d_name, finfo.fname, FF_SFN_BUF); 00779 #endif 00780 00781 return 1; 00782 } 00783 00784 void FATFileSystem::dir_seek(fs_dir_t dir, off_t offset) 00785 { 00786 FATFS_DIR *dh = static_cast<FATFS_DIR*>(dir); 00787 off_t dptr = static_cast<off_t>(dh->dptr); 00788 00789 lock(); 00790 00791 if (offset < dptr) { 00792 f_rewinddir(dh); 00793 } 00794 while (dptr < offset) { 00795 FILINFO finfo; 00796 FRESULT res; 00797 00798 res = f_readdir(dh, &finfo); 00799 dptr = dh->dptr; 00800 if (res != FR_OK) { 00801 break; 00802 } else if (finfo.fname[0] == 0) { 00803 break; 00804 } 00805 } 00806 unlock(); 00807 } 00808 00809 off_t FATFileSystem::dir_tell(fs_dir_t dir) 00810 { 00811 FATFS_DIR *dh = static_cast<FATFS_DIR*>(dir); 00812 00813 lock(); 00814 off_t offset = dh->dptr; 00815 unlock(); 00816 00817 return offset; 00818 } 00819 00820 void FATFileSystem::dir_rewind(fs_dir_t dir) 00821 { 00822 FATFS_DIR *dh = static_cast<FATFS_DIR*>(dir); 00823 00824 lock(); 00825 f_rewinddir(dh); 00826 unlock(); 00827 } 00828
Generated on Tue Jul 12 2022 12:44:02 by
