mbed-os5 only for TYBLE16
Dependents: TYBLE16_simple_data_logger TYBLE16_MP3_Air
features/storage/filesystem/fat/FATFileSystem.cpp@1:9db0e321a9f4, 2019-12-31 (annotated)
- 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?
User | Revision | Line number | New 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 |