]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - GRUB2/MOD_SRC/grub-2.04/grub-core/fs/fat.c
1. change some directory structure for the build script
[Ventoy.git] / GRUB2 / MOD_SRC / grub-2.04 / grub-core / fs / fat.c
1 /* fat.c - FAT filesystem */
2 /*
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2000,2001,2002,2003,2004,2005,2007,2008,2009 Free Software Foundation, Inc.
5 *
6 * GRUB is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * GRUB is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <grub/fs.h>
21 #include <grub/disk.h>
22 #include <grub/file.h>
23 #include <grub/types.h>
24 #include <grub/misc.h>
25 #include <grub/mm.h>
26 #include <grub/err.h>
27 #include <grub/dl.h>
28 #include <grub/charset.h>
29 #ifndef MODE_EXFAT
30 #include <grub/fat.h>
31 #else
32 #include <grub/exfat.h>
33 #endif
34 #include <grub/fshelp.h>
35 #include <grub/i18n.h>
36 #include <grub/time.h>
37 #include <grub/ventoy.h>
38
39 GRUB_MOD_LICENSE ("GPLv3+");
40
41 enum
42 {
43 GRUB_FAT_ATTR_READ_ONLY = 0x01,
44 GRUB_FAT_ATTR_HIDDEN = 0x02,
45 GRUB_FAT_ATTR_SYSTEM = 0x04,
46 #ifndef MODE_EXFAT
47 GRUB_FAT_ATTR_VOLUME_ID = 0x08,
48 #endif
49 GRUB_FAT_ATTR_DIRECTORY = 0x10,
50 GRUB_FAT_ATTR_ARCHIVE = 0x20,
51
52 #ifndef MODE_EXFAT
53 GRUB_FAT_ATTR_LONG_NAME = (GRUB_FAT_ATTR_READ_ONLY
54 | GRUB_FAT_ATTR_HIDDEN
55 | GRUB_FAT_ATTR_SYSTEM
56 | GRUB_FAT_ATTR_VOLUME_ID),
57 #endif
58 GRUB_FAT_ATTR_VALID = (GRUB_FAT_ATTR_READ_ONLY
59 | GRUB_FAT_ATTR_HIDDEN
60 | GRUB_FAT_ATTR_SYSTEM
61 | GRUB_FAT_ATTR_DIRECTORY
62 | GRUB_FAT_ATTR_ARCHIVE
63 #ifndef MODE_EXFAT
64 | GRUB_FAT_ATTR_VOLUME_ID
65 #endif
66 )
67 };
68
69 #ifdef MODE_EXFAT
70 typedef struct grub_exfat_bpb grub_current_fat_bpb_t;
71 #else
72 typedef struct grub_fat_bpb grub_current_fat_bpb_t;
73 #endif
74
75 #ifdef MODE_EXFAT
76 enum
77 {
78 FLAG_CONTIGUOUS = 2
79 };
80 struct grub_fat_dir_entry
81 {
82 grub_uint8_t entry_type;
83 union
84 {
85 grub_uint8_t placeholder[31];
86 struct {
87 grub_uint8_t secondary_count;
88 grub_uint16_t checksum;
89 grub_uint16_t attr;
90 grub_uint16_t reserved1;
91 grub_uint32_t c_time;
92 grub_uint32_t m_time;
93 grub_uint32_t a_time;
94 grub_uint8_t c_time_tenth;
95 grub_uint8_t m_time_tenth;
96 grub_uint8_t a_time_tenth;
97 grub_uint8_t reserved2[9];
98 } GRUB_PACKED file;
99 struct {
100 grub_uint8_t flags;
101 grub_uint8_t reserved1;
102 grub_uint8_t name_length;
103 grub_uint16_t name_hash;
104 grub_uint16_t reserved2;
105 grub_uint64_t valid_size;
106 grub_uint32_t reserved3;
107 grub_uint32_t first_cluster;
108 grub_uint64_t file_size;
109 } GRUB_PACKED stream_extension;
110 struct {
111 grub_uint8_t flags;
112 grub_uint16_t str[15];
113 } GRUB_PACKED file_name;
114 struct {
115 grub_uint8_t character_count;
116 grub_uint16_t str[15];
117 } GRUB_PACKED volume_label;
118 } GRUB_PACKED type_specific;
119 } GRUB_PACKED;
120
121 struct grub_fat_dir_node
122 {
123 grub_uint32_t attr;
124 grub_uint32_t first_cluster;
125 grub_uint64_t file_size;
126 grub_uint64_t valid_size;
127 int have_stream;
128 int is_contiguous;
129 };
130
131 typedef struct grub_fat_dir_node grub_fat_dir_node_t;
132
133 #else
134 struct grub_fat_dir_entry
135 {
136 grub_uint8_t name[11];
137 grub_uint8_t attr;
138 grub_uint8_t nt_reserved;
139 grub_uint8_t c_time_tenth;
140 grub_uint16_t c_time;
141 grub_uint16_t c_date;
142 grub_uint16_t a_date;
143 grub_uint16_t first_cluster_high;
144 grub_uint16_t w_time;
145 grub_uint16_t w_date;
146 grub_uint16_t first_cluster_low;
147 grub_uint32_t file_size;
148 } GRUB_PACKED;
149
150 struct grub_fat_long_name_entry
151 {
152 grub_uint8_t id;
153 grub_uint16_t name1[5];
154 grub_uint8_t attr;
155 grub_uint8_t reserved;
156 grub_uint8_t checksum;
157 grub_uint16_t name2[6];
158 grub_uint16_t first_cluster;
159 grub_uint16_t name3[2];
160 } GRUB_PACKED;
161
162 typedef struct grub_fat_dir_entry grub_fat_dir_node_t;
163
164 #endif
165
166 struct grub_fat_data
167 {
168 int logical_sector_bits;
169 grub_uint32_t num_sectors;
170
171 grub_uint32_t fat_sector;
172 grub_uint32_t sectors_per_fat;
173 int fat_size;
174
175 grub_uint32_t root_cluster;
176 #ifndef MODE_EXFAT
177 grub_uint32_t root_sector;
178 grub_uint32_t num_root_sectors;
179 #endif
180
181 int cluster_bits;
182 grub_uint32_t cluster_eof_mark;
183 grub_uint32_t cluster_sector;
184 grub_uint32_t num_clusters;
185
186 grub_uint32_t uuid;
187 };
188
189 struct grub_fshelp_node {
190 grub_disk_t disk;
191 struct grub_fat_data *data;
192
193 grub_uint8_t attr;
194 #ifndef MODE_EXFAT
195 grub_uint32_t file_size;
196 #else
197 grub_uint64_t file_size;
198 #endif
199 grub_uint32_t file_cluster;
200 grub_uint32_t cur_cluster_num;
201 grub_uint32_t cur_cluster;
202
203 #ifdef MODE_EXFAT
204 int is_contiguous;
205 #endif
206 };
207
208 static grub_dl_t my_mod;
209
210 #ifndef MODE_EXFAT
211 static int
212 fat_log2 (unsigned x)
213 {
214 int i;
215
216 if (x == 0)
217 return -1;
218
219 for (i = 0; (x & 1) == 0; i++)
220 x >>= 1;
221
222 if (x != 1)
223 return -1;
224
225 return i;
226 }
227 #endif
228
229 static struct grub_fat_data *
230 grub_fat_mount (grub_disk_t disk)
231 {
232 grub_current_fat_bpb_t bpb;
233 struct grub_fat_data *data = 0;
234 grub_uint32_t first_fat, magic;
235
236 if (! disk)
237 goto fail;
238
239 data = (struct grub_fat_data *) grub_malloc (sizeof (*data));
240 if (! data)
241 goto fail;
242
243 /* Read the BPB. */
244 if (grub_disk_read (disk, 0, 0, sizeof (bpb), &bpb))
245 goto fail;
246
247 #ifdef MODE_EXFAT
248 if (grub_memcmp ((const char *) bpb.oem_name, "EXFAT ",
249 sizeof (bpb.oem_name)) != 0)
250 goto fail;
251 #endif
252
253 /* Get the sizes of logical sectors and clusters. */
254 #ifdef MODE_EXFAT
255 data->logical_sector_bits = bpb.bytes_per_sector_shift;
256 #else
257 data->logical_sector_bits =
258 fat_log2 (grub_le_to_cpu16 (bpb.bytes_per_sector));
259 #endif
260 if (data->logical_sector_bits < GRUB_DISK_SECTOR_BITS
261 || data->logical_sector_bits >= 16)
262 goto fail;
263 data->logical_sector_bits -= GRUB_DISK_SECTOR_BITS;
264
265 #ifdef MODE_EXFAT
266 data->cluster_bits = bpb.sectors_per_cluster_shift;
267 #else
268 data->cluster_bits = fat_log2 (bpb.sectors_per_cluster);
269 #endif
270 if (data->cluster_bits < 0 || data->cluster_bits > 25)
271 goto fail;
272 data->cluster_bits += data->logical_sector_bits;
273
274 /* Get information about FATs. */
275 #ifdef MODE_EXFAT
276 data->fat_sector = (grub_le_to_cpu32 (bpb.num_reserved_sectors)
277 << data->logical_sector_bits);
278 #else
279 data->fat_sector = (grub_le_to_cpu16 (bpb.num_reserved_sectors)
280 << data->logical_sector_bits);
281 #endif
282 if (data->fat_sector == 0)
283 goto fail;
284
285 #ifdef MODE_EXFAT
286 data->sectors_per_fat = (grub_le_to_cpu32 (bpb.sectors_per_fat)
287 << data->logical_sector_bits);
288 #else
289 data->sectors_per_fat = ((bpb.sectors_per_fat_16
290 ? grub_le_to_cpu16 (bpb.sectors_per_fat_16)
291 : grub_le_to_cpu32 (bpb.version_specific.fat32.sectors_per_fat_32))
292 << data->logical_sector_bits);
293 #endif
294 if (data->sectors_per_fat == 0)
295 goto fail;
296
297 /* Get the number of sectors in this volume. */
298 #ifdef MODE_EXFAT
299 data->num_sectors = ((grub_le_to_cpu64 (bpb.num_total_sectors))
300 << data->logical_sector_bits);
301 #else
302 data->num_sectors = ((bpb.num_total_sectors_16
303 ? grub_le_to_cpu16 (bpb.num_total_sectors_16)
304 : grub_le_to_cpu32 (bpb.num_total_sectors_32))
305 << data->logical_sector_bits);
306 #endif
307 if (data->num_sectors == 0)
308 goto fail;
309
310 /* Get information about the root directory. */
311 if (bpb.num_fats == 0)
312 goto fail;
313
314 #ifndef MODE_EXFAT
315 data->root_sector = data->fat_sector + bpb.num_fats * data->sectors_per_fat;
316 data->num_root_sectors
317 = ((((grub_uint32_t) grub_le_to_cpu16 (bpb.num_root_entries)
318 * sizeof (struct grub_fat_dir_entry)
319 + grub_le_to_cpu16 (bpb.bytes_per_sector) - 1)
320 >> (data->logical_sector_bits + GRUB_DISK_SECTOR_BITS))
321 << (data->logical_sector_bits));
322 #endif
323
324 #ifdef MODE_EXFAT
325 data->cluster_sector = (grub_le_to_cpu32 (bpb.cluster_offset)
326 << data->logical_sector_bits);
327 data->num_clusters = (grub_le_to_cpu32 (bpb.cluster_count)
328 << data->logical_sector_bits);
329 #else
330 data->cluster_sector = data->root_sector + data->num_root_sectors;
331 data->num_clusters = (((data->num_sectors - data->cluster_sector)
332 >> data->cluster_bits)
333 + 2);
334 #endif
335
336 if (data->num_clusters <= 2)
337 goto fail;
338
339 #ifdef MODE_EXFAT
340 {
341 /* exFAT. */
342 data->root_cluster = grub_le_to_cpu32 (bpb.root_cluster);
343 data->fat_size = 32;
344 data->cluster_eof_mark = 0xffffffff;
345
346 if ((bpb.volume_flags & grub_cpu_to_le16_compile_time (0x1))
347 && bpb.num_fats > 1)
348 data->fat_sector += data->sectors_per_fat;
349 }
350 #else
351 if (! bpb.sectors_per_fat_16)
352 {
353 /* FAT32. */
354 grub_uint16_t flags = grub_le_to_cpu16 (bpb.version_specific.fat32.extended_flags);
355
356 data->root_cluster = grub_le_to_cpu32 (bpb.version_specific.fat32.root_cluster);
357 data->fat_size = 32;
358 data->cluster_eof_mark = 0x0ffffff8;
359
360 if (flags & 0x80)
361 {
362 /* Get an active FAT. */
363 unsigned active_fat = flags & 0xf;
364
365 if (active_fat > bpb.num_fats)
366 goto fail;
367
368 data->fat_sector += active_fat * data->sectors_per_fat;
369 }
370
371 if (bpb.num_root_entries != 0 || bpb.version_specific.fat32.fs_version != 0)
372 goto fail;
373 }
374 else
375 {
376 /* FAT12 or FAT16. */
377 data->root_cluster = ~0U;
378
379 if (data->num_clusters <= 4085 + 2)
380 {
381 /* FAT12. */
382 data->fat_size = 12;
383 data->cluster_eof_mark = 0x0ff8;
384 }
385 else
386 {
387 /* FAT16. */
388 data->fat_size = 16;
389 data->cluster_eof_mark = 0xfff8;
390 }
391 }
392 #endif
393
394 /* More sanity checks. */
395 if (data->num_sectors <= data->fat_sector)
396 goto fail;
397
398 if (grub_disk_read (disk,
399 data->fat_sector,
400 0,
401 sizeof (first_fat),
402 &first_fat))
403 goto fail;
404
405 first_fat = grub_le_to_cpu32 (first_fat);
406
407 if (data->fat_size == 32)
408 {
409 first_fat &= 0x0fffffff;
410 magic = 0x0fffff00;
411 }
412 else if (data->fat_size == 16)
413 {
414 first_fat &= 0x0000ffff;
415 magic = 0xff00;
416 }
417 else
418 {
419 first_fat &= 0x00000fff;
420 magic = 0x0f00;
421 }
422
423 /* Serial number. */
424 #ifdef MODE_EXFAT
425 data->uuid = grub_le_to_cpu32 (bpb.num_serial);
426 #else
427 if (bpb.sectors_per_fat_16)
428 data->uuid = grub_le_to_cpu32 (bpb.version_specific.fat12_or_fat16.num_serial);
429 else
430 data->uuid = grub_le_to_cpu32 (bpb.version_specific.fat32.num_serial);
431 #endif
432
433 #ifndef MODE_EXFAT
434 /* Ignore the 3rd bit, because some BIOSes assigns 0xF0 to the media
435 descriptor, even if it is a so-called superfloppy (e.g. an USB key).
436 The check may be too strict for this kind of stupid BIOSes, as
437 they overwrite the media descriptor. */
438 if ((first_fat | 0x8) != (magic | bpb.media | 0x8))
439 goto fail;
440 #else
441 (void) magic;
442 #endif
443
444 return data;
445
446 fail:
447
448 grub_free (data);
449 grub_error (GRUB_ERR_BAD_FS, "not a FAT filesystem");
450 return 0;
451 }
452
453 static grub_ssize_t
454 grub_fat_read_data (grub_disk_t disk, grub_fshelp_node_t node,
455 grub_disk_read_hook_t read_hook, void *read_hook_data,
456 grub_off_t offset, grub_size_t len, char *buf)
457 {
458 grub_size_t size;
459 grub_uint32_t logical_cluster;
460 unsigned logical_cluster_bits;
461 grub_ssize_t ret = 0;
462 unsigned long sector;
463
464 #ifndef MODE_EXFAT
465 /* This is a special case. FAT12 and FAT16 doesn't have the root directory
466 in clusters. */
467 if (node->file_cluster == ~0U)
468 {
469 size = (node->data->num_root_sectors << GRUB_DISK_SECTOR_BITS) - offset;
470 if (size > len)
471 size = len;
472
473 if (grub_disk_read (disk, node->data->root_sector, offset, size, buf))
474 return -1;
475
476 return size;
477 }
478 #endif
479
480 #ifdef MODE_EXFAT
481 if (node->is_contiguous)
482 {
483 /* Read the data here. */
484 sector = (node->data->cluster_sector
485 + ((node->file_cluster - 2)
486 << node->data->cluster_bits));
487
488 disk->read_hook = read_hook;
489 disk->read_hook_data = read_hook_data;
490 grub_disk_read (disk, sector + (offset >> GRUB_DISK_SECTOR_BITS),
491 offset & (GRUB_DISK_SECTOR_SIZE - 1), len, buf);
492 disk->read_hook = 0;
493 if (grub_errno)
494 return -1;
495
496 return len;
497 }
498 #endif
499
500 /* Calculate the logical cluster number and offset. */
501 logical_cluster_bits = (node->data->cluster_bits
502 + GRUB_DISK_SECTOR_BITS);
503 logical_cluster = offset >> logical_cluster_bits;
504 offset &= (1ULL << logical_cluster_bits) - 1;
505
506 if (logical_cluster < node->cur_cluster_num)
507 {
508 node->cur_cluster_num = 0;
509 node->cur_cluster = node->file_cluster;
510 }
511
512 while (len)
513 {
514 while (logical_cluster > node->cur_cluster_num)
515 {
516 /* Find next cluster. */
517 grub_uint32_t next_cluster;
518 grub_uint32_t fat_offset;
519
520 switch (node->data->fat_size)
521 {
522 case 32:
523 fat_offset = node->cur_cluster << 2;
524 break;
525 case 16:
526 fat_offset = node->cur_cluster << 1;
527 break;
528 default:
529 /* case 12: */
530 fat_offset = node->cur_cluster + (node->cur_cluster >> 1);
531 break;
532 }
533
534 /* Read the FAT. */
535 if (grub_disk_read (disk, node->data->fat_sector, fat_offset,
536 (node->data->fat_size + 7) >> 3,
537 (char *) &next_cluster))
538 return -1;
539
540 next_cluster = grub_le_to_cpu32 (next_cluster);
541 switch (node->data->fat_size)
542 {
543 case 16:
544 next_cluster &= 0xFFFF;
545 break;
546 case 12:
547 if (node->cur_cluster & 1)
548 next_cluster >>= 4;
549
550 next_cluster &= 0x0FFF;
551 break;
552 }
553
554 grub_dprintf ("fat", "fat_size=%d, next_cluster=%u\n",
555 node->data->fat_size, next_cluster);
556
557 /* Check the end. */
558 if (next_cluster >= node->data->cluster_eof_mark)
559 return ret;
560
561 if (next_cluster < 2 || (next_cluster - 2) >= node->data->num_clusters)
562 {
563 grub_error (GRUB_ERR_BAD_FS, "invalid cluster %u",
564 next_cluster);
565 return -1;
566 }
567
568 node->cur_cluster = next_cluster;
569 node->cur_cluster_num++;
570 }
571
572 /* Read the data here. */
573 sector = (node->data->cluster_sector
574 + ((node->cur_cluster - 2)
575 << node->data->cluster_bits));
576 size = (1 << logical_cluster_bits) - offset;
577 if (size > len)
578 size = len;
579
580 disk->read_hook = read_hook;
581 disk->read_hook_data = read_hook_data;
582 grub_disk_read (disk, sector, offset, size, buf);
583 disk->read_hook = 0;
584 if (grub_errno)
585 return -1;
586
587 len -= size;
588 buf += size;
589 ret += size;
590 logical_cluster++;
591 offset = 0;
592 }
593
594 return ret;
595 }
596
597 struct grub_fat_iterate_context
598 {
599 #ifdef MODE_EXFAT
600 struct grub_fat_dir_node dir;
601 #else
602 struct grub_fat_dir_entry dir;
603 #endif
604 char *filename;
605 grub_uint16_t *unibuf;
606 grub_ssize_t offset;
607 };
608
609 static grub_err_t
610 grub_fat_iterate_init (struct grub_fat_iterate_context *ctxt)
611 {
612 ctxt->offset = -sizeof (struct grub_fat_dir_entry);
613
614 #ifndef MODE_EXFAT
615 /* Allocate space enough to hold a long name. */
616 ctxt->filename = grub_malloc (0x40 * 13 * GRUB_MAX_UTF8_PER_UTF16 + 1);
617 ctxt->unibuf = (grub_uint16_t *) grub_malloc (0x40 * 13 * 2);
618 #else
619 ctxt->unibuf = grub_malloc (15 * 256 * 2);
620 ctxt->filename = grub_malloc (15 * 256 * GRUB_MAX_UTF8_PER_UTF16 + 1);
621 #endif
622
623 if (! ctxt->filename || ! ctxt->unibuf)
624 {
625 grub_free (ctxt->filename);
626 grub_free (ctxt->unibuf);
627 return grub_errno;
628 }
629 return GRUB_ERR_NONE;
630 }
631
632 static void
633 grub_fat_iterate_fini (struct grub_fat_iterate_context *ctxt)
634 {
635 grub_free (ctxt->filename);
636 grub_free (ctxt->unibuf);
637 }
638
639 #ifdef MODE_EXFAT
640 static grub_err_t
641 grub_fat_iterate_dir_next (grub_fshelp_node_t node,
642 struct grub_fat_iterate_context *ctxt)
643 {
644 grub_memset (&ctxt->dir, 0, sizeof (ctxt->dir));
645 while (1)
646 {
647 struct grub_fat_dir_entry dir;
648
649 ctxt->offset += sizeof (dir);
650
651 if (grub_fat_read_data (node->disk, node, 0, 0, ctxt->offset, sizeof (dir),
652 (char *) &dir)
653 != sizeof (dir))
654 break;
655
656 if (dir.entry_type == 0)
657 break;
658 if (!(dir.entry_type & 0x80))
659 continue;
660
661 if (dir.entry_type == 0x85)
662 {
663 unsigned i, nsec, slots = 0;
664
665 nsec = dir.type_specific.file.secondary_count;
666
667 ctxt->dir.attr = grub_cpu_to_le16 (dir.type_specific.file.attr);
668 ctxt->dir.have_stream = 0;
669 for (i = 0; i < nsec; i++)
670 {
671 struct grub_fat_dir_entry sec;
672 ctxt->offset += sizeof (sec);
673 if (grub_fat_read_data (node->disk, node, 0, 0,
674 ctxt->offset, sizeof (sec), (char *) &sec)
675 != sizeof (sec))
676 break;
677 if (!(sec.entry_type & 0x80))
678 continue;
679 if (!(sec.entry_type & 0x40))
680 break;
681 switch (sec.entry_type)
682 {
683 case 0xc0:
684 ctxt->dir.first_cluster = grub_cpu_to_le32 (sec.type_specific.stream_extension.first_cluster);
685 ctxt->dir.valid_size
686 = grub_cpu_to_le64 (sec.type_specific.stream_extension.valid_size);
687 ctxt->dir.file_size
688 = grub_cpu_to_le64 (sec.type_specific.stream_extension.file_size);
689 ctxt->dir.have_stream = 1;
690 ctxt->dir.is_contiguous = !!(sec.type_specific.stream_extension.flags
691 & grub_cpu_to_le16_compile_time (FLAG_CONTIGUOUS));
692 break;
693 case 0xc1:
694 {
695 int j;
696 for (j = 0; j < 15; j++)
697 ctxt->unibuf[slots * 15 + j]
698 = grub_le_to_cpu16 (sec.type_specific.file_name.str[j]);
699 slots++;
700 }
701 break;
702 default:
703 grub_dprintf ("exfat", "unknown secondary type 0x%02x\n",
704 sec.entry_type);
705 }
706 }
707
708 if (i != nsec)
709 {
710 ctxt->offset -= sizeof (dir);
711 continue;
712 }
713
714 *grub_utf16_to_utf8 ((grub_uint8_t *) ctxt->filename, ctxt->unibuf,
715 slots * 15) = '\0';
716
717 return 0;
718 }
719 /* Allocation bitmap. */
720 if (dir.entry_type == 0x81)
721 continue;
722 /* Upcase table. */
723 if (dir.entry_type == 0x82)
724 continue;
725 /* Volume label. */
726 if (dir.entry_type == 0x83)
727 continue;
728 grub_dprintf ("exfat", "unknown primary type 0x%02x\n",
729 dir.entry_type);
730 }
731 return grub_errno ? : GRUB_ERR_EOF;
732 }
733
734 #else
735
736 static grub_err_t
737 grub_fat_iterate_dir_next (grub_fshelp_node_t node,
738 struct grub_fat_iterate_context *ctxt)
739 {
740 char *filep = 0;
741 int checksum = -1;
742 int slot = -1, slots = -1;
743
744 while (1)
745 {
746 unsigned i;
747
748 /* Adjust the offset. */
749 ctxt->offset += sizeof (ctxt->dir);
750
751 /* Read a directory entry. */
752 if (grub_fat_read_data (node->disk, node, 0, 0,
753 ctxt->offset, sizeof (ctxt->dir),
754 (char *) &ctxt->dir)
755 != sizeof (ctxt->dir) || ctxt->dir.name[0] == 0)
756 break;
757
758 /* Handle long name entries. */
759 if (ctxt->dir.attr == GRUB_FAT_ATTR_LONG_NAME)
760 {
761 struct grub_fat_long_name_entry *long_name
762 = (struct grub_fat_long_name_entry *) &ctxt->dir;
763 grub_uint8_t id = long_name->id;
764
765 if (id & 0x40)
766 {
767 id &= 0x3f;
768 slots = slot = id;
769 checksum = long_name->checksum;
770 }
771
772 if (id != slot || slot == 0 || checksum != long_name->checksum)
773 {
774 checksum = -1;
775 continue;
776 }
777
778 slot--;
779 grub_memcpy (ctxt->unibuf + slot * 13, long_name->name1, 5 * 2);
780 grub_memcpy (ctxt->unibuf + slot * 13 + 5, long_name->name2, 6 * 2);
781 grub_memcpy (ctxt->unibuf + slot * 13 + 11, long_name->name3, 2 * 2);
782 continue;
783 }
784
785 /* Check if this entry is valid. */
786 if (ctxt->dir.name[0] == 0xe5 || (ctxt->dir.attr & ~GRUB_FAT_ATTR_VALID))
787 continue;
788
789 /* This is a workaround for Japanese. */
790 if (ctxt->dir.name[0] == 0x05)
791 ctxt->dir.name[0] = 0xe5;
792
793 if (checksum != -1 && slot == 0)
794 {
795 grub_uint8_t sum;
796
797 for (sum = 0, i = 0; i < sizeof (ctxt->dir.name); i++)
798 sum = ((sum >> 1) | (sum << 7)) + ctxt->dir.name[i];
799
800 if (sum == checksum)
801 {
802 int u;
803
804 for (u = 0; u < slots * 13; u++)
805 ctxt->unibuf[u] = grub_le_to_cpu16 (ctxt->unibuf[u]);
806
807 *grub_utf16_to_utf8 ((grub_uint8_t *) ctxt->filename,
808 ctxt->unibuf,
809 slots * 13) = '\0';
810
811 return GRUB_ERR_NONE;
812 }
813
814 checksum = -1;
815 }
816
817 /* Convert the 8.3 file name. */
818 filep = ctxt->filename;
819 if (ctxt->dir.attr & GRUB_FAT_ATTR_VOLUME_ID)
820 {
821 for (i = 0; i < sizeof (ctxt->dir.name) && ctxt->dir.name[i]; i++)
822 *filep++ = ctxt->dir.name[i];
823 while (i > 0 && ctxt->dir.name[i - 1] == ' ')
824 {
825 filep--;
826 i--;
827 }
828 }
829 else
830 {
831 for (i = 0; i < 8 && ctxt->dir.name[i]; i++)
832 *filep++ = grub_tolower (ctxt->dir.name[i]);
833 while (i > 0 && ctxt->dir.name[i - 1] == ' ')
834 {
835 filep--;
836 i--;
837 }
838
839 /* XXX should we check that dir position is 0 or 1? */
840 if (i > 2 || filep[0] != '.' || (i == 2 && filep[1] != '.'))
841 *filep++ = '.';
842
843 for (i = 8; i < 11 && ctxt->dir.name[i]; i++)
844 *filep++ = grub_tolower (ctxt->dir.name[i]);
845 while (i > 8 && ctxt->dir.name[i - 1] == ' ')
846 {
847 filep--;
848 i--;
849 }
850
851 if (i == 8)
852 filep--;
853 }
854 *filep = '\0';
855 return GRUB_ERR_NONE;
856 }
857
858 return grub_errno ? : GRUB_ERR_EOF;
859 }
860
861 #endif
862
863 static grub_err_t lookup_file (grub_fshelp_node_t node,
864 const char *name,
865 grub_fshelp_node_t *foundnode,
866 enum grub_fshelp_filetype *foundtype)
867 {
868 grub_err_t err;
869 struct grub_fat_iterate_context ctxt;
870
871 err = grub_fat_iterate_init (&ctxt);
872 if (err)
873 return err;
874
875 while (!(err = grub_fat_iterate_dir_next (node, &ctxt)))
876 {
877
878 #ifdef MODE_EXFAT
879 if (!ctxt.dir.have_stream)
880 continue;
881 #else
882 if (ctxt.dir.attr & GRUB_FAT_ATTR_VOLUME_ID)
883 continue;
884 #endif
885
886 if (grub_strcasecmp (name, ctxt.filename) == 0)
887 {
888 *foundnode = grub_malloc (sizeof (struct grub_fshelp_node));
889 if (!*foundnode)
890 return grub_errno;
891 (*foundnode)->attr = ctxt.dir.attr;
892 #ifdef MODE_EXFAT
893 (*foundnode)->file_size = ctxt.dir.file_size;
894 (*foundnode)->file_cluster = ctxt.dir.first_cluster;
895 (*foundnode)->is_contiguous = ctxt.dir.is_contiguous;
896 #else
897 (*foundnode)->file_size = grub_le_to_cpu32 (ctxt.dir.file_size);
898 (*foundnode)->file_cluster = ((grub_le_to_cpu16 (ctxt.dir.first_cluster_high) << 16)
899 | grub_le_to_cpu16 (ctxt.dir.first_cluster_low));
900 /* If directory points to root, starting cluster is 0 */
901 if (!(*foundnode)->file_cluster)
902 (*foundnode)->file_cluster = node->data->root_cluster;
903 #endif
904 (*foundnode)->cur_cluster_num = ~0U;
905 (*foundnode)->data = node->data;
906 (*foundnode)->disk = node->disk;
907
908 *foundtype = ((*foundnode)->attr & GRUB_FAT_ATTR_DIRECTORY) ? GRUB_FSHELP_DIR : GRUB_FSHELP_REG;
909
910 grub_fat_iterate_fini (&ctxt);
911 return GRUB_ERR_NONE;
912 }
913 }
914
915 grub_fat_iterate_fini (&ctxt);
916 if (err == GRUB_ERR_EOF)
917 err = 0;
918
919 return err;
920
921 }
922
923 static grub_err_t
924 grub_fat_dir (grub_device_t device, const char *path, grub_fs_dir_hook_t hook,
925 void *hook_data)
926 {
927 struct grub_fat_data *data = 0;
928 grub_disk_t disk = device->disk;
929 grub_fshelp_node_t found = NULL;
930 grub_err_t err;
931 struct grub_fat_iterate_context ctxt;
932
933 grub_dl_ref (my_mod);
934
935 data = grub_fat_mount (disk);
936 if (! data)
937 goto fail;
938
939 struct grub_fshelp_node root = {
940 .data = data,
941 .disk = disk,
942 .attr = GRUB_FAT_ATTR_DIRECTORY,
943 .file_size = 0,
944 .file_cluster = data->root_cluster,
945 .cur_cluster_num = ~0U,
946 .cur_cluster = 0,
947 #ifdef MODE_EXFAT
948 .is_contiguous = 0,
949 #endif
950 };
951
952 err = grub_fshelp_find_file_lookup (path, &root, &found, lookup_file, NULL, GRUB_FSHELP_DIR);
953 if (err)
954 goto fail;
955
956 err = grub_fat_iterate_init (&ctxt);
957 if (err)
958 goto fail;
959
960 while (!(err = grub_fat_iterate_dir_next (found, &ctxt)))
961 {
962 struct grub_dirhook_info info;
963 grub_memset (&info, 0, sizeof (info));
964
965 info.dir = !! (ctxt.dir.attr & GRUB_FAT_ATTR_DIRECTORY);
966 info.case_insensitive = 1;
967
968 if (!info.dir)
969 info.size = ctxt.dir.file_size;
970
971 #ifdef MODE_EXFAT
972 if (!ctxt.dir.have_stream)
973 continue;
974 #else
975 if (ctxt.dir.attr & GRUB_FAT_ATTR_VOLUME_ID)
976 continue;
977 #endif
978
979 if (hook (ctxt.filename, &info, hook_data))
980 break;
981 }
982 grub_fat_iterate_fini (&ctxt);
983 if (err == GRUB_ERR_EOF)
984 err = 0;
985
986 fail:
987 if (found != &root)
988 grub_free (found);
989
990 grub_free (data);
991
992 grub_dl_unref (my_mod);
993
994 return grub_errno;
995 }
996
997 static grub_err_t
998 grub_fat_open (grub_file_t file, const char *name)
999 {
1000 struct grub_fat_data *data = 0;
1001 grub_fshelp_node_t found = NULL;
1002 grub_err_t err;
1003 grub_disk_t disk = file->device->disk;
1004
1005 grub_dl_ref (my_mod);
1006
1007 data = grub_fat_mount (disk);
1008 if (! data)
1009 goto fail;
1010
1011 struct grub_fshelp_node root = {
1012 .data = data,
1013 .disk = disk,
1014 .attr = GRUB_FAT_ATTR_DIRECTORY,
1015 .file_size = 0,
1016 .file_cluster = data->root_cluster,
1017 .cur_cluster_num = ~0U,
1018 .cur_cluster = 0,
1019 #ifdef MODE_EXFAT
1020 .is_contiguous = 0,
1021 #endif
1022 };
1023
1024 err = grub_fshelp_find_file_lookup (name, &root, &found, lookup_file, NULL, GRUB_FSHELP_REG);
1025 if (err)
1026 goto fail;
1027
1028 file->data = found;
1029 file->size = found->file_size;
1030
1031 return GRUB_ERR_NONE;
1032
1033 fail:
1034
1035 if (found != &root)
1036 grub_free (found);
1037
1038 grub_free (data);
1039
1040 grub_dl_unref (my_mod);
1041
1042 return grub_errno;
1043 }
1044
1045 static grub_ssize_t
1046 grub_fat_read (grub_file_t file, char *buf, grub_size_t len)
1047 {
1048 return grub_fat_read_data (file->device->disk, file->data,
1049 file->read_hook, file->read_hook_data,
1050 file->offset, len, buf);
1051 }
1052
1053 static grub_err_t
1054 grub_fat_close (grub_file_t file)
1055 {
1056 grub_fshelp_node_t node = file->data;
1057
1058 grub_free (node->data);
1059 grub_free (node);
1060
1061 grub_dl_unref (my_mod);
1062
1063 return grub_errno;
1064 }
1065
1066 #ifdef MODE_EXFAT
1067 static grub_err_t
1068 grub_fat_label (grub_device_t device, char **label)
1069 {
1070 struct grub_fat_dir_entry dir;
1071 grub_ssize_t offset = -sizeof(dir);
1072 grub_disk_t disk = device->disk;
1073 struct grub_fshelp_node root = {
1074 .disk = disk,
1075 .attr = GRUB_FAT_ATTR_DIRECTORY,
1076 .file_size = 0,
1077 .cur_cluster_num = ~0U,
1078 .cur_cluster = 0,
1079 .is_contiguous = 0,
1080 };
1081
1082 root.data = grub_fat_mount (disk);
1083 if (! root.data)
1084 return grub_errno;
1085
1086 root.file_cluster = root.data->root_cluster;
1087
1088 *label = NULL;
1089
1090 while (1)
1091 {
1092 offset += sizeof (dir);
1093
1094 if (grub_fat_read_data (disk, &root, 0, 0,
1095 offset, sizeof (dir), (char *) &dir)
1096 != sizeof (dir))
1097 break;
1098
1099 if (dir.entry_type == 0)
1100 break;
1101 if (!(dir.entry_type & 0x80))
1102 continue;
1103
1104 /* Volume label. */
1105 if (dir.entry_type == 0x83)
1106 {
1107 grub_size_t chc;
1108 grub_uint16_t t[ARRAY_SIZE (dir.type_specific.volume_label.str)];
1109 grub_size_t i;
1110 *label = grub_malloc (ARRAY_SIZE (dir.type_specific.volume_label.str)
1111 * GRUB_MAX_UTF8_PER_UTF16 + 1);
1112 if (!*label)
1113 {
1114 grub_free (root.data);
1115 return grub_errno;
1116 }
1117 chc = dir.type_specific.volume_label.character_count;
1118 if (chc > ARRAY_SIZE (dir.type_specific.volume_label.str))
1119 chc = ARRAY_SIZE (dir.type_specific.volume_label.str);
1120 for (i = 0; i < chc; i++)
1121 t[i] = grub_le_to_cpu16 (dir.type_specific.volume_label.str[i]);
1122 *grub_utf16_to_utf8 ((grub_uint8_t *) *label, t, chc) = '\0';
1123 }
1124 }
1125
1126 grub_free (root.data);
1127 return grub_errno;
1128 }
1129
1130 #else
1131
1132 static grub_err_t
1133 grub_fat_label (grub_device_t device, char **label)
1134 {
1135 grub_disk_t disk = device->disk;
1136 grub_err_t err;
1137 struct grub_fat_iterate_context ctxt;
1138 struct grub_fshelp_node root = {
1139 .disk = disk,
1140 .attr = GRUB_FAT_ATTR_DIRECTORY,
1141 .file_size = 0,
1142 .cur_cluster_num = ~0U,
1143 .cur_cluster = 0,
1144 };
1145
1146 *label = 0;
1147
1148 grub_dl_ref (my_mod);
1149
1150 root.data = grub_fat_mount (disk);
1151 if (! root.data)
1152 goto fail;
1153
1154 root.file_cluster = root.data->root_cluster;
1155
1156 err = grub_fat_iterate_init (&ctxt);
1157 if (err)
1158 goto fail;
1159
1160 while (!(err = grub_fat_iterate_dir_next (&root, &ctxt)))
1161 if ((ctxt.dir.attr & ~GRUB_FAT_ATTR_ARCHIVE) == GRUB_FAT_ATTR_VOLUME_ID)
1162 {
1163 *label = grub_strdup (ctxt.filename);
1164 break;
1165 }
1166
1167 grub_fat_iterate_fini (&ctxt);
1168
1169 fail:
1170
1171 grub_dl_unref (my_mod);
1172
1173 grub_free (root.data);
1174
1175 return grub_errno;
1176 }
1177
1178 #endif
1179
1180 static grub_err_t
1181 grub_fat_uuid (grub_device_t device, char **uuid)
1182 {
1183 struct grub_fat_data *data;
1184 grub_disk_t disk = device->disk;
1185
1186 grub_dl_ref (my_mod);
1187
1188 data = grub_fat_mount (disk);
1189 if (data)
1190 {
1191 char *ptr;
1192 *uuid = grub_xasprintf ("%04x-%04x",
1193 (grub_uint16_t) (data->uuid >> 16),
1194 (grub_uint16_t) data->uuid);
1195 for (ptr = *uuid; ptr && *ptr; ptr++)
1196 *ptr = grub_toupper (*ptr);
1197 }
1198 else
1199 *uuid = NULL;
1200
1201 grub_dl_unref (my_mod);
1202
1203 grub_free (data);
1204
1205 return grub_errno;
1206 }
1207
1208 #ifdef GRUB_UTIL
1209 #ifndef MODE_EXFAT
1210 grub_disk_addr_t
1211 grub_fat_get_cluster_sector (grub_disk_t disk, grub_uint64_t *sec_per_lcn)
1212 #else
1213 grub_disk_addr_t
1214 grub_exfat_get_cluster_sector (grub_disk_t disk, grub_uint64_t *sec_per_lcn)
1215 #endif
1216 {
1217 grub_disk_addr_t ret;
1218 struct grub_fat_data *data;
1219 data = grub_fat_mount (disk);
1220 if (!data)
1221 return 0;
1222 ret = data->cluster_sector;
1223
1224 *sec_per_lcn = 1ULL << data->cluster_bits;
1225
1226 grub_free (data);
1227 return ret;
1228 }
1229 #endif
1230
1231 static struct grub_fs grub_fat_fs =
1232 {
1233 #ifdef MODE_EXFAT
1234 .name = "exfat",
1235 #else
1236 .name = "fat",
1237 #endif
1238 .fs_dir = grub_fat_dir,
1239 .fs_open = grub_fat_open,
1240 .fs_read = grub_fat_read,
1241 .fs_close = grub_fat_close,
1242 .fs_label = grub_fat_label,
1243 .fs_uuid = grub_fat_uuid,
1244 #ifdef GRUB_UTIL
1245 #ifdef MODE_EXFAT
1246 /* ExFAT BPB is 30 larger than FAT32 one. */
1247 .reserved_first_sector = 0,
1248 #else
1249 .reserved_first_sector = 1,
1250 #endif
1251 .blocklist_install = 1,
1252 #endif
1253 .next = 0
1254 };
1255
1256 #ifdef MODE_EXFAT
1257 GRUB_MOD_INIT(exfat)
1258 #else
1259 GRUB_MOD_INIT(fat)
1260 #endif
1261 {
1262 COMPILE_TIME_ASSERT (sizeof (struct grub_fat_dir_entry) == 32);
1263 grub_fs_register (&grub_fat_fs);
1264 my_mod = mod;
1265 }
1266 #ifdef MODE_EXFAT
1267 GRUB_MOD_FINI(exfat)
1268 #else
1269 GRUB_MOD_FINI(fat)
1270 #endif
1271 {
1272 grub_fs_unregister (&grub_fat_fs);
1273 }
1274
1275 #ifdef MODE_EXFAT
1276
1277 int grub_fat_get_file_chunk(grub_uint64_t part_start, grub_file_t file, ventoy_img_chunk_list *chunk_list)
1278 {
1279 grub_size_t size;
1280 grub_uint32_t i;
1281 grub_uint32_t logical_cluster;
1282 unsigned logical_cluster_bits;
1283 unsigned long sector;
1284 grub_fshelp_node_t node;
1285 grub_disk_t disk;
1286 grub_uint64_t len;
1287
1288 disk = file->device->disk;
1289 node = file->data;
1290 len = file->size;
1291
1292 if (node->is_contiguous)
1293 {
1294 /* Read the data here. */
1295 sector = (node->data->cluster_sector + ((node->file_cluster - 2) << node->data->cluster_bits));
1296
1297 chunk_list->chunk[0].img_start_sector = 0;
1298 chunk_list->chunk[0].img_end_sector = (file->size >> 11) - 1;
1299 chunk_list->chunk[0].disk_start_sector = sector;
1300 chunk_list->chunk[0].disk_end_sector = sector + (file->size >> disk->log_sector_size) - 1;
1301 chunk_list->cur_chunk = 1;
1302
1303 goto END;
1304 }
1305
1306 /* Calculate the logical cluster number and offset. */
1307 logical_cluster = 0;
1308 logical_cluster_bits = (node->data->cluster_bits + GRUB_DISK_SECTOR_BITS);
1309
1310 if (logical_cluster < node->cur_cluster_num)
1311 {
1312 node->cur_cluster_num = 0;
1313 node->cur_cluster = node->file_cluster;
1314 }
1315
1316 while (len)
1317 {
1318 while (logical_cluster > node->cur_cluster_num)
1319 {
1320 /* Find next cluster. */
1321 grub_uint32_t next_cluster;
1322 grub_uint32_t fat_offset;
1323
1324 switch (node->data->fat_size)
1325 {
1326 case 32:
1327 fat_offset = node->cur_cluster << 2;
1328 break;
1329 case 16:
1330 fat_offset = node->cur_cluster << 1;
1331 break;
1332 default:
1333 /* case 12: */
1334 fat_offset = node->cur_cluster + (node->cur_cluster >> 1);
1335 break;
1336 }
1337
1338 /* Read the FAT. */
1339 if (grub_disk_read (disk, node->data->fat_sector, fat_offset,
1340 (node->data->fat_size + 7) >> 3,
1341 (char *) &next_cluster))
1342 {
1343 return -1;
1344 }
1345
1346 next_cluster = grub_le_to_cpu32 (next_cluster);
1347 switch (node->data->fat_size)
1348 {
1349 case 16:
1350 next_cluster &= 0xFFFF;
1351 break;
1352 case 12:
1353 if (node->cur_cluster & 1)
1354 next_cluster >>= 4;
1355
1356 next_cluster &= 0x0FFF;
1357 break;
1358 }
1359
1360 grub_dprintf ("fat", "fat_size=%d, next_cluster=%u\n", node->data->fat_size, next_cluster);
1361
1362 /* Check the end. */
1363 if (next_cluster >= node->data->cluster_eof_mark)
1364 {
1365 return 0;
1366 }
1367
1368 if (next_cluster < 2 || (next_cluster - 2) >= node->data->num_clusters)
1369 {
1370 grub_error (GRUB_ERR_BAD_FS, "invalid cluster %u", next_cluster);
1371 return -1;
1372 }
1373
1374 node->cur_cluster = next_cluster;
1375 node->cur_cluster_num++;
1376 }
1377
1378 /* Read the data here. */
1379 sector = (node->data->cluster_sector
1380 + ((node->cur_cluster - 2)
1381 << node->data->cluster_bits));
1382 size = (1 << logical_cluster_bits);
1383 if (size > len)
1384 size = len;
1385
1386 grub_disk_blocklist_read(chunk_list, sector, size, disk->log_sector_size);
1387
1388 len -= size;
1389 logical_cluster++;
1390 }
1391
1392 END:
1393
1394 for (i = 0; i < chunk_list->cur_chunk; i++)
1395 {
1396 chunk_list->chunk[i].disk_start_sector += part_start;
1397 chunk_list->chunk[i].disk_end_sector += part_start;
1398 }
1399
1400 return 0;
1401 }
1402
1403 #endif