mbed-os5 only for TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Committer:
kenjiArai
Date:
Tue Dec 31 06:02:27 2019 +0000
Revision:
1:9db0e321a9f4
Parent:
0:5b88d5760320
updated based on mbed-os5.15.0

Who changed what in which revision?

UserRevisionLine numberNew contents of line
kenjiArai 0:5b88d5760320 1 /* mbed Microcontroller Library
kenjiArai 1:9db0e321a9f4 2 * Copyright (c) 2006-2019 ARM Limited
kenjiArai 0:5b88d5760320 3 *
kenjiArai 0:5b88d5760320 4 * Permission is hereby granted, free of charge, to any person obtaining a copy
kenjiArai 0:5b88d5760320 5 * of this software and associated documentation files (the "Software"), to deal
kenjiArai 0:5b88d5760320 6 * in the Software without restriction, including without limitation the rights
kenjiArai 0:5b88d5760320 7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
kenjiArai 0:5b88d5760320 8 * copies of the Software, and to permit persons to whom the Software is
kenjiArai 0:5b88d5760320 9 * furnished to do so, subject to the following conditions:
kenjiArai 0:5b88d5760320 10 *
kenjiArai 0:5b88d5760320 11 * The above copyright notice and this permission notice shall be included in
kenjiArai 0:5b88d5760320 12 * all copies or substantial portions of the Software.
kenjiArai 0:5b88d5760320 13 *
kenjiArai 0:5b88d5760320 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
kenjiArai 0:5b88d5760320 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
kenjiArai 0:5b88d5760320 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
kenjiArai 0:5b88d5760320 17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
kenjiArai 0:5b88d5760320 18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
kenjiArai 0:5b88d5760320 19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
kenjiArai 0:5b88d5760320 20 * SOFTWARE.
kenjiArai 0:5b88d5760320 21 */
kenjiArai 1:9db0e321a9f4 22 #include "features/storage/filesystem/fat/ChaN/diskio.h"
kenjiArai 1:9db0e321a9f4 23 #include "features/storage/filesystem/fat/ChaN/ffconf.h"
kenjiArai 1:9db0e321a9f4 24 #include "features/storage/filesystem/fat/ChaN/ff.h"
kenjiArai 0:5b88d5760320 25 #include "platform/mbed_debug.h"
kenjiArai 0:5b88d5760320 26 #include "platform/mbed_critical.h"
kenjiArai 1:9db0e321a9f4 27 #include "features/storage/filesystem/mbed_filesystem.h"
kenjiArai 0:5b88d5760320 28 #include "FATFileSystem.h"
kenjiArai 0:5b88d5760320 29
kenjiArai 0:5b88d5760320 30 #include <errno.h>
kenjiArai 0:5b88d5760320 31 #include <stdlib.h>
kenjiArai 0:5b88d5760320 32
kenjiArai 0:5b88d5760320 33 namespace mbed {
kenjiArai 0:5b88d5760320 34
kenjiArai 0:5b88d5760320 35 using namespace mbed;
kenjiArai 0:5b88d5760320 36
kenjiArai 0:5b88d5760320 37 static int fat_error_remap(FRESULT res)
kenjiArai 0:5b88d5760320 38 {
kenjiArai 0:5b88d5760320 39 switch (res) {
kenjiArai 0:5b88d5760320 40 case FR_OK: // (0) Succeeded
kenjiArai 0:5b88d5760320 41 return 0;
kenjiArai 0:5b88d5760320 42 case FR_DISK_ERR: // (1) A hard error occurred in the low level disk I/O layer
kenjiArai 0:5b88d5760320 43 return -EIO;
kenjiArai 0:5b88d5760320 44 case FR_INT_ERR: // (2) Assertion failed
kenjiArai 0:5b88d5760320 45 return -1;
kenjiArai 0:5b88d5760320 46 case FR_NOT_READY: // (3) The physical drive cannot work
kenjiArai 0:5b88d5760320 47 return -EIO;
kenjiArai 0:5b88d5760320 48 case FR_NO_FILE: // (4) Could not find the file
kenjiArai 0:5b88d5760320 49 return -ENOENT;
kenjiArai 0:5b88d5760320 50 case FR_NO_PATH: // (5) Could not find the path
kenjiArai 0:5b88d5760320 51 return -ENOTDIR;
kenjiArai 0:5b88d5760320 52 case FR_INVALID_NAME: // (6) The path name format is invalid
kenjiArai 0:5b88d5760320 53 return -EINVAL;
kenjiArai 0:5b88d5760320 54 case FR_DENIED: // (7) Access denied due to prohibited access or directory full
kenjiArai 0:5b88d5760320 55 return -EACCES;
kenjiArai 0:5b88d5760320 56 case FR_EXIST: // (8) Access denied due to prohibited access
kenjiArai 0:5b88d5760320 57 return -EEXIST;
kenjiArai 0:5b88d5760320 58 case FR_INVALID_OBJECT: // (9) The file/directory object is invalid
kenjiArai 0:5b88d5760320 59 return -EBADF;
kenjiArai 0:5b88d5760320 60 case FR_WRITE_PROTECTED: // (10) The physical drive is write protected
kenjiArai 0:5b88d5760320 61 return -EACCES;
kenjiArai 0:5b88d5760320 62 case FR_INVALID_DRIVE: // (11) The logical drive number is invalid
kenjiArai 0:5b88d5760320 63 return -ENODEV;
kenjiArai 0:5b88d5760320 64 case FR_NOT_ENABLED: // (12) The volume has no work area
kenjiArai 0:5b88d5760320 65 return -ENODEV;
kenjiArai 0:5b88d5760320 66 case FR_NO_FILESYSTEM: // (13) There is no valid FAT volume
kenjiArai 0:5b88d5760320 67 return -EINVAL;
kenjiArai 0:5b88d5760320 68 case FR_MKFS_ABORTED: // (14) The f_mkfs() aborted due to any problem
kenjiArai 0:5b88d5760320 69 return -EIO;
kenjiArai 0:5b88d5760320 70 case FR_TIMEOUT: // (15) Could not get a grant to access the volume within defined period
kenjiArai 0:5b88d5760320 71 return -ETIMEDOUT;
kenjiArai 0:5b88d5760320 72 case FR_LOCKED: // (16) The operation is rejected according to the file sharing policy
kenjiArai 0:5b88d5760320 73 return -EBUSY;
kenjiArai 0:5b88d5760320 74 case FR_NOT_ENOUGH_CORE: // (17) LFN working buffer could not be allocated
kenjiArai 0:5b88d5760320 75 return -ENOMEM;
kenjiArai 0:5b88d5760320 76 case FR_TOO_MANY_OPEN_FILES: // (18) Number of open files > FF_FS_LOCK
kenjiArai 0:5b88d5760320 77 return -ENFILE;
kenjiArai 0:5b88d5760320 78 case FR_INVALID_PARAMETER: // (19) Given parameter is invalid
kenjiArai 0:5b88d5760320 79 return -EINVAL;
kenjiArai 0:5b88d5760320 80 default:
kenjiArai 0:5b88d5760320 81 return -res;
kenjiArai 0:5b88d5760320 82 }
kenjiArai 0:5b88d5760320 83 }
kenjiArai 0:5b88d5760320 84
kenjiArai 0:5b88d5760320 85 // Helper class for deferring operations when variable falls out of scope
kenjiArai 0:5b88d5760320 86 template <typename T>
kenjiArai 0:5b88d5760320 87 class Deferred {
kenjiArai 0:5b88d5760320 88 public:
kenjiArai 0:5b88d5760320 89 T _t;
kenjiArai 0:5b88d5760320 90 Callback<void(T)> _ondefer;
kenjiArai 0:5b88d5760320 91
kenjiArai 0:5b88d5760320 92 Deferred(const Deferred &);
kenjiArai 0:5b88d5760320 93 Deferred &operator=(const Deferred &);
kenjiArai 0:5b88d5760320 94
kenjiArai 0:5b88d5760320 95 public:
kenjiArai 0:5b88d5760320 96 Deferred(T t, Callback<void(T)> ondefer = NULL)
kenjiArai 0:5b88d5760320 97 : _t(t), _ondefer(ondefer)
kenjiArai 0:5b88d5760320 98 {
kenjiArai 0:5b88d5760320 99 }
kenjiArai 0:5b88d5760320 100
kenjiArai 0:5b88d5760320 101 operator T()
kenjiArai 0:5b88d5760320 102 {
kenjiArai 0:5b88d5760320 103 return _t;
kenjiArai 0:5b88d5760320 104 }
kenjiArai 0:5b88d5760320 105
kenjiArai 0:5b88d5760320 106 ~Deferred()
kenjiArai 0:5b88d5760320 107 {
kenjiArai 0:5b88d5760320 108 if (_ondefer) {
kenjiArai 0:5b88d5760320 109 _ondefer(_t);
kenjiArai 0:5b88d5760320 110 }
kenjiArai 0:5b88d5760320 111 }
kenjiArai 0:5b88d5760320 112 };
kenjiArai 0:5b88d5760320 113
kenjiArai 0:5b88d5760320 114 static void dodelete(const char *data)
kenjiArai 0:5b88d5760320 115 {
kenjiArai 0:5b88d5760320 116 delete[] data;
kenjiArai 0:5b88d5760320 117 }
kenjiArai 0:5b88d5760320 118
kenjiArai 0:5b88d5760320 119 // Adds prefix needed internally by fatfs, this can be avoided for the first fatfs
kenjiArai 0:5b88d5760320 120 // (id 0) otherwise a prefix of "id:/" is inserted in front of the string.
kenjiArai 0:5b88d5760320 121 static Deferred<const char *> fat_path_prefix(int id, const char *path)
kenjiArai 0:5b88d5760320 122 {
kenjiArai 0:5b88d5760320 123 // We can avoid dynamic allocation when only on fatfs is in use
kenjiArai 0:5b88d5760320 124 if (id == 0) {
kenjiArai 0:5b88d5760320 125 return path;
kenjiArai 0:5b88d5760320 126 }
kenjiArai 0:5b88d5760320 127
kenjiArai 0:5b88d5760320 128 // Prefix path with id, will look something like 2:/hi/hello/filehere.txt
kenjiArai 0:5b88d5760320 129 char *buffer = new char[strlen("0:/") + strlen(path) + 1];
kenjiArai 0:5b88d5760320 130 if (!buffer) {
kenjiArai 0:5b88d5760320 131 return NULL;
kenjiArai 0:5b88d5760320 132 }
kenjiArai 0:5b88d5760320 133
kenjiArai 0:5b88d5760320 134 buffer[0] = '0' + id;
kenjiArai 0:5b88d5760320 135 buffer[1] = ':';
kenjiArai 0:5b88d5760320 136 buffer[2] = '/';
kenjiArai 0:5b88d5760320 137 strcpy(buffer + strlen("0:/"), path);
kenjiArai 0:5b88d5760320 138 return Deferred<const char *>(buffer, dodelete);
kenjiArai 0:5b88d5760320 139 }
kenjiArai 0:5b88d5760320 140
kenjiArai 0:5b88d5760320 141 ////// Disk operations //////
kenjiArai 0:5b88d5760320 142
kenjiArai 0:5b88d5760320 143 // Global access to block device from FAT driver
kenjiArai 0:5b88d5760320 144 static mbed::BlockDevice *_ffs[FF_VOLUMES] = {0};
kenjiArai 0:5b88d5760320 145 static SingletonPtr<PlatformMutex> _ffs_mutex;
kenjiArai 0:5b88d5760320 146
kenjiArai 0:5b88d5760320 147 // FAT driver functions
kenjiArai 0:5b88d5760320 148 extern "C" DWORD get_fattime(void)
kenjiArai 0:5b88d5760320 149 {
kenjiArai 0:5b88d5760320 150 time_t rawtime;
kenjiArai 0:5b88d5760320 151 time(&rawtime);
kenjiArai 0:5b88d5760320 152 struct tm *ptm = localtime(&rawtime);
kenjiArai 0:5b88d5760320 153 return (DWORD)(ptm->tm_year - 80) << 25
kenjiArai 0:5b88d5760320 154 | (DWORD)(ptm->tm_mon + 1) << 21
kenjiArai 0:5b88d5760320 155 | (DWORD)(ptm->tm_mday) << 16
kenjiArai 0:5b88d5760320 156 | (DWORD)(ptm->tm_hour) << 11
kenjiArai 0:5b88d5760320 157 | (DWORD)(ptm->tm_min) << 5
kenjiArai 0:5b88d5760320 158 | (DWORD)(ptm->tm_sec / 2);
kenjiArai 0:5b88d5760320 159 }
kenjiArai 0:5b88d5760320 160
kenjiArai 0:5b88d5760320 161 extern "C" void *ff_memalloc(UINT size)
kenjiArai 0:5b88d5760320 162 {
kenjiArai 0:5b88d5760320 163 return malloc(size);
kenjiArai 0:5b88d5760320 164 }
kenjiArai 0:5b88d5760320 165
kenjiArai 0:5b88d5760320 166 extern "C" void ff_memfree(void *p)
kenjiArai 0:5b88d5760320 167 {
kenjiArai 0:5b88d5760320 168 free(p);
kenjiArai 0:5b88d5760320 169 }
kenjiArai 0:5b88d5760320 170
kenjiArai 0:5b88d5760320 171 // Implementation of diskio functions (see ChaN/diskio.h)
kenjiArai 0:5b88d5760320 172 static WORD disk_get_sector_size(BYTE pdrv)
kenjiArai 0:5b88d5760320 173 {
kenjiArai 0:5b88d5760320 174 bd_size_t sector_size = _ffs[pdrv]->get_erase_size();
kenjiArai 0:5b88d5760320 175 MBED_ASSERT(sector_size <= WORD(-1));
kenjiArai 0:5b88d5760320 176
kenjiArai 0:5b88d5760320 177 WORD ssize = sector_size;
kenjiArai 0:5b88d5760320 178 if (ssize < 512) {
kenjiArai 0:5b88d5760320 179 ssize = 512;
kenjiArai 0:5b88d5760320 180 }
kenjiArai 0:5b88d5760320 181
kenjiArai 0:5b88d5760320 182 MBED_ASSERT(ssize >= FF_MIN_SS && ssize <= FF_MAX_SS);
kenjiArai 0:5b88d5760320 183 MBED_ASSERT(_ffs[pdrv]->get_read_size() <= _ffs[pdrv]->get_erase_size());
kenjiArai 0:5b88d5760320 184 MBED_ASSERT(_ffs[pdrv]->get_program_size() <= _ffs[pdrv]->get_erase_size());
kenjiArai 0:5b88d5760320 185 return ssize;
kenjiArai 0:5b88d5760320 186 }
kenjiArai 0:5b88d5760320 187
kenjiArai 0:5b88d5760320 188 static DWORD disk_get_sector_count(BYTE pdrv)
kenjiArai 0:5b88d5760320 189 {
kenjiArai 0:5b88d5760320 190 DWORD scount = _ffs[pdrv]->size() / disk_get_sector_size(pdrv);
kenjiArai 0:5b88d5760320 191 MBED_ASSERT(scount >= 64);
kenjiArai 0:5b88d5760320 192 return scount;
kenjiArai 0:5b88d5760320 193 }
kenjiArai 0:5b88d5760320 194
kenjiArai 0:5b88d5760320 195 extern "C" DSTATUS disk_status(BYTE pdrv)
kenjiArai 0:5b88d5760320 196 {
kenjiArai 0:5b88d5760320 197 debug_if(FFS_DBG, "disk_status on pdrv [%d]\n", pdrv);
kenjiArai 0:5b88d5760320 198 return RES_OK;
kenjiArai 0:5b88d5760320 199 }
kenjiArai 0:5b88d5760320 200
kenjiArai 0:5b88d5760320 201 extern "C" DSTATUS disk_initialize(BYTE pdrv)
kenjiArai 0:5b88d5760320 202 {
kenjiArai 0:5b88d5760320 203 debug_if(FFS_DBG, "disk_initialize on pdrv [%d]\n", pdrv);
kenjiArai 0:5b88d5760320 204 return (DSTATUS)_ffs[pdrv]->init();
kenjiArai 0:5b88d5760320 205 }
kenjiArai 0:5b88d5760320 206
kenjiArai 0:5b88d5760320 207 extern "C" DRESULT disk_read(BYTE pdrv, BYTE *buff, DWORD sector, UINT count)
kenjiArai 0:5b88d5760320 208 {
kenjiArai 0:5b88d5760320 209 debug_if(FFS_DBG, "disk_read(sector %lu, count %u) on pdrv [%d]\n", sector, count, pdrv);
kenjiArai 0:5b88d5760320 210 DWORD ssize = disk_get_sector_size(pdrv);
kenjiArai 0:5b88d5760320 211 mbed::bd_addr_t addr = (mbed::bd_addr_t)sector * ssize;
kenjiArai 0:5b88d5760320 212 mbed::bd_size_t size = (mbed::bd_size_t)count * ssize;
kenjiArai 0:5b88d5760320 213 int err = _ffs[pdrv]->read(buff, addr, size);
kenjiArai 0:5b88d5760320 214 return err ? RES_PARERR : RES_OK;
kenjiArai 0:5b88d5760320 215 }
kenjiArai 0:5b88d5760320 216
kenjiArai 0:5b88d5760320 217 extern "C" DRESULT disk_write(BYTE pdrv, const BYTE *buff, DWORD sector, UINT count)
kenjiArai 0:5b88d5760320 218 {
kenjiArai 0:5b88d5760320 219 debug_if(FFS_DBG, "disk_write(sector %lu, count %u) on pdrv [%d]\n", sector, count, pdrv);
kenjiArai 0:5b88d5760320 220 DWORD ssize = disk_get_sector_size(pdrv);
kenjiArai 0:5b88d5760320 221 mbed::bd_addr_t addr = (mbed::bd_addr_t)sector * ssize;
kenjiArai 0:5b88d5760320 222 mbed::bd_size_t size = (mbed::bd_size_t)count * ssize;
kenjiArai 0:5b88d5760320 223
kenjiArai 0:5b88d5760320 224 int err = _ffs[pdrv]->erase(addr, size);
kenjiArai 0:5b88d5760320 225 if (err) {
kenjiArai 0:5b88d5760320 226 return RES_PARERR;
kenjiArai 0:5b88d5760320 227 }
kenjiArai 0:5b88d5760320 228
kenjiArai 0:5b88d5760320 229 err = _ffs[pdrv]->program(buff, addr, size);
kenjiArai 0:5b88d5760320 230 if (err) {
kenjiArai 0:5b88d5760320 231 return RES_PARERR;
kenjiArai 0:5b88d5760320 232 }
kenjiArai 0:5b88d5760320 233
kenjiArai 0:5b88d5760320 234 return RES_OK;
kenjiArai 0:5b88d5760320 235 }
kenjiArai 0:5b88d5760320 236
kenjiArai 0:5b88d5760320 237 extern "C" DRESULT disk_ioctl(BYTE pdrv, BYTE cmd, void *buff)
kenjiArai 0:5b88d5760320 238 {
kenjiArai 0:5b88d5760320 239 debug_if(FFS_DBG, "disk_ioctl(%d)\n", cmd);
kenjiArai 0:5b88d5760320 240 switch (cmd) {
kenjiArai 0:5b88d5760320 241 case CTRL_SYNC:
kenjiArai 0:5b88d5760320 242 if (_ffs[pdrv] == NULL) {
kenjiArai 0:5b88d5760320 243 return RES_NOTRDY;
kenjiArai 0:5b88d5760320 244 } else {
kenjiArai 0:5b88d5760320 245 return RES_OK;
kenjiArai 0:5b88d5760320 246 }
kenjiArai 0:5b88d5760320 247 case GET_SECTOR_COUNT:
kenjiArai 0:5b88d5760320 248 if (_ffs[pdrv] == NULL) {
kenjiArai 0:5b88d5760320 249 return RES_NOTRDY;
kenjiArai 0:5b88d5760320 250 } else {
kenjiArai 0:5b88d5760320 251 *((DWORD *)buff) = disk_get_sector_count(pdrv);
kenjiArai 0:5b88d5760320 252 return RES_OK;
kenjiArai 0:5b88d5760320 253 }
kenjiArai 0:5b88d5760320 254 case GET_SECTOR_SIZE:
kenjiArai 0:5b88d5760320 255 if (_ffs[pdrv] == NULL) {
kenjiArai 0:5b88d5760320 256 return RES_NOTRDY;
kenjiArai 0:5b88d5760320 257 } else {
kenjiArai 0:5b88d5760320 258 *((WORD *)buff) = disk_get_sector_size(pdrv);
kenjiArai 0:5b88d5760320 259 return RES_OK;
kenjiArai 0:5b88d5760320 260 }
kenjiArai 0:5b88d5760320 261 case GET_BLOCK_SIZE:
kenjiArai 0:5b88d5760320 262 *((DWORD *)buff) = 1; // default when not known
kenjiArai 0:5b88d5760320 263 return RES_OK;
kenjiArai 0:5b88d5760320 264 case CTRL_TRIM:
kenjiArai 0:5b88d5760320 265 if (_ffs[pdrv] == NULL) {
kenjiArai 0:5b88d5760320 266 return RES_NOTRDY;
kenjiArai 0:5b88d5760320 267 } else {
kenjiArai 0:5b88d5760320 268 DWORD *sectors = (DWORD *)buff;
kenjiArai 0:5b88d5760320 269 DWORD ssize = disk_get_sector_size(pdrv);
kenjiArai 0:5b88d5760320 270 mbed::bd_addr_t addr = (mbed::bd_addr_t)sectors[0] * ssize;
kenjiArai 0:5b88d5760320 271 mbed::bd_size_t size = (mbed::bd_size_t)(sectors[1] - sectors[0] + 1) * ssize;
kenjiArai 0:5b88d5760320 272 int err = _ffs[pdrv]->trim(addr, size);
kenjiArai 0:5b88d5760320 273 return err ? RES_PARERR : RES_OK;
kenjiArai 0:5b88d5760320 274 }
kenjiArai 0:5b88d5760320 275 }
kenjiArai 0:5b88d5760320 276
kenjiArai 0:5b88d5760320 277 return RES_PARERR;
kenjiArai 0:5b88d5760320 278 }
kenjiArai 0:5b88d5760320 279
kenjiArai 0:5b88d5760320 280 ////// Generic filesystem operations //////
kenjiArai 0:5b88d5760320 281
kenjiArai 0:5b88d5760320 282 // Filesystem implementation (See FATFilySystem.h)
kenjiArai 0:5b88d5760320 283 FATFileSystem::FATFileSystem(const char *name, BlockDevice *bd)
kenjiArai 1:9db0e321a9f4 284 : FileSystem(name), _fs(), _id(-1)
kenjiArai 0:5b88d5760320 285 {
kenjiArai 0:5b88d5760320 286 if (bd) {
kenjiArai 0:5b88d5760320 287 mount(bd);
kenjiArai 0:5b88d5760320 288 }
kenjiArai 0:5b88d5760320 289 }
kenjiArai 0:5b88d5760320 290
kenjiArai 0:5b88d5760320 291 FATFileSystem::~FATFileSystem()
kenjiArai 0:5b88d5760320 292 {
kenjiArai 0:5b88d5760320 293 // nop if unmounted
kenjiArai 0:5b88d5760320 294 unmount();
kenjiArai 0:5b88d5760320 295 }
kenjiArai 0:5b88d5760320 296
kenjiArai 0:5b88d5760320 297 int FATFileSystem::mount(BlockDevice *bd)
kenjiArai 0:5b88d5760320 298 {
kenjiArai 0:5b88d5760320 299 // requires duplicate definition to allow virtual overload to work
kenjiArai 0:5b88d5760320 300 return mount(bd, true);
kenjiArai 0:5b88d5760320 301 }
kenjiArai 0:5b88d5760320 302
kenjiArai 0:5b88d5760320 303 int FATFileSystem::mount(BlockDevice *bd, bool mount)
kenjiArai 0:5b88d5760320 304 {
kenjiArai 0:5b88d5760320 305 lock();
kenjiArai 0:5b88d5760320 306 if (_id != -1) {
kenjiArai 0:5b88d5760320 307 unlock();
kenjiArai 0:5b88d5760320 308 return -EINVAL;
kenjiArai 0:5b88d5760320 309 }
kenjiArai 0:5b88d5760320 310
kenjiArai 0:5b88d5760320 311 for (int i = 0; i < FF_VOLUMES; i++) {
kenjiArai 0:5b88d5760320 312 if (!_ffs[i]) {
kenjiArai 0:5b88d5760320 313 _id = i;
kenjiArai 0:5b88d5760320 314 _ffs[_id] = bd;
kenjiArai 0:5b88d5760320 315 _fsid[0] = '0' + _id;
kenjiArai 0:5b88d5760320 316 _fsid[1] = ':';
kenjiArai 0:5b88d5760320 317 _fsid[2] = '\0';
kenjiArai 0:5b88d5760320 318 debug_if(FFS_DBG, "Mounting [%s] on ffs drive [%s]\n", getName(), _fsid);
kenjiArai 0:5b88d5760320 319 FRESULT res = f_mount(&_fs, _fsid, mount);
kenjiArai 0:5b88d5760320 320 unlock();
kenjiArai 0:5b88d5760320 321 return fat_error_remap(res);
kenjiArai 0:5b88d5760320 322 }
kenjiArai 0:5b88d5760320 323 }
kenjiArai 0:5b88d5760320 324
kenjiArai 0:5b88d5760320 325 unlock();
kenjiArai 0:5b88d5760320 326 return -ENOMEM;
kenjiArai 0:5b88d5760320 327 }
kenjiArai 0:5b88d5760320 328
kenjiArai 0:5b88d5760320 329 int FATFileSystem::unmount()
kenjiArai 0:5b88d5760320 330 {
kenjiArai 0:5b88d5760320 331 lock();
kenjiArai 0:5b88d5760320 332 if (_id == -1) {
kenjiArai 0:5b88d5760320 333 unlock();
kenjiArai 0:5b88d5760320 334 return -EINVAL;
kenjiArai 0:5b88d5760320 335 }
kenjiArai 0:5b88d5760320 336
kenjiArai 0:5b88d5760320 337 FRESULT res = f_mount(NULL, _fsid, 0);
kenjiArai 0:5b88d5760320 338 _ffs[_id] = NULL;
kenjiArai 0:5b88d5760320 339 _id = -1;
kenjiArai 0:5b88d5760320 340 unlock();
kenjiArai 0:5b88d5760320 341 return fat_error_remap(res);
kenjiArai 0:5b88d5760320 342 }
kenjiArai 0:5b88d5760320 343
kenjiArai 0:5b88d5760320 344 /* See http://elm-chan.org/fsw/ff/en/mkfs.html for details of f_mkfs() and
kenjiArai 0:5b88d5760320 345 * associated arguments. */
kenjiArai 0:5b88d5760320 346 int FATFileSystem::format(BlockDevice *bd, bd_size_t cluster_size)
kenjiArai 0:5b88d5760320 347 {
kenjiArai 0:5b88d5760320 348 FATFileSystem fs;
kenjiArai 0:5b88d5760320 349 fs.lock();
kenjiArai 0:5b88d5760320 350
kenjiArai 0:5b88d5760320 351 int err = bd->init();
kenjiArai 0:5b88d5760320 352 if (err) {
kenjiArai 0:5b88d5760320 353 fs.unlock();
kenjiArai 0:5b88d5760320 354 return err;
kenjiArai 0:5b88d5760320 355 }
kenjiArai 0:5b88d5760320 356
kenjiArai 0:5b88d5760320 357 // erase first handful of blocks
kenjiArai 0:5b88d5760320 358 bd_size_t header = 2 * bd->get_erase_size();
kenjiArai 0:5b88d5760320 359 err = bd->erase(0, header);
kenjiArai 0:5b88d5760320 360 if (err) {
kenjiArai 0:5b88d5760320 361 bd->deinit();
kenjiArai 0:5b88d5760320 362 fs.unlock();
kenjiArai 0:5b88d5760320 363 return err;
kenjiArai 0:5b88d5760320 364 }
kenjiArai 0:5b88d5760320 365
kenjiArai 0:5b88d5760320 366 if (bd->get_erase_value() < 0) {
kenjiArai 0:5b88d5760320 367 // erase is unknown, need to write 1s
kenjiArai 0:5b88d5760320 368 bd_size_t program_size = bd->get_program_size();
kenjiArai 0:5b88d5760320 369 void *buf = malloc(program_size);
kenjiArai 0:5b88d5760320 370 if (!buf) {
kenjiArai 0:5b88d5760320 371 bd->deinit();
kenjiArai 0:5b88d5760320 372 fs.unlock();
kenjiArai 0:5b88d5760320 373 return -ENOMEM;
kenjiArai 0:5b88d5760320 374 }
kenjiArai 0:5b88d5760320 375
kenjiArai 0:5b88d5760320 376 memset(buf, 0xff, program_size);
kenjiArai 0:5b88d5760320 377
kenjiArai 0:5b88d5760320 378 for (bd_addr_t i = 0; i < header; i += program_size) {
kenjiArai 0:5b88d5760320 379 err = bd->program(buf, i, program_size);
kenjiArai 0:5b88d5760320 380 if (err) {
kenjiArai 0:5b88d5760320 381 free(buf);
kenjiArai 0:5b88d5760320 382 bd->deinit();
kenjiArai 0:5b88d5760320 383 fs.unlock();
kenjiArai 0:5b88d5760320 384 return err;
kenjiArai 0:5b88d5760320 385 }
kenjiArai 0:5b88d5760320 386 }
kenjiArai 0:5b88d5760320 387
kenjiArai 0:5b88d5760320 388 free(buf);
kenjiArai 0:5b88d5760320 389 }
kenjiArai 0:5b88d5760320 390
kenjiArai 0:5b88d5760320 391 // trim entire device to indicate it is unneeded
kenjiArai 0:5b88d5760320 392 err = bd->trim(0, bd->size());
kenjiArai 0:5b88d5760320 393 if (err) {
kenjiArai 0:5b88d5760320 394 bd->deinit();
kenjiArai 0:5b88d5760320 395 fs.unlock();
kenjiArai 0:5b88d5760320 396 return err;
kenjiArai 0:5b88d5760320 397 }
kenjiArai 0:5b88d5760320 398
kenjiArai 0:5b88d5760320 399 err = bd->deinit();
kenjiArai 0:5b88d5760320 400 if (err) {
kenjiArai 0:5b88d5760320 401 fs.unlock();
kenjiArai 0:5b88d5760320 402 return err;
kenjiArai 0:5b88d5760320 403 }
kenjiArai 0:5b88d5760320 404
kenjiArai 0:5b88d5760320 405 err = fs.mount(bd, false);
kenjiArai 0:5b88d5760320 406 if (err) {
kenjiArai 0:5b88d5760320 407 fs.unlock();
kenjiArai 0:5b88d5760320 408 return err;
kenjiArai 0:5b88d5760320 409 }
kenjiArai 0:5b88d5760320 410
kenjiArai 0:5b88d5760320 411 // Logical drive number, Partitioning rule, Allocation unit size (bytes per cluster)
kenjiArai 0:5b88d5760320 412 FRESULT res = f_mkfs(fs._fsid, FM_ANY | FM_SFD, cluster_size, NULL, 0);
kenjiArai 0:5b88d5760320 413 if (res != FR_OK) {
kenjiArai 0:5b88d5760320 414 fs.unmount();
kenjiArai 0:5b88d5760320 415 fs.unlock();
kenjiArai 0:5b88d5760320 416 return fat_error_remap(res);
kenjiArai 0:5b88d5760320 417 }
kenjiArai 0:5b88d5760320 418
kenjiArai 0:5b88d5760320 419 err = fs.unmount();
kenjiArai 0:5b88d5760320 420 if (err) {
kenjiArai 0:5b88d5760320 421 fs.unlock();
kenjiArai 0:5b88d5760320 422 return err;
kenjiArai 0:5b88d5760320 423 }
kenjiArai 0:5b88d5760320 424
kenjiArai 0:5b88d5760320 425 fs.unlock();
kenjiArai 0:5b88d5760320 426 return 0;
kenjiArai 0:5b88d5760320 427 }
kenjiArai 0:5b88d5760320 428
kenjiArai 0:5b88d5760320 429 int FATFileSystem::reformat(BlockDevice *bd, int allocation_unit)
kenjiArai 0:5b88d5760320 430 {
kenjiArai 0:5b88d5760320 431 lock();
kenjiArai 0:5b88d5760320 432 if (_id != -1) {
kenjiArai 0:5b88d5760320 433 if (!bd) {
kenjiArai 0:5b88d5760320 434 bd = _ffs[_id];
kenjiArai 0:5b88d5760320 435 }
kenjiArai 0:5b88d5760320 436
kenjiArai 0:5b88d5760320 437 int err = unmount();
kenjiArai 0:5b88d5760320 438 if (err) {
kenjiArai 0:5b88d5760320 439 unlock();
kenjiArai 0:5b88d5760320 440 return err;
kenjiArai 0:5b88d5760320 441 }
kenjiArai 0:5b88d5760320 442 }
kenjiArai 0:5b88d5760320 443
kenjiArai 0:5b88d5760320 444 if (!bd) {
kenjiArai 0:5b88d5760320 445 unlock();
kenjiArai 0:5b88d5760320 446 return -ENODEV;
kenjiArai 0:5b88d5760320 447 }
kenjiArai 0:5b88d5760320 448
kenjiArai 0:5b88d5760320 449 int err = FATFileSystem::format(bd, allocation_unit);
kenjiArai 0:5b88d5760320 450 if (err) {
kenjiArai 0:5b88d5760320 451 unlock();
kenjiArai 0:5b88d5760320 452 return err;
kenjiArai 0:5b88d5760320 453 }
kenjiArai 0:5b88d5760320 454
kenjiArai 0:5b88d5760320 455 err = mount(bd);
kenjiArai 0:5b88d5760320 456 unlock();
kenjiArai 0:5b88d5760320 457 return err;
kenjiArai 0:5b88d5760320 458 }
kenjiArai 0:5b88d5760320 459
kenjiArai 0:5b88d5760320 460 int FATFileSystem::remove(const char *path)
kenjiArai 0:5b88d5760320 461 {
kenjiArai 0:5b88d5760320 462 Deferred<const char *> fpath = fat_path_prefix(_id, path);
kenjiArai 0:5b88d5760320 463
kenjiArai 0:5b88d5760320 464 lock();
kenjiArai 0:5b88d5760320 465 FRESULT res = f_unlink(fpath);
kenjiArai 0:5b88d5760320 466 unlock();
kenjiArai 0:5b88d5760320 467
kenjiArai 0:5b88d5760320 468 if (res != FR_OK) {
kenjiArai 0:5b88d5760320 469 debug_if(FFS_DBG, "f_unlink() failed: %d\n", res);
kenjiArai 0:5b88d5760320 470 if (res == FR_DENIED) {
kenjiArai 0:5b88d5760320 471 return -ENOTEMPTY;
kenjiArai 0:5b88d5760320 472 }
kenjiArai 0:5b88d5760320 473 }
kenjiArai 0:5b88d5760320 474 return fat_error_remap(res);
kenjiArai 0:5b88d5760320 475 }
kenjiArai 0:5b88d5760320 476
kenjiArai 0:5b88d5760320 477 int FATFileSystem::rename(const char *oldpath, const char *newpath)
kenjiArai 0:5b88d5760320 478 {
kenjiArai 0:5b88d5760320 479 Deferred<const char *> oldfpath = fat_path_prefix(_id, oldpath);
kenjiArai 0:5b88d5760320 480 Deferred<const char *> newfpath = fat_path_prefix(_id, newpath);
kenjiArai 0:5b88d5760320 481
kenjiArai 0:5b88d5760320 482 lock();
kenjiArai 0:5b88d5760320 483 FRESULT res = f_rename(oldfpath, newfpath);
kenjiArai 0:5b88d5760320 484 unlock();
kenjiArai 0:5b88d5760320 485
kenjiArai 0:5b88d5760320 486 if (res != FR_OK) {
kenjiArai 0:5b88d5760320 487 debug_if(FFS_DBG, "f_rename() failed: %d\n", res);
kenjiArai 0:5b88d5760320 488 }
kenjiArai 0:5b88d5760320 489 return fat_error_remap(res);
kenjiArai 0:5b88d5760320 490 }
kenjiArai 0:5b88d5760320 491
kenjiArai 0:5b88d5760320 492 int FATFileSystem::mkdir(const char *path, mode_t mode)
kenjiArai 0:5b88d5760320 493 {
kenjiArai 0:5b88d5760320 494 Deferred<const char *> fpath = fat_path_prefix(_id, path);
kenjiArai 0:5b88d5760320 495
kenjiArai 0:5b88d5760320 496 lock();
kenjiArai 0:5b88d5760320 497 FRESULT res = f_mkdir(fpath);
kenjiArai 0:5b88d5760320 498 unlock();
kenjiArai 0:5b88d5760320 499
kenjiArai 0:5b88d5760320 500 if (res != FR_OK) {
kenjiArai 0:5b88d5760320 501 debug_if(FFS_DBG, "f_mkdir() failed: %d\n", res);
kenjiArai 0:5b88d5760320 502 }
kenjiArai 0:5b88d5760320 503 return fat_error_remap(res);
kenjiArai 0:5b88d5760320 504 }
kenjiArai 0:5b88d5760320 505
kenjiArai 0:5b88d5760320 506 int FATFileSystem::stat(const char *path, struct stat *st)
kenjiArai 0:5b88d5760320 507 {
kenjiArai 0:5b88d5760320 508 Deferred<const char *> fpath = fat_path_prefix(_id, path);
kenjiArai 0:5b88d5760320 509
kenjiArai 0:5b88d5760320 510 lock();
kenjiArai 0:5b88d5760320 511 FILINFO f;
kenjiArai 0:5b88d5760320 512 memset(&f, 0, sizeof(f));
kenjiArai 0:5b88d5760320 513
kenjiArai 0:5b88d5760320 514 FRESULT res = f_stat(fpath, &f);
kenjiArai 0:5b88d5760320 515 if (res != FR_OK) {
kenjiArai 0:5b88d5760320 516 unlock();
kenjiArai 0:5b88d5760320 517 return fat_error_remap(res);
kenjiArai 0:5b88d5760320 518 }
kenjiArai 0:5b88d5760320 519
kenjiArai 0:5b88d5760320 520 st->st_size = f.fsize;
kenjiArai 0:5b88d5760320 521 st->st_mode = 0;
kenjiArai 0:5b88d5760320 522 st->st_mode |= (f.fattrib & AM_DIR) ? S_IFDIR : S_IFREG;
kenjiArai 0:5b88d5760320 523 st->st_mode |= (f.fattrib & AM_RDO) ?
kenjiArai 0:5b88d5760320 524 (S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) :
kenjiArai 0:5b88d5760320 525 (S_IRWXU | S_IRWXG | S_IRWXO);
kenjiArai 0:5b88d5760320 526 unlock();
kenjiArai 0:5b88d5760320 527
kenjiArai 0:5b88d5760320 528 return 0;
kenjiArai 0:5b88d5760320 529 }
kenjiArai 0:5b88d5760320 530
kenjiArai 0:5b88d5760320 531 int FATFileSystem::statvfs(const char *path, struct statvfs *buf)
kenjiArai 0:5b88d5760320 532 {
kenjiArai 0:5b88d5760320 533
kenjiArai 0:5b88d5760320 534 memset(buf, 0, sizeof(struct statvfs));
kenjiArai 0:5b88d5760320 535 FATFS *fs;
kenjiArai 0:5b88d5760320 536 DWORD fre_clust;
kenjiArai 0:5b88d5760320 537
kenjiArai 0:5b88d5760320 538 lock();
kenjiArai 0:5b88d5760320 539 FRESULT res = f_getfree(_fsid, &fre_clust, &fs);
kenjiArai 0:5b88d5760320 540 if (res != FR_OK) {
kenjiArai 0:5b88d5760320 541 unlock();
kenjiArai 0:5b88d5760320 542 return fat_error_remap(res);
kenjiArai 0:5b88d5760320 543 }
kenjiArai 0:5b88d5760320 544
kenjiArai 0:5b88d5760320 545 buf->f_bsize = fs->ssize;
kenjiArai 0:5b88d5760320 546 buf->f_frsize = fs->ssize;
kenjiArai 0:5b88d5760320 547 buf->f_blocks = (fs->n_fatent - 2) * fs->csize;
kenjiArai 0:5b88d5760320 548 buf->f_bfree = fre_clust * fs->csize;
kenjiArai 0:5b88d5760320 549 buf->f_bavail = buf->f_bfree;
kenjiArai 0:5b88d5760320 550 #if FF_USE_LFN
kenjiArai 0:5b88d5760320 551 buf->f_namemax = FF_LFN_BUF;
kenjiArai 0:5b88d5760320 552 #else
kenjiArai 0:5b88d5760320 553 buf->f_namemax = FF_SFN_BUF;
kenjiArai 0:5b88d5760320 554 #endif
kenjiArai 0:5b88d5760320 555
kenjiArai 0:5b88d5760320 556 unlock();
kenjiArai 0:5b88d5760320 557 return 0;
kenjiArai 0:5b88d5760320 558 }
kenjiArai 0:5b88d5760320 559
kenjiArai 0:5b88d5760320 560 void FATFileSystem::lock()
kenjiArai 0:5b88d5760320 561 {
kenjiArai 0:5b88d5760320 562 _ffs_mutex->lock();
kenjiArai 0:5b88d5760320 563 }
kenjiArai 0:5b88d5760320 564
kenjiArai 0:5b88d5760320 565 void FATFileSystem::unlock()
kenjiArai 0:5b88d5760320 566 {
kenjiArai 0:5b88d5760320 567 _ffs_mutex->unlock();
kenjiArai 0:5b88d5760320 568 }
kenjiArai 0:5b88d5760320 569
kenjiArai 0:5b88d5760320 570
kenjiArai 0:5b88d5760320 571 ////// File operations //////
kenjiArai 0:5b88d5760320 572 int FATFileSystem::file_open(fs_file_t *file, const char *path, int flags)
kenjiArai 0:5b88d5760320 573 {
kenjiArai 0:5b88d5760320 574 debug_if(FFS_DBG, "open(%s) on filesystem [%s], drv [%d]\n", path, getName(), _id);
kenjiArai 0:5b88d5760320 575
kenjiArai 0:5b88d5760320 576 FIL *fh = new FIL;
kenjiArai 0:5b88d5760320 577 Deferred<const char *> fpath = fat_path_prefix(_id, path);
kenjiArai 0:5b88d5760320 578
kenjiArai 0:5b88d5760320 579 /* POSIX flags -> FatFS open mode */
kenjiArai 0:5b88d5760320 580 BYTE openmode;
kenjiArai 0:5b88d5760320 581 if (flags & O_RDWR) {
kenjiArai 0:5b88d5760320 582 openmode = FA_READ | FA_WRITE;
kenjiArai 0:5b88d5760320 583 } else if (flags & O_WRONLY) {
kenjiArai 0:5b88d5760320 584 openmode = FA_WRITE;
kenjiArai 0:5b88d5760320 585 } else {
kenjiArai 0:5b88d5760320 586 openmode = FA_READ;
kenjiArai 0:5b88d5760320 587 }
kenjiArai 0:5b88d5760320 588
kenjiArai 0:5b88d5760320 589 if (flags & O_CREAT) {
kenjiArai 0:5b88d5760320 590 if (flags & O_TRUNC) {
kenjiArai 0:5b88d5760320 591 openmode |= FA_CREATE_ALWAYS;
kenjiArai 0:5b88d5760320 592 } else {
kenjiArai 0:5b88d5760320 593 openmode |= FA_OPEN_ALWAYS;
kenjiArai 0:5b88d5760320 594 }
kenjiArai 0:5b88d5760320 595 }
kenjiArai 0:5b88d5760320 596
kenjiArai 0:5b88d5760320 597 if (flags & O_APPEND) {
kenjiArai 0:5b88d5760320 598 openmode |= FA_OPEN_APPEND;
kenjiArai 0:5b88d5760320 599 }
kenjiArai 0:5b88d5760320 600
kenjiArai 0:5b88d5760320 601 lock();
kenjiArai 0:5b88d5760320 602 FRESULT res = f_open(fh, fpath, openmode);
kenjiArai 0:5b88d5760320 603
kenjiArai 0:5b88d5760320 604 if (res != FR_OK) {
kenjiArai 0:5b88d5760320 605 unlock();
kenjiArai 0:5b88d5760320 606 debug_if(FFS_DBG, "f_open('w') failed: %d\n", res);
kenjiArai 0:5b88d5760320 607 delete fh;
kenjiArai 0:5b88d5760320 608 return fat_error_remap(res);
kenjiArai 0:5b88d5760320 609 }
kenjiArai 0:5b88d5760320 610
kenjiArai 0:5b88d5760320 611 unlock();
kenjiArai 0:5b88d5760320 612
kenjiArai 0:5b88d5760320 613 *file = fh;
kenjiArai 0:5b88d5760320 614 return 0;
kenjiArai 0:5b88d5760320 615 }
kenjiArai 0:5b88d5760320 616
kenjiArai 0:5b88d5760320 617 int FATFileSystem::file_close(fs_file_t file)
kenjiArai 0:5b88d5760320 618 {
kenjiArai 0:5b88d5760320 619 FIL *fh = static_cast<FIL *>(file);
kenjiArai 0:5b88d5760320 620
kenjiArai 0:5b88d5760320 621 lock();
kenjiArai 0:5b88d5760320 622 FRESULT res = f_close(fh);
kenjiArai 0:5b88d5760320 623 unlock();
kenjiArai 0:5b88d5760320 624
kenjiArai 0:5b88d5760320 625 delete fh;
kenjiArai 0:5b88d5760320 626 return fat_error_remap(res);
kenjiArai 0:5b88d5760320 627 }
kenjiArai 0:5b88d5760320 628
kenjiArai 0:5b88d5760320 629 ssize_t FATFileSystem::file_read(fs_file_t file, void *buffer, size_t len)
kenjiArai 0:5b88d5760320 630 {
kenjiArai 0:5b88d5760320 631 FIL *fh = static_cast<FIL *>(file);
kenjiArai 0:5b88d5760320 632
kenjiArai 0:5b88d5760320 633 lock();
kenjiArai 0:5b88d5760320 634 UINT n;
kenjiArai 0:5b88d5760320 635 FRESULT res = f_read(fh, buffer, len, &n);
kenjiArai 0:5b88d5760320 636 unlock();
kenjiArai 0:5b88d5760320 637
kenjiArai 0:5b88d5760320 638 if (res != FR_OK) {
kenjiArai 0:5b88d5760320 639 debug_if(FFS_DBG, "f_read() failed: %d\n", res);
kenjiArai 0:5b88d5760320 640 return fat_error_remap(res);
kenjiArai 0:5b88d5760320 641 } else {
kenjiArai 0:5b88d5760320 642 return n;
kenjiArai 0:5b88d5760320 643 }
kenjiArai 0:5b88d5760320 644 }
kenjiArai 0:5b88d5760320 645
kenjiArai 0:5b88d5760320 646 ssize_t FATFileSystem::file_write(fs_file_t file, const void *buffer, size_t len)
kenjiArai 0:5b88d5760320 647 {
kenjiArai 0:5b88d5760320 648 FIL *fh = static_cast<FIL *>(file);
kenjiArai 0:5b88d5760320 649
kenjiArai 0:5b88d5760320 650 lock();
kenjiArai 0:5b88d5760320 651 UINT n;
kenjiArai 0:5b88d5760320 652 FRESULT res = f_write(fh, buffer, len, &n);
kenjiArai 0:5b88d5760320 653 unlock();
kenjiArai 0:5b88d5760320 654
kenjiArai 0:5b88d5760320 655 if (res != FR_OK) {
kenjiArai 0:5b88d5760320 656 debug_if(FFS_DBG, "f_write() failed: %d", res);
kenjiArai 0:5b88d5760320 657 return fat_error_remap(res);
kenjiArai 0:5b88d5760320 658 } else {
kenjiArai 0:5b88d5760320 659 return n;
kenjiArai 0:5b88d5760320 660 }
kenjiArai 0:5b88d5760320 661 }
kenjiArai 0:5b88d5760320 662
kenjiArai 0:5b88d5760320 663 int FATFileSystem::file_sync(fs_file_t file)
kenjiArai 0:5b88d5760320 664 {
kenjiArai 0:5b88d5760320 665 FIL *fh = static_cast<FIL *>(file);
kenjiArai 0:5b88d5760320 666
kenjiArai 0:5b88d5760320 667 lock();
kenjiArai 0:5b88d5760320 668 FRESULT res = f_sync(fh);
kenjiArai 0:5b88d5760320 669 unlock();
kenjiArai 0:5b88d5760320 670
kenjiArai 0:5b88d5760320 671 if (res != FR_OK) {
kenjiArai 0:5b88d5760320 672 debug_if(FFS_DBG, "f_sync() failed: %d\n", res);
kenjiArai 0:5b88d5760320 673 }
kenjiArai 0:5b88d5760320 674 return fat_error_remap(res);
kenjiArai 0:5b88d5760320 675 }
kenjiArai 0:5b88d5760320 676
kenjiArai 0:5b88d5760320 677 off_t FATFileSystem::file_seek(fs_file_t file, off_t offset, int whence)
kenjiArai 0:5b88d5760320 678 {
kenjiArai 0:5b88d5760320 679 FIL *fh = static_cast<FIL *>(file);
kenjiArai 0:5b88d5760320 680
kenjiArai 0:5b88d5760320 681 lock();
kenjiArai 0:5b88d5760320 682 if (whence == SEEK_END) {
kenjiArai 0:5b88d5760320 683 offset += f_size(fh);
kenjiArai 0:5b88d5760320 684 } else if (whence == SEEK_CUR) {
kenjiArai 0:5b88d5760320 685 offset += f_tell(fh);
kenjiArai 0:5b88d5760320 686 }
kenjiArai 0:5b88d5760320 687
kenjiArai 0:5b88d5760320 688 FRESULT res = f_lseek(fh, offset);
kenjiArai 0:5b88d5760320 689 off_t noffset = fh->fptr;
kenjiArai 0:5b88d5760320 690 unlock();
kenjiArai 0:5b88d5760320 691
kenjiArai 0:5b88d5760320 692 if (res != FR_OK) {
kenjiArai 0:5b88d5760320 693 debug_if(FFS_DBG, "lseek failed: %d\n", res);
kenjiArai 0:5b88d5760320 694 return fat_error_remap(res);
kenjiArai 0:5b88d5760320 695 } else {
kenjiArai 0:5b88d5760320 696 return noffset;
kenjiArai 0:5b88d5760320 697 }
kenjiArai 0:5b88d5760320 698 }
kenjiArai 0:5b88d5760320 699
kenjiArai 0:5b88d5760320 700 off_t FATFileSystem::file_tell(fs_file_t file)
kenjiArai 0:5b88d5760320 701 {
kenjiArai 0:5b88d5760320 702 FIL *fh = static_cast<FIL *>(file);
kenjiArai 0:5b88d5760320 703
kenjiArai 0:5b88d5760320 704 lock();
kenjiArai 0:5b88d5760320 705 off_t res = f_tell(fh);
kenjiArai 0:5b88d5760320 706 unlock();
kenjiArai 0:5b88d5760320 707
kenjiArai 0:5b88d5760320 708 return res;
kenjiArai 0:5b88d5760320 709 }
kenjiArai 0:5b88d5760320 710
kenjiArai 0:5b88d5760320 711 off_t FATFileSystem::file_size(fs_file_t file)
kenjiArai 0:5b88d5760320 712 {
kenjiArai 0:5b88d5760320 713 FIL *fh = static_cast<FIL *>(file);
kenjiArai 0:5b88d5760320 714
kenjiArai 0:5b88d5760320 715 lock();
kenjiArai 0:5b88d5760320 716 off_t res = f_size(fh);
kenjiArai 0:5b88d5760320 717 unlock();
kenjiArai 0:5b88d5760320 718
kenjiArai 0:5b88d5760320 719 return res;
kenjiArai 0:5b88d5760320 720 }
kenjiArai 0:5b88d5760320 721
kenjiArai 0:5b88d5760320 722 int FATFileSystem::file_truncate(fs_file_t file, off_t length)
kenjiArai 0:5b88d5760320 723 {
kenjiArai 0:5b88d5760320 724 FIL *fh = static_cast<FIL *>(file);
kenjiArai 0:5b88d5760320 725
kenjiArai 0:5b88d5760320 726 lock();
kenjiArai 0:5b88d5760320 727 // save current position
kenjiArai 0:5b88d5760320 728 FSIZE_t oldoff = f_tell(fh);
kenjiArai 0:5b88d5760320 729
kenjiArai 0:5b88d5760320 730 // seek to new file size and truncate
kenjiArai 0:5b88d5760320 731 FRESULT res = f_lseek(fh, length);
kenjiArai 0:5b88d5760320 732 if (res) {
kenjiArai 0:5b88d5760320 733 unlock();
kenjiArai 0:5b88d5760320 734 return fat_error_remap(res);
kenjiArai 0:5b88d5760320 735 }
kenjiArai 0:5b88d5760320 736
kenjiArai 0:5b88d5760320 737 res = f_truncate(fh);
kenjiArai 0:5b88d5760320 738 if (res) {
kenjiArai 0:5b88d5760320 739 unlock();
kenjiArai 0:5b88d5760320 740 return fat_error_remap(res);
kenjiArai 0:5b88d5760320 741 }
kenjiArai 0:5b88d5760320 742
kenjiArai 0:5b88d5760320 743 // restore old position
kenjiArai 0:5b88d5760320 744 res = f_lseek(fh, oldoff);
kenjiArai 0:5b88d5760320 745 if (res) {
kenjiArai 0:5b88d5760320 746 unlock();
kenjiArai 0:5b88d5760320 747 return fat_error_remap(res);
kenjiArai 0:5b88d5760320 748 }
kenjiArai 0:5b88d5760320 749
kenjiArai 0:5b88d5760320 750 return 0;
kenjiArai 0:5b88d5760320 751 }
kenjiArai 0:5b88d5760320 752
kenjiArai 0:5b88d5760320 753
kenjiArai 0:5b88d5760320 754 ////// Dir operations //////
kenjiArai 0:5b88d5760320 755 int FATFileSystem::dir_open(fs_dir_t *dir, const char *path)
kenjiArai 0:5b88d5760320 756 {
kenjiArai 0:5b88d5760320 757 FATFS_DIR *dh = new FATFS_DIR;
kenjiArai 0:5b88d5760320 758 Deferred<const char *> fpath = fat_path_prefix(_id, path);
kenjiArai 0:5b88d5760320 759
kenjiArai 0:5b88d5760320 760 lock();
kenjiArai 0:5b88d5760320 761 FRESULT res = f_opendir(dh, fpath);
kenjiArai 0:5b88d5760320 762 unlock();
kenjiArai 0:5b88d5760320 763
kenjiArai 0:5b88d5760320 764 if (res != FR_OK) {
kenjiArai 0:5b88d5760320 765 debug_if(FFS_DBG, "f_opendir() failed: %d\n", res);
kenjiArai 0:5b88d5760320 766 delete dh;
kenjiArai 0:5b88d5760320 767 return fat_error_remap(res);
kenjiArai 0:5b88d5760320 768 }
kenjiArai 0:5b88d5760320 769
kenjiArai 0:5b88d5760320 770 *dir = dh;
kenjiArai 0:5b88d5760320 771 return 0;
kenjiArai 0:5b88d5760320 772 }
kenjiArai 0:5b88d5760320 773
kenjiArai 0:5b88d5760320 774 int FATFileSystem::dir_close(fs_dir_t dir)
kenjiArai 0:5b88d5760320 775 {
kenjiArai 0:5b88d5760320 776 FATFS_DIR *dh = static_cast<FATFS_DIR *>(dir);
kenjiArai 0:5b88d5760320 777
kenjiArai 0:5b88d5760320 778 lock();
kenjiArai 0:5b88d5760320 779 FRESULT res = f_closedir(dh);
kenjiArai 0:5b88d5760320 780 unlock();
kenjiArai 0:5b88d5760320 781
kenjiArai 0:5b88d5760320 782 delete dh;
kenjiArai 0:5b88d5760320 783 return fat_error_remap(res);
kenjiArai 0:5b88d5760320 784 }
kenjiArai 0:5b88d5760320 785
kenjiArai 0:5b88d5760320 786 ssize_t FATFileSystem::dir_read(fs_dir_t dir, struct dirent *ent)
kenjiArai 0:5b88d5760320 787 {
kenjiArai 0:5b88d5760320 788 FATFS_DIR *dh = static_cast<FATFS_DIR *>(dir);
kenjiArai 0:5b88d5760320 789 FILINFO finfo;
kenjiArai 0:5b88d5760320 790
kenjiArai 0:5b88d5760320 791 lock();
kenjiArai 0:5b88d5760320 792 FRESULT res = f_readdir(dh, &finfo);
kenjiArai 0:5b88d5760320 793 unlock();
kenjiArai 0:5b88d5760320 794
kenjiArai 0:5b88d5760320 795 if (res != FR_OK) {
kenjiArai 0:5b88d5760320 796 return fat_error_remap(res);
kenjiArai 0:5b88d5760320 797 } else if (finfo.fname[0] == 0) {
kenjiArai 0:5b88d5760320 798 return 0;
kenjiArai 0:5b88d5760320 799 }
kenjiArai 0:5b88d5760320 800
kenjiArai 0:5b88d5760320 801 ent->d_type = (finfo.fattrib & AM_DIR) ? DT_DIR : DT_REG;
kenjiArai 0:5b88d5760320 802
kenjiArai 0:5b88d5760320 803 #if FF_USE_LFN
kenjiArai 0:5b88d5760320 804 if (ent->d_name[0] == 0) {
kenjiArai 0:5b88d5760320 805 // No long filename so use short filename.
kenjiArai 0:5b88d5760320 806 strncpy(ent->d_name, finfo.fname, FF_LFN_BUF);
kenjiArai 0:5b88d5760320 807 }
kenjiArai 0:5b88d5760320 808 #else
kenjiArai 0:5b88d5760320 809 strncpy(ent->d_name, finfo.fname, FF_SFN_BUF);
kenjiArai 0:5b88d5760320 810 #endif
kenjiArai 0:5b88d5760320 811
kenjiArai 0:5b88d5760320 812 return 1;
kenjiArai 0:5b88d5760320 813 }
kenjiArai 0:5b88d5760320 814
kenjiArai 0:5b88d5760320 815 void FATFileSystem::dir_seek(fs_dir_t dir, off_t offset)
kenjiArai 0:5b88d5760320 816 {
kenjiArai 0:5b88d5760320 817 FATFS_DIR *dh = static_cast<FATFS_DIR *>(dir);
kenjiArai 0:5b88d5760320 818 off_t dptr = static_cast<off_t>(dh->dptr);
kenjiArai 0:5b88d5760320 819
kenjiArai 0:5b88d5760320 820 lock();
kenjiArai 0:5b88d5760320 821
kenjiArai 0:5b88d5760320 822 if (offset < dptr) {
kenjiArai 0:5b88d5760320 823 f_rewinddir(dh);
kenjiArai 0:5b88d5760320 824 }
kenjiArai 0:5b88d5760320 825 while (dptr < offset) {
kenjiArai 0:5b88d5760320 826 FILINFO finfo;
kenjiArai 0:5b88d5760320 827 FRESULT res;
kenjiArai 0:5b88d5760320 828
kenjiArai 0:5b88d5760320 829 res = f_readdir(dh, &finfo);
kenjiArai 0:5b88d5760320 830 dptr = dh->dptr;
kenjiArai 0:5b88d5760320 831 if (res != FR_OK) {
kenjiArai 0:5b88d5760320 832 break;
kenjiArai 0:5b88d5760320 833 } else if (finfo.fname[0] == 0) {
kenjiArai 0:5b88d5760320 834 break;
kenjiArai 0:5b88d5760320 835 }
kenjiArai 0:5b88d5760320 836 }
kenjiArai 0:5b88d5760320 837 unlock();
kenjiArai 0:5b88d5760320 838 }
kenjiArai 0:5b88d5760320 839
kenjiArai 0:5b88d5760320 840 off_t FATFileSystem::dir_tell(fs_dir_t dir)
kenjiArai 0:5b88d5760320 841 {
kenjiArai 0:5b88d5760320 842 FATFS_DIR *dh = static_cast<FATFS_DIR *>(dir);
kenjiArai 0:5b88d5760320 843
kenjiArai 0:5b88d5760320 844 lock();
kenjiArai 0:5b88d5760320 845 off_t offset = dh->dptr;
kenjiArai 0:5b88d5760320 846 unlock();
kenjiArai 0:5b88d5760320 847
kenjiArai 0:5b88d5760320 848 return offset;
kenjiArai 0:5b88d5760320 849 }
kenjiArai 0:5b88d5760320 850
kenjiArai 0:5b88d5760320 851 void FATFileSystem::dir_rewind(fs_dir_t dir)
kenjiArai 0:5b88d5760320 852 {
kenjiArai 0:5b88d5760320 853 FATFS_DIR *dh = static_cast<FATFS_DIR *>(dir);
kenjiArai 0:5b88d5760320 854
kenjiArai 0:5b88d5760320 855 lock();
kenjiArai 0:5b88d5760320 856 f_rewinddir(dh);
kenjiArai 0:5b88d5760320 857 unlock();
kenjiArai 0:5b88d5760320 858 }
kenjiArai 0:5b88d5760320 859
kenjiArai 0:5b88d5760320 860 } // namespace mbed