1 /* fat.c - FAT filesystem */
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/>.
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)
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
;
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
;
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
;
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];
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
115 grub_uint16_t name1
[5];
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
));
126 int logical_sector_bits
;
127 grub_uint32_t num_sectors
;
129 grub_uint16_t fat_sector
;
130 grub_uint32_t sectors_per_fat
;
133 grub_uint32_t root_cluster
;
134 grub_uint32_t root_sector
;
135 grub_uint32_t num_root_sectors
;
138 grub_uint32_t cluster_eof_mark
;
139 grub_uint32_t cluster_sector
;
140 grub_uint32_t num_clusters
;
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
;
152 static grub_dl_t my_mod
;
156 fat_log2 (unsigned x
)
163 for (i
= 0; (x
& 1) == 0; 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
;
182 data
= (struct grub_fat_data
*) grub_malloc (sizeof (*data
));
187 if (grub_disk_read (disk
, 0, 0, sizeof (bpb
), (char *) &bpb
))
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))
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
)
200 data
->logical_sector_bits
-= GRUB_DISK_SECTOR_BITS
;
202 data
->cluster_bits
= fat_log2 (bpb
.sectors_per_cluster
);
203 if (data
->cluster_bits
< 0)
205 data
->cluster_bits
+= data
->logical_sector_bits
;
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)
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)
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)
228 /* Get information about the root directory. */
229 if (bpb
.num_fats
== 0)
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
));
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
))
245 if (data
->num_clusters
<= 2)
248 if (! bpb
.sectors_per_fat_16
)
251 grub_uint16_t flags
= grub_le_to_cpu16 (bpb
.version_specific
.fat32
.extended_flags
);
253 data
->root_cluster
= grub_le_to_cpu32 (bpb
.version_specific
.fat32
.root_cluster
);
255 data
->cluster_eof_mark
= 0x0ffffff8;
259 /* Get an active FAT. */
260 unsigned active_fat
= flags
& 0xf;
262 if (active_fat
> bpb
.num_fats
)
265 data
->fat_sector
+= active_fat
* data
->sectors_per_fat
;
268 if (bpb
.num_root_entries
!= 0 || bpb
.version_specific
.fat32
.fs_version
!= 0)
273 /* FAT12 or FAT16. */
274 data
->root_cluster
= ~0U;
276 if (data
->num_clusters
<= 4085 + 2)
280 data
->cluster_eof_mark
= 0x0ff8;
286 data
->cluster_eof_mark
= 0xfff8;
290 /* More sanity checks. */
291 if (data
->num_sectors
<= data
->fat_sector
)
294 if (grub_disk_read (disk
,
298 (char *) &first_fat
))
301 first_fat
= grub_le_to_cpu32 (first_fat
);
303 if (data
->fat_size
== 32)
305 first_fat
&= 0x0fffffff;
308 else if (data
->fat_size
== 16)
310 first_fat
&= 0x0000ffff;
315 first_fat
&= 0x00000fff;
320 if (bpb
.sectors_per_fat_16
)
321 data
->uuid
= grub_le_to_cpu32 (bpb
.version_specific
.fat12_or_fat16
.num_serial
);
323 data
->uuid
= grub_le_to_cpu32 (bpb
.version_specific
.fat32
.num_serial
);
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))
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
;
341 grub_error (GRUB_ERR_BAD_FS
, "not a fat filesystem");
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
)
352 grub_uint32_t logical_cluster
;
353 unsigned logical_cluster_bits
;
354 grub_ssize_t ret
= 0;
355 unsigned long sector
;
357 /* This is a special case. FAT12 and FAT16 doesn't have the root directory
359 if (data
->file_cluster
== ~0U)
361 size
= (data
->num_root_sectors
<< GRUB_DISK_SECTOR_BITS
) - offset
;
365 if (grub_disk_read (disk
, data
->root_sector
, offset
, size
, buf
))
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;
378 if (logical_cluster
< data
->cur_cluster_num
)
380 data
->cur_cluster_num
= 0;
381 data
->cur_cluster
= data
->file_cluster
;
386 while (logical_cluster
> data
->cur_cluster_num
)
388 /* Find next cluster. */
389 grub_uint32_t next_cluster
;
390 unsigned long fat_offset
;
392 switch (data
->fat_size
)
395 fat_offset
= data
->cur_cluster
<< 2;
398 fat_offset
= data
->cur_cluster
<< 1;
402 fat_offset
= data
->cur_cluster
+ (data
->cur_cluster
>> 1);
407 if (grub_disk_read (disk
, data
->fat_sector
, fat_offset
,
408 (data
->fat_size
+ 7) >> 3,
409 (char *) &next_cluster
))
412 next_cluster
= grub_le_to_cpu32 (next_cluster
);
413 switch (data
->fat_size
)
416 next_cluster
&= 0xFFFF;
419 if (data
->cur_cluster
& 1)
422 next_cluster
&= 0x0FFF;
427 grub_printf ("%s:%d: fat_size=%d, next_cluster=%u\n",
428 __FILE__
, __LINE__
, data
->fat_size
, next_cluster
);
432 if (next_cluster
>= data
->cluster_eof_mark
)
435 if (next_cluster
< 2 || next_cluster
>= data
->num_clusters
)
437 grub_error (GRUB_ERR_BAD_FS
, "invalid cluster %u",
442 data
->cur_cluster
= next_cluster
;
443 data
->cur_cluster_num
++;
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
;
454 disk
->read_hook
= read_hook
;
455 grub_disk_read (disk
, sector
, offset
, size
, buf
);
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. */
474 grub_fat_find_dir (grub_disk_t disk
, struct grub_fat_data
*data
,
476 int (*hook
) (const char *filename
, int dir
))
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;
484 grub_ssize_t offset
= -sizeof(dir
);
487 if (! (data
->attr
& GRUB_FAT_ATTR_DIRECTORY
))
489 grub_error (GRUB_ERR_BAD_FILE_TYPE
, "not a directory");
493 /* Extract a directory name. */
497 dirp
= grub_strchr (path
, '/');
500 unsigned len
= dirp
- path
;
502 dirname
= grub_malloc (len
+ 1);
506 grub_memcpy (dirname
, path
, len
);
510 /* This is actually a file. */
511 dirname
= grub_strdup (path
);
513 call_hook
= (! dirp
&& hook
);
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
)
520 grub_free (filename
);
530 /* Adjust the offset. */
531 offset
+= sizeof (dir
);
533 /* Read a directory entry. */
534 if ((grub_fat_read_data (disk
, data
, 0,
535 offset
, sizeof (dir
), (char *) &dir
)
539 if (grub_errno
== GRUB_ERR_NONE
&& ! call_hook
)
540 grub_error (GRUB_ERR_FILE_NOT_FOUND
, "file not found");
545 /* Handle long name entries. */
546 if (dir
.attr
== GRUB_FAT_ATTR_LONG_NAME
)
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
;
556 checksum
= long_name
->checksum
;
559 if (id
!= slot
|| slot
== 0 || checksum
!= long_name
->checksum
)
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);
572 /* Check if this entry is valid. */
573 if (dir
.name
[0] == 0xe5 || (dir
.attr
& ~GRUB_FAT_ATTR_VALID
))
576 /* This is a workaround for Japanese. */
577 if (dir
.name
[0] == 0x05)
580 if (checksum
!= -1 && slot
== 0)
584 for (sum
= 0, i
= 0; i
< sizeof (dir
.name
); i
++)
585 sum
= ((sum
>> 1) | (sum
<< 7)) + dir
.name
[i
];
591 for (u
= 0; u
< slots
* 13; u
++)
592 unibuf
[u
] = grub_le_to_cpu16 (unibuf
[u
]);
594 *grub_utf16_to_utf8 ((grub_uint8_t
*) filename
, unibuf
,
597 if (*dirname
== '\0' && call_hook
)
599 if (hook (filename
, dir
.attr
& GRUB_FAT_ATTR_DIRECTORY
))
606 if (grub_strcmp (dirname
, filename
) == 0)
609 hook (filename
, dir
.attr
& GRUB_FAT_ATTR_DIRECTORY
);
618 /* Convert the 8.3 file name. */
621 for (i
= 0; i
< 8 && dir
.name
[i
] && ! grub_isspace (dir
.name
[i
]); i
++)
622 *filep
++ = grub_tolower (dir
.name
[i
]);
626 for (i
= 8; i
< 11 && dir
.name
[i
] && ! grub_isspace (dir
.name
[i
]); i
++)
627 *++filep
= grub_tolower (dir
.name
[i
]);
634 if (*dirname
== '\0' && call_hook
)
636 if (hook (filename
, dir
.attr
& GRUB_FAT_ATTR_DIRECTORY
))
639 else if (grub_strncasecmp (dirname
, filename
, GRUB_FAT_MAXFILE
) == 0)
642 hook (filename
, dir
.attr
& GRUB_FAT_ATTR_DIRECTORY
);
648 grub_free (filename
);
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;
661 grub_fat_dir (grub_device_t device
, const char *path
,
662 int (*hook
) (const char *filename
, int dir
))
664 struct grub_fat_data
*data
= 0;
665 grub_disk_t disk
= device
->disk
;
671 grub_dl_ref (my_mod
);
674 data
= grub_fat_mount (disk
);
678 /* Make sure that DIRNAME terminates with '/'. */
679 len
= grub_strlen (path
);
680 dirname
= grub_malloc (len
+ 1 + 1);
683 grub_memcpy (dirname
, path
, len
);
685 if (path
[len
- 1] != '/')
692 p
= grub_fat_find_dir (disk
, data
, p
, hook
);
694 while (p
&& grub_errno
== GRUB_ERR_NONE
);
702 grub_dl_unref (my_mod
);
709 grub_fat_open (grub_file_t file
, const char *name
)
711 struct grub_fat_data
*data
= 0;
712 char *p
= (char *) name
;
715 grub_dl_ref (my_mod
);
718 data
= grub_fat_mount (file
->device
->disk
);
724 p
= grub_fat_find_dir (file
->device
->disk
, data
, p
, 0);
725 if (grub_errno
!= GRUB_ERR_NONE
)
730 if (data
->attr
& GRUB_FAT_ATTR_DIRECTORY
)
732 grub_error (GRUB_ERR_BAD_FILE_TYPE
, "not a file");
737 file
->size
= data
->file_size
;
739 return GRUB_ERR_NONE
;
746 grub_dl_unref (my_mod
);
753 grub_fat_read (grub_file_t file
, char *buf
, grub_size_t len
)
755 return grub_fat_read_data (file
->device
->disk
, file
->data
, file
->read_hook
,
756 file
->offset
, len
, buf
);
760 grub_fat_close (grub_file_t file
)
762 grub_free (file
->data
);
765 grub_dl_unref (my_mod
);
772 grub_fat_label (grub_device_t device
, char **label
)
774 struct grub_fat_data
*data
;
775 grub_disk_t disk
= device
->disk
;
776 grub_ssize_t offset
= -sizeof(struct grub_fat_dir_entry
);
780 grub_dl_ref (my_mod
);
783 data
= grub_fat_mount (disk
);
787 if (! (data
->attr
& GRUB_FAT_ATTR_DIRECTORY
))
789 grub_error (GRUB_ERR_BAD_FILE_TYPE
, "not a directory");
795 struct grub_fat_dir_entry dir
;
797 /* Adjust the offset. */
798 offset
+= sizeof (dir
);
800 /* Read a directory entry. */
801 if ((grub_fat_read_data (disk
, data
, 0,
802 offset
, sizeof (dir
), (char *) &dir
)
806 if (grub_errno
!= GRUB_ERR_NONE
)
811 return GRUB_ERR_NONE
;
815 if (dir
.attr
== GRUB_FAT_ATTR_VOLUME_ID
)
817 *label
= grub_strndup ((char *) dir
.name
, 11);
818 return GRUB_ERR_NONE
;
827 grub_dl_unref (my_mod
);
836 grub_fat_uuid (grub_device_t device
, char **uuid
)
838 struct grub_fat_data
*data
;
839 grub_disk_t disk
= device
->disk
;
842 grub_dl_ref (my_mod
);
845 data
= grub_fat_mount (disk
);
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
);
856 grub_dl_unref (my_mod
);
864 static struct grub_fs grub_fat_fs
=
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
,
878 grub_fs_register (&grub_fat_fs
);
886 grub_fs_unregister (&grub_fat_fs
);