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 /* Get the sizes of logical sectors and clusters. */
191 data
->logical_sector_bits
=
192 fat_log2 (grub_le_to_cpu16 (bpb
.bytes_per_sector
));
193 if (data
->logical_sector_bits
< GRUB_DISK_SECTOR_BITS
)
195 data
->logical_sector_bits
-= GRUB_DISK_SECTOR_BITS
;
197 data
->cluster_bits
= fat_log2 (bpb
.sectors_per_cluster
);
198 if (data
->cluster_bits
< 0)
200 data
->cluster_bits
+= data
->logical_sector_bits
;
202 /* Get information about FATs. */
203 data
->fat_sector
= (grub_le_to_cpu16 (bpb
.num_reserved_sectors
)
204 << data
->logical_sector_bits
);
205 if (data
->fat_sector
== 0)
208 data
->sectors_per_fat
= ((bpb
.sectors_per_fat_16
209 ? grub_le_to_cpu16 (bpb
.sectors_per_fat_16
)
210 : grub_le_to_cpu32 (bpb
.version_specific
.fat32
.sectors_per_fat_32
))
211 << data
->logical_sector_bits
);
212 if (data
->sectors_per_fat
== 0)
215 /* Get the number of sectors in this volume. */
216 data
->num_sectors
= ((bpb
.num_total_sectors_16
217 ? grub_le_to_cpu16 (bpb
.num_total_sectors_16
)
218 : grub_le_to_cpu32 (bpb
.num_total_sectors_32
))
219 << data
->logical_sector_bits
);
220 if (data
->num_sectors
== 0)
223 /* Get information about the root directory. */
224 if (bpb
.num_fats
== 0)
227 data
->root_sector
= data
->fat_sector
+ bpb
.num_fats
* data
->sectors_per_fat
;
228 data
->num_root_sectors
229 = ((((grub_uint32_t
) grub_le_to_cpu16 (bpb
.num_root_entries
)
230 * GRUB_FAT_DIR_ENTRY_SIZE
231 + grub_le_to_cpu16 (bpb
.bytes_per_sector
) - 1)
232 >> (data
->logical_sector_bits
+ GRUB_DISK_SECTOR_BITS
))
233 << (data
->logical_sector_bits
));
235 data
->cluster_sector
= data
->root_sector
+ data
->num_root_sectors
;
236 data
->num_clusters
= (((data
->num_sectors
- data
->cluster_sector
)
237 >> (data
->cluster_bits
+ data
->logical_sector_bits
))
240 if (data
->num_clusters
<= 2)
243 if (! bpb
.sectors_per_fat_16
)
246 grub_uint16_t flags
= grub_le_to_cpu16 (bpb
.version_specific
.fat32
.extended_flags
);
248 data
->root_cluster
= grub_le_to_cpu32 (bpb
.version_specific
.fat32
.root_cluster
);
250 data
->cluster_eof_mark
= 0x0ffffff8;
254 /* Get an active FAT. */
255 unsigned active_fat
= flags
& 0xf;
257 if (active_fat
> bpb
.num_fats
)
260 data
->fat_sector
+= active_fat
* data
->sectors_per_fat
;
263 if (bpb
.num_root_entries
!= 0 || bpb
.version_specific
.fat32
.fs_version
!= 0)
268 /* FAT12 or FAT16. */
269 data
->root_cluster
= ~0U;
271 if (data
->num_clusters
<= 4085 + 2)
275 data
->cluster_eof_mark
= 0x0ff8;
281 data
->cluster_eof_mark
= 0xfff8;
285 /* More sanity checks. */
286 if (data
->num_sectors
<= data
->fat_sector
)
289 if (grub_disk_read (disk
,
293 (char *) &first_fat
))
296 first_fat
= grub_le_to_cpu32 (first_fat
);
298 if (data
->fat_size
== 32)
300 first_fat
&= 0x0fffffff;
303 else if (data
->fat_size
== 16)
305 first_fat
&= 0x0000ffff;
310 first_fat
&= 0x00000fff;
315 if (bpb
.sectors_per_fat_16
)
316 data
->uuid
= grub_le_to_cpu32 (bpb
.version_specific
.fat12_or_fat16
.num_serial
);
318 data
->uuid
= grub_le_to_cpu32 (bpb
.version_specific
.fat32
.num_serial
);
320 /* Ignore the 3rd bit, because some BIOSes assigns 0xF0 to the media
321 descriptor, even if it is a so-called superfloppy (e.g. an USB key).
322 The check may be too strict for this kind of stupid BIOSes, as
323 they overwrite the media descriptor. */
324 if ((first_fat
| 0x8) != (magic
| bpb
.media
| 0x8))
327 /* Start from the root directory. */
328 data
->file_cluster
= data
->root_cluster
;
329 data
->cur_cluster_num
= ~0U;
330 data
->attr
= GRUB_FAT_ATTR_DIRECTORY
;
336 grub_error (GRUB_ERR_BAD_FS
, "not a fat filesystem");
341 grub_fat_read_data (grub_disk_t disk
, struct grub_fat_data
*data
,
342 void NESTED_FUNC_ATTR (*read_hook
) (grub_disk_addr_t sector
,
343 unsigned offset
, unsigned length
),
344 grub_off_t offset
, grub_size_t len
, char *buf
)
347 grub_uint32_t logical_cluster
;
348 unsigned logical_cluster_bits
;
349 grub_ssize_t ret
= 0;
350 unsigned long sector
;
352 /* This is a special case. FAT12 and FAT16 doesn't have the root directory
354 if (data
->file_cluster
== ~0U)
356 size
= (data
->num_root_sectors
<< GRUB_DISK_SECTOR_BITS
) - offset
;
360 if (grub_disk_read (disk
, data
->root_sector
, offset
, size
, buf
))
366 /* Calculate the logical cluster number and offset. */
367 logical_cluster_bits
= (data
->cluster_bits
368 + data
->logical_sector_bits
369 + GRUB_DISK_SECTOR_BITS
);
370 logical_cluster
= offset
>> logical_cluster_bits
;
371 offset
&= (1 << logical_cluster_bits
) - 1;
373 if (logical_cluster
< data
->cur_cluster_num
)
375 data
->cur_cluster_num
= 0;
376 data
->cur_cluster
= data
->file_cluster
;
381 while (logical_cluster
> data
->cur_cluster_num
)
383 /* Find next cluster. */
384 grub_uint32_t next_cluster
;
385 unsigned long fat_offset
;
387 switch (data
->fat_size
)
390 fat_offset
= data
->cur_cluster
<< 2;
393 fat_offset
= data
->cur_cluster
<< 1;
397 fat_offset
= data
->cur_cluster
+ (data
->cur_cluster
>> 1);
402 if (grub_disk_read (disk
, data
->fat_sector
, fat_offset
,
403 (data
->fat_size
+ 7) >> 3,
404 (char *) &next_cluster
))
407 next_cluster
= grub_le_to_cpu32 (next_cluster
);
408 switch (data
->fat_size
)
411 next_cluster
&= 0xFFFF;
414 if (data
->cur_cluster
& 1)
417 next_cluster
&= 0x0FFF;
422 grub_printf ("%s:%d: fat_size=%d, next_cluster=%u\n",
423 __FILE__
, __LINE__
, data
->fat_size
, next_cluster
);
427 if (next_cluster
>= data
->cluster_eof_mark
)
430 if (next_cluster
< 2 || next_cluster
>= data
->num_clusters
)
432 grub_error (GRUB_ERR_BAD_FS
, "invalid cluster %u",
437 data
->cur_cluster
= next_cluster
;
438 data
->cur_cluster_num
++;
441 /* Read the data here. */
442 sector
= (data
->cluster_sector
443 + ((data
->cur_cluster
- 2)
444 << (data
->cluster_bits
+ data
->logical_sector_bits
)));
445 size
= (1 << logical_cluster_bits
) - offset
;
449 disk
->read_hook
= read_hook
;
450 grub_disk_read (disk
, sector
, offset
, size
, buf
);
465 /* Find the underlying directory or file in PATH and return the
466 next path. If there is no next path or an error occurs, return NULL.
467 If HOOK is specified, call it with each file name. */
469 grub_fat_find_dir (grub_disk_t disk
, struct grub_fat_data
*data
,
471 int (*hook
) (const char *filename
, int dir
))
473 struct grub_fat_dir_entry dir
;
474 char *dirname
, *dirp
;
475 char *filename
, *filep
= 0;
476 grub_uint16_t
*unibuf
;
477 int slot
= -1, slots
= -1;
479 grub_ssize_t offset
= -sizeof(dir
);
482 if (! (data
->attr
& GRUB_FAT_ATTR_DIRECTORY
))
484 grub_error (GRUB_ERR_BAD_FILE_TYPE
, "not a directory");
488 /* Extract a directory name. */
492 dirp
= grub_strchr (path
, '/');
495 unsigned len
= dirp
- path
;
497 dirname
= grub_malloc (len
+ 1);
501 grub_memcpy (dirname
, path
, len
);
505 /* This is actually a file. */
506 dirname
= grub_strdup (path
);
508 call_hook
= (! dirp
&& hook
);
510 /* Allocate space enough to hold a long name. */
511 filename
= grub_malloc (0x40 * 13 * 4 + 1);
512 unibuf
= (grub_uint16_t
*) grub_malloc (0x40 * 13 * 2);
513 if (! filename
|| ! unibuf
)
515 grub_free (filename
);
525 /* Adjust the offset. */
526 offset
+= sizeof (dir
);
528 /* Read a directory entry. */
529 if ((grub_fat_read_data (disk
, data
, 0,
530 offset
, sizeof (dir
), (char *) &dir
)
534 if (grub_errno
== GRUB_ERR_NONE
&& ! call_hook
)
535 grub_error (GRUB_ERR_FILE_NOT_FOUND
, "file not found");
540 /* Handle long name entries. */
541 if (dir
.attr
== GRUB_FAT_ATTR_LONG_NAME
)
543 struct grub_fat_long_name_entry
*long_name
544 = (struct grub_fat_long_name_entry
*) &dir
;
545 grub_uint8_t id
= long_name
->id
;
551 checksum
= long_name
->checksum
;
554 if (id
!= slot
|| slot
== 0 || checksum
!= long_name
->checksum
)
561 grub_memcpy (unibuf
+ slot
* 13, long_name
->name1
, 5 * 2);
562 grub_memcpy (unibuf
+ slot
* 13 + 5, long_name
->name2
, 6 * 2);
563 grub_memcpy (unibuf
+ slot
* 13 + 11, long_name
->name3
, 2 * 2);
567 /* Check if this entry is valid. */
568 if (dir
.name
[0] == 0xe5 || (dir
.attr
& ~GRUB_FAT_ATTR_VALID
))
571 /* This is a workaround for Japanese. */
572 if (dir
.name
[0] == 0x05)
575 if (checksum
!= -1 && slot
== 0)
579 for (sum
= 0, i
= 0; i
< sizeof (dir
.name
); i
++)
580 sum
= ((sum
>> 1) | (sum
<< 7)) + dir
.name
[i
];
586 for (u
= 0; u
< slots
* 13; u
++)
587 unibuf
[u
] = grub_le_to_cpu16 (unibuf
[u
]);
589 *grub_utf16_to_utf8 ((grub_uint8_t
*) filename
, unibuf
,
592 if (*dirname
== '\0' && call_hook
)
594 if (hook (filename
, dir
.attr
& GRUB_FAT_ATTR_DIRECTORY
))
601 if (grub_strcmp (dirname
, filename
) == 0)
604 hook (filename
, dir
.attr
& GRUB_FAT_ATTR_DIRECTORY
);
613 /* Convert the 8.3 file name. */
616 for (i
= 0; i
< 8 && dir
.name
[i
] && ! grub_isspace (dir
.name
[i
]); i
++)
617 *filep
++ = grub_tolower (dir
.name
[i
]);
621 for (i
= 8; i
< 11 && dir
.name
[i
] && ! grub_isspace (dir
.name
[i
]); i
++)
622 *++filep
= grub_tolower (dir
.name
[i
]);
629 if (*dirname
== '\0' && call_hook
)
631 if (hook (filename
, dir
.attr
& GRUB_FAT_ATTR_DIRECTORY
))
634 else if (grub_strncasecmp (dirname
, filename
, GRUB_FAT_MAXFILE
) == 0)
637 hook (filename
, dir
.attr
& GRUB_FAT_ATTR_DIRECTORY
);
643 grub_free (filename
);
646 data
->attr
= dir
.attr
;
647 data
->file_size
= grub_le_to_cpu32 (dir
.file_size
);
648 data
->file_cluster
= ((grub_le_to_cpu16 (dir
.first_cluster_high
) << 16)
649 | grub_le_to_cpu16 (dir
.first_cluster_low
));
650 data
->cur_cluster_num
= ~0U;
656 grub_fat_dir (grub_device_t device
, const char *path
,
657 int (*hook
) (const char *filename
, int dir
))
659 struct grub_fat_data
*data
= 0;
660 grub_disk_t disk
= device
->disk
;
666 grub_dl_ref (my_mod
);
669 data
= grub_fat_mount (disk
);
673 /* Make sure that DIRNAME terminates with '/'. */
674 len
= grub_strlen (path
);
675 dirname
= grub_malloc (len
+ 1 + 1);
678 grub_memcpy (dirname
, path
, len
);
680 if (path
[len
- 1] != '/')
687 p
= grub_fat_find_dir (disk
, data
, p
, hook
);
689 while (p
&& grub_errno
== GRUB_ERR_NONE
);
697 grub_dl_unref (my_mod
);
704 grub_fat_open (grub_file_t file
, const char *name
)
706 struct grub_fat_data
*data
= 0;
707 char *p
= (char *) name
;
710 grub_dl_ref (my_mod
);
713 data
= grub_fat_mount (file
->device
->disk
);
719 p
= grub_fat_find_dir (file
->device
->disk
, data
, p
, 0);
720 if (grub_errno
!= GRUB_ERR_NONE
)
725 if (data
->attr
& GRUB_FAT_ATTR_DIRECTORY
)
727 grub_error (GRUB_ERR_BAD_FILE_TYPE
, "not a file");
732 file
->size
= data
->file_size
;
734 return GRUB_ERR_NONE
;
741 grub_dl_unref (my_mod
);
748 grub_fat_read (grub_file_t file
, char *buf
, grub_size_t len
)
750 return grub_fat_read_data (file
->device
->disk
, file
->data
, file
->read_hook
,
751 file
->offset
, len
, buf
);
755 grub_fat_close (grub_file_t file
)
757 grub_free (file
->data
);
760 grub_dl_unref (my_mod
);
767 grub_fat_label (grub_device_t device
, char **label
)
769 struct grub_fat_data
*data
;
770 grub_disk_t disk
= device
->disk
;
771 grub_ssize_t offset
= -sizeof(struct grub_fat_dir_entry
);
775 grub_dl_ref (my_mod
);
778 data
= grub_fat_mount (disk
);
782 if (! (data
->attr
& GRUB_FAT_ATTR_DIRECTORY
))
784 grub_error (GRUB_ERR_BAD_FILE_TYPE
, "not a directory");
790 struct grub_fat_dir_entry dir
;
792 /* Adjust the offset. */
793 offset
+= sizeof (dir
);
795 /* Read a directory entry. */
796 if ((grub_fat_read_data (disk
, data
, 0,
797 offset
, sizeof (dir
), (char *) &dir
)
801 if (grub_errno
!= GRUB_ERR_NONE
)
806 return GRUB_ERR_NONE
;
810 if (dir
.attr
== GRUB_FAT_ATTR_VOLUME_ID
)
812 *label
= grub_strndup ((char *) dir
.name
, 11);
813 return GRUB_ERR_NONE
;
822 grub_dl_unref (my_mod
);
831 grub_fat_uuid (grub_device_t device
, char **uuid
)
833 struct grub_fat_data
*data
;
834 grub_disk_t disk
= device
->disk
;
837 grub_dl_ref (my_mod
);
840 data
= grub_fat_mount (disk
);
843 *uuid
= grub_malloc (sizeof ("xxxx-xxxx"));
844 grub_sprintf (*uuid
, "%04x-%04x", (grub_uint16_t
) (data
->uuid
>> 8),
845 (grub_uint16_t
) data
->uuid
);
851 grub_dl_unref (my_mod
);
859 static struct grub_fs grub_fat_fs
=
863 .open
= grub_fat_open
,
864 .read
= grub_fat_read
,
865 .close
= grub_fat_close
,
866 .label
= grub_fat_label
,
867 .uuid
= grub_fat_uuid
,
873 grub_fs_register (&grub_fat_fs
);
881 grub_fs_unregister (&grub_fat_fs
);