📄 boot.c
字号:
d++;
for(i = 8; i < 11; i++)
{
if(src[i] == ' ')
break;
*d = src[i];
d++;
}
}
*d = '\0';
/* make it lower case */
strlwr(dst);
DEBUG(cprintf("fat_convert_name_from_fat: `%11.11s' -> `%s'\n\r",
src, dst);)
}
/*****************************************************************************
*****************************************************************************/
static int fat_find_root(mount_t *mount, file_t *root_dir)
{
root_dir->pos = 0;
root_dir->mount = mount;
root_dir->inode = MAGIC_ROOT_CLUSTER;
root_dir->file_size = -1uL; /* xxx - get root dir size */
root_dir->is_dir = 1;
strcpy(root_dir->name, "/");
return 0;
}
/*****************************************************************************
FAT file attribute bits:
Bit(s) Description (Table 01401)
0 read-only
1 hidden
2 system
3 volume label or LFN
4 directory
5 archive
6 ?
7 if set, file is shareable under Novell NetWare
*****************************************************************************/
static int fat_find_file(file_t *dir, char *name)
{
char fat_name[16], dirent[FAT_DIRENT_LEN];
unsigned handle;
int err;
err = fat_convert_name_to_fat(fat_name, name);
if(err < 0)
return err;
handle = dir - _files;
do
{
while(1)
{
/* read one 32-byte FAT directory entry */
err = read(handle, dirent, FAT_DIRENT_LEN);
if(err != FAT_DIRENT_LEN)
{
/* short read means end of dir */
if(err >= 0)
return -ERR_EOF;
return err;
}
/* "virgin" dir entry means end of dir, for both root dir and subdir */
if(dirent[0] == 0)
return -ERR_EOF;
/* deleted file */
if(dirent[0] == 5 || dirent[0] == '\xE5')
continue;
/* volume label or LFN */
if((dirent[11] & 0x08) == 0)
break;
}
} while(memcmp(fat_name, dirent + 0, 11));
/* found it! */
dir->pos = 0;
dir->inode = read_le16(dirent + 26);
dir->file_size = read_le32(dirent + 28);
if(dirent[11] & 0x10)
dir->is_dir = 1;
else
dir->is_dir = 0;
fat_convert_name_from_fat(dir->name, dirent);
if(dir->inode == 0)
{
/* directory with inode==0 is actually a pointer to the root directory */
if(dir->is_dir)
dir->inode = MAGIC_ROOT_CLUSTER;
/* file with inode==0 is a zero-length file
(no disk space allocated for it) */
}
else if(dir->inode < 2)
return -ERR_FILE_SYSTEM;
if(dir->file_size == 0)
{
/* I guess FAT doesn't store the correct size of subdirectories
in the directory entry */
if(dir->is_dir)
dir->file_size = -1uL;
/* else zero-length file? */
}
DEBUG(cprintf("fat_find_file for `%s': starting cluster %lu, "
"size %ld bytes%s\n\r", name, dir->inode, dir->file_size,
dir->is_dir ? ", dir" : "");)
return 0;
}
/*****************************************************************************
convert 'cluster' to 'sector', then advance to next cluster in FAT chain
and store next cluster at 'cluster'
*****************************************************************************/
static int fat_read(file_t *file, unsigned char HUGE *buf, unsigned want);
static int fat_walk(const file_t *file, sector_t *sector,
unsigned short *cluster)
{
unsigned char buf[2];
unsigned short entry;
file_t the_fat;
sector_t temp;
fat_t *fat;
int err;
DEBUG1(
cprintf("entering fat_walk: file=%p", file);
if(file >= _files && file < _files + sizeof(file_t) * 20)
cprintf(" (handle %u)", (file - _files) /
sizeof(file_t));
cprintf(", cluster=%u\n\r", file, *cluster);
)
fat = (fat_t *)(file->mount->fsinfo.info);
/* make a "fake" file_t (not part of the global file_t pool at "_files")
for use only by fat_walk() */
memset(&the_fat, 0, sizeof(file_t));
the_fat.mount = file->mount;
the_fat.inode = MAGIC_FAT_CLUSTER;
the_fat.file_size = -1uL;
the_fat.is_open = 1;
/* must be cluster within data area of disk */
temp = (*cluster);
if(temp < 2)
return -EINVAL;
temp -= 2;
/* convert cluster to sector */
temp *= fat->sectors_per_cluster;
temp += fat->data_start;
(*sector) = temp;
/* now convert cluster to byte offset into FAT */
temp = (*cluster);
if(fat->fat_type == FAT12)
{
/* 12 bits per FAT entry, so byte offset into FAT is 3/2 * temp
set the_fat.pos directly, without using lseek() */
temp *= 3;
the_fat.pos = temp >> 1;
/* read 2-byte entry */
err = fat_read(&the_fat, buf, 2);
if(err < 0)
return err;
entry = read_le16(buf);
/* top 12 bits or bottom 12 bits? */
if(temp & 1)
entry >>= 4;
else
entry &= 0x0FFF;
}
else if(fat->fat_type == FAT16)
{
/* 16 bits per FAT entry */
temp <<= 1;
the_fat.pos = temp;
/* read 2-byte entry */
err = fat_read(&the_fat, buf, 2);
if(err < 0)
return err;
entry = read_le16(buf);
}
else
{
cprintf("fat_walk: FAT32 not yet supported\n\r");
return -ENOIMP;
}
/* that's what we want! */
(*cluster) = entry;
DEBUG1(cprintf("leaving fat_walk: file=%p, cluster=%u, sector=%lu\n\r",
file, *cluster, *sector);)
return 0;
}
/*****************************************************************************
*****************************************************************************/
static int fat_read_sector(file_t *file, sector_t rel_sector,
unsigned char **blk)
{
unsigned short rel_cluster, abs_cluster;
sector_t abs_sector;
fsinfo_t *fsinfo;
mount_t *mount;
dev_t *dev;
fat_t *fat;
int err;
DEBUG1(
cprintf("entering fat_read_sector: file=%p", file);
if(file >= _files && file < _files + sizeof(file_t) * 20)
cprintf(" (handle %u)", (file - _files) /
sizeof(file_t));
cprintf(", rel_sector=%lu\n\r", rel_sector);
)
mount = file->mount;
dev = mount->dev;
fsinfo = &mount->fsinfo;
fat = (fat_t *)fsinfo->info;
abs_cluster = file->inode;
/* starting cluster == 0: read from FAT */
if(abs_cluster == MAGIC_FAT_CLUSTER)
{
abs_sector = fat->fat_start + rel_sector;
if(abs_sector >= fat->root_start)
return -ERR_EOF;
}
/* starting cluster == 1: read from root directory */
else if(abs_cluster == MAGIC_ROOT_CLUSTER)
{
abs_sector = fat->root_start + rel_sector;
if(abs_sector >= fat->data_start)
return -ERR_EOF;
}
/* starting cluster >= 2: normal read from data area of disk */
else
{
/* cluster within file */
rel_cluster = rel_sector / fat->sectors_per_cluster;
/* sector within cluster */
rel_sector %= fat->sectors_per_cluster;
/* chase clusters, so we go from relative cluster (cluster-within-file)... */
for(;;)
{
if(abs_cluster > fat->max_cluster)
return -ERR_EOF;
err = fat_walk(file, &abs_sector, &abs_cluster);
if(err != 0)
return err;
if(rel_cluster == 0)
break;
rel_cluster--;
}
/* ...to absolute cluster (cluster-within-disk). fat_walk() also
converted cluster to sector, so add things together to get the
absolute sector number (finally!) */
abs_sector += rel_sector;
}
/* load it */
err = read_sector(dev, mount->partition_start + abs_sector, blk);
DEBUG1(cprintf("leaving fat_read_sector: file=%p, abs_sector=%lu, "
"err=%d\n\r", file, abs_sector, err);)
return err;
}
/*****************************************************************************
xxx - this is slow
*****************************************************************************/
static void memcpy2f(unsigned char HUGE *dst, unsigned char *src,
unsigned count)
{
unsigned short dst_seg, dst_off;
dst_seg = FP_SEG(dst);
dst_off = FP_OFF(dst);
for(; count != 0; count--)
{
pokeb(dst_seg, dst_off, *src);
dst_off++;
if(dst_off == 0)
dst_seg += 0x1000;
src++;
}
}
/*****************************************************************************
*****************************************************************************/
static int fat_read(file_t *file, unsigned char HUGE *buf, unsigned want)
{
unsigned short byte_in_sector;
sector_t rel_sector;
unsigned got, count;
unsigned char *blk;
mount_t *mount;
dev_t *dev;
int err;
DEBUG1(
cprintf("entering fat_read: file=%p", file);
if(file >= _files && file < _files + sizeof(file_t) * 20)
cprintf(" (handle %u)", (file - _files) /
sizeof(file_t));
cprintf(", want=%u\n\r", want);
)
if(want == 0)
return 0;
mount = file->mount;
dev = mount->dev;
count = 0;
do
{
rel_sector = file->pos;
/* byte within sector */
byte_in_sector = rel_sector % dev->bytes_per_sector;
/* sector within file */
rel_sector /= dev->bytes_per_sector;
/* read the sector */
err = fat_read_sector(file, rel_sector, &blk);
if(err < 0)
return err;
/* how many bytes can we read from this sector? */
got = dev->bytes_per_sector - byte_in_sector;
/* nearing end of file? */
if(file->pos + got > file->file_size)
got = file->file_size - file->pos;
if(got == 0)
break;
/* how many will we actually read from it? */
got = min(got, want);
/* read them */
memcpy2f(buf, blk + byte_in_sector, got);
/* advance pointers */
file->pos += got;
buf += got;
want -= got;
count += got;
/* done? */
} while(want != 0);
DEBUG1(cprintf("leaving fat_read: got=%u\n\r", count);)
return count;
}
/*****************************************************************************
*****************************************************************************/
int fat_mount(mount_t *mount, dev_t *dev, unsigned char part)
{
unsigned char *blk, *ptab_rec; /* partition table record */
unsigned long total_sectors;
fat_type_t fat_type;
fsinfo_t *fsinfo;
fat_t *fat;
int err;
/* floppy */
if(dev->int13_dev < 0x80)
{
fat_type = FAT12;
mount->partition_start = 0;
}
/* hard disk */
else
{
if(part > 3)
{
cprintf("fat_mount: partition number must be 0-3\n\r");
return -EINVAL;
}
/* read sector 0 of hard disk == MBR == partition table */
err = read_sector(dev, 0, &blk);
if(err != 0)
return err;
/* point to 16-byte partition table record */
ptab_rec = blk + 446 + 16 * part;
switch(ptab_rec[4])
{
case 1:
fat_type = FAT12;
break;
case 4: /* up to 32 meg - UNTESTED */
case 6: /* DOS 3.31+, >32 meg */
fat_type = FAT16;
break;
/* case 0x0B: FAT32 CHS
case 0x0C: FAT32 LBA
case 0x0E: same as 6 (FAT16 >32 meg), but uses INT 13h LBA */
default:
NOT: if(dev->int13_dev >= 0x80)
cprintf("fat_mount: partition "
"%u on ", part);
else
cprintf("fat_mount: ");
cprintf("drive 0x%02X is not FAT12 "
"or FAT16\n\r", dev->int13_dev);
return -ERR_FILE_SYSTEM;
}
mount->partition_start = read_le32(ptab_rec + 8);
}
/* read sector 0 of partition == boot sector */
err = read_sector(dev, mount->partition_start, &blk);
if(err != 0)
return err;
/* make sure it's a FAT disk */
if(blk[0] != 0xEB || blk[2] != 0x90 || /* JMP short, NOP */
read_le16(blk + 0x0B) != 512) /* bytes/sector */
goto NOT;
mount->dev = dev;
mount->curr_dir = MAGIC_ROOT_CLUSTER;
/* init FAT-specific info in fsinfo */
fsinfo = &mount->fsinfo;
fsinfo->read = fat_read;
fsinfo->find_root = fat_find_root;
fsinfo->find_file = fat_find_file;
fat = (fat_t *)fsinfo->info;
/* xxx (fat_t *)fsinfo->info = fat = malloc(sizeof(fat_t));
if(fat == NULL)
return ERR_MEM; */
fat->sectors_per_cluster = blk[13];
fat->fat_start = read_le16(blk + 14); /* reserved_sectors */
fat->root_start = fat->fat_start +
blk[16] * /* num_fats */
read_le16(blk + 22); /* sectors_per_fat */
fat->data_start = fat->root_start +
(FAT_DIRENT_LEN * /* bytes_per_dir_ent */
read_le16(blk + 17)) / /* num_root_dir_ents */
BPS; /* bytes_per_sector */
total_sectors = read_le16(blk + 19);
if(total_sectors == 0)
total_sectors = read_le32(blk + 32);
fat->max_cluster = total_sectors / fat->sectors_per_cluster -
fat->data_start - 1;
fat->fat_type = fat_type;
#if 0
cprintf("disk CHS=??:%u:%u\n\r", dev->heads, dev->sects);
cprintf("drive 0x%02X, partition %u: %s partition starting at sector %lu\n\r",
dev->int13_dev, part, fat->fat_type == FAT12 ? "FAT12" : "FAT16",
mount->partition_start);
cprintf("%u sector(s)/cluster, ", fat->sectors_per_cluster);
cprintf("%u FATs, ", blk[0x10]);
cprintf("root at sector %lu, ", fat->root_start);
cprintf("data at sector %lu\n\r", fat->data_start);
cprintf("FAT(s) at sector %lu, ", fat->fat_start);
cprintf("%u entries in root dir, ", read_le16(blk + 0x11));
cprintf("%lu total sectors ", total_sectors);
if(total_sectors >= 16384)
cprintf("(%luM)\n\r\n\r", total_sectors / 2048);
else
cprintf("(%luK)\n\r\n\r", total_sectors / 2);
#endif
DEBUG(cprintf("fat_mount for partition %u, drive 0x%02X: "
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -