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.
Fork of gr-peach-opencv-project-sd-card by
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 void *ff_memalloc(UINT size) 00150 { 00151 return malloc(size); 00152 } 00153 00154 void ff_memfree(void *p) 00155 { 00156 free(p); 00157 } 00158 00159 // Implementation of diskio functions (see ChaN/diskio.h) 00160 DSTATUS disk_status(BYTE pdrv) 00161 { 00162 debug_if(FFS_DBG, "disk_status on pdrv [%d]\n", pdrv); 00163 return RES_OK; 00164 } 00165 00166 DSTATUS disk_initialize(BYTE pdrv) 00167 { 00168 debug_if(FFS_DBG, "disk_initialize on pdrv [%d]\n", pdrv); 00169 return (DSTATUS)_ffs[pdrv]->init(); 00170 } 00171 00172 DRESULT disk_read(BYTE pdrv, BYTE *buff, DWORD sector, UINT count) 00173 { 00174 debug_if(FFS_DBG, "disk_read(sector %d, count %d) on pdrv [%d]\n", sector, count, pdrv); 00175 bd_size_t ssize = _ffs[pdrv]->get_erase_size(); 00176 int err = _ffs[pdrv]->read(buff, sector*ssize, count*ssize); 00177 return err ? RES_PARERR : RES_OK; 00178 } 00179 00180 DRESULT disk_write(BYTE pdrv, const BYTE *buff, DWORD sector, UINT count) 00181 { 00182 debug_if(FFS_DBG, "disk_write(sector %d, count %d) on pdrv [%d]\n", sector, count, pdrv); 00183 bd_size_t ssize = _ffs[pdrv]->get_erase_size(); 00184 int err = _ffs[pdrv]->erase(sector*ssize, count*ssize); 00185 if (err) { 00186 return RES_PARERR; 00187 } 00188 00189 err = _ffs[pdrv]->program(buff, sector*ssize, count*ssize); 00190 if (err) { 00191 return RES_PARERR; 00192 } 00193 00194 return RES_OK; 00195 } 00196 00197 DRESULT disk_ioctl(BYTE pdrv, BYTE cmd, void *buff) 00198 { 00199 debug_if(FFS_DBG, "disk_ioctl(%d)\n", cmd); 00200 switch (cmd) { 00201 case CTRL_SYNC: 00202 if (_ffs[pdrv] == NULL) { 00203 return RES_NOTRDY; 00204 } else { 00205 return RES_OK; 00206 } 00207 case GET_SECTOR_COUNT: 00208 if (_ffs[pdrv] == NULL) { 00209 return RES_NOTRDY; 00210 } else { 00211 DWORD count = _ffs[pdrv]->size() / _ffs[pdrv]->get_erase_size(); 00212 *((DWORD*)buff) = count; 00213 return RES_OK; 00214 } 00215 case GET_SECTOR_SIZE: 00216 if (_ffs[pdrv] == NULL) { 00217 return RES_NOTRDY; 00218 } else { 00219 DWORD size = _ffs[pdrv]->get_erase_size(); 00220 *((DWORD*)buff) = size; 00221 return RES_OK; 00222 } 00223 case GET_BLOCK_SIZE: 00224 *((DWORD*)buff) = 1; // default when not known 00225 return RES_OK; 00226 } 00227 00228 return RES_PARERR; 00229 } 00230 00231 00232 ////// Generic filesystem operations ////// 00233 00234 // Filesystem implementation (See FATFilySystem.h) 00235 FATFileSystem::FATFileSystem(const char *name, BlockDevice *bd) 00236 : FileSystem(name), _id(-1) { 00237 if (bd) { 00238 mount(bd); 00239 } 00240 } 00241 00242 FATFileSystem::~FATFileSystem() 00243 { 00244 // nop if unmounted 00245 unmount(); 00246 } 00247 00248 int FATFileSystem::mount(BlockDevice *bd) { 00249 // requires duplicate definition to allow virtual overload to work 00250 return mount(bd, false); 00251 } 00252 00253 int FATFileSystem::mount(BlockDevice *bd, bool force) { 00254 lock(); 00255 if (_id != -1) { 00256 unlock(); 00257 return -EINVAL; 00258 } 00259 00260 for (int i = 0; i < _VOLUMES; i++) { 00261 if (!_ffs[i]) { 00262 _id = i; 00263 _ffs[_id] = bd; 00264 _fsid[0] = '0' + _id; 00265 _fsid[1] = ':'; 00266 _fsid[2] = '\0'; 00267 debug_if(FFS_DBG, "Mounting [%s] on ffs drive [%s]\n", getName(), _fsid); 00268 FRESULT res = f_mount(&_fs, _fsid, force); 00269 unlock(); 00270 return fat_error_remap(res); 00271 } 00272 } 00273 00274 unlock(); 00275 return -ENOMEM; 00276 } 00277 00278 int FATFileSystem::unmount() 00279 { 00280 lock(); 00281 if (_id == -1) { 00282 unlock(); 00283 return -EINVAL; 00284 } 00285 00286 FRESULT res = f_mount(NULL, _fsid, 0); 00287 _ffs[_id] = NULL; 00288 _id = -1; 00289 unlock(); 00290 return fat_error_remap(res); 00291 } 00292 00293 /* See http://elm-chan.org/fsw/ff/en/mkfs.html for details of f_mkfs() and 00294 * associated arguments. */ 00295 int FATFileSystem::format(BlockDevice *bd, int allocation_unit) { 00296 FATFileSystem fs; 00297 int err = fs.mount(bd, false); 00298 if (err) { 00299 return err; 00300 } 00301 00302 // Logical drive number, Partitioning rule, Allocation unit size (bytes per cluster) 00303 fs.lock(); 00304 FRESULT res = f_mkfs(fs._fsid, 1, allocation_unit); 00305 fs.unlock(); 00306 if (res != FR_OK) { 00307 return fat_error_remap(res); 00308 } 00309 00310 err = fs.unmount(); 00311 if (err) { 00312 return err; 00313 } 00314 00315 return 0; 00316 } 00317 00318 int FATFileSystem::remove(const char *filename) { 00319 lock(); 00320 FRESULT res = f_unlink(filename); 00321 unlock(); 00322 00323 if (res != FR_OK) { 00324 debug_if(FFS_DBG, "f_unlink() failed: %d\n", res); 00325 } 00326 return fat_error_remap(res); 00327 } 00328 00329 int FATFileSystem::rename(const char *oldname, const char *newname) { 00330 lock(); 00331 FRESULT res = f_rename(oldname, newname); 00332 unlock(); 00333 00334 if (res != FR_OK) { 00335 debug_if(FFS_DBG, "f_rename() failed: %d\n", res); 00336 } 00337 return fat_error_remap(res); 00338 } 00339 00340 int FATFileSystem::mkdir(const char *name, mode_t mode) { 00341 lock(); 00342 FRESULT res = f_mkdir(name); 00343 unlock(); 00344 00345 if (res != FR_OK) { 00346 debug_if(FFS_DBG, "f_mkdir() failed: %d\n", res); 00347 } 00348 return fat_error_remap(res); 00349 } 00350 00351 int FATFileSystem::stat(const char *name, struct stat *st) { 00352 lock(); 00353 FILINFO f; 00354 memset(&f, 0, sizeof(f)); 00355 00356 FRESULT res = f_stat(name, &f); 00357 if (res != FR_OK) { 00358 unlock(); 00359 return fat_error_remap(res); 00360 } 00361 00362 /* ARMCC doesnt support stat(), and these symbols are not defined by the toolchain. */ 00363 #ifdef TOOLCHAIN_GCC 00364 st->st_size = f.fsize; 00365 st->st_mode = 0; 00366 st->st_mode |= (f.fattrib & AM_DIR) ? S_IFDIR : S_IFREG; 00367 st->st_mode |= (f.fattrib & AM_RDO) ? 00368 (S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) : 00369 (S_IRWXU | S_IRWXG | S_IRWXO); 00370 #endif /* TOOLCHAIN_GCC */ 00371 unlock(); 00372 00373 return 0; 00374 } 00375 00376 void FATFileSystem::lock() { 00377 _ffs_mutex->lock(); 00378 } 00379 00380 void FATFileSystem::unlock() { 00381 _ffs_mutex->unlock(); 00382 } 00383 00384 00385 ////// File operations ////// 00386 int FATFileSystem::file_open(fs_file_t *file, const char *path, int flags) { 00387 debug_if(FFS_DBG, "open(%s) on filesystem [%s], drv [%s]\n", path, getName(), _fsid); 00388 00389 FIL *fh = new FIL; 00390 char *buffer = new char[strlen(_fsid) + strlen(path) + 3]; 00391 strcpy(buffer, _fsid); 00392 strcat(buffer, "/"); 00393 strcat(buffer, path); 00394 00395 /* POSIX flags -> FatFS open mode */ 00396 BYTE openmode; 00397 if (flags & O_RDWR) { 00398 openmode = FA_READ | FA_WRITE; 00399 } else if (flags & O_WRONLY) { 00400 openmode = FA_WRITE; 00401 } else { 00402 openmode = FA_READ; 00403 } 00404 if (flags & O_CREAT) { 00405 if (flags & O_TRUNC) { 00406 openmode |= FA_CREATE_ALWAYS; 00407 } else { 00408 openmode |= FA_OPEN_ALWAYS; 00409 } 00410 } 00411 00412 lock(); 00413 FRESULT res = f_open(fh, buffer, openmode); 00414 00415 if (res != FR_OK) { 00416 unlock(); 00417 debug_if(FFS_DBG, "f_open('w') failed: %d\n", res); 00418 delete[] buffer; 00419 delete fh; 00420 return fat_error_remap(res); 00421 } 00422 00423 if (flags & O_APPEND) { 00424 f_lseek(fh, fh->fsize); 00425 } 00426 unlock(); 00427 00428 delete[] buffer; 00429 *file = fh; 00430 return 0; 00431 } 00432 00433 int FATFileSystem::file_close(fs_file_t file) { 00434 FIL *fh = static_cast<FIL*>(file); 00435 00436 lock(); 00437 FRESULT res = f_close(fh); 00438 unlock(); 00439 00440 delete fh; 00441 return fat_error_remap(res); 00442 } 00443 00444 ssize_t FATFileSystem::file_read(fs_file_t file, void *buffer, size_t len) { 00445 FIL *fh = static_cast<FIL*>(file); 00446 00447 lock(); 00448 UINT n; 00449 FRESULT res = f_read(fh, buffer, len, &n); 00450 unlock(); 00451 00452 if (res != FR_OK) { 00453 debug_if(FFS_DBG, "f_read() failed: %d\n", res); 00454 return fat_error_remap(res); 00455 } else { 00456 return n; 00457 } 00458 } 00459 00460 ssize_t FATFileSystem::file_write(fs_file_t file, const void *buffer, size_t len) { 00461 FIL *fh = static_cast<FIL*>(file); 00462 00463 lock(); 00464 UINT n; 00465 FRESULT res = f_write(fh, buffer, len, &n); 00466 unlock(); 00467 00468 if (res != FR_OK) { 00469 debug_if(FFS_DBG, "f_write() failed: %d", res); 00470 return fat_error_remap(res); 00471 } else { 00472 return n; 00473 } 00474 } 00475 00476 int FATFileSystem::file_sync(fs_file_t file) { 00477 FIL *fh = static_cast<FIL*>(file); 00478 00479 lock(); 00480 FRESULT res = f_sync(fh); 00481 unlock(); 00482 00483 if (res != FR_OK) { 00484 debug_if(FFS_DBG, "f_sync() failed: %d\n", res); 00485 } 00486 return fat_error_remap(res); 00487 } 00488 00489 off_t FATFileSystem::file_seek(fs_file_t file, off_t offset, int whence) { 00490 FIL *fh = static_cast<FIL*>(file); 00491 00492 lock(); 00493 if (whence == SEEK_END) { 00494 offset += fh->fsize; 00495 } else if(whence==SEEK_CUR) { 00496 offset += fh->fptr; 00497 } 00498 00499 FRESULT res = f_lseek(fh, offset); 00500 off_t noffset = fh->fptr; 00501 unlock(); 00502 00503 if (res != FR_OK) { 00504 debug_if(FFS_DBG, "lseek failed: %d\n", res); 00505 return fat_error_remap(res); 00506 } else { 00507 return noffset; 00508 } 00509 } 00510 00511 off_t FATFileSystem::file_tell(fs_file_t file) { 00512 FIL *fh = static_cast<FIL*>(file); 00513 00514 lock(); 00515 off_t res = fh->fptr; 00516 unlock(); 00517 00518 return res; 00519 } 00520 00521 off_t FATFileSystem::file_size(fs_file_t file) { 00522 FIL *fh = static_cast<FIL*>(file); 00523 00524 lock(); 00525 off_t res = fh->fsize; 00526 unlock(); 00527 00528 return res; 00529 } 00530 00531 00532 ////// Dir operations ////// 00533 int FATFileSystem::dir_open(fs_dir_t *dir, const char *path) { 00534 FATFS_DIR *dh = new FATFS_DIR; 00535 00536 lock(); 00537 FRESULT res = f_opendir(dh, path); 00538 unlock(); 00539 00540 if (res != FR_OK) { 00541 debug_if(FFS_DBG, "f_opendir() failed: %d\n", res); 00542 delete dh; 00543 return fat_error_remap(res); 00544 } 00545 00546 *dir = dh; 00547 return 0; 00548 } 00549 00550 int FATFileSystem::dir_close(fs_dir_t dir) { 00551 FATFS_DIR *dh = static_cast<FATFS_DIR*>(dir); 00552 00553 lock(); 00554 FRESULT res = f_closedir(dh); 00555 unlock(); 00556 00557 delete dh; 00558 return fat_error_remap(res); 00559 } 00560 00561 ssize_t FATFileSystem::dir_read(fs_dir_t dir, struct dirent *ent) { 00562 FATFS_DIR *dh = static_cast<FATFS_DIR*>(dir); 00563 FILINFO finfo; 00564 00565 #if _USE_LFN 00566 finfo.lfname = ent->d_name; 00567 finfo.lfsize = NAME_MAX; 00568 #endif // _USE_LFN 00569 00570 lock(); 00571 FRESULT res = f_readdir(dh, &finfo); 00572 unlock(); 00573 00574 if (res != FR_OK) { 00575 return fat_error_remap(res); 00576 } else if (finfo.fname[0] == 0) { 00577 return 0; 00578 } 00579 00580 ent->d_type = (finfo.fattrib & AM_DIR) ? DT_DIR : DT_REG; 00581 00582 #if _USE_LFN 00583 if (ent->d_name[0] == 0) { 00584 // No long filename so use short filename. 00585 strncpy(ent->d_name, finfo.fname, NAME_MAX); 00586 } 00587 #else 00588 strncpy(end->d_name, finfo.fname, len); 00589 #endif 00590 00591 return 1; 00592 } 00593 00594 void FATFileSystem::dir_seek(fs_dir_t dir, off_t offset) { 00595 FATFS_DIR *dh = static_cast<FATFS_DIR*>(dir); 00596 00597 lock(); 00598 dh->index = offset; 00599 unlock(); 00600 } 00601 00602 off_t FATFileSystem::dir_tell(fs_dir_t dir) { 00603 FATFS_DIR *dh = static_cast<FATFS_DIR*>(dir); 00604 00605 lock(); 00606 off_t offset = dh->index; 00607 unlock(); 00608 00609 return offset; 00610 } 00611 00612 void FATFileSystem::dir_rewind(fs_dir_t dir) { 00613 FATFS_DIR *dh = static_cast<FATFS_DIR*>(dir); 00614 00615 lock(); 00616 dh->index = 0; 00617 unlock(); 00618 } 00619 00620
Generated on Tue Jul 12 2022 14:46:36 by
