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