add long filename support into FAT, fix a typo in configure.
This commit is contained in:
parent
7c4acb2539
commit
85c66cb4c8
12 changed files with 431 additions and 240 deletions
4
BUGS
4
BUGS
|
@ -1,6 +1,8 @@
|
|||
|
||||
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
|
||||
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
|
||||
|
|
49
ChangeLog
49
ChangeLog
|
@ -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>
|
||||
|
||||
Pass the boot partition information to a chain-loader, in the
|
||||
|
|
1
NEWS
1
NEWS
|
@ -40,6 +40,7 @@ New in 0.5.94:
|
|||
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
|
||||
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:
|
||||
* ELF format of FreeBSD kernel is supported.
|
||||
|
|
2
configure
vendored
2
configure
vendored
|
@ -2479,7 +2479,7 @@ if test "${enable_3c90x+set}" = set; then
|
|||
fi
|
||||
|
||||
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"
|
||||
fi
|
||||
|
||||
|
|
|
@ -254,7 +254,7 @@ fi
|
|||
AC_ARG_ENABLE(3c90x,
|
||||
[ --enable-3c90x enable 3Com90x driver])
|
||||
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"
|
||||
fi
|
||||
|
||||
|
|
|
@ -80,7 +80,8 @@ e2fs_stage1_5_exec_LDFLAGS = $(STAGE1_5_LINK)
|
|||
# For fat_stage1_5 target.
|
||||
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
|
||||
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)
|
||||
|
||||
# For ffs_stage1_5 target.
|
||||
|
|
|
@ -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 \
|
||||
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)
|
||||
|
||||
# For ffs_stage1_5 target.
|
||||
|
|
|
@ -675,7 +675,7 @@ grub_tolower (int c)
|
|||
int
|
||||
grub_isspace (int c)
|
||||
{
|
||||
if (c == ' ' || c == '\t' || c == '\n')
|
||||
if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -45,7 +45,7 @@ struct fsys_entry fsys_table[NUM_FSYS + 1] =
|
|||
{"tftp", tftp_mount, tftp_read, tftp_dir, tftp_close},
|
||||
# endif
|
||||
# ifdef FSYS_FAT
|
||||
{"fat", fat_mount, 0, fat_dir, 0},
|
||||
{"fat", fat_mount, fat_read, fat_dir, 0},
|
||||
# endif
|
||||
# ifdef FSYS_EXT2FS
|
||||
{"ext2fs", ext2fs_mount, ext2fs_read, ext2fs_dir, 0},
|
||||
|
|
107
stage2/fat.h
107
stage2/fat.h
|
@ -23,65 +23,44 @@
|
|||
* 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? */
|
||||
#define FAT_BPB_CHECK_SIG(bpb) \
|
||||
(*((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...
|
||||
/* Note that some shorts are not aligned, and must therefore
|
||||
* be declared as array of two bytes.
|
||||
*/
|
||||
#define FAT_BPB_HIDDEN_SECTORS(bpb) \
|
||||
(*((unsigned long *) (((int)bpb) + 28)))
|
||||
struct fat_bpb {
|
||||
__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) \
|
||||
( FAT_BPB_NUM_FAT(bpb) * FAT_BPB_FAT_SECTORS(bpb) \
|
||||
+ FAT_BPB_FAT_START(bpb) )
|
||||
/* The following fields are only used by FAT32 */
|
||||
__u32 fat32_length; /* sectors/FAT */
|
||||
__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) \
|
||||
( (*((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 */
|
||||
#define FAT_CVT_U16(bytarr) (* (__u16*)(bytarr))
|
||||
|
||||
/*
|
||||
* 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_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
|
||||
*/
|
||||
|
@ -103,7 +75,7 @@
|
|||
#define FAT_ATTRIB_OK_MASK 0x37
|
||||
#define FAT_ATTRIB_NOT_OK_MASK 0xC8
|
||||
#define FAT_ATTRIB_DIR 0x10
|
||||
|
||||
#define FAT_ATTRIB_LONGNAME 0x0F
|
||||
|
||||
/*
|
||||
* Defines for FAT directory entries
|
||||
|
@ -115,9 +87,14 @@
|
|||
(*((unsigned char *) (entry+11)))
|
||||
#define FAT_DIRENTRY_VALID(entry) \
|
||||
( ((*((unsigned char *) entry)) != 0) \
|
||||
& ((*((unsigned char *) entry)) != 0xE5) \
|
||||
& !(FAT_DIRENTRY_ATTRIB(entry) & FAT_ATTRIB_NOT_OK_MASK) )
|
||||
&& ((*((unsigned char *) entry)) != 0xE5) \
|
||||
&& !(FAT_DIRENTRY_ATTRIB(entry) & FAT_ATTRIB_NOT_OK_MASK) )
|
||||
#define FAT_DIRENTRY_FIRST_CLUSTER(entry) \
|
||||
((*((unsigned short *) (entry+26)))+(*((unsigned short *) (entry+20)) << 16))
|
||||
#define FAT_DIRENTRY_FILELENGTH(entry) \
|
||||
(*((unsigned long *) (entry+28)))
|
||||
|
||||
#define FAT_LONGDIR_ID(entry) \
|
||||
(*((unsigned char *) (entry)))
|
||||
#define FAT_LONGDIR_ALIASCHECKSUM(entry) \
|
||||
(*((unsigned char *) (entry+13)))
|
||||
|
|
|
@ -33,11 +33,8 @@ int ffs_dir (char *dirname);
|
|||
#ifdef FSYS_FAT
|
||||
#define FSYS_FAT_NUM 1
|
||||
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);
|
||||
#ifdef NO_BLOCK_FILES
|
||||
#undef NO_BLOCK_FILES
|
||||
#endif /* NO_BLOCK_FILES */
|
||||
#else
|
||||
#define FSYS_FAT_NUM 0
|
||||
#endif
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* 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
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -20,161 +21,247 @@
|
|||
#ifdef FSYS_FAT
|
||||
|
||||
#include "shared.h"
|
||||
|
||||
#include "filesys.h"
|
||||
|
||||
#include "fat.h"
|
||||
|
||||
static int num_clust;
|
||||
static int mapblock;
|
||||
static int data_offset;
|
||||
static int fat_size;
|
||||
static int root_dir;
|
||||
struct fat_superblock
|
||||
{
|
||||
int fat_offset;
|
||||
int fat_length;
|
||||
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 */
|
||||
#define BPB ( FSYS_BUF + 32256 ) /* 512 bytes long */
|
||||
#define FAT_BUF ( FSYS_BUF + 30208 ) /* 4 sector FAT buffer */
|
||||
#define FAT_SUPER ( (struct fat_superblock *) \
|
||||
( FSYS_BUF + 32256) )/* 512 bytes long */
|
||||
#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
|
||||
fat_mount (void)
|
||||
{
|
||||
int retval = 1;
|
||||
|
||||
if ((((current_drive & 0x80) || (current_slice != 0))
|
||||
&& ! IS_PC_SLICE_TYPE_FAT (current_slice)
|
||||
&& (! IS_PC_SLICE_TYPE_BSD_WITH_FS (current_slice, FS_MSDOS)))
|
||||
|| !devread (0, 0, SECTOR_SIZE, (char *) BPB)
|
||||
|| FAT_BPB_BYTES_PER_SECTOR (BPB) != SECTOR_SIZE
|
||||
|| FAT_BPB_SECT_PER_CLUST (BPB) < 1
|
||||
|| (FAT_BPB_SECT_PER_CLUST (BPB) & (FAT_BPB_SECT_PER_CLUST (BPB) - 1))
|
||||
|| !((current_drive & 0x80)
|
||||
|| FAT_BPB_FLOPPY_NUM_SECTORS (BPB)))
|
||||
retval = 0;
|
||||
else
|
||||
struct fat_bpb bpb;
|
||||
int i;
|
||||
|
||||
/* Check partition type for harddisk */
|
||||
if (((current_drive & 0x80) || (current_slice != 0))
|
||||
&& ! IS_PC_SLICE_TYPE_FAT (current_slice)
|
||||
&& (! IS_PC_SLICE_TYPE_BSD_WITH_FS (current_slice, FS_MSDOS)))
|
||||
return 0;
|
||||
|
||||
/* Read bpb */
|
||||
if (!devread (0, 0, sizeof(bpb), (char *) &bpb))
|
||||
return 0;
|
||||
|
||||
for (i = 0; (1 << i) < FAT_CVT_U16(bpb.bytes_per_sect); i++)
|
||||
{}
|
||||
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;
|
||||
data_offset = FAT_BPB_DATA_OFFSET (BPB);
|
||||
num_clust = FAT_BPB_NUM_CLUST (BPB) + 2;
|
||||
root_dir = -1;
|
||||
if (FAT_BPB_IS_FAT32 (BPB))
|
||||
{
|
||||
fat_size = 8;
|
||||
root_dir = FAT_BPB_ROOT_DIR_CLUSTER (BPB);
|
||||
}
|
||||
else if (num_clust > FAT_MAX_12BIT_CLUST)
|
||||
fat_size = 4;
|
||||
/* This is a FAT32 */
|
||||
if (FAT_CVT_U16(bpb.dir_entries))
|
||||
return 0;
|
||||
FAT_SUPER->fat_size = 8;
|
||||
FAT_SUPER->root_cluster = bpb.root_cluster;
|
||||
}
|
||||
else
|
||||
{
|
||||
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_size = 3;
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
fat_create_blocklist (int first_fat_entry)
|
||||
int
|
||||
fat_read (char *buf, int len)
|
||||
{
|
||||
BLK_CUR_FILEPOS = 0;
|
||||
BLK_CUR_BLKNUM = 0;
|
||||
BLK_CUR_BLKLIST = BLK_BLKLIST_START;
|
||||
block_file = 1;
|
||||
filepos = 0;
|
||||
|
||||
if (first_fat_entry < 0)
|
||||
int logical_clust;
|
||||
int offset;
|
||||
int ret = 0;
|
||||
int size;
|
||||
|
||||
if (FAT_SUPER->file_cluster < 0)
|
||||
{
|
||||
/* root directory */
|
||||
|
||||
BLK_BLKSTART (BLK_BLKLIST_START) = FAT_BPB_ROOT_DIR_START (BPB);
|
||||
fsmax = filemax = SECTOR_SIZE * (BLK_BLKLENGTH (BLK_BLKLIST_START)
|
||||
= FAT_BPB_ROOT_DIR_LENGTH (BPB));
|
||||
return 1;
|
||||
/* root directory for non-fat16 */
|
||||
size = FAT_SUPER->root_max - filepos;
|
||||
if (size > len)
|
||||
size = len;
|
||||
if (!devread(FAT_SUPER->root_offset, filepos, size, buf))
|
||||
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;
|
||||
int last_fat_entry, new_mapblock;
|
||||
|
||||
fsmax = 0;
|
||||
|
||||
do
|
||||
{
|
||||
BLK_BLKSTART (blk_cur_blklist)
|
||||
= (first_fat_entry - 2) * FAT_BPB_SECT_PER_CLUST (BPB) + data_offset;
|
||||
blk_cur_blknum = 0;
|
||||
|
||||
do
|
||||
{
|
||||
blk_cur_blknum += FAT_BPB_SECT_PER_CLUST (BPB);
|
||||
last_fat_entry = first_fat_entry;
|
||||
|
||||
/*
|
||||
* Do FAT table translation here!
|
||||
*/
|
||||
|
||||
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 :
|
||||
((new_mapblock - 6) & ~0x1FF));
|
||||
if (!devread ((mapblock >> 9) + FAT_BPB_FAT_START (BPB),
|
||||
0, SECTOR_SIZE * 4, (char *) FAT_BUF))
|
||||
return 0;
|
||||
}
|
||||
|
||||
first_fat_entry
|
||||
= *((unsigned long *) (FAT_BUF + (new_mapblock - mapblock)));
|
||||
|
||||
if (fat_size == 3)
|
||||
{
|
||||
if (last_fat_entry & 1)
|
||||
first_fat_entry >>= 4;
|
||||
|
||||
first_fat_entry &= 0xFFF;
|
||||
}
|
||||
else if (fat_size == 4)
|
||||
first_fat_entry &= 0xFFFF;
|
||||
|
||||
if (first_fat_entry < 2)
|
||||
{
|
||||
errnum = ERR_FSYS_CORRUPT;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
while (first_fat_entry == (last_fat_entry + 1)
|
||||
&& first_fat_entry < num_clust);
|
||||
|
||||
BLK_BLKLENGTH (blk_cur_blklist) = blk_cur_blknum;
|
||||
fsmax += blk_cur_blknum * SECTOR_SIZE;
|
||||
blk_cur_blklist += BLK_BLKLIST_INC_VAL;
|
||||
}
|
||||
while (first_fat_entry < num_clust && blk_cur_blklist < (FAT_BUF - 7));
|
||||
FAT_SUPER->current_cluster_num = 0;
|
||||
FAT_SUPER->current_cluster = FAT_SUPER->file_cluster;
|
||||
}
|
||||
|
||||
return first_fat_entry >= num_clust;
|
||||
|
||||
while (len > 0)
|
||||
{
|
||||
int sector;
|
||||
while (logical_clust > FAT_SUPER->current_cluster_num)
|
||||
{
|
||||
/* calculate next cluster */
|
||||
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 ||
|
||||
(cached_pos + FAT_SUPER->fat_size) > 2*FAT_CACHE_SIZE)
|
||||
{
|
||||
FAT_SUPER->cached_fat = (fat_entry & ~(2*SECTOR_SIZE - 1));
|
||||
cached_pos = (fat_entry - FAT_SUPER->cached_fat);
|
||||
sector = FAT_SUPER->fat_offset
|
||||
+ FAT_SUPER->cached_fat / (2*SECTOR_SIZE);
|
||||
if (!devread (sector, 0, FAT_CACHE_SIZE, (char*) FAT_BUF))
|
||||
return 0;
|
||||
}
|
||||
next_cluster = * (unsigned long *) (FAT_BUF + (cached_pos >> 1));
|
||||
if (FAT_SUPER->fat_size == 3)
|
||||
{
|
||||
if (cached_pos & 1)
|
||||
next_cluster >>= 4;
|
||||
next_cluster &= 0xFFF;
|
||||
}
|
||||
else if (FAT_SUPER->fat_size == 4)
|
||||
next_cluster &= 0xFFFF;
|
||||
|
||||
if (next_cluster < 2)
|
||||
{
|
||||
errnum = ERR_FSYS_CORRUPT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (next_cluster >= FAT_SUPER->num_clust)
|
||||
return ret;
|
||||
|
||||
FAT_SUPER->current_cluster = next_cluster;
|
||||
FAT_SUPER->current_cluster_num++;
|
||||
}
|
||||
|
||||
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
|
||||
fat_dir (char *dirname)
|
||||
{
|
||||
char *rest, ch, filename[13], dir_buf[FAT_DIRENTRY_LENGTH];
|
||||
int attrib = FAT_ATTRIB_DIR, map = root_dir;
|
||||
|
||||
/* main loop to find desired directory entry */
|
||||
loop:
|
||||
|
||||
if (!fat_create_blocklist (map))
|
||||
return 0;
|
||||
|
||||
char *rest, ch, dir_buf[FAT_DIRENTRY_LENGTH];
|
||||
char *filename = (char *) NAME_BUF;
|
||||
int attrib = FAT_ATTRIB_DIR;
|
||||
#ifndef STAGE1_5
|
||||
int do_possibilities = 0;
|
||||
#endif
|
||||
|
||||
/* XXX I18N:
|
||||
* 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;
|
||||
|
||||
FAT_SUPER->file_cluster = FAT_SUPER->root_cluster;
|
||||
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),
|
||||
then this is where we want to exit */
|
||||
|
||||
|
||||
if (!*dirname || isspace (*dirname))
|
||||
{
|
||||
if (attrib & FAT_ATTRIB_DIR)
|
||||
|
@ -182,33 +269,40 @@ loop:
|
|||
errnum = ERR_BAD_FILETYPE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* continue with the file/directory name interpretation */
|
||||
|
||||
|
||||
while (*dirname == '/')
|
||||
dirname++;
|
||||
|
||||
filemax = fsmax;
|
||||
|
||||
if (!filemax || !(attrib & FAT_ATTRIB_DIR))
|
||||
|
||||
if (!(attrib & FAT_ATTRIB_DIR))
|
||||
{
|
||||
errnum = ERR_BAD_FILETYPE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Directories don't have a file size */
|
||||
filemax = MAXINT;
|
||||
|
||||
for (rest = dirname; (ch = *rest) && !isspace (ch) && ch != '/'; rest++);
|
||||
|
||||
|
||||
*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)
|
||||
{
|
||||
# ifndef STAGE1_5
|
||||
if (print_possibilities < 0)
|
||||
{
|
||||
#if 0
|
||||
|
@ -216,54 +310,123 @@ loop:
|
|||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
# endif /* STAGE1_5 */
|
||||
|
||||
errnum = ERR_FILE_NOT_FOUND;
|
||||
*rest = ch;
|
||||
}
|
||||
|
||||
|
||||
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))
|
||||
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 */
|
||||
{
|
||||
int i, j, c;
|
||||
|
||||
|
||||
for (i = 0; i < 8 && (c = filename[i] = tolower (dir_buf[i]))
|
||||
&& !isspace (c); i++);
|
||||
|
||||
&& !isspace (c); i++);
|
||||
|
||||
filename[i++] = '.';
|
||||
|
||||
|
||||
for (j = 0; j < 3 && (c = filename[i + j] = tolower (dir_buf[8 + j]))
|
||||
&& !isspace (c); j++);
|
||||
|
||||
&& !isspace (c); j++);
|
||||
|
||||
if (j == 0)
|
||||
i--;
|
||||
|
||||
|
||||
filename[i + j] = 0;
|
||||
}
|
||||
|
||||
|
||||
# ifndef STAGE1_5
|
||||
if (print_possibilities && ch != '/'
|
||||
&& (!*dirname || substring (dirname, filename) <= 0))
|
||||
if (do_possibilities)
|
||||
{
|
||||
if (print_possibilities > 0)
|
||||
print_possibilities = -print_possibilities;
|
||||
print_a_completion (filename);
|
||||
print_filename:
|
||||
if (substring (dirname, filename) <= 0)
|
||||
{
|
||||
if (print_possibilities > 0)
|
||||
print_possibilities = -print_possibilities;
|
||||
print_a_completion (filename);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
# endif /* STAGE1_5 */
|
||||
|
||||
if (substring (dirname, filename) == 0)
|
||||
break;
|
||||
}
|
||||
while (substring (dirname, filename) != 0 ||
|
||||
(print_possibilities && ch != '/'));
|
||||
|
||||
|
||||
*(dirname = rest) = ch;
|
||||
|
||||
|
||||
attrib = FAT_DIRENTRY_ATTRIB (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 */
|
||||
goto loop;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue