takashi kadono / Mbed OS Nucleo_446

Dependencies:   ssd1331

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