1 /* fat.c - FAT filesystem */
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2000,2001,2002,2003,2004,2005,2007 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_ATTR_LONG_NAME (GRUB_FAT_ATTR_READ_ONLY \
39 | GRUB_FAT_ATTR_HIDDEN \
40 | GRUB_FAT_ATTR_SYSTEM \
41 | GRUB_FAT_ATTR_VOLUME_ID)
42 #define GRUB_FAT_ATTR_VALID (GRUB_FAT_ATTR_READ_ONLY \
43 | GRUB_FAT_ATTR_HIDDEN \
44 | GRUB_FAT_ATTR_SYSTEM \
45 | GRUB_FAT_ATTR_DIRECTORY \
46 | GRUB_FAT_ATTR_ARCHIVE)
50 grub_uint8_t jmp_boot
[3];
51 grub_uint8_t oem_name
[8];
52 grub_uint16_t bytes_per_sector
;
53 grub_uint8_t sectors_per_cluster
;
54 grub_uint16_t num_reserved_sectors
;
55 grub_uint8_t num_fats
;
56 grub_uint16_t num_root_entries
;
57 grub_uint16_t num_total_sectors_16
;
59 grub_uint16_t sectors_per_fat_16
;
60 grub_uint16_t sectors_per_track
;
61 grub_uint16_t num_heads
;
62 grub_uint32_t num_hidden_sectors
;
63 grub_uint32_t num_total_sectors_32
;
65 /* The following fields are only used by FAT32. */
66 grub_uint32_t sectors_per_fat_32
;
67 grub_uint16_t extended_flags
;
68 grub_uint16_t fs_version
;
69 grub_uint32_t root_cluster
;
70 grub_uint16_t fs_info
;
71 grub_uint16_t backup_boot_sector
;
72 } __attribute__ ((packed
));
74 struct grub_fat_dir_entry
76 grub_uint8_t name
[11];
78 grub_uint8_t nt_reserved
;
79 grub_uint8_t c_time_tenth
;
83 grub_uint16_t first_cluster_high
;
86 grub_uint16_t first_cluster_low
;
87 grub_uint32_t file_size
;
88 } __attribute__ ((packed
));
90 struct grub_fat_long_name_entry
93 grub_uint16_t name1
[5];
95 grub_uint8_t reserved
;
96 grub_uint8_t checksum
;
97 grub_uint16_t name2
[6];
98 grub_uint16_t first_cluster
;
99 grub_uint16_t name3
[2];
100 } __attribute__ ((packed
));
104 int logical_sector_bits
;
105 grub_uint32_t num_sectors
;
107 grub_uint16_t fat_sector
;
108 grub_uint32_t sectors_per_fat
;
111 grub_uint32_t root_cluster
;
112 grub_uint32_t root_sector
;
113 grub_uint32_t num_root_sectors
;
116 grub_uint32_t cluster_eof_mark
;
117 grub_uint32_t cluster_sector
;
118 grub_uint32_t num_clusters
;
121 grub_ssize_t file_size
;
122 grub_uint32_t file_cluster
;
123 grub_uint32_t cur_cluster_num
;
124 grub_uint32_t cur_cluster
;
128 static grub_dl_t my_mod
;
132 fat_log2 (unsigned x
)
139 for (i
= 0; (x
& 1) == 0; i
++)
148 static struct grub_fat_data
*
149 grub_fat_mount (grub_disk_t disk
)
151 struct grub_fat_bpb bpb
;
152 struct grub_fat_data
*data
= 0;
153 grub_uint32_t first_fat
, magic
;
158 data
= (struct grub_fat_data
*) grub_malloc (sizeof (*data
));
163 if (grub_disk_read (disk
, 0, 0, sizeof (bpb
), (char *) &bpb
))
166 /* Get the sizes of logical sectors and clusters. */
167 data
->logical_sector_bits
=
168 fat_log2 (grub_le_to_cpu16 (bpb
.bytes_per_sector
));
169 if (data
->logical_sector_bits
< GRUB_DISK_SECTOR_BITS
)
171 data
->logical_sector_bits
-= GRUB_DISK_SECTOR_BITS
;
173 data
->cluster_bits
= fat_log2 (bpb
.sectors_per_cluster
);
174 if (data
->cluster_bits
< 0)
176 data
->cluster_bits
+= data
->logical_sector_bits
;
178 /* Get information about FATs. */
179 data
->fat_sector
= (grub_le_to_cpu16 (bpb
.num_reserved_sectors
)
180 << data
->logical_sector_bits
);
181 if (data
->fat_sector
== 0)
184 data
->sectors_per_fat
= ((bpb
.sectors_per_fat_16
185 ? grub_le_to_cpu16 (bpb
.sectors_per_fat_16
)
186 : grub_le_to_cpu32 (bpb
.sectors_per_fat_32
))
187 << data
->logical_sector_bits
);
188 if (data
->sectors_per_fat
== 0)
191 /* Get the number of sectors in this volume. */
192 data
->num_sectors
= ((bpb
.num_total_sectors_16
193 ? grub_le_to_cpu16 (bpb
.num_total_sectors_16
)
194 : grub_le_to_cpu32 (bpb
.num_total_sectors_32
))
195 << data
->logical_sector_bits
);
196 if (data
->num_sectors
== 0)
199 /* Get information about the root directory. */
200 if (bpb
.num_fats
== 0)
203 data
->root_sector
= data
->fat_sector
+ bpb
.num_fats
* data
->sectors_per_fat
;
204 data
->num_root_sectors
205 = ((((grub_uint32_t
) grub_le_to_cpu16 (bpb
.num_root_entries
)
206 * GRUB_FAT_DIR_ENTRY_SIZE
207 + grub_le_to_cpu16 (bpb
.bytes_per_sector
) - 1)
208 >> (data
->logical_sector_bits
+ GRUB_DISK_SECTOR_BITS
))
209 << (data
->logical_sector_bits
));
211 data
->cluster_sector
= data
->root_sector
+ data
->num_root_sectors
;
212 data
->num_clusters
= (((data
->num_sectors
- data
->cluster_sector
)
213 >> (data
->cluster_bits
+ data
->logical_sector_bits
))
216 if (data
->num_clusters
<= 2)
219 if (! bpb
.sectors_per_fat_16
)
222 grub_uint16_t flags
= grub_le_to_cpu16 (bpb
.extended_flags
);
224 data
->root_cluster
= grub_le_to_cpu32 (bpb
.root_cluster
);
226 data
->cluster_eof_mark
= 0x0ffffff8;
230 /* Get an active FAT. */
231 unsigned active_fat
= flags
& 0xf;
233 if (active_fat
> bpb
.num_fats
)
236 data
->fat_sector
+= active_fat
* data
->sectors_per_fat
;
239 if (bpb
.num_root_entries
!= 0 || bpb
.fs_version
!= 0)
244 /* FAT12 or FAT16. */
245 data
->root_cluster
= ~0U;
247 if (data
->num_clusters
<= 4085 + 2)
251 data
->cluster_eof_mark
= 0x0ff8;
257 data
->cluster_eof_mark
= 0xfff8;
261 /* More sanity checks. */
262 if (data
->num_sectors
<= data
->fat_sector
)
265 if (grub_disk_read (disk
,
269 (char *) &first_fat
))
272 first_fat
= grub_le_to_cpu32 (first_fat
);
274 if (data
->fat_size
== 32)
276 first_fat
&= 0x0fffffff;
279 else if (data
->fat_size
== 16)
281 first_fat
&= 0x0000ffff;
286 first_fat
&= 0x00000fff;
290 /* Ignore the 3rd bit, because some BIOSes assigns 0xF0 to the media
291 descriptor, even if it is a so-called superfloppy (e.g. an USB key).
292 The check may be too strict for this kind of stupid BIOSes, as
293 they overwrite the media descriptor. */
294 if ((first_fat
| 0x8) != (magic
| bpb
.media
| 0x8))
297 /* Start from the root directory. */
298 data
->file_cluster
= data
->root_cluster
;
299 data
->cur_cluster_num
= ~0U;
300 data
->attr
= GRUB_FAT_ATTR_DIRECTORY
;
306 grub_error (GRUB_ERR_BAD_FS
, "not a fat filesystem");
311 grub_fat_read_data (grub_disk_t disk
, struct grub_fat_data
*data
,
312 void NESTED_FUNC_ATTR (*read_hook
) (grub_disk_addr_t sector
,
313 unsigned offset
, unsigned length
),
314 grub_off_t offset
, grub_size_t len
, char *buf
)
317 grub_uint32_t logical_cluster
;
318 unsigned logical_cluster_bits
;
319 grub_ssize_t ret
= 0;
320 unsigned long sector
;
322 /* This is a special case. FAT12 and FAT16 doesn't have the root directory
324 if (data
->file_cluster
== ~0U)
326 size
= (data
->num_root_sectors
<< GRUB_DISK_SECTOR_BITS
) - offset
;
330 if (grub_disk_read (disk
, data
->root_sector
, offset
, size
, buf
))
336 /* Calculate the logical cluster number and offset. */
337 logical_cluster_bits
= (data
->cluster_bits
338 + data
->logical_sector_bits
339 + GRUB_DISK_SECTOR_BITS
);
340 logical_cluster
= offset
>> logical_cluster_bits
;
341 offset
&= (1 << logical_cluster_bits
) - 1;
343 if (logical_cluster
< data
->cur_cluster_num
)
345 data
->cur_cluster_num
= 0;
346 data
->cur_cluster
= data
->file_cluster
;
351 while (logical_cluster
> data
->cur_cluster_num
)
353 /* Find next cluster. */
354 grub_uint32_t next_cluster
;
355 unsigned long fat_offset
;
357 switch (data
->fat_size
)
360 fat_offset
= data
->cur_cluster
<< 2;
363 fat_offset
= data
->cur_cluster
<< 1;
367 fat_offset
= data
->cur_cluster
+ (data
->cur_cluster
>> 1);
372 if (grub_disk_read (disk
, data
->fat_sector
, fat_offset
,
373 (data
->fat_size
+ 7) >> 3,
374 (char *) &next_cluster
))
377 next_cluster
= grub_le_to_cpu32 (next_cluster
);
378 switch (data
->fat_size
)
381 next_cluster
&= 0xFFFF;
384 if (data
->cur_cluster
& 1)
387 next_cluster
&= 0x0FFF;
392 grub_printf ("%s:%d: fat_size=%d, next_cluster=%u\n",
393 __FILE__
, __LINE__
, data
->fat_size
, next_cluster
);
397 if (next_cluster
>= data
->cluster_eof_mark
)
400 if (next_cluster
< 2 || next_cluster
>= data
->num_clusters
)
402 grub_error (GRUB_ERR_BAD_FS
, "invalid cluster %u",
407 data
->cur_cluster
= next_cluster
;
408 data
->cur_cluster_num
++;
411 /* Read the data here. */
412 sector
= (data
->cluster_sector
413 + ((data
->cur_cluster
- 2)
414 << (data
->cluster_bits
+ data
->logical_sector_bits
)));
415 size
= (1 << logical_cluster_bits
) - offset
;
419 disk
->read_hook
= read_hook
;
420 grub_disk_read (disk
, sector
, offset
, size
, buf
);
435 /* Find the underlying directory or file in PATH and return the
436 next path. If there is no next path or an error occurs, return NULL.
437 If HOOK is specified, call it with each file name. */
439 grub_fat_find_dir (grub_disk_t disk
, struct grub_fat_data
*data
,
441 int (*hook
) (const char *filename
, int dir
))
443 struct grub_fat_dir_entry dir
;
444 char *dirname
, *dirp
;
445 char *filename
, *filep
= 0;
446 grub_uint16_t
*unibuf
;
447 int slot
= -1, slots
= -1;
449 grub_ssize_t offset
= -sizeof(dir
);
452 if (! (data
->attr
& GRUB_FAT_ATTR_DIRECTORY
))
454 grub_error (GRUB_ERR_BAD_FILE_TYPE
, "not a directory");
458 /* Extract a directory name. */
462 dirp
= grub_strchr (path
, '/');
465 unsigned len
= dirp
- path
;
467 dirname
= grub_malloc (len
+ 1);
471 grub_memcpy (dirname
, path
, len
);
475 /* This is actually a file. */
476 dirname
= grub_strdup (path
);
478 call_hook
= (! dirp
&& hook
);
480 /* Allocate space enough to hold a long name. */
481 filename
= grub_malloc (0x40 * 13 * 4 + 1);
482 unibuf
= (grub_uint16_t
*) grub_malloc (0x40 * 13 * 2);
483 if (! filename
|| ! unibuf
)
485 grub_free (filename
);
495 /* Adjust the offset. */
496 offset
+= sizeof (dir
);
498 /* Read a directory entry. */
499 if ((grub_fat_read_data (disk
, data
, 0,
500 offset
, sizeof (dir
), (char *) &dir
)
504 if (grub_errno
== GRUB_ERR_NONE
&& ! call_hook
)
505 grub_error (GRUB_ERR_FILE_NOT_FOUND
, "file not found");
510 /* Handle long name entries. */
511 if (dir
.attr
== GRUB_FAT_ATTR_LONG_NAME
)
513 struct grub_fat_long_name_entry
*long_name
514 = (struct grub_fat_long_name_entry
*) &dir
;
515 grub_uint8_t id
= long_name
->id
;
521 checksum
= long_name
->checksum
;
524 if (id
!= slot
|| slot
== 0 || checksum
!= long_name
->checksum
)
531 grub_memcpy (unibuf
+ slot
* 13, long_name
->name1
, 5 * 2);
532 grub_memcpy (unibuf
+ slot
* 13 + 5, long_name
->name2
, 6 * 2);
533 grub_memcpy (unibuf
+ slot
* 13 + 11, long_name
->name3
, 2 * 2);
537 /* Check if this entry is valid. */
538 if (dir
.name
[0] == 0xe5 || (dir
.attr
& ~GRUB_FAT_ATTR_VALID
))
541 /* This is a workaround for Japanese. */
542 if (dir
.name
[0] == 0x05)
545 if (checksum
!= -1 && slot
== 0)
549 for (sum
= 0, i
= 0; i
< sizeof (dir
.name
); i
++)
550 sum
= ((sum
>> 1) | (sum
<< 7)) + dir
.name
[i
];
556 for (u
= 0; u
< slots
* 13; u
++)
557 unibuf
[u
] = grub_le_to_cpu16 (unibuf
[u
]);
559 *grub_utf16_to_utf8 ((grub_uint8_t
*) filename
, unibuf
,
562 if (*dirname
== '\0' && call_hook
)
564 if (hook (filename
, dir
.attr
& GRUB_FAT_ATTR_DIRECTORY
))
571 if (grub_strcmp (dirname
, filename
) == 0)
574 hook (filename
, dir
.attr
& GRUB_FAT_ATTR_DIRECTORY
);
583 /* Convert the 8.3 file name. */
586 for (i
= 0; i
< 8 && dir
.name
[i
] && ! grub_isspace (dir
.name
[i
]); i
++)
587 *filep
++ = grub_tolower (dir
.name
[i
]);
591 for (i
= 8; i
< 11 && dir
.name
[i
] && ! grub_isspace (dir
.name
[i
]); i
++)
592 *++filep
= grub_tolower (dir
.name
[i
]);
599 if (*dirname
== '\0' && call_hook
)
601 if (hook (filename
, dir
.attr
& GRUB_FAT_ATTR_DIRECTORY
))
604 else if (grub_strcmp (dirname
, filename
) == 0)
607 hook (filename
, dir
.attr
& GRUB_FAT_ATTR_DIRECTORY
);
613 grub_free (filename
);
616 data
->attr
= dir
.attr
;
617 data
->file_size
= grub_le_to_cpu32 (dir
.file_size
);
618 data
->file_cluster
= ((grub_le_to_cpu16 (dir
.first_cluster_high
) << 16)
619 | grub_le_to_cpu16 (dir
.first_cluster_low
));
620 data
->cur_cluster_num
= ~0U;
626 grub_fat_dir (grub_device_t device
, const char *path
,
627 int (*hook
) (const char *filename
, int dir
))
629 struct grub_fat_data
*data
= 0;
630 grub_disk_t disk
= device
->disk
;
636 grub_dl_ref (my_mod
);
639 data
= grub_fat_mount (disk
);
643 /* Make sure that DIRNAME terminates with '/'. */
644 len
= grub_strlen (path
);
645 dirname
= grub_malloc (len
+ 1 + 1);
648 grub_memcpy (dirname
, path
, len
);
650 if (path
[len
- 1] != '/')
657 p
= grub_fat_find_dir (disk
, data
, p
, hook
);
659 while (p
&& grub_errno
== GRUB_ERR_NONE
);
667 grub_dl_unref (my_mod
);
674 grub_fat_open (grub_file_t file
, const char *name
)
676 struct grub_fat_data
*data
= 0;
677 char *p
= (char *) name
;
680 grub_dl_ref (my_mod
);
683 data
= grub_fat_mount (file
->device
->disk
);
689 p
= grub_fat_find_dir (file
->device
->disk
, data
, p
, 0);
690 if (grub_errno
!= GRUB_ERR_NONE
)
695 if (data
->attr
& GRUB_FAT_ATTR_DIRECTORY
)
697 grub_error (GRUB_ERR_BAD_FILE_TYPE
, "not a file");
702 file
->size
= data
->file_size
;
704 return GRUB_ERR_NONE
;
711 grub_dl_unref (my_mod
);
718 grub_fat_read (grub_file_t file
, char *buf
, grub_size_t len
)
720 return grub_fat_read_data (file
->device
->disk
, file
->data
, file
->read_hook
,
721 file
->offset
, len
, buf
);
725 grub_fat_close (grub_file_t file
)
727 grub_free (file
->data
);
730 grub_dl_unref (my_mod
);
737 grub_fat_label (grub_device_t device
, char **label
)
739 struct grub_fat_data
*data
;
740 grub_disk_t disk
= device
->disk
;
741 grub_ssize_t offset
= -sizeof(struct grub_fat_dir_entry
);
745 grub_dl_ref (my_mod
);
748 data
= grub_fat_mount (disk
);
752 if (! (data
->attr
& GRUB_FAT_ATTR_DIRECTORY
))
754 grub_error (GRUB_ERR_BAD_FILE_TYPE
, "not a directory");
760 struct grub_fat_dir_entry dir
;
762 /* Adjust the offset. */
763 offset
+= sizeof (dir
);
765 /* Read a directory entry. */
766 if ((grub_fat_read_data (disk
, data
, 0,
767 offset
, sizeof (dir
), (char *) &dir
)
771 if (grub_errno
!= GRUB_ERR_NONE
)
776 return GRUB_ERR_NONE
;
780 if (dir
.attr
== GRUB_FAT_ATTR_VOLUME_ID
)
782 *label
= grub_strndup ((char *) dir
.name
, 11);
783 return GRUB_ERR_NONE
;
792 grub_dl_unref (my_mod
);
800 static struct grub_fs grub_fat_fs
=
804 .open
= grub_fat_open
,
805 .read
= grub_fat_read
,
806 .close
= grub_fat_close
,
807 .label
= grub_fat_label
,
813 grub_fs_register (&grub_fat_fs
);
821 grub_fs_unregister (&grub_fat_fs
);