Gleb Klochkov / Mbed OS Climatcontroll_Main

Dependencies:   esp8266-driver

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