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