⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 boot.c

📁 一个类linux的dos下开发的操作系统.
💻 C
📖 第 1 页 / 共 5 页
字号:
		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 + -