backported more fixes from 256boss
[bootcensus] / src / fsfat.c
1 /*
2 pcboot - bootable PC demo/game kernel
3 Copyright (C) 2018-2019  John Tsiombikas <nuclear@member.fsf.org>
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY, without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program.  If not, see <https://www.gnu.org/licenses/>.
17 */
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <inttypes.h>
22 #include <ctype.h>
23 #include <errno.h>
24 #include <assert.h>
25 #include "fs.h"
26 #include "bootdev.h"
27 #include "boot.h"
28 #include "panic.h"
29
30 #define MAX_NAME        195
31
32 #define DIRENT_UNUSED   0xe5
33
34 #define DENT_IS_NULL(dent)      (((unsigned char*)(dent))[0] == 0)
35 #define DENT_IS_UNUSED(dent)    (((unsigned char*)(dent))[0] == DIRENT_UNUSED)
36
37 #define ATTR_RO         0x01
38 #define ATTR_HIDDEN     0x02
39 #define ATTR_SYSTEM     0x04
40 #define ATTR_VOLID      0x08
41 #define ATTR_DIR        0x10
42 #define ATTR_ARCHIVE    0x20
43 #define ATTR_LFN        0xf
44
45
46 enum { FAT12, FAT16, FAT32, EXFAT };
47 static const char *typestr[] = { "fat12", "fat16", "fat32", "exfat" };
48
49 struct fat_dirent;
50 struct fat_dir;
51
52 struct fatfs {
53         int type;
54         int dev;
55         uint64_t start_sect;
56         uint32_t size;
57         int cluster_size;
58         int fat_size;
59         uint32_t fat_sect;
60         uint32_t root_sect;
61         int root_size;
62         uint32_t first_data_sect;
63         uint32_t num_data_sect;
64         uint32_t num_clusters;
65         char label[12];
66
67         void *fat;
68         struct fat_dir *rootdir;
69         unsigned int clust_mask;
70         int clust_shift;
71 };
72
73 struct bparam {
74         uint8_t jmp[3];
75         unsigned char fmtid[8];
76         uint16_t sect_bytes;
77         uint8_t cluster_size;
78         uint16_t reserved_sect;
79         uint8_t num_fats;
80         uint16_t num_dirent;
81         uint16_t num_sectors;
82         uint8_t medium;
83         uint16_t fat_size;
84         uint16_t track_size;
85         uint16_t num_heads;
86         uint32_t num_hidden;
87         uint32_t num_sectors32;
88 } __attribute__((packed));
89
90 struct bparam_ext16 {
91         uint8_t driveno;
92         uint8_t ntflags;
93         uint8_t signature;
94         uint32_t volume_id;
95         char label[11];
96         char sysid[8];
97 } __attribute__((packed));
98
99 struct bparam_ext32 {
100         uint32_t fat_size;
101         uint16_t flags;
102         uint16_t version;
103         uint32_t root_clust;
104         uint16_t fsinfo_sect;
105         uint16_t backup_boot_sect;
106         char junk[12];
107         uint8_t driveno;
108         uint8_t ntflags;
109         uint8_t signature;
110         uint32_t volume_id;
111         char label[11];
112         char sysid[8];
113 } __attribute__((packed));
114
115 struct fat_dirent {
116         char name[11];
117         uint8_t attr;
118         uint8_t junk;
119         uint8_t ctime_tenths;
120         uint16_t ctime_halfsec;
121         uint16_t ctime_date;
122         uint16_t atime_date;
123         uint16_t first_cluster_high;    /* 0 for FAT12 and FAT16 */
124         uint16_t mtime_hsec;
125         uint16_t mtime_date;
126         uint16_t first_cluster_low;
127         uint32_t size_bytes;
128 } __attribute__((packed));
129
130 struct fat_lfnent {
131         uint8_t seq;
132         uint16_t part1[5];
133         uint8_t attr;
134         uint8_t type;
135         uint8_t csum;
136         uint16_t part2[6];
137         uint16_t zero;
138         uint16_t part3[2];
139 } __attribute__((packed));
140
141
142 struct fat_dir {
143         struct fatfs *fatfs;
144
145         struct fat_dirent *ent;
146         int max_nent;
147
148         struct fs_dirent *fsent;
149         int fsent_size;
150         int cur_ent;
151
152         int ref;
153 };
154
155 struct fat_file {
156         struct fat_dirent ent;
157         int32_t first_clust;
158         int64_t cur_pos;
159         int32_t cur_clust;      /* cluster number corresponding to cur_pos */
160
161         char *clustbuf;
162         int buf_valid;
163 };
164
165
166 static void destroy(struct filesys *fs);
167
168 static struct fs_node *open(struct filesys *fs, const char *path, unsigned int flags);
169 static void close(struct fs_node *node);
170 static long fsize(struct fs_node *node);
171 static int seek(struct fs_node *node, int offs, int whence);
172 static long tell(struct fs_node *node);
173 static int read(struct fs_node *node, void *buf, int sz);
174 static int write(struct fs_node *node, void *buf, int sz);
175 static int rewinddir(struct fs_node *node);
176 static struct fs_dirent *readdir(struct fs_node *node);
177 static int rename(struct fs_node *node, const char *name);
178 static int remove(struct fs_node *node);
179
180 static struct fat_dir *load_dir(struct fatfs *fs, struct fat_dirent *dent);
181 static void parse_dir_entries(struct fat_dir *dir);
182 static void free_dir(struct fat_dir *dir);
183
184 static struct fat_file *init_file(struct fatfs *fatfs, struct fat_dirent *dent);
185 static void free_file(struct fat_file *file);
186
187 static int read_sectors(int dev, uint64_t sidx, int count, void *sect);
188 static int read_cluster(struct fatfs *fatfs, uint32_t addr, void *clust);
189 static int dent_filename(struct fat_dirent *dent, struct fat_dirent *prev, char *buf);
190 static struct fs_dirent *find_entry(struct fat_dir *dir, const char *name);
191
192 static uint32_t read_fat(struct fatfs *fatfs, uint32_t addr);
193 static int32_t next_cluster(struct fatfs *fatfs, int32_t addr);
194 static int32_t find_cluster(struct fatfs *fatfs, int count, int32_t clust);
195
196 /* static void dbg_printdir(struct fat_dirent *dir, int max_entries); */
197 static void clean_trailws(char *s);
198
199 static struct fs_operations fs_fat_ops = {
200         destroy,
201         open, close,
202
203         fsize,
204         seek, tell,
205         read, write,
206
207         rewinddir, readdir,
208
209         rename, remove
210 };
211
212 static unsigned char sectbuf[512];
213 static int max_sect_once;
214
215 struct filesys *fsfat_create(int dev, uint64_t start, uint64_t size)
216 {
217         int num_read;
218         char *endp, *ptr;
219         struct filesys *fs;
220         struct fatfs *fatfs;
221         struct fat_dir *rootdir;
222         struct bparam *bpb;
223         struct bparam_ext16 *bpb16;
224         struct bparam_ext32 *bpb32;
225
226         max_sect_once = ((unsigned char*)0xa0000 - low_mem_buffer) / 512;
227         /* some BIOS implementations have a maximum limit of 127 sectors */
228         if(max_sect_once > 127) max_sect_once = 127;
229
230         if(read_sectors(dev, start, 1, sectbuf) == -1) {
231                 return 0;
232         }
233         bpb = (struct bparam*)sectbuf;
234         bpb16 = (struct bparam_ext16*)(sectbuf + sizeof *bpb);
235         bpb32 = (struct bparam_ext32*)(sectbuf + sizeof *bpb);
236
237         if(bpb->jmp[0] != 0xeb || bpb->jmp[2] != 0x90) {
238                 return 0;
239         }
240         if(bpb->sect_bytes != 512) {
241                 return 0;
242         }
243
244         if(!(fatfs = malloc(sizeof *fatfs))) {
245                 panic("FAT: create failed to allocate memory for the fat filesystem data\n");
246         }
247         memset(fatfs, 0, sizeof *fatfs);
248         fatfs->dev = dev < 0 ? boot_drive_number : dev;
249         fatfs->start_sect = start;
250         fatfs->size = bpb->num_sectors ? bpb->num_sectors : bpb->num_sectors32;
251         fatfs->cluster_size = bpb->cluster_size;
252         fatfs->fat_size = bpb->fat_size ? bpb->fat_size : bpb32->fat_size;
253         fatfs->fat_sect = bpb->reserved_sect;
254         fatfs->root_sect = fatfs->fat_sect + fatfs->fat_size * bpb->num_fats;
255         fatfs->root_size = (bpb->num_dirent * sizeof(struct fat_dirent) + 511) / 512;
256         fatfs->first_data_sect = bpb->reserved_sect + bpb->num_fats * fatfs->fat_size + fatfs->root_size;
257         fatfs->num_data_sect = fatfs->size - (bpb->reserved_sect + bpb->num_fats * fatfs->fat_size + fatfs->root_size);
258         fatfs->num_clusters = fatfs->num_data_sect / fatfs->cluster_size;
259
260         if(fatfs->num_clusters < 4085) {
261                 fatfs->type = FAT12;
262         } else if(fatfs->num_clusters < 65525) {
263                 fatfs->type = FAT16;
264         } else if(fatfs->num_clusters < 268435445) {
265                 fatfs->type = FAT32;
266         } else {
267                 fatfs->type = EXFAT;
268         }
269
270         switch(fatfs->type) {
271         case FAT16:
272                 memcpy(fatfs->label, bpb16->label, sizeof bpb16->label);
273                 break;
274
275         case FAT32:
276         case EXFAT:
277                 fatfs->root_sect = bpb32->root_clust / fatfs->cluster_size;
278                 fatfs->root_size = 0;
279                 memcpy(fatfs->label, bpb32->label, sizeof bpb32->label);
280                 break;
281
282         default:
283                 break;
284         }
285
286         endp = fatfs->label + sizeof fatfs->label - 2;
287         while(endp >= fatfs->label && isspace(*endp)) {
288                 *endp-- = 0;
289         }
290
291         /* read the FAT */
292         if(!(fatfs->fat = malloc(fatfs->fat_size * 512))) {
293                 panic("FAT: failed to allocate memory for the FAT (%lu bytes)\n", (unsigned long)fatfs->fat_size * 512);
294         }
295         ptr = fatfs->fat;
296         num_read = 0;
297         while(num_read < fatfs->fat_size) {
298                 int count = fatfs->fat_size - num_read;
299                 if(count > max_sect_once) count = max_sect_once;
300
301                 read_sectors(dev, fatfs->start_sect + fatfs->fat_sect + num_read, count, ptr);
302                 ptr += count * 512;
303                 num_read += count;
304         }
305
306         /* open root directory */
307         if(fatfs->type == FAT32) {
308                 struct fat_dirent ent;
309                 ent.attr = ATTR_DIR;
310                 ent.first_cluster_low = bpb32->root_clust;
311                 ent.first_cluster_high = bpb32->root_clust >> 16;
312                 if(!(rootdir = load_dir(fatfs, &ent))) {
313                         panic("FAT: failed to load FAT32 root directory\n");
314                 }
315
316         } else {
317                 if(!(rootdir = malloc(sizeof *rootdir))) {
318                         panic("FAT: failed to allocate root directory structure\n");
319                 }
320                 rootdir->fatfs = fatfs;
321
322                 rootdir->max_nent = fatfs->root_size * 512 / sizeof(struct fat_dirent);
323                 if(!(rootdir->ent = malloc(fatfs->root_size * 512))) {
324                         panic("FAT: failed to allocate memory for the root directory\n");
325                 }
326                 ptr = (char*)rootdir->ent;
327
328                 num_read = 0;
329                 while(num_read < fatfs->root_size) {
330                         int count = fatfs->root_size - num_read;
331                         if(count > max_sect_once) count = max_sect_once;
332
333                         read_sectors(dev, fatfs->start_sect + fatfs->root_sect + num_read, count, ptr);
334                         ptr += count * 512;
335                         num_read += count;
336                 }
337
338                 parse_dir_entries(rootdir);
339         }
340         rootdir->ref = 1;
341         fatfs->rootdir = rootdir;
342
343         /* assume cluster_size is a power of two */
344         fatfs->clust_mask = (fatfs->cluster_size * 512) - 1;
345         fatfs->clust_shift = 0;
346         while((1 << fatfs->clust_shift) < (fatfs->cluster_size * 512)) {
347                 fatfs->clust_shift++;
348         }
349
350         /* fill generic fs structure */
351         if(!(fs = malloc(sizeof *fs))) {
352                 panic("FAT: create failed to allocate memory for the filesystem structure\n");
353         }
354         fs->type = FSTYPE_FAT;
355         fs->name = fatfs->label;
356         fs->fsop = &fs_fat_ops;
357         fs->data = fatfs;
358
359
360         printf("opened %s filesystem dev: %x, start: %lld\n", typestr[fatfs->type], fatfs->dev, start);
361         if(fatfs->label[0]) {
362                 printf("  volume label: %s\n", fatfs->label);
363         }
364
365         return fs;
366 }
367
368 static void destroy(struct filesys *fs)
369 {
370         struct fatfs *fatfs = fs->data;
371         free(fatfs);
372         free(fs);
373 }
374
375 static struct fs_node *open(struct filesys *fs, const char *path, unsigned int flags)
376 {
377         char name[MAX_NAME];
378         struct fatfs *fatfs = fs->data;
379         struct fat_dir *dir, *newdir;
380         struct fs_dirent *dent;
381         struct fat_dirent *fatdent;
382         struct fs_node *node;
383
384         if(path[0] == '/') {
385                 dir = fatfs->rootdir;
386                 path = fs_path_skipsep((char*)path);
387         } else {
388                 if(cwdnode->fs->type != FSTYPE_FAT) {
389                         return 0;
390                 }
391                 dir = cwdnode->data;
392         }
393
394         while(*path) {
395                 if(!dir) {
396                         /* we have more path components, yet the last one wasn't a dir */
397                         errno = ENOTDIR;
398                         return 0;
399                 }
400
401                 path = fs_path_next((char*)path, name, sizeof name);
402
403                 if(name[0] == '.' && name[1] == 0) {
404                         continue;
405                 }
406
407                 if(!(dent = find_entry(dir, name))) {
408                         errno = ENOENT;
409                         return 0;
410                 }
411                 fatdent = dent->data;
412
413                 if((fatdent->first_cluster_low | fatdent->first_cluster_high) == 0) {
414                         if(fatdent->attr == ATTR_DIR) {
415                                 /* ".." entries back to the root directory seem to have a 0
416                                  * cluster address as a special case
417                                  */
418                                 newdir = fatfs->rootdir;
419                         } else {
420                                 return 0;       /* but we can't have 0-address files (right?) */
421                         }
422                 } else {
423                         newdir = fatdent->attr == ATTR_DIR ? load_dir(fatfs, fatdent) : 0;
424                 }
425                 if(dir != fatfs->rootdir && dir != cwdnode->data) {
426                         free_dir(dir);
427                 }
428                 dir = newdir;
429         }
430
431
432         if(!(node = malloc(sizeof *node))) {
433                 panic("FAT: open failed to allocate fs_node structure\n");
434         }
435         node->fs = fs;
436         if(dir) {
437                 if(dir == fatfs->rootdir) {
438                         if(!(newdir = malloc(sizeof *newdir))) {
439                                 panic("FAT: failed to allocate directory structure\n");
440                         }
441                         *newdir = *dir;
442                         dir = newdir;
443                         dir->ref = 0;
444                 }
445                 node->type = FSNODE_DIR;
446                 node->data = dir;
447                 dir->cur_ent = 0;
448                 dir->ref++;
449         } else {
450                 node->type = FSNODE_FILE;
451                 if(!(node->data = init_file(fatfs, fatdent))) {
452                         panic("FAT: failed to allocate file entry structure\n");
453                 }
454         }
455
456         return node;
457 }
458
459 static void close(struct fs_node *node)
460 {
461         switch(node->type) {
462         case FSNODE_FILE:
463                 free_file(node->data);
464                 break;
465
466         case FSNODE_DIR:
467                 free_dir(node->data);
468                 break;
469
470         default:
471                 panic("FAT: close node is not a file nor a dir\n");
472         }
473
474         free(node);
475 }
476
477 static long fsize(struct fs_node *node)
478 {
479         struct fat_file *file;
480
481         if(node->type != FSNODE_FILE) {
482                 return -1;
483         }
484         file = node->data;
485         return file->ent.size_bytes;
486 }
487
488 static int seek(struct fs_node *node, int offs, int whence)
489 {
490         struct fatfs *fatfs;
491         struct fat_file *file;
492         int64_t new_pos;
493         unsigned int cur_clust_idx, new_clust_idx;
494
495         if(node->type != FSNODE_FILE) {
496                 return -1;
497         }
498
499         fatfs = node->fs->data;
500         file = node->data;
501
502         switch(whence) {
503         case FSSEEK_SET:
504                 new_pos = offs;
505                 break;
506
507         case FSSEEK_CUR:
508                 new_pos = file->cur_pos + offs;
509                 break;
510
511         case FSSEEK_END:
512                 new_pos = file->ent.size_bytes + offs;
513                 break;
514
515         default:
516                 return -1;
517         }
518
519         if(new_pos < 0) new_pos = 0;
520
521         cur_clust_idx = file->cur_pos >> fatfs->clust_shift;
522         new_clust_idx = new_pos >> fatfs->clust_shift;
523         /* if the new position does not fall in the same cluster as the previous one
524          * re-calculate cur_clust
525          */
526         if(new_clust_idx != cur_clust_idx) {
527                 if(new_clust_idx < cur_clust_idx) {
528                         file->cur_clust = find_cluster(fatfs, new_clust_idx, file->first_clust);
529                 } else {
530                         file->cur_clust = find_cluster(fatfs, new_clust_idx - cur_clust_idx, file->cur_clust);
531                 }
532                 file->buf_valid = 0;
533         }
534         file->cur_pos = new_pos;
535         return 0;
536 }
537
538 static long tell(struct fs_node *node)
539 {
540         struct fat_file *file;
541
542         if(!node || node->type != FSNODE_FILE) {
543                 return -1;
544         }
545
546         file = node->data;
547         return file->cur_pos;
548 }
549
550 static int read(struct fs_node *node, void *buf, int sz)
551 {
552         struct fatfs *fatfs;
553         struct fat_file *file;
554         char *bufptr = buf;
555         int num_read = 0;
556         int offs, len, buf_left, rd_left;
557         unsigned int cur_clust_idx, new_clust_idx;
558
559         if(!node || !buf || sz < 0 || node->type != FSNODE_FILE) {
560                 return -1;
561         }
562
563         fatfs = node->fs->data;
564         file = node->data;
565
566         if(file->cur_clust < 0) {
567                 return 0;       /* EOF */
568         }
569
570         cur_clust_idx = file->cur_pos >> fatfs->clust_shift;
571
572         while(num_read < sz) {
573                 if(!file->buf_valid) {
574                         read_cluster(fatfs, file->cur_clust, file->clustbuf);
575                         file->buf_valid = 1;
576                 }
577
578                 offs = file->cur_pos & fatfs->clust_mask;
579                 buf_left = fatfs->cluster_size * 512 - offs;
580                 rd_left = sz - num_read;
581                 len = buf_left < rd_left ? buf_left : rd_left;
582
583                 if(file->cur_pos + len > file->ent.size_bytes) {
584                         len = file->ent.size_bytes - file->cur_pos;
585                 }
586
587                 memcpy(bufptr, file->clustbuf + offs, len);
588                 num_read += len;
589                 bufptr += len;
590
591                 file->cur_pos += len;
592                 if(file->cur_pos >= file->ent.size_bytes) {
593                         file->cur_clust = -1;
594                         file->buf_valid = 0;
595                         break;  /* reached EOF */
596                 }
597
598                 new_clust_idx = file->cur_pos >> fatfs->clust_shift;
599                 if(new_clust_idx != cur_clust_idx) {
600                         file->buf_valid = 0;
601                         if((file->cur_clust = next_cluster(fatfs, file->cur_clust)) < 0) {
602                                 break;  /* reached EOF */
603                         }
604                         cur_clust_idx = new_clust_idx;
605                 }
606         }
607         return num_read;
608 }
609
610 static int write(struct fs_node *node, void *buf, int sz)
611 {
612         return -1;      /* TODO */
613 }
614
615 static int rewinddir(struct fs_node *node)
616 {
617         struct fat_dir *dir;
618
619         if(node->type != FSNODE_DIR) {
620                 return -1;
621         }
622
623         dir = node->data;
624         dir->cur_ent = 0;
625         return 0;
626 }
627
628 static struct fs_dirent *readdir(struct fs_node *node)
629 {
630         struct fat_dir *dir;
631
632         if(node->type != FSNODE_DIR) {
633                 return 0;
634         }
635
636         dir = node->data;
637         if(dir->cur_ent >= dir->fsent_size) {
638                 return 0;
639         }
640
641         return dir->fsent + dir->cur_ent++;
642 }
643
644 static int rename(struct fs_node *node, const char *name)
645 {
646         return -1;      /* TODO */
647 }
648
649 static int remove(struct fs_node *node)
650 {
651         errno = EPERM;
652         return -1;      /* TODO */
653 }
654
655 static struct fat_dir *load_dir(struct fatfs *fs, struct fat_dirent *dent)
656 {
657         int32_t addr;
658         struct fat_dir *dir;
659         char *buf = 0;
660         int bufsz = 0;
661
662         if(dent->attr != ATTR_DIR) return 0;
663
664         addr = dent->first_cluster_low;
665         if(fs->type >= FAT32) {
666                 addr |= (uint32_t)dent->first_cluster_high << 16;
667         }
668
669         do {
670                 int prevsz = bufsz;
671                 bufsz += fs->cluster_size * 512;
672                 if(!(buf = realloc(buf, bufsz))) {
673                         panic("FAT: failed to allocate cluster buffer (%d bytes)\n", bufsz);
674                 }
675
676                 if(read_cluster(fs, addr, buf + prevsz) == -1) {
677                         printf("load_dir: failed to read cluster: %lu\n", (unsigned long)addr);
678                         free(buf);
679                         return 0;
680                 }
681         } while((addr = next_cluster(fs, addr)) >= 0);
682
683         if(!(dir = malloc(sizeof *dir))) {
684                 panic("FAT: failed to allocate directory structure\n");
685         }
686         dir->fatfs = fs;
687         dir->ent = (struct fat_dirent*)buf;
688         dir->max_nent = bufsz / sizeof *dir->ent;
689         dir->cur_ent = 0;
690         dir->ref = 0;
691
692         parse_dir_entries(dir);
693         return dir;
694 }
695
696 static void parse_dir_entries(struct fat_dir *dir)
697 {
698         int i;
699         struct fat_dirent *dent, *prev_dent;
700         struct fs_dirent *eptr;
701         char entname[MAX_NAME];
702
703         /* create an fs_dirent array with one element for each actual entry
704          * (disregarding volume labels, and LFN entries).
705          */
706         if(!(dir->fsent = malloc(dir->max_nent * sizeof *dir->fsent))) {
707                 panic("FAT: failed to allocate dirent array\n");
708         }
709         eptr = dir->fsent;
710         dent = dir->ent;
711         prev_dent = dent - 1;
712
713         for(i=0; i<dir->max_nent; i++) {
714                 if(DENT_IS_NULL(dent)) break;
715
716                 if(!DENT_IS_UNUSED(dent) && dent->attr != ATTR_VOLID && dent->attr != ATTR_LFN) {
717                         if(dent_filename(dent, prev_dent, entname) > 0) {
718                                 if(!(eptr->name = malloc(strlen(entname) + 1))) {
719                                         panic("FAT: failed to allocate dirent name\n");
720                                 }
721                                 strcpy(eptr->name, entname);
722                                 eptr->data = dent;
723                                 eptr->type = dent->attr == ATTR_DIR ? FSNODE_DIR : FSNODE_FILE;
724                                 eptr->fsize = dent->size_bytes;
725                                 eptr++;
726                         }
727                 }
728                 if(dent->attr != ATTR_LFN) {
729                         prev_dent = dent;
730                 }
731                 dent++;
732         }
733         dir->fsent_size = eptr - dir->fsent;
734         dir->cur_ent = 0;
735 }
736
737 static void free_dir(struct fat_dir *dir)
738 {
739         int i;
740         struct fat_dir *root = dir->fatfs->rootdir;
741
742         if(dir) {
743                 if(--dir->ref > 0) return;
744
745                 if(dir->ent != root->ent) {
746                         free(dir->ent);
747                         if(dir->fsent) {
748                                 for(i=0; i<dir->fsent_size; i++) {
749                                         free(dir->fsent[i].name);
750                                 }
751                                 free(dir->fsent);
752                         }
753                 }
754                 free(dir);
755         }
756 }
757
758 static struct fat_file *init_file(struct fatfs *fatfs, struct fat_dirent *dent)
759 {
760         struct fat_file *file;
761
762         if(!(file = calloc(1, sizeof *file))) {
763                 panic("FAT: failed to allocate file structure\n");
764         }
765         if(!(file->clustbuf = malloc(fatfs->cluster_size * 512))) {
766                 panic("FAT: failed to allocate file cluster buffer\n");
767         }
768         file->ent = *dent;
769         file->first_clust = dent->first_cluster_low | ((int32_t)dent->first_cluster_high << 16);
770         file->cur_clust = file->first_clust;
771         return file;
772 }
773
774 static void free_file(struct fat_file *file)
775 {
776         if(file) {
777                 free(file->clustbuf);
778                 free(file);
779         }
780 }
781
782 static int read_sectors(int dev, uint64_t sidx, int count, void *sect)
783 {
784         if(dev == -1 || dev == boot_drive_number) {
785                 if(bdev_read_range(sidx, count, sect) == -1) {
786                         return -1;
787                 }
788                 return 0;
789         }
790
791         printf("BUG: reading sectors from drives other than the boot drive not implemented yet\n");
792         return -1;
793 }
794
795 static int read_cluster(struct fatfs *fatfs, uint32_t addr, void *clust)
796 {
797         char *ptr = clust;
798         uint64_t saddr = (uint64_t)(addr - 2) * fatfs->cluster_size + fatfs->first_data_sect + fatfs->start_sect;
799
800         if(read_sectors(fatfs->dev, saddr, fatfs->cluster_size, ptr) == -1) {
801                 return -1;
802         }
803         return 0;
804 }
805
806 static int dent_filename(struct fat_dirent *dent, struct fat_dirent *prev, char *buf)
807 {
808         int len = 0;
809         char *ptr = buf;
810         struct fat_lfnent *lfn = (struct fat_lfnent*)(dent - 1);
811
812         if(lfn > (struct fat_lfnent*)prev && lfn->attr == ATTR_LFN) {
813                 /* found a long filename entry, use that */
814                 do {
815                         uint16_t ustr[14], *uptr = ustr;
816                         memcpy(uptr, lfn->part1, sizeof lfn->part1);
817                         uptr += sizeof lfn->part1 / sizeof *lfn->part1;
818                         memcpy(uptr, lfn->part2, sizeof lfn->part2);
819                         uptr += sizeof lfn->part2 / sizeof *lfn->part2;
820                         memcpy(uptr, lfn->part3, sizeof lfn->part3);
821                         ustr[13] = 0;
822
823                         uptr = ustr;
824                         while(*uptr) {
825                                 *ptr++ = *(char*)uptr++;
826                                 len++;
827                         }
828                         *ptr = 0;
829
830                         if(uptr < ustr + 13 || (lfn->seq & 0xf0) == 0x40) break;
831                         lfn -= 1;
832                 } while(lfn > (struct fat_lfnent*)prev && lfn->attr == ATTR_LFN);
833
834         } else {
835                 /* regular 8.3 filename */
836                 memcpy(buf, dent->name, 8);
837                 buf[8] = 0;
838                 clean_trailws(buf);
839                 if(!buf[0]) return 0;
840
841                 if(dent->name[8] && dent->name[8] != ' ') {
842                         ptr = buf + strlen(buf);
843                         *ptr++ = '.';
844                         memcpy(ptr, dent->name + 8, 3);
845                         ptr[3] = 0;
846                         clean_trailws(ptr);
847                 }
848
849                 len = strlen(buf);
850         }
851         return len;
852 }
853
854 static struct fs_dirent *find_entry(struct fat_dir *dir, const char *name)
855 {
856         int i;
857         struct fs_dirent *dent = dir->fsent;
858
859         for(i=0; i<dir->fsent_size; i++) {
860                 if(strcasecmp(dent->name, name) == 0) {
861                         return dent;
862                 }
863                 dent++;
864         }
865         return 0;
866 }
867
868 static uint32_t read_fat(struct fatfs *fatfs, uint32_t addr)
869 {
870         uint32_t res = 0xffffffff;
871
872         switch(fatfs->type) {
873         case FAT12:
874                 {
875                         uint32_t idx = addr + addr / 2;
876                         res = ((uint16_t*)fatfs->fat)[idx];
877
878                         if(idx & 1) {
879                                 res >>= 4;              /* odd entries end up on the high 12 bits */
880                         } else {
881                                 res &= 0xfff;   /* even entries end up on the low 12 bits */
882                         }
883                 }
884                 break;
885
886         case FAT16:
887                 res = ((uint16_t*)fatfs->fat)[addr];
888                 break;
889
890         case FAT32:
891         case EXFAT:
892                 res = ((uint32_t*)fatfs->fat)[addr];
893                 break;
894
895         default:
896                 break;
897         }
898
899         return res;
900 }
901
902 static int32_t next_cluster(struct fatfs *fatfs, int32_t addr)
903 {
904         uint32_t fatval = read_fat(fatfs, addr);
905
906         if(fatval == 0) return -1;
907
908         switch(fatfs->type) {
909         case FAT12:
910                 if(fatval >= 0xff8) return -1;
911                 break;
912
913         case FAT16:
914                 if(fatval >= 0xfff8) return -1;
915                 break;
916
917         case FAT32:
918         case EXFAT:     /* XXX ? */
919                 if(fatval >= 0xffffff8) return -1;
920                 break;
921
922         default:
923                 break;
924         }
925
926         return fatval;
927 }
928
929 static int32_t find_cluster(struct fatfs *fatfs, int count, int32_t clust)
930 {
931         while(count-- > 0 && (clust = next_cluster(fatfs, clust)) >= 0);
932         return clust;
933 }
934
935 /*
936 static void dbg_printdir(struct fat_dirent *dir, int max_entries)
937 {
938         char name[MAX_NAME];
939         struct fat_dirent *prev = dir - 1;
940         struct fat_dirent *end = max_entries > 0 ? dir + max_entries : 0;
941
942         while(!DENT_IS_NULL(dir) && (!end || dir < end)) {
943                 if(!DENT_IS_UNUSED(dir) && dir->attr != ATTR_VOLID && dir->attr != ATTR_LFN) {
944                         if(dent_filename(dir, prev, name) > 0) {
945                                 printf("%s%c\n", name, dir->attr == ATTR_DIR ? '/' : ' ');
946                         }
947                 }
948                 if(dir->attr != ATTR_LFN) {
949                         prev = dir;
950                 }
951                 dir++;
952         }
953 }
954 */
955
956 static void clean_trailws(char *s)
957 {
958         char *p;
959
960         if(!s || !*s) return;
961
962         p = s + strlen(s) - 1;
963         while(p >= s && isspace(*p)) p--;
964         p[1] = 0;
965 }