Renesas GR-PEACH OpenCV Development / gr-peach-opencv-project-sd-card_update

Fork of gr-peach-opencv-project-sd-card by the do

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 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