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.
Dependents: mbed-os-example-blinky-gr-lychee GR-Boads_Camera_sample GR-Boards_Audio_Recoder GR-Boads_Camera_DisplayApp ... more
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 void fat_filesystem_set_errno(FRESULT res) 00075 { 00076 switch(res) { 00077 case FR_OK: /* (0) Succeeded */ 00078 errno = 0; /* no error */ 00079 break; 00080 case FR_DISK_ERR: /* (1) A hard error occurred in the low level disk I/O layer */ 00081 case FR_NOT_READY: /* (3) The physical drive cannot work */ 00082 errno = EIO; /* I/O error */ 00083 break; 00084 case FR_NO_FILE: /* (4) Could not find the file */ 00085 case FR_NO_PATH: /* (5) Could not find the path */ 00086 case FR_INVALID_NAME: /* (6) The path name format is invalid */ 00087 case FR_INVALID_DRIVE: /* (11) The logical drive number is invalid */ 00088 case FR_NO_FILESYSTEM: /* (13) There is no valid FAT volume */ 00089 errno = ENOENT; /* No such file or directory */ 00090 break; 00091 case FR_DENIED: /* (7) Access denied due to prohibited access or directory full */ 00092 errno = EACCES; /* Permission denied */ 00093 break; 00094 case FR_EXIST: /* (8) Access denied due to prohibited access */ 00095 errno = EEXIST; /* File exists */ 00096 break; 00097 case FR_WRITE_PROTECTED: /* (10) The physical drive is write protected */ 00098 case FR_LOCKED: /* (16) The operation is rejected according to the file sharing policy */ 00099 errno = EACCES; /* Permission denied */ 00100 break; 00101 case FR_INVALID_OBJECT: /* (9) The file/directory object is invalid */ 00102 errno = EFAULT; /* Bad address */ 00103 break; 00104 case FR_NOT_ENABLED: /* (12) The volume has no work area */ 00105 errno = ENXIO; /* No such device or address */ 00106 break; 00107 case FR_NOT_ENOUGH_CORE: /* (17) LFN working buffer could not be allocated */ 00108 errno = ENOMEM; /* Not enough space */ 00109 break; 00110 case FR_TOO_MANY_OPEN_FILES: /* (18) Number of open files > _FS_LOCK */ 00111 errno = ENFILE; /* Too many open files in system */ 00112 break; 00113 case FR_INVALID_PARAMETER: /* (19) Given parameter is invalid */ 00114 errno = ENOEXEC; /* Exec format error */ 00115 break; 00116 case FR_INT_ERR: /* (2) Assertion failed */ 00117 case FR_MKFS_ABORTED: /* (14) The f_mkfs() aborted due to any parameter error */ 00118 case FR_TIMEOUT: /* (15) Could not get a grant to access the volume within defined period */ 00119 default: 00120 errno = EBADF; /* Bad file number */ 00121 break; 00122 } 00123 return; 00124 } 00125 00126 00127 00128 ////// Disk operations ////// 00129 00130 // Global access to block device from FAT driver 00131 static BlockDevice *_ffs[_VOLUMES] = {0}; 00132 static SingletonPtr<PlatformMutex> _ffs_mutex; 00133 00134 00135 // FAT driver functions 00136 DWORD get_fattime(void) 00137 { 00138 time_t rawtime; 00139 time(&rawtime); 00140 struct tm *ptm = localtime(&rawtime); 00141 return (DWORD)(ptm->tm_year - 80) << 25 00142 | (DWORD)(ptm->tm_mon + 1 ) << 21 00143 | (DWORD)(ptm->tm_mday ) << 16 00144 | (DWORD)(ptm->tm_hour ) << 11 00145 | (DWORD)(ptm->tm_min ) << 5 00146 | (DWORD)(ptm->tm_sec/2 ); 00147 } 00148 00149 // Implementation of diskio functions (see ChaN/diskio.h) 00150 DSTATUS disk_status(BYTE pdrv) 00151 { 00152 debug_if(FFS_DBG, "disk_status on pdrv [%d]\n", pdrv); 00153 return RES_OK; 00154 } 00155 00156 DSTATUS disk_initialize(BYTE pdrv) 00157 { 00158 debug_if(FFS_DBG, "disk_initialize on pdrv [%d]\n", pdrv); 00159 return (DSTATUS)_ffs[pdrv]->init(); 00160 } 00161 00162 DRESULT disk_read(BYTE pdrv, BYTE *buff, DWORD sector, UINT count) 00163 { 00164 debug_if(FFS_DBG, "disk_read(sector %d, count %d) on pdrv [%d]\n", sector, count, pdrv); 00165 bd_size_t ssize = _ffs[pdrv]->get_erase_size(); 00166 int err = _ffs[pdrv]->read(buff, sector*ssize, count*ssize); 00167 return err ? RES_PARERR : RES_OK; 00168 } 00169 00170 DRESULT disk_write(BYTE pdrv, const BYTE *buff, DWORD sector, UINT count) 00171 { 00172 debug_if(FFS_DBG, "disk_write(sector %d, count %d) on pdrv [%d]\n", sector, count, pdrv); 00173 bd_size_t ssize = _ffs[pdrv]->get_erase_size(); 00174 int err = _ffs[pdrv]->erase(sector*ssize, count*ssize); 00175 if (err) { 00176 return RES_PARERR; 00177 } 00178 00179 err = _ffs[pdrv]->program(buff, sector*ssize, count*ssize); 00180 if (err) { 00181 return RES_PARERR; 00182 } 00183 00184 return RES_OK; 00185 } 00186 00187 DRESULT disk_ioctl(BYTE pdrv, BYTE cmd, void *buff) 00188 { 00189 debug_if(FFS_DBG, "disk_ioctl(%d)\n", cmd); 00190 switch (cmd) { 00191 case CTRL_SYNC: 00192 if (_ffs[pdrv] == NULL) { 00193 return RES_NOTRDY; 00194 } else { 00195 return RES_OK; 00196 } 00197 case GET_SECTOR_COUNT: 00198 if (_ffs[pdrv] == NULL) { 00199 return RES_NOTRDY; 00200 } else { 00201 DWORD count = _ffs[pdrv]->size() / _ffs[pdrv]->get_erase_size(); 00202 *((DWORD*)buff) = count; 00203 return RES_OK; 00204 } 00205 case GET_SECTOR_SIZE: 00206 if (_ffs[pdrv] == NULL) { 00207 return RES_NOTRDY; 00208 } else { 00209 DWORD size = _ffs[pdrv]->get_erase_size(); 00210 *((DWORD*)buff) = size; 00211 return RES_OK; 00212 } 00213 case GET_BLOCK_SIZE: 00214 *((DWORD*)buff) = 1; // default when not known 00215 return RES_OK; 00216 } 00217 00218 return RES_PARERR; 00219 } 00220 00221 00222 ////// Generic filesystem operations ////// 00223 00224 // Filesystem implementation (See FATFilySystem.h) 00225 FATFileSystem::FATFileSystem(const char *name, BlockDevice *bd) 00226 : FileSystem(name), _id(-1) { 00227 if (bd) { 00228 mount(bd); 00229 } 00230 } 00231 00232 FATFileSystem::~FATFileSystem() 00233 { 00234 // nop if unmounted 00235 unmount(); 00236 } 00237 00238 int FATFileSystem::mount(BlockDevice *bd) { 00239 // requires duplicate definition to allow virtual overload to work 00240 return mount(bd, false); 00241 } 00242 00243 int FATFileSystem::mount(BlockDevice *bd, bool force) { 00244 lock(); 00245 if (_id != -1) { 00246 unlock(); 00247 return -EINVAL; 00248 } 00249 00250 for (int i = 0; i < _VOLUMES; i++) { 00251 if (!_ffs[i]) { 00252 _id = i; 00253 _ffs[_id] = bd; 00254 _fsid[0] = '0' + _id; 00255 _fsid[1] = '\0'; 00256 debug_if(FFS_DBG, "Mounting [%s] on ffs drive [%s]\n", getName(), _fsid); 00257 FRESULT res = f_mount(&_fs, _fsid, force); 00258 unlock(); 00259 return fat_error_remap(res); 00260 } 00261 } 00262 00263 unlock(); 00264 return -ENOMEM; 00265 } 00266 00267 int FATFileSystem::unmount() 00268 { 00269 lock(); 00270 if (_id == -1) { 00271 unlock(); 00272 return -EINVAL; 00273 } 00274 00275 FRESULT res = f_mount(NULL, _fsid, 0); 00276 _ffs[_id] = NULL; 00277 _id = -1; 00278 unlock(); 00279 return fat_error_remap(res); 00280 } 00281 00282 /* See http://elm-chan.org/fsw/ff/en/mkfs.html for details of f_mkfs() and 00283 * associated arguments. */ 00284 int FATFileSystem::format(BlockDevice *bd, int allocation_unit) { 00285 FATFileSystem fs; 00286 int err = fs.mount(bd, false); 00287 if (err) { 00288 return err; 00289 } 00290 00291 // Logical drive number, Partitioning rule, Allocation unit size (bytes per cluster) 00292 fs.lock(); 00293 FRESULT res = f_mkfs(fs._fsid, 0, allocation_unit); 00294 fs.unlock(); 00295 if (res != FR_OK) { 00296 return fat_error_remap(res); 00297 } 00298 00299 err = fs.unmount(); 00300 if (err) { 00301 return err; 00302 } 00303 00304 return 0; 00305 } 00306 00307 int FATFileSystem::remove(const char *filename) { 00308 lock(); 00309 FRESULT res = f_unlink(filename); 00310 unlock(); 00311 00312 if (res != FR_OK) { 00313 debug_if(FFS_DBG, "f_unlink() failed: %d\n", res); 00314 } 00315 return fat_error_remap(res); 00316 } 00317 00318 int FATFileSystem::rename(const char *oldname, const char *newname) { 00319 lock(); 00320 FRESULT res = f_rename(oldname, newname); 00321 unlock(); 00322 00323 if (res != FR_OK) { 00324 debug_if(FFS_DBG, "f_rename() failed: %d\n", res); 00325 } 00326 return fat_error_remap(res); 00327 } 00328 00329 int FATFileSystem::mkdir(const char *name, mode_t mode) { 00330 lock(); 00331 FRESULT res = f_mkdir(name); 00332 unlock(); 00333 00334 if (res != FR_OK) { 00335 debug_if(FFS_DBG, "f_mkdir() failed: %d\n", res); 00336 } 00337 return fat_error_remap(res); 00338 } 00339 00340 int FATFileSystem::stat(const char *name, struct stat *st) { 00341 lock(); 00342 FILINFO f; 00343 memset(&f, 0, sizeof(f)); 00344 00345 FRESULT res = f_stat(name, &f); 00346 if (res != FR_OK) { 00347 unlock(); 00348 return fat_error_remap(res); 00349 } 00350 00351 /* ARMCC doesnt support stat(), and these symbols are not defined by the toolchain. */ 00352 #ifdef TOOLCHAIN_GCC 00353 st->st_size = f.fsize; 00354 st->st_mode = 0; 00355 st->st_mode |= (f.fattrib & AM_DIR) ? S_IFDIR : S_IFREG; 00356 st->st_mode |= (f.fattrib & AM_RDO) ? 00357 (S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) : 00358 (S_IRWXU | S_IRWXG | S_IRWXO); 00359 #endif /* TOOLCHAIN_GCC */ 00360 unlock(); 00361 00362 return 0; 00363 } 00364 00365 void FATFileSystem::lock() { 00366 _ffs_mutex->lock(); 00367 } 00368 00369 void FATFileSystem::unlock() { 00370 _ffs_mutex->unlock(); 00371 } 00372 00373 00374 ////// File operations ////// 00375 int FATFileSystem::file_open(fs_file_t *file, const char *path, int flags) { 00376 debug_if(FFS_DBG, "open(%s) on filesystem [%s], drv [%s]\n", path, getName(), _fsid); 00377 00378 FIL *fh = new FIL; 00379 char *buffer = new char[strlen(_fsid) + strlen(path) + 3]; 00380 sprintf(buffer, "%s:/%s", _fsid, path); 00381 00382 /* POSIX flags -> FatFS open mode */ 00383 BYTE openmode; 00384 if (flags & O_RDWR) { 00385 openmode = FA_READ | FA_WRITE; 00386 } else if (flags & O_WRONLY) { 00387 openmode = FA_WRITE; 00388 } else { 00389 openmode = FA_READ; 00390 } 00391 if (flags & O_CREAT) { 00392 if (flags & O_TRUNC) { 00393 openmode |= FA_CREATE_ALWAYS; 00394 } else { 00395 openmode |= FA_OPEN_ALWAYS; 00396 } 00397 } 00398 00399 lock(); 00400 FRESULT res = f_open(fh, buffer, openmode); 00401 00402 if (res != FR_OK) { 00403 unlock(); 00404 debug_if(FFS_DBG, "f_open('w') failed: %d\n", res); 00405 delete[] buffer; 00406 delete fh; 00407 return fat_error_remap(res); 00408 } 00409 00410 if (flags & O_APPEND) { 00411 f_lseek(fh, fh->fsize); 00412 } 00413 unlock(); 00414 00415 delete[] buffer; 00416 *file = fh; 00417 return 0; 00418 } 00419 00420 int FATFileSystem::file_close(fs_file_t file) { 00421 FIL *fh = static_cast<FIL*>(file); 00422 00423 lock(); 00424 FRESULT res = f_close(fh); 00425 unlock(); 00426 00427 delete fh; 00428 return fat_error_remap(res); 00429 } 00430 00431 ssize_t FATFileSystem::file_read(fs_file_t file, void *buffer, size_t len) { 00432 FIL *fh = static_cast<FIL*>(file); 00433 00434 lock(); 00435 UINT n; 00436 FRESULT res = f_read(fh, buffer, len, &n); 00437 unlock(); 00438 00439 if (res != FR_OK) { 00440 debug_if(FFS_DBG, "f_read() failed: %d\n", res); 00441 return fat_error_remap(res); 00442 } else { 00443 return n; 00444 } 00445 } 00446 00447 ssize_t FATFileSystem::file_write(fs_file_t file, const void *buffer, size_t len) { 00448 FIL *fh = static_cast<FIL*>(file); 00449 00450 lock(); 00451 UINT n; 00452 FRESULT res = f_write(fh, buffer, len, &n); 00453 unlock(); 00454 00455 if (res != FR_OK) { 00456 debug_if(FFS_DBG, "f_write() failed: %d", res); 00457 return fat_error_remap(res); 00458 } else { 00459 return n; 00460 } 00461 } 00462 00463 int FATFileSystem::file_sync(fs_file_t file) { 00464 FIL *fh = static_cast<FIL*>(file); 00465 00466 lock(); 00467 FRESULT res = f_sync(fh); 00468 unlock(); 00469 00470 if (res != FR_OK) { 00471 debug_if(FFS_DBG, "f_sync() failed: %d\n", res); 00472 } 00473 return fat_error_remap(res); 00474 } 00475 00476 off_t FATFileSystem::file_seek(fs_file_t file, off_t offset, int whence) { 00477 FIL *fh = static_cast<FIL*>(file); 00478 00479 lock(); 00480 if (whence == SEEK_END) { 00481 offset += fh->fsize; 00482 } else if(whence==SEEK_CUR) { 00483 offset += fh->fptr; 00484 } 00485 00486 FRESULT res = f_lseek(fh, offset); 00487 off_t noffset = fh->fptr; 00488 unlock(); 00489 00490 if (res != FR_OK) { 00491 debug_if(FFS_DBG, "lseek failed: %d\n", res); 00492 return fat_error_remap(res); 00493 } else { 00494 return noffset; 00495 } 00496 } 00497 00498 off_t FATFileSystem::file_tell(fs_file_t file) { 00499 FIL *fh = static_cast<FIL*>(file); 00500 00501 lock(); 00502 off_t res = fh->fptr; 00503 unlock(); 00504 00505 return res; 00506 } 00507 00508 size_t FATFileSystem::file_size(fs_file_t file) { 00509 FIL *fh = static_cast<FIL*>(file); 00510 00511 lock(); 00512 size_t res = fh->fsize; 00513 unlock(); 00514 00515 return res; 00516 } 00517 00518 00519 ////// Dir operations ////// 00520 int FATFileSystem::dir_open(fs_dir_t *dir, const char *path) { 00521 FATFS_DIR *dh = new FATFS_DIR; 00522 00523 lock(); 00524 FRESULT res = f_opendir(dh, path); 00525 unlock(); 00526 00527 if (res != FR_OK) { 00528 debug_if(FFS_DBG, "f_opendir() failed: %d\n", res); 00529 delete dh; 00530 return fat_error_remap(res); 00531 } 00532 00533 *dir = dh; 00534 return 0; 00535 } 00536 00537 int FATFileSystem::dir_close(fs_dir_t dir) { 00538 FATFS_DIR *dh = static_cast<FATFS_DIR*>(dir); 00539 00540 lock(); 00541 FRESULT res = f_closedir(dh); 00542 unlock(); 00543 00544 delete dh; 00545 return fat_error_remap(res); 00546 } 00547 00548 ssize_t FATFileSystem::dir_read(fs_dir_t dir, struct dirent *ent) { 00549 FATFS_DIR *dh = static_cast<FATFS_DIR*>(dir); 00550 FILINFO finfo; 00551 00552 #if _USE_LFN 00553 finfo.lfname = ent->d_name; 00554 finfo.lfsize = NAME_MAX; 00555 #endif // _USE_LFN 00556 00557 lock(); 00558 FRESULT res = f_readdir(dh, &finfo); 00559 unlock(); 00560 00561 if (res != FR_OK) { 00562 return fat_error_remap(res); 00563 } else if (finfo.fname[0] == 0) { 00564 return 0; 00565 } 00566 00567 ent->d_type = (finfo.fattrib & AM_DIR) ? DT_DIR : DT_REG; 00568 00569 #if _USE_LFN 00570 if (ent->d_name[0] == 0) { 00571 // No long filename so use short filename. 00572 strncpy(ent->d_name, finfo.fname, NAME_MAX); 00573 } 00574 #else 00575 strncpy(end->d_name, finfo.fname, len); 00576 #endif 00577 00578 return 1; 00579 } 00580 00581 void FATFileSystem::dir_seek(fs_dir_t dir, off_t offset) { 00582 FATFS_DIR *dh = static_cast<FATFS_DIR*>(dir); 00583 00584 lock(); 00585 dh->index = offset; 00586 unlock(); 00587 } 00588 00589 off_t FATFileSystem::dir_tell(fs_dir_t dir) { 00590 FATFS_DIR *dh = static_cast<FATFS_DIR*>(dir); 00591 00592 lock(); 00593 off_t offset = dh->index; 00594 unlock(); 00595 00596 return offset; 00597 } 00598 00599 void FATFileSystem::dir_rewind(fs_dir_t dir) { 00600 FATFS_DIR *dh = static_cast<FATFS_DIR*>(dir); 00601 00602 lock(); 00603 dh->index = 0; 00604 unlock(); 00605 } 00606
Generated on Tue Jul 12 2022 11:02:24 by
1.7.2