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