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

📄 ext2.c

📁 这是一个开放源代码的与WINNT/WIN2K/WIN2003兼容的操作系统
💻 C
📖 第 1 页 / 共 3 页
字号:
/*
 *  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 + -