]> git.proxmox.com Git - grub2.git/blob - fs/fat.c
2009-02-14 Felix Zielcke <fzielcke@z-51.de>
[grub2.git] / 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
29 #define GRUB_FAT_DIR_ENTRY_SIZE 32
30
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
37
38 #define GRUB_FAT_MAXFILE 256
39
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
50 struct grub_fat_bpb
51 {
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
67 {
68 struct
69 {
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
78 {
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));
95
96 struct grub_fat_dir_entry
97 {
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));
111
112 struct grub_fat_long_name_entry
113 {
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));
123
124 struct grub_fat_data
125 {
126 int logical_sector_bits;
127 grub_uint32_t num_sectors;
128
129 grub_uint16_t fat_sector;
130 grub_uint32_t sectors_per_fat;
131 int fat_size;
132
133 grub_uint32_t root_cluster;
134 grub_uint32_t root_sector;
135 grub_uint32_t num_root_sectors;
136
137 int cluster_bits;
138 grub_uint32_t cluster_eof_mark;
139 grub_uint32_t cluster_sector;
140 grub_uint32_t num_clusters;
141
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;
147
148 grub_uint32_t uuid;
149 };
150
151 #ifndef GRUB_UTIL
152 static grub_dl_t my_mod;
153 #endif
154
155 static int
156 fat_log2 (unsigned x)
157 {
158 int i;
159
160 if (x == 0)
161 return -1;
162
163 for (i = 0; (x & 1) == 0; i++)
164 x >>= 1;
165
166 if (x != 1)
167 return -1;
168
169 return i;
170 }
171
172 static struct grub_fat_data *
173 grub_fat_mount (grub_disk_t disk)
174 {
175 struct grub_fat_bpb bpb;
176 struct grub_fat_data *data = 0;
177 grub_uint32_t first_fat, magic;
178
179 if (! disk)
180 goto fail;
181
182 data = (struct grub_fat_data *) grub_malloc (sizeof (*data));
183 if (! data)
184 goto fail;
185
186 /* Read the BPB. */
187 if (grub_disk_read (disk, 0, 0, sizeof (bpb), (char *) &bpb))
188 goto fail;
189
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;
194
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;
201
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;
206
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;
212
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;
219
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;
227
228 /* Get information about the root directory. */
229 if (bpb.num_fats == 0)
230 goto fail;
231
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));
239
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);
244
245 if (data->num_clusters <= 2)
246 goto fail;
247
248 if (! bpb.sectors_per_fat_16)
249 {
250 /* FAT32. */
251 grub_uint16_t flags = grub_le_to_cpu16 (bpb.version_specific.fat32.extended_flags);
252
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;
256
257 if (flags & 0x80)
258 {
259 /* Get an active FAT. */
260 unsigned active_fat = flags & 0xf;
261
262 if (active_fat > bpb.num_fats)
263 goto fail;
264
265 data->fat_sector += active_fat * data->sectors_per_fat;
266 }
267
268 if (bpb.num_root_entries != 0 || bpb.version_specific.fat32.fs_version != 0)
269 goto fail;
270 }
271 else
272 {
273 /* FAT12 or FAT16. */
274 data->root_cluster = ~0U;
275
276 if (data->num_clusters <= 4085 + 2)
277 {
278 /* FAT12. */
279 data->fat_size = 12;
280 data->cluster_eof_mark = 0x0ff8;
281 }
282 else
283 {
284 /* FAT16. */
285 data->fat_size = 16;
286 data->cluster_eof_mark = 0xfff8;
287 }
288 }
289
290 /* More sanity checks. */
291 if (data->num_sectors <= data->fat_sector)
292 goto fail;
293
294 if (grub_disk_read (disk,
295 data->fat_sector,
296 0,
297 sizeof (first_fat),
298 (char *) &first_fat))
299 goto fail;
300
301 first_fat = grub_le_to_cpu32 (first_fat);
302
303 if (data->fat_size == 32)
304 {
305 first_fat &= 0x0fffffff;
306 magic = 0x0fffff00;
307 }
308 else if (data->fat_size == 16)
309 {
310 first_fat &= 0x0000ffff;
311 magic = 0xff00;
312 }
313 else
314 {
315 first_fat &= 0x00000fff;
316 magic = 0x0f00;
317 }
318
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);
324
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;
331
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;
337
338 fail:
339
340 grub_free (data);
341 grub_error (GRUB_ERR_BAD_FS, "not a fat filesystem");
342 return 0;
343 }
344
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)
350 {
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;
356
357 /* This is a special case. FAT12 and FAT16 doesn't have the root directory
358 in clusters. */
359 if (data->file_cluster == ~0U)
360 {
361 size = (data->num_root_sectors << GRUB_DISK_SECTOR_BITS) - offset;
362 if (size > len)
363 size = len;
364
365 if (grub_disk_read (disk, data->root_sector, offset, size, buf))
366 return -1;
367
368 return size;
369 }
370
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;
377
378 if (logical_cluster < data->cur_cluster_num)
379 {
380 data->cur_cluster_num = 0;
381 data->cur_cluster = data->file_cluster;
382 }
383
384 while (len)
385 {
386 while (logical_cluster > data->cur_cluster_num)
387 {
388 /* Find next cluster. */
389 grub_uint32_t next_cluster;
390 unsigned long fat_offset;
391
392 switch (data->fat_size)
393 {
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;
404 }
405
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;
411
412 next_cluster = grub_le_to_cpu32 (next_cluster);
413 switch (data->fat_size)
414 {
415 case 16:
416 next_cluster &= 0xFFFF;
417 break;
418 case 12:
419 if (data->cur_cluster & 1)
420 next_cluster >>= 4;
421
422 next_cluster &= 0x0FFF;
423 break;
424 }
425
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
430
431 /* Check the end. */
432 if (next_cluster >= data->cluster_eof_mark)
433 return ret;
434
435 if (next_cluster < 2 || next_cluster >= data->num_clusters)
436 {
437 grub_error (GRUB_ERR_BAD_FS, "invalid cluster %u",
438 next_cluster);
439 return -1;
440 }
441
442 data->cur_cluster = next_cluster;
443 data->cur_cluster_num++;
444 }
445
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;
453
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;
459
460 len -= size;
461 buf += size;
462 ret += size;
463 logical_cluster++;
464 offset = 0;
465 }
466
467 return ret;
468 }
469
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))
477 {
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;
486
487 if (! (data->attr & GRUB_FAT_ATTR_DIRECTORY))
488 {
489 grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a directory");
490 return 0;
491 }
492
493 /* Extract a directory name. */
494 while (*path == '/')
495 path++;
496
497 dirp = grub_strchr (path, '/');
498 if (dirp)
499 {
500 unsigned len = dirp - path;
501
502 dirname = grub_malloc (len + 1);
503 if (! dirname)
504 return 0;
505
506 grub_memcpy (dirname, path, len);
507 dirname[len] = '\0';
508 }
509 else
510 /* This is actually a file. */
511 dirname = grub_strdup (path);
512
513 call_hook = (! dirp && hook);
514
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)
519 {
520 grub_free (filename);
521 grub_free (unibuf);
522 grub_free (dirname);
523 return 0;
524 }
525
526 while (1)
527 {
528 unsigned i;
529
530 /* Adjust the offset. */
531 offset += sizeof (dir);
532
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)
538 {
539 if (grub_errno == GRUB_ERR_NONE && ! call_hook)
540 grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found");
541
542 break;
543 }
544
545 /* Handle long name entries. */
546 if (dir.attr == GRUB_FAT_ATTR_LONG_NAME)
547 {
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;
551
552 if (id & 0x40)
553 {
554 id &= 0x3f;
555 slots = slot = id;
556 checksum = long_name->checksum;
557 }
558
559 if (id != slot || slot == 0 || checksum != long_name->checksum)
560 {
561 checksum = -1;
562 continue;
563 }
564
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;
570 }
571
572 /* Check if this entry is valid. */
573 if (dir.name[0] == 0xe5 || (dir.attr & ~GRUB_FAT_ATTR_VALID))
574 continue;
575
576 /* This is a workaround for Japanese. */
577 if (dir.name[0] == 0x05)
578 dir.name[0] = 0xe5;
579
580 if (checksum != -1 && slot == 0)
581 {
582 grub_uint8_t sum;
583
584 for (sum = 0, i = 0; i < sizeof (dir.name); i++)
585 sum = ((sum >> 1) | (sum << 7)) + dir.name[i];
586
587 if (sum == checksum)
588 {
589 int u;
590
591 for (u = 0; u < slots * 13; u++)
592 unibuf[u] = grub_le_to_cpu16 (unibuf[u]);
593
594 *grub_utf16_to_utf8 ((grub_uint8_t *) filename, unibuf,
595 slots * 13) = '\0';
596
597 if (*dirname == '\0' && call_hook)
598 {
599 if (hook (filename, dir.attr & GRUB_FAT_ATTR_DIRECTORY))
600 break;
601
602 checksum = -1;
603 continue;
604 }
605
606 if (grub_strcmp (dirname, filename) == 0)
607 {
608 if (call_hook)
609 hook (filename, dir.attr & GRUB_FAT_ATTR_DIRECTORY);
610
611 break;
612 }
613 }
614
615 checksum = -1;
616 }
617
618 /* Convert the 8.3 file name. */
619 filep = filename;
620
621 for (i = 0; i < 8 && dir.name[i] && ! grub_isspace (dir.name[i]); i++)
622 *filep++ = grub_tolower (dir.name[i]);
623
624 *filep = '.';
625
626 for (i = 8; i < 11 && dir.name[i] && ! grub_isspace (dir.name[i]); i++)
627 *++filep = grub_tolower (dir.name[i]);
628
629 if (*filep != '.')
630 filep++;
631
632 *filep = '\0';
633
634 if (*dirname == '\0' && call_hook)
635 {
636 if (hook (filename, dir.attr & GRUB_FAT_ATTR_DIRECTORY))
637 break;
638 }
639 else if (grub_strncasecmp (dirname, filename, GRUB_FAT_MAXFILE) == 0)
640 {
641 if (call_hook)
642 hook (filename, dir.attr & GRUB_FAT_ATTR_DIRECTORY);
643
644 break;
645 }
646 }
647
648 grub_free (filename);
649 grub_free (dirname);
650
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;
656
657 return dirp;
658 }
659
660 static grub_err_t
661 grub_fat_dir (grub_device_t device, const char *path,
662 int (*hook) (const char *filename, int dir))
663 {
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;
669
670 #ifndef GRUB_UTIL
671 grub_dl_ref (my_mod);
672 #endif
673
674 data = grub_fat_mount (disk);
675 if (! data)
676 goto fail;
677
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;
689
690 do
691 {
692 p = grub_fat_find_dir (disk, data, p, hook);
693 }
694 while (p && grub_errno == GRUB_ERR_NONE);
695
696 fail:
697
698 grub_free (dirname);
699 grub_free (data);
700
701 #ifndef GRUB_UTIL
702 grub_dl_unref (my_mod);
703 #endif
704
705 return grub_errno;
706 }
707
708 static grub_err_t
709 grub_fat_open (grub_file_t file, const char *name)
710 {
711 struct grub_fat_data *data = 0;
712 char *p = (char *) name;
713
714 #ifndef GRUB_UTIL
715 grub_dl_ref (my_mod);
716 #endif
717
718 data = grub_fat_mount (file->device->disk);
719 if (! data)
720 goto fail;
721
722 do
723 {
724 p = grub_fat_find_dir (file->device->disk, data, p, 0);
725 if (grub_errno != GRUB_ERR_NONE)
726 goto fail;
727 }
728 while (p);
729
730 if (data->attr & GRUB_FAT_ATTR_DIRECTORY)
731 {
732 grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a file");
733 goto fail;
734 }
735
736 file->data = data;
737 file->size = data->file_size;
738
739 return GRUB_ERR_NONE;
740
741 fail:
742
743 grub_free (data);
744
745 #ifndef GRUB_UTIL
746 grub_dl_unref (my_mod);
747 #endif
748
749 return grub_errno;
750 }
751
752 static grub_ssize_t
753 grub_fat_read (grub_file_t file, char *buf, grub_size_t len)
754 {
755 return grub_fat_read_data (file->device->disk, file->data, file->read_hook,
756 file->offset, len, buf);
757 }
758
759 static grub_err_t
760 grub_fat_close (grub_file_t file)
761 {
762 grub_free (file->data);
763
764 #ifndef GRUB_UTIL
765 grub_dl_unref (my_mod);
766 #endif
767
768 return grub_errno;
769 }
770
771 static grub_err_t
772 grub_fat_label (grub_device_t device, char **label)
773 {
774 struct grub_fat_data *data;
775 grub_disk_t disk = device->disk;
776 grub_ssize_t offset = -sizeof(struct grub_fat_dir_entry);
777
778
779 #ifndef GRUB_UTIL
780 grub_dl_ref (my_mod);
781 #endif
782
783 data = grub_fat_mount (disk);
784 if (! data)
785 goto fail;
786
787 if (! (data->attr & GRUB_FAT_ATTR_DIRECTORY))
788 {
789 grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a directory");
790 return 0;
791 }
792
793 while (1)
794 {
795 struct grub_fat_dir_entry dir;
796
797 /* Adjust the offset. */
798 offset += sizeof (dir);
799
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)
805 {
806 if (grub_errno != GRUB_ERR_NONE)
807 goto fail;
808 else
809 {
810 *label = 0;
811 return GRUB_ERR_NONE;
812 }
813 }
814
815 if (dir.attr == GRUB_FAT_ATTR_VOLUME_ID)
816 {
817 *label = grub_strndup ((char *) dir.name, 11);
818 return GRUB_ERR_NONE;
819 }
820 }
821
822 *label = 0;
823
824 fail:
825
826 #ifndef GRUB_UTIL
827 grub_dl_unref (my_mod);
828 #endif
829
830 grub_free (data);
831
832 return grub_errno;
833 }
834
835 static grub_err_t
836 grub_fat_uuid (grub_device_t device, char **uuid)
837 {
838 struct grub_fat_data *data;
839 grub_disk_t disk = device->disk;
840
841 #ifndef GRUB_UTIL
842 grub_dl_ref (my_mod);
843 #endif
844
845 data = grub_fat_mount (disk);
846 if (data)
847 {
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);
851 }
852 else
853 *uuid = NULL;
854
855 #ifndef GRUB_UTIL
856 grub_dl_unref (my_mod);
857 #endif
858
859 grub_free (data);
860
861 return grub_errno;
862 }
863
864 static struct grub_fs grub_fat_fs =
865 {
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
874 };
875
876 GRUB_MOD_INIT(fat)
877 {
878 grub_fs_register (&grub_fat_fs);
879 #ifndef GRUB_UTIL
880 my_mod = mod;
881 #endif
882 }
883
884 GRUB_MOD_FINI(fat)
885 {
886 grub_fs_unregister (&grub_fat_fs);
887 }
888