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 <r_fs.h>
21 #include <grub/fs.h>
22 #include <grub/fshelp.h>
23 #include <grub/disk.h>
24 #include <grub/file.h>
25 #include <grub/types.h>
26 #include <grub/misc.h>
27 #include <grub/mm.h>
28 #include <grub/err.h>
29 #include <grub/charset.h>
30
31 #define GRUB_FAT_DIR_ENTRY_SIZE 32
32
33 #define GRUB_FAT_ATTR_READ_ONLY 0x01
34 #define GRUB_FAT_ATTR_HIDDEN 0x02
35 #define GRUB_FAT_ATTR_SYSTEM 0x04
36 #define GRUB_FAT_ATTR_VOLUME_ID 0x08
37 #define GRUB_FAT_ATTR_DIRECTORY 0x10
38 #define GRUB_FAT_ATTR_ARCHIVE 0x20
39
40 #define GRUB_FAT_MAXFILE 256
41
42 #define GRUB_FAT_ATTR_LONG_NAME (GRUB_FAT_ATTR_READ_ONLY \
43 | GRUB_FAT_ATTR_HIDDEN \
44 | GRUB_FAT_ATTR_SYSTEM \
45 | GRUB_FAT_ATTR_VOLUME_ID)
46 #define GRUB_FAT_ATTR_VALID (GRUB_FAT_ATTR_READ_ONLY \
47 | GRUB_FAT_ATTR_HIDDEN \
48 | GRUB_FAT_ATTR_SYSTEM \
49 | GRUB_FAT_ATTR_DIRECTORY \
50 | GRUB_FAT_ATTR_ARCHIVE \
51 | GRUB_FAT_ATTR_VOLUME_ID)
52 R_PACKED(
53 struct grub_fat_bpb
54 {
55 grub_uint8_t jmp_boot[3];
56 grub_uint8_t oem_name[8];
57 grub_uint16_t bytes_per_sector;
58 grub_uint8_t sectors_per_cluster;
59 grub_uint16_t num_reserved_sectors;
60 grub_uint8_t num_fats;
61 grub_uint16_t num_root_entries;
62 grub_uint16_t num_total_sectors_16;
63 grub_uint8_t media;
64 grub_uint16_t sectors_per_fat_16;
65 grub_uint16_t sectors_per_track;
66 grub_uint16_t num_heads;
67 grub_uint32_t num_hidden_sectors;
68 grub_uint32_t num_total_sectors_32;
69 R_PACKED(
70 union
71 {
72 R_PACKED(
73 struct
74 {
75 grub_uint8_t num_ph_drive;
76 grub_uint8_t reserved;
77 grub_uint8_t boot_sig;
78 grub_uint32_t num_serial;
79 grub_uint8_t label[11];
80 grub_uint8_t fstype[8];
81 }) fat12_or_fat16;
82 R_PACKED(
83 struct
84 {
85 grub_uint32_t sectors_per_fat_32;
86 grub_uint16_t extended_flags;
87 grub_uint16_t fs_version;
88 grub_uint32_t root_cluster;
89 grub_uint16_t fs_info;
90 grub_uint16_t backup_boot_sector;
91 grub_uint8_t reserved[12];
92 grub_uint8_t num_ph_drive;
93 grub_uint8_t reserved1;
94 grub_uint8_t boot_sig;
95 grub_uint32_t num_serial;
96 grub_uint8_t label[11];
97 grub_uint8_t fstype[8];
98 }) fat32;
99 }) version_specific;
100 });
101 R_PACKED(
102 struct grub_fat_dir_entry
103 {
104 grub_uint8_t name[11];
105 grub_uint8_t attr;
106 grub_uint8_t nt_reserved;
107 grub_uint8_t c_time_tenth;
108 grub_uint16_t c_time;
109 grub_uint16_t c_date;
110 grub_uint16_t a_date;
111 grub_uint16_t first_cluster_high;
112 grub_uint16_t w_time;
113 grub_uint16_t w_date;
114 grub_uint16_t first_cluster_low;
115 grub_uint32_t file_size;
116 });
117
118 R_PACKED(
119 struct grub_fat_long_name_entry
120 {
121 grub_uint8_t id;
122 grub_uint16_t name1[5];
123 grub_uint8_t attr;
124 grub_uint8_t reserved;
125 grub_uint8_t checksum;
126 grub_uint16_t name2[6];
127 grub_uint16_t first_cluster;
128 grub_uint16_t name3[2];
129 });
130
131 struct grub_fat_data
132 {
133 int logical_sector_bits;
134 grub_uint32_t num_sectors;
135
136 grub_uint16_t fat_sector;
137 grub_uint32_t sectors_per_fat;
138 int fat_size;
139
140 grub_uint32_t root_cluster;
141 grub_uint32_t root_sector;
142 grub_uint32_t num_root_sectors;
143
144 int cluster_bits;
145 grub_uint32_t cluster_eof_mark;
146 grub_uint32_t cluster_sector;
147 grub_uint32_t num_clusters;
148
149 grub_uint8_t attr;
150 grub_ssize_t file_size;
151 grub_uint32_t file_cluster;
152 grub_uint32_t cur_cluster_num;
153 grub_uint32_t cur_cluster;
154
155 grub_uint32_t uuid;
156 };
157
158 static int
fat_log2(unsigned x)159 fat_log2 (unsigned x)
160 {
161 int i;
162
163 if (x == 0)
164 return -1;
165
166 for (i = 0; (x & 1) == 0; i++)
167 x >>= 1;
168
169 if (x != 1)
170 return -1;
171
172 return i;
173 }
174
175 static struct grub_fat_data *
grub_fat_mount(grub_disk_t disk)176 grub_fat_mount (grub_disk_t disk)
177 {
178 struct grub_fat_bpb bpb;
179 struct grub_fat_data *data = 0;
180 grub_uint32_t first_fat, magic;
181
182 if (! disk)
183 goto fail;
184
185 data = (struct grub_fat_data *) grub_malloc (sizeof (*data));
186 if (! data)
187 goto fail;
188
189 /* Read the BPB. */
190 if (grub_disk_read (disk, 0, 0, sizeof (bpb), &bpb))
191 goto fail;
192
193 if (grub_strncmp((const char *) bpb.version_specific.fat12_or_fat16.fstype, "FAT12", 5)
194 && grub_strncmp((const char *) bpb.version_specific.fat12_or_fat16.fstype, "FAT16", 5)
195 && grub_strncmp((const char *) bpb.version_specific.fat32.fstype, "FAT32", 5))
196 goto fail;
197
198 /* Get the sizes of logical sectors and clusters. */
199 data->logical_sector_bits =
200 fat_log2 (grub_le_to_cpu16 (bpb.bytes_per_sector));
201 if (data->logical_sector_bits < GRUB_DISK_SECTOR_BITS)
202 goto fail;
203 data->logical_sector_bits -= GRUB_DISK_SECTOR_BITS;
204
205 data->cluster_bits = fat_log2 (bpb.sectors_per_cluster);
206 if (data->cluster_bits < 0)
207 goto fail;
208 data->cluster_bits += data->logical_sector_bits;
209
210 /* Get information about FATs. */
211 data->fat_sector = (grub_le_to_cpu16 (bpb.num_reserved_sectors)
212 << data->logical_sector_bits);
213 if (data->fat_sector == 0)
214 goto fail;
215
216 data->sectors_per_fat = ((bpb.sectors_per_fat_16
217 ? grub_le_to_cpu16 (bpb.sectors_per_fat_16)
218 : grub_le_to_cpu32 (bpb.version_specific.fat32.sectors_per_fat_32))
219 << data->logical_sector_bits);
220 if (data->sectors_per_fat == 0)
221 goto fail;
222
223 /* Get the number of sectors in this volume. */
224 data->num_sectors = ((bpb.num_total_sectors_16
225 ? grub_le_to_cpu16 (bpb.num_total_sectors_16)
226 : grub_le_to_cpu32 (bpb.num_total_sectors_32))
227 << data->logical_sector_bits);
228 if (data->num_sectors == 0)
229 goto fail;
230
231 /* Get information about the root directory. */
232 if (bpb.num_fats == 0)
233 goto fail;
234
235 data->root_sector = data->fat_sector + bpb.num_fats * data->sectors_per_fat;
236 data->num_root_sectors
237 = ((((grub_uint32_t) grub_le_to_cpu16 (bpb.num_root_entries)
238 * GRUB_FAT_DIR_ENTRY_SIZE
239 + grub_le_to_cpu16 (bpb.bytes_per_sector) - 1)
240 >> (data->logical_sector_bits + GRUB_DISK_SECTOR_BITS))
241 << (data->logical_sector_bits));
242
243 data->cluster_sector = data->root_sector + data->num_root_sectors;
244 data->num_clusters = (((data->num_sectors - data->cluster_sector)
245 >> (data->cluster_bits + data->logical_sector_bits))
246 + 2);
247
248 if (data->num_clusters <= 2)
249 goto fail;
250
251 if (! bpb.sectors_per_fat_16)
252 {
253 /* FAT32. */
254 grub_uint16_t flags = grub_le_to_cpu16 (bpb.version_specific.fat32.extended_flags);
255
256 data->root_cluster = grub_le_to_cpu32 (bpb.version_specific.fat32.root_cluster);
257 data->fat_size = 32;
258 data->cluster_eof_mark = 0x0ffffff8;
259
260 if (flags & 0x80)
261 {
262 /* Get an active FAT. */
263 unsigned active_fat = flags & 0xf;
264
265 if (active_fat > bpb.num_fats)
266 goto fail;
267
268 data->fat_sector += active_fat * data->sectors_per_fat;
269 }
270
271 if (bpb.num_root_entries != 0 || bpb.version_specific.fat32.fs_version != 0)
272 goto fail;
273 }
274 else
275 {
276 /* FAT12 or FAT16. */
277 data->root_cluster = ~0U;
278
279 if (data->num_clusters <= 4085 + 2)
280 {
281 /* FAT12. */
282 data->fat_size = 12;
283 data->cluster_eof_mark = 0x0ff8;
284 }
285 else
286 {
287 /* FAT16. */
288 data->fat_size = 16;
289 data->cluster_eof_mark = 0xfff8;
290 }
291 }
292
293 /* More sanity checks. */
294 if (data->num_sectors <= data->fat_sector)
295 goto fail;
296
297 if (grub_disk_read (disk,
298 data->fat_sector,
299 0,
300 sizeof (first_fat),
301 &first_fat))
302 goto fail;
303
304 first_fat = grub_le_to_cpu32 (first_fat);
305
306 if (data->fat_size == 32)
307 {
308 first_fat &= 0x0fffffff;
309 magic = 0x0fffff00;
310 }
311 else if (data->fat_size == 16)
312 {
313 first_fat &= 0x0000ffff;
314 magic = 0xff00;
315 }
316 else
317 {
318 first_fat &= 0x00000fff;
319 magic = 0x0f00;
320 }
321
322 /* Serial number. */
323 if (bpb.sectors_per_fat_16)
324 data->uuid = grub_le_to_cpu32 (bpb.version_specific.fat12_or_fat16.num_serial);
325 else
326 data->uuid = grub_le_to_cpu32 (bpb.version_specific.fat32.num_serial);
327
328 /* Ignore the 3rd bit, because some BIOSes assigns 0xF0 to the media
329 descriptor, even if it is a so-called superfloppy (e.g. an USB key).
330 The check may be too strict for this kind of stupid BIOSes, as
331 they overwrite the media descriptor. */
332 if ((first_fat | 0x8) != (magic | bpb.media | 0x8))
333 goto fail;
334
335 /* Start from the root directory. */
336 data->file_cluster = data->root_cluster;
337 data->cur_cluster_num = ~0U;
338 data->attr = GRUB_FAT_ATTR_DIRECTORY;
339 return data;
340
341 fail:
342
343 grub_free (data);
344 grub_error (GRUB_ERR_BAD_FS, "not a FAT filesystem");
345 return 0;
346 }
347
348 static grub_ssize_t
grub_fat_read_data(grub_disk_t disk,struct grub_fat_data * data,void (* read_hook)(grub_disk_addr_t sector,unsigned offset,unsigned length,void * closure),void * closure,int flags,grub_off_t offset,grub_size_t len,char * buf)349 grub_fat_read_data (grub_disk_t disk, struct grub_fat_data *data,
350 void (*read_hook) (grub_disk_addr_t sector,
351 unsigned offset, unsigned length,
352 void *closure),
353 void *closure, int flags,
354 grub_off_t offset, grub_size_t len, char *buf)
355 {
356 grub_size_t size;
357 grub_uint32_t logical_cluster;
358 unsigned logical_cluster_bits;
359 grub_ssize_t ret = 0;
360 unsigned long sector;
361
362 /* This is a special case. FAT12 and FAT16 doesn't have the root directory
363 in clusters. */
364 if (data->file_cluster == ~0U)
365 {
366 size = (data->num_root_sectors << GRUB_DISK_SECTOR_BITS) - offset;
367 if (size > len)
368 size = len;
369
370 if (grub_disk_read (disk, data->root_sector, offset, size, buf))
371 return -1;
372
373 return size;
374 }
375
376 /* Calculate the logical cluster number and offset. */
377 logical_cluster_bits = (data->cluster_bits
378 + data->logical_sector_bits
379 + GRUB_DISK_SECTOR_BITS);
380 logical_cluster = offset >> logical_cluster_bits;
381 offset &= (1 << logical_cluster_bits) - 1;
382
383 if (logical_cluster < data->cur_cluster_num)
384 {
385 data->cur_cluster_num = 0;
386 data->cur_cluster = data->file_cluster;
387 }
388
389 while (len)
390 {
391 while (logical_cluster > data->cur_cluster_num)
392 {
393 /* Find next cluster. */
394 grub_uint32_t next_cluster;
395 unsigned long fat_offset;
396
397 switch (data->fat_size)
398 {
399 case 32:
400 fat_offset = data->cur_cluster << 2;
401 break;
402 case 16:
403 fat_offset = data->cur_cluster << 1;
404 break;
405 default:
406 /* case 12: */
407 fat_offset = data->cur_cluster + (data->cur_cluster >> 1);
408 break;
409 }
410
411 /* Read the FAT. */
412 if (grub_disk_read (disk, data->fat_sector, fat_offset,
413 (data->fat_size + 7) >> 3,
414 (char *) &next_cluster))
415 return -1;
416
417 next_cluster = grub_le_to_cpu32 (next_cluster);
418 switch (data->fat_size)
419 {
420 case 16:
421 next_cluster &= 0xFFFF;
422 break;
423 case 12:
424 if (data->cur_cluster & 1)
425 next_cluster >>= 4;
426
427 next_cluster &= 0x0FFF;
428 break;
429 }
430
431 grub_dprintf ("fat", "fat_size=%d, next_cluster=%u\n",
432 data->fat_size, next_cluster);
433
434 /* Check the end. */
435 if (next_cluster >= data->cluster_eof_mark)
436 return ret;
437
438 if (next_cluster < 2 || next_cluster >= data->num_clusters)
439 {
440 grub_error (GRUB_ERR_BAD_FS, "invalid cluster %u",
441 next_cluster);
442 return -1;
443 }
444
445 data->cur_cluster = next_cluster;
446 data->cur_cluster_num++;
447 }
448
449 /* Read the data here. */
450 sector = (data->cluster_sector
451 + ((data->cur_cluster - 2)
452 << (data->cluster_bits + data->logical_sector_bits)));
453 size = (1 << logical_cluster_bits) - offset;
454 if (size > len)
455 size = len;
456
457 disk->read_hook = read_hook;
458 disk->closure = closure;
459 grub_disk_read_ex (disk, sector, offset, size, buf, flags);
460 disk->read_hook = 0;
461 if (grub_errno)
462 return -1;
463
464 len -= size;
465 if (buf)
466 buf += size;
467 ret += size;
468 logical_cluster++;
469 offset = 0;
470 }
471
472 return ret;
473 }
474
475 static grub_err_t
grub_fat_iterate_dir(grub_disk_t disk,struct grub_fat_data * data,int (* hook)(const char * filename,struct grub_fat_dir_entry * dir,void * closure),void * closure)476 grub_fat_iterate_dir (grub_disk_t disk, struct grub_fat_data *data,
477 int (*hook) (const char *filename,
478 struct grub_fat_dir_entry *dir,
479 void *closure),
480 void *closure)
481 {
482 struct grub_fat_dir_entry dir;
483 char *filename, *filep = 0;
484 grub_uint16_t *unibuf;
485 int slot = -1, slots = -1;
486 int checksum = -1;
487 grub_ssize_t offset;
488
489 if (! (data->attr & GRUB_FAT_ATTR_DIRECTORY))
490 return grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a directory");
491
492 /* Allocate space enough to hold a long name. */
493 filename = grub_malloc (0x40 * 13 * 4 + 1);
494 unibuf = (grub_uint16_t *) grub_malloc (0x40 * 13 * 2);
495 if (! filename || ! unibuf)
496 {
497 grub_free (filename);
498 grub_free (unibuf);
499 return 0;
500 }
501
502 //while (1)
503 for (offset = 0; ; offset += sizeof (dir)) {
504 unsigned i;
505
506 /* Adjust the offset. */
507 //offset += sizeof (dir);
508
509 /* Read a directory entry. */
510 if ((grub_fat_read_data (disk, data, 0, 0, 0,
511 offset, sizeof (dir), (char *) &dir)
512 != sizeof (dir) || dir.name[0] == 0))
513 break;
514 /* Handle long name entries. */
515 if (dir.attr == GRUB_FAT_ATTR_LONG_NAME)
516 {
517 struct grub_fat_long_name_entry *long_name
518 = (struct grub_fat_long_name_entry *) &dir;
519 grub_uint8_t id = long_name->id;
520
521 if (id & 0x40)
522 {
523 id &= 0x3f;
524 slots = slot = id;
525 checksum = long_name->checksum;
526 }
527
528 if (id != slot || slot == 0 || checksum != long_name->checksum)
529 {
530 checksum = -1;
531 continue;
532 }
533
534 slot--;
535 grub_memcpy (unibuf + slot * 13, long_name->name1, 5 * 2);
536 grub_memcpy (unibuf + slot * 13 + 5, long_name->name2, 6 * 2);
537 grub_memcpy (unibuf + slot * 13 + 11, long_name->name3, 2 * 2);
538 continue;
539 }
540
541 /* Check if this entry is valid. */
542 if (!(grub_fshelp_view & R_FS_VIEW_DELETED)) {
543 if (dir.name[0] == 0xe5 || (dir.attr & ~GRUB_FAT_ATTR_VALID))
544 continue;
545 }
546
547 /* This is a workaround for Japanese. */
548 if (dir.name[0] == 0x05)
549 dir.name[0] = 0xe5;
550
551 if (checksum != -1 && slot == 0)
552 {
553 grub_uint8_t sum;
554
555 for (sum = 0, i = 0; i < sizeof (dir.name); i++)
556 sum = ((sum >> 1) | (sum << 7)) + dir.name[i];
557
558 if (sum == checksum)
559 {
560 int u;
561
562 for (u = 0; u < slots * 13; u++)
563 unibuf[u] = grub_le_to_cpu16 (unibuf[u]);
564
565 *grub_utf16_to_utf8 ((grub_uint8_t *) filename, unibuf,
566 slots * 13) = '\0';
567
568 if (hook && hook (filename, &dir, closure))
569 break;
570
571 checksum = -1;
572 continue;
573 }
574
575 checksum = -1;
576 }
577
578 /* Convert the 8.3 file name. */
579 filep = filename;
580 if (dir.attr & GRUB_FAT_ATTR_VOLUME_ID)
581 {
582 for (i = 0; i < sizeof (dir.name) && dir.name[i]
583 && ! grub_isspace (dir.name[i]); i++)
584 *filep++ = dir.name[i];
585 }
586 else
587 {
588 for (i = 0; i < 8 && dir.name[i] && ! grub_isspace (dir.name[i]); i++)
589 *filep++ = grub_tolower (dir.name[i]);
590
591 *filep = '.';
592
593 for (i = 8; i < 11 && dir.name[i] && ! grub_isspace (dir.name[i]); i++)
594 *++filep = grub_tolower (dir.name[i]);
595
596 if (*filep != '.')
597 filep++;
598 }
599 *filep = '\0';
600
601 if (hook (filename, &dir, closure))
602 break;
603 }
604
605 grub_free (filename);
606 grub_free (unibuf);
607
608 return grub_errno;
609 }
610
611 struct grub_fat_find_dir_closure
612 {
613 struct grub_fat_data *data;
614 int (*hook) (const char *filename,
615 const struct grub_dirhook_info *info,
616 void *closure);
617 void *closure;
618 char *dirname;
619 int call_hook;
620 int found;
621 };
622
623 static int
grub_fat_find_dir_hook(const char * filename,struct grub_fat_dir_entry * dir,void * closure)624 grub_fat_find_dir_hook (const char *filename, struct grub_fat_dir_entry *dir,
625 void *closure)
626 {
627 struct grub_fat_find_dir_closure *c = closure;
628 struct grub_dirhook_info info;
629 grub_memset (&info, 0, sizeof (info));
630
631 info.dir = !! (dir->attr & GRUB_FAT_ATTR_DIRECTORY);
632 info.case_insensitive = 1;
633
634 if (dir->attr & GRUB_FAT_ATTR_VOLUME_ID)
635 return 0;
636 if (*(c->dirname) == '\0' && (c->call_hook))
637 return c->hook (filename, &info, c->closure);
638
639 if (grub_strcasecmp (c->dirname, filename) == 0)
640 {
641 struct grub_fat_data *data = c->data;
642
643 c->found = 1;
644 data->attr = dir->attr;
645 data->file_size = grub_le_to_cpu32 (dir->file_size);
646 data->file_cluster = ((grub_le_to_cpu16 (dir->first_cluster_high) << 16)
647 | grub_le_to_cpu16 (dir->first_cluster_low));
648 data->cur_cluster_num = ~0U;
649
650 if (c->call_hook)
651 c->hook (filename, &info, c->closure);
652
653 return 1;
654 }
655 return 0;
656 }
657
658 /* Find the underlying directory or file in PATH and return the
659 next path. If there is no next path or an error occurs, return NULL.
660 If HOOK is specified, call it with each file name. */
661 static char *
grub_fat_find_dir(grub_disk_t disk,struct grub_fat_data * data,const char * path,int (* hook)(const char * filename,const struct grub_dirhook_info * info,void * closure),void * closure)662 grub_fat_find_dir (grub_disk_t disk, struct grub_fat_data *data,
663 const char *path,
664 int (*hook) (const char *filename,
665 const struct grub_dirhook_info *info,
666 void *closure),
667 void *closure)
668 {
669 char *dirname, *dirp;
670 struct grub_fat_find_dir_closure c;
671
672 if (! (data->attr & GRUB_FAT_ATTR_DIRECTORY))
673 {
674 grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a directory");
675 return 0;
676 }
677
678 /* Extract a directory name. */
679 while (*path == '/')
680 path++;
681
682 dirp = grub_strchr (path, '/');
683 if (dirp)
684 {
685 unsigned len = dirp - path;
686
687 dirname = grub_malloc (len + 1);
688 if (! dirname)
689 return 0;
690
691 grub_memcpy (dirname, path, len);
692 dirname[len] = '\0';
693 }
694 else
695 /* This is actually a file. */
696 dirname = grub_strdup (path);
697
698 c.data = data;
699 c.hook = hook;
700 c.closure = closure;
701 c.dirname =dirname;
702 c.found = 0;
703 c.call_hook = (! dirp && hook);
704 grub_fat_iterate_dir (disk, data, grub_fat_find_dir_hook, &c);
705 if (grub_errno == GRUB_ERR_NONE && ! c.found && !c.call_hook)
706 grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found");
707
708 grub_free (dirname);
709
710 return c.found ? dirp : 0;
711 }
712
713 static grub_err_t
grub_fat_dir(grub_device_t device,const char * path,int (* hook)(const char * filename,const struct grub_dirhook_info * info,void * closure),void * closure)714 grub_fat_dir (grub_device_t device, const char *path,
715 int (*hook) (const char *filename,
716 const struct grub_dirhook_info *info, void *closure),
717 void *closure)
718 {
719 struct grub_fat_data *data = 0;
720 grub_disk_t disk = device->disk;
721 grub_size_t len;
722 char *dirname = 0;
723 char *p;
724
725 data = grub_fat_mount (disk);
726 if (! data)
727 goto fail;
728
729 /* Make sure that DIRNAME terminates with '/'. */
730 len = grub_strlen (path);
731 dirname = grub_malloc (len + 1 + 1);
732 if (! dirname)
733 goto fail;
734 grub_memcpy (dirname, path, len);
735 p = dirname + len;
736 if (len>0 && path[len - 1] != '/')
737 *p++ = '/';
738 *p = '\0';
739 p = dirname;
740
741 do
742 {
743 p = grub_fat_find_dir (disk, data, p, hook, closure);
744 }
745 while (p && grub_errno == GRUB_ERR_NONE);
746
747 fail:
748
749 grub_free (dirname);
750 grub_free (data);
751
752 return grub_errno;
753 }
754
755 static grub_err_t
grub_fat_open(grub_file_t file,const char * name)756 grub_fat_open (grub_file_t file, const char *name)
757 {
758 struct grub_fat_data *data = 0;
759 char *p = (char *) name;
760
761 data = grub_fat_mount (file->device->disk);
762 if (! data)
763 goto fail;
764
765 do
766 {
767 p = grub_fat_find_dir (file->device->disk, data, p, 0, 0);
768 if (grub_errno != GRUB_ERR_NONE)
769 goto fail;
770 }
771 while (p);
772
773 if (data->attr & GRUB_FAT_ATTR_DIRECTORY)
774 {
775 grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a file");
776 goto fail;
777 }
778
779 file->data = data;
780 file->size = data->file_size;
781
782 return GRUB_ERR_NONE;
783
784 fail:
785
786 grub_free (data);
787
788 return grub_errno;
789 }
790
791 static grub_ssize_t
grub_fat_read(grub_file_t file,char * buf,grub_size_t len)792 grub_fat_read (grub_file_t file, char *buf, grub_size_t len)
793 {
794 return grub_fat_read_data (file->device->disk, file->data, file->read_hook,
795 file->closure, file->flags,
796 file->offset, len, buf);
797 }
798
799 static grub_err_t
grub_fat_close(grub_file_t file)800 grub_fat_close (grub_file_t file)
801 {
802 grub_free (file->data);
803
804 return grub_errno;
805 }
806
807 static int
grub_fat_label_hook(const char * filename,struct grub_fat_dir_entry * dir,void * closure)808 grub_fat_label_hook (const char *filename, struct grub_fat_dir_entry *dir,
809 void *closure)
810 {
811 char **label = closure;
812
813 if (dir->attr == GRUB_FAT_ATTR_VOLUME_ID)
814 {
815 *label = grub_strdup (filename);
816 return 1;
817 }
818 return 0;
819 }
820
821 static grub_err_t
grub_fat_label(grub_device_t device,char ** label)822 grub_fat_label (grub_device_t device, char **label)
823 {
824 struct grub_fat_data *data;
825 grub_disk_t disk = device->disk;
826
827 data = grub_fat_mount (disk);
828 if (! data)
829 goto fail;
830
831 if (! (data->attr & GRUB_FAT_ATTR_DIRECTORY))
832 {
833 grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a directory");
834 return 0;
835 }
836
837 *label = 0;
838
839 grub_fat_iterate_dir (disk, data, grub_fat_label_hook, label);
840
841 fail:
842
843 grub_free (data);
844
845 return grub_errno;
846 }
847
848 static grub_err_t
grub_fat_uuid(grub_device_t device,char ** uuid)849 grub_fat_uuid (grub_device_t device, char **uuid)
850 {
851 struct grub_fat_data *data;
852 grub_disk_t disk = device->disk;
853
854 data = grub_fat_mount (disk);
855 if (data)
856 {
857 *uuid = grub_xasprintf ("%04x-%04x",
858 (grub_uint16_t) (data->uuid >> 16),
859 (grub_uint16_t) data->uuid);
860 }
861 else
862 *uuid = NULL;
863
864 grub_free (data);
865
866 return grub_errno;
867 }
868
869 struct grub_fs grub_fat_fs =
870 {
871 .name = "fat",
872 .dir = grub_fat_dir,
873 .open = grub_fat_open,
874 .read = grub_fat_read,
875 .close = grub_fat_close,
876 .label = grub_fat_label,
877 .uuid = grub_fat_uuid,
878 #ifdef GRUB_UTIL
879 .reserved_first_sector = 1,
880 #endif
881 .next = 0
882 };
883