]> git.proxmox.com Git - grub2.git/blob - grub-core/fs/fat.c
Add gcc_struct to all packed structures when compiling with mingw.
[grub2.git] / 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/i18n.h>
35
36 GRUB_MOD_LICENSE ("GPLv3+");
37
38 enum
39 {
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,
48
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
63 )
64 };
65
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
71
72 #ifdef MODE_EXFAT
73 enum
74 {
75 FLAG_CONTIGUOUS = 2
76 };
77 struct grub_fat_dir_entry
78 {
79 grub_uint8_t entry_type;
80 union
81 {
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;
117
118 struct grub_fat_dir_node
119 {
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;
126 };
127
128 typedef struct grub_fat_dir_node grub_fat_dir_node_t;
129
130 #else
131 struct grub_fat_dir_entry
132 {
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;
146
147 struct grub_fat_long_name_entry
148 {
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;
158
159 typedef struct grub_fat_dir_entry grub_fat_dir_node_t;
160
161 #endif
162
163 struct grub_fat_data
164 {
165 int logical_sector_bits;
166 grub_uint32_t num_sectors;
167
168 grub_uint32_t fat_sector;
169 grub_uint32_t sectors_per_fat;
170 int fat_size;
171
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
179
180 int cluster_bits;
181 grub_uint32_t cluster_eof_mark;
182 grub_uint32_t cluster_sector;
183 grub_uint32_t num_clusters;
184
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;
190
191 grub_uint32_t uuid;
192 };
193
194 static grub_dl_t my_mod;
195
196 #ifndef MODE_EXFAT
197 static int
198 fat_log2 (unsigned x)
199 {
200 int i;
201
202 if (x == 0)
203 return -1;
204
205 for (i = 0; (x & 1) == 0; i++)
206 x >>= 1;
207
208 if (x != 1)
209 return -1;
210
211 return i;
212 }
213 #endif
214
215 static struct grub_fat_data *
216 grub_fat_mount (grub_disk_t disk)
217 {
218 grub_current_fat_bpb_t bpb;
219 struct grub_fat_data *data = 0;
220 grub_uint32_t first_fat, magic;
221
222 if (! disk)
223 goto fail;
224
225 data = (struct grub_fat_data *) grub_malloc (sizeof (*data));
226 if (! data)
227 goto fail;
228
229 /* Read the BPB. */
230 if (grub_disk_read (disk, 0, 0, sizeof (bpb), &bpb))
231 goto fail;
232
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
238
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;
250
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;
259
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;
270
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;
282
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;
295
296 /* Get information about the root directory. */
297 if (bpb.num_fats == 0)
298 goto fail;
299
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
309
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
321
322 if (data->num_clusters <= 2)
323 goto fail;
324
325 #ifdef MODE_EXFAT
326 {
327 /* exFAT. */
328 data->root_cluster = grub_le_to_cpu32 (bpb.root_cluster);
329 data->fat_size = 32;
330 data->cluster_eof_mark = 0xffffffff;
331
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;
335 }
336 #else
337 if (! bpb.sectors_per_fat_16)
338 {
339 /* FAT32. */
340 grub_uint16_t flags = grub_le_to_cpu16 (bpb.version_specific.fat32.extended_flags);
341
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;
345
346 if (flags & 0x80)
347 {
348 /* Get an active FAT. */
349 unsigned active_fat = flags & 0xf;
350
351 if (active_fat > bpb.num_fats)
352 goto fail;
353
354 data->fat_sector += active_fat * data->sectors_per_fat;
355 }
356
357 if (bpb.num_root_entries != 0 || bpb.version_specific.fat32.fs_version != 0)
358 goto fail;
359 }
360 else
361 {
362 /* FAT12 or FAT16. */
363 data->root_cluster = ~0U;
364
365 if (data->num_clusters <= 4085 + 2)
366 {
367 /* FAT12. */
368 data->fat_size = 12;
369 data->cluster_eof_mark = 0x0ff8;
370 }
371 else
372 {
373 /* FAT16. */
374 data->fat_size = 16;
375 data->cluster_eof_mark = 0xfff8;
376 }
377 }
378 #endif
379
380 /* More sanity checks. */
381 if (data->num_sectors <= data->fat_sector)
382 goto fail;
383
384 if (grub_disk_read (disk,
385 data->fat_sector,
386 0,
387 sizeof (first_fat),
388 &first_fat))
389 goto fail;
390
391 first_fat = grub_le_to_cpu32 (first_fat);
392
393 if (data->fat_size == 32)
394 {
395 first_fat &= 0x0fffffff;
396 magic = 0x0fffff00;
397 }
398 else if (data->fat_size == 16)
399 {
400 first_fat &= 0x0000ffff;
401 magic = 0xff00;
402 }
403 else
404 {
405 first_fat &= 0x00000fff;
406 magic = 0x0f00;
407 }
408
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
418
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
429
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;
438
439 fail:
440
441 grub_free (data);
442 grub_error (GRUB_ERR_BAD_FS, "not a FAT filesystem");
443 return 0;
444 }
445
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)
450 {
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;
456
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)
461 {
462 size = (data->num_root_sectors << GRUB_DISK_SECTOR_BITS) - offset;
463 if (size > len)
464 size = len;
465
466 if (grub_disk_read (disk, data->root_sector, offset, size, buf))
467 return -1;
468
469 return size;
470 }
471 #endif
472
473 #ifdef MODE_EXFAT
474 if (data->is_contiguous)
475 {
476 /* Read the data here. */
477 sector = (data->cluster_sector
478 + ((data->file_cluster - 2)
479 << data->cluster_bits));
480
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;
488
489 return len;
490 }
491 #endif
492
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;
498
499 if (logical_cluster < data->cur_cluster_num)
500 {
501 data->cur_cluster_num = 0;
502 data->cur_cluster = data->file_cluster;
503 }
504
505 while (len)
506 {
507 while (logical_cluster > data->cur_cluster_num)
508 {
509 /* Find next cluster. */
510 grub_uint32_t next_cluster;
511 grub_uint32_t fat_offset;
512
513 switch (data->fat_size)
514 {
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;
525 }
526
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;
532
533 next_cluster = grub_le_to_cpu32 (next_cluster);
534 switch (data->fat_size)
535 {
536 case 16:
537 next_cluster &= 0xFFFF;
538 break;
539 case 12:
540 if (data->cur_cluster & 1)
541 next_cluster >>= 4;
542
543 next_cluster &= 0x0FFF;
544 break;
545 }
546
547 grub_dprintf ("fat", "fat_size=%d, next_cluster=%u\n",
548 data->fat_size, next_cluster);
549
550 /* Check the end. */
551 if (next_cluster >= data->cluster_eof_mark)
552 return ret;
553
554 if (next_cluster < 2 || next_cluster >= data->num_clusters)
555 {
556 grub_error (GRUB_ERR_BAD_FS, "invalid cluster %u",
557 next_cluster);
558 return -1;
559 }
560
561 data->cur_cluster = next_cluster;
562 data->cur_cluster_num++;
563 }
564
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;
572
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;
579
580 len -= size;
581 buf += size;
582 ret += size;
583 logical_cluster++;
584 offset = 0;
585 }
586
587 return ret;
588 }
589
590 struct grub_fat_iterate_context
591 {
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;
600 };
601
602 static grub_err_t
603 grub_fat_iterate_init (struct grub_fat_iterate_context *ctxt)
604 {
605 ctxt->offset = -sizeof (struct grub_fat_dir_entry);
606
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
615
616 if (! ctxt->filename || ! ctxt->unibuf)
617 {
618 grub_free (ctxt->filename);
619 grub_free (ctxt->unibuf);
620 return grub_errno;
621 }
622 return GRUB_ERR_NONE;
623 }
624
625 static void
626 grub_fat_iterate_fini (struct grub_fat_iterate_context *ctxt)
627 {
628 grub_free (ctxt->filename);
629 grub_free (ctxt->unibuf);
630 }
631
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)
636 {
637 grub_memset (&ctxt->dir, 0, sizeof (ctxt->dir));
638 while (1)
639 {
640 struct grub_fat_dir_entry dir;
641
642 ctxt->offset += sizeof (dir);
643
644 if (grub_fat_read_data (disk, data, 0, 0, ctxt->offset, sizeof (dir),
645 (char *) &dir)
646 != sizeof (dir))
647 break;
648
649 if (dir.entry_type == 0)
650 break;
651 if (!(dir.entry_type & 0x80))
652 continue;
653
654 if (dir.entry_type == 0x85)
655 {
656 unsigned i, nsec, slots = 0;
657
658 nsec = dir.type_specific.file.secondary_count;
659
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++)
663 {
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)
675 {
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:
687 {
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++;
693 }
694 break;
695 default:
696 grub_dprintf ("exfat", "unknown secondary type 0x%02x\n",
697 sec.entry_type);
698 }
699 }
700
701 if (i != nsec)
702 {
703 ctxt->offset -= sizeof (dir);
704 continue;
705 }
706
707 *grub_utf16_to_utf8 ((grub_uint8_t *) ctxt->filename, ctxt->unibuf,
708 slots * 15) = '\0';
709
710 return 0;
711 }
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);
723 }
724 return grub_errno ? : GRUB_ERR_EOF;
725 }
726
727 #else
728
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)
732 {
733 char *filep = 0;
734 int checksum = -1;
735 int slot = -1, slots = -1;
736
737 while (1)
738 {
739 unsigned i;
740
741 /* Adjust the offset. */
742 ctxt->offset += sizeof (ctxt->dir);
743
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;
750
751 /* Handle long name entries. */
752 if (ctxt->dir.attr == GRUB_FAT_ATTR_LONG_NAME)
753 {
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;
757
758 if (id & 0x40)
759 {
760 id &= 0x3f;
761 slots = slot = id;
762 checksum = long_name->checksum;
763 }
764
765 if (id != slot || slot == 0 || checksum != long_name->checksum)
766 {
767 checksum = -1;
768 continue;
769 }
770
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;
776 }
777
778 /* Check if this entry is valid. */
779 if (ctxt->dir.name[0] == 0xe5 || (ctxt->dir.attr & ~GRUB_FAT_ATTR_VALID))
780 continue;
781
782 /* This is a workaround for Japanese. */
783 if (ctxt->dir.name[0] == 0x05)
784 ctxt->dir.name[0] = 0xe5;
785
786 if (checksum != -1 && slot == 0)
787 {
788 grub_uint8_t sum;
789
790 for (sum = 0, i = 0; i < sizeof (ctxt->dir.name); i++)
791 sum = ((sum >> 1) | (sum << 7)) + ctxt->dir.name[i];
792
793 if (sum == checksum)
794 {
795 int u;
796
797 for (u = 0; u < slots * 13; u++)
798 ctxt->unibuf[u] = grub_le_to_cpu16 (ctxt->unibuf[u]);
799
800 *grub_utf16_to_utf8 ((grub_uint8_t *) ctxt->filename,
801 ctxt->unibuf,
802 slots * 13) = '\0';
803
804 return GRUB_ERR_NONE;
805 }
806
807 checksum = -1;
808 }
809
810 /* Convert the 8.3 file name. */
811 filep = ctxt->filename;
812 if (ctxt->dir.attr & GRUB_FAT_ATTR_VOLUME_ID)
813 {
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] == ' ')
817 {
818 filep--;
819 i--;
820 }
821 }
822 else
823 {
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] == ' ')
827 {
828 filep--;
829 i--;
830 }
831
832 *filep++ = '.';
833
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] == ' ')
837 {
838 filep--;
839 i--;
840 }
841
842 if (i == 8)
843 filep--;
844 }
845 *filep = '\0';
846 return GRUB_ERR_NONE;
847 }
848
849 return grub_errno ? : GRUB_ERR_EOF;
850 }
851
852 #endif
853
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)
861 {
862 char *dirname, *dirp;
863 int call_hook;
864 int found = 0;
865 struct grub_fat_iterate_context ctxt;
866 grub_err_t err;
867
868 if (! (data->attr & GRUB_FAT_ATTR_DIRECTORY))
869 {
870 grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a directory"));
871 return 0;
872 }
873
874 /* Extract a directory name. */
875 while (*path == '/')
876 path++;
877
878 dirp = grub_strchr (path, '/');
879 if (dirp)
880 {
881 unsigned len = dirp - path;
882
883 dirname = grub_malloc (len + 1);
884 if (! dirname)
885 goto fail;
886
887 grub_memcpy (dirname, path, len);
888 dirname[len] = '\0';
889 }
890 else
891 /* This is actually a file. */
892 dirname = grub_strdup (path);
893
894 call_hook = (! dirp && hook);
895
896 err = grub_fat_iterate_init (&ctxt);
897 if (err)
898 {
899 grub_free (dirname);
900 return 0;
901 }
902
903 while (!(err = grub_fat_iterate_dir_next (disk, data, &ctxt)))
904 {
905 struct grub_dirhook_info info;
906 grub_memset (&info, 0, sizeof (info));
907
908 info.dir = !! (ctxt.dir.attr & GRUB_FAT_ATTR_DIRECTORY);
909 info.case_insensitive = 1;
910
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)
919 {
920 if (hook (ctxt.filename, &info, hook_data))
921 break;
922 else
923 continue;
924 }
925
926 if (grub_strcasecmp (dirname, ctxt.filename) == 0)
927 {
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;
940
941 if (call_hook)
942 hook (ctxt.filename, &info, hook_data);
943
944 break;
945 }
946 }
947
948 grub_fat_iterate_fini (&ctxt);
949 if (err == GRUB_ERR_EOF)
950 err = 0;
951
952 if (grub_errno == GRUB_ERR_NONE && ! found && !call_hook)
953 grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("file `%s' not found"), origpath);
954
955 fail:
956 grub_free (dirname);
957
958 return found ? dirp : 0;
959 }
960
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)
964 {
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;
970
971 grub_dl_ref (my_mod);
972
973 data = grub_fat_mount (disk);
974 if (! data)
975 goto fail;
976
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;
988
989 do
990 {
991 p = grub_fat_find_dir (disk, data, p, path, hook, hook_data);
992 }
993 while (p && grub_errno == GRUB_ERR_NONE);
994
995 fail:
996
997 grub_free (dirname);
998 grub_free (data);
999
1000 grub_dl_unref (my_mod);
1001
1002 return grub_errno;
1003 }
1004
1005 static grub_err_t
1006 grub_fat_open (grub_file_t file, const char *name)
1007 {
1008 struct grub_fat_data *data = 0;
1009 char *p = (char *) name;
1010
1011 grub_dl_ref (my_mod);
1012
1013 data = grub_fat_mount (file->device->disk);
1014 if (! data)
1015 goto fail;
1016
1017 do
1018 {
1019 p = grub_fat_find_dir (file->device->disk, data, p, name, 0, 0);
1020 if (grub_errno != GRUB_ERR_NONE)
1021 goto fail;
1022 }
1023 while (p);
1024
1025 if (data->attr & GRUB_FAT_ATTR_DIRECTORY)
1026 {
1027 grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a regular file"));
1028 goto fail;
1029 }
1030
1031 file->data = data;
1032 file->size = data->file_size;
1033
1034 return GRUB_ERR_NONE;
1035
1036 fail:
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_free (file->data);
1057
1058 grub_dl_unref (my_mod);
1059
1060 return grub_errno;
1061 }
1062
1063 #ifdef MODE_EXFAT
1064 static grub_err_t
1065 grub_fat_label (grub_device_t device, char **label)
1066 {
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;
1071
1072 data = grub_fat_mount (disk);
1073 if (! data)
1074 return grub_errno;
1075
1076 *label = NULL;
1077
1078 while (1)
1079 {
1080 offset += sizeof (dir);
1081
1082 if (grub_fat_read_data (disk, data, 0, 0,
1083 offset, sizeof (dir), (char *) &dir)
1084 != sizeof (dir))
1085 break;
1086
1087 if (dir.entry_type == 0)
1088 break;
1089 if (!(dir.entry_type & 0x80))
1090 continue;
1091
1092 /* Volume label. */
1093 if (dir.entry_type == 0x83)
1094 {
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)
1101 {
1102 grub_free (data);
1103 return grub_errno;
1104 }
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';
1111 }
1112 }
1113
1114 grub_free (data);
1115 return grub_errno;
1116 }
1117
1118 #else
1119
1120 static grub_err_t
1121 grub_fat_label (grub_device_t device, char **label)
1122 {
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;
1127
1128 *label = 0;
1129
1130 grub_dl_ref (my_mod);
1131
1132 data = grub_fat_mount (disk);
1133 if (! data)
1134 goto fail;
1135
1136 if (! (data->attr & GRUB_FAT_ATTR_DIRECTORY))
1137 {
1138 grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a directory"));
1139 return 0;
1140 }
1141
1142 err = grub_fat_iterate_init (&ctxt);
1143 if (err)
1144 goto fail;
1145
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)
1148 {
1149 *label = grub_strdup (ctxt.filename);
1150 break;
1151 }
1152
1153 grub_fat_iterate_fini (&ctxt);
1154
1155 fail:
1156
1157 grub_dl_unref (my_mod);
1158
1159 grub_free (data);
1160
1161 return grub_errno;
1162 }
1163
1164 #endif
1165
1166 static grub_err_t
1167 grub_fat_uuid (grub_device_t device, char **uuid)
1168 {
1169 struct grub_fat_data *data;
1170 grub_disk_t disk = device->disk;
1171
1172 grub_dl_ref (my_mod);
1173
1174 data = grub_fat_mount (disk);
1175 if (data)
1176 {
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);
1183 }
1184 else
1185 *uuid = NULL;
1186
1187 grub_dl_unref (my_mod);
1188
1189 grub_free (data);
1190
1191 return grub_errno;
1192 }
1193
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
1202 {
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;
1209
1210 *sec_per_lcn = 1ULL << data->cluster_bits;
1211
1212 grub_free (data);
1213 return ret;
1214 }
1215 #endif
1216
1217 static struct grub_fs grub_fat_fs =
1218 {
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
1240 };
1241
1242 #ifdef MODE_EXFAT
1243 GRUB_MOD_INIT(exfat)
1244 #else
1245 GRUB_MOD_INIT(fat)
1246 #endif
1247 {
1248 COMPILE_TIME_ASSERT (sizeof (struct grub_fat_dir_entry) == 32);
1249 grub_fs_register (&grub_fat_fs);
1250 my_mod = mod;
1251 }
1252 #ifdef MODE_EXFAT
1253 GRUB_MOD_FINI(exfat)
1254 #else
1255 GRUB_MOD_FINI(fat)
1256 #endif
1257 {
1258 grub_fs_unregister (&grub_fat_fs);
1259 }
1260