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