add long filename support into FAT, fix a typo in configure.

This commit is contained in:
okuji 2000-02-18 04:34:42 +00:00
parent 7c4acb2539
commit 85c66cb4c8
12 changed files with 431 additions and 240 deletions

4
BUGS
View file

@ -1,6 +1,8 @@
Known problems/bugs: Known problems/bugs:
- GRUB cannot boot FreeBSD 3.4 and 4.0 directly. So you must
chain-load them instead.
- GRUB hangs up when accessing a disk via Adaptec AIC-7880 - GRUB hangs up when accessing a disk via Adaptec AIC-7880
SCSI-controller in LBA mode. It is unknown if this is due to GRUB or SCSI-controller in LBA mode. It is unknown if this is due to GRUB or
the SCSI BIOS. For now, you need to disable the BIOS support for the SCSI BIOS. For now, you need to disable the BIOS support for

View file

@ -1,3 +1,52 @@
2000-02-17 OKUJI Yoshinori <okuji@gnu.org>
* configure.in (--enable-3c90x): Add -DINCLUDE_3C90X=1 instead
of -DINCLUDE_3C90x=1. This was just a typo. Reported by Per
Lundberg.
2000-02-17 Jochen Hoenicke <jochen@gnu.org>
* stage2/fsys_fat.c (fat_read): Forgot to increase BUF.
(fat_dir): Use fat_read instead of grub_read; this makes
setting the FSMAX unnecessary.
(fat_mount): FSMAX is no longer set.
2000-02-16 Jochen Hoenicke <jochen@gnu.org>
* stage2/char_io.c (grub_isspace): Make carriage return a white
space.
* stage2/fsys_fat.c (fat_dir): Long filename support.
(NAME_BUF): New macro.
* stage2/fat.h (FAT_LONGDIR_ID, FAT_LONGDIR_ALIASCHECKSUM,
FAT_ATTRIB_LONGNAME): New Macros.
* stage2/fsys_fat.c (fat_create_blocklist): Deleted, instead
fat_read is implemented.
(fat_read): new function.
* stage2/disk_io.c (fsys_table): Use fat_read.
* stage2/filesys.h: Declare fat_read, remove NO_BLOCK_FILES
hack.
* stage2/Makefile.am: Compile fat_stage1_5 with
-DNO_BLOCK_FILES=1.
* stage2/fat.h (fat_bpb): New structure describing bpb.
(FAT_CVT_U16): New macro.
(FAT_BPB_CHECK_SIG, FAT_BPB_NUM_SECTORS,
FAT_BPB_BYTES_PER_SECTOR, FAT_BPB_SECT_PER_CLUS, FAT_BPB_NUMFAT,
FAT_BPB_RESERVED_SECTORS, FAT_BPB_FAT_SECTORS_16,
FAT_BPB_FAT_SECTORS_32, FAT_BPB_IS_FAT32, FAT_BPB_FAT_SECTORS,
FAT_BPB_FAT_START, FAT_BPB_ROOT_DIR_CLUSTER,
FAT_BPB_HIDDEN_SECTORS, FAT_BPB_ROOT_DIR_START,
FAT_BPB_ROOT_DIR_LENGTH, FAT_BPB_DATA_OFFSET,
FAT_BPB_NUM_CLUST): Macros removed.
* stage2/fsys_fat.c (fat_superblock): New structure containing
all info about currently mounted filesystem.
(FAT_SUPER): New Macro.
(BPB): Macro removod.
(fat_mount): Use fat_bpb structure, fill FAT_SUPER.
(fat_read, fat_dir): Use FAT_SUPER info.
2000-02-16 OKUJI Yoshinori <okuji@gnu.org> 2000-02-16 OKUJI Yoshinori <okuji@gnu.org>
Pass the boot partition information to a chain-loader, in the Pass the boot partition information to a chain-loader, in the

1
NEWS
View file

@ -40,6 +40,7 @@ New in 0.5.94:
check if GRUB accesses a drive in LBA mode by the command "geometry". check if GRUB accesses a drive in LBA mode by the command "geometry".
* New commands "bootp", "dhcp" and "rarp" can be used to initialize a * New commands "bootp", "dhcp" and "rarp" can be used to initialize a
network device and get IP addresses from a network. network device and get IP addresses from a network.
* Long filename support in the FAT filesystem is added.
New in 0.5.93 - 1999-10-30: New in 0.5.93 - 1999-10-30:
* ELF format of FreeBSD kernel is supported. * ELF format of FreeBSD kernel is supported.

2
configure vendored
View file

@ -2479,7 +2479,7 @@ if test "${enable_3c90x+set}" = set; then
fi fi
if test "x$enable_3c90x" = xyes; then if test "x$enable_3c90x" = xyes; then
NET_CFLAGS="$NET_CFLAGS -DINCLUDE_3C90x=1" NET_CFLAGS="$NET_CFLAGS -DINCLUDE_3C90X=1"
NETBOOT_DRIVERS="$NETBOOT_DRIVERS 3c90x.o" NETBOOT_DRIVERS="$NETBOOT_DRIVERS 3c90x.o"
fi fi

View file

@ -254,7 +254,7 @@ fi
AC_ARG_ENABLE(3c90x, AC_ARG_ENABLE(3c90x,
[ --enable-3c90x enable 3Com90x driver]) [ --enable-3c90x enable 3Com90x driver])
if test "x$enable_3c90x" = xyes; then if test "x$enable_3c90x" = xyes; then
NET_CFLAGS="$NET_CFLAGS -DINCLUDE_3C90x=1" NET_CFLAGS="$NET_CFLAGS -DINCLUDE_3C90X=1"
NETBOOT_DRIVERS="$NETBOOT_DRIVERS 3c90x.o" NETBOOT_DRIVERS="$NETBOOT_DRIVERS 3c90x.o"
fi fi

View file

@ -80,7 +80,8 @@ e2fs_stage1_5_exec_LDFLAGS = $(STAGE1_5_LINK)
# For fat_stage1_5 target. # For fat_stage1_5 target.
fat_stage1_5_exec_SOURCES = start.S asm.S common.c char_io.c disk_io.c \ fat_stage1_5_exec_SOURCES = start.S asm.S common.c char_io.c disk_io.c \
stage1_5.c fsys_fat.c bios.c stage1_5.c fsys_fat.c bios.c
fat_stage1_5_exec_CFLAGS = $(STAGE1_5_COMPILE) -DFSYS_FAT=1 fat_stage1_5_exec_CFLAGS = $(STAGE1_5_COMPILE) -DFSYS_FAT=1 \
-DNO_BLOCK_FILES=1
fat_stage1_5_exec_LDFLAGS = $(STAGE1_5_LINK) fat_stage1_5_exec_LDFLAGS = $(STAGE1_5_LINK)
# For ffs_stage1_5 target. # For ffs_stage1_5 target.

View file

@ -158,7 +158,8 @@ e2fs_stage1_5_exec_LDFLAGS = $(STAGE1_5_LINK)
fat_stage1_5_exec_SOURCES = start.S asm.S common.c char_io.c disk_io.c \ fat_stage1_5_exec_SOURCES = start.S asm.S common.c char_io.c disk_io.c \
stage1_5.c fsys_fat.c bios.c stage1_5.c fsys_fat.c bios.c
fat_stage1_5_exec_CFLAGS = $(STAGE1_5_COMPILE) -DFSYS_FAT=1 fat_stage1_5_exec_CFLAGS = $(STAGE1_5_COMPILE) -DFSYS_FAT=1 \
-DNO_BLOCK_FILES=1
fat_stage1_5_exec_LDFLAGS = $(STAGE1_5_LINK) fat_stage1_5_exec_LDFLAGS = $(STAGE1_5_LINK)
# For ffs_stage1_5 target. # For ffs_stage1_5 target.

View file

@ -675,7 +675,7 @@ grub_tolower (int c)
int int
grub_isspace (int c) grub_isspace (int c)
{ {
if (c == ' ' || c == '\t' || c == '\n') if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
return 1; return 1;
return 0; return 0;

View file

@ -45,7 +45,7 @@ struct fsys_entry fsys_table[NUM_FSYS + 1] =
{"tftp", tftp_mount, tftp_read, tftp_dir, tftp_close}, {"tftp", tftp_mount, tftp_read, tftp_dir, tftp_close},
# endif # endif
# ifdef FSYS_FAT # ifdef FSYS_FAT
{"fat", fat_mount, 0, fat_dir, 0}, {"fat", fat_mount, fat_read, fat_dir, 0},
# endif # endif
# ifdef FSYS_EXT2FS # ifdef FSYS_EXT2FS
{"ext2fs", ext2fs_mount, ext2fs_read, ext2fs_dir, 0}, {"ext2fs", ext2fs_mount, ext2fs_read, ext2fs_dir, 0},

View file

@ -23,65 +23,44 @@
* of the partition. * of the partition.
*/ */
#define FAT_BPB_SIGNATURE 0x29 typedef __signed__ char __s8;
typedef unsigned char __u8;
typedef __signed__ short __s16;
typedef unsigned short __u16;
typedef __signed__ int __s32;
typedef unsigned int __u32;
/* is checking for this signature thing even valid? */ /* Note that some shorts are not aligned, and must therefore
#define FAT_BPB_CHECK_SIG(bpb) \ * be declared as array of two bytes.
(*((unsigned char *) (((int)bpb) + 38)) == FAT_BPB_SIGNATURE)
#define FAT_BPB_NUM_SECTORS(bpb) \
( *((unsigned short *) (((int)bpb) + 19)) ? \
*((unsigned short *) (((int)bpb) + 19)) : \
*((unsigned long *) (((int)bpb) + 32)) )
#define FAT_BPB_BYTES_PER_SECTOR(bpb) \
(*((unsigned short *) (((int)bpb) + 11)))
#define FAT_BPB_SECT_PER_CLUST(bpb) \
(*((unsigned char *) (((int)bpb) + 13)))
#define FAT_BPB_NUM_FAT(bpb) \
(*((unsigned char *) (((int)bpb) + 16)))
#define FAT_BPB_RESERVED_SECTORS(bpb) \
(*((unsigned short *) (((int)bpb) + 14)))
#define FAT_BPB_FAT_SECTORS_16(bpb) \
(*((unsigned short *) (((int)bpb) + 22)))
#define FAT_BPB_FAT_SECTORS_32(bpb) \
(*((unsigned long *) (((int)bpb) + 36)))
#define FAT_BPB_IS_FAT32(bpb) \
(FAT_BPB_FAT_SECTORS_16(bpb) == 0)
#define FAT_BPB_FAT_SECTORS(bpb) \
(FAT_BPB_FAT_SECTORS_16(bpb) \
? FAT_BPB_FAT_SECTORS_16(bpb) : FAT_BPB_FAT_SECTORS_32(bpb))
#define FAT_BPB_FAT_START(bpb) FAT_BPB_RESERVED_SECTORS(bpb)
#define FAT_BPB_ROOT_DIR_CLUSTER(bpb) \
(*((unsigned long *) (((int)bpb) + 44)))
/*
* This appears to be a MAJOR kludge!! Don't use it if possible...
*/ */
#define FAT_BPB_HIDDEN_SECTORS(bpb) \ struct fat_bpb {
(*((unsigned long *) (((int)bpb) + 28))) __s8 ignored[3]; /* Boot strap short or near jump */
__s8 system_id[8]; /* Name - can be used to special case
partition manager volumes */
__u8 bytes_per_sect[2]; /* bytes per logical sector */
__u8 sects_per_clust;/* sectors/cluster */
__u8 reserved_sects[2]; /* reserved sectors */
__u8 num_fats; /* number of FATs */
__u8 dir_entries[2]; /* root directory entries */
__u8 short_sectors[2]; /* number of sectors */
__u8 media; /* media code (unused) */
__u16 fat_length; /* sectors/FAT */
__u16 secs_track; /* sectors per track */
__u16 heads; /* number of heads */
__u32 hidden; /* hidden sectors (unused) */
__u32 long_sectors; /* number of sectors (if short_sectors == 0) */
#define FAT_BPB_ROOT_DIR_START(bpb) \ /* The following fields are only used by FAT32 */
( FAT_BPB_NUM_FAT(bpb) * FAT_BPB_FAT_SECTORS(bpb) \ __u32 fat32_length; /* sectors/FAT */
+ FAT_BPB_FAT_START(bpb) ) __u16 flags; /* bit 8: fat mirroring, low 4: active fat */
__u8 version[2]; /* major, minor filesystem version */
__u32 root_cluster; /* first cluster in root directory */
__u16 info_sector; /* filesystem info sector */
__u16 backup_boot; /* backup boot sector */
__u16 reserved2[6]; /* Unused */
};
#define FAT_BPB_ROOT_DIR_LENGTH(bpb) \ #define FAT_CVT_U16(bytarr) (* (__u16*)(bytarr))
( (*((unsigned short *) (((int)bpb) + 17)) + 0xF) >> 4 )
#define FAT_BPB_DATA_OFFSET(bpb) \
( FAT_BPB_ROOT_DIR_START(bpb) + FAT_BPB_ROOT_DIR_LENGTH(bpb) )
#define FAT_BPB_NUM_CLUST(bpb) \
( ( FAT_BPB_NUM_SECTORS(bpb) - FAT_BPB_DATA_OFFSET(bpb) ) \
/ FAT_BPB_SECT_PER_CLUST(bpb) )
/*
* Defines minimum disk size to be considered a FAT partition
*/
#define FAT_MIN_NUM_SECTORS 720 /* 360 K disk */
/* /*
* Defines how to differentiate a 12-bit and 16-bit FAT. * Defines how to differentiate a 12-bit and 16-bit FAT.
@ -89,13 +68,6 @@
#define FAT_MAX_12BIT_CLUST 4087 /* 4085 + 2 */ #define FAT_MAX_12BIT_CLUST 4087 /* 4085 + 2 */
#define FAT_BPB_FLOPPY_NUM_SECTORS(bpb) \
( *((unsigned short *) (((int)bpb) + 19)) \
&& !*((unsigned long *) (((int)bpb) + 32)) \
&& *((unsigned short *) (((int)bpb) + 19)) >= FAT_MIN_NUM_SECTORS \
&& ((*((unsigned short *) (((int)bpb) + 19)) - FAT_BPB_DATA_OFFSET(bpb)) \
/ FAT_BPB_SECT_PER_CLUST(bpb)) < (FAT_BPB_FAT_SECTORS(bpb) * 342) )
/* /*
* Defines for the file "attribute" byte * Defines for the file "attribute" byte
*/ */
@ -103,7 +75,7 @@
#define FAT_ATTRIB_OK_MASK 0x37 #define FAT_ATTRIB_OK_MASK 0x37
#define FAT_ATTRIB_NOT_OK_MASK 0xC8 #define FAT_ATTRIB_NOT_OK_MASK 0xC8
#define FAT_ATTRIB_DIR 0x10 #define FAT_ATTRIB_DIR 0x10
#define FAT_ATTRIB_LONGNAME 0x0F
/* /*
* Defines for FAT directory entries * Defines for FAT directory entries
@ -115,9 +87,14 @@
(*((unsigned char *) (entry+11))) (*((unsigned char *) (entry+11)))
#define FAT_DIRENTRY_VALID(entry) \ #define FAT_DIRENTRY_VALID(entry) \
( ((*((unsigned char *) entry)) != 0) \ ( ((*((unsigned char *) entry)) != 0) \
& ((*((unsigned char *) entry)) != 0xE5) \ && ((*((unsigned char *) entry)) != 0xE5) \
& !(FAT_DIRENTRY_ATTRIB(entry) & FAT_ATTRIB_NOT_OK_MASK) ) && !(FAT_DIRENTRY_ATTRIB(entry) & FAT_ATTRIB_NOT_OK_MASK) )
#define FAT_DIRENTRY_FIRST_CLUSTER(entry) \ #define FAT_DIRENTRY_FIRST_CLUSTER(entry) \
((*((unsigned short *) (entry+26)))+(*((unsigned short *) (entry+20)) << 16)) ((*((unsigned short *) (entry+26)))+(*((unsigned short *) (entry+20)) << 16))
#define FAT_DIRENTRY_FILELENGTH(entry) \ #define FAT_DIRENTRY_FILELENGTH(entry) \
(*((unsigned long *) (entry+28))) (*((unsigned long *) (entry+28)))
#define FAT_LONGDIR_ID(entry) \
(*((unsigned char *) (entry)))
#define FAT_LONGDIR_ALIASCHECKSUM(entry) \
(*((unsigned char *) (entry+13)))

View file

@ -33,11 +33,8 @@ int ffs_dir (char *dirname);
#ifdef FSYS_FAT #ifdef FSYS_FAT
#define FSYS_FAT_NUM 1 #define FSYS_FAT_NUM 1
int fat_mount (void); int fat_mount (void);
/* XX FAT filesystem uses block filesystem code for read! */ int fat_read (char *buf, int len);
int fat_dir (char *dirname); int fat_dir (char *dirname);
#ifdef NO_BLOCK_FILES
#undef NO_BLOCK_FILES
#endif /* NO_BLOCK_FILES */
#else #else
#define FSYS_FAT_NUM 0 #define FSYS_FAT_NUM 0
#endif #endif

View file

@ -1,6 +1,7 @@
/* /*
* GRUB -- GRand Unified Bootloader * GRUB -- GRand Unified Bootloader
* Copyright (C) 1996 Erich Boleyn <erich@uruk.org> * Copyright (C) 1996 Erich Boleyn <erich@uruk.org>
* Copyright (C) 2000 Free Software Foundation, Inc.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -20,157 +21,243 @@
#ifdef FSYS_FAT #ifdef FSYS_FAT
#include "shared.h" #include "shared.h"
#include "filesys.h" #include "filesys.h"
#include "fat.h" #include "fat.h"
static int num_clust; struct fat_superblock
static int mapblock; {
static int data_offset; int fat_offset;
static int fat_size; int fat_length;
static int root_dir; int fat_size;
int root_offset;
int root_max;
int data_offset;
int num_sectors;
int num_clust;
int sects_per_clust;
int sectsize_bits;
int clustsize_bits;
int root_cluster;
int cached_fat;
int file_cluster;
int current_cluster_num;
int current_cluster;
};
/* pointer(s) into filesystem info buffer for DOS stuff */ /* pointer(s) into filesystem info buffer for DOS stuff */
#define BPB ( FSYS_BUF + 32256 ) /* 512 bytes long */ #define FAT_SUPER ( (struct fat_superblock *) \
( FSYS_BUF + 32256) )/* 512 bytes long */
#define FAT_BUF ( FSYS_BUF + 30208 ) /* 4 sector FAT buffer */ #define FAT_BUF ( FSYS_BUF + 30208 ) /* 4 sector FAT buffer */
#define NAME_BUF ( FSYS_BUF + 29184 ) /* Filename buffer (833 bytes) */
#define FAT_CACHE_SIZE 2048
int int
fat_mount (void) fat_mount (void)
{ {
int retval = 1; struct fat_bpb bpb;
int i;
if ((((current_drive & 0x80) || (current_slice != 0)) /* Check partition type for harddisk */
if (((current_drive & 0x80) || (current_slice != 0))
&& ! IS_PC_SLICE_TYPE_FAT (current_slice) && ! IS_PC_SLICE_TYPE_FAT (current_slice)
&& (! IS_PC_SLICE_TYPE_BSD_WITH_FS (current_slice, FS_MSDOS))) && (! IS_PC_SLICE_TYPE_BSD_WITH_FS (current_slice, FS_MSDOS)))
|| !devread (0, 0, SECTOR_SIZE, (char *) BPB) return 0;
|| FAT_BPB_BYTES_PER_SECTOR (BPB) != SECTOR_SIZE
|| FAT_BPB_SECT_PER_CLUST (BPB) < 1 /* Read bpb */
|| (FAT_BPB_SECT_PER_CLUST (BPB) & (FAT_BPB_SECT_PER_CLUST (BPB) - 1)) if (!devread (0, 0, sizeof(bpb), (char *) &bpb))
|| !((current_drive & 0x80) return 0;
|| FAT_BPB_FLOPPY_NUM_SECTORS (BPB)))
retval = 0; for (i = 0; (1 << i) < FAT_CVT_U16(bpb.bytes_per_sect); i++)
else {}
FAT_SUPER->sectsize_bits = i;
for (i = 0; (1 << i) < bpb.sects_per_clust; i++)
{}
FAT_SUPER->clustsize_bits = FAT_SUPER->sectsize_bits + i;
/* Fill in info about super block */
FAT_SUPER->num_sectors = FAT_CVT_U16(bpb.short_sectors)
? FAT_CVT_U16(bpb.short_sectors) : bpb.long_sectors;
/* FAT offset and length */
FAT_SUPER->fat_offset = FAT_CVT_U16(bpb.reserved_sects);
FAT_SUPER->fat_length =
bpb.fat_length ? bpb.fat_length : bpb.fat32_length;
/* Rootdir offset and length for FAT12/16 */
FAT_SUPER->root_offset =
FAT_SUPER->fat_offset + bpb.num_fats * FAT_SUPER->fat_length;
FAT_SUPER->root_max = FAT_DIRENTRY_LENGTH * FAT_CVT_U16(bpb.dir_entries);
/* Data offset and number of clusters */
FAT_SUPER->data_offset =
FAT_SUPER->root_offset
+ ((FAT_SUPER->root_max - 1) >> FAT_SUPER->sectsize_bits) + 1;
FAT_SUPER->num_clust =
(FAT_SUPER->num_sectors - FAT_SUPER->data_offset) / bpb.sects_per_clust;
FAT_SUPER->sects_per_clust = bpb.sects_per_clust;
if (!bpb.fat_length)
{ {
mapblock = -4096; /* This is a FAT32 */
data_offset = FAT_BPB_DATA_OFFSET (BPB); if (FAT_CVT_U16(bpb.dir_entries))
num_clust = FAT_BPB_NUM_CLUST (BPB) + 2; return 0;
root_dir = -1; FAT_SUPER->fat_size = 8;
if (FAT_BPB_IS_FAT32 (BPB)) FAT_SUPER->root_cluster = bpb.root_cluster;
{
fat_size = 8;
root_dir = FAT_BPB_ROOT_DIR_CLUSTER (BPB);
} }
else if (num_clust > FAT_MAX_12BIT_CLUST)
fat_size = 4;
else else
fat_size = 3; {
if (!FAT_SUPER->root_max)
return 0;
FAT_SUPER->root_cluster = -1;
if (FAT_SUPER->num_clust > FAT_MAX_12BIT_CLUST)
FAT_SUPER->fat_size = 4;
else
FAT_SUPER->fat_size = 3;
} }
return retval;
/* Now do some sanity checks */
if (FAT_CVT_U16(bpb.bytes_per_sect) != (1 << FAT_SUPER->sectsize_bits)
|| FAT_CVT_U16(bpb.bytes_per_sect) != SECTOR_SIZE
|| bpb.sects_per_clust != (1 << (FAT_SUPER->clustsize_bits
- FAT_SUPER->sectsize_bits))
|| FAT_SUPER->num_clust <= 0
|| (FAT_SUPER->fat_size * FAT_SUPER->num_clust / (2 * SECTOR_SIZE)
> FAT_SUPER->fat_length))
return 0;
FAT_SUPER->cached_fat = - 2 * FAT_CACHE_SIZE;
return 1;
} }
int
static int fat_read (char *buf, int len)
fat_create_blocklist (int first_fat_entry)
{ {
BLK_CUR_FILEPOS = 0; int logical_clust;
BLK_CUR_BLKNUM = 0; int offset;
BLK_CUR_BLKLIST = BLK_BLKLIST_START; int ret = 0;
block_file = 1; int size;
filepos = 0;
if (first_fat_entry < 0) if (FAT_SUPER->file_cluster < 0)
{ {
/* root directory */ /* root directory for non-fat16 */
size = FAT_SUPER->root_max - filepos;
BLK_BLKSTART (BLK_BLKLIST_START) = FAT_BPB_ROOT_DIR_START (BPB); if (size > len)
fsmax = filemax = SECTOR_SIZE * (BLK_BLKLENGTH (BLK_BLKLIST_START) size = len;
= FAT_BPB_ROOT_DIR_LENGTH (BPB)); if (!devread(FAT_SUPER->root_offset, filepos, size, buf))
return 1; return 0;
filepos += size;
return size;
} }
else
/* any real directory/file */ logical_clust = filepos >> FAT_SUPER->clustsize_bits;
offset = (filepos & ((1 << FAT_SUPER->clustsize_bits) - 1));
if (logical_clust < FAT_SUPER->current_cluster_num)
{ {
int blk_cur_blklist = BLK_BLKLIST_START, blk_cur_blknum; FAT_SUPER->current_cluster_num = 0;
int last_fat_entry, new_mapblock; FAT_SUPER->current_cluster = FAT_SUPER->file_cluster;
}
fsmax = 0; while (len > 0)
do
{ {
BLK_BLKSTART (blk_cur_blklist) int sector;
= (first_fat_entry - 2) * FAT_BPB_SECT_PER_CLUST (BPB) + data_offset; while (logical_clust > FAT_SUPER->current_cluster_num)
blk_cur_blknum = 0;
do
{ {
blk_cur_blknum += FAT_BPB_SECT_PER_CLUST (BPB); /* calculate next cluster */
last_fat_entry = first_fat_entry; int fat_entry =
FAT_SUPER->current_cluster * FAT_SUPER->fat_size;
int next_cluster;
int cached_pos = (fat_entry - FAT_SUPER->cached_fat);
/* if (cached_pos < 0 ||
* Do FAT table translation here! (cached_pos + FAT_SUPER->fat_size) > 2*FAT_CACHE_SIZE)
*/
new_mapblock = (last_fat_entry * fat_size) >> 1;
if (new_mapblock > (mapblock + SECTOR_SIZE * 4 - 3)
|| new_mapblock < (mapblock + 3))
{ {
mapblock = ((new_mapblock < 6) ? 0 : FAT_SUPER->cached_fat = (fat_entry & ~(2*SECTOR_SIZE - 1));
((new_mapblock - 6) & ~0x1FF)); cached_pos = (fat_entry - FAT_SUPER->cached_fat);
if (!devread ((mapblock >> 9) + FAT_BPB_FAT_START (BPB), sector = FAT_SUPER->fat_offset
0, SECTOR_SIZE * 4, (char *) FAT_BUF)) + FAT_SUPER->cached_fat / (2*SECTOR_SIZE);
if (!devread (sector, 0, FAT_CACHE_SIZE, (char*) FAT_BUF))
return 0; return 0;
} }
next_cluster = * (unsigned long *) (FAT_BUF + (cached_pos >> 1));
first_fat_entry if (FAT_SUPER->fat_size == 3)
= *((unsigned long *) (FAT_BUF + (new_mapblock - mapblock)));
if (fat_size == 3)
{ {
if (last_fat_entry & 1) if (cached_pos & 1)
first_fat_entry >>= 4; next_cluster >>= 4;
next_cluster &= 0xFFF;
first_fat_entry &= 0xFFF;
} }
else if (fat_size == 4) else if (FAT_SUPER->fat_size == 4)
first_fat_entry &= 0xFFFF; next_cluster &= 0xFFFF;
if (first_fat_entry < 2) if (next_cluster < 2)
{ {
errnum = ERR_FSYS_CORRUPT; errnum = ERR_FSYS_CORRUPT;
return 0; return 0;
} }
}
while (first_fat_entry == (last_fat_entry + 1)
&& first_fat_entry < num_clust);
BLK_BLKLENGTH (blk_cur_blklist) = blk_cur_blknum; if (next_cluster >= FAT_SUPER->num_clust)
fsmax += blk_cur_blknum * SECTOR_SIZE; return ret;
blk_cur_blklist += BLK_BLKLIST_INC_VAL;
} FAT_SUPER->current_cluster = next_cluster;
while (first_fat_entry < num_clust && blk_cur_blklist < (FAT_BUF - 7)); FAT_SUPER->current_cluster_num++;
} }
return first_fat_entry >= num_clust; sector = FAT_SUPER->data_offset +
((FAT_SUPER->current_cluster - 2) << (FAT_SUPER->clustsize_bits
- FAT_SUPER->sectsize_bits));
size = (1 << FAT_SUPER->clustsize_bits) - offset;
if (size > len)
size = len;
#ifndef STAGE1_5
disk_read_func = disk_read_hook;
#endif /* STAGE1_5 */
devread(sector, offset, size, buf);
#ifndef STAGE1_5
disk_read_func = NULL;
#endif /* STAGE1_5 */
len -= size;
buf += size;
ret += size;
filepos += size;
logical_clust++;
offset = 0;
}
return errnum ? 0 : ret;
} }
/* XX FAT filesystem uses the block-list filesystem read function,
so none is defined here. */
int int
fat_dir (char *dirname) fat_dir (char *dirname)
{ {
char *rest, ch, filename[13], dir_buf[FAT_DIRENTRY_LENGTH]; char *rest, ch, dir_buf[FAT_DIRENTRY_LENGTH];
int attrib = FAT_ATTRIB_DIR, map = root_dir; char *filename = (char *) NAME_BUF;
int attrib = FAT_ATTRIB_DIR;
#ifndef STAGE1_5
int do_possibilities = 0;
#endif
/* main loop to find desired directory entry */ /* XXX I18N:
loop: * the positions 2,4,6 etc are high bytes of a 16 bit unicode char
*/
static unsigned char longdir_pos[] =
{ 1, 3, 5, 7, 9, 14, 16, 18, 20, 22, 24, 28, 30 };
int slot = -2;
int alias_checksum = -1;
if (!fat_create_blocklist (map)) FAT_SUPER->file_cluster = FAT_SUPER->root_cluster;
return 0; filepos = 0;
FAT_SUPER->current_cluster_num = MAXINT;
/* main loop to find desired directory entry */
loop:
/* if we have a real file (and we're not just printing possibilities), /* if we have a real file (and we're not just printing possibilities),
then this is where we want to exit */ then this is where we want to exit */
@ -191,24 +278,31 @@ loop:
while (*dirname == '/') while (*dirname == '/')
dirname++; dirname++;
filemax = fsmax; if (!(attrib & FAT_ATTRIB_DIR))
if (!filemax || !(attrib & FAT_ATTRIB_DIR))
{ {
errnum = ERR_BAD_FILETYPE; errnum = ERR_BAD_FILETYPE;
return 0; return 0;
} }
/* Directories don't have a file size */
filemax = MAXINT;
for (rest = dirname; (ch = *rest) && !isspace (ch) && ch != '/'; rest++); for (rest = dirname; (ch = *rest) && !isspace (ch) && ch != '/'; rest++);
*rest = 0; *rest = 0;
do # ifndef STAGE1_5
if (print_possibilities && ch != '/')
do_possibilities = 1;
# endif
while (1)
{ {
if (grub_read (dir_buf, FAT_DIRENTRY_LENGTH) != FAT_DIRENTRY_LENGTH) if (fat_read (dir_buf, FAT_DIRENTRY_LENGTH) != FAT_DIRENTRY_LENGTH
|| dir_buf[0] == 0)
{ {
if (!errnum) if (!errnum)
{ {
# ifndef STAGE1_5
if (print_possibilities < 0) if (print_possibilities < 0)
{ {
#if 0 #if 0
@ -216,6 +310,7 @@ loop:
#endif #endif
return 1; return 1;
} }
# endif /* STAGE1_5 */
errnum = ERR_FILE_NOT_FOUND; errnum = ERR_FILE_NOT_FOUND;
*rest = ch; *rest = ch;
@ -224,9 +319,70 @@ loop:
return 0; return 0;
} }
if (FAT_DIRENTRY_ATTRIB (dir_buf) == FAT_ATTRIB_LONGNAME)
{
/* This is a long filename. The filename is build from back
* to front and may span multiple entries. To bind these
* entries together they all contain the same checksum over
* the short alias.
*
* The id field tells if this is the first entry (the last
* part) of the long filename, and also at which offset this
* belongs.
*
* We just write the part of the long filename this entry
* describes and continue with the next dir entry.
*/
int i, offset;
unsigned char id = FAT_LONGDIR_ID(dir_buf);
if ((id & 0x40))
{
id &= 0x3f;
slot = id;
filename[slot * 13] = 0;
alias_checksum = FAT_LONGDIR_ALIASCHECKSUM(dir_buf);
}
if (id != slot || slot == 0
|| alias_checksum != FAT_LONGDIR_ALIASCHECKSUM(dir_buf))
{
alias_checksum = -1;
continue;
}
slot--;
offset = slot * 13;
for (i=0; i < 13; i++)
filename[offset+i] = dir_buf[longdir_pos[i]];
continue;
}
if (!FAT_DIRENTRY_VALID (dir_buf)) if (!FAT_DIRENTRY_VALID (dir_buf))
continue; continue;
if (alias_checksum != -1 && slot == 0)
{
int i;
unsigned char sum;
slot = -2;
for (sum = 0, i = 0; i< 11; i++)
sum = ((sum >> 1) | (sum << 7)) + dir_buf[i];
if (sum == alias_checksum)
{
# ifndef STAGE1_5
if (do_possibilities)
goto print_filename;
# endif /* STAGE1_5 */
if (substring (dirname, filename) == 0)
break;
}
}
/* XXX convert to 8.3 filename format here */ /* XXX convert to 8.3 filename format here */
{ {
int i, j, c; int i, j, c;
@ -246,23 +402,30 @@ loop:
} }
# ifndef STAGE1_5 # ifndef STAGE1_5
if (print_possibilities && ch != '/' if (do_possibilities)
&& (!*dirname || substring (dirname, filename) <= 0)) {
print_filename:
if (substring (dirname, filename) <= 0)
{ {
if (print_possibilities > 0) if (print_possibilities > 0)
print_possibilities = -print_possibilities; print_possibilities = -print_possibilities;
print_a_completion (filename); print_a_completion (filename);
} }
# endif /* STAGE1_5 */ continue;
}
# endif /* STAGE1_5 */
if (substring (dirname, filename) == 0)
break;
} }
while (substring (dirname, filename) != 0 ||
(print_possibilities && ch != '/'));
*(dirname = rest) = ch; *(dirname = rest) = ch;
attrib = FAT_DIRENTRY_ATTRIB (dir_buf); attrib = FAT_DIRENTRY_ATTRIB (dir_buf);
filemax = FAT_DIRENTRY_FILELENGTH (dir_buf); filemax = FAT_DIRENTRY_FILELENGTH (dir_buf);
map = FAT_DIRENTRY_FIRST_CLUSTER (dir_buf); filepos = 0;
FAT_SUPER->file_cluster = FAT_DIRENTRY_FIRST_CLUSTER (dir_buf);
FAT_SUPER->current_cluster_num = MAXINT;
/* go back to main loop at top of function */ /* go back to main loop at top of function */
goto loop; goto loop;