2009-07-21 Pavel Roskin <proski@gnu.org>
[grub2/phcoder.git] / fs / fat.c
blobcc733362fc7cd79b331a6a30775c26f78ab095dd
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 #if 0
426 grub_printf ("%s:%d: fat_size=%d, next_cluster=%u\n",
427 __FILE__, __LINE__, data->fat_size, next_cluster);
428 #endif
430 /* Check the end. */
431 if (next_cluster >= data->cluster_eof_mark)
432 return ret;
434 if (next_cluster < 2 || next_cluster >= data->num_clusters)
436 grub_error (GRUB_ERR_BAD_FS, "invalid cluster %u",
437 next_cluster);
438 return -1;
441 data->cur_cluster = next_cluster;
442 data->cur_cluster_num++;
445 /* Read the data here. */
446 sector = (data->cluster_sector
447 + ((data->cur_cluster - 2)
448 << (data->cluster_bits + data->logical_sector_bits)));
449 size = (1 << logical_cluster_bits) - offset;
450 if (size > len)
451 size = len;
453 disk->read_hook = read_hook;
454 grub_disk_read (disk, sector, offset, size, buf);
455 disk->read_hook = 0;
456 if (grub_errno)
457 return -1;
459 len -= size;
460 buf += size;
461 ret += size;
462 logical_cluster++;
463 offset = 0;
466 return ret;
469 static grub_err_t
470 grub_fat_iterate_dir (grub_disk_t disk, struct grub_fat_data *data,
471 int (*hook) (const char *filename,
472 struct grub_fat_dir_entry *dir))
474 struct grub_fat_dir_entry dir;
475 char *filename, *filep = 0;
476 grub_uint16_t *unibuf;
477 int slot = -1, slots = -1;
478 int checksum = -1;
479 grub_ssize_t offset = -sizeof(dir);
481 if (! (data->attr & GRUB_FAT_ATTR_DIRECTORY))
482 return grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a directory");
484 /* Allocate space enough to hold a long name. */
485 filename = grub_malloc (0x40 * 13 * 4 + 1);
486 unibuf = (grub_uint16_t *) grub_malloc (0x40 * 13 * 2);
487 if (! filename || ! unibuf)
489 grub_free (filename);
490 grub_free (unibuf);
491 return 0;
494 while (1)
496 unsigned i;
498 /* Adjust the offset. */
499 offset += sizeof (dir);
501 /* Read a directory entry. */
502 if ((grub_fat_read_data (disk, data, 0,
503 offset, sizeof (dir), (char *) &dir)
504 != sizeof (dir) || dir.name[0] == 0))
505 break;
506 /* Handle long name entries. */
507 if (dir.attr == GRUB_FAT_ATTR_LONG_NAME)
509 struct grub_fat_long_name_entry *long_name
510 = (struct grub_fat_long_name_entry *) &dir;
511 grub_uint8_t id = long_name->id;
513 if (id & 0x40)
515 id &= 0x3f;
516 slots = slot = id;
517 checksum = long_name->checksum;
520 if (id != slot || slot == 0 || checksum != long_name->checksum)
522 checksum = -1;
523 continue;
526 slot--;
527 grub_memcpy (unibuf + slot * 13, long_name->name1, 5 * 2);
528 grub_memcpy (unibuf + slot * 13 + 5, long_name->name2, 6 * 2);
529 grub_memcpy (unibuf + slot * 13 + 11, long_name->name3, 2 * 2);
530 continue;
533 /* Check if this entry is valid. */
534 if (dir.name[0] == 0xe5 || (dir.attr & ~GRUB_FAT_ATTR_VALID))
535 continue;
537 /* This is a workaround for Japanese. */
538 if (dir.name[0] == 0x05)
539 dir.name[0] = 0xe5;
541 if (checksum != -1 && slot == 0)
543 grub_uint8_t sum;
545 for (sum = 0, i = 0; i < sizeof (dir.name); i++)
546 sum = ((sum >> 1) | (sum << 7)) + dir.name[i];
548 if (sum == checksum)
550 int u;
552 for (u = 0; u < slots * 13; u++)
553 unibuf[u] = grub_le_to_cpu16 (unibuf[u]);
555 *grub_utf16_to_utf8 ((grub_uint8_t *) filename, unibuf,
556 slots * 13) = '\0';
558 if (hook (filename, &dir))
559 break;
561 checksum = -1;
562 continue;
565 checksum = -1;
568 /* Convert the 8.3 file name. */
569 filep = filename;
570 if (dir.attr & GRUB_FAT_ATTR_VOLUME_ID)
572 for (i = 0; i < sizeof (dir.name) && dir.name[i]
573 && ! grub_isspace (dir.name[i]); i++)
574 *filep++ = dir.name[i];
576 else
578 for (i = 0; i < 8 && dir.name[i] && ! grub_isspace (dir.name[i]); i++)
579 *filep++ = grub_tolower (dir.name[i]);
581 *filep = '.';
583 for (i = 8; i < 11 && dir.name[i] && ! grub_isspace (dir.name[i]); i++)
584 *++filep = grub_tolower (dir.name[i]);
586 if (*filep != '.')
587 filep++;
589 *filep = '\0';
591 if (hook (filename, &dir))
592 break;
595 grub_free (filename);
597 return grub_errno;
601 /* Find the underlying directory or file in PATH and return the
602 next path. If there is no next path or an error occurs, return NULL.
603 If HOOK is specified, call it with each file name. */
604 static char *
605 grub_fat_find_dir (grub_disk_t disk, struct grub_fat_data *data,
606 const char *path,
607 int (*hook) (const char *filename,
608 const struct grub_dirhook_info *info))
610 char *dirname, *dirp;
611 int call_hook;
612 int found = 0;
614 auto int iter_hook (const char *filename, struct grub_fat_dir_entry *dir);
615 int iter_hook (const char *filename, struct grub_fat_dir_entry *dir)
617 struct grub_dirhook_info info;
618 grub_memset (&info, 0, sizeof (info));
620 info.dir = !! (dir->attr & GRUB_FAT_ATTR_DIRECTORY);
621 info.case_insensitive = 1;
623 if (dir->attr & GRUB_FAT_ATTR_VOLUME_ID)
624 return 0;
625 if (*dirname == '\0' && call_hook)
626 return hook (filename, &info);
628 if (grub_strcasecmp (dirname, filename) == 0)
630 found = 1;
631 data->attr = dir->attr;
632 data->file_size = grub_le_to_cpu32 (dir->file_size);
633 data->file_cluster = ((grub_le_to_cpu16 (dir->first_cluster_high) << 16)
634 | grub_le_to_cpu16 (dir->first_cluster_low));
635 data->cur_cluster_num = ~0U;
637 if (call_hook)
638 hook (filename, &info);
640 return 1;
642 return 0;
645 if (! (data->attr & GRUB_FAT_ATTR_DIRECTORY))
647 grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a directory");
648 return 0;
651 /* Extract a directory name. */
652 while (*path == '/')
653 path++;
655 dirp = grub_strchr (path, '/');
656 if (dirp)
658 unsigned len = dirp - path;
660 dirname = grub_malloc (len + 1);
661 if (! dirname)
662 return 0;
664 grub_memcpy (dirname, path, len);
665 dirname[len] = '\0';
667 else
668 /* This is actually a file. */
669 dirname = grub_strdup (path);
671 call_hook = (! dirp && hook);
673 grub_fat_iterate_dir (disk, data, iter_hook);
674 if (grub_errno == GRUB_ERR_NONE && ! found && !call_hook)
675 grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found");
677 grub_free (dirname);
679 return found ? dirp : 0;
682 static grub_err_t
683 grub_fat_dir (grub_device_t device, const char *path,
684 int (*hook) (const char *filename,
685 const struct grub_dirhook_info *info))
687 struct grub_fat_data *data = 0;
688 grub_disk_t disk = device->disk;
689 grub_size_t len;
690 char *dirname = 0;
691 char *p;
693 grub_dl_ref (my_mod);
695 data = grub_fat_mount (disk);
696 if (! data)
697 goto fail;
699 /* Make sure that DIRNAME terminates with '/'. */
700 len = grub_strlen (path);
701 dirname = grub_malloc (len + 1 + 1);
702 if (! dirname)
703 goto fail;
704 grub_memcpy (dirname, path, len);
705 p = dirname + len;
706 if (path[len - 1] != '/')
707 *p++ = '/';
708 *p = '\0';
709 p = dirname;
713 p = grub_fat_find_dir (disk, data, p, hook);
715 while (p && grub_errno == GRUB_ERR_NONE);
717 fail:
719 grub_free (dirname);
720 grub_free (data);
722 grub_dl_unref (my_mod);
724 return grub_errno;
727 static grub_err_t
728 grub_fat_open (grub_file_t file, const char *name)
730 struct grub_fat_data *data = 0;
731 char *p = (char *) name;
733 grub_dl_ref (my_mod);
735 data = grub_fat_mount (file->device->disk);
736 if (! data)
737 goto fail;
741 p = grub_fat_find_dir (file->device->disk, data, p, 0);
742 if (grub_errno != GRUB_ERR_NONE)
743 goto fail;
745 while (p);
747 if (data->attr & GRUB_FAT_ATTR_DIRECTORY)
749 grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a file");
750 goto fail;
753 file->data = data;
754 file->size = data->file_size;
756 return GRUB_ERR_NONE;
758 fail:
760 grub_free (data);
762 grub_dl_unref (my_mod);
764 return grub_errno;
767 static grub_ssize_t
768 grub_fat_read (grub_file_t file, char *buf, grub_size_t len)
770 return grub_fat_read_data (file->device->disk, file->data, file->read_hook,
771 file->offset, len, buf);
774 static grub_err_t
775 grub_fat_close (grub_file_t file)
777 grub_free (file->data);
779 grub_dl_unref (my_mod);
781 return grub_errno;
784 static grub_err_t
785 grub_fat_label (grub_device_t device, char **label)
787 struct grub_fat_data *data;
788 grub_disk_t disk = device->disk;
790 auto int iter_hook (const char *filename, struct grub_fat_dir_entry *dir);
791 int iter_hook (const char *filename, struct grub_fat_dir_entry *dir)
793 if (dir->attr == GRUB_FAT_ATTR_VOLUME_ID)
795 *label = grub_strdup (filename);
796 return 1;
798 return 0;
801 grub_dl_ref (my_mod);
803 data = grub_fat_mount (disk);
804 if (! data)
805 goto fail;
807 if (! (data->attr & GRUB_FAT_ATTR_DIRECTORY))
809 grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a directory");
810 return 0;
813 *label = 0;
815 grub_fat_iterate_dir (disk, data, iter_hook);
817 fail:
819 grub_dl_unref (my_mod);
821 grub_free (data);
823 return grub_errno;
826 static grub_err_t
827 grub_fat_uuid (grub_device_t device, char **uuid)
829 struct grub_fat_data *data;
830 grub_disk_t disk = device->disk;
832 grub_dl_ref (my_mod);
834 data = grub_fat_mount (disk);
835 if (data)
837 *uuid = grub_malloc (sizeof ("xxxx-xxxx"));
838 grub_sprintf (*uuid, "%04x-%04x", (grub_uint16_t) (data->uuid >> 16),
839 (grub_uint16_t) data->uuid);
841 else
842 *uuid = NULL;
844 grub_dl_unref (my_mod);
846 grub_free (data);
848 return grub_errno;
851 static struct grub_fs grub_fat_fs =
853 .name = "fat",
854 .dir = grub_fat_dir,
855 .open = grub_fat_open,
856 .read = grub_fat_read,
857 .close = grub_fat_close,
858 .label = grub_fat_label,
859 .uuid = grub_fat_uuid,
860 .next = 0
863 GRUB_MOD_INIT(fat)
865 grub_fs_register (&grub_fat_fs);
866 my_mod = mod;
869 GRUB_MOD_FINI(fat)
871 grub_fs_unregister (&grub_fat_fs);