2009-02-09 Felix Zielcke <fzielcke@z-51.de>
[grub2/phcoder.git] / fs / fat.c
blob6b39ef0f673c52455fd360a44e7e06387743aa9b
1 /* fat.c - FAT filesystem */
2 /*
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2000,2001,2002,2003,2004,2005,2007,2008 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)
50 struct grub_fat_bpb
52 grub_uint8_t jmp_boot[3];
53 grub_uint8_t oem_name[8];
54 grub_uint16_t bytes_per_sector;
55 grub_uint8_t sectors_per_cluster;
56 grub_uint16_t num_reserved_sectors;
57 grub_uint8_t num_fats;
58 grub_uint16_t num_root_entries;
59 grub_uint16_t num_total_sectors_16;
60 grub_uint8_t media;
61 grub_uint16_t sectors_per_fat_16;
62 grub_uint16_t sectors_per_track;
63 grub_uint16_t num_heads;
64 grub_uint32_t num_hidden_sectors;
65 grub_uint32_t num_total_sectors_32;
66 union
68 struct
70 grub_uint8_t num_ph_drive;
71 grub_uint8_t reserved;
72 grub_uint8_t boot_sig;
73 grub_uint32_t num_serial;
74 grub_uint8_t label[11];
75 grub_uint8_t fstype[8];
76 } __attribute__ ((packed)) fat12_or_fat16;
77 struct
79 grub_uint32_t sectors_per_fat_32;
80 grub_uint16_t extended_flags;
81 grub_uint16_t fs_version;
82 grub_uint32_t root_cluster;
83 grub_uint16_t fs_info;
84 grub_uint16_t backup_boot_sector;
85 grub_uint8_t reserved[12];
86 grub_uint8_t num_ph_drive;
87 grub_uint8_t reserved1;
88 grub_uint8_t boot_sig;
89 grub_uint32_t num_serial;
90 grub_uint8_t label[11];
91 grub_uint8_t fstype[8];
92 } __attribute__ ((packed)) fat32;
93 } __attribute__ ((packed)) version_specific;
94 } __attribute__ ((packed));
96 struct grub_fat_dir_entry
98 grub_uint8_t name[11];
99 grub_uint8_t attr;
100 grub_uint8_t nt_reserved;
101 grub_uint8_t c_time_tenth;
102 grub_uint16_t c_time;
103 grub_uint16_t c_date;
104 grub_uint16_t a_date;
105 grub_uint16_t first_cluster_high;
106 grub_uint16_t w_time;
107 grub_uint16_t w_date;
108 grub_uint16_t first_cluster_low;
109 grub_uint32_t file_size;
110 } __attribute__ ((packed));
112 struct grub_fat_long_name_entry
114 grub_uint8_t id;
115 grub_uint16_t name1[5];
116 grub_uint8_t attr;
117 grub_uint8_t reserved;
118 grub_uint8_t checksum;
119 grub_uint16_t name2[6];
120 grub_uint16_t first_cluster;
121 grub_uint16_t name3[2];
122 } __attribute__ ((packed));
124 struct grub_fat_data
126 int logical_sector_bits;
127 grub_uint32_t num_sectors;
129 grub_uint16_t fat_sector;
130 grub_uint32_t sectors_per_fat;
131 int fat_size;
133 grub_uint32_t root_cluster;
134 grub_uint32_t root_sector;
135 grub_uint32_t num_root_sectors;
137 int cluster_bits;
138 grub_uint32_t cluster_eof_mark;
139 grub_uint32_t cluster_sector;
140 grub_uint32_t num_clusters;
142 grub_uint8_t attr;
143 grub_ssize_t file_size;
144 grub_uint32_t file_cluster;
145 grub_uint32_t cur_cluster_num;
146 grub_uint32_t cur_cluster;
148 grub_uint32_t uuid;
151 #ifndef GRUB_UTIL
152 static grub_dl_t my_mod;
153 #endif
155 static int
156 fat_log2 (unsigned x)
158 int i;
160 if (x == 0)
161 return -1;
163 for (i = 0; (x & 1) == 0; i++)
164 x >>= 1;
166 if (x != 1)
167 return -1;
169 return i;
172 static struct grub_fat_data *
173 grub_fat_mount (grub_disk_t disk)
175 struct grub_fat_bpb bpb;
176 struct grub_fat_data *data = 0;
177 grub_uint32_t first_fat, magic;
179 if (! disk)
180 goto fail;
182 data = (struct grub_fat_data *) grub_malloc (sizeof (*data));
183 if (! data)
184 goto fail;
186 /* Read the BPB. */
187 if (grub_disk_read (disk, 0, 0, sizeof (bpb), (char *) &bpb))
188 goto fail;
190 if (! grub_strncmp((const char *) bpb.version_specific.fat12_or_fat16.fstype, "FAT12",5)
191 || ! grub_strncmp((const char *) bpb.version_specific.fat12_or_fat16.fstype, "FAT16",5)
192 || ! grub_strncmp((const char *) bpb.version_specific.fat32.fstype, "FAT32",5))
193 goto fail;
195 /* Get the sizes of logical sectors and clusters. */
196 data->logical_sector_bits =
197 fat_log2 (grub_le_to_cpu16 (bpb.bytes_per_sector));
198 if (data->logical_sector_bits < GRUB_DISK_SECTOR_BITS)
199 goto fail;
200 data->logical_sector_bits -= GRUB_DISK_SECTOR_BITS;
202 data->cluster_bits = fat_log2 (bpb.sectors_per_cluster);
203 if (data->cluster_bits < 0)
204 goto fail;
205 data->cluster_bits += data->logical_sector_bits;
207 /* Get information about FATs. */
208 data->fat_sector = (grub_le_to_cpu16 (bpb.num_reserved_sectors)
209 << data->logical_sector_bits);
210 if (data->fat_sector == 0)
211 goto fail;
213 data->sectors_per_fat = ((bpb.sectors_per_fat_16
214 ? grub_le_to_cpu16 (bpb.sectors_per_fat_16)
215 : grub_le_to_cpu32 (bpb.version_specific.fat32.sectors_per_fat_32))
216 << data->logical_sector_bits);
217 if (data->sectors_per_fat == 0)
218 goto fail;
220 /* Get the number of sectors in this volume. */
221 data->num_sectors = ((bpb.num_total_sectors_16
222 ? grub_le_to_cpu16 (bpb.num_total_sectors_16)
223 : grub_le_to_cpu32 (bpb.num_total_sectors_32))
224 << data->logical_sector_bits);
225 if (data->num_sectors == 0)
226 goto fail;
228 /* Get information about the root directory. */
229 if (bpb.num_fats == 0)
230 goto fail;
232 data->root_sector = data->fat_sector + bpb.num_fats * data->sectors_per_fat;
233 data->num_root_sectors
234 = ((((grub_uint32_t) grub_le_to_cpu16 (bpb.num_root_entries)
235 * GRUB_FAT_DIR_ENTRY_SIZE
236 + grub_le_to_cpu16 (bpb.bytes_per_sector) - 1)
237 >> (data->logical_sector_bits + GRUB_DISK_SECTOR_BITS))
238 << (data->logical_sector_bits));
240 data->cluster_sector = data->root_sector + data->num_root_sectors;
241 data->num_clusters = (((data->num_sectors - data->cluster_sector)
242 >> (data->cluster_bits + data->logical_sector_bits))
243 + 2);
245 if (data->num_clusters <= 2)
246 goto fail;
248 if (! bpb.sectors_per_fat_16)
250 /* FAT32. */
251 grub_uint16_t flags = grub_le_to_cpu16 (bpb.version_specific.fat32.extended_flags);
253 data->root_cluster = grub_le_to_cpu32 (bpb.version_specific.fat32.root_cluster);
254 data->fat_size = 32;
255 data->cluster_eof_mark = 0x0ffffff8;
257 if (flags & 0x80)
259 /* Get an active FAT. */
260 unsigned active_fat = flags & 0xf;
262 if (active_fat > bpb.num_fats)
263 goto fail;
265 data->fat_sector += active_fat * data->sectors_per_fat;
268 if (bpb.num_root_entries != 0 || bpb.version_specific.fat32.fs_version != 0)
269 goto fail;
271 else
273 /* FAT12 or FAT16. */
274 data->root_cluster = ~0U;
276 if (data->num_clusters <= 4085 + 2)
278 /* FAT12. */
279 data->fat_size = 12;
280 data->cluster_eof_mark = 0x0ff8;
282 else
284 /* FAT16. */
285 data->fat_size = 16;
286 data->cluster_eof_mark = 0xfff8;
290 /* More sanity checks. */
291 if (data->num_sectors <= data->fat_sector)
292 goto fail;
294 if (grub_disk_read (disk,
295 data->fat_sector,
297 sizeof (first_fat),
298 (char *) &first_fat))
299 goto fail;
301 first_fat = grub_le_to_cpu32 (first_fat);
303 if (data->fat_size == 32)
305 first_fat &= 0x0fffffff;
306 magic = 0x0fffff00;
308 else if (data->fat_size == 16)
310 first_fat &= 0x0000ffff;
311 magic = 0xff00;
313 else
315 first_fat &= 0x00000fff;
316 magic = 0x0f00;
319 /* Serial number. */
320 if (bpb.sectors_per_fat_16)
321 data->uuid = grub_le_to_cpu32 (bpb.version_specific.fat12_or_fat16.num_serial);
322 else
323 data->uuid = grub_le_to_cpu32 (bpb.version_specific.fat32.num_serial);
325 /* Ignore the 3rd bit, because some BIOSes assigns 0xF0 to the media
326 descriptor, even if it is a so-called superfloppy (e.g. an USB key).
327 The check may be too strict for this kind of stupid BIOSes, as
328 they overwrite the media descriptor. */
329 if ((first_fat | 0x8) != (magic | bpb.media | 0x8))
330 goto fail;
332 /* Start from the root directory. */
333 data->file_cluster = data->root_cluster;
334 data->cur_cluster_num = ~0U;
335 data->attr = GRUB_FAT_ATTR_DIRECTORY;
336 return data;
338 fail:
340 grub_free (data);
341 grub_error (GRUB_ERR_BAD_FS, "not a fat filesystem");
342 return 0;
345 static grub_ssize_t
346 grub_fat_read_data (grub_disk_t disk, struct grub_fat_data *data,
347 void NESTED_FUNC_ATTR (*read_hook) (grub_disk_addr_t sector,
348 unsigned offset, unsigned length),
349 grub_off_t offset, grub_size_t len, char *buf)
351 grub_size_t size;
352 grub_uint32_t logical_cluster;
353 unsigned logical_cluster_bits;
354 grub_ssize_t ret = 0;
355 unsigned long sector;
357 /* This is a special case. FAT12 and FAT16 doesn't have the root directory
358 in clusters. */
359 if (data->file_cluster == ~0U)
361 size = (data->num_root_sectors << GRUB_DISK_SECTOR_BITS) - offset;
362 if (size > len)
363 size = len;
365 if (grub_disk_read (disk, data->root_sector, offset, size, buf))
366 return -1;
368 return size;
371 /* Calculate the logical cluster number and offset. */
372 logical_cluster_bits = (data->cluster_bits
373 + data->logical_sector_bits
374 + GRUB_DISK_SECTOR_BITS);
375 logical_cluster = offset >> logical_cluster_bits;
376 offset &= (1 << logical_cluster_bits) - 1;
378 if (logical_cluster < data->cur_cluster_num)
380 data->cur_cluster_num = 0;
381 data->cur_cluster = data->file_cluster;
384 while (len)
386 while (logical_cluster > data->cur_cluster_num)
388 /* Find next cluster. */
389 grub_uint32_t next_cluster;
390 unsigned long fat_offset;
392 switch (data->fat_size)
394 case 32:
395 fat_offset = data->cur_cluster << 2;
396 break;
397 case 16:
398 fat_offset = data->cur_cluster << 1;
399 break;
400 default:
401 /* case 12: */
402 fat_offset = data->cur_cluster + (data->cur_cluster >> 1);
403 break;
406 /* Read the FAT. */
407 if (grub_disk_read (disk, data->fat_sector, fat_offset,
408 (data->fat_size + 7) >> 3,
409 (char *) &next_cluster))
410 return -1;
412 next_cluster = grub_le_to_cpu32 (next_cluster);
413 switch (data->fat_size)
415 case 16:
416 next_cluster &= 0xFFFF;
417 break;
418 case 12:
419 if (data->cur_cluster & 1)
420 next_cluster >>= 4;
422 next_cluster &= 0x0FFF;
423 break;
426 #if 0
427 grub_printf ("%s:%d: fat_size=%d, next_cluster=%u\n",
428 __FILE__, __LINE__, data->fat_size, next_cluster);
429 #endif
431 /* Check the end. */
432 if (next_cluster >= data->cluster_eof_mark)
433 return ret;
435 if (next_cluster < 2 || next_cluster >= data->num_clusters)
437 grub_error (GRUB_ERR_BAD_FS, "invalid cluster %u",
438 next_cluster);
439 return -1;
442 data->cur_cluster = next_cluster;
443 data->cur_cluster_num++;
446 /* Read the data here. */
447 sector = (data->cluster_sector
448 + ((data->cur_cluster - 2)
449 << (data->cluster_bits + data->logical_sector_bits)));
450 size = (1 << logical_cluster_bits) - offset;
451 if (size > len)
452 size = len;
454 disk->read_hook = read_hook;
455 grub_disk_read (disk, sector, offset, size, buf);
456 disk->read_hook = 0;
457 if (grub_errno)
458 return -1;
460 len -= size;
461 buf += size;
462 ret += size;
463 logical_cluster++;
464 offset = 0;
467 return ret;
470 /* Find the underlying directory or file in PATH and return the
471 next path. If there is no next path or an error occurs, return NULL.
472 If HOOK is specified, call it with each file name. */
473 static char *
474 grub_fat_find_dir (grub_disk_t disk, struct grub_fat_data *data,
475 const char *path,
476 int (*hook) (const char *filename, int dir))
478 struct grub_fat_dir_entry dir;
479 char *dirname, *dirp;
480 char *filename, *filep = 0;
481 grub_uint16_t *unibuf;
482 int slot = -1, slots = -1;
483 int checksum = -1;
484 grub_ssize_t offset = -sizeof(dir);
485 int call_hook;
487 if (! (data->attr & GRUB_FAT_ATTR_DIRECTORY))
489 grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a directory");
490 return 0;
493 /* Extract a directory name. */
494 while (*path == '/')
495 path++;
497 dirp = grub_strchr (path, '/');
498 if (dirp)
500 unsigned len = dirp - path;
502 dirname = grub_malloc (len + 1);
503 if (! dirname)
504 return 0;
506 grub_memcpy (dirname, path, len);
507 dirname[len] = '\0';
509 else
510 /* This is actually a file. */
511 dirname = grub_strdup (path);
513 call_hook = (! dirp && hook);
515 /* Allocate space enough to hold a long name. */
516 filename = grub_malloc (0x40 * 13 * 4 + 1);
517 unibuf = (grub_uint16_t *) grub_malloc (0x40 * 13 * 2);
518 if (! filename || ! unibuf)
520 grub_free (filename);
521 grub_free (unibuf);
522 grub_free (dirname);
523 return 0;
526 while (1)
528 unsigned i;
530 /* Adjust the offset. */
531 offset += sizeof (dir);
533 /* Read a directory entry. */
534 if ((grub_fat_read_data (disk, data, 0,
535 offset, sizeof (dir), (char *) &dir)
536 != sizeof (dir))
537 || dir.name[0] == 0)
539 if (grub_errno == GRUB_ERR_NONE && ! call_hook)
540 grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found");
542 break;
545 /* Handle long name entries. */
546 if (dir.attr == GRUB_FAT_ATTR_LONG_NAME)
548 struct grub_fat_long_name_entry *long_name
549 = (struct grub_fat_long_name_entry *) &dir;
550 grub_uint8_t id = long_name->id;
552 if (id & 0x40)
554 id &= 0x3f;
555 slots = slot = id;
556 checksum = long_name->checksum;
559 if (id != slot || slot == 0 || checksum != long_name->checksum)
561 checksum = -1;
562 continue;
565 slot--;
566 grub_memcpy (unibuf + slot * 13, long_name->name1, 5 * 2);
567 grub_memcpy (unibuf + slot * 13 + 5, long_name->name2, 6 * 2);
568 grub_memcpy (unibuf + slot * 13 + 11, long_name->name3, 2 * 2);
569 continue;
572 /* Check if this entry is valid. */
573 if (dir.name[0] == 0xe5 || (dir.attr & ~GRUB_FAT_ATTR_VALID))
574 continue;
576 /* This is a workaround for Japanese. */
577 if (dir.name[0] == 0x05)
578 dir.name[0] = 0xe5;
580 if (checksum != -1 && slot == 0)
582 grub_uint8_t sum;
584 for (sum = 0, i = 0; i < sizeof (dir.name); i++)
585 sum = ((sum >> 1) | (sum << 7)) + dir.name[i];
587 if (sum == checksum)
589 int u;
591 for (u = 0; u < slots * 13; u++)
592 unibuf[u] = grub_le_to_cpu16 (unibuf[u]);
594 *grub_utf16_to_utf8 ((grub_uint8_t *) filename, unibuf,
595 slots * 13) = '\0';
597 if (*dirname == '\0' && call_hook)
599 if (hook (filename, dir.attr & GRUB_FAT_ATTR_DIRECTORY))
600 break;
602 checksum = -1;
603 continue;
606 if (grub_strcmp (dirname, filename) == 0)
608 if (call_hook)
609 hook (filename, dir.attr & GRUB_FAT_ATTR_DIRECTORY);
611 break;
615 checksum = -1;
618 /* Convert the 8.3 file name. */
619 filep = filename;
621 for (i = 0; i < 8 && dir.name[i] && ! grub_isspace (dir.name[i]); i++)
622 *filep++ = grub_tolower (dir.name[i]);
624 *filep = '.';
626 for (i = 8; i < 11 && dir.name[i] && ! grub_isspace (dir.name[i]); i++)
627 *++filep = grub_tolower (dir.name[i]);
629 if (*filep != '.')
630 filep++;
632 *filep = '\0';
634 if (*dirname == '\0' && call_hook)
636 if (hook (filename, dir.attr & GRUB_FAT_ATTR_DIRECTORY))
637 break;
639 else if (grub_strncasecmp (dirname, filename, GRUB_FAT_MAXFILE) == 0)
641 if (call_hook)
642 hook (filename, dir.attr & GRUB_FAT_ATTR_DIRECTORY);
644 break;
648 grub_free (filename);
649 grub_free (dirname);
651 data->attr = dir.attr;
652 data->file_size = grub_le_to_cpu32 (dir.file_size);
653 data->file_cluster = ((grub_le_to_cpu16 (dir.first_cluster_high) << 16)
654 | grub_le_to_cpu16 (dir.first_cluster_low));
655 data->cur_cluster_num = ~0U;
657 return dirp;
660 static grub_err_t
661 grub_fat_dir (grub_device_t device, const char *path,
662 int (*hook) (const char *filename, int dir))
664 struct grub_fat_data *data = 0;
665 grub_disk_t disk = device->disk;
666 grub_size_t len;
667 char *dirname = 0;
668 char *p;
670 #ifndef GRUB_UTIL
671 grub_dl_ref (my_mod);
672 #endif
674 data = grub_fat_mount (disk);
675 if (! data)
676 goto fail;
678 /* Make sure that DIRNAME terminates with '/'. */
679 len = grub_strlen (path);
680 dirname = grub_malloc (len + 1 + 1);
681 if (! dirname)
682 goto fail;
683 grub_memcpy (dirname, path, len);
684 p = dirname + len;
685 if (path[len - 1] != '/')
686 *p++ = '/';
687 *p = '\0';
688 p = dirname;
692 p = grub_fat_find_dir (disk, data, p, hook);
694 while (p && grub_errno == GRUB_ERR_NONE);
696 fail:
698 grub_free (dirname);
699 grub_free (data);
701 #ifndef GRUB_UTIL
702 grub_dl_unref (my_mod);
703 #endif
705 return grub_errno;
708 static grub_err_t
709 grub_fat_open (grub_file_t file, const char *name)
711 struct grub_fat_data *data = 0;
712 char *p = (char *) name;
714 #ifndef GRUB_UTIL
715 grub_dl_ref (my_mod);
716 #endif
718 data = grub_fat_mount (file->device->disk);
719 if (! data)
720 goto fail;
724 p = grub_fat_find_dir (file->device->disk, data, p, 0);
725 if (grub_errno != GRUB_ERR_NONE)
726 goto fail;
728 while (p);
730 if (data->attr & GRUB_FAT_ATTR_DIRECTORY)
732 grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a file");
733 goto fail;
736 file->data = data;
737 file->size = data->file_size;
739 return GRUB_ERR_NONE;
741 fail:
743 grub_free (data);
745 #ifndef GRUB_UTIL
746 grub_dl_unref (my_mod);
747 #endif
749 return grub_errno;
752 static grub_ssize_t
753 grub_fat_read (grub_file_t file, char *buf, grub_size_t len)
755 return grub_fat_read_data (file->device->disk, file->data, file->read_hook,
756 file->offset, len, buf);
759 static grub_err_t
760 grub_fat_close (grub_file_t file)
762 grub_free (file->data);
764 #ifndef GRUB_UTIL
765 grub_dl_unref (my_mod);
766 #endif
768 return grub_errno;
771 static grub_err_t
772 grub_fat_label (grub_device_t device, char **label)
774 struct grub_fat_data *data;
775 grub_disk_t disk = device->disk;
776 grub_ssize_t offset = -sizeof(struct grub_fat_dir_entry);
779 #ifndef GRUB_UTIL
780 grub_dl_ref (my_mod);
781 #endif
783 data = grub_fat_mount (disk);
784 if (! data)
785 goto fail;
787 if (! (data->attr & GRUB_FAT_ATTR_DIRECTORY))
789 grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a directory");
790 return 0;
793 while (1)
795 struct grub_fat_dir_entry dir;
797 /* Adjust the offset. */
798 offset += sizeof (dir);
800 /* Read a directory entry. */
801 if ((grub_fat_read_data (disk, data, 0,
802 offset, sizeof (dir), (char *) &dir)
803 != sizeof (dir))
804 || dir.name[0] == 0)
806 if (grub_errno != GRUB_ERR_NONE)
807 goto fail;
808 else
810 *label = 0;
811 return GRUB_ERR_NONE;
815 if (dir.attr == GRUB_FAT_ATTR_VOLUME_ID)
817 *label = grub_strndup ((char *) dir.name, 11);
818 return GRUB_ERR_NONE;
822 *label = 0;
824 fail:
826 #ifndef GRUB_UTIL
827 grub_dl_unref (my_mod);
828 #endif
830 grub_free (data);
832 return grub_errno;
835 static grub_err_t
836 grub_fat_uuid (grub_device_t device, char **uuid)
838 struct grub_fat_data *data;
839 grub_disk_t disk = device->disk;
841 #ifndef GRUB_UTIL
842 grub_dl_ref (my_mod);
843 #endif
845 data = grub_fat_mount (disk);
846 if (data)
848 *uuid = grub_malloc (sizeof ("xxxx-xxxx"));
849 grub_sprintf (*uuid, "%04x-%04x", (grub_uint16_t) (data->uuid >> 16),
850 (grub_uint16_t) data->uuid);
852 else
853 *uuid = NULL;
855 #ifndef GRUB_UTIL
856 grub_dl_unref (my_mod);
857 #endif
859 grub_free (data);
861 return grub_errno;
864 static struct grub_fs grub_fat_fs =
866 .name = "fat",
867 .dir = grub_fat_dir,
868 .open = grub_fat_open,
869 .read = grub_fat_read,
870 .close = grub_fat_close,
871 .label = grub_fat_label,
872 .uuid = grub_fat_uuid,
873 .next = 0
876 GRUB_MOD_INIT(fat)
878 grub_fs_register (&grub_fat_fs);
879 #ifndef GRUB_UTIL
880 my_mod = mod;
881 #endif
884 GRUB_MOD_FINI(fat)
886 grub_fs_unregister (&grub_fat_fs);