1 /* fat.c - FAT filesystem */
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2000,2001,2002,2003,2004,2005,2007,2008,2009 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/>.
21 #include <grub/disk.h>
22 #include <grub/file.h>
23 #include <grub/types.h>
24 #include <grub/misc.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 \
49 | GRUB_FAT_ATTR_VOLUME_ID)
53 grub_uint8_t jmp_boot
[3];
54 grub_uint8_t oem_name
[8];
55 grub_uint16_t bytes_per_sector
;
56 grub_uint8_t sectors_per_cluster
;
57 grub_uint16_t num_reserved_sectors
;
58 grub_uint8_t num_fats
;
59 grub_uint16_t num_root_entries
;
60 grub_uint16_t num_total_sectors_16
;
62 grub_uint16_t sectors_per_fat_16
;
63 grub_uint16_t sectors_per_track
;
64 grub_uint16_t num_heads
;
65 grub_uint32_t num_hidden_sectors
;
66 grub_uint32_t num_total_sectors_32
;
71 grub_uint8_t num_ph_drive
;
72 grub_uint8_t reserved
;
73 grub_uint8_t boot_sig
;
74 grub_uint32_t num_serial
;
75 grub_uint8_t label
[11];
76 grub_uint8_t fstype
[8];
77 } __attribute__ ((packed
)) fat12_or_fat16
;
80 grub_uint32_t sectors_per_fat_32
;
81 grub_uint16_t extended_flags
;
82 grub_uint16_t fs_version
;
83 grub_uint32_t root_cluster
;
84 grub_uint16_t fs_info
;
85 grub_uint16_t backup_boot_sector
;
86 grub_uint8_t reserved
[12];
87 grub_uint8_t num_ph_drive
;
88 grub_uint8_t reserved1
;
89 grub_uint8_t boot_sig
;
90 grub_uint32_t num_serial
;
91 grub_uint8_t label
[11];
92 grub_uint8_t fstype
[8];
93 } __attribute__ ((packed
)) fat32
;
94 } __attribute__ ((packed
)) version_specific
;
95 } __attribute__ ((packed
));
97 struct grub_fat_dir_entry
99 grub_uint8_t name
[11];
101 grub_uint8_t nt_reserved
;
102 grub_uint8_t c_time_tenth
;
103 grub_uint16_t c_time
;
104 grub_uint16_t c_date
;
105 grub_uint16_t a_date
;
106 grub_uint16_t first_cluster_high
;
107 grub_uint16_t w_time
;
108 grub_uint16_t w_date
;
109 grub_uint16_t first_cluster_low
;
110 grub_uint32_t file_size
;
111 } __attribute__ ((packed
));
113 struct grub_fat_long_name_entry
116 grub_uint16_t name1
[5];
118 grub_uint8_t reserved
;
119 grub_uint8_t checksum
;
120 grub_uint16_t name2
[6];
121 grub_uint16_t first_cluster
;
122 grub_uint16_t name3
[2];
123 } __attribute__ ((packed
));
127 int logical_sector_bits
;
128 grub_uint32_t num_sectors
;
130 grub_uint16_t fat_sector
;
131 grub_uint32_t sectors_per_fat
;
134 grub_uint32_t root_cluster
;
135 grub_uint32_t root_sector
;
136 grub_uint32_t num_root_sectors
;
139 grub_uint32_t cluster_eof_mark
;
140 grub_uint32_t cluster_sector
;
141 grub_uint32_t num_clusters
;
144 grub_ssize_t file_size
;
145 grub_uint32_t file_cluster
;
146 grub_uint32_t cur_cluster_num
;
147 grub_uint32_t cur_cluster
;
152 static grub_dl_t my_mod
;
155 fat_log2 (unsigned x
)
162 for (i
= 0; (x
& 1) == 0; i
++)
171 static struct grub_fat_data
*
172 grub_fat_mount (grub_disk_t disk
)
174 struct grub_fat_bpb bpb
;
175 struct grub_fat_data
*data
= 0;
176 grub_uint32_t first_fat
, magic
;
181 data
= (struct grub_fat_data
*) grub_malloc (sizeof (*data
));
186 if (grub_disk_read (disk
, 0, 0, sizeof (bpb
), &bpb
))
189 if (grub_strncmp((const char *) bpb
.version_specific
.fat12_or_fat16
.fstype
, "FAT12", 5)
190 && grub_strncmp((const char *) bpb
.version_specific
.fat12_or_fat16
.fstype
, "FAT16", 5)
191 && grub_strncmp((const char *) bpb
.version_specific
.fat32
.fstype
, "FAT32", 5))
194 /* Get the sizes of logical sectors and clusters. */
195 data
->logical_sector_bits
=
196 fat_log2 (grub_le_to_cpu16 (bpb
.bytes_per_sector
));
197 if (data
->logical_sector_bits
< GRUB_DISK_SECTOR_BITS
)
199 data
->logical_sector_bits
-= GRUB_DISK_SECTOR_BITS
;
201 data
->cluster_bits
= fat_log2 (bpb
.sectors_per_cluster
);
202 if (data
->cluster_bits
< 0)
204 data
->cluster_bits
+= data
->logical_sector_bits
;
206 /* Get information about FATs. */
207 data
->fat_sector
= (grub_le_to_cpu16 (bpb
.num_reserved_sectors
)
208 << data
->logical_sector_bits
);
209 if (data
->fat_sector
== 0)
212 data
->sectors_per_fat
= ((bpb
.sectors_per_fat_16
213 ? grub_le_to_cpu16 (bpb
.sectors_per_fat_16
)
214 : grub_le_to_cpu32 (bpb
.version_specific
.fat32
.sectors_per_fat_32
))
215 << data
->logical_sector_bits
);
216 if (data
->sectors_per_fat
== 0)
219 /* Get the number of sectors in this volume. */
220 data
->num_sectors
= ((bpb
.num_total_sectors_16
221 ? grub_le_to_cpu16 (bpb
.num_total_sectors_16
)
222 : grub_le_to_cpu32 (bpb
.num_total_sectors_32
))
223 << data
->logical_sector_bits
);
224 if (data
->num_sectors
== 0)
227 /* Get information about the root directory. */
228 if (bpb
.num_fats
== 0)
231 data
->root_sector
= data
->fat_sector
+ bpb
.num_fats
* data
->sectors_per_fat
;
232 data
->num_root_sectors
233 = ((((grub_uint32_t
) grub_le_to_cpu16 (bpb
.num_root_entries
)
234 * GRUB_FAT_DIR_ENTRY_SIZE
235 + grub_le_to_cpu16 (bpb
.bytes_per_sector
) - 1)
236 >> (data
->logical_sector_bits
+ GRUB_DISK_SECTOR_BITS
))
237 << (data
->logical_sector_bits
));
239 data
->cluster_sector
= data
->root_sector
+ data
->num_root_sectors
;
240 data
->num_clusters
= (((data
->num_sectors
- data
->cluster_sector
)
241 >> (data
->cluster_bits
+ data
->logical_sector_bits
))
244 if (data
->num_clusters
<= 2)
247 if (! bpb
.sectors_per_fat_16
)
250 grub_uint16_t flags
= grub_le_to_cpu16 (bpb
.version_specific
.fat32
.extended_flags
);
252 data
->root_cluster
= grub_le_to_cpu32 (bpb
.version_specific
.fat32
.root_cluster
);
254 data
->cluster_eof_mark
= 0x0ffffff8;
258 /* Get an active FAT. */
259 unsigned active_fat
= flags
& 0xf;
261 if (active_fat
> bpb
.num_fats
)
264 data
->fat_sector
+= active_fat
* data
->sectors_per_fat
;
267 if (bpb
.num_root_entries
!= 0 || bpb
.version_specific
.fat32
.fs_version
!= 0)
272 /* FAT12 or FAT16. */
273 data
->root_cluster
= ~0U;
275 if (data
->num_clusters
<= 4085 + 2)
279 data
->cluster_eof_mark
= 0x0ff8;
285 data
->cluster_eof_mark
= 0xfff8;
289 /* More sanity checks. */
290 if (data
->num_sectors
<= data
->fat_sector
)
293 if (grub_disk_read (disk
,
300 first_fat
= grub_le_to_cpu32 (first_fat
);
302 if (data
->fat_size
== 32)
304 first_fat
&= 0x0fffffff;
307 else if (data
->fat_size
== 16)
309 first_fat
&= 0x0000ffff;
314 first_fat
&= 0x00000fff;
319 if (bpb
.sectors_per_fat_16
)
320 data
->uuid
= grub_le_to_cpu32 (bpb
.version_specific
.fat12_or_fat16
.num_serial
);
322 data
->uuid
= grub_le_to_cpu32 (bpb
.version_specific
.fat32
.num_serial
);
324 /* Ignore the 3rd bit, because some BIOSes assigns 0xF0 to the media
325 descriptor, even if it is a so-called superfloppy (e.g. an USB key).
326 The check may be too strict for this kind of stupid BIOSes, as
327 they overwrite the media descriptor. */
328 if ((first_fat
| 0x8) != (magic
| bpb
.media
| 0x8))
331 /* Start from the root directory. */
332 data
->file_cluster
= data
->root_cluster
;
333 data
->cur_cluster_num
= ~0U;
334 data
->attr
= GRUB_FAT_ATTR_DIRECTORY
;
340 grub_error (GRUB_ERR_BAD_FS
, "not a fat filesystem");
345 grub_fat_read_data (grub_disk_t disk
, struct grub_fat_data
*data
,
346 void NESTED_FUNC_ATTR (*read_hook
) (grub_disk_addr_t sector
,
347 unsigned offset
, unsigned length
),
348 grub_off_t offset
, grub_size_t len
, char *buf
)
351 grub_uint32_t logical_cluster
;
352 unsigned logical_cluster_bits
;
353 grub_ssize_t ret
= 0;
354 unsigned long sector
;
356 /* This is a special case. FAT12 and FAT16 doesn't have the root directory
358 if (data
->file_cluster
== ~0U)
360 size
= (data
->num_root_sectors
<< GRUB_DISK_SECTOR_BITS
) - offset
;
364 if (grub_disk_read (disk
, data
->root_sector
, offset
, size
, buf
))
370 /* Calculate the logical cluster number and offset. */
371 logical_cluster_bits
= (data
->cluster_bits
372 + data
->logical_sector_bits
373 + GRUB_DISK_SECTOR_BITS
);
374 logical_cluster
= offset
>> logical_cluster_bits
;
375 offset
&= (1 << logical_cluster_bits
) - 1;
377 if (logical_cluster
< data
->cur_cluster_num
)
379 data
->cur_cluster_num
= 0;
380 data
->cur_cluster
= data
->file_cluster
;
385 while (logical_cluster
> data
->cur_cluster_num
)
387 /* Find next cluster. */
388 grub_uint32_t next_cluster
;
389 unsigned long fat_offset
;
391 switch (data
->fat_size
)
394 fat_offset
= data
->cur_cluster
<< 2;
397 fat_offset
= data
->cur_cluster
<< 1;
401 fat_offset
= data
->cur_cluster
+ (data
->cur_cluster
>> 1);
406 if (grub_disk_read (disk
, data
->fat_sector
, fat_offset
,
407 (data
->fat_size
+ 7) >> 3,
408 (char *) &next_cluster
))
411 next_cluster
= grub_le_to_cpu32 (next_cluster
);
412 switch (data
->fat_size
)
415 next_cluster
&= 0xFFFF;
418 if (data
->cur_cluster
& 1)
421 next_cluster
&= 0x0FFF;
426 grub_printf ("%s:%d: fat_size=%d, next_cluster=%u\n",
427 __FILE__
, __LINE__
, data
->fat_size
, next_cluster
);
431 if (next_cluster
>= data
->cluster_eof_mark
)
434 if (next_cluster
< 2 || next_cluster
>= data
->num_clusters
)
436 grub_error (GRUB_ERR_BAD_FS
, "invalid cluster %u",
441 data
->cur_cluster
= next_cluster
;
442 data
->cur_cluster_num
++;
445 /* Read the data here. */
446 sector
= (data
->cluster_sector
447 + ((data
->cur_cluster
- 2)
448 << (data
->cluster_bits
+ data
->logical_sector_bits
)));
449 size
= (1 << logical_cluster_bits
) - offset
;
453 disk
->read_hook
= read_hook
;
454 grub_disk_read (disk
, sector
, offset
, size
, buf
);
470 grub_fat_iterate_dir (grub_disk_t disk
, struct grub_fat_data
*data
,
471 int (*hook
) (const char *filename
,
472 struct grub_fat_dir_entry
*dir
))
474 struct grub_fat_dir_entry dir
;
475 char *filename
, *filep
= 0;
476 grub_uint16_t
*unibuf
;
477 int slot
= -1, slots
= -1;
479 grub_ssize_t offset
= -sizeof(dir
);
481 if (! (data
->attr
& GRUB_FAT_ATTR_DIRECTORY
))
482 return grub_error (GRUB_ERR_BAD_FILE_TYPE
, "not a directory");
484 /* Allocate space enough to hold a long name. */
485 filename
= grub_malloc (0x40 * 13 * 4 + 1);
486 unibuf
= (grub_uint16_t
*) grub_malloc (0x40 * 13 * 2);
487 if (! filename
|| ! unibuf
)
489 grub_free (filename
);
498 /* Adjust the offset. */
499 offset
+= sizeof (dir
);
501 /* Read a directory entry. */
502 if ((grub_fat_read_data (disk
, data
, 0,
503 offset
, sizeof (dir
), (char *) &dir
)
504 != sizeof (dir
) || dir
.name
[0] == 0))
506 /* Handle long name entries. */
507 if (dir
.attr
== GRUB_FAT_ATTR_LONG_NAME
)
509 struct grub_fat_long_name_entry
*long_name
510 = (struct grub_fat_long_name_entry
*) &dir
;
511 grub_uint8_t id
= long_name
->id
;
517 checksum
= long_name
->checksum
;
520 if (id
!= slot
|| slot
== 0 || checksum
!= long_name
->checksum
)
527 grub_memcpy (unibuf
+ slot
* 13, long_name
->name1
, 5 * 2);
528 grub_memcpy (unibuf
+ slot
* 13 + 5, long_name
->name2
, 6 * 2);
529 grub_memcpy (unibuf
+ slot
* 13 + 11, long_name
->name3
, 2 * 2);
533 /* Check if this entry is valid. */
534 if (dir
.name
[0] == 0xe5 || (dir
.attr
& ~GRUB_FAT_ATTR_VALID
))
537 /* This is a workaround for Japanese. */
538 if (dir
.name
[0] == 0x05)
541 if (checksum
!= -1 && slot
== 0)
545 for (sum
= 0, i
= 0; i
< sizeof (dir
.name
); i
++)
546 sum
= ((sum
>> 1) | (sum
<< 7)) + dir
.name
[i
];
552 for (u
= 0; u
< slots
* 13; u
++)
553 unibuf
[u
] = grub_le_to_cpu16 (unibuf
[u
]);
555 *grub_utf16_to_utf8 ((grub_uint8_t
*) filename
, unibuf
,
558 if (hook (filename
, &dir
))
568 /* Convert the 8.3 file name. */
570 if (dir
.attr
& GRUB_FAT_ATTR_VOLUME_ID
)
572 for (i
= 0; i
< sizeof (dir
.name
) && dir
.name
[i
]
573 && ! grub_isspace (dir
.name
[i
]); i
++)
574 *filep
++ = dir
.name
[i
];
578 for (i
= 0; i
< 8 && dir
.name
[i
] && ! grub_isspace (dir
.name
[i
]); i
++)
579 *filep
++ = grub_tolower (dir
.name
[i
]);
583 for (i
= 8; i
< 11 && dir
.name
[i
] && ! grub_isspace (dir
.name
[i
]); i
++)
584 *++filep
= grub_tolower (dir
.name
[i
]);
591 if (hook (filename
, &dir
))
595 grub_free (filename
);
601 /* Find the underlying directory or file in PATH and return the
602 next path. If there is no next path or an error occurs, return NULL.
603 If HOOK is specified, call it with each file name. */
605 grub_fat_find_dir (grub_disk_t disk
, struct grub_fat_data
*data
,
607 int (*hook
) (const char *filename
,
608 const struct grub_dirhook_info
*info
))
610 char *dirname
, *dirp
;
614 auto int iter_hook (const char *filename
, struct grub_fat_dir_entry
*dir
);
615 int iter_hook (const char *filename
, struct grub_fat_dir_entry
*dir
)
617 struct grub_dirhook_info info
;
618 grub_memset (&info
, 0, sizeof (info
));
620 info
.dir
= !! (dir
->attr
& GRUB_FAT_ATTR_DIRECTORY
);
621 info
.case_insensitive
= 1;
623 if (dir
->attr
& GRUB_FAT_ATTR_VOLUME_ID
)
625 if (*dirname
== '\0' && call_hook
)
626 return hook (filename
, &info
);
628 if (grub_strcasecmp (dirname
, filename
) == 0)
631 data
->attr
= dir
->attr
;
632 data
->file_size
= grub_le_to_cpu32 (dir
->file_size
);
633 data
->file_cluster
= ((grub_le_to_cpu16 (dir
->first_cluster_high
) << 16)
634 | grub_le_to_cpu16 (dir
->first_cluster_low
));
635 data
->cur_cluster_num
= ~0U;
638 hook (filename
, &info
);
645 if (! (data
->attr
& GRUB_FAT_ATTR_DIRECTORY
))
647 grub_error (GRUB_ERR_BAD_FILE_TYPE
, "not a directory");
651 /* Extract a directory name. */
655 dirp
= grub_strchr (path
, '/');
658 unsigned len
= dirp
- path
;
660 dirname
= grub_malloc (len
+ 1);
664 grub_memcpy (dirname
, path
, len
);
668 /* This is actually a file. */
669 dirname
= grub_strdup (path
);
671 call_hook
= (! dirp
&& hook
);
673 grub_fat_iterate_dir (disk
, data
, iter_hook
);
674 if (grub_errno
== GRUB_ERR_NONE
&& ! found
&& !call_hook
)
675 grub_error (GRUB_ERR_FILE_NOT_FOUND
, "file not found");
679 return found
? dirp
: 0;
683 grub_fat_dir (grub_device_t device
, const char *path
,
684 int (*hook
) (const char *filename
,
685 const struct grub_dirhook_info
*info
))
687 struct grub_fat_data
*data
= 0;
688 grub_disk_t disk
= device
->disk
;
693 grub_dl_ref (my_mod
);
695 data
= grub_fat_mount (disk
);
699 /* Make sure that DIRNAME terminates with '/'. */
700 len
= grub_strlen (path
);
701 dirname
= grub_malloc (len
+ 1 + 1);
704 grub_memcpy (dirname
, path
, len
);
706 if (path
[len
- 1] != '/')
713 p
= grub_fat_find_dir (disk
, data
, p
, hook
);
715 while (p
&& grub_errno
== GRUB_ERR_NONE
);
722 grub_dl_unref (my_mod
);
728 grub_fat_open (grub_file_t file
, const char *name
)
730 struct grub_fat_data
*data
= 0;
731 char *p
= (char *) name
;
733 grub_dl_ref (my_mod
);
735 data
= grub_fat_mount (file
->device
->disk
);
741 p
= grub_fat_find_dir (file
->device
->disk
, data
, p
, 0);
742 if (grub_errno
!= GRUB_ERR_NONE
)
747 if (data
->attr
& GRUB_FAT_ATTR_DIRECTORY
)
749 grub_error (GRUB_ERR_BAD_FILE_TYPE
, "not a file");
754 file
->size
= data
->file_size
;
756 return GRUB_ERR_NONE
;
762 grub_dl_unref (my_mod
);
768 grub_fat_read (grub_file_t file
, char *buf
, grub_size_t len
)
770 return grub_fat_read_data (file
->device
->disk
, file
->data
, file
->read_hook
,
771 file
->offset
, len
, buf
);
775 grub_fat_close (grub_file_t file
)
777 grub_free (file
->data
);
779 grub_dl_unref (my_mod
);
785 grub_fat_label (grub_device_t device
, char **label
)
787 struct grub_fat_data
*data
;
788 grub_disk_t disk
= device
->disk
;
790 auto int iter_hook (const char *filename
, struct grub_fat_dir_entry
*dir
);
791 int iter_hook (const char *filename
, struct grub_fat_dir_entry
*dir
)
793 if (dir
->attr
== GRUB_FAT_ATTR_VOLUME_ID
)
795 *label
= grub_strdup (filename
);
801 grub_dl_ref (my_mod
);
803 data
= grub_fat_mount (disk
);
807 if (! (data
->attr
& GRUB_FAT_ATTR_DIRECTORY
))
809 grub_error (GRUB_ERR_BAD_FILE_TYPE
, "not a directory");
815 grub_fat_iterate_dir (disk
, data
, iter_hook
);
819 grub_dl_unref (my_mod
);
827 grub_fat_uuid (grub_device_t device
, char **uuid
)
829 struct grub_fat_data
*data
;
830 grub_disk_t disk
= device
->disk
;
832 grub_dl_ref (my_mod
);
834 data
= grub_fat_mount (disk
);
837 *uuid
= grub_malloc (sizeof ("xxxx-xxxx"));
838 grub_sprintf (*uuid
, "%04x-%04x", (grub_uint16_t
) (data
->uuid
>> 16),
839 (grub_uint16_t
) data
->uuid
);
844 grub_dl_unref (my_mod
);
851 static struct grub_fs grub_fat_fs
=
855 .open
= grub_fat_open
,
856 .read
= grub_fat_read
,
857 .close
= grub_fat_close
,
858 .label
= grub_fat_label
,
859 .uuid
= grub_fat_uuid
,
865 grub_fs_register (&grub_fat_fs
);
871 grub_fs_unregister (&grub_fat_fs
);