Knight KE / Mbed OS Game_Master
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;
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