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