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 + -
显示快捷键?