:: limine / common / fs / fat32.s2.c 24.4 KB raw

1
#include <stdint.h>
2
#include <fs/fat32.h>
3
#include <lib/misc.h>
4
#include <drivers/disk.h>
5
#include <lib/libc.h>
6
#include <lib/print.h>
7
#include <mm/pmm.h>
8
#include <stdbool.h>
9
10
#define FAT32_LFN_MAX_ENTRIES 20
11
#define FAT32_LFN_MAX_FILENAME_LENGTH (FAT32_LFN_MAX_ENTRIES * 13 + 1)
12
13
#define FAT32_ATTRIBUTE_SUBDIRECTORY 0x10
14
#define FAT32_LFN_ATTRIBUTE 0x0F
15
#define FAT32_ATTRIBUTE_VOLLABEL 0x08
16
17
struct fat32_context {
18
    struct volume *part;
19
    int type;
20
    char *label;
21
    uint16_t bytes_per_sector;
22
    uint8_t sectors_per_cluster;
23
    uint16_t reserved_sectors;
24
    uint8_t number_of_fats;
25
    uint32_t hidden_sectors;
26
    uint32_t sectors_per_fat;
27
    uint32_t fat_start_lba;
28
    uint32_t data_start_lba;
29
    uint32_t root_directory_cluster;
30
    uint16_t root_entries;
31
    uint32_t root_start;
32
    uint32_t root_size;
33
};
34
35
struct fat32_file_handle {
36
    struct fat32_context context;
37
    uint32_t first_cluster;
38
    uint32_t size_bytes;
39
40
    uint32_t *cluster_chain;
41
    size_t chain_len;
42
};
43
44
struct fat32_bpb {
45
    union {
46
        struct {
47
            uint8_t jump[3];
48
            char oem[8];
49
            uint16_t bytes_per_sector;
50
            uint8_t sectors_per_cluster;
51
            uint16_t reserved_sectors;
52
            uint8_t fats_count;
53
            uint16_t root_entries_count;
54
            uint16_t sectors_count_16;
55
            uint8_t media_descriptor_type;
56
            uint16_t sectors_per_fat_16;
57
            uint16_t sectors_per_track;
58
            uint16_t heads_count;
59
            uint32_t hidden_sectors_count;
60
            uint32_t sectors_count_32;
61
            uint32_t sectors_per_fat_32;
62
            uint16_t flags;
63
            uint16_t fat_version_number;
64
            uint32_t root_directory_cluster;
65
            uint16_t fs_info_sector;
66
            uint16_t backup_boot_sector;
67
            uint8_t reserved[12];
68
            uint8_t drive_number;
69
            uint8_t nt_flags;
70
            uint8_t signature;
71
            uint32_t volume_serial_number;
72
            char label[11];
73
            char system_identifier[8];
74
        } __attribute__((packed));
75
        uint8_t padding[512];
76
    };
77
} __attribute__((packed));
78
79
struct fat32_directory_entry {
80
    char file_name_and_ext[8 + 3];
81
    uint8_t attribute;
82
    uint8_t file_data_1[8];
83
    uint16_t cluster_num_high;
84
    uint8_t file_data_2[4];
85
    uint16_t cluster_num_low;
86
    uint32_t file_size_bytes;
87
} __attribute__((packed));
88
89
struct fat32_lfn_entry {
90
    uint8_t sequence_number;
91
    char name1[10];
92
    uint8_t attribute;
93
    uint8_t type;
94
    uint8_t dos_checksum;
95
    char name2[12];
96
    uint16_t first_cluster;
97
    char name3[4];
98
} __attribute__((packed));
99
100
static int fat32_open_in(struct fat32_context* context, struct fat32_directory_entry* directory, struct fat32_directory_entry* file, const char* name);
101
102
static int fat32_init_context(struct fat32_context* context, struct volume *part) {
103
    context->part = part;
104
105
    struct fat32_bpb bpb;
106
    if (!volume_read(context->part, &bpb, 0, sizeof(struct fat32_bpb))) {
107
        return 1;
108
    }
109
110
    // Sanity check of bpb
111
112
    // Checks for FAT12/16
113
    if (strncmp((((void *)&bpb) + 0x36), "FAT", 3) == 0) {
114
        goto signature_valid;
115
    }
116
117
    // Checks for FAT32
118
    if (strncmp((((void *)&bpb) + 0x52), "FAT", 3) == 0) {
119
        goto signature_valid;
120
    }
121
122
    // Checks for FAT32 (with 64-bit sector count)
123
    if (strncmp((((void *)&bpb) + 0x03), "FAT32", 5) == 0) {
124
        goto signature_valid;
125
    }
126
127
    return 1;
128
129
signature_valid:;
130
131
    const uint8_t sector_per_cluster_valid_values[] = { 1, 2, 4, 8, 16, 32, 64, 128 };
132
    for (size_t i = 0; i < SIZEOF_ARRAY(sector_per_cluster_valid_values); i++) {
133
        if (bpb.sectors_per_cluster == sector_per_cluster_valid_values[i]) {
134
            goto sector_per_cluster_valid;
135
        }
136
    }
137
138
    return 1;
139
140
sector_per_cluster_valid:;
141
142
    const uint16_t bytes_per_sector_valid_values[] = { 512, 1024, 2048, 4096 };
143
    for (size_t i = 0; i < SIZEOF_ARRAY(bytes_per_sector_valid_values); i++) {
144
        if (bpb.bytes_per_sector == bytes_per_sector_valid_values[i]) {
145
            goto bytes_per_sector_valid;
146
        }
147
    }
148
149
    return 1;
150
151
bytes_per_sector_valid:;
152
153
    // Validate fats_count (typically 1 or 2, but allow up to 4)
154
    if (bpb.fats_count == 0 || bpb.fats_count > 4) {
155
        return 1;
156
    }
157
158
    // The boot sector itself occupies at least sector 0
159
    if (bpb.reserved_sectors == 0) {
160
        return 1;
161
    }
162
163
    // The following mess to identify the FAT type is from the FAT spec
164
    // at paragraph 3.5
165
    size_t root_dir_sects = ((bpb.root_entries_count * 32) + (bpb.bytes_per_sector - 1)) / bpb.bytes_per_sector;
166
167
    // Calculate total sectors and metadata sectors separately to check for underflow
168
    uint64_t total_sects = bpb.sectors_count_16 ? bpb.sectors_count_16 : bpb.sectors_count_32;
169
    uint64_t sectors_per_fat = bpb.sectors_per_fat_16 ? bpb.sectors_per_fat_16 : bpb.sectors_per_fat_32;
170
    uint64_t metadata_sects = (uint64_t)bpb.reserved_sectors + ((uint64_t)bpb.fats_count * sectors_per_fat) + root_dir_sects;
171
172
    // Check for underflow before subtraction
173
    if (metadata_sects >= total_sects) {
174
        return 1;  // Invalid filesystem: metadata exceeds total size
175
    }
176
177
    size_t data_sects = total_sects - metadata_sects;
178
    size_t clusters_count = data_sects / bpb.sectors_per_cluster;
179
180
    if (clusters_count < 4085) {
181
        context->type = 12;
182
    } else if (clusters_count < 65525) {
183
        context->type = 16;
184
    } else {
185
        context->type = 32;
186
    }
187
188
    context->bytes_per_sector = bpb.bytes_per_sector;
189
    context->sectors_per_cluster = bpb.sectors_per_cluster;
190
    context->reserved_sectors = bpb.reserved_sectors;
191
    context->number_of_fats = bpb.fats_count;
192
    context->hidden_sectors = bpb.hidden_sectors_count;
193
    context->sectors_per_fat = context->type == 32 ? bpb.sectors_per_fat_32 : bpb.sectors_per_fat_16;
194
    if (context->sectors_per_fat == 0) {
195
        return 1;
196
    }
197
    context->root_directory_cluster = bpb.root_directory_cluster;
198
    context->fat_start_lba = bpb.reserved_sectors;
199
    context->root_entries = bpb.root_entries_count;
200
201
    // FAT12/16 require a non-zero root directory entry count
202
    if (context->type != 32 && context->root_entries == 0) {
203
        return 1;
204
    }
205
206
    // Calculate root_start with overflow check
207
    uint64_t root_start_64 = (uint64_t)context->reserved_sectors + (uint64_t)context->number_of_fats * context->sectors_per_fat;
208
    if (root_start_64 > UINT32_MAX) {
209
        return 1;  // Overflow in root_start calculation
210
    }
211
    context->root_start = (uint32_t)root_start_64;
212
    context->root_size = DIV_ROUNDUP(context->root_entries * sizeof(struct fat32_directory_entry), context->bytes_per_sector, return 1);
213
    switch (context->type) {
214
        case 12:
215
        case 16:
216
            context->data_start_lba = CHECKED_ADD(context->root_start, context->root_size, return 1);
217
            break;
218
        case 32:
219
            context->data_start_lba = context->root_start;
220
            break;
221
        default:
222
            __builtin_unreachable();
223
    }
224
225
    // get the volume label
226
    struct fat32_directory_entry _current_directory;
227
    struct fat32_directory_entry *current_directory;
228
229
    switch (context->type) {
230
        case 12:
231
        case 16:
232
            current_directory = NULL;
233
            break;
234
        case 32:
235
            _current_directory.cluster_num_low = context->root_directory_cluster & 0xFFFF;
236
            _current_directory.cluster_num_high = context->root_directory_cluster >> 16;
237
            current_directory = &_current_directory;
238
            break;
239
        default:
240
            __builtin_unreachable();
241
    }
242
243
    char *vol_label;
244
    if (fat32_open_in(context, current_directory, (struct fat32_directory_entry *)&vol_label, NULL) == 0) {
245
        context->label = vol_label;
246
    } else {
247
        context->label = NULL;
248
    }
249
250
    return 0;
251
}
252
253
static int read_cluster_from_map(struct fat32_context *context, uint32_t cluster, uint32_t *out) {
254
    uint64_t fat_base = (uint64_t)context->fat_start_lba * context->bytes_per_sector;
255
    uint64_t fat_size = (uint64_t)context->sectors_per_fat * context->bytes_per_sector;
256
257
    switch (context->type) {
258
        case 12: {
259
            *out = 0;
260
            uint16_t tmp = 0;
261
            uint64_t offset = (uint64_t)cluster + (uint64_t)(cluster / 2);
262
263
            // Ensure 2-byte reads won't exceed FAT table bounds
264
            if (offset + sizeof(uint16_t) > fat_size) {
265
                return -1;
266
            }
267
268
            if (!volume_read(context->part, &tmp, fat_base + offset, sizeof(uint16_t))) {
269
                return -1;
270
            }
271
            if (cluster % 2 == 0) {
272
                *out = tmp & 0xfff;
273
            } else {
274
                *out = tmp >> 4;
275
            }
276
            break;
277
        }
278
        case 16: {
279
            *out = 0;
280
            uint64_t offset = (uint64_t)cluster * sizeof(uint16_t);
281
            if (offset + sizeof(uint16_t) > fat_size) {
282
                return -1;
283
            }
284
            if (!volume_read(context->part, out, fat_base + offset, sizeof(uint16_t))) {
285
                return -1;
286
            }
287
            break;
288
        }
289
        case 32: {
290
            uint64_t offset = (uint64_t)cluster * sizeof(uint32_t);
291
            if (offset + sizeof(uint32_t) > fat_size) {
292
                return -1;
293
            }
294
            if (!volume_read(context->part, out, fat_base + offset, sizeof(uint32_t))) {
295
                return -1;
296
            }
297
            *out &= 0x0fffffff;
298
            break;
299
        }
300
        default:
301
            __builtin_unreachable();
302
    }
303
304
    return 0;
305
}
306
307
// Maximum cluster chain length to prevent memory exhaustion (64MB of cluster chain data)
308
#define FAT32_MAX_CHAIN_LENGTH (64 * 1024 * 1024 / sizeof(uint32_t))
309
310
static uint32_t *cache_cluster_chain(struct fat32_context *context,
311
                                     uint32_t initial_cluster,
312
                                     size_t *_chain_length) {
313
    uint32_t cluster_limit = (context->type == 12 ? 0xfef     : 0)
314
                           | (context->type == 16 ? 0xffef    : 0)
315
                           | (context->type == 32 ? 0xfffffef : 0);
316
    if (initial_cluster < 0x2 || initial_cluster > cluster_limit)
317
        return NULL;
318
319
    // Limit chain length to prevent memory exhaustion from malicious filesystems
320
    size_t max_clusters = cluster_limit - 1;
321
    if (max_clusters > FAT32_MAX_CHAIN_LENGTH) {
322
        max_clusters = FAT32_MAX_CHAIN_LENGTH;
323
    }
324
325
    uint32_t cluster = initial_cluster;
326
    size_t chain_length;
327
    for (chain_length = 1; chain_length <= max_clusters; chain_length++) {
328
        if (read_cluster_from_map(context, cluster, &cluster) != 0) {
329
            return NULL;
330
        }
331
        if (cluster < 0x2 || cluster > cluster_limit)
332
            break;
333
    }
334
335
    if (chain_length > max_clusters) {
336
        // Circular or corrupted cluster chain detected
337
        return NULL;
338
    }
339
340
    uint32_t *cluster_chain = ext_mem_alloc_counted(chain_length, sizeof(uint32_t));
341
    cluster = initial_cluster;
342
    for (size_t i = 0; i < chain_length; i++) {
343
        cluster_chain[i] = cluster;
344
        if (read_cluster_from_map(context, cluster, &cluster) != 0) {
345
            pmm_free(cluster_chain, chain_length * sizeof(uint32_t));
346
            return NULL;
347
        }
348
    }
349
    *_chain_length = chain_length;
350
    return cluster_chain;
351
}
352
353
static bool read_cluster_chain(struct fat32_context *context,
354
                               uint32_t *cluster_chain,
355
                               size_t chain_len,
356
                               void *buf, uint64_t loc, uint64_t count) {
357
    uint64_t block_size = (uint64_t)context->sectors_per_cluster * (uint64_t)context->bytes_per_sector;
358
    for (uint64_t progress = 0; progress < count;) {
359
        uint64_t block = (loc + progress) / block_size;
360
361
        // Bounds check: ensure block index is within cluster chain
362
        if (block >= chain_len) {
363
            return false;
364
        }
365
366
        // Validate cluster number before arithmetic to prevent underflow
367
        uint32_t cluster = cluster_chain[block];
368
        if (cluster < 2) {
369
            return false;
370
        }
371
372
        uint64_t chunk = count - progress;
373
        uint64_t offset = (loc + progress) % block_size;
374
        if (chunk > block_size - offset)
375
            chunk = block_size - offset;
376
377
        uint64_t base = ((uint64_t)context->data_start_lba + (uint64_t)(cluster - 2) * context->sectors_per_cluster) * context->bytes_per_sector;
378
        if (!volume_read(context->part, buf + progress, base + offset, chunk)) {
379
            return false;
380
        }
381
382
        progress += chunk;
383
    }
384
385
    return true;
386
}
387
388
// Copy ucs-2 characters to char*, with bounds checking
389
static void fat32_lfncpy(char* destination, size_t dest_size, size_t dest_offset,
390
                         const void* source, unsigned int size) {
391
    for (unsigned int i = 0; i < size; i++) {
392
        if (dest_offset + i >= dest_size) {
393
            return;  // Prevent buffer overflow
394
        }
395
        // ignore high bytes
396
        *(((uint8_t*) destination) + dest_offset + i) = *(((uint8_t*) source) + (i * 2));
397
    }
398
}
399
400
static bool fat32_filename_to_8_3(char *dest, const char *src) {
401
    int i = 0, j = 0;
402
    bool ext = false;
403
404
    for (size_t k = 0; k < 8+3; k++)
405
        dest[k] = ' ';
406
407
    while (src[i]) {
408
        if (src[i] == '.') {
409
            if (ext) {
410
                // This is a double extension here, just give up.
411
                return false;
412
            }
413
            ext = true;
414
            j = 8;
415
            i++;
416
            continue;
417
        }
418
        if (j >= 8+3 || (j >= 8 && !ext)) {
419
            // Filename too long, give up.
420
            return false;
421
        }
422
        dest[j++] = toupper(src[i++]);
423
    }
424
425
    return true;
426
}
427
428
static int fat32_open_in(struct fat32_context* context, struct fat32_directory_entry* directory, struct fat32_directory_entry* file, const char* name) {
429
    size_t block_size = context->sectors_per_cluster * context->bytes_per_sector;
430
    char current_lfn[FAT32_LFN_MAX_FILENAME_LENGTH] = {0};
431
    unsigned int lfn_expected = 0;
432
433
    size_t dir_chain_len;
434
    struct fat32_directory_entry *directory_entries;
435
436
    if (directory != NULL) {
437
        uint32_t current_cluster_number = directory->cluster_num_low;
438
        if (context->type == 32)
439
            current_cluster_number |= (uint32_t)directory->cluster_num_high << 16;
440
441
        uint32_t *directory_cluster_chain = cache_cluster_chain(context, current_cluster_number, &dir_chain_len);
442
443
        if (directory_cluster_chain == NULL)
444
            return -1;
445
446
        size_t alloc_size = CHECKED_MUL(dir_chain_len, block_size, ({
447
            pmm_free(directory_cluster_chain, dir_chain_len * sizeof(uint32_t));
448
            return -1;
449
        }));
450
        if (alloc_size > 256 * 1024 * 1024) {
451
            pmm_free(directory_cluster_chain, dir_chain_len * sizeof(uint32_t));
452
            return -1;
453
        }
454
455
        directory_entries = ext_mem_alloc(alloc_size);
456
457
        if (!read_cluster_chain(context, directory_cluster_chain, dir_chain_len, directory_entries, 0, alloc_size)) {
458
            pmm_free(directory_entries, alloc_size);
459
            pmm_free(directory_cluster_chain, dir_chain_len * sizeof(uint32_t));
460
            return -1;
461
        }
462
463
        pmm_free(directory_cluster_chain, dir_chain_len * sizeof(uint32_t));
464
    } else {
465
        dir_chain_len = DIV_ROUNDUP(context->root_entries * sizeof(struct fat32_directory_entry), block_size, return 1);
466
467
        size_t alloc_size = CHECKED_MUL(dir_chain_len, block_size, return -1);
468
        if (alloc_size > 256 * 1024 * 1024) {
469
            return -1;
470
        }
471
472
        directory_entries = ext_mem_alloc(alloc_size);
473
474
        if (!volume_read(context->part, directory_entries, (uint64_t)context->root_start * context->bytes_per_sector, context->root_entries * sizeof(struct fat32_directory_entry))) {
475
            pmm_free(directory_entries, alloc_size);
476
            return -1;
477
        }
478
    }
479
480
    int ret;
481
482
    for (size_t i = 0; i < (dir_chain_len * block_size) / sizeof(struct fat32_directory_entry); i++) {
483
        if (directory_entries[i].file_name_and_ext[0] == 0x00) {
484
            // no more entries here
485
            break;
486
        }
487
488
        if (name == NULL) {
489
            if (directory_entries[i].attribute != FAT32_ATTRIBUTE_VOLLABEL) {
490
                continue;
491
            }
492
            char *r = ext_mem_alloc(12);
493
            memcpy(r, directory_entries[i].file_name_and_ext, 11);
494
            // remove trailing spaces
495
            for (int j = 10; j >= 0; j--) {
496
                if (r[j] == ' ') {
497
                    r[j] = 0;
498
                    continue;
499
                }
500
                break;
501
            }
502
            *((char **)file) = r;
503
            ret = 0;
504
            goto out;
505
        }
506
507
        if (directory_entries[i].attribute == FAT32_LFN_ATTRIBUTE) {
508
            // Skip deleted LFN entries, otherwise their 0xE5 sequence_number
509
            // would be interpreted as a first-of-chain marker.
510
            if ((uint8_t)directory_entries[i].file_name_and_ext[0] == 0xE5) {
511
                lfn_expected = 0;
512
                continue;
513
            }
514
515
            struct fat32_lfn_entry* lfn = (struct fat32_lfn_entry*) &directory_entries[i];
516
517
            const unsigned int seq_num = lfn->sequence_number & 0b00011111;
518
519
            if (lfn->sequence_number & 0b01000000) {
520
                // this lfn is the first entry in the table, clear the lfn buffer
521
                memset(current_lfn, ' ', sizeof(current_lfn));
522
                lfn_expected = seq_num;
523
            }
524
525
            if (seq_num == 0 || seq_num != lfn_expected) {
526
                lfn_expected = 0;  // Invalidate: out of order or gap
527
                continue;
528
            }
529
            lfn_expected--;
530
531
            const unsigned int lfn_index = (seq_num - 1U) * 13U;
532
            if (lfn_index >= FAT32_LFN_MAX_ENTRIES * 13) {
533
                lfn_expected = 0;
534
                continue;
535
            }
536
537
            fat32_lfncpy(current_lfn, sizeof(current_lfn), lfn_index + 0, lfn->name1, 5);
538
            fat32_lfncpy(current_lfn, sizeof(current_lfn), lfn_index + 5, lfn->name2, 6);
539
            fat32_lfncpy(current_lfn, sizeof(current_lfn), lfn_index + 11, lfn->name3, 2);
540
541
            if (seq_num != 1)
542
                continue;
543
544
            // remove trailing spaces
545
            for (int j = SIZEOF_ARRAY(current_lfn) - 2; j >= -1; j--) {
546
                if (j == -1 || current_lfn[j] != ' ') {
547
                    current_lfn[j + 1] = 0;
548
                    break;
549
                }
550
            }
551
552
            int (*strcmpfn)(const char *, const char *) = case_insensitive_fopen ? strcasecmp : strcmp;
553
554
            if (strcmpfn(current_lfn, name) == 0) {
555
                // Ensure i+1 is within bounds before accessing
556
                if (i + 1 >= (dir_chain_len * block_size) / sizeof(struct fat32_directory_entry)) {
557
                    ret = -1;
558
                    goto out;
559
                }
560
                // Validate that the next entry is a valid SFN entry (not LFN, deleted, or end-of-dir)
561
                struct fat32_directory_entry *sfn_entry = &directory_entries[i+1];
562
                if (sfn_entry->file_name_and_ext[0] == 0x00 ||
563
                    (uint8_t)sfn_entry->file_name_and_ext[0] == 0xE5 ||
564
                    sfn_entry->attribute == FAT32_LFN_ATTRIBUTE) {
565
                    // Corrupted LFN sequence - expected SFN entry not found
566
                    ret = -1;
567
                    goto out;
568
                }
569
                *file = *sfn_entry;
570
                ret = 0;
571
                goto out;
572
            }
573
        }
574
575
        if (directory_entries[i].attribute & (1 << 3)) {
576
            // It is a volume label, skip
577
            continue;
578
        }
579
        // SFN
580
        char fn[8+3];
581
        if (!fat32_filename_to_8_3(fn, name)) {
582
            continue;
583
        }
584
        if (!strncmp(directory_entries[i].file_name_and_ext, fn, 8+3)) {
585
            *file = directory_entries[i];
586
            ret = 0;
587
            goto out;
588
        }
589
    }
590
591
    // file not found
592
    ret = -1;
593
594
out:
595
    pmm_free(directory_entries, dir_chain_len * block_size);
596
    return ret;
597
}
598
599
char *fat32_get_label(struct volume *part) {
600
    struct fat32_context context;
601
    if (fat32_init_context(&context, part) != 0) {
602
        return NULL;
603
    }
604
605
    return context.label;
606
}
607
608
static uint64_t fat32_read(struct file_handle *handle, void *buf, uint64_t loc, uint64_t count);
609
static void fat32_close(struct file_handle *file);
610
611
struct file_handle *fat32_open(struct volume *part, const char *path) {
612
    struct fat32_context context;
613
    int r = fat32_init_context(&context, part);
614
615
    if (r) {
616
        return NULL;
617
    }
618
619
    struct fat32_directory_entry _current_directory;
620
    struct fat32_directory_entry *current_directory;
621
    struct fat32_directory_entry current_file;
622
    unsigned int current_index = 0;
623
    char current_part[FAT32_LFN_MAX_FILENAME_LENGTH];
624
625
    // skip leading slashes
626
    while (path[current_index] == '/') {
627
        current_index++;
628
    }
629
630
    // walk down the directory tree
631
    switch (context.type) {
632
        case 12:
633
        case 16:
634
            current_directory = NULL;
635
            break;
636
        case 32:
637
            _current_directory.cluster_num_low = context.root_directory_cluster & 0xFFFF;
638
            _current_directory.cluster_num_high = context.root_directory_cluster >> 16;
639
            current_directory = &_current_directory;
640
            break;
641
        default:
642
            __builtin_unreachable();
643
    }
644
645
    for (;;) {
646
        bool expect_directory = false;
647
        bool found_terminator = false;
648
649
        for (unsigned int i = 0; i < SIZEOF_ARRAY(current_part) - 1; i++) {
650
            // Check for overflow before computing path index
651
            unsigned int path_idx;
652
            path_idx = CHECKED_ADD(i, current_index, return NULL);
653
654
            if (path[path_idx] == 0) {
655
                memcpy(current_part, path + current_index, i);
656
                current_part[i] = 0;
657
                expect_directory = false;
658
                found_terminator = true;
659
                break;
660
            }
661
662
            if (path[path_idx] == '/') {
663
                memcpy(current_part, path + current_index, i);
664
                current_part[i] = 0;
665
                current_index = CHECKED_ADD(current_index, i + 1, return NULL);
666
                expect_directory = true;
667
                found_terminator = true;
668
                break;
669
            }
670
        }
671
672
        // If loop completed without finding terminator, path component is too long
673
        if (!found_terminator) {
674
            return NULL;
675
        }
676
677
        if ((r = fat32_open_in(&context, current_directory, &current_file, current_part)) != 0) {
678
            return NULL;
679
        }
680
681
        if (expect_directory) {
682
            if (!(current_file.attribute & FAT32_ATTRIBUTE_SUBDIRECTORY)) {
683
                return NULL;
684
            }
685
            _current_directory = current_file;
686
            current_directory = &_current_directory;
687
        } else {
688
            struct file_handle *handle = ext_mem_alloc(sizeof(struct file_handle));
689
            struct fat32_file_handle *ret = ext_mem_alloc(sizeof(struct fat32_file_handle));
690
691
            ret->context = context;
692
            ret->first_cluster = current_file.cluster_num_low;
693
            if (context.type == 32)
694
                ret->first_cluster |= (uint64_t)current_file.cluster_num_high << 16;
695
696
            ret->size_bytes = current_file.file_size_bytes;
697
            // Initialize chain_len before calling cache_cluster_chain
698
            // (cache_cluster_chain may return NULL without setting it for empty files)
699
            ret->chain_len = 0;
700
            ret->cluster_chain = cache_cluster_chain(&context, ret->first_cluster, &ret->chain_len);
701
702
            if (ret->cluster_chain == NULL && ret->size_bytes != 0) {
703
                pmm_free(ret, sizeof(struct fat32_file_handle));
704
                pmm_free(handle, sizeof(struct file_handle));
705
                return NULL;
706
            }
707
708
            handle->fd = (void *)ret;
709
            handle->read = (void *)fat32_read;
710
            handle->close = (void *)fat32_close;
711
            handle->size = ret->size_bytes;
712
            handle->vol = part;
713
#if defined (UEFI)
714
            handle->efi_part_handle = part->efi_part_handle;
715
#endif
716
717
            return handle;
718
        }
719
    }
720
}
721
722
static uint64_t fat32_read(struct file_handle *file, void *buf, uint64_t loc, uint64_t count) {
723
    struct fat32_file_handle *f = file->fd;
724
    if (!read_cluster_chain(&f->context, f->cluster_chain, f->chain_len, buf, loc, count)) {
725
        panic(false, "fat32: cluster chain read failed (corrupted filesystem?)");
726
    }
727
    return count;
728
}
729
730
static void fat32_close(struct file_handle *file) {
731
    struct fat32_file_handle *f = file->fd;
732
    pmm_free(f->cluster_chain, f->chain_len * sizeof(uint32_t));
733
    pmm_free(f, sizeof(struct fat32_file_handle));
734
}
tab: 248 wrap: offon