Kenji Arai / TYBLE16_mbedlized_os5_several_examples_1st

Dependencies:   nRF51_Vdd TextLCD BME280

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 "diskio.h"
00023 #include "ffconf.h"
00024 #include "platform/mbed_debug.h"
00025 #include "platform/mbed_critical.h"
00026 #include "filesystem/mbed_filesystem.h"
00027 #include "FATFileSystem.h"
00028 
00029 #include <errno.h>
00030 ////// Error handling /////
00031 
00032 using namespace mbed;
00033 
00034 static int fat_error_remap(FRESULT res)
00035 {
00036     switch(res) {
00037         case FR_OK:                   // (0) Succeeded
00038             return 0;
00039         case FR_DISK_ERR:             // (1) A hard error occurred in the low level disk I/O layer
00040             return -EIO;
00041         case FR_INT_ERR:              // (2) Assertion failed
00042             return -1;
00043         case FR_NOT_READY:            // (3) The physical drive cannot work
00044             return -EIO;
00045         case FR_NO_FILE:              // (4) Could not find the file
00046             return -ENOENT;
00047         case FR_NO_PATH:              // (5) Could not find the path
00048             return -ENOTDIR;
00049         case FR_INVALID_NAME:         // (6) The path name format is invalid
00050             return -EINVAL;
00051         case FR_DENIED:               // (7) Access denied due to prohibited access or directory full
00052             return -EACCES;
00053         case FR_EXIST:                // (8) Access denied due to prohibited access
00054             return -EEXIST;
00055         case FR_INVALID_OBJECT:       // (9) The file/directory object is invalid
00056             return -EBADF;
00057         case FR_WRITE_PROTECTED:      // (10) The physical drive is write protected
00058             return -EACCES;
00059         case FR_INVALID_DRIVE:        // (11) The logical drive number is invalid
00060             return -ENODEV;
00061         case FR_NOT_ENABLED:          // (12) The volume has no work area
00062             return -ENODEV;
00063         case FR_NO_FILESYSTEM:        // (13) There is no valid FAT volume
00064             return -EINVAL;
00065         case FR_MKFS_ABORTED:         // (14) The f_mkfs() aborted due to any problem
00066             return -EIO;
00067         case FR_TIMEOUT:              // (15) Could not get a grant to access the volume within defined period
00068             return -ETIMEDOUT;
00069         case FR_LOCKED:               // (16) The operation is rejected according to the file sharing policy
00070             return -EBUSY;
00071         case FR_NOT_ENOUGH_CORE:      // (17) LFN working buffer could not be allocated
00072             return -ENOMEM;
00073         case FR_TOO_MANY_OPEN_FILES:  // (18) Number of open files > FF_FS_LOCK
00074             return -ENFILE;
00075         case FR_INVALID_PARAMETER:    // (19) Given parameter is invalid
00076             return -EINVAL;
00077         default:
00078             return -res;
00079     }
00080 }
00081 
00082 // Helper class for deferring operations when variable falls out of scope
00083 template <typename T>
00084 class Deferred {
00085 public:
00086     T _t;
00087     Callback<void(T)> _ondefer;
00088 
00089     Deferred(const Deferred&);
00090     Deferred &operator=(const Deferred&);
00091 
00092 public:
00093     Deferred(T t, Callback<void(T)> ondefer = NULL)
00094         : _t(t), _ondefer(ondefer)
00095     {
00096     }
00097 
00098     operator T()
00099     {
00100         return _t;
00101     }
00102 
00103     ~Deferred()
00104     {
00105         if (_ondefer) {
00106             _ondefer(_t);
00107         }
00108     }
00109 };
00110 
00111 static void dodelete(const char *data)
00112 {
00113     delete[] data;
00114 }
00115 
00116 // Adds prefix needed internally by fatfs, this can be avoided for the first fatfs
00117 // (id 0) otherwise a prefix of "id:/" is inserted in front of the string.
00118 static Deferred<const char*> fat_path_prefix(int id, const char *path)
00119 {
00120     // We can avoid dynamic allocation when only on fatfs is in use
00121     if (id == 0) {
00122         return path;
00123     }
00124 
00125     // Prefix path with id, will look something like 2:/hi/hello/filehere.txt
00126     char *buffer = new char[strlen("0:/") + strlen(path) + 1];
00127     if (!buffer) {
00128         return NULL;
00129     }
00130 
00131     buffer[0] = '0' + id;
00132     buffer[1] = ':';
00133     buffer[2] = '/';
00134     strcpy(buffer + strlen("0:/"), path);
00135     return Deferred<const char*>(buffer, dodelete);
00136 }
00137 
00138 
00139 ////// Disk operations //////
00140 
00141 // Global access to block device from FAT driver
00142 static BlockDevice *_ffs[FF_VOLUMES] = {0};
00143 static SingletonPtr<PlatformMutex>  _ffs_mutex;
00144 
00145 
00146 // FAT driver functions
00147 DWORD get_fattime(void)
00148 {
00149     time_t rawtime;
00150     time(&rawtime);
00151     struct tm *ptm = localtime(&rawtime);
00152     return (DWORD)(ptm->tm_year - 80) << 25
00153            | (DWORD)(ptm->tm_mon + 1  ) << 21
00154            | (DWORD)(ptm->tm_mday     ) << 16
00155            | (DWORD)(ptm->tm_hour     ) << 11
00156            | (DWORD)(ptm->tm_min      ) << 5
00157            | (DWORD)(ptm->tm_sec/2    );
00158 }
00159 
00160 void *ff_memalloc(UINT size)
00161 {
00162     return malloc(size);
00163 }
00164 
00165 void ff_memfree(void *p)
00166 {
00167     free(p);
00168 }
00169 
00170 // Implementation of diskio functions (see ChaN/diskio.h)
00171 static WORD disk_get_sector_size(BYTE pdrv)
00172 {
00173     bd_size_t sector_size = _ffs[pdrv]->get_erase_size();
00174     MBED_ASSERT(sector_size <= WORD(-1));
00175 
00176     WORD ssize = sector_size;
00177     if (ssize < 512) {
00178         ssize = 512;
00179     }
00180 
00181     MBED_ASSERT(ssize >= FF_MIN_SS && ssize <= FF_MAX_SS);
00182     MBED_ASSERT(_ffs[pdrv]->get_read_size() <= _ffs[pdrv]->get_erase_size());
00183     MBED_ASSERT(_ffs[pdrv]->get_program_size() <= _ffs[pdrv]->get_erase_size());
00184     return ssize;
00185 }
00186 
00187 static DWORD disk_get_sector_count(BYTE pdrv)
00188 {
00189     DWORD scount = _ffs[pdrv]->size() / disk_get_sector_size(pdrv);
00190     MBED_ASSERT(scount >= 64);
00191     return scount;
00192 }
00193 
00194 DSTATUS disk_status(BYTE pdrv)
00195 {
00196     debug_if(FFS_DBG, "disk_status on pdrv [%d]\n", pdrv);
00197     return RES_OK;
00198 }
00199 
00200 DSTATUS disk_initialize(BYTE pdrv)
00201 {
00202     debug_if(FFS_DBG, "disk_initialize on pdrv [%d]\n", pdrv);
00203     return (DSTATUS)_ffs[pdrv]->init();
00204 }
00205 
00206 DRESULT disk_read(BYTE pdrv, BYTE *buff, DWORD sector, UINT count)
00207 {
00208     debug_if(FFS_DBG, "disk_read(sector %d, count %d) on pdrv [%d]\n", sector, count, pdrv);
00209     DWORD ssize = disk_get_sector_size(pdrv);
00210     bd_addr_t addr = (bd_addr_t)sector*ssize;
00211     bd_size_t size = (bd_size_t)count*ssize;
00212     int err = _ffs[pdrv]->read(buff, addr, size);
00213     return err ? RES_PARERR : RES_OK;
00214 }
00215 
00216 DRESULT disk_write(BYTE pdrv, const BYTE *buff, DWORD sector, UINT count)
00217 {
00218     debug_if(FFS_DBG, "disk_write(sector %d, count %d) on pdrv [%d]\n", sector, count, pdrv);
00219     DWORD ssize = disk_get_sector_size(pdrv);
00220     bd_addr_t addr = (bd_addr_t)sector*ssize;
00221     bd_size_t size = (bd_size_t)count*ssize;
00222     int err = _ffs[pdrv]->erase(addr, size);
00223     if (err) {
00224         return RES_PARERR;
00225     }
00226 
00227     err = _ffs[pdrv]->program(buff, addr, size);
00228     if (err) {
00229         return RES_PARERR;
00230     }
00231 
00232     return RES_OK;
00233 }
00234 
00235 DRESULT disk_ioctl(BYTE pdrv, BYTE cmd, void *buff)
00236 {
00237     debug_if(FFS_DBG, "disk_ioctl(%d)\n", cmd);
00238     switch (cmd) {
00239         case CTRL_SYNC:
00240             if (_ffs[pdrv] == NULL) {
00241                 return RES_NOTRDY;
00242             } else {
00243                 return RES_OK;
00244             }
00245         case GET_SECTOR_COUNT:
00246             if (_ffs[pdrv] == NULL) {
00247                 return RES_NOTRDY;
00248             } else {
00249                 *((DWORD*)buff) = disk_get_sector_count(pdrv);
00250                 return RES_OK;
00251             }
00252         case GET_SECTOR_SIZE:
00253             if (_ffs[pdrv] == NULL) {
00254                 return RES_NOTRDY;
00255             } else {
00256                 *((WORD*)buff) = disk_get_sector_size(pdrv);
00257                 return RES_OK;
00258             }
00259         case GET_BLOCK_SIZE:
00260             *((DWORD*)buff) = 1; // default when not known
00261             return RES_OK;
00262         case CTRL_TRIM:
00263             if (_ffs[pdrv] == NULL) {
00264                 return RES_NOTRDY;
00265             } else {
00266                 DWORD *sectors = (DWORD*)buff;
00267                 DWORD ssize = disk_get_sector_size(pdrv);
00268                 bd_addr_t addr = (bd_addr_t)sectors[0]*ssize;
00269                 bd_size_t size = (bd_size_t)(sectors[1]-sectors[0]+1)*ssize;
00270                 int err = _ffs[pdrv]->trim(addr, size);
00271                 return err ? RES_PARERR : RES_OK;
00272             }
00273     }
00274 
00275     return RES_PARERR;
00276 }
00277 
00278 
00279 ////// Generic filesystem operations //////
00280 
00281 // Filesystem implementation (See FATFilySystem.h)
00282 FATFileSystem::FATFileSystem(const char *name, BlockDevice *bd)
00283         : FileSystem(name), _id(-1) {
00284     if (bd) {
00285         mount(bd);
00286     }
00287 }
00288 
00289 FATFileSystem::~FATFileSystem()
00290 {
00291     // nop if unmounted
00292     unmount();
00293 }
00294 
00295 int FATFileSystem::mount(BlockDevice *bd)
00296 {
00297     // requires duplicate definition to allow virtual overload to work
00298     return mount(bd, true);
00299 }
00300 
00301 int FATFileSystem::mount(BlockDevice *bd, bool mount)
00302 {
00303     lock();
00304     if (_id != -1) {
00305         unlock();
00306         return -EINVAL;
00307     }
00308 
00309     for (int i = 0; i < FF_VOLUMES; i++) {
00310         if (!_ffs[i]) {
00311             _id = i;
00312             _ffs[_id] = bd;
00313             _fsid[0] = '0' + _id;
00314             _fsid[1] = ':';
00315             _fsid[2] = '\0';
00316             debug_if(FFS_DBG, "Mounting [%s] on ffs drive [%s]\n", getName(), _fsid);
00317             FRESULT res = f_mount(&_fs, _fsid, mount);
00318             unlock();
00319             return fat_error_remap(res);
00320         }
00321     }
00322 
00323     unlock();
00324     return -ENOMEM;
00325 }
00326 
00327 int FATFileSystem::unmount()
00328 {
00329     lock();
00330     if (_id == -1) {
00331         unlock();
00332         return -EINVAL;
00333     }
00334 
00335     FRESULT res = f_mount(NULL, _fsid, 0);
00336     _ffs[_id] = NULL;
00337     _id = -1;
00338     unlock();
00339     return fat_error_remap(res);
00340 }
00341 
00342 /* See http://elm-chan.org/fsw/ff/en/mkfs.html for details of f_mkfs() and
00343  * associated arguments. */
00344 int FATFileSystem::format(BlockDevice *bd, bd_size_t cluster_size)
00345 {
00346     FATFileSystem fs;
00347     fs.lock();
00348 
00349     int err = bd->init();
00350     if (err) {
00351         fs.unlock();
00352         return err;
00353     }
00354 
00355     // erase first handful of blocks
00356     bd_size_t header = 2*bd->get_erase_size();
00357     err = bd->erase(0, header);
00358     if (err) {
00359         bd->deinit();
00360         fs.unlock();
00361         return err;
00362     }
00363 
00364     if (bd->get_erase_value() < 0) {
00365         // erase is unknown, need to write 1s
00366         bd_size_t program_size = bd->get_program_size();
00367         void *buf = malloc(program_size);
00368         if (!buf) {
00369             bd->deinit();
00370             fs.unlock();
00371             return -ENOMEM;
00372         }
00373 
00374         memset(buf, 0xff, program_size);
00375 
00376         for (bd_addr_t i = 0; i < header; i += program_size) {
00377             err = bd->program(buf, i, program_size);
00378             if (err) {
00379                 free(buf);
00380                 bd->deinit();
00381                 fs.unlock();
00382                 return err;
00383             }
00384         }
00385 
00386         free(buf);
00387     }
00388 
00389     // trim entire device to indicate it is unneeded
00390     err = bd->trim(0, bd->size());
00391     if (err) {
00392         bd->deinit();
00393         fs.unlock();
00394         return err;
00395     }
00396 
00397     err = bd->deinit();
00398     if (err) {
00399         fs.unlock();
00400         return err;
00401     }
00402 
00403     err = fs.mount(bd, false);
00404     if (err) {
00405         fs.unlock();
00406         return err;
00407     }
00408 
00409     // Logical drive number, Partitioning rule, Allocation unit size (bytes per cluster)
00410     FRESULT res = f_mkfs(fs._fsid, FM_ANY | FM_SFD, cluster_size, NULL, 0);
00411     if (res != FR_OK) {
00412         fs.unmount();
00413         fs.unlock();
00414         return fat_error_remap(res);
00415     }
00416 
00417     err = fs.unmount();
00418     if (err) {
00419         fs.unlock();
00420         return err;
00421     }
00422 
00423     fs.unlock();
00424     return 0;
00425 }
00426 
00427 int FATFileSystem::reformat(BlockDevice *bd, int allocation_unit)
00428 {
00429     lock();
00430     if (_id != -1) {
00431         if (!bd) {
00432             bd = _ffs[_id];
00433         }
00434 
00435         int err = unmount();
00436         if (err) {
00437             unlock();
00438             return err;
00439         }
00440     }
00441 
00442     if (!bd) {
00443         unlock();
00444         return -ENODEV;
00445     }
00446 
00447     int err = FATFileSystem::format(bd, allocation_unit);
00448     if (err) {
00449         unlock();
00450         return err;
00451     }
00452 
00453     err = mount(bd);
00454     unlock();
00455     return err;
00456 }
00457 
00458 int FATFileSystem::remove(const char *path)
00459 {
00460     Deferred<const char*> fpath = fat_path_prefix(_id, path);
00461 
00462     lock();
00463     FRESULT res = f_unlink(fpath);
00464     unlock();
00465 
00466     if (res != FR_OK) {
00467         debug_if(FFS_DBG, "f_unlink() failed: %d\n", res);
00468         if (res == FR_DENIED) {
00469             return -ENOTEMPTY;
00470         }
00471     }
00472     return fat_error_remap(res);
00473 }
00474 
00475 int FATFileSystem::rename(const char *oldpath, const char *newpath)
00476 {
00477     Deferred<const char*> oldfpath = fat_path_prefix(_id, oldpath);
00478     Deferred<const char*> newfpath = fat_path_prefix(_id, newpath);
00479 
00480     lock();
00481     FRESULT res = f_rename(oldfpath, newfpath);
00482     unlock();
00483 
00484     if (res != FR_OK) {
00485         debug_if(FFS_DBG, "f_rename() failed: %d\n", res);
00486     }
00487     return fat_error_remap(res);
00488 }
00489 
00490 int FATFileSystem::mkdir(const char *path, mode_t mode)
00491 {
00492     Deferred<const char*> fpath = fat_path_prefix(_id, path);
00493 
00494     lock();
00495     FRESULT res = f_mkdir(fpath);
00496     unlock();
00497 
00498     if (res != FR_OK) {
00499         debug_if(FFS_DBG, "f_mkdir() failed: %d\n", res);
00500     }
00501     return fat_error_remap(res);
00502 }
00503 
00504 int FATFileSystem::stat(const char *path, struct stat *st)
00505 {
00506     Deferred<const char*> fpath = fat_path_prefix(_id, path);
00507 
00508     lock();
00509     FILINFO f;
00510     memset(&f, 0, sizeof(f));
00511 
00512     FRESULT res = f_stat(fpath, &f);
00513     if (res != FR_OK) {
00514         unlock();
00515         return fat_error_remap(res);
00516     }
00517 
00518     /* ARMCC doesnt support stat(), and these symbols are not defined by the toolchain. */
00519 #ifdef TOOLCHAIN_GCC
00520     st->st_size = f.fsize;
00521     st->st_mode = 0;
00522     st->st_mode |= (f.fattrib & AM_DIR) ? S_IFDIR : S_IFREG;
00523     st->st_mode |= (f.fattrib & AM_RDO) ?
00524         (S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) :
00525         (S_IRWXU | S_IRWXG | S_IRWXO);
00526 #endif /* TOOLCHAIN_GCC */
00527     unlock();
00528 
00529     return 0;
00530 }
00531 
00532 int FATFileSystem::statvfs(const char *path, struct statvfs *buf)
00533 {
00534 
00535     memset(buf, 0, sizeof(struct statvfs));
00536     FATFS *fs;
00537     DWORD fre_clust;
00538 
00539     lock();
00540     FRESULT res = f_getfree(_fsid, &fre_clust, &fs);
00541     if (res != FR_OK) {
00542         unlock();
00543         return fat_error_remap(res);
00544     }
00545 
00546     buf->f_bsize = fs->ssize;
00547     buf->f_frsize = fs->ssize;
00548     buf->f_blocks = (fs->n_fatent - 2) * fs->csize;
00549     buf->f_bfree = fre_clust * fs->csize;
00550     buf->f_bavail = buf->f_bfree;
00551 #if FF_USE_LFN
00552     buf->f_namemax = FF_LFN_BUF;
00553 #else
00554     buf->f_namemax = FF_SFN_BUF;
00555 #endif
00556 
00557     unlock();
00558     return 0;
00559 }
00560 
00561 void FATFileSystem::lock()
00562 {
00563     _ffs_mutex->lock();
00564 }
00565 
00566 void FATFileSystem::unlock()
00567 {
00568     _ffs_mutex->unlock();
00569 }
00570 
00571 
00572 ////// File operations //////
00573 int FATFileSystem::file_open(fs_file_t *file, const char *path, int flags)
00574 {
00575     debug_if(FFS_DBG, "open(%s) on filesystem [%s], drv [%s]\n", path, getName(), _id);
00576 
00577     FIL *fh = new FIL;
00578     Deferred<const char*> fpath = fat_path_prefix(_id, path);
00579 
00580     /* POSIX flags -> FatFS open mode */
00581     BYTE openmode;
00582     if (flags & O_RDWR) {
00583         openmode = FA_READ | FA_WRITE;
00584     } else if (flags & O_WRONLY) {
00585         openmode = FA_WRITE;
00586     } else {
00587         openmode = FA_READ;
00588     }
00589 
00590     if (flags & O_CREAT) {
00591         if (flags & O_TRUNC) {
00592             openmode |= FA_CREATE_ALWAYS;
00593         } else {
00594             openmode |= FA_OPEN_ALWAYS;
00595         }
00596     }
00597 
00598     if (flags & O_APPEND) {
00599         openmode |= FA_OPEN_APPEND;
00600     }
00601 
00602     lock();
00603     FRESULT res = f_open(fh, fpath, openmode);
00604 
00605     if (res != FR_OK) {
00606         unlock();
00607         debug_if(FFS_DBG, "f_open('w') failed: %d\n", res);
00608         delete fh;
00609         return fat_error_remap(res);
00610     }
00611 
00612     unlock();
00613 
00614     *file = fh;
00615     return 0;
00616 }
00617 
00618 int FATFileSystem::file_close(fs_file_t file)
00619 {
00620     FIL *fh = static_cast<FIL*>(file);
00621 
00622     lock();
00623     FRESULT res = f_close(fh);
00624     unlock();
00625 
00626     delete fh;
00627     return fat_error_remap(res);
00628 }
00629 
00630 ssize_t FATFileSystem::file_read(fs_file_t file, void *buffer, size_t len)
00631 {
00632     FIL *fh = static_cast<FIL*>(file);
00633 
00634     lock();
00635     UINT n;
00636     FRESULT res = f_read(fh, buffer, len, &n);
00637     unlock();
00638 
00639     if (res != FR_OK) {
00640         debug_if(FFS_DBG, "f_read() failed: %d\n", res);
00641         return fat_error_remap(res);
00642     } else {
00643         return n;
00644     }
00645 }
00646 
00647 ssize_t FATFileSystem::file_write(fs_file_t file, const void *buffer, size_t len)
00648 {
00649     FIL *fh = static_cast<FIL*>(file);
00650 
00651     lock();
00652     UINT n;
00653     FRESULT res = f_write(fh, buffer, len, &n);
00654     unlock();
00655 
00656     if (res != FR_OK) {
00657         debug_if(FFS_DBG, "f_write() failed: %d", res);
00658         return fat_error_remap(res);
00659     } else {
00660         return n;
00661     }
00662 }
00663 
00664 int FATFileSystem::file_sync(fs_file_t file)
00665 {
00666     FIL *fh = static_cast<FIL*>(file);
00667 
00668     lock();
00669     FRESULT res = f_sync(fh);
00670     unlock();
00671 
00672     if (res != FR_OK) {
00673         debug_if(FFS_DBG, "f_sync() failed: %d\n", res);
00674     }
00675     return fat_error_remap(res);
00676 }
00677 
00678 off_t FATFileSystem::file_seek(fs_file_t file, off_t offset, int whence)
00679 {
00680     FIL *fh = static_cast<FIL*>(file);
00681 
00682     lock();
00683     if (whence == SEEK_END) {
00684         offset += f_size(fh);
00685     } else if(whence==SEEK_CUR) {
00686         offset += f_tell(fh);
00687     }
00688 
00689     FRESULT res = f_lseek(fh, offset);
00690     off_t noffset = fh->fptr;
00691     unlock();
00692 
00693     if (res != FR_OK) {
00694         debug_if(FFS_DBG, "lseek failed: %d\n", res);
00695         return fat_error_remap(res);
00696     } else {
00697         return noffset;
00698     }
00699 }
00700 
00701 off_t FATFileSystem::file_tell(fs_file_t file)
00702 {
00703     FIL *fh = static_cast<FIL*>(file);
00704 
00705     lock();
00706     off_t res = f_tell(fh);
00707     unlock();
00708 
00709     return res;
00710 }
00711 
00712 off_t FATFileSystem::file_size(fs_file_t file)
00713 {
00714     FIL *fh = static_cast<FIL*>(file);
00715 
00716     lock();
00717     off_t res = f_size(fh);
00718     unlock();
00719 
00720     return res;
00721 }
00722 
00723 
00724 ////// Dir operations //////
00725 int FATFileSystem::dir_open(fs_dir_t *dir, const char *path)
00726 {
00727     FATFS_DIR *dh = new FATFS_DIR;
00728     Deferred<const char*> fpath = fat_path_prefix(_id, path);
00729 
00730     lock();
00731     FRESULT res = f_opendir(dh, fpath);
00732     unlock();
00733 
00734     if (res != FR_OK) {
00735         debug_if(FFS_DBG, "f_opendir() failed: %d\n", res);
00736         delete dh;
00737         return fat_error_remap(res);
00738     }
00739 
00740     *dir = dh;
00741     return 0;
00742 }
00743 
00744 int FATFileSystem::dir_close(fs_dir_t dir)
00745 {
00746     FATFS_DIR *dh = static_cast<FATFS_DIR*>(dir);
00747 
00748     lock();
00749     FRESULT res = f_closedir(dh);
00750     unlock();
00751 
00752     delete dh;
00753     return fat_error_remap(res);
00754 }
00755 
00756 ssize_t FATFileSystem::dir_read(fs_dir_t dir, struct dirent *ent)
00757 {
00758     FATFS_DIR *dh = static_cast<FATFS_DIR*>(dir);
00759     FILINFO finfo;
00760 
00761     lock();
00762     FRESULT res = f_readdir(dh, &finfo);
00763     unlock();
00764 
00765     if (res != FR_OK) {
00766         return fat_error_remap(res);
00767     } else if (finfo.fname[0] == 0) {
00768         return 0;
00769     }
00770 
00771     ent->d_type = (finfo.fattrib & AM_DIR) ? DT_DIR : DT_REG;
00772 
00773 #if FF_USE_LFN
00774     if (ent->d_name[0] == 0) {
00775         // No long filename so use short filename.
00776         strncpy(ent->d_name, finfo.fname, FF_LFN_BUF);
00777     }
00778 #else
00779     strncpy(ent->d_name, finfo.fname, FF_SFN_BUF);
00780 #endif
00781 
00782     return 1;
00783 }
00784 
00785 void FATFileSystem::dir_seek(fs_dir_t dir, off_t offset)
00786 {
00787     FATFS_DIR *dh = static_cast<FATFS_DIR*>(dir);
00788     off_t dptr = static_cast<off_t>(dh->dptr);
00789 
00790     lock();
00791 
00792     if (offset < dptr) {
00793         f_rewinddir(dh);
00794     }
00795     while (dptr < offset) {
00796         FILINFO finfo;
00797         FRESULT res;
00798 
00799         res = f_readdir(dh, &finfo);
00800         dptr = dh->dptr;
00801         if (res != FR_OK) {
00802             break;
00803         } else if (finfo.fname[0] == 0) {
00804             break;
00805         }
00806     }
00807     unlock();
00808 }
00809 
00810 off_t FATFileSystem::dir_tell(fs_dir_t dir)
00811 {
00812     FATFS_DIR *dh = static_cast<FATFS_DIR*>(dir);
00813 
00814     lock();
00815     off_t offset = dh->dptr;
00816     unlock();
00817 
00818     return offset;
00819 }
00820 
00821 void FATFileSystem::dir_rewind(fs_dir_t dir)
00822 {
00823     FATFS_DIR *dh = static_cast<FATFS_DIR*>(dir);
00824 
00825     lock();
00826     f_rewinddir(dh);
00827     unlock();
00828 }
00829