Indentation fix, cleanup.
[AROS.git] / arch / all-pc / boot / grub2-aros / grub-core / fs / fat.c
blob71537ff4458b7717dbab564049b396b52e51b809
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.
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.
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.
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/>.
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/i18n.h>
36 GRUB_MOD_LICENSE ("GPLv3+");
38 enum
40 GRUB_FAT_ATTR_READ_ONLY = 0x01,
41 GRUB_FAT_ATTR_HIDDEN = 0x02,
42 GRUB_FAT_ATTR_SYSTEM = 0x04,
43 #ifndef MODE_EXFAT
44 GRUB_FAT_ATTR_VOLUME_ID = 0x08,
45 #endif
46 GRUB_FAT_ATTR_DIRECTORY = 0x10,
47 GRUB_FAT_ATTR_ARCHIVE = 0x20,
49 #ifndef MODE_EXFAT
50 GRUB_FAT_ATTR_LONG_NAME = (GRUB_FAT_ATTR_READ_ONLY
51 | GRUB_FAT_ATTR_HIDDEN
52 | GRUB_FAT_ATTR_SYSTEM
53 | GRUB_FAT_ATTR_VOLUME_ID),
54 #endif
55 GRUB_FAT_ATTR_VALID = (GRUB_FAT_ATTR_READ_ONLY
56 | GRUB_FAT_ATTR_HIDDEN
57 | GRUB_FAT_ATTR_SYSTEM
58 | GRUB_FAT_ATTR_DIRECTORY
59 | GRUB_FAT_ATTR_ARCHIVE
60 #ifndef MODE_EXFAT
61 | GRUB_FAT_ATTR_VOLUME_ID
62 #endif
66 #ifdef MODE_EXFAT
67 typedef struct grub_exfat_bpb grub_current_fat_bpb_t;
68 #else
69 typedef struct grub_fat_bpb grub_current_fat_bpb_t;
70 #endif
72 #ifdef MODE_EXFAT
73 enum
75 FLAG_CONTIGUOUS = 2
77 struct grub_fat_dir_entry
79 grub_uint8_t entry_type;
80 union
82 grub_uint8_t placeholder[31];
83 struct {
84 grub_uint8_t secondary_count;
85 grub_uint16_t checksum;
86 grub_uint16_t attr;
87 grub_uint16_t reserved1;
88 grub_uint32_t c_time;
89 grub_uint32_t m_time;
90 grub_uint32_t a_time;
91 grub_uint8_t c_time_tenth;
92 grub_uint8_t m_time_tenth;
93 grub_uint8_t a_time_tenth;
94 grub_uint8_t reserved2[9];
95 } GRUB_PACKED file;
96 struct {
97 grub_uint8_t flags;
98 grub_uint8_t reserved1;
99 grub_uint8_t name_length;
100 grub_uint16_t name_hash;
101 grub_uint16_t reserved2;
102 grub_uint64_t valid_size;
103 grub_uint32_t reserved3;
104 grub_uint32_t first_cluster;
105 grub_uint64_t file_size;
106 } GRUB_PACKED stream_extension;
107 struct {
108 grub_uint8_t flags;
109 grub_uint16_t str[15];
110 } GRUB_PACKED file_name;
111 struct {
112 grub_uint8_t character_count;
113 grub_uint16_t str[15];
114 } GRUB_PACKED volume_label;
115 } GRUB_PACKED type_specific;
116 } GRUB_PACKED;
118 struct grub_fat_dir_node
120 grub_uint32_t attr;
121 grub_uint32_t first_cluster;
122 grub_uint64_t file_size;
123 grub_uint64_t valid_size;
124 int have_stream;
125 int is_contiguous;
128 typedef struct grub_fat_dir_node grub_fat_dir_node_t;
130 #else
131 struct grub_fat_dir_entry
133 grub_uint8_t name[11];
134 grub_uint8_t attr;
135 grub_uint8_t nt_reserved;
136 grub_uint8_t c_time_tenth;
137 grub_uint16_t c_time;
138 grub_uint16_t c_date;
139 grub_uint16_t a_date;
140 grub_uint16_t first_cluster_high;
141 grub_uint16_t w_time;
142 grub_uint16_t w_date;
143 grub_uint16_t first_cluster_low;
144 grub_uint32_t file_size;
145 } GRUB_PACKED;
147 struct grub_fat_long_name_entry
149 grub_uint8_t id;
150 grub_uint16_t name1[5];
151 grub_uint8_t attr;
152 grub_uint8_t reserved;
153 grub_uint8_t checksum;
154 grub_uint16_t name2[6];
155 grub_uint16_t first_cluster;
156 grub_uint16_t name3[2];
157 } GRUB_PACKED;
159 typedef struct grub_fat_dir_entry grub_fat_dir_node_t;
161 #endif
163 struct grub_fat_data
165 int logical_sector_bits;
166 grub_uint32_t num_sectors;
168 grub_uint32_t fat_sector;
169 grub_uint32_t sectors_per_fat;
170 int fat_size;
172 grub_uint32_t root_cluster;
173 #ifndef MODE_EXFAT
174 grub_uint32_t root_sector;
175 grub_uint32_t num_root_sectors;
176 #else
177 int is_contiguous;
178 #endif
180 int cluster_bits;
181 grub_uint32_t cluster_eof_mark;
182 grub_uint32_t cluster_sector;
183 grub_uint32_t num_clusters;
185 grub_uint8_t attr;
186 grub_ssize_t file_size;
187 grub_uint32_t file_cluster;
188 grub_uint32_t cur_cluster_num;
189 grub_uint32_t cur_cluster;
191 grub_uint32_t uuid;
194 static grub_dl_t my_mod;
196 #ifndef MODE_EXFAT
197 static int
198 fat_log2 (unsigned x)
200 int i;
202 if (x == 0)
203 return -1;
205 for (i = 0; (x & 1) == 0; i++)
206 x >>= 1;
208 if (x != 1)
209 return -1;
211 return i;
213 #endif
215 static struct grub_fat_data *
216 grub_fat_mount (grub_disk_t disk)
218 grub_current_fat_bpb_t bpb;
219 struct grub_fat_data *data = 0;
220 grub_uint32_t first_fat, magic;
222 if (! disk)
223 goto fail;
225 data = (struct grub_fat_data *) grub_malloc (sizeof (*data));
226 if (! data)
227 goto fail;
229 /* Read the BPB. */
230 if (grub_disk_read (disk, 0, 0, sizeof (bpb), &bpb))
231 goto fail;
233 #ifdef MODE_EXFAT
234 if (grub_memcmp ((const char *) bpb.oem_name, "EXFAT ",
235 sizeof (bpb.oem_name)) != 0)
236 goto fail;
237 #endif
239 /* Get the sizes of logical sectors and clusters. */
240 #ifdef MODE_EXFAT
241 data->logical_sector_bits = bpb.bytes_per_sector_shift;
242 #else
243 data->logical_sector_bits =
244 fat_log2 (grub_le_to_cpu16 (bpb.bytes_per_sector));
245 #endif
246 if (data->logical_sector_bits < GRUB_DISK_SECTOR_BITS
247 || data->logical_sector_bits >= 16)
248 goto fail;
249 data->logical_sector_bits -= GRUB_DISK_SECTOR_BITS;
251 #ifdef MODE_EXFAT
252 data->cluster_bits = bpb.sectors_per_cluster_shift;
253 #else
254 data->cluster_bits = fat_log2 (bpb.sectors_per_cluster);
255 #endif
256 if (data->cluster_bits < 0 || data->cluster_bits > 25)
257 goto fail;
258 data->cluster_bits += data->logical_sector_bits;
260 /* Get information about FATs. */
261 #ifdef MODE_EXFAT
262 data->fat_sector = (grub_le_to_cpu32 (bpb.num_reserved_sectors)
263 << data->logical_sector_bits);
264 #else
265 data->fat_sector = (grub_le_to_cpu16 (bpb.num_reserved_sectors)
266 << data->logical_sector_bits);
267 #endif
268 if (data->fat_sector == 0)
269 goto fail;
271 #ifdef MODE_EXFAT
272 data->sectors_per_fat = (grub_le_to_cpu32 (bpb.sectors_per_fat)
273 << data->logical_sector_bits);
274 #else
275 data->sectors_per_fat = ((bpb.sectors_per_fat_16
276 ? grub_le_to_cpu16 (bpb.sectors_per_fat_16)
277 : grub_le_to_cpu32 (bpb.version_specific.fat32.sectors_per_fat_32))
278 << data->logical_sector_bits);
279 #endif
280 if (data->sectors_per_fat == 0)
281 goto fail;
283 /* Get the number of sectors in this volume. */
284 #ifdef MODE_EXFAT
285 data->num_sectors = ((grub_le_to_cpu64 (bpb.num_total_sectors))
286 << data->logical_sector_bits);
287 #else
288 data->num_sectors = ((bpb.num_total_sectors_16
289 ? grub_le_to_cpu16 (bpb.num_total_sectors_16)
290 : grub_le_to_cpu32 (bpb.num_total_sectors_32))
291 << data->logical_sector_bits);
292 #endif
293 if (data->num_sectors == 0)
294 goto fail;
296 /* Get information about the root directory. */
297 if (bpb.num_fats == 0)
298 goto fail;
300 #ifndef MODE_EXFAT
301 data->root_sector = data->fat_sector + bpb.num_fats * data->sectors_per_fat;
302 data->num_root_sectors
303 = ((((grub_uint32_t) grub_le_to_cpu16 (bpb.num_root_entries)
304 * sizeof (struct grub_fat_dir_entry)
305 + grub_le_to_cpu16 (bpb.bytes_per_sector) - 1)
306 >> (data->logical_sector_bits + GRUB_DISK_SECTOR_BITS))
307 << (data->logical_sector_bits));
308 #endif
310 #ifdef MODE_EXFAT
311 data->cluster_sector = (grub_le_to_cpu32 (bpb.cluster_offset)
312 << data->logical_sector_bits);
313 data->num_clusters = (grub_le_to_cpu32 (bpb.cluster_count)
314 << data->logical_sector_bits);
315 #else
316 data->cluster_sector = data->root_sector + data->num_root_sectors;
317 data->num_clusters = (((data->num_sectors - data->cluster_sector)
318 >> data->cluster_bits)
319 + 2);
320 #endif
322 if (data->num_clusters <= 2)
323 goto fail;
325 #ifdef MODE_EXFAT
327 /* exFAT. */
328 data->root_cluster = grub_le_to_cpu32 (bpb.root_cluster);
329 data->fat_size = 32;
330 data->cluster_eof_mark = 0xffffffff;
332 if ((bpb.volume_flags & grub_cpu_to_le16_compile_time (0x1))
333 && bpb.num_fats > 1)
334 data->fat_sector += data->sectors_per_fat;
336 #else
337 if (! bpb.sectors_per_fat_16)
339 /* FAT32. */
340 grub_uint16_t flags = grub_le_to_cpu16 (bpb.version_specific.fat32.extended_flags);
342 data->root_cluster = grub_le_to_cpu32 (bpb.version_specific.fat32.root_cluster);
343 data->fat_size = 32;
344 data->cluster_eof_mark = 0x0ffffff8;
346 if (flags & 0x80)
348 /* Get an active FAT. */
349 unsigned active_fat = flags & 0xf;
351 if (active_fat > bpb.num_fats)
352 goto fail;
354 data->fat_sector += active_fat * data->sectors_per_fat;
357 if (bpb.num_root_entries != 0 || bpb.version_specific.fat32.fs_version != 0)
358 goto fail;
360 else
362 /* FAT12 or FAT16. */
363 data->root_cluster = ~0U;
365 if (data->num_clusters <= 4085 + 2)
367 /* FAT12. */
368 data->fat_size = 12;
369 data->cluster_eof_mark = 0x0ff8;
371 else
373 /* FAT16. */
374 data->fat_size = 16;
375 data->cluster_eof_mark = 0xfff8;
378 #endif
380 /* More sanity checks. */
381 if (data->num_sectors <= data->fat_sector)
382 goto fail;
384 if (grub_disk_read (disk,
385 data->fat_sector,
387 sizeof (first_fat),
388 &first_fat))
389 goto fail;
391 first_fat = grub_le_to_cpu32 (first_fat);
393 if (data->fat_size == 32)
395 first_fat &= 0x0fffffff;
396 magic = 0x0fffff00;
398 else if (data->fat_size == 16)
400 first_fat &= 0x0000ffff;
401 magic = 0xff00;
403 else
405 first_fat &= 0x00000fff;
406 magic = 0x0f00;
409 /* Serial number. */
410 #ifdef MODE_EXFAT
411 data->uuid = grub_le_to_cpu32 (bpb.num_serial);
412 #else
413 if (bpb.sectors_per_fat_16)
414 data->uuid = grub_le_to_cpu32 (bpb.version_specific.fat12_or_fat16.num_serial);
415 else
416 data->uuid = grub_le_to_cpu32 (bpb.version_specific.fat32.num_serial);
417 #endif
419 #ifndef MODE_EXFAT
420 /* Ignore the 3rd bit, because some BIOSes assigns 0xF0 to the media
421 descriptor, even if it is a so-called superfloppy (e.g. an USB key).
422 The check may be too strict for this kind of stupid BIOSes, as
423 they overwrite the media descriptor. */
424 if ((first_fat | 0x8) != (magic | bpb.media | 0x8))
425 goto fail;
426 #else
427 (void) magic;
428 #endif
430 /* Start from the root directory. */
431 data->file_cluster = data->root_cluster;
432 data->cur_cluster_num = ~0U;
433 data->attr = GRUB_FAT_ATTR_DIRECTORY;
434 #ifdef MODE_EXFAT
435 data->is_contiguous = 0;
436 #endif
437 return data;
439 fail:
441 grub_free (data);
442 grub_error (GRUB_ERR_BAD_FS, "not a FAT filesystem");
443 return 0;
446 static grub_ssize_t
447 grub_fat_read_data (grub_disk_t disk, struct grub_fat_data *data,
448 grub_disk_read_hook_t read_hook, void *read_hook_data,
449 grub_off_t offset, grub_size_t len, char *buf)
451 grub_size_t size;
452 grub_uint32_t logical_cluster;
453 unsigned logical_cluster_bits;
454 grub_ssize_t ret = 0;
455 unsigned long sector;
457 #ifndef MODE_EXFAT
458 /* This is a special case. FAT12 and FAT16 doesn't have the root directory
459 in clusters. */
460 if (data->file_cluster == ~0U)
462 size = (data->num_root_sectors << GRUB_DISK_SECTOR_BITS) - offset;
463 if (size > len)
464 size = len;
466 if (grub_disk_read (disk, data->root_sector, offset, size, buf))
467 return -1;
469 return size;
471 #endif
473 #ifdef MODE_EXFAT
474 if (data->is_contiguous)
476 /* Read the data here. */
477 sector = (data->cluster_sector
478 + ((data->file_cluster - 2)
479 << data->cluster_bits));
481 disk->read_hook = read_hook;
482 disk->read_hook_data = read_hook_data;
483 grub_disk_read (disk, sector + (offset >> GRUB_DISK_SECTOR_BITS),
484 offset & (GRUB_DISK_SECTOR_SIZE - 1), len, buf);
485 disk->read_hook = 0;
486 if (grub_errno)
487 return -1;
489 return len;
491 #endif
493 /* Calculate the logical cluster number and offset. */
494 logical_cluster_bits = (data->cluster_bits
495 + GRUB_DISK_SECTOR_BITS);
496 logical_cluster = offset >> logical_cluster_bits;
497 offset &= (1ULL << logical_cluster_bits) - 1;
499 if (logical_cluster < data->cur_cluster_num)
501 data->cur_cluster_num = 0;
502 data->cur_cluster = data->file_cluster;
505 while (len)
507 while (logical_cluster > data->cur_cluster_num)
509 /* Find next cluster. */
510 grub_uint32_t next_cluster;
511 grub_uint32_t fat_offset;
513 switch (data->fat_size)
515 case 32:
516 fat_offset = data->cur_cluster << 2;
517 break;
518 case 16:
519 fat_offset = data->cur_cluster << 1;
520 break;
521 default:
522 /* case 12: */
523 fat_offset = data->cur_cluster + (data->cur_cluster >> 1);
524 break;
527 /* Read the FAT. */
528 if (grub_disk_read (disk, data->fat_sector, fat_offset,
529 (data->fat_size + 7) >> 3,
530 (char *) &next_cluster))
531 return -1;
533 next_cluster = grub_le_to_cpu32 (next_cluster);
534 switch (data->fat_size)
536 case 16:
537 next_cluster &= 0xFFFF;
538 break;
539 case 12:
540 if (data->cur_cluster & 1)
541 next_cluster >>= 4;
543 next_cluster &= 0x0FFF;
544 break;
547 grub_dprintf ("fat", "fat_size=%d, next_cluster=%u\n",
548 data->fat_size, next_cluster);
550 /* Check the end. */
551 if (next_cluster >= data->cluster_eof_mark)
552 return ret;
554 if (next_cluster < 2 || next_cluster >= data->num_clusters)
556 grub_error (GRUB_ERR_BAD_FS, "invalid cluster %u",
557 next_cluster);
558 return -1;
561 data->cur_cluster = next_cluster;
562 data->cur_cluster_num++;
565 /* Read the data here. */
566 sector = (data->cluster_sector
567 + ((data->cur_cluster - 2)
568 << data->cluster_bits));
569 size = (1 << logical_cluster_bits) - offset;
570 if (size > len)
571 size = len;
573 disk->read_hook = read_hook;
574 disk->read_hook_data = read_hook_data;
575 grub_disk_read (disk, sector, offset, size, buf);
576 disk->read_hook = 0;
577 if (grub_errno)
578 return -1;
580 len -= size;
581 buf += size;
582 ret += size;
583 logical_cluster++;
584 offset = 0;
587 return ret;
590 struct grub_fat_iterate_context
592 #ifdef MODE_EXFAT
593 struct grub_fat_dir_node dir;
594 #else
595 struct grub_fat_dir_entry dir;
596 #endif
597 char *filename;
598 grub_uint16_t *unibuf;
599 grub_ssize_t offset;
602 static grub_err_t
603 grub_fat_iterate_init (struct grub_fat_iterate_context *ctxt)
605 ctxt->offset = -sizeof (struct grub_fat_dir_entry);
607 #ifndef MODE_EXFAT
608 /* Allocate space enough to hold a long name. */
609 ctxt->filename = grub_malloc (0x40 * 13 * GRUB_MAX_UTF8_PER_UTF16 + 1);
610 ctxt->unibuf = (grub_uint16_t *) grub_malloc (0x40 * 13 * 2);
611 #else
612 ctxt->unibuf = grub_malloc (15 * 256 * 2);
613 ctxt->filename = grub_malloc (15 * 256 * GRUB_MAX_UTF8_PER_UTF16 + 1);
614 #endif
616 if (! ctxt->filename || ! ctxt->unibuf)
618 grub_free (ctxt->filename);
619 grub_free (ctxt->unibuf);
620 return grub_errno;
622 return GRUB_ERR_NONE;
625 static void
626 grub_fat_iterate_fini (struct grub_fat_iterate_context *ctxt)
628 grub_free (ctxt->filename);
629 grub_free (ctxt->unibuf);
632 #ifdef MODE_EXFAT
633 static grub_err_t
634 grub_fat_iterate_dir_next (grub_disk_t disk, struct grub_fat_data *data,
635 struct grub_fat_iterate_context *ctxt)
637 grub_memset (&ctxt->dir, 0, sizeof (ctxt->dir));
638 while (1)
640 struct grub_fat_dir_entry dir;
642 ctxt->offset += sizeof (dir);
644 if (grub_fat_read_data (disk, data, 0, 0, ctxt->offset, sizeof (dir),
645 (char *) &dir)
646 != sizeof (dir))
647 break;
649 if (dir.entry_type == 0)
650 break;
651 if (!(dir.entry_type & 0x80))
652 continue;
654 if (dir.entry_type == 0x85)
656 unsigned i, nsec, slots = 0;
658 nsec = dir.type_specific.file.secondary_count;
660 ctxt->dir.attr = grub_cpu_to_le16 (dir.type_specific.file.attr);
661 ctxt->dir.have_stream = 0;
662 for (i = 0; i < nsec; i++)
664 struct grub_fat_dir_entry sec;
665 ctxt->offset += sizeof (sec);
666 if (grub_fat_read_data (disk, data, 0, 0,
667 ctxt->offset, sizeof (sec), (char *) &sec)
668 != sizeof (sec))
669 break;
670 if (!(sec.entry_type & 0x80))
671 continue;
672 if (!(sec.entry_type & 0x40))
673 break;
674 switch (sec.entry_type)
676 case 0xc0:
677 ctxt->dir.first_cluster = grub_cpu_to_le32 (sec.type_specific.stream_extension.first_cluster);
678 ctxt->dir.valid_size
679 = grub_cpu_to_le64 (sec.type_specific.stream_extension.valid_size);
680 ctxt->dir.file_size
681 = grub_cpu_to_le64 (sec.type_specific.stream_extension.file_size);
682 ctxt->dir.have_stream = 1;
683 ctxt->dir.is_contiguous = !!(dir.type_specific.stream_extension.flags
684 & grub_cpu_to_le16_compile_time (FLAG_CONTIGUOUS));
685 break;
686 case 0xc1:
688 int j;
689 for (j = 0; j < 15; j++)
690 ctxt->unibuf[slots * 15 + j]
691 = grub_le_to_cpu16 (sec.type_specific.file_name.str[j]);
692 slots++;
694 break;
695 default:
696 grub_dprintf ("exfat", "unknown secondary type 0x%02x\n",
697 sec.entry_type);
701 if (i != nsec)
703 ctxt->offset -= sizeof (dir);
704 continue;
707 *grub_utf16_to_utf8 ((grub_uint8_t *) ctxt->filename, ctxt->unibuf,
708 slots * 15) = '\0';
710 return 0;
712 /* Allocation bitmap. */
713 if (dir.entry_type == 0x81)
714 continue;
715 /* Upcase table. */
716 if (dir.entry_type == 0x82)
717 continue;
718 /* Volume label. */
719 if (dir.entry_type == 0x83)
720 continue;
721 grub_dprintf ("exfat", "unknown primary type 0x%02x\n",
722 dir.entry_type);
724 return grub_errno ? : GRUB_ERR_EOF;
727 #else
729 static grub_err_t
730 grub_fat_iterate_dir_next (grub_disk_t disk, struct grub_fat_data *data,
731 struct grub_fat_iterate_context *ctxt)
733 char *filep = 0;
734 int checksum = -1;
735 int slot = -1, slots = -1;
737 while (1)
739 unsigned i;
741 /* Adjust the offset. */
742 ctxt->offset += sizeof (ctxt->dir);
744 /* Read a directory entry. */
745 if (grub_fat_read_data (disk, data, 0, 0,
746 ctxt->offset, sizeof (ctxt->dir),
747 (char *) &ctxt->dir)
748 != sizeof (ctxt->dir) || ctxt->dir.name[0] == 0)
749 break;
751 /* Handle long name entries. */
752 if (ctxt->dir.attr == GRUB_FAT_ATTR_LONG_NAME)
754 struct grub_fat_long_name_entry *long_name
755 = (struct grub_fat_long_name_entry *) &ctxt->dir;
756 grub_uint8_t id = long_name->id;
758 if (id & 0x40)
760 id &= 0x3f;
761 slots = slot = id;
762 checksum = long_name->checksum;
765 if (id != slot || slot == 0 || checksum != long_name->checksum)
767 checksum = -1;
768 continue;
771 slot--;
772 grub_memcpy (ctxt->unibuf + slot * 13, long_name->name1, 5 * 2);
773 grub_memcpy (ctxt->unibuf + slot * 13 + 5, long_name->name2, 6 * 2);
774 grub_memcpy (ctxt->unibuf + slot * 13 + 11, long_name->name3, 2 * 2);
775 continue;
778 /* Check if this entry is valid. */
779 if (ctxt->dir.name[0] == 0xe5 || (ctxt->dir.attr & ~GRUB_FAT_ATTR_VALID))
780 continue;
782 /* This is a workaround for Japanese. */
783 if (ctxt->dir.name[0] == 0x05)
784 ctxt->dir.name[0] = 0xe5;
786 if (checksum != -1 && slot == 0)
788 grub_uint8_t sum;
790 for (sum = 0, i = 0; i < sizeof (ctxt->dir.name); i++)
791 sum = ((sum >> 1) | (sum << 7)) + ctxt->dir.name[i];
793 if (sum == checksum)
795 int u;
797 for (u = 0; u < slots * 13; u++)
798 ctxt->unibuf[u] = grub_le_to_cpu16 (ctxt->unibuf[u]);
800 *grub_utf16_to_utf8 ((grub_uint8_t *) ctxt->filename,
801 ctxt->unibuf,
802 slots * 13) = '\0';
804 return GRUB_ERR_NONE;
807 checksum = -1;
810 /* Convert the 8.3 file name. */
811 filep = ctxt->filename;
812 if (ctxt->dir.attr & GRUB_FAT_ATTR_VOLUME_ID)
814 for (i = 0; i < sizeof (ctxt->dir.name) && ctxt->dir.name[i]; i++)
815 *filep++ = ctxt->dir.name[i];
816 while (i > 0 && ctxt->dir.name[i - 1] == ' ')
818 filep--;
819 i--;
822 else
824 for (i = 0; i < 8 && ctxt->dir.name[i]; i++)
825 *filep++ = grub_tolower (ctxt->dir.name[i]);
826 while (i > 0 && ctxt->dir.name[i - 1] == ' ')
828 filep--;
829 i--;
832 *filep++ = '.';
834 for (i = 8; i < 11 && ctxt->dir.name[i]; i++)
835 *filep++ = grub_tolower (ctxt->dir.name[i]);
836 while (i > 8 && ctxt->dir.name[i - 1] == ' ')
838 filep--;
839 i--;
842 if (i == 8)
843 filep--;
845 *filep = '\0';
846 return GRUB_ERR_NONE;
849 return grub_errno ? : GRUB_ERR_EOF;
852 #endif
854 /* Find the underlying directory or file in PATH and return the
855 next path. If there is no next path or an error occurs, return NULL.
856 If HOOK is specified, call it with each file name. */
857 static char *
858 grub_fat_find_dir (grub_disk_t disk, struct grub_fat_data *data,
859 const char *path, const char *origpath,
860 grub_fs_dir_hook_t hook, void *hook_data)
862 char *dirname, *dirp;
863 int call_hook;
864 int found = 0;
865 struct grub_fat_iterate_context ctxt;
866 grub_err_t err;
868 if (! (data->attr & GRUB_FAT_ATTR_DIRECTORY))
870 grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a directory"));
871 return 0;
874 /* Extract a directory name. */
875 while (*path == '/')
876 path++;
878 dirp = grub_strchr (path, '/');
879 if (dirp)
881 unsigned len = dirp - path;
883 dirname = grub_malloc (len + 1);
884 if (! dirname)
885 goto fail;
887 grub_memcpy (dirname, path, len);
888 dirname[len] = '\0';
890 else
891 /* This is actually a file. */
892 dirname = grub_strdup (path);
894 call_hook = (! dirp && hook);
896 err = grub_fat_iterate_init (&ctxt);
897 if (err)
899 grub_free (dirname);
900 return 0;
903 while (!(err = grub_fat_iterate_dir_next (disk, data, &ctxt)))
905 struct grub_dirhook_info info;
906 grub_memset (&info, 0, sizeof (info));
908 info.dir = !! (ctxt.dir.attr & GRUB_FAT_ATTR_DIRECTORY);
909 info.case_insensitive = 1;
911 #ifdef MODE_EXFAT
912 if (!ctxt.dir.have_stream)
913 continue;
914 #else
915 if (ctxt.dir.attr & GRUB_FAT_ATTR_VOLUME_ID)
916 continue;
917 #endif
918 if (*dirname == '\0' && call_hook)
920 if (hook (ctxt.filename, &info, hook_data))
921 break;
922 else
923 continue;
926 if (grub_strcasecmp (dirname, ctxt.filename) == 0)
928 found = 1;
929 data->attr = ctxt.dir.attr;
930 #ifdef MODE_EXFAT
931 data->file_size = ctxt.dir.file_size;
932 data->file_cluster = ctxt.dir.first_cluster;
933 data->is_contiguous = ctxt.dir.is_contiguous;
934 #else
935 data->file_size = grub_le_to_cpu32 (ctxt.dir.file_size);
936 data->file_cluster = ((grub_le_to_cpu16 (ctxt.dir.first_cluster_high) << 16)
937 | grub_le_to_cpu16 (ctxt.dir.first_cluster_low));
938 #endif
939 data->cur_cluster_num = ~0U;
941 if (call_hook)
942 hook (ctxt.filename, &info, hook_data);
944 break;
948 grub_fat_iterate_fini (&ctxt);
949 if (err == GRUB_ERR_EOF)
950 err = 0;
952 if (grub_errno == GRUB_ERR_NONE && ! found && !call_hook)
953 grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("file `%s' not found"), origpath);
955 fail:
956 grub_free (dirname);
958 return found ? dirp : 0;
961 static grub_err_t
962 grub_fat_dir (grub_device_t device, const char *path, grub_fs_dir_hook_t hook,
963 void *hook_data)
965 struct grub_fat_data *data = 0;
966 grub_disk_t disk = device->disk;
967 grub_size_t len;
968 char *dirname = 0;
969 char *p;
971 grub_dl_ref (my_mod);
973 data = grub_fat_mount (disk);
974 if (! data)
975 goto fail;
977 /* Make sure that DIRNAME terminates with '/'. */
978 len = grub_strlen (path);
979 dirname = grub_malloc (len + 1 + 1);
980 if (! dirname)
981 goto fail;
982 grub_memcpy (dirname, path, len);
983 p = dirname + len;
984 if (path[len - 1] != '/')
985 *p++ = '/';
986 *p = '\0';
987 p = dirname;
991 p = grub_fat_find_dir (disk, data, p, path, hook, hook_data);
993 while (p && grub_errno == GRUB_ERR_NONE);
995 fail:
997 grub_free (dirname);
998 grub_free (data);
1000 grub_dl_unref (my_mod);
1002 return grub_errno;
1005 static grub_err_t
1006 grub_fat_open (grub_file_t file, const char *name)
1008 struct grub_fat_data *data = 0;
1009 char *p = (char *) name;
1011 grub_dl_ref (my_mod);
1013 data = grub_fat_mount (file->device->disk);
1014 if (! data)
1015 goto fail;
1019 p = grub_fat_find_dir (file->device->disk, data, p, name, 0, 0);
1020 if (grub_errno != GRUB_ERR_NONE)
1021 goto fail;
1023 while (p);
1025 if (data->attr & GRUB_FAT_ATTR_DIRECTORY)
1027 grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a regular file"));
1028 goto fail;
1031 file->data = data;
1032 file->size = data->file_size;
1034 return GRUB_ERR_NONE;
1036 fail:
1038 grub_free (data);
1040 grub_dl_unref (my_mod);
1042 return grub_errno;
1045 static grub_ssize_t
1046 grub_fat_read (grub_file_t file, char *buf, grub_size_t len)
1048 return grub_fat_read_data (file->device->disk, file->data,
1049 file->read_hook, file->read_hook_data,
1050 file->offset, len, buf);
1053 static grub_err_t
1054 grub_fat_close (grub_file_t file)
1056 grub_free (file->data);
1058 grub_dl_unref (my_mod);
1060 return grub_errno;
1063 #ifdef MODE_EXFAT
1064 static grub_err_t
1065 grub_fat_label (grub_device_t device, char **label)
1067 struct grub_fat_dir_entry dir;
1068 grub_ssize_t offset = -sizeof(dir);
1069 struct grub_fat_data *data;
1070 grub_disk_t disk = device->disk;
1072 data = grub_fat_mount (disk);
1073 if (! data)
1074 return grub_errno;
1076 *label = NULL;
1078 while (1)
1080 offset += sizeof (dir);
1082 if (grub_fat_read_data (disk, data, 0, 0,
1083 offset, sizeof (dir), (char *) &dir)
1084 != sizeof (dir))
1085 break;
1087 if (dir.entry_type == 0)
1088 break;
1089 if (!(dir.entry_type & 0x80))
1090 continue;
1092 /* Volume label. */
1093 if (dir.entry_type == 0x83)
1095 grub_size_t chc;
1096 grub_uint16_t t[ARRAY_SIZE (dir.type_specific.volume_label.str)];
1097 grub_size_t i;
1098 *label = grub_malloc (ARRAY_SIZE (dir.type_specific.volume_label.str)
1099 * GRUB_MAX_UTF8_PER_UTF16 + 1);
1100 if (!*label)
1102 grub_free (data);
1103 return grub_errno;
1105 chc = dir.type_specific.volume_label.character_count;
1106 if (chc > ARRAY_SIZE (dir.type_specific.volume_label.str))
1107 chc = ARRAY_SIZE (dir.type_specific.volume_label.str);
1108 for (i = 0; i < chc; i++)
1109 t[i] = grub_le_to_cpu16 (dir.type_specific.volume_label.str[i]);
1110 *grub_utf16_to_utf8 ((grub_uint8_t *) *label, t, chc) = '\0';
1114 grub_free (data);
1115 return grub_errno;
1118 #else
1120 static grub_err_t
1121 grub_fat_label (grub_device_t device, char **label)
1123 struct grub_fat_data *data;
1124 grub_disk_t disk = device->disk;
1125 grub_err_t err;
1126 struct grub_fat_iterate_context ctxt;
1128 *label = 0;
1130 grub_dl_ref (my_mod);
1132 data = grub_fat_mount (disk);
1133 if (! data)
1134 goto fail;
1136 if (! (data->attr & GRUB_FAT_ATTR_DIRECTORY))
1138 grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a directory"));
1139 goto fail;
1142 err = grub_fat_iterate_init (&ctxt);
1143 if (err)
1144 goto fail;
1146 while (!(err = grub_fat_iterate_dir_next (disk, data, &ctxt)))
1147 if ((ctxt.dir.attr & ~GRUB_FAT_ATTR_ARCHIVE) == GRUB_FAT_ATTR_VOLUME_ID)
1149 *label = grub_strdup (ctxt.filename);
1150 break;
1153 grub_fat_iterate_fini (&ctxt);
1155 fail:
1157 grub_dl_unref (my_mod);
1159 grub_free (data);
1161 return grub_errno;
1164 #endif
1166 static grub_err_t
1167 grub_fat_uuid (grub_device_t device, char **uuid)
1169 struct grub_fat_data *data;
1170 grub_disk_t disk = device->disk;
1172 grub_dl_ref (my_mod);
1174 data = grub_fat_mount (disk);
1175 if (data)
1177 char *ptr;
1178 *uuid = grub_xasprintf ("%04x-%04x",
1179 (grub_uint16_t) (data->uuid >> 16),
1180 (grub_uint16_t) data->uuid);
1181 for (ptr = *uuid; ptr && *ptr; ptr++)
1182 *ptr = grub_toupper (*ptr);
1184 else
1185 *uuid = NULL;
1187 grub_dl_unref (my_mod);
1189 grub_free (data);
1191 return grub_errno;
1194 #ifdef GRUB_UTIL
1195 #ifndef MODE_EXFAT
1196 grub_disk_addr_t
1197 grub_fat_get_cluster_sector (grub_disk_t disk, grub_uint64_t *sec_per_lcn)
1198 #else
1199 grub_disk_addr_t
1200 grub_exfat_get_cluster_sector (grub_disk_t disk, grub_uint64_t *sec_per_lcn)
1201 #endif
1203 grub_disk_addr_t ret;
1204 struct grub_fat_data *data;
1205 data = grub_fat_mount (disk);
1206 if (!data)
1207 return 0;
1208 ret = data->cluster_sector;
1210 *sec_per_lcn = 1ULL << data->cluster_bits;
1212 grub_free (data);
1213 return ret;
1215 #endif
1217 static struct grub_fs grub_fat_fs =
1219 #ifdef MODE_EXFAT
1220 .name = "exfat",
1221 #else
1222 .name = "fat",
1223 #endif
1224 .dir = grub_fat_dir,
1225 .open = grub_fat_open,
1226 .read = grub_fat_read,
1227 .close = grub_fat_close,
1228 .label = grub_fat_label,
1229 .uuid = grub_fat_uuid,
1230 #ifdef GRUB_UTIL
1231 #ifdef MODE_EXFAT
1232 /* ExFAT BPB is 30 larger than FAT32 one. */
1233 .reserved_first_sector = 0,
1234 #else
1235 .reserved_first_sector = 1,
1236 #endif
1237 .blocklist_install = 1,
1238 #endif
1239 .next = 0
1242 #ifdef MODE_EXFAT
1243 GRUB_MOD_INIT(exfat)
1244 #else
1245 GRUB_MOD_INIT(fat)
1246 #endif
1248 COMPILE_TIME_ASSERT (sizeof (struct grub_fat_dir_entry) == 32);
1249 grub_fs_register (&grub_fat_fs);
1250 my_mod = mod;
1252 #ifdef MODE_EXFAT
1253 GRUB_MOD_FINI(exfat)
1254 #else
1255 GRUB_MOD_FINI(fat)
1256 #endif
1258 grub_fs_unregister (&grub_fat_fs);