Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

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-2019 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 "features/storage/filesystem/fat/ChaN/diskio.h"
00023 #include "features/storage/filesystem/fat/ChaN/ffconf.h"
00024 #include "features/storage/filesystem/fat/ChaN/ff.h"
00025 #include "platform/mbed_debug.h"
00026 #include "platform/mbed_critical.h"
00027 #include "features/storage/filesystem/mbed_filesystem.h"
00028 #include "FATFileSystem.h"
00029 
00030 #include <errno.h>
00031 #include <stdlib.h>
00032 
00033 namespace mbed {
00034 
00035 using namespace mbed;
00036 
00037 static int fat_error_remap(FRESULT res)
00038 {
00039     switch (res) {
00040         case FR_OK:                   // (0) Succeeded
00041             return 0;
00042         case FR_DISK_ERR:             // (1) A hard error occurred in the low level disk I/O layer
00043             return -EIO;
00044         case FR_INT_ERR:              // (2) Assertion failed
00045             return -1;
00046         case FR_NOT_READY:            // (3) The physical drive cannot work
00047             return -EIO;
00048         case FR_NO_FILE:              // (4) Could not find the file
00049             return -ENOENT;
00050         case FR_NO_PATH:              // (5) Could not find the path
00051             return -ENOTDIR;
00052         case FR_INVALID_NAME:         // (6) The path name format is invalid
00053             return -EINVAL;
00054         case FR_DENIED:               // (7) Access denied due to prohibited access or directory full
00055             return -EACCES;
00056         case FR_EXIST:                // (8) Access denied due to prohibited access
00057             return -EEXIST;
00058         case FR_INVALID_OBJECT:       // (9) The file/directory object is invalid
00059             return -EBADF;
00060         case FR_WRITE_PROTECTED:      // (10) The physical drive is write protected
00061             return -EACCES;
00062         case FR_INVALID_DRIVE:        // (11) The logical drive number is invalid
00063             return -ENODEV;
00064         case FR_NOT_ENABLED:          // (12) The volume has no work area
00065             return -ENODEV;
00066         case FR_NO_FILESYSTEM:        // (13) There is no valid FAT volume
00067             return -EINVAL;
00068         case FR_MKFS_ABORTED:         // (14) The f_mkfs() aborted due to any problem
00069             return -EIO;
00070         case FR_TIMEOUT:              // (15) Could not get a grant to access the volume within defined period
00071             return -ETIMEDOUT;
00072         case FR_LOCKED:               // (16) The operation is rejected according to the file sharing policy
00073             return -EBUSY;
00074         case FR_NOT_ENOUGH_CORE:      // (17) LFN working buffer could not be allocated
00075             return -ENOMEM;
00076         case FR_TOO_MANY_OPEN_FILES:  // (18) Number of open files > FF_FS_LOCK
00077             return -ENFILE;
00078         case FR_INVALID_PARAMETER:    // (19) Given parameter is invalid
00079             return -EINVAL;
00080         default:
00081             return -res;
00082     }
00083 }
00084 
00085 // Helper class for deferring operations when variable falls out of scope
00086 template <typename T>
00087 class Deferred {
00088 public:
00089     T _t;
00090     Callback<void(T)> _ondefer;
00091 
00092     Deferred(const Deferred &);
00093     Deferred &operator=(const Deferred &);
00094 
00095 public:
00096     Deferred(T t, Callback<void(T)> ondefer = NULL)
00097         : _t(t), _ondefer(ondefer)
00098     {
00099     }
00100 
00101     operator T()
00102     {
00103         return _t;
00104     }
00105 
00106     ~Deferred()
00107     {
00108         if (_ondefer) {
00109             _ondefer(_t);
00110         }
00111     }
00112 };
00113 
00114 static void dodelete(const char *data)
00115 {
00116     delete[] data;
00117 }
00118 
00119 // Adds prefix needed internally by fatfs, this can be avoided for the first fatfs
00120 // (id 0) otherwise a prefix of "id:/" is inserted in front of the string.
00121 static Deferred<const char *> fat_path_prefix(int id, const char *path)
00122 {
00123     // We can avoid dynamic allocation when only on fatfs is in use
00124     if (id == 0) {
00125         return path;
00126     }
00127 
00128     // Prefix path with id, will look something like 2:/hi/hello/filehere.txt
00129     char *buffer = new char[strlen("0:/") + strlen(path) + 1];
00130     if (!buffer) {
00131         return NULL;
00132     }
00133 
00134     buffer[0] = '0' + id;
00135     buffer[1] = ':';
00136     buffer[2] = '/';
00137     strcpy(buffer + strlen("0:/"), path);
00138     return Deferred<const char *>(buffer, dodelete);
00139 }
00140 
00141 ////// Disk operations //////
00142 
00143 // Global access to block device from FAT driver
00144 static mbed::BlockDevice *_ffs[FF_VOLUMES] = {0};
00145 static SingletonPtr<PlatformMutex>  _ffs_mutex;
00146 
00147 // FAT driver functions
00148 extern "C" 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 extern "C" void *ff_memalloc(UINT size)
00162 {
00163     return malloc(size);
00164 }
00165 
00166 extern "C" 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     bd_size_t sector_size = _ffs[pdrv]->get_erase_size();
00175     MBED_ASSERT(sector_size <= WORD(-1));
00176 
00177     WORD ssize = sector_size;
00178     if (ssize < 512) {
00179         ssize = 512;
00180     }
00181 
00182     MBED_ASSERT(ssize >= FF_MIN_SS && ssize <= FF_MAX_SS);
00183     MBED_ASSERT(_ffs[pdrv]->get_read_size() <= _ffs[pdrv]->get_erase_size());
00184     MBED_ASSERT(_ffs[pdrv]->get_program_size() <= _ffs[pdrv]->get_erase_size());
00185     return ssize;
00186 }
00187 
00188 static DWORD disk_get_sector_count(BYTE pdrv)
00189 {
00190     DWORD scount = _ffs[pdrv]->size() / disk_get_sector_size(pdrv);
00191     MBED_ASSERT(scount >= 64);
00192     return scount;
00193 }
00194 
00195 extern "C" DSTATUS disk_status(BYTE pdrv)
00196 {
00197     debug_if(FFS_DBG, "disk_status on pdrv [%d]\n", pdrv);
00198     return RES_OK;
00199 }
00200 
00201 extern "C" DSTATUS disk_initialize(BYTE pdrv)
00202 {
00203     debug_if(FFS_DBG, "disk_initialize on pdrv [%d]\n", pdrv);
00204     return (DSTATUS)_ffs[pdrv]->init();
00205 }
00206 
00207 extern "C" DRESULT disk_read(BYTE pdrv, BYTE *buff, DWORD sector, UINT count)
00208 {
00209     debug_if(FFS_DBG, "disk_read(sector %lu, count %u) on pdrv [%d]\n", sector, count, pdrv);
00210     DWORD ssize = disk_get_sector_size(pdrv);
00211     mbed::bd_addr_t addr = (mbed::bd_addr_t)sector * ssize;
00212     mbed::bd_size_t size = (mbed::bd_size_t)count * ssize;
00213     int err = _ffs[pdrv]->read(buff, addr, size);
00214     return err ? RES_PARERR : RES_OK;
00215 }
00216 
00217 extern "C" DRESULT disk_write(BYTE pdrv, const BYTE *buff, DWORD sector, UINT count)
00218 {
00219     debug_if(FFS_DBG, "disk_write(sector %lu, count %u) on pdrv [%d]\n", sector, count, pdrv);
00220     DWORD ssize = disk_get_sector_size(pdrv);
00221     mbed::bd_addr_t addr = (mbed::bd_addr_t)sector * ssize;
00222     mbed::bd_size_t size = (mbed::bd_size_t)count * ssize;
00223 
00224     int err = _ffs[pdrv]->erase(addr, size);
00225     if (err) {
00226         return RES_PARERR;
00227     }
00228 
00229     err = _ffs[pdrv]->program(buff, addr, size);
00230     if (err) {
00231         return RES_PARERR;
00232     }
00233 
00234     return RES_OK;
00235 }
00236 
00237 extern "C" DRESULT disk_ioctl(BYTE pdrv, BYTE cmd, void *buff)
00238 {
00239     debug_if(FFS_DBG, "disk_ioctl(%d)\n", cmd);
00240     switch (cmd) {
00241         case CTRL_SYNC:
00242             if (_ffs[pdrv] == NULL) {
00243                 return RES_NOTRDY;
00244             } else {
00245                 return RES_OK;
00246             }
00247         case GET_SECTOR_COUNT:
00248             if (_ffs[pdrv] == NULL) {
00249                 return RES_NOTRDY;
00250             } else {
00251                 *((DWORD *)buff) = disk_get_sector_count(pdrv);
00252                 return RES_OK;
00253             }
00254         case GET_SECTOR_SIZE:
00255             if (_ffs[pdrv] == NULL) {
00256                 return RES_NOTRDY;
00257             } else {
00258                 *((WORD *)buff) = disk_get_sector_size(pdrv);
00259                 return RES_OK;
00260             }
00261         case GET_BLOCK_SIZE:
00262             *((DWORD *)buff) = 1; // default when not known
00263             return RES_OK;
00264         case CTRL_TRIM:
00265             if (_ffs[pdrv] == NULL) {
00266                 return RES_NOTRDY;
00267             } else {
00268                 DWORD *sectors = (DWORD *)buff;
00269                 DWORD ssize = disk_get_sector_size(pdrv);
00270                 mbed::bd_addr_t addr = (mbed::bd_addr_t)sectors[0] * ssize;
00271                 mbed::bd_size_t size = (mbed::bd_size_t)(sectors[1] - sectors[0] + 1) * ssize;
00272                 int err = _ffs[pdrv]->trim(addr, size);
00273                 return err ? RES_PARERR : RES_OK;
00274             }
00275     }
00276 
00277     return RES_PARERR;
00278 }
00279 
00280 ////// Generic filesystem operations //////
00281 
00282 // Filesystem implementation (See FATFilySystem.h)
00283 FATFileSystem::FATFileSystem(const char *name, BlockDevice *bd)
00284     : FileSystem(name), _fs(), _id(-1)
00285 {
00286     if (bd) {
00287         mount(bd);
00288     }
00289 }
00290 
00291 FATFileSystem::~FATFileSystem()
00292 {
00293     // nop if unmounted
00294     unmount();
00295 }
00296 
00297 int FATFileSystem::mount(BlockDevice *bd)
00298 {
00299     // requires duplicate definition to allow virtual overload to work
00300     return mount(bd, true);
00301 }
00302 
00303 int FATFileSystem::mount(BlockDevice *bd, bool mount)
00304 {
00305     lock();
00306     if (_id != -1) {
00307         unlock();
00308         return -EINVAL;
00309     }
00310 
00311     for (int i = 0; i < FF_VOLUMES; i++) {
00312         if (!_ffs[i]) {
00313             _id = i;
00314             _ffs[_id] = bd;
00315             _fsid[0] = '0' + _id;
00316             _fsid[1] = ':';
00317             _fsid[2] = '\0';
00318             debug_if(FFS_DBG, "Mounting [%s] on ffs drive [%s]\n", getName(), _fsid);
00319             FRESULT res = f_mount(&_fs, _fsid, mount);
00320             unlock();
00321             return fat_error_remap(res);
00322         }
00323     }
00324 
00325     unlock();
00326     return -ENOMEM;
00327 }
00328 
00329 int FATFileSystem::unmount()
00330 {
00331     lock();
00332     if (_id == -1) {
00333         unlock();
00334         return -EINVAL;
00335     }
00336 
00337     FRESULT res = f_mount(NULL, _fsid, 0);
00338     _ffs[_id] = NULL;
00339     _id = -1;
00340     unlock();
00341     return fat_error_remap(res);
00342 }
00343 
00344 /* See http://elm-chan.org/fsw/ff/en/mkfs.html for details of f_mkfs() and
00345  * associated arguments. */
00346 int FATFileSystem::format(BlockDevice *bd, bd_size_t cluster_size)
00347 {
00348     FATFileSystem fs;
00349     fs.lock();
00350 
00351     int err = bd->init();
00352     if (err) {
00353         fs.unlock();
00354         return err;
00355     }
00356 
00357     // erase first handful of blocks
00358     bd_size_t header = 2 * bd->get_erase_size();
00359     err = bd->erase(0, header);
00360     if (err) {
00361         bd->deinit();
00362         fs.unlock();
00363         return err;
00364     }
00365 
00366     if (bd->get_erase_value() < 0) {
00367         // erase is unknown, need to write 1s
00368         bd_size_t program_size = bd->get_program_size();
00369         void *buf = malloc(program_size);
00370         if (!buf) {
00371             bd->deinit();
00372             fs.unlock();
00373             return -ENOMEM;
00374         }
00375 
00376         memset(buf, 0xff, program_size);
00377 
00378         for (bd_addr_t i = 0; i < header; i += program_size) {
00379             err = bd->program(buf, i, program_size);
00380             if (err) {
00381                 free(buf);
00382                 bd->deinit();
00383                 fs.unlock();
00384                 return err;
00385             }
00386         }
00387 
00388         free(buf);
00389     }
00390 
00391     // trim entire device to indicate it is unneeded
00392     err = bd->trim(0, bd->size());
00393     if (err) {
00394         bd->deinit();
00395         fs.unlock();
00396         return err;
00397     }
00398 
00399     err = bd->deinit();
00400     if (err) {
00401         fs.unlock();
00402         return err;
00403     }
00404 
00405     err = fs.mount(bd, false);
00406     if (err) {
00407         fs.unlock();
00408         return err;
00409     }
00410 
00411     // Logical drive number, Partitioning rule, Allocation unit size (bytes per cluster)
00412     FRESULT res = f_mkfs(fs._fsid, FM_ANY | FM_SFD, cluster_size, NULL, 0);
00413     if (res != FR_OK) {
00414         fs.unmount();
00415         fs.unlock();
00416         return fat_error_remap(res);
00417     }
00418 
00419     err = fs.unmount();
00420     if (err) {
00421         fs.unlock();
00422         return err;
00423     }
00424 
00425     fs.unlock();
00426     return 0;
00427 }
00428 
00429 int FATFileSystem::reformat(BlockDevice *bd, int allocation_unit)
00430 {
00431     lock();
00432     if (_id != -1) {
00433         if (!bd) {
00434             bd = _ffs[_id];
00435         }
00436 
00437         int err = unmount();
00438         if (err) {
00439             unlock();
00440             return err;
00441         }
00442     }
00443 
00444     if (!bd) {
00445         unlock();
00446         return -ENODEV;
00447     }
00448 
00449     int err = FATFileSystem::format(bd, allocation_unit);
00450     if (err) {
00451         unlock();
00452         return err;
00453     }
00454 
00455     err = mount(bd);
00456     unlock();
00457     return err;
00458 }
00459 
00460 int FATFileSystem::remove(const char *path)
00461 {
00462     Deferred<const char *> fpath = fat_path_prefix(_id, path);
00463 
00464     lock();
00465     FRESULT res = f_unlink(fpath);
00466     unlock();
00467 
00468     if (res != FR_OK) {
00469         debug_if(FFS_DBG, "f_unlink() failed: %d\n", res);
00470         if (res == FR_DENIED) {
00471             return -ENOTEMPTY;
00472         }
00473     }
00474     return fat_error_remap(res);
00475 }
00476 
00477 int FATFileSystem::rename(const char *oldpath, const char *newpath)
00478 {
00479     Deferred<const char *> oldfpath = fat_path_prefix(_id, oldpath);
00480     Deferred<const char *> newfpath = fat_path_prefix(_id, newpath);
00481 
00482     lock();
00483     FRESULT res = f_rename(oldfpath, newfpath);
00484     unlock();
00485 
00486     if (res != FR_OK) {
00487         debug_if(FFS_DBG, "f_rename() failed: %d\n", res);
00488     }
00489     return fat_error_remap(res);
00490 }
00491 
00492 int FATFileSystem::mkdir(const char *path, mode_t mode)
00493 {
00494     Deferred<const char *> fpath = fat_path_prefix(_id, path);
00495 
00496     lock();
00497     FRESULT res = f_mkdir(fpath);
00498     unlock();
00499 
00500     if (res != FR_OK) {
00501         debug_if(FFS_DBG, "f_mkdir() failed: %d\n", res);
00502     }
00503     return fat_error_remap(res);
00504 }
00505 
00506 int FATFileSystem::stat(const char *path, struct stat *st)
00507 {
00508     Deferred<const char *> fpath = fat_path_prefix(_id, path);
00509 
00510     lock();
00511     FILINFO f;
00512     memset(&f, 0, sizeof(f));
00513 
00514     FRESULT res = f_stat(fpath, &f);
00515     if (res != FR_OK) {
00516         unlock();
00517         return fat_error_remap(res);
00518     }
00519 
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     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 [%d]\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 int FATFileSystem::file_truncate(fs_file_t file, off_t length)
00723 {
00724     FIL *fh = static_cast<FIL *>(file);
00725 
00726     lock();
00727     // save current position
00728     FSIZE_t oldoff = f_tell(fh);
00729 
00730     // seek to new file size and truncate
00731     FRESULT res = f_lseek(fh, length);
00732     if (res) {
00733         unlock();
00734         return fat_error_remap(res);
00735     }
00736 
00737     res = f_truncate(fh);
00738     if (res) {
00739         unlock();
00740         return fat_error_remap(res);
00741     }
00742 
00743     // restore old position
00744     res = f_lseek(fh, oldoff);
00745     if (res) {
00746         unlock();
00747         return fat_error_remap(res);
00748     }
00749 
00750     return 0;
00751 }
00752 
00753 
00754 ////// Dir operations //////
00755 int FATFileSystem::dir_open(fs_dir_t *dir, const char *path)
00756 {
00757     FATFS_DIR *dh = new FATFS_DIR;
00758     Deferred<const char *> fpath = fat_path_prefix(_id, path);
00759 
00760     lock();
00761     FRESULT res = f_opendir(dh, fpath);
00762     unlock();
00763 
00764     if (res != FR_OK) {
00765         debug_if(FFS_DBG, "f_opendir() failed: %d\n", res);
00766         delete dh;
00767         return fat_error_remap(res);
00768     }
00769 
00770     *dir = dh;
00771     return 0;
00772 }
00773 
00774 int FATFileSystem::dir_close(fs_dir_t dir)
00775 {
00776     FATFS_DIR *dh = static_cast<FATFS_DIR *>(dir);
00777 
00778     lock();
00779     FRESULT res = f_closedir(dh);
00780     unlock();
00781 
00782     delete dh;
00783     return fat_error_remap(res);
00784 }
00785 
00786 ssize_t FATFileSystem::dir_read(fs_dir_t dir, struct dirent *ent)
00787 {
00788     FATFS_DIR *dh = static_cast<FATFS_DIR *>(dir);
00789     FILINFO finfo;
00790 
00791     lock();
00792     FRESULT res = f_readdir(dh, &finfo);
00793     unlock();
00794 
00795     if (res != FR_OK) {
00796         return fat_error_remap(res);
00797     } else if (finfo.fname[0] == 0) {
00798         return 0;
00799     }
00800 
00801     ent->d_type = (finfo.fattrib & AM_DIR) ? DT_DIR : DT_REG;
00802 
00803 #if FF_USE_LFN
00804     if (ent->d_name[0] == 0) {
00805         // No long filename so use short filename.
00806         strncpy(ent->d_name, finfo.fname, FF_LFN_BUF);
00807     }
00808 #else
00809     strncpy(ent->d_name, finfo.fname, FF_SFN_BUF);
00810 #endif
00811 
00812     return 1;
00813 }
00814 
00815 void FATFileSystem::dir_seek(fs_dir_t dir, off_t offset)
00816 {
00817     FATFS_DIR *dh = static_cast<FATFS_DIR *>(dir);
00818     off_t dptr = static_cast<off_t>(dh->dptr);
00819 
00820     lock();
00821 
00822     if (offset < dptr) {
00823         f_rewinddir(dh);
00824     }
00825     while (dptr < offset) {
00826         FILINFO finfo;
00827         FRESULT res;
00828 
00829         res = f_readdir(dh, &finfo);
00830         dptr = dh->dptr;
00831         if (res != FR_OK) {
00832             break;
00833         } else if (finfo.fname[0] == 0) {
00834             break;
00835         }
00836     }
00837     unlock();
00838 }
00839 
00840 off_t FATFileSystem::dir_tell(fs_dir_t dir)
00841 {
00842     FATFS_DIR *dh = static_cast<FATFS_DIR *>(dir);
00843 
00844     lock();
00845     off_t offset = dh->dptr;
00846     unlock();
00847 
00848     return offset;
00849 }
00850 
00851 void FATFileSystem::dir_rewind(fs_dir_t dir)
00852 {
00853     FATFS_DIR *dh = static_cast<FATFS_DIR *>(dir);
00854 
00855     lock();
00856     f_rewinddir(dh);
00857     unlock();
00858 }
00859 
00860 } // namespace mbed