summaryrefslogtreecommitdiff
path: root/firmware/drivers/fat.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/drivers/fat.c')
-rw-r--r--firmware/drivers/fat.c4206
1 files changed, 2230 insertions, 1976 deletions
diff --git a/firmware/drivers/fat.c b/firmware/drivers/fat.c
index fb75355898..44e5ab2f4c 100644
--- a/firmware/drivers/fat.c
+++ b/firmware/drivers/fat.c
@@ -8,6 +8,7 @@
8 * $Id$ 8 * $Id$
9 * 9 *
10 * Copyright (C) 2002 by Linus Nielsen Feltzing 10 * Copyright (C) 2002 by Linus Nielsen Feltzing
11 * Copyright (C) 2014 by Michael Sevakis
11 * 12 *
12 * This program is free software; you can redistribute it and/or 13 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License 14 * modify it under the terms of the GNU General Public License
@@ -18,27 +19,44 @@
18 * KIND, either express or implied. 19 * KIND, either express or implied.
19 * 20 *
20 ****************************************************************************/ 21 ****************************************************************************/
21#include <stdio.h> 22#include "config.h"
23#include "system.h"
24#include "sys/types.h"
22#include <string.h> 25#include <string.h>
23#include <stdlib.h>
24#include <ctype.h> 26#include <ctype.h>
25#include <stdbool.h> 27#include <stdlib.h>
26#include "fat.h" 28#include <stdio.h>
29#include "fs_attr.h"
30#include "pathfuncs.h"
31#include "disk_cache.h"
32#include "file_internal.h" /* for struct filestr_cache */
27#include "storage.h" 33#include "storage.h"
28#include "debug.h"
29#include "panic.h"
30#include "system.h"
31#include "timefuncs.h" 34#include "timefuncs.h"
32#include "kernel.h"
33#include "rbunicode.h" 35#include "rbunicode.h"
36#include "debug.h"
37#include "panic.h"
34/*#define LOGF_ENABLE*/ 38/*#define LOGF_ENABLE*/
35#include "logf.h" 39#include "logf.h"
36 40
37#define BYTES2INT16(array,pos) \ 41#define BYTES2INT32(array, pos) \
38 (array[pos] | (array[pos+1] << 8 )) 42 (((uint32_t)array[pos+0] << 0) | \
39#define BYTES2INT32(array,pos) \ 43 ((uint32_t)array[pos+1] << 8) | \
40 ((long)array[pos] | ((long)array[pos+1] << 8 ) | \ 44 ((uint32_t)array[pos+2] << 16) | \
41 ((long)array[pos+2] << 16 ) | ((long)array[pos+3] << 24 )) 45 ((uint32_t)array[pos+3] << 24))
46
47#define INT322BYTES(array, pos, val) \
48 ((array[pos+0] = (uint32_t)(val) >> 0), \
49 (array[pos+1] = (uint32_t)(val) >> 8), \
50 (array[pos+2] = (uint32_t)(val) >> 16), \
51 (array[pos+3] = (uint32_t)(val) >> 24))
52
53#define BYTES2INT16(array, pos) \
54 (((uint32_t)array[pos+0] << 0) | \
55 ((uint32_t)array[pos+1] << 8))
56
57#define INT162BYTES(array, pos, val) \
58 ((array[pos+0] = (uint16_t)(val) >> 0), \
59 (array[pos+1] = (uint16_t)(val) >> 8))
42 60
43#define FATTYPE_FAT12 0 61#define FATTYPE_FAT12 0
44#define FATTYPE_FAT16 1 62#define FATTYPE_FAT16 1
@@ -83,82 +101,129 @@
83 101
84#define BPB_LAST_WORD 510 102#define BPB_LAST_WORD 510
85 103
104/* Short and long name directory entry template */
105union raw_dirent
106{
107 struct /* short entry */
108 {
109 uint8_t name[8+3]; /* 0 */
110 uint8_t attr; /* 11 */
111 uint8_t ntres; /* 12 */
112 uint8_t crttimetenth; /* 13 */
113 uint16_t crttime; /* 14 */
114 uint16_t crtdate; /* 16 */
115 uint16_t lstaccdate; /* 18 */
116 uint16_t fstclushi; /* 20 */
117 uint16_t wrttime; /* 22 */
118 uint16_t wrtdate; /* 24 */
119 uint16_t fstcluslo; /* 26 */
120 uint32_t filesize; /* 28 */
121 /* 32 */
122 };
123 struct /* long entry */
124 {
125 uint8_t ldir_ord; /* 0 */
126 uint8_t ldir_name1[10]; /* 1 */
127 uint8_t ldir_attr; /* 11 */
128 uint8_t ldir_type; /* 12 */
129 uint8_t ldir_chksum; /* 13 */
130 uint8_t ldir_name2[12]; /* 14 */
131 uint16_t ldir_fstcluslo; /* 26 */
132 uint8_t ldir_name3[4]; /* 28 */
133 /* 32 */
134 };
135 struct /* raw byte array */
136 {
137 uint8_t data[32]; /* 0 */
138 /* 32 */
139 };
140};
141
142
143/* at most 20 LFN entries */
144#define FATLONG_MAX_ORDER 20
145#define FATLONG_NAME_CHARS 13
146#define FATLONG_ORD_F_LAST 0x40
86 147
87/* attributes */ 148/* attributes */
88#define FAT_ATTR_LONG_NAME (FAT_ATTR_READ_ONLY | FAT_ATTR_HIDDEN | \ 149#define ATTR_LONG_NAME (ATTR_READ_ONLY | ATTR_HIDDEN | \
89 FAT_ATTR_SYSTEM | FAT_ATTR_VOLUME_ID) 150 ATTR_SYSTEM | ATTR_VOLUME_ID)
90#define FAT_ATTR_LONG_NAME_MASK (FAT_ATTR_READ_ONLY | FAT_ATTR_HIDDEN | \ 151#define ATTR_LONG_NAME_MASK (ATTR_READ_ONLY | ATTR_HIDDEN | \
91 FAT_ATTR_SYSTEM | FAT_ATTR_VOLUME_ID | \ 152 ATTR_SYSTEM | ATTR_VOLUME_ID | \
92 FAT_ATTR_DIRECTORY | FAT_ATTR_ARCHIVE ) 153 ATTR_DIRECTORY | ATTR_ARCHIVE )
154
155#define IS_LDIR_ATTR(attr) \
156 (((attr) & ATTR_LONG_NAME_MASK) == ATTR_LONG_NAME)
157
158#define IS_VOL_ID_ATTR(attr) \
159 (((attr) & (ATTR_VOLUME_ID | ATTR_DIRECTORY)) == ATTR_VOLUME_ID)
93 160
94/* NTRES flags */ 161/* NTRES flags */
95#define FAT_NTRES_LC_NAME 0x08 162#define FAT_NTRES_LC_NAME 0x08
96#define FAT_NTRES_LC_EXT 0x10 163#define FAT_NTRES_LC_EXT 0x10
97 164
98#define FATDIR_NAME 0 165#define CLUSTERS_PER_FAT_SECTOR (SECTOR_SIZE / 4)
99#define FATDIR_ATTR 11 166#define CLUSTERS_PER_FAT16_SECTOR (SECTOR_SIZE / 2)
100#define FATDIR_NTRES 12 167#define DIR_ENTRIES_PER_SECTOR (SECTOR_SIZE / DIR_ENTRY_SIZE)
101#define FATDIR_CRTTIMETENTH 13 168#define DIR_ENTRY_SIZE 32
102#define FATDIR_CRTTIME 14 169#define FAT_BAD_MARK 0x0ffffff7
103#define FATDIR_CRTDATE 16 170#define FAT_EOF_MARK 0x0ffffff8
104#define FATDIR_LSTACCDATE 18 171#define FAT16_BAD_MARK 0xfff7
105#define FATDIR_FSTCLUSHI 20 172#define FAT16_EOF_MARK 0xfff8
106#define FATDIR_WRTTIME 22 173
107#define FATDIR_WRTDATE 24 174struct fsinfo
108#define FATDIR_FSTCLUSLO 26 175{
109#define FATDIR_FILESIZE 28 176 unsigned long freecount; /* last known free cluster count */
110 177 unsigned long nextfree; /* first cluster to start looking for free
111#define FATLONG_ORDER 0 178 clusters, or 0xffffffff for no hint */
112#define FATLONG_TYPE 12
113#define FATLONG_CHKSUM 13
114#define FATLONG_LAST_LONG_ENTRY 0x40
115#define FATLONG_NAME_BYTES_PER_ENTRY 26
116/* at most 20 LFN entries, keep coherent with fat_dir->longname size ! */
117#define FATLONG_MAX_ORDER 20
118
119#define FATLONG_NAME_CHUNKS 3
120static unsigned char FATLONG_NAME_POS[FATLONG_NAME_CHUNKS] = {1, 14, 28};
121static unsigned char FATLONG_NAME_SIZE[FATLONG_NAME_CHUNKS] = {10, 12, 4};
122
123#define CLUSTERS_PER_FAT_SECTOR (SECTOR_SIZE / 4)
124#define CLUSTERS_PER_FAT16_SECTOR (SECTOR_SIZE / 2)
125#define DIR_ENTRIES_PER_SECTOR (SECTOR_SIZE / DIR_ENTRY_SIZE)
126#define DIR_ENTRY_SIZE 32
127#define NAME_BYTES_PER_ENTRY 13
128#define FAT_BAD_MARK 0x0ffffff7
129#define FAT_EOF_MARK 0x0ffffff8
130#define FAT_LONGNAME_PAD_BYTE 0xff
131#define FAT_LONGNAME_PAD_UCS 0xffff
132
133struct fsinfo {
134 uint32_t freecount; /* last known free cluster count */
135 uint32_t nextfree; /* first cluster to start looking for free
136 clusters, or 0xffffffff for no hint */
137}; 179};
138/* fsinfo offsets */ 180/* fsinfo offsets */
139#define FSINFO_FREECOUNT 488 181#define FSINFO_FREECOUNT 488
140#define FSINFO_NEXTFREE 492 182#define FSINFO_NEXTFREE 492
141 183
184#ifdef HAVE_FAT16SUPPORT
185#define BPB_FN_SET16(bpb, fn) (bpb)->fn##__ = fn##16
186#define BPB_FN_SET32(bpb, fn) (bpb)->fn##__ = fn##32
187#define BPB_FN_DECL(fn, args...) (*fn##__)(struct bpb *bpb , ##args)
188#define BPB_CALL(fn, bpb, args...) ((bpb)->fn##__(bpb , ##args))
189
190#define get_next_cluster(bpb, cluster) \
191 BPB_CALL(get_next_cluster, (bpb), (cluster))
192#define find_free_cluster(bpb, startcluster) \
193 BPB_CALL(find_free_cluster, (bpb), (startcluster))
194#define update_fat_entry(bpb, entry, value) \
195 BPB_CALL(update_fat_entry, (bpb), (entry), (value))
196#define fat_recalc_free_internal(bpb) \
197 BPB_CALL(fat_recalc_free_internal, (bpb))
198#else /* !HAVE_FAT16SUPPORT */
199#define get_next_cluster get_next_cluster32
200#define find_free_cluster find_free_cluster32
201#define update_fat_entry update_fat_entry32
202#define fat_recalc_free_internal fat_recalc_free_internal32
203#endif /* HAVE_FAT16SUPPORT */
204struct bpb;
205static void update_fsinfo32(struct bpb *fat_bpb);
206
142/* Note: This struct doesn't hold the raw values after mounting if 207/* Note: This struct doesn't hold the raw values after mounting if
143 * bpb_bytspersec isn't 512. All sector counts are normalized to 512 byte 208 * bpb_bytspersec isn't 512. All sector counts are normalized to 512 byte
144 * physical sectors. */ 209 * physical sectors. */
145struct bpb 210static struct bpb
146{ 211{
147 int bpb_bytspersec; /* Bytes per sector, typically 512 */ 212 unsigned long bpb_bytspersec; /* Bytes per sector, typically 512 */
148 unsigned int bpb_secperclus; /* Sectors per cluster */ 213 unsigned long bpb_secperclus; /* Sectors per cluster */
149 int bpb_rsvdseccnt; /* Number of reserved sectors */ 214 unsigned long bpb_rsvdseccnt; /* Number of reserved sectors */
150 int bpb_numfats; /* Number of FAT structures, typically 2 */ 215 unsigned long bpb_totsec16; /* Number of sectors on volume (old 16-bit) */
151 int bpb_totsec16; /* Number of sectors on the volume (old 16-bit) */ 216 uint8_t bpb_numfats; /* Number of FAT structures, typically 2 */
152 int bpb_media; /* Media type (typically 0xf0 or 0xf8) */ 217 uint8_t bpb_media; /* Media type (typically 0xf0 or 0xf8) */
153 int bpb_fatsz16; /* Number of used sectors per FAT structure */ 218 uint16_t bpb_fatsz16; /* Number of used sectors per FAT structure */
154 unsigned long bpb_totsec32; /* Number of sectors on the volume 219 unsigned long bpb_totsec32; /* Number of sectors on the volume
155 (new 32-bit) */ 220 (new 32-bit) */
156 unsigned int last_word; /* 0xAA55 */ 221 uint16_t last_word; /* 0xAA55 */
222 long bpb_rootclus;
157 223
158 /**** FAT32 specific *****/ 224 /**** FAT32 specific *****/
159 long bpb_fatsz32; 225 unsigned long bpb_fatsz32;
160 long bpb_rootclus; 226 unsigned long bpb_fsinfo;
161 long bpb_fsinfo;
162 227
163 /* variables for internal use */ 228 /* variables for internal use */
164 unsigned long fatsize; 229 unsigned long fatsize;
@@ -167,936 +232,1246 @@ struct bpb
167 unsigned long firstdatasector; 232 unsigned long firstdatasector;
168 unsigned long startsector; 233 unsigned long startsector;
169 unsigned long dataclusters; 234 unsigned long dataclusters;
235 unsigned long fatrgnstart;
236 unsigned long fatrgnend;
170 struct fsinfo fsinfo; 237 struct fsinfo fsinfo;
171#ifdef HAVE_FAT16SUPPORT 238#ifdef HAVE_FAT16SUPPORT
172 int bpb_rootentcnt; /* Number of dir entries in the root */ 239 unsigned int bpb_rootentcnt; /* Number of dir entries in the root */
173 /* internals for FAT16 support */ 240 /* internals for FAT16 support */
174 bool is_fat16; /* true if we mounted a FAT16 partition, false if FAT32 */ 241 unsigned long rootdirsectornum; /* sector offset of root dir relative to start
175 unsigned int rootdiroffset; /* sector offset of root dir relative to start 242 * of first pseudo cluster */
176 * of first pseudo cluster */ 243#endif /* HAVE_FAT16SUPPORT */
177#endif /* #ifdef HAVE_FAT16SUPPORT */ 244
178#ifdef HAVE_MULTIVOLUME 245 /** Additional information kept for each volume **/
179#ifdef HAVE_MULTIDRIVE 246#ifdef HAVE_FAT16SUPPORT
180 int drive; /* on which physical device is this located */ 247 uint8_t is_fat16; /* true if we mounted a FAT16 partition, false if FAT32 */
181#endif 248#endif
182 bool mounted; /* flag if this volume is mounted */ 249#ifdef HAVE_MULTIDRIVE
250 uint8_t drive; /* on which physical device is this located */
183#endif 251#endif
184};
185
186static struct bpb fat_bpbs[NUM_VOLUMES]; /* mounted partition info */
187static bool initialized = false;
188
189static int update_fsinfo(IF_MV_NONVOID(struct bpb* fat_bpb));
190static int flush_fat(IF_MV_NONVOID(struct bpb* fat_bpb));
191static int bpb_is_sane(IF_MV_NONVOID(struct bpb* fat_bpb));
192static void *cache_fat_sector(IF_MV(struct bpb* fat_bpb,)
193 long secnum, bool dirty);
194static void create_dos_name(const unsigned char *name, unsigned char *newname);
195static void randomize_dos_name(unsigned char *name);
196static unsigned long find_free_cluster(IF_MV(struct bpb* fat_bpb,)
197 unsigned long start);
198static int transfer(IF_MV(struct bpb* fat_bpb,) unsigned long start,
199 long count, char* buf, bool write );
200
201#define FAT_CACHE_SIZE 0x20
202#define FAT_CACHE_MASK (FAT_CACHE_SIZE-1)
203
204struct fat_cache_entry
205{
206 long secnum;
207 bool inuse;
208 bool dirty;
209#ifdef HAVE_MULTIVOLUME 252#ifdef HAVE_MULTIVOLUME
210 struct bpb* fat_vol ; /* shared cache for all volumes */ 253 uint8_t volume; /* on which volume is this located (shortcut) */
211#endif 254#endif
255 uint8_t mounted; /* true if volume is mounted, false otherwise */
256#ifdef HAVE_FAT16SUPPORT
257 /* some functions are different for different FAT types */
258 long BPB_FN_DECL(get_next_cluster, long);
259 long BPB_FN_DECL(find_free_cluster, long);
260 int BPB_FN_DECL(update_fat_entry, unsigned long, unsigned long);
261 void BPB_FN_DECL(fat_recalc_free_internal);
262#endif /* HAVE_FAT16SUPPORT */
263
264} fat_bpbs[NUM_VOLUMES]; /* mounted partition info */
265
266#define IS_FAT_SECTOR(bpb, sector) \
267 (!((sector) >= (bpb)->fatrgnend || (sector) < (bpb)->fatrgnstart))
268
269/* set error code and jump to routine exit */
270#define FAT_ERROR(_rc) \
271 ({ __builtin_constant_p(_rc) ? \
272 ({ if (_rc != RC) rc = (_rc); }) : \
273 ({ rc = (_rc); }); \
274 goto fat_error; })
275
276#define FAT_BPB(volume) \
277 ({ struct bpb * _bpb = &fat_bpbs[IF_MV_VOL(volume)]; \
278 if (!_bpb->mounted) \
279 { \
280 DEBUGF("%s() - volume %d not mounted\n", \
281 __func__, IF_MV_VOL(volume)); \
282 _bpb = NULL; \
283 } \
284 _bpb; })
285
286enum add_dir_entry_flags
287{
288 DIRENT_RETURN = 0x01, /* return the new short entry */
289 DIRENT_TEMPL = 0x0e, /* all TEMPL flags */
290 DIRENT_TEMPL_CRT = 0x02, /* use template crttime */
291 DIRENT_TEMPL_WRT = 0x04, /* use template wrttime */
292 DIRENT_TEMPL_ACC = 0x08, /* use template lstacc time */
293 DIRENT_TEMPL_TIMES = 0x0e, /* keep all time fields */
212}; 294};
213 295
214static char fat_cache_sectors[FAT_CACHE_SIZE][SECTOR_SIZE] CACHEALIGN_ATTR; 296struct fatlong_parse_state
215static struct fat_cache_entry fat_cache[FAT_CACHE_SIZE]; 297{
216static struct mutex cache_mutex SHAREDBSS_ATTR; 298 int ord_max;
217static struct mutex tempbuf_mutex; 299 int ord;
218static char fat_tempbuf[SECTOR_SIZE] CACHEALIGN_ATTR; 300 uint8_t chksum;
219static bool tempbuf_locked; 301};
220 302
221#if defined(HAVE_HOTSWAP) 303static void cache_commit(struct bpb *fat_bpb)
222void fat_lock(void)
223{ 304{
224 mutex_lock(&cache_mutex); 305 dc_lock_cache();
306#ifdef HAVE_FAT16SUPPORT
307 if (!fat_bpb->is_fat16)
308#endif
309 update_fsinfo32(fat_bpb);
310 dc_commit_all(IF_MV(fat_bpb->volume));
311 dc_unlock_cache();
225} 312}
226 313
227void fat_unlock(void) 314static void cache_discard(IF_MV_NONVOID(struct bpb *fat_bpb))
228{ 315{
229 mutex_unlock(&cache_mutex); 316 dc_lock_cache();
317 dc_discard_all(IF_MV(fat_bpb->volume));
318 dc_unlock_cache();
230} 319}
231#endif
232 320
233static long cluster2sec(IF_MV(struct bpb* fat_bpb,) long cluster) 321/* caches a FAT or data area sector */
322static void * cache_sector(struct bpb *fat_bpb, unsigned long secnum)
234{ 323{
235#ifndef HAVE_MULTIVOLUME 324 unsigned int flags;
236 struct bpb* fat_bpb = &fat_bpbs[0]; 325 void *buf = dc_cache_probe(IF_MV(fat_bpb->volume,) secnum, &flags);
237#endif
238#ifdef HAVE_FAT16SUPPORT
239 /* negative clusters (FAT16 root dir) don't get the 2 offset */
240 int zerocluster = cluster < 0 ? 0 : 2;
241#else
242 const long zerocluster = 2;
243#endif
244 326
245 if (cluster > (long)(fat_bpb->dataclusters + 1)) 327 if (!flags)
246 { 328 {
247 DEBUGF( "cluster2sec() - Bad cluster number (%ld)\n", cluster); 329 int rc = storage_read_sectors(IF_MD(fat_bpb->drive,)
248 return -1; 330 secnum + fat_bpb->startsector, 1, buf);
331 if (UNLIKELY(rc < 0))
332 {
333 DEBUGF("%s() - Could not read sector %ld"
334 " (error %d)\n", __func__, secnum, rc);
335 dc_discard_buf(buf);
336 return NULL;
337 }
249 } 338 }
250 339
251 return (cluster - zerocluster) * fat_bpb->bpb_secperclus 340 return buf;
252 + fat_bpb->firstdatasector;
253} 341}
254 342
255void fat_size(IF_MV(int volume,) unsigned long* size, unsigned long* free) 343/* returns a raw buffer for a sector; buffer counts as INUSE but filesystem
344 * contents are NOT loaded before returning - use when completely overwriting
345 * a sector's contents in order to avoid a fill */
346static void * cache_sector_buffer(IF_MV(struct bpb *fat_bpb,)
347 unsigned long secnum)
256{ 348{
257#ifndef HAVE_MULTIVOLUME 349 unsigned int flags;
258 const int volume = 0; 350 return dc_cache_probe(IF_MV(fat_bpb->volume,) secnum, &flags);
259#endif
260 struct bpb* fat_bpb = &fat_bpbs[volume];
261 if (size)
262 *size = fat_bpb->dataclusters * (fat_bpb->bpb_secperclus * SECTOR_SIZE / 1024);
263 if (free)
264 *free = fat_bpb->fsinfo.freecount * (fat_bpb->bpb_secperclus * SECTOR_SIZE / 1024);
265} 351}
266 352
267void fat_init(void) 353/* flush a cache buffer to storage */
354void dc_writeback_callback(IF_MV(int volume,) unsigned long sector, void *buf)
268{ 355{
269 unsigned int i; 356 struct bpb * const fat_bpb = &fat_bpbs[IF_MV_VOL(volume)];
357 unsigned int copies = !IS_FAT_SECTOR(fat_bpb, sector) ?
358 1 : fat_bpb->bpb_numfats;
359
360 sector += fat_bpb->startsector;
270 361
271 if (!initialized) 362 while (1)
272 { 363 {
273 initialized = true; 364 int rc = storage_write_sectors(IF_MD(fat_bpb->drive,) sector, 1, buf);
274 mutex_init(&cache_mutex); 365 if (rc < 0)
275 mutex_init(&tempbuf_mutex); 366 {
276 tempbuf_locked = false; 367 panicf("%s() - Could not write sector %ld"
368 " (error %d)\n", __func__, sector, rc);
369 }
370
371 if (--copies == 0)
372 break;
373
374 /* Update next FAT */
375 sector += fat_bpb->fatsize;
277 } 376 }
377}
278 378
279#ifdef HAVE_PRIORITY_SCHEDULING 379static void raw_dirent_set_fstclus(union raw_dirent *ent, long fstclus)
280 /* Disable this because it is dangerous due to the assumption that 380{
281 * mutex_unlock won't yield */ 381 ent->fstclushi = htole16(fstclus >> 16);
282 mutex_set_preempt(&cache_mutex, false); 382 ent->fstcluslo = htole16(fstclus & 0xffff);
283#endif 383}
284 384
285 /* mark the FAT cache as unused */ 385static int bpb_is_sane(struct bpb *fat_bpb)
286 for(i = 0;i < FAT_CACHE_SIZE;i++) 386{
387 if (fat_bpb->bpb_bytspersec % SECTOR_SIZE)
287 { 388 {
288 fat_cache[i].secnum = 8; /* We use a "safe" sector just in case */ 389 DEBUGF("%s() - Error: sector size is not sane (%lu)\n",
289 fat_cache[i].inuse = false; 390 __func__, fat_bpb->bpb_bytspersec);
290 fat_cache[i].dirty = false; 391 return -1;
291#ifdef HAVE_MULTIVOLUME
292 fat_cache[i].fat_vol = NULL;
293#endif
294 } 392 }
295#ifdef HAVE_MULTIVOLUME 393
296 /* mark the possible volumes as not mounted */ 394 if (fat_bpb->bpb_secperclus * fat_bpb->bpb_bytspersec > 128*1024ul)
297 for (i=0; i<NUM_VOLUMES;i++)
298 { 395 {
299 fat_bpbs[i].mounted = false; 396 DEBUGF("%s() - Error: cluster size is larger than 128K "
397 "(%lu * %lu = %lu)\n", __func__,
398 fat_bpb->bpb_bytspersec, fat_bpb->bpb_secperclus,
399 fat_bpb->bpb_bytspersec * fat_bpb->bpb_secperclus);
400 return -2;
300 } 401 }
301#endif
302}
303 402
304/* fat_mount_internal is split out of fat_mount() to avoid having both the sector 403 if (fat_bpb->bpb_numfats != 2)
305 * buffer used here and the sector buffer used by update_fsinfo() on stack */ 404 {
306static int fat_mount_internal(IF_MV(int volume,) IF_MD(int drive,) long startsector) 405 DEBUGF("%s() - Warning: NumFATS is not 2 (%u)\n",
307{ 406 __func__, fat_bpb->bpb_numfats);
308#ifndef HAVE_MULTIVOLUME 407 }
309 const int volume = 0;
310#endif
311 struct bpb* fat_bpb = &fat_bpbs[volume];
312 int rc;
313 int secmult;
314 long datasec;
315#ifdef HAVE_FAT16SUPPORT
316 int rootdirsectors;
317#endif
318 408
319 unsigned char* buf = fat_get_sector_buffer(); 409 if (fat_bpb->bpb_media != 0xf0 && fat_bpb->bpb_media < 0xf8)
320 /* Read the sector */
321 rc = storage_read_sectors(IF_MD(drive,) startsector,1,buf);
322 if(rc)
323 { 410 {
324 fat_release_sector_buffer(); 411 DEBUGF("%s() - Warning: Non-standard media type "
325 DEBUGF( "fat_mount() - Couldn't read BPB (error code %d)\n", rc); 412 "(0x%02x)\n", __func__, fat_bpb->bpb_media);
326 return rc * 10 - 1;
327 } 413 }
328 414
329 memset(fat_bpb, 0, sizeof(struct bpb)); 415 if (fat_bpb->last_word != 0xaa55)
330 fat_bpb->startsector = startsector; 416 {
331#ifdef HAVE_MULTIDRIVE 417 DEBUGF("%s() - Error: Last word is not "
332 fat_bpb->drive = drive; 418 "0xaa55 (0x%04x)\n", __func__, fat_bpb->last_word);
333#endif 419 return -3;
420 }
334 421
335 fat_bpb->bpb_bytspersec = BYTES2INT16(buf,BPB_BYTSPERSEC); 422 if (fat_bpb->fsinfo.freecount >
336 secmult = fat_bpb->bpb_bytspersec / SECTOR_SIZE; 423 (fat_bpb->totalsectors - fat_bpb->firstdatasector) /
337 /* Sanity check is performed later */ 424 fat_bpb->bpb_secperclus)
425 {
426 DEBUGF("%s() - Error: FSInfo.Freecount > disk size "
427 "(0x%04lx)\n", __func__,
428 (unsigned long)fat_bpb->fsinfo.freecount);
429 return -4;
430 }
338 431
339 fat_bpb->bpb_secperclus = secmult * buf[BPB_SECPERCLUS]; 432 return 0;
340 fat_bpb->bpb_rsvdseccnt = secmult * BYTES2INT16(buf,BPB_RSVDSECCNT); 433}
341 fat_bpb->bpb_numfats = buf[BPB_NUMFATS];
342 fat_bpb->bpb_media = buf[BPB_MEDIA];
343 fat_bpb->bpb_fatsz16 = secmult * BYTES2INT16(buf,BPB_FATSZ16);
344 fat_bpb->bpb_fatsz32 = secmult * BYTES2INT32(buf,BPB_FATSZ32);
345 fat_bpb->bpb_totsec16 = secmult * BYTES2INT16(buf,BPB_TOTSEC16);
346 fat_bpb->bpb_totsec32 = secmult * BYTES2INT32(buf,BPB_TOTSEC32);
347 fat_bpb->last_word = BYTES2INT16(buf,BPB_LAST_WORD);
348 434
349 /* calculate a few commonly used values */ 435static uint8_t shortname_checksum(const unsigned char *shortname)
350 if (fat_bpb->bpb_fatsz16 != 0) 436{
351 fat_bpb->fatsize = fat_bpb->bpb_fatsz16; 437 /* calculate shortname checksum */
352 else 438 uint8_t chksum = 0;
353 fat_bpb->fatsize = fat_bpb->bpb_fatsz32;
354 439
355 if (fat_bpb->bpb_totsec16 != 0) 440 for (unsigned int i = 0; i < 11; i++)
356 fat_bpb->totalsectors = fat_bpb->bpb_totsec16; 441 chksum = (chksum << 7) + (chksum >> 1) + shortname[i];
357 else
358 fat_bpb->totalsectors = fat_bpb->bpb_totsec32;
359 442
360#ifdef HAVE_FAT16SUPPORT 443 return chksum;
361 fat_bpb->bpb_rootentcnt = BYTES2INT16(buf,BPB_ROOTENTCNT); 444}
362 if (!fat_bpb->bpb_bytspersec)
363 {
364 fat_release_sector_buffer();
365 return -2;
366 }
367 rootdirsectors = secmult * ((fat_bpb->bpb_rootentcnt * DIR_ENTRY_SIZE
368 + fat_bpb->bpb_bytspersec - 1) / fat_bpb->bpb_bytspersec);
369#endif /* #ifdef HAVE_FAT16SUPPORT */
370 445
371 fat_bpb->firstdatasector = fat_bpb->bpb_rsvdseccnt 446static void parse_short_direntry(const union raw_dirent *ent,
372#ifdef HAVE_FAT16SUPPORT 447 struct fat_direntry *fatent)
373 + rootdirsectors 448{
374#endif 449 fatent->attr = ent->attr;
375 + fat_bpb->bpb_numfats * fat_bpb->fatsize; 450 fatent->crttimetenth = ent->crttimetenth;
451 fatent->crttime = letoh16(ent->crttime);
452 fatent->crtdate = letoh16(ent->crtdate);
453 fatent->lstaccdate = letoh16(ent->lstaccdate);
454 fatent->wrttime = letoh16(ent->wrttime);
455 fatent->wrtdate = letoh16(ent->wrtdate);
456 fatent->filesize = letoh32(ent->filesize);
457 fatent->firstcluster = ((uint32_t)letoh16(ent->fstcluslo) ) |
458 ((uint32_t)letoh16(ent->fstclushi) << 16);
376 459
377 /* Determine FAT type */ 460 /* fix the name */
378 datasec = fat_bpb->totalsectors - fat_bpb->firstdatasector; 461 bool lowercase = ent->ntres & FAT_NTRES_LC_NAME;
379 if (fat_bpb->bpb_secperclus) 462 unsigned char c = ent->name[0];
380 fat_bpb->dataclusters = datasec / fat_bpb->bpb_secperclus; 463
381 else 464 if (c == 0x05) /* special kanji char */
465 c = 0xe5;
466
467 int j = 0;
468
469 for (int i = 0; c != ' '; c = ent->name[i])
382 { 470 {
383 fat_release_sector_buffer(); 471 fatent->shortname[j++] = lowercase ? tolower(c) : c;
384 return -2;
385 }
386 472
387#ifdef TEST_FAT 473 if (++i >= 8)
388 /* 474 break;
389 we are sometimes testing with "illegally small" fat32 images,
390 so we don't use the proper fat32 test case for test code
391 */
392 if ( fat_bpb->bpb_fatsz16 )
393#else
394 if ( fat_bpb->dataclusters < 65525 )
395#endif
396 { /* FAT16 */
397#ifdef HAVE_FAT16SUPPORT
398 fat_bpb->is_fat16 = true;
399 if (fat_bpb->dataclusters < 4085)
400 { /* FAT12 */
401 fat_release_sector_buffer();
402 DEBUGF("This is FAT12. Go away!\n");
403 return -2;
404 }
405#else /* #ifdef HAVE_FAT16SUPPORT */
406 fat_release_sector_buffer();
407 DEBUGF("This is not FAT32. Go away!\n");
408 return -2;
409#endif /* #ifndef HAVE_FAT16SUPPORT */
410 } 475 }
411 476
412#ifdef HAVE_FAT16SUPPORT 477 if (ent->name[8] != ' ')
413 if (fat_bpb->is_fat16) 478 {
414 { /* FAT16 specific part of BPB */ 479 lowercase = ent->ntres & FAT_NTRES_LC_EXT;
415 int dirclusters; 480 fatent->shortname[j++] = '.';
416 fat_bpb->rootdirsector = fat_bpb->bpb_rsvdseccnt 481
417 + fat_bpb->bpb_numfats * fat_bpb->bpb_fatsz16; 482 for (int i = 8; i < 11 && (c = ent->name[i]) != ' '; i++)
418 dirclusters = ((rootdirsectors + fat_bpb->bpb_secperclus - 1) 483 fatent->shortname[j++] = lowercase ? tolower(c) : c;
419 / fat_bpb->bpb_secperclus); /* rounded up, to full clusters */
420 /* I assign negative pseudo cluster numbers for the root directory,
421 their range is counted upward until -1. */
422 fat_bpb->bpb_rootclus = 0 - dirclusters; /* backwards, before the data*/
423 fat_bpb->rootdiroffset = dirclusters * fat_bpb->bpb_secperclus
424 - rootdirsectors;
425 }
426 else
427#endif /* #ifdef HAVE_FAT16SUPPORT */
428 { /* FAT32 specific part of BPB */
429 fat_bpb->bpb_rootclus = BYTES2INT32(buf,BPB_ROOTCLUS);
430 fat_bpb->bpb_fsinfo = secmult * BYTES2INT16(buf,BPB_FSINFO);
431 fat_bpb->rootdirsector = cluster2sec(IF_MV(fat_bpb,)
432 fat_bpb->bpb_rootclus);
433 } 484 }
434 485
435 rc = bpb_is_sane(IF_MV(fat_bpb)); 486 fatent->shortname[j] = 0;
436 if (rc < 0) 487}
488
489static unsigned char char2dos(unsigned char c, int *np)
490{
491 /* FIXME: needs conversion to OEM charset FIRST but there is currently
492 no unicode function for that! */
493
494 /* smallest tables with one-step lookup that directly map the lists;
495 here we're only concerned with what gets through the longname
496 filter (check_longname will have been called earlier so common
497 illegal chars are neither in these tables nor checked for) */
498 static const unsigned char remove_chars_tbl[3] =
499 { 0, '.', ' ' };
500
501 static const unsigned char replace_chars_tbl[11] =
502 { ',', 0, 0, '[', ';', ']', '=', 0, 0, 0, '+' };
503
504 if (remove_chars_tbl[c % 3] == c)
437 { 505 {
438 fat_release_sector_buffer(); 506 /* Illegal char, remove */
439 DEBUGF( "fat_mount() - BPB is not sane\n"); 507 c = 0;
440 return rc * 10 - 3; 508 *np = 0;
441 } 509 }
442 510 else if (c >= 0x80 || replace_chars_tbl[c % 11] == c)
443#ifdef HAVE_FAT16SUPPORT
444 if (fat_bpb->is_fat16)
445 { 511 {
446 fat_bpb->fsinfo.freecount = 0xffffffff; /* force recalc below */ 512 /* Illegal char, replace (note: NTFS behavior for extended chars) */
447 fat_bpb->fsinfo.nextfree = 0xffffffff; 513 c = '_';
514 *np = 0;
448 } 515 }
449 else 516 else
450#endif /* #ifdef HAVE_FAT16SUPPORT */
451 { 517 {
452 /* Read the fsinfo sector */ 518 c = toupper(c);
453 rc = storage_read_sectors(IF_MD(drive,)
454 startsector + fat_bpb->bpb_fsinfo, 1, buf);
455 if (rc < 0)
456 {
457 fat_release_sector_buffer();
458 DEBUGF( "fat_mount() - Couldn't read FSInfo (error code %d)\n", rc);
459 return rc * 10 - 4;
460 }
461 fat_bpb->fsinfo.freecount = BYTES2INT32(buf, FSINFO_FREECOUNT);
462 fat_bpb->fsinfo.nextfree = BYTES2INT32(buf, FSINFO_NEXTFREE);
463 } 519 }
464 fat_release_sector_buffer();
465 return 0;
466}
467 520
468void* fat_get_sector_buffer() 521 return c;
469{
470 mutex_lock(&tempbuf_mutex);
471 if (tempbuf_locked)
472 panicf("FAT: Tried to lock temporary sector buffer twice!");
473 tempbuf_locked = true;
474 return fat_tempbuf;
475} 522}
476 523
477void fat_release_sector_buffer() 524/* convert long name into dos name, possibly recommending randomization */
525static void create_dos_name(unsigned char *basisname,
526 const unsigned char *name, int *np)
478{ 527{
479 tempbuf_locked = false; 528 int i;
480 mutex_unlock(&tempbuf_mutex); 529
530 /* FIXME: needs conversion to OEM charset FIRST but there is currently
531 no unicode function for that! */
532
533 /* as per FAT spec, set "lossy conversion" flag if any destructive
534 alterations to the name occur other than case changes */
535 *np = -1;
536
537 /* find extension part */
538 unsigned char *ext = strrchr(name, '.');
539 if (ext && (ext == name || strchr(ext, ' ')))
540 ext = NULL; /* handle .dotnames / extensions cannot have spaces */
541
542 /* name part */
543 for (i = 0; *name && (!ext || name < ext) && (i < 8); name++)
544 {
545 unsigned char c = char2dos(*name, np);
546 if (c)
547 basisname[i++] = c;
548 }
549
550 /* pad both name and extension */
551 while (i < 11)
552 basisname[i++] = ' ';
553
554 if (basisname[0] == 0xe5) /* special kanji character */
555 basisname[0] = 0x05;
556
557 /* extension part */
558 if (!ext++)
559 return; /* no extension */
560
561 for (i = 8; *ext && i < 11; ext++)
562 {
563 unsigned char c = char2dos(*ext, np);
564 if (c)
565 basisname[i++] = c;
566 }
567
568 if (*ext)
569 *np = 0; /* extension too long */
481} 570}
482 571
483#ifdef MAX_LOG_SECTOR_SIZE 572static void randomize_dos_name(unsigned char *dosname,
484int fat_get_bytes_per_sector(IF_MV_NONVOID(int volume)) 573 const unsigned char *basisname,
574 int *np)
485{ 575{
486#ifdef HAVE_MULTIVOLUME 576 int n = *np;
487 if(!fat_bpbs[volume].mounted) 577
488 return 0; 578 memcpy(dosname, basisname, 11);
489 return fat_bpbs[volume].bpb_bytspersec; 579
490#else 580 if (n < 0)
491 return fat_bpbs[0].bpb_bytspersec; 581 {
492#endif 582 /* first one just copies */
583 *np = 0;
584 return;
585 }
586
587 /* the "~n" string can range from "~1" to "~999999"
588 of course a directory can have at most 65536 entries which means
589 the numbers will never be required to get that big in order to map
590 to a unique name */
591 if (++n > 999999)
592 n = 1;
593
594 unsigned char numtail[8]; /* holds "~n" */
595 unsigned int numtaillen = snprintf(numtail, 8, "~%d", n);
596
597 unsigned int basislen = 0;
598 while (basislen < 8 && basisname[basislen] != ' ')
599 basislen++;
600
601 memcpy(dosname + MIN(8 - numtaillen, basislen), numtail, numtaillen);
602
603 *np = n;
493} 604}
494#endif
495 605
496int fat_mount(IF_MV(int volume,) IF_MD(int drive,) long startsector) 606/* check long filename for validity */
607static int check_longname(const unsigned char *name)
497{ 608{
498#ifndef HAVE_MULTIVOLUME 609 /* smallest table with one-step lookup that directly maps the list */
499 const int volume = 0; 610 static const unsigned char invalid_chars_tbl[19] =
500#endif 611 {
501 struct bpb* fat_bpb = &fat_bpbs[volume]; 612 0, ':', 0, '<', '*', '>', '?', 0, 0,
502 int rc; 613 '/', '|', 0, 0, 0x7f, 0, '"', '\\', 0, 0
614 };
503 615
504 rc = fat_mount_internal(IF_MV(volume,) IF_MD(drive,) startsector); 616 if (!name)
617 return -1;
505 618
506 if(rc!=0) return rc; 619 unsigned int c = *name;
507 620
508 /* calculate freecount if unset */ 621 do
509 if ( fat_bpb->fsinfo.freecount == 0xffffffff )
510 { 622 {
511 fat_recalc_free(IF_MV(volume)); 623 if (c < 0x20 || invalid_chars_tbl[c % 19] == c)
624 return -2;
512 } 625 }
626 while ((c = *++name));
513 627
514 LDEBUGF("Freecount: %ld\n",(unsigned long)fat_bpb->fsinfo.freecount); 628 /* check trailing space(s) and periods */
515 LDEBUGF("Nextfree: 0x%lx\n",(unsigned long)fat_bpb->fsinfo.nextfree); 629 c = *--name;
516 LDEBUGF("Cluster count: 0x%lx\n",(unsigned long)fat_bpb->dataclusters); 630 if (c == ' ' || c == '.')
517 LDEBUGF("Sectors per cluster: %d\n",fat_bpb->bpb_secperclus); 631 return -3;
518 LDEBUGF("FAT sectors: 0x%lx\n",(unsigned long)fat_bpb->fatsize);
519
520#ifdef HAVE_MULTIVOLUME
521 fat_bpb->mounted = true;
522#endif
523 632
524 return 0; 633 return 0;
525} 634}
526 635
527int fat_unmount(int volume, bool flush) 636/* Get first longname entry name offset */
637static inline unsigned int longent_char_first(void)
528{ 638{
529 int rc; 639 return 1;
530#ifdef HAVE_MULTIVOLUME 640}
531 struct bpb* fat_bpb = &fat_bpbs[volume];
532#else
533 (void)volume;
534#endif
535 641
536 if(flush) 642/* Get the next longname entry offset or 0 if the end is reached */
643static inline unsigned int longent_char_next(unsigned int i)
644{
645 switch (i += 2)
537 { 646 {
538 rc = flush_fat(IF_MV(fat_bpb)); /* the clean way, while still alive */ 647 case 26: i -= 1; /* return 28 */
648 case 11: i += 3; /* return 14 */
539 } 649 }
540 else 650
541 { /* volume is not accessible any more, e.g. MMC removed */ 651 return i < 32 ? i : 0;
542 int i;
543 mutex_lock(&cache_mutex);
544 for(i = 0;i < FAT_CACHE_SIZE;i++)
545 {
546 struct fat_cache_entry *fce = &fat_cache[i];
547 if(fce->inuse
548#ifdef HAVE_MULTIVOLUME
549 && fce->fat_vol == fat_bpb
550#endif
551 )
552 {
553 fce->inuse = false; /* discard all from that volume */
554 fce->dirty = false;
555 }
556 }
557 mutex_unlock(&cache_mutex);
558 rc = 0;
559 }
560#ifdef HAVE_MULTIVOLUME
561 fat_bpb->mounted = false;
562#endif
563 return rc;
564} 652}
565 653
566void fat_recalc_free(IF_MV_NONVOID(int volume)) 654/* initialize the parse state; call before parsing first long entry */
655static void NO_INLINE fatlong_parse_start(struct fatlong_parse_state *lnparse)
567{ 656{
568#ifndef HAVE_MULTIVOLUME 657 /* no inline so gcc can't figure out what isn't initialized here;
569 const int volume = 0; 658 ord_max is king as to the validity of all other fields */
570#endif 659 lnparse->ord_max = -1; /* one resync per parse operation */
571 struct bpb* fat_bpb = &fat_bpbs[volume]; 660}
572 long free = 0; 661
573 unsigned long i; 662/* convert the FAT long name entry to a contiguous segment */
574#ifdef HAVE_FAT16SUPPORT 663static bool fatlong_parse_entry(struct fatlong_parse_state *lnparse,
575 if (fat_bpb->is_fat16) 664 const union raw_dirent *ent,
665 struct fat_direntry *fatent)
666{
667 int ord = ent->ldir_ord;
668
669 if (ord & FATLONG_ORD_F_LAST)
576 { 670 {
577 for (i = 0; i<fat_bpb->fatsize; i++) { 671 /* this entry is the first long entry (first in order but
578 unsigned int j; 672 containing last part) */
579 uint16_t* fat = cache_fat_sector(IF_MV(fat_bpb,) i, false); 673 ord &= ~FATLONG_ORD_F_LAST;
580 for (j = 0; j < CLUSTERS_PER_FAT16_SECTOR; j++) { 674
581 unsigned int c = i * CLUSTERS_PER_FAT16_SECTOR + j; 675 if (ord == 0 || ord > FATLONG_MAX_ORDER)
582 if ( c > fat_bpb->dataclusters+1 ) /* nr 0 is unused */ 676 {
583 break; 677 lnparse->ord_max = 0;
584 678 return true;
585 if (letoh16(fat[j]) == 0x0000) {
586 free++;
587 if ( fat_bpb->fsinfo.nextfree == 0xffffffff )
588 fat_bpb->fsinfo.nextfree = c;
589 }
590 }
591 } 679 }
680
681 lnparse->ord_max = ord;
682 lnparse->ord = ord;
683 lnparse->chksum = ent->ldir_chksum;
592 } 684 }
593 else 685 else
594#endif /* #ifdef HAVE_FAT16SUPPORT */ 686 {
595 { 687 /* valid ordinals yet? */
596 for (i = 0; i<fat_bpb->fatsize; i++) { 688 if (lnparse->ord_max <= 0)
597 unsigned int j; 689 {
598 uint32_t* fat = cache_fat_sector(IF_MV(fat_bpb,) i, false); 690 if (lnparse->ord_max == 0)
599 for (j = 0; j < CLUSTERS_PER_FAT_SECTOR; j++) { 691 return true;
600 unsigned long c = i * CLUSTERS_PER_FAT_SECTOR + j; 692
601 if ( c > fat_bpb->dataclusters+1 ) /* nr 0 is unused */ 693 lnparse->ord_max = 0;
602 break; 694 return false; /* try resync */
603 695 }
604 if (!(letoh32(fat[j]) & 0x0fffffff)) { 696
605 free++; 697 /* check ordinal continuity and that the checksum matches the
606 if ( fat_bpb->fsinfo.nextfree == 0xffffffff ) 698 one stored in the last entry */
607 fat_bpb->fsinfo.nextfree = c; 699 if (ord == 0 || ord != lnparse->ord - 1 ||
608 } 700 lnparse->chksum != ent->ldir_chksum)
609 } 701 {
702 lnparse->ord_max = 0;
703 return true;
610 } 704 }
611 } 705 }
612 fat_bpb->fsinfo.freecount = free;
613 update_fsinfo(IF_MV(fat_bpb));
614}
615 706
616static int bpb_is_sane(IF_MV_NONVOID(struct bpb* fat_bpb)) 707 /* so far so good; save entry information */
617{ 708 lnparse->ord = ord;
618#ifndef HAVE_MULTIVOLUME 709
619 struct bpb* fat_bpb = &fat_bpbs[0]; 710 uint16_t *ucsp = fatent->ucssegs[ord - 1 + 5];
620#endif 711 unsigned int i = longent_char_first();
621 if(fat_bpb->bpb_bytspersec % SECTOR_SIZE) 712
713 while ((*ucsp++ = BYTES2INT16(ent->data, i)))
622 { 714 {
623 DEBUGF( "bpb_is_sane() - Error: sector size is not sane (%d)\n", 715 if (!(i = longent_char_next(i)))
624 fat_bpb->bpb_bytspersec); 716 return true;
625 return -1;
626 }
627 if((long)fat_bpb->bpb_secperclus * SECTOR_SIZE > 128L*1024L)
628 {
629 /* We don't multiply by bpb_bytspersec here, because
630 * back in fat_mount_internal() bpb_secperclus has been
631 * "normalised" to 512 byte clusters, by multiplying with
632 * secmult. */
633 DEBUGF( "bpb_is_sane() - Error: cluster size is larger than 128K "
634 "(%d * %d = %d)\n",
635 fat_bpb->bpb_bytspersec,
636 fat_bpb->bpb_secperclus / (fat_bpb->bpb_bytspersec / SECTOR_SIZE),
637 fat_bpb->bpb_bytspersec * fat_bpb->bpb_secperclus /
638 (fat_bpb->bpb_bytspersec / SECTOR_SIZE));
639 return -2;
640 } 717 }
641 if(fat_bpb->bpb_numfats != 2) 718
719 /* segment may end early only in last entry */
720 if (ord == lnparse->ord_max)
642 { 721 {
643 DEBUGF( "bpb_is_sane() - Warning: NumFATS is not 2 (%d)\n", 722 /* the only valid padding, if any, is 0xffff */
644 fat_bpb->bpb_numfats); 723 do
724 {
725 if (!(i = longent_char_next(i)))
726 return true;
727 }
728 while (BYTES2INT16(ent->data, i) == 0xffff);
645 } 729 }
646 if(fat_bpb->bpb_media != 0xf0 && fat_bpb->bpb_media < 0xf8) 730
731 /* long filename is corrupt */
732 lnparse->ord_max = 0;
733 return true;
734}
735
736/* finish parsing of the longname entries and do the conversion to
737 UTF-8 if we have all the segments */
738static bool fatlong_parse_finish(struct fatlong_parse_state *lnparse,
739 const union raw_dirent *ent,
740 struct fat_direntry *fatent)
741{
742 parse_short_direntry(ent, fatent);
743
744 /* ord_max must not have been set to <= 0 because of any earlier problems
745 and the ordinal immediately before the shortname entry must be 1 */
746 if (lnparse->ord_max <= 0 || lnparse->ord != 1)
747 return false;
748
749 /* check the longname checksums against the shortname checksum */
750 if (lnparse->chksum != shortname_checksum(ent->name))
751 return false;
752
753 /* longname is good so far so convert all the segments to UTF-8 */
754 unsigned char * const name = fatent->name;
755 unsigned char *p = name;
756
757 /* ensure the last segment is NULL-terminated if it is filled */
758 fatent->ucssegs[lnparse->ord_max + 5][0] = 0x0000;
759
760 for (uint16_t *ucsp = fatent->ucssegs[5], ucc = *ucsp;
761 ucc; ucc = *++ucsp)
647 { 762 {
648 DEBUGF( "bpb_is_sane() - Warning: Non-standard " 763 /* end should be hit before ever seeing padding */
649 "media type (0x%02x)\n", 764 if (ucc == 0xffff)
650 fat_bpb->bpb_media); 765 return false;
766
767 if ((p = utf8encode(ucc, p)) - name > FAT_DIRENTRY_NAME_MAX)
768 return false;
651 } 769 }
652 if(fat_bpb->last_word != 0xaa55) 770
771 /* longname ok */
772 *p = '\0';
773 return true;
774}
775
776static unsigned long cluster2sec(struct bpb *fat_bpb, long cluster)
777{
778 long zerocluster = 2;
779
780 /* negative clusters (FAT16 root dir) don't get the 2 offset */
781#ifdef HAVE_FAT16SUPPORT
782 if (fat_bpb->is_fat16 && cluster < 0)
653 { 783 {
654 DEBUGF( "bpb_is_sane() - Error: Last word is not " 784 zerocluster = 0;
655 "0xaa55 (0x%04x)\n", fat_bpb->last_word);
656 return -3;
657 } 785 }
658 786 else
659 if (fat_bpb->fsinfo.freecount > 787#endif /* HAVE_FAT16SUPPORT */
660 (fat_bpb->totalsectors - fat_bpb->firstdatasector)/ 788 if ((unsigned long)cluster > fat_bpb->dataclusters + 1)
661 fat_bpb->bpb_secperclus)
662 { 789 {
663 DEBUGF( "bpb_is_sane() - Error: FSInfo.Freecount > disk size " 790 DEBUGF( "%s() - Bad cluster number (%ld)\n", __func__, cluster);
664 "(0x%04lx)\n", (unsigned long)fat_bpb->fsinfo.freecount); 791 return 0;
665 return -4;
666 } 792 }
667 793
668 return 0; 794 return (unsigned long)(cluster - zerocluster)*fat_bpb->bpb_secperclus
795 + fat_bpb->firstdatasector;
669} 796}
670 797
671static void flush_fat_sector(struct fat_cache_entry *fce, 798#ifdef HAVE_FAT16SUPPORT
672 unsigned char *sectorbuf) 799static long get_next_cluster16(struct bpb *fat_bpb, long startcluster)
673{ 800{
674 int rc; 801 /* if FAT16 root dir, dont use the FAT */
675 long secnum; 802 if (startcluster < 0)
803 return startcluster + 1;
676 804
677 /* With multivolume, use only the FAT info from the cached sector! */ 805 unsigned long entry = startcluster;
678#ifdef HAVE_MULTIVOLUME 806 unsigned long sector = entry / CLUSTERS_PER_FAT16_SECTOR;
679 secnum = fce->secnum + fce->fat_vol->startsector; 807 unsigned long offset = entry % CLUSTERS_PER_FAT16_SECTOR;
680#else 808
681 secnum = fce->secnum + fat_bpbs[0].startsector; 809 dc_lock_cache();
682#endif
683 810
684 /* Write to the first FAT */ 811 uint16_t *sec = cache_sector(fat_bpb, sector + fat_bpb->fatrgnstart);
685 rc = storage_write_sectors(IF_MD(fce->fat_vol->drive,) 812 if (!sec)
686 secnum, 1,
687 sectorbuf);
688 if(rc < 0)
689 { 813 {
690 panicf("flush_fat_sector() - Could not write sector %ld" 814 dc_unlock_cache();
691 " (error %d)\n", 815 DEBUGF("%s: Could not cache sector %d\n", __func__, sector);
692 secnum, rc); 816 return -1;
693 } 817 }
694#ifdef HAVE_MULTIVOLUME 818
695 if(fce->fat_vol->bpb_numfats > 1) 819 long next = letoh16(sec[offset]);
696#else 820
697 if(fat_bpbs[0].bpb_numfats > 1) 821 /* is this last cluster in chain? */
698#endif 822 if (next >= FAT16_EOF_MARK)
823 next = 0;
824
825 dc_unlock_cache();
826 return next;
827}
828
829static long find_free_cluster16(struct bpb *fat_bpb, long startcluster)
830{
831 unsigned long entry = startcluster;
832 unsigned long sector = entry / CLUSTERS_PER_FAT16_SECTOR;
833 unsigned long offset = entry % CLUSTERS_PER_FAT16_SECTOR;
834
835 for (unsigned long i = 0; i < fat_bpb->fatsize; i++)
699 { 836 {
700 /* Write to the second FAT */ 837 unsigned long nr = (i + sector) % fat_bpb->fatsize;
701#ifdef HAVE_MULTIVOLUME 838 uint16_t *sec = cache_sector(fat_bpb, nr + fat_bpb->fatrgnstart);
702 secnum += fce->fat_vol->fatsize; 839 if (!sec)
703#else 840 break;
704 secnum += fat_bpbs[0].fatsize; 841
705#endif 842 for (unsigned long j = 0; j < CLUSTERS_PER_FAT16_SECTOR; j++)
706 rc = storage_write_sectors(IF_MD(fce->fat_vol->drive,)
707 secnum, 1, sectorbuf);
708 if(rc < 0)
709 { 843 {
710 panicf("flush_fat_sector() - Could not write sector %ld" 844 unsigned long k = (j + offset) % CLUSTERS_PER_FAT16_SECTOR;
711 " (error %d)\n", 845
712 secnum, rc); 846 if (letoh16(sec[k]) == 0x0000)
847 {
848 unsigned long c = nr * CLUSTERS_PER_FAT16_SECTOR + k;
849 /* Ignore the reserved clusters 0 & 1, and also
850 cluster numbers out of bounds */
851 if (c < 2 || c > fat_bpb->dataclusters + 1)
852 continue;
853
854 DEBUGF("%s(%lx) == %x\n", __func__, startcluster, c);
855
856 fat_bpb->fsinfo.nextfree = c;
857 return c;
858 }
713 } 859 }
860
861 offset = 0;
714 } 862 }
715 fce->dirty = false; 863
864 DEBUGF("%s(%lx) == 0\n", __func__, startcluster);
865 return 0; /* 0 is an illegal cluster number */
716} 866}
717 867
718/* Note: The returned pointer is only safely valid until the next 868static int update_fat_entry16(struct bpb *fat_bpb, unsigned long entry,
719 task switch! (Any subsequent ata read/write may yield.) */ 869 unsigned long val)
720static void *cache_fat_sector(IF_MV(struct bpb* fat_bpb,)
721 long fatsector, bool dirty)
722{ 870{
723#ifndef HAVE_MULTIVOLUME 871 unsigned long sector = entry / CLUSTERS_PER_FAT16_SECTOR;
724 struct bpb* fat_bpb = &fat_bpbs[0]; 872 unsigned long offset = entry % CLUSTERS_PER_FAT16_SECTOR;
725#endif
726 long secnum = fatsector + fat_bpb->bpb_rsvdseccnt;
727 int cache_index = secnum & FAT_CACHE_MASK;
728 struct fat_cache_entry *fce = &fat_cache[cache_index];
729 unsigned char *sectorbuf = &fat_cache_sectors[cache_index][0];
730 int rc;
731 873
732 mutex_lock(&cache_mutex); /* make changes atomic */ 874 val &= 0xFFFF;
733 875
734 /* Delete the cache entry if it isn't the sector we want */ 876 DEBUGF("%s(entry:%lx,val:%lx)\n", __func__, entry, val);
735 if(fce->inuse && (fce->secnum != secnum 877
736#ifdef HAVE_MULTIVOLUME 878 if (entry == val)
737 || fce->fat_vol != fat_bpb 879 panicf("Creating FAT16 loop: %lx,%lx\n", entry, val);
738#endif 880
739 )) 881 if (entry < 2)
882 panicf("Updating reserved FAT16 entry %lu\n", entry);
883
884 dc_lock_cache();
885
886 int16_t *sec = cache_sector(fat_bpb, sector + fat_bpb->fatrgnstart);
887 if (!sec)
740 { 888 {
741 /* Write back if it is dirty */ 889 dc_unlock_cache();
742 if(fce->dirty) 890 DEBUGF("Could not cache sector %u\n", sector);
743 { 891 return -1;
744 flush_fat_sector(fce, sectorbuf);
745 }
746 fce->inuse = false;
747 } 892 }
748 893
749 /* Load the sector if it is not cached */ 894 uint16_t curval = letoh16(sec[offset]);
750 if(!fce->inuse) 895
896 if (val)
751 { 897 {
752 rc = storage_read_sectors(IF_MD(fat_bpb->drive,) 898 /* being allocated */
753 secnum + fat_bpb->startsector,1, 899 if (curval == 0x0000 && fat_bpb->fsinfo.freecount > 0)
754 sectorbuf); 900 fat_bpb->fsinfo.freecount--;
755 if(rc < 0)
756 {
757 DEBUGF( "cache_fat_sector() - Could not read sector %ld"
758 " (error %d)\n", secnum, rc);
759 mutex_unlock(&cache_mutex);
760 return NULL;
761 }
762 fce->inuse = true;
763 fce->secnum = secnum;
764#ifdef HAVE_MULTIVOLUME
765 fce->fat_vol = fat_bpb;
766#endif
767 } 901 }
768 if (dirty) 902 else
769 fce->dirty = true; /* dirt remains, sticky until flushed */ 903 {
770 mutex_unlock(&cache_mutex); 904 /* being freed */
771 return sectorbuf; 905 if (curval != 0x0000)
906 fat_bpb->fsinfo.freecount++;
907 }
908
909 DEBUGF("%lu free clusters\n", (unsigned long)fat_bpb->fsinfo.freecount);
910
911 sec[offset] = htole16(val);
912 dc_dirty_buf(sec);
913
914 dc_unlock_cache();
915 return 0;
772} 916}
773 917
774static unsigned long find_free_cluster(IF_MV(struct bpb* fat_bpb,) 918static void fat_recalc_free_internal16(struct bpb *fat_bpb)
775 unsigned long startcluster)
776{ 919{
777#ifndef HAVE_MULTIVOLUME 920 unsigned long free = 0;
778 struct bpb* fat_bpb = &fat_bpbs[0];
779#endif
780 unsigned long sector;
781 unsigned long offset;
782 unsigned long i;
783 921
784#ifdef HAVE_FAT16SUPPORT 922 for (unsigned long i = 0; i < fat_bpb->fatsize; i++)
785 if (fat_bpb->is_fat16)
786 { 923 {
787 sector = startcluster / CLUSTERS_PER_FAT16_SECTOR; 924 uint16_t *sec = cache_sector(fat_bpb, i + fat_bpb->fatrgnstart);
788 offset = startcluster % CLUSTERS_PER_FAT16_SECTOR; 925 if (!sec)
926 break;
789 927
790 for (i = 0; i<fat_bpb->fatsize; i++) { 928 for (unsigned long j = 0; j < CLUSTERS_PER_FAT16_SECTOR; j++)
791 unsigned int j; 929 {
792 unsigned int nr = (i + sector) % fat_bpb->fatsize; 930 unsigned long c = i * CLUSTERS_PER_FAT16_SECTOR + j;
793 uint16_t* fat = cache_fat_sector(IF_MV(fat_bpb,) nr, false); 931
794 if ( !fat ) 932 if (c < 2 || c > fat_bpb->dataclusters + 1) /* nr 0 is unused */
795 break; 933 continue;
796 for (j = 0; j < CLUSTERS_PER_FAT16_SECTOR; j++) { 934
797 int k = (j + offset) % CLUSTERS_PER_FAT16_SECTOR; 935 if (letoh16(sec[j]) != 0x0000)
798 if (letoh16(fat[k]) == 0x0000) { 936 continue;
799 unsigned int c = nr * CLUSTERS_PER_FAT16_SECTOR + k; 937
800 /* Ignore the reserved clusters 0 & 1, and also 938 free++;
801 cluster numbers out of bounds */ 939 if (fat_bpb->fsinfo.nextfree == 0xffffffff)
802 if ( c < 2 || c > fat_bpb->dataclusters+1 ) 940 fat_bpb->fsinfo.nextfree = c;
803 continue;
804 LDEBUGF("find_free_cluster(%lx) == %x\n",startcluster,c);
805 fat_bpb->fsinfo.nextfree = c;
806 return c;
807 }
808 }
809 offset = 0;
810 } 941 }
811 } 942 }
812 else
813#endif /* #ifdef HAVE_FAT16SUPPORT */
814 {
815 sector = startcluster / CLUSTERS_PER_FAT_SECTOR;
816 offset = startcluster % CLUSTERS_PER_FAT_SECTOR;
817 943
818 for (i = 0; i<fat_bpb->fatsize; i++) { 944 fat_bpb->fsinfo.freecount = free;
819 unsigned int j; 945}
820 unsigned long nr = (i + sector) % fat_bpb->fatsize; 946#endif /* HAVE_FAT16SUPPORT */
821 uint32_t* fat = cache_fat_sector(IF_MV(fat_bpb,) nr, false); 947
822 if ( !fat ) 948static void update_fsinfo32(struct bpb *fat_bpb)
823 break; 949{
824 for (j = 0; j < CLUSTERS_PER_FAT_SECTOR; j++) { 950 uint8_t *fsinfo = cache_sector(fat_bpb, fat_bpb->bpb_fsinfo);
825 int k = (j + offset) % CLUSTERS_PER_FAT_SECTOR; 951 if (!fsinfo)
826 if (!(letoh32(fat[k]) & 0x0fffffff)) { 952 {
827 unsigned long c = nr * CLUSTERS_PER_FAT_SECTOR + k; 953 DEBUGF("%s() - Couldn't read FSInfo"
828 /* Ignore the reserved clusters 0 & 1, and also 954 " (err code %d)", __func__, rc);
829 cluster numbers out of bounds */ 955 return;
830 if ( c < 2 || c > fat_bpb->dataclusters+1 )
831 continue;
832 LDEBUGF("find_free_cluster(%lx) == %lx\n",startcluster,c);
833 fat_bpb->fsinfo.nextfree = c;
834 return c;
835 }
836 }
837 offset = 0;
838 }
839 } 956 }
840 957
841 LDEBUGF("find_free_cluster(%lx) == 0\n",startcluster); 958 INT322BYTES(fsinfo, FSINFO_FREECOUNT, fat_bpb->fsinfo.freecount);
842 return 0; /* 0 is an illegal cluster number */ 959 INT322BYTES(fsinfo, FSINFO_NEXTFREE, fat_bpb->fsinfo.nextfree);
960 dc_dirty_buf(fsinfo);
843} 961}
844 962
845static int update_fat_entry(IF_MV(struct bpb* fat_bpb,) unsigned long entry, 963static long get_next_cluster32(struct bpb *fat_bpb, long startcluster)
846 unsigned long val)
847{ 964{
848#ifndef HAVE_MULTIVOLUME 965 unsigned long entry = startcluster;
849 struct bpb* fat_bpb = &fat_bpbs[0]; 966 unsigned long sector = entry / CLUSTERS_PER_FAT_SECTOR;
850#endif 967 unsigned long offset = entry % CLUSTERS_PER_FAT_SECTOR;
851#ifdef HAVE_FAT16SUPPORT 968
852 if (fat_bpb->is_fat16) 969 dc_lock_cache();
970
971 uint32_t *sec = cache_sector(fat_bpb, sector + fat_bpb->fatrgnstart);
972 if (!sec)
853 { 973 {
854 int sector = entry / CLUSTERS_PER_FAT16_SECTOR; 974 dc_unlock_cache();
855 int offset = entry % CLUSTERS_PER_FAT16_SECTOR; 975 DEBUGF("%s: Could not cache sector %d\n", __func__, sector);
856 unsigned short* sec; 976 return -1;
977 }
857 978
858 val &= 0xFFFF; 979 long next = letoh32(sec[offset]) & 0x0fffffff;
859 980
860 LDEBUGF("update_fat_entry(%lx,%lx)\n",entry,val); 981 /* is this last cluster in chain? */
982 if (next >= FAT_EOF_MARK)
983 next = 0;
861 984
862 if (entry==val) 985 dc_unlock_cache();
863 panicf("Creating FAT loop: %lx,%lx\n",entry,val); 986 return next;
987}
864 988
865 if ( entry < 2 ) 989static long find_free_cluster32(struct bpb *fat_bpb, long startcluster)
866 panicf("Updating reserved FAT entry %ld.\n",entry); 990{
991 unsigned long entry = startcluster;
992 unsigned long sector = entry / CLUSTERS_PER_FAT_SECTOR;
993 unsigned long offset = entry % CLUSTERS_PER_FAT_SECTOR;
867 994
868 sec = cache_fat_sector(IF_MV(fat_bpb,) sector, true); 995 for (unsigned long i = 0; i < fat_bpb->fatsize; i++)
996 {
997 unsigned long nr = (i + sector) % fat_bpb->fatsize;
998 uint32_t *sec = cache_sector(fat_bpb, nr + fat_bpb->fatrgnstart);
869 if (!sec) 999 if (!sec)
1000 break;
1001
1002 for (unsigned long j = 0; j < CLUSTERS_PER_FAT_SECTOR; j++)
870 { 1003 {
871 DEBUGF( "update_fat_entry() - Could not cache sector %d\n", sector); 1004 unsigned long k = (j + offset) % CLUSTERS_PER_FAT_SECTOR;
872 return -1;
873 }
874 1005
875 if ( val ) { 1006 if (!(letoh32(sec[k]) & 0x0fffffff))
876 if (letoh16(sec[offset]) == 0x0000 && fat_bpb->fsinfo.freecount > 0) 1007 {
877 fat_bpb->fsinfo.freecount--; 1008 unsigned long c = nr * CLUSTERS_PER_FAT_SECTOR + k;
878 } 1009 /* Ignore the reserved clusters 0 & 1, and also
879 else { 1010 cluster numbers out of bounds */
880 if (letoh16(sec[offset])) 1011 if (c < 2 || c > fat_bpb->dataclusters + 1)
881 fat_bpb->fsinfo.freecount++; 1012 continue;
1013
1014 DEBUGF("%s(%lx) == %lx\n", __func__, startcluster, c);
1015
1016 fat_bpb->fsinfo.nextfree = c;
1017 return c;
1018 }
882 } 1019 }
883 1020
884 LDEBUGF("update_fat_entry: %lu free clusters\n", 1021 offset = 0;
885 (unsigned long)fat_bpb->fsinfo.freecount); 1022 }
1023
1024 DEBUGF("%s(%lx) == 0\n", __func__, startcluster);
1025 return 0; /* 0 is an illegal cluster number */
1026}
1027
1028static int update_fat_entry32(struct bpb *fat_bpb, unsigned long entry,
1029 unsigned long val)
1030{
1031 unsigned long sector = entry / CLUSTERS_PER_FAT_SECTOR;
1032 unsigned long offset = entry % CLUSTERS_PER_FAT_SECTOR;
1033
1034 DEBUGF("%s(entry:%lx,val:%lx)\n", __func__, entry, val);
1035
1036 if (entry == val)
1037 panicf("Creating FAT32 loop: %lx,%lx\n", entry, val);
1038
1039 if (entry < 2)
1040 panicf("Updating reserved FAT32 entry %lu\n", entry);
1041
1042 dc_lock_cache();
1043
1044 uint32_t *sec = cache_sector(fat_bpb, sector + fat_bpb->fatrgnstart);
1045 if (!sec)
1046 {
1047 dc_unlock_cache();
1048 DEBUGF("Could not cache sector %u\n", sector);
1049 return -1;
1050 }
886 1051
887 sec[offset] = htole16(val); 1052 uint32_t curval = letoh32(sec[offset]);
1053
1054 if (val)
1055 {
1056 /* being allocated */
1057 if (!(curval & 0x0fffffff) && fat_bpb->fsinfo.freecount > 0)
1058 fat_bpb->fsinfo.freecount--;
888 } 1059 }
889 else 1060 else
890#endif /* #ifdef HAVE_FAT16SUPPORT */
891 { 1061 {
892 long sector = entry / CLUSTERS_PER_FAT_SECTOR; 1062 /* being freed */
893 int offset = entry % CLUSTERS_PER_FAT_SECTOR; 1063 if (curval & 0x0fffffff)
894 uint32_t* sec; 1064 fat_bpb->fsinfo.freecount++;
1065 }
1066
1067 DEBUGF("%lu free clusters\n", (unsigned long)fat_bpb->fsinfo.freecount);
895 1068
896 LDEBUGF("update_fat_entry(%lx,%lx)\n",entry,val); 1069 /* don't change top 4 bits */
1070 sec[offset] = htole32((curval & 0xf0000000) | (val & 0x0fffffff));
1071 dc_dirty_buf(sec);
897 1072
898 if (entry==val) 1073 dc_unlock_cache();
899 panicf("Creating FAT loop: %lx,%lx\n",entry,val); 1074 return 0;
1075}
900 1076
901 if ( entry < 2 ) 1077static void fat_recalc_free_internal32(struct bpb *fat_bpb)
902 panicf("Updating reserved FAT entry %ld.\n",entry); 1078{
1079 unsigned long free = 0;
903 1080
904 sec = cache_fat_sector(IF_MV(fat_bpb,) sector, true); 1081 for (unsigned long i = 0; i < fat_bpb->fatsize; i++)
1082 {
1083 uint32_t *sec = cache_sector(fat_bpb, i + fat_bpb->fatrgnstart);
905 if (!sec) 1084 if (!sec)
1085 break;
1086
1087 for (unsigned long j = 0; j < CLUSTERS_PER_FAT_SECTOR; j++)
906 { 1088 {
907 DEBUGF("update_fat_entry() - Could not cache sector %ld\n", sector); 1089 unsigned long c = i * CLUSTERS_PER_FAT_SECTOR + j;
908 return -1;
909 }
910 1090
911 if ( val ) { 1091 if (c < 2 || c > fat_bpb->dataclusters + 1) /* nr 0 is unused */
912 if (!(letoh32(sec[offset]) & 0x0fffffff) && 1092 continue;
913 fat_bpb->fsinfo.freecount > 0)
914 fat_bpb->fsinfo.freecount--;
915 }
916 else {
917 if (letoh32(sec[offset]) & 0x0fffffff)
918 fat_bpb->fsinfo.freecount++;
919 }
920 1093
921 LDEBUGF("update_fat_entry: %ld free clusters\n", 1094 if (letoh32(sec[j]) & 0x0fffffff)
922 (unsigned long)fat_bpb->fsinfo.freecount); 1095 continue;
923 1096
924 /* don't change top 4 bits */ 1097 free++;
925 sec[offset] &= htole32(0xf0000000); 1098 if (fat_bpb->fsinfo.nextfree == 0xffffffff)
926 sec[offset] |= htole32(val & 0x0fffffff); 1099 fat_bpb->fsinfo.nextfree = c;
1100 }
927 } 1101 }
928 1102
929 return 0; 1103 fat_bpb->fsinfo.freecount = free;
1104 update_fsinfo32(fat_bpb);
930} 1105}
931 1106
932static long read_fat_entry(IF_MV(struct bpb* fat_bpb,) unsigned long entry) 1107static int fat_mount_internal(struct bpb *fat_bpb)
933{ 1108{
1109 int rc;
1110 /* safe to grab buffer: bpb is irrelevant and no sector will be cached
1111 for this volume since it isn't mounted */
1112 uint8_t * const buf = dc_get_buffer();
1113 if (!buf)
1114 FAT_ERROR(-1);
1115
1116 /* Read the sector */
1117 rc = storage_read_sectors(IF_MD(fat_bpb->drive,) fat_bpb->startsector,
1118 1, buf);
1119 if(rc)
1120 {
1121 DEBUGF("%s() - Couldn't read BPB"
1122 " (err %d)\n", __func__, rc);
1123 FAT_ERROR(rc * 10 - 2);
1124 }
1125
1126 fat_bpb->bpb_bytspersec = BYTES2INT16(buf, BPB_BYTSPERSEC);
1127 unsigned long secmult = fat_bpb->bpb_bytspersec / SECTOR_SIZE;
1128 /* Sanity check is performed later */
1129
1130 fat_bpb->bpb_secperclus = secmult * buf[BPB_SECPERCLUS];
1131 fat_bpb->bpb_rsvdseccnt = secmult * BYTES2INT16(buf, BPB_RSVDSECCNT);
1132 fat_bpb->bpb_numfats = buf[BPB_NUMFATS];
1133 fat_bpb->bpb_media = buf[BPB_MEDIA];
1134 fat_bpb->bpb_fatsz16 = secmult * BYTES2INT16(buf, BPB_FATSZ16);
1135 fat_bpb->bpb_fatsz32 = secmult * BYTES2INT32(buf, BPB_FATSZ32);
1136 fat_bpb->bpb_totsec16 = secmult * BYTES2INT16(buf, BPB_TOTSEC16);
1137 fat_bpb->bpb_totsec32 = secmult * BYTES2INT32(buf, BPB_TOTSEC32);
1138 fat_bpb->last_word = BYTES2INT16(buf, BPB_LAST_WORD);
1139
1140 /* calculate a few commonly used values */
1141 if (fat_bpb->bpb_fatsz16 != 0)
1142 fat_bpb->fatsize = fat_bpb->bpb_fatsz16;
1143 else
1144 fat_bpb->fatsize = fat_bpb->bpb_fatsz32;
1145
1146 fat_bpb->fatrgnstart = fat_bpb->bpb_rsvdseccnt;
1147 fat_bpb->fatrgnend = fat_bpb->bpb_rsvdseccnt + fat_bpb->fatsize;
1148
1149 if (fat_bpb->bpb_totsec16 != 0)
1150 fat_bpb->totalsectors = fat_bpb->bpb_totsec16;
1151 else
1152 fat_bpb->totalsectors = fat_bpb->bpb_totsec32;
1153
1154 unsigned int rootdirsectors = 0;
1155#ifdef HAVE_FAT16SUPPORT
1156 fat_bpb->bpb_rootentcnt = BYTES2INT16(buf, BPB_ROOTENTCNT);
1157
1158 if (!fat_bpb->bpb_bytspersec)
1159 FAT_ERROR(-3);
1160
1161 rootdirsectors = secmult * ((fat_bpb->bpb_rootentcnt * DIR_ENTRY_SIZE
1162 + fat_bpb->bpb_bytspersec - 1) / fat_bpb->bpb_bytspersec);
1163#endif /* HAVE_FAT16SUPPORT */
1164
1165 fat_bpb->firstdatasector = fat_bpb->bpb_rsvdseccnt
1166 + fat_bpb->bpb_numfats * fat_bpb->fatsize
1167 + rootdirsectors;
1168
1169 /* Determine FAT type */
1170 unsigned long datasec = fat_bpb->totalsectors - fat_bpb->firstdatasector;
1171
1172 if (!fat_bpb->bpb_secperclus)
1173 FAT_ERROR(-4);
1174
1175 fat_bpb->dataclusters = datasec / fat_bpb->bpb_secperclus;
1176
1177#ifdef TEST_FAT
1178 /*
1179 we are sometimes testing with "illegally small" fat32 images,
1180 so we don't use the proper fat32 test case for test code
1181 */
1182 if (fat_bpb->bpb_fatsz16)
1183#else /* !TEST_FAT */
1184 if (fat_bpb->dataclusters < 65525)
1185#endif /* TEST_FAT */
1186 { /* FAT16 */
1187#ifdef HAVE_FAT16SUPPORT
1188 fat_bpb->is_fat16 = true;
1189 if (fat_bpb->dataclusters < 4085)
1190 { /* FAT12 */
1191 DEBUGF("This is FAT12. Go away!\n");
1192 FAT_ERROR(-5);
1193 }
1194#else /* !HAVE_FAT16SUPPORT */
1195 DEBUGF("This is not FAT32. Go away!\n");
1196 FAT_ERROR(-6);
1197#endif /* HAVE_FAT16SUPPORT */
1198 }
1199
934#ifdef HAVE_FAT16SUPPORT 1200#ifdef HAVE_FAT16SUPPORT
935#ifndef HAVE_MULTIVOLUME
936 struct bpb* fat_bpb = &fat_bpbs[0];
937#endif
938 if (fat_bpb->is_fat16) 1201 if (fat_bpb->is_fat16)
939 { 1202 {
940 int sector = entry / CLUSTERS_PER_FAT16_SECTOR; 1203 /* FAT16 specific part of BPB */
941 int offset = entry % CLUSTERS_PER_FAT16_SECTOR; 1204 fat_bpb->rootdirsector = fat_bpb->bpb_rsvdseccnt
942 unsigned short* sec; 1205 + fat_bpb->bpb_numfats * fat_bpb->bpb_fatsz16;
1206 long dirclusters = ((rootdirsectors + fat_bpb->bpb_secperclus - 1)
1207 / fat_bpb->bpb_secperclus); /* rounded up, to full clusters */
1208 /* I assign negative pseudo cluster numbers for the root directory,
1209 their range is counted upward until -1. */
1210 fat_bpb->bpb_rootclus = 0 - dirclusters; /* backwards, before the data */
1211 fat_bpb->rootdirsectornum = dirclusters * fat_bpb->bpb_secperclus
1212 - rootdirsectors;
1213 }
1214 else
1215#endif /* HAVE_FAT16SUPPORT */
1216 {
1217 /* FAT32 specific part of BPB */
1218 fat_bpb->bpb_rootclus = BYTES2INT32(buf, BPB_ROOTCLUS);
1219 fat_bpb->bpb_fsinfo = secmult * BYTES2INT16(buf, BPB_FSINFO);
1220 fat_bpb->rootdirsector = cluster2sec(fat_bpb, fat_bpb->bpb_rootclus);
1221 }
943 1222
944 sec = cache_fat_sector(IF_MV(fat_bpb,) sector, false); 1223 rc = bpb_is_sane(fat_bpb);
945 if (!sec) 1224 if (rc < 0)
946 { 1225 {
947 DEBUGF( "read_fat_entry() - Could not cache sector %d\n", sector); 1226 DEBUGF("%s: BPB is insane!\n", __func__);
948 return -1; 1227 FAT_ERROR(rc * 10 - 7);
949 } 1228 }
950 1229
951 return letoh16(sec[offset]); 1230#ifdef HAVE_FAT16SUPPORT
1231 if (fat_bpb->is_fat16)
1232 {
1233 fat_bpb->fsinfo.freecount = 0xffffffff; /* force recalc later */
1234 fat_bpb->fsinfo.nextfree = 0xffffffff;
952 } 1235 }
953 else 1236 else
954#endif /* #ifdef HAVE_FAT16SUPPORT */ 1237#endif /* HAVE_FAT16SUPPORT */
955 { 1238 {
956 long sector = entry / CLUSTERS_PER_FAT_SECTOR; 1239 /* Read the fsinfo sector */
957 int offset = entry % CLUSTERS_PER_FAT_SECTOR; 1240 rc = storage_read_sectors(IF_MD(fat_bpb->drive,)
958 uint32_t* sec; 1241 fat_bpb->startsector + fat_bpb->bpb_fsinfo, 1, buf);
959 1242
960 sec = cache_fat_sector(IF_MV(fat_bpb,) sector, false); 1243 if (rc < 0)
961 if (!sec)
962 { 1244 {
963 DEBUGF( "read_fat_entry() - Could not cache sector %ld\n", sector); 1245 DEBUGF("%s() - Couldn't read FSInfo"
964 return -1; 1246 " (error code %d)\n", __func__, rc);
1247 FAT_ERROR(rc * 10 - 8);
965 } 1248 }
966 1249
967 return letoh32(sec[offset]) & 0x0fffffff; 1250 fat_bpb->fsinfo.freecount = BYTES2INT32(buf, FSINFO_FREECOUNT);
1251 fat_bpb->fsinfo.nextfree = BYTES2INT32(buf, FSINFO_NEXTFREE);
968 } 1252 }
969}
970
971static long get_next_cluster(IF_MV(struct bpb* fat_bpb,) long cluster)
972{
973 long next_cluster;
974 long eof_mark = FAT_EOF_MARK;
975 1253
976#ifdef HAVE_FAT16SUPPORT 1254#ifdef HAVE_FAT16SUPPORT
977#ifndef HAVE_MULTIVOLUME 1255 /* Fix up calls that change per FAT type */
978 struct bpb* fat_bpb = &fat_bpbs[0];
979#endif
980 if (fat_bpb->is_fat16) 1256 if (fat_bpb->is_fat16)
981 { 1257 {
982 eof_mark &= 0xFFFF; /* only 16 bit */ 1258 BPB_FN_SET16(fat_bpb, get_next_cluster);
983 if (cluster < 0) /* FAT16 root dir */ 1259 BPB_FN_SET16(fat_bpb, find_free_cluster);
984 return cluster + 1; /* don't use the FAT */ 1260 BPB_FN_SET16(fat_bpb, update_fat_entry);
1261 BPB_FN_SET16(fat_bpb, fat_recalc_free_internal);
985 } 1262 }
986#endif
987 next_cluster = read_fat_entry(IF_MV(fat_bpb,) cluster);
988
989 /* is this last cluster in chain? */
990 if ( next_cluster >= eof_mark )
991 return 0;
992 else 1263 else
993 return next_cluster; 1264 {
1265 BPB_FN_SET32(fat_bpb, get_next_cluster);
1266 BPB_FN_SET32(fat_bpb, find_free_cluster);
1267 BPB_FN_SET32(fat_bpb, update_fat_entry);
1268 BPB_FN_SET32(fat_bpb, fat_recalc_free_internal);
1269 }
1270#endif /* HAVE_FAT16SUPPORT */
1271
1272 rc = 0;
1273fat_error:
1274 dc_release_buffer(buf);
1275 return rc;
994} 1276}
995 1277
996static int update_fsinfo(IF_MV_NONVOID(struct bpb* fat_bpb)) 1278static union raw_dirent * cache_direntry(struct bpb *fat_bpb,
1279 struct fat_filestr *filestr,
1280 unsigned int entry)
997{ 1281{
998#ifndef HAVE_MULTIVOLUME 1282 filestr->eof = false;
999 struct bpb* fat_bpb = &fat_bpbs[0];
1000#endif
1001 uint32_t* intptr;
1002 int rc;
1003 1283
1004#ifdef HAVE_FAT16SUPPORT 1284 if (entry >= MAX_DIRENTRIES)
1005 if (fat_bpb->is_fat16) 1285 {
1006 return 0; /* FAT16 has no FsInfo */ 1286 DEBUGF("%s() - Dir is too large (entry %u)\n", __func__, entry);
1007#endif /* #ifdef HAVE_FAT16SUPPORT */ 1287 return NULL;
1288 }
1008 1289
1009 unsigned char* fsinfo = fat_get_sector_buffer(); 1290 unsigned long sector = entry / DIR_ENTRIES_PER_SECTOR;
1010 /* update fsinfo */ 1291
1011 rc = storage_read_sectors(IF_MD(fat_bpb->drive,) 1292 if (fat_query_sectornum(filestr) != sector + 1)
1012 fat_bpb->startsector + fat_bpb->bpb_fsinfo, 1,fsinfo);
1013 if (rc < 0)
1014 { 1293 {
1015 fat_release_sector_buffer(); 1294 int rc = fat_seek(filestr, sector + 1);
1016 DEBUGF( "update_fsinfo() - Couldn't read FSInfo (error code %d)", rc); 1295 if (rc < 0)
1017 return rc * 10 - 1; 1296 {
1297 if (rc == FAT_SEEK_EOF)
1298 {
1299 DEBUGF("%s() - End of dir (entry %u)\n", __func__, entry);
1300 fat_seek(filestr, sector);
1301 filestr->eof = true;
1302 }
1303
1304 return NULL;
1305 }
1018 } 1306 }
1019 intptr = (uint32_t*)&(fsinfo[FSINFO_FREECOUNT]);
1020 *intptr = htole32(fat_bpb->fsinfo.freecount);
1021 1307
1022 intptr = (uint32_t*)&(fsinfo[FSINFO_NEXTFREE]); 1308 union raw_dirent *ent = cache_sector(fat_bpb, filestr->lastsector);
1023 *intptr = htole32(fat_bpb->fsinfo.nextfree);
1024 1309
1025 rc = storage_write_sectors(IF_MD(fat_bpb->drive,) 1310 if (ent)
1026 fat_bpb->startsector + fat_bpb->bpb_fsinfo,1,fsinfo); 1311 ent += entry % DIR_ENTRIES_PER_SECTOR;
1027 fat_release_sector_buffer(); 1312
1028 if (rc < 0) 1313 return ent;
1314}
1315
1316static long next_write_cluster(struct bpb *fat_bpb, long oldcluster)
1317{
1318 DEBUGF("%s(old:%lx)\n", __func__, oldcluster);
1319
1320 long cluster = 0;
1321
1322 /* cluster already allocated? */
1323 if (oldcluster)
1324 cluster = get_next_cluster(fat_bpb, oldcluster);
1325
1326 if (!cluster)
1029 { 1327 {
1030 DEBUGF( "update_fsinfo() - Couldn't write FSInfo (error code %d)", rc); 1328 /* passed end of existing entries and now need to append */
1031 return rc * 10 - 2; 1329 #ifdef HAVE_FAT16SUPPORT
1330 if (UNLIKELY(oldcluster < 0))
1331 return 0; /* negative, pseudo-cluster of the root dir */
1332 /* impossible to append something to the root */
1333 #endif /* HAVE_FAT16SUPPORT */
1334
1335 dc_lock_cache();
1336
1337 long findstart = oldcluster > 0 ?
1338 oldcluster + 1 : (long)fat_bpb->fsinfo.nextfree;
1339
1340 cluster = find_free_cluster(fat_bpb, findstart);
1341
1342 if (cluster)
1343 {
1344 /* create the cluster chain */
1345 if (oldcluster)
1346 update_fat_entry(fat_bpb, oldcluster, cluster);
1347
1348 update_fat_entry(fat_bpb, cluster, FAT_EOF_MARK);
1349 }
1350 else
1351 {
1352 #ifdef TEST_FAT
1353 if (fat_bpb->fsinfo.freecount > 0)
1354 panicf("There is free space, but find_free_cluster() "
1355 "didn't find it!\n");
1356 #endif
1357 DEBUGF("Disk full!\n");
1358 }
1359
1360 dc_unlock_cache();
1032 } 1361 }
1033 1362
1034 return 0; 1363 return cluster;
1035} 1364}
1036 1365
1037static int flush_fat(IF_MV_NONVOID(struct bpb* fat_bpb)) 1366/* extend dir file by one cluster and clear it; file position should be at the
1367 current last cluster before calling and size of dir checked */
1368static int fat_extend_dir(struct bpb *fat_bpb, struct fat_filestr *dirstr)
1038{ 1369{
1039 int i; 1370 DEBUGF("%s()\n", __func__);
1371
1040 int rc; 1372 int rc;
1041 unsigned char *sec;
1042 LDEBUGF("flush_fat()\n");
1043 1373
1044 mutex_lock(&cache_mutex); 1374 long cluster = dirstr->lastcluster;
1045 for(i = 0;i < FAT_CACHE_SIZE;i++) 1375 long newcluster = next_write_cluster(fat_bpb, cluster);
1376
1377 if (!newcluster)
1046 { 1378 {
1047 struct fat_cache_entry *fce = &fat_cache[i]; 1379 /* no more room or something went wrong */
1048 if(fce->inuse 1380 DEBUGF("Out of space\n");
1049#ifdef HAVE_MULTIVOLUME 1381 FAT_ERROR(FAT_RC_ENOSPC);
1050 && fce->fat_vol == fat_bpb 1382 }
1051#endif 1383
1052 && fce->dirty) 1384 /* we must clear whole clusters */
1385 unsigned long startsector = cluster2sec(fat_bpb, newcluster);
1386 unsigned long sector = startsector - 1;
1387
1388 if (startsector == 0)
1389 FAT_ERROR(-1);
1390
1391 for (unsigned int i = 0; i < fat_bpb->bpb_secperclus; i++)
1392 {
1393 dc_lock_cache();
1394
1395 void *sec = cache_sector_buffer(IF_MV(fat_bpb,) ++sector);
1396 if (!sec)
1053 { 1397 {
1054 sec = fat_cache_sectors[i]; 1398 dc_unlock_cache();
1055 flush_fat_sector(fce, sec); 1399 DEBUGF("Cannot clear cluster %ld\n", newcluster);
1400 update_fat_entry(fat_bpb, newcluster, 0);
1401 FAT_ERROR(-2);
1056 } 1402 }
1403
1404 memset(sec, 0, SECTOR_SIZE);
1405 dc_dirty_buf(sec);
1406 dc_unlock_cache();
1057 } 1407 }
1058 mutex_unlock(&cache_mutex);
1059 1408
1060 rc = update_fsinfo(IF_MV(fat_bpb)); 1409 if (!dirstr->fatfilep->firstcluster)
1061 if (rc < 0) 1410 dirstr->fatfilep->firstcluster = newcluster;
1062 return rc * 10 - 3;
1063 1411
1064 return 0; 1412 dirstr->lastcluster = newcluster;
1413 dirstr->lastsector = sector;
1414 dirstr->clusternum++;
1415 dirstr->sectornum = sector - startsector;
1416 dirstr->eof = false;
1417
1418 rc = 0;
1419fat_error:
1420 return rc;
1065} 1421}
1066 1422
1067static void fat_time(unsigned short* date, 1423static void fat_open_internal(IF_MV(int volume,) long startcluster,
1068 unsigned short* time, 1424 struct fat_file *file)
1069 unsigned short* tenth )
1070{ 1425{
1426#ifdef HAVE_MULTIVOLUME
1427 file->volume = volume;
1428#endif
1429 file->firstcluster = startcluster;
1430 file->dircluster = 0;
1431 file->e.entry = 0;
1432 file->e.entries = 0;
1433}
1434
1071#if CONFIG_RTC 1435#if CONFIG_RTC
1072 struct tm* tm = get_time(); 1436static void fat_time(uint16_t *date, uint16_t *time, int16_t *tenth)
1437{
1438 struct tm *tm = get_time();
1073 1439
1074 if (date) 1440 if (date)
1441 {
1075 *date = ((tm->tm_year - 80) << 9) | 1442 *date = ((tm->tm_year - 80) << 9) |
1076 ((tm->tm_mon + 1) << 5) | 1443 ((tm->tm_mon + 1) << 5) |
1077 tm->tm_mday; 1444 tm->tm_mday;
1445 }
1078 1446
1079 if (time) 1447 if (time)
1448 {
1080 *time = (tm->tm_hour << 11) | 1449 *time = (tm->tm_hour << 11) |
1081 (tm->tm_min << 5) | 1450 (tm->tm_min << 5) |
1082 (tm->tm_sec >> 1); 1451 (tm->tm_sec >> 1);
1452 }
1083 1453
1084 if (tenth) 1454 if (tenth)
1085 *tenth = (tm->tm_sec & 1) * 100; 1455 *tenth = (tm->tm_sec & 1) * 100;
1086#else 1456}
1457
1458#else /* !CONFIG_RTC */
1459
1460static void fat_time(uint16_t *date, uint16_t *time, int16_t *tenth)
1461{
1087 /* non-RTC version returns an increment from the supplied time, or a 1462 /* non-RTC version returns an increment from the supplied time, or a
1088 * fixed standard time/date if no time given as input */ 1463 * fixed standard time/date if no time given as input */
1089 1464
1090/* Macros to convert a 2-digit string to a decimal constant. 1465 /* Macros to convert a 2-digit string to a decimal constant.
1091 (YEAR), MONTH and DAY are set by the date command, which outputs 1466 (YEAR), MONTH and DAY are set by the date command, which outputs
1092 DAY as 00..31 and MONTH as 01..12. The leading zero would lead to 1467 DAY as 00..31 and MONTH as 01..12. The leading zero would lead to
1093 misinterpretation as an octal constant. */ 1468 misinterpretation as an octal constant. */
1094#define S100(x) 1 ## x 1469 #define S100(x) 1 ## x
1095#define C2DIG2DEC(x) (S100(x)-100) 1470 #define C2DIG2DEC(x) (S100(x)-100)
1096/* The actual build date, as FAT date constant */ 1471 /* The actual build date, as FAT date constant */
1097#define BUILD_DATE_FAT (((YEAR - 1980) << 9) \ 1472 #define BUILD_DATE_FAT (((YEAR - 1980) << 9) \
1098 | (C2DIG2DEC(MONTH) << 5) \ 1473 | (C2DIG2DEC(MONTH) << 5) \
1099 | C2DIG2DEC(DAY)) 1474 | C2DIG2DEC(DAY))
1100 1475
1101 bool date_forced = false; 1476 bool date_forced = false;
1102 bool next_day = false; 1477 bool next_day = false;
@@ -1107,7 +1482,7 @@ static void fat_time(unsigned short* date,
1107 *date = BUILD_DATE_FAT; 1482 *date = BUILD_DATE_FAT;
1108 date_forced = true; 1483 date_forced = true;
1109 } 1484 }
1110 1485
1111 if (time) 1486 if (time)
1112 { 1487 {
1113 time2 = *time << 1; 1488 time2 = *time << 1;
@@ -1119,8 +1494,8 @@ static void fat_time(unsigned short* date,
1119 { 1494 {
1120 unsigned mins = (time2 >> 6) & 0x3f; 1495 unsigned mins = (time2 >> 6) & 0x3f;
1121 unsigned hours = (time2 >> 12) & 0x1f; 1496 unsigned hours = (time2 >> 12) & 0x1f;
1122 1497
1123 mins = 11 * ((mins/11) + 1); /* advance to next multiple of 11 */ 1498 mins = 11 * ((mins / 11) + 1); /* advance to next multiple of 11 */
1124 if (mins > 59) 1499 if (mins > 59)
1125 { 1500 {
1126 mins = 11; /* 00 would be a bad marker */ 1501 mins = 11; /* 00 would be a bad marker */
@@ -1134,14 +1509,14 @@ static void fat_time(unsigned short* date,
1134 } 1509 }
1135 *time = time2 >> 1; 1510 *time = time2 >> 1;
1136 } 1511 }
1137 1512
1138 if (tenth) 1513 if (tenth)
1139 *tenth = (time2 & 1) * 100; 1514 *tenth = (time2 & 1) * 100;
1140 1515
1141 if (date && next_day) 1516 if (date && next_day)
1142 { 1517 {
1143 static const unsigned char daysinmonth[] = 1518 static const unsigned char daysinmonth[] =
1144 {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; 1519 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
1145 unsigned day = *date & 0x1f; 1520 unsigned day = *date & 0x1f;
1146 unsigned month = (*date >> 5) & 0x0f; 1521 unsigned month = (*date >> 5) & 0x0f;
1147 unsigned year = (*date >> 9) & 0x7f; 1522 unsigned year = (*date >> 9) & 0x7f;
@@ -1156,1514 +1531,1393 @@ static void fat_time(unsigned short* date,
1156 year++; 1531 year++;
1157 } 1532 }
1158 } 1533 }
1534
1159 *date = (year << 9) | (month << 5) | day; 1535 *date = (year << 9) | (month << 5) | day;
1160 } 1536 }
1161
1162#endif /* CONFIG_RTC */
1163} 1537}
1538#endif /* CONFIG_RTC */
1164 1539
1165static int write_long_name(struct fat_file* file, 1540static int write_longname(struct bpb *fat_bpb, struct fat_filestr *parentstr,
1166 unsigned int firstentry, 1541 struct fat_file *file, const unsigned char *name,
1167 unsigned int numentries, 1542 unsigned long ucslen, const unsigned char *shortname,
1168 const unsigned char* name, 1543 union raw_dirent *srcent, uint8_t attr,
1169 const unsigned char* shortname, 1544 unsigned int flags)
1170 bool is_directory)
1171{ 1545{
1172 unsigned char* entry; 1546 DEBUGF("%s(file:%lx, first:%d, num:%d, name:%s)\n", __func__,
1173 unsigned int idx = firstentry % DIR_ENTRIES_PER_SECTOR; 1547 parent->info->firstcluster, firstentry, numentries, name);
1174 unsigned int sector = firstentry / DIR_ENTRIES_PER_SECTOR; 1548
1175 unsigned char chksum = 0;
1176 unsigned int i, j=0;
1177 unsigned int nameidx=0, namelen = utf8length(name);
1178 int rc; 1549 int rc;
1179 unsigned short name_utf16[namelen + 1]; 1550 union raw_dirent *ent;
1551
1552 uint16_t date = 0, time = 0, tenth = 0;
1553 fat_time(&date, &time, &tenth);
1554 time = htole16(time);
1555 date = htole16(date);
1180 1556
1181 LDEBUGF("write_long_name(file:%lx, first:%d, num:%d, name:%s)\n", 1557 /* shortname checksum saved in each longname entry */
1182 file->firstcluster, firstentry, numentries, name); 1558 uint8_t chksum = shortname_checksum(shortname);
1183 1559
1184 rc = fat_seek(file, sector); 1560 /* we need to convert the name first since the entries are written in
1185 if (rc<0) 1561 reverse order */
1186 return rc * 10 - 1; 1562 unsigned long ucspadlen = ALIGN_UP(ucslen, FATLONG_NAME_CHARS);
1563 uint16_t ucsname[ucspadlen];
1187 1564
1188 unsigned char* buf = fat_get_sector_buffer(); 1565 for (unsigned long i = 0; i < ucspadlen; i++)
1189 rc = fat_readwrite(file, 1, buf, false);
1190 if (rc<1)
1191 { 1566 {
1192 fat_release_sector_buffer(); 1567 if (i < ucslen)
1193 return rc * 10 - 2; 1568 name = utf8decode(name, &ucsname[i]);
1569 else if (i == ucslen)
1570 ucsname[i] = 0x0000; /* name doesn't fill last block */
1571 else /* i > ucslen */
1572 ucsname[i] = 0xffff; /* pad-out to end */
1194 } 1573 }
1195 1574
1196 /* calculate shortname checksum */ 1575 dc_lock_cache();
1197 for (i=11; i>0; i--)
1198 chksum = ((chksum & 1) ? 0x80 : 0) + (chksum >> 1) + shortname[j++];
1199
1200 /* calc position of last name segment */
1201 if ( namelen > NAME_BYTES_PER_ENTRY )
1202 for (nameidx=0;
1203 nameidx < (namelen - NAME_BYTES_PER_ENTRY);
1204 nameidx += NAME_BYTES_PER_ENTRY);
1205
1206 /* we need to convert the name first */
1207 /* since it is written in reverse order */
1208 for (i = 0; i <= namelen; i++)
1209 name = utf8decode(name, &name_utf16[i]);
1210
1211 for (i=0; i < numentries; i++) {
1212 /* new sector? */
1213 if ( idx >= DIR_ENTRIES_PER_SECTOR ) {
1214 /* update current sector */
1215 rc = fat_seek(file, sector);
1216 if (rc<0)
1217 {
1218 fat_release_sector_buffer();
1219 return rc * 10 - 3;
1220 }
1221
1222 rc = fat_readwrite(file, 1, buf, true);
1223 if (rc<1)
1224 {
1225 fat_release_sector_buffer();
1226 return rc * 10 - 4;
1227 }
1228
1229 /* read next sector */
1230 rc = fat_readwrite(file, 1, buf, false);
1231 if (rc<0) {
1232 fat_release_sector_buffer();
1233 LDEBUGF("Failed writing new sector: %d\n",rc);
1234 return rc * 10 - 5;
1235 }
1236 if (rc==0)
1237 /* end of dir */
1238 memset(buf, 0, SECTOR_SIZE);
1239 1576
1240 sector++; 1577 const unsigned int longentries = file->e.entries - 1;
1241 idx = 0; 1578 const unsigned int firstentry = file->e.entry - longentries;
1242 }
1243 1579
1244 entry = buf + idx * DIR_ENTRY_SIZE; 1580 /* longame entries */
1581 for (unsigned int i = 0; i < longentries; i++)
1582 {
1583 ent = cache_direntry(fat_bpb, parentstr, firstentry + i);
1584 if (!ent)
1585 FAT_ERROR(-2);
1245 1586
1246 /* verify this entry is free */ 1587 /* verify this entry is free */
1247 if (entry[0] && entry[0] != 0xe5 ) 1588 if (ent->name[0] && ent->name[0] != 0xe5)
1248 { 1589 {
1249 fat_release_sector_buffer();
1250 panicf("Dir entry %d in sector %x is not free! " 1590 panicf("Dir entry %d in sector %x is not free! "
1251 "%02x %02x %02x %02x", 1591 "%02x %02x %02x %02x",
1252 idx, sector, 1592 i + firstentry, (unsigned)parentstr->lastsector,
1253 entry[0], entry[1], entry[2], entry[3]); 1593 (unsigned)ent->data[0], (unsigned)ent->data[1],
1594 (unsigned)ent->data[2], (unsigned)ent->data[3]);
1254 } 1595 }
1255 1596
1256 memset(entry, 0, DIR_ENTRY_SIZE); 1597 memset(ent->data, 0, DIR_ENTRY_SIZE);
1257 if ( i+1 < numentries ) {
1258 /* longname entry */
1259 unsigned int k, l = nameidx;
1260
1261 entry[FATLONG_ORDER] = numentries-i-1;
1262 if (i==0) {
1263 /* mark this as last long entry */
1264 entry[FATLONG_ORDER] |= FATLONG_LAST_LONG_ENTRY;
1265
1266 /* pad name with 0xffff */
1267 for (k=1; k<11; k++) entry[k] = FAT_LONGNAME_PAD_BYTE;
1268 for (k=14; k<26; k++) entry[k] = FAT_LONGNAME_PAD_BYTE;
1269 for (k=28; k<32; k++) entry[k] = FAT_LONGNAME_PAD_BYTE;
1270 };
1271 /* set name */
1272 for (k=0; k<5 && l <= namelen; k++) {
1273 entry[k*2 + 1] = (unsigned char)(name_utf16[l] & 0xff);
1274 entry[k*2 + 2] = (unsigned char)(name_utf16[l++] >> 8);
1275 }
1276 for (k=0; k<6 && l <= namelen; k++) {
1277 entry[k*2 + 14] = (unsigned char)(name_utf16[l] & 0xff);
1278 entry[k*2 + 15] = (unsigned char)(name_utf16[l++] >> 8);
1279 }
1280 for (k=0; k<2 && l <= namelen; k++) {
1281 entry[k*2 + 28] = (unsigned char)(name_utf16[l] & 0xff);
1282 entry[k*2 + 29] = (unsigned char)(name_utf16[l++] >> 8);
1283 }
1284 1598
1285 entry[FATDIR_ATTR] = FAT_ATTR_LONG_NAME; 1599 unsigned int ord = longentries - i;
1286 entry[FATDIR_FSTCLUSLO] = 0; 1600
1287 entry[FATLONG_TYPE] = 0; 1601 ent->ldir_ord = ord | (i == 0 ? FATLONG_ORD_F_LAST : 0);
1288 entry[FATLONG_CHKSUM] = chksum; 1602 ent->ldir_attr = ATTR_LONG_NAME;
1289 LDEBUGF("Longname entry %d: %s\n", idx, name+nameidx); 1603 ent->ldir_chksum = chksum;
1290 } 1604
1291 else { 1605 /* set name */
1292 /* shortname entry */ 1606 uint16_t *ucsptr = &ucsname[(ord - 1) * FATLONG_NAME_CHARS];
1293 unsigned short date=0, time=0, tenth=0; 1607 for (unsigned j = longent_char_first(); j; j = longent_char_next(j))
1294 LDEBUGF("Shortname entry: %s\n", shortname); 1608 {
1295 memcpy(entry + FATDIR_NAME, shortname, 11); 1609 uint16_t ucs = *ucsptr++;
1296 entry[FATDIR_ATTR] = is_directory?FAT_ATTR_DIRECTORY:0; 1610 INT162BYTES(ent->data, j, ucs);
1297 entry[FATDIR_NTRES] = 0;
1298
1299 fat_time(&date, &time, &tenth);
1300 entry[FATDIR_CRTTIMETENTH] = tenth;
1301 *(unsigned short*)(entry + FATDIR_CRTTIME) = htole16(time);
1302 *(unsigned short*)(entry + FATDIR_WRTTIME) = htole16(time);
1303 *(unsigned short*)(entry + FATDIR_CRTDATE) = htole16(date);
1304 *(unsigned short*)(entry + FATDIR_WRTDATE) = htole16(date);
1305 *(unsigned short*)(entry + FATDIR_LSTACCDATE) = htole16(date);
1306 } 1611 }
1307 idx++; 1612
1308 nameidx -= NAME_BYTES_PER_ENTRY; 1613 dc_dirty_buf(ent);
1614 DEBUGF("Longname entry %d\n", ord);
1309 } 1615 }
1310 1616
1311 /* update last sector */ 1617 /* shortname entry */
1312 rc = fat_seek(file, sector); 1618 DEBUGF("Shortname '%s'\n", shortname);
1313 if (rc<0) 1619
1620 ent = cache_direntry(fat_bpb, parentstr, file->e.entry);
1621 if (!ent)
1622 FAT_ERROR(-2);
1623
1624 if (srcent && (flags & DIRENT_TEMPL))
1314 { 1625 {
1315 fat_release_sector_buffer(); 1626 /* srcent points to short entry template */
1316 return rc * 10 - 6; 1627 *ent = *srcent;
1628 }
1629 else
1630 {
1631 /* make our own short entry */
1632 memset(ent->data, 0, DIR_ENTRY_SIZE);
1633 ent->attr = attr;
1317 } 1634 }
1318 1635
1319 rc = fat_readwrite(file, 1, buf, true); 1636 /* short name may change even if just moving */
1320 fat_release_sector_buffer(); 1637 memcpy(ent->name, shortname, 11);
1321 if (rc<1) 1638 raw_dirent_set_fstclus(ent, file->firstcluster);
1322 return rc * 10 - 7;
1323 1639
1324 return 0; 1640 if (!(flags & DIRENT_TEMPL_CRT))
1325}
1326
1327static int fat_checkname(const unsigned char* newname)
1328{
1329 static const char invalid_chars[] = "\"*/:<>?\\|";
1330 int len = strlen(newname);
1331 /* More sanity checks are probably needed */
1332 if (len > 255 || newname[len - 1] == '.')
1333 { 1641 {
1334 return -1; 1642 ent->crttimetenth = tenth;
1643 ent->crttime = time;
1644 ent->crtdate = date;
1335 } 1645 }
1336 while (*newname) 1646
1647 if (!(flags & DIRENT_TEMPL_WRT))
1337 { 1648 {
1338 if (*newname < ' ' || strchr(invalid_chars, *newname) != NULL) 1649 ent->wrttime = time;
1339 return -1; 1650 ent->wrtdate = date;
1340 newname++;
1341 } 1651 }
1342 /* check trailing space(s) */
1343 if(*(--newname) == ' ')
1344 return -1;
1345 1652
1346 return 0; 1653 if (!(flags & DIRENT_TEMPL_ACC))
1654 ent->lstaccdate = date;
1655
1656 if (srcent && (flags & DIRENT_RETURN))
1657 *srcent = *ent; /* caller wants */
1658
1659 dc_dirty_buf(ent);
1660
1661 rc = 0;
1662fat_error:
1663 dc_unlock_cache();
1664 return rc;
1347} 1665}
1348 1666
1349static int add_dir_entry(struct fat_dir* dir, 1667static int add_dir_entry(struct bpb *fat_bpb, struct fat_filestr *parentstr,
1350 struct fat_file* file, 1668 struct fat_file *file, const char *name,
1351 const char* name, 1669 union raw_dirent *srcent, uint8_t attr,
1352 bool is_directory, 1670 unsigned int flags)
1353 bool dotdir)
1354{ 1671{
1355#ifdef HAVE_MULTIVOLUME 1672 DEBUGF("%s(name:\"%s\",first:%lx)\n", __func__, name,
1356 struct bpb* fat_bpb = &fat_bpbs[dir->file.volume]; 1673 file->firstcluster);
1357#else
1358 struct bpb* fat_bpb = &fat_bpbs[0];
1359#endif
1360 unsigned char shortname[12];
1361 int rc;
1362 unsigned int sector;
1363 bool done = false;
1364 int entries_needed, entries_found = 0;
1365 int firstentry;
1366
1367 LDEBUGF( "add_dir_entry(%s,%lx)\n",
1368 name, file->firstcluster);
1369
1370 /* Don't check dotdirs name for validity */
1371 if (dotdir == false) {
1372 rc = fat_checkname(name);
1373 if (rc < 0) {
1374 /* filename is invalid */
1375 return rc * 10 - 1;
1376 }
1377 }
1378 1674
1379#ifdef HAVE_MULTIVOLUME 1675 int rc;
1380 file->volume = dir->file.volume; /* inherit the volume, to make sure */
1381#endif
1382 1676
1383 /* The "." and ".." directory entries must not be long names */ 1677 unsigned char basisname[11], shortname[11];
1384 if(dotdir) { 1678 int n;
1385 int i; 1679 int entries_needed;
1386 strlcpy(shortname, name, 12); 1680 unsigned long ucslen = 0;
1387 for(i = strlen(shortname); i < 12; i++)
1388 shortname[i] = ' ';
1389 1681
1682 if (is_dotdir_name(name) && (attr & ATTR_DIRECTORY))
1683 {
1684 /* The "." and ".." directory entries must not be long names */
1685 int dots = strlcpy(shortname, name, 11);
1686 memset(&shortname[dots], ' ', 11 - dots);
1390 entries_needed = 1; 1687 entries_needed = 1;
1391 } else { 1688 }
1392 create_dos_name(name, shortname); 1689 else
1690 {
1691 rc = check_longname(name);
1692 if (rc < 0)
1693 FAT_ERROR(rc * 10 - 1); /* filename is invalid */
1694
1695 create_dos_name(basisname, name, &n);
1696 randomize_dos_name(shortname, basisname, &n);
1393 1697
1394 /* one dir entry needed for every 13 bytes of filename, 1698 /* one dir entry needed for every 13 characters of filename,
1395 plus one entry for the short name */ 1699 plus one entry for the short name */
1396 entries_needed = (utf8length(name) + (NAME_BYTES_PER_ENTRY-1)) 1700 ucslen = utf8length(name);
1397 / NAME_BYTES_PER_ENTRY + 1; 1701 if (ucslen > 255)
1702 FAT_ERROR(-2); /* name is too long */
1703
1704 entries_needed = (ucslen + FATLONG_NAME_CHARS - 1)
1705 / FATLONG_NAME_CHARS + 1;
1398 } 1706 }
1399 1707
1400 unsigned char* buf = fat_get_sector_buffer(); 1708 int entry = 0, entries_found = 0, firstentry = -1;
1401 restart: 1709 const int entperclus = DIR_ENTRIES_PER_SECTOR*fat_bpb->bpb_secperclus;
1402 firstentry = -1;
1403 1710
1404 rc = fat_seek(&dir->file, 0); 1711 /* step 1: search for a sufficiently-long run of free entries and check
1405 if (rc < 0) 1712 for duplicate shortname */
1406 { 1713 dc_lock_cache();
1407 fat_release_sector_buffer();
1408 return rc * 10 - 2;
1409 }
1410 1714
1411 /* step 1: search for free entries and check for duplicate shortname */ 1715 for (bool done = false; !done;)
1412 for (sector = 0; !done; sector++)
1413 { 1716 {
1414 unsigned int i; 1717 union raw_dirent *ent = cache_direntry(fat_bpb, parentstr, entry);
1415 1718
1416 rc = fat_readwrite(&dir->file, 1, buf, false); 1719 if (!ent)
1417 if (rc < 0) { 1720 {
1418 fat_release_sector_buffer(); 1721 if (parentstr->eof)
1419 DEBUGF( "add_dir_entry() - Couldn't read dir" 1722 {
1420 " (error code %d)\n", rc); 1723 DEBUGF("End of dir (entry %d)\n", entry);
1421 return rc * 10 - 3; 1724 break;
1422 } 1725 }
1423 1726
1424 if (rc == 0) { /* current end of dir reached */ 1727 DEBUGF("Couldn't read dir (entry %d)\n", entry);
1425 LDEBUGF("End of dir on cluster boundary\n"); 1728 dc_unlock_cache();
1426 break; 1729 FAT_ERROR(-3);
1427 } 1730 }
1428 1731
1429 /* look for free slots */ 1732 switch (ent->name[0])
1430 for (i = 0; i < DIR_ENTRIES_PER_SECTOR; i++)
1431 { 1733 {
1432 switch (buf[i * DIR_ENTRY_SIZE]) { 1734 case 0: /* all remaining entries in cluster are free */
1433 case 0: 1735 DEBUGF("Found end of dir %d\n", entry);
1434 entries_found += DIR_ENTRIES_PER_SECTOR - i; 1736 int found = entperclus - (entry % entperclus);
1435 LDEBUGF("Found end of dir %d\n", 1737 entries_found += found;
1436 sector * DIR_ENTRIES_PER_SECTOR + i); 1738 entry += found; /* move entry passed end of cluster */
1437 i = DIR_ENTRIES_PER_SECTOR - 1; 1739 done = true;
1438 done = true; 1740 break;
1439 break;
1440 1741
1441 case 0xe5: 1742 case 0xe5: /* individual free entry */
1442 entries_found++; 1743 entries_found++;
1443 LDEBUGF("Found free entry %d (%d/%d)\n", 1744 entry++;
1444 sector * DIR_ENTRIES_PER_SECTOR + i, 1745 DEBUGF("Found free entry %d (%d/%d)\n",
1445 entries_found, entries_needed); 1746 entry, entries_found, entries_needed);
1446 break; 1747 break;
1447 1748
1448 default: 1749 default: /* occupied */
1449 entries_found = 0; 1750 entries_found = 0;
1751 entry++;
1450 1752
1451 /* check that our intended shortname doesn't already exist */ 1753 if ((ent->ldir_attr & ATTR_LONG_NAME_MASK) == ATTR_LONG_NAME)
1452 if (!strncmp(shortname, buf + i * DIR_ENTRY_SIZE, 11)) { 1754 break; /* ignore long name entry */
1453 /* shortname exists already, make a new one */
1454 randomize_dos_name(shortname);
1455 LDEBUGF("Duplicate shortname, changing to %s\n",
1456 shortname);
1457 1755
1458 /* name has changed, we need to restart search */ 1756 /* check that our intended shortname doesn't already exist */
1459 goto restart; 1757 if (!strncmp(shortname, ent->name, 11))
1460 } 1758 {
1461 break; 1759 /* shortname exists already, make a new one */
1760 DEBUGF("Duplicate shortname '%.11s'", shortname);
1761 randomize_dos_name(shortname, basisname, &n);
1762 DEBUGF(", changing to '%.11s'\n", shortname);
1763
1764 /* name has changed, we need to restart search */
1765 entry = 0;
1766 firstentry = -1;
1462 } 1767 }
1463 if (firstentry < 0 && (entries_found >= entries_needed)) 1768 break;
1464 firstentry = sector * DIR_ENTRIES_PER_SECTOR + i + 1 1769 }
1465 - entries_found; 1770
1771 if (firstentry < 0 && entries_found >= entries_needed)
1772 {
1773 /* found adequate space; point to initial free entry */
1774 firstentry = entry - entries_found;
1466 } 1775 }
1467 } 1776 }
1468 1777
1778 dc_unlock_cache();
1779
1469 /* step 2: extend the dir if necessary */ 1780 /* step 2: extend the dir if necessary */
1470 if (firstentry < 0) 1781 if (firstentry < 0)
1471 { 1782 {
1472 LDEBUGF("Adding new sector(s) to dir\n"); 1783 DEBUGF("Adding new cluster(s) to dir\n");
1473 rc = fat_seek(&dir->file, sector); 1784
1474 if (rc < 0) 1785 if (entry + entries_needed - entries_found > MAX_DIRENTRIES)
1475 { 1786 {
1476 fat_release_sector_buffer(); 1787 /* FAT specification allows no more than 65536 entries (2MB)
1477 return rc * 10 - 4; 1788 per directory */
1789 DEBUGF("Directory would be too large.\n");
1790 FAT_ERROR(-4);
1478 } 1791 }
1479 memset(buf, 0, SECTOR_SIZE);
1480 1792
1481 /* we must clear whole clusters */ 1793 while (entries_found < entries_needed)
1482 for (; (entries_found < entries_needed) ||
1483 (dir->file.sectornum < (int)fat_bpb->bpb_secperclus); sector++)
1484 { 1794 {
1485 if (sector >= (65536/DIR_ENTRIES_PER_SECTOR)) 1795 rc = fat_extend_dir(fat_bpb, parentstr);
1486 { 1796 if (rc == FAT_RC_ENOSPC)
1487 fat_release_sector_buffer(); 1797 FAT_ERROR(RC);
1488 return -5; /* dir too large -- FAT specification */ 1798 else if (rc < 0)
1489 } 1799 FAT_ERROR(rc * 10 - 5);
1490 1800
1491 rc = fat_readwrite(&dir->file, 1, buf, true); 1801 entries_found += entperclus;
1492 if (rc < 1) /* No more room or something went wrong */ 1802 entry += entperclus;
1493 {
1494 fat_release_sector_buffer();
1495 return rc * 10 - 6;
1496 }
1497
1498 entries_found += DIR_ENTRIES_PER_SECTOR;
1499 } 1803 }
1500 1804
1501 firstentry = sector * DIR_ENTRIES_PER_SECTOR - entries_found; 1805 firstentry = entry - entries_found;
1502 } 1806 }
1503 fat_release_sector_buffer();
1504 1807
1505 /* step 3: add entry */ 1808 /* remember the parent directory entry information */
1506 sector = firstentry / DIR_ENTRIES_PER_SECTOR; 1809#ifdef HAVE_MULTIVOLUME
1507 LDEBUGF("Adding longname to entry %d in sector %d\n", 1810 file->volume = parentstr->fatfilep->volume;
1508 firstentry, sector); 1811#endif
1812 file->dircluster = parentstr->fatfilep->firstcluster;
1813 file->e.entry = firstentry + entries_needed - 1;
1814 file->e.entries = entries_needed;
1509 1815
1510 rc = write_long_name(&dir->file, firstentry, 1816 /* step 3: add entry */
1511 entries_needed, name, 1817 DEBUGF("Adding longname to entry %d\n", firstentry);
1512 shortname, is_directory); 1818 rc = write_longname(fat_bpb, parentstr, file, name, ucslen,
1819 shortname, srcent, attr, flags);
1513 if (rc < 0) 1820 if (rc < 0)
1514 return rc * 10 - 7; 1821 FAT_ERROR(rc * 10 - 6);
1515 1822
1516 /* remember where the shortname dir entry is located */ 1823 DEBUGF("Added new dir entry %u; using %u entries\n",
1517 file->direntry = firstentry + entries_needed - 1; 1824 file->e.entry, file->e.entries);
1518 file->direntries = entries_needed;
1519 file->dircluster = dir->file.firstcluster;
1520 LDEBUGF("Added new dir entry %d, using %d slots.\n",
1521 file->direntry, file->direntries);
1522 1825
1523 return 0; 1826 rc = 0;
1827fat_error:
1828 return rc;
1524} 1829}
1525 1830
1526static unsigned char char2dos(unsigned char c, int* randomize) 1831static int update_short_entry(struct bpb *fat_bpb, struct fat_file *file,
1832 uint32_t size, struct fat_direntry *fatent)
1527{ 1833{
1528 static const char invalid_chars[] = "\"*+,./:;<=>?[\\]|"; 1834 DEBUGF("%s(cluster:%lx entry:%d size:%ld)\n",
1529 1835 __func__, file->firstcluster, file->e.entry, size);
1530 if (c <= 0x20)
1531 c = 0; /* Illegal char, remove */
1532 else if (strchr(invalid_chars, c) != NULL)
1533 {
1534 /* Illegal char, replace */
1535 c = '_';
1536 *randomize = 1; /* as per FAT spec */
1537 }
1538 else
1539 c = toupper(c);
1540 1836
1541 return c; 1837 int rc;
1542}
1543
1544static void create_dos_name(const unsigned char *name, unsigned char *newname)
1545{
1546 int i;
1547 unsigned char *ext;
1548 int randomize = 0;
1549 1838
1550 /* Find extension part */ 1839#if CONFIG_RTC
1551 ext = strrchr(name, '.'); 1840 uint16_t time = 0;
1552 if (ext == name) /* handle .dotnames */ 1841 uint16_t date = 0;
1553 ext = NULL; 1842#else
1843 /* get old time to increment from */
1844 uint16_t time = letoh16(fatent->wrttime);
1845 uint16_t date = letoh16(fatent->wrtdate);
1846#endif
1847 fat_time(&date, &time, NULL);
1848 date = htole16(date);
1849 time = htole16(time);
1554 1850
1555 /* needs to randomize? */ 1851 /* open the parent directory */
1556 if((ext && (strlen(ext) > 4)) || 1852 struct fat_file parent;
1557 ((ext ? (unsigned int)(ext-name) : strlen(name)) > 8) ) 1853 fat_open_internal(IF_MV(file->volume,) file->dircluster, &parent);
1558 randomize = 1;
1559 1854
1560 /* Name part */ 1855 struct fat_filestr parentstr;
1561 for (i = 0; *name && (!ext || name < ext) && (i < 8); name++) 1856 fat_filestr_init(&parentstr, &parent);
1562 {
1563 unsigned char c = char2dos(*name, &randomize);
1564 if (c)
1565 newname[i++] = c;
1566 }
1567 1857
1568 /* Pad both name and extension */ 1858 dc_lock_cache();
1569 while (i < 11)
1570 newname[i++] = ' ';
1571 1859
1572 if (newname[0] == 0xe5) /* Special kanji character */ 1860 union raw_dirent *ent = cache_direntry(fat_bpb, &parentstr, file->e.entry);
1573 newname[0] = 0x05; 1861 if (!ent)
1862 FAT_ERROR(-1);
1574 1863
1575 if (ext) 1864 if (!ent->name[0] || ent->name[0] == 0xe5)
1576 { /* Extension part */ 1865 panicf("Updating size on empty dir entry %d\n", file->e.entry);
1577 ext++;
1578 for (i = 8; *ext && (i < 11); ext++)
1579 {
1580 unsigned char c = char2dos(*ext, &randomize);
1581 if (c)
1582 newname[i++] = c;
1583 }
1584 }
1585 1866
1586 if(randomize) 1867 /* basic file data */
1587 randomize_dos_name(newname); 1868 raw_dirent_set_fstclus(ent, file->firstcluster);
1588} 1869 ent->filesize = htole32(size);
1589 1870
1590static void randomize_dos_name(unsigned char *name) 1871 /* time and date info */
1591{ 1872 ent->wrttime = time;
1592 unsigned char* tilde = NULL; /* ~ location */ 1873 ent->wrtdate = date;
1593 unsigned char* lastpt = NULL; /* last point of filename */ 1874 ent->lstaccdate = date;
1594 unsigned char* nameptr = name; /* working copy of name pointer */
1595 unsigned char num[9]; /* holds number as string */
1596 int i = 0;
1597 int cnt = 1;
1598 int numlen;
1599 int offset;
1600 1875
1601 while(i++ < 8) 1876 if (fatent)
1602 { 1877 {
1603 /* hunt for ~ and where to put it */ 1878 fatent->name[0] = '\0'; /* not gonna bother here */
1604 if(!tilde && *nameptr == '~') 1879 parse_short_direntry(ent, fatent);
1605 tilde = nameptr;
1606 if(!lastpt && (*nameptr == ' ' || *nameptr == '~'))
1607 lastpt = nameptr;
1608 nameptr++;
1609 } 1880 }
1610 if(tilde)
1611 {
1612 /* extract current count and increment */
1613 memcpy(num,tilde+1,7-(unsigned int)(tilde-name));
1614 num[7-(unsigned int)(tilde-name)] = 0;
1615 cnt = atoi(num) + 1;
1616 }
1617 cnt %= 10000000; /* protection */
1618 snprintf(num, 9, "~%d", cnt); /* allow room for trailing zero */
1619 numlen = strlen(num); /* required space */
1620 offset = (unsigned int)(lastpt ? lastpt - name : 8); /* prev startpoint */
1621 if(offset > (8-numlen)) offset = 8-numlen; /* correct for new numlen */
1622 1881
1623 memcpy(&name[offset], num, numlen); 1882 dc_dirty_buf(ent);
1624 1883
1625 /* in special case of counter overflow: pad with spaces */ 1884 rc = 0;
1626 for(offset = offset+numlen; offset < 8; offset++) 1885fat_error:
1627 name[offset] = ' '; 1886 dc_unlock_cache();
1887 return rc;
1628} 1888}
1629 1889
1630static int update_short_entry( struct fat_file* file, long size, int attr ) 1890static int free_direntries(struct bpb *fat_bpb, struct fat_file *file)
1631{ 1891{
1632 int sector = file->direntry / DIR_ENTRIES_PER_SECTOR; 1892 /* open the parent directory */
1633 uint32_t* sizeptr; 1893 struct fat_file parent;
1634 uint16_t* clusptr; 1894 fat_open_internal(IF_MV(file->volume,) file->dircluster, &parent);
1635 struct fat_file dir;
1636 int rc;
1637 1895
1638 LDEBUGF("update_file_size(cluster:%lx entry:%d size:%ld)\n", 1896 struct fat_filestr parentstr;
1639 file->firstcluster, file->direntry, size); 1897 fat_filestr_init(&parentstr, &parent);
1640 1898
1641 /* create a temporary file handle for the dir holding this file */ 1899 for (unsigned int entries = file->e.entries,
1642 rc = fat_open(IF_MV(file->volume,) file->dircluster, &dir, NULL); 1900 entry = file->e.entry - entries + 1;
1643 if (rc < 0) 1901 entries; entries--, entry++)
1644 return rc * 10 - 1;
1645
1646 rc = fat_seek( &dir, sector );
1647 if (rc<0)
1648 return rc * 10 - 2;
1649
1650 unsigned char* buf = fat_get_sector_buffer();
1651 unsigned char* entry =
1652 buf + DIR_ENTRY_SIZE * (file->direntry % DIR_ENTRIES_PER_SECTOR);
1653 rc = fat_readwrite(&dir, 1, buf, false);
1654 if (rc < 1)
1655 { 1902 {
1656 fat_release_sector_buffer(); 1903 DEBUGF("Clearing dir entry %d (%d/%d)\n",
1657 return rc * 10 - 3; 1904 entry, entry - numentries + 1, numentries);
1658 }
1659 1905
1660 if (!entry[0] || entry[0] == 0xe5) 1906 dc_lock_cache();
1661 {
1662 fat_release_sector_buffer();
1663 panicf("Updating size on empty dir entry %d\n", file->direntry);
1664 }
1665 1907
1666 entry[FATDIR_ATTR] = attr & 0xFF; 1908 union raw_dirent *ent = cache_direntry(fat_bpb, &parentstr, entry);
1909 if (!ent)
1910 {
1911 dc_unlock_cache();
1667 1912
1668 clusptr = (uint16_t*)(entry + FATDIR_FSTCLUSHI); 1913 if (entries == file->e.entries)
1669 *clusptr = htole16(file->firstcluster >> 16); 1914 return -1; /* nothing at all freed */
1670 1915
1671 clusptr = (uint16_t*)(entry + FATDIR_FSTCLUSLO); 1916 /* longname already destroyed; revert to shortname */
1672 *clusptr = htole16(file->firstcluster & 0xffff); 1917 file->e.entries = 1;
1918 return 0;
1919 }
1673 1920
1674 sizeptr = (uint32_t*)(entry + FATDIR_FILESIZE); 1921 ent->data[0] = 0xe5;
1675 *sizeptr = htole32(size);
1676 1922
1677 { 1923 dc_dirty_buf(ent);
1678#if CONFIG_RTC 1924 dc_unlock_cache();
1679 uint16_t time = 0;
1680 uint16_t date = 0;
1681#else
1682 /* get old time to increment from */
1683 uint16_t time = htole16(*(uint16_t*)(entry+FATDIR_WRTTIME));
1684 uint16_t date = htole16(*(uint16_t*)(entry+FATDIR_WRTDATE));
1685#endif
1686 fat_time(&date, &time, NULL);
1687 *(uint16_t*)(entry + FATDIR_WRTTIME) = htole16(time);
1688 *(uint16_t*)(entry + FATDIR_WRTDATE) = htole16(date);
1689 *(uint16_t*)(entry + FATDIR_LSTACCDATE) = htole16(date);
1690 } 1925 }
1691 1926
1692 rc = fat_seek( &dir, sector ); 1927 /* directory entry info is now gone */
1693 if (rc < 0) 1928 file->dircluster = 0;
1694 { 1929 file->e.entry = FAT_RW_VAL;
1695 fat_release_sector_buffer(); 1930 file->e.entries = 0;
1696 return rc * 10 - 4;
1697 }
1698
1699 rc = fat_readwrite(&dir, 1, buf, true);
1700 fat_release_sector_buffer();
1701 if (rc < 1)
1702 return rc * 10 - 5;
1703 1931
1704 return 0; 1932 return 1;
1705} 1933}
1706 1934
1707static int parse_direntry(struct fat_direntry *de, const unsigned char *buf) 1935static int free_cluster_chain(struct bpb *fat_bpb, long startcluster)
1708{ 1936{
1709 int i=0,j=0; 1937 for (long last = startcluster, next; last; last = next)
1710 unsigned char c; 1938 {
1711 bool lowercase; 1939 next = get_next_cluster(fat_bpb, last);
1940 int rc = update_fat_entry(fat_bpb, last, 0);
1941 if (LIKELY(rc >= 0 && !startcluster))
1942 continue;
1712 1943
1713 memset(de, 0, sizeof(struct fat_direntry)); 1944 if (rc < 0)
1714 de->attr = buf[FATDIR_ATTR]; 1945 return startcluster ? -1 : 0;
1715 de->crttimetenth = buf[FATDIR_CRTTIMETENTH];
1716 de->crtdate = BYTES2INT16(buf,FATDIR_CRTDATE);
1717 de->crttime = BYTES2INT16(buf,FATDIR_CRTTIME);
1718 de->wrtdate = BYTES2INT16(buf,FATDIR_WRTDATE);
1719 de->wrttime = BYTES2INT16(buf,FATDIR_WRTTIME);
1720 de->filesize = BYTES2INT32(buf,FATDIR_FILESIZE);
1721 de->firstcluster = ((long)(unsigned)BYTES2INT16(buf,FATDIR_FSTCLUSLO)) |
1722 ((long)(unsigned)BYTES2INT16(buf,FATDIR_FSTCLUSHI) << 16);
1723 /* The double cast is to prevent a sign-extension to be done on CalmRISC16.
1724 (the result of the shift is always considered signed) */
1725 1946
1726 /* fix the name */ 1947 startcluster = 0;
1727 lowercase = (buf[FATDIR_NTRES] & FAT_NTRES_LC_NAME);
1728 c = buf[FATDIR_NAME];
1729 if (c == 0x05) /* special kanji char */
1730 c = 0xe5;
1731 i = 0;
1732 while (c != ' ') {
1733 de->name[j++] = lowercase ? tolower(c) : c;
1734 if (++i >= 8)
1735 break;
1736 c = buf[FATDIR_NAME+i];
1737 }
1738 if (buf[FATDIR_NAME+8] != ' ') {
1739 lowercase = (buf[FATDIR_NTRES] & FAT_NTRES_LC_EXT);
1740 de->name[j++] = '.';
1741 for (i = 8; (i < 11) && ((c = buf[FATDIR_NAME+i]) != ' '); i++)
1742 de->name[j++] = lowercase ? tolower(c) : c;
1743 } 1948 }
1949
1744 return 1; 1950 return 1;
1745} 1951}
1746 1952
1747int fat_open(IF_MV(int volume,)
1748 long startcluster,
1749 struct fat_file *file,
1750 const struct fat_dir* dir)
1751{
1752 /* Remember where the file's dir entry is located
1753 * Do it before assigning other fields so that fat_open
1754 * can be called with file == &dir->file (see fat_opendir) */
1755 if ( dir ) {
1756 file->direntry = dir->entry - 1;
1757 file->direntries = dir->entrycount;
1758 file->dircluster = dir->file.firstcluster;
1759 }
1760
1761 file->firstcluster = startcluster;
1762 file->lastcluster = startcluster;
1763 file->lastsector = 0;
1764 file->clusternum = 0;
1765 file->sectornum = 0;
1766 file->eof = false;
1767#ifdef HAVE_MULTIVOLUME
1768 file->volume = volume;
1769 /* fixme: remove error check when done */
1770 if (volume >= NUM_VOLUMES || !fat_bpbs[volume].mounted)
1771 {
1772 LDEBUGF("fat_open() illegal volume %d\n", volume);
1773 return -1;
1774 }
1775#endif
1776 1953
1777 LDEBUGF("fat_open(%lx), entry %d\n",startcluster,file->direntry); 1954/** File entity functions **/
1778 return 0;
1779}
1780 1955
1781int fat_create_file(const char* name, 1956int fat_create_file(struct fat_file *parent, const char *name,
1782 struct fat_file* file, 1957 uint8_t attr, struct fat_file *file,
1783 struct fat_dir* dir) 1958 struct fat_direntry *fatent)
1784{ 1959{
1785 int rc; 1960 DEBUGF("%s(\"%s\",%lx,%lx)\n", __func__, name, (long)file, (long)dir);
1786 1961 struct bpb * const fat_bpb = FAT_BPB(parent->volume);
1787 LDEBUGF("fat_create_file(\"%s\",%lx,%lx)\n",name,(long)file,(long)dir); 1962 if (!fat_bpb)
1788 rc = add_dir_entry(dir, file, name, false, false); 1963 return -1;
1789 if (!rc) {
1790 file->firstcluster = 0;
1791 file->lastcluster = 0;
1792 file->lastsector = 0;
1793 file->clusternum = 0;
1794 file->sectornum = 0;
1795 file->eof = false;
1796 }
1797 1964
1798 return rc; 1965 int rc;
1799}
1800 1966
1801/* noinline because this is only split out of fat_create_dir to make sure 1967 fat_open_internal(IF_MV(parent->volume,) 0, file);
1802 * the sector buffer doesn't remain on the stack, to avoid nasty stack
1803 * overflows later on (when flush_fat() is called) */
1804static __attribute__((noinline)) int fat_clear_cluster(int sector,
1805 struct bpb *fat_bpb)
1806{
1807 unsigned char* buf = fat_get_sector_buffer();
1808 int i,rc;
1809 memset(buf, 0, SECTOR_SIZE);
1810 for(i = 0;i < (int)fat_bpb->bpb_secperclus;i++) {
1811 rc = transfer(IF_MV(fat_bpb,) sector + i, 1, buf, true );
1812 if (rc < 0)
1813 {
1814 fat_release_sector_buffer();
1815 return rc * 10 - 2;
1816 }
1817 }
1818 fat_release_sector_buffer();
1819 return 0;
1820}
1821 1968
1822int fat_create_dir(const char* name, 1969 struct fat_filestr parentstr;
1823 struct fat_dir* newdir, 1970 fat_filestr_init(&parentstr, parent);
1824 struct fat_dir* dir)
1825{
1826#ifdef HAVE_MULTIVOLUME
1827 struct bpb* fat_bpb = &fat_bpbs[dir->file.volume];
1828#else
1829 struct bpb* fat_bpb = &fat_bpbs[0];
1830#endif
1831 long sector;
1832 int rc;
1833 struct fat_file dummyfile;
1834 1971
1835 LDEBUGF("fat_create_dir(\"%s\",%lx,%lx)\n",name,(long)newdir,(long)dir); 1972 const bool isdir = attr & ATTR_DIRECTORY;
1973 unsigned int addflags = fatent ? DIRENT_RETURN : 0;
1974 union raw_dirent *newentp = (isdir || fatent) ?
1975 alloca(sizeof (union raw_dirent)) : NULL;
1836 1976
1837 memset(newdir, 0, sizeof(struct fat_dir)); 1977 if (isdir)
1838 memset(&dummyfile, 0, sizeof(struct fat_file)); 1978 {
1979 struct fat_filestr dirstr;
1980 fat_filestr_init(&dirstr, file);
1839 1981
1840 /* First, add the entry in the parent directory */ 1982 /* create the first cluster */
1841 rc = add_dir_entry(dir, &newdir->file, name, true, false); 1983 rc = fat_extend_dir(fat_bpb, &dirstr);
1842 if (rc < 0) 1984 if (rc == FAT_RC_ENOSPC)
1843 return rc * 10 - 1; 1985 FAT_ERROR(RC);
1986 else if (rc < 0)
1987 FAT_ERROR(rc * 10 - 2);
1844 1988
1845 /* Allocate a new cluster for the directory */ 1989 struct fat_file dummyfile;
1846 newdir->file.firstcluster = find_free_cluster(IF_MV(fat_bpb,)
1847 fat_bpb->fsinfo.nextfree);
1848 if(newdir->file.firstcluster == 0)
1849 return -1;
1850 1990
1851 update_fat_entry(IF_MV(fat_bpb,) newdir->file.firstcluster, FAT_EOF_MARK); 1991 /* add the "." entry */
1992 fat_open_internal(IF_MV(0,) file->firstcluster, &dummyfile);
1852 1993
1853 /* Clear the entire cluster */ 1994 /* this returns the short entry template for the remaining entries */
1854 sector = cluster2sec(IF_MV(fat_bpb,) newdir->file.firstcluster); 1995 rc = add_dir_entry(fat_bpb, &dirstr, &dummyfile, ".", newentp,
1855 rc = fat_clear_cluster(sector,fat_bpb); 1996 attr, DIRENT_RETURN);
1856 if (rc < 0) 1997 if (rc < 0)
1857 return rc; 1998 FAT_ERROR(rc * 10 - 3);
1858 1999
2000 /* and the ".." entry */
2001 /* the root cluster is cluster 0 in the ".." entry */
2002 fat_open_internal(IF_MV(0,)
2003 parent->firstcluster == fat_bpb->bpb_rootclus ?
2004 0 : parent->firstcluster, &dummyfile);
1859 2005
1860 /* Then add the "." entry */ 2006 rc = add_dir_entry(fat_bpb, &dirstr, &dummyfile, "..", newentp,
1861 rc = add_dir_entry(newdir, &dummyfile, ".", true, true); 2007 attr, DIRENT_TEMPL_TIMES);
1862 if (rc < 0) 2008 if (rc < 0)
1863 return rc * 10 - 3; 2009 FAT_ERROR(rc * 10 - 4);
1864 dummyfile.firstcluster = newdir->file.firstcluster;
1865 update_short_entry(&dummyfile, 0, FAT_ATTR_DIRECTORY);
1866 2010
1867 /* and the ".." entry */ 2011 addflags |= DIRENT_TEMPL_TIMES;
1868 rc = add_dir_entry(newdir, &dummyfile, "..", true, true); 2012 }
1869 if (rc < 0)
1870 return rc * 10 - 4;
1871 2013
1872 /* The root cluster is cluster 0 in the ".." entry */ 2014 /* lastly, add the entry in the parent directory */
1873 if(dir->file.firstcluster == fat_bpb->bpb_rootclus) 2015 rc = add_dir_entry(fat_bpb, &parentstr, file, name, newentp,
1874 dummyfile.firstcluster = 0; 2016 attr, addflags);
1875 else 2017 if (rc == FAT_RC_ENOSPC)
1876 dummyfile.firstcluster = dir->file.firstcluster; 2018 FAT_ERROR(RC);
1877 update_short_entry(&dummyfile, 0, FAT_ATTR_DIRECTORY); 2019 else if (rc < 0)
2020 FAT_ERROR(rc * 10 - 5);
1878 2021
1879 /* Set the firstcluster field in the direntry */ 2022 if (fatent)
1880 update_short_entry(&newdir->file, 0, FAT_ATTR_DIRECTORY); 2023 {
2024 strcpy(fatent->name, name);
2025 parse_short_direntry(newentp, fatent);
2026 }
1881 2027
1882 rc = flush_fat(IF_MV(fat_bpb)); 2028 rc = 0;
2029fat_error:
1883 if (rc < 0) 2030 if (rc < 0)
1884 return rc * 10 - 5; 2031 free_cluster_chain(fat_bpb, file->firstcluster);
1885 2032
2033 cache_commit(fat_bpb);
1886 return rc; 2034 return rc;
1887} 2035}
1888 2036
1889int fat_truncate(const struct fat_file *file) 2037bool fat_dir_is_parent(const struct fat_file *dir, const struct fat_file *file)
2038{
2039 /* if the directory file's first cluster is the same as the file's
2040 directory cluster and they're on the same volume, 'dir' is its parent
2041 directory; the file must also have a dircluster (ie. not removed) */
2042 long dircluster = file->dircluster;
2043 return dircluster && dircluster == dir->firstcluster
2044 IF_MV( && dir->volume == file->volume );
2045}
2046
2047bool fat_file_is_same(const struct fat_file *file1,
2048 const struct fat_file *file2)
2049{
2050 /* first, triviality */
2051 if (file1 == file2)
2052 return true;
2053
2054 /* if the directory info matches and the volumes are the same, file1 and
2055 file2 refer to the same file/directory */
2056 return file1->dircluster == file2->dircluster
2057 && file1->e.entry == file2->e.entry
2058 IF_MV( && file1->volume == file2->volume );
2059}
2060
2061int fat_open(const struct fat_file *parent, long startcluster,
2062 struct fat_file *file)
1890{ 2063{
1891 /* truncate trailing clusters */ 2064 if (!parent)
1892 long next; 2065 return -2; /* this does _not_ open any root */
1893 long last = file->lastcluster; 2066
2067 struct bpb * const fat_bpb = FAT_BPB(parent->volume);
2068 if (!fat_bpb)
2069 return -1;
2070
2071 /* inherit basic parent information; dirscan info is expected to have been
2072 initialized beforehand (usually via scanning for the entry ;) */
1894#ifdef HAVE_MULTIVOLUME 2073#ifdef HAVE_MULTIVOLUME
1895 struct bpb* fat_bpb = &fat_bpbs[file->volume]; 2074 file->volume = parent->volume;
1896#endif 2075#endif
2076 file->firstcluster = startcluster;
2077 file->dircluster = parent->firstcluster;
1897 2078
1898 LDEBUGF("fat_truncate(%lx, %lx)\n", file->firstcluster, last); 2079 return 0;
2080}
1899 2081
1900 for ( last = get_next_cluster(IF_MV(fat_bpb,) last); last; last = next ) { 2082int fat_open_rootdir(IF_MV(int volume,) struct fat_file *dir)
1901 next = get_next_cluster(IF_MV(fat_bpb,) last); 2083{
1902 update_fat_entry(IF_MV(fat_bpb,) last,0); 2084 struct bpb * const fat_bpb = FAT_BPB(volume);
1903 } 2085 if (!fat_bpb)
1904 if (file->lastcluster) 2086 return -1;
1905 update_fat_entry(IF_MV(fat_bpb,) file->lastcluster,FAT_EOF_MARK);
1906 2087
2088 fat_open_internal(IF_MV(volume,) fat_bpb->bpb_rootclus, dir);
1907 return 0; 2089 return 0;
1908} 2090}
1909 2091
1910int fat_closewrite(struct fat_file *file, long size, int attr) 2092int fat_remove(struct fat_file *file, enum fat_remove_op what)
1911{ 2093{
2094 struct bpb * const fat_bpb = FAT_BPB(file->volume);
2095 if (!fat_bpb)
2096 return -1;
2097
1912 int rc; 2098 int rc;
1913#ifdef HAVE_MULTIVOLUME
1914 struct bpb* fat_bpb = &fat_bpbs[file->volume];
1915#endif
1916 LDEBUGF("fat_closewrite(size=%ld)\n",size);
1917 2099
1918 if (!size) { 2100 if (file->firstcluster == fat_bpb->bpb_rootclus)
1919 /* empty file */ 2101 {
1920 if ( file->firstcluster ) { 2102 DEBUGF("Trying to remove root of volume %d\n",
1921 update_fat_entry(IF_MV(fat_bpb,) file->firstcluster, 0); 2103 IF_MV_VOL(info->volume));
1922 file->firstcluster = 0; 2104 FAT_ERROR(-2);
1923 }
1924 } 2105 }
1925 2106
1926 if (file->dircluster) { 2107 if (file->dircluster && (what & FAT_RM_DIRENTRIES))
1927 rc = update_short_entry(file, size, attr); 2108 {
1928 if (rc < 0) 2109 /* free everything in the parent directory */
1929 return rc * 10 - 1; 2110 DEBUGF("Removing dir entries: %lX\n", info->dircluster);
2111 rc = free_direntries(fat_bpb, file);
2112 if (rc <= 0)
2113 FAT_ERROR(rc * 10 - 3);
1930 } 2114 }
1931 2115
1932 flush_fat(IF_MV(fat_bpb)); 2116 if (file->firstcluster && (what & FAT_RM_DATA))
2117 {
2118 /* mark all clusters in the chain as free */
2119 DEBUGF("Removing cluster chain: %lX\n", file->firstcluster);
2120 rc = free_cluster_chain(fat_bpb, file->firstcluster);
2121 if (rc < 0)
2122 FAT_ERROR(rc * 10 - 4);
1933 2123
1934#ifdef TEST_FAT 2124 /* at least the first cluster was freed */
1935 if ( file->firstcluster ) { 2125 file->firstcluster = 0;
1936 /* debug */ 2126
1937#ifdef HAVE_MULTIVOLUME 2127 if (rc == 0)
1938 struct bpb* fat_bpb = &fat_bpbs[file->volume]; 2128 FAT_ERROR(-5);
1939#else
1940 struct bpb* fat_bpb = &fat_bpbs[0];
1941#endif
1942 long count = 0;
1943 long len;
1944 long next;
1945 for ( next = file->firstcluster; next;
1946 next = get_next_cluster(IF_MV(fat_bpb,) next) ) {
1947 LDEBUGF("cluster %ld: %lx\n", count, next);
1948 count++;
1949 }
1950 len = count * fat_bpb->bpb_secperclus * SECTOR_SIZE;
1951 LDEBUGF("File is %ld clusters (chainlen=%ld, size=%ld)\n",
1952 count, len, size );
1953 if ( len > size + fat_bpb->bpb_secperclus * SECTOR_SIZE)
1954 panicf("Cluster chain is too long\n");
1955 if ( len < size )
1956 panicf("Cluster chain is too short\n");
1957 } 2129 }
1958#endif
1959 2130
1960 return 0; 2131 rc = 0;
2132fat_error:
2133 cache_commit(fat_bpb);
2134 return rc;
1961} 2135}
1962 2136
1963static int free_direntries(struct fat_file* file) 2137int fat_rename(struct fat_file *parent, struct fat_file *file,
2138 const unsigned char *newname)
1964{ 2139{
1965 struct fat_file dir; 2140 struct bpb * const fat_bpb = FAT_BPB(parent->volume);
1966 int numentries = file->direntries; 2141 if (!fat_bpb)
1967 unsigned int entry = file->direntry - numentries + 1; 2142 return -1;
1968 unsigned int sector = entry / DIR_ENTRIES_PER_SECTOR; 2143
1969 int i;
1970 int rc; 2144 int rc;
2145 /* save old file; don't change it unless everything succeeds */
2146 struct fat_file newfile = *file;
1971 2147
1972 /* create a temporary file handle for the dir holding this file */ 2148#ifdef HAVE_MULTIVOLUME
1973 rc = fat_open(IF_MV(file->volume,) file->dircluster, &dir, NULL); 2149 /* rename only works on the same volume */
1974 if (rc < 0) 2150 if (file->volume != parent->volume)
1975 return rc * 10 - 1; 2151 {
2152 DEBUGF("No rename across volumes!\n");
2153 FAT_ERROR(-2);
2154 }
2155#endif
1976 2156
1977 rc = fat_seek( &dir, sector ); 2157 /* root directories can't be renamed */
1978 if (rc < 0) 2158 if (file->firstcluster == fat_bpb->bpb_rootclus)
1979 return rc * 10 - 2; 2159 {
2160 DEBUGF("Trying to rename root of volume %d\n",
2161 IF_MV_VOL(file->volume));
2162 FAT_ERROR(-3);
2163 }
1980 2164
1981 unsigned char* buf = fat_get_sector_buffer(); 2165 if (!file->dircluster)
1982 rc = fat_readwrite(&dir, 1, buf, false);
1983 if (rc < 1)
1984 { 2166 {
1985 fat_release_sector_buffer(); 2167 /* file was removed but is still open */
1986 return rc * 10 - 3; 2168 DEBUGF("File has no dir cluster!\n");
2169 FAT_ERROR(-4);
1987 } 2170 }
1988 2171
1989 for (i=0; i < numentries; i++) { 2172 struct fat_file dir;
1990 LDEBUGF("Clearing dir entry %d (%d/%d)\n", 2173 struct fat_filestr dirstr;
1991 entry, i+1, numentries);
1992 buf[(entry % DIR_ENTRIES_PER_SECTOR) * DIR_ENTRY_SIZE] = 0xe5;
1993 entry++;
1994 2174
1995 if ( (entry % DIR_ENTRIES_PER_SECTOR) == 0 ) { 2175 /* open old parent */
1996 /* flush this sector */ 2176 fat_open_internal(IF_MV(file->volume,) file->dircluster, &dir);
1997 rc = fat_seek(&dir, sector); 2177 fat_filestr_init(&dirstr, &dir);
1998 if (rc < 0)
1999 {
2000 fat_release_sector_buffer();
2001 return rc * 10 - 4;
2002 }
2003 2178
2004 rc = fat_readwrite(&dir, 1, buf, true); 2179 /* fetch a copy of the existing short entry */
2005 if (rc < 1) 2180 dc_lock_cache();
2006 {
2007 fat_release_sector_buffer();
2008 return rc * 10 - 5;
2009 }
2010 2181
2011 if ( i+1 < numentries ) { 2182 union raw_dirent *ent = cache_direntry(fat_bpb, &dirstr, file->e.entry);
2012 /* read next sector */ 2183 if (!ent)
2013 rc = fat_readwrite(&dir, 1, buf, false); 2184 {
2014 if (rc < 1) 2185 dc_unlock_cache();
2015 { 2186 FAT_ERROR(-5);
2016 fat_release_sector_buffer();
2017 return rc * 10 - 6;
2018 }
2019 }
2020 sector++;
2021 }
2022 } 2187 }
2023 2188
2024 if ( entry % DIR_ENTRIES_PER_SECTOR ) { 2189 union raw_dirent rawent = *ent;
2025 /* flush this sector */ 2190
2026 rc = fat_seek(&dir, sector); 2191 dc_unlock_cache();
2027 if (rc < 0) 2192
2193 /* create new name in new parent directory */
2194 fat_filestr_init(&dirstr, parent);
2195 rc = add_dir_entry(fat_bpb, &dirstr, &newfile, newname, &rawent,
2196 0, DIRENT_TEMPL_CRT | DIRENT_TEMPL_WRT);
2197 if (rc == FAT_RC_ENOSPC)
2198 FAT_ERROR(RC);
2199 else if (rc < 0)
2200 FAT_ERROR(rc * 10 - 6);
2201
2202 /* if renaming a directory and it was a move, update the '..' entry to
2203 keep it pointing to its parent directory */
2204 if ((rawent.attr & ATTR_DIRECTORY) && newfile.dircluster != file->dircluster)
2205 {
2206 /* open the dir that was renamed */
2207 fat_open_internal(IF_MV(newfile.volume,) newfile.firstcluster, &dir);
2208 fat_filestr_init(&dirstr, &dir);
2209
2210 /* obtain dot-dot directory entry */
2211 dc_lock_cache();
2212 ent = cache_direntry(fat_bpb, &dirstr, 1);
2213 if (!ent)
2028 { 2214 {
2029 fat_release_sector_buffer(); 2215 dc_unlock_cache();
2030 return rc * 10 - 7; 2216 FAT_ERROR(-7);
2031 } 2217 }
2032 2218
2033 rc = fat_readwrite(&dir, 1, buf, true); 2219 if (strncmp(".. ", ent->name, 11))
2034 if (rc < 1)
2035 { 2220 {
2036 fat_release_sector_buffer(); 2221 /* .. entry must be second entry according to FAT spec (p.29) */
2037 return rc * 10 - 8; 2222 DEBUGF("Second dir entry is not double-dot!\n");
2223 dc_unlock_cache();
2224 FAT_ERROR(-8);
2038 } 2225 }
2039 }
2040 fat_release_sector_buffer();
2041 2226
2042 return 0; 2227 /* parent cluster is 0 if parent dir is the root - FAT spec (p.29) */
2043} 2228 long parentcluster = 0;
2044 2229 if (parent->firstcluster != fat_bpb->bpb_rootclus)
2045int fat_remove(struct fat_file* file) 2230 parentcluster = parent->firstcluster;
2046{
2047 long next, last = file->firstcluster;
2048 int rc;
2049#ifdef HAVE_MULTIVOLUME
2050 struct bpb* fat_bpb = &fat_bpbs[file->volume];
2051#endif
2052 2231
2053 LDEBUGF("fat_remove(%lx)\n",last); 2232 raw_dirent_set_fstclus(ent, parentcluster);
2054 2233
2055 while ( last ) { 2234 dc_dirty_buf(ent);
2056 next = get_next_cluster(IF_MV(fat_bpb,) last); 2235 dc_unlock_cache();
2057 update_fat_entry(IF_MV(fat_bpb,) last,0);
2058 last = next;
2059 } 2236 }
2060 2237
2061 if ( file->dircluster ) { 2238 /* remove old name */
2062 rc = free_direntries(file); 2239 rc = free_direntries(fat_bpb, file);
2063 if (rc < 0) 2240 if (rc <= 0)
2064 return rc * 10 - 1; 2241 FAT_ERROR(rc * 10 - 9);
2065 }
2066 2242
2067 file->firstcluster = 0; 2243 /* finally, update old file with new directory entry info */
2068 file->dircluster = 0; 2244 *file = newfile;
2069 2245
2070 rc = flush_fat(IF_MV(fat_bpb)); 2246 rc = 0;
2071 if (rc < 0) 2247fat_error:
2072 return rc * 10 - 2; 2248 if (rc < 0 && !fat_file_is_same(&newfile, file))
2249 free_direntries(fat_bpb, &newfile);
2073 2250
2074 return 0; 2251 cache_commit(fat_bpb);
2252 return rc;
2075} 2253}
2076 2254
2077int fat_rename(struct fat_file* file,
2078 struct fat_dir* dir,
2079 const unsigned char* newname,
2080 long size,
2081 int attr)
2082{
2083 int rc;
2084 struct fat_file olddir_file;
2085 struct fat_file newfile = *file;
2086 unsigned char* entry = NULL;
2087 unsigned short* clusptr = NULL;
2088 unsigned int parentcluster;
2089#ifdef HAVE_MULTIVOLUME
2090 struct bpb* fat_bpb = &fat_bpbs[file->volume];
2091 2255
2092 if (file->volume != dir->file.volume) { 2256/** File stream functions **/
2093 DEBUGF("No rename across volumes!\n");
2094 return -1;
2095 }
2096#else
2097 struct bpb* fat_bpb = &fat_bpbs[0];
2098#endif
2099
2100 if ( !file->dircluster ) {
2101 DEBUGF("File has no dir cluster!\n");
2102 return -2;
2103 }
2104
2105 /* create new name */
2106 rc = add_dir_entry(dir, &newfile, newname, false, false);
2107 if (rc < 0)
2108 return rc * 10 - 2;
2109
2110 /* write size and cluster link */
2111 rc = update_short_entry(&newfile, size, attr);
2112 if (rc < 0)
2113 return rc * 10 - 3;
2114 2257
2115 /* remove old name */ 2258int fat_closewrite(struct fat_filestr *filestr, uint32_t size,
2116 rc = free_direntries(file); 2259 struct fat_direntry *fatentp)
2117 if (rc < 0) 2260{
2118 return rc * 10 - 4; 2261 DEBUGF("%s(size=%ld)\n", __func__, size);
2262 struct fat_file * const file = filestr->fatfilep;
2263 struct bpb * const fat_bpb = FAT_BPB(file->volume);
2264 if (!fat_bpb)
2265 return -1;
2119 2266
2120 rc = flush_fat(IF_MV(fat_bpb)); 2267 int rc;
2121 if (rc < 0)
2122 return rc * 10 - 5;
2123 2268
2124 /* if renaming a directory, update the .. entry to make sure 2269 if (!size && file->firstcluster)
2125 it points to its parent directory (we don't check if it was a move) */ 2270 {
2126 if(FAT_ATTR_DIRECTORY == attr) { 2271 /* empty file */
2127 /* open the dir that was renamed, we re-use the olddir_file struct */ 2272 rc = update_fat_entry(fat_bpb, file->firstcluster, 0);
2128 rc = fat_open(IF_MV(file->volume,) newfile.firstcluster, &olddir_file, NULL);
2129 if (rc < 0) 2273 if (rc < 0)
2130 return rc * 10 - 6; 2274 FAT_ERROR(rc * 10 - 2);
2131 2275
2132 /* get the first sector of the dir */ 2276 file->firstcluster = 0;
2133 rc = fat_seek(&olddir_file, 0); 2277 fat_rewind(filestr);
2134 if (rc < 0) 2278 }
2135 return rc * 10 - 7;
2136 2279
2137 unsigned char* buf = fat_get_sector_buffer(); 2280 if (file->dircluster)
2138 rc = fat_readwrite(&olddir_file, 1, buf, false); 2281 {
2282 rc = update_short_entry(fat_bpb, file, size, fatentp);
2139 if (rc < 0) 2283 if (rc < 0)
2140 { 2284 FAT_ERROR(rc * 10 - 3);
2141 fat_release_sector_buffer(); 2285 }
2142 return rc * 10 - 8; 2286 else if (fatentp)
2143 } 2287 {
2144 2288 fat_empty_fat_direntry(fatentp);
2145 /* parent cluster is 0 if parent dir is the root - FAT spec (p.29) */ 2289 }
2146 if(dir->file.firstcluster == fat_bpb->bpb_rootclus)
2147 parentcluster = 0;
2148 else
2149 parentcluster = dir->file.firstcluster;
2150 2290
2151 entry = buf + DIR_ENTRY_SIZE; 2291#ifdef TEST_FAT
2152 if(strncmp(".. ", entry, 11)) 2292 if (file->firstcluster)
2293 {
2294 unsigned long count = 0;
2295 for (long next = file->firstcluster; next;
2296 next = get_next_cluster(fat_bpb, next))
2153 { 2297 {
2154 fat_release_sector_buffer(); 2298 DEBUGF("cluster %ld: %lx\n", count, next);
2155 /* .. entry must be second entry according to FAT spec (p.29) */ 2299 count++;
2156 DEBUGF("Second dir entry is not double-dot!\n");
2157 return rc * 10 - 9;
2158 } 2300 }
2159 clusptr = (short*)(entry + FATDIR_FSTCLUSHI);
2160 *clusptr = htole16(parentcluster >> 16);
2161 2301
2162 clusptr = (short*)(entry + FATDIR_FSTCLUSLO); 2302 uint32_t len = count * fat_bpb->bpb_secperclus * SECTOR_SIZE;
2163 *clusptr = htole16(parentcluster & 0xffff); 2303 DEBUGF("File is %lu clusters (chainlen=%lu, size=%lu)\n",
2304 count, len, size );
2164 2305
2165 /* write back this sector */ 2306 if (len > size + fat_bpb->bpb_secperclus * SECTOR_SIZE)
2166 rc = fat_seek(&olddir_file, 0); 2307 panicf("Cluster chain is too long\n");
2167 if (rc < 0)
2168 {
2169 fat_release_sector_buffer();
2170 return rc * 10 - 7;
2171 }
2172 2308
2173 rc = fat_readwrite(&olddir_file, 1, buf, true); 2309 if (len < size)
2174 fat_release_sector_buffer(); 2310 panicf("Cluster chain is too short\n");
2175 if (rc < 1)
2176 return rc * 10 - 8;
2177 } 2311 }
2312#endif /* TEST_FAT */
2178 2313
2179 return 0; 2314 rc = 0;
2315fat_error:
2316 cache_commit(fat_bpb);
2317 return rc;
2180} 2318}
2181 2319
2182static long next_write_cluster(struct fat_file* file, 2320void fat_filestr_init(struct fat_filestr *fatstr, struct fat_file *file)
2183 long oldcluster,
2184 long* newsector)
2185{ 2321{
2186#ifdef HAVE_MULTIVOLUME 2322 fatstr->fatfilep = file;
2187 struct bpb* fat_bpb = &fat_bpbs[file->volume]; 2323 fat_rewind(fatstr);
2188#else 2324}
2189 struct bpb* fat_bpb = &fat_bpbs[0];
2190#endif
2191 long cluster = 0;
2192 long sector;
2193
2194 LDEBUGF("next_write_cluster(%lx,%lx)\n",file->firstcluster, oldcluster);
2195
2196 if (oldcluster)
2197 cluster = get_next_cluster(IF_MV(fat_bpb,) oldcluster);
2198
2199 if (!cluster) {
2200 if (oldcluster > 0)
2201 cluster = find_free_cluster(IF_MV(fat_bpb,) oldcluster+1);
2202 else if (oldcluster == 0)
2203 cluster = find_free_cluster(IF_MV(fat_bpb,)
2204 fat_bpb->fsinfo.nextfree);
2205#ifdef HAVE_FAT16SUPPORT
2206 else /* negative, pseudo-cluster of the root dir */
2207 return 0; /* impossible to append something to the root */
2208#endif
2209 2325
2210 if (cluster) { 2326unsigned long fat_query_sectornum(const struct fat_filestr *filestr)
2211 if (oldcluster) 2327{
2212 update_fat_entry(IF_MV(fat_bpb,) oldcluster, cluster); 2328 /* return next sector number to be transferred */
2213 else 2329 struct bpb * const fat_bpb = FAT_BPB(filestr->fatfilep->volume);
2214 file->firstcluster = cluster; 2330 if (!fat_bpb)
2215 update_fat_entry(IF_MV(fat_bpb,) cluster, FAT_EOF_MARK); 2331 return INVALID_SECNUM;
2216 }
2217 else {
2218#ifdef TEST_FAT
2219 if (fat_bpb->fsinfo.freecount>0)
2220 panicf("There is free space, but find_free_cluster() "
2221 "didn't find it!\n");
2222#endif
2223 DEBUGF("next_write_cluster(): Disk full!\n");
2224 return 0;
2225 }
2226 }
2227 sector = cluster2sec(IF_MV(fat_bpb,) cluster);
2228 if (sector<0)
2229 return 0;
2230 2332
2231 *newsector = sector; 2333 return fat_bpb->bpb_secperclus*filestr->clusternum + filestr->sectornum + 1;
2232 return cluster;
2233} 2334}
2234 2335
2235static int transfer(IF_MV(struct bpb* fat_bpb,) 2336/* helper for fat_readwrite */
2236 unsigned long start, long count, char* buf, bool write ) 2337static long transfer(struct bpb *fat_bpb, unsigned long start, long count,
2338 char *buf, bool write)
2237{ 2339{
2238#ifndef HAVE_MULTIVOLUME 2340 long rc = 0;
2239 struct bpb* fat_bpb = &fat_bpbs[0];
2240#endif
2241 int rc;
2242 2341
2243 LDEBUGF("transfer(s=%lx, c=%lx, %s)\n", 2342 DEBUGF("%s(s=%lx, c=%lx, wr=%u)\n", __func__,
2244 start+ fat_bpb->startsector, count, write?"write":"read"); 2343 start + fat_bpb->startsector, count, write ? 1 : 0);
2245 if (write) { 2344
2345 if (write)
2346 {
2246 unsigned long firstallowed; 2347 unsigned long firstallowed;
2247#ifdef HAVE_FAT16SUPPORT 2348#ifdef HAVE_FAT16SUPPORT
2248 if (fat_bpb->is_fat16) 2349 if (fat_bpb->is_fat16)
2249 firstallowed = fat_bpb->rootdirsector; 2350 firstallowed = fat_bpb->rootdirsector;
2250 else 2351 else
2251#endif 2352#endif /* HAVE_FAT16SUPPORT */
2252 firstallowed = fat_bpb->firstdatasector; 2353 firstallowed = fat_bpb->firstdatasector;
2253 2354
2254 if (start < firstallowed) 2355 if (start < firstallowed)
2255 panicf("Write %ld before data\n", firstallowed - start); 2356 panicf("Write %ld before data\n", firstallowed - start);
2357
2256 if (start + count > fat_bpb->totalsectors) 2358 if (start + count > fat_bpb->totalsectors)
2359 {
2257 panicf("Write %ld after data\n", 2360 panicf("Write %ld after data\n",
2258 start + count - fat_bpb->totalsectors); 2361 start + count - fat_bpb->totalsectors);
2259 rc = storage_write_sectors(IF_MD(fat_bpb->drive,) 2362 }
2260 start + fat_bpb->startsector, count, buf); 2363 else
2364 {
2365 rc = storage_write_sectors(IF_MD(fat_bpb->drive,)
2366 start + fat_bpb->startsector, count, buf);
2367 }
2261 } 2368 }
2262 else 2369 else
2370 {
2263 rc = storage_read_sectors(IF_MD(fat_bpb->drive,) 2371 rc = storage_read_sectors(IF_MD(fat_bpb->drive,)
2264 start + fat_bpb->startsector, count, buf); 2372 start + fat_bpb->startsector, count, buf);
2265 if (rc < 0) { 2373 }
2266 DEBUGF( "transfer() - Couldn't %s sector %lx" 2374
2267 " (error code %d)\n", 2375 if (rc < 0)
2268 write ? "write":"read", start, rc); 2376 {
2377 DEBUGF("Couldn't %s sector %lx (err %d)\n",
2378 write ? "write":"read", start, rc);
2269 return rc; 2379 return rc;
2270 } 2380 }
2381
2271 return 0; 2382 return 0;
2272} 2383}
2273 2384
2274 2385long fat_readwrite(struct fat_filestr *filestr, unsigned long sectorcount,
2275long fat_readwrite( struct fat_file *file, long sectorcount, 2386 void *buf, bool write)
2276 void* buf, bool write )
2277{ 2387{
2278#ifdef HAVE_MULTIVOLUME 2388 struct fat_file * const file = filestr->fatfilep;
2279 struct bpb* fat_bpb = &fat_bpbs[file->volume]; 2389 struct bpb * const fat_bpb = FAT_BPB(file->volume);
2280#else 2390 if (!fat_bpb)
2281 struct bpb* fat_bpb = &fat_bpbs[0]; 2391 return -1;
2282#endif
2283 long cluster = file->lastcluster;
2284 long sector = file->lastsector;
2285 long clusternum = file->clusternum;
2286 long numsec = file->sectornum;
2287 bool eof = file->eof;
2288 long first=0, last=0;
2289 long i;
2290 int rc;
2291 2392
2292 LDEBUGF( "fat_readwrite(file:%lx,count:0x%lx,buf:%lx,%s)\n", 2393 bool eof = filestr->eof;
2293 file->firstcluster,sectorcount,(long)buf,write?"write":"read");
2294 LDEBUGF( "fat_readwrite: sec=%lx numsec=%ld eof=%d\n",
2295 sector,numsec, eof?1:0);
2296 2394
2297 if ( eof && !write) 2395 if ((eof && !write) || !sectorcount)
2298 return 0; 2396 return 0;
2299 2397
2300 /* find sequential sectors and write them all at once */ 2398 long rc;
2301 for (i=0; (i < sectorcount) && (sector > -1); i++ ) {
2302 numsec++;
2303 if ( numsec > (long)fat_bpb->bpb_secperclus || !cluster ) {
2304 long oldcluster = cluster;
2305 long oldsector = sector;
2306 long oldnumsec = numsec;
2307 if (write)
2308 cluster = next_write_cluster(file, cluster, &sector);
2309 else {
2310 cluster = get_next_cluster(IF_MV(fat_bpb,) cluster);
2311 sector = cluster2sec(IF_MV(fat_bpb,) cluster);
2312 }
2313 2399
2314 clusternum++; 2400 long cluster = filestr->lastcluster;
2315 numsec=1; 2401 unsigned long sector = filestr->lastsector;
2402 long clusternum = filestr->clusternum;
2403 unsigned long sectornum = filestr->sectornum;
2316 2404
2317 if (!cluster) { 2405 DEBUGF("%s(file:%lx,count:0x%lx,buf:%lx,%s)\n", __func__,
2318 eof = true; 2406 file->firstcluster, sectorcount, (long)buf,
2319 if ( write ) { 2407 write ? "write":"read");
2320 /* remember last cluster, in case 2408 DEBUGF("%s: sec:%lx numsec:%ld eof:%d\n", __func__,
2321 we want to append to the file */ 2409 sector, (long)sectornum, eof ? 1 : 0);
2322 sector = oldsector; 2410
2323 cluster = oldcluster; 2411 eof = false;
2324 numsec = oldnumsec; 2412
2325 clusternum--; 2413 if (!sector)
2326 i = -1; /* Error code */ 2414 {
2327 break; 2415 /* look up first sector of file */
2328 } 2416 long newcluster = file->firstcluster;
2329 } 2417
2330 else 2418 if (write && !newcluster)
2331 eof = false; 2419 {
2420 /* file is empty; try to allocate its first cluster */
2421 newcluster = next_write_cluster(fat_bpb, 0);
2422 file->firstcluster = newcluster;
2332 } 2423 }
2333 else { 2424
2334 if (sector) 2425 if (newcluster)
2335 sector++; 2426 {
2336 else { 2427 cluster = newcluster;
2337 /* look up first sector of file */ 2428 sector = cluster2sec(fat_bpb, cluster) - 1;
2338 sector = cluster2sec(IF_MV(fat_bpb,) file->firstcluster); 2429
2339 numsec=1; 2430 #ifdef HAVE_FAT16SUPPORT
2340#ifdef HAVE_FAT16SUPPORT 2431 if (fat_bpb->is_fat16 && file->firstcluster < 0)
2341 if (file->firstcluster < 0) 2432 {
2342 { /* FAT16 root dir */ 2433 sector += fat_bpb->rootdirsectornum;
2343 sector += fat_bpb->rootdiroffset; 2434 sectornum = fat_bpb->rootdirsectornum;
2344 numsec += fat_bpb->rootdiroffset;
2345 }
2346#endif
2347 } 2435 }
2436 #endif /* HAVE_FAT16SUPPORT */
2348 } 2437 }
2438 }
2349 2439
2350 if (!first) 2440 if (!sector)
2351 first = sector; 2441 {
2442 sectorcount = 0;
2443 eof = true;
2444 }
2352 2445
2353 if ( ((sector != first) && (sector != last+1)) || /* not sequential */ 2446 unsigned long transferred = 0;
2354 (last-first+1 == 256) ) { /* max 256 sectors per ata request */ 2447 unsigned long count = 0;
2355 long count = last - first + 1; 2448 unsigned long last = sector;
2356 rc = transfer(IF_MV(fat_bpb,) first, count, buf, write );
2357 if (rc < 0)
2358 return rc * 10 - 1;
2359 2449
2360 buf = (char *)buf + count * SECTOR_SIZE; 2450 while (transferred + count < sectorcount)
2361 first = sector; 2451 {
2452 if (++sectornum >= fat_bpb->bpb_secperclus)
2453 {
2454 /* out of sectors in this cluster; get the next cluster */
2455 long newcluster = write ? next_write_cluster(fat_bpb, cluster) :
2456 get_next_cluster(fat_bpb, cluster);
2457 if (newcluster)
2458 {
2459 cluster = newcluster;
2460 sector = cluster2sec(fat_bpb, cluster) - 1;
2461 clusternum++;
2462 sectornum = 0;
2463
2464 /* jumped clusters right at start? */
2465 if (!count)
2466 last = sector;
2467 }
2468 else
2469 {
2470 sectornum--; /* remain in previous position */
2471 eof = true;
2472 break;
2473 }
2362 } 2474 }
2363 2475
2364 if ((i == sectorcount-1) && /* last sector requested */ 2476 /* find sequential sectors and transfer them all at once */
2365 (!eof)) 2477 if (sector != last || count >= FAT_MAX_TRANSFER_SIZE)
2366 { 2478 {
2367 long count = sector - first + 1; 2479 /* not sequential/over limit */
2368 rc = transfer(IF_MV(fat_bpb,) first, count, buf, write ); 2480 rc = transfer(fat_bpb, last - count + 1, count, buf, write);
2369 if (rc < 0) 2481 if (rc < 0)
2370 return rc * 10 - 2; 2482 FAT_ERROR(rc * 10 - 2);
2483
2484 transferred += count;
2485 buf += count * SECTOR_SIZE;
2486 count = 0;
2371 } 2487 }
2372 2488
2373 last = sector; 2489 count++;
2490 last = ++sector;
2374 } 2491 }
2375 2492
2376 file->lastcluster = cluster; 2493 if (count)
2377 file->lastsector = sector; 2494 {
2378 file->clusternum = clusternum; 2495 /* transfer any remainder */
2379 file->sectornum = numsec; 2496 rc = transfer(fat_bpb, last - count + 1, count, buf, write);
2380 file->eof = eof; 2497 if (rc < 0)
2498 FAT_ERROR(rc * 10 - 3);
2499
2500 transferred += count;
2501 }
2502
2503 rc = (eof && write) ? FAT_RC_ENOSPC : (long)transferred;
2504fat_error:
2505 filestr->lastcluster = cluster;
2506 filestr->lastsector = sector;
2507 filestr->clusternum = clusternum;
2508 filestr->sectornum = sectornum;
2509 filestr->eof = eof;
2510
2511 if (rc >= 0)
2512 DEBUGF("Sectors transferred: %ld\n", rc);
2381 2513
2382 /* if eof, don't report last block as read/written */ 2514 return rc;
2383 if (eof) 2515}
2384 i--;
2385 2516
2386 DEBUGF("Sectors written: %ld\n", i); 2517void fat_rewind(struct fat_filestr *filestr)
2387 return i; 2518{
2519 /* rewind the file position */
2520 filestr->lastcluster = filestr->fatfilep->firstcluster;
2521 filestr->lastsector = 0;
2522 filestr->clusternum = 0;
2523 filestr->sectornum = FAT_RW_VAL;
2524 filestr->eof = false;
2388} 2525}
2389 2526
2390int fat_seek(struct fat_file *file, unsigned long seeksector ) 2527int fat_seek(struct fat_filestr *filestr, unsigned long seeksector)
2391{ 2528{
2392#ifdef HAVE_MULTIVOLUME 2529 const struct fat_file * const file = filestr->fatfilep;
2393 struct bpb* fat_bpb = &fat_bpbs[file->volume]; 2530 struct bpb * const fat_bpb = FAT_BPB(file->volume);
2394#else 2531 if (!fat_bpb)
2395 struct bpb* fat_bpb = &fat_bpbs[0]; 2532 return -1;
2396#endif 2533
2397 long clusternum=0, numclusters=0, sectornum=0, sector=0; 2534 int rc;
2398 long cluster = file->firstcluster; 2535 long cluster = file->firstcluster;
2399 long i; 2536 unsigned long sector = 0;
2537 long clusternum = 0;
2538 unsigned long sectornum = FAT_RW_VAL;
2400 2539
2401#ifdef HAVE_FAT16SUPPORT 2540#ifdef HAVE_FAT16SUPPORT
2402 if (cluster < 0) /* FAT16 root dir */ 2541 if (fat_bpb->is_fat16 && cluster < 0) /* FAT16 root dir */
2403 seeksector += fat_bpb->rootdiroffset; 2542 seeksector += fat_bpb->rootdirsectornum;
2404#endif 2543#endif /* HAVE_FAT16SUPPORT */
2544
2545 filestr->eof = false;
2546 if (seeksector)
2547 {
2548 if (cluster == 0)
2549 {
2550 DEBUGF("Seeking beyond the end of empty file! "
2551 "(sector %lu, cluster %ld)\n", seeksector,
2552 seeksector / fat_bpb->bpb_secperclus);
2553 FAT_ERROR(FAT_SEEK_EOF);
2554 }
2405 2555
2406 file->eof = false;
2407 if (seeksector) {
2408 /* we need to find the sector BEFORE the requested, since 2556 /* we need to find the sector BEFORE the requested, since
2409 the file struct stores the last accessed sector */ 2557 the file struct stores the last accessed sector */
2410 seeksector--; 2558 seeksector--;
2411 numclusters = clusternum = seeksector / fat_bpb->bpb_secperclus; 2559 clusternum = seeksector / fat_bpb->bpb_secperclus;
2412 sectornum = seeksector % fat_bpb->bpb_secperclus; 2560 sectornum = seeksector % fat_bpb->bpb_secperclus;
2413 2561
2414 if (file->clusternum && clusternum >= file->clusternum) 2562 long numclusters = clusternum;
2563
2564 if (filestr->clusternum && clusternum >= filestr->clusternum)
2415 { 2565 {
2416 cluster = file->lastcluster; 2566 /* seek forward from current position */
2417 numclusters -= file->clusternum; 2567 cluster = filestr->lastcluster;
2568 numclusters -= filestr->clusternum;
2418 } 2569 }
2419 2570
2420 for (i=0; i<numclusters; i++) { 2571 for (long i = 0; i < numclusters; i++)
2421 cluster = get_next_cluster(IF_MV(fat_bpb,) cluster); 2572 {
2422 if (!cluster) { 2573 cluster = get_next_cluster(fat_bpb, cluster);
2574
2575 if (!cluster)
2576 {
2423 DEBUGF("Seeking beyond the end of the file! " 2577 DEBUGF("Seeking beyond the end of the file! "
2424 "(sector %ld, cluster %ld)\n", seeksector, i); 2578 "(sector %lu, cluster %ld)\n", seeksector, i);
2425 return -1; 2579 FAT_ERROR(FAT_SEEK_EOF);
2426 } 2580 }
2427 } 2581 }
2428 2582
2429 sector = cluster2sec(IF_MV(fat_bpb,) cluster) + sectornum; 2583 sector = cluster2sec(fat_bpb, cluster) + sectornum;
2430 }
2431 else {
2432 sectornum = -1;
2433 } 2584 }
2434 2585
2435 LDEBUGF("fat_seek(%lx, %lx) == %lx, %lx, %lx\n", 2586 DEBUGF("%s(%lx, %lx) == %lx, %lx, %lx\n", __func__,
2436 file->firstcluster, seeksector, cluster, sector, sectornum); 2587 file->firstcluster, seeksector, cluster, sector, sectornum);
2437 2588
2438 file->lastcluster = cluster; 2589 filestr->lastcluster = cluster;
2439 file->lastsector = sector; 2590 filestr->lastsector = sector;
2440 file->clusternum = clusternum; 2591 filestr->clusternum = clusternum;
2441 file->sectornum = sectornum + 1; 2592 filestr->sectornum = sectornum;
2442 return 0; 2593
2594 rc = 0;
2595fat_error:
2596 return rc;
2443} 2597}
2444 2598
2445int fat_opendir(IF_MV(int volume,) 2599int fat_truncate(const struct fat_filestr *filestr)
2446 struct fat_dir *dir, unsigned long startcluster,
2447 const struct fat_dir *parent_dir)
2448{ 2600{
2449#ifdef HAVE_MULTIVOLUME 2601 DEBUGF("%s(): %lX\n", __func__, filestr->lastcluster);
2450 struct bpb* fat_bpb = &fat_bpbs[volume]; 2602
2451 /* fixme: remove error check when done */ 2603 struct bpb * const fat_bpb = FAT_BPB(filestr->fatfilep->volume);
2452 if (volume >= NUM_VOLUMES || !fat_bpbs[volume].mounted) 2604 if (!fat_bpb)
2453 {
2454 LDEBUGF("fat_open() illegal volume %d\n", volume);
2455 return -1; 2605 return -1;
2456 }
2457#else
2458 struct bpb* fat_bpb = &fat_bpbs[0];
2459#endif
2460 int rc;
2461 2606
2462 if (startcluster == 0) 2607 int rc = 1;
2463 startcluster = fat_bpb->bpb_rootclus;
2464 2608
2465 rc = fat_open(IF_MV(volume,) startcluster, &dir->file, parent_dir); 2609 long last = filestr->lastcluster;
2466 if(rc) 2610 long next = 0;
2611
2612 /* truncate trailing clusters after the current position */
2613 if (last)
2467 { 2614 {
2468 DEBUGF( "fat_opendir() - Couldn't open dir" 2615 next = get_next_cluster(fat_bpb, last);
2469 " (error code %d)\n", rc); 2616 int rc2 = update_fat_entry(fat_bpb, last, FAT_EOF_MARK);
2470 return rc * 10 - 1; 2617 if (rc2 < 0)
2618 FAT_ERROR(rc2 * 10 - 2);
2471 } 2619 }
2472
2473 /* assign them after fat_open call so that fat_opendir can be called with the same
2474 * fat_dir as parent and result */
2475 dir->entry = 0;
2476 dir->sector = 0;
2477 2620
2478 return 0; 2621 int rc2 = free_cluster_chain(fat_bpb, next);
2622 if (rc2 <= 0)
2623 {
2624 DEBUGF("Failed freeing cluster chain\n");
2625 rc = 0; /* still partial success */
2626 }
2627
2628fat_error:
2629 return rc;
2479} 2630}
2480 2631
2481int fat_getnext(struct fat_dir *dir, struct fat_direntry *entry) 2632
2633/** Directory stream functions **/
2634
2635int fat_readdir(struct fat_filestr *dirstr, struct fat_dirscan_info *scan,
2636 struct filestr_cache *cachep, struct fat_direntry *entry)
2482{ 2637{
2483 bool done = false; 2638 int rc = 0;
2484 int i, j; 2639
2485 int rc; 2640 /* long file names are stored in special entries; each entry holds up to
2486 int order; 2641 13 UTF-16 characters' thus, UTF-8 converted names can be max 255 chars
2487 unsigned char firstbyte; 2642 (1020 bytes) long, not including the trailing '\0'. */
2488 /* Long file names are stored in special entries. Each entry holds 2643 struct fatlong_parse_state lnparse;
2489 up to 13 characters. Names can be max 255 chars (not bytes!) long */ 2644 fatlong_parse_start(&lnparse);
2490 /* The number of long entries in the long name can be retrieve from the first
2491 * long entry because there are stored in reverse order and have an ordinal */
2492 int nb_longs = 0;
2493 /* The long entries are expected to be in order, so remember the last ordinal */
2494 int last_long_ord = 0;
2495 2645
2496 dir->entrycount = 0; 2646 scan->entries = 0;
2497 2647
2498 while(!done) 2648 while (1)
2499 { 2649 {
2500 if ( !(dir->entry % DIR_ENTRIES_PER_SECTOR) || !dir->sector ) 2650 unsigned int direntry = ++scan->entry;
2651 if (direntry >= MAX_DIRENTRIES)
2501 { 2652 {
2502 rc = fat_readwrite(&dir->file, 1, dir->sectorcache, false); 2653 DEBUGF("%s() - Dir is too large (entry %u)\n", __func__,
2503 if (rc == 0) { 2654 direntry);
2504 /* eof */ 2655 FAT_ERROR(-1);
2505 entry->name[0] = 0; 2656 }
2506 break; 2657
2658 unsigned long sector = direntry / DIR_ENTRIES_PER_SECTOR;
2659 if (cachep->sector != sector)
2660 {
2661 if (cachep->sector + 1 != sector)
2662 {
2663 /* Nothing cached or sector isn't contiguous */
2664 int rc2 = fat_seek(dirstr, sector);
2665 if (rc2 < 0)
2666 FAT_ERROR(rc2 * 10 - 2);
2507 } 2667 }
2508 if (rc < 0) { 2668
2509 DEBUGF( "fat_getnext() - Couldn't read dir" 2669 int rc2 = fat_readwrite(dirstr, 1, cachep->buffer, false);
2510 " (error code %d)\n", rc); 2670 if (rc2 <= 0)
2511 return rc * 10 - 1; 2671 {
2672 if (rc2 == 0)
2673 break; /* eof */
2674
2675 DEBUGF("%s() - Couldn't read dir (err %d)\n", __func__, rc);
2676 FAT_ERROR(rc2 * 10 - 3);
2512 } 2677 }
2513 dir->sector = dir->file.lastsector; 2678
2679 cachep->sector = sector;
2514 } 2680 }
2515 2681
2516 for (i = dir->entry % DIR_ENTRIES_PER_SECTOR; 2682 unsigned int index = direntry % DIR_ENTRIES_PER_SECTOR;
2517 i < DIR_ENTRIES_PER_SECTOR; i++) { 2683 union raw_dirent *ent = &((union raw_dirent *)cachep->buffer)[index];
2518 unsigned int entrypos = i * DIR_ENTRY_SIZE;
2519 2684
2520 firstbyte = dir->sectorcache[entrypos]; 2685 if (ent->name[0] == 0)
2521 dir->entry++; 2686 break; /* last entry */
2522 2687
2523 if (firstbyte == 0xe5) { 2688 if (ent->name[0] == 0xe5)
2524 /* free entry */ 2689 {
2525 dir->entrycount = 0; 2690 scan->entries = 0;
2526 continue; 2691 continue; /* free entry */
2527 } 2692 }
2528 2693
2529 if (firstbyte == 0) { 2694 ++scan->entries;
2530 /* last entry */
2531 entry->name[0] = 0;
2532 dir->entrycount = 0;
2533 return 0;
2534 }
2535 2695
2536 dir->entrycount++; 2696 if (IS_LDIR_ATTR(ent->ldir_attr))
2537 2697 {
2538 /* LFN entry? */ 2698 /* LFN entry */
2539 if ( ( dir->sectorcache[entrypos + FATDIR_ATTR] & 2699 if (UNLIKELY(!fatlong_parse_entry(&lnparse, ent, entry)))
2540 FAT_ATTR_LONG_NAME_MASK ) == FAT_ATTR_LONG_NAME ) { 2700 {
2541 /* extract ordinal */ 2701 /* resync so we don't return just the short name if what we
2542 order = dir->sectorcache[entrypos + FATLONG_ORDER] & ~FATLONG_LAST_LONG_ENTRY; 2702 landed in the middle of is valid (directory changes
2543 /* is this entry the first long entry ? (first in order but containing last part) */ 2703 between calls likely created the situation; ignoring this
2544 if (dir->sectorcache[entrypos + FATLONG_ORDER] & FATLONG_LAST_LONG_ENTRY) { 2704 case can be harmful elsewhere and is destructive to the
2545 /* check that order is not too big ! (and non-zero) */ 2705 entry series itself) */
2546 if(order <= 0 || order > FATLONG_MAX_ORDER) 2706 struct bpb *fat_bpb = FAT_BPB(dirstr->fatfilep->volume);
2547 continue; /* ignore the whole LFN, will trigger lots of warnings */ 2707 if (!fat_bpb)
2548 nb_longs = order; 2708 FAT_ERROR(-4);
2549 last_long_ord = order; 2709
2550 } 2710 dc_lock_cache();
2551 else { 2711
2552 /* check orphan entry */ 2712 while (--scan->entry != FAT_RW_VAL) /* at beginning? */
2553 if (nb_longs == 0) { 2713 {
2554 logf("fat warning: orphan LFN entry"); 2714 ent = cache_direntry(fat_bpb, dirstr, scan->entry);
2555 /* ignore */
2556 continue;
2557 }
2558
2559 /* check order */
2560 if (order != (last_long_ord - 1)) {
2561 logf("fat warning: wrong LFN ordinal");
2562 /* ignore the whole LFN, will trigger lots of warnings */
2563 nb_longs = 0;
2564 }
2565
2566 last_long_ord = order;
2567 }
2568 2715
2569 /* copy part, reuse [order] for another purpose :) */ 2716 /* name[0] == 0 shouldn't happen here but... */
2570 order = (order - 1) * FATLONG_NAME_BYTES_PER_ENTRY; 2717 if (!ent || ent->name[0] == 0 || ent->name[0] == 0xe5 ||
2571 for(j = 0; j < FATLONG_NAME_CHUNKS; j++) { 2718 !IS_LDIR_ATTR(ent->ldir_attr))
2572 memcpy(dir->longname + order, 2719 break;
2573 dir->sectorcache + entrypos + FATLONG_NAME_POS[j],
2574 FATLONG_NAME_SIZE[j]);
2575 order += FATLONG_NAME_SIZE[j];
2576 } 2720 }
2721
2722 dc_unlock_cache();
2723
2724 /* retry it once from the new position */
2725 scan->entries = 0;
2726 continue;
2577 } 2727 }
2578 else { 2728 }
2579 if ( parse_direntry(entry, dir->sectorcache + entrypos) ) { 2729 else if (!IS_VOL_ID_ATTR(ent->attr)) /* ignore volume id entry */
2580 2730 {
2581 /* don't return volume id entry */ 2731 rc = 1;
2582 if ( (entry->attr & 2732
2583 (FAT_ATTR_VOLUME_ID|FAT_ATTR_DIRECTORY)) 2733 if (!fatlong_parse_finish(&lnparse, ent, entry))
2584 == FAT_ATTR_VOLUME_ID) 2734 {
2585 continue; 2735 /* the long entries failed to pass all checks or there is
2586 2736 just a short entry. */
2587 /* replace shortname with longname? */ 2737 DEBUGF("SN-DOS:'%s'", entry->shortname);
2588 /* check that the long name is complete */ 2738 strcpy(entry->name, entry->shortname);
2589 if (nb_longs != 0 && last_long_ord == 1) { 2739 scan->entries = 1;
2590 /* hold a copy of the shortname in case the long one is too long */ 2740 rc = 2; /* name is OEM */
2591 unsigned char shortname[13]; /* 8+3+dot+\0 */
2592 int longname_utf8len = 0;
2593 /* One character at a time, add 1 for trailing \0, 4 is the maximum size
2594 * of a UTF8 encoded character in rockbox */
2595 unsigned char longname_utf8segm[4 + 1];
2596 unsigned short ucs;
2597 int segm_utf8len;
2598 /* Temporarily store short name */
2599 strcpy(shortname, entry->name);
2600 entry->name[0] = 0;
2601
2602 /* Convert the FAT name to a utf8-encoded one.
2603 * The name is not necessary NUL-terminated ! */
2604 for (j = 0; j < nb_longs * FATLONG_NAME_BYTES_PER_ENTRY; j += 2) {
2605 ucs = dir->longname[j] | (dir->longname[j + 1] << 8);
2606 if(ucs == 0 || ucs == FAT_LONGNAME_PAD_UCS)
2607 break;
2608 /* utf8encode will return a pointer after the converted
2609 * string, subtract the pointer to the start to get the length of it */
2610 segm_utf8len = utf8encode(ucs, longname_utf8segm) - longname_utf8segm;
2611
2612 /* warn the trailing zero ! (FAT_FILENAME_BYTES includes it) */
2613 if (longname_utf8len + segm_utf8len >= FAT_FILENAME_BYTES) {
2614 /* force use of short name */
2615 longname_utf8len = FAT_FILENAME_BYTES + 1;
2616 break; /* fallback later */
2617 }
2618 else {
2619 longname_utf8segm[segm_utf8len] = 0;
2620 strcat(entry->name + longname_utf8len, longname_utf8segm);
2621 longname_utf8len += segm_utf8len;
2622 }
2623 }
2624
2625 /* Does the utf8-encoded name fit into the entry? */
2626 /* warn the trailing zero ! (FAT_FILENAME_BYTES includes it) */
2627 if (longname_utf8len >= FAT_FILENAME_BYTES) {
2628 /* Take the short DOS name. Need to utf8-encode it
2629 since it may contain chars from the upper half of
2630 the OEM code page which wouldn't be a valid utf8.
2631 Beware: this file will be shown with strange
2632 glyphs in file browser since unicode 0x80 to 0x9F
2633 are control characters. */
2634 logf("SN-DOS: %s", shortname);
2635 unsigned char *utf8;
2636 utf8 = iso_decode(shortname, entry->name, -1,
2637 strlen(shortname));
2638 *utf8 = 0;
2639 logf("SN: %s", entry->name);
2640 } else {
2641 logf("LN: %s", entry->name);
2642 logf("LNLen: %d", longname_utf8len);
2643 }
2644 }
2645 done = true;
2646 i++;
2647 break;
2648 }
2649 } 2741 }
2742
2743 DEBUGF("LN:\"%s\"", entry->name);
2744 break;
2650 } 2745 }
2746 } /* end while */
2747
2748fat_error:
2749 if (rc <= 0)
2750 {
2751 /* error or eod; stay on last good position */
2752 fat_empty_fat_direntry(entry);
2753 scan->entry--;
2754 scan->entries = 0;
2651 } 2755 }
2756
2757 return rc;
2758}
2759
2760void fat_rewinddir(struct fat_dirscan_info *scan)
2761{
2762 /* rewind the directory scan counter to the beginning */
2763 scan->entry = FAT_RW_VAL;
2764 scan->entries = 0;
2765}
2766
2767
2768/** Mounting and unmounting functions **/
2769
2770bool fat_ismounted(IF_MV_NONVOID(int volume))
2771{
2772 return !!FAT_BPB(volume);
2773}
2774
2775int fat_mount(IF_MV(int volume,) IF_MD(int drive,) unsigned long startsector)
2776{
2777 int rc;
2778
2779 struct bpb * const fat_bpb = &fat_bpbs[IF_MV_VOL(volume)];
2780 if (fat_bpb->mounted)
2781 FAT_ERROR(-1); /* double mount */
2782
2783 /* fill-in basic info first */
2784 fat_bpb->startsector = startsector;
2785#ifdef HAVE_MULTIVOLUME
2786 fat_bpb->volume = volume;
2787#endif
2788#ifdef HAVE_MULTIDRIVE
2789 fat_bpb->drive = drive;
2790#endif
2791
2792 rc = fat_mount_internal(fat_bpb);
2793 if (rc < 0)
2794 FAT_ERROR(rc * 10 - 2);
2795
2796 /* it worked */
2797 fat_bpb->mounted = true;
2798
2799 /* calculate freecount if unset */
2800 if (fat_bpb->fsinfo.freecount == 0xffffffff)
2801 fat_recalc_free(IF_MV(fat_bpb->volume));
2802
2803 DEBUGF("Freecount: %ld\n", (unsigned long)fat_bpb->fsinfo.freecount);
2804 DEBUGF("Nextfree: 0x%lx\n", (unsigned long)fat_bpb->fsinfo.nextfree);
2805 DEBUGF("Cluster count: 0x%lx\n", fat_bpb->dataclusters);
2806 DEBUGF("Sectors per cluster: %d\n", fat_bpb->bpb_secperclus);
2807 DEBUGF("FAT sectors: 0x%lx\n", fat_bpb->fatsize);
2808
2809 rc = 0;
2810fat_error:
2811 return rc;
2812}
2813
2814int fat_unmount(IF_MV_NONVOID(int volume))
2815{
2816 struct bpb * const fat_bpb = FAT_BPB(volume);
2817 if (!fat_bpb)
2818 return -1; /* not mounted */
2819
2820 /* free the entries for this volume */
2821 cache_discard(IF_MV(fat_bpb));
2822 fat_bpb->mounted = false;
2823
2652 return 0; 2824 return 0;
2653} 2825}
2654 2826
2827
2828/** Debug screen stuff **/
2829
2830#ifdef MAX_LOG_SECTOR_SIZE
2831int fat_get_bytes_per_sector(IF_MV_NONVOID(int volume))
2832{
2833 int bytes = 0;
2834
2835 struct bpb * const fat_bpb = FAT_BPB(volume);
2836 if (fat_bpb)
2837 bytes = fat_bpb->bpb_bytspersec;
2838
2839 return bytes;
2840}
2841#endif /* MAX_LOG_SECTOR_SIZE */
2842
2655unsigned int fat_get_cluster_size(IF_MV_NONVOID(int volume)) 2843unsigned int fat_get_cluster_size(IF_MV_NONVOID(int volume))
2656{ 2844{
2657#ifndef HAVE_MULTIVOLUME 2845 unsigned int size = 0;
2658 const int volume = 0; 2846
2659#endif 2847 struct bpb * const fat_bpb = FAT_BPB(volume);
2660 struct bpb* fat_bpb = &fat_bpbs[volume]; 2848 if (fat_bpb)
2661 return fat_bpb->bpb_secperclus * SECTOR_SIZE; 2849 size = fat_bpb->bpb_secperclus * SECTOR_SIZE;
2850
2851 return size;
2662} 2852}
2663 2853
2664#ifdef HAVE_MULTIVOLUME 2854void fat_recalc_free(IF_MV_NONVOID(int volume))
2665bool fat_ismounted(int volume)
2666{ 2855{
2667 return (volume<NUM_VOLUMES && fat_bpbs[volume].mounted); 2856 struct bpb * const fat_bpb = FAT_BPB(volume);
2857 if (!fat_bpb)
2858 return;
2859
2860 dc_lock_cache();
2861 fat_recalc_free_internal(fat_bpb);
2862 dc_unlock_cache();
2863}
2864
2865bool fat_size(IF_MV(int volume,) unsigned long *size, unsigned long *free)
2866{
2867 struct bpb * const fat_bpb = FAT_BPB(volume);
2868 if (!fat_bpb)
2869 return false;
2870
2871 unsigned long factor = fat_bpb->bpb_secperclus * SECTOR_SIZE / 1024;
2872
2873 if (size) *size = fat_bpb->dataclusters * factor;
2874 if (free) *free = fat_bpb->fsinfo.freecount * factor;
2875
2876 return true;
2877}
2878
2879
2880/** Misc. **/
2881
2882void fat_empty_fat_direntry(struct fat_direntry *entry)
2883{
2884 entry->name[0] = 0;
2885 entry->shortname[0] = 0;
2886 entry->attr = 0;
2887 entry->crttimetenth = 0;
2888 entry->crttime = 0;
2889 entry->crtdate = 0;
2890 entry->lstaccdate = 0;
2891 entry->wrttime = 0;
2892 entry->wrtdate = 0;
2893 entry->filesize = 0;
2894 entry->firstcluster = 0;
2895}
2896
2897time_t fattime_mktime(uint16_t fatdate, uint16_t fattime)
2898{
2899 /* this knows our mktime() only uses these struct tm fields */
2900 struct tm tm;
2901 tm.tm_sec = ((fattime ) & 0x1f) * 2;
2902 tm.tm_min = ((fattime >> 5) & 0x3f);
2903 tm.tm_hour = ((fattime >> 11) );
2904 tm.tm_mday = ((fatdate ) & 0x1f);
2905 tm.tm_mon = ((fatdate >> 5) & 0x0f) - 1;
2906 tm.tm_year = ((fatdate >> 9) ) + 80;
2907
2908 return mktime(&tm);
2909}
2910
2911void fat_init(void)
2912{
2913 dc_lock_cache();
2914
2915 /* mark the possible volumes as not mounted */
2916 for (unsigned int i = 0; i < NUM_VOLUMES; i++)
2917 {
2918 dc_discard_all(IF_MV(i));
2919 fat_bpbs[i].mounted = false;
2920 }
2921
2922 dc_unlock_cache();
2668} 2923}
2669#endif