ext2fs.c

来自「EFI(Extensible Firmware Interface)是下一代BI」· C语言 代码 · 共 1,005 行 · 第 1/2 页

C
1,005
字号
	 * Whatever we got must match up with the last one.	 */	return dir_inode;}/* * Read block number "blkno" from the specified file. */static int ext2_bread(ext2fs_priv_state_t *e2fs, int fd, long blkno, long nblks, char *buffer){	struct ext2_inode * ip;	ip = &e2fs->inode_table[fd].inode;	return ext2_breadi(e2fs, ip, blkno, nblks, buffer);}#if 0/* * Note: don't mix any kind of file lookup or other I/O with this or * you will lose horribly (as it reuses blkbuf) */static const char *ext2_readdir(ext2fs_priv_state_t *e2fs, int fd, int rewind){	struct ext2_inode * ip = &e2fs->inode_table[fd].inode;	struct ext2_dir_entry_2 * ent;	if (!S_ISDIR(ip->i_mode)) {		ERR_PRT((L"fd %d (inode %d) is not a directory (mode %x)",		       fd, e2fs->inode_table[fd].inumber, ip->i_mode));		return NULL;	}	ent = ext2_readdiri(e2fs, ip, rewind);	if (ent) {		ent->name[ent->name_len] = '\0';		return ent->name;	} else { 		return NULL;	}}#endifstatic int ext2_fstat(ext2fs_priv_state_t *e2fs, int fd, ext2fs_stat_t *buf){	struct ext2_inode * ip = &e2fs->inode_table[fd].inode;	Memset(buf, 0, sizeof(*buf));	/* fill in relevant fields */	buf->st_ino = e2fs->inode_table[fd].inumber;	buf->st_mode = ip->i_mode;	buf->st_nlink = ip->i_links_count;	buf->st_uid = ip->i_uid;	buf->st_gid = ip->i_gid;	buf->st_size = ip->i_size;	buf->st_atime = ip->i_atime;	buf->st_mtime = ip->i_mtime;	buf->st_ctime = ip->i_ctime;	return 0; /* NOTHING CAN GO WROGN! */}static EFI_STATUSext2fs_fstat(ext2fs_interface_t *this, UINTN fd, ext2fs_stat_t *st){	ext2fs_priv_state_t *e2fs;	if (this == NULL || fd > MAX_OPEN_FILES || st == NULL) return EFI_INVALID_PARAMETER;	e2fs = FS_PRIVATE(this);	ext2_fstat(e2fs, fd, st);	return EFI_SUCCESS;}static EFI_STATUSext2fs_seek(ext2fs_interface_t *this, UINTN fd, UINT64 newpos){	ext2fs_priv_state_t *e2fs;	if (this == NULL || fd > MAX_OPEN_FILES || newpos >= EXT2_FILESIZE_MAX) return EFI_INVALID_PARAMETER;	e2fs = FS_PRIVATE(this);	if (newpos > (UINT64)e2fs->inode_table[fd].inode.i_size) return EFI_INVALID_PARAMETER;	e2fs->inode_table[fd].pos = newpos;	return EFI_SUCCESS;}static EFI_STATUSext2fs_read(ext2fs_interface_t *this, UINTN fd, VOID *buf, UINTN *size){	ext2fs_priv_state_t *e2fs;	UINTN count, nc, bofs, bnum, pos;	EFI_STATUS ret = EFI_INVALID_PARAMETER;	CHAR8 *block;	if (this == NULL || size == NULL || buf == NULL || fd > MAX_OPEN_FILES) return EFI_INVALID_PARAMETER;	e2fs = FS_PRIVATE(this);	count = MIN(*size, e2fs->inode_table[fd].inode.i_size - e2fs->inode_table[fd].pos);	if (count == 0)  {		*size = 0;		return EFI_SUCCESS;	}	block = e2fs->blkbuf;	*size = 0;	pos = e2fs->inode_table[fd].pos;  	DBG_PRT((L"size=%d i_size=%d count=%d pos=%ld", *size,e2fs->inode_table[fd].inode.i_size, count, pos));	while (count) {		bnum = pos / e2fs->blocksize;		bofs = pos % e2fs->blocksize;		nc   = MIN(count, e2fs->blocksize - bofs);		DBG_PRT((L"bnum =%d bofs=%d nc=%d *size=%d", bnum, bofs, nc, *size));		if (ext2_bread(e2fs, fd, bnum, 1, block) == -1) goto error;#if 0				{ int i; char *p = block+bofs; 			for(i=MIN(nc, 64); i>=0 ; i--, p++) {				if (i % 16 == 0) Print(L"\n");				Print(L"%02x ", (UINTN)*p & 0xff);			}		}#endif		Memcpy(buf, block+bofs, nc);		count -= nc;		pos   += nc;		buf   += nc;		*size += nc;	}	e2fs->inode_table[fd].pos += *size;	ret = EFI_SUCCESS;error:	DBG_PRT((L"*size=%d ret=%r", *size, ret));	return ret;}static struct ext2_inode *ext2_follow_link(ext2fs_priv_state_t *e2fs, struct ext2_inode * from, const char * base){	char *linkto;	if (from->i_blocks) {		linkto = e2fs->blkbuf;		if (ext2_breadi(e2fs, from, 0, 1, e2fs->blkbuf) == -1)			return NULL;		DBG_PRT((L"long link!"));	} else {		linkto = (char*)from->i_block;	}	DBG_PRT((L"symlink to %s", linkto));	/* Resolve relative links */	if (linkto[0] != '/') {		char *end = strrchra(base, '/');		if (end) {			//char fullname[(end - base + 1) + strlena(linkto) + 1];			char fullname[EXT2FS_PATH_MAXLEN];			if (((end - base + 1) + strlena(linkto) + 1) >= EXT2FS_PATH_MAXLEN) {				Print(L"%s: filename too long, can't resolve\n", __FUNCTION__);				return NULL;			}			strncpya(fullname, base, end - base + 1);			fullname[end - base + 1] = '\0';			strcata(fullname, linkto);			DBG_PRT((L"resolved to %s", fullname));			return ext2_namei(e2fs, fullname);		} else {			/* Assume it's in the root */			return ext2_namei(e2fs, linkto);		}	} else {		return ext2_namei(e2fs, linkto);	}}static intext2_open(ext2fs_priv_state_t *e2fs, char *filename){	/*	 * Unix-like open routine.  Returns a small integer (actually	 * an index into the inode table...	 */	struct ext2_inode * ip;	ip = ext2_namei(e2fs, filename);	if (ip) {		struct inode_table_entry *itp;		while (S_ISLNK(ip->i_mode)) {			ip = ext2_follow_link(e2fs, ip, filename);			if (!ip) return -1;		}		itp = (struct inode_table_entry *)ip;		return itp - e2fs->inode_table;	} else		return -1;}static void ext2_close(ext2fs_priv_state_t *e2fs, int fd){	/* blah, hack, don't close the root inode ever */	if (&e2fs->inode_table[fd].inode != e2fs->root_inode)		ext2_iput(e2fs, &e2fs->inode_table[fd].inode);}static EFI_STATUSext2fs_close(ext2fs_interface_t *this, UINTN fd){	ext2fs_priv_state_t *e2fs;	if (this == NULL || fd > MAX_OPEN_FILES) return EFI_INVALID_PARAMETER;	e2fs = FS_PRIVATE(this);	ext2_close(e2fs, fd);	return EFI_SUCCESS;}static EFI_STATUSext2fs_open(ext2fs_interface_t *this, CHAR16 *name, UINTN *fd){	ext2fs_priv_state_t *e2fs;	CHAR8 filename[EXT2FS_PATH_MAXLEN]; /* XXX: kind of big for a stack object */	INTN tmp;	DBG_PRT((L"name:%s fd=%x", name, fd));	if (this == NULL || name == NULL || fd == NULL || StrLen(name) >=EXT2FS_PATH_MAXLEN) return EFI_INVALID_PARAMETER;	e2fs = FS_PRIVATE(this);	/*	 * XXX: for security reasons, we may have to force a prefix like /boot to all filenames	 */	StrnXCpy(filename, name, EXT2FS_PATH_MAXLEN);		DBG_PRT((L"ASCII name:%a UTF-name:%s", filename, name));	tmp = ext2_open(e2fs, filename);	if (tmp != -1) {		*fd = (UINTN)tmp;		e2fs->inode_table[tmp].pos = 0; /* reset file position */	}	DBG_PRT((L"name: %s fd=%d tmp=%d", name, *fd, tmp));	return tmp == -1 ? EFI_NOT_FOUND : EFI_SUCCESS;}static EFI_STATUSext2fs_name(ext2fs_interface_t *this, CHAR16 *name, UINTN maxlen){	if (name == NULL || maxlen < 1) return EFI_INVALID_PARAMETER;	StrnCpy(name, FS_NAME, maxlen-1);	name[maxlen-1] = CHAR_NULL;	return EFI_SUCCESS;}static INTNext2fs_init_state(ext2fs_t *ext2fs, EFI_HANDLE dev, EFI_BLOCK_IO *blkio, struct ext2_super_block *sb){	ext2fs_priv_state_t *e2fs = FS_PRIVATE(ext2fs);	UINTN i;	EFI_STATUS status;	Memset(ext2fs, 0, sizeof(*ext2fs));	e2fs->dev     = dev;	e2fs->blkio   = blkio;	e2fs->mediaid = blkio->Media->MediaId;	/* fools gcc builtin memcpy */	Memcpy(&e2fs->sb, sb, sizeof(*sb));	e2fs->ngroups = (sb->s_blocks_count - sb->s_first_data_block + EXT2_BLOCKS_PER_GROUP(sb) - 1) / EXT2_BLOCKS_PER_GROUP(sb);	e2fs->gds = (struct ext2_group_desc *)alloc(e2fs->ngroups * sizeof(struct ext2_group_desc), EXT2FS_MEMTYPE);	if (e2fs->gds == NULL) {		ERR_PRT((L"failed to allocate gds"));		return EFI_OUT_OF_RESOURCES;	}		e2fs->blocksize = EXT2_BLOCK_SIZE(sb);	DBG_PRT((L"gds_size=%d gds_offset=%d ngroups=%d blocksize=%d",				e2fs->ngroups * sizeof(struct ext2_group_desc), 				e2fs->blocksize * (EXT2_MIN_BLOCK_SIZE/e2fs->blocksize + 1),				e2fs->ngroups, (UINTN)e2fs->blocksize));	/* read in the group descriptors (immediately follows superblock) */	status = read_bytes(blkio, e2fs->mediaid, e2fs->blocksize * (EXT2_MIN_BLOCK_SIZE/e2fs->blocksize + 1),			e2fs->gds, e2fs->ngroups * sizeof(struct ext2_group_desc));	if (EFI_ERROR(status)) {		ERR_PRT((L"cannot read gds: %r", status));		free(e2fs->gds);		return EFI_INVALID_PARAMETER;	}#if 0	{ int i; char *p = (char *)e2fs->gds;		for(i=e2fs->ngroups*sizeof(*e2fs->gds); i ; i--, p++) {			if (i % 16 == 0) Print(L"\n");			Print(L"%02x ", (UINTN)*p & 0xff);		}	}#endif	e2fs->cached_diblkno = -1;	e2fs->cached_iblkno  = -1;	/* initialize the inode table */	for (i = 0; i < MAX_OPEN_FILES; i++) {		e2fs->inode_table[i].free = 1;		e2fs->inode_table[i].inumber = 0;	}	/* clear the root inode pointer (very important!) */	e2fs->root_inode = NULL;	/*	 * Calculate direct/indirect block limits for this file system	 * (blocksize dependent):	ext2_blocksize = EXT2_BLOCK_SIZE(&sb);	 */	e2fs->directlim    = EXT2_NDIR_BLOCKS - 1;	e2fs->ptrs_per_blk = e2fs->blocksize/sizeof(unsigned int);	e2fs->ind1lim      = e2fs->ptrs_per_blk + e2fs->directlim;	e2fs->ind2lim      = (e2fs->ptrs_per_blk * e2fs->ptrs_per_blk) + e2fs->directlim;	ext2fs->pub_intf.ext2fs_name     = ext2fs_name;	ext2fs->pub_intf.ext2fs_open     = ext2fs_open;	ext2fs->pub_intf.ext2fs_read     = ext2fs_read;	ext2fs->pub_intf.ext2fs_close    = ext2fs_close;	ext2fs->pub_intf.ext2fs_seek     = ext2fs_seek;	ext2fs->pub_intf.ext2fs_fstat    = ext2fs_fstat;	return EFI_SUCCESS;}static EFI_STATUSext2fs_install_one(EFI_HANDLE dev, VOID **intf){	struct ext2_super_block sb;	long sb_block = 1;	EFI_STATUS status;	EFI_BLOCK_IO *blkio;	ext2fs_t *ext2fs;	status = BS->HandleProtocol (dev, &Ext2FsProtocol, (VOID **)&ext2fs);	if (status == EFI_SUCCESS) {		ERR_PRT((L"Warning: found existing %s protocol on device", FS_NAME));		goto found;	}		status = BS->HandleProtocol(dev, &BlockIoProtocol, (VOID **)&blkio);	if (EFI_ERROR(status)) return EFI_INVALID_PARAMETER;		VERB_PRT(5,		{ EFI_DEVICE_PATH *dp; CHAR16 *str;		  dp  = DevicePathFromHandle(dev);		  str = DevicePathToStr(dp);		  Print(L"dev:%s\nLogical partition: %s  BlockSize: %d WriteCaching: %s \n", str, 			  blkio->Media->LogicalPartition ? L"Yes": L"No",			  blkio->Media->BlockSize,			  blkio->Media->WriteCaching ? L"Yes":L"No");		  FreePool(str);		});	if (blkio->Media->LogicalPartition == FALSE) return EFI_INVALID_PARAMETER;#if 0	/*	 * Used to be necessary on some older versions of EFI to avoid getting	 * stuck. Now can cause problems with some SCSI controllers when enabled. 	 * Does not seem necessary with EFI 12.38	 */	blkio->Reset(blkio, FALSE);#endif	status = read_bytes(blkio, blkio->Media->MediaId, sb_block * EXT2_MIN_BLOCK_SIZE, &sb, sizeof(sb));	if (EFI_ERROR(status)) {		DBG_PRT((L"cannot read superblock: %r", status));		return EFI_INVALID_PARAMETER;	}		if (sb.s_magic != EXT2_SUPER_MAGIC) {		DBG_PRT((L"bad magic 0x%x\n", sb.s_magic));		return EFI_INVALID_PARAMETER;	}		ext2fs = (ext2fs_t *)alloc(sizeof(*ext2fs), EXT2FS_MEMTYPE);	if (ext2fs == NULL) return EFI_OUT_OF_RESOURCES;	status = ext2fs_init_state(ext2fs, dev, blkio, &sb);	if (status != EFI_SUCCESS) {		free(ext2fs);		return status;	}	status = LibInstallProtocolInterfaces(&dev, &Ext2FsProtocol, ext2fs, NULL);	if (EFI_ERROR(status)) {		ERR_PRT((L"Cannot install %s protocol: %r", FS_NAME, status));		free(ext2fs);		return status;	}found:	if (intf) *intf = (VOID *)ext2fs;	VERB_PRT(3,		{ EFI_DEVICE_PATH *dp; CHAR16 *str;		  dp  = DevicePathFromHandle(dev);		  str = DevicePathToStr(dp);		  Print(L"dev:%s %s detected\n", str, FS_NAME);		  FreePool(str);		});	return EFI_SUCCESS;}EFI_STATUSext2fs_install(VOID){	UINTN size = 0;	UINTN i;	EFI_STATUS status;	VOID *intf;	BS->LocateHandle(ByProtocol, &BlockIoProtocol, NULL, &size, NULL);	if (size == 0) return EFI_UNSUPPORTED; /* no device found, oh well */	DBG_PRT((L"size=%d", size));	dev_tab = (dev_tab_t *)alloc(size, EfiLoaderData);	if (dev_tab == NULL) {		ERR_PRT((L"failed to allocate handle table"));		return EFI_OUT_OF_RESOURCES;	}		status = BS->LocateHandle(ByProtocol, &BlockIoProtocol, NULL, &size, (VOID **)dev_tab);	if (status != EFI_SUCCESS) {		ERR_PRT((L"failed to get handles: %r", status));		free(dev_tab);		return status;	}	ndev = size / sizeof(EFI_HANDLE);	for(i=0; i < ndev; i++) {		intf = NULL;		ext2fs_install_one(dev_tab[i].dev, &intf);		/* override device handle with interface pointer */		dev_tab[i].intf = intf;	}	return EFI_SUCCESS;}	EFI_STATUSext2fs_uninstall(VOID){		ext2fs_priv_state_t *e2fs;	EFI_STATUS status;	UINTN i;	for(i=0; i < ndev; i++) {		if (dev_tab[i].intf == NULL) continue;		e2fs = FS_PRIVATE(dev_tab[i].intf);		status = BS->UninstallProtocolInterface(e2fs->dev, &Ext2FsProtocol, dev_tab[i].intf);		if (EFI_ERROR(status)) {			ERR_PRT((L"Uninstall %s error: %r", FS_NAME, status));			continue;		}		VERB_PRT(3,			{ EFI_DEVICE_PATH *dp; CHAR16 *str;		  	dp  = DevicePathFromHandle(e2fs->dev);		  	str = DevicePathToStr(dp);		  	Print(L"uninstalled %s on %s\n", FS_NAME, str);		  	FreePool(str);			});		free(dev_tab[i].intf);	}	if (dev_tab) free(dev_tab);	return EFI_SUCCESS;}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?