📄 ext2.c
字号:
/*
* FreeLoader
* Copyright (C) 1998-2003 Brian Palmer <brianp@sginet.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <freeldr.h>
#include <debug.h>
GEOMETRY Ext2DiskGeometry; // Ext2 file system disk geometry
PEXT2_SUPER_BLOCK Ext2SuperBlock = NULL; // Ext2 file system super block
PEXT2_GROUP_DESC Ext2GroupDescriptors = NULL; // Ext2 file system group descriptors
UCHAR Ext2DriveNumber = 0; // Ext2 file system drive number
ULONGLONG Ext2VolumeStartSector = 0; // Ext2 file system starting sector
ULONG Ext2BlockSizeInBytes = 0; // Block size in bytes
ULONG Ext2BlockSizeInSectors = 0; // Block size in sectors
ULONG Ext2FragmentSizeInBytes = 0; // Fragment size in bytes
ULONG Ext2FragmentSizeInSectors = 0; // Fragment size in sectors
ULONG Ext2GroupCount = 0; // Number of groups in this file system
ULONG Ext2InodesPerBlock = 0; // Number of inodes in one block
ULONG Ext2GroupDescPerBlock = 0; // Number of group descriptors in one block
BOOLEAN Ext2OpenVolume(UCHAR DriveNumber, ULONGLONG VolumeStartSector)
{
DbgPrint((DPRINT_FILESYSTEM, "Ext2OpenVolume() DriveNumber = 0x%x VolumeStartSector = %d\n", DriveNumber, VolumeStartSector));
// Store the drive number and start sector
Ext2DriveNumber = DriveNumber;
Ext2VolumeStartSector = VolumeStartSector;
if (!MachDiskGetDriveGeometry(DriveNumber, &Ext2DiskGeometry))
{
return FALSE;
}
//
// Initialize the disk cache for this drive
//
if (!CacheInitializeDrive(DriveNumber))
{
return FALSE;
}
// Read in the super block
if (!Ext2ReadSuperBlock())
{
return FALSE;
}
// Read in the group descriptors
if (!Ext2ReadGroupDescriptors())
{
return FALSE;
}
return TRUE;
}
/*
* Ext2OpenFile()
* Tries to open the file 'name' and returns true or false
* for success and failure respectively
*/
FILE* Ext2OpenFile(PCSTR FileName)
{
EXT2_FILE_INFO TempExt2FileInfo;
PEXT2_FILE_INFO FileHandle;
CHAR SymLinkPath[EXT3_NAME_LEN];
CHAR FullPath[EXT3_NAME_LEN * 2];
ULONG Index;
DbgPrint((DPRINT_FILESYSTEM, "Ext2OpenFile() FileName = %s\n", FileName));
RtlZeroMemory(SymLinkPath, EXT3_NAME_LEN);
// Lookup the file in the file system
if (!Ext2LookupFile(FileName, &TempExt2FileInfo))
{
return NULL;
}
// If we got a symbolic link then fix up the path
// and re-call this function
if ((TempExt2FileInfo.Inode.i_mode & EXT2_S_IFMT) == EXT2_S_IFLNK)
{
DbgPrint((DPRINT_FILESYSTEM, "File is a symbolic link\n"));
// Now read in the symbolic link path
if (!Ext2ReadFile(&TempExt2FileInfo, TempExt2FileInfo.FileSize, NULL, SymLinkPath))
{
if (TempExt2FileInfo.FileBlockList != NULL)
{
MmFreeMemory(TempExt2FileInfo.FileBlockList);
}
return NULL;
}
DbgPrint((DPRINT_FILESYSTEM, "Symbolic link path = %s\n", SymLinkPath));
// Get the full path
if (SymLinkPath[0] == '/' || SymLinkPath[0] == '\\')
{
// Symbolic link is an absolute path
// So copy it to FullPath, but skip over
// the '/' char at the beginning
strcpy(FullPath, &SymLinkPath[1]);
}
else
{
// Symbolic link is a relative path
// Copy the first part of the path
strcpy(FullPath, FileName);
// Remove the last part of the path
for (Index=strlen(FullPath); Index>0; )
{
Index--;
if (FullPath[Index] == '/' || FullPath[Index] == '\\')
{
break;
}
}
FullPath[Index] = '\0';
// Concatenate the symbolic link
strcat(FullPath, Index == 0 ? "" : "/");
strcat(FullPath, SymLinkPath);
}
DbgPrint((DPRINT_FILESYSTEM, "Full file path = %s\n", FullPath));
if (TempExt2FileInfo.FileBlockList != NULL)
{
MmFreeMemory(TempExt2FileInfo.FileBlockList);
}
return Ext2OpenFile(FullPath);
}
else
{
FileHandle = MmAllocateMemory(sizeof(EXT2_FILE_INFO));
if (FileHandle == NULL)
{
if (TempExt2FileInfo.FileBlockList != NULL)
{
MmFreeMemory(TempExt2FileInfo.FileBlockList);
}
return NULL;
}
RtlCopyMemory(FileHandle, &TempExt2FileInfo, sizeof(EXT2_FILE_INFO));
return (FILE*)FileHandle;
}
}
/*
* Ext2LookupFile()
* This function searches the file system for the
* specified filename and fills in a EXT2_FILE_INFO structure
* with info describing the file, etc. returns true
* if the file exists or false otherwise
*/
BOOLEAN Ext2LookupFile(PCSTR FileName, PEXT2_FILE_INFO Ext2FileInfoPointer)
{
UINT i;
ULONG NumberOfPathParts;
CHAR PathPart[261];
PVOID DirectoryBuffer;
ULONG DirectoryInode = EXT3_ROOT_INO;
EXT2_INODE InodeData;
EXT2_DIR_ENTRY DirectoryEntry;
DbgPrint((DPRINT_FILESYSTEM, "Ext2LookupFile() FileName = %s\n", FileName));
RtlZeroMemory(Ext2FileInfoPointer, sizeof(EXT2_FILE_INFO));
//
// Figure out how many sub-directories we are nested in
//
NumberOfPathParts = FsGetNumPathParts(FileName);
//
// Loop once for each part
//
for (i=0; i<NumberOfPathParts; i++)
{
//
// Get first path part
//
FsGetFirstNameFromPath(PathPart, FileName);
//
// Advance to the next part of the path
//
for (; (*FileName != '\\') && (*FileName != '/') && (*FileName != '\0'); FileName++)
{
}
FileName++;
//
// Buffer the directory contents
//
if (!Ext2ReadDirectory(DirectoryInode, &DirectoryBuffer, &InodeData))
{
return FALSE;
}
//
// Search for file name in directory
//
if (!Ext2SearchDirectoryBufferForFile(DirectoryBuffer, (ULONG)Ext2GetInodeFileSize(&InodeData), PathPart, &DirectoryEntry))
{
MmFreeMemory(DirectoryBuffer);
return FALSE;
}
MmFreeMemory(DirectoryBuffer);
DirectoryInode = DirectoryEntry.inode;
}
if (!Ext2ReadInode(DirectoryInode, &InodeData))
{
return FALSE;
}
if (((InodeData.i_mode & EXT2_S_IFMT) != EXT2_S_IFREG) &&
((InodeData.i_mode & EXT2_S_IFMT) != EXT2_S_IFLNK))
{
FileSystemError("Inode is not a regular file or symbolic link.");
return FALSE;
}
// Set the drive number
Ext2FileInfoPointer->DriveNumber = Ext2DriveNumber;
// If it's a regular file or a regular symbolic link
// then get the block pointer list otherwise it must
// be a fast symbolic link which doesn't have a block list
if (((InodeData.i_mode & EXT2_S_IFMT) == EXT2_S_IFREG) ||
((InodeData.i_mode & EXT2_S_IFMT) == EXT2_S_IFLNK && InodeData.i_size > FAST_SYMLINK_MAX_NAME_SIZE))
{
Ext2FileInfoPointer->FileBlockList = Ext2ReadBlockPointerList(&InodeData);
if (Ext2FileInfoPointer->FileBlockList == NULL)
{
return FALSE;
}
}
else
{
Ext2FileInfoPointer->FileBlockList = NULL;
}
Ext2FileInfoPointer->FilePointer = 0;
Ext2FileInfoPointer->FileSize = Ext2GetInodeFileSize(&InodeData);
RtlCopyMemory(&Ext2FileInfoPointer->Inode, &InodeData, sizeof(EXT2_INODE));
return TRUE;
}
BOOLEAN Ext2SearchDirectoryBufferForFile(PVOID DirectoryBuffer, ULONG DirectorySize, PCHAR FileName, PEXT2_DIR_ENTRY DirectoryEntry)
{
ULONG CurrentOffset;
PEXT2_DIR_ENTRY CurrentDirectoryEntry;
DbgPrint((DPRINT_FILESYSTEM, "Ext2SearchDirectoryBufferForFile() DirectoryBuffer = 0x%x DirectorySize = %d FileName = %s\n", DirectoryBuffer, DirectorySize, FileName));
for (CurrentOffset=0; CurrentOffset<DirectorySize; )
{
CurrentDirectoryEntry = (PEXT2_DIR_ENTRY)((ULONG_PTR)DirectoryBuffer + CurrentOffset);
if (CurrentDirectoryEntry->rec_len == 0)
{
break;
}
if ((CurrentDirectoryEntry->rec_len + CurrentOffset) > DirectorySize)
{
FileSystemError("Directory entry extends past end of directory file.");
return FALSE;
}
DbgPrint((DPRINT_FILESYSTEM, "Dumping directory entry at offset %d:\n", CurrentOffset));
DbgDumpBuffer(DPRINT_FILESYSTEM, CurrentDirectoryEntry, CurrentDirectoryEntry->rec_len);
if ((_strnicmp(FileName, CurrentDirectoryEntry->name, CurrentDirectoryEntry->name_len) == 0) &&
(strlen(FileName) == CurrentDirectoryEntry->name_len))
{
RtlCopyMemory(DirectoryEntry, CurrentDirectoryEntry, sizeof(EXT2_DIR_ENTRY));
DbgPrint((DPRINT_FILESYSTEM, "EXT2 Directory Entry:\n"));
DbgPrint((DPRINT_FILESYSTEM, "inode = %d\n", DirectoryEntry->inode));
DbgPrint((DPRINT_FILESYSTEM, "rec_len = %d\n", DirectoryEntry->rec_len));
DbgPrint((DPRINT_FILESYSTEM, "name_len = %d\n", DirectoryEntry->name_len));
DbgPrint((DPRINT_FILESYSTEM, "file_type = %d\n", DirectoryEntry->file_type));
DbgPrint((DPRINT_FILESYSTEM, "name = "));
for (CurrentOffset=0; CurrentOffset<DirectoryEntry->name_len; CurrentOffset++)
{
DbgPrint((DPRINT_FILESYSTEM, "%c", DirectoryEntry->name[CurrentOffset]));
}
DbgPrint((DPRINT_FILESYSTEM, "\n"));
return TRUE;
}
CurrentOffset += CurrentDirectoryEntry->rec_len;
}
return FALSE;
}
/*
* Ext2ReadFile()
* Reads BytesToRead from open file and
* returns the number of bytes read in BytesRead
*/
BOOLEAN Ext2ReadFile(FILE *FileHandle, ULONGLONG BytesToRead, ULONGLONG* BytesRead, PVOID Buffer)
{
PEXT2_FILE_INFO Ext2FileInfo = (PEXT2_FILE_INFO)FileHandle;
ULONG BlockNumber;
ULONG BlockNumberIndex;
ULONG OffsetInBlock;
ULONG LengthInBlock;
ULONG NumberOfBlocks;
DbgPrint((DPRINT_FILESYSTEM, "Ext2ReadFile() BytesToRead = %d Buffer = 0x%x\n", (ULONG)BytesToRead, Buffer));
if (BytesRead != NULL)
{
*BytesRead = 0;
}
// Make sure we have the block pointer list if we need it
if (Ext2FileInfo->FileBlockList == NULL)
{
// Block pointer list is NULL
// so this better be a fast symbolic link or else
if (((Ext2FileInfo->Inode.i_mode & EXT2_S_IFMT) != EXT2_S_IFLNK) ||
(Ext2FileInfo->FileSize > FAST_SYMLINK_MAX_NAME_SIZE))
{
FileSystemError("Block pointer list is NULL and file is not a fast symbolic link.");
return FALSE;
}
}
//
// If they are trying to read past the
// end of the file then return success
// with BytesRead == 0
//
if (Ext2FileInfo->FilePointer >= Ext2FileInfo->FileSize)
{
return TRUE;
}
//
// If they are trying to read more than there is to read
// then adjust the amount to read
//
if ((Ext2FileInfo->FilePointer + BytesToRead) > Ext2FileInfo->FileSize)
{
BytesToRead = (Ext2FileInfo->FileSize - Ext2FileInfo->FilePointer);
}
// Check if this is a fast symbolic link
// if so then the read is easy
if (((Ext2FileInfo->Inode.i_mode & EXT2_S_IFMT) == EXT2_S_IFLNK) &&
(Ext2FileInfo->FileSize <= FAST_SYMLINK_MAX_NAME_SIZE))
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -