2008-11-22 Robert Millan <rmh@aybabtu.com>
[grub2/phcoder/solaris.git] / fs / fat.c
blob8db176009d857ecc71126454f3eb765a6fc06e82
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 /* Get the sizes of logical sectors and clusters. */
191 data->logical_sector_bits =
192 fat_log2 (grub_le_to_cpu16 (bpb.bytes_per_sector));
193 if (data->logical_sector_bits < GRUB_DISK_SECTOR_BITS)
194 goto fail;
195 data->logical_sector_bits -= GRUB_DISK_SECTOR_BITS;
197 data->cluster_bits = fat_log2 (bpb.sectors_per_cluster);
198 if (data->cluster_bits < 0)
199 goto fail;
200 data->cluster_bits += data->logical_sector_bits;
202 /* Get information about FATs. */
203 data->fat_sector = (grub_le_to_cpu16 (bpb.num_reserved_sectors)
204 << data->logical_sector_bits);
205 if (data->fat_sector == 0)
206 goto fail;
208 data->sectors_per_fat = ((bpb.sectors_per_fat_16
209 ? grub_le_to_cpu16 (bpb.sectors_per_fat_16)
210 : grub_le_to_cpu32 (bpb.version_specific.fat32.sectors_per_fat_32))
211 << data->logical_sector_bits);
212 if (data->sectors_per_fat == 0)
213 goto fail;
215 /* Get the number of sectors in this volume. */
216 data->num_sectors = ((bpb.num_total_sectors_16
217 ? grub_le_to_cpu16 (bpb.num_total_sectors_16)
218 : grub_le_to_cpu32 (bpb.num_total_sectors_32))
219 << data->logical_sector_bits);
220 if (data->num_sectors == 0)
221 goto fail;
223 /* Get information about the root directory. */
224 if (bpb.num_fats == 0)
225 goto fail;
227 data->root_sector = data->fat_sector + bpb.num_fats * data->sectors_per_fat;
228 data->num_root_sectors
229 = ((((grub_uint32_t) grub_le_to_cpu16 (bpb.num_root_entries)
230 * GRUB_FAT_DIR_ENTRY_SIZE
231 + grub_le_to_cpu16 (bpb.bytes_per_sector) - 1)
232 >> (data->logical_sector_bits + GRUB_DISK_SECTOR_BITS))
233 << (data->logical_sector_bits));
235 data->cluster_sector = data->root_sector + data->num_root_sectors;
236 data->num_clusters = (((data->num_sectors - data->cluster_sector)
237 >> (data->cluster_bits + data->logical_sector_bits))
238 + 2);
240 if (data->num_clusters <= 2)
241 goto fail;
243 if (! bpb.sectors_per_fat_16)
245 /* FAT32. */
246 grub_uint16_t flags = grub_le_to_cpu16 (bpb.version_specific.fat32.extended_flags);
248 data->root_cluster = grub_le_to_cpu32 (bpb.version_specific.fat32.root_cluster);
249 data->fat_size = 32;
250 data->cluster_eof_mark = 0x0ffffff8;
252 if (flags & 0x80)
254 /* Get an active FAT. */
255 unsigned active_fat = flags & 0xf;
257 if (active_fat > bpb.num_fats)
258 goto fail;
260 data->fat_sector += active_fat * data->sectors_per_fat;
263 if (bpb.num_root_entries != 0 || bpb.version_specific.fat32.fs_version != 0)
264 goto fail;
266 else
268 /* FAT12 or FAT16. */
269 data->root_cluster = ~0U;
271 if (data->num_clusters <= 4085 + 2)
273 /* FAT12. */
274 data->fat_size = 12;
275 data->cluster_eof_mark = 0x0ff8;
277 else
279 /* FAT16. */
280 data->fat_size = 16;
281 data->cluster_eof_mark = 0xfff8;
285 /* More sanity checks. */
286 if (data->num_sectors <= data->fat_sector)
287 goto fail;
289 if (grub_disk_read (disk,
290 data->fat_sector,
292 sizeof (first_fat),
293 (char *) &first_fat))
294 goto fail;
296 first_fat = grub_le_to_cpu32 (first_fat);
298 if (data->fat_size == 32)
300 first_fat &= 0x0fffffff;
301 magic = 0x0fffff00;
303 else if (data->fat_size == 16)
305 first_fat &= 0x0000ffff;
306 magic = 0xff00;
308 else
310 first_fat &= 0x00000fff;
311 magic = 0x0f00;
314 /* Serial number. */
315 if (bpb.sectors_per_fat_16)
316 data->uuid = grub_le_to_cpu32 (bpb.version_specific.fat12_or_fat16.num_serial);
317 else
318 data->uuid = grub_le_to_cpu32 (bpb.version_specific.fat32.num_serial);
320 /* Ignore the 3rd bit, because some BIOSes assigns 0xF0 to the media
321 descriptor, even if it is a so-called superfloppy (e.g. an USB key).
322 The check may be too strict for this kind of stupid BIOSes, as
323 they overwrite the media descriptor. */
324 if ((first_fat | 0x8) != (magic | bpb.media | 0x8))
325 goto fail;
327 /* Start from the root directory. */
328 data->file_cluster = data->root_cluster;
329 data->cur_cluster_num = ~0U;
330 data->attr = GRUB_FAT_ATTR_DIRECTORY;
331 return data;
333 fail:
335 grub_free (data);
336 grub_error (GRUB_ERR_BAD_FS, "not a fat filesystem");
337 return 0;
340 static grub_ssize_t
341 grub_fat_read_data (grub_disk_t disk, struct grub_fat_data *data,
342 void NESTED_FUNC_ATTR (*read_hook) (grub_disk_addr_t sector,
343 unsigned offset, unsigned length),
344 grub_off_t offset, grub_size_t len, char *buf)
346 grub_size_t size;
347 grub_uint32_t logical_cluster;
348 unsigned logical_cluster_bits;
349 grub_ssize_t ret = 0;
350 unsigned long sector;
352 /* This is a special case. FAT12 and FAT16 doesn't have the root directory
353 in clusters. */
354 if (data->file_cluster == ~0U)
356 size = (data->num_root_sectors << GRUB_DISK_SECTOR_BITS) - offset;
357 if (size > len)
358 size = len;
360 if (grub_disk_read (disk, data->root_sector, offset, size, buf))
361 return -1;
363 return size;
366 /* Calculate the logical cluster number and offset. */
367 logical_cluster_bits = (data->cluster_bits
368 + data->logical_sector_bits
369 + GRUB_DISK_SECTOR_BITS);
370 logical_cluster = offset >> logical_cluster_bits;
371 offset &= (1 << logical_cluster_bits) - 1;
373 if (logical_cluster < data->cur_cluster_num)
375 data->cur_cluster_num = 0;
376 data->cur_cluster = data->file_cluster;
379 while (len)
381 while (logical_cluster > data->cur_cluster_num)
383 /* Find next cluster. */
384 grub_uint32_t next_cluster;
385 unsigned long fat_offset;
387 switch (data->fat_size)
389 case 32:
390 fat_offset = data->cur_cluster << 2;
391 break;
392 case 16:
393 fat_offset = data->cur_cluster << 1;
394 break;
395 default:
396 /* case 12: */
397 fat_offset = data->cur_cluster + (data->cur_cluster >> 1);
398 break;
401 /* Read the FAT. */
402 if (grub_disk_read (disk, data->fat_sector, fat_offset,
403 (data->fat_size + 7) >> 3,
404 (char *) &next_cluster))
405 return -1;
407 next_cluster = grub_le_to_cpu32 (next_cluster);
408 switch (data->fat_size)
410 case 16:
411 next_cluster &= 0xFFFF;
412 break;
413 case 12:
414 if (data->cur_cluster & 1)
415 next_cluster >>= 4;
417 next_cluster &= 0x0FFF;
418 break;
421 #if 0
422 grub_printf ("%s:%d: fat_size=%d, next_cluster=%u\n",
423 __FILE__, __LINE__, data->fat_size, next_cluster);
424 #endif
426 /* Check the end. */
427 if (next_cluster >= data->cluster_eof_mark)
428 return ret;
430 if (next_cluster < 2 || next_cluster >= data->num_clusters)
432 grub_error (GRUB_ERR_BAD_FS, "invalid cluster %u",
433 next_cluster);
434 return -1;
437 data->cur_cluster = next_cluster;
438 data->cur_cluster_num++;
441 /* Read the data here. */
442 sector = (data->cluster_sector
443 + ((data->cur_cluster - 2)
444 << (data->cluster_bits + data->logical_sector_bits)));
445 size = (1 << logical_cluster_bits) - offset;
446 if (size > len)
447 size = len;
449 disk->read_hook = read_hook;
450 grub_disk_read (disk, sector, offset, size, buf);
451 disk->read_hook = 0;
452 if (grub_errno)
453 return -1;
455 len -= size;
456 buf += size;
457 ret += size;
458 logical_cluster++;
459 offset = 0;
462 return ret;
465 /* Find the underlying directory or file in PATH and return the
466 next path. If there is no next path or an error occurs, return NULL.
467 If HOOK is specified, call it with each file name. */
468 static char *
469 grub_fat_find_dir (grub_disk_t disk, struct grub_fat_data *data,
470 const char *path,
471 int (*hook) (const char *filename, int dir))
473 struct grub_fat_dir_entry dir;
474 char *dirname, *dirp;
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);
480 int call_hook;
482 if (! (data->attr & GRUB_FAT_ATTR_DIRECTORY))
484 grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a directory");
485 return 0;
488 /* Extract a directory name. */
489 while (*path == '/')
490 path++;
492 dirp = grub_strchr (path, '/');
493 if (dirp)
495 unsigned len = dirp - path;
497 dirname = grub_malloc (len + 1);
498 if (! dirname)
499 return 0;
501 grub_memcpy (dirname, path, len);
502 dirname[len] = '\0';
504 else
505 /* This is actually a file. */
506 dirname = grub_strdup (path);
508 call_hook = (! dirp && hook);
510 /* Allocate space enough to hold a long name. */
511 filename = grub_malloc (0x40 * 13 * 4 + 1);
512 unibuf = (grub_uint16_t *) grub_malloc (0x40 * 13 * 2);
513 if (! filename || ! unibuf)
515 grub_free (filename);
516 grub_free (unibuf);
517 grub_free (dirname);
518 return 0;
521 while (1)
523 unsigned i;
525 /* Adjust the offset. */
526 offset += sizeof (dir);
528 /* Read a directory entry. */
529 if ((grub_fat_read_data (disk, data, 0,
530 offset, sizeof (dir), (char *) &dir)
531 != sizeof (dir))
532 || dir.name[0] == 0)
534 if (grub_errno == GRUB_ERR_NONE && ! call_hook)
535 grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found");
537 break;
540 /* Handle long name entries. */
541 if (dir.attr == GRUB_FAT_ATTR_LONG_NAME)
543 struct grub_fat_long_name_entry *long_name
544 = (struct grub_fat_long_name_entry *) &dir;
545 grub_uint8_t id = long_name->id;
547 if (id & 0x40)
549 id &= 0x3f;
550 slots = slot = id;
551 checksum = long_name->checksum;
554 if (id != slot || slot == 0 || checksum != long_name->checksum)
556 checksum = -1;
557 continue;
560 slot--;
561 grub_memcpy (unibuf + slot * 13, long_name->name1, 5 * 2);
562 grub_memcpy (unibuf + slot * 13 + 5, long_name->name2, 6 * 2);
563 grub_memcpy (unibuf + slot * 13 + 11, long_name->name3, 2 * 2);
564 continue;
567 /* Check if this entry is valid. */
568 if (dir.name[0] == 0xe5 || (dir.attr & ~GRUB_FAT_ATTR_VALID))
569 continue;
571 /* This is a workaround for Japanese. */
572 if (dir.name[0] == 0x05)
573 dir.name[0] = 0xe5;
575 if (checksum != -1 && slot == 0)
577 grub_uint8_t sum;
579 for (sum = 0, i = 0; i < sizeof (dir.name); i++)
580 sum = ((sum >> 1) | (sum << 7)) + dir.name[i];
582 if (sum == checksum)
584 int u;
586 for (u = 0; u < slots * 13; u++)
587 unibuf[u] = grub_le_to_cpu16 (unibuf[u]);
589 *grub_utf16_to_utf8 ((grub_uint8_t *) filename, unibuf,
590 slots * 13) = '\0';
592 if (*dirname == '\0' && call_hook)
594 if (hook (filename, dir.attr & GRUB_FAT_ATTR_DIRECTORY))
595 break;
597 checksum = -1;
598 continue;
601 if (grub_strcmp (dirname, filename) == 0)
603 if (call_hook)
604 hook (filename, dir.attr & GRUB_FAT_ATTR_DIRECTORY);
606 break;
610 checksum = -1;
613 /* Convert the 8.3 file name. */
614 filep = filename;
616 for (i = 0; i < 8 && dir.name[i] && ! grub_isspace (dir.name[i]); i++)
617 *filep++ = grub_tolower (dir.name[i]);
619 *filep = '.';
621 for (i = 8; i < 11 && dir.name[i] && ! grub_isspace (dir.name[i]); i++)
622 *++filep = grub_tolower (dir.name[i]);
624 if (*filep != '.')
625 filep++;
627 *filep = '\0';
629 if (*dirname == '\0' && call_hook)
631 if (hook (filename, dir.attr & GRUB_FAT_ATTR_DIRECTORY))
632 break;
634 else if (grub_strncasecmp (dirname, filename, GRUB_FAT_MAXFILE) == 0)
636 if (call_hook)
637 hook (filename, dir.attr & GRUB_FAT_ATTR_DIRECTORY);
639 break;
643 grub_free (filename);
644 grub_free (dirname);
646 data->attr = dir.attr;
647 data->file_size = grub_le_to_cpu32 (dir.file_size);
648 data->file_cluster = ((grub_le_to_cpu16 (dir.first_cluster_high) << 16)
649 | grub_le_to_cpu16 (dir.first_cluster_low));
650 data->cur_cluster_num = ~0U;
652 return dirp;
655 static grub_err_t
656 grub_fat_dir (grub_device_t device, const char *path,
657 int (*hook) (const char *filename, int dir))
659 struct grub_fat_data *data = 0;
660 grub_disk_t disk = device->disk;
661 grub_size_t len;
662 char *dirname = 0;
663 char *p;
665 #ifndef GRUB_UTIL
666 grub_dl_ref (my_mod);
667 #endif
669 data = grub_fat_mount (disk);
670 if (! data)
671 goto fail;
673 /* Make sure that DIRNAME terminates with '/'. */
674 len = grub_strlen (path);
675 dirname = grub_malloc (len + 1 + 1);
676 if (! dirname)
677 goto fail;
678 grub_memcpy (dirname, path, len);
679 p = dirname + len;
680 if (path[len - 1] != '/')
681 *p++ = '/';
682 *p = '\0';
683 p = dirname;
687 p = grub_fat_find_dir (disk, data, p, hook);
689 while (p && grub_errno == GRUB_ERR_NONE);
691 fail:
693 grub_free (dirname);
694 grub_free (data);
696 #ifndef GRUB_UTIL
697 grub_dl_unref (my_mod);
698 #endif
700 return grub_errno;
703 static grub_err_t
704 grub_fat_open (grub_file_t file, const char *name)
706 struct grub_fat_data *data = 0;
707 char *p = (char *) name;
709 #ifndef GRUB_UTIL
710 grub_dl_ref (my_mod);
711 #endif
713 data = grub_fat_mount (file->device->disk);
714 if (! data)
715 goto fail;
719 p = grub_fat_find_dir (file->device->disk, data, p, 0);
720 if (grub_errno != GRUB_ERR_NONE)
721 goto fail;
723 while (p);
725 if (data->attr & GRUB_FAT_ATTR_DIRECTORY)
727 grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a file");
728 goto fail;
731 file->data = data;
732 file->size = data->file_size;
734 return GRUB_ERR_NONE;
736 fail:
738 grub_free (data);
740 #ifndef GRUB_UTIL
741 grub_dl_unref (my_mod);
742 #endif
744 return grub_errno;
747 static grub_ssize_t
748 grub_fat_read (grub_file_t file, char *buf, grub_size_t len)
750 return grub_fat_read_data (file->device->disk, file->data, file->read_hook,
751 file->offset, len, buf);
754 static grub_err_t
755 grub_fat_close (grub_file_t file)
757 grub_free (file->data);
759 #ifndef GRUB_UTIL
760 grub_dl_unref (my_mod);
761 #endif
763 return grub_errno;
766 static grub_err_t
767 grub_fat_label (grub_device_t device, char **label)
769 struct grub_fat_data *data;
770 grub_disk_t disk = device->disk;
771 grub_ssize_t offset = -sizeof(struct grub_fat_dir_entry);
774 #ifndef GRUB_UTIL
775 grub_dl_ref (my_mod);
776 #endif
778 data = grub_fat_mount (disk);
779 if (! data)
780 goto fail;
782 if (! (data->attr & GRUB_FAT_ATTR_DIRECTORY))
784 grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a directory");
785 return 0;
788 while (1)
790 struct grub_fat_dir_entry dir;
792 /* Adjust the offset. */
793 offset += sizeof (dir);
795 /* Read a directory entry. */
796 if ((grub_fat_read_data (disk, data, 0,
797 offset, sizeof (dir), (char *) &dir)
798 != sizeof (dir))
799 || dir.name[0] == 0)
801 if (grub_errno != GRUB_ERR_NONE)
802 goto fail;
803 else
805 *label = 0;
806 return GRUB_ERR_NONE;
810 if (dir.attr == GRUB_FAT_ATTR_VOLUME_ID)
812 *label = grub_strndup ((char *) dir.name, 11);
813 return GRUB_ERR_NONE;
817 *label = 0;
819 fail:
821 #ifndef GRUB_UTIL
822 grub_dl_unref (my_mod);
823 #endif
825 grub_free (data);
827 return grub_errno;
830 static grub_err_t
831 grub_fat_uuid (grub_device_t device, char **uuid)
833 struct grub_fat_data *data;
834 grub_disk_t disk = device->disk;
836 #ifndef GRUB_UTIL
837 grub_dl_ref (my_mod);
838 #endif
840 data = grub_fat_mount (disk);
841 if (data)
843 *uuid = grub_malloc (sizeof ("xxxx-xxxx"));
844 grub_sprintf (*uuid, "%04x-%04x", (grub_uint16_t) (data->uuid >> 8),
845 (grub_uint16_t) data->uuid);
847 else
848 *uuid = NULL;
850 #ifndef GRUB_UTIL
851 grub_dl_unref (my_mod);
852 #endif
854 grub_free (data);
856 return grub_errno;
859 static struct grub_fs grub_fat_fs =
861 .name = "fat",
862 .dir = grub_fat_dir,
863 .open = grub_fat_open,
864 .read = grub_fat_read,
865 .close = grub_fat_close,
866 .label = grub_fat_label,
867 .uuid = grub_fat_uuid,
868 .next = 0
871 GRUB_MOD_INIT(fat)
873 grub_fs_register (&grub_fat_fs);
874 #ifndef GRUB_UTIL
875 my_mod = mod;
876 #endif
879 GRUB_MOD_FINI(fat)
881 grub_fs_unregister (&grub_fat_fs);