2009-11-21 Samuel Thibault <samuel.thibault@ens-lyon.org>
[grub2.git] / fs / fat.c
blobe7f01629e4721ba81c6633e6e27db97fedcc6008
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>
29 #define GRUB_FAT_DIR_ENTRY_SIZE 32
31 #define GRUB_FAT_ATTR_READ_ONLY 0x01
32 #define GRUB_FAT_ATTR_HIDDEN 0x02
33 #define GRUB_FAT_ATTR_SYSTEM 0x04
34 #define GRUB_FAT_ATTR_VOLUME_ID 0x08
35 #define GRUB_FAT_ATTR_DIRECTORY 0x10
36 #define GRUB_FAT_ATTR_ARCHIVE 0x20
38 #define GRUB_FAT_MAXFILE 256
40 #define GRUB_FAT_ATTR_LONG_NAME (GRUB_FAT_ATTR_READ_ONLY \
41 | GRUB_FAT_ATTR_HIDDEN \
42 | GRUB_FAT_ATTR_SYSTEM \
43 | GRUB_FAT_ATTR_VOLUME_ID)
44 #define GRUB_FAT_ATTR_VALID (GRUB_FAT_ATTR_READ_ONLY \
45 | GRUB_FAT_ATTR_HIDDEN \
46 | GRUB_FAT_ATTR_SYSTEM \
47 | GRUB_FAT_ATTR_DIRECTORY \
48 | GRUB_FAT_ATTR_ARCHIVE \
49 | GRUB_FAT_ATTR_VOLUME_ID)
51 struct grub_fat_bpb
53 grub_uint8_t jmp_boot[3];
54 grub_uint8_t oem_name[8];
55 grub_uint16_t bytes_per_sector;
56 grub_uint8_t sectors_per_cluster;
57 grub_uint16_t num_reserved_sectors;
58 grub_uint8_t num_fats;
59 grub_uint16_t num_root_entries;
60 grub_uint16_t num_total_sectors_16;
61 grub_uint8_t media;
62 grub_uint16_t sectors_per_fat_16;
63 grub_uint16_t sectors_per_track;
64 grub_uint16_t num_heads;
65 grub_uint32_t num_hidden_sectors;
66 grub_uint32_t num_total_sectors_32;
67 union
69 struct
71 grub_uint8_t num_ph_drive;
72 grub_uint8_t reserved;
73 grub_uint8_t boot_sig;
74 grub_uint32_t num_serial;
75 grub_uint8_t label[11];
76 grub_uint8_t fstype[8];
77 } __attribute__ ((packed)) fat12_or_fat16;
78 struct
80 grub_uint32_t sectors_per_fat_32;
81 grub_uint16_t extended_flags;
82 grub_uint16_t fs_version;
83 grub_uint32_t root_cluster;
84 grub_uint16_t fs_info;
85 grub_uint16_t backup_boot_sector;
86 grub_uint8_t reserved[12];
87 grub_uint8_t num_ph_drive;
88 grub_uint8_t reserved1;
89 grub_uint8_t boot_sig;
90 grub_uint32_t num_serial;
91 grub_uint8_t label[11];
92 grub_uint8_t fstype[8];
93 } __attribute__ ((packed)) fat32;
94 } __attribute__ ((packed)) version_specific;
95 } __attribute__ ((packed));
97 struct grub_fat_dir_entry
99 grub_uint8_t name[11];
100 grub_uint8_t attr;
101 grub_uint8_t nt_reserved;
102 grub_uint8_t c_time_tenth;
103 grub_uint16_t c_time;
104 grub_uint16_t c_date;
105 grub_uint16_t a_date;
106 grub_uint16_t first_cluster_high;
107 grub_uint16_t w_time;
108 grub_uint16_t w_date;
109 grub_uint16_t first_cluster_low;
110 grub_uint32_t file_size;
111 } __attribute__ ((packed));
113 struct grub_fat_long_name_entry
115 grub_uint8_t id;
116 grub_uint16_t name1[5];
117 grub_uint8_t attr;
118 grub_uint8_t reserved;
119 grub_uint8_t checksum;
120 grub_uint16_t name2[6];
121 grub_uint16_t first_cluster;
122 grub_uint16_t name3[2];
123 } __attribute__ ((packed));
125 struct grub_fat_data
127 int logical_sector_bits;
128 grub_uint32_t num_sectors;
130 grub_uint16_t fat_sector;
131 grub_uint32_t sectors_per_fat;
132 int fat_size;
134 grub_uint32_t root_cluster;
135 grub_uint32_t root_sector;
136 grub_uint32_t num_root_sectors;
138 int cluster_bits;
139 grub_uint32_t cluster_eof_mark;
140 grub_uint32_t cluster_sector;
141 grub_uint32_t num_clusters;
143 grub_uint8_t attr;
144 grub_ssize_t file_size;
145 grub_uint32_t file_cluster;
146 grub_uint32_t cur_cluster_num;
147 grub_uint32_t cur_cluster;
149 grub_uint32_t uuid;
152 static grub_dl_t my_mod;
154 static int
155 fat_log2 (unsigned x)
157 int i;
159 if (x == 0)
160 return -1;
162 for (i = 0; (x & 1) == 0; i++)
163 x >>= 1;
165 if (x != 1)
166 return -1;
168 return i;
171 static struct grub_fat_data *
172 grub_fat_mount (grub_disk_t disk)
174 struct grub_fat_bpb bpb;
175 struct grub_fat_data *data = 0;
176 grub_uint32_t first_fat, magic;
178 if (! disk)
179 goto fail;
181 data = (struct grub_fat_data *) grub_malloc (sizeof (*data));
182 if (! data)
183 goto fail;
185 /* Read the BPB. */
186 if (grub_disk_read (disk, 0, 0, sizeof (bpb), &bpb))
187 goto fail;
189 if (grub_strncmp((const char *) bpb.version_specific.fat12_or_fat16.fstype, "FAT12", 5)
190 && grub_strncmp((const char *) bpb.version_specific.fat12_or_fat16.fstype, "FAT16", 5)
191 && grub_strncmp((const char *) bpb.version_specific.fat32.fstype, "FAT32", 5))
192 goto fail;
194 /* Get the sizes of logical sectors and clusters. */
195 data->logical_sector_bits =
196 fat_log2 (grub_le_to_cpu16 (bpb.bytes_per_sector));
197 if (data->logical_sector_bits < GRUB_DISK_SECTOR_BITS)
198 goto fail;
199 data->logical_sector_bits -= GRUB_DISK_SECTOR_BITS;
201 data->cluster_bits = fat_log2 (bpb.sectors_per_cluster);
202 if (data->cluster_bits < 0)
203 goto fail;
204 data->cluster_bits += data->logical_sector_bits;
206 /* Get information about FATs. */
207 data->fat_sector = (grub_le_to_cpu16 (bpb.num_reserved_sectors)
208 << data->logical_sector_bits);
209 if (data->fat_sector == 0)
210 goto fail;
212 data->sectors_per_fat = ((bpb.sectors_per_fat_16
213 ? grub_le_to_cpu16 (bpb.sectors_per_fat_16)
214 : grub_le_to_cpu32 (bpb.version_specific.fat32.sectors_per_fat_32))
215 << data->logical_sector_bits);
216 if (data->sectors_per_fat == 0)
217 goto fail;
219 /* Get the number of sectors in this volume. */
220 data->num_sectors = ((bpb.num_total_sectors_16
221 ? grub_le_to_cpu16 (bpb.num_total_sectors_16)
222 : grub_le_to_cpu32 (bpb.num_total_sectors_32))
223 << data->logical_sector_bits);
224 if (data->num_sectors == 0)
225 goto fail;
227 /* Get information about the root directory. */
228 if (bpb.num_fats == 0)
229 goto fail;
231 data->root_sector = data->fat_sector + bpb.num_fats * data->sectors_per_fat;
232 data->num_root_sectors
233 = ((((grub_uint32_t) grub_le_to_cpu16 (bpb.num_root_entries)
234 * GRUB_FAT_DIR_ENTRY_SIZE
235 + grub_le_to_cpu16 (bpb.bytes_per_sector) - 1)
236 >> (data->logical_sector_bits + GRUB_DISK_SECTOR_BITS))
237 << (data->logical_sector_bits));
239 data->cluster_sector = data->root_sector + data->num_root_sectors;
240 data->num_clusters = (((data->num_sectors - data->cluster_sector)
241 >> (data->cluster_bits + data->logical_sector_bits))
242 + 2);
244 if (data->num_clusters <= 2)
245 goto fail;
247 if (! bpb.sectors_per_fat_16)
249 /* FAT32. */
250 grub_uint16_t flags = grub_le_to_cpu16 (bpb.version_specific.fat32.extended_flags);
252 data->root_cluster = grub_le_to_cpu32 (bpb.version_specific.fat32.root_cluster);
253 data->fat_size = 32;
254 data->cluster_eof_mark = 0x0ffffff8;
256 if (flags & 0x80)
258 /* Get an active FAT. */
259 unsigned active_fat = flags & 0xf;
261 if (active_fat > bpb.num_fats)
262 goto fail;
264 data->fat_sector += active_fat * data->sectors_per_fat;
267 if (bpb.num_root_entries != 0 || bpb.version_specific.fat32.fs_version != 0)
268 goto fail;
270 else
272 /* FAT12 or FAT16. */
273 data->root_cluster = ~0U;
275 if (data->num_clusters <= 4085 + 2)
277 /* FAT12. */
278 data->fat_size = 12;
279 data->cluster_eof_mark = 0x0ff8;
281 else
283 /* FAT16. */
284 data->fat_size = 16;
285 data->cluster_eof_mark = 0xfff8;
289 /* More sanity checks. */
290 if (data->num_sectors <= data->fat_sector)
291 goto fail;
293 if (grub_disk_read (disk,
294 data->fat_sector,
296 sizeof (first_fat),
297 &first_fat))
298 goto fail;
300 first_fat = grub_le_to_cpu32 (first_fat);
302 if (data->fat_size == 32)
304 first_fat &= 0x0fffffff;
305 magic = 0x0fffff00;
307 else if (data->fat_size == 16)
309 first_fat &= 0x0000ffff;
310 magic = 0xff00;
312 else
314 first_fat &= 0x00000fff;
315 magic = 0x0f00;
318 /* Serial number. */
319 if (bpb.sectors_per_fat_16)
320 data->uuid = grub_le_to_cpu32 (bpb.version_specific.fat12_or_fat16.num_serial);
321 else
322 data->uuid = grub_le_to_cpu32 (bpb.version_specific.fat32.num_serial);
324 /* Ignore the 3rd bit, because some BIOSes assigns 0xF0 to the media
325 descriptor, even if it is a so-called superfloppy (e.g. an USB key).
326 The check may be too strict for this kind of stupid BIOSes, as
327 they overwrite the media descriptor. */
328 if ((first_fat | 0x8) != (magic | bpb.media | 0x8))
329 goto fail;
331 /* Start from the root directory. */
332 data->file_cluster = data->root_cluster;
333 data->cur_cluster_num = ~0U;
334 data->attr = GRUB_FAT_ATTR_DIRECTORY;
335 return data;
337 fail:
339 grub_free (data);
340 grub_error (GRUB_ERR_BAD_FS, "not a fat filesystem");
341 return 0;
344 static grub_ssize_t
345 grub_fat_read_data (grub_disk_t disk, struct grub_fat_data *data,
346 void NESTED_FUNC_ATTR (*read_hook) (grub_disk_addr_t sector,
347 unsigned offset, unsigned length),
348 grub_off_t offset, grub_size_t len, char *buf)
350 grub_size_t size;
351 grub_uint32_t logical_cluster;
352 unsigned logical_cluster_bits;
353 grub_ssize_t ret = 0;
354 unsigned long sector;
356 /* This is a special case. FAT12 and FAT16 doesn't have the root directory
357 in clusters. */
358 if (data->file_cluster == ~0U)
360 size = (data->num_root_sectors << GRUB_DISK_SECTOR_BITS) - offset;
361 if (size > len)
362 size = len;
364 if (grub_disk_read (disk, data->root_sector, offset, size, buf))
365 return -1;
367 return size;
370 /* Calculate the logical cluster number and offset. */
371 logical_cluster_bits = (data->cluster_bits
372 + data->logical_sector_bits
373 + GRUB_DISK_SECTOR_BITS);
374 logical_cluster = offset >> logical_cluster_bits;
375 offset &= (1 << logical_cluster_bits) - 1;
377 if (logical_cluster < data->cur_cluster_num)
379 data->cur_cluster_num = 0;
380 data->cur_cluster = data->file_cluster;
383 while (len)
385 while (logical_cluster > data->cur_cluster_num)
387 /* Find next cluster. */
388 grub_uint32_t next_cluster;
389 unsigned long fat_offset;
391 switch (data->fat_size)
393 case 32:
394 fat_offset = data->cur_cluster << 2;
395 break;
396 case 16:
397 fat_offset = data->cur_cluster << 1;
398 break;
399 default:
400 /* case 12: */
401 fat_offset = data->cur_cluster + (data->cur_cluster >> 1);
402 break;
405 /* Read the FAT. */
406 if (grub_disk_read (disk, data->fat_sector, fat_offset,
407 (data->fat_size + 7) >> 3,
408 (char *) &next_cluster))
409 return -1;
411 next_cluster = grub_le_to_cpu32 (next_cluster);
412 switch (data->fat_size)
414 case 16:
415 next_cluster &= 0xFFFF;
416 break;
417 case 12:
418 if (data->cur_cluster & 1)
419 next_cluster >>= 4;
421 next_cluster &= 0x0FFF;
422 break;
425 grub_dprintf ("fat", "fat_size=%d, next_cluster=%u\n",
426 data->fat_size, next_cluster);
428 /* Check the end. */
429 if (next_cluster >= data->cluster_eof_mark)
430 return ret;
432 if (next_cluster < 2 || next_cluster >= data->num_clusters)
434 grub_error (GRUB_ERR_BAD_FS, "invalid cluster %u",
435 next_cluster);
436 return -1;
439 data->cur_cluster = next_cluster;
440 data->cur_cluster_num++;
443 /* Read the data here. */
444 sector = (data->cluster_sector
445 + ((data->cur_cluster - 2)
446 << (data->cluster_bits + data->logical_sector_bits)));
447 size = (1 << logical_cluster_bits) - offset;
448 if (size > len)
449 size = len;
451 disk->read_hook = read_hook;
452 grub_disk_read (disk, sector, offset, size, buf);
453 disk->read_hook = 0;
454 if (grub_errno)
455 return -1;
457 len -= size;
458 buf += size;
459 ret += size;
460 logical_cluster++;
461 offset = 0;
464 return ret;
467 static grub_err_t
468 grub_fat_iterate_dir (grub_disk_t disk, struct grub_fat_data *data,
469 int (*hook) (const char *filename,
470 struct grub_fat_dir_entry *dir))
472 struct grub_fat_dir_entry dir;
473 char *filename, *filep = 0;
474 grub_uint16_t *unibuf;
475 int slot = -1, slots = -1;
476 int checksum = -1;
477 grub_ssize_t offset = -sizeof(dir);
479 if (! (data->attr & GRUB_FAT_ATTR_DIRECTORY))
480 return grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a directory");
482 /* Allocate space enough to hold a long name. */
483 filename = grub_malloc (0x40 * 13 * 4 + 1);
484 unibuf = (grub_uint16_t *) grub_malloc (0x40 * 13 * 2);
485 if (! filename || ! unibuf)
487 grub_free (filename);
488 grub_free (unibuf);
489 return 0;
492 while (1)
494 unsigned i;
496 /* Adjust the offset. */
497 offset += sizeof (dir);
499 /* Read a directory entry. */
500 if ((grub_fat_read_data (disk, data, 0,
501 offset, sizeof (dir), (char *) &dir)
502 != sizeof (dir) || dir.name[0] == 0))
503 break;
504 /* Handle long name entries. */
505 if (dir.attr == GRUB_FAT_ATTR_LONG_NAME)
507 struct grub_fat_long_name_entry *long_name
508 = (struct grub_fat_long_name_entry *) &dir;
509 grub_uint8_t id = long_name->id;
511 if (id & 0x40)
513 id &= 0x3f;
514 slots = slot = id;
515 checksum = long_name->checksum;
518 if (id != slot || slot == 0 || checksum != long_name->checksum)
520 checksum = -1;
521 continue;
524 slot--;
525 grub_memcpy (unibuf + slot * 13, long_name->name1, 5 * 2);
526 grub_memcpy (unibuf + slot * 13 + 5, long_name->name2, 6 * 2);
527 grub_memcpy (unibuf + slot * 13 + 11, long_name->name3, 2 * 2);
528 continue;
531 /* Check if this entry is valid. */
532 if (dir.name[0] == 0xe5 || (dir.attr & ~GRUB_FAT_ATTR_VALID))
533 continue;
535 /* This is a workaround for Japanese. */
536 if (dir.name[0] == 0x05)
537 dir.name[0] = 0xe5;
539 if (checksum != -1 && slot == 0)
541 grub_uint8_t sum;
543 for (sum = 0, i = 0; i < sizeof (dir.name); i++)
544 sum = ((sum >> 1) | (sum << 7)) + dir.name[i];
546 if (sum == checksum)
548 int u;
550 for (u = 0; u < slots * 13; u++)
551 unibuf[u] = grub_le_to_cpu16 (unibuf[u]);
553 *grub_utf16_to_utf8 ((grub_uint8_t *) filename, unibuf,
554 slots * 13) = '\0';
556 if (hook (filename, &dir))
557 break;
559 checksum = -1;
560 continue;
563 checksum = -1;
566 /* Convert the 8.3 file name. */
567 filep = filename;
568 if (dir.attr & GRUB_FAT_ATTR_VOLUME_ID)
570 for (i = 0; i < sizeof (dir.name) && dir.name[i]
571 && ! grub_isspace (dir.name[i]); i++)
572 *filep++ = dir.name[i];
574 else
576 for (i = 0; i < 8 && dir.name[i] && ! grub_isspace (dir.name[i]); i++)
577 *filep++ = grub_tolower (dir.name[i]);
579 *filep = '.';
581 for (i = 8; i < 11 && dir.name[i] && ! grub_isspace (dir.name[i]); i++)
582 *++filep = grub_tolower (dir.name[i]);
584 if (*filep != '.')
585 filep++;
587 *filep = '\0';
589 if (hook (filename, &dir))
590 break;
593 grub_free (filename);
595 return grub_errno;
599 /* Find the underlying directory or file in PATH and return the
600 next path. If there is no next path or an error occurs, return NULL.
601 If HOOK is specified, call it with each file name. */
602 static char *
603 grub_fat_find_dir (grub_disk_t disk, struct grub_fat_data *data,
604 const char *path,
605 int (*hook) (const char *filename,
606 const struct grub_dirhook_info *info))
608 char *dirname, *dirp;
609 int call_hook;
610 int found = 0;
612 auto int iter_hook (const char *filename, struct grub_fat_dir_entry *dir);
613 int iter_hook (const char *filename, struct grub_fat_dir_entry *dir)
615 struct grub_dirhook_info info;
616 grub_memset (&info, 0, sizeof (info));
618 info.dir = !! (dir->attr & GRUB_FAT_ATTR_DIRECTORY);
619 info.case_insensitive = 1;
621 if (dir->attr & GRUB_FAT_ATTR_VOLUME_ID)
622 return 0;
623 if (*dirname == '\0' && call_hook)
624 return hook (filename, &info);
626 if (grub_strcasecmp (dirname, filename) == 0)
628 found = 1;
629 data->attr = dir->attr;
630 data->file_size = grub_le_to_cpu32 (dir->file_size);
631 data->file_cluster = ((grub_le_to_cpu16 (dir->first_cluster_high) << 16)
632 | grub_le_to_cpu16 (dir->first_cluster_low));
633 data->cur_cluster_num = ~0U;
635 if (call_hook)
636 hook (filename, &info);
638 return 1;
640 return 0;
643 if (! (data->attr & GRUB_FAT_ATTR_DIRECTORY))
645 grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a directory");
646 return 0;
649 /* Extract a directory name. */
650 while (*path == '/')
651 path++;
653 dirp = grub_strchr (path, '/');
654 if (dirp)
656 unsigned len = dirp - path;
658 dirname = grub_malloc (len + 1);
659 if (! dirname)
660 return 0;
662 grub_memcpy (dirname, path, len);
663 dirname[len] = '\0';
665 else
666 /* This is actually a file. */
667 dirname = grub_strdup (path);
669 call_hook = (! dirp && hook);
671 grub_fat_iterate_dir (disk, data, iter_hook);
672 if (grub_errno == GRUB_ERR_NONE && ! found && !call_hook)
673 grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found");
675 grub_free (dirname);
677 return found ? dirp : 0;
680 static grub_err_t
681 grub_fat_dir (grub_device_t device, const char *path,
682 int (*hook) (const char *filename,
683 const struct grub_dirhook_info *info))
685 struct grub_fat_data *data = 0;
686 grub_disk_t disk = device->disk;
687 grub_size_t len;
688 char *dirname = 0;
689 char *p;
691 grub_dl_ref (my_mod);
693 data = grub_fat_mount (disk);
694 if (! data)
695 goto fail;
697 /* Make sure that DIRNAME terminates with '/'. */
698 len = grub_strlen (path);
699 dirname = grub_malloc (len + 1 + 1);
700 if (! dirname)
701 goto fail;
702 grub_memcpy (dirname, path, len);
703 p = dirname + len;
704 if (path[len - 1] != '/')
705 *p++ = '/';
706 *p = '\0';
707 p = dirname;
711 p = grub_fat_find_dir (disk, data, p, hook);
713 while (p && grub_errno == GRUB_ERR_NONE);
715 fail:
717 grub_free (dirname);
718 grub_free (data);
720 grub_dl_unref (my_mod);
722 return grub_errno;
725 static grub_err_t
726 grub_fat_open (grub_file_t file, const char *name)
728 struct grub_fat_data *data = 0;
729 char *p = (char *) name;
731 grub_dl_ref (my_mod);
733 data = grub_fat_mount (file->device->disk);
734 if (! data)
735 goto fail;
739 p = grub_fat_find_dir (file->device->disk, data, p, 0);
740 if (grub_errno != GRUB_ERR_NONE)
741 goto fail;
743 while (p);
745 if (data->attr & GRUB_FAT_ATTR_DIRECTORY)
747 grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a file");
748 goto fail;
751 file->data = data;
752 file->size = data->file_size;
754 return GRUB_ERR_NONE;
756 fail:
758 grub_free (data);
760 grub_dl_unref (my_mod);
762 return grub_errno;
765 static grub_ssize_t
766 grub_fat_read (grub_file_t file, char *buf, grub_size_t len)
768 return grub_fat_read_data (file->device->disk, file->data, file->read_hook,
769 file->offset, len, buf);
772 static grub_err_t
773 grub_fat_close (grub_file_t file)
775 grub_free (file->data);
777 grub_dl_unref (my_mod);
779 return grub_errno;
782 static grub_err_t
783 grub_fat_label (grub_device_t device, char **label)
785 struct grub_fat_data *data;
786 grub_disk_t disk = device->disk;
788 auto int iter_hook (const char *filename, struct grub_fat_dir_entry *dir);
789 int iter_hook (const char *filename, struct grub_fat_dir_entry *dir)
791 if (dir->attr == GRUB_FAT_ATTR_VOLUME_ID)
793 *label = grub_strdup (filename);
794 return 1;
796 return 0;
799 grub_dl_ref (my_mod);
801 data = grub_fat_mount (disk);
802 if (! data)
803 goto fail;
805 if (! (data->attr & GRUB_FAT_ATTR_DIRECTORY))
807 grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a directory");
808 return 0;
811 *label = 0;
813 grub_fat_iterate_dir (disk, data, iter_hook);
815 fail:
817 grub_dl_unref (my_mod);
819 grub_free (data);
821 return grub_errno;
824 static grub_err_t
825 grub_fat_uuid (grub_device_t device, char **uuid)
827 struct grub_fat_data *data;
828 grub_disk_t disk = device->disk;
830 grub_dl_ref (my_mod);
832 data = grub_fat_mount (disk);
833 if (data)
835 *uuid = grub_malloc (sizeof ("xxxx-xxxx"));
836 grub_sprintf (*uuid, "%04x-%04x", (grub_uint16_t) (data->uuid >> 16),
837 (grub_uint16_t) data->uuid);
839 else
840 *uuid = NULL;
842 grub_dl_unref (my_mod);
844 grub_free (data);
846 return grub_errno;
849 static struct grub_fs grub_fat_fs =
851 .name = "fat",
852 .dir = grub_fat_dir,
853 .open = grub_fat_open,
854 .read = grub_fat_read,
855 .close = grub_fat_close,
856 .label = grub_fat_label,
857 .uuid = grub_fat_uuid,
858 #ifdef GRUB_UTIL
859 .reserved_first_sector = 1,
860 #endif
861 .next = 0
864 GRUB_MOD_INIT(fat)
866 grub_fs_register (&grub_fat_fs);
867 my_mod = mod;
870 GRUB_MOD_FINI(fat)
872 grub_fs_unregister (&grub_fat_fs);