You've already forked slimbootloader
mirror of
https://github.com/Dasharo/slimbootloader.git
synced 2026-03-06 15:26:20 -08:00
This patch fixes 2 issues related to symbolic links:
1. when "fs ls" a directory, symbolic links are not shown.
It is because Ext2fsLs() only shows regular files and directories.
2. when "fs ls <symbolic_link>" the output is incorrect.
It is because File->FileNamePtr points to a local variable,
"NameBuf" in Ext2fsOpen(), if the file is a symbolic link
This patch replaces File->FileNamePtr with FileNameBuf.
It slightly increases Ext2fsLs/Ext2fsOpen/SearchDirectory time,
because of the use of strcpy and strcat.
Test method:
1. create a regular file, "a", in directory "x"
2. create a symbolic link file, "b", pointing to "a".
3. under the shell of OSLoader,
"fs ls x"
- expected result: a, b (symbolic link)
"fs ls x/a"
- expected result: a and its file size is shown
"fs ls x/b"
- expected result: b -> a, and the file size of a is shown
Verify: TGL-UP3 RVP
Signed-off-by: Stanley Chang <stanley.chang@intel.com>
1250 lines
35 KiB
C
1250 lines
35 KiB
C
/** @file
|
|
|
|
Copyright (c) 2021 - 2022, Intel Corporation. All rights reserved.<BR>
|
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
|
|
Copyright (c) 1997 Manuel Bouyer.
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions
|
|
are met:
|
|
1. Redistributions of source code must retain the above copyright
|
|
notice, this list of conditions and the following disclaimer.
|
|
2. Redistributions in binary form must reproduce the above copyright
|
|
notice, this list of conditions and the following disclaimer in the
|
|
documentation and/or other materials provided with the distribution.
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
-
|
|
Copyright (c) 1993
|
|
The Regents of the University of California. All rights reserved.
|
|
|
|
This code is derived from software contributed to Berkeley by
|
|
The Mach Operating System project at Carnegie-Mellon University.
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions
|
|
are met:
|
|
1. Redistributions of source code must retain the above copyright
|
|
notice, this list of conditions and the following disclaimer.
|
|
2. Redistributions in binary form must reproduce the above copyright
|
|
notice, this list of conditions and the following disclaimer in the
|
|
documentation and/or other materials provided with the distribution.
|
|
3. Neither the Name of the University nor the names of its contributors
|
|
may be used to endorse or promote products derived from this software
|
|
without specific prior written permission.
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
|
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
SUCH DAMAGE.
|
|
|
|
|
|
Copyright (c) 1990, 1991 Carnegie Mellon University
|
|
All Rights Reserved.
|
|
|
|
Author: David Golub
|
|
|
|
Permission to use, copy, modify and distribute this software and its
|
|
documentation is hereby granted, provided that both the copyright
|
|
notice and this permission notice appear in all copies of the
|
|
software, derivative works or modified versions, and any portions
|
|
thereof, and that both notices appear in supporting documentation.
|
|
|
|
CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
|
|
CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
|
|
ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
|
|
|
|
Carnegie Mellon requests users of this software to return to
|
|
|
|
Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
|
|
School of Computer Science
|
|
Carnegie Mellon University
|
|
Pittsburgh PA 15213-3890
|
|
|
|
any improvements or extensions that they make and grant Carnegie the
|
|
rights to redistribute these changes.
|
|
|
|
Stand-alone FILE reading package for Ext2 FILE system.
|
|
**/
|
|
|
|
#include <Library/DebugLib.h>
|
|
#include <Library/MemoryAllocationLib.h>
|
|
#include <Library/MediaAccessLib.h>
|
|
#include "Ext2Fs.h"
|
|
#include "LibsaFsStand.h"
|
|
|
|
#define HOWMANY(x, y) (((x)+((y)-1))/(y))
|
|
|
|
#if defined(LIBSA_FS_SINGLECOMPONENT) && !defined(LIBSA_NO_FS_SYMLINK)
|
|
#define LIBSA_NO_FS_SYMLINK
|
|
#endif
|
|
|
|
/**
|
|
Given an offset in a FILE, find the disk block number that
|
|
contains that block.
|
|
|
|
@param[in] File pointer to an Open file.
|
|
@param[in] FileBlock Block to find the file.
|
|
@param[out] DiskBlockPtr Pointer to the disk which contains block.
|
|
|
|
@retval 0 if success
|
|
@retval other if error.
|
|
**/
|
|
STATIC
|
|
RETURN_STATUS
|
|
BlockMap (
|
|
IN OPEN_FILE *File,
|
|
IN INDPTR FileBlock,
|
|
OUT INDPTR *DiskBlockPtr
|
|
);
|
|
|
|
/**
|
|
Search a directory for a Name and return its inode number.
|
|
|
|
@param[in] Name Name to compare with
|
|
@param[in] Length Length of the dir name
|
|
@param[in/out] File Pointer to file private data
|
|
@param[out] INumPtr pointer to Inode number.
|
|
|
|
@retval 0 if success
|
|
@retval other if error.
|
|
**/
|
|
STATIC
|
|
RETURN_STATUS
|
|
SearchDirectory (
|
|
IN CHAR8 *Name,
|
|
IN INT32 Length,
|
|
IN OUT OPEN_FILE *File,
|
|
OUT INODE32 *INumPtr
|
|
);
|
|
|
|
/**
|
|
Gives the info of device block config.
|
|
|
|
@param[in] DevData Device privete data.
|
|
@param[in] ReadWrite Read or Write
|
|
@param[in] BlockNum Block number to start
|
|
@param[in] Size Size to read block.
|
|
@param[out] Buf Buffer to read the block data.
|
|
@param[out] RSize Actual read size
|
|
|
|
@retval 0 if success
|
|
@retval other if error.
|
|
**/
|
|
RETURN_STATUS
|
|
EFIAPI
|
|
BDevStrategy (
|
|
IN VOID *DevData,
|
|
IN INT32 ReadWrite,
|
|
IN DADDRESS BlockNum,
|
|
IN UINT32 Size,
|
|
OUT VOID *Buf,
|
|
OUT UINT32 *RSize
|
|
)
|
|
{
|
|
RETURN_STATUS Status;
|
|
PEI_EXT_PRIVATE_DATA *PrivateData;
|
|
UINT64 Startblockno;
|
|
|
|
PrivateData = DevData;
|
|
|
|
if (ReadWrite != F_READ && ReadWrite != F_WRITE) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
if ((Size % PrivateData->BlockSize) != 0) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
Startblockno = BlockNum + PrivateData->StartBlock;
|
|
if (ReadWrite == F_READ) {
|
|
Status = MediaReadBlocks (PrivateData->PhysicalDevNo, (UINT32)Startblockno, Size, Buf);
|
|
if (RETURN_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
*RSize = Size;
|
|
return RETURN_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Read a new inode into a FILE structure.
|
|
|
|
@param[in] INumber inode number
|
|
@param[in/out] File pointer to open file struct.
|
|
|
|
@retval 0 if success
|
|
@retval other if error.
|
|
**/
|
|
RETURN_STATUS
|
|
EFIAPI
|
|
ReadInode (
|
|
IN INODE32 INumber,
|
|
IN OPEN_FILE *File
|
|
)
|
|
{
|
|
FILE *Fp;
|
|
M_EXT2FS *FileSystem;
|
|
CHAR8 *Buf;
|
|
UINT32 RSize;
|
|
RETURN_STATUS Status;
|
|
DADDRESS InodeSector;
|
|
EXT2GD *Ext2FsGrpDes;
|
|
EXTFS_DINODE *DInodePtr;
|
|
|
|
Fp = (FILE *)File->FileSystemSpecificData;
|
|
FileSystem = Fp->SuperBlockPtr;
|
|
|
|
Ext2FsGrpDes = &FileSystem->Ext2FsGrpDes[INOTOCG(FileSystem, INumber)];
|
|
|
|
InodeSector = (DADDRESS) (Ext2FsGrpDes->Ext2BGDInodeTables + DivU64x32 (ModU64x32 ((INumber - 1), FileSystem->Ext2Fs.Ext2FsINodesPerGroup), FileSystem->Ext2FsInodesPerBlock));
|
|
|
|
if (FileSystem->Ext2FsGDSize > 32) {
|
|
if (Ext2FsGrpDes->Ext2BGDInodeTablesHi !=0) {
|
|
InodeSector |= LShiftU64 ((UINT64) (Ext2FsGrpDes->Ext2BGDInodeTablesHi), 32);
|
|
}
|
|
}
|
|
InodeSector = FSBTODB (FileSystem, InodeSector);
|
|
|
|
//
|
|
// Read inode and save it.
|
|
//
|
|
Buf = Fp->Buffer;
|
|
Status = DEV_STRATEGY (File->DevPtr) (File->FileDevData, F_READ,
|
|
InodeSector, FileSystem->Ext2FsBlockSize, Buf, &RSize);
|
|
if (RETURN_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
if (RSize != (UINT32)FileSystem->Ext2FsBlockSize) {
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
DInodePtr = (EXTFS_DINODE *) (Buf +
|
|
EXT2_DINODE_SIZE (FileSystem) * INODETOFSBO (FileSystem, INumber));
|
|
E2FSILOAD (DInodePtr, &Fp->DiskInode);
|
|
|
|
//
|
|
// Clear out the Old buffers
|
|
//
|
|
Fp->InodeCacheBlock = ~0;
|
|
Fp->BufferBlockNum = -1;
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Given an offset in a FILE, find the disk block number that
|
|
contains that block.
|
|
|
|
@param[in] File pointer to an Open file.
|
|
@param[in] FileBlock Block to find the file.
|
|
@param[out] DiskBlockPtr Pointer to the disk which contains block.
|
|
|
|
@retval 0 if success
|
|
@retval other if error.
|
|
**/
|
|
STATIC
|
|
RETURN_STATUS
|
|
BlockMap (
|
|
IN OPEN_FILE *File,
|
|
IN INDPTR FileBlock,
|
|
OUT INDPTR *DiskBlockPtr
|
|
)
|
|
{
|
|
FILE *Fp;
|
|
M_EXT2FS *FileSystem;
|
|
UINT32 Level;
|
|
INDPTR IndCache;
|
|
INDPTR IndBlockNum;
|
|
UINT32 RSize;
|
|
INDPTR *Buf;
|
|
UINT32 Index;
|
|
UINT64 NextLevelNode;
|
|
EXT4_EXTENT_TABLE *Etable;
|
|
EXT4_EXTENT_INDEX *ExtIndex;
|
|
EXT4_EXTENT *Extent;
|
|
RETURN_STATUS Status;
|
|
|
|
Fp = (FILE *)File->FileSystemSpecificData;
|
|
FileSystem = Fp->SuperBlockPtr;
|
|
Buf = (VOID *)Fp->Buffer;
|
|
|
|
if ((Fp->DiskInode.Ext2DInodeStatusFlags & EXT4_EXTENTS) != 0) {
|
|
Etable = (EXT4_EXTENT_TABLE*) &(Fp->DiskInode.Ext2DInodeBlocks);
|
|
if (Etable->Eheader.EhMagic != EXT4_EXTENT_HEADER_MAGIC) {
|
|
DEBUG ((DEBUG_ERROR, "EXT4 extent header magic mismatch 0x%X!\n", Etable->Eheader.EhMagic));
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
while (Etable->Eheader.EhDepth > 0) {
|
|
ExtIndex = NULL;
|
|
|
|
/* if only one entry exists, the first entry should be used */
|
|
if (Etable->Eheader.EhEntries == 1) {
|
|
ExtIndex = &(Etable->Enodes.Eindex[0]);
|
|
}
|
|
|
|
for (Index=1; Index < Etable->Eheader.EhEntries; Index++) {
|
|
ExtIndex = &(Etable->Enodes.Eindex[Index]);
|
|
if (((UINT32) FileBlock) < ExtIndex->EiBlk) {
|
|
ExtIndex = &(Etable->Enodes.Eindex[Index-1]);
|
|
break;
|
|
}
|
|
ExtIndex = NULL;
|
|
}
|
|
|
|
if (ExtIndex != NULL) {
|
|
//
|
|
// TODO: Need to support 48-bit block device addressing.
|
|
// Throw an ASSERT if upper 16-bits are non-zero.
|
|
//
|
|
ASSERT (ExtIndex->EiLeafHi == 0);
|
|
NextLevelNode = ExtIndex->EiLeafLo; //LShiftU64((UINT64)ExtIndex->EiLeafHi, 32) | ExtIndex->EiLeafLo;
|
|
|
|
//
|
|
// We need to read the next level node of the extent tree since the data was not in the current level.
|
|
//
|
|
Status = DEV_STRATEGY (File->DevPtr) (File->FileDevData, F_READ,
|
|
FSBTODB (Fp->SuperBlockPtr, (DADDRESS) NextLevelNode), FileSystem->Ext2FsBlockSize,
|
|
Buf, &RSize);
|
|
if (RETURN_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
if (RSize != (UINT32)FileSystem->Ext2FsBlockSize) {
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
Etable = (EXT4_EXTENT_TABLE*) Buf;
|
|
if (Etable->Eheader.EhMagic != EXT4_EXTENT_HEADER_MAGIC) {
|
|
DEBUG ((DEBUG_ERROR, "EXT4 extent header magic mismatch 0x%X!\n", Etable->Eheader.EhMagic));
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
} else {
|
|
DEBUG ((DEBUG_ERROR, "Could not find FileBlock #%d in the index extent data!\n", FileBlock));
|
|
return EFI_NO_MAPPING;
|
|
}
|
|
}
|
|
|
|
Extent = NULL;
|
|
for (Index=0; Index < Etable->Eheader.EhEntries; Index++) {
|
|
Extent = &(Etable->Enodes.Extent[Index]);
|
|
if ((((UINT32) FileBlock) >= Extent->Eblk) && (((UINT32) FileBlock) < (Extent->Eblk + Extent->Elen))) {
|
|
break;
|
|
}
|
|
Extent = NULL;
|
|
}
|
|
|
|
if (Extent != NULL) {
|
|
//
|
|
// TODO: Need to support 48-bit block device addressing
|
|
// Throw an ASSERT if upper 16-bits are non-zero.
|
|
//
|
|
ASSERT (Extent->EstartHi == 0);
|
|
*DiskBlockPtr = Extent->EstartLo + (FileBlock - Extent->Eblk); // (LShiftU64((UINT64)Extent->EiLeafHi, 32) | Extent->EstartLo) + (FileBlock - Extent->Eblk);
|
|
} else {
|
|
*DiskBlockPtr = 0;
|
|
}
|
|
} else {
|
|
if (FileBlock < NDADDR) {
|
|
//
|
|
// Direct block.
|
|
//
|
|
*DiskBlockPtr = Fp->DiskInode.Ext2DInodeBlocks[FileBlock];
|
|
return 0;
|
|
}
|
|
|
|
FileBlock -= NDADDR;
|
|
|
|
IndCache = FileBlock >> LN2_IND_CACHE_SZ;
|
|
if (IndCache == Fp->InodeCacheBlock) {
|
|
*DiskBlockPtr =
|
|
Fp->InodeCache[FileBlock & IND_CACHE_MASK];
|
|
return 0;
|
|
}
|
|
|
|
for (Level = 0;;) {
|
|
Level += Fp->NiShift;
|
|
if (FileBlock < (INDPTR)1 << Level) {
|
|
break;
|
|
}
|
|
if (Level > NIADDR * Fp->NiShift)
|
|
//
|
|
// Block number too high
|
|
//
|
|
{
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
FileBlock -= (INDPTR)1 << Level;
|
|
}
|
|
|
|
IndBlockNum =
|
|
Fp->DiskInode.Ext2DInodeBlocks[NDADDR + (Level / Fp->NiShift - 1)];
|
|
|
|
while (1) {
|
|
Level -= Fp->NiShift;
|
|
if (IndBlockNum == 0) {
|
|
*DiskBlockPtr = 0; // missing
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// If we were feeling brave, we could work out the number
|
|
// of the disk sector and read a single disk sector instead
|
|
// of a filesystem block.
|
|
// However we don't do this very often anyway...
|
|
//
|
|
Status = DEV_STRATEGY (File->DevPtr) (File->FileDevData, F_READ,
|
|
FSBTODB (Fp->SuperBlockPtr, IndBlockNum), FileSystem->Ext2FsBlockSize,
|
|
Buf, &RSize);
|
|
if (RETURN_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
if (RSize != (UINT32)FileSystem->Ext2FsBlockSize) {
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
IndBlockNum = Buf[FileBlock >> Level];
|
|
if (Level == 0) {
|
|
break;
|
|
}
|
|
FileBlock &= (1 << Level) - 1;
|
|
}
|
|
//
|
|
// Save the part of the block that contains this sector
|
|
//
|
|
CopyMem (Fp->InodeCache, &Buf[FileBlock & ~IND_CACHE_MASK],
|
|
IND_CACHE_SZ * sizeof Fp->InodeCache[0]);
|
|
Fp->InodeCacheBlock = IndCache;
|
|
|
|
*DiskBlockPtr = IndBlockNum;
|
|
}
|
|
|
|
return RETURN_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Read a portion of a FILE into an internal buffer.
|
|
|
|
Return the location in the buffer and the amount in the buffer.
|
|
|
|
@param[in] File Pointer to the open file.
|
|
@param[out] BufferPtr buffer corresponding to offset
|
|
@param[out] SizePtr Size of remainder of buffer.
|
|
|
|
@retval 0 if success
|
|
@retval other if error.
|
|
**/
|
|
RETURN_STATUS
|
|
EFIAPI
|
|
BufReadFile (
|
|
IN OPEN_FILE *File,
|
|
OUT CHAR8 **BufferPtr,
|
|
OUT UINT32 *SizePtr
|
|
)
|
|
{
|
|
FILE *Fp;
|
|
M_EXT2FS *FileSystem;
|
|
INT32 Off;
|
|
INDPTR FileBlock;
|
|
INDPTR DiskBlock;
|
|
UINT32 BlockSize;
|
|
RETURN_STATUS Rc;
|
|
|
|
Fp = (FILE *)File->FileSystemSpecificData;
|
|
FileSystem = Fp->SuperBlockPtr;
|
|
DiskBlock = 0;
|
|
|
|
Off = BLOCKOFFSET (FileSystem, Fp->SeekPtr);
|
|
FileBlock = LBLKNO (FileSystem, Fp->SeekPtr);
|
|
BlockSize = FileSystem->Ext2FsBlockSize; // no fragment
|
|
|
|
if (FileBlock != Fp->BufferBlockNum) {
|
|
Rc = BlockMap (File, FileBlock, &DiskBlock);
|
|
if (Rc != 0) {
|
|
return Rc;
|
|
}
|
|
|
|
if (DiskBlock == 0) {
|
|
SetMem32 (Fp->Buffer, BlockSize, 0);
|
|
Fp->BufferSize = BlockSize;
|
|
} else {
|
|
|
|
Rc = DEV_STRATEGY (File->DevPtr) (File->FileDevData, F_READ,
|
|
FSBTODB (FileSystem, DiskBlock),
|
|
BlockSize, Fp->Buffer, &Fp->BufferSize);
|
|
if (Rc != 0) {
|
|
return Rc;
|
|
}
|
|
}
|
|
|
|
Fp->BufferBlockNum = FileBlock;
|
|
}
|
|
|
|
//
|
|
// Return address of byte in buffer corresponding to
|
|
// offset, and Size of remainder of buffer after that
|
|
// byte.
|
|
//
|
|
*BufferPtr = Fp->Buffer + Off;
|
|
*SizePtr = BlockSize - Off;
|
|
|
|
//
|
|
// But truncate buffer at end of FILE.
|
|
//
|
|
// XXX should handle LARGEFILE
|
|
//
|
|
if (*SizePtr > Fp->DiskInode.Ext2DInodeSize - Fp->SeekPtr) {
|
|
*SizePtr = Fp->DiskInode.Ext2DInodeSize - Fp->SeekPtr;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
Search a directory for a Name and return its inode number.
|
|
|
|
@param[in] Name Name to compare with
|
|
@param[in] Length Length of the dir name
|
|
@param[in/out] File Pointer to file private data
|
|
@param[out] INumPtr pointer to Inode number.
|
|
|
|
@retval 0 if success
|
|
@retval other if error.
|
|
**/
|
|
STATIC
|
|
RETURN_STATUS
|
|
SearchDirectory (
|
|
IN CHAR8 *Name,
|
|
IN INT32 Length,
|
|
IN OUT OPEN_FILE *File,
|
|
OUT INODE32 *INumPtr
|
|
)
|
|
{
|
|
FILE *Fp;
|
|
EXT2FS_DIRECT *Dp;
|
|
EXT2FS_DIRECT *EdPtr;
|
|
CHAR8 *Buf;
|
|
UINT32 BufSize;
|
|
INT32 NameLen;
|
|
RETURN_STATUS Status;
|
|
|
|
Fp = (FILE *)File->FileSystemSpecificData;
|
|
|
|
Fp->SeekPtr = 0;
|
|
//
|
|
// XXX should handle LARGEFILE
|
|
//
|
|
while (Fp->SeekPtr < (OFFSET)Fp->DiskInode.Ext2DInodeSize) {
|
|
Status = BufReadFile (File, &Buf, &BufSize);
|
|
if (RETURN_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
Dp = (EXT2FS_DIRECT *)Buf;
|
|
EdPtr = (EXT2FS_DIRECT *) (Buf + BufSize);
|
|
for (; Dp < EdPtr;
|
|
Dp = (VOID *) ((CHAR8 *)Dp + Dp->Ext2DirectRecLen)) {
|
|
if (Dp->Ext2DirectRecLen <= 0) {
|
|
break;
|
|
}
|
|
if (Dp->Ext2DirectInodeNumber == (INODE32)0) {
|
|
continue;
|
|
}
|
|
NameLen = Dp->Ext2DirectNameLen;
|
|
if (NameLen == Length &&
|
|
!CompareMem (Name, Dp->Ext2DirectName, Length)) {
|
|
//
|
|
// found entry
|
|
//
|
|
*INumPtr = Dp->Ext2DirectInodeNumber;
|
|
AsciiStrCpyS (File->FileNameBuf, EXT2FS_MAXNAMLEN, Name);
|
|
return 0;
|
|
}
|
|
}
|
|
Fp->SeekPtr += BufSize;
|
|
}
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
/**
|
|
Validate EXT2 Superblock
|
|
|
|
@param[in] FsHandle EXT file system handle.
|
|
@param[in] File File for which super block needs to be read.
|
|
@param[out] RExt2Fs EXT2FS meta data to retreive.
|
|
|
|
@retval 0 if superblock validation is success
|
|
@retval other if error.
|
|
**/
|
|
RETURN_STATUS
|
|
EFIAPI
|
|
Ext2SbValidate (
|
|
IN CONST EFI_HANDLE FsHandle,
|
|
IN CONST OPEN_FILE *File OPTIONAL,
|
|
OUT EXT2FS *RExt2Fs OPTIONAL
|
|
)
|
|
{
|
|
PEI_EXT_PRIVATE_DATA *PrivateData;
|
|
UINT8 *Buffer;
|
|
EXT2FS *Ext2Fs;
|
|
UINT32 BufSize;
|
|
RETURN_STATUS Rc;
|
|
UINT32 SbOffset;
|
|
|
|
Rc = 0;
|
|
Buffer = NULL;
|
|
|
|
if (FsHandle == NULL) {
|
|
Rc = RETURN_INVALID_PARAMETER;
|
|
goto Exit;
|
|
}
|
|
|
|
PrivateData = (PEI_EXT_PRIVATE_DATA *)FsHandle;
|
|
|
|
Buffer = AllocatePool ((PrivateData->BlockSize > SBSIZE) ? PrivateData->BlockSize : SBSIZE);
|
|
if (Buffer == NULL) {
|
|
Rc = EFI_OUT_OF_RESOURCES;
|
|
goto Exit;
|
|
}
|
|
|
|
if (File == NULL) {
|
|
Rc = BDevStrategy (PrivateData, F_READ,
|
|
SBOFF / PrivateData->BlockSize, PrivateData->BlockSize, Buffer, &BufSize);
|
|
} else {
|
|
Rc = DEV_STRATEGY (File->DevPtr) (PrivateData, F_READ,
|
|
SBOFF / PrivateData->BlockSize, PrivateData->BlockSize,
|
|
Buffer, &BufSize);
|
|
}
|
|
|
|
if (Rc != 0) {
|
|
goto Exit;
|
|
}
|
|
|
|
SbOffset = (SBOFF < PrivateData->BlockSize) ? SBOFF : 0;
|
|
Ext2Fs = (EXT2FS *)(&Buffer[SbOffset]);
|
|
if (Ext2Fs->Ext2FsMagic != E2FS_MAGIC) {
|
|
Rc = EFI_UNSUPPORTED;
|
|
goto Exit;
|
|
}
|
|
|
|
if (Ext2Fs->Ext2FsRev > E2FS_REV1 ||
|
|
(Ext2Fs->Ext2FsRev == E2FS_REV1 &&
|
|
(Ext2Fs->Ext2FsFirstInode != EXT2_FIRSTINO ||
|
|
(Ext2Fs->Ext2FsInodeSize != 128 && Ext2Fs->Ext2FsInodeSize != 256) ||
|
|
Ext2Fs->Ext2FsFeaturesIncompat & ~EXT2F_INCOMPAT_SUPP))) {
|
|
Rc = EFI_UNSUPPORTED;
|
|
goto Exit;
|
|
}
|
|
|
|
if (Ext2Fs->Ext2FsRev == E2FS_REV0) {
|
|
Ext2Fs->Ext2FsFirstInode = 11;
|
|
Ext2Fs->Ext2FsInodeSize = 128;
|
|
}
|
|
|
|
if (RExt2Fs != NULL) {
|
|
E2FS_SBLOAD ((VOID *)Ext2Fs, RExt2Fs);
|
|
}
|
|
|
|
Exit:
|
|
if (Buffer != NULL) {
|
|
FreePool (Buffer);
|
|
}
|
|
|
|
return Rc;
|
|
}
|
|
|
|
/**
|
|
Read Superblock of the file.
|
|
|
|
@param[in] File File for which super block needs to be read.
|
|
@param[in/out] FileSystem Fs on which super block is computed.
|
|
|
|
@retval 0 if superblock compute is success
|
|
@retval other if error.
|
|
**/
|
|
RETURN_STATUS
|
|
EFIAPI
|
|
ReadSBlock (
|
|
IN OPEN_FILE *File,
|
|
IN OUT M_EXT2FS *FileSystem
|
|
)
|
|
{
|
|
PEI_EXT_PRIVATE_DATA *PrivateData;
|
|
RETURN_STATUS Rc;
|
|
|
|
Rc = 0;
|
|
|
|
PrivateData = (PEI_EXT_PRIVATE_DATA*) File->FileDevData;
|
|
|
|
Rc = Ext2SbValidate ((EFI_HANDLE)PrivateData, File, &FileSystem->Ext2Fs);
|
|
if (RETURN_ERROR (Rc)) {
|
|
goto Exit;
|
|
}
|
|
|
|
//
|
|
// compute in-memory m_ext2fs values
|
|
//
|
|
FileSystem->Ext2FsNumCylinder =
|
|
HOWMANY (FileSystem->Ext2Fs.Ext2FsBlockCount - FileSystem->Ext2Fs.Ext2FsFirstDataBlock,
|
|
FileSystem->Ext2Fs.Ext2FsBlocksPerGroup);
|
|
|
|
FileSystem->Ext2FsFsbtobd = (INT32)(FileSystem->Ext2Fs.Ext2FsLogBlockSize + 10) - (INT32)HighBitSet32 (PrivateData->BlockSize);
|
|
FileSystem->Ext2FsBlockSize = MINBSIZE << FileSystem->Ext2Fs.Ext2FsLogBlockSize;
|
|
FileSystem->Ext2FsLogicalBlock = LOG_MINBSIZE + FileSystem->Ext2Fs.Ext2FsLogBlockSize;
|
|
FileSystem->Ext2FsQuadBlockOffset = FileSystem->Ext2FsBlockSize - 1;
|
|
FileSystem->Ext2FsBlockOffset = (UINT32)~FileSystem->Ext2FsQuadBlockOffset;
|
|
FileSystem->Ext2FsGDSize = 32;
|
|
if (FileSystem->Ext2Fs.Ext2FsFeaturesIncompat & EXT2F_INCOMPAT_64BIT) {
|
|
FileSystem->Ext2FsGDSize = FileSystem->Ext2Fs.Ext2FsGDSize;
|
|
}
|
|
FileSystem->Ext2FsNumGrpDesBlock =
|
|
HOWMANY (FileSystem->Ext2FsNumCylinder, FileSystem->Ext2FsBlockSize / FileSystem->Ext2FsGDSize);
|
|
FileSystem->Ext2FsInodesPerBlock = FileSystem->Ext2FsBlockSize / FileSystem->Ext2Fs.Ext2FsInodeSize;
|
|
FileSystem->Ext2FsInodesTablePerGrp = FileSystem->Ext2Fs.Ext2FsINodesPerGroup / FileSystem->Ext2FsInodesPerBlock;
|
|
|
|
Exit:
|
|
return Rc;
|
|
}
|
|
|
|
/**
|
|
Read group descriptor of the file.
|
|
|
|
@param[in/out] File File for which group descriptor needs to be read.
|
|
@param[in] FileSystem Fs on which super block is computed.
|
|
|
|
@retval 0 if Group descriptor read is success
|
|
@retval other if error.
|
|
**/
|
|
RETURN_STATUS
|
|
EFIAPI
|
|
ReadGDBlock (
|
|
IN OUT OPEN_FILE *File,
|
|
IN M_EXT2FS *FileSystem
|
|
)
|
|
{
|
|
FILE *Fp;
|
|
UINT32 RSize;
|
|
UINT32 gdpb;
|
|
INT32 Index;
|
|
INT32 Cnt;
|
|
INT32 i;
|
|
CHAR8 *Ptr;
|
|
RETURN_STATUS Status;
|
|
|
|
Fp = (FILE *)File->FileSystemSpecificData;
|
|
|
|
gdpb = FileSystem->Ext2FsBlockSize / FileSystem->Ext2FsGDSize;
|
|
|
|
for (Index = 0; Index < FileSystem->Ext2FsNumGrpDesBlock; Index++) {
|
|
Status = DEV_STRATEGY (File->DevPtr) (File->FileDevData, F_READ,
|
|
FSBTODB (FileSystem, FileSystem->Ext2Fs.Ext2FsFirstDataBlock +
|
|
1 /* superblock */ + Index),
|
|
FileSystem->Ext2FsBlockSize, Fp->Buffer, &RSize);
|
|
if (RETURN_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
if (RSize != (UINT32)FileSystem->Ext2FsBlockSize) {
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
/* Ext2FsGDSize may not be sizeof Ext2FsGrpDes */
|
|
if (FileSystem->Ext2FsGDSize == sizeof(EXT2GD)) {
|
|
E2FS_CGLOAD ((EXT2GD *)Fp->Buffer,
|
|
&FileSystem->Ext2FsGrpDes[Index * gdpb],
|
|
(Index == (FileSystem->Ext2FsNumGrpDesBlock - 1)) ?
|
|
(FileSystem->Ext2FsNumCylinder - gdpb * Index) * FileSystem->Ext2FsGDSize :
|
|
FileSystem->Ext2FsBlockSize);
|
|
} else {
|
|
Cnt = (Index == (FileSystem->Ext2FsNumGrpDesBlock - 1)) ?
|
|
FileSystem->Ext2FsNumCylinder - gdpb * Index :
|
|
gdpb;
|
|
|
|
for (i = 0; i < Cnt; i++) {
|
|
Ptr = Fp->Buffer + (i * FileSystem->Ext2FsGDSize);
|
|
E2FS_CGLOAD (Ptr,
|
|
&FileSystem->Ext2FsGrpDes[Index * gdpb + i],
|
|
FileSystem->Ext2FsGDSize);
|
|
}
|
|
}
|
|
}
|
|
|
|
return RETURN_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Open struct file.
|
|
|
|
@param[in] Path Path to locate the file
|
|
@param[in/out] File The struct having the device and file info
|
|
|
|
@retval RETURN_SUCCESS if file open is success
|
|
@retval other if error.
|
|
**/
|
|
RETURN_STATUS
|
|
EFIAPI
|
|
Ext2fsOpen (
|
|
IN CHAR8 *Path,
|
|
IN OUT OPEN_FILE *File
|
|
)
|
|
{
|
|
#ifndef LIBSA_FS_SINGLECOMPONENT
|
|
CHAR8 *Cp;
|
|
CHAR8 *Ncp;
|
|
INT32 Component;
|
|
#endif
|
|
INODE32 INumber;
|
|
FILE *Fp;
|
|
M_EXT2FS *FileSystem;
|
|
RETURN_STATUS Status;
|
|
#ifndef LIBSA_NO_FS_SYMLINK
|
|
INODE32 ParentInumber;
|
|
INT32 Nlinks;
|
|
CHAR8 NameBuf[MAXPATHLEN+1];
|
|
CHAR8 *Buf;
|
|
|
|
Nlinks = 0;
|
|
CHAR8 SymFileNameBuf[EXT2FS_MAXNAMLEN];
|
|
#endif
|
|
|
|
INDPTR mult;
|
|
INT32 Length2;
|
|
|
|
//
|
|
// allocate struct file system specific data structure
|
|
//
|
|
Fp = AllocatePool (sizeof (FILE));
|
|
if (Fp == NULL) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto out;
|
|
}
|
|
|
|
SetMem32 (Fp, sizeof (FILE), 0 );
|
|
File->FileSystemSpecificData = (VOID *)Fp;
|
|
//
|
|
// allocate space and read super block
|
|
//
|
|
FileSystem = AllocatePool (sizeof (*FileSystem));
|
|
if (FileSystem == NULL) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto out;
|
|
}
|
|
|
|
SetMem32 (FileSystem, sizeof (*FileSystem), 0);
|
|
Fp->SuperBlockPtr = FileSystem;
|
|
|
|
Status = ReadSBlock (File, FileSystem);
|
|
if (RETURN_ERROR (Status)) {
|
|
goto out;
|
|
}
|
|
|
|
#ifdef EXT2FS_DEBUG
|
|
DumpSBlock (FileSystem);
|
|
#endif
|
|
//
|
|
// alloc a block sized buffer used for all FileSystem transfers
|
|
//
|
|
Fp->Buffer = AllocatePool (FileSystem->Ext2FsBlockSize);
|
|
//
|
|
// read group descriptor blocks
|
|
//
|
|
FileSystem->Ext2FsGrpDes = AllocatePool (sizeof(EXT2GD) * FileSystem->Ext2FsNumCylinder);
|
|
Status = ReadGDBlock (File, FileSystem);
|
|
if (RETURN_ERROR (Status)) {
|
|
goto out;
|
|
}
|
|
|
|
#ifdef EXT2FS_DEBUG
|
|
DumpGroupDesBlock (FileSystem);
|
|
#endif
|
|
//
|
|
// Calculate indirect block levels.
|
|
//
|
|
//
|
|
// We note that the number of indirect blocks is always
|
|
// a power of 2. This lets us use shifts and masks instead
|
|
// of divide and remainder and avoinds pulling in the
|
|
// 64bit division routine into the boot code.
|
|
//
|
|
mult = NINDIR (FileSystem);
|
|
for (Length2 = 0; mult != 1; Length2++) {
|
|
mult >>= 1;
|
|
}
|
|
|
|
Fp->NiShift = Length2;
|
|
|
|
INumber = EXT2_ROOTINO;
|
|
Status = ReadInode (INumber, File);
|
|
if (RETURN_ERROR (Status)) {
|
|
goto out;
|
|
}
|
|
|
|
#ifndef LIBSA_FS_SINGLECOMPONENT
|
|
Cp = Path;
|
|
while (*Cp != '\0') {
|
|
//
|
|
// Remove extra separators
|
|
//
|
|
while (*Cp == '/') {
|
|
Cp++;
|
|
}
|
|
if (*Cp == '\0') {
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Check that current node is a directory.
|
|
//
|
|
if ((Fp->DiskInode.Ext2DInodeMode & EXT2_IFMT) != EXT2_IFDIR) {
|
|
Status = EFI_LOAD_ERROR;
|
|
goto out;
|
|
}
|
|
|
|
//
|
|
// Get next component of Path Name.
|
|
//
|
|
Ncp = Cp;
|
|
while ((Component = *Cp) != '\0' && Component != '/') {
|
|
Cp++;
|
|
}
|
|
|
|
//
|
|
// Look up component in current directory.
|
|
// Save directory INumber in case we find a
|
|
// symbolic link.
|
|
//
|
|
#ifndef LIBSA_NO_FS_SYMLINK
|
|
ParentInumber = INumber;
|
|
#endif
|
|
Status = SearchDirectory (Ncp, (INT32)(Cp - Ncp), File, &INumber);
|
|
if (RETURN_ERROR (Status)) {
|
|
goto out;
|
|
}
|
|
|
|
//
|
|
// Open next component.
|
|
//
|
|
Status = ReadInode (INumber, File);
|
|
if (RETURN_ERROR (Status)) {
|
|
goto out;
|
|
}
|
|
|
|
#ifndef LIBSA_NO_FS_SYMLINK
|
|
//
|
|
// Check for symbolic link.
|
|
//
|
|
if ((Fp->DiskInode.Ext2DInodeMode & EXT2_IFMT) == EXT2_IFLNK) {
|
|
//
|
|
// XXX should handle LARGEFILE
|
|
//
|
|
UINTN LinkLength;
|
|
UINTN Len;
|
|
|
|
LinkLength = Fp->DiskInode.Ext2DInodeSize;
|
|
|
|
Len = AsciiStrLen (Cp);
|
|
|
|
if (Nlinks == 0) {
|
|
/* copy the top-most filename */
|
|
AsciiStrCpyS (SymFileNameBuf, EXT2FS_MAXNAMLEN, Ncp);
|
|
}
|
|
|
|
if (((LinkLength + Len) > MAXPATHLEN) ||
|
|
((++Nlinks) > MAXSYMLINKS)) {
|
|
Status = RETURN_LOAD_ERROR;
|
|
goto out;
|
|
}
|
|
|
|
CopyMem (&NameBuf[LinkLength], Cp, Len + 1);
|
|
|
|
if (LinkLength < EXT2_MAXSYMLINKLEN) {
|
|
CopyMem (NameBuf, Fp->DiskInode.Ext2DInodeBlocks, LinkLength);
|
|
} else {
|
|
//
|
|
// Read FILE for symbolic link
|
|
//
|
|
UINT32 BufSize;
|
|
INDPTR DiskBlock;
|
|
|
|
Buf = Fp->Buffer;
|
|
Status = BlockMap (File, (INDPTR)0, &DiskBlock);
|
|
if (RETURN_ERROR (Status)) {
|
|
goto out;
|
|
}
|
|
|
|
Status = DEV_STRATEGY (File->DevPtr) (File->FileDevData,
|
|
F_READ, FSBTODB (FileSystem, DiskBlock),
|
|
FileSystem->Ext2FsBlockSize, Buf, &BufSize);
|
|
if (RETURN_ERROR (Status)) {
|
|
goto out;
|
|
}
|
|
|
|
CopyMem (NameBuf, Buf, LinkLength);
|
|
}
|
|
|
|
//
|
|
// If relative pathname, restart at parent directory.
|
|
// If absolute pathname, restart at root.
|
|
//
|
|
Cp = NameBuf;
|
|
if (*Cp != '/') {
|
|
INumber = ParentInumber;
|
|
} else {
|
|
INumber = (INODE32)EXT2_ROOTINO;
|
|
}
|
|
|
|
if (Nlinks == 1) {
|
|
/* only show the dest name of the next link */
|
|
AsciiStrCatS (SymFileNameBuf, EXT2FS_MAXNAMLEN, " -> ");
|
|
AsciiStrCatS (SymFileNameBuf, EXT2FS_MAXNAMLEN, NameBuf);
|
|
}
|
|
|
|
Status = ReadInode (INumber, File);
|
|
if (RETURN_ERROR (Status)) {
|
|
goto out;
|
|
}
|
|
}
|
|
#endif // !LIBSA_NO_FS_SYMLINK
|
|
}
|
|
|
|
//
|
|
// Found terminal component.
|
|
//
|
|
Status = RETURN_SUCCESS;
|
|
|
|
#else // !LIBSA_FS_SINGLECOMPONENT
|
|
//
|
|
// look up component in the current (root) directory
|
|
//
|
|
Status = SearchDirectory (Path, AsciiStrLen (Path), File, &INumber);
|
|
if (RETURN_ERROR (Status)) {
|
|
goto out;
|
|
}
|
|
//
|
|
// open it
|
|
//
|
|
Status = ReadInode (INumber, File);
|
|
|
|
#endif // !LIBSA_FS_SINGLECOMPONENT
|
|
|
|
Fp->SeekPtr = 0; // reset seek pointer
|
|
|
|
#ifndef LIBSA_NO_FS_SYMLINK
|
|
if (Nlinks > 0) {
|
|
AsciiStrCpyS (File->FileNameBuf, EXT2FS_MAXNAMLEN, SymFileNameBuf);
|
|
}
|
|
#endif
|
|
|
|
out:
|
|
if (RETURN_ERROR (Status)) {
|
|
Ext2fsClose (File);
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Close the opened file.
|
|
|
|
@param[in/out] File File to be closed.
|
|
|
|
@retval RETURN_SUCCESS regardless of success/fail condition
|
|
**/
|
|
RETURN_STATUS
|
|
EFIAPI
|
|
Ext2fsClose (
|
|
IN OUT OPEN_FILE *File
|
|
)
|
|
{
|
|
FILE *Fp;
|
|
|
|
Fp = (FILE *)File->FileSystemSpecificData;
|
|
|
|
File->FileSystemSpecificData = NULL;
|
|
if (Fp == NULL) {
|
|
return RETURN_SUCCESS;
|
|
}
|
|
|
|
if (Fp->SuperBlockPtr->Ext2FsGrpDes) {
|
|
FreePool (Fp->SuperBlockPtr->Ext2FsGrpDes);
|
|
}
|
|
if (Fp->Buffer) {
|
|
FreePool (Fp->Buffer);
|
|
}
|
|
FreePool (Fp->SuperBlockPtr);
|
|
FreePool (Fp);
|
|
return RETURN_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Gets the size of the file from descriptor.
|
|
|
|
@param[in] File File to be closed.
|
|
|
|
@retval size of the file from descriptor.
|
|
**/
|
|
UINT32
|
|
EFIAPI
|
|
Ext2fsFileSize (
|
|
IN OPEN_FILE *File
|
|
)
|
|
{
|
|
FILE *Fp;
|
|
Fp = (FILE *)File->FileSystemSpecificData;
|
|
return (UINT32)Fp->DiskInode.Ext2DInodeSize;
|
|
}
|
|
|
|
/**
|
|
Copy a portion of a FILE into a memory.
|
|
Cross block boundaries when necessary
|
|
|
|
@param[in/out] File File handle to be read
|
|
@param[in] Start Start address of read buffer
|
|
@param[in] Size Size to be read
|
|
@param[out] ResId Actual read size
|
|
|
|
@retval RETURN_SUCCESS if file read is success
|
|
@retval other if error.
|
|
**/
|
|
RETURN_STATUS
|
|
EFIAPI
|
|
Ext2fsRead (
|
|
IN OUT OPEN_FILE *File,
|
|
IN VOID *Start,
|
|
IN UINT32 Size,
|
|
OUT UINT32 *ResId
|
|
)
|
|
{
|
|
FILE *Fp;
|
|
UINT32 Csize;
|
|
CHAR8 *Buf;
|
|
UINT32 BufSize;
|
|
CHAR8 *Address;
|
|
RETURN_STATUS Status;
|
|
|
|
Fp = (FILE *)File->FileSystemSpecificData;
|
|
Status = RETURN_SUCCESS;
|
|
Address = Start;
|
|
|
|
while (Size != 0) {
|
|
//
|
|
// XXX should handle LARGEFILE
|
|
//
|
|
if (Fp->SeekPtr >= (OFFSET)Fp->DiskInode.Ext2DInodeSize) {
|
|
break;
|
|
}
|
|
|
|
Status = BufReadFile (File, &Buf, &BufSize);
|
|
if (RETURN_ERROR (Status)) {
|
|
break;
|
|
}
|
|
|
|
Csize = Size;
|
|
if (Csize > BufSize) {
|
|
Csize = BufSize;
|
|
}
|
|
|
|
CopyMem (Address, Buf, Csize);
|
|
|
|
Fp->SeekPtr += Csize;
|
|
Address += Csize;
|
|
Size -= Csize;
|
|
}
|
|
if (ResId != NULL) {
|
|
*ResId = Size;
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
#ifdef EXT2FS_DEBUG
|
|
/**
|
|
Dump the file system super block info.
|
|
|
|
@param[in] FileSystem pointer to filesystem.
|
|
|
|
@retval none
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
DumpSBlock (
|
|
IN M_EXT2FS *FileSystem
|
|
)
|
|
{
|
|
|
|
DEBUG ((DEBUG_INFO, "FileSystem->Ext2Fs.Ext2FsBlockCount = %u\n", FileSystem->Ext2Fs.Ext2FsBlockCount));
|
|
DEBUG ((DEBUG_INFO, "FileSystem->Ext2Fs.Ext2FsFirstDataBlock = %u\n", FileSystem->Ext2Fs.Ext2FsFirstDataBlock));
|
|
DEBUG ((DEBUG_INFO, "FileSystem->Ext2Fs.Ext2FsLogBlockSize = %u\n", FileSystem->Ext2Fs.Ext2FsLogBlockSize));
|
|
DEBUG ((DEBUG_INFO, "FileSystem->Ext2Fs.Ext2FsBlocksPerGroup = %u\n", FileSystem->Ext2Fs.Ext2FsBlocksPerGroup));
|
|
DEBUG ((DEBUG_INFO, "FileSystem->Ext2Fs.Ext2FsINodesPerGroup = %u\n", FileSystem->Ext2Fs.Ext2FsINodesPerGroup));
|
|
DEBUG ((DEBUG_INFO, "FileSystem->Ext2Fs.Ext2FsMagic = 0x%x\n", FileSystem->Ext2Fs.Ext2FsMagic));
|
|
DEBUG ((DEBUG_INFO, "FileSystem->Ext2Fs.Ext2FsRev = %u\n", FileSystem->Ext2Fs.Ext2FsRev));
|
|
|
|
if (FileSystem->Ext2Fs.Ext2FsRev == E2FS_REV1) {
|
|
DEBUG ((DEBUG_INFO, "FileSystem->Ext2Fs.Ext2FsFirstInode = %u\n",
|
|
FileSystem->Ext2Fs.Ext2FsFirstInode));
|
|
DEBUG ((DEBUG_INFO, "FileSystem->Ext2Fs.Ext2FsInodeSize = %u\n",
|
|
FileSystem->Ext2Fs.Ext2FsInodeSize));
|
|
DEBUG ((DEBUG_INFO, "FileSystem->Ext2Fs.Ext2FsFeaturesCompat = %u\n",
|
|
FileSystem->Ext2Fs.Ext2FsFeaturesCompat));
|
|
DEBUG ((DEBUG_INFO, "FileSystem->Ext2Fs.Ext2FsFeaturesIncompat = %u\n",
|
|
FileSystem->Ext2Fs.Ext2FsFeaturesIncompat));
|
|
DEBUG ((DEBUG_INFO, "FileSystem->Ext2Fs.Ext2FsFeaturesROCompat = %u\n",
|
|
FileSystem->Ext2Fs.Ext2FsFeaturesROCompat));
|
|
DEBUG ((DEBUG_INFO, "FileSystem->Ext2Fs.Ext2FsRsvdGDBlock = %u\n",
|
|
FileSystem->Ext2Fs.Ext2FsRsvdGDBlock));
|
|
}
|
|
|
|
DEBUG ((DEBUG_INFO, "FileSystem->Ext2FsGDSize = %u\n", FileSystem->Ext2FsGDSize));
|
|
DEBUG ((DEBUG_INFO, "FileSystem->Ext2FsBlockSize = %u\n", FileSystem->Ext2FsBlockSize));
|
|
DEBUG ((DEBUG_INFO, "FileSystem->Ext2FsFsbtobd = %u\n", FileSystem->Ext2FsFsbtobd));
|
|
DEBUG ((DEBUG_INFO, "FileSystem->Ext2FsNumCylinder = %u\n", FileSystem->Ext2FsNumCylinder));
|
|
DEBUG ((DEBUG_INFO, "FileSystem->Ext2FsNumGrpDesBlock = %u\n", FileSystem->Ext2FsNumGrpDesBlock));
|
|
DEBUG ((DEBUG_INFO, "FileSystem->Ext2FsInodesPerBlock = %u\n", FileSystem->Ext2FsInodesPerBlock));
|
|
DEBUG ((DEBUG_INFO, "FileSystem->Ext2FsInodesTablePerGrp = %u\n", FileSystem->Ext2FsInodesTablePerGrp));
|
|
}
|
|
|
|
/**
|
|
Dump the file group descriptor block info.
|
|
|
|
@param[in] FileSystem pointer to filesystem.
|
|
|
|
@retval none
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
DumpGroupDesBlock (
|
|
IN M_EXT2FS *FileSystem
|
|
)
|
|
{
|
|
INT32 Index;
|
|
EXT2GD *Ext2FsGrpDesEntry;
|
|
|
|
for (Index=0; Index < FileSystem->Ext2FsNumCylinder; Index++) {
|
|
Ext2FsGrpDesEntry = (EXT2GD*) ((UINT32) FileSystem->Ext2FsGrpDes + (Index * FileSystem->Ext2FsGDSize));
|
|
DEBUG ((DEBUG_INFO, "Ext2FsGrpDes[Index=%u]\n", Index));
|
|
DEBUG ((DEBUG_INFO, " Ext2BGDBlockBitmap %u\n", Ext2FsGrpDesEntry->Ext2BGDBlockBitmap));
|
|
DEBUG ((DEBUG_INFO, " Ext2BGDInodeBitmap %u\n", Ext2FsGrpDesEntry->Ext2BGDInodeBitmap));
|
|
DEBUG ((DEBUG_INFO, " Ext2BGDInodeTables %u\n", Ext2FsGrpDesEntry->Ext2BGDInodeTables));
|
|
DEBUG ((DEBUG_INFO, " Ext2BGDFreeBlocks %u\n", Ext2FsGrpDesEntry->Ext2BGDFreeBlocks));
|
|
DEBUG ((DEBUG_INFO, " Ext2BGDFreeInodes %u\n", Ext2FsGrpDesEntry->Ext2BGDFreeInodes));
|
|
DEBUG ((DEBUG_INFO, " Ext2BGDNumDir %u\n", Ext2FsGrpDesEntry->Ext2BGDNumDir));
|
|
if (FileSystem->Ext2FsGDSize > 32) {
|
|
DEBUG ((DEBUG_INFO, " Ext2BGDInodeTablesHi %u\n", Ext2FsGrpDesEntry->Ext2BGDInodeTablesHi));
|
|
}
|
|
}
|
|
}
|
|
#endif
|