Daiki Kato / mbed-os-lychee

Dependents:   mbed-os-example-blinky-gr-lychee GR-Boads_Camera_sample GR-Boards_Audio_Recoder GR-Boads_Camera_DisplayApp ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers FATFileSystem.cpp Source File

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