From d31a52e4237302943e35c778cad013402443305e Mon Sep 17 00:00:00 2001 From: Art Yerkes Date: Thu, 13 Jan 2005 01:51:33 +0000 Subject: [PATCH 1/8] ext2 import by filip navara with minor editing by arty. svn path=/branches/ext2/; revision=13009 --- reactos/drivers/fs/ext2/attr.c | 136 - reactos/drivers/fs/ext2/blockdev.c | 155 -- reactos/drivers/fs/ext2/dir.c | 338 --- reactos/drivers/fs/ext2/ext2fs.h | 289 -- reactos/drivers/fs/ext2/file.c | 61 - reactos/drivers/fs/ext2/inc/errmsg.h | 68 + reactos/drivers/fs/ext2/inc/ext2_fs.h | 615 +++++ reactos/drivers/fs/ext2/inc/ext2fsd.h | 250 ++ reactos/drivers/fs/ext2/inc/ext2metadata.h | 115 + reactos/drivers/fs/ext2/inc/protos.h | 782 ++++++ reactos/drivers/fs/ext2/inc/resource.h | 16 + reactos/drivers/fs/ext2/inc/struct.h | 674 +++++ reactos/drivers/fs/ext2/inode.c | 148 - reactos/drivers/fs/ext2/makefile | 58 +- reactos/drivers/fs/ext2/quota.c | 49 - reactos/drivers/fs/ext2/rw.c | 219 -- reactos/drivers/fs/ext2/security.c | 41 - reactos/drivers/fs/ext2/src/.cvsignore | 9 + reactos/drivers/fs/ext2/src/DiskIO.c | 215 ++ reactos/drivers/fs/ext2/src/cleanup.c | 400 +++ reactos/drivers/fs/ext2/src/close.c | 459 ++++ reactos/drivers/fs/ext2/src/create.c | 1681 ++++++++++++ reactos/drivers/fs/ext2/src/devcntrl.c | 210 ++ reactos/drivers/fs/ext2/src/dircntrl.c | 937 +++++++ reactos/drivers/fs/ext2/src/ext2.rc | 116 + reactos/drivers/fs/ext2/src/ext2init.c | 381 +++ reactos/drivers/fs/ext2/src/fastio.c | 1757 ++++++++++++ reactos/drivers/fs/ext2/src/fileinfo.c | 1125 ++++++++ reactos/drivers/fs/ext2/src/flush.c | 350 +++ reactos/drivers/fs/ext2/src/fsctrl.c | 944 +++++++ reactos/drivers/fs/ext2/src/io.c | 543 ++++ reactos/drivers/fs/ext2/src/metadata.c | 2837 ++++++++++++++++++++ reactos/drivers/fs/ext2/src/misc.c | 2116 +++++++++++++++ reactos/drivers/fs/ext2/src/read.c | 1476 ++++++++++ reactos/drivers/fs/ext2/src/shutdown.c | 211 ++ reactos/drivers/fs/ext2/src/volinfo.c | 339 +++ reactos/drivers/fs/ext2/src/write.c | 1483 ++++++++++ reactos/drivers/fs/ext2/super.c | 202 -- 38 files changed, 20152 insertions(+), 1653 deletions(-) delete mode 100644 reactos/drivers/fs/ext2/attr.c delete mode 100644 reactos/drivers/fs/ext2/blockdev.c delete mode 100644 reactos/drivers/fs/ext2/dir.c delete mode 100644 reactos/drivers/fs/ext2/ext2fs.h delete mode 100644 reactos/drivers/fs/ext2/file.c create mode 100644 reactos/drivers/fs/ext2/inc/errmsg.h create mode 100644 reactos/drivers/fs/ext2/inc/ext2_fs.h create mode 100644 reactos/drivers/fs/ext2/inc/ext2fsd.h create mode 100644 reactos/drivers/fs/ext2/inc/ext2metadata.h create mode 100644 reactos/drivers/fs/ext2/inc/protos.h create mode 100644 reactos/drivers/fs/ext2/inc/resource.h create mode 100644 reactos/drivers/fs/ext2/inc/struct.h delete mode 100644 reactos/drivers/fs/ext2/inode.c delete mode 100644 reactos/drivers/fs/ext2/quota.c delete mode 100644 reactos/drivers/fs/ext2/rw.c delete mode 100644 reactos/drivers/fs/ext2/security.c create mode 100644 reactos/drivers/fs/ext2/src/.cvsignore create mode 100644 reactos/drivers/fs/ext2/src/DiskIO.c create mode 100644 reactos/drivers/fs/ext2/src/cleanup.c create mode 100644 reactos/drivers/fs/ext2/src/close.c create mode 100644 reactos/drivers/fs/ext2/src/create.c create mode 100644 reactos/drivers/fs/ext2/src/devcntrl.c create mode 100644 reactos/drivers/fs/ext2/src/dircntrl.c create mode 100644 reactos/drivers/fs/ext2/src/ext2.rc create mode 100644 reactos/drivers/fs/ext2/src/ext2init.c create mode 100644 reactos/drivers/fs/ext2/src/fastio.c create mode 100644 reactos/drivers/fs/ext2/src/fileinfo.c create mode 100644 reactos/drivers/fs/ext2/src/flush.c create mode 100644 reactos/drivers/fs/ext2/src/fsctrl.c create mode 100644 reactos/drivers/fs/ext2/src/io.c create mode 100644 reactos/drivers/fs/ext2/src/metadata.c create mode 100644 reactos/drivers/fs/ext2/src/misc.c create mode 100644 reactos/drivers/fs/ext2/src/read.c create mode 100644 reactos/drivers/fs/ext2/src/shutdown.c create mode 100644 reactos/drivers/fs/ext2/src/volinfo.c create mode 100644 reactos/drivers/fs/ext2/src/write.c delete mode 100644 reactos/drivers/fs/ext2/super.c diff --git a/reactos/drivers/fs/ext2/attr.c b/reactos/drivers/fs/ext2/attr.c deleted file mode 100644 index 9992d7a9022..00000000000 --- a/reactos/drivers/fs/ext2/attr.c +++ /dev/null @@ -1,136 +0,0 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS kernel - * FILE: services/fs/ext2/attr.c - * PURPOSE: Set/Get file attributes support - * PROGRAMMER: David Welch (welch@cwcom.net) - * UPDATE HISTORY: - */ - -/* INCLUDES *****************************************************************/ - -#include -#include -#include - -//#define NDEBUG -#include - -#include "ext2fs.h" - -/* FUNCTIONS ****************************************************************/ - -NTSTATUS STDCALL -Ext2SetInformation(PDEVICE_OBJECT DeviceObject, PIRP Irp) -{ - DPRINT("Ext2SetInformation(DeviceObject %x Irp %x)\n",DeviceObject,Irp); - - Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED; - Irp->IoStatus.Information = 0; - IoCompleteRequest(Irp, - IO_NO_INCREMENT); - - return(STATUS_UNSUCCESSFUL); -} - -NTSTATUS STDCALL -Ext2QueryInformation(PDEVICE_OBJECT DeviceObject, PIRP Irp) -{ - NTSTATUS Status; - PIO_STACK_LOCATION Param; - PFILE_OBJECT FileObject; - PDEVICE_EXTENSION DeviceExt; - ULONG Length; - PFILE_BASIC_INFORMATION PFileBasicInformation; - PFILE_STANDARD_INFORMATION PFileStandardInformation; - PFILE_INTERNAL_INFORMATION PFileInternalInformation; - PFILE_EA_INFORMATION PFileEaInformation; - PFILE_ACCESS_INFORMATION PFileAccessInformation; - PFILE_NAME_INFORMATION PFileNameInformation; - PFILE_POSITION_INFORMATION PFilePositionInformation; - PVOID Buffer; - - DPRINT("Ext2QueryInformation(DeviceObject %x Irp %x)\n", DeviceObject, Irp); - - Param = IoGetCurrentIrpStackLocation(Irp); - FileObject = Param->FileObject; - DeviceExt = DeviceObject->DeviceExtension; - Length = Param->Parameters.QueryFile.Length; - Buffer = Irp->AssociatedIrp.SystemBuffer; - - switch (Param->Parameters.QueryFile.FileInformationClass) - { - case FileDirectoryInformation: - case FileFullDirectoryInformation: - case FileBothDirectoryInformation: - Status = STATUS_NOT_IMPLEMENTED; - break; - - case FileBasicInformation: - PFileBasicInformation = (PFILE_BASIC_INFORMATION)Buffer; - memset(PFileBasicInformation, 0, sizeof(FILE_BASIC_INFORMATION)); - Status = STATUS_SUCCESS; - break; - - case FileStandardInformation: - PFileStandardInformation = (PFILE_STANDARD_INFORMATION)Buffer; - memset(PFileStandardInformation, 0, sizeof(FILE_STANDARD_INFORMATION)); - Status = STATUS_SUCCESS; - break; - - case FileInternalInformation: - PFileInternalInformation = (PFILE_INTERNAL_INFORMATION)Buffer; - memset(PFileInternalInformation, 0, sizeof(FILE_INTERNAL_INFORMATION)); - Status = STATUS_SUCCESS; - break; - - case FileEaInformation: - PFileEaInformation = (PFILE_EA_INFORMATION)Buffer; - memset(PFileEaInformation, 0, sizeof(FILE_EA_INFORMATION)); - PFileEaInformation->EaSize = 0; - Status = STATUS_SUCCESS; - break; - - case FileAccessInformation: - PFileAccessInformation = (PFILE_ACCESS_INFORMATION)Buffer; - memset(PFileAccessInformation, 0, sizeof(FILE_ACCESS_INFORMATION)); - PFileAccessInformation->AccessFlags = 0; - Status = STATUS_SUCCESS; - break; - - case FileNameInformation: - PFileNameInformation = (PFILE_NAME_INFORMATION)Buffer; - memset(PFileNameInformation, 0, sizeof(FILE_NAME_INFORMATION)); - Status = STATUS_SUCCESS; - break; - - case FilePositionInformation: - PFilePositionInformation = (PFILE_POSITION_INFORMATION)Buffer; - memcpy(PFilePositionInformation, - &FileObject->CurrentByteOffset, - sizeof(FileObject->CurrentByteOffset)); - Status = STATUS_SUCCESS; - break; - - case FileRenameInformation: - Status = STATUS_NOT_IMPLEMENTED; - break; - - default: - Status = STATUS_NOT_SUPPORTED; - } - - - - - Irp->IoStatus.Status = Status; - if (NT_SUCCESS(Status)) - Irp->IoStatus.Information = - Param->Parameters.QueryFile.Length - Length; - else - Irp->IoStatus.Information = 0; - IoCompleteRequest(Irp, - IO_NO_INCREMENT); - - return(Status); -} diff --git a/reactos/drivers/fs/ext2/blockdev.c b/reactos/drivers/fs/ext2/blockdev.c deleted file mode 100644 index c64ae87fa62..00000000000 --- a/reactos/drivers/fs/ext2/blockdev.c +++ /dev/null @@ -1,155 +0,0 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS kernel - * FILE: services/fs/ext2/blockdev.c - * PURPOSE: Temporary sector reading support - * PROGRAMMER: David Welch (welch@cwcom.net) - * UPDATE HISTORY: - */ - -/* INCLUDES *****************************************************************/ - -#include - -//#define NDEBUG -#include - -#include "ext2fs.h" - -/* FUNCTIONS ***************************************************************/ - -BOOLEAN -Ext2ReadSectors(IN PDEVICE_OBJECT pDeviceObject, - IN ULONG DiskSector, - IN ULONG SectorCount, - IN PVOID Buffer) -{ - LARGE_INTEGER sectorNumber; - PIRP irp; - IO_STATUS_BLOCK ioStatus; - KEVENT event; - NTSTATUS status; - ULONG sectorSize; - int j; - - DPRINT("VFATReadSector(pDeviceObject %x, DiskSector %d, Buffer %x)\n", - pDeviceObject,DiskSector,Buffer); - - sectorNumber.u.HighPart = 0; - sectorNumber.u.LowPart = DiskSector * BLOCKSIZE; - - DPRINT("DiskSector:%ld BLKSZ:%ld sectorNumber:%ld:%ld\n", - (unsigned long) DiskSector, - (unsigned long) BLOCKSIZE, - (unsigned long) sectorNumber.u.HighPart, - (unsigned long) sectorNumber.u.LowPart); - - KeInitializeEvent(&event, NotificationEvent, FALSE); - - sectorSize = BLOCKSIZE*SectorCount; - - - DPRINT("Building synchronous FSD Request...\n"); - irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ, - pDeviceObject, - Buffer, - sectorSize, - §orNumber, - &event, - &ioStatus ); - - if (!irp) - { - DbgPrint("READ failed!!!\n"); - return FALSE; - } - - DPRINT("Calling IO Driver...\n"); - status = IoCallDriver(pDeviceObject, irp); - - DPRINT("Waiting for IO Operation...\n"); - if (status == STATUS_PENDING) - { - KeWaitForSingleObject(&event, - Suspended, - KernelMode, - FALSE, - NULL); - DPRINT("Getting IO Status...\n"); - status = ioStatus.Status; - } - - if (!NT_SUCCESS(status)) - { - DbgPrint("IO failed!!! Error code: %d(%x)\n", status, status); - return FALSE; - } - - return TRUE; -} - -BOOLEAN VFATWriteSectors(IN PDEVICE_OBJECT pDeviceObject, - IN ULONG DiskSector, - IN ULONG SectorCount, - IN UCHAR* Buffer) -{ - LARGE_INTEGER sectorNumber; - PIRP irp; - IO_STATUS_BLOCK ioStatus; - KEVENT event; - NTSTATUS status; - ULONG sectorSize; - PULONG mbr; - int j; - - DPRINT("VFATWriteSector(pDeviceObject %x, DiskSector %d, Buffer %x)\n", - pDeviceObject,DiskSector,Buffer); - - sectorNumber.u.HighPart = 0; - sectorNumber.u.LowPart = DiskSector * BLOCKSIZE; - - KeInitializeEvent(&event, NotificationEvent, FALSE); - - sectorSize = BLOCKSIZE*SectorCount; - - - DPRINT("Building synchronous FSD Request...\n"); - irp = IoBuildSynchronousFsdRequest(IRP_MJ_WRITE, - pDeviceObject, - Buffer, - sectorSize, - §orNumber, - &event, - &ioStatus ); - - if (!irp) { - DbgPrint("WRITE failed!!!\n"); - return FALSE; - } - - DPRINT("Calling IO Driver...\n"); - status = IoCallDriver(pDeviceObject, - irp); - - DPRINT("Waiting for IO Operation...\n"); - if (status == STATUS_PENDING) { - KeWaitForSingleObject(&event, - Suspended, - KernelMode, - FALSE, - NULL); - DPRINT("Getting IO Status...\n"); - status = ioStatus.Status; - } - - if (!NT_SUCCESS(status)) { - DbgPrint("IO failed!!! Error code: %d(%x)\n", status, status); - return FALSE; - } - - - ExFreePool(mbr); - DPRINT("Block request succeeded\n"); - return TRUE; -} - diff --git a/reactos/drivers/fs/ext2/dir.c b/reactos/drivers/fs/ext2/dir.c deleted file mode 100644 index f40d07b6ab0..00000000000 --- a/reactos/drivers/fs/ext2/dir.c +++ /dev/null @@ -1,338 +0,0 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS kernel - * FILE: services/fs/ext2/dir.c - * PURPOSE: ext2 filesystem - * PROGRAMMER: David Welch (welch@cwcom.net) - * UPDATE HISTORY: - */ - -/* INCLUDES *****************************************************************/ - -#include -#include -#include - -//#define NDEBUG -#include - -#include "ext2fs.h" - -/* FUNCTIONS *****************************************************************/ - - -static VOID Ext2ConvertName(PWSTR Out, PCH In, ULONG Len) -{ - ULONG i; - - for (i=0; iinode, - &inode); - - switch (IoStack->Parameters.QueryDirectory.FileInformationClass) - { - case FileNamesInformation: - FNI = (PFILE_NAMES_INFORMATION)Buffer; - FNI->NextEntryOffset = sizeof(FileDirectoryInformation) + - dir_entry->name_len + 1; - FNI->FileNameLength = dir_entry->name_len; - Ext2ConvertName(FNI->FileName, dir_entry->name, dir_entry->name_len); - Buffer = Buffer + FNI->NextEntryOffset; - break; - - case FileDirectoryInformation: - FDI = (PFILE_DIRECTORY_INFORMATION)Buffer; - FDI->NextEntryOffset = sizeof(FileDirectoryInformation) + - dir_entry->name_len + 1; - FDI->FileIndex = FileIndex; -// FDI->CreationTime = 0; -// FDI->LastAccessTime = 0; -// FDI->LastWriteTime = 0; -// FDI->ChangeTime = 0; - FDI->AllocationSize.QuadPart = FDI->EndOfFile.QuadPart = inode.i_size; - FDI->FileAttributes = 0; - FDI->FileNameLength = dir_entry->name_len; - Ext2ConvertName(FDI->FileName, dir_entry->name, dir_entry->name_len); - Buffer = Buffer + FDI->NextEntryOffset; - break; - - case FileBothDirectoryInformation: - FBI = (PFILE_BOTH_DIRECTORY_INFORMATION)Buffer; - FBI->NextEntryOffset = sizeof(FileBothDirectoryInformation) + - dir_entry->name_len + 1; - FBI->FileIndex = FileIndex; - FBI->AllocationSize.QuadPart = FBI->EndOfFile.QuadPart = inode.i_size; - FBI->FileAttributes = 0; - FBI->FileNameLength = dir_entry->name_len; - Ext2ConvertName(FBI->FileName, dir_entry->name, dir_entry->name_len); - memset(FBI->ShortName, 0, sizeof(FBI->ShortName)); - Buffer = Buffer + FBI->NextEntryOffset; - break; - - default: - UNIMPLEMENTED; - } - return(Buffer); -} - - -NTSTATUS Ext2QueryDirectory(PDEVICE_EXTENSION DeviceExt, - PEXT2_FCB Fcb, - PIRP Irp, - PIO_STACK_LOCATION IoStack) -{ - ULONG Max; - ULONG i; - ULONG StartIndex; - PVOID Buffer = NULL; - struct ext2_dir_entry dir_entry; - - Buffer = Irp->UserBuffer; - DPRINT("Buffer %x\n",Buffer); - DPRINT("IoStack->Flags %x\n",IoStack->Flags); - - if (IoStack->Flags & SL_RETURN_SINGLE_ENTRY) - { - Max = 1; - } - else - { - UNIMPLEMENTED; - } - - DPRINT("Buffer->FileIndex %d\n", - ((PFILE_DIRECTORY_INFORMATION)Buffer)->FileIndex); - if (IoStack->Flags & SL_INDEX_SPECIFIED) - { - StartIndex = ((PFILE_DIRECTORY_INFORMATION)Buffer)->FileIndex; - } - else - { - StartIndex = 0; - } - - if (IoStack->Flags & SL_RESTART_SCAN) - { - StartIndex = 0; - } - - DPRINT("StartIndex %d\n",StartIndex); - - for (i=0; iinode,"*",&dir_entry,&StartIndex)) - { - ((PFILE_DIRECTORY_INFORMATION)Buffer)->NextEntryOffset = 0; - return(STATUS_NO_MORE_FILES); - } - Buffer = Ext2ProcessDirEntry(DeviceExt, - &dir_entry, - IoStack, - Buffer, - StartIndex); - } - return(STATUS_SUCCESS); -} - -NTSTATUS STDCALL -Ext2DirectoryControl(PDEVICE_OBJECT DeviceObject, PIRP Irp) -{ - PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp); - PFILE_OBJECT FileObject = Stack->FileObject; - PEXT2_FCB Fcb = (PVOID)FileObject->FsContext; - NTSTATUS Status; - PDEVICE_EXTENSION DeviceExt; - - DPRINT("Ext2DirectoryControl(DeviceObject %x, Irp %x)\n",DeviceObject,Irp); - - DeviceExt = DeviceObject->DeviceExtension; - - switch (Stack->MinorFunction) - { - case IRP_MN_QUERY_DIRECTORY: - Status = Ext2QueryDirectory(DeviceExt, Fcb, Irp, Stack); - break; - - default: - Status = STATUS_UNSUCCESSFUL; - } - - Irp->IoStatus.Status = Status; - Irp->IoStatus.Information = 0; - - IoCompleteRequest(Irp, IO_NO_INCREMENT); - return(Status); -} - -BOOL Ext2ScanDir(PDEVICE_EXTENSION DeviceExt, - struct ext2_inode* dir, - PCH filename, - struct ext2_dir_entry* ret, - PULONG StartIndex) -{ - ULONG i; - char* buffer; - ULONG offset; - char name[255]; - struct ext2_dir_entry* current; - ULONG block; - BOOL b; - - DPRINT("Ext2ScanDir(dir %x, filename %s, ret %x)\n",dir,filename,ret); - - buffer = ExAllocatePool(NonPagedPool, BLOCKSIZE); - - for (i=0; i<((*StartIndex)/BLOCKSIZE); i++); - for (; (block = Ext2BlockMap(DeviceExt, dir, i)) != 0; i++) - { - DPRINT("block %d\n",block); - b = Ext2ReadSectors(DeviceExt->StorageDevice, - block, - 1, - buffer); - if (!b) - { - DbgPrint("ext2fs:%s:%d: Disk io failed\n", __FILE__, __LINE__); - return(FALSE); - } - - offset = (*StartIndex)%BLOCKSIZE; - while (offset < BLOCKSIZE) - { - current = &buffer[offset]; - - strncpy(name,current->name,current->name_len); - name[current->name_len]=0; - - DPRINT("Scanning offset %d inode %d name %s\n", - offset,current->inode,name); - - DPRINT("Comparing %s %s\n",name,filename); - if (strcmp(name,filename)==0 || strcmp(filename,"*")==0) - { - DPRINT("Match found\n"); - *StartIndex = (i*BLOCKSIZE) + offset + current->rec_len; - memcpy(ret,current,sizeof(struct ext2_dir_entry)); - ExFreePool(buffer); - return(TRUE); - } - - offset = offset + current->rec_len; - ASSERT(current->rec_len != 0); - DPRINT("offset %d\n",offset); - } - DPRINT("Onto next block\n"); - } - DPRINT("No match\n"); - ExFreePool(buffer); - return(FALSE); -} - -void unicode_to_ansi(PCH StringA, PWSTR StringW) -{ - while((*StringW)!=0) - { - *StringA = *StringW; - StringA++; - StringW++; - } - *StringA = 0; -} - -NTSTATUS Ext2OpenFile(PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject, - PWSTR FileName) -/* - * FUNCTION: Opens a file - */ -{ - EXT2_INODE parent_inode; - struct ext2_dir_entry entry; - char name[255]; - ULONG current_inode = 2; - char* current_segment; - PEXT2_FCB Fcb; - ULONG StartIndex = 0; - - DPRINT("Ext2OpenFile(DeviceExt %x, FileObject %x, FileName %S)\n", - DeviceExt,FileObject,FileName); - - Fcb = ExAllocatePool(NonPagedPool, sizeof(EXT2_FCB)); - - unicode_to_ansi(name,FileName); - DPRINT("name %s\n",name); - DPRINT("strtok %x\n",strtok); - current_segment = strtok(name,"\\"); - DPRINT("current_segment %x\n", current_segment); - while (current_segment!=NULL) - { - Ext2LoadInode(DeviceExt, - current_inode, - &parent_inode); - if (!Ext2ScanDir(DeviceExt, - parent_inode.inode, - current_segment, - &entry, - &StartIndex)) - { - Ext2ReleaseInode(DeviceExt, - &parent_inode); - ExFreePool(Fcb); - return(STATUS_UNSUCCESSFUL); - } - current_inode = entry.inode; - current_segment = strtok(NULL,"\\"); - StartIndex = 0; - Ext2ReleaseInode(DeviceExt, - &parent_inode); - } - DPRINT("Found file\n"); - - Fcb->inode = current_inode; - CcRosInitializeFileCache(FileObject, &Fcb->Bcb, PAGE_SIZE*3); - FileObject->FsContext = Fcb; - - return(STATUS_SUCCESS); -} - -NTSTATUS STDCALL -Ext2Create(PDEVICE_OBJECT DeviceObject, PIRP Irp) -{ - PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp); - PFILE_OBJECT FileObject = Stack->FileObject; - NTSTATUS Status; - PDEVICE_EXTENSION DeviceExt; - - DPRINT("Ext2Create(DeviceObject %x, Irp %x)\n",DeviceObject,Irp); - - DeviceExt = DeviceObject->DeviceExtension; - Status = Ext2OpenFile(DeviceExt,FileObject,FileObject->FileName.Buffer); - - Irp->IoStatus.Status = Status; - Irp->IoStatus.Information = 0; - - IoCompleteRequest(Irp, IO_NO_INCREMENT); - return(Status); -} diff --git a/reactos/drivers/fs/ext2/ext2fs.h b/reactos/drivers/fs/ext2/ext2fs.h deleted file mode 100644 index 9d18ae790f3..00000000000 --- a/reactos/drivers/fs/ext2/ext2fs.h +++ /dev/null @@ -1,289 +0,0 @@ -#include -#include - -BOOLEAN Ext2ReadSectors(IN PDEVICE_OBJECT pDeviceObject, - IN ULONG DiskSector, - IN ULONG SectorCount, - IN PVOID Buffer); - -#define BLOCKSIZE (1024) - -struct ext2_super_block { - ULONG s_inodes_count; /* Inodes count */ - ULONG s_blocks_count; /* Blocks count */ - ULONG s_r_blocks_count; /* Reserved blocks count */ - ULONG s_free_blocks_count; /* Free blocks count */ - ULONG s_free_inodes_count; /* Free inodes count */ - ULONG s_first_data_block; /* First Data Block */ - ULONG s_log_block_size; /* Block size */ - LONG s_log_frag_size; /* Fragment size */ - ULONG s_blocks_per_group; /* # Blocks per group */ - ULONG s_frags_per_group; /* # Fragments per group */ - ULONG s_inodes_per_group; /* # Inodes per group */ - ULONG s_mtime; /* Mount time */ - ULONG s_wtime; /* Write time */ - USHORT s_mnt_count; /* Mount count */ - SHORT s_max_mnt_count; /* Maximal mount count */ - USHORT s_magic; /* Magic signature */ - USHORT s_state; /* File system state */ - USHORT s_errors; /* Behaviour when detecting errors */ - USHORT s_minor_rev_level; /* minor revision level */ - ULONG s_lastcheck; /* time of last check */ - ULONG s_checkinterval; /* max. time between checks */ - ULONG s_creator_os; /* OS */ - ULONG s_rev_level; /* Revision level */ - USHORT s_def_resuid; /* Default uid for reserved blocks */ - USHORT s_def_resgid; /* Default gid for reserved blocks */ - /* - * These fields are for EXT2_DYNAMIC_REV superblocks only. - * - * Note: the difference between the compatible feature set and - * the incompatible feature set is that if there is a bit set - * in the incompatible feature set that the kernel doesn't - * know about, it should refuse to mount the filesystem. - * - * e2fsck's requirements are more strict; if it doesn't know - * about a feature in either the compatible or incompatible - * feature set, it must abort and not try to meddle with - * things it doesn't understand... - */ - ULONG s_first_ino; /* First non-reserved inode */ - USHORT s_inode_size; /* size of inode structure */ - USHORT s_block_group_nr; /* block group # of this superblock */ - ULONG s_feature_compat; /* compatible feature set */ - ULONG s_feature_incompat; /* incompatible feature set */ - ULONG s_feature_ro_compat; /* readonly-compatible feature set */ - ULONG s_reserved[230]; /* Padding to the end of the block */ -}; - -/* - * Codes for operating systems - */ -#define EXT2_OS_LINUX 0 -#define EXT2_OS_HURD 1 -#define EXT2_OS_MASIX 2 -#define EXT2_OS_FREEBSD 3 -#define EXT2_OS_LITES 4 - -/* - * Revision levels - */ -#define EXT2_GOOD_OLD_REV 0 /* The good old (original) format */ -#define EXT2_DYNAMIC_REV 1 /* V2 format w/ dynamic inode sizes */ - -#define EXT2_CURRENT_REV EXT2_GOOD_OLD_REV -#define EXT2_MAX_SUPP_REV EXT2_DYNAMIC_REV - -/* - * The second extended file system magic number - */ -#define EXT2_SUPER_MAGIC 0xEF53 - -/* - * Constants relative to the data blocks - */ -#define EXT2_NDIR_BLOCKS 12 -#define EXT2_IND_BLOCK EXT2_NDIR_BLOCKS -#define EXT2_DIND_BLOCK (EXT2_IND_BLOCK + 1) -#define EXT2_TIND_BLOCK (EXT2_DIND_BLOCK + 1) -#define EXT2_N_BLOCKS (EXT2_TIND_BLOCK + 1) - - -/* - * Structure of an inode on the disk - */ -struct ext2_inode { - USHORT i_mode; /* File mode */ - USHORT i_uid; /* Owner Uid */ - ULONG i_size; /* Size in bytes */ - ULONG i_atime; /* Access time */ - ULONG i_ctime; /* Creation time */ - ULONG i_mtime; /* Modification time */ - ULONG i_dtime; /* Deletion Time */ - USHORT i_gid; /* Group Id */ - USHORT i_links_count; /* Links count */ - ULONG i_blocks; /* Blocks count */ - ULONG i_flags; /* File flags */ - union { - struct { - ULONG l_i_reserved1; - } linux1; - struct { - ULONG h_i_translator; - } hurd1; - struct { - ULONG m_i_reserved1; - } masix1; - } osd1; /* OS dependent 1 */ - ULONG i_block[EXT2_N_BLOCKS];/* Pointers to blocks */ - ULONG i_version; /* File version (for NFS) */ - ULONG i_file_acl; /* File ACL */ - ULONG i_dir_acl; /* Directory ACL */ - ULONG i_faddr; /* Fragment address */ - union { - struct { - UCHAR l_i_frag; /* Fragment number */ - UCHAR l_i_fsize; /* Fragment size */ - USHORT i_pad1; - ULONG l_i_reserved2[2]; - } linux2; - struct { - UCHAR h_i_frag; /* Fragment number */ - UCHAR h_i_fsize; /* Fragment size */ - USHORT h_i_mode_high; - USHORT h_i_uid_high; - USHORT h_i_gid_high; - ULONG h_i_author; - } hurd2; - struct { - UCHAR m_i_frag; /* Fragment number */ - UCHAR m_i_fsize; /* Fragment size */ - USHORT m_pad1; - ULONG m_i_reserved2[2]; - } masix2; - } osd2; /* OS dependent 2 */ -}; - -#if defined(__KERNEL__) || defined(__linux__) -#define i_reserved1 osd1.linux1.l_i_reserved1 -#define i_frag osd2.linux2.l_i_frag -#define i_fsize osd2.linux2.l_i_fsize -#define i_reserved2 osd2.linux2.l_i_reserved2 -#endif - -#ifdef __hurd__ -#define i_translator osd1.hurd1.h_i_translator -#define i_frag osd2.hurd2.h_i_frag; -#define i_fsize osd2.hurd2.h_i_fsize; -#define i_uid_high osd2.hurd2.h_i_uid_high -#define i_gid_high osd2.hurd2.h_i_gid_high -#define i_author osd2.hurd2.h_i_author -#endif - -#ifdef __masix__ -#define i_reserved1 osd1.masix1.m_i_reserved1 -#define i_frag osd2.masix2.m_i_frag -#define i_fsize osd2.masix2.m_i_fsize -#define i_reserved2 osd2.masix2.m_i_reserved2 -#endif - -/* - * Constants relative to the data blocks - */ -#define EXT2_NDIR_BLOCKS 12 -#define EXT2_IND_BLOCK EXT2_NDIR_BLOCKS -#define EXT2_DIND_BLOCK (EXT2_IND_BLOCK + 1) -#define EXT2_TIND_BLOCK (EXT2_DIND_BLOCK + 1) -#define EXT2_N_BLOCKS (EXT2_TIND_BLOCK + 1) - -/* - * Inode flags - */ -#define EXT2_SECRM_FL 0x00000001 /* Secure deletion */ -#define EXT2_UNRM_FL 0x00000002 /* Undelete */ -#define EXT2_COMPR_FL 0x00000004 /* Compress file */ -#define EXT2_SYNC_FL 0x00000008 /* Synchronous updates */ -#define EXT2_IMMUTABLE_FL 0x00000010 /* Immutable file */ -#define EXT2_APPEND_FL 0x00000020 /* writes to file may only append */ -#define EXT2_NODUMP_FL 0x00000040 /* do not dump file */ -#define EXT2_RESERVED_FL 0x80000000 /* reserved for ext2 lib */ - - -/* - * Structure of a blocks group descriptor - */ -struct ext2_group_desc -{ - ULONG bg_block_bitmap; /* Blocks bitmap block */ - ULONG bg_inode_bitmap; /* Inodes bitmap block */ - ULONG bg_inode_table; /* Inodes table block */ - USHORT bg_free_blocks_count; /* Free blocks count */ - USHORT bg_free_inodes_count; /* Free inodes count */ - USHORT bg_used_dirs_count; /* Directories count */ - USHORT bg_pad; - ULONG bg_reserved[3]; -}; - -#define EXT2_NAME_LEN 255 - -struct ext2_dir_entry { - ULONG inode; /* Inode number */ - USHORT rec_len; /* Directory entry length */ - USHORT name_len; /* Name length */ - char name[EXT2_NAME_LEN]; /* File name */ -}; - -typedef struct -{ - PDEVICE_OBJECT StorageDevice; - struct ext2_super_block* superblock; - PFILE_OBJECT FileObject; - PBCB Bcb; -} DEVICE_EXTENSION, *PDEVICE_EXTENSION; - -typedef struct _EXT2_GROUP_DESC -{ - ERESOURCE Lock; - struct ext2_group_desc* desc; - PCACHE_SEGMENT CacheSeg; - PVOID BaseAddress; -} EXT2_GROUP_DESC, *PEXT2_GROUP_DESC; - -PEXT2_GROUP_DESC Ext2LoadGroup(PDEVICE_EXTENSION DeviceExt, - ULONG BlockGrp); -VOID Ext2ReleaseGroup(PDEVICE_EXTENSION DeviceExt, - PEXT2_GROUP_DESC GrpDesc); - -VOID Ext2ReadInode(PDEVICE_EXTENSION DeviceExt, - ULONG ino, - struct ext2_inode* inode); -struct ext2_group_desc* Ext2LoadGroupDesc(PDEVICE_EXTENSION DeviceExt, - ULONG block_group); - -typedef struct _EXT2_INODE -{ - struct ext2_inode* inode; - PVOID BaseAddress; - PCACHE_SEGMENT CacheSeg; -} EXT2_INODE, *PEXT2_INODE; - -typedef struct _EXT2_FCB -{ - ULONG inode; - EXT2_INODE i; - PBCB Bcb; -} EXT2_FCB, *PEXT2_FCB; - -ULONG Ext2BlockMap(PDEVICE_EXTENSION DeviceExt, - struct ext2_inode* inode, - ULONG offset); -NTSTATUS Ext2OpenFile(PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject, - PWSTR FileName); -NTSTATUS Ext2ReadFile(PDEVICE_EXTENSION DeviceExt, - PFILE_OBJECT FileObject, - PVOID Buffer, - ULONG Length, - LARGE_INTEGER Offset); -NTSTATUS STDCALL Ext2Create(PDEVICE_OBJECT DeviceObject, PIRP Irp); -NTSTATUS STDCALL Ext2DirectoryControl(PDEVICE_OBJECT DeviceObject, PIRP Irp); -NTSTATUS STDCALL Ext2QueryQuota(PDEVICE_OBJECT DeviceObject, PIRP Irp); -NTSTATUS STDCALL Ext2SetQuota(PDEVICE_OBJECT DeviceObject, PIRP Irp); -NTSTATUS STDCALL Ext2SetSecurity(PDEVICE_OBJECT DeviceObject, PIRP Irp); -NTSTATUS STDCALL Ext2QuerySecurity(PDEVICE_OBJECT DeviceObject, PIRP Irp); -NTSTATUS STDCALL Ext2SetInformation(PDEVICE_OBJECT DeviceObject, PIRP Irp); -NTSTATUS STDCALL Ext2QueryInformation(PDEVICE_OBJECT DeviceObject, PIRP Irp); -NTSTATUS STDCALL Ext2Read(PDEVICE_OBJECT DeviceObject, PIRP Irp); -NTSTATUS STDCALL Ext2Write(PDEVICE_OBJECT DeviceObject, PIRP Irp); -NTSTATUS STDCALL Ext2Cleanup(PDEVICE_OBJECT DeviceObject, PIRP Irp); -NTSTATUS STDCALL Ext2FlushBuffers(PDEVICE_OBJECT DeviceObject, PIRP Irp); -NTSTATUS STDCALL Ext2Shutdown(PDEVICE_OBJECT DeviceObject, PIRP Irp); -NTSTATUS Ext2ReadPage(PDEVICE_EXTENSION DeviceExt, - PEXT2_FCB Fcb, - PVOID Buffer, - ULONG Offset); -VOID Ext2LoadInode(PDEVICE_EXTENSION DeviceExt, - ULONG ino, - PEXT2_INODE Inode); -VOID Ext2ReleaseInode(PDEVICE_EXTENSION DeviceExt, - PEXT2_INODE Inode); - diff --git a/reactos/drivers/fs/ext2/file.c b/reactos/drivers/fs/ext2/file.c deleted file mode 100644 index ee35ca3bec0..00000000000 --- a/reactos/drivers/fs/ext2/file.c +++ /dev/null @@ -1,61 +0,0 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS kernel - * FILE: services/fs/ext2/super.c - * PURPOSE: ext2 filesystem - * PROGRAMMER: David Welch (welch@mcmail.com) - * UPDATE HISTORY: - */ - -/* INCLUDES *****************************************************************/ - -#include - -#define NDEBUG -#include - -#include "ext2fs.h" - -/* FUNCTIONS ****************************************************************/ - -#define addr_per_block (BLOCKSIZE / sizeof(ULONG)) - -ULONG Ext2BlockMap(PDEVICE_EXTENSION DeviceExt, - struct ext2_inode* inode, - ULONG offset) -{ - ULONG block; - PULONG TempBuffer; - BOOL b; - - DPRINT("Ext2BlockMap(DeviceExt %x, inode %x, offset %d)\n", - DeviceExt,inode,offset); - if (offset < EXT2_NDIR_BLOCKS) - { - block = inode->i_block[offset]; - DPRINT("block %d\n",block); - return(block); - } - offset = offset - EXT2_NDIR_BLOCKS; - if (offset < addr_per_block) - { - block = inode->i_block[EXT2_IND_BLOCK]; - TempBuffer = ExAllocatePool(NonPagedPool, BLOCKSIZE); - b = Ext2ReadSectors(DeviceExt->StorageDevice, - block, - 1, - TempBuffer); - if (!b) - { - DbgPrint("ext2fs:%s:%d: Disk io failed\n", __FILE__, __LINE__); - return(0); - } - block = TempBuffer[offset]; - ExFreePool(TempBuffer); - return(block); - } - offset = offset - addr_per_block; - DbgPrint("Failed at %s:%d\n",__FILE__,__LINE__); - for(;;); -} - diff --git a/reactos/drivers/fs/ext2/inc/errmsg.h b/reactos/drivers/fs/ext2/inc/errmsg.h new file mode 100644 index 00000000000..d672cfa870e --- /dev/null +++ b/reactos/drivers/fs/ext2/inc/errmsg.h @@ -0,0 +1,68 @@ +/************************************************************************* +* +* File: errmsg.msg +* +* Product: Ext2 FSD +* +* Module: Ext2 FSD Event Log Messages +* +* Description: +* Contains error strings in a format understandable to the message compiler. +* Please compile (using mc) with the -c option which will set the +* "Customer" bit in all errors. +* Use values beginning at 0xA000 (e.g. 0xA001) for the Ext2 FSD +* errors. +* Do NOT use %1 for insertion strings. The I/O manager assumes that +* the first insertion string is the name of the driver/device. +* +* +*************************************************************************/ +// +// Values are 32 bit values layed out as follows: +// +// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 +// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 +// +---+-+-+-----------------------+-------------------------------+ +// |Sev|C|R| Facility | Code | +// +---+-+-+-----------------------+-------------------------------+ +// +// where +// +// Sev - is the severity code +// +// 00 - Success +// 01 - Informational +// 10 - Warning +// 11 - Error +// +// C - is the Customer code flag +// +// R - is a reserved bit +// +// Facility - is the facility code +// +// Code - is the facility's status code +// +// +// Define the facility codes +// + + +// +// Define the severity codes +// +#define STATUS_SEVERITY_WARNING 0x2 +#define STATUS_SEVERITY_SUCCESS 0x0 +#define STATUS_SEVERITY_INFORMATIONAL 0x1 +#define STATUS_SEVERITY_ERROR 0x3 + + +// +// MessageId: EXT2_ERROR_INTERNAL_ERROR +// +// MessageText: +// +// The Ext2 FSD encountered an internal error. Please check log data information. +// +#define EXT2_ERROR_INTERNAL_ERROR ((ULONG)0xE004A001L) + diff --git a/reactos/drivers/fs/ext2/inc/ext2_fs.h b/reactos/drivers/fs/ext2/inc/ext2_fs.h new file mode 100644 index 00000000000..8f6842d2c87 --- /dev/null +++ b/reactos/drivers/fs/ext2/inc/ext2_fs.h @@ -0,0 +1,615 @@ +/* + * linux/include/linux/ext2_fs.h + * + * Copyright (C) 1992, 1993, 1994, 1995 + * Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * from + * + * linux/include/linux/minix_fs.h + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +#ifndef _LINUX_EXT2_FS_H +#define _LINUX_EXT2_FS_H + +// #include + +/* + * The second extended filesystem constants/structures + */ + + +/* + * Define EXT2_PREALLOCATE to preallocate data blocks for expanding files + */ +#define EXT2_PREALLOCATE +#define EXT2_DEFAULT_PREALLOC_BLOCKS 8 + +/* + * The second extended file system version + */ +#define EXT2FS_DATE "95/08/09" +#define EXT2FS_VERSION "0.5b" + +/* + * Debug code + */ + +/* + * Special inodes numbers + */ +#define EXT2_BAD_INO 1 /* Bad blocks inode */ +#define EXT2_ROOT_INO 2 /* Root inode */ +#define EXT2_ACL_IDX_INO 3 /* ACL inode */ +#define EXT2_ACL_DATA_INO 4 /* ACL inode */ +#define EXT2_BOOT_LOADER_INO 5 /* Boot loader inode */ +#define EXT2_UNDEL_DIR_INO 6 /* Undelete directory inode */ + +/* First non-reserved inode for old ext2 filesystems */ +#define EXT2_GOOD_OLD_FIRST_INO 11 + +/* + * The second extended file system magic number + */ +#define EXT2_SUPER_MAGIC 0xEF53 + +/* + * Maximal count of links to a file + */ +#define EXT2_LINK_MAX 32000 + +/* + * Macro-instructions used to manage several block sizes + */ +#define EXT2_MIN_BLOCK_SIZE 1024 +#define EXT2_MAX_BLOCK_SIZE 4096 +#define EXT2_MIN_BLOCK_LOG_SIZE 10 +#ifdef __KERNEL__ +# define EXT2_BLOCK_SIZE(s) ((s)->s_blocksize) +#else +# define EXT2_BLOCK_SIZE(s) (EXT2_MIN_BLOCK_SIZE << (s)->s_log_block_size) +#endif +#define EXT2_ACLE_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_acl_entry)) +#define EXT2_ADDR_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (__u32)) +#ifdef __KERNEL__ +# define EXT2_BLOCK_SIZE_BITS(s) ((s)->s_blocksize_bits) +#else +# define EXT2_BLOCK_SIZE_BITS(s) ((s)->s_log_block_size + 10) +#endif +#ifdef __KERNEL__ +#define EXT2_ADDR_PER_BLOCK_BITS(s) ((s)->u.ext2_sb.s_addr_per_block_bits) +#define EXT2_INODE_SIZE(s) ((s)->u.ext2_sb.s_inode_size) +#define EXT2_FIRST_INO(s) ((s)->u.ext2_sb.s_first_ino) +#else +#define EXT2_INODE_SIZE(s) (((s)->s_rev_level == EXT2_GOOD_OLD_REV) ? \ + EXT2_GOOD_OLD_INODE_SIZE : \ + (s)->s_inode_size) +#define EXT2_FIRST_INO(s) (((s)->s_rev_level == EXT2_GOOD_OLD_REV) ? \ + EXT2_GOOD_OLD_FIRST_INO : \ + (s)->s_first_ino) +#endif + +/* + * Macro-instructions used to manage fragments + */ +#define EXT2_MIN_FRAG_SIZE 1024 +#define EXT2_MAX_FRAG_SIZE 4096 +#define EXT2_MIN_FRAG_LOG_SIZE 10 +#ifdef __KERNEL__ +# define EXT2_FRAG_SIZE(s) ((s)->u.ext2_sb.s_frag_size) +# define EXT2_FRAGS_PER_BLOCK(s) ((s)->u.ext2_sb.s_frags_per_block) +#else +# define EXT2_FRAG_SIZE(s) (EXT2_MIN_FRAG_SIZE << (s)->s_log_frag_size) +# define EXT2_FRAGS_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / EXT2_FRAG_SIZE(s)) +#endif + +/* + * ACL structures + */ +struct ext2_acl_header /* Header of Access Control Lists */ +{ + __u32 aclh_size; + __u32 aclh_file_count; + __u32 aclh_acle_count; + __u32 aclh_first_acle; +}; + +struct ext2_acl_entry /* Access Control List Entry */ +{ + __u32 acle_size; + __u16 acle_perms; /* Access permissions */ + __u16 acle_type; /* Type of entry */ + __u16 acle_tag; /* User or group identity */ + __u16 acle_pad1; + __u32 acle_next; /* Pointer on next entry for the */ + /* same inode or on next free entry */ +}; + +/* + * Structure of a blocks group descriptor + */ +struct ext2_group_desc +{ + __u32 bg_block_bitmap; /* Blocks bitmap block */ + __u32 bg_inode_bitmap; /* Inodes bitmap block */ + __u32 bg_inode_table; /* Inodes table block */ + __u16 bg_free_blocks_count; /* Free blocks count */ + __u16 bg_free_inodes_count; /* Free inodes count */ + __u16 bg_used_dirs_count; /* Directories count */ + __u16 bg_pad; + __u32 bg_reserved[3]; +}; + +/* + * Macro-instructions used to manage group descriptors + */ +#ifdef __KERNEL__ +# define EXT2_BLOCKS_PER_GROUP(s) ((s)->u.ext2_sb.s_blocks_per_group) +# define EXT2_DESC_PER_BLOCK(s) ((s)->u.ext2_sb.s_desc_per_block) +# define EXT2_INODES_PER_GROUP(s) ((s)->u.ext2_sb.s_inodes_per_group) +# define EXT2_DESC_PER_BLOCK_BITS(s) ((s)->u.ext2_sb.s_desc_per_block_bits) +#else +# define EXT2_BLOCKS_PER_GROUP(s) ((s)->s_blocks_per_group) +# define EXT2_DESC_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_group_desc)) +# define EXT2_INODES_PER_GROUP(s) ((s)->s_inodes_per_group) +#endif + +/* + * Constants relative to the data blocks + */ +#define EXT2_NDIR_BLOCKS 12 +#define EXT2_IND_BLOCK EXT2_NDIR_BLOCKS +#define EXT2_DIND_BLOCK (EXT2_IND_BLOCK + 1) +#define EXT2_TIND_BLOCK (EXT2_DIND_BLOCK + 1) +#define EXT2_N_BLOCKS (EXT2_TIND_BLOCK + 1) + +/* + * Inode flags + */ +#define EXT2_SECRM_FL 0x00000001 /* Secure deletion */ +#define EXT2_UNRM_FL 0x00000002 /* Undelete */ +#define EXT2_COMPR_FL 0x00000004 /* Compress file */ +#define EXT2_SYNC_FL 0x00000008 /* Synchronous updates */ +#define EXT2_IMMUTABLE_FL 0x00000010 /* Immutable file */ +#define EXT2_APPEND_FL 0x00000020 /* writes to file may only append */ +#define EXT2_NODUMP_FL 0x00000040 /* do not dump file */ +#define EXT2_NOATIME_FL 0x00000080 /* do not update atime */ +/* Reserved for compression usage... */ +#define EXT2_DIRTY_FL 0x00000100 +#define EXT2_COMPRBLK_FL 0x00000200 /* One or more compressed clusters */ +#define EXT2_NOCOMP_FL 0x00000400 /* Don't compress */ +#define EXT2_ECOMPR_FL 0x00000800 /* Compression error */ +/* End compression flags --- maybe not all used */ +#define EXT2_BTREE_FL 0x00001000 /* btree format dir */ +#define EXT2_RESERVED_FL 0x80000000 /* reserved for ext2 lib */ + +#define EXT2_FL_USER_VISIBLE 0x00001FFF /* User visible flags */ +#define EXT2_FL_USER_MODIFIABLE 0x000000FF /* User modifiable flags */ + +/* + * ioctl commands + */ +#define EXT2_IOC_GETFLAGS _IOR('f', 1, long) +#define EXT2_IOC_SETFLAGS _IOW('f', 2, long) +#define EXT2_IOC_GETVERSION _IOR('v', 1, long) +#define EXT2_IOC_SETVERSION _IOW('v', 2, long) + +/* + * Structure of an inode on the disk + */ +struct ext2_inode { + __u16 i_mode; /* File mode */ + __u16 i_uid; /* Low 16 bits of Owner Uid */ + __u32 i_size; /* Size in bytes */ + __u32 i_atime; /* Access time */ + __u32 i_ctime; /* Creation time */ + __u32 i_mtime; /* Modification time */ + __u32 i_dtime; /* Deletion Time */ + __u16 i_gid; /* Low 16 bits of Group Id */ + __u16 i_links_count; /* Links count */ + __u32 i_blocks; /* Blocks count */ + __u32 i_flags; /* File flags */ + union { + struct { + __u32 l_i_reserved1; + } linux1; + struct { + __u32 h_i_translator; + } hurd1; + struct { + __u32 m_i_reserved1; + } masix1; + } osd1; /* OS dependent 1 */ + __u32 i_block[EXT2_N_BLOCKS];/* Pointers to blocks */ + __u32 i_generation; /* File version (for NFS) */ + __u32 i_file_acl; /* File ACL */ + __u32 i_dir_acl; /* Directory ACL */ + __u32 i_faddr; /* Fragment address */ + union { + struct { + __u8 l_i_frag; /* Fragment number */ + __u8 l_i_fsize; /* Fragment size */ + __u16 i_pad1; + __u16 l_i_uid_high; /* these 2 fields */ + __u16 l_i_gid_high; /* were reserved2[0] */ + __u32 l_i_reserved2; + } linux2; + struct { + __u8 h_i_frag; /* Fragment number */ + __u8 h_i_fsize; /* Fragment size */ + __u16 h_i_mode_high; + __u16 h_i_uid_high; + __u16 h_i_gid_high; + __u32 h_i_author; + } hurd2; + struct { + __u8 m_i_frag; /* Fragment number */ + __u8 m_i_fsize; /* Fragment size */ + __u16 m_pad1; + __u32 m_i_reserved2[2]; + } masix2; + } osd2; /* OS dependent 2 */ +}; + +#define i_size_high i_dir_acl + +#if defined(__KERNEL__) || defined(__linux__) +#define i_reserved1 osd1.linux1.l_i_reserved1 +#define i_frag osd2.linux2.l_i_frag +#define i_fsize osd2.linux2.l_i_fsize +#define i_uid_low i_uid +#define i_gid_low i_gid +#define i_uid_high osd2.linux2.l_i_uid_high +#define i_gid_high osd2.linux2.l_i_gid_high +#define i_reserved2 osd2.linux2.l_i_reserved2 +#endif + +#ifdef __hurd__ +#define i_translator osd1.hurd1.h_i_translator +#define i_frag osd2.hurd2.h_i_frag; +#define i_fsize osd2.hurd2.h_i_fsize; +#define i_uid_high osd2.hurd2.h_i_uid_high +#define i_gid_high osd2.hurd2.h_i_gid_high +#define i_author osd2.hurd2.h_i_author +#endif + +#ifdef __masix__ +#define i_reserved1 osd1.masix1.m_i_reserved1 +#define i_frag osd2.masix2.m_i_frag +#define i_fsize osd2.masix2.m_i_fsize +#define i_reserved2 osd2.masix2.m_i_reserved2 +#endif + +/* + * File system states + */ +#define EXT2_VALID_FS 0x0001 /* Unmounted cleanly */ +#define EXT2_ERROR_FS 0x0002 /* Errors detected */ + +/* + * Mount flags + */ +#define EXT2_MOUNT_CHECK 0x0001 /* Do mount-time checks */ +#define EXT2_MOUNT_GRPID 0x0004 /* Create files with directory's group */ +#define EXT2_MOUNT_DEBUG 0x0008 /* Some debugging messages */ +#define EXT2_MOUNT_ERRORS_CONT 0x0010 /* Continue on errors */ +#define EXT2_MOUNT_ERRORS_RO 0x0020 /* Remount fs ro on errors */ +#define EXT2_MOUNT_ERRORS_PANIC 0x0040 /* Panic on errors */ +#define EXT2_MOUNT_MINIX_DF 0x0080 /* Mimics the Minix statfs */ +#define EXT2_MOUNT_NO_UID32 0x0200 /* Disable 32-bit UIDs */ + +#define clear_opt(o, opt) o &= ~EXT2_MOUNT_##opt +#define set_opt(o, opt) o |= EXT2_MOUNT_##opt +#define test_opt(sb, opt) ((sb)->u.ext2_sb.s_mount_opt & \ + EXT2_MOUNT_##opt) +/* + * Maximal mount counts between two filesystem checks + */ +#define EXT2_DFL_MAX_MNT_COUNT 20 /* Allow 20 mounts */ +#define EXT2_DFL_CHECKINTERVAL 0 /* Don't use interval check */ + +/* + * Behaviour when detecting errors + */ +#define EXT2_ERRORS_CONTINUE 1 /* Continue execution */ +#define EXT2_ERRORS_RO 2 /* Remount fs read-only */ +#define EXT2_ERRORS_PANIC 3 /* Panic */ +#define EXT2_ERRORS_DEFAULT EXT2_ERRORS_CONTINUE + +/* + * Structure of the super block + */ +struct ext2_super_block { + __u32 s_inodes_count; /* Inodes count */ + __u32 s_blocks_count; /* Blocks count */ + __u32 s_r_blocks_count; /* Reserved blocks count */ + __u32 s_free_blocks_count; /* Free blocks count */ + __u32 s_free_inodes_count; /* Free inodes count */ + __u32 s_first_data_block; /* First Data Block */ + __u32 s_log_block_size; /* Block size */ + __s32 s_log_frag_size; /* Fragment size */ + __u32 s_blocks_per_group; /* # Blocks per group */ + __u32 s_frags_per_group; /* # Fragments per group */ + __u32 s_inodes_per_group; /* # Inodes per group */ + __u32 s_mtime; /* Mount time */ + __u32 s_wtime; /* Write time */ + __u16 s_mnt_count; /* Mount count */ + __s16 s_max_mnt_count; /* Maximal mount count */ + __u16 s_magic; /* Magic signature */ + __u16 s_state; /* File system state */ + __u16 s_errors; /* Behaviour when detecting errors */ + __u16 s_minor_rev_level; /* minor revision level */ + __u32 s_lastcheck; /* time of last check */ + __u32 s_checkinterval; /* max. time between checks */ + __u32 s_creator_os; /* OS */ + __u32 s_rev_level; /* Revision level */ + __u16 s_def_resuid; /* Default uid for reserved blocks */ + __u16 s_def_resgid; /* Default gid for reserved blocks */ + /* + * These fields are for EXT2_DYNAMIC_REV superblocks only. + * + * Note: the difference between the compatible feature set and + * the incompatible feature set is that if there is a bit set + * in the incompatible feature set that the kernel doesn't + * know about, it should refuse to mount the filesystem. + * + * e2fsck's requirements are more strict; if it doesn't know + * about a feature in either the compatible or incompatible + * feature set, it must abort and not try to meddle with + * things it doesn't understand... + */ + __u32 s_first_ino; /* First non-reserved inode */ + __u16 s_inode_size; /* size of inode structure */ + __u16 s_block_group_nr; /* block group # of this superblock */ + __u32 s_feature_compat; /* compatible feature set */ + __u32 s_feature_incompat; /* incompatible feature set */ + __u32 s_feature_ro_compat; /* readonly-compatible feature set */ + __u8 s_uuid[16]; /* 128-bit uuid for volume */ + char s_volume_name[16]; /* volume name */ + char s_last_mounted[64]; /* directory where last mounted */ + __u32 s_algorithm_usage_bitmap; /* For compression */ + /* + * Performance hints. Directory preallocation should only + * happen if the EXT2_COMPAT_PREALLOC flag is on. + */ + __u8 s_prealloc_blocks; /* Nr of blocks to try to preallocate*/ + __u8 s_prealloc_dir_blocks; /* Nr to preallocate for dirs */ + __u16 s_padding1; + __u32 s_reserved[204]; /* Padding to the end of the block */ +}; + +#ifdef __KERNEL__ +#define EXT2_SB(sb) (&((sb)->u.ext2_sb)) +#else +/* Assume that user mode programs are passing in an ext2fs superblock, not + * a kernel struct super_block. This will allow us to call the feature-test + * macros from user land. */ +#define EXT2_SB(sb) (sb) +#endif + +/* + * Codes for operating systems + */ +#define EXT2_OS_LINUX 0 +#define EXT2_OS_HURD 1 +#define EXT2_OS_MASIX 2 +#define EXT2_OS_FREEBSD 3 +#define EXT2_OS_LITES 4 + +/* + * Revision levels + */ +#define EXT2_GOOD_OLD_REV 0 /* The good old (original) format */ +#define EXT2_DYNAMIC_REV 1 /* V2 format w/ dynamic inode sizes */ + +#define EXT2_CURRENT_REV EXT2_GOOD_OLD_REV +#define EXT2_MAX_SUPP_REV EXT2_DYNAMIC_REV + +#define EXT2_GOOD_OLD_INODE_SIZE 128 + +/* + * Feature set definitions + */ + +#define EXT2_HAS_COMPAT_FEATURE(sb,mask) \ + ( EXT2_SB(sb)->s_es->s_feature_compat & cpu_to_le32(mask) ) +#define EXT2_HAS_RO_COMPAT_FEATURE(sb,mask) \ + ( EXT2_SB(sb)->s_es->s_feature_ro_compat & cpu_to_le32(mask) ) +#define EXT2_HAS_INCOMPAT_FEATURE(sb,mask) \ + ( EXT2_SB(sb)->s_es->s_feature_incompat & cpu_to_le32(mask) ) +#define EXT2_SET_COMPAT_FEATURE(sb,mask) \ + EXT2_SB(sb)->s_es->s_feature_compat |= cpu_to_le32(mask) +#define EXT2_SET_RO_COMPAT_FEATURE(sb,mask) \ + EXT2_SB(sb)->s_es->s_feature_ro_compat |= cpu_to_le32(mask) +#define EXT2_SET_INCOMPAT_FEATURE(sb,mask) \ + EXT2_SB(sb)->s_es->s_feature_incompat |= cpu_to_le32(mask) +#define EXT2_CLEAR_COMPAT_FEATURE(sb,mask) \ + EXT2_SB(sb)->s_es->s_feature_compat &= ~cpu_to_le32(mask) +#define EXT2_CLEAR_RO_COMPAT_FEATURE(sb,mask) \ + EXT2_SB(sb)->s_es->s_feature_ro_compat &= ~cpu_to_le32(mask) +#define EXT2_CLEAR_INCOMPAT_FEATURE(sb,mask) \ + EXT2_SB(sb)->s_es->s_feature_incompat &= ~cpu_to_le32(mask) + +#define EXT2_FEATURE_COMPAT_DIR_PREALLOC 0x0001 + +#define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001 +#define EXT2_FEATURE_RO_COMPAT_LARGE_FILE 0x0002 +#define EXT2_FEATURE_RO_COMPAT_BTREE_DIR 0x0004 + +#define EXT2_FEATURE_INCOMPAT_COMPRESSION 0x0001 +#define EXT2_FEATURE_INCOMPAT_FILETYPE 0x0002 + +#define EXT2_FEATURE_COMPAT_SUPP 0 +#define EXT2_FEATURE_INCOMPAT_SUPP EXT2_FEATURE_INCOMPAT_FILETYPE +#define EXT2_FEATURE_RO_COMPAT_SUPP (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \ + EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \ + EXT2_FEATURE_RO_COMPAT_BTREE_DIR) + +/* + * Default values for user and/or group using reserved blocks + */ +#define EXT2_DEF_RESUID 0 +#define EXT2_DEF_RESGID 0 + +/* + * Structure of a directory entry + */ +#define EXT2_NAME_LEN 255 + +struct ext2_dir_entry { + __u32 inode; /* Inode number */ + __u16 rec_len; /* Directory entry length */ + __u16 name_len; /* Name length */ + char name[EXT2_NAME_LEN]; /* File name */ +}; + +/* + * The new version of the directory entry. Since EXT2 structures are + * stored in intel byte order, and the name_len field could never be + * bigger than 255 chars, it's safe to reclaim the extra byte for the + * file_type field. + */ +struct ext2_dir_entry_2 { + __u32 inode; /* Inode number */ + __u16 rec_len; /* Directory entry length */ + __u8 name_len; /* Name length */ + __u8 file_type; + char name[EXT2_NAME_LEN]; /* File name */ +}; + +/* + * Ext2 directory file types. Only the low 3 bits are used. The + * other bits are reserved for now. + */ +#define EXT2_FT_UNKNOWN 0 +#define EXT2_FT_REG_FILE 1 +#define EXT2_FT_DIR 2 +#define EXT2_FT_CHRDEV 3 +#define EXT2_FT_BLKDEV 4 +#define EXT2_FT_FIFO 5 +#define EXT2_FT_SOCK 6 +#define EXT2_FT_SYMLINK 7 + +#define EXT2_FT_MAX 8 + +/* + * EXT2_DIR_PAD defines the directory entries boundaries + * + * NOTE: It must be a multiple of 4 + */ +#define EXT2_DIR_PAD 4 +#define EXT2_DIR_ROUND (EXT2_DIR_PAD - 1) +#define EXT2_DIR_REC_LEN(name_len) (((name_len) + 8 + EXT2_DIR_ROUND) & \ + ~EXT2_DIR_ROUND) + +#ifdef __KERNEL__ +/* + * Function prototypes + */ + +/* + * Ok, these declarations are also in but none of the + * ext2 source programs needs to include it so they are duplicated here. + */ +# define NORET_TYPE /**/ +# define ATTRIB_NORET __attribute__((noreturn)) +# define NORET_AND noreturn, + +/* acl.c */ +extern int ext2_permission (struct inode *, int); + +/* balloc.c */ +extern int ext2_bg_has_super(struct super_block *sb, int group); +extern unsigned long ext2_bg_num_gdb(struct super_block *sb, int group); +extern int ext2_new_block (struct inode *, unsigned long, + __u32 *, __u32 *, int *); +extern void ext2_free_blocks (struct inode *, unsigned long, + unsigned long); +extern unsigned long ext2_count_free_blocks (struct super_block *); +extern void ext2_check_blocks_bitmap (struct super_block *); +extern struct ext2_group_desc * ext2_get_group_desc(struct super_block * sb, + unsigned int block_group, + struct buffer_head ** bh); + +/* bitmap.c */ +extern unsigned long ext2_count_free (struct buffer_head *, unsigned); + +/* dir.c */ +extern int ext2_check_dir_entry (const char *, struct inode *, + struct ext2_dir_entry_2 *, struct buffer_head *, + unsigned long); + +/* file.c */ +extern int ext2_read (struct inode *, struct file *, char *, int); +extern int ext2_write (struct inode *, struct file *, char *, int); + +/* fsync.c */ +extern int ext2_sync_file (struct file *, struct dentry *, int); +extern int ext2_fsync_inode (struct inode *, int); + +/* ialloc.c */ +extern struct inode * ext2_new_inode (const struct inode *, int); +extern void ext2_free_inode (struct inode *); +extern unsigned long ext2_count_free_inodes (struct super_block *); +extern void ext2_check_inodes_bitmap (struct super_block *); + +/* inode.c */ + +extern struct buffer_head * ext2_getblk (struct inode *, long, int, int *); +extern struct buffer_head * ext2_bread (struct inode *, int, int, int *); + +extern void ext2_read_inode (struct inode *); +extern void ext2_write_inode (struct inode *, int); +extern void ext2_put_inode (struct inode *); +extern void ext2_delete_inode (struct inode *); +extern int ext2_sync_inode (struct inode *); +extern void ext2_discard_prealloc (struct inode *); + +/* ioctl.c */ +extern int ext2_ioctl (struct inode *, struct file *, unsigned int, + unsigned long); + +/* namei.c */ +extern struct inode_operations ext2_dir_inode_operations; + +/* super.c */ +extern void ext2_error (struct super_block *, const char *, const char *, ...) + __attribute__ ((format (printf, 3, 4))); +extern NORET_TYPE void ext2_panic (struct super_block *, const char *, + const char *, ...) + __attribute__ ((NORET_AND format (printf, 3, 4))); +extern void ext2_warning (struct super_block *, const char *, const char *, ...) + __attribute__ ((format (printf, 3, 4))); +extern void ext2_update_dynamic_rev (struct super_block *sb); +extern void ext2_put_super (struct super_block *); +extern void ext2_write_super (struct super_block *); +extern int ext2_remount (struct super_block *, int *, char *); +extern struct super_block * ext2_read_super (struct super_block *,void *,int); +extern int ext2_statfs (struct super_block *, struct statfs *); + +/* truncate.c */ +extern void ext2_truncate (struct inode *); + +/* + * Inodes and files operations + */ + +/* dir.c */ +extern struct file_operations ext2_dir_operations; + +/* file.c */ +extern struct inode_operations ext2_file_inode_operations; +extern struct file_operations ext2_file_operations; + +/* symlink.c */ +extern struct inode_operations ext2_fast_symlink_inode_operations; + +extern struct address_space_operations ext2_aops; + +#endif /* __KERNEL__ */ + +#endif /* _LINUX_EXT2_FS_H */ diff --git a/reactos/drivers/fs/ext2/inc/ext2fsd.h b/reactos/drivers/fs/ext2/inc/ext2fsd.h new file mode 100644 index 00000000000..07791a3d20c --- /dev/null +++ b/reactos/drivers/fs/ext2/inc/ext2fsd.h @@ -0,0 +1,250 @@ +/************************************************************************* +* +* File: ext2fsd.h +* +* Module: Ext2 File System Driver (Kernel mode execution only) +* +* Description: +* The main include file for the Ext2 file system driver. +* +* Author: Manoj Paul Joseph +* +* +*************************************************************************/ + + +#ifndef _EXT2_FSD_H_ +#define _EXT2_FSD_H_ + +#define EXT2_POOL_WITH_TAG + + +// some constant definitions +#define EXT2_PANIC_IDENTIFIER (0x86427531) + +// any directory information EXT2 obtains from the local file system +// will use a buffer of the following size ... (in KB) +#define EXT2_READ_DIR_BUFFER_LENGTH (512) +#define EXT2_MAXCLOSABLE_FCBS_UL 20 +#define EXT2_MAXCLOSABLE_FCBS_LL 10 + +// Some type definitions... +// These are used later... + +typedef unsigned char UCHAR; +typedef unsigned int UINT; +typedef UCHAR BYTE; +typedef UCHAR BOOLEAN; // winnt +typedef BOOLEAN * PBOOLEAN; // winnt +typedef void * PVOID64; // winnt +typedef long LONG; +typedef LONG HRESULT; + + +#if defined(_M_IX86) +#define FASTCALL _fastcall +#else +#define FASTCALL +#endif + + + +// Common include files - should be in the include dir of the MS supplied IFS Kit +#include +#include + + +/* REACTOS FIXME */ +#undef DeleteFile +/* This is deprecated and should be changed in the EXT2FS driver. */ +#define RtlLargeIntegerLessThan(a, b) (a).QuadPart < (b).QuadPart +#define RtlLargeIntegerGreaterThan(a, b) (a).QuadPart > (b).QuadPart + + +// the following include files should be in the inc sub-dir associated with this driver +#include "ext2metadata.h" +#include "struct.h" +#include "protos.h" +#include "errmsg.h" + + +// global variables - minimize these +extern Ext2Data Ext2GlobalData; + +// try-finally simulation +#define try_return(S) { S; goto try_exit; } +#define try_return1(S) { S; goto try_exit1; } +#define try_return2(S) { S; goto try_exit2; } + +// some global (helpful) macros +#define Ext2IsFlagOn(Flags,SingleFlag) ((BOOLEAN)((((Flags) & (SingleFlag)) != 0))) +#define Ext2SetFlag(Flag, Value) ((Flag) |= (Value)) +#define Ext2ClearFlag(Flag, Value) ((Flag) &= ~(Value)) + +#define Ext2QuadAlign(Value) ((((uint32)(Value)) + 7) & 0xfffffff8) + +// to perform a bug-check (panic), the following macro is used +#define Ext2Panic(arg1, arg2, arg3) \ + (KeBugCheckEx(EXT2_PANIC_IDENTIFIER, EXT2_BUG_CHECK_ID | __LINE__, (uint32)(arg1), (uint32)(arg2), (uint32)(arg3))) + +// a convenient macro (must be invoked in the context of the thread that acquired the resource) +#define Ext2ReleaseResource(Resource) \ + (ExReleaseResourceForThreadLite((Resource), ExGetCurrentResourceThread())) + +// each file has a unique bug-check identifier associated with it. +// Here is a list of constant definitions for these identifiers +#define EXT2_FILE_INIT (0x00000001) +#define EXT2_FILE_REGISTRY (0x00000002) +#define EXT2_FILE_CREATE (0x00000003) +#define EXT2_FILE_CLEANUP (0x00000004) +#define EXT2_FILE_CLOSE (0x00000005) +#define EXT2_FILE_READ (0x00000006) +#define EXT2_FILE_WRITE (0x00000007) +#define EXT2_FILE_INFORMATION (0x00000008) +#define EXT2_FILE_FLUSH (0x00000009) +#define EXT2_FILE_VOL_INFORMATION (0x0000000A) +#define EXT2_FILE_DIR_CONTROL (0x0000000B) +#define EXT2_FILE_FILE_CONTROL (0x0000000C) +#define EXT2_FILE_DEVICE_CONTROL (0x0000000D) +#define EXT2_FILE_SHUTDOWN (0x0000000E) +#define EXT2_FILE_LOCK_CONTROL (0x0000000F) +#define EXT2_FILE_SECURITY (0x00000010) +#define EXT2_FILE_EXT_ATTR (0x00000011) +#define EXT2_FILE_MISC (0x00000012) +#define EXT2_FILE_FAST_IO (0x00000013) +#define EXT2_FILE_IO (0x00000014) +#define EXT2_FILE_METADATA_IO (0x00000015) + + + +#if DBG +#define Ext2BreakPoint() DbgBreakPoint() +#else +#define Ext2BreakPoint() +#endif + +#define Ext2RaiseStatus(IRPCONTEXT,STATUS) \ +{ \ + (IRPCONTEXT)->ExceptionStatus = (STATUS); \ + ExRaiseStatus( (STATUS) ); \ +} + +#ifdef EXT2_POOL_WITH_TAG + #define Ext2AllocatePool(PoolType,NumberOfBytes) \ + ExAllocatePoolWithTag( PoolType, NumberOfBytes, '2txE' ) +#else + #define Ext2AllocatePool(PoolType,NumberOfBytes) \ + ExAllocatePool( PoolType, NumberOfBytes ) +#endif + + +#if DBG + +// +// Trace types... +// Any number of these may be enabled... +// +#define DEBUG_TRACE_IRQL (0x00000001) +#define DEBUG_TRACE_IRP_ENTRY (0x00000002) +#define DEBUG_TRACE_RESOURCE_ACQUIRE (0x00000004) +#define DEBUG_TRACE_RESOURCE_RELEASE (0x00000008) +#define DEBUG_TRACE_RESOURCE_RETRY (0x00000010) +#define DEBUG_TRACE_ASYNC (0x00000020) +#define DEBUG_TRACE_MOUNT (0x00000040) +#define DEBUG_TRACE_RESOURCE_STATE (0x00000080) +#define DEBUG_TRACE_MISC (0x00000100) +#define DEBUG_TRACE_FILE_OBJ (0x00000200) +#define DEBUG_TRACE_FILE_NAME (0x00000400) +#define DEBUG_TRACE_SPECIAL (0x00000800) +#define DEBUG_TRACE_ERROR (0x00001000) +#define DEBUG_TRACE_READ_DETAILS (0x00002000) +#define DEBUG_TRACE_WRITE_DETAILS (0x00004000) +#define DEBUG_TRACE_FILEINFO (0x00008000) +#define DEBUG_TRACE_DIRINFO (0x00010000) +#define DEBUG_TRACE_REFERENCE (0x00020000) +#define DEBUG_TRACE_FSCTRL (0x00040000) +#define DEBUG_TRACE_FREE (0x00080000) +#define DEBUG_TRACE_LINENO (0x00100000) +#define DEBUG_TRACE_TRIPLE (0x00200000) + +#define DEBUG_TRACE_ALL (0xffffffff) +#define DEBUG_TRACE_NONE 0 +// +// The permitted DebugTrace types... +// +#define PERMITTED_DEBUG_TRACE_TYPES /* DEBUG_TRACE_TRIPLE */ DEBUG_TRACE_ALL +/* +#define PERMITTED_DEBUG_TRACE_TYPES DEBUG_TRACE_ERROR | DEBUG_TRACE_IRP_ENTRY | \ + DEBUG_TRACE_FILE_NAME | DEBUG_TRACE_SPECIAL | \ + DEBUG_TRACE_ASYNC + +*/ + + +#define DebugTrace( TYPE, X, Y ) \ +{ \ + if( ( TYPE ) & ( PERMITTED_DEBUG_TRACE_TYPES ) ) \ + { \ + DbgPrint("\n "); \ + DbgPrint(X,Y); \ + if( ( DEBUG_TRACE_IRQL ) & ( PERMITTED_DEBUG_TRACE_TYPES ) ) \ + { \ + DbgPrint( " IRQL = %d ", KeGetCurrentIrql( ) ); \ + } \ + if( ( DEBUG_TRACE_LINENO ) & ( PERMITTED_DEBUG_TRACE_TYPES ) ) \ + { \ + DbgPrint( " [%s] Line No = %ld", __FILE__, __LINE__ ); \ + } \ + } \ +} + + +#define DebugTraceState( STR, X1, X2, X3) \ +{ \ + if( ( DEBUG_TRACE_RESOURCE_STATE ) & ( PERMITTED_DEBUG_TRACE_TYPES ) ) \ + { \ + DbgPrint("\nState: "); \ + DbgPrint( STR, X1, X2, X3 ); \ + if( ( DEBUG_TRACE_IRQL ) & ( PERMITTED_DEBUG_TRACE_TYPES ) ) \ + { \ + DbgPrint( " IRQL = %d ", KeGetCurrentIrql( ) ); \ + } \ + } \ +} + +#define AssertFCB( PtrFCB ) \ +{ \ + if( !(PtrFCB) || (PtrFCB)->NodeIdentifier.NodeType != EXT2_NODE_TYPE_FCB ) \ + { \ + Ext2BreakPoint(); \ + } \ +} + +#define AssertVCB( PtrVCB ) \ +{ \ + if( !(PtrVCB) || (PtrVCB)->NodeIdentifier.NodeType != EXT2_NODE_TYPE_VCB ) \ + { \ + Ext2BreakPoint(); \ + } \ +} + +#define AssertFCBorVCB( PtrVCBorFCB ) \ +{ \ + if( !(PtrVCBorFCB) || \ + ( (PtrVCBorFCB)->NodeIdentifier.NodeType != EXT2_NODE_TYPE_VCB && \ + (PtrVCBorFCB)->NodeIdentifier.NodeType != EXT2_NODE_TYPE_FCB ) ) \ + { \ + Ext2BreakPoint(); \ + } \ +} + +#else + #define DebugTrace( TYPE, X, Y ) + #define DebugTraceState( STR, X1, X2, X3 ) + #define AssertFCB( PtrFCB ) + #define AssertVCB( PtrVCB ) + #define AssertFCBorVCB( PtrVCBorFCB ) + +#endif + +#endif // _EXT2_FSD_H_ diff --git a/reactos/drivers/fs/ext2/inc/ext2metadata.h b/reactos/drivers/fs/ext2/inc/ext2metadata.h new file mode 100644 index 00000000000..e860f9f3200 --- /dev/null +++ b/reactos/drivers/fs/ext2/inc/ext2metadata.h @@ -0,0 +1,115 @@ +/************************************************************************* +* +* File: ext2metadata.h +* +* Module: Ext2 File System Driver (Kernel mode execution only) +* +* Description: +* Contains the definitions for the Ext2 Metadata structures. +* +* Author: Manoj Paul Joseph +* +* +*************************************************************************/ + +#ifndef EXT2_METADATA_STRUCTURES +#define EXT2_METADATA_STRUCTURES + +// +// Some type definitions... +// These are used in the ext2_fs.h header file +// +typedef unsigned int __u32 ; +typedef signed int __s32 ; +typedef unsigned short int __u16 ; +typedef signed short int __s16 ; +typedef unsigned char __u8 ; + +// +//****************************************************** +// +// Using Remy Card's (slightly modified) Ext2 header... +// +#include "ext2_fs.h" +// +//****************************************************** +// + +typedef struct ext2_super_block EXT2_SUPER_BLOCK; +typedef EXT2_SUPER_BLOCK * PEXT2_SUPER_BLOCK; + +typedef struct ext2_inode EXT2_INODE; +typedef EXT2_INODE * PEXT2_INODE; + +typedef struct ext2_group_desc EXT2_GROUP_DESCRIPTOR; +typedef EXT2_GROUP_DESCRIPTOR * PEXT2_GROUP_DESCRIPTOR; + +typedef struct ext2_dir_entry_2 EXT2_DIR_ENTRY; +typedef EXT2_DIR_ENTRY * PEXT2_DIR_ENTRY; + +// +// Ext2 Supported File Types... +// +#define IMODE_FIFO 0x01 +#define IMODE_CHARDEV 0x02 +#define IMODE_DIR 0x04 +#define IMODE_BLOCKDEV 0x06 +#define IMODE_FILE 0x08 +#define IMODE_SLINK 0x0A +#define IMODE_SOCKET 0x0C + +#define _MKMODE(m) ( ( (m) >> 12 ) & 0x000F) +#define Ext2IsModeRegularFile(m) ( _MKMODE(m) == IMODE_FILE ) +#define Ext2IsModeDirectory(m) ( _MKMODE(m) == IMODE_DIR ) +#define Ext2IsModeSymbolicLink(m) ( _MKMODE(m) == IMODE_SLINK ) +#define Ext2IsModePipe(m) ( _MKMODE(m) == IMODE_FIFO ) +#define Ext2IsModeCharacterDevice(m) ( _MKMODE(m) == IMODE_CHARDEV ) +#define Ext2IsModeBlockDevice(m) ( _MKMODE(m) == IMODE_BLOCKDEV ) +#define Ext2IsModeSocket(m) ( _MKMODE(m) == IMODE_SOCKET ) + +#define Ext2IsModeHidden(m) ( (m & 0x124) == 0) // No Read Permission +#define Ext2IsModeReadOnly(m) ( (m & 0x92) == 0) // No write Permission + +#define Ext2SetModeHidden(m) m = (m & (~0x124)); // Turn off Read Permission +#define Ext2SetModeReadOnly(m) m = (m & (~0x92)); // Turn off write Permission +#define Ext2SetModeReadWrite(m) m = (m & 0x1ff); // Set read/write Permission + + +// +// Define the Packed and Unpacked BIOS Parameter Block +// +typedef struct _PACKED_BIOS_PARAMETER_BLOCK { + UCHAR BytesPerSector[2]; // offset = 0x000 0 + UCHAR SectorsPerCluster[1]; // offset = 0x002 2 + UCHAR ReservedSectors[2]; // offset = 0x003 3 + UCHAR Fats[1]; // offset = 0x005 5 + UCHAR RootEntries[2]; // offset = 0x006 6 + UCHAR Sectors[2]; // offset = 0x008 8 + UCHAR Media[1]; // offset = 0x00A 10 + UCHAR SectorsPerFat[2]; // offset = 0x00B 11 + UCHAR SectorsPerTrack[2]; // offset = 0x00D 13 + UCHAR Heads[2]; // offset = 0x00F 15 + UCHAR HiddenSectors[4]; // offset = 0x011 17 + UCHAR LargeSectors[4]; // offset = 0x015 21 +} PACKED_BIOS_PARAMETER_BLOCK; // sizeof = 0x019 25 +typedef PACKED_BIOS_PARAMETER_BLOCK *PPACKED_BIOS_PARAMETER_BLOCK; + +// +// Define the boot sector +// +typedef struct _PACKED_BOOT_SECTOR { + UCHAR Jump[3]; // offset = 0x000 0 + UCHAR Oem[8]; // offset = 0x003 3 + PACKED_BIOS_PARAMETER_BLOCK PackedBpb; // offset = 0x00B 11 + UCHAR PhysicalDriveNumber; // offset = 0x024 36 + UCHAR CurrentHead; // offset = 0x025 37 + UCHAR Signature; // offset = 0x026 38 + UCHAR Id[4]; // offset = 0x027 39 + UCHAR VolumeLabel[11]; // offset = 0x02B 43 + UCHAR SystemId[8]; // offset = 0x036 54 +} PACKED_BOOT_SECTOR; // sizeof = 0x03E 62 + +typedef PACKED_BOOT_SECTOR *PPACKED_BOOT_SECTOR; + + +#endif diff --git a/reactos/drivers/fs/ext2/inc/protos.h b/reactos/drivers/fs/ext2/inc/protos.h new file mode 100644 index 00000000000..450f41a0f95 --- /dev/null +++ b/reactos/drivers/fs/ext2/inc/protos.h @@ -0,0 +1,782 @@ +/************************************************************************* +* +* File: protos.h +* +* Module: Ext2 File System Driver (Kernel mode execution only) +* +* Description: +* Contains the prototypes for functions in this sample FSD. +* +* Author: Manoj Paul Joseph +* +* +*************************************************************************/ + +#ifndef _EXT2_PROTOS_H_ +#define _EXT2_PROTOS_H_ + +#ifdef __REACTOS__ +typedef PIO_STACK_LOCATION PEXTENDED_IO_STACK_LOCATION; +#endif + +/************************************************************************* +* Prototypes for the file sfsdinit.c +*************************************************************************/ +extern NTSTATUS STDCALL DriverEntry( + PDRIVER_OBJECT DriverObject, // created by the I/O sub-system + PUNICODE_STRING RegistryPath); // path to the registry key + +extern void STDCALL Ext2FsdInitializeFunctionPointers( + PDRIVER_OBJECT DriverObject); // created by the I/O sub-system + + +extern VOID STDCALL Ext2QueueHandlerThread( + IN PVOID StartContext); + +/************************************************************************* +* Prototypes for the file fsctrl.c +*************************************************************************/ + +extern NTSTATUS STDCALL Ext2FileSystemControl( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp + ); + +extern NTSTATUS STDCALL Ext2VerifyVolume ( + IN PIRP Irp, + IN PIO_STACK_LOCATION IrpSp ); + + +/************************************************************************* +* Prototypes for the file create.c +*************************************************************************/ +extern NTSTATUS STDCALL Ext2Create( +PDEVICE_OBJECT DeviceObject, // the logical volume device object +PIRP Irp); // I/O Request Packet + +extern NTSTATUS STDCALL Ext2CommonCreate( +PtrExt2IrpContext PtrIrpContext, +PIRP PtrIrp, +BOOLEAN FirstAttempt ); + +extern NTSTATUS STDCALL Ext2OpenVolume( + PtrExt2VCB PtrVCB, // volume to be opened + PtrExt2IrpContext PtrIrpContext, // IRP context + PIRP PtrIrp, // original/user IRP + unsigned short ShareAccess, // share access + PIO_SECURITY_CONTEXT PtrSecurityContext, // caller's context (incl access) + PFILE_OBJECT PtrNewFileObject); // I/O Mgr. created file object + +extern NTSTATUS STDCALL Ext2OpenRootDirectory( + PtrExt2VCB PtrVCB, // volume to be opened + PtrExt2IrpContext PtrIrpContext, // IRP context + PIRP PtrIrp, // original/user IRP + unsigned short ShareAccess, // share access + PIO_SECURITY_CONTEXT PtrSecurityContext, // caller's context (incl access) + PFILE_OBJECT PtrNewFileObject); // I/O Mgr. created file object + +extern void STDCALL Ext2InitializeFCB( + PtrExt2FCB PtrNewFCB, // FCB structure to be initialized + PtrExt2VCB PtrVCB, // logical volume (VCB) pointer + PtrExt2ObjectName PtrObjectName, // name of the object + uint32 Flags, // is this a file/directory, etc. + PFILE_OBJECT PtrFileObject);// optional file object to be initialized + +extern PtrExt2FCB STDCALL Ext2LocateChildFCBInCore( + PtrExt2VCB PtrVCB, + PUNICODE_STRING PtrName, + ULONG ParentInodeNo ); + +extern PtrExt2FCB STDCALL Ext2LocateFCBInCore( + PtrExt2VCB PtrVCB, + ULONG InodeNo ); + + +extern ULONG STDCALL Ext2LocateFileInDisk( + PtrExt2VCB PtrVCB, + PUNICODE_STRING PtrCurrentName, + PtrExt2FCB PtrParentFCB, + ULONG *Type ); + +extern ULONG STDCALL Ext2CreateFile( + PtrExt2IrpContext PtrIrpContext, + PtrExt2VCB PtrVCB, + PUNICODE_STRING PtrName, + PtrExt2FCB PtrParentFCB, + ULONG Type); + +extern BOOLEAN STDCALL Ext2OverwriteFile( + PtrExt2FCB PtrFCB, + PtrExt2IrpContext PtrIrpContext); + +extern BOOLEAN STDCALL Ext2SupersedeFile( + PtrExt2FCB PtrFCB, + PtrExt2IrpContext PtrIrpContext); + +/************************************************************************* +* Prototypes for the file misc.c +*************************************************************************/ +extern NTSTATUS STDCALL Ext2InitializeZones( +void); + +extern void STDCALL Ext2DestroyZones( +void); + +extern BOOLEAN STDCALL Ext2IsIrpTopLevel( +PIRP Irp); // the IRP sent to our dispatch routine + +extern long STDCALL Ext2ExceptionFilter( +PtrExt2IrpContext PtrIrpContext, +PEXCEPTION_POINTERS PtrExceptionPointers); + +extern NTSTATUS STDCALL Ext2ExceptionHandler( +PtrExt2IrpContext PtrIrpContext, +PIRP Irp); + +extern void STDCALL Ext2LogEvent( +NTSTATUS Ext2EventLogId, // the Ext2 private message id +NTSTATUS RC); // any NT error code we wish to log ... + +extern PtrExt2ObjectName STDCALL Ext2AllocateObjectName( +void); + +extern void STDCALL Ext2ReleaseObjectName( +PtrExt2ObjectName PtrObjectName); + +extern PtrExt2CCB STDCALL Ext2AllocateCCB( +void ); + +extern PtrExt2FCB STDCALL Ext2GetUsedFCB( +PtrExt2VCB PtrVCB ); + +extern BOOLEAN STDCALL Ext2CloseClosableFCB( +PtrExt2FCB PtrFCB ); + +extern void STDCALL Ext2ReleaseCCB( +PtrExt2CCB PtrCCB); + +extern PtrExt2FCB STDCALL Ext2AllocateFCB( +void); + +extern NTSTATUS STDCALL Ext2CreateNewFCB( +PtrExt2FCB *ReturnedFCB, +LARGE_INTEGER AllocationSize, +LARGE_INTEGER EndOfFile, +PFILE_OBJECT PtrFileObject, +PtrExt2VCB PtrVCB, +PtrExt2ObjectName PtrObjectName); + +extern NTSTATUS STDCALL Ext2CreateNewCCB( +PtrExt2CCB *ReturnedCCB, +PtrExt2FCB PtrFCB, +PFILE_OBJECT PtrFileObject); + +extern void STDCALL Ext2ReleaseFCB( +PtrExt2FCB PtrFCB); + +extern PtrExt2FileLockInfo STDCALL Ext2AllocateByteLocks( +void); + +extern void STDCALL Ext2ReleaseByteLocks( +PtrExt2FileLockInfo PtrByteLocks); + +extern PtrExt2IrpContext STDCALL Ext2AllocateIrpContext( +PIRP Irp, +PDEVICE_OBJECT PtrTargetDeviceObject); + +extern void STDCALL Ext2ReleaseIrpContext( +PtrExt2IrpContext PtrIrpContext); + +extern NTSTATUS STDCALL Ext2PostRequest( +PtrExt2IrpContext PtrIrpContext, +PIRP PtrIrp); + +extern void STDCALL Ext2CommonDispatch( +void *Context); // actually an IRPContext structure + +extern void STDCALL Ext2InitializeVCB( +PDEVICE_OBJECT PtrVolumeDeviceObject, +PDEVICE_OBJECT PtrTargetDeviceObject, +PVPB PtrVPB, +PLARGE_INTEGER AllocationSize); + +extern void STDCALL Ext2CompleteRequest( + IN PIRP Irp OPTIONAL, + IN NTSTATUS Status + ); + +extern NTSTATUS STDCALL Ext2DenyAccess( + IN PIRP Irp + ); +extern NTSTATUS STDCALL Ext2GetFCB_CCB_VCB_FromFileObject( + IN PFILE_OBJECT PtrFileObject, + OUT PtrExt2FCB *PPtrFCB, + OUT PtrExt2CCB *PPtrCCB, + OUT PtrExt2VCB *PPtrVCB ); + +extern void STDCALL Ext2CopyUnicodeString( + IN OUT PUNICODE_STRING PtrDestinationString, + IN PUNICODE_STRING PtrSourceString ); + +extern void STDCALL Ext2CopyWideCharToUnicodeString( + IN OUT PUNICODE_STRING PtrDestinationString, + IN PCWSTR PtrSourceString ); + +extern void STDCALL Ext2CopyCharToUnicodeString( + IN OUT PUNICODE_STRING PtrDestinationString, + IN PCSTR PtrSourceString, + IN USHORT SourceStringLength ); + +extern void STDCALL Ext2CopyZCharToUnicodeString( + IN OUT PUNICODE_STRING PtrDestinationString, + IN PCSTR PtrSourceString ); + +extern void STDCALL Ext2DeallocateUnicodeString( + PUNICODE_STRING PtrUnicodeString ); + +extern void STDCALL Ext2ZerooutUnicodeString( + PUNICODE_STRING PtrUnicodeString ); + +extern BOOLEAN STDCALL Ext2SaveBCB( + PtrExt2IrpContext PtrIrpContext, + PBCB PtrBCB, + PFILE_OBJECT PtrFileObject); + +extern BOOLEAN STDCALL Ext2FlushSavedBCBs( + PtrExt2IrpContext PtrIrpContext); + +extern BOOLEAN STDCALL AssertBCB( + PBCB PtrBCB); + +extern ULONG STDCALL Ext2Align( + ULONG NumberToBeAligned, + ULONG Alignment); + +extern LONGLONG STDCALL Ext2Align64( + LONGLONG NumberToBeAligned, + LONGLONG Alignment); + +extern ULONG STDCALL Ext2GetCurrentTime(); + +/************************************************************************* +* Prototypes for the file cleanup.c +*************************************************************************/ +extern NTSTATUS STDCALL Ext2Cleanup( +PDEVICE_OBJECT DeviceObject, // the logical volume device object +PIRP Irp); // I/O Request Packet + +extern NTSTATUS STDCALL Ext2CommonCleanup( +PtrExt2IrpContext PtrIrpContext, +PIRP PtrIrp, +BOOLEAN FirstAttempt ); + +/************************************************************************* +* Prototypes for the file close.c +*************************************************************************/ +extern NTSTATUS STDCALL Ext2Close( +PDEVICE_OBJECT DeviceObject, // the logical volume device object +PIRP Irp); // I/O Request Packet + +extern NTSTATUS STDCALL Ext2CommonClose( +PtrExt2IrpContext PtrIrpContext, +PIRP PtrIrp, +BOOLEAN FirstAttempt ); + +/************************************************************************* +* Prototypes for the file read.c +*************************************************************************/ +extern NTSTATUS STDCALL Ext2Read( +PDEVICE_OBJECT DeviceObject, // the logical volume device object +PIRP Irp); // I/O Request Packet + +extern NTSTATUS STDCALL Ext2CommonRead( +PtrExt2IrpContext PtrIrpContext, +PIRP PtrIrp, +BOOLEAN FirstAttempt ); + +extern void * STDCALL Ext2GetCallersBuffer( +PIRP PtrIrp); + +extern NTSTATUS STDCALL Ext2LockCallersBuffer( +PIRP PtrIrp, +BOOLEAN IsReadOperation, +uint32 Length); + +extern void STDCALL Ext2MdlComplete( +PtrExt2IrpContext PtrIrpContext, +PIRP PtrIrp, +PIO_STACK_LOCATION PtrIoStackLocation, +BOOLEAN ReadCompletion); + +/************************************************************************* +* Prototypes for the file write.c +*************************************************************************/ +extern NTSTATUS STDCALL Ext2Write( +PDEVICE_OBJECT DeviceObject, // the logical volume device object +PIRP Irp); // I/O Request Packet + +extern NTSTATUS STDCALL Ext2CommonWrite( +PtrExt2IrpContext PtrIrpContext, +PIRP PtrIrp); + +extern void STDCALL Ext2DeferredWriteCallBack ( +void *Context1, // Should be PtrIrpContext +void *Context2); // Should be PtrIrp + +/************************************************************************* +* Prototypes for the file fileinfo.c +*************************************************************************/ +extern NTSTATUS STDCALL Ext2FileInfo( +PDEVICE_OBJECT DeviceObject, // the logical volume device object +PIRP Irp); // I/O Request Packet + +extern NTSTATUS STDCALL Ext2CommonFileInfo( +PtrExt2IrpContext PtrIrpContext, +PIRP PtrIrp); + +extern NTSTATUS STDCALL Ext2GetBasicInformation( + PtrExt2FCB PtrFCB, + PFILE_BASIC_INFORMATION PtrBuffer, + long *PtrReturnedLength); + +extern NTSTATUS STDCALL Ext2GetStandardInformation( + PtrExt2FCB PtrFCB, + PFILE_STANDARD_INFORMATION PtrStdInformation, + long *PtrReturnedLength); + +extern NTSTATUS STDCALL Ext2GetNetworkOpenInformation( + PtrExt2FCB PtrFCB, + PFILE_NETWORK_OPEN_INFORMATION PtrNetworkOpenInformation, + long *PtrReturnedLength ); + +extern NTSTATUS STDCALL Ext2GetFullNameInformation( + PtrExt2FCB PtrFCB, + PtrExt2CCB PtrCCB, + PFILE_NAME_INFORMATION PtrNameInformation, + long *PtrReturnedLength); + +extern NTSTATUS STDCALL Ext2SetBasicInformation( + PtrExt2IrpContext PtrIrpContext, + PtrExt2FCB PtrFCB, + PFILE_OBJECT PtrFileObject, + PFILE_BASIC_INFORMATION PtrFileInformation ); + +extern NTSTATUS STDCALL Ext2SetDispositionInformation( +PtrExt2FCB PtrFCB, +PtrExt2CCB PtrCCB, +PtrExt2VCB PtrVCB, +PFILE_OBJECT PtrFileObject, +PtrExt2IrpContext PtrIrpContext, +PIRP PtrIrp, +PFILE_DISPOSITION_INFORMATION PtrBuffer); + +extern NTSTATUS STDCALL Ext2SetAllocationInformation( +PtrExt2FCB PtrFCB, +PtrExt2CCB PtrCCB, +PtrExt2VCB PtrVCB, +PFILE_OBJECT PtrFileObject, +PtrExt2IrpContext PtrIrpContext, +PIRP PtrIrp, +PFILE_ALLOCATION_INFORMATION PtrBuffer); + +/************************************************************************* +* Prototypes for the file flush.c +*************************************************************************/ +extern NTSTATUS STDCALL Ext2Flush( +PDEVICE_OBJECT DeviceObject, // the logical volume device object +PIRP Irp); // I/O Request Packet + +extern NTSTATUS STDCALL Ext2CommonFlush( +PtrExt2IrpContext PtrIrpContext, +PIRP PtrIrp); + +extern void STDCALL Ext2FlushAFile( +PtrExt2NTRequiredFCB PtrReqdFCB, +PIO_STATUS_BLOCK PtrIoStatus); + +extern void STDCALL Ext2FlushLogicalVolume( +PtrExt2IrpContext PtrIrpContext, +PIRP PtrIrp, +PtrExt2VCB PtrVCB); + +extern NTSTATUS STDCALL Ext2FlushCompletion( +PDEVICE_OBJECT PtrDeviceObject, +PIRP PtrIrp, +PVOID Context); + +/************************************************************************* +* Prototypes for the file dircntrl.c +*************************************************************************/ +extern NTSTATUS STDCALL Ext2DirControl( +PDEVICE_OBJECT DeviceObject, // the logical volume device object +PIRP Irp); // I/O Request Packet + +extern NTSTATUS STDCALL Ext2CommonDirControl( +PtrExt2IrpContext PtrIrpContext, +PIRP PtrIrp); + +extern NTSTATUS STDCALL Ext2QueryDirectory( +PtrExt2IrpContext PtrIrpContext, +PIRP PtrIrp, +PEXTENDED_IO_STACK_LOCATION PtrIoStackLocation, +PFILE_OBJECT PtrFileObject, +PtrExt2FCB PtrFCB, +PtrExt2CCB PtrCCB); + +extern NTSTATUS STDCALL Ext2NotifyChangeDirectory( +PtrExt2IrpContext PtrIrpContext, +PIRP PtrIrp, +PEXTENDED_IO_STACK_LOCATION PtrIoStackLocation, +PFILE_OBJECT PtrFileObject, +PtrExt2FCB PtrFCB, +PtrExt2CCB PtrCCB); + +/************************************************************************* +* Prototypes for the file devcntrl.c +*************************************************************************/ +extern NTSTATUS STDCALL Ext2DeviceControl( +PDEVICE_OBJECT DeviceObject, // the logical volume device object +PIRP Irp); // I/O Request Packet + +extern NTSTATUS STDCALL Ext2CommonDeviceControl( +PtrExt2IrpContext PtrIrpContext, +PIRP PtrIrp); + +extern NTSTATUS STDCALL Ext2DevIoctlCompletion( +PDEVICE_OBJECT PtrDeviceObject, +PIRP PtrIrp, +void *Context); + +extern NTSTATUS STDCALL Ext2HandleQueryPath( +void *BufferPointer); + +/************************************************************************* +* Prototypes for the file shutdown.c +*************************************************************************/ +extern NTSTATUS STDCALL Ext2Shutdown( +PDEVICE_OBJECT DeviceObject, // the logical volume device object +PIRP Irp); // I/O Request Packet + +extern NTSTATUS STDCALL Ext2CommonShutdown( +PtrExt2IrpContext PtrIrpContext, +PIRP PtrIrp); + +/************************************************************************* +* Prototypes for the file volinfo.c +*************************************************************************/ +extern NTSTATUS STDCALL Ext2QueryVolInfo( +PDEVICE_OBJECT DeviceObject, // the logical volume device object +PIRP Irp); // I/O Request Packet + +NTSTATUS STDCALL Ext2SetVolInfo( + IN PDEVICE_OBJECT DeviceObject, // the logical volume device object + IN PIRP Irp); // I/O Request Packet + + +/************************************************************************* +* Prototypes for the file fastio.c +*************************************************************************/ +extern BOOLEAN STDCALL Ext2FastIoCheckIfPossible( +IN PFILE_OBJECT FileObject, +IN PLARGE_INTEGER FileOffset, +IN ULONG Length, +IN BOOLEAN Wait, +IN ULONG LockKey, +IN BOOLEAN CheckForReadOperation, +OUT PIO_STATUS_BLOCK IoStatus, +IN PDEVICE_OBJECT DeviceObject); + +extern BOOLEAN STDCALL Ext2FastIoRead( +IN PFILE_OBJECT FileObject, +IN PLARGE_INTEGER FileOffset, +IN ULONG Length, +IN BOOLEAN Wait, +IN ULONG LockKey, +OUT PVOID Buffer, +OUT PIO_STATUS_BLOCK IoStatus, +IN PDEVICE_OBJECT DeviceObject); + +extern BOOLEAN STDCALL Ext2FastIoWrite( +IN PFILE_OBJECT FileObject, +IN PLARGE_INTEGER FileOffset, +IN ULONG Length, +IN BOOLEAN Wait, +IN ULONG LockKey, +OUT PVOID Buffer, +OUT PIO_STATUS_BLOCK IoStatus, +IN PDEVICE_OBJECT DeviceObject); + +extern BOOLEAN STDCALL Ext2FastIoQueryBasicInfo( +IN PFILE_OBJECT FileObject, +IN BOOLEAN Wait, +OUT PFILE_BASIC_INFORMATION Buffer, +OUT PIO_STATUS_BLOCK IoStatus, +IN PDEVICE_OBJECT DeviceObject); + +extern BOOLEAN STDCALL Ext2FastIoQueryStdInfo( +IN PFILE_OBJECT FileObject, +IN BOOLEAN Wait, +OUT PFILE_STANDARD_INFORMATION Buffer, +OUT PIO_STATUS_BLOCK IoStatus, +IN PDEVICE_OBJECT DeviceObject); + +extern BOOLEAN STDCALL Ext2FastIoLock( +IN PFILE_OBJECT FileObject, +IN PLARGE_INTEGER FileOffset, +IN PLARGE_INTEGER Length, +PEPROCESS ProcessId, +ULONG Key, +BOOLEAN FailImmediately, +BOOLEAN ExclusiveLock, +OUT PIO_STATUS_BLOCK IoStatus, +IN PDEVICE_OBJECT DeviceObject); + +extern BOOLEAN STDCALL Ext2FastIoUnlockSingle( +IN PFILE_OBJECT FileObject, +IN PLARGE_INTEGER FileOffset, +IN PLARGE_INTEGER Length, +PEPROCESS ProcessId, +ULONG Key, +OUT PIO_STATUS_BLOCK IoStatus, +IN PDEVICE_OBJECT DeviceObject); + +extern BOOLEAN STDCALL Ext2FastIoUnlockAll( +IN PFILE_OBJECT FileObject, +PEPROCESS ProcessId, +OUT PIO_STATUS_BLOCK IoStatus, +IN PDEVICE_OBJECT DeviceObject); + +extern BOOLEAN STDCALL Ext2FastIoUnlockAllByKey( +IN PFILE_OBJECT FileObject, +PEPROCESS ProcessId, +ULONG Key, +OUT PIO_STATUS_BLOCK IoStatus, +IN PDEVICE_OBJECT DeviceObject); + +extern void STDCALL Ext2FastIoAcqCreateSec( +IN PFILE_OBJECT FileObject); + +extern void STDCALL Ext2FastIoRelCreateSec( +IN PFILE_OBJECT FileObject); + +extern BOOLEAN STDCALL Ext2AcqLazyWrite( +IN PVOID Context, +IN BOOLEAN Wait); + +extern void STDCALL Ext2RelLazyWrite( +IN PVOID Context); + +extern BOOLEAN STDCALL Ext2AcqReadAhead( +IN PVOID Context, +IN BOOLEAN Wait); + +extern void STDCALL Ext2RelReadAhead( +IN PVOID Context); + +// the remaining are only valid under NT Version 4.0 and later +#if(_WIN32_WINNT >= 0x0400) + +extern BOOLEAN STDCALL Ext2FastIoQueryNetInfo( +IN PFILE_OBJECT FileObject, +IN BOOLEAN Wait, +OUT PFILE_NETWORK_OPEN_INFORMATION Buffer, +OUT PIO_STATUS_BLOCK IoStatus, +IN PDEVICE_OBJECT DeviceObject); + +extern BOOLEAN STDCALL Ext2FastIoMdlRead( +IN PFILE_OBJECT FileObject, +IN PLARGE_INTEGER FileOffset, +IN ULONG Length, +IN ULONG LockKey, +OUT PMDL *MdlChain, +OUT PIO_STATUS_BLOCK IoStatus, +IN PDEVICE_OBJECT DeviceObject); + +extern BOOLEAN STDCALL Ext2FastIoMdlReadComplete( +IN PFILE_OBJECT FileObject, +OUT PMDL MdlChain, +IN PDEVICE_OBJECT DeviceObject); + +extern BOOLEAN STDCALL Ext2FastIoPrepareMdlWrite( +IN PFILE_OBJECT FileObject, +IN PLARGE_INTEGER FileOffset, +IN ULONG Length, +IN ULONG LockKey, +OUT PMDL *MdlChain, +OUT PIO_STATUS_BLOCK IoStatus, +IN PDEVICE_OBJECT DeviceObject); + +extern BOOLEAN STDCALL Ext2FastIoMdlWriteComplete( +IN PFILE_OBJECT FileObject, +IN PLARGE_INTEGER FileOffset, +OUT PMDL MdlChain, +IN PDEVICE_OBJECT DeviceObject); + +extern NTSTATUS STDCALL Ext2FastIoAcqModWrite( +IN PFILE_OBJECT FileObject, +IN PLARGE_INTEGER EndingOffset, +OUT PERESOURCE *ResourceToRelease, +IN PDEVICE_OBJECT DeviceObject); + +extern NTSTATUS STDCALL Ext2FastIoRelModWrite( +IN PFILE_OBJECT FileObject, +IN PERESOURCE ResourceToRelease, +IN PDEVICE_OBJECT DeviceObject); + +extern NTSTATUS STDCALL Ext2FastIoAcqCcFlush( +IN PFILE_OBJECT FileObject, +IN PDEVICE_OBJECT DeviceObject); + +extern NTSTATUS STDCALL Ext2FastIoRelCcFlush( +IN PFILE_OBJECT FileObject, +IN PDEVICE_OBJECT DeviceObject); + +#endif // (_WIN32_WINNT >= 0x0400) + +/************************************************************************* +* Prototypes for the file DiskIO.c +*************************************************************************/ +extern NTSTATUS STDCALL Ext2ReadLogicalBlocks( +PDEVICE_OBJECT PtrTargetDeviceObject, // the Target Device Object +VOID *Buffer, // The Buffer that takes the data read in +LARGE_INTEGER StartLogicalBlock, // The logical block from which reading is to start +unsigned int NoOfLogicalBlocks); // The no. of logical blocks to be read + +extern NTSTATUS STDCALL Ext2ReadPhysicalBlocks( + PDEVICE_OBJECT PtrTargetDeviceObject, // the Target Device Object + VOID *Buffer, // The Buffer that takes the data read in + LARGE_INTEGER StartBlock, // The Physical block from which reading is to start + unsigned int NoOfBlocks); // The no. of Physical blocks to be read + +/************************************************************************* +* Prototypes for the file metadata.c +*************************************************************************/ + +extern void STDCALL Ext2InitializeFCBInodeInfo ( + PtrExt2FCB PtrFCB ); + +extern NTSTATUS STDCALL Ext2ReadInode( + PtrExt2VCB PtrVcb, // the Volume Control Block + uint32 InodeNo, // The Inode no + PEXT2_INODE PtrInode ); // The Inode Buffer + +extern NTSTATUS STDCALL Ext2WriteInode( + PtrExt2IrpContext PtrIrpContext, + PtrExt2VCB PtrVcb, // the Volume Control Block + uint32 InodeNo, // The Inode no + PEXT2_INODE PtrInode // The Inode Buffer + ); + +extern ULONG STDCALL Ext2AllocInode( + PtrExt2IrpContext PtrIrpContext, + PtrExt2VCB PtrVCB, + ULONG ParentINodeNo ); + +extern BOOLEAN STDCALL Ext2DeallocInode( + PtrExt2IrpContext PtrIrpContext, + PtrExt2VCB PtrVCB, + ULONG INodeNo ); + +extern BOOLEAN STDCALL Ext2MakeNewDirectoryEntry( + PtrExt2IrpContext PtrIrpContext, // The Irp context + PtrExt2FCB PtrParentFCB, // Parent Folder FCB + PFILE_OBJECT PtrFileObject, // Parent Folder Object + PUNICODE_STRING PtrName, // New entry's name + ULONG Type, // The type of the new entry + ULONG NewInodeNo); // The inode no of the new entry... + +extern BOOLEAN STDCALL Ext2FreeDirectoryEntry( + PtrExt2IrpContext PtrIrpContext, + PtrExt2FCB PtrParentFCB, + PUNICODE_STRING PtrName); + +extern BOOLEAN STDCALL Ext2AddBlockToFile( + PtrExt2IrpContext PtrIrpContext, + PtrExt2VCB PtrVCB, + PtrExt2FCB PtrFCB, + PFILE_OBJECT PtrFileObject, + BOOLEAN UpdateFileSize); + +extern BOOLEAN STDCALL Ext2ReleaseDataBlocks( + PtrExt2FCB PtrFCB, + PtrExt2IrpContext PtrIrpContext); + +extern BOOLEAN STDCALL Ext2TruncateFileAllocationSize( + PtrExt2IrpContext PtrIrpContext, + PtrExt2FCB PtrFCB, + PFILE_OBJECT PtrFileObject, + PLARGE_INTEGER PtrAllocationSize ); + +extern ULONG STDCALL Ext2AllocBlock( + PtrExt2IrpContext PtrIrpContext, + PtrExt2VCB PtrVCB, + ULONG Count); + +extern BOOLEAN STDCALL Ext2DeallocBlock( + PtrExt2IrpContext PtrIrpContext, + PtrExt2VCB PtrVCB, + ULONG BlockNo); + +extern BOOLEAN STDCALL Ext2UpdateFileSize( + PtrExt2IrpContext PtrIrpContext, + PFILE_OBJECT PtrFileObject, + PtrExt2FCB PtrFCB); + + +extern BOOLEAN STDCALL Ext2DeleteFile( + PtrExt2FCB PtrFCB, + PtrExt2IrpContext PtrIrpContext); + +extern BOOLEAN STDCALL Ext2IsDirectoryEmpty( + PtrExt2FCB PtrFCB, + PtrExt2CCB PtrCCB, + PtrExt2IrpContext PtrIrpContext); + +extern NTSTATUS STDCALL Ext2RenameOrLinkFile( + PtrExt2FCB PtrSourceFCB, + PFILE_OBJECT PtrSourceFileObject, + PtrExt2IrpContext PtrIrpContext, + PIRP PtrIrp, + PFILE_RENAME_INFORMATION PtrRenameInfo); +/************************************************************************* +* Prototypes for the file io.c +*************************************************************************/ +extern NTSTATUS STDCALL Ext2PassDownSingleReadWriteIRP( + PtrExt2IrpContext PtrIrpContext, + PIRP PtrIrp, + PtrExt2VCB PtrVCB, + LARGE_INTEGER ByteOffset, + uint32 ReadWriteLength, + BOOLEAN SynchronousIo); + +extern NTSTATUS STDCALL Ext2PassDownMultiReadWriteIRP( + PEXT2_IO_RUN PtrIoRuns, + UINT Count, + ULONG TotalReadWriteLength, + PtrExt2IrpContext PtrIrpContext, + PtrExt2FCB PtrFCB, + BOOLEAN SynchronousIo); + +extern NTSTATUS STDCALL Ext2SingleSyncCompletionRoutine( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID Contxt + ); + +extern NTSTATUS STDCALL Ext2SingleAsyncCompletionRoutine ( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID Contxt + ); + +extern NTSTATUS STDCALL Ext2MultiSyncCompletionRoutine( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID Contxt); + +extern NTSTATUS STDCALL Ext2MultiAsyncCompletionRoutine( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID Contxt); + +#endif // _EXT2_PROTOS_H_ diff --git a/reactos/drivers/fs/ext2/inc/resource.h b/reactos/drivers/fs/ext2/inc/resource.h new file mode 100644 index 00000000000..8824707c58c --- /dev/null +++ b/reactos/drivers/fs/ext2/inc/resource.h @@ -0,0 +1,16 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by D:\Work\VC\Drivers\ext2FSD\src\ext2.rc +// + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NO_MFC 1 +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/reactos/drivers/fs/ext2/inc/struct.h b/reactos/drivers/fs/ext2/inc/struct.h new file mode 100644 index 00000000000..8bae485b34c --- /dev/null +++ b/reactos/drivers/fs/ext2/inc/struct.h @@ -0,0 +1,674 @@ +/************************************************************************* +* +* File: struct.h +* +* Module: Ext2 File System Driver (Kernel mode execution only) +* +* Description: +* This file contains structure definitions for the sample file system +* driver. Note that all structures are prefixed with the letters +* "Ext2". The structures are all aligned using normal alignment +* used by the compiler (typically quad-word aligned). +* +* Author: Manoj Paul Joseph +* +* +*************************************************************************/ + +#ifndef _EXT2_STRUCTURES_H_ +#define _EXT2_STRUCTURES_H_ + +/************************************************************************** + some useful definitions +**************************************************************************/ +#ifdef _CPU_X86_ +typedef char int8; +typedef short int16; +typedef int int32; + +typedef unsigned char uint8; +typedef unsigned short uint16; +typedef unsigned int uint32; + +typedef PVOID PBCB; + +// we will use the LARGE_INTEGER structure as defined by NT + +#else // Please define appropriate types here + +!!!! You must define your types here for compilation to proceed !!!! + +#endif // if _CPU_X86_ + +/************************************************************************** + some empty typedefs defined here so we can reference them easily +**************************************************************************/ +struct _Ext2Identifier; +struct _Ext2ObjectName; +struct _Ext2ContextControlBlock; +struct _Ext2NTRequiredFCB; +struct _Ext2DiskDependentFCB; +struct _Ext2FileControlBlock; +struct _Ext2FileByteLocks; +struct _Ext2VolumeControlBlock; +struct _Ext2IrpContext; +struct _Ext2Data; + +/************************************************************************** + each structure has a unique "node type" or signature associated with it +**************************************************************************/ +#define EXT2_NODE_TYPE_OBJECT_NAME (0xfdecba01) +#define EXT2_NODE_TYPE_CCB (0xfdecba02) +#define EXT2_NODE_TYPE_FCB (0xfdecba03) +#define EXT2_NODE_TYPE_LOCKS (0xfdecba04) +#define EXT2_NODE_TYPE_VCB (0xfdecba05) +#define EXT2_NODE_TYPE_IRP_CONTEXT (0xfdecba06) +#define EXT2_NODE_TYPE_GLOBAL_DATA (0xfdecba07) +#define EXT2_NODE_TYPE_IO_CONTEXT (0xfdecba08) +#define EXT2_NODE_TYPE_SAVED_BCB (0xfdecba09) +#define EXT2_NODE_TYPE_FREED (0x10101010) +#define EXT2_NODE_TYPE_INVALID (0x10101010) + +/************************************************************************** + every structure has a node type, and a node size associated with it. + The node type serves as a signature field. The size is used for + consistency checking ... +**************************************************************************/ +typedef struct _Ext2Identifier { + uint32 NodeType; // a 32 bit identifier for the structure + uint32 NodeSize; // computed as sizeof(structure) +} Ext2Identifier, *PtrExt2Identifier; + +/************************************************************************** + Structures for byte-range lock support. +**************************************************************************/ +typedef struct Ext2FileLockAnchor { + LIST_ENTRY GrantedFileLockList; + LIST_ENTRY PendingFileLockList; +} Ext2FileLockAnchor, *PtrExt2FileLockAnchor; + +typedef struct Ext2FileLockInfo { + Ext2Identifier NodeIdentifier; + uint32 FileLockFlags; + PVOID OwningProcess; + LARGE_INTEGER StartingOffset; + LARGE_INTEGER Length; + LARGE_INTEGER EndingOffset; + ULONG Key; + BOOLEAN ExclusiveLock; + PIRP PendingIRP; + LIST_ENTRY NextFileLockEntry; +} Ext2FileLockInfo, *PtrExt2FileLockInfo; + +#define EXT2_BYTE_LOCK_NOT_FROM_ZONE (0x80000000) +#define EXT2_BYTE_LOCK_IS_PENDING (0x00000001) + +/************************************************************************** + Every open on-disk object must have a name associated with it + This name has two components: + (a) the path-name (prefix) that leads to this on-disk object + (b) the name of the object itself + Note that with multiply linked objects, a single object might be + associated with more than one name structure. + This sample FSD does not correctly support multiply linked objects. + + This structure must be quad-word aligned because it is zone allocated. +**************************************************************************/ +typedef struct _Ext2ObjectName { + Ext2Identifier NodeIdentifier; + uint32 ObjectNameFlags; + // an absolute pathname of the object is stored below + UNICODE_STRING ObjectName; +} Ext2ObjectName, *PtrExt2ObjectName; + +#define EXT2_OB_NAME_NOT_FROM_ZONE (0x80000000) + +/************************************************************************** + Each file open instance is represented by a context control block. + For each successful create/open request; a file object and a CCB will + be created. + For open operations performed internally by the FSD, there may not + exist file objects; but a CCB will definitely be created. + + This structure must be quad-word aligned because it is zone allocated. +**************************************************************************/ +typedef struct _Ext2ContextControlBlock { + Ext2Identifier NodeIdentifier; + // ptr to the associated FCB + struct _Ext2FileControlBlock *PtrFCB; + // all CCB structures for a FCB are linked together + LIST_ENTRY NextCCB; + // each CCB is associated with a file object + PFILE_OBJECT PtrFileObject; + // flags (see below) associated with this CCB + uint32 CCBFlags; + // current byte offset is required sometimes + LARGE_INTEGER CurrentByteOffset; + // if this CCB represents a directory object open, we may + // need to maintain a search pattern + + // PSTRING DirectorySearchPattern; + UNICODE_STRING DirectorySearchPattern; + + // The full path name for the file... + UNICODE_STRING AbsolutePathName; + + // Rename/Link Target file name + // Used only in a Rename/Link operation + UNICODE_STRING RenameLinkTargetFileName; + + // we must maintain user specified file time values + uint32 UserSpecifiedTime; + + +} Ext2CCB, *PtrExt2CCB; + + +/************************************************************************** + the following CCBFlags values are relevant. These flag + values are bit fields; therefore we can test whether + a bit position is set (1) or not set (0). +**************************************************************************/ + +// some on-disk file/directories are opened by EXT2 itself +// as opposed to being opened on behalf of a user process +#define EXT2_CCB_OPENED_BY_EXT2 (0x00000001) +// the file object specified synchronous access at create/open time. +// this implies that EXT2 must maintain the current byte offset +#define EXT2_CCB_OPENED_FOR_SYNC_ACCESS (0x00000002) +// file object specified sequential access for this file +#define EXT2_CCB_OPENED_FOR_SEQ_ACCESS (0x00000004) +// the CCB has had an IRP_MJ_CLEANUP issued on it. we must +// no longer allow the file object / CCB to be used in I/O requests. +#define EXT2_CCB_CLEANED (0x00000008) +// if we were invoked via the fast i/o path to perform file i/o; +// we should set the CCB access/modification time at cleanup +#define EXT2_CCB_ACCESSED (0x00000010) +#define EXT2_CCB_MODIFIED (0x00000020) +// if an application process set the file date time, we must +// honor that request and *not* overwrite the values at cleanup +#define EXT2_CCB_ACCESS_TIME_SET (0x00000040) +#define EXT2_CCB_MODIFY_TIME_SET (0x00000080) +#define EXT2_CCB_CREATE_TIME_SET (0x00000100) + +#define EXT2_CCB_NOT_FROM_ZONE (0x80000000) + +// this CCB was allocated for a "volume open" operation +#define EXT2_CCB_VOLUME_OPEN (0x00000100) + +/************************************************************************** + each open file/directory/volume is represented by a file control block. + NOTE: Currently, EXT2 does not handle multiply linked files correctly. + In your FSD implementation, you must be careful about handling + such on-disk files correctly i.e. a single (unique) FCB must + represent an on-disk file/directory regardless of the path used + to access the on-disk object. + With the current EXT2 implementation, an on-disk file object + with more than a single (hard) link will be treated incorrectly! + + Each FCB can logically be divided into two: + (a) a structure that must have a field of type FSRTL_COMMON_FCB_HEADER + as the first field in the structure. + This portion should also contain other structures/resources required + by the NT Cache Manager + We will call this structure the "NT Required" FCB. Note that this + portion of the FCB must be allocated from non-paged pool. + (b) the remainder of the FCB is dependent upon the particular FSD + requirements. + This portion of the FCB could possibly be allocated from paged + memory, though in the sample FSD, it will always be allocated + from non-paged pool. + + FCB structures are protected by the MainResource as well as the + PagingIoResource. Of course, if your FSD implementation requires + it, you can associate other syncronization structures with the + FCB. + + This structure must be quad-word aligned because it is zone allocated. +**************************************************************************/ +typedef struct _Ext2NTRequiredFCB +{ + FSRTL_COMMON_FCB_HEADER CommonFCBHeader; + SECTION_OBJECT_POINTERS SectionObject; + ERESOURCE MainResource; + ERESOURCE PagingIoResource; +} Ext2NTRequiredFCB, *PtrExt2NTRequiredFCB; + +typedef struct _Ext2DiskDependentFCB +{ + // although the sample FSD does not maintain on-disk data structures, + // this structure serves as a reminder of the logical separation that + // your FSD can maintain between the disk dependent and the disk + // independent portions of the FCB. + uint16 DummyField; // placeholder +} Ext2DiskDependentFCB, *PtrExt2DiskDependentFCB; + +typedef struct _Ext2FileControlBlock +{ + Ext2Identifier NodeIdentifier; + // we will go ahead and embed the "NT Required FCB" right here. + // Note though that it is just as acceptable to simply allocate + // memory separately for the other half of the FCB and store a + // pointer to the "NT Required" portion here instead of embedding + // it ... + Ext2NTRequiredFCB NTRequiredFCB; + // the disk dependent portion of the FCB is embedded right here + Ext2DiskDependentFCB DiskDependentFCB; + // this FCB belongs to some mounted logical volume + struct _Ext2VolumeControlBlock *PtrVCB; + // to be able to access all open file(s) for a volume, we will + // link all FCB structures for a logical volume together + LIST_ENTRY NextFCB; + + // to be used if this FCB is on the Closable FCB List... + struct _ClosableFCBs + { + LIST_ENTRY ClosableFCBList; + BOOLEAN OnClosableFCBList; + }ClosableFCBs; + + // some state information for the FCB is maintained using the + // flags field + uint32 FCBFlags; + // all CCB's for this particular FCB are linked off the following + // list head. + LIST_ENTRY CCBListHead; + // NT requires that a file system maintain and honor the various + // SHARE_ACCESS modes ... + SHARE_ACCESS FCBShareAccess; + // to identify the lazy writer thread(s) we will grab and store + // the thread id here when a request to acquire resource(s) + // arrives .. + uint32 LazyWriterThreadID; + // whenever a file stream has a create/open operation performed, + // the Reference count below is incremented AND the OpenHandle count + // below is also incremented. + // When an IRP_MJ_CLEANUP is received, the OpenHandle count below + // is decremented. + // When an IRP_MJ_CLOSE is received, the Reference count below is + // decremented. + // When the Reference count goes down to zero, the FCB can be de-allocated. + // Note that a zero Reference count implies a zero OpenHandle count. + // This invariant must always hold true ... (if it is really an invariant, + // shoudn't the previous statement be redundant ... hmmm!!!) + LONG ReferenceCount; + LONG OpenHandleCount; + // for the sample fsd, there exists a 1-1 correspondence between an + // object name structure and a FCB + PtrExt2ObjectName FCBName; + // we will maintain some time information here to make our life easier + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + // Byte-range file lock support (we roll our own) + Ext2FileLockAnchor FCBByteRangeLock; + // The OPLOCK support package requires the following structure + OPLOCK FCBOplock; + + // The I-Node no of this file / folder + ULONG INodeNo; + ULONG ParentINodeNo; + // Pointers to blocks + uint32 IBlock[EXT2_N_BLOCKS]; + + USHORT LinkCount; + union _DCBFCB + { + struct + { + PFILE_OBJECT PtrDirFileObject; + } Dcb; + + struct _FCB + { + PFILE_OBJECT PtrDirFileObject; + // FCB specific stuff go here... + } Fcb; + + }DcbFcb; + +} Ext2FCB, *PtrExt2FCB, Ext2DCB, *PtrExt2DCB; + +/************************************************************************** + the following FCBFlags values are relevant. These flag + values are bit fields; therefore we can test whether + a bit position is set (1) or not set (0). +**************************************************************************/ +#define EXT2_FCB_IN_INIT (0x00000001) +#define EXT2_FCB_IN_TEARDOWN (0x00000002) +#define EXT2_FCB_PAGE_FILE (0x00000004) +#define EXT2_FCB_DIRECTORY (0x00000008) +#define EXT2_FCB_ROOT_DIRECTORY (0x00000018) +#define EXT2_FCB_WRITE_THROUGH (0x00000020) +#define EXT2_FCB_MAPPED (0x00000040) +#define EXT2_FCB_FAST_IO_READ_IN_PROGESS (0x00000080) +#define EXT2_FCB_FAST_IO_WRITE_IN_PROGESS (0x00000100) +#define EXT2_FCB_DELETE_ON_CLOSE (0x00000200) +#define EXT2_FCB_MODIFIED (0x00000400) +#define EXT2_FCB_ACCESSED (0x00000800) +#define EXT2_FCB_READ_ONLY (0x00001000) + +#define EXT2_INITIALIZED_MAIN_RESOURCE (0x00002000) +#define EXT2_INITIALIZED_PAGING_IO_RESOURCE (0x00004000) +#define EXT2_FCB_BLOCKS_INITIALIZED (0x00008000) +#define EXT2_FCB_SPECIAL_FILE (0x00010000) +#define EXT2_FCB_HIDDEN_FILE (0x00020000) +#define EXT2_FCB_NOT_FROM_ZONE (0x80000000) + + +typedef struct _GroupDescriptors +{ + uint32 InodeTablesBlock; /* Inodes table block => bg_inode_table */ + uint32 InodeBitmapBlock; /* Inodes bitmap block => bg_inode_bitmap */ + uint32 BlockBitmapBlock; /* Blocks bitmap block => bg_block_bitmap */ + uint32 FreeBlocksCount; + uint32 FreeInodesCount; +}Ext2GroupDescriptors, *PtrExt2GroupDescriptors; + + + +/************************************************************************** + A logical volume is represented using the following structure. + This structure is allocated as part of the device extension + for a device object that this sample FSD will create, to represent + the mounted logical volume. + + NOTE: If you were to extend this sample FSD to be a "real" FSD, + you would be worried about allocated clusters/sectiors, + bitmaps providing such information for the mounted volume, + dirty/modified clusters/sectiors etc. + This sample FSD does not maintain such information in the + in-memory VCB, though you may wish to consider it. +**************************************************************************/ +typedef struct _Ext2VolumeControlBlock +{ + Ext2Identifier NodeIdentifier; + + // Required to use the Cache Manager. + FSRTL_COMMON_FCB_HEADER CommonVCBHeader; + SECTION_OBJECT_POINTERS SectionObject; + // a resource to protect the fields contained within the VCB + ERESOURCE VCBResource; + + // a resource to synchronise paging io + ERESOURCE PagingIoResource; + + // Pointer to a stream file object created for the volume information + // to be more easily read from secondary storage (with the support of + // the NT Cache Manager). + PFILE_OBJECT PtrStreamFileObject; + + // each VCB is accessible off a global linked list + LIST_ENTRY NextVCB; + + // each VCB points to a VPB structure created by the NT I/O Manager + PVPB PtrVPB; + + // a set of flags that might mean something useful + uint32 VCBFlags; + + // A count of the number of open files/directories + // As long as the count is != 0, the volume cannot + // be dismounted or locked. + uint32 VCBOpenCount; + + // a global list of all FCB structures associated with the VCB + LIST_ENTRY FCBListHead; + + // + // a list of FCBs created at the FSD's initiative... + // These FCBs have a reference count of 0 + // This list should never be allowed to cross a limit... + // + struct Ext2ClosableFCB + { + LIST_ENTRY ClosableFCBListHead; + ULONG Count; + }ClosableFCBs; + // we will maintain a global list of IRP's that are pending + // because of a directory notify request. + LIST_ENTRY NextNotifyIRP; + // the above list is protected only by the mutex declared below + KMUTEX NotifyIRPMutex; + // for each mounted volume, we create a device object. Here then + // is a back pointer to that device object + PDEVICE_OBJECT VCBDeviceObject; + // We also retain a pointer to the physical device object on which we + // have mounted ourselves. The I/O Manager passes us a pointer to this + // device object when requesting a mount operation. + PDEVICE_OBJECT TargetDeviceObject; + // the volume structure contains a pointer to the root directory FCB + PtrExt2FCB PtrRootDirectoryFCB; + // the complete name of the user visible drive letter we serve + uint8 *PtrVolumePath; + // For volume open operations, we do not create a FCB (we use the VCB + // directly instead). Therefore, all CCB structures for the volume + // open operation are linked directly off the VCB + LIST_ENTRY VolumeOpenListHead; + + + // Volume information + ULONG BlocksCount; + ULONG InodesCount; + ULONG ReservedBlocksCount; + ULONG FreeBlocksCount; + ULONG FreeInodesCount; + ULONG LogBlockSize; // Block size = 1024 << LogBlockSize + + // Group Information Saved up in the VCB... + PtrExt2GroupDescriptors PtrGroupDescriptors; + ULONG NoOfGroups; + + uint32 InodesPerGroup; + uint32 BlocksPerGroup; + +} Ext2VCB, *PtrExt2VCB; + +// some valid flags for the VCB +#define EXT2_VCB_FLAGS_VOLUME_MOUNTED (0x00000001) +#define EXT2_VCB_FLAGS_VOLUME_LOCKED (0x00000002) +#define EXT2_VCB_FLAGS_BEING_DISMOUNTED (0x00000004) +#define EXT2_VCB_FLAGS_SHUTDOWN (0x00000008) +#define EXT2_VCB_FLAGS_VOLUME_READ_ONLY (0x00000010) + +#define EXT2_VCB_FLAGS_VCB_INITIALIZED (0x00000020) + +typedef struct _EXT2_IO_CONTEXT +{ + Ext2Identifier NodeIdentifier; + ULONG ReadWriteLength; + LONG Count; + PIRP PtrMasterIrp; + PKEVENT PtrSyncEvent; + +} EXT2_IO_CONTEXT, *PEXT2_IO_CONTEXT; + + +typedef struct _Ext2SavedBCBs +{ + Ext2Identifier NodeIdentifier; + PBCB PtrBCB; + LIST_ENTRY SavedBCBsListEntry; + +} EXT2_SAVED_BCBS, *PEXT2_SAVED_BCBS; + + +/************************************************************************** + The IRP context encapsulates the current request. This structure is + used in the "common" dispatch routines invoked either directly in + the context of the original requestor, or indirectly in the context + of a system worker thread. +**************************************************************************/ +typedef struct _Ext2IrpContext +{ + Ext2Identifier NodeIdentifier; + uint32 IrpContextFlags; + // copied from the IRP + uint8 MajorFunction; + // copied from the IRP + uint8 MinorFunction; + + // to queue this IRP for asynchronous processing + WORK_QUEUE_ITEM WorkQueueItem; + // the IRP for which this context structure was created + PIRP Irp; + // the target of the request (obtained from the IRP) + PDEVICE_OBJECT TargetDeviceObject; + // if an exception occurs, we will store the code here + NTSTATUS SavedExceptionCode; + + // This list entry is used if asnchronous processing is required... + LIST_ENTRY ThreadQueueListEntry; + + // This list entry is used if BCBs are to be saved and then flushed... + // Could have been put somewhere else... + LIST_ENTRY SavedBCBsListHead; + ULONG SavedCount; + +} Ext2IrpContext, *PtrExt2IrpContext; + +#define EXT2_IRP_CONTEXT_CAN_BLOCK (0x00000001) +#define EXT2_IRP_CONTEXT_WRITE_THROUGH (0x00000002) +#define EXT2_IRP_CONTEXT_EXCEPTION (0x00000004) +#define EXT2_IRP_CONTEXT_DEFERRED_WRITE (0x00000008) +#define EXT2_IRP_CONTEXT_ASYNC_PROCESSING (0x00000010) +#define EXT2_IRP_CONTEXT_NOT_TOP_LEVEL (0x00000020) + +#define EXT2_IRP_CONTEXT_NOT_FROM_ZONE (0x80000000) + +typedef struct _Ext2ThreadQueue +{ + HANDLE QueueHandlerThread; + + LIST_ENTRY ThreadQueueListHead; // This holds the Contexts + // that are to be scheduled + KSPIN_LOCK SpinLock; // To synchronize access to + // the list + KEVENT QueueEvent; // The Worker thread queue + // package waits on this event +} Ext2ThreadQueue; + +/************************************************************************** + we will store all of our global variables in one structure. + Global variables are not specific to any mounted volume BUT + by definition are required for successful operation of the + FSD implementation. +**************************************************************************/ +typedef struct _Ext2Data +{ + Ext2Identifier NodeIdentifier; + // the fields in this list are protected by the following resource + ERESOURCE GlobalDataResource; + // each driver has a driver object created for it by the NT I/O Mgr. + // we are no exception to this rule. + PDRIVER_OBJECT Ext2DriverObject; + // we will create a device object for our FSD as well ... + // Although not really required, it helps if a helper application + // writen by us wishes to send us control information via + // IOCTL requests ... + PDEVICE_OBJECT Ext2DeviceObject; + // we will keep a list of all logical volumes for our sample FSD + LIST_ENTRY NextVCB; + // the NT Cache Manager, the I/O Manager and we will conspire + // to bypass IRP usage using the function pointers contained + // in the following structure + FAST_IO_DISPATCH Ext2FastIoDispatch; + // The NT Cache Manager uses the following call backs to ensure + // correct locking hierarchy is maintained + CACHE_MANAGER_CALLBACKS CacheMgrCallBacks; + // structures allocated from a zone need some fields here. Note + // that under version 4.0, it might be better to use lookaside + // lists + KSPIN_LOCK ZoneAllocationSpinLock; + ZONE_HEADER ObjectNameZoneHeader; + ZONE_HEADER CCBZoneHeader; + ZONE_HEADER FCBZoneHeader; + ZONE_HEADER ByteLockZoneHeader; + ZONE_HEADER IrpContextZoneHeader; + void *ObjectNameZone; + void *CCBZone; + void *FCBZone; + void *ByteLockZone; + void *IrpContextZone; + + // currently, there is a single default zone size value used for + // all zones. This should ideally be changed by you to be 1 per + // type of zone (e.g. a default size for the FCB zone might be + // different from the default size for the ByteLock zone). + + // Of course, you will need to use different values (min/max) + // for lookaside lists (if you decide to use them instead) + uint32 DefaultZoneSizeInNumStructs; + + // some state information is maintained in the flags field + uint32 Ext2Flags; + + // Handle returned by the MUP is stored here. + HANDLE MupHandle; + + // Time difference + LARGE_INTEGER TimeDiff; + + // The Worker Thread package uses this structure... + Ext2ThreadQueue ThreadQueue; + +}Ext2Data, *PtrExt2Data; + +// valid flag values for the global data structure +#define EXT2_DATA_FLAGS_RESOURCE_INITIALIZED (0x00000001) +#define EXT2_DATA_FLAGS_ZONES_INITIALIZED (0x00000002) + +// a default size of the number of pages of non-paged pool allocated +// for each of the zones ... + +// Note that the values are absolutely arbitrary, the only information +// worth using from the values themselves is that they increase for +// larger systems (i.e. systems with more memory) +#define EXT2_DEFAULT_ZONE_SIZE_SMALL_SYSTEM (0x4) +#define EXT2_DEFAULT_ZONE_SIZE_MEDIUM_SYSTEM (0x8) +#define EXT2_DEFAULT_ZONE_SIZE_LARGE_SYSTEM (0xc) + +// another simplistic (brain dead ? :-) method used is to simply double +// the values for a "server" machine + +// So, for all you guys who "modified" the registry ;-) to change the +// wkstation into a server, tough luck ! +#define EXT2_NTAS_MULTIPLE (0x2) + +/*************************************************************************** +The following locking hierarchy is maintained in this sample filesystem +driver: + +(a) the global structure resource can be acquired at any time. However, + it is an "end resource" i.e. once acquired, no other resource can + be obtained until the global structure resource is released. +(b) the logical volume resource must be acquired (if required) before + any of the other resources are acquired. +(c) a file control block can be acquired next (if required). If two + FCB structures need to be acquired, the FCB "higher" in the directory + tree must be acquired first. + For a FCB, the "main resource" must be acquired first before a + "paging i/o" resource is acquired. + +Whenever a file is opened, the logical volume structure is referenced. +This ensures that the volume cannot be dismounted while any file is open. + +***************************************************************************/ + +typedef struct _IO_RUN +{ + UINT LogicalBlock; + UINT StartOffset; + UINT EndOffset; + PIRP PtrAssociatedIrp; + +} EXT2_IO_RUN, *PEXT2_IO_RUN; + +typedef struct _SIBlocks +{ + PBCB PtrBCB; + ULONG * PtrSIBlocks; +} EXT2_SIBLOCKS, *PEXT2_SIBLOCKS; + +#endif // has this file been included? + diff --git a/reactos/drivers/fs/ext2/inode.c b/reactos/drivers/fs/ext2/inode.c deleted file mode 100644 index cb0e1ee49a8..00000000000 --- a/reactos/drivers/fs/ext2/inode.c +++ /dev/null @@ -1,148 +0,0 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS kernel - * FILE: services/fs/ext2/inode.c - * PURPOSE: Manipulating inodes - * PROGRAMMER: David Welch (welch@cwcom.net) - * UPDATE HISTORY: - * 26/12/98: Created - */ - -/* INCLUDES ****************************************************************/ - -#include - -//#define NDEBUG -#include - -#include "ext2fs.h" - -/* FUNCTIONS ***************************************************************/ - -struct ext2_group_desc* Ext2LoadGroupDesc(PDEVICE_EXTENSION DeviceExt, - ULONG block_group) -{ - struct ext2_group_desc* buffer; - ULONG block; - struct ext2_group_desc* gdp; - - buffer = ExAllocatePool(NonPagedPool, BLOCKSIZE); - - block = block_group / (BLOCKSIZE / sizeof(struct ext2_group_desc)); - - Ext2ReadSectors(DeviceExt->StorageDevice, - 2 + block, - 1, - buffer); - - gdp = &buffer[block_group % (BLOCKSIZE / sizeof(struct ext2_group_desc))]; - - DPRINT("gdp->bg_free_blocks_count %d\n",gdp->bg_free_blocks_count); - DPRINT("gdp->bg_inode_table %d\n",gdp->bg_inode_table); - - return(gdp); - -} - -#define INODES_PER_PAGE (PAGE_SIZE / sizeof(struct ext2_inode)) -#define INODES_PER_BLOCK (BLOCKSIZE / sizeof(struct ext2_inode)) - -VOID Ext2LoadInode(PDEVICE_EXTENSION DeviceExt, - ULONG ino, - PEXT2_INODE Inode) -{ - ULONG block_group; - struct ext2_group_desc* gdp; - ULONG offset; - ULONG dsec; - BOOLEAN Uptodate; - struct ext2_inode* ibuffer; - - DPRINT("Ext2LoadInode(DeviceExt %x, ino %d, Inode %x)\n", - DeviceExt, ino, Inode); - - block_group = (ino - 1) / DeviceExt->superblock->s_inodes_per_group; - - DPRINT("block_group %d\n",block_group); - - gdp = Ext2LoadGroupDesc(DeviceExt, block_group); - - offset = (ino - 1) % DeviceExt->superblock->s_inodes_per_group; - - DPRINT("offset %d\n", offset); - - dsec = (gdp->bg_inode_table + (offset / INODES_PER_BLOCK)) * BLOCKSIZE; - - DPRINT("dsec %d (dsec/BLOCKSIZE) %d PAGE_ROUND_DOWN(dsec) %d\n", - dsec, (dsec/BLOCKSIZE), PAGE_ROUND_DOWN(dsec)); - - CcRequestCachePage(DeviceExt->Bcb, - PAGE_ROUND_DOWN(dsec), - &Inode->BaseAddress, - &Uptodate, - &Inode->CacheSeg); - DPRINT("PAGE_ROUND_DOWN(dsec)/BLOCKSIZE %d\n", - PAGE_ROUND_DOWN(dsec)/BLOCKSIZE); - if (!Uptodate) - { - Ext2ReadSectors(DeviceExt->StorageDevice, - PAGE_ROUND_DOWN(dsec) / BLOCKSIZE, - 4, - Inode->BaseAddress); - } - ibuffer = ((struct ext2_inode *)Inode->BaseAddress) + - (dsec - PAGE_ROUND_DOWN(dsec)); - DPRINT("Inode->BaseAddress 0x%x ibuffer 0x%x\n", - Inode->BaseAddress, ibuffer); - Inode->inode = &ibuffer[offset % INODES_PER_PAGE]; - - DPRINT("inode->i_uid %d\n",Inode->inode->i_uid); - DPRINT("inode->i_links_count %d\n",Inode->inode->i_links_count); - DPRINT("inode->i_blocks %d\n",Inode->inode->i_blocks); - - DPRINT("Ext2LoadInode() finished\n"); -} - -VOID Ext2ReleaseInode(PDEVICE_EXTENSION DeviceExt, - PEXT2_INODE Inode) -{ - CcReleaseCachePage(DeviceExt->Bcb, - Inode->CacheSeg, - TRUE); - Inode->CacheSeg = NULL; - Inode->BaseAddress = NULL; - Inode->inode = NULL; -} - -VOID Ext2ReadInode(PDEVICE_EXTENSION DeviceExt, - ULONG ino, - struct ext2_inode* inode) -{ - ULONG block_group; - struct ext2_group_desc* gdp; - ULONG offset; - struct ext2_inode* buffer; - - DPRINT("Ext2ReadInode(DeviceExt %x, ino %d, inode %x)\n", - DeviceExt,ino,inode); - - block_group = (ino - 1) / DeviceExt->superblock->s_inodes_per_group; - - gdp = Ext2LoadGroupDesc(DeviceExt, block_group); - - - - offset = (ino - 1) % DeviceExt->superblock->s_inodes_per_group; - - buffer = ExAllocatePool(NonPagedPool, BLOCKSIZE); - Ext2ReadSectors(DeviceExt->StorageDevice, - gdp->bg_inode_table + (offset / INODES_PER_BLOCK), - 1, - buffer); - memcpy(inode,&buffer[offset % INODES_PER_BLOCK],sizeof(struct ext2_inode)); - - DPRINT("inode->i_uid %d\n",inode->i_uid); - DPRINT("inode->i_links_count %d\n",inode->i_links_count); - DPRINT("inode->i_blocks %d\n",inode->i_blocks); - -} diff --git a/reactos/drivers/fs/ext2/makefile b/reactos/drivers/fs/ext2/makefile index 6925dbab3b4..7e59c8e3c4d 100644 --- a/reactos/drivers/fs/ext2/makefile +++ b/reactos/drivers/fs/ext2/makefile @@ -1,26 +1,54 @@ # $Id$ PATH_TO_TOP = ../../.. - +TARGET_BOOTSTRAP = yes TARGET_TYPE = driver +TARGET_NAME = ext2 +TARGET_GCCLIBS = gcc +TARGET_CFLAGS = -Iinc -I$(W32API_PATH)/include/ddk -D__USE_W32API \ + -D_CPU_X86_ -O2 -DDBG=1 -D__REACTOS__ -TARGET_NAME = ext2fs +# FIXME: Enabling this reveals that there is quite a few pieces of unused +# code. +#TARGET_CFLAGS += -Wall -TARGET_CFLAGS = -I./include -DDBG +# FIXME: Do not b*tch about multi-character constants used for TAGs. Use +# the TAG macro instead? +TARGET_CFLAGS += -Wno-multichar + +# FIXME: Force STDCALL as default calling convention. Due bug in GCC it +# it still produces non-STDCALL function if an function declaration +# preceeds the actual function definition and doesn't explicitely +# specify calling convention. +TARGET_CFLAGS += -mrtd + +# FIXME: Until PSEH and MS2PS will get up to speed we'll ignore SEH. +TARGET_CFLAGS += "-Dtry=if(1)" "-Dexcept(x)=if(0)" "-Dfinally=if(1)" TARGET_OBJECTS = \ - attr.o \ - blockdev.o \ - dir.o \ - file.o \ - inode.o \ - rw.o \ - quota.o \ - security.o \ - super.o + src/cleanup.o \ + src/close.o \ + src/create.o \ + src/devcntrl.o \ + src/dircntrl.o \ + src/DiskIO.o \ + src/ext2init.o \ + src/fastio.o \ + src/fileinfo.o \ + src/flush.o \ + src/fsctrl.o \ + src/io.o \ + src/metadata.o \ + src/misc.o \ + src/read.o \ + src/shutdown.o \ + src/volinfo.o \ + src/write.o +TARGET_RC_SRCS = src/ext2.rc +DEP_OBJECTS = $(TARGET_OBJECTS) + +include $(PATH_TO_TOP)/config include $(PATH_TO_TOP)/rules.mak - include $(TOOLS_PATH)/helper.mk - -# EOF +include $(TOOLS_PATH)/depend.mk diff --git a/reactos/drivers/fs/ext2/quota.c b/reactos/drivers/fs/ext2/quota.c deleted file mode 100644 index d7130c76fad..00000000000 --- a/reactos/drivers/fs/ext2/quota.c +++ /dev/null @@ -1,49 +0,0 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS kernel - * FILE: services/fs/ext2/quota.c - * PURPOSE: Quota support - * PROGRAMMER: David Welch (welch@mcmail.com) - * UPDATE HISTORY: - */ - -/* INCLUDES *****************************************************************/ - -#include -#include -#include - -//#define NDEBUG -#include - -#include "ext2fs.h" - -/* FUNCTIONS ****************************************************************/ - -NTSTATUS STDCALL -Ext2QueryQuota(PDEVICE_OBJECT DeviceObject, PIRP Irp) -{ - NTSTATUS Status; - - Status = STATUS_NOT_IMPLEMENTED; - - Irp->IoStatus.Status = Status; - Irp->IoStatus.Information = 0; - - IoCompleteRequest(Irp, IO_NO_INCREMENT); - return(Status); -} - -NTSTATUS STDCALL -Ext2SetQuota(PDEVICE_OBJECT DeviceObject, PIRP Irp) -{ - NTSTATUS Status; - - Status = STATUS_NOT_IMPLEMENTED; - - Irp->IoStatus.Status = Status; - Irp->IoStatus.Information = 0; - - IoCompleteRequest(Irp, IO_NO_INCREMENT); - return(Status); -} diff --git a/reactos/drivers/fs/ext2/rw.c b/reactos/drivers/fs/ext2/rw.c deleted file mode 100644 index a2c3b9a953b..00000000000 --- a/reactos/drivers/fs/ext2/rw.c +++ /dev/null @@ -1,219 +0,0 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS kernel - * FILE: services/fs/ext2/super.c - * PURPOSE: ext2 filesystem - * PROGRAMMER: David Welch (welch@mcmail.com) - * UPDATE HISTORY: - */ - -/* INCLUDES *****************************************************************/ - -#include -#include - -#define NDEBUG -#include - -#include "ext2fs.h" - -/* FUNCTIONS *****************************************************************/ - -NTSTATUS Ext2ReadPage(PDEVICE_EXTENSION DeviceExt, - PEXT2_FCB Fcb, - PVOID Buffer, - ULONG Offset) -{ - ULONG block, i; - - for (i=0; i<4; i++) - { - block = Ext2BlockMap(DeviceExt, - Fcb->i.inode, - Offset + i); - Ext2ReadSectors(DeviceExt->StorageDevice, - block, - 1, - Buffer + (i*BLOCKSIZE)); - } - return(STATUS_SUCCESS); -} - -NTSTATUS Ext2ReadFile(PDEVICE_EXTENSION DeviceExt, - PFILE_OBJECT FileObject, - PVOID Buffer, - ULONG Length, - LARGE_INTEGER OffsetL) -{ - PVOID BaseAddress; - BOOLEAN Uptodate = FALSE; - PCACHE_SEGMENT CacheSeg; - ULONG Offset = (ULONG)OffsetL.u.LowPart; - PEXT2_FCB Fcb; - ULONG block, i, Delta; - DPRINT("Ext2ReadFile(DeviceExt %x, FileObject %x, Buffer %x, Length %d, \n" - "OffsetL %d)\n",DeviceExt,FileObject,Buffer,Length,(ULONG)OffsetL); - - Fcb = (PEXT2_FCB)FileObject->FsContext; - - Ext2LoadInode(DeviceExt, - Fcb->inode, - &Fcb->i); - - if (Offset >= Fcb->i.inode->i_size) - { - DPRINT("Returning end of file\n"); - return(STATUS_END_OF_FILE); - } - if ((Offset + Length) > Fcb->i.inode->i_size) - { - Length = Fcb->i.inode->i_size - Offset; - } - - Ext2ReleaseInode(DeviceExt, - &Fcb->i); - - if ((Offset % PAGE_SIZE) != 0) - { - Delta = min(PAGE_SIZE - (Offset % PAGE_SIZE),Length); - CcRequestCachePage(Fcb->Bcb, - Offset, - &BaseAddress, - &Uptodate, - &CacheSeg); - if (Uptodate == FALSE) - { - Ext2ReadPage(DeviceExt, - Fcb, - BaseAddress, - Offset / BLOCKSIZE); - } - memcpy(Buffer, BaseAddress + (Offset % PAGE_SIZE), Delta); - CcReleaseCachePage(Fcb->Bcb, - CacheSeg, - TRUE); - Length = Length - Delta; - Offset = Offset + Delta; - Buffer = Buffer + Delta; - } - CHECKPOINT; - for (i=0; i<(Length/PAGE_SIZE); i++) - { - CcRequestCachePage(Fcb->Bcb, - Offset, - &BaseAddress, - &Uptodate, - &CacheSeg); - if (Uptodate == FALSE) - { - Ext2ReadPage(DeviceExt, - Fcb, - BaseAddress, - (Offset / BLOCKSIZE)); - } - memcpy(Buffer, BaseAddress, PAGE_SIZE); - CcReleaseCachePage(Fcb->Bcb, - CacheSeg, - TRUE); - Length = Length - PAGE_SIZE; - Offset = Offset + PAGE_SIZE; - Buffer = Buffer + PAGE_SIZE; - } - CHECKPOINT; - if ((Length % PAGE_SIZE) != 0) - { - CcRequestCachePage(Fcb->Bcb, - Offset, - &BaseAddress, - &Uptodate, - &CacheSeg); - if (Uptodate == FALSE) - { - Ext2ReadPage(DeviceExt, - Fcb, - BaseAddress, - (Offset / BLOCKSIZE)); - } - DPRINT("Copying %x to %x Length %d\n",BaseAddress,Buffer,Length); - memcpy(Buffer,BaseAddress,Length); - CcReleaseCachePage(Fcb->Bcb, - CacheSeg, - TRUE); - } - CHECKPOINT; - - return(STATUS_SUCCESS); -} - - -NTSTATUS STDCALL -Ext2Write(PDEVICE_OBJECT DeviceObject, PIRP Irp) -{ - DPRINT("Ext2Write(DeviceObject %x Irp %x)\n",DeviceObject,Irp); - - Irp->IoStatus.Status = STATUS_UNSUCCESSFUL; - Irp->IoStatus.Information = 0; - return(STATUS_UNSUCCESSFUL); -} - -NTSTATUS STDCALL -Ext2FlushBuffers(PDEVICE_OBJECT DeviceObject, PIRP Irp) -{ - DPRINT("Ext2FlushBuffers(DeviceObject %x Irp %x)\n",DeviceObject,Irp); - - Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED; - Irp->IoStatus.Information = 0; - return(STATUS_UNSUCCESSFUL); -} - -NTSTATUS STDCALL -Ext2Shutdown(PDEVICE_OBJECT DeviceObject, PIRP Irp) -{ - DPRINT("Ext2Shutdown(DeviceObject %x Irp %x)\n",DeviceObject,Irp); - - Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED; - Irp->IoStatus.Information = 0; - return(STATUS_UNSUCCESSFUL); -} - -NTSTATUS STDCALL -Ext2Cleanup(PDEVICE_OBJECT DeviceObject, PIRP Irp) -{ - DbgPrint("Ext2Cleanup(DeviceObject %x Irp %x)\n",DeviceObject,Irp); - - Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED; - Irp->IoStatus.Information = 0; - - DbgPrint("Ext2Cleanup() finished\n"); - - return(STATUS_UNSUCCESSFUL); -} - -NTSTATUS STDCALL -Ext2Read(PDEVICE_OBJECT DeviceObject, PIRP Irp) -{ - ULONG Length; - PVOID Buffer; - PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp); - PFILE_OBJECT FileObject = Stack->FileObject; - PDEVICE_EXTENSION DeviceExt = DeviceObject->DeviceExtension; - NTSTATUS Status; - - DPRINT("Ext2Read(DeviceObject %x, FileObject %x, Irp %x)\n", - DeviceObject, FileObject, Irp); - - Length = Stack->Parameters.Read.Length; - CHECKPOINT; - Buffer = MmGetSystemAddressForMdl(Irp->MdlAddress); - CHECKPOINT; - CHECKPOINT; - - Status = Ext2ReadFile(DeviceExt,FileObject,Buffer,Length, - Stack->Parameters.Read.ByteOffset); - - Irp->IoStatus.Status = Status; - Irp->IoStatus.Information = Length; - IoCompleteRequest(Irp,IO_NO_INCREMENT); - - return(Status); -} diff --git a/reactos/drivers/fs/ext2/security.c b/reactos/drivers/fs/ext2/security.c deleted file mode 100644 index ab2297ba7ce..00000000000 --- a/reactos/drivers/fs/ext2/security.c +++ /dev/null @@ -1,41 +0,0 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS kernel - * FILE: services/fs/ext2/security.c - * PURPOSE: Security support - * PROGRAMMER: David Welch (welch@mcmail.com) - * UPDATE HISTORY: - */ - -/* INCLUDES *****************************************************************/ - -#include -#include -#include - -//#define NDEBUG -#include - -#include "ext2fs.h" - -/* FUNCTIONS ****************************************************************/ - -NTSTATUS STDCALL -Ext2QuerySecurity(PDEVICE_OBJECT DeviceObject, PIRP Irp) -{ - DPRINT("Ext2QuerySecurity(DeviceObject %x Irp %x)\n",DeviceObject,Irp); - - Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED; - Irp->IoStatus.Information = 0; - return(STATUS_UNSUCCESSFUL); -} - -NTSTATUS STDCALL -Ext2SetSecurity(PDEVICE_OBJECT DeviceObject, PIRP Irp) -{ - DPRINT("Ext2SetSecurity(DeviceObject %x Irp %x)\n",DeviceObject,Irp); - - Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED; - Irp->IoStatus.Information = 0; - return(STATUS_UNSUCCESSFUL); -} diff --git a/reactos/drivers/fs/ext2/src/.cvsignore b/reactos/drivers/fs/ext2/src/.cvsignore new file mode 100644 index 00000000000..a064feae216 --- /dev/null +++ b/reactos/drivers/fs/ext2/src/.cvsignore @@ -0,0 +1,9 @@ +base.tmp +junk.tmp +temp.exp +vfatfs.coff +*.d +*.o +*.sys +*.sym +*.map diff --git a/reactos/drivers/fs/ext2/src/DiskIO.c b/reactos/drivers/fs/ext2/src/DiskIO.c new file mode 100644 index 00000000000..a6c0e9cd1c2 --- /dev/null +++ b/reactos/drivers/fs/ext2/src/DiskIO.c @@ -0,0 +1,215 @@ +/************************************************************************* +* +* File: DiskIO.c +* +* Module: Ext2 File System Driver (Kernel mode execution only) +* +* Description: +* Should contain code to handle Disk IO. +* +* +* Author: Manoj Paul Joseph +* +* +*************************************************************************/ + +#include "ext2fsd.h" + +#define EXT2_BUG_CHECK_ID EXT2_FILE_DISK_IO + +#define DEBUG_LEVEL ( DEBUG_TRACE_DISKIO ) + + +/************************************************************************* +* +* Function: Ext2ReadLogicalBlocks() +* +* Description: +* The higherlevel functions will use this to read in logical blocks +* This function deals with the logical to physical block translation +* +* LogicalBlock - This is a 1 based index. +* That is, the first block is Block 1 +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: The Status of the Read IO +* +*************************************************************************/ +NTSTATUS Ext2ReadLogicalBlocks ( + PDEVICE_OBJECT PtrTargetDeviceObject, // the Target Device Object + VOID *Buffer, // The Buffer that takes the data read in + LARGE_INTEGER StartLogicalBlock, // The logical block from which reading is to start + unsigned int NoOfLogicalBlocks // The no. of logical blocks to be read + ) +{ + // The Status to be returned... + NTSTATUS Status = STATUS_SUCCESS; + + // The Device Object representing the mounted volume + PDEVICE_OBJECT PtrVolumeDeviceObject = NULL; + + // Volume Control Block + PtrExt2VCB PtrVCB = NULL; + + // Logical Block Size + ULONG LogicalBlockSize; + + // Physical Block Size + ULONG PhysicalBlockSize; + + // The starting Physical Block No... + LARGE_INTEGER StartPhysicalBlock; + + unsigned int NoOfPhysicalBlocks; + + + + // Done with declerations... + // Now for some code ;) + + // Getting the Logical and Physical Sector sizes + PtrVolumeDeviceObject = PtrTargetDeviceObject->Vpb->DeviceObject; + ASSERT( PtrVolumeDeviceObject ); + PtrVCB = (PtrExt2VCB)(PtrVolumeDeviceObject->DeviceExtension); + ASSERT(PtrVCB); + ASSERT(PtrVCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB); + + LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize; + PhysicalBlockSize = PtrTargetDeviceObject->SectorSize; + + NoOfPhysicalBlocks = NoOfLogicalBlocks * LogicalBlockSize / PhysicalBlockSize; + + StartPhysicalBlock.QuadPart = ( StartLogicalBlock.QuadPart ) * + ( LogicalBlockSize / PhysicalBlockSize ); + + Status = Ext2ReadPhysicalBlocks( PtrTargetDeviceObject, + Buffer, StartPhysicalBlock, NoOfPhysicalBlocks ); + + return Status; +} + +/************************************************************************* +* +* Function: Ext2ReadPhysicalBlocks() +* +* Description: +* The higherlevel functions will use this to read in physical blocks +* +* PhysicalBlock - This is a 0 based number. +* That is, the first block is Block 0 +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: The Status of the Read IO +* +*************************************************************************/ +NTSTATUS Ext2ReadPhysicalBlocks ( + PDEVICE_OBJECT PtrTargetDeviceObject, // the Target Device Object + VOID *Buffer, // The Buffer that takes the data read in + LARGE_INTEGER StartPhysicalBlock, // The block from which reading is to start + unsigned int NoOfBlocks // The no. of blocks to be read + ) +{ + // The Status to be returned... + NTSTATUS Status = STATUS_SUCCESS; + + // Physical Block Size + ULONG PhysicalBlockSize; + + // No of bytes to read + ULONG NumberOfBytesToRead; + + // Synchronisation Event + KEVENT Event; + + // IRP + PIRP Irp; + + // Status Block + IO_STATUS_BLOCK Iosb; + + // Byte Offset + LARGE_INTEGER ByteOffset; + + // Done with declerations... + // Now for some code ;) + + // Getting the Physical Sector size + PhysicalBlockSize = PtrTargetDeviceObject->SectorSize; + + NumberOfBytesToRead = PhysicalBlockSize * NoOfBlocks; + + ByteOffset.QuadPart = StartPhysicalBlock.QuadPart * PhysicalBlockSize; + + try + { + // + // Initialize the event we're going to use + // + KeInitializeEvent( &Event, NotificationEvent, FALSE ); + + // + // Build the irp for the operation and also set the overrride flag + // + Irp = IoBuildSynchronousFsdRequest( IRP_MJ_READ, + PtrTargetDeviceObject, + Buffer, + NumberOfBytesToRead, + &ByteOffset , + &Event, + &Iosb ); + + if ( Irp == NULL ) + { + DebugTrace(DEBUG_TRACE_MISC, " !!!! Unable to create an IRP", 0 ); + Status = STATUS_INSUFFICIENT_RESOURCES; + try_return( Status ); + } + + // + // Call the device to do the read and wait for it to finish. + // + Status = IoCallDriver( PtrTargetDeviceObject, Irp ); + + // + // Check if it is done already!!!! + // + if (Status == STATUS_PENDING) + { + // + // Read not done yet... + // Wait till it is... + // + (VOID)KeWaitForSingleObject( &Event, Executive, KernelMode, FALSE, (PLARGE_INTEGER)NULL ); + Status = Iosb.Status; + } + + try_exit: NOTHING; + } + finally + { + if (!NT_SUCCESS(Status)) + { + if( Status == STATUS_VERIFY_REQUIRED ) + { + DebugTrace(DEBUG_TRACE_MISC, " !!!! Verify Required! Failed to read disk",0 ); + } + else if (Status == STATUS_INVALID_PARAMETER) + { + DebugTrace(DEBUG_TRACE_MISC, " !!!! Invalid Parameter! Failed to read disk",0 ); + } + else + { + DebugTrace(DEBUG_TRACE_MISC, " !!!! Failed to read disk! Status returned = %d", Status ); + } + } + } + return Status; +} + + diff --git a/reactos/drivers/fs/ext2/src/cleanup.c b/reactos/drivers/fs/ext2/src/cleanup.c new file mode 100644 index 00000000000..ab8a536d5ad --- /dev/null +++ b/reactos/drivers/fs/ext2/src/cleanup.c @@ -0,0 +1,400 @@ +/************************************************************************* +* +* File: cleanup.c +* +* Module: Ext2 File System Driver (Kernel mode execution only) +* +* Description: +* Should contain code to handle the "Cleanup" dispatch entry point. +* This file serves as a placeholder. Please update this file as part +* of designing and implementing your FSD. +* +* Author: Manoj Paul Joseph +* +* +*************************************************************************/ + +#include "ext2fsd.h" + +// define the file specific bug-check id +#define EXT2_BUG_CHECK_ID EXT2_FILE_CLEANUP +#define DEBUG_LEVEL (DEBUG_TRACE_CLEANUP) + + +/************************************************************************* +* +* Function: Ext2Cleanup() +* +* Description: +* The I/O Manager will invoke this routine to handle a cleanup +* request +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution +* to be deferred to a worker thread context) +* +* Return Value: Does not matter! +* +*************************************************************************/ +NTSTATUS Ext2Cleanup( +PDEVICE_OBJECT DeviceObject, // the logical volume device object +PIRP Irp) // I/O Request Packet +{ + NTSTATUS RC = STATUS_SUCCESS; + PtrExt2IrpContext PtrIrpContext = NULL; + BOOLEAN AreWeTopLevel = FALSE; + + DebugTrace( DEBUG_TRACE_IRP_ENTRY, "Cleanup IRP Received...", 0); + + FsRtlEnterFileSystem(); + ASSERT(DeviceObject); + ASSERT(Irp); + + // set the top level context + AreWeTopLevel = Ext2IsIrpTopLevel(Irp); + + try + { + + // get an IRP context structure and issue the request + PtrIrpContext = Ext2AllocateIrpContext(Irp, DeviceObject); + ASSERT(PtrIrpContext); + + RC = Ext2CommonCleanup(PtrIrpContext, Irp, TRUE); + + } + except( Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation() ) ) + { + + RC = Ext2ExceptionHandler(PtrIrpContext, Irp); + + Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); + } + + if (AreWeTopLevel) + { + IoSetTopLevelIrp(NULL); + } + + FsRtlExitFileSystem(); + + return(RC); +} + +/************************************************************************* +* +* Function: Ext2CommonCleanup() +* +* Description: +* The actual work is performed here. This routine may be invoked in one' +* of the two possible contexts: +* (a) in the context of a system worker thread +* (b) in the context of the original caller +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: Does not matter! +* +*************************************************************************/ +NTSTATUS Ext2CommonCleanup( +PtrExt2IrpContext PtrIrpContext, +PIRP PtrIrp, +BOOLEAN FirstAttempt ) +{ + + NTSTATUS RC = STATUS_SUCCESS; + PIO_STACK_LOCATION PtrIoStackLocation = NULL; + PFILE_OBJECT PtrFileObject = NULL; + PtrExt2FCB PtrFCB = NULL; + PtrExt2CCB PtrCCB = NULL; + PtrExt2VCB PtrVCB = NULL; + PtrExt2NTRequiredFCB PtrReqdFCB = NULL; + PERESOURCE PtrResourceAcquired = NULL; + IO_STATUS_BLOCK LocalIoStatus; + + BOOLEAN CompleteIrp = TRUE; + BOOLEAN PostRequest = FALSE; + BOOLEAN AcquiredVCB = FALSE; + BOOLEAN CanWait = FALSE; + BOOLEAN BlockForResource; + int i = 1; + + try + { + // First, get a pointer to the current I/O stack location + PtrIoStackLocation = IoGetCurrentIrpStackLocation(PtrIrp); + ASSERT(PtrIoStackLocation); + + PtrFileObject = PtrIoStackLocation->FileObject; + ASSERT(PtrFileObject); + + if( !PtrFileObject->FsContext2 ) + { + // This must be a Cleanup request received + // as a result of IoCreateStreamFileObject + // Only such a File object would have a NULL CCB + + DebugTrace( DEBUG_TRACE_MISC, " === Cleanup with NULL CCB", 0); + if( PtrFileObject ) + { + DebugTrace( DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Cleanup]", PtrFileObject); + } + try_return( RC ); + } + + + Ext2GetFCB_CCB_VCB_FromFileObject ( + PtrFileObject, &PtrFCB, &PtrCCB, &PtrVCB ); + + if( PtrFCB && PtrFCB->FCBName && PtrFCB->FCBName->ObjectName.Length && PtrFCB->FCBName->ObjectName.Buffer ) + //if( PtrFileObject->FileName.Length && PtrFileObject->FileName.Buffer ) + { + DebugTrace( DEBUG_TRACE_FILE_NAME, " === Cleanup File Name : -%S-", PtrFCB->FCBName->ObjectName.Buffer ); + } + else + { + DebugTrace( DEBUG_TRACE_FILE_NAME, " === Cleanup Volume", 0); + } + + + PtrVCB = (PtrExt2VCB)(PtrIrpContext->TargetDeviceObject->DeviceExtension); + ASSERT(PtrVCB); + ASSERT(PtrVCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB); + + // (a) Acquiring the VCBResource Exclusively... + // This is done to synchronise with the close and cleanup routines... + BlockForResource = !FirstAttempt; + if( !FirstAttempt ) + { + + DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** Going into a block to acquire VCB Exclusively [Cleanup]", 0); + } + else + { + DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** Attempting to acquire VCB Exclusively [Cleanup]", 0); + } + + if( PtrFileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Cleanup]", PtrFileObject); + } + + i = 1; + while( !AcquiredVCB ) + { + DebugTraceState("VCB AC:0x%LX SW:0x%LX EX:0x%LX [Cleanup]", PtrVCB->VCBResource.ActiveCount, PtrVCB->VCBResource.NumberOfExclusiveWaiters, PtrVCB->VCBResource.NumberOfSharedWaiters ); + if( ! ExAcquireResourceExclusiveLite( &(PtrVCB->VCBResource), FALSE ) ) + { + DebugTrace( DEBUG_TRACE_RESOURCE_ACQUIRE, "*** VCB Acquisition FAILED [Cleanup]", 0); + if( BlockForResource && i != 1000 ) + { + LARGE_INTEGER Delay; + Delay.QuadPart = -500 * i; + KeDelayExecutionThread( KernelMode, FALSE, &Delay ); + DebugTrace(DEBUG_TRACE_RESOURCE_RETRY, "*** Retrying... after 50 * %ld ms [Cleanup]", i); + } + else + { + if( i == 1000 ) + DebugTrace(DEBUG_TRACE_RESOURCE_RETRY, "*** Reposting... [Cleanup]", 0 ); + PostRequest = TRUE; + try_return( RC = STATUS_PENDING ); + } + } + else + { + DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** VCB Acquired in [Cleanup]", 0); + AcquiredVCB = TRUE; + } + i *= 10; + } + + + // (b) Acquire the file (FCB) exclusively + if( PtrFCB && PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_FCB ) + { + // This FCB is an FCB indeed. ;) + // So acquiring it exclusively... + // This is done to synchronise with read/write routines... + if( !FirstAttempt ) + { + DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** Going into a block to acquire FCB Exclusively [Cleanup]", 0); + } + else + { + DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** Attempting to acquire FCB Exclusively [Cleanup]", 0); + } + if( PtrFileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Cleanup]", PtrFileObject); + } + + i = 1; + while( !PtrResourceAcquired ) + { + PtrReqdFCB = &(PtrFCB->NTRequiredFCB); + DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [Cleanup]", PtrReqdFCB->MainResource.ActiveCount, PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, PtrReqdFCB->MainResource.NumberOfSharedWaiters ); + if(! ExAcquireResourceExclusiveLite( &(PtrFCB->NTRequiredFCB.MainResource ), FALSE ) ) + { + DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** FCB Acquisition FAILED [Cleanup]", 0); + if( BlockForResource && i != 1000 ) + { + LARGE_INTEGER Delay; + Delay.QuadPart = -500 * i; + KeDelayExecutionThread( KernelMode, FALSE, &Delay ); + DebugTrace(DEBUG_TRACE_RESOURCE_RETRY, "*** Retrying... after 50 * %ld ms [Cleanup]", i); + } + else + { + if( i == 1000 ) + DebugTrace(DEBUG_TRACE_RESOURCE_RETRY, "*** Reposting... [Cleanup]", 0 ); + PostRequest = TRUE; + try_return( RC = STATUS_PENDING ); + } + } + else + { + DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** FCB acquired [Cleanup]", 0); + PtrResourceAcquired = & ( PtrFCB->NTRequiredFCB.MainResource ); + } + i *= 10; + } + + // (c) Flush file data to disk + if ( PtrFileObject->PrivateCacheMap != NULL) + { + IO_STATUS_BLOCK Status; + CcFlushCache( PtrFileObject->SectionObjectPointer, NULL, 0, &Status ); + } + + // (d) Talk to the FSRTL package (if you use it) about pending oplocks. + // (e) Notify the FSRTL package (if you use it) for use with pending + // notification IRPs + // (f) Unlock byte-range locks (if any were acquired by process) + + // (g) Attempting to update time stamp values + // Errors are ignored... + // Not considered as critical errors... + + /* + if( PtrFCB->OpenHandleCount == 1 ) + { + ULONG CreationTime, AccessTime, ModificationTime; + EXT2_INODE Inode; + + CreationTime = (ULONG) ( (PtrFCB->CreationTime.QuadPart + - Ext2GlobalData.TimeDiff.QuadPart) / 10000000 ); + AccessTime = (ULONG) ( (PtrFCB->LastAccessTime.QuadPart + - Ext2GlobalData.TimeDiff.QuadPart) / 10000000 ); + ModificationTime = (ULONG) ( (PtrFCB->LastWriteTime.QuadPart + - Ext2GlobalData.TimeDiff.QuadPart) / 10000000 ); + if( NT_SUCCESS( Ext2ReadInode( PtrVCB, PtrFCB->INodeNo, &Inode ) ) ) + { + // Update time stamps in the inode... + Inode.i_ctime = CreationTime; + Inode.i_atime = AccessTime; + Inode.i_mtime = ModificationTime; + + // Updating the inode... + Ext2WriteInode( PtrIrpContext, PtrVCB, PtrFCB->INodeNo, &Inode ); + } + } + */ + + // (h) Inform the Cache Manager to uninitialize Cache Maps ... + CcUninitializeCacheMap( PtrFileObject, NULL, NULL ); + + // (i) Decrementing the Open Handle count... + if( PtrFCB->OpenHandleCount ) + { + InterlockedDecrement( &PtrFCB->OpenHandleCount ); + } + else + { + Ext2BreakPoint(); + } + + PtrFCB->FCBFlags |= FO_CLEANUP_COMPLETE; + + DebugTrace(DEBUG_TRACE_REFERENCE, "^^^^^ReferenceCount = 0x%lX [Cleanup]", PtrFCB->ReferenceCount ); + DebugTrace(DEBUG_TRACE_REFERENCE, "^^^^^OpenHandleCount = 0x%lX [Cleanup]", PtrFCB->OpenHandleCount ); + + // (j) Remove share access... + // Will do that later ;) + + // (k) Is this a close on delete file? + // If so, delete the file... + if( Ext2IsFlagOn( PtrFCB->FCBFlags, EXT2_FCB_DELETE_ON_CLOSE) && + !PtrFCB->OpenHandleCount ) + { + // + // Have to delete this file... + // + Ext2DeleteFile( PtrFCB, PtrIrpContext ); + PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart = 0; + PtrFCB->INodeNo = 0; + } + } + else + { + // This must be a volume close... + // Just go ahead and complete this IRP... + PtrVCB->VCBOpenCount--; + DebugTrace(DEBUG_TRACE_MISC, "VCB Cleanup Requested !!!", 0); + CompleteIrp = TRUE; + } + + try_return( RC ); + + try_exit: NOTHING; + + } + finally + { + if(PtrResourceAcquired) + { + Ext2ReleaseResource(PtrResourceAcquired); + DebugTrace(DEBUG_TRACE_RESOURCE_RELEASE, "*** Resource Released [Cleanup]", 0); + DebugTraceState( "Resource AC:0x%LX SW:0x%LX EX:0x%LX [Cleanup]", + PtrResourceAcquired->ActiveCount, + PtrResourceAcquired->NumberOfExclusiveWaiters, + PtrResourceAcquired->NumberOfSharedWaiters ); + + if( PtrFileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Cleanup]", PtrFileObject); + } + + } + + if( AcquiredVCB ) + { + ASSERT(PtrVCB); + Ext2ReleaseResource(&(PtrVCB->VCBResource)); + DebugTrace(DEBUG_TRACE_RESOURCE_RELEASE, "*** VCB Released [Cleanup]", 0); + DebugTraceState( "VCB AC:0x%LX SW:0x%LX EX:0x%LX [Cleanup]", PtrVCB->VCBResource.ActiveCount, PtrVCB->VCBResource.NumberOfExclusiveWaiters, PtrVCB->VCBResource.NumberOfSharedWaiters ); + AcquiredVCB = FALSE; + if( PtrFileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Cleanup]", PtrFileObject); + } + + } + + if( PostRequest ) + { + RC = Ext2PostRequest(PtrIrpContext, PtrIrp); + } + if( RC != STATUS_PENDING ) + { + Ext2ReleaseIrpContext( PtrIrpContext ); + // complete the IRP + IoCompleteRequest( PtrIrp, IO_DISK_INCREMENT ); + } + } // end of "finally" processing + + return(RC); +} diff --git a/reactos/drivers/fs/ext2/src/close.c b/reactos/drivers/fs/ext2/src/close.c new file mode 100644 index 00000000000..c29ce93df4f --- /dev/null +++ b/reactos/drivers/fs/ext2/src/close.c @@ -0,0 +1,459 @@ +/************************************************************************* +* +* File: close.c +* +* Module: Ext2 File System Driver (Kernel mode execution only) +* +* Description: +* Should contain code to handle the "Close" dispatch entry point. +* This file serves as a placeholder. Please update this file as part +* of designing and implementing your FSD. +* +* Author: Manoj Paul Joseph +* +* +*************************************************************************/ + +#include "ext2fsd.h" + +// define the file specific bug-check id +#define EXT2_BUG_CHECK_ID EXT2_FILE_CLOSE + +#define DEBUG_LEVEL (DEBUG_TRACE_CLOSE) + + +/************************************************************************* +* +* Function: Ext2Close() +* +* Description: +* The I/O Manager will invoke this routine to handle a close +* request +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution +* to be deferred to a worker thread context) +* +* Return Value: Does not matter! +* +*************************************************************************/ +NTSTATUS Ext2Close( +PDEVICE_OBJECT DeviceObject, // the logical volume device object +PIRP Irp) // I/O Request Packet +{ + NTSTATUS RC = STATUS_SUCCESS; + PtrExt2IrpContext PtrIrpContext = NULL; + BOOLEAN AreWeTopLevel = FALSE; + + DebugTrace(DEBUG_TRACE_IRP_ENTRY, "Close IRP Received...", 0); + + + FsRtlEnterFileSystem(); + + ASSERT(DeviceObject); + ASSERT(Irp); + + // set the top level context + AreWeTopLevel = Ext2IsIrpTopLevel(Irp); + + try + { + + // get an IRP context structure and issue the request + PtrIrpContext = Ext2AllocateIrpContext(Irp, DeviceObject); + ASSERT(PtrIrpContext); + + RC = Ext2CommonClose(PtrIrpContext, Irp, TRUE); + + } + except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) + { + + RC = Ext2ExceptionHandler(PtrIrpContext, Irp); + Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); + } + + if (AreWeTopLevel) + { + IoSetTopLevelIrp(NULL); + } + + FsRtlExitFileSystem(); + + return(RC); +} + + +/************************************************************************* +* +* Function: Ext2CommonClose() +* +* Description: +* The actual work is performed here. This routine may be invoked in one' +* of the two possible contexts: +* (a) in the context of a system worker thread +* (b) in the context of the original caller +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: Does not matter! +* +*************************************************************************/ +NTSTATUS Ext2CommonClose( +PtrExt2IrpContext PtrIrpContext, +PIRP PtrIrp, +BOOLEAN FirstAttempt ) +{ + NTSTATUS RC = STATUS_SUCCESS; + PIO_STACK_LOCATION PtrIoStackLocation = NULL; + PFILE_OBJECT PtrFileObject = NULL; + PtrExt2FCB PtrFCB = NULL; + PtrExt2CCB PtrCCB = NULL; + PtrExt2VCB PtrVCB = NULL; + PtrExt2NTRequiredFCB PtrReqdFCB = NULL; + PERESOURCE PtrResourceAcquired = NULL; + IO_STATUS_BLOCK LocalIoStatus; + + BOOLEAN CompleteIrp = TRUE; + BOOLEAN PostRequest = FALSE; + BOOLEAN AcquiredVCB = FALSE; + BOOLEAN CanWait = FALSE; + BOOLEAN BlockForResource; + int i = 1; + + try + { + // First, get a pointer to the current I/O stack location + PtrIoStackLocation = IoGetCurrentIrpStackLocation(PtrIrp); + ASSERT(PtrIoStackLocation); + + PtrFileObject = PtrIoStackLocation->FileObject; + ASSERT(PtrFileObject); + + if( !PtrFileObject->FsContext2 ) + { + // This must be a Cleanup request received + // as a result of IoCreateStreamFileObject + // Only such a File object would have a NULL CCB + + DebugTrace( DEBUG_TRACE_SPECIAL, " === Close with NULL CCB", 0); + if( PtrFileObject ) + { + DebugTrace( DEBUG_TRACE_SPECIAL, "###### File Pointer 0x%LX [Close]", PtrFileObject); + } + Ext2BreakPoint(); + try_return( RC ); + } + + // Get the FCB and CCB pointers + + Ext2GetFCB_CCB_VCB_FromFileObject ( + PtrFileObject, &PtrFCB, &PtrCCB, &PtrVCB ); + + PtrVCB = (PtrExt2VCB)(PtrIrpContext->TargetDeviceObject->DeviceExtension); + ASSERT( PtrVCB ); + + if( PtrFCB && PtrFCB->FCBName && PtrFCB->FCBName->ObjectName.Length && PtrFCB->FCBName->ObjectName.Buffer ) + //if( PtrFileObject->FileName.Length && PtrFileObject->FileName.Buffer ) + { + DebugTrace(DEBUG_TRACE_FILE_NAME, " === Close File Name : -%S-", PtrFCB->FCBName->ObjectName.Buffer ); + } + else + { + DebugTrace(DEBUG_TRACE_FILE_NAME, " === Close File Name : -null-", 0); + } + + // (a) Acquiring the VCBResource Exclusively... + // This is done to synchronise with the close and cleanup routines... +// if( ExTryToAcquireResourceExclusiveLite(&(PtrVCB->VCBResource) ) ) + + BlockForResource = !FirstAttempt; + if( !FirstAttempt ) + { + DebugTrace(DEBUG_TRACE_MISC, "*** Going into a block to acquire VCB Exclusively [Close]", 0); + } + else + { + DebugTrace(DEBUG_TRACE_MISC, "*** Attempting to acquire VCB Exclusively [Close]", 0); + } + if( PtrFileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Close]", PtrFileObject); + } + i = 1; + while( !AcquiredVCB ) + { + DebugTraceState( "VCB AC:0x%LX SW:0x%LX EX:0x%LX [Close]", PtrVCB->VCBResource.ActiveCount, PtrVCB->VCBResource.NumberOfExclusiveWaiters, PtrVCB->VCBResource.NumberOfSharedWaiters ); + if(! ExAcquireResourceExclusiveLite( &(PtrVCB->VCBResource), FALSE ) ) + { + DebugTrace(DEBUG_TRACE_MISC, "*** VCB Acquisition FAILED [Close]", 0); + if( BlockForResource && i != 1000 ) + { + LARGE_INTEGER Delay; + + //KeSetPriorityThread( PsGetCurrentThread(),LOW_REALTIME_PRIORITY ); + + Delay.QuadPart = -500 * i; + KeDelayExecutionThread( KernelMode, FALSE, &Delay ); + DebugTrace(DEBUG_TRACE_MISC, "*** Retrying... after 50 * %ld ms [Close]", i); + } + else + { + if( i == 1000 ) + DebugTrace(DEBUG_TRACE_MISC, "*** Reposting... [Close]", 0 ); + PostRequest = TRUE; + try_return( RC = STATUS_PENDING ); + } + } + else + { + DebugTrace(DEBUG_TRACE_MISC, "*** VCB Acquired in [Close]", 0); + AcquiredVCB = TRUE; + } + i *= 10; + } + + // (b) Acquire the file (FCB) exclusively + if( PtrFCB && PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_FCB ) + { + // This FCB is an FCB indeed. ;) + // So acquiring it exclusively... + // This is done to synchronise with read/write routines... + if( !FirstAttempt ) + { + DebugTrace(DEBUG_TRACE_MISC, "*** Going into a block to acquire FCB Exclusively [Close]", 0); + } + else + { + DebugTrace(DEBUG_TRACE_MISC, "*** Attempting to acquire FCB Exclusively [Close]", 0); + } + if( PtrFileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Close]", PtrFileObject); + } + i = 1; + while( !PtrResourceAcquired ) + { + PtrReqdFCB = &(PtrFCB->NTRequiredFCB); + + DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [Close]", PtrReqdFCB->MainResource.ActiveCount, PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, PtrReqdFCB->MainResource.NumberOfSharedWaiters ); + if(! ExAcquireResourceExclusiveLite( &(PtrFCB->NTRequiredFCB.MainResource ), FALSE ) ) + { + DebugTrace(DEBUG_TRACE_MISC, "*** FCB Acquisition FAILED [Close]", 0); + if( BlockForResource && i != 1000 ) + { + LARGE_INTEGER Delay; + + //KeSetPriorityThread( PsGetCurrentThread(),LOW_REALTIME_PRIORITY ); + + Delay.QuadPart = -500 * i; + KeDelayExecutionThread( KernelMode, FALSE, &Delay ); + DebugTrace(DEBUG_TRACE_MISC, "*** Retrying... after 50 * %ld ms [Close]", i); + } + else + { + if( i == 1000 ) + DebugTrace(DEBUG_TRACE_MISC, "*** Reposting... [Close]", 0 ); + PostRequest = TRUE; + try_return( RC = STATUS_PENDING ); + } + } + else + { + DebugTrace(DEBUG_TRACE_MISC, "*** FCB acquired [Close]", 0); + PtrResourceAcquired = & ( PtrFCB->NTRequiredFCB.MainResource ); + } + i *= 10; + } + + // (c) Delete the CCB structure (free memory) + RemoveEntryList( &PtrCCB->NextCCB ); + Ext2ReleaseCCB( PtrCCB ); + PtrFileObject->FsContext2 = NULL; + + // (d) Decrementing the Reference Count... + if( PtrFCB->ReferenceCount ) + { + InterlockedDecrement( &PtrFCB->ReferenceCount ); + } + else + { + Ext2BreakPoint(); + } + DebugTrace(DEBUG_TRACE_REFERENCE, "^^^^^ReferenceCount = 0x%lX [Close]", PtrFCB->ReferenceCount ); + DebugTrace(DEBUG_TRACE_REFERENCE, "^^^^^OpenHandleCount = 0x%lX [Close]", PtrFCB->OpenHandleCount ); + if( PtrFCB->ReferenceCount == 0 ) + { + + // Attempting to update time stamp values + // Errors are ignored... + // Not considered as critical errors... + + { + ULONG CreationTime, AccessTime, ModificationTime; + EXT2_INODE Inode; + + CreationTime = (ULONG) ( (PtrFCB->CreationTime.QuadPart + - Ext2GlobalData.TimeDiff.QuadPart) / 10000000 ); + AccessTime = (ULONG) ( (PtrFCB->LastAccessTime.QuadPart + - Ext2GlobalData.TimeDiff.QuadPart) / 10000000 ); + ModificationTime = (ULONG) ( (PtrFCB->LastWriteTime.QuadPart + - Ext2GlobalData.TimeDiff.QuadPart) / 10000000 ); + if( NT_SUCCESS( Ext2ReadInode( PtrVCB, PtrFCB->INodeNo, &Inode ) ) ) + { + // Update time stamps in the inode... + Inode.i_ctime = CreationTime; + Inode.i_atime = AccessTime; + Inode.i_mtime = ModificationTime; + + // Updating the inode... + Ext2WriteInode( NULL, PtrVCB, PtrFCB->INodeNo, &Inode ); + } + } + + + if( PtrFCB->INodeNo == EXT2_ROOT_INO ) + { + // + // Root Directory FCB + // Preserve this + // FSD has a File Object for this FCB... + // + DebugTrace(DEBUG_TRACE_MISC, "^^^^^Root Directory FCB ; leaveing it alone[Close]", 0); + // Do nothing... + + } + else if( PtrFCB->DcbFcb.Dcb.PtrDirFileObject ) + { + // + // If this is a FCB created on the FSD's initiative + // Leave it alone + // + DebugTrace(DEBUG_TRACE_MISC, "^^^^^FCB Created on the FSD's initiative; leaveing it alone[Close]", 0); + if( !PtrFCB->ClosableFCBs.OnClosableFCBList ) + { + InsertTailList( &PtrVCB->ClosableFCBs.ClosableFCBListHead, + &PtrFCB->ClosableFCBs.ClosableFCBList ); + PtrVCB->ClosableFCBs.Count++; + + PtrFCB->ClosableFCBs.OnClosableFCBList = TRUE; + } + + if( PtrVCB->ClosableFCBs.Count > EXT2_MAXCLOSABLE_FCBS_UL ) + { + PtrExt2FCB PtrTempFCB = NULL; + // Checking if Closable FCBs are too many in number... + // Shouldn't block the + // Should do this asynchronously... + // Maybe later... + PLIST_ENTRY PtrEntry = NULL; + + PtrEntry = RemoveHeadList( &PtrVCB->ClosableFCBs.ClosableFCBListHead ); + + PtrTempFCB = CONTAINING_RECORD( PtrEntry, Ext2FCB, ClosableFCBs.ClosableFCBList ); + if( Ext2CloseClosableFCB( PtrTempFCB ) ) + { + DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [Close]", PtrTempFCB ); + ExFreePool( PtrTempFCB ); + PtrVCB->ClosableFCBs.Count--; + } + else + { + // Put the FCB back in the list... + InsertHeadList( &PtrVCB->ClosableFCBs.ClosableFCBListHead, + &PtrTempFCB->ClosableFCBs.ClosableFCBList ); + } + DebugTrace( DEBUG_TRACE_SPECIAL, "ClosableFCBs Count = %ld [Close]", PtrVCB->ClosableFCBs.Count ); + } + } + else + { + // Remove this FCB as well... + DebugTrace(DEBUG_TRACE_MISC, "^^^^^Deleting FCB [Close]", 0); + RemoveEntryList( &PtrFCB->NextFCB ); + + if ( PtrResourceAcquired ) + { + Ext2ReleaseResource(PtrResourceAcquired); + DebugTrace(DEBUG_TRACE_MISC, "*** FCB Released [Close]", 0); + DebugTraceState( "Resource AC:0x%LX SW:0x%LX EX:0x%LX [Close]", + PtrResourceAcquired->ActiveCount, + PtrResourceAcquired->NumberOfExclusiveWaiters, + PtrResourceAcquired->NumberOfSharedWaiters ); + + if( PtrFileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Close]", PtrFileObject); + } + PtrResourceAcquired = FALSE; + } + Ext2ReleaseFCB( PtrFCB ); + } + + } + CompleteIrp = TRUE; + } + else + { + // This must be a volume close... + // What do I do now? ;) + DebugTrace(DEBUG_TRACE_MISC, "VCB Close Requested !!!", 0); + CompleteIrp = TRUE; + } + try_return( RC ); + + try_exit: NOTHING; + + } + finally + { + if ( PtrResourceAcquired ) + { + Ext2ReleaseResource(PtrResourceAcquired); + DebugTrace(DEBUG_TRACE_MISC, "*** FCB Released [Close]", 0); + DebugTraceState( "Resource AC:0x%LX SW:0x%LX EX:0x%LX [Close]", + PtrResourceAcquired->ActiveCount, + PtrResourceAcquired->NumberOfExclusiveWaiters, + PtrResourceAcquired->NumberOfSharedWaiters ); + + if( PtrFileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Close]", PtrFileObject); + } + PtrResourceAcquired = FALSE; + } + + if (AcquiredVCB) + { + ASSERT(PtrVCB); + Ext2ReleaseResource(&(PtrVCB->VCBResource)); + DebugTraceState( "VCB AC:0x%LX SW:0x%LX EX:0x%LX [Close]", PtrVCB->VCBResource.ActiveCount, PtrVCB->VCBResource.NumberOfExclusiveWaiters, PtrVCB->VCBResource.NumberOfSharedWaiters ); + DebugTrace(DEBUG_TRACE_MISC, "*** VCB Released [Close]", 0); + + AcquiredVCB = FALSE; + if( PtrFileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Close]", PtrFileObject); + } + + } + + if( PostRequest ) + { + RC = Ext2PostRequest(PtrIrpContext, PtrIrp); + } + else if( CompleteIrp && RC != STATUS_PENDING ) + { + // complete the IRP + IoCompleteRequest( PtrIrp, IO_DISK_INCREMENT ); + + Ext2ReleaseIrpContext( PtrIrpContext ); + } + + } // end of "finally" processing + + return(RC); +} diff --git a/reactos/drivers/fs/ext2/src/create.c b/reactos/drivers/fs/ext2/src/create.c new file mode 100644 index 00000000000..45887dfe029 --- /dev/null +++ b/reactos/drivers/fs/ext2/src/create.c @@ -0,0 +1,1681 @@ +/************************************************************************* +* +* File: create.c +* +* Module: Ext2 File System Driver (Kernel mode execution only) +* +* Description: +* Contains code to handle the "Create"/"Open" dispatch entry point. +* +* Author: Manoj Paul Joseph +* +* +*************************************************************************/ + +#include "ext2fsd.h" + +// define the file specific bug-check id +#define EXT2_BUG_CHECK_ID EXT2_FILE_CREATE + +#define DEBUG_LEVEL (DEBUG_TRACE_CREATE) + + +/************************************************************************* +* +* Function: Ext2Create() +* +* Description: +* The I/O Manager will invoke this routine to handle a create/open +* request +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution +* to be deferred to a worker thread context) +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +NTSTATUS Ext2Create( +PDEVICE_OBJECT DeviceObject, // the logical volume device object +PIRP Irp) // I/O Request Packet +{ + NTSTATUS RC = STATUS_SUCCESS; + PtrExt2IrpContext PtrIrpContext; + BOOLEAN AreWeTopLevel = FALSE; + + DebugTrace( DEBUG_TRACE_IRP_ENTRY, "Create Control IRP received...", 0); + + FsRtlEnterFileSystem(); + + // Ext2BreakPoint(); + + ASSERT(DeviceObject); + ASSERT(Irp); + + // sometimes, we may be called here with the device object representing + // the file system (instead of the device object created for a logical + // volume. In this case, there is not much we wish to do (this create + // typically will happen 'cause some process has to open the FSD device + // object so as to be able to send an IOCTL to the FSD) + + // All of the logical volume device objects we create have a device + // extension whereas the device object representing the FSD has no + // device extension. This seems like a good enough method to identify + // between the two device objects ... + if (DeviceObject->Size == (unsigned short)(sizeof(DEVICE_OBJECT))) + { + // this is an open of the FSD itself + DebugTrace( DEBUG_TRACE_MISC, " === Open for the FSD itself", 0); + Irp->IoStatus.Status = RC; + Irp->IoStatus.Information = FILE_OPENED; + + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return(RC); + } + + // set the top level context + AreWeTopLevel = Ext2IsIrpTopLevel(Irp); + + try + { + + // get an IRP context structure and issue the request + PtrIrpContext = Ext2AllocateIrpContext(Irp, DeviceObject); + ASSERT(PtrIrpContext); + + RC = Ext2CommonCreate(PtrIrpContext, Irp, TRUE ); + + } + except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) + { + + RC = Ext2ExceptionHandler(PtrIrpContext, Irp); + + Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); + } + + if (AreWeTopLevel) + { + IoSetTopLevelIrp(NULL); + } + + FsRtlExitFileSystem(); + + return(RC); +} + + + +/************************************************************************* +* +* Function: Ext2CommonCreate() +* +* Description: +* The actual work is performed here. This routine may be invoked in one' +* of the two possible contexts: +* (a) in the context of a system worker thread +* (b) in the context of the original caller +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +NTSTATUS Ext2CommonCreate( +PtrExt2IrpContext PtrIrpContext, +PIRP PtrIrp, +BOOLEAN FirstAttempt) +{ + NTSTATUS RC = STATUS_SUCCESS; + PIO_STACK_LOCATION PtrIoStackLocation = NULL; + PIO_SECURITY_CONTEXT PtrSecurityContext = NULL; + PFILE_OBJECT PtrNewFileObject = NULL; + PFILE_OBJECT PtrRelatedFileObject = NULL; + uint32 AllocationSize = 0; // if we create a new file + PFILE_FULL_EA_INFORMATION PtrExtAttrBuffer = NULL; + unsigned long RequestedOptions = 0; + unsigned long RequestedDisposition = 0; + uint8 FileAttributes = 0; + unsigned short ShareAccess = 0; + unsigned long ExtAttrLength = 0; + ACCESS_MASK DesiredAccess; + + BOOLEAN DeferredProcessing = FALSE; + + PtrExt2VCB PtrVCB = NULL; + BOOLEAN AcquiredVCB = FALSE; + + BOOLEAN DirectoryOnlyRequested = FALSE; + BOOLEAN FileOnlyRequested = FALSE; + BOOLEAN NoBufferingSpecified = FALSE; + BOOLEAN WriteThroughRequested = FALSE; + BOOLEAN DeleteOnCloseSpecified = FALSE; + BOOLEAN NoExtAttrKnowledge = FALSE; + BOOLEAN CreateTreeConnection = FALSE; + BOOLEAN OpenByFileId = FALSE; + + BOOLEAN SequentialOnly = FALSE; + BOOLEAN RandomAccess = FALSE; + + // Are we dealing with a page file? + BOOLEAN PageFileManipulation = FALSE; + + // Is this open for a target directory (used in rename operations)? + BOOLEAN OpenTargetDirectory = FALSE; + + // Should we ignore case when attempting to locate the object? + BOOLEAN IgnoreCaseWhenChecking = FALSE; + + PtrExt2CCB PtrRelatedCCB = NULL, PtrNewCCB = NULL; + PtrExt2FCB PtrRelatedFCB = NULL, PtrNewFCB = NULL; + + unsigned long ReturnedInformation = -1; + + UNICODE_STRING TargetObjectName; + UNICODE_STRING RelatedObjectName; + + UNICODE_STRING AbsolutePathName; + UNICODE_STRING RenameLinkTargetFileName; + + LARGE_INTEGER FileAllocationSize, FileEndOfFile; + + + ASSERT(PtrIrpContext); + ASSERT(PtrIrp); + + try + { + + AbsolutePathName.Buffer = NULL; + AbsolutePathName.Length = AbsolutePathName.MaximumLength = 0; + + // Getting a pointer to the current I/O stack location + PtrIoStackLocation = IoGetCurrentIrpStackLocation(PtrIrp); + ASSERT(PtrIoStackLocation); + + // Can we block? + if (!(PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_CAN_BLOCK)) + { + // Asynchronous processing required... + RC = Ext2PostRequest(PtrIrpContext, PtrIrp); + DeferredProcessing = TRUE; + try_return(RC); + } + + // Obtaining the parameters specified by the user. + PtrNewFileObject = PtrIoStackLocation->FileObject; + TargetObjectName = PtrNewFileObject->FileName; + PtrRelatedFileObject = PtrNewFileObject->RelatedFileObject; + + if( PtrNewFileObject->FileName.Length && PtrNewFileObject->FileName.Buffer ) + { + if( PtrNewFileObject->FileName.Buffer[ PtrNewFileObject->FileName.Length/2 ] != 0 ) + { + DebugTrace(DEBUG_TRACE_MISC, "&&&&&&&&& PtrFileObject->FileName not NULL terminated! [Create]", 0 ); + } + DebugTrace( DEBUG_TRACE_FILE_NAME, " === Create/Open File Name : -%S- [Create]", PtrNewFileObject->FileName.Buffer ); + } + else + { + DebugTrace( DEBUG_TRACE_FILE_NAME, " === Create/Open File Name : -null- [Create]", 0); + } + + // Is this a Relative Create/Open? + if (PtrRelatedFileObject) + { + PtrRelatedCCB = (PtrExt2CCB)(PtrRelatedFileObject->FsContext2); + ASSERT(PtrRelatedCCB); + ASSERT(PtrRelatedCCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_CCB); + // each CCB in turn points to a FCB + PtrRelatedFCB = PtrRelatedCCB->PtrFCB; + ASSERT(PtrRelatedFCB); + if( PtrRelatedFCB->NodeIdentifier.NodeType != EXT2_NODE_TYPE_FCB && + PtrRelatedFCB->NodeIdentifier.NodeType != EXT2_NODE_TYPE_VCB ) + { + // How the hell can this happen!!! + Ext2BreakPoint(); + } + + AssertFCBorVCB( PtrRelatedFCB ); + + RelatedObjectName = PtrRelatedFileObject->FileName; + + if( PtrRelatedFileObject->FileName.Length && PtrRelatedFileObject->FileName.Buffer ) + { + DebugTrace( DEBUG_TRACE_FILE_NAME, " === Relative to : -%S-", PtrRelatedFileObject->FileName.Buffer ); + } + else + { + DebugTrace( DEBUG_TRACE_FILE_NAME, " === Relative to : -null-",0); + } + + } + + + AllocationSize = PtrIrp->Overlay.AllocationSize.LowPart; + // Only 32 bit file sizes supported... + + if (PtrIrp->Overlay.AllocationSize.HighPart) + { + RC = STATUS_INVALID_PARAMETER; + try_return(RC); + } + + // Getting a pointer to the supplied security context + PtrSecurityContext = PtrIoStackLocation->Parameters.Create.SecurityContext; + + // Obtaining the desired access + DesiredAccess = PtrSecurityContext->DesiredAccess; + + // Getting the options supplied by the user... + RequestedOptions = (PtrIoStackLocation->Parameters.Create.Options & FILE_VALID_OPTION_FLAGS); + RequestedDisposition = ((PtrIoStackLocation->Parameters.Create.Options >> 24) & 0xFF); + + FileAttributes = (uint8)(PtrIoStackLocation->Parameters.Create.FileAttributes & FILE_ATTRIBUTE_VALID_FLAGS); + ShareAccess = PtrIoStackLocation->Parameters.Create.ShareAccess; + PtrExtAttrBuffer = PtrIrp->AssociatedIrp.SystemBuffer; + + ExtAttrLength = PtrIoStackLocation->Parameters.Create.EaLength; + + SequentialOnly = ((RequestedOptions & FILE_SEQUENTIAL_ONLY ) ? TRUE : FALSE); + RandomAccess = ((RequestedOptions & FILE_RANDOM_ACCESS ) ? TRUE : FALSE); + + + DirectoryOnlyRequested = ((RequestedOptions & FILE_DIRECTORY_FILE) ? TRUE : FALSE); + FileOnlyRequested = ((RequestedOptions & FILE_NON_DIRECTORY_FILE) ? TRUE : FALSE); + NoBufferingSpecified = ((RequestedOptions & FILE_NO_INTERMEDIATE_BUFFERING) ? TRUE : FALSE); + WriteThroughRequested = ((RequestedOptions & FILE_WRITE_THROUGH) ? TRUE : FALSE); + DeleteOnCloseSpecified = ((RequestedOptions & FILE_DELETE_ON_CLOSE) ? TRUE : FALSE); + NoExtAttrKnowledge = ((RequestedOptions & FILE_NO_EA_KNOWLEDGE) ? TRUE : FALSE); + CreateTreeConnection = ((RequestedOptions & FILE_CREATE_TREE_CONNECTION) ? TRUE : FALSE); + OpenByFileId = ((RequestedOptions & FILE_OPEN_BY_FILE_ID) ? TRUE : FALSE); + PageFileManipulation = ((PtrIoStackLocation->Flags & SL_OPEN_PAGING_FILE) ? TRUE : FALSE); + OpenTargetDirectory = ((PtrIoStackLocation->Flags & SL_OPEN_TARGET_DIRECTORY) ? TRUE : FALSE); + IgnoreCaseWhenChecking = ((PtrIoStackLocation->Flags & SL_CASE_SENSITIVE) ? TRUE : FALSE); + + // Ensure that the operation has been directed to a valid VCB ... + PtrVCB = (PtrExt2VCB)(PtrIrpContext->TargetDeviceObject->DeviceExtension); + ASSERT(PtrVCB); + ASSERT(PtrVCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB); + + + if( !PtrNewFileObject->Vpb ) + { + PtrNewFileObject->Vpb = PtrVCB->PtrVPB; + } + + // Acquiring the VCBResource Exclusively... + // This is done to synchronise with the close and cleanup routines... + + DebugTrace(DEBUG_TRACE_MISC, "*** Going into a block to acquire VCB Exclusively [Create]", 0); + + DebugTraceState( "VCB AC:0x%LX SW:0x%LX EX:0x%LX [Create]", PtrVCB->VCBResource.ActiveCount, PtrVCB->VCBResource.NumberOfExclusiveWaiters, PtrVCB->VCBResource.NumberOfSharedWaiters ); + ExAcquireResourceExclusiveLite(&(PtrVCB->VCBResource), TRUE); + + AcquiredVCB = TRUE; + + DebugTrace(DEBUG_TRACE_MISC, "*** VCB Acquired in Create", 0); + if( PtrNewFileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Create]", PtrNewFileObject); + } + + // Verify Volume... + // if (!NT_SUCCESS(RC = Ext2VerifyVolume(PtrVCB))) + // { + // try_return(RC); + // } + + // If the volume has been locked, fail the request + + if (PtrVCB->VCBFlags & EXT2_VCB_FLAGS_VOLUME_LOCKED) + { + DebugTrace(DEBUG_TRACE_MISC, "Volume locked. Failing Create", 0 ); + RC = STATUS_ACCESS_DENIED; + try_return(RC); + } + + + if ((PtrNewFileObject->FileName.Length == 0) && ((PtrRelatedFileObject == NULL) || + (PtrRelatedFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB))) + { + // + // >>>>>>>>>>>>> Volume Open requested. <<<<<<<<<<<<< + // + + // Performing validity checks... + if ((OpenTargetDirectory) || (PtrExtAttrBuffer)) + { + RC = STATUS_INVALID_PARAMETER; + try_return(RC); + } + + if (DirectoryOnlyRequested) + { + // a volume is not a directory + RC = STATUS_NOT_A_DIRECTORY; + try_return(RC); + } + + if ((RequestedDisposition != FILE_OPEN) && (RequestedDisposition != FILE_OPEN_IF)) + { + // cannot create a new volume, I'm afraid ... + RC = STATUS_ACCESS_DENIED; + try_return(RC); + } + DebugTrace(DEBUG_TRACE_MISC, "Volume open requested", 0 ); + RC = Ext2OpenVolume(PtrVCB, PtrIrpContext, PtrIrp, ShareAccess, PtrSecurityContext, PtrNewFileObject); + ReturnedInformation = PtrIrp->IoStatus.Information; + + try_return(RC); + } + + if (OpenByFileId) + { + DebugTrace(DEBUG_TRACE_MISC, "Open by File Id requested", 0 ); + RC = STATUS_ACCESS_DENIED; + try_return(RC); + } + + // Relative path name specified... + if (PtrRelatedFileObject) + { + + if (!(PtrRelatedFCB->FCBFlags & EXT2_FCB_DIRECTORY)) + { + // we must have a directory as the "related" object + RC = STATUS_INVALID_PARAMETER; + try_return(RC); + } + + // Performing validity checks... + if ((RelatedObjectName.Length == 0) || (RelatedObjectName.Buffer[0] != L'\\')) + { + RC = STATUS_INVALID_PARAMETER; + try_return(RC); + } + + if ((TargetObjectName.Length != 0) && (TargetObjectName.Buffer[0] == L'\\')) + { + RC = STATUS_INVALID_PARAMETER; + try_return(RC); + } + + // Creating an absolute path-name. + { + AbsolutePathName.MaximumLength = TargetObjectName.Length + RelatedObjectName.Length + sizeof(WCHAR); + if (!(AbsolutePathName.Buffer = Ext2AllocatePool(PagedPool, AbsolutePathName.MaximumLength ))) + { + RC = STATUS_INSUFFICIENT_RESOURCES; + try_return(RC); + } + + RtlZeroMemory(AbsolutePathName.Buffer, AbsolutePathName.MaximumLength); + + RtlCopyMemory((void *)(AbsolutePathName.Buffer), (void *)(RelatedObjectName.Buffer), RelatedObjectName.Length); + AbsolutePathName.Length = RelatedObjectName.Length; + RtlAppendUnicodeToString(&AbsolutePathName, L"\\"); + RtlAppendUnicodeToString(&AbsolutePathName, TargetObjectName.Buffer); + } + + } + // Absolute Path name specified... + else + { + + + // Validity Checks... + if (TargetObjectName.Buffer[0] != L'\\') + { + RC = STATUS_INVALID_PARAMETER; + try_return(RC); + } + + { + AbsolutePathName.MaximumLength = TargetObjectName.Length; + if (!(AbsolutePathName.Buffer = Ext2AllocatePool(PagedPool, AbsolutePathName.MaximumLength ))) { + RC = STATUS_INSUFFICIENT_RESOURCES; + try_return(RC); + } + + RtlZeroMemory(AbsolutePathName.Buffer, AbsolutePathName.MaximumLength); + + RtlCopyMemory((void *)(AbsolutePathName.Buffer), (void *)(TargetObjectName.Buffer), TargetObjectName.Length); + AbsolutePathName.Length = TargetObjectName.Length; + } + } + + + // Parsing the path... + if (AbsolutePathName.Length == 2) + { + + // this is an open of the root directory, ensure that the caller has not requested a file only + if (FileOnlyRequested || (RequestedDisposition == FILE_SUPERSEDE) || (RequestedDisposition == FILE_OVERWRITE) || + (RequestedDisposition == FILE_OVERWRITE_IF)) + { + RC = STATUS_FILE_IS_A_DIRECTORY; + try_return(RC); + } + + RC = Ext2OpenRootDirectory(PtrVCB, PtrIrpContext, PtrIrp, ShareAccess, PtrSecurityContext, PtrNewFileObject); + DebugTrace(DEBUG_TRACE_MISC, " === Root directory opened", 0 ); + try_return(RC); + } + + + { + // Used during parsing the file path... + UNICODE_STRING RemainingName; + UNICODE_STRING CurrentName; + UNICODE_STRING NextRemainingName; + PEXT2_INODE PtrNextInode = NULL; + ULONG CurrInodeNo = 0; + PtrExt2FCB PtrCurrFCB = NULL; + PtrExt2FCB PtrNextFCB = NULL; + PFILE_OBJECT PtrCurrFileObject = NULL; + UINT NameBufferIndex; + ULONG Type = 0; + LARGE_INTEGER ZeroSize; + BOOLEAN Found = FALSE; + + ZeroSize.QuadPart = 0; + if ( PtrRelatedFileObject ) + { + CurrInodeNo = PtrRelatedFCB->INodeNo; + PtrCurrFCB = PtrRelatedFCB; + } + else + { + CurrInodeNo = PtrVCB->PtrRootDirectoryFCB->INodeNo; + PtrCurrFCB = PtrVCB->PtrRootDirectoryFCB; + + } + + // Ext2ZerooutUnicodeString( &RemainingName ); + Ext2ZerooutUnicodeString( &CurrentName ); + Ext2ZerooutUnicodeString( &NextRemainingName ); + + RemainingName = TargetObjectName; + + while ( !Found && CurrInodeNo ) + { + FsRtlDissectName ( RemainingName, &CurrentName, &NextRemainingName ); + + RemainingName = NextRemainingName; + // CurrInodeNo is the parent inode for the entry I am searching for + // PtrCurrFCB is the parent's FCB + // Current Name is its name... + + + PtrNextFCB = Ext2LocateChildFCBInCore ( PtrVCB, &CurrentName, CurrInodeNo ); + + if( PtrNextFCB ) + { + CurrInodeNo = PtrNextFCB->INodeNo; + + if( NextRemainingName.Length == 0 ) + { + // + // Done Parsing... + // Found the file... + // + Found = TRUE; + + if( OpenTargetDirectory ) + { + int i; + // + // This is for a rename/move operation... + // + ReturnedInformation = FILE_EXISTS; + + // Now replace the file name field with that of the + // Target file name... + Ext2CopyUnicodeString( + &RenameLinkTargetFileName, + &CurrentName ); + /* + + for( i = 0; i < (CurrentName.Length/2); i++ ) + { + PtrNewFileObject->FileName.Buffer[i] = CurrentName.Buffer[i]; + } + PtrNewFileObject->FileName.Length = CurrentName.Length; + */ + // Now open the Parent Directory... + PtrNextFCB = PtrCurrFCB; + CurrInodeNo = PtrNextFCB->INodeNo; + } + + // + // Relating the FCB to the New File Object + // + PtrNewFileObject->Vpb = PtrVCB->PtrVPB; + PtrNewFileObject->PrivateCacheMap = NULL; + PtrNewFileObject->FsContext = (void *)( &(PtrNextFCB->NTRequiredFCB.CommonFCBHeader) ); + PtrNewFileObject->SectionObjectPointer = &(PtrNextFCB->NTRequiredFCB.SectionObject) ; + break; + } + + else if( !Ext2IsFlagOn( PtrNextFCB->FCBFlags, EXT2_FCB_DIRECTORY ) ) + { + // Invalid path... + // Can have only a directory in the middle of the path... + // + RC = STATUS_OBJECT_PATH_NOT_FOUND; + try_return( RC ); + } + } + else // searching on the disk... + { + CurrInodeNo = Ext2LocateFileInDisk( PtrVCB, &CurrentName, PtrCurrFCB, &Type ); + if( !CurrInodeNo ) + { + // + // Not found... + // Quit searching... + // + + if( ( NextRemainingName.Length == 0 ) && + ( RequestedDisposition == FILE_CREATE ) || + ( RequestedDisposition == FILE_OPEN_IF) || + ( RequestedDisposition == FILE_OVERWRITE_IF) ) + + { + // + // Just the last component was not found... + // A create was requested... + // + if( DirectoryOnlyRequested ) + { + Type = EXT2_FT_DIR; + } + else + { + Type = EXT2_FT_REG_FILE; + } + + CurrInodeNo = Ext2CreateFile( PtrIrpContext, PtrVCB, + &CurrentName, PtrCurrFCB, Type ); + + if( !CurrInodeNo ) + { + RC = STATUS_OBJECT_PATH_NOT_FOUND; + try_return( RC ); + } + // Set the allocation size for the object is specified + //IoSetShareAccess(DesiredAccess, ShareAccess, PtrNewFileObject, &(PtrNewFCB->FCBShareAccess)); + // RC = STATUS_SUCCESS; + ReturnedInformation = FILE_CREATED; + + // Should also create a CCB structure... + // Doing that a little fathre down... ;) + + } + else if( NextRemainingName.Length == 0 && OpenTargetDirectory ) + { + int i; + // + // This is for a rename/move operation... + // Just the last component was not found... + // + ReturnedInformation = FILE_DOES_NOT_EXIST; + + // Now replace the file name field with that of the + // Target file name... + Ext2CopyUnicodeString( + &RenameLinkTargetFileName, + &CurrentName ); + /* + for( i = 0; i < (CurrentName.Length/2); i++ ) + { + PtrNewFileObject->FileName.Buffer[i] = CurrentName.Buffer[i]; + } + PtrNewFileObject->FileName.Length = CurrentName.Length; + */ + + // Now open the Parent Directory... + PtrNextFCB = PtrCurrFCB; + CurrInodeNo = PtrNextFCB->INodeNo; + // Initialize the FsContext + PtrNewFileObject->FsContext = &PtrNextFCB->NTRequiredFCB.CommonFCBHeader; + // Initialize the section object pointer... + PtrNewFileObject->SectionObjectPointer = &(PtrNextFCB->NTRequiredFCB.SectionObject); + PtrNewFileObject->Vpb = PtrVCB->PtrVPB; + PtrNewFileObject->PrivateCacheMap = NULL; + + break; + } + else + { + RC = STATUS_OBJECT_PATH_NOT_FOUND; + try_return( RC ); + } + } + + if( NextRemainingName.Length ) + { + // Should be a directory... + if( Type != EXT2_FT_DIR ) + { + // Invalid path... + // Can have only a directory in the middle of the path... + // + RC = STATUS_OBJECT_PATH_NOT_FOUND; + try_return( RC ); + } + + PtrCurrFileObject = NULL; + } + else + { + // + // Done Parsing... + // Found the file... + // + Found = TRUE; + + // + // Was I supposed to create a new file? + // + if (RequestedDisposition == FILE_CREATE && + ReturnedInformation != FILE_CREATED ) + { + ReturnedInformation = FILE_EXISTS; + RC = STATUS_OBJECT_NAME_COLLISION; + try_return(RC); + } + + // Is this the type of file I was looking for? + // Do some checking here... + + if( Type != EXT2_FT_DIR && Type != EXT2_FT_REG_FILE ) + { + // Deny access! + // Cannot open a special file... + RC = STATUS_ACCESS_DENIED; + try_return( RC ); + + } + if( DirectoryOnlyRequested && Type != EXT2_FT_DIR ) + { + RC = STATUS_NOT_A_DIRECTORY; + try_return( RC ); + } + if( FileOnlyRequested && Type == EXT2_FT_DIR ) + { + RC = STATUS_FILE_IS_A_DIRECTORY; + try_return(RC); + } + + PtrCurrFileObject = PtrNewFileObject; + // Things seem to be ok enough! + // Proceeing with the Open/Create... + + } + + + // + // Create an FCB and initialise it... + // + { + PtrExt2ObjectName PtrObjectName; + + // Initialising the object name... + PtrObjectName = Ext2AllocateObjectName(); + Ext2CopyUnicodeString( &PtrObjectName->ObjectName, &CurrentName ); + // RtlInitUnicodeString( &PtrObjectName->ObjectName, CurrentName.Buffer ); + + if( !NT_SUCCESS( Ext2CreateNewFCB( + &PtrNextFCB, // the new FCB + ZeroSize, // AllocationSize, + ZeroSize, // EndOfFile, + PtrCurrFileObject, // The File Object + PtrVCB, + PtrObjectName ) ) ) + { + RC = STATUS_INSUFFICIENT_RESOURCES; + try_return(RC); + } + + if( Type == EXT2_FT_DIR ) + PtrNextFCB->FCBFlags |= EXT2_FCB_DIRECTORY; + else if( Type != EXT2_FT_REG_FILE ) + PtrNextFCB->FCBFlags |= EXT2_FCB_SPECIAL_FILE; + + PtrNextFCB->INodeNo = CurrInodeNo ; + PtrNextFCB->ParentINodeNo = PtrCurrFCB->INodeNo; + + if( PtrCurrFileObject == NULL && CurrInodeNo != EXT2_ROOT_INO ) + { + // This is an FCB created to cache the reads done while parsing + // Put this FCB on the ClosableFCBList + if( !PtrNextFCB->ClosableFCBs.OnClosableFCBList ) + { + InsertTailList( &PtrVCB->ClosableFCBs.ClosableFCBListHead, + &PtrNextFCB->ClosableFCBs.ClosableFCBList ); + PtrVCB->ClosableFCBs.Count++; + PtrNextFCB->ClosableFCBs.OnClosableFCBList = TRUE; + } + } + } + } + + // + // Still not done parsing... + // miles to go before I open... ;) + // + PtrCurrFCB = PtrNextFCB; + } + + PtrNewFCB = PtrNextFCB; + } + + + // If I get this far... + // it means, I have located the file... + // I even have an FCB to represent it!!! + + if ( NT_SUCCESS (RC) ) + { + + if ((PtrNewFCB->FCBFlags & EXT2_FCB_DIRECTORY) && ((RequestedDisposition == FILE_SUPERSEDE) || + (RequestedDisposition == FILE_OVERWRITE) || (RequestedDisposition == FILE_OVERWRITE_IF ))) + { + RC = STATUS_FILE_IS_A_DIRECTORY; + try_return(RC); + } + + + // Check share access and fail if the share conflicts with an existing + // open. + + if (PtrNewFCB->OpenHandleCount > 0) + { + // The FCB is currently in use by some thread. + // We must check whether the requested access/share access + // conflicts with the existing open operations. + + if (!NT_SUCCESS(RC = IoCheckShareAccess(DesiredAccess, ShareAccess, PtrNewFileObject, + &(PtrNewFCB->FCBShareAccess), TRUE))) + { + // Ext2CloseCCB(PtrNewCCB); + try_return(RC); + } + } + else + { + IoSetShareAccess(DesiredAccess, ShareAccess, PtrNewFileObject, &(PtrNewFCB->FCBShareAccess)); + } + + // + // Allocating a new CCB Structure... + // + Ext2CreateNewCCB( &PtrNewCCB, PtrNewFCB, PtrNewFileObject); + PtrNewFileObject->FsContext2 = (void *) PtrNewCCB; + Ext2CopyUnicodeString( &(PtrNewCCB->AbsolutePathName), &AbsolutePathName ); + + if( ReturnedInformation == -1 ) + { + // + // ReturnedInformation has not been set so far... + // + ReturnedInformation = FILE_OPENED; + } + + // If a supersede or overwrite was requested, do so now ... + if (RequestedDisposition == FILE_SUPERSEDE) + { + // Attempt the operation here ... + if( Ext2SupersedeFile( PtrNewFCB, PtrIrpContext) ) + { + ReturnedInformation = FILE_SUPERSEDED; + } + } + + else if ((RequestedDisposition == FILE_OVERWRITE) || (RequestedDisposition == FILE_OVERWRITE_IF)) + { + // Attempt the overwrite operation... + if( Ext2OverwriteFile( PtrNewFCB, PtrIrpContext) ) + { + ReturnedInformation = FILE_OVERWRITTEN; + } + } + if( AllocationSize ) + { + if( ReturnedInformation == FILE_CREATED || + ReturnedInformation == FILE_SUPERSEDED ) + { + ULONG CurrentSize; + ULONG LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize; + + for( CurrentSize = 0; CurrentSize < AllocationSize; CurrentSize += LogicalBlockSize ) + { + Ext2AddBlockToFile( PtrIrpContext, PtrVCB, PtrNewFCB, PtrNewFileObject, FALSE ); + } + } + } + + if( ReturnedInformation == FILE_CREATED ) + { + // Allocate some data blocks if + // 1. initial file size has been specified... + // 2. if the file is a Directory... + // In case of (2) make entries for '.' and '..' + // Zero out the Blocks... + + UNICODE_STRING Name; + + if( DirectoryOnlyRequested ) + { + + Ext2CopyCharToUnicodeString( &Name, ".", 1 ); + Ext2MakeNewDirectoryEntry( PtrIrpContext, PtrNewFCB, PtrNewFileObject, &Name, EXT2_FT_DIR, PtrNewFCB->INodeNo); + + Name.Buffer[1] = '.'; + Name.Buffer[2] = '\0'; + Name.Length += 2; + Ext2MakeNewDirectoryEntry( PtrIrpContext, PtrNewFCB, PtrNewFileObject, &Name, EXT2_FT_DIR, PtrNewFCB->ParentINodeNo ); + Ext2DeallocateUnicodeString( &Name ); + } + } + if( OpenTargetDirectory ) + { + // + // Save the taget file name in the CCB... + // + Ext2CopyUnicodeString( + &PtrNewCCB->RenameLinkTargetFileName, + &RenameLinkTargetFileName ); + Ext2DeallocateUnicodeString( &RenameLinkTargetFileName ); + } + } + + try_exit: NOTHING; + + } + finally + { + if (AcquiredVCB) + { + ASSERT(PtrVCB); + Ext2ReleaseResource(&(PtrVCB->VCBResource)); + + AcquiredVCB = FALSE; + DebugTrace(DEBUG_TRACE_MISC, "*** VCB released [Create]", 0); + + if( PtrNewFileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Create]", PtrNewFileObject); + } + } + + if (AbsolutePathName.Buffer != NULL) + { + DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [Create]", AbsolutePathName.Buffer ); + ExFreePool(AbsolutePathName.Buffer); + } + + // Complete the request unless we are here as part of unwinding + // when an exception condition was encountered, OR + // if the request has been deferred (i.e. posted for later handling) + if (RC != STATUS_PENDING) + { + // If we acquired any FCB resources, release them now ... + + // If any intermediate (directory) open operations were performed, + // implement the corresponding close (do *not* however close + // the target you have opened on behalf of the caller ...). + + if (NT_SUCCESS(RC)) + { + // Update the file object such that: + // (a) the FsContext field points to the NTRequiredFCB field + // in the FCB + // (b) the FsContext2 field points to the CCB created as a + // result of the open operation + + // If write-through was requested, then mark the file object + // appropriately + if (WriteThroughRequested) + { + PtrNewFileObject->Flags |= FO_WRITE_THROUGH; + } + DebugTrace( DEBUG_TRACE_SPECIAL, " === Create/Open successful", 0 ); + } + else + { + DebugTrace( DEBUG_TRACE_SPECIAL, " === Create/Open failed", 0 ); + // Perform failure related post-processing now + } + + // As long as this unwinding is not being performed as a result of + // an exception condition, complete the IRP ... + if (!(PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_EXCEPTION)) + { + PtrIrp->IoStatus.Status = RC; + PtrIrp->IoStatus.Information = ReturnedInformation; + + // Free up the Irp Context + Ext2ReleaseIrpContext(PtrIrpContext); + + // complete the IRP + IoCompleteRequest(PtrIrp, IO_DISK_INCREMENT); + } + } + } + return(RC); +} + + +/************************************************************************* +* +* Function: Ext2OpenVolume() +* +* Description: +* Open a logical volume for the caller. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +NTSTATUS Ext2OpenVolume( +PtrExt2VCB PtrVCB, // volume to be opened +PtrExt2IrpContext PtrIrpContext, // IRP context +PIRP PtrIrp, // original/user IRP +unsigned short ShareAccess, // share access +PIO_SECURITY_CONTEXT PtrSecurityContext, // caller's context (incl access) +PFILE_OBJECT PtrNewFileObject) // I/O Mgr. created file object +{ + NTSTATUS RC = STATUS_SUCCESS; + PtrExt2CCB PtrCCB = NULL; + + try { + // check for exclusive open requests (using share modes supplied) + // and determine whether it is even possible to open the volume + // with the specified share modes (e.g. if caller does not + // wish to share read or share write ...) + + // Use IoCheckShareAccess() and IoSetShareAccess() here ... + // They are defined in the DDK. + + // You might also wish to check the caller's security context + // to see whether you wish to allow the volume open or not. + // Use the SeAccessCheck() routine described in the DDK for this purpose. + + // create a new CCB structure + if (!(PtrCCB = Ext2AllocateCCB())) + { + RC = STATUS_INSUFFICIENT_RESOURCES; + try_return(RC); + } + + // initialize the CCB + PtrCCB->PtrFCB = (PtrExt2FCB)(PtrVCB); + InsertTailList(&(PtrVCB->VolumeOpenListHead), &(PtrCCB->NextCCB)); + + // initialize the CCB to point to the file object + PtrCCB->PtrFileObject = PtrNewFileObject; + + Ext2SetFlag(PtrCCB->CCBFlags, EXT2_CCB_VOLUME_OPEN); + + // initialize the file object appropriately + PtrNewFileObject->FsContext = (void *)( &(PtrVCB->CommonVCBHeader) ); + PtrNewFileObject->FsContext2 = (void *)(PtrCCB); + + // increment the number of outstanding open operations on this + // logical volume (i.e. volume cannot be dismounted) + + // You might be concerned about 32 bit wrap-around though I would + // argue that it is unlikely ... :-) + (PtrVCB->VCBOpenCount)++; + + // now set the IoStatus Information value correctly in the IRP + // (caller will set the status field) + PtrIrp->IoStatus.Information = FILE_OPENED; + + try_exit: NOTHING; + } + finally + { + NOTHING; + } + + return(RC); +} + +/************************************************************************* +* +* Function: Ext2InitializeFCB() +* +* Description: +* Initialize a new FCB structure and also the sent-in file object +* (if supplied) +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: None +* +************************************************************************* +void Ext2InitializeFCB( +PtrExt2FCB PtrNewFCB, // FCB structure to be initialized +PtrExt2VCB PtrVCB, // logical volume (VCB) pointer +PtrExt2ObjectName PtrObjectName, // name of the object +uint32 Flags, // is this a file/directory, etc. +PFILE_OBJECT PtrFileObject) // optional file object to be initialized +{ + // Initialize the disk dependent portion as you see fit + + // Initialize the two ERESOURCE objects + ExInitializeResourceLite(&(PtrNewFCB->NTRequiredFCB.MainResource)); + ExInitializeResourceLite(&(PtrNewFCB->NTRequiredFCB.PagingIoResource)); + + PtrNewFCB->FCBFlags |= EXT2_INITIALIZED_MAIN_RESOURCE | EXT2_INITIALIZED_PAGING_IO_RESOURCE | Flags; + + PtrNewFCB->PtrVCB = PtrVCB; + + // caller MUST ensure that VCB has been acquired exclusively + InsertTailList(&(PtrVCB->FCBListHead), &(PtrNewFCB->NextFCB)); + + // initialize the various list heads + InitializeListHead(&(PtrNewFCB->CCBListHead)); + +// PtrNewFCB->ReferenceCount = 1; +// PtrNewFCB->OpenHandleCount = 1; + + if( PtrObjectName ) + { + PtrNewFCB->FCBName = PtrObjectName; + } + + if ( PtrFileObject ) + { + PtrFileObject->FsContext = (void *)(&(PtrNewFCB->NTRequiredFCB)); + } + + return; +} +*/ + +/************************************************************************* +* +* Function: Ext2OpenRootDirectory() +* +* Description: +* Open the root directory for a volume +* +* +* Expected Interrupt Level (for execution) : +* +* ??? +* +* Return Value: None +* +*************************************************************************/ +NTSTATUS Ext2OpenRootDirectory( + PtrExt2VCB PtrVCB, // volume + PtrExt2IrpContext PtrIrpContext, // IRP context + PIRP PtrIrp, // original/user IRP + unsigned short ShareAccess, // share access + PIO_SECURITY_CONTEXT PtrSecurityContext, // caller's context (incl access) + PFILE_OBJECT PtrNewFileObject // I/O Mgr. created file object + ) +{ + // Declerations... + PtrExt2CCB PtrCCB; + + ASSERT( PtrVCB ); + ASSERT( PtrVCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB); + ASSERT( PtrVCB->PtrRootDirectoryFCB ); + AssertFCB( PtrVCB->PtrRootDirectoryFCB ); + + PtrVCB->PtrRootDirectoryFCB->INodeNo = EXT2_ROOT_INO; + + // Create a new CCB... + Ext2CreateNewCCB( &PtrCCB, PtrVCB->PtrRootDirectoryFCB, PtrNewFileObject); + PtrNewFileObject->FsContext = (void *) &(PtrVCB->PtrRootDirectoryFCB->NTRequiredFCB.CommonFCBHeader); + PtrVCB->PtrRootDirectoryFCB->FCBFlags |= EXT2_FCB_DIRECTORY; + PtrNewFileObject->FsContext2 = (void *) PtrCCB; + PtrNewFileObject->SectionObjectPointer = &PtrVCB->PtrRootDirectoryFCB->NTRequiredFCB.SectionObject; + PtrNewFileObject->Vpb = PtrVCB->PtrVPB; + + Ext2CopyUnicodeString( &(PtrCCB->AbsolutePathName), &PtrVCB->PtrRootDirectoryFCB->FCBName->ObjectName ); + + + return STATUS_SUCCESS; +} + + + +PtrExt2FCB Ext2LocateChildFCBInCore( + PtrExt2VCB PtrVCB, + PUNICODE_STRING PtrName, + ULONG ParentInodeNo ) +{ + + PtrExt2FCB PtrFCB = NULL; + ULONG InodeNo = 0; + PLIST_ENTRY PtrEntry; + + if( IsListEmpty( &(PtrVCB->FCBListHead) ) ) + { + return NULL; // Failure; + } + + for( PtrEntry = PtrVCB->FCBListHead.Flink; + PtrEntry != &PtrVCB->FCBListHead; + PtrEntry = PtrEntry->Flink ) + { + PtrFCB = CONTAINING_RECORD( PtrEntry, Ext2FCB, NextFCB ); + ASSERT( PtrFCB ); + if( PtrFCB->ParentINodeNo == ParentInodeNo ) + { + if( RtlCompareUnicodeString( &PtrFCB->FCBName->ObjectName, PtrName, TRUE ) == 0 ) + return PtrFCB; + } + } + + return NULL; +} + +PtrExt2FCB Ext2LocateFCBInCore( + PtrExt2VCB PtrVCB, + ULONG InodeNo ) +{ + PtrExt2FCB PtrFCB = NULL; + PLIST_ENTRY PtrEntry; + + if( IsListEmpty( &(PtrVCB->FCBListHead) ) ) + { + return NULL; // Failure; + } + + for( PtrEntry = PtrVCB->FCBListHead.Flink; + PtrEntry != &PtrVCB->FCBListHead; + PtrEntry = PtrEntry->Flink ) + { + PtrFCB = CONTAINING_RECORD( PtrEntry, Ext2FCB, NextFCB ); + ASSERT( PtrFCB ); + if( PtrFCB->INodeNo == InodeNo ) + { + return PtrFCB; + } + } + + return NULL; +} + + +ULONG Ext2LocateFileInDisk ( + PtrExt2VCB PtrVCB, + PUNICODE_STRING PtrCurrentName, + PtrExt2FCB PtrParentFCB, + ULONG *Type ) +{ + + PtrExt2FCB PtrNewFCB = NULL; + PFILE_OBJECT PtrFileObject = NULL; + ULONG InodeNo = 0; + + *Type = EXT2_FT_UNKNOWN; + + // 1. + // Initialize the Blocks in the FCB... + // + Ext2InitializeFCBInodeInfo( PtrParentFCB ); + + + // 2. + // Is there a file object I can use for caching?? + // If not create one... + // + if( !PtrParentFCB->DcbFcb.Dcb.PtrDirFileObject ) + { + // + // No Directory File Object? + // No problem, will create one... + // + + // Acquire the MainResource first though... + + PtrParentFCB->DcbFcb.Dcb.PtrDirFileObject = IoCreateStreamFileObject(NULL, PtrVCB->TargetDeviceObject ); + PtrFileObject = PtrParentFCB->DcbFcb.Dcb.PtrDirFileObject; + + if( !PtrFileObject ) + { + Ext2BreakPoint(); + return 0; + } + PtrFileObject->ReadAccess = TRUE; + PtrFileObject->WriteAccess = TRUE; + + // Associate the file stream with the Volume parameter block... + PtrFileObject->Vpb = PtrVCB->PtrVPB; + + // No caching as yet... + PtrFileObject->PrivateCacheMap = NULL; + + // this establishes the FCB - File Object connection... + PtrFileObject->FsContext = (void *)( & (PtrParentFCB->NTRequiredFCB.CommonFCBHeader) ); + + // Initialize the section object pointer... + PtrFileObject->SectionObjectPointer = &(PtrParentFCB->NTRequiredFCB.SectionObject); + } + else + { + // + // I do have a file object... + // I am using it now! + // + PtrFileObject = PtrParentFCB->DcbFcb.Dcb.PtrDirFileObject; + } + + // 3. + // Got hold of a file object? Good ;) + // Now initiating Caching, pinned access to be precise ... + // + if (PtrFileObject->PrivateCacheMap == NULL) + { + CcInitializeCacheMap(PtrFileObject, (PCC_FILE_SIZES)(&(PtrParentFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize)), + TRUE, // We utilize pin access for directories + &(Ext2GlobalData.CacheMgrCallBacks), // callbacks + PtrParentFCB ); // The context used in callbacks + } + + // 4. + // Getting down to the real business now... ;) + // Read in the directory contents and do a search + // a sequential search to be precise... + // Wish Mm'm Renuga were reading this + // Would feel proud... ;) + // + { + LARGE_INTEGER StartBufferOffset; + ULONG PinBufferLength; + ULONG BufferIndex; + PBCB PtrBCB = NULL; + BYTE * PtrPinnedBlockBuffer = NULL; + PEXT2_DIR_ENTRY PtrDirEntry = NULL; + BOOLEAN Found; + int i; + + + StartBufferOffset.QuadPart = 0; + + // + // Read in the whole damn directory + // **Bad programming** + // Will do for now. + // + PinBufferLength = PtrParentFCB->NTRequiredFCB.CommonFCBHeader.FileSize.LowPart; + if (!CcMapData( PtrFileObject, + &StartBufferOffset, + PinBufferLength, + TRUE, + &PtrBCB, + (PVOID*)&PtrPinnedBlockBuffer ) ) + { + + + } + // + // Walking through now... + // + + for( BufferIndex = 0, Found = FALSE; !Found && BufferIndex < ( PtrParentFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart - 1) ; BufferIndex += PtrDirEntry->rec_len ) + { + PtrDirEntry = (PEXT2_DIR_ENTRY) &PtrPinnedBlockBuffer[ BufferIndex ]; + if( PtrDirEntry->name_len == 0 || PtrDirEntry->rec_len == 0 || PtrDirEntry->inode == 0) + { + // Invalid entry... + // Ignore... + continue; + } + // + // Comparing ( case sensitive ) + // Directory entry is not NULL terminated... + // nor is the CurrentName... + // + if( PtrDirEntry->name_len != (PtrCurrentName->Length / 2) ) + continue; + + for( i = 0, Found = TRUE ; i < PtrDirEntry->name_len ; i++ ) + { + if( PtrDirEntry->name[ i ] != PtrCurrentName->Buffer[ i ] ) + { + Found = FALSE; + break; + + } + } + + } + if( Found ) + { + InodeNo = PtrDirEntry->inode; + + if( PtrDirEntry->file_type == EXT2_FT_UNKNOWN ) + { + + // Old Fashioned Directory entries... + // Will have to read in the Inode to determine the File Type... + EXT2_INODE Inode; + // PtrInode = Ext2AllocatePool( NonPagedPool, sizeof( EXT2_INODE ) ); + Ext2ReadInode( PtrVCB, InodeNo, &Inode ); + + if( Ext2IsModeRegularFile( Inode.i_mode ) ) + { + *Type = EXT2_FT_REG_FILE; + } + else if ( Ext2IsModeDirectory( Inode.i_mode) ) + { + // Directory... + *Type = EXT2_FT_DIR; + } + else if( Ext2IsModeSymbolicLink(Inode.i_mode) ) + { + *Type = EXT2_FT_SYMLINK; + } + else if( Ext2IsModePipe(Inode.i_mode) ) + { + *Type = EXT2_FT_FIFO; + } + else if( Ext2IsModeCharacterDevice(Inode.i_mode) ) + { + *Type = EXT2_FT_CHRDEV; + } + else if( Ext2IsModeBlockDevice(Inode.i_mode) ) + { + *Type = EXT2_FT_BLKDEV; + } + else if( Ext2IsModeSocket(Inode.i_mode) ) + { + *Type = EXT2_FT_SOCK; + } + else + { + *Type = EXT2_FT_UNKNOWN; + } + + //DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [Create]", PtrInode ); + //ExFreePool( PtrInode ); + } + else + { + *Type = PtrDirEntry->file_type; + } + } + + CcUnpinData( PtrBCB ); + PtrBCB = NULL; + + return InodeNo; + } +} + + +/************************************************************************* +* +* Function: Ext2CreateFile() +* +* Description: +* Creates a new file on the disk +* +* Expected Interrupt Level (for execution) : +* IRQL_PASSIVE_LEVEL +* +* Restrictions: +* Expects the VCB to be acquired Exclusively before being invoked +* +* Return Value: None +* +*************************************************************************/ +ULONG Ext2CreateFile( + PtrExt2IrpContext PtrIrpContext, + PtrExt2VCB PtrVCB, + PUNICODE_STRING PtrName, + PtrExt2FCB PtrParentFCB, + ULONG Type) +{ + EXT2_INODE Inode, ParentInode; + + ULONG NewInodeNo = 0; + BOOLEAN FCBAcquired = FALSE; + + ULONG LogicalBlockSize = 0; + + try + { + + + // 0. Verify if the creation is possible,,, + if( Type != EXT2_FT_DIR && Type != EXT2_FT_REG_FILE ) + { + // + // Can create only a directory or a regular file... + // + return 0; + } + + // 1. Allocate an i-node... + + NewInodeNo = Ext2AllocInode( PtrIrpContext, PtrVCB, PtrParentFCB->INodeNo ); + + // NewInodeNo = 12; + + if( !NewInodeNo ) + { + return 0; + } + + // 2. Acquire the Parent FCB Exclusively... + if( !ExAcquireResourceExclusiveLite(&( PtrParentFCB->NTRequiredFCB.MainResource ), TRUE) ) + { + Ext2DeallocInode( PtrIrpContext, PtrVCB, NewInodeNo ); + try_return( NewInodeNo = 0); + } + FCBAcquired = TRUE; + + // 3. Make an entry in the parent Directory... + ASSERT( PtrParentFCB->DcbFcb.Dcb.PtrDirFileObject ); + + Ext2MakeNewDirectoryEntry( + PtrIrpContext, + PtrParentFCB, + PtrParentFCB->DcbFcb.Dcb.PtrDirFileObject, + PtrName, Type, NewInodeNo ); + + + // 4. Initialize an inode entry and write it to disk... + LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize; + + { + // To be deleted + Ext2ReadInode( PtrVCB, NewInodeNo, &Inode ); + } + + RtlZeroMemory( &Inode, sizeof( EXT2_INODE ) ); + if( Type == EXT2_FT_DIR ) + { + Inode.i_mode = 0x41ff; + + // In addition to the usual link, + // there will be an additional link in the directory itself - the '.' entry + Inode.i_links_count = 2; + + // Incrementing the link count for the parent as well... + Ext2ReadInode( PtrVCB, PtrParentFCB->INodeNo, &ParentInode ); + ParentInode.i_links_count++; + Ext2WriteInode( PtrIrpContext, PtrVCB, PtrParentFCB->INodeNo, &ParentInode ); + + } + else + { + Inode.i_mode = 0x81ff; + Inode.i_links_count = 1; + } + + + { + // + // Setting the time fields in the inode... + // + ULONG Time; + Time = Ext2GetCurrentTime(); + Inode.i_ctime = Time; + Inode.i_atime = Time; + Inode.i_mtime = Time; + Inode.i_dtime = 0; // Deleted time; + } + + Ext2WriteInode( PtrIrpContext, PtrVCB, NewInodeNo, &Inode ); + + try_exit: NOTHING; + } + finally + { + if( FCBAcquired ) + { + Ext2ReleaseResource( &(PtrParentFCB->NTRequiredFCB.MainResource) ); + } + } + + return NewInodeNo ; +} + +/************************************************************************* +* +* Function: Ext2CreateFile() +* +* Description: +* Overwrites an existing file on the disk +* +* Expected Interrupt Level (for execution) : +* IRQL_PASSIVE_LEVEL +* +* Restrictions: +* Expects the VCB to be acquired Exclusively before being invoked +* +* Return Value: None +* +*************************************************************************/ +BOOLEAN Ext2OverwriteFile( + PtrExt2FCB PtrFCB, + PtrExt2IrpContext PtrIrpContext) +{ + EXT2_INODE Inode; + PtrExt2VCB PtrVCB = PtrFCB->PtrVCB; + ULONG i; + ULONG Time; + Time = Ext2GetCurrentTime(); + + Ext2InitializeFCBInodeInfo( PtrFCB ); + // 1. + // Update the inode... + if( !NT_SUCCESS( Ext2ReadInode( PtrVCB, PtrFCB->INodeNo, &Inode ) ) ) + { + return FALSE; + } + + Inode.i_size = 0; + Inode.i_blocks = 0; + Inode.i_atime = Time; + Inode.i_mtime = Time; + Inode.i_dtime = 0; + + for( i = 0; i < EXT2_N_BLOCKS; i++ ) + { + Inode.i_block[ i ] = 0; + } + + if( !NT_SUCCESS( Ext2WriteInode( PtrIrpContext, PtrVCB, PtrFCB->INodeNo, &Inode ) ) ) + { + return FALSE; + } + + // 2. + // Release all the data blocks... + if( !Ext2ReleaseDataBlocks( PtrFCB, PtrIrpContext) ) + { + return FALSE; + } + + Ext2ClearFlag( PtrFCB->FCBFlags, EXT2_FCB_BLOCKS_INITIALIZED ); + Ext2InitializeFCBInodeInfo( PtrFCB ); + + return TRUE; +} + +/************************************************************************* +* +* Function: Ext2SupersedeFile() +* +* Description: +* Supersedes an existing file on the disk +* +* Expected Interrupt Level (for execution) : +* IRQL_PASSIVE_LEVEL +* +* Restrictions: +* Expects the VCB to be acquired Exclusively before being invoked +* +* Return Value: None +* +*************************************************************************/ +BOOLEAN Ext2SupersedeFile( + PtrExt2FCB PtrFCB, + PtrExt2IrpContext PtrIrpContext) +{ + EXT2_INODE Inode; + PtrExt2VCB PtrVCB = PtrFCB->PtrVCB; + ULONG i; + + Ext2InitializeFCBInodeInfo( PtrFCB ); + + // 1. + // Initialize the inode... + RtlZeroMemory( &Inode, sizeof( EXT2_INODE ) ); + + // Setting the file mode... + // This operation is allowed only for a regular file... + Inode.i_mode = 0x81ff; + + // Maintaining the old link count... + Inode.i_links_count = PtrFCB->LinkCount; + + // Setting the time fields in the inode... + { + ULONG Time; + Time = Ext2GetCurrentTime(); + Inode.i_ctime = Time; + Inode.i_atime = Time; + Inode.i_mtime = Time; + Inode.i_dtime = 0; // Deleted time; + } + + if( !NT_SUCCESS( Ext2WriteInode( PtrIrpContext, PtrVCB, PtrFCB->INodeNo, &Inode ) ) ) + { + return FALSE; + } + + // 2. + // Release all the data blocks... + if( !Ext2ReleaseDataBlocks( PtrFCB, PtrIrpContext) ) + { + return FALSE; + } + + Ext2ClearFlag( PtrFCB->FCBFlags, EXT2_FCB_BLOCKS_INITIALIZED ); + Ext2InitializeFCBInodeInfo( PtrFCB ); + + return TRUE; +} diff --git a/reactos/drivers/fs/ext2/src/devcntrl.c b/reactos/drivers/fs/ext2/src/devcntrl.c new file mode 100644 index 00000000000..891f2fe7e93 --- /dev/null +++ b/reactos/drivers/fs/ext2/src/devcntrl.c @@ -0,0 +1,210 @@ +/************************************************************************* +* +* File: devcntrl.c +* +* Module: Ext2 File System Driver (Kernel mode execution only) +* +* Description: +* Contains code to handle the "Device IOCTL" dispatch entry point. +* +* Author: Manoj Paul Joseph +* +* +*************************************************************************/ + +#include "ext2fsd.h" + +// define the file specific bug-check id +#define EXT2_BUG_CHECK_ID EXT2_FILE_DEVICE_CONTROL +#define DEBUG_LEVEL DEBUG_TRACE_DEVCTRL + + +#if(_WIN32_WINNT < 0x0400) +#define IOCTL_REDIR_QUERY_PATH CTL_CODE(FILE_DEVICE_NETWORK_FILE_SYSTEM, 99, METHOD_NEITHER, FILE_ANY_ACCESS) + +typedef struct _QUERY_PATH_REQUEST +{ + ULONG PathNameLength; + PIO_SECURITY_CONTEXT SecurityContext; + WCHAR FilePathName[1]; +} QUERY_PATH_REQUEST, *PQUERY_PATH_REQUEST; + +typedef struct _QUERY_PATH_RESPONSE +{ + ULONG LengthAccepted; +} QUERY_PATH_RESPONSE, *PQUERY_PATH_RESPONSE; +#endif + + +/************************************************************************* +* +* Function: Ext2DeviceControl() +* +* Description: +* The I/O Manager will invoke this routine to handle a Device IOCTL +* request +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution +* to be deferred to a worker thread context) +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +NTSTATUS Ext2DeviceControl( +PDEVICE_OBJECT DeviceObject, // the logical volume device object +PIRP Irp) // I/O Request Packet +{ + NTSTATUS RC = STATUS_SUCCESS; + PtrExt2IrpContext PtrIrpContext = NULL; + BOOLEAN AreWeTopLevel = FALSE; + + // Ext2BreakPoint(); + + DebugTrace(DEBUG_TRACE_IRP_ENTRY, "Device Control IRP Received...", 0); + + FsRtlEnterFileSystem(); + ASSERT(DeviceObject); + ASSERT(Irp); + + // set the top level context + AreWeTopLevel = Ext2IsIrpTopLevel(Irp); + + try { + + // get an IRP context structure and issue the request + PtrIrpContext = Ext2AllocateIrpContext(Irp, DeviceObject); + ASSERT(PtrIrpContext); + + RC = Ext2CommonDeviceControl(PtrIrpContext, Irp); + + } except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) { + + RC = Ext2ExceptionHandler(PtrIrpContext, Irp); + + Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); + } + + if (AreWeTopLevel) { + IoSetTopLevelIrp(NULL); + } + + FsRtlExitFileSystem(); + + return(RC); +} + + +/************************************************************************* +* +* Function: Ext2CommonDeviceControl() +* +* Description: +* The actual work is performed here. This routine may be invoked in one' +* of the two possible contexts: +* (a) in the context of a system worker thread +* (b) in the context of the original caller +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +NTSTATUS Ext2CommonDeviceControl( +PtrExt2IrpContext PtrIrpContext, +PIRP PtrIrp) +{ + NTSTATUS RC = STATUS_SUCCESS; + PIO_STACK_LOCATION PtrIoStackLocation = NULL; + PIO_STACK_LOCATION PtrNextIoStackLocation = NULL; + PFILE_OBJECT PtrFileObject = NULL; + PtrExt2FCB PtrFCB = NULL; + PtrExt2CCB PtrCCB = NULL; + PtrExt2VCB PtrVCB = NULL; + ULONG IoControlCode = 0; + void *BufferPointer = NULL; + + try + { + // First, get a pointer to the current I/O stack location + PtrIoStackLocation = IoGetCurrentIrpStackLocation(PtrIrp); + ASSERT(PtrIoStackLocation); + + PtrFileObject = PtrIoStackLocation->FileObject; + ASSERT(PtrFileObject); + + PtrCCB = (PtrExt2CCB)(PtrFileObject->FsContext2); + ASSERT(PtrCCB); + PtrFCB = PtrCCB->PtrFCB; + ASSERT(PtrFCB); + + + if( PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB ) + { + PtrVCB = (PtrExt2VCB)(PtrFCB); + } + else + { + AssertFCB( PtrFCB ); + ASSERT(PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_FCB); + PtrVCB = PtrFCB->PtrVCB; + } + + // Get the IoControlCode value + IoControlCode = PtrIoStackLocation->Parameters.DeviceIoControl.IoControlCode; + + // You may wish to allow only volume open operations. + + // Invoke the lower level driver in the chain. + PtrNextIoStackLocation = IoGetNextIrpStackLocation(PtrIrp); + *PtrNextIoStackLocation = *PtrIoStackLocation; + // Set a completion routine. + IoSetCompletionRoutine(PtrIrp, Ext2DevIoctlCompletion, NULL, TRUE, TRUE, TRUE); + // Send the request. + RC = IoCallDriver(PtrVCB->TargetDeviceObject, PtrIrp); + + try_exit: NOTHING; + + } + finally + { + // Release the IRP context + if (!(PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_EXCEPTION)) + { + // Free up the Irp Context + Ext2ReleaseIrpContext(PtrIrpContext); + } + } + + return(RC); +} + + +/************************************************************************* +* +* Function: Ext2DevIoctlCompletion() +* +* Description: +* Completion routine. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: STATUS_SUCCESS +* +*************************************************************************/ +NTSTATUS Ext2DevIoctlCompletion( +PDEVICE_OBJECT PtrDeviceObject, +PIRP PtrIrp, +void *Context) +{ + if (PtrIrp->PendingReturned) { + IoMarkIrpPending(PtrIrp); + } + + return(STATUS_SUCCESS); +} diff --git a/reactos/drivers/fs/ext2/src/dircntrl.c b/reactos/drivers/fs/ext2/src/dircntrl.c new file mode 100644 index 00000000000..759f2c25212 --- /dev/null +++ b/reactos/drivers/fs/ext2/src/dircntrl.c @@ -0,0 +1,937 @@ +/************************************************************************* +* +* File: dircntrl.c +* +* Module: Ext2 File System Driver (Kernel mode execution only) +* +* Description: +* Contains code to handle the "directory control" dispatch entry point. +* +* Author: Manoj Paul Joseph +* +* +*************************************************************************/ + +#include "ext2fsd.h" + +// define the file specific bug-check id +#define EXT2_BUG_CHECK_ID EXT2_FILE_DIR_CONTROL + +#define DEBUG_LEVEL (DEBUG_TRACE_DIRCTRL) + + +/************************************************************************* +* +* Function: Ext2DirControl() +* +* Description: +* The I/O Manager will invoke this routine to handle a directory control +* request +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution +* to be deferred to a worker thread context) +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +NTSTATUS Ext2DirControl( +PDEVICE_OBJECT DeviceObject, // the logical volume device object +PIRP Irp) // I/O Request Packet +{ + NTSTATUS RC = STATUS_SUCCESS; + PtrExt2IrpContext PtrIrpContext = NULL; + BOOLEAN AreWeTopLevel = FALSE; + + DebugTrace(DEBUG_TRACE_IRP_ENTRY, "DIR Control IRP received...", 0); + + + FsRtlEnterFileSystem(); + + ASSERT(DeviceObject); + ASSERT(Irp); + + // set the top level context + AreWeTopLevel = Ext2IsIrpTopLevel(Irp); + + try + { + // get an IRP context structure and issue the request + PtrIrpContext = Ext2AllocateIrpContext(Irp, DeviceObject); + ASSERT(PtrIrpContext); + + RC = Ext2CommonDirControl(PtrIrpContext, Irp); + + } + except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) + { + + RC = Ext2ExceptionHandler(PtrIrpContext, Irp); + + Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); + } + + if (AreWeTopLevel) { + IoSetTopLevelIrp(NULL); + } + + FsRtlExitFileSystem(); + + return(RC); +} + + + +/************************************************************************* +* +* Function: Ext2CommonDirControl() +* +* Description: +* The actual work is performed here. This routine may be invoked in one' +* of the two possible contexts: +* (a) in the context of a system worker thread +* (b) in the context of the original caller +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +NTSTATUS Ext2CommonDirControl( +PtrExt2IrpContext PtrIrpContext, +PIRP PtrIrp) +{ + NTSTATUS RC = STATUS_SUCCESS; + PIO_STACK_LOCATION PtrIoStackLocation = NULL; + PFILE_OBJECT PtrFileObject = NULL; + PtrExt2FCB PtrFCB = NULL; + PtrExt2CCB PtrCCB = NULL; + PtrExt2VCB PtrVCB = NULL; + + // First, get a pointer to the current I/O stack location + PtrIoStackLocation = IoGetCurrentIrpStackLocation(PtrIrp); + ASSERT(PtrIoStackLocation); + + PtrFileObject = PtrIoStackLocation->FileObject; + ASSERT(PtrFileObject); + + // Get the FCB and CCB pointers + PtrCCB = (PtrExt2CCB)(PtrFileObject->FsContext2); + ASSERT(PtrCCB); + PtrFCB = PtrCCB->PtrFCB; + + AssertFCB( PtrFCB ); + + + // Get some of the parameters supplied to us + switch (PtrIoStackLocation->MinorFunction) { + case IRP_MN_QUERY_DIRECTORY: +#ifdef _GNU_NTIFS_ + RC = Ext2QueryDirectory(PtrIrpContext, PtrIrp, (PEXTENDED_IO_STACK_LOCATION)PtrIoStackLocation, PtrFileObject, PtrFCB, PtrCCB); +#else + RC = Ext2QueryDirectory(PtrIrpContext, PtrIrp, PtrIoStackLocation, PtrFileObject, PtrFCB, PtrCCB); +#endif + break; + case IRP_MN_NOTIFY_CHANGE_DIRECTORY: + { + RC = STATUS_NOT_IMPLEMENTED; + PtrIrp->IoStatus.Status = RC; + PtrIrp->IoStatus.Information = 0; + IoCompleteRequest(PtrIrp, IO_DISK_INCREMENT); + } + // RC = Ext2NotifyChangeDirectory(PtrIrpContext, PtrIrp, PtrIoStackLocation, PtrFileObject, PtrFCB, PtrCCB); + break; + default: + // This should not happen. + RC = STATUS_INVALID_DEVICE_REQUEST; + PtrIrp->IoStatus.Status = RC; + PtrIrp->IoStatus.Information = 0; + + // Free up the Irp Context + Ext2ReleaseIrpContext(PtrIrpContext); + + // complete the IRP + IoCompleteRequest(PtrIrp, IO_NO_INCREMENT); + break; + } + + return(RC); +} + + +/************************************************************************* +* +* Function: Ext2QueryDirectory() +* +* Description: +* Query directory request. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +NTSTATUS Ext2QueryDirectory( +PtrExt2IrpContext PtrIrpContext, +PIRP PtrIrp, +#ifdef _GNU_NTIFS_ +PEXTENDED_IO_STACK_LOCATION PtrIoStackLocation, +#else +PIO_STACK_LOCATION PtrIoStackLocation, +#endif +PFILE_OBJECT PtrFileObject, +PtrExt2FCB PtrFCB, +PtrExt2CCB PtrCCB) +{ + NTSTATUS RC = STATUS_SUCCESS; + BOOLEAN CompleteRequest = TRUE; + BOOLEAN PostRequest = FALSE; + PtrExt2NTRequiredFCB PtrReqdFCB = NULL; + BOOLEAN CanWait = FALSE; + PtrExt2VCB PtrVCB = NULL; + BOOLEAN AcquiredFCB = FALSE; + unsigned long BufferLength = 0; + unsigned long BufferIndex = 0; + unsigned long FileIndex = 0; + PUNICODE_STRING PtrSearchPattern = NULL; + FILE_INFORMATION_CLASS FileInformationClass; + BOOLEAN RestartScan = FALSE; + BOOLEAN ReturnSingleEntry = FALSE; + BOOLEAN IndexSpecified = FALSE; + unsigned char *Buffer = NULL; + BOOLEAN FirstTimeQuery = FALSE; + unsigned long StartingIndexForSearch = 0; + unsigned long BytesReturned = 0; + BOOLEAN BufferUsedup = FALSE; + + BOOLEAN SearchWithWildCards = FALSE; + + PFILE_BOTH_DIR_INFORMATION BothDirInformation = NULL; + PFILE_FULL_DIR_INFORMATION FullDirInformation = NULL; + PFILE_DIRECTORY_INFORMATION DirectoryInformation = NULL; + PFILE_NAMES_INFORMATION NamesInformation = NULL; + + + PEXT2_DIR_ENTRY PtrDirEntry = NULL; + PEXT2_INODE PtrInode = NULL; + + unsigned long LogicalBlockSize; + + unsigned long ThisBlock; + + // The starting Physical Block No... + //LARGE_INTEGER StartPhysicalBlock; + LARGE_INTEGER StartBufferOffset ; + ULONG PinBufferLength; + + // Buffer Control Block + PBCB PtrBCB = NULL; + BYTE * PtrPinnedBlockBuffer = NULL; + + unsigned int i,j; + + DebugTrace(DEBUG_TRACE_MISC, " === Querying Directory %S", PtrFCB->FCBName->ObjectName.Buffer ); + + try + { + // Validate the sent-in FCB + if ((PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB) || !(PtrFCB->FCBFlags & EXT2_FCB_DIRECTORY)) + { + // We will only allow notify requests on directories. + RC = STATUS_INVALID_PARAMETER; + } + + PtrReqdFCB = &(PtrFCB->NTRequiredFCB); + CanWait = ((PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_CAN_BLOCK) ? TRUE : FALSE); + PtrVCB = PtrFCB->PtrVCB; + + // + // Asynchronous IO requested + // Posting request... + // + /* + * This is incorrect because posted IRP_MJ_DIRECTORY_CONTROL + * requests aren't handled in the worker thread yet. I tried + * adding handling of them to the worked routine, but there + * were problems with accessing the PtrIoStackLocation-> + * Parameters.QueryDirectory.FileName variable. + * -- Filip Navara, 18/08/2004 + */ +#if 0 + if (!CanWait) + { + PostRequest = TRUE; + try_return(RC = STATUS_PENDING); + } +#endif + + // Obtain the callers parameters + BufferLength = PtrIoStackLocation->Parameters.QueryDirectory.Length; + PtrSearchPattern = ( PUNICODE_STRING ) PtrIoStackLocation->Parameters.QueryDirectory.FileName; + FileInformationClass = PtrIoStackLocation->Parameters.QueryDirectory.FileInformationClass; + FileIndex = PtrIoStackLocation->Parameters.QueryDirectory.FileIndex; + + // Some additional arguments that affect the FSD behavior + RestartScan = (PtrIoStackLocation->Flags & SL_RESTART_SCAN); + ReturnSingleEntry = (PtrIoStackLocation->Flags & SL_RETURN_SINGLE_ENTRY); + IndexSpecified = (PtrIoStackLocation->Flags & SL_INDEX_SPECIFIED); + + // + // Acquiring exclusive access to the FCB. + // This is not mandatory + // + DebugTrace(DEBUG_TRACE_MISC, "*** Going into a block to acquire FCB Exclusively[DirCtrl]", 0); + + DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [DirCtrl]", PtrReqdFCB->MainResource.ActiveCount, PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, PtrReqdFCB->MainResource.NumberOfSharedWaiters ); + ExAcquireResourceExclusiveLite(&(PtrReqdFCB->MainResource), TRUE); + + DebugTrace(DEBUG_TRACE_MISC, "*** FCB acquired [DirCtrl]", 0); + AcquiredFCB = TRUE; + + // We must determine the buffer pointer to be used. Since this + // routine could either be invoked directly in the context of the + // calling thread, or in the context of a worker thread, here is + // a general way of determining what we should use. + Buffer = Ext2GetCallersBuffer ( PtrIrp ); + + // The method of determining where to look from and what to look for is + // unfortunately extremely confusing. However, here is a methodology you + // you can broadly adopt: + // (a) You have to maintain a search buffer per CCB structure. + // (b) This search buffer is initialized the very first time + // a query directory operation is performed using the file object. + // (For the sample FSD, the search buffer is stored in the + // DirectorySearchPattern field) + // However, the caller still has the option of "overriding" this stored + // search pattern by supplying a new one in a query directory operation. + // + + if( PtrCCB->DirectorySearchPattern.Length ) + { + if( PtrCCB->DirectorySearchPattern.Buffer[PtrCCB->DirectorySearchPattern.Length/2] != 0 ) + { + DebugTrace(DEBUG_TRACE_MISC, "&&&&&&&&& PtrCCB->DirectorySearchPattern not NULL terminated!", 0); + } + DebugTrace(DEBUG_TRACE_MISC, " === Old Search pattern %S", PtrCCB->DirectorySearchPattern.Buffer ); + } + + if (PtrSearchPattern != NULL) + { + // User has supplied a search pattern + // Now validate that the search pattern is legitimate + + if ( PtrCCB->DirectorySearchPattern.Length == 0 ) + { + // This must be the very first query request. + FirstTimeQuery = TRUE; + } + else + { + // We should ignore the search pattern in the CCB and instead, + // use the user-supplied pattern for this particular query + // directory request. + Ext2DeallocateUnicodeString( &PtrCCB->DirectorySearchPattern ); + } + + // Now, allocate enough memory to contain the caller + // supplied search pattern and fill in the DirectorySearchPattern + // field in the CCB + Ext2CopyUnicodeString( &PtrCCB->DirectorySearchPattern, PtrSearchPattern ); + /* + PtrCCB->DirectorySearchPattern = Ext2AllocatePool(PagedPool, sizeof( PtrSearchPattern ) ); + ASSERT(PtrCCB->DirectorySearchPattern); + RtlCopyMemory( PtrCCB->DirectorySearchPattern, PtrSearchPattern, sizeof( PtrSearchPattern ) ); + */ + } + else if ( PtrCCB->DirectorySearchPattern.Length == 0 ) + { + // This MUST be the first directory query operation (else the + // DirectorySearchPattern field would never be empty. Also, the caller + // has neglected to provide a pattern so we MUST invent one. + // Use "*" (following NT conventions) as your search pattern + // and store it in the PtrCCB->DirectorySearchPattern field. + + /* + PtrCCB->DirectorySearchPattern = Ext2AllocatePool(PagedPool, sizeof(L"*") ); + ASSERT(PtrCCB->DirectorySearchPattern); + RtlCopyMemory( PtrCCB->DirectorySearchPattern, L"*", 4 );*/ + + Ext2CopyWideCharToUnicodeString( &PtrCCB->DirectorySearchPattern, L"*" ); + + FirstTimeQuery = TRUE; + } + else + { + // The caller has not supplied any search pattern... + // Using previously supplied pattern + PtrSearchPattern = &PtrCCB->DirectorySearchPattern; + } + + if( PtrCCB->DirectorySearchPattern.Buffer[PtrCCB->DirectorySearchPattern.Length/2] != 0 ) + { + DebugTrace(DEBUG_TRACE_MISC, "&&&&&&&&& PtrCCB->DirectorySearchPattern not NULL terminated!", 0 ); + } + DebugTrace(DEBUG_TRACE_MISC, " === Search pattern %S", PtrCCB->DirectorySearchPattern.Buffer ); + SearchWithWildCards = FsRtlDoesNameContainWildCards( PtrSearchPattern ); + + // There is one other piece of information that your FSD must store + // in the CCB structure for query directory support. This is the index + // value (i.e. the offset in your on-disk directory structure) from + // which you should start searching. + // However, the flags supplied with the IRP can make us override this + // as well. + + if (FileIndex) + { + // Caller has told us wherefrom to begin. + // You may need to round this to an appropriate directory entry + // entry alignment value. + StartingIndexForSearch = FileIndex; + } + else if (RestartScan) + { + StartingIndexForSearch = 0; + } + else + { + // Get the starting offset from the CCB. + StartingIndexForSearch = PtrCCB->CurrentByteOffset.LowPart; + } + + // Read in the file inode if it hasn't already been read... + Ext2InitializeFCBInodeInfo( PtrFCB ); + + if (PtrFileObject->PrivateCacheMap == NULL) + { + CcInitializeCacheMap(PtrFileObject, (PCC_FILE_SIZES)(&(PtrReqdFCB->CommonFCBHeader.AllocationSize)), + TRUE, // We will utilize pin access for directories + &(Ext2GlobalData.CacheMgrCallBacks), // callbacks + PtrCCB); // The context used in callbacks + } + + + // + // Read in the next Data Block of this directory + // + LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize; + StartBufferOffset.QuadPart = ( StartingIndexForSearch / LogicalBlockSize ); + StartBufferOffset.QuadPart *= LogicalBlockSize; // This should be the StartBufferOffset alaigned to LBlock boundary... + + PinBufferLength = PtrReqdFCB->CommonFCBHeader.FileSize.LowPart - StartBufferOffset.LowPart; + + if ( !CcMapData( PtrFileObject, + &StartBufferOffset, + PinBufferLength, + TRUE, + &PtrBCB, + (PVOID*)&PtrPinnedBlockBuffer ) ) + { + // Read Failure + DebugTrace(DEBUG_TRACE_MISC, "Cache read failiure while reading in volume meta data", 0); + try_return( STATUS_ACCESS_DENIED ); + } + else + { + DebugTrace(DEBUG_TRACE_MISC, "Cache hit while reading in volume meta data", 0); + } + + PtrInode = Ext2AllocatePool( PagedPool, sizeof( EXT2_INODE ) ); + + // + // Walking through the directory entries... + for( BufferUsedup = FALSE, BufferIndex = 0; !BufferUsedup && StartingIndexForSearch < ( PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart - 1) ; ) + { + PtrDirEntry = (PEXT2_DIR_ENTRY) &PtrPinnedBlockBuffer[ StartingIndexForSearch - StartBufferOffset.LowPart ]; + + StartingIndexForSearch += PtrDirEntry->rec_len; + PtrCCB->CurrentByteOffset.LowPart = StartingIndexForSearch; + + if( PtrDirEntry->inode == 0 ) + { + continue; + } + if( PtrDirEntry->name_len == 0 || PtrDirEntry->rec_len == 0 ) + { + // + // This should not happen + // Hqw can this be so!!! + // + Ext2BreakPoint(); + if( BothDirInformation ) + { + BothDirInformation->NextEntryOffset = 0; + } + if( !BytesReturned ) + { + if( FirstTimeQuery ) + RC = STATUS_NO_SUCH_FILE; + else + RC = STATUS_NO_MORE_FILES; + } + break; + } + + // Does this entry match the search criterian? + // Checking + // + { + UNICODE_STRING FileName; + LONG Matched = 0; + // Constructing a counted Unicode string out of PtrDirEntry + Ext2CopyCharToUnicodeString( &FileName, PtrDirEntry->name, PtrDirEntry->name_len ); + + if ( SearchWithWildCards ) + { + Matched = FsRtlIsNameInExpression ( PtrSearchPattern, &FileName, FALSE, NULL ); + } + else + { + Matched = ! RtlCompareUnicodeString( PtrSearchPattern, &FileName, FALSE ); + } + + Ext2DeallocateUnicodeString( &FileName ); + if( !Matched ) + { + continue; + } + } + + switch( FileInformationClass ) + { + case FileBothDirectoryInformation: + + DebugTrace(DEBUG_TRACE_DIRINFO, " === FileBothDirectoryInformation", 0 ); + ThisBlock = sizeof( FILE_BOTH_DIR_INFORMATION ); + ThisBlock += PtrDirEntry->name_len*2; + ThisBlock = Ext2QuadAlign( ThisBlock ); + + if( ( BufferIndex + ThisBlock ) > BufferLength ) + { + // + // Next entry won't fit into the buffer... + // will have to return... + // :( + // + if( BothDirInformation ) + BothDirInformation->NextEntryOffset = 0; + if( !BytesReturned ) + RC = STATUS_NO_MORE_FILES; + BufferUsedup = TRUE; + break; + } + + Ext2ReadInode( PtrVCB, PtrDirEntry->inode, PtrInode ); + if( !PtrInode ) + { + try_return( RC = STATUS_UNSUCCESSFUL ); + } + + BothDirInformation = ( PFILE_BOTH_DIR_INFORMATION ) ( Buffer + ( BufferIndex ) ); + BothDirInformation->EaSize = 0; + BothDirInformation->AllocationSize.QuadPart = PtrInode->i_blocks * 512; + BothDirInformation->EndOfFile.QuadPart = PtrInode->i_size; + BothDirInformation->ChangeTime.QuadPart = 0; + + BothDirInformation->CreationTime.QuadPart = ( __int64 ) PtrInode->i_ctime * 10000000; + BothDirInformation->CreationTime.QuadPart += Ext2GlobalData.TimeDiff.QuadPart; + + BothDirInformation->LastAccessTime.QuadPart = Ext2GlobalData.TimeDiff.QuadPart + ( ( __int64 ) PtrInode->i_atime * 10000000 ); + BothDirInformation->LastWriteTime.QuadPart = Ext2GlobalData.TimeDiff.QuadPart + ( ( __int64 )PtrInode->i_mtime * 10000000 ); + + // Getting the file type... + BothDirInformation->FileAttributes = FILE_ATTRIBUTE_NORMAL; + if( ! Ext2IsModeRegularFile( PtrInode->i_mode ) ) + { + // Not a reqular file... + if( Ext2IsModeDirectory( PtrInode->i_mode) ) + { + // Directory... + BothDirInformation->FileAttributes |= FILE_ATTRIBUTE_DIRECTORY; + } + else + { + // Special File... + // Treated with respect... ;) + // + BothDirInformation->FileAttributes |= ( FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_READONLY); + // FILE_ATTRIBUTE_DEVICE + } + if ( Ext2IsModeHidden( PtrInode->i_mode ) ) + { + BothDirInformation->FileAttributes |= FILE_ATTRIBUTE_HIDDEN; + } + + if ( Ext2IsModeReadOnly( PtrInode->i_mode ) ) + { + BothDirInformation->FileAttributes |= FILE_ATTRIBUTE_READONLY; + } + } + + BothDirInformation->FileIndex = StartingIndexForSearch; + BothDirInformation->FileNameLength = PtrDirEntry->name_len*2 + 2; + BothDirInformation->ShortNameLength = 0; + BothDirInformation->ShortName[0] = 0; + + // Copying out the name as WCHAR null terminated strings + for( j = 0; j< PtrDirEntry->name_len ; j ++ ) + { + // BothDirInformation->ShortName[ j ] = PtrDirEntry->name[j]; + BothDirInformation->FileName[ j ] = PtrDirEntry->name[j]; + // if( j < 11 ) + // BothDirInformation->ShortName[j] = PtrDirEntry->name[j];; + } + + /* + if( j < 11 ) + { + BothDirInformation->ShortNameLength = j * 2 + 2; + BothDirInformation->ShortName[ j ] = 0; + } + else + { + BothDirInformation->ShortNameLength = 24; + BothDirInformation->ShortName[ 11 ] = 0; + }*/ + + BothDirInformation->FileName[ j ] = 0; + BytesReturned += ThisBlock; + BufferIndex += ThisBlock; + + if( !ReturnSingleEntry && ( StartingIndexForSearch < ( PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart - 1) )) + BothDirInformation->NextEntryOffset = ThisBlock; + else + BothDirInformation->NextEntryOffset = 0; + break; + + case FileDirectoryInformation: + // DirectoryInformation + DebugTrace(DEBUG_TRACE_DIRINFO, " === FileDirectoryInformation", 0 ); + ThisBlock = sizeof( FILE_DIRECTORY_INFORMATION ); + ThisBlock += PtrDirEntry->name_len*2; + ThisBlock = Ext2QuadAlign( ThisBlock ); + + if( ( BufferIndex + ThisBlock ) > BufferLength ) + { + // + // Next entry won't fit into the buffer... + // will have to return... + // :( + // + if( DirectoryInformation ) + DirectoryInformation->NextEntryOffset = 0; + if( !BytesReturned ) + RC = STATUS_NO_MORE_FILES; + BufferUsedup = TRUE; + break; + } + + Ext2ReadInode( PtrVCB, PtrDirEntry->inode, PtrInode ); + if( !PtrInode ) + { + try_return( RC = STATUS_UNSUCCESSFUL ); + } + + DirectoryInformation = ( PFILE_DIRECTORY_INFORMATION ) ( Buffer + ( BufferIndex ) ); + DirectoryInformation->AllocationSize.QuadPart = PtrInode->i_blocks * 512; + DirectoryInformation->EndOfFile.QuadPart = PtrInode->i_size; + DirectoryInformation->ChangeTime.QuadPart = 0; + + DirectoryInformation->CreationTime.QuadPart = ( __int64 ) PtrInode->i_ctime * 10000000; + DirectoryInformation->CreationTime.QuadPart += Ext2GlobalData.TimeDiff.QuadPart; + + DirectoryInformation->LastAccessTime.QuadPart = Ext2GlobalData.TimeDiff.QuadPart + ( ( __int64 ) PtrInode->i_atime * 10000000 ); + DirectoryInformation->LastWriteTime.QuadPart = Ext2GlobalData.TimeDiff.QuadPart + ( ( __int64 )PtrInode->i_mtime * 10000000 ); + + // Getting the file type... + DirectoryInformation->FileAttributes = FILE_ATTRIBUTE_NORMAL; + if( ! Ext2IsModeRegularFile( PtrInode->i_mode ) ) + { + // Not a reqular file... + if( Ext2IsModeDirectory( PtrInode->i_mode) ) + { + // Directory... + DirectoryInformation->FileAttributes |= FILE_ATTRIBUTE_DIRECTORY; + } + else + { + // Special File... + // Treated with respect... ;) + // + DirectoryInformation->FileAttributes |= ( FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_READONLY); + // FILE_ATTRIBUTE_DEVICE + } + if ( Ext2IsModeHidden( PtrInode->i_mode ) ) + { + DirectoryInformation->FileAttributes |= FILE_ATTRIBUTE_HIDDEN; + } + + if ( Ext2IsModeReadOnly( PtrInode->i_mode ) ) + { + DirectoryInformation->FileAttributes |= FILE_ATTRIBUTE_READONLY; + } + } + + DirectoryInformation->FileIndex = StartingIndexForSearch; + DirectoryInformation->FileNameLength = PtrDirEntry->name_len*2 + 2; + + // Copying out the name as WCHAR null terminated strings + for( j = 0; j< PtrDirEntry->name_len ; j ++ ) + { + DirectoryInformation->FileName[ j ] = PtrDirEntry->name[j]; + } + + DirectoryInformation->FileName[ j ] = 0; + BytesReturned += ThisBlock; + BufferIndex += ThisBlock; + + if( !ReturnSingleEntry && ( StartingIndexForSearch < ( PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart - 1) )) + DirectoryInformation->NextEntryOffset = ThisBlock; + else + DirectoryInformation->NextEntryOffset = 0; + break; + + case FileFullDirectoryInformation: + // FullDirInformation-> + DebugTrace(DEBUG_TRACE_DIRINFO, " === FileFullDirectoryInformation - Not handled", 0 ); + try_return( RC ); + case FileNamesInformation: + // NamesInformation-> + DebugTrace(DEBUG_TRACE_DIRINFO, " === FileNamesInformation - Not handled", 0 ); + try_return( RC ); + default: + DebugTrace(DEBUG_TRACE_DIRINFO, " === Invalid Dir Info class - Not handled", 0 ); + try_return( RC = STATUS_INVALID_INFO_CLASS ); + } + if( ReturnSingleEntry ) + { + break; + } + }// end of for... + + + + if( !BytesReturned && StartingIndexForSearch >= ( PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart) ) + { + Ext2DeallocateUnicodeString( &PtrCCB->DirectorySearchPattern ); + PtrCCB->CurrentByteOffset.QuadPart = 0; + if( FirstTimeQuery ) + RC = STATUS_NO_SUCH_FILE; + else + RC = STATUS_NO_MORE_FILES; + try_return( RC ); + } + else if( BytesReturned ) + { + BothDirInformation->NextEntryOffset = 0; + } + + try_exit: NOTHING; + } + finally + { + + if( PtrInode ) + { + DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [DirCtrl]", PtrInode ); + ExFreePool( PtrInode ); + } + + if( PtrBCB ) + { + CcUnpinData( PtrBCB ); + PtrBCB = NULL; + } + + if (PostRequest) + { + if (AcquiredFCB) + { + Ext2ReleaseResource(&(PtrReqdFCB->MainResource)); + DebugTrace(DEBUG_TRACE_MISC, "*** FCB Released in [DirCtrl]", 0); + DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [DirCtrl]", + PtrReqdFCB->MainResource.ActiveCount, + PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, + PtrReqdFCB->MainResource.NumberOfSharedWaiters ); + } + + // Map the users buffer and then post the request. + RC = Ext2LockCallersBuffer(PtrIrp, TRUE, BufferLength); + ASSERT(NT_SUCCESS(RC)); + + RC = Ext2PostRequest(PtrIrpContext, PtrIrp); + + } + else if (!(PtrIrpContext->IrpContextFlags & + EXT2_IRP_CONTEXT_EXCEPTION)) + { + if (AcquiredFCB) + { + Ext2ReleaseResource(&(PtrReqdFCB->MainResource)); + DebugTrace(DEBUG_TRACE_MISC, "*** FCB Released [DirCtrl]", 0); + DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [DirCtrl]", + PtrReqdFCB->MainResource.ActiveCount, + PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, + PtrReqdFCB->MainResource.NumberOfSharedWaiters ); + } + + // Complete the request. + PtrIrp->IoStatus.Status = RC; + PtrIrp->IoStatus.Information = BytesReturned; + + // Free up the Irp Context + Ext2ReleaseIrpContext(PtrIrpContext); + + // complete the IRP + IoCompleteRequest(PtrIrp, IO_DISK_INCREMENT); + } + + // Flush the saved BCBs... + // Ext2FlushSavedBCBs ( PtrIrpContext ); + + } + + return(RC); +} + + + +/************************************************************************* +* +* Function: Ext2NotifyChangeDirectory() +* +* Description: +* Handle the notify request. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +NTSTATUS Ext2NotifyChangeDirectory( +PtrExt2IrpContext PtrIrpContext, +PIRP PtrIrp, +#ifdef _GNU_NTIFS_ +PEXTENDED_IO_STACK_LOCATION PtrIoStackLocation, +#else +PIO_STACK_LOCATION PtrIoStackLocation, +#endif +PFILE_OBJECT PtrFileObject, +PtrExt2FCB PtrFCB, +PtrExt2CCB PtrCCB) +{ + NTSTATUS RC = STATUS_SUCCESS; + BOOLEAN CompleteRequest = FALSE; + BOOLEAN PostRequest = FALSE; + PtrExt2NTRequiredFCB PtrReqdFCB = NULL; + BOOLEAN CanWait = FALSE; + ULONG CompletionFilter = 0; + BOOLEAN WatchTree = FALSE; + PtrExt2VCB PtrVCB = NULL; + BOOLEAN AcquiredFCB = FALSE; + + try { + + // Validate the sent-in FCB + if ((PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB) || !(PtrFCB->FCBFlags & EXT2_FCB_DIRECTORY)) { + // We will only allow notify requests on directories. + RC = STATUS_INVALID_PARAMETER; + CompleteRequest = TRUE; + } + + PtrReqdFCB = &(PtrFCB->NTRequiredFCB); + CanWait = ((PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_CAN_BLOCK) ? TRUE : FALSE); + PtrVCB = PtrFCB->PtrVCB; + + // Acquire the FCB resource shared + DebugTrace(DEBUG_TRACE_MISC, "*** Attempting to acquire FCB Shared[DirCtrl]", 0); + DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [DirCtrl]", PtrReqdFCB->MainResource.ActiveCount, PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, PtrReqdFCB->MainResource.NumberOfSharedWaiters ); + if (!ExAcquireResourceSharedLite(&(PtrReqdFCB->MainResource), CanWait)) + { + DebugTrace(DEBUG_TRACE_MISC, "*** FCB Acquisition FAILED [DirCtrl]", 0); + PostRequest = TRUE; + try_return(RC = STATUS_PENDING); + } + AcquiredFCB = TRUE; + DebugTrace(DEBUG_TRACE_MISC, "*** FCB acquired [DirCtrl]", 0); + + // Obtain some parameters sent by the caller + CompletionFilter = PtrIoStackLocation->Parameters.NotifyDirectory.CompletionFilter; + WatchTree = (PtrIoStackLocation->Flags & SL_WATCH_TREE ? TRUE : FALSE); + + // If you wish to capture the subject context, you can do so as + // follows: + // { + // PSECURITY_SUBJECT_CONTEXT SubjectContext; + // SubjectContext = Ext2AllocatePool(PagedPool, + // sizeof(SECURITY_SUBJECT_CONTEXT) ); + // SeCaptureSubjectContext(SubjectContext); + // } + + FsRtlNotifyFullChangeDirectory((PNOTIFY_SYNC)&(PtrVCB->NotifyIRPMutex), &(PtrVCB->NextNotifyIRP), (void *)PtrCCB, + (PSTRING)(PtrFCB->FCBName->ObjectName.Buffer), WatchTree, FALSE, CompletionFilter, PtrIrp, + NULL, // Ext2TraverseAccessCheck(...) ? + NULL); // SubjectContext ? + + RC = STATUS_PENDING; + + try_exit: NOTHING; + + } + finally + { + + if (PostRequest) + { + // Perform appropriate post related processing here + if (AcquiredFCB) + { + Ext2ReleaseResource(&(PtrReqdFCB->MainResource)); + DebugTrace(DEBUG_TRACE_MISC, "*** FCB Released in DirCtrl", 0); + DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [DirCtrl]", + PtrReqdFCB->MainResource.ActiveCount, + PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, + PtrReqdFCB->MainResource.NumberOfSharedWaiters ); + + AcquiredFCB = FALSE; + } + RC = Ext2PostRequest(PtrIrpContext, PtrIrp); + } + else if (CompleteRequest) + { + PtrIrp->IoStatus.Status = RC; + PtrIrp->IoStatus.Information = 0; + + // Free up the Irp Context + Ext2ReleaseIrpContext(PtrIrpContext); + + // complete the IRP + IoCompleteRequest(PtrIrp, IO_DISK_INCREMENT); + } else { + // Simply free up the IrpContext since the IRP has been queued + Ext2ReleaseIrpContext(PtrIrpContext); + } + + // Release the FCB resources if acquired. + if (AcquiredFCB) + { + Ext2ReleaseResource(&(PtrReqdFCB->MainResource)); + DebugTrace(DEBUG_TRACE_MISC, "*** FReleased in [DirCtrl]", 0); + DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [DirCtrl]", + PtrReqdFCB->MainResource.ActiveCount, + PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, + PtrReqdFCB->MainResource.NumberOfSharedWaiters ); + + AcquiredFCB = FALSE; + } + + } + + return(RC); +} diff --git a/reactos/drivers/fs/ext2/src/ext2.rc b/reactos/drivers/fs/ext2/src/ext2.rc new file mode 100644 index 00000000000..650d01d0a52 --- /dev/null +++ b/reactos/drivers/fs/ext2/src/ext2.rc @@ -0,0 +1,116 @@ +//Microsoft Developer Studio generated resource script. +// +#include "../inc/resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#define APSTUDIO_HIDDEN_SYMBOLS +#include "windows.h" +#undef APSTUDIO_HIDDEN_SYMBOLS +/* REACTOS FIXME */ +/* #include "ntverp.h" */ + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "..\\inc\\resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#define APSTUDIO_HIDDEN_SYMBOLS\r\n" + "#include ""windows.h""\r\n" + "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n" + "#include ""ntverp.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 0,0,0,3 + PRODUCTVERSION 0,0,0,3 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x29L +#else + FILEFLAGS 0x28L +#endif + FILEOS 0x40004L + FILETYPE 0x3L + FILESUBTYPE 0x7L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", "Ext2 File System Driver\0" + VALUE "CompanyName", "Purayidathil\0" + VALUE "FileDescription", "Ext2 File System Driver\0" + VALUE "FileVersion", "0, 0, 0, 3\0" + VALUE "InternalName", "ext2.sys\0" + VALUE "LegalCopyright", "Copyright © 2002 Manoj Paul Joseph\0" + VALUE "LegalTrademarks", " - \0" + VALUE "OriginalFilename", "ext2.sys\0" + VALUE "PrivateBuild", " - \0" + VALUE "ProductName", "Ext2 File System Driver for Windows NT\0" + VALUE "ProductVersion", "0, 0, 0, 3\0" + VALUE "SpecialBuild", " - \0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // !_MAC + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/reactos/drivers/fs/ext2/src/ext2init.c b/reactos/drivers/fs/ext2/src/ext2init.c new file mode 100644 index 00000000000..3617e514869 --- /dev/null +++ b/reactos/drivers/fs/ext2/src/ext2init.c @@ -0,0 +1,381 @@ +/************************************************************************* +* +* File: ext2init.c +* +* Module: Ext2 File System Driver (Kernel mode execution only) +* +* Description: +* This file contains the initialization code for the kernel mode +* Ext2 FSD module. The DriverEntry() routine is called by the I/O +* sub-system to initialize the FSD. +* +* Author: Manoj Paul Joseph +* +*************************************************************************/ + + +#include "ext2fsd.h" + +// define the file specific bug-check id +#define EXT2_BUG_CHECK_ID EXT2_FILE_INIT +#define DEBUG_LEVEL (DEBUG_TRACE_INIT) + +#define EXT2_FS_NAME L"\\ext2" + +// global variables are declared here +Ext2Data Ext2GlobalData; + + +/************************************************************************* +* +* Function: DriverEntry() +* +* Description: +* This routine is the standard entry point for all kernel mode drivers. +* The routine is invoked at IRQL PASSIVE_LEVEL in the context of a +* system worker thread. +* All FSD specific data structures etc. are initialized here. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: STATUS_SUCCESS/Error (will cause driver to be unloaded). +* +*************************************************************************/ +NTSTATUS DriverEntry( +PDRIVER_OBJECT DriverObject, // created by the I/O sub-system +PUNICODE_STRING RegistryPath) // path to the registry key +{ + NTSTATUS RC = STATUS_SUCCESS; + UNICODE_STRING DriverDeviceName; + BOOLEAN RegisteredShutdown = FALSE; + +#if 0 + Ext2BreakPoint(); +#endif + + try + { + try + { + + DebugTrace(DEBUG_TRACE_IRP_ENTRY, "Ext2 File System Driver Entry <<<<<<<", 0); + // initialize the global data structure + RtlZeroMemory(&Ext2GlobalData, sizeof(Ext2GlobalData)); + + // initialize some required fields + Ext2GlobalData.NodeIdentifier.NodeType = EXT2_NODE_TYPE_GLOBAL_DATA; + Ext2GlobalData.NodeIdentifier.NodeSize = sizeof(Ext2GlobalData); + + // initialize the global data resource and remember the fact that + // the resource has been initialized + RC = ExInitializeResourceLite(&(Ext2GlobalData.GlobalDataResource)); + ASSERT(NT_SUCCESS(RC)); + Ext2SetFlag(Ext2GlobalData.Ext2Flags, EXT2_DATA_FLAGS_RESOURCE_INITIALIZED); + + // keep a ptr to the driver object sent to us by the I/O Mgr + Ext2GlobalData.Ext2DriverObject = DriverObject; + + // initialize the mounted logical volume list head + InitializeListHead( &( Ext2GlobalData.NextVCB ) ); + + // before we proceed with any more initialization, read in + // user supplied configurable values ... + // if (!NT_SUCCESS(RC = Ext2ObtainRegistryValues(RegistryPath))) { + // in your commercial driver implementation, it would be + // advisable for your driver to print an appropriate error + // message to the system error log before leaving + // try_return(RC); + // } + + // we should have the registry data (if any), allocate zone memory ... + // This is an example of when FSD implementations try to pre-allocate + // some fixed amount of memory to avoid internal fragmentation and/or waiting + // later during run-time ... + +#ifdef USE_ZONES + + if (!NT_SUCCESS(RC = Ext2InitializeZones())) + { + // we failed, print a message and leave ... + try_return(RC); + } +#endif + + // + // Initialize the Thread queue structure... + // + KeInitializeEvent( + &Ext2GlobalData.ThreadQueue.QueueEvent, + SynchronizationEvent, + FALSE + ); + KeInitializeSpinLock( &Ext2GlobalData.ThreadQueue.SpinLock ); + InitializeListHead( &Ext2GlobalData.ThreadQueue.ThreadQueueListHead ); + + // + // Done Initializing... + // Now Creating a worker thread to handle Worker threads... + // + PsCreateSystemThread( + &Ext2GlobalData.ThreadQueue.QueueHandlerThread, (ACCESS_MASK) 0L, + NULL, NULL, NULL, Ext2QueueHandlerThread, NULL ); + + // initialize the IRP major function table, and the fast I/O table + Ext2FsdInitializeFunctionPointers(DriverObject); + + // create a device object representing the driver itself + // so that requests can be targeted to the driver ... + // e.g. for a disk-based FSD, "mount" requests will be sent to + // this device object by the I/O Manager.\ + // For a redirector/server, you may have applications + // send "special" IOCTL's using this device object ... + RtlInitUnicodeString(&DriverDeviceName, EXT2_FS_NAME); + if (!NT_SUCCESS(RC = IoCreateDevice( + DriverObject, // our driver object + 0, // don't need an extension for this object + &DriverDeviceName,// name - can be used to "open" the driver + // see the book for alternate choices + FILE_DEVICE_DISK_FILE_SYSTEM, + 0, // no special characteristics + // do not want this as an exclusive device, though you might + FALSE, + &(Ext2GlobalData.Ext2DeviceObject)))) + { + // failed to create a device object, leave ... + try_return(RC); + } + + + + // register the driver with the I/O Manager, pretend as if this is + // a physical disk based FSD (or in order words, this FSD manages + // logical volumes residing on physical disk drives) + IoRegisterFileSystem(Ext2GlobalData.Ext2DeviceObject); + + { + TIME_FIELDS TimeFields; + + TimeFields.Day = 1; + TimeFields.Hour = 0; + TimeFields.Milliseconds = 0; + TimeFields.Minute = 0; + TimeFields.Month = 1; + TimeFields.Second = 0; + TimeFields.Weekday = 0; + TimeFields.Year = 1970; + RtlTimeFieldsToTime( &TimeFields, &Ext2GlobalData.TimeDiff ); + + /* + Ext2GlobalData.TimeDiff.QuadPart = 0; + RtlTimeToTimeFields( &Ext2GlobalData.TimeDiff,&TimeFields ); + TimeFields.Year = 2002; + RtlTimeFieldsToTime( &TimeFields, &Ext2GlobalData.TimeDiff ); + */ + + } + } + except (EXCEPTION_EXECUTE_HANDLER) + { + // we encountered an exception somewhere, eat it up + RC = GetExceptionCode(); + } + + try_exit: NOTHING; + } + finally + { + // start unwinding if we were unsuccessful + if (!NT_SUCCESS(RC)) + { + + // Now, delete any device objects, etc. we may have created + if (Ext2GlobalData.Ext2DeviceObject) + { + IoDeleteDevice(Ext2GlobalData.Ext2DeviceObject); + Ext2GlobalData.Ext2DeviceObject = NULL; + } + + // free up any memory we might have reserved for zones/lookaside + // lists + if (Ext2GlobalData.Ext2Flags & EXT2_DATA_FLAGS_ZONES_INITIALIZED) + { + Ext2DestroyZones(); + } + + // delete the resource we may have initialized + if (Ext2GlobalData.Ext2Flags & EXT2_DATA_FLAGS_RESOURCE_INITIALIZED) + { + // un-initialize this resource + ExDeleteResourceLite(&(Ext2GlobalData.GlobalDataResource)); + Ext2ClearFlag(Ext2GlobalData.Ext2Flags, EXT2_DATA_FLAGS_RESOURCE_INITIALIZED); + } + } + } + + return(RC); +} + +/************************************************************************* +* +* Function: Ext2FsdInitializeFunctionPointers() +* +* Description: +* Initialize the IRP... function pointer array in the driver object +* structure. Also initialize the fast-io function ptr array ... +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: None +* +*************************************************************************/ +void Ext2FsdInitializeFunctionPointers( +PDRIVER_OBJECT DriverObject) // created by the I/O sub-system +{ + PFAST_IO_DISPATCH PtrFastIoDispatch = NULL; + + // initialize the function pointers for the IRP major + // functions that this FSD is prepared to handle ... + // NT Version 4.0 has 28 possible functions that a + // kernel mode driver can handle. + // NT Version 3.51 and before has only 22 such functions, + // of which 18 are typically interesting to most FSD's. + + // The only interesting new functions that a FSD might + // want to respond to beginning with Version 4.0 are the + // IRP_MJ_QUERY_QUOTA and the IRP_MJ_SET_QUOTA requests. + + // The code below does not handle quota manipulation, neither + // does the NT Version 4.0 operating system (or I/O Manager). + // However, you should be on the lookout for any such new + // functionality that your FSD might have to implement in + // the near future. + + DriverObject->MajorFunction[IRP_MJ_CREATE] = Ext2Create; + DriverObject->MajorFunction[IRP_MJ_CLOSE] = Ext2Close; + DriverObject->MajorFunction[IRP_MJ_READ] = Ext2Read; + DriverObject->MajorFunction[IRP_MJ_WRITE] = Ext2Write; + + DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION] = Ext2FileInfo; + DriverObject->MajorFunction[IRP_MJ_SET_INFORMATION] = Ext2FileInfo; + + DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = Ext2Flush; + // To implement support for querying and modifying volume attributes + // (volume information query/set operations), enable initialization + // of the following two function pointers and then implement the supporting + // functions. Use Chapter 11 in the text to assist you in your efforts. + DriverObject->MajorFunction[IRP_MJ_QUERY_VOLUME_INFORMATION] = Ext2QueryVolInfo; + DriverObject->MajorFunction[IRP_MJ_SET_VOLUME_INFORMATION] = Ext2SetVolInfo; + DriverObject->MajorFunction[IRP_MJ_DIRECTORY_CONTROL] = Ext2DirControl; + // To implement support for file system IOCTL calls, enable initialization + // of the following function pointer and implement appropriate support. Use + // Chapter 11 in the text to assist you in your efforts. + DriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] = Ext2FileSystemControl; + DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = Ext2DeviceControl; + DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = Ext2Shutdown; + // For byte-range lock support, enable initialization of the following + // function pointer and implement appropriate support. Use Chapter 10 + // in the text to assist you in your efforts. + // DriverObject->MajorFunction[IRP_MJ_LOCK_CONTROL] = Ext2LockControl; + DriverObject->MajorFunction[IRP_MJ_CLEANUP] = Ext2Cleanup; + // If your FSD supports security attributes, you should provide appropriate + // dispatch entry points and initialize the function pointers as given below. + // DriverObject->MajorFunction[IRP_MJ_QUERY_SECURITY] = Ext2Security; + // DriverObject->MajorFunction[IRP_MJ_SET_SECURITY] = Ext2Security; + // If you support extended attributes, you should provide appropriate + // dispatch entry points and initialize the function pointers as given below. + // DriverObject->MajorFunction[IRP_MJ_QUERY_EA] = Ext2ExtendedAttr; + // DriverObject->MajorFunction[IRP_MJ_SET_EA] = Ext2ExtendedAttr; + + // Now, it is time to initialize the fast-io stuff ... +/* + DriverObject->FastIoDispatch = NULL; + +*/ + PtrFastIoDispatch = DriverObject->FastIoDispatch = &(Ext2GlobalData.Ext2FastIoDispatch); + + // initialize the global fast-io structure + // NOTE: The fast-io structure has undergone a substantial revision + // in Windows NT Version 4.0. The structure has been extensively expanded. + // Therefore, if your driver needs to work on both V3.51 and V4.0+, + // you will have to be able to distinguish between the two versions at compile time. + PtrFastIoDispatch->SizeOfFastIoDispatch = sizeof(FAST_IO_DISPATCH); + PtrFastIoDispatch->FastIoCheckIfPossible = Ext2FastIoCheckIfPossible; + PtrFastIoDispatch->FastIoRead = Ext2FastIoRead; + PtrFastIoDispatch->FastIoWrite = Ext2FastIoWrite; + PtrFastIoDispatch->FastIoQueryBasicInfo = Ext2FastIoQueryBasicInfo; + PtrFastIoDispatch->FastIoQueryStandardInfo = Ext2FastIoQueryStdInfo; + PtrFastIoDispatch->FastIoLock = Ext2FastIoLock; + PtrFastIoDispatch->FastIoUnlockSingle = Ext2FastIoUnlockSingle; + PtrFastIoDispatch->FastIoUnlockAll = Ext2FastIoUnlockAll; + PtrFastIoDispatch->FastIoUnlockAllByKey = Ext2FastIoUnlockAllByKey; + PtrFastIoDispatch->AcquireFileForNtCreateSection = Ext2FastIoAcqCreateSec; + PtrFastIoDispatch->ReleaseFileForNtCreateSection = Ext2FastIoRelCreateSec; + + // the remaining are only valid under NT Version 4.0 and later +#if(_WIN32_WINNT >= 0x0400) + PtrFastIoDispatch->FastIoQueryNetworkOpenInfo = Ext2FastIoQueryNetInfo; + PtrFastIoDispatch->AcquireForModWrite = Ext2FastIoAcqModWrite; + PtrFastIoDispatch->ReleaseForModWrite = Ext2FastIoRelModWrite; + PtrFastIoDispatch->AcquireForCcFlush = Ext2FastIoAcqCcFlush; + PtrFastIoDispatch->ReleaseForCcFlush = Ext2FastIoRelCcFlush; + + // MDL functionality + PtrFastIoDispatch->MdlRead = Ext2FastIoMdlRead; + PtrFastIoDispatch->MdlReadComplete = Ext2FastIoMdlReadComplete; + PtrFastIoDispatch->PrepareMdlWrite = Ext2FastIoPrepareMdlWrite; + PtrFastIoDispatch->MdlWriteComplete = Ext2FastIoMdlWriteComplete; + + // although this FSD does not support compressed read/write functionality, + // NTFS does, and if you design a FSD that can provide such functionality, + // you should consider initializing the fast io entry points for reading + // and/or writing compressed data ... +#endif // (_WIN32_WINNT >= 0x0400) + + + // last but not least, initialize the Cache Manager callback functions + // which are used in CcInitializeCacheMap() + Ext2GlobalData.CacheMgrCallBacks.AcquireForLazyWrite = Ext2AcqLazyWrite; + Ext2GlobalData.CacheMgrCallBacks.ReleaseFromLazyWrite = Ext2RelLazyWrite; + Ext2GlobalData.CacheMgrCallBacks.AcquireForReadAhead = Ext2AcqReadAhead; + Ext2GlobalData.CacheMgrCallBacks.ReleaseFromReadAhead = Ext2RelReadAhead; + + return; +} + + +VOID Ext2QueueHandlerThread( + IN PVOID StartContext ) +{ + + DebugTrace(DEBUG_TRACE_MISC, "Ext2QueueHandlerThread!!!", 0); + + while( 1 ) + { + KeWaitForSingleObject( &Ext2GlobalData.ThreadQueue.QueueEvent, + Executive, KernelMode, FALSE, (PLARGE_INTEGER)NULL ); + + DebugTrace(DEBUG_TRACE_MISC, "Ext2QueueHandlerThread Alerted!!!", 0); + + while( !IsListEmpty( &Ext2GlobalData.ThreadQueue.ThreadQueueListHead ) ) + { + HANDLE ThreadHandle; + PLIST_ENTRY PtrEntry = NULL; + PtrExt2IrpContext PtrIrpContext = NULL; + + + PtrEntry = ExInterlockedRemoveHeadList( + &Ext2GlobalData.ThreadQueue.ThreadQueueListHead, + &Ext2GlobalData.ThreadQueue.SpinLock ); + ASSERT( PtrEntry ); + PtrIrpContext = CONTAINING_RECORD( PtrEntry, Ext2IrpContext, ThreadQueueListEntry ); + + PsCreateSystemThread( + &ThreadHandle, (ACCESS_MASK) 0L, + NULL, NULL, NULL, Ext2CommonDispatch, PtrIrpContext ); + } + } +} diff --git a/reactos/drivers/fs/ext2/src/fastio.c b/reactos/drivers/fs/ext2/src/fastio.c new file mode 100644 index 00000000000..e48b2b5fb0a --- /dev/null +++ b/reactos/drivers/fs/ext2/src/fastio.c @@ -0,0 +1,1757 @@ +/************************************************************************* +* +* File: fastio.c +* +* Module: Ext2 File System Driver (Kernel mode execution only) +* +* Description: +* Contains code to handle the various "fast-io" calls. +* +* Author: Manoj Paul Joseph +* +* +*************************************************************************/ + +#include "ext2fsd.h" + +// define the file specific bug-check id +#define EXT2_BUG_CHECK_ID EXT2_FILE_FAST_IO + + + +/************************************************************************* +* +* Function: Ext2FastIoCheckIfPossible() +* +* Description: +* To fast-io or not to fast-io, that is the question ... +* This routine helps the I/O Manager determine whether the FSD wishes +* to permit fast-io on a specific file stream. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: TRUE/FALSE +* +*************************************************************************/ +BOOLEAN Ext2FastIoCheckIfPossible( +IN PFILE_OBJECT FileObject, +IN PLARGE_INTEGER FileOffset, +IN ULONG Length, +IN BOOLEAN Wait, +IN ULONG LockKey, +IN BOOLEAN CheckForReadOperation, +OUT PIO_STATUS_BLOCK IoStatus, +IN PDEVICE_OBJECT DeviceObject) +{ + BOOLEAN ReturnedStatus = FALSE; + PtrExt2FCB PtrFCB = NULL; + PtrExt2CCB PtrCCB = NULL; + LARGE_INTEGER IoLength; + + // Obtain a pointer to the FCB and CCB for the file stream. + PtrCCB = (PtrExt2CCB)(FileObject->FsContext2); + ASSERT(PtrCCB); + PtrFCB = PtrCCB->PtrFCB; + ASSERT(PtrFCB); + + DebugTrace(DEBUG_TRACE_IRP_ENTRY, "~~~[FastIO call]~~~ Ext2FastIoCheckIfPossible - Denying", 0); + if( FileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", FileObject); + } + + AssertFCBorVCB( PtrFCB ); + +/* if( !( PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_FCB + || PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB ) ) + { + // Ext2BreakPoint(); + DebugTrace(DEBUG_TRACE_ERROR, "~~~[FastIO call]~~~ Invalid FCB...", 0); + + return FALSE; + } +*/ + + return FALSE; + + // Validate that this is a fast-IO request to a regular file. + // The sample FSD for example, will not allow fast-IO requests + // to volume objects, or to directories. + if ((PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB) || + (PtrFCB->FCBFlags & EXT2_FCB_DIRECTORY)) + { + // This is not allowed. + return(ReturnedStatus); + } + + IoLength = RtlConvertUlongToLargeInteger(Length); + + // Your FSD can determine the checks that it needs to perform. + // Typically, a FSD will check whether there exist any byte-range + // locks that would prevent a fast-IO operation from proceeding. + + // ... (FSD specific checks go here). + + if (CheckForReadOperation) + { + // Chapter 11 describes how to use the FSRTL package for byte-range + // lock requests. The following routine is exported by the FSRTL + // package and it returns TRUE if the read operation should be + // allowed to proceed based on the status of the current byte-range + // locks on the file stream. If you do not use the FSRTL package + // for byte-range locking support, then you must substitute your + // own checks over here. + // ReturnedStatus = FsRtlFastCheckLockForRead(&(PtrFCB->FCBByteRangeLock), + // FileOffset, &IoLength, LockKey, FileObject, + // PsGetCurrentProcess()); + } + else + { + // This is a write request. Invoke the FSRTL byte-range lock package + // to see whether the write should be allowed to proceed. + // ReturnedStatus = FsRtlFastCheckLockForWrite(&(PtrFCB->FCBByteRangeLock), + // FileOffset, &IoLength, LockKey, FileObject, + // PsGetCurrentProcess()); + } + + return(ReturnedStatus); +} + + +/************************************************************************* +* +* Function: Ext2FastIoRead() +* +* Description: +* Bypass the traditional IRP method to perform a read operation. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: TRUE/FALSE +* +*************************************************************************/ +BOOLEAN Ext2FastIoRead( +IN PFILE_OBJECT FileObject, +IN PLARGE_INTEGER FileOffset, +IN ULONG Length, +IN BOOLEAN Wait, +IN ULONG LockKey, +OUT PVOID Buffer, +OUT PIO_STATUS_BLOCK IoStatus, +IN PDEVICE_OBJECT DeviceObject) +{ + + BOOLEAN ReturnedStatus = FALSE; // fast i/o failed/not allowed + NTSTATUS RC = STATUS_SUCCESS; + PtrExt2IrpContext PtrIrpContext = NULL; + + FsRtlEnterFileSystem(); + + DebugTrace(DEBUG_TRACE_IRP_ENTRY, "~~~[FastIO call]~~~ Ext2FastIoRead", 0); + if( FileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", FileObject); + } + + + try + { + + try + { + + // Chapter 11 describes how to roll your own fast-IO entry points. + // Typically, you will acquire appropriate resources here and + // then (maybe) forward the request to FsRtlCopyRead(). + // If you are a suitably complex file system, you may even choose + // to do some pre-processing (e.g. prefetching data from someplace) + // before passing on the request to the FSRTL package. + + // Of course, you also have the option of bypassing the FSRTL + // package completely and simply forwarding the request directly + // to the NT Cache Manager. + + // Bottom line is that you have complete flexibility on determining + // what you decide to do here. Read Chapter 11 well (and obviously + // other related issues) before filling in this and other fast-IO + // dispatch entry points. + + NOTHING; + + } + except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) + { + + RC = Ext2ExceptionHandler(PtrIrpContext, NULL); + + Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); + + } + + try_exit: NOTHING; + + } finally { + + } + + FsRtlExitFileSystem(); + + return(ReturnedStatus); +} + + +/************************************************************************* +* +* Function: Ext2FastIoWrite() +* +* Description: +* Bypass the traditional IRP method to perform a write operation. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: TRUE/FALSE +* +*************************************************************************/ +BOOLEAN Ext2FastIoWrite( +IN PFILE_OBJECT FileObject, +IN PLARGE_INTEGER FileOffset, +IN ULONG Length, +IN BOOLEAN Wait, +IN ULONG LockKey, +OUT PVOID Buffer, +OUT PIO_STATUS_BLOCK IoStatus, +IN PDEVICE_OBJECT DeviceObject) +{ + BOOLEAN ReturnedStatus = FALSE; // fast i/o failed/not allowed + NTSTATUS RC = STATUS_SUCCESS; + PtrExt2IrpContext PtrIrpContext = NULL; + + FsRtlEnterFileSystem(); + + DebugTrace(DEBUG_TRACE_IRP_ENTRY, "~~~[FastIO call]~~~ Ext2FastIoWrite", 0); + if( FileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", FileObject); + } + try + { + try + { + + // See description in Ext2FastIoRead() before filling-in the + // stub here. + NOTHING; + + } + except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) + { + + RC = Ext2ExceptionHandler(PtrIrpContext, NULL); + + Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); + + } + + try_exit: NOTHING; + + } + finally + { + + } + + FsRtlExitFileSystem(); + + return(ReturnedStatus); +} + + +/************************************************************************* +* +* Function: Ext2FastIoQueryBasicInfo() +* +* Description: +* Bypass the traditional IRP method to perform a query basic +* information operation. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: TRUE/FALSE +* +*************************************************************************/ +BOOLEAN Ext2FastIoQueryBasicInfo( +IN PFILE_OBJECT FileObject, +IN BOOLEAN Wait, +OUT PFILE_BASIC_INFORMATION Buffer, +OUT PIO_STATUS_BLOCK IoStatus, +IN PDEVICE_OBJECT DeviceObject) +{ + BOOLEAN ReturnedStatus = FALSE; // fast i/o failed/not allowed + NTSTATUS RC = STATUS_SUCCESS; + PtrExt2IrpContext PtrIrpContext = NULL; + + FsRtlEnterFileSystem(); + + DebugTrace(DEBUG_TRACE_IRP_ENTRY, "~~~[FastIO call]~~~ Ext2FastIoQueryBasicInfo", 0); + if( FileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", FileObject); + } + try + { + + try + { + + // See description in Ext2FastIoRead() before filling-in the + // stub here. + NOTHING; + + } + except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) + { + RC = Ext2ExceptionHandler(PtrIrpContext, NULL); + Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); + } + + try_exit: NOTHING; + + } + finally + { + + } + + FsRtlExitFileSystem(); + + return(ReturnedStatus); +} + +/************************************************************************* +* +* Function: Ext2FastIoQueryStdInfo() +* +* Description: +* Bypass the traditional IRP method to perform a query standard +* information operation. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: TRUE/FALSE +* +*************************************************************************/ +BOOLEAN Ext2FastIoQueryStdInfo( +IN PFILE_OBJECT FileObject, +IN BOOLEAN Wait, +OUT PFILE_STANDARD_INFORMATION Buffer, +OUT PIO_STATUS_BLOCK IoStatus, +IN PDEVICE_OBJECT DeviceObject) +{ + BOOLEAN ReturnedStatus = FALSE; // fast i/o failed/not allowed + NTSTATUS RC = STATUS_SUCCESS; + PtrExt2IrpContext PtrIrpContext = NULL; + + FsRtlEnterFileSystem(); + + DebugTrace(DEBUG_TRACE_IRP_ENTRY, "~~~[FastIO call]~~~ Ext2FastIoQueryStdInfo", 0); + if( FileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", FileObject); + } + try + { + + try + { + + // See description in Ext2FastIoRead() before filling-in the + // stub here. + NOTHING; + + } + except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) + { + RC = Ext2ExceptionHandler(PtrIrpContext, NULL); + Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); + } + + try_exit: NOTHING; + + } + finally + { + + } + + FsRtlExitFileSystem(); + + return(ReturnedStatus); +} + +/************************************************************************* +* +* Function: Ext2FastIoLock() +* +* Description: +* Bypass the traditional IRP method to perform a byte range lock +* operation. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: TRUE/FALSE +* +*************************************************************************/ +BOOLEAN Ext2FastIoLock( +IN PFILE_OBJECT FileObject, +IN PLARGE_INTEGER FileOffset, +IN PLARGE_INTEGER Length, +PEPROCESS ProcessId, +ULONG Key, +BOOLEAN FailImmediately, +BOOLEAN ExclusiveLock, +OUT PIO_STATUS_BLOCK IoStatus, +IN PDEVICE_OBJECT DeviceObject) +{ + BOOLEAN ReturnedStatus = FALSE; // fast i/o failed/not allowed + NTSTATUS RC = STATUS_SUCCESS; + PtrExt2IrpContext PtrIrpContext = NULL; + + FsRtlEnterFileSystem(); + + DebugTrace(DEBUG_TRACE_IRP_ENTRY, "~~~[FastIO call]~~~ Ext2FastIoLock", 0); + if( FileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", FileObject); + } + + try + { + + try + { + + // See description in Ext2FastIoRead() before filling-in the + // stub here. + NOTHING; + + } + except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) + { + RC = Ext2ExceptionHandler(PtrIrpContext, NULL); + Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); + } + + try_exit: NOTHING; + + } + finally + { + + } + + FsRtlExitFileSystem(); + + return(ReturnedStatus); +} + + +/************************************************************************* +* +* Function: Ext2FastIoUnlockSingle() +* +* Description: +* Bypass the traditional IRP method to perform a byte range unlock +* operation. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: TRUE/FALSE +* +*************************************************************************/ +BOOLEAN Ext2FastIoUnlockSingle( +IN PFILE_OBJECT FileObject, +IN PLARGE_INTEGER FileOffset, +IN PLARGE_INTEGER Length, +PEPROCESS ProcessId, +ULONG Key, +OUT PIO_STATUS_BLOCK IoStatus, +IN PDEVICE_OBJECT DeviceObject) +{ + BOOLEAN ReturnedStatus = FALSE; // fast i/o failed/not allowed + NTSTATUS RC = STATUS_SUCCESS; + PtrExt2IrpContext PtrIrpContext = NULL; + + FsRtlEnterFileSystem(); + + DebugTrace(DEBUG_TRACE_IRP_ENTRY, "~~~[FastIO call]~~~ Ext2FastIoUnlockSingle", 0); + if( FileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", FileObject); + } + + try + { + + try + { + + // See description in Ext2FastIoRead() before filling-in the + // stub here. + NOTHING; + + } + except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) + { + RC = Ext2ExceptionHandler(PtrIrpContext, NULL); + Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); + } + + try_exit: NOTHING; + + } + finally + { + + } + + FsRtlExitFileSystem(); + + return(ReturnedStatus); +} + + +/************************************************************************* +* +* Function: Ext2FastIoUnlockAll() +* +* Description: +* Bypass the traditional IRP method to perform multiple byte range unlock +* operations. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: TRUE/FALSE +* +*************************************************************************/ +BOOLEAN Ext2FastIoUnlockAll( +IN PFILE_OBJECT FileObject, +PEPROCESS ProcessId, +OUT PIO_STATUS_BLOCK IoStatus, +IN PDEVICE_OBJECT DeviceObject) +{ + BOOLEAN ReturnedStatus = FALSE; // fast i/o failed/not allowed + NTSTATUS RC = STATUS_SUCCESS; + PtrExt2IrpContext PtrIrpContext = NULL; + + FsRtlEnterFileSystem(); + + DebugTrace(DEBUG_TRACE_IRP_ENTRY, "~~~[FastIO call]~~~ Ext2FastIoUnlockAll", 0); + if( FileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", FileObject); + } + + try + { + try + { + + // See description in Ext2FastIoRead() before filling-in the + // stub here. + NOTHING; + + } + except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) + { + RC = Ext2ExceptionHandler(PtrIrpContext, NULL); + Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); + } + + try_exit: NOTHING; + + } + finally + { + + } + + FsRtlExitFileSystem(); + + return(ReturnedStatus); +} + + +/************************************************************************* +* +* Function: Ext2FastIoUnlockAllByKey() +* +* Description: +* Bypass the traditional IRP method to perform multiple byte range unlock +* operations. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: TRUE/FALSE +* +*************************************************************************/ +BOOLEAN Ext2FastIoUnlockAllByKey( +IN PFILE_OBJECT FileObject, +PEPROCESS ProcessId, +ULONG Key, +OUT PIO_STATUS_BLOCK IoStatus, +IN PDEVICE_OBJECT DeviceObject) +{ + BOOLEAN ReturnedStatus = FALSE; // fast i/o failed/not allowed + NTSTATUS RC = STATUS_SUCCESS; + PtrExt2IrpContext PtrIrpContext = NULL; + + FsRtlEnterFileSystem(); + + DebugTrace(DEBUG_TRACE_IRP_ENTRY, "~~~[FastIO call]~~~ Ext2FastIoUnlockAllByKey", 0); + if( FileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", FileObject); + } + try + { + + try + { + + // See description in Ext2FastIoRead() before filling-in the + // stub here. + NOTHING; + + } + except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) + { + RC = Ext2ExceptionHandler(PtrIrpContext, NULL); + Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); + } + + try_exit: NOTHING; + + } + finally + { + + } + + FsRtlExitFileSystem(); + + return(ReturnedStatus); +} + + +/************************************************************************* +* +* Function: Ext2FastIoAcqCreateSec() +* +* Description: +* Not really a fast-io operation. Used by the VMM to acquire FSD resources +* before processing a file map (create section object) request. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: None (we must be prepared to handle VMM initiated calls) +* +*************************************************************************/ +void Ext2FastIoAcqCreateSec( +IN PFILE_OBJECT FileObject) +{ + PtrExt2FCB PtrFCB = NULL; + PtrExt2CCB PtrCCB = NULL; + PtrExt2NTRequiredFCB PtrReqdFCB = NULL; + + // Obtain a pointer to the FCB and CCB for the file stream. + PtrCCB = (PtrExt2CCB)(FileObject->FsContext2); + ASSERT(PtrCCB); + PtrFCB = PtrCCB->PtrFCB; + ASSERT(PtrFCB); + + AssertFCB( PtrFCB ); + +/* if( PtrFCB->NodeIdentifier.NodeType != EXT2_NODE_TYPE_FCB ) + { + // Ext2BreakPoint(); + DebugTrace(DEBUG_TRACE_ERROR, "~~~[FastIO call]~~~ Invalid FCB...", 0); + return; + } */ + + PtrReqdFCB = &(PtrFCB->NTRequiredFCB); + + DebugTrace(DEBUG_TRACE_IRP_ENTRY, "~~~[FastIO call]~~~ Ext2FastIoAcqCreateSec", 0); + if( FileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", FileObject); + } + + // Acquire the MainResource exclusively for the file stream + + DebugTrace(DEBUG_TRACE_MISC, "*** Attempting to acquire FCB Exclusively [FastIo]", 0); + + DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [FastIo]", PtrReqdFCB->MainResource.ActiveCount, PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, PtrReqdFCB->MainResource.NumberOfSharedWaiters ); + ExAcquireResourceExclusiveLite(&(PtrReqdFCB->MainResource), TRUE); + + DebugTrace(DEBUG_TRACE_MISC,"*** FCB acquired [FastIo]", 0); + + // Although this is typically not required, the sample FSD will + // also acquire the PagingIoResource exclusively at this time + // to conform with the resource acquisition described in the set + // file information routine. Once again though, you will probably + // not need to do this. + DebugTrace(DEBUG_TRACE_MISC,"*** Attempting to acquire FCBPaging Exclusively [FastIo]", 0); + DebugTraceState( "FCBPaging AC:0x%LX SW:0x%LX EX:0x%LX [FastIo]", PtrReqdFCB->PagingIoResource.ActiveCount, PtrReqdFCB->PagingIoResource.NumberOfExclusiveWaiters, PtrReqdFCB->PagingIoResource.NumberOfSharedWaiters ); + ExAcquireResourceExclusiveLite(&(PtrReqdFCB->PagingIoResource), TRUE); + + DebugTrace(DEBUG_TRACE_MISC,"*** FCBPaging acquired [FastIo]", 0); + + return; +} + + +/************************************************************************* +* +* Function: Ext2FastIoRelCreateSec() +* +* Description: +* Not really a fast-io operation. Used by the VMM to release FSD resources +* after processing a file map (create section object) request. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: None +* +*************************************************************************/ +void Ext2FastIoRelCreateSec( +IN PFILE_OBJECT FileObject) +{ + + PtrExt2FCB PtrFCB = NULL; + PtrExt2CCB PtrCCB = NULL; + PtrExt2NTRequiredFCB PtrReqdFCB = NULL; + + // Obtain a pointer to the FCB and CCB for the file stream. + PtrCCB = (PtrExt2CCB)(FileObject->FsContext2); + ASSERT(PtrCCB); + PtrFCB = PtrCCB->PtrFCB; + ASSERT(PtrFCB); + AssertFCB( PtrFCB ); + +/* if( PtrFCB->NodeIdentifier.NodeType != EXT2_NODE_TYPE_FCB ) + { + // Ext2BreakPoint(); + DebugTrace(DEBUG_TRACE_ERROR, "~~~[FastIO call]~~~ Invalid FCB...", 0); + return; + }*/ + + PtrReqdFCB = &(PtrFCB->NTRequiredFCB); + + DebugTrace(DEBUG_TRACE_IRP_ENTRY,"~~~[FastIO call]~~~ Ext2FastIoRelCreateSec", 0); + if( FileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", FileObject); + } + + // Release the PagingIoResource for the file stream + Ext2ReleaseResource(&(PtrReqdFCB->PagingIoResource)); + DebugTrace(DEBUG_TRACE_MISC, "*** FCBPaging Released in [FastIo]", 0); + DebugTraceState( "FCBPaging AC:0x%LX SW:0x%LX EX:0x%LX [FastIo]", + PtrReqdFCB->PagingIoResource.ActiveCount, + PtrReqdFCB->PagingIoResource.NumberOfExclusiveWaiters, + PtrReqdFCB->PagingIoResource.NumberOfSharedWaiters ); + + // Release the MainResource for the file stream + Ext2ReleaseResource(&(PtrReqdFCB->MainResource)); + DebugTrace(DEBUG_TRACE_MISC, "*** FCB Released [FastIo]", 0); + DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [FastIo]", + PtrReqdFCB->MainResource.ActiveCount, + PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, + PtrReqdFCB->MainResource.NumberOfSharedWaiters ); + + return; +} + + +/************************************************************************* +* +* Function: Ext2AcqLazyWrite() +* +* Description: +* Not really a fast-io operation. Used by the NT Cache Mgr to acquire FSD +* resources before performing a delayed write (write behind/lazy write) +* operation. +* NOTE: this function really must succeed since the Cache Manager will +* typically ignore failure and continue on ... +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: TRUE/FALSE (Cache Manager does not tolerate FALSE well) +* +*************************************************************************/ +BOOLEAN Ext2AcqLazyWrite( +IN PVOID Context, +IN BOOLEAN Wait) +{ + BOOLEAN ReturnedStatus = TRUE; + + PtrExt2VCB PtrVCB = NULL; + PtrExt2FCB PtrFCB = NULL; + PtrExt2CCB PtrCCB = NULL; + PtrExt2NTRequiredFCB PtrReqdFCB = NULL; + + // The context is whatever we passed to the Cache Manager when invoking + // the CcInitializeCacheMaps() function. In the case of the sample FSD + // implementation, this context is a pointer to the CCB structure. + + ASSERT(Context); + PtrCCB = (PtrExt2CCB)(Context); + + DebugTrace(DEBUG_TRACE_IRP_ENTRY,"~~~[FastIO call]~~~ Ext2AcqLazyWrite", 0); + + if(PtrCCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_CCB) + { + // + // Acquiring Resource for a file write... + // + PtrFCB = PtrCCB->PtrFCB; + AssertFCB( PtrFCB ); + } + else if( PtrCCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB ) + { + // + // Acquiring Resource for a volume write... + // + PtrVCB = ( PtrExt2VCB )PtrCCB; + PtrCCB = NULL; + DebugTrace(DEBUG_TRACE_MISC,"~~~[FastIO call]~~~ Ext2AcqLazyWrite - for Volume", 0); + + // Acquire nothing... + // Just proceed... + return TRUE; + + } + else if( PtrCCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_FCB ) + { + // + // This must have been a FCB created / maintained on the FSD's initiative... + // This would have been done to cache access to a directory... + // + PtrFCB = ( PtrExt2FCB )PtrCCB; + PtrCCB = NULL; + } + else + { + DebugTrace(DEBUG_TRACE_ERROR, "~~~[FastIO call]~~~ Ext2AcqLazyWrite - Invalid context", 0); + Ext2BreakPoint(); + return FALSE; + } + + if( PtrCCB && PtrCCB->PtrFileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", PtrCCB->PtrFileObject ); + } + + AssertFCB( PtrFCB ); + + + PtrReqdFCB = &(PtrFCB->NTRequiredFCB); + + + // Acquire the MainResource in the FCB exclusively. Then, set the + // lazy-writer thread id in the FCB structure for identification when + // an actual write request is received by the FSD. + // Note: The lazy-writer typically always supplies WAIT set to TRUE. + + DebugTrace(DEBUG_TRACE_MISC,"*** Attempting to acquire FCB Exclusively [FastIo]", 0); + + DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [FastIo]", PtrReqdFCB->MainResource.ActiveCount, PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, PtrReqdFCB->MainResource.NumberOfSharedWaiters ); + if (!ExAcquireResourceExclusiveLite(&(PtrReqdFCB->MainResource), + Wait)) + { + DebugTrace(DEBUG_TRACE_MISC,"*** Attempt to acquire FCB FAILED [FastIo]", 0); + ReturnedStatus = FALSE; + } + else + { + DebugTrace(DEBUG_TRACE_MISC,"*** FCB acquired [FastIo]", 0); + // Now, set the lazy-writer thread id. + ASSERT(!(PtrFCB->LazyWriterThreadID)); + PtrFCB->LazyWriterThreadID = (unsigned int)(PsGetCurrentThread()); + } + + // If your FSD needs to perform some special preparations in anticipation + // of receving a lazy-writer request, do so now. + + return(ReturnedStatus); +} + + +/************************************************************************* +* +* Function: Ext2RelLazyWrite() +* +* Description: +* Not really a fast-io operation. Used by the NT Cache Mgr to release FSD +* resources after performing a delayed write (write behind/lazy write) +* operation. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: None +* +*************************************************************************/ +void Ext2RelLazyWrite( +IN PVOID Context) +{ + + BOOLEAN ReturnedStatus = TRUE; + + PtrExt2VCB PtrVCB = NULL; + PtrExt2FCB PtrFCB = NULL; + PtrExt2CCB PtrCCB = NULL; + PtrExt2NTRequiredFCB PtrReqdFCB = NULL; + + // The context is whatever we passed to the Cache Manager when invoking + // the CcInitializeCacheMaps() function. In the case of the sample FSD + // implementation, this context is a pointer to the CCB structure. + + DebugTrace(DEBUG_TRACE_IRP_ENTRY,"~~~[FastIO call]~~~ Ext2RelLazyWrite", 0); + + ASSERT(Context); + PtrCCB = (PtrExt2CCB)(Context); + + if(PtrCCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_CCB) + { + PtrFCB = PtrCCB->PtrFCB; + AssertFCB( PtrFCB ); + } + else if( PtrCCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB ) + { + PtrVCB = ( PtrExt2VCB )PtrCCB; + PtrCCB = NULL; + DebugTrace(DEBUG_TRACE_MISC,"~~~[FastIO call]~~~ Ext2RelLazyWrite - for Volume", 0); + + // Acquire was acquired nothing... + // Just return... + return; + + } + else if( PtrCCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_FCB ) + { + // + // This must have been a FCB created / maintained on the FSD's initiative... + // This would have been done to cache access to a directory... + // + PtrFCB = ( PtrExt2FCB )PtrCCB; + PtrCCB = NULL; + } + else + { + DebugTrace(DEBUG_TRACE_ERROR, "~~~[FastIO call]~~~ Ext2RelLazyWrite - Invalid context", 0); + Ext2BreakPoint(); + return ; + } + + if( PtrCCB && PtrCCB->PtrFileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", PtrCCB->PtrFileObject ); + } + + PtrReqdFCB = &(PtrFCB->NTRequiredFCB); + + // Remove the current thread-id from the FCB and release the MainResource. + ASSERT( (PtrFCB->LazyWriterThreadID) == (unsigned int)PsGetCurrentThread() ); + PtrFCB->LazyWriterThreadID = 0; + + + // Release the acquired resource. + Ext2ReleaseResource(&(PtrReqdFCB->MainResource)); + DebugTrace(DEBUG_TRACE_MISC, "*** FCB Released [FastIo]", 0); + DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [FastIo]", + PtrReqdFCB->MainResource.ActiveCount, + PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, + PtrReqdFCB->MainResource.NumberOfSharedWaiters ); + + // + // Undo whatever else seems appropriate at this time... + // + + return; +} + + +/************************************************************************* +* +* Function: Ext2AcqReadAhead() +* +* Description: +* Not really a fast-io operation. Used by the NT Cache Mgr to acquire FSD +* resources before performing a read-ahead operation. +* NOTE: this function really must succeed since the Cache Manager will +* typically ignore failure and continue on ... +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: TRUE/FALSE (Cache Manager does not tolerate FALSE well) +* +*************************************************************************/ +BOOLEAN Ext2AcqReadAhead( +IN PVOID Context, +IN BOOLEAN Wait) +{ + + BOOLEAN ReturnedStatus = TRUE; + + PtrExt2FCB PtrFCB = NULL; + PtrExt2CCB PtrCCB = NULL; + PtrExt2NTRequiredFCB PtrReqdFCB = NULL; + + // The context is whatever we passed to the Cache Manager when invoking + // the CcInitializeCacheMaps() function. In the case of the sample FSD + // implementation, this context is a pointer to the CCB structure. + + ASSERT(Context); + PtrCCB = (PtrExt2CCB)(Context); + ASSERT(PtrCCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_CCB); + + DebugTrace(DEBUG_TRACE_IRP_ENTRY,"~~~[FastIO call]~~~ Ext2AcqReadAhead", 0); + if( PtrCCB && PtrCCB->PtrFileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", PtrCCB->PtrFileObject ); + } + + PtrFCB = PtrCCB->PtrFCB; + ASSERT(PtrFCB); + + AssertFCB( PtrFCB ); +/* + if( PtrFCB->NodeIdentifier.NodeType != EXT2_NODE_TYPE_FCB ) + { + // Ext2BreakPoint(); + DebugTrace(DEBUG_TRACE_ERROR, "~~~[FastIO call]~~~ Invalid FCB...", 0); + return TRUE; + } */ + + PtrReqdFCB = &(PtrFCB->NTRequiredFCB); + + // Acquire the MainResource in the FCB shared. + // Note: The read-ahead thread typically always supplies WAIT set to TRUE. + DebugTrace(DEBUG_TRACE_MISC,"*** Attempting to acquire FCB Shared [FastIo]", 0); + + DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [FastIo]", PtrReqdFCB->MainResource.ActiveCount, PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, PtrReqdFCB->MainResource.NumberOfSharedWaiters ); + if (!ExAcquireResourceSharedLite(&(PtrReqdFCB->MainResource), Wait)) + { + DebugTrace(DEBUG_TRACE_MISC,"*** Attempt to acquire FCB FAILED [FastIo]", 0); + ReturnedStatus = FALSE; + } + else + { + DebugTrace(DEBUG_TRACE_MISC,"*** FCB acquired [FastIo]", 0); + } + + // If your FSD needs to perform some special preparations in anticipation + // of receving a read-ahead request, do so now. + + return ReturnedStatus; + +} + + + +/************************************************************************* +* +* Function: Ext2RelReadAhead() +* +* Description: +* Not really a fast-io operation. Used by the NT Cache Mgr to release FSD +* resources after performing a read-ahead operation. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: None +* +*************************************************************************/ +void Ext2RelReadAhead( +IN PVOID Context) +{ + BOOLEAN ReturnedStatus = TRUE; + PtrExt2FCB PtrFCB = NULL; + PtrExt2CCB PtrCCB = NULL; + PtrExt2NTRequiredFCB PtrReqdFCB = NULL; + + + // The context is whatever we passed to the Cache Manager when invoking + // the CcInitializeCacheMaps() function. In the case of the sample FSD + // implementation, this context is a pointer to the CCB structure. + + ASSERT(Context); + PtrCCB = (PtrExt2CCB)(Context); + ASSERT(PtrCCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_CCB); + + PtrFCB = PtrCCB->PtrFCB; + + AssertFCB( PtrFCB ); + + // ASSERT(PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_FCB ); + + DebugTrace(DEBUG_TRACE_IRP_ENTRY,"~~~[FastIO call]~~~ Ext2RelReadAhead", 0); + if( PtrCCB && PtrCCB->PtrFileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", PtrCCB->PtrFileObject ); + } + +/* if( PtrFCB->NodeIdentifier.NodeType != EXT2_NODE_TYPE_FCB ) + { + // Ext2BreakPoint(); + DebugTrace(DEBUG_TRACE_ERROR, "~~~[FastIO call]~~~ Invalid FCB...", 0); + return; + } */ + + PtrReqdFCB = &(PtrFCB->NTRequiredFCB); + + + // Release the acquired resource. + Ext2ReleaseResource(&(PtrReqdFCB->MainResource)); + DebugTrace(DEBUG_TRACE_MISC, "*** FCB Released [FastIo]", 0); + DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [FastIo]", + PtrReqdFCB->MainResource.ActiveCount, + PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, + PtrReqdFCB->MainResource.NumberOfSharedWaiters ); + + // Of course, your FSD should undo whatever else seems appropriate at this + // time. + + return; +} + + +/* the remaining are only valid under NT Version 4.0 and later */ +#if(_WIN32_WINNT >= 0x0400) + + +/************************************************************************* +* +* Function: Ext2FastIoQueryNetInfo() +* +* Description: +* Get information requested by a redirector across the network. This call +* will originate from the LAN Manager server. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: TRUE/FALSE +* +*************************************************************************/ +BOOLEAN Ext2FastIoQueryNetInfo( +IN PFILE_OBJECT FileObject, +IN BOOLEAN Wait, +OUT PFILE_NETWORK_OPEN_INFORMATION Buffer, +OUT PIO_STATUS_BLOCK IoStatus, +IN PDEVICE_OBJECT DeviceObject) +{ + BOOLEAN ReturnedStatus = FALSE; // fast i/o failed/not allowed + NTSTATUS RC = STATUS_SUCCESS; + PtrExt2IrpContext PtrIrpContext = NULL; + + FsRtlEnterFileSystem(); + + DebugTrace(DEBUG_TRACE_IRP_ENTRY,"~~~[FastIO call]~~~ Ext2FastIoQueryNetInfo", 0); + if( FileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", FileObject); + } + + try + { + + try + { + + // See description in Ext2FastIoRead() before filling-in the + // stub here. + NOTHING; + + + } + except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) + { + RC = Ext2ExceptionHandler(PtrIrpContext, NULL); + Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); + } + + try_exit: NOTHING; + + } + finally + { + + } + + FsRtlExitFileSystem(); + + return(ReturnedStatus); +} + + +/************************************************************************* +* +* Function: Ext2FastIoMdlRead() +* +* Description: +* Bypass the traditional IRP method to perform a MDL read operation. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: TRUE/FALSE +* +*************************************************************************/ +BOOLEAN Ext2FastIoMdlRead( +IN PFILE_OBJECT FileObject, +IN PLARGE_INTEGER FileOffset, +IN ULONG Length, +IN ULONG LockKey, +OUT PMDL *MdlChain, +OUT PIO_STATUS_BLOCK IoStatus, +IN PDEVICE_OBJECT DeviceObject) +{ + BOOLEAN ReturnedStatus = FALSE; // fast i/o failed/not allowed + NTSTATUS RC = STATUS_SUCCESS; + PtrExt2IrpContext PtrIrpContext = NULL; + + FsRtlEnterFileSystem(); + + DebugTrace(DEBUG_TRACE_IRP_ENTRY,"~~~[FastIO call]~~~ Ext2FastIoMdlRead", 0); + if( FileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", FileObject); + } + + try + { + + try + { + + // See description in Ext2FastIoRead() before filling-in the + // stub here. + NOTHING; + + + } + except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) + { + RC = Ext2ExceptionHandler(PtrIrpContext, NULL); + Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); + } + + try_exit: NOTHING; + + } + finally + { + + } + + FsRtlExitFileSystem(); + + return(ReturnedStatus); +} + + +/************************************************************************* +* +* Function: Ext2FastIoMdlReadComplete() +* +* Description: +* Bypass the traditional IRP method to inform the NT Cache Manager and the +* FSD that the caller no longer requires the data locked in the system cache +* or the MDL to stay around anymore .. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: TRUE/FALSE +* +*************************************************************************/ +BOOLEAN Ext2FastIoMdlReadComplete( +IN PFILE_OBJECT FileObject, +OUT PMDL MdlChain, +IN PDEVICE_OBJECT DeviceObject) +{ + BOOLEAN ReturnedStatus = FALSE; // fast i/o failed/not allowed + NTSTATUS RC = STATUS_SUCCESS; + PtrExt2IrpContext PtrIrpContext = NULL; + + FsRtlEnterFileSystem(); + + DebugTrace(DEBUG_TRACE_IRP_ENTRY,"~~~[FastIO call]~~~ Ext2FastIoMdlReadComplete", 0); + if( FileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", FileObject); + } + + try + { + + try + { + + // See description in Ext2FastIoRead() before filling-in the + // stub here. + NOTHING; + + } + except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) + { + + RC = Ext2ExceptionHandler(PtrIrpContext, NULL); + + Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); + + } + + try_exit: NOTHING; + + } + finally + { + + } + + FsRtlExitFileSystem(); + + return(ReturnedStatus); +} + + +/************************************************************************* +* +* Function: Ext2FastIoPrepareMdlWrite() +* +* Description: +* Bypass the traditional IRP method to prepare for a MDL write operation. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: TRUE/FALSE +* +*************************************************************************/ +BOOLEAN Ext2FastIoPrepareMdlWrite( +IN PFILE_OBJECT FileObject, +IN PLARGE_INTEGER FileOffset, +IN ULONG Length, +IN ULONG LockKey, +OUT PMDL *MdlChain, +OUT PIO_STATUS_BLOCK IoStatus, +IN PDEVICE_OBJECT DeviceObject) +{ + BOOLEAN ReturnedStatus = FALSE; // fast i/o failed/not allowed + NTSTATUS RC = STATUS_SUCCESS; + PtrExt2IrpContext PtrIrpContext = NULL; + + FsRtlEnterFileSystem(); + + DebugTrace(DEBUG_TRACE_IRP_ENTRY,"~~~[FastIO call]~~~ Ext2FastIoPrepareMdlWrite", 0); + if( FileObject ) + { + DebugTrace( DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", FileObject); + } + + try + { + try + { + + // See description in Ext2FastIoRead() before filling-in the + // stub here. + NOTHING; + + } except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) { + + RC = Ext2ExceptionHandler(PtrIrpContext, NULL); + + Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); + + } + + try_exit: NOTHING; + + } + finally + { + + } + + FsRtlExitFileSystem(); + + return(ReturnedStatus); +} + + +/************************************************************************* +* +* Function: Ext2FastIoMdlWriteComplete() +* +* Description: +* Bypass the traditional IRP method to inform the NT Cache Manager and the +* FSD that the caller has updated the contents of the MDL. This data can +* now be asynchronously written out to secondary storage by the Cache Mgr. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: TRUE/FALSE +* +*************************************************************************/ +BOOLEAN Ext2FastIoMdlWriteComplete( +IN PFILE_OBJECT FileObject, +IN PLARGE_INTEGER FileOffset, +OUT PMDL MdlChain, +IN PDEVICE_OBJECT DeviceObject) +{ + BOOLEAN ReturnedStatus = FALSE; // fast i/o failed/not allowed + NTSTATUS RC = STATUS_SUCCESS; + PtrExt2IrpContext PtrIrpContext = NULL; + + FsRtlEnterFileSystem(); + + DebugTrace(DEBUG_TRACE_IRP_ENTRY,"~~~[FastIO call]~~~ Ext2FastIoMdlWriteComplete", 0); + if( FileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", FileObject); + } + + try + { + + try + { + + // See description in Ext2FastIoRead() before filling-in the + // stub here. + NOTHING; + + } + except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) + { + RC = Ext2ExceptionHandler(PtrIrpContext, NULL); + Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); + } + + try_exit: NOTHING; + + } + finally + { + + } + + FsRtlExitFileSystem(); + + return(ReturnedStatus); +} + + +/************************************************************************* +* +* Function: Ext2FastIoAcqModWrite() +* +* Description: +* Not really a fast-io operation. Used by the VMM to acquire FSD resources +* before initiating a write operation via the Modified Page/Block Writer. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: STATUS_SUCCESS/Error (try not to return an error, will 'ya ? :-) +* +*************************************************************************/ +NTSTATUS Ext2FastIoAcqModWrite( +IN PFILE_OBJECT FileObject, +IN PLARGE_INTEGER EndingOffset, +OUT PERESOURCE *ResourceToRelease, +IN PDEVICE_OBJECT DeviceObject) +{ + NTSTATUS RC = STATUS_SUCCESS; + PtrExt2IrpContext PtrIrpContext = NULL; + + FsRtlEnterFileSystem(); + + DebugTrace(DEBUG_TRACE_IRP_ENTRY,"~~~[FastIO call]~~~ Ext2FastIoAcqModWrite", 0); + if( FileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", FileObject); + } + + try + { + try + { + + // You must determine which resource(s) you would like to + // acquire at this time. You know that a write is imminent; + // you will probably therefore acquire appropriate resources + // exclusively. + + // You must first get the FCB and CCB pointers from the file object + // that is passed in to this function (as an argument). Note that + // the ending offset (when examined in conjunction with current valid data + // length) may help you in determining the appropriate resource(s) to acquire. + + // For example, if the ending offset is beyond current valid data length, + // you may decide to acquire *both* the MainResource and the PagingIoResource + // exclusively; otherwise, you may decide simply to acquire the PagingIoResource. + + // Consult the text for more information on synchronization in FSDs. + + // One final note; the VMM expects that you will return a pointer to + // the resource that you acquired (single return value). This pointer + // will be returned back to you in the release call (below). + + NOTHING; + + } + except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) + { + RC = Ext2ExceptionHandler(PtrIrpContext, NULL); + Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); + } + + try_exit: NOTHING; + + } + finally + { + + } + + FsRtlExitFileSystem(); + + return(RC); +} + + +/************************************************************************* +* +* Function: Ext2FastIoRelModWrite() +* +* Description: +* Not really a fast-io operation. Used by the VMM to release FSD resources +* after processing a modified page/block write operation. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: STATUS_SUCCESS/Error (an error returned here is really not expected!) +* +*************************************************************************/ +NTSTATUS Ext2FastIoRelModWrite( +IN PFILE_OBJECT FileObject, +IN PERESOURCE ResourceToRelease, +IN PDEVICE_OBJECT DeviceObject) +{ + NTSTATUS RC = STATUS_SUCCESS; + PtrExt2IrpContext PtrIrpContext = NULL; + + FsRtlEnterFileSystem(); + + DebugTrace( DEBUG_TRACE_IRP_ENTRY, "~~~[FastIO call]~~~ Ext2FastIoRelModWrite", 0); + if( FileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", FileObject); + } + + try + { + try + { + + // The MPW has complete the write for modified pages and therefore + // wants you to release pre-acquired resource(s). + + // You must undo here whatever it is that you did in the + // Ext2FastIoAcqModWrite() call above. + + NOTHING; + + } + except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) + { + RC = Ext2ExceptionHandler(PtrIrpContext, NULL); + Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); + } + + try_exit: NOTHING; + + } + finally + { + + } + + FsRtlExitFileSystem(); + + return(RC); +} + + +/************************************************************************* +* +* Function: Ext2FastIoAcqCcFlush() +* +* Description: +* Not really a fast-io operation. Used by the NT Cache Mgr to acquire FSD +* resources before performing a CcFlush() operation on a specific file +* stream. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +NTSTATUS Ext2FastIoAcqCcFlush( +IN PFILE_OBJECT FileObject, +IN PDEVICE_OBJECT DeviceObject) +{ + NTSTATUS RC = STATUS_SUCCESS; + PtrExt2IrpContext PtrIrpContext = NULL; + + FsRtlEnterFileSystem(); + + DebugTrace(DEBUG_TRACE_IRP_ENTRY, "~~~[FastIO call]~~~ Ext2FastIoAcqCcFlush", 0); + if( FileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", FileObject); + } + + try + { + try + { + // Acquire appropriate resources that will allow correct synchronization + // with a flush call (and avoid deadlock). + NOTHING; + + } + except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) + { + RC = Ext2ExceptionHandler(PtrIrpContext, NULL); + Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); + } + + try_exit: NOTHING; + + } + finally + { + + } + + FsRtlExitFileSystem(); + + return(RC); +} + + +/************************************************************************* +* +* Function: Ext2FastIoRelCcFlush() +* +* Description: +* Not really a fast-io operation. Used by the NT Cache Mgr to acquire FSD +* resources before performing a CcFlush() operation on a specific file +* stream. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +NTSTATUS Ext2FastIoRelCcFlush( +IN PFILE_OBJECT FileObject, +IN PDEVICE_OBJECT DeviceObject) +{ + NTSTATUS RC = STATUS_SUCCESS; + PtrExt2IrpContext PtrIrpContext = NULL; + + FsRtlEnterFileSystem(); + + DebugTrace(DEBUG_TRACE_IRP_ENTRY, "~~~[FastIO call]~~~ Ext2FastIoRelCcFlush", 0); + if( FileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", FileObject); + } + + try + { + try + { + // Release resources acquired in Ext2FastIoAcqCcFlush() above. + NOTHING; + + } + except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) + { + RC = Ext2ExceptionHandler(PtrIrpContext, NULL); + Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); + } + + try_exit: NOTHING; + + } + finally + { + + } + + FsRtlExitFileSystem(); + + return(RC); +} + +#endif //_WIN32_WINNT >= 0x0400 diff --git a/reactos/drivers/fs/ext2/src/fileinfo.c b/reactos/drivers/fs/ext2/src/fileinfo.c new file mode 100644 index 00000000000..0047d50f23f --- /dev/null +++ b/reactos/drivers/fs/ext2/src/fileinfo.c @@ -0,0 +1,1125 @@ +/************************************************************************* +* +* File: fileinfo.c +* +* Module: Ext2 File System Driver (Kernel mode execution only) +* +* Description: +* Contains code to handle the "set/query file information" dispatch +* entry points. +* +* Author: Manoj Paul Joseph +* +* +*************************************************************************/ + +#include "ext2fsd.h" + +// define the file specific bug-check id +#define EXT2_BUG_CHECK_ID EXT2_FILE_INFORMATION +#define DEBUG_LEVEL (DEBUG_TRACE_FILEINFO) + + +/************************************************************************* +* +* Function: Ext2FileInfo() +* +* Description: +* The I/O Manager will invoke this routine to handle a set/query file +* information request +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution +* to be deferred to a worker thread context) +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +NTSTATUS Ext2FileInfo( +PDEVICE_OBJECT DeviceObject, // the logical volume device object +PIRP Irp) // I/O Request Packet +{ + NTSTATUS RC = STATUS_SUCCESS; + PtrExt2IrpContext PtrIrpContext = NULL; + BOOLEAN AreWeTopLevel = FALSE; + + DebugTrace(DEBUG_TRACE_IRP_ENTRY, "File Info Control IRP received...", 0); + + FsRtlEnterFileSystem(); + + ASSERT(DeviceObject); + ASSERT(Irp); + + // set the top level context + AreWeTopLevel = Ext2IsIrpTopLevel(Irp); + + try + { + + // get an IRP context structure and issue the request + PtrIrpContext = Ext2AllocateIrpContext(Irp, DeviceObject); + ASSERT(PtrIrpContext); + + RC = Ext2CommonFileInfo(PtrIrpContext, Irp); + + } + except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) + { + + RC = Ext2ExceptionHandler(PtrIrpContext, Irp); + + Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); + } + + if (AreWeTopLevel) + { + IoSetTopLevelIrp(NULL); + } + + FsRtlExitFileSystem(); + + return(RC); +} + + + +/************************************************************************* +* +* Function: Ext2CommonFileInfo() +* +* Description: +* The actual work is performed here. This routine may be invoked in one' +* of the two possible contexts: +* (a) in the context of a system worker thread +* (b) in the context of the original caller +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +NTSTATUS Ext2CommonFileInfo( +PtrExt2IrpContext PtrIrpContext, +PIRP PtrIrp) +{ + NTSTATUS RC = STATUS_SUCCESS; + PIO_STACK_LOCATION PtrIoStackLocation = NULL; + PFILE_OBJECT PtrFileObject = NULL; + PtrExt2FCB PtrFCB = NULL; + PtrExt2CCB PtrCCB = NULL; + PtrExt2VCB PtrVCB = NULL; + PtrExt2NTRequiredFCB PtrReqdFCB = NULL; + BOOLEAN MainResourceAcquired = FALSE; + BOOLEAN VCBResourceAcquired = FALSE; + BOOLEAN PagingIoResourceAcquired = FALSE; + IO_STATUS_BLOCK LocalIoStatus; + void *PtrSystemBuffer = NULL; + long BufferLength = 0; + FILE_INFORMATION_CLASS FunctionalityRequested; + BOOLEAN CanWait = FALSE; + BOOLEAN PostRequest = FALSE; + + try + { + // First, get a pointer to the current I/O stack location. + PtrIoStackLocation = IoGetCurrentIrpStackLocation(PtrIrp); + ASSERT(PtrIoStackLocation); + + PtrFileObject = PtrIoStackLocation->FileObject; + ASSERT(PtrFileObject); + + // Get the FCB and CCB pointers + Ext2GetFCB_CCB_VCB_FromFileObject ( + PtrFileObject, &PtrFCB, &PtrCCB, &PtrVCB ); + + PtrReqdFCB = &(PtrFCB->NTRequiredFCB); + + CanWait = ((PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_CAN_BLOCK) ? TRUE : FALSE); + + // If the caller has opened a logical volume and is attempting to + // query information for it as a file stream, return an error. + if (PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB) + { + // This is not allowed. Caller must use get/set volume information instead. + RC = STATUS_INVALID_PARAMETER; + try_return(RC); + } + + // ASSERT(PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_FCB); + AssertFCB( PtrFCB ); + + PtrSystemBuffer = PtrIrp->AssociatedIrp.SystemBuffer; + + if (PtrIoStackLocation->MajorFunction == IRP_MJ_QUERY_INFORMATION) + { + // *********************** + // Query File Information + // *********************** + + // Now, obtain some parameters. + DebugTrace(DEBUG_TRACE_MISC, "Buffer length = 0x%lX[FileInfo]", BufferLength ); + + BufferLength = PtrIoStackLocation->Parameters.QueryFile.Length; + + FunctionalityRequested = PtrIoStackLocation->Parameters.QueryFile.FileInformationClass; + + // Read in the file inode if it hasn't already been read... + Ext2InitializeFCBInodeInfo( PtrFCB ); + + // + // Acquire the MainResource shared + // except for page files... + // + if (!(PtrFCB->FCBFlags & EXT2_FCB_PAGE_FILE)) + { + // Acquire the MainResource shared. + DebugTrace(DEBUG_TRACE_MISC, "*** Attempting to acquire FCB Shared [FileInfo]", 0); + DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [FileInfo]", PtrReqdFCB->MainResource.ActiveCount, PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, PtrReqdFCB->MainResource.NumberOfSharedWaiters ); + if (!ExAcquireResourceSharedLite(&(PtrReqdFCB->MainResource), CanWait)) + { + DebugTrace(DEBUG_TRACE_MISC, "*** FCB acquisition FAILED [FileInfo]", 0); + PostRequest = TRUE; + try_return(RC = STATUS_PENDING); + } + MainResourceAcquired = TRUE; + DebugTrace(DEBUG_TRACE_MISC, "*** FCB acquired [FileInfo]", 0); + } + + // Do whatever the caller asked us to do + switch (FunctionalityRequested) + { + case FileBasicInformation: + DebugTrace(DEBUG_TRACE_FILEINFO, "FileBasicInformation requested for %S", PtrFCB->FCBName->ObjectName.Buffer ); + RC = Ext2GetBasicInformation(PtrFCB, (PFILE_BASIC_INFORMATION)PtrSystemBuffer, &BufferLength); + break; + case FileStandardInformation: + DebugTrace(DEBUG_TRACE_FILEINFO, "FileStandardInformation requested for %S", PtrFCB->FCBName->ObjectName.Buffer ); + RC = Ext2GetStandardInformation(PtrFCB, (PFILE_STANDARD_INFORMATION)PtrSystemBuffer, &BufferLength); + break; + // Similarly, implement all of the other query information routines + // that your FSD can support. +#if(_WIN32_WINNT >= 0x0400) + case FileNetworkOpenInformation: + DebugTrace(DEBUG_TRACE_FILEINFO, "FileNetworkOpenInformation requested for %S", PtrFCB->FCBName->ObjectName.Buffer ); + RC = Ext2GetNetworkOpenInformation(PtrFCB, (PFILE_NETWORK_OPEN_INFORMATION)PtrSystemBuffer, &BufferLength); + // RC = STATUS_INVALID_PARAMETER; + // try_return(RC); + break; +#endif // _WIN32_WINNT >= 0x0400 + case FileInternalInformation: + DebugTrace(DEBUG_TRACE_FILEINFO, "FileInternalInformation requested for %S", PtrFCB->FCBName->ObjectName.Buffer ); + // RC = Ext2GetInternalInformation(...); + RC = STATUS_INVALID_PARAMETER; + try_return(RC); + break; + case FileEaInformation: + DebugTrace(DEBUG_TRACE_FILEINFO, "FileEaInformation requested for %S", PtrFCB->FCBName->ObjectName.Buffer ); + { + PFILE_EA_INFORMATION EaInformation; + EaInformation = (PFILE_EA_INFORMATION) PtrSystemBuffer; + EaInformation->EaSize = 0; + BufferLength = sizeof( FILE_EA_INFORMATION ); + break; + } + // RC = Ext2GetEaInformation(...); + break; + + case FilePositionInformation: + DebugTrace(DEBUG_TRACE_FILEINFO, "FilePositionInformation requested for %S", PtrFCB->FCBName->ObjectName.Buffer ); + // This is fairly simple. Copy over the information from the + // file object. + { + PFILE_POSITION_INFORMATION PtrFileInfoBuffer; + + PtrFileInfoBuffer = (PFILE_POSITION_INFORMATION)PtrSystemBuffer; + + ASSERT(BufferLength >= sizeof(FILE_POSITION_INFORMATION)); + PtrFileInfoBuffer->CurrentByteOffset = PtrFileObject->CurrentByteOffset; + // Modify the local variable for BufferLength appropriately. + BufferLength = sizeof(FILE_POSITION_INFORMATION); + } + break; + case FileStreamInformation: + DebugTrace(DEBUG_TRACE_FILEINFO, "FileStreamInformation requested for %S", PtrFCB->FCBName->ObjectName.Buffer ); + // RC = Ext2GetFileStreamInformation(...); + + RC = STATUS_INVALID_PARAMETER; + try_return(RC); + + break; + case FileAllInformation: + DebugTrace(DEBUG_TRACE_FILEINFO, "FileAllInformation requested for %S", PtrFCB->FCBName->ObjectName.Buffer ); + // The I/O Manager supplies the Mode, Access, and Alignment + // information. The rest is up to us to provide. + // Therefore, decrement the BufferLength appropriately (assuming + // that the above 3 types on information are already in the + // buffer) + { + + PFILE_POSITION_INFORMATION PtrFileInfoBuffer; + PFILE_ALL_INFORMATION PtrAllInfo = (PFILE_ALL_INFORMATION)PtrSystemBuffer; + + // Fill in the position information. + + PtrFileInfoBuffer = (PFILE_POSITION_INFORMATION)&(PtrAllInfo->PositionInformation); + + PtrFileInfoBuffer->CurrentByteOffset = PtrFileObject->CurrentByteOffset; + + // Modify the local variable for BufferLength appropriately. + BufferLength = sizeof(FILE_ALL_INFORMATION); + + // Get the remaining stuff. + if (!NT_SUCCESS(RC = Ext2GetBasicInformation(PtrFCB, (PFILE_BASIC_INFORMATION)&(PtrAllInfo->BasicInformation), + &BufferLength))) + { + try_return(RC); + } + if (!NT_SUCCESS(RC = Ext2GetStandardInformation(PtrFCB, &(PtrAllInfo->StandardInformation), &BufferLength))) + { + try_return(RC); + } + // Similarly, get all of the others ... + } + break; + case FileNameInformation: + DebugTrace(DEBUG_TRACE_FILEINFO, "FileNameInformation requested for %S", PtrFCB->FCBName->ObjectName.Buffer ); + // RC = Ext2GetFullNameInformation(...); + RC = Ext2GetFullNameInformation(PtrFCB, PtrCCB, (PFILE_NAME_INFORMATION)PtrSystemBuffer, &BufferLength); + break; + case FileAlternateNameInformation: + DebugTrace(DEBUG_TRACE_FILEINFO, "FileAlternateNameInformation requested for %S", PtrFCB->FCBName->ObjectName.Buffer ); + RC = STATUS_INVALID_PARAMETER; + try_return(RC); + // RC = Ext2GetAltNameInformation(...); + break; + case FileCompressionInformation: + DebugTrace(DEBUG_TRACE_FILEINFO, "FileCompressionInformation requested for %S", PtrFCB->FCBName->ObjectName.Buffer ); + RC = STATUS_INVALID_PARAMETER; + try_return(RC); + // RC = Ext2GetCompressionInformation(...); + break; + + default: + RC = STATUS_INVALID_PARAMETER; + try_return(RC); + } + + // If we completed successfully, the return the amount of information transferred. + if (NT_SUCCESS(RC)) + { + PtrIrp->IoStatus.Information = BufferLength; + } + else + { + PtrIrp->IoStatus.Information = 0; + } + + } + else + { + // *********************** + // Set File Information + // *********************** + ASSERT(PtrIoStackLocation->MajorFunction == IRP_MJ_SET_INFORMATION); + + DebugTrace(DEBUG_TRACE_FILEINFO, ">>>>>>>> Set File Information <<<<<<<<< [FileInfo]", 0); + + + // Now, obtain some parameters. + FunctionalityRequested = PtrIoStackLocation->Parameters.SetFile.FileInformationClass; + + // Check oplocks... + + // + // Acquire the VCB resource exclusively for + // deletion, rename and link operations... + // To synchronize with create and cleanup operations + // + if ((FunctionalityRequested == FileDispositionInformation) || + (FunctionalityRequested == FileRenameInformation) || + (FunctionalityRequested == FileLinkInformation)) + { + DebugTrace(DEBUG_TRACE_MISC, "*** Attempting to acquire VCB Exclusively [FileInfo]", 0); + DebugTraceState( " VCB AC:0x%LX SW:0x%LX EX:0x%LX [FileInfo]", PtrVCB->VCBResource.ActiveCount, PtrVCB->VCBResource.NumberOfExclusiveWaiters, PtrVCB->VCBResource.NumberOfSharedWaiters ); + if (!ExAcquireResourceExclusiveLite(&(PtrVCB->VCBResource), CanWait)) + { + DebugTrace(DEBUG_TRACE_MISC, "*** VCB Acquisition FAILED [FileInfo]", 0); + PostRequest = TRUE; + try_return(RC = STATUS_PENDING); + } + // We have the VCB acquired exclusively. + DebugTrace(DEBUG_TRACE_MISC, "*** VCB Acquired [FileInfo]", 0); + VCBResourceAcquired = TRUE; + } + + + // Acquire the FCB exclusively at this time... + if (!(PtrFCB->FCBFlags & EXT2_FCB_PAGE_FILE)) + { + // Acquire the MainResource shared. + DebugTrace(DEBUG_TRACE_MISC, "*** Attempting to acquire FCB Exclusively [FileInfo]", 0); + DebugTraceState( " FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [FileInfo]", PtrReqdFCB->MainResource.ActiveCount, PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, PtrReqdFCB->MainResource.NumberOfSharedWaiters ); + if (!ExAcquireResourceExclusiveLite(&(PtrReqdFCB->MainResource), CanWait)) + { + DebugTrace(DEBUG_TRACE_MISC, "*** FCB Acquisition FAILED [FileInfo]", 0); + PostRequest = TRUE; + try_return(RC = STATUS_PENDING); + } + MainResourceAcquired = TRUE; + DebugTrace(DEBUG_TRACE_MISC, "*** FCB Acquired [FileInfo]", 0); + } + + // + // For delete link (rename), + // set allocation size, and set EOF, should also acquire the paging-IO + // resource, thereby synchronizing with paging-IO requests. + // + if( PtrFileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FileInfo]", PtrFileObject); + + } + DebugTrace(DEBUG_TRACE_MISC, "*** Attempting to acquire FCBPaging Exclusively [FileInfo]", 0); + DebugTraceState( " FCBPaging AC:0x%LX SW:0x%LX EX:0x%LX [FileInfo]", PtrReqdFCB->PagingIoResource.ActiveCount, PtrReqdFCB->PagingIoResource.NumberOfExclusiveWaiters, PtrReqdFCB->PagingIoResource.NumberOfSharedWaiters ); + if (!ExAcquireResourceExclusiveLite(&(PtrReqdFCB->PagingIoResource), CanWait)) + { + DebugTrace(DEBUG_TRACE_MISC, "*** Attempt to acquire FCBPaging FAILED [FileInfo]", 0); + PostRequest = TRUE; + try_return(RC = STATUS_PENDING); + } + PagingIoResourceAcquired = TRUE; + DebugTrace(DEBUG_TRACE_MISC, "*** Acquired FCBPaging [FileInfo]", 0); + + // Do whatever the caller asked us to do + switch (FunctionalityRequested) + { + case FileBasicInformation: + DebugTrace(DEBUG_TRACE_FILEINFO, "Attempt to set FileBasicInformation for %S", PtrFCB->FCBName->ObjectName.Buffer ); + RC = Ext2SetBasicInformation(PtrIrpContext, PtrFCB, PtrFileObject, (PFILE_BASIC_INFORMATION)PtrSystemBuffer); + // RC = STATUS_ACCESS_DENIED; + break; + case FileAllocationInformation: + DebugTrace(DEBUG_TRACE_FILEINFO, "Attempt to set FileAllocationInformation for %S", PtrFCB->FCBName->ObjectName.Buffer ); + RC = Ext2SetAllocationInformation(PtrFCB, PtrCCB, PtrVCB, PtrFileObject, + PtrIrpContext, PtrIrp, PtrSystemBuffer); + break; + case FileEndOfFileInformation: + DebugTrace(DEBUG_TRACE_FILEINFO, "Attempt to set FileEndOfFileInformation for %S", PtrFCB->FCBName->ObjectName.Buffer ); + // RC = Ext2SetEOF(...); + RC = STATUS_INVALID_PARAMETER; + try_return(RC); + break; + + case FilePositionInformation: + DebugTrace(DEBUG_TRACE_FILEINFO, "Attempt to set FilePositionInformation for %S", PtrFCB->FCBName->ObjectName.Buffer ); + // Check if no intermediate buffering has been specified. + // If it was specified, do not allow non-aligned set file + // position requests to succeed. + { + PFILE_POSITION_INFORMATION PtrFileInfoBuffer; + + PtrFileInfoBuffer = (PFILE_POSITION_INFORMATION)PtrSystemBuffer; + + if (PtrFileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) + { + if (PtrFileInfoBuffer->CurrentByteOffset.LowPart & PtrIoStackLocation->DeviceObject->AlignmentRequirement) + { + // Invalid alignment. + try_return(RC = STATUS_INVALID_PARAMETER); + } + } + PtrFileObject->CurrentByteOffset = PtrFileInfoBuffer->CurrentByteOffset; + } + break; + + case FileDispositionInformation: + DebugTrace(DEBUG_TRACE_FILEINFO, "Attempt to set FileDispositionInformation for %S", PtrFCB->FCBName->ObjectName.Buffer ); + RC = Ext2SetDispositionInformation(PtrFCB, PtrCCB, PtrVCB, PtrFileObject, + PtrIrpContext, PtrIrp, + (PFILE_DISPOSITION_INFORMATION)PtrSystemBuffer); + break; + + case FileRenameInformation: + DebugTrace(DEBUG_TRACE_FILEINFO, "Attempt to set FileRenameInformation for %S", PtrFCB->FCBName->ObjectName.Buffer ); + RC = Ext2RenameOrLinkFile( PtrFCB, PtrFileObject, PtrIrpContext, + PtrIrp, (PFILE_RENAME_INFORMATION)PtrSystemBuffer); + break; + case FileLinkInformation: + DebugTrace(DEBUG_TRACE_FILEINFO, "Attempt to set FileLinkInformation for %S", PtrFCB->FCBName->ObjectName.Buffer ); + RC = STATUS_INVALID_PARAMETER; + try_return(RC); + // When you implement your rename/link routine, be careful to + // check the following two arguments: + // TargetFileObject = PtrIoStackLocation->Parameters.SetFile.FileObject; + // ReplaceExistingFile = PtrIoStackLocation->Parameters.SetFile.ReplaceIfExists; + // + // The TargetFileObject argument is a pointer to the "target + // directory" file object obtained during the "create" routine + // invoked by the NT I/O Manager with the SL_OPEN_TARGET_DIRECTORY + // flag specified. Remember that it is quite possible that if the + // rename/link is contained within a single directory, the target + // and source directories will be the same. + // The ReplaceExistingFile argument should be used by you to + // determine if the caller wishes to replace the target (if it + // currently exists) with the new link/renamed file. If this + // value is FALSE, and if the target directory entry (being + // renamed-to, or the target of the link) exists, you should + // return a STATUS_OBJECT_NAME_COLLISION error to the caller. + + // RC = Ext2RenameOrLinkFile(PtrFCB, PtrCCB, PtrFileObject, PtrIrpContext, + // PtrIrp, (PFILE_RENAME_INFORMATION)PtrSystemBuffer); + + // Once you have completed the rename/link operation, do not + // forget to notify any "notify IRPs" about the actions you have + // performed. + // An example is if you renamed across directories, you should + // report that a new entry was added with the FILE_ACTION_ADDED + // action type. The actual modification would then be reported + // as either FILE_NOTIFY_CHANGE_FILE_NAME (if a file was renamed) + // or FILE_NOTIFY_CHANGE_DIR_NAME (if a directory was renamed). + + break; + default: + DebugTrace(DEBUG_TRACE_FILEINFO, "Unrecoganised SetFileInformation code for %S", PtrFCB->FCBName->ObjectName.Buffer ); + RC = STATUS_INVALID_PARAMETER; + try_return(RC); + } + } + + try_exit: NOTHING; + } + finally + { + if (PagingIoResourceAcquired) + { + Ext2ReleaseResource(&(PtrReqdFCB->PagingIoResource)); + DebugTrace(DEBUG_TRACE_MISC, "*** FCBPaging Released [FileInfo]", 0); + DebugTraceState( " FCBPaging AC:0x%LX SW:0x%LX EX:0x%LX [FileInfo]", + PtrReqdFCB->PagingIoResource.ActiveCount, + PtrReqdFCB->PagingIoResource.NumberOfExclusiveWaiters, + PtrReqdFCB->PagingIoResource.NumberOfSharedWaiters ); + + if( PtrFileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FileInfo]", PtrFileObject); + } + + PagingIoResourceAcquired = FALSE; + } + + if (MainResourceAcquired) + { + Ext2ReleaseResource(&(PtrReqdFCB->MainResource)); + DebugTrace(DEBUG_TRACE_MISC, "*** FCB Released [FileInfo]", 0); + DebugTraceState( " FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [FileInfo]", + PtrReqdFCB->MainResource.ActiveCount, + PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, + PtrReqdFCB->MainResource.NumberOfSharedWaiters ); + if( PtrFileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FileInfo]", PtrFileObject); + } + + MainResourceAcquired = FALSE; + } + + if (VCBResourceAcquired) + { + Ext2ReleaseResource(&(PtrVCB->VCBResource)); + DebugTrace(DEBUG_TRACE_MISC, "*** VCB Released [FileInfo]", 0); + DebugTraceState( " VCB AC:0x%LX SW:0x%LX EX:0x%LX [FileInfo]", + PtrVCB->VCBResource.ActiveCount, + PtrVCB->VCBResource.NumberOfExclusiveWaiters, + PtrVCB->VCBResource.NumberOfSharedWaiters ); + + VCBResourceAcquired = FALSE; + } + + // Post IRP if required + if (PostRequest) + { + + // Since, the I/O Manager gave us a system buffer, we do not + // need to "lock" anything. + + // Perform the post operation which will mark the IRP pending + // and will return STATUS_PENDING back to us + RC = Ext2PostRequest(PtrIrpContext, PtrIrp); + + } + else + { + + // Can complete the IRP here if no exception was encountered + if (!(PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_EXCEPTION)) { + PtrIrp->IoStatus.Status = RC; + + // Free up the Irp Context + Ext2ReleaseIrpContext(PtrIrpContext); + + // complete the IRP + IoCompleteRequest(PtrIrp, IO_DISK_INCREMENT); + } + } // can we complete the IRP ? + } // end of "finally" processing + + // DbgPrint( "\n === File Info IRP returning --> RC : 0x%lX Bytes: 0x%lX", PtrIrp->IoStatus.Status, PtrIrp->IoStatus.Information ); + + return(RC); +} + + +/************************************************************************* +* +* Function: Ext2GetBasicInformation() +* +* Description: +* Return some time-stamps and file attributes to the caller. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +NTSTATUS Ext2GetBasicInformation( +PtrExt2FCB PtrFCB, +PFILE_BASIC_INFORMATION PtrBuffer, +long *PtrReturnedLength ) +{ + NTSTATUS RC = STATUS_SUCCESS; + + try + { + if (*PtrReturnedLength < sizeof(FILE_BASIC_INFORMATION)) + { + try_return(RC = STATUS_BUFFER_OVERFLOW); + } + + // Zero out the supplied buffer. + RtlZeroMemory(PtrBuffer, sizeof(FILE_BASIC_INFORMATION)); + + // Get information from the FCB. + PtrBuffer->CreationTime = PtrFCB->CreationTime; + PtrBuffer->LastAccessTime = PtrFCB->LastAccessTime; + PtrBuffer->LastWriteTime = PtrFCB->LastWriteTime; + PtrBuffer->ChangeTime = PtrFCB->LastWriteTime; + + // Now fill in the attributes. + PtrBuffer->FileAttributes = FILE_ATTRIBUTE_NORMAL; + if ( Ext2IsFlagOn( PtrFCB->FCBFlags, EXT2_FCB_DIRECTORY ) ) + { + PtrBuffer->FileAttributes |= FILE_ATTRIBUTE_DIRECTORY; + } + else if ( Ext2IsFlagOn( PtrFCB->FCBFlags, EXT2_FCB_SPECIAL_FILE ) ) + { + // Special File... + // Treated with respect... ;) + // + PtrBuffer->FileAttributes |= ( FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_READONLY) ; + } + + if ( Ext2IsFlagOn( PtrFCB->FCBFlags, EXT2_FCB_HIDDEN_FILE ) ) + { + PtrBuffer->FileAttributes |= FILE_ATTRIBUTE_HIDDEN; + } + + if ( Ext2IsFlagOn( PtrFCB->FCBFlags, EXT2_FCB_READ_ONLY ) ) + { + PtrBuffer->FileAttributes |= FILE_ATTRIBUTE_READONLY; + } + + try_exit: NOTHING; + } + finally + { + if (NT_SUCCESS(RC)) + { + // Return the amount of information filled in. + *PtrReturnedLength = sizeof(FILE_BASIC_INFORMATION); + } + } + return(RC); +} + +NTSTATUS Ext2GetStandardInformation( +PtrExt2FCB PtrFCB, + +PFILE_STANDARD_INFORMATION PtrStdInformation, +long *PtrReturnedLength ) +{ + + NTSTATUS RC = STATUS_SUCCESS; + + + try + { + if (*PtrReturnedLength < sizeof( FILE_STANDARD_INFORMATION )) + { + try_return(RC = STATUS_BUFFER_OVERFLOW); + } + + // Zero out the supplied buffer. + RtlZeroMemory(PtrStdInformation, sizeof(FILE_STANDARD_INFORMATION)); + + + PtrStdInformation->AllocationSize = PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize; + PtrStdInformation->EndOfFile = PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize; + PtrStdInformation->DeletePending = Ext2IsFlagOn( PtrFCB->FCBFlags, EXT2_FCB_DELETE_ON_CLOSE); + PtrStdInformation->Directory = Ext2IsFlagOn( PtrFCB->FCBFlags, EXT2_FCB_DIRECTORY ); + PtrStdInformation->NumberOfLinks = PtrFCB->LinkCount; + + try_exit: NOTHING; + } + finally + { + if (NT_SUCCESS(RC)) + { + // Return the amount of information filled in. + *PtrReturnedLength = sizeof( FILE_STANDARD_INFORMATION ); + } + } + return(RC); +} + +NTSTATUS Ext2GetNetworkOpenInformation( + PtrExt2FCB PtrFCB, + PFILE_NETWORK_OPEN_INFORMATION PtrNetworkOpenInformation, + long *PtrReturnedLength ) +{ + + NTSTATUS RC = STATUS_SUCCESS; + + try + { + if (*PtrReturnedLength < sizeof( FILE_NETWORK_OPEN_INFORMATION )) + { + try_return(RC = STATUS_BUFFER_OVERFLOW); + } + + // Zero out the supplied buffer. + RtlZeroMemory(PtrNetworkOpenInformation, sizeof(FILE_NETWORK_OPEN_INFORMATION)); + + PtrNetworkOpenInformation->CreationTime = PtrFCB->CreationTime; + PtrNetworkOpenInformation->LastAccessTime = PtrFCB->LastAccessTime; + PtrNetworkOpenInformation->LastWriteTime = PtrFCB->LastWriteTime; + PtrNetworkOpenInformation->ChangeTime = PtrFCB->LastWriteTime; + PtrNetworkOpenInformation->AllocationSize = PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize; + PtrNetworkOpenInformation->EndOfFile = PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize; + + // Now fill in the attributes. + PtrNetworkOpenInformation->FileAttributes = FILE_ATTRIBUTE_NORMAL; + + if ( Ext2IsFlagOn( PtrFCB->FCBFlags, EXT2_FCB_DIRECTORY ) ) + { + PtrNetworkOpenInformation->FileAttributes |= FILE_ATTRIBUTE_DIRECTORY; + } + else if ( Ext2IsFlagOn( PtrFCB->FCBFlags, EXT2_FCB_SPECIAL_FILE ) ) + { + // Special File... + // Treated with respect... ;) + // + PtrNetworkOpenInformation->FileAttributes |= ( FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_READONLY) ; + } + if ( Ext2IsFlagOn( PtrFCB->FCBFlags, EXT2_FCB_HIDDEN_FILE ) ) + { + PtrNetworkOpenInformation->FileAttributes |= FILE_ATTRIBUTE_HIDDEN; + } + + if ( Ext2IsFlagOn( PtrFCB->FCBFlags, EXT2_FCB_READ_ONLY ) ) + { + PtrNetworkOpenInformation->FileAttributes |= FILE_ATTRIBUTE_READONLY; + } + try_exit: NOTHING; + } + finally + { + if (NT_SUCCESS(RC)) + { + // Return the amount of information filled in. + *PtrReturnedLength = sizeof( FILE_NETWORK_OPEN_INFORMATION ); + } + } + return(RC); +} + + +NTSTATUS Ext2GetFullNameInformation( + PtrExt2FCB PtrFCB, + PtrExt2CCB PtrCCB, + PFILE_NAME_INFORMATION PtrNameInformation, + long *PtrReturnedLength ) +{ + + NTSTATUS RC = STATUS_SUCCESS; + + try + { + if (*PtrReturnedLength < + (long)( sizeof(FILE_NAME_INFORMATION) + PtrCCB->AbsolutePathName.Length) ) + { + try_return(RC = STATUS_BUFFER_OVERFLOW); + } + + // Zero out the supplied buffer. + RtlZeroMemory(PtrNameInformation, sizeof( FILE_NAME_INFORMATION ) ); + + if( PtrCCB->AbsolutePathName.Length ) + { + RtlCopyMemory( + PtrNameInformation->FileName, // Destination, + PtrCCB->AbsolutePathName.Buffer, // Source, + PtrCCB->AbsolutePathName.Length ); // Length + + PtrNameInformation->FileNameLength = PtrCCB->AbsolutePathName.Length; + try_return(RC = STATUS_SUCCESS); + } + else + { + try_return(RC = STATUS_INVALID_PARAMETER); + } + + try_exit: NOTHING; + } + finally + { + if (NT_SUCCESS(RC)) + { + // Return the amount of information filled in. + *PtrReturnedLength = + sizeof( FILE_NAME_INFORMATION ) + + PtrCCB->AbsolutePathName.Length; + } + } + return(RC); +} +/************************************************************************* +* +* Function: Ext2SetBasicInformation() +* +* Description: +* Set some time-stamps and file attributes supplied by the caller. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +NTSTATUS Ext2SetBasicInformation( + PtrExt2IrpContext PtrIrpContext, + PtrExt2FCB PtrFCB, + PFILE_OBJECT PtrFileObject, + PFILE_BASIC_INFORMATION PtrFileInformation ) +{ + NTSTATUS RC = STATUS_SUCCESS; + + PtrExt2VCB PtrVCB = PtrFCB->PtrVCB; + AssertVCB( PtrVCB ); + + // BOOLEAN CreationTimeChanged = FALSE; + // BOOLEAN AttributesChanged = FALSE; + +// return STATUS_INVALID_PARAMETER; + + try + { + EXT2_INODE Inode; + RtlZeroMemory(&Inode, sizeof( EXT2_INODE )); + + if( NT_SUCCESS( Ext2ReadInode( PtrVCB, PtrFCB->INodeNo, &Inode ) ) ) + { + // + // Update time stamps in the inode + // and in the FCB... + // + if( PtrFileInformation->CreationTime.QuadPart ) + { + PtrFCB->CreationTime.QuadPart = PtrFileInformation->CreationTime.QuadPart; + Inode.i_ctime = (ULONG) ( (PtrFCB->CreationTime.QuadPart + - Ext2GlobalData.TimeDiff.QuadPart) / 10000000 ); + + } + if( PtrFileInformation->LastAccessTime.QuadPart ) + { + PtrFCB->LastAccessTime.QuadPart = PtrFileInformation->LastAccessTime.QuadPart; + Inode.i_atime = (ULONG) ( (PtrFCB->LastAccessTime.QuadPart + - Ext2GlobalData.TimeDiff.QuadPart) / 10000000 ); + + } + if( PtrFileInformation->LastWriteTime.QuadPart ) + { + PtrFCB->LastWriteTime.QuadPart = PtrFileInformation->LastWriteTime.QuadPart; + Inode.i_mtime = (ULONG) ( (PtrFCB->LastWriteTime.QuadPart + - Ext2GlobalData.TimeDiff.QuadPart) / 10000000 ); + } + + // Now come the attributes. + if (PtrFileInformation->FileAttributes) + { + if (PtrFileInformation->FileAttributes & FILE_ATTRIBUTE_READONLY ) + { + // Turn off the write bits... + Ext2SetModeReadOnly( Inode.i_mode ); + } + if (PtrFileInformation->FileAttributes & FILE_ATTRIBUTE_HIDDEN ) + { + // Turn off the read and write bits... + Ext2SetModeHidden( Inode.i_mode ); + + } + if (PtrFileInformation->FileAttributes & FILE_ATTRIBUTE_SYSTEM ) + { + // Just turn off the read and write bits... + // No special field to indicate that this is a system file... + Ext2SetModeReadOnly( Inode.i_mode ); + Ext2SetModeHidden( Inode.i_mode ); + } + } + + // Updating the inode... + Ext2WriteInode( PtrIrpContext, PtrVCB, PtrFCB->INodeNo, &Inode ); + } + + if (PtrFileInformation->FileAttributes & FILE_ATTRIBUTE_TEMPORARY) + { + Ext2SetFlag(PtrFileObject->Flags, FO_TEMPORARY_FILE); + } + else + { + Ext2ClearFlag(PtrFileObject->Flags, FO_TEMPORARY_FILE); + } + + try_exit: NOTHING; + } + finally + { + ; + } + return(RC); +} + + +/************************************************************************* +* +* Function: Ext2SetDispositionInformation() +* +* Description: +* Mark/Unmark a file for deletion. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +NTSTATUS Ext2SetDispositionInformation( +PtrExt2FCB PtrFCB, +PtrExt2CCB PtrCCB, +PtrExt2VCB PtrVCB, +PFILE_OBJECT PtrFileObject, +PtrExt2IrpContext PtrIrpContext, +PIRP PtrIrp, +PFILE_DISPOSITION_INFORMATION PtrBuffer) +{ + NTSTATUS RC = STATUS_SUCCESS; + + try + { + if (!PtrBuffer->DeleteFile) + { + // "un-delete" the file. + Ext2ClearFlag(PtrFCB->FCBFlags, EXT2_FCB_DELETE_ON_CLOSE); + PtrFileObject->DeletePending = FALSE; + try_return(RC); + } + + // Do some checking to see if the file can even be deleted. + + if (PtrFCB->FCBFlags & EXT2_FCB_DELETE_ON_CLOSE) + { + // All done! + try_return(RC); + } + + if (PtrFCB->FCBFlags & EXT2_FCB_READ_ONLY) + { + try_return(RC = STATUS_CANNOT_DELETE); + } + + if (PtrVCB->VCBFlags & EXT2_VCB_FLAGS_VOLUME_READ_ONLY) + { + try_return(RC = STATUS_CANNOT_DELETE); + } + + // An important step is to check if the file stream has been + // mapped by any process. The delete cannot be allowed to proceed + // in this case. + if (!MmFlushImageSection(&(PtrFCB->NTRequiredFCB.SectionObject), MmFlushForDelete)) + { + try_return(RC = STATUS_CANNOT_DELETE); + } + + // Disallow deletion of either a root + // directory or a directory that is not empty. + if( PtrFCB->INodeNo == EXT2_ROOT_INO ) + { + try_return(RC = STATUS_CANNOT_DELETE); + } + + if (PtrFCB->FCBFlags & EXT2_FCB_DIRECTORY) + { + if (!Ext2IsDirectoryEmpty(PtrFCB, PtrCCB, PtrIrpContext)) + { + try_return(RC = STATUS_DIRECTORY_NOT_EMPTY); + } + } + + // Set a flag to indicate that this directory entry will become history + // at cleanup. + Ext2SetFlag(PtrFCB->FCBFlags, EXT2_FCB_DELETE_ON_CLOSE); + PtrFileObject->DeletePending = TRUE; + + try_exit: NOTHING; + } + finally + { + ; + } + return(RC); +} + + + +/************************************************************************* +* +* Function: Ext2SetAllocationInformation() +* +* Description: +* Mark/Unmark a file for deletion. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +NTSTATUS Ext2SetAllocationInformation( +PtrExt2FCB PtrFCB, +PtrExt2CCB PtrCCB, +PtrExt2VCB PtrVCB, +PFILE_OBJECT PtrFileObject, +PtrExt2IrpContext PtrIrpContext, +PIRP PtrIrp, +PFILE_ALLOCATION_INFORMATION PtrBuffer) +{ + NTSTATUS RC = STATUS_SUCCESS; + BOOLEAN TruncatedFile = FALSE; + BOOLEAN ModifiedAllocSize = FALSE; + + try + { + + // Are we increasing the allocation size? + if (RtlLargeIntegerLessThan( + PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize, + PtrBuffer->AllocationSize)) + { + ULONG CurrentSize; + ULONG LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize; + + for( CurrentSize = 0; CurrentSize < PtrBuffer->AllocationSize.QuadPart; CurrentSize += LogicalBlockSize ) + { + Ext2AddBlockToFile( PtrIrpContext, PtrVCB, PtrFCB, PtrFileObject, FALSE ); + } + ModifiedAllocSize = TRUE; + } + else if (RtlLargeIntegerGreaterThan(PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize, + PtrBuffer->AllocationSize)) + { + // This is the painful part. See if the VMM will allow us to proceed. + // The VMM will deny the request if: + // (a) any image section exists OR + // (b) a data section exists and the size of the user mapped view + // is greater than the new size + // Otherwise, the VMM should allow the request to proceed. + if (!MmCanFileBeTruncated(&(PtrFCB->NTRequiredFCB.SectionObject), &(PtrBuffer->AllocationSize))) + { + // VMM said no way! + try_return(RC = STATUS_USER_MAPPED_FILE); + } + + if( !Ext2TruncateFileAllocationSize( PtrIrpContext, PtrFCB, PtrFileObject, &PtrBuffer->AllocationSize) ) + { + // This will do until I figure out a better error message code ;) + RC = STATUS_INSUFFICIENT_RESOURCES; + + } + + ModifiedAllocSize = TRUE; + TruncatedFile = TRUE; + } + + try_exit: + + // This is a good place to check if we have performed a truncate + // operation. If we have perform a truncate (whether we extended + // or reduced file size), you should update file time stamps. + + // Last, but not the lease, you must inform the Cache Manager of file size changes. + if (ModifiedAllocSize && NT_SUCCESS(RC)) + { + // Update the FCB Header with the new allocation size. + PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize = PtrBuffer->AllocationSize; + + // If we decreased the allocation size to less than the + // current file size, modify the file size value. + // Similarly, if we decreased the value to less than the + // current valid data length, modify that value as well. + if (TruncatedFile) + { + if (RtlLargeIntegerLessThan(PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize, PtrBuffer->AllocationSize)) + { + // Decrease the file size value. + PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize = PtrBuffer->AllocationSize; + } + + if (RtlLargeIntegerLessThan(PtrFCB->NTRequiredFCB.CommonFCBHeader.ValidDataLength, PtrBuffer->AllocationSize)) + { + // Decrease the valid data length value. + PtrFCB->NTRequiredFCB.CommonFCBHeader.ValidDataLength = PtrBuffer->AllocationSize; + } + } + + + // If the FCB has not had caching initiated, it is still valid + // for you to invoke the NT Cache Manager. It is possible in such + // situations for the call to be no'oped (unless some user has + // mapped in the file) + + // NOTE: The invocation to CcSetFileSizes() will quite possibly + // result in a recursive call back into the file system. + // This is because the NT Cache Manager will typically + // perform a flush before telling the VMM to purge pages + // especially when caching has not been initiated on the + // file stream, but the user has mapped the file into + // the process' virtual address space. + CcSetFileSizes(PtrFileObject, (PCC_FILE_SIZES)&(PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize)); + + // Inform any pending IRPs (notify change directory). + } + + } + finally + { + ; + } + return(RC); +} diff --git a/reactos/drivers/fs/ext2/src/flush.c b/reactos/drivers/fs/ext2/src/flush.c new file mode 100644 index 00000000000..fd25fa33899 --- /dev/null +++ b/reactos/drivers/fs/ext2/src/flush.c @@ -0,0 +1,350 @@ +/************************************************************************* +* +* File: flush.c +* +* Module: Ext2 File System Driver (Kernel mode execution only) +* +* Description: +* Contains code to handle the "Flush Buffers" dispatch entry point. +* +* Author: Manoj Paul Joseph +* +* +*************************************************************************/ + +#include "ext2fsd.h" + +// define the file specific bug-check id +#define EXT2_BUG_CHECK_ID EXT2_FILE_FLUSH + +#define DEBUG_LEVEL (DEBUG_TRACE_FLUSH) + + +/************************************************************************* +* +* Function: Ext2Flush() +* +* Description: +* The I/O Manager will invoke this routine to handle a flush buffers +* request +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution +* to be deferred to a worker thread context) +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +NTSTATUS Ext2Flush( + PDEVICE_OBJECT DeviceObject, // the logical volume device object + PIRP Irp) // I/O Request Packet +{ + NTSTATUS RC = STATUS_SUCCESS; + PtrExt2IrpContext PtrIrpContext = NULL; + BOOLEAN AreWeTopLevel = FALSE; + + DebugTrace(DEBUG_TRACE_IRP_ENTRY, "Flush IRP Received...", 0); + + // Ext2BreakPoint(); + + FsRtlEnterFileSystem(); + ASSERT(DeviceObject); + ASSERT(Irp); + + // set the top level context + AreWeTopLevel = Ext2IsIrpTopLevel(Irp); + + try + { + + // get an IRP context structure and issue the request + PtrIrpContext = Ext2AllocateIrpContext(Irp, DeviceObject); + ASSERT(PtrIrpContext); + + RC = Ext2CommonFlush(PtrIrpContext, Irp); + + } except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) { + + RC = Ext2ExceptionHandler(PtrIrpContext, Irp); + + Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); + } + + if (AreWeTopLevel) { + IoSetTopLevelIrp(NULL); + } + + FsRtlExitFileSystem(); + + return(RC); +} + + +/************************************************************************* +* +* Function: Ext2CommonFlush() +* +* Description: +* The actual work is performed here. This routine may be invoked in one' +* of the two possible contexts: +* (a) in the context of a system worker thread +* (b) in the context of the original caller +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +NTSTATUS Ext2CommonFlush( +PtrExt2IrpContext PtrIrpContext, +PIRP PtrIrp) +{ + NTSTATUS RC = STATUS_SUCCESS; + PIO_STACK_LOCATION PtrIoStackLocation = NULL; + PFILE_OBJECT PtrFileObject = NULL; + PtrExt2FCB PtrFCB = NULL; + PtrExt2CCB PtrCCB = NULL; + PtrExt2VCB PtrVCB = NULL; + PtrExt2NTRequiredFCB PtrReqdFCB = NULL; + BOOLEAN AcquiredFCB = FALSE; + BOOLEAN PostRequest = FALSE; + BOOLEAN CanWait = TRUE; + + try { + // First, get a pointer to the current I/O stack location + PtrIoStackLocation = IoGetCurrentIrpStackLocation(PtrIrp); + ASSERT(PtrIoStackLocation); + + PtrFileObject = PtrIoStackLocation->FileObject; + ASSERT(PtrFileObject); + + // Get the FCB and CCB pointers + PtrCCB = (PtrExt2CCB)(PtrFileObject->FsContext2); + ASSERT(PtrCCB); + PtrFCB = PtrCCB->PtrFCB; + AssertFCB( PtrFCB ); + + /*ASSERT(PtrFCB); + ASSERT(PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_FCB );*/ + + PtrReqdFCB = &(PtrFCB->NTRequiredFCB); + + // Get some of the parameters supplied to us + CanWait = ((PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_CAN_BLOCK) ? TRUE : FALSE); + + // If we cannot wait, post the request immediately since a flush is inherently blocking/synchronous. + if (!CanWait) { + PostRequest = TRUE; + try_return(RC); + } + + // Check the type of object passed-in. That will determine the course of + // action we take. + if ((PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB) || (PtrFCB->FCBFlags & EXT2_FCB_ROOT_DIRECTORY)) { + + if (PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB) { + PtrVCB = (PtrExt2VCB)(PtrFCB); + } else { + PtrVCB = PtrFCB->PtrVCB; + } + + // The caller wishes to flush all files for the mounted + // logical volume. The flush volume routine below should simply + // walk through all of the open file streams, acquire the + // FCB resource, and request the flush operation from the Cache + // Manager. Basically, the sequence of operations listed below + // for a single file should be executed on all open files. + + Ext2FlushLogicalVolume(PtrIrpContext, PtrIrp, PtrVCB); + + try_return(RC); + } + + if (!(PtrFCB->FCBFlags & EXT2_FCB_DIRECTORY)) + { + // This is a regular file. + ExAcquireResourceExclusiveLite(&(PtrReqdFCB->MainResource), TRUE); + AcquiredFCB = TRUE; + + // Request the Cache Manager to perform a flush operation. + // Further, instruct the Cache Manager that we wish to flush the + // entire file stream. + Ext2FlushAFile(PtrReqdFCB, &(PtrIrp->IoStatus)); + RC = PtrIrp->IoStatus.Status; + // All done. You may want to also flush the directory entry for the + // file stream at this time. + + // Some log-based FSD implementations may wish to flush their + // log files at this time. Finally, you should update the time-stamp + // values for the file stream appropriately. This would involve + // obtaining the current time and modifying the appropriate directory + // entry fields. + } + + try_exit: + + if (AcquiredFCB) + { + Ext2ReleaseResource(&(PtrReqdFCB->MainResource)); + DebugTrace(DEBUG_TRACE_MISC, "*** FCB Released [Flush]", 0); + DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [Flush]", + PtrReqdFCB->MainResource.ActiveCount, + PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, + PtrReqdFCB->MainResource.NumberOfSharedWaiters ); + + AcquiredFCB = FALSE; + } + + if (!PostRequest) + { + PIO_STACK_LOCATION PtrNextIoStackLocation = NULL; + NTSTATUS RC1 = STATUS_SUCCESS; + + // Send the request down at this point. + // To do this, you must set the next IRP stack location, and + // maybe set a completion routine. + // Be careful about marking the IRP pending if the lower level + // driver returned pending and you do have a completion routine! + PtrNextIoStackLocation = IoGetNextIrpStackLocation(PtrIrp); + *PtrNextIoStackLocation = *PtrIoStackLocation; + + // Set the completion routine to "eat-up" any + // STATUS_INVALID_DEVICE_REQUEST error code returned by the lower + // level driver. + IoSetCompletionRoutine(PtrIrp, Ext2FlushCompletion, NULL, TRUE, TRUE, TRUE); + + /* + * The exception handlers propably masked out the + * fact that PtrVCB was never set. + * -- Filip Navara, 18/08/2004 + */ + PtrVCB = PtrFCB->PtrVCB; + RC1 = IoCallDriver(PtrVCB->TargetDeviceObject, PtrIrp); + + RC = ((RC1 == STATUS_INVALID_DEVICE_REQUEST) ? RC : RC1); + } + + } finally { + if (PostRequest) { + // Nothing to lock now. + RC = Ext2PostRequest(PtrIrpContext, PtrIrp); + } else { + // Release the IRP context at this time. + Ext2ReleaseIrpContext(PtrIrpContext); + } + } + + return(RC); +} + +/************************************************************************* +* +* Function: Ext2FlushAFile() +* +* Description: +* Tell the Cache Manager to perform a flush. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: None +* +*************************************************************************/ +void Ext2FlushAFile( +PtrExt2NTRequiredFCB PtrReqdFCB, +PIO_STATUS_BLOCK PtrIoStatus) +{ + CcFlushCache(&(PtrReqdFCB->SectionObject), NULL, 0, PtrIoStatus); + return; +} + +/************************************************************************* +* +* Function: Ext2FlushLogicalVolume() +* +* Description: +* Flush everything beginning at root directory. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: None +* +*************************************************************************/ +void Ext2FlushLogicalVolume( +PtrExt2IrpContext PtrIrpContext, +PIRP PtrIrp, +PtrExt2VCB PtrVCB) +{ + BOOLEAN AcquiredVCB = FALSE; + PtrExt2FCB PtrFCB = NULL; + PLIST_ENTRY PtrNextFCB = NULL; + + try { + ExAcquireResourceExclusiveLite(&(PtrVCB->VCBResource), TRUE); + + AcquiredVCB = TRUE; + DebugTrace(DEBUG_TRACE_MISC, "*** VCB Acquired Ex [Flush] ", 0); + + // Go through the list of FCB's. You would probably + // flush all of the files. Then, you could flush the + // directories that you may have have pinned into memory. + + // NOTE: This function may also be invoked internally as part of + // processing a shutdown request. + + } + finally + { + if (AcquiredVCB) + { + Ext2ReleaseResource(&(PtrVCB->VCBResource)); + DebugTrace(DEBUG_TRACE_MISC, "*** VCB Released [Flush]", 0); + DebugTraceState( "VCB AC:0x%LX SW:0x%LX EX:0x%LX [Flush]", + PtrVCB->VCBResource.ActiveCount, + PtrVCB->VCBResource.NumberOfExclusiveWaiters, + PtrVCB->VCBResource.NumberOfSharedWaiters ); + } + } + + return; +} + + +/************************************************************************* +* +* Function: Ext2FlushCompletion() +* +* Description: +* Eat up any bad errors. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: None +* +*************************************************************************/ +NTSTATUS Ext2FlushCompletion( +PDEVICE_OBJECT PtrDeviceObject, +PIRP PtrIrp, +PVOID Context) +{ + NTSTATUS RC = STATUS_SUCCESS; + + if (PtrIrp->PendingReturned) { + IoMarkIrpPending(PtrIrp); + } + + if (PtrIrp->IoStatus.Status == STATUS_INVALID_DEVICE_REQUEST) { + // cannot do much here, can we? + PtrIrp->IoStatus.Status = STATUS_SUCCESS; + } + + return(STATUS_SUCCESS); +} diff --git a/reactos/drivers/fs/ext2/src/fsctrl.c b/reactos/drivers/fs/ext2/src/fsctrl.c new file mode 100644 index 00000000000..8c4afe3354a --- /dev/null +++ b/reactos/drivers/fs/ext2/src/fsctrl.c @@ -0,0 +1,944 @@ +/************************************************************************* +* +* File: fsctrl.c +* +* Module: Ext2 File System Driver (Kernel mode execution only) +* +* Description: +* Contains code to handle the various File System Control calls. +* +* Author: Manoj Paul Joseph +* +* +*************************************************************************/ + + + +#include "ext2fsd.h" + + + +// define the file specific bug-check id +#define EXT2_BUG_CHECK_ID EXT2_FILE_FILE_CONTROL +#define DEBUG_LEVEL (DEBUG_TRACE_FSCTRL) + + +NTSTATUS +Ext2MountVolume( + IN PIRP Irp, + IN PIO_STACK_LOCATION IrpSp ); + +NTSTATUS +Ext2GetPartitionInfo( + IN PDEVICE_OBJECT TargetDeviceObject, + IN PPARTITION_INFORMATION PartitionInformation + ); + +NTSTATUS +Ext2GetDriveLayout( + IN PDEVICE_OBJECT TargetDeviceObject, + IN PDRIVE_LAYOUT_INFORMATION DriveLayoutInformation, + IN int BufferSize + ); + +BOOLEAN +Ext2PerformVerifyDiskRead( + IN PDEVICE_OBJECT TargetDeviceObject, + IN PVOID Buffer, + IN LONGLONG Lbo, + IN ULONG NumberOfBytesToRead + ); + +NTSTATUS Ext2UserFileSystemRequest( + IN PIRP Irp, + IN PIO_STACK_LOCATION IrpSp ); + + +/************************************************************************* +* +* Function: Ext2FileSystemControl +* +* Description: +* The I/O Manager will invoke this routine to handle a +* File System Control IRP +* +* Expected Interrupt Level (for execution) : +* +* ??? +* +* Arguments: +* +* DeviceObject - Supplies the volume device object where the +* file exists +* +* Irp - Supplies the Irp being processed +* +* +* Return Value: +* +* NTSTATUS - The FSD status for the IRP +* +*************************************************************************/ +NTSTATUS +Ext2FileSystemControl( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp + ) +{ + + NTSTATUS Status = STATUS_SUCCESS; + PIO_STACK_LOCATION IrpSp; + + DebugTrace(DEBUG_TRACE_IRP_ENTRY, "File System Control IRP Received...", 0); + + // Ext2BreakPoint(); + + FsRtlEnterFileSystem(); + + ASSERT(DeviceObject); + ASSERT(Irp); + + // + // Get a pointer to the current Irp stack location + // + IrpSp = IoGetCurrentIrpStackLocation( Irp ); + + + if( IrpSp->MinorFunction == IRP_MN_MOUNT_VOLUME ) + { + DebugTrace(DEBUG_TRACE_MOUNT, "Mount Request Received...", 0); + Status = Ext2MountVolume ( Irp, IrpSp ); + Ext2CompleteRequest( Irp, Status ); + } + else if( IrpSp->MinorFunction == IRP_MN_USER_FS_REQUEST ) + { + DebugTrace(DEBUG_TRACE_FSCTRL, "IRP_MN_USER_FS_REQUEST received...", 0); + Status = Ext2UserFileSystemRequest( Irp, IrpSp ); + Ext2CompleteRequest( Irp, Status ); + } + else + { + if( IrpSp->MinorFunction == IRP_MN_VERIFY_VOLUME ) + { + DebugTrace(DEBUG_TRACE_FSCTRL, "IRP_MN_VERIFY_VOLUME received...", 0); + } + else if( IrpSp->MinorFunction == IRP_MN_LOAD_FILE_SYSTEM ) + { + DebugTrace(DEBUG_TRACE_FSCTRL, "IRP_MN_LOAD_FILE_SYSTEM received...", 0); + } + else + { + DebugTrace(DEBUG_TRACE_FSCTRL, "Unknown Minor IRP code received...", 0); + } + + Status = STATUS_INVALID_DEVICE_REQUEST; + Ext2CompleteRequest( Irp, Status ); + } + + FsRtlExitFileSystem(); + + return Status; +} + + + +/************************************************************************* +* +* Function: Ext2MountVolume() +* +* Description: +* This routine verifies and mounts the volume; +* Called by FSCTRL IRP handler to attempt a +* volume mount. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* +* Arguments: +* +* Irp - Supplies the Irp being processed +* IrpSp - Irp Stack Location pointer +* +* Return Value: +* +* NTSTATUS - The Mount status +* +*************************************************************************/ +NTSTATUS +Ext2MountVolume ( + IN PIRP Irp, + IN PIO_STACK_LOCATION IrpSp ) +{ + + // Volume Parameter Block + PVPB PtrVPB; + + // The target device object + PDEVICE_OBJECT TargetDeviceObject = NULL; + + // The new volume device object (to be created if partition is Ext2) + PDEVICE_OBJECT PtrVolumeDeviceObject = NULL; + + // Return Status + NTSTATUS Status = STATUS_UNRECOGNIZED_VOLUME; + + // Number of bytes to read for Volume verification... + unsigned long NumberOfBytesToRead = 0; + + // Starting Offset for 'read' + LONGLONG StartingOffset = 0; + + // Boot Sector information... + PPACKED_BOOT_SECTOR BootSector = NULL; + + // Ext2 Super Block information... + PEXT2_SUPER_BLOCK SuperBlock = NULL; + + // Volume Control Block + PtrExt2VCB PtrVCB = NULL; + + // The File Object for the root directory + PFILE_OBJECT PtrRootFileObject = NULL; + + // Flag + int WeClearedVerifyRequiredBit; + + // Used by a for loop... + unsigned int i; + + // + LARGE_INTEGER VolumeByteOffset; + + unsigned long LogicalBlockSize = 0; + + // Buffer Control Block + PBCB PtrBCB = NULL; + + // Cache Buffer - used for pinned access of volume... + PVOID PtrCacheBuffer = NULL; + + PEXT2_GROUP_DESCRIPTOR PtrGroupDescriptor = NULL; + + PEXT2_INODE PtrInode = NULL; + + // Inititalising variables + + PtrVPB = IrpSp->Parameters.MountVolume.Vpb; + TargetDeviceObject = IrpSp->Parameters.MountVolume.DeviceObject; + + try + { + // + // 1. Reading in Volume meta data + // + + // Temporarily clear the DO_VERIFY_VOLUME Flag + WeClearedVerifyRequiredBit = 0; + if ( Ext2IsFlagOn( PtrVPB->RealDevice->Flags, DO_VERIFY_VOLUME ) ) + { + Ext2ClearFlag( PtrVPB->RealDevice->Flags, DO_VERIFY_VOLUME ); + WeClearedVerifyRequiredBit = 1; + } + + // Allocating memory for reading in Boot Sector... + NumberOfBytesToRead = Ext2Align( sizeof( EXT2_SUPER_BLOCK ), TargetDeviceObject->SectorSize ); + BootSector = Ext2AllocatePool( PagedPool, NumberOfBytesToRead ); + RtlZeroMemory( BootSector, NumberOfBytesToRead ); + + // Reading in Boot Sector + StartingOffset = 0L; + Ext2PerformVerifyDiskRead ( TargetDeviceObject, + BootSector, StartingOffset, NumberOfBytesToRead ); + + // Allocating memory for reading in Super Block... + + SuperBlock = Ext2AllocatePool( PagedPool, NumberOfBytesToRead ); + RtlZeroMemory( SuperBlock, NumberOfBytesToRead ); + StartingOffset = 1024; + + // Reading in the Super Block... + Ext2PerformVerifyDiskRead ( TargetDeviceObject, + SuperBlock, StartingOffset, NumberOfBytesToRead ); + + // Resetting the DO_VERIFY_VOLUME Flag + if( WeClearedVerifyRequiredBit ) + { + PtrVPB->RealDevice->Flags |= DO_VERIFY_VOLUME; + } + + // Verifying the Super Block.. + if( SuperBlock->s_magic == EXT2_SUPER_MAGIC ) + { + // + // Found a valid super block. + // No more tests for now. + // Assuming that this is an ext2 partition... + // Going ahead with mount. + // + DebugTrace(DEBUG_TRACE_MOUNT, "Valid Ext2 partition detected\nMounting %s...", SuperBlock->s_volume_name); + // + // 2. Creating a volume device object + // + if (!NT_SUCCESS( IoCreateDevice( + Ext2GlobalData.Ext2DriverObject, // (This) Driver object + Ext2QuadAlign( sizeof(Ext2VCB) ), // Device Extension + NULL, // Device Name - no name ;) + FILE_DEVICE_DISK_FILE_SYSTEM, // Disk File System + 0, // DeviceCharacteristics + FALSE, // Not an exclusive device + (PDEVICE_OBJECT *)&PtrVolumeDeviceObject)) // The Volume Device Object + ) + { + try_return( Status ); + } + + // + // Our alignment requirement is the larger of the processor alignment requirement + // already in the volume device object and that in the TargetDeviceObject + // + + if (TargetDeviceObject->AlignmentRequirement > PtrVolumeDeviceObject->AlignmentRequirement) + { + PtrVolumeDeviceObject->AlignmentRequirement = TargetDeviceObject->AlignmentRequirement; + } + + // + // Clearing the Device Initialising Flag + // + Ext2ClearFlag( PtrVolumeDeviceObject->Flags, DO_DEVICE_INITIALIZING); + + + // + // Setting the Stack Size for the newly created Volume Device Object + // + PtrVolumeDeviceObject->StackSize = (CCHAR)(TargetDeviceObject->StackSize + 1); + + + // + // 3. Creating the link between Target Device Object + // and the Volume Device Object via the Volume Parameter Block + // + PtrVPB->DeviceObject = PtrVolumeDeviceObject; + + // Remembring the Volume parameters in the VPB bock + for( i = 0; i < 16 ; i++ ) + { + PtrVPB->VolumeLabel[i] = SuperBlock->s_volume_name[i]; + if( SuperBlock->s_volume_name[i] == 0 ) + break; + } + PtrVPB->VolumeLabelLength = i * 2; + PtrVPB->SerialNumber = ((ULONG*)SuperBlock->s_uuid)[0]; + + // + // 4. Initialise the Volume Comtrol Block + // + { + LARGE_INTEGER AllocationSize; + + AllocationSize .QuadPart = + ( EXT2_MIN_BLOCK_SIZE << SuperBlock->s_log_block_size ) * + SuperBlock->s_blocks_count; + + Ext2InitializeVCB( + PtrVolumeDeviceObject, + TargetDeviceObject, + PtrVPB, + &AllocationSize); + PtrVCB = (PtrExt2VCB)(PtrVolumeDeviceObject->DeviceExtension); + ASSERT( PtrVCB ); + } + + PtrVCB->InodesCount = SuperBlock->s_inodes_count; + PtrVCB->BlocksCount = SuperBlock->s_blocks_count; + PtrVCB->ReservedBlocksCount = SuperBlock->s_r_blocks_count; + PtrVCB->FreeBlocksCount = SuperBlock->s_free_blocks_count; + PtrVCB->FreeInodesCount = SuperBlock->s_free_inodes_count; + PtrVCB->LogBlockSize = SuperBlock->s_log_block_size; + PtrVCB->InodesPerGroup = SuperBlock->s_inodes_per_group; + PtrVCB->BlocksPerGroup = SuperBlock->s_blocks_per_group; + PtrVCB->NoOfGroups = ( SuperBlock->s_blocks_count - SuperBlock->s_first_data_block + + SuperBlock->s_blocks_per_group - 1 ) + / SuperBlock->s_blocks_per_group; + + PtrVCB->PtrGroupDescriptors = Ext2AllocatePool( NonPagedPool, sizeof( Ext2GroupDescriptors ) * PtrVCB->NoOfGroups ); + + RtlZeroMemory( PtrVCB->PtrGroupDescriptors , sizeof( Ext2GroupDescriptors ) * PtrVCB->NoOfGroups ); + + // + // Attempting to Read in some matadata from the Cache... + // using pin access... + // + LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize; + + // + // Reading Group Descriptors... + // + if( PtrVCB->LogBlockSize ) + { + // First block contains the descriptors... + VolumeByteOffset.QuadPart = LogicalBlockSize; + } + else + { + // Second block contains the descriptors... + VolumeByteOffset.QuadPart = LogicalBlockSize * 2; + } + + NumberOfBytesToRead = PtrVCB->NoOfGroups * sizeof( struct ext2_group_desc ); + NumberOfBytesToRead = Ext2Align( NumberOfBytesToRead, LogicalBlockSize ); + + if (!CcMapData( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + NumberOfBytesToRead, + TRUE, + &PtrBCB, + &PtrCacheBuffer )) + { + DebugTrace(DEBUG_TRACE_ERROR, "Cache read failiure while reading in volume meta data", 0); + try_return( Status = STATUS_INSUFFICIENT_RESOURCES ); + } + else + { + // + // Saving up Often Used Group Descriptor Information in the VCB... + // + unsigned int DescIndex ; + + DebugTrace(DEBUG_TRACE_MISC, "Cache hit while reading in volume meta data", 0); + PtrGroupDescriptor = (PEXT2_GROUP_DESCRIPTOR )PtrCacheBuffer; + for( DescIndex = 0; DescIndex < PtrVCB->NoOfGroups; DescIndex++ ) + { + PtrVCB->PtrGroupDescriptors[ DescIndex ].InodeTablesBlock + = PtrGroupDescriptor[ DescIndex ].bg_inode_table; + + PtrVCB->PtrGroupDescriptors[ DescIndex ].InodeBitmapBlock + = PtrGroupDescriptor[ DescIndex ].bg_inode_bitmap + ; + PtrVCB->PtrGroupDescriptors[ DescIndex ].BlockBitmapBlock + = PtrGroupDescriptor[ DescIndex ].bg_block_bitmap + ; + PtrVCB->PtrGroupDescriptors[ DescIndex ].FreeBlocksCount + = PtrGroupDescriptor[ DescIndex ].bg_free_blocks_count; + + PtrVCB->PtrGroupDescriptors[ DescIndex ].FreeInodesCount + = PtrGroupDescriptor[ DescIndex ].bg_free_inodes_count; + } + CcUnpinData( PtrBCB ); + PtrBCB = NULL; + } + + // + // 5. Creating a Root Directory FCB + // + PtrRootFileObject = IoCreateStreamFileObject(NULL, TargetDeviceObject ); + if( !PtrRootFileObject ) + { + try_return( Status ); + } + // + // Associate the file stream with the Volume parameter block... + // I do it now + // + PtrRootFileObject->Vpb = PtrVCB->PtrVPB; + + PtrRootFileObject->ReadAccess = TRUE; + PtrRootFileObject->WriteAccess = TRUE; + + { + PtrExt2ObjectName PtrObjectName; + LARGE_INTEGER ZeroSize; + + PtrObjectName = Ext2AllocateObjectName(); + RtlInitUnicodeString( &PtrObjectName->ObjectName, L"\\" ); + Ext2CopyWideCharToUnicodeString( &PtrObjectName->ObjectName, L"\\" ); + + + ZeroSize.QuadPart = 0; + if ( !NT_SUCCESS( Ext2CreateNewFCB( + &PtrVCB->PtrRootDirectoryFCB, // Root FCB + ZeroSize, // AllocationSize, + ZeroSize, // EndOfFile, + PtrRootFileObject, // The Root Dircetory File Object + PtrVCB, + PtrObjectName ) ) ) + { + try_return( Status ); + } + + + PtrVCB->PtrRootDirectoryFCB->FCBFlags |= EXT2_FCB_DIRECTORY | EXT2_FCB_ROOT_DIRECTORY; + + + } + + PtrVCB->PtrRootDirectoryFCB->DcbFcb.Dcb.PtrDirFileObject = PtrRootFileObject; + PtrVCB->PtrRootDirectoryFCB->INodeNo = EXT2_ROOT_INO; + PtrRootFileObject->SectionObjectPointer = &(PtrVCB->PtrRootDirectoryFCB->NTRequiredFCB.SectionObject); + RtlInitUnicodeString( &PtrRootFileObject->FileName, L"\\" ); + + Ext2InitializeFCBInodeInfo( PtrVCB->PtrRootDirectoryFCB ); + + // + // Initiating caching for root directory... + // + + CcInitializeCacheMap(PtrRootFileObject, + (PCC_FILE_SIZES)(&(PtrVCB->PtrRootDirectoryFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize)), + TRUE, // We will utilize pin access for directories + &(Ext2GlobalData.CacheMgrCallBacks), // callbacks + PtrVCB->PtrRootDirectoryFCB ); // The context used in callbacks + + + // + // 6. Update the VCB Flags + // + PtrVCB->VCBFlags |= EXT2_VCB_FLAGS_VOLUME_MOUNTED ; // | EXT2_VCB_FLAGS_VOLUME_READ_ONLY; + + + // + // 7. Mount Success + // + Status = STATUS_SUCCESS; + + { + // + // This block is for testing.... + // To be removed... + + /* + EXT2_INODE Inode ; + Ext2ReadInode( PtrVCB, 100, &Inode ); + DebugTrace( DEBUG_TRACE_MISC, "Inode size= %lX [FS Ctrl]", Inode.i_size ); + Ext2DeallocInode( NULL, PtrVCB, 0xfb6 ); + */ + } + + // ObDereferenceObject( TargetDeviceObject ); + } + else + { + DebugTrace(DEBUG_TRACE_MOUNT, "Failing mount. Partition not Ext2...", 0); + } + + try_exit: NOTHING; + } + finally + { + // Freeing Allocated Memory... + if( SuperBlock != NULL ) + { + DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [FS Ctrl]", SuperBlock ); + ExFreePool( SuperBlock ); + } + if( BootSector != NULL ) + { + DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [FS Ctrl]", BootSector); + ExFreePool( BootSector ); + } + + // start unwinding if we were unsuccessful + if (!NT_SUCCESS( Status )) + { + + } + } + + return Status; +} + +/************************************************************************* +* +* Function: Ext2MountVolume() +* +* Description: +* This routine is used for querying the partition information. +* +* Expected Interrupt Level (for execution) : +* IRQL_PASSIVE_LEVEL +* +* Arguments: +* +* TargetDeviceObject - The target of the query +* PartitionInformation - Receives the result of the query +* +* Return Value: +* +* NTSTATUS - The return status for the operation +* +*************************************************************************/ +NTSTATUS +Ext2GetPartitionInfo ( + IN PDEVICE_OBJECT TargetDeviceObject, + IN PPARTITION_INFORMATION PartitionInformation + ) +{ + PIRP Irp; + KEVENT *PtrEvent = NULL; + NTSTATUS Status; + IO_STATUS_BLOCK Iosb; + + // + // Query the partition table + // + PtrEvent = ( KEVENT * )Ext2AllocatePool( NonPagedPool, Ext2QuadAlign( sizeof( KEVENT ) ) ); + + + + + KeInitializeEvent( PtrEvent, NotificationEvent, FALSE ); + + Irp = IoBuildDeviceIoControlRequest( IOCTL_DISK_GET_PARTITION_INFO, + TargetDeviceObject, + NULL, + 0, + PartitionInformation, + sizeof(PARTITION_INFORMATION), + FALSE, + PtrEvent, + &Iosb ); + + if ( Irp == NULL ) + { + DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [FS Ctrl]", PtrEvent); + ExFreePool( PtrEvent ); + return 0; + } + + Status = IoCallDriver( TargetDeviceObject, Irp ); + + if ( Status == STATUS_PENDING ) { + + (VOID) KeWaitForSingleObject( PtrEvent, + Executive, + KernelMode, + FALSE, + (PLARGE_INTEGER)NULL ); + + Status = Iosb.Status; + } + DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [FS Ctrl]", PtrEvent); + ExFreePool( PtrEvent ); + return Status; +} + +/************************************************************************* +* +* Function: Ext2MountVolume() +* +* Description: +* This routine is used for querying the Drive Layout Information. +* +* Expected Interrupt Level (for execution) : +* IRQL_PASSIVE_LEVEL +* +* Arguments: +* +* TargetDeviceObject - The target of the query +* PartitionInformation - Receives the result of the query +* +* Return Value: +* +* NTSTATUS - The return status for the operation +* +*************************************************************************/ +NTSTATUS Ext2GetDriveLayout ( + IN PDEVICE_OBJECT TargetDeviceObject, + IN PDRIVE_LAYOUT_INFORMATION DriveLayoutInformation, + IN int BufferSize + ) +{ + PIRP Irp; + KEVENT *PtrEvent = NULL; + NTSTATUS Status; + IO_STATUS_BLOCK Iosb; + + // + // Query the partition table + // + PtrEvent = ( KEVENT * )Ext2AllocatePool( NonPagedPool, Ext2QuadAlign( sizeof( KEVENT ) ) ); + KeInitializeEvent( PtrEvent, NotificationEvent, FALSE ); + Irp = IoBuildDeviceIoControlRequest( IOCTL_DISK_GET_DRIVE_LAYOUT, + TargetDeviceObject, + NULL, + 0, + DriveLayoutInformation, + BufferSize, + FALSE, + PtrEvent, + &Iosb ); + + if ( Irp == NULL ) + { + DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [FS Ctrl]", PtrEvent); + ExFreePool( PtrEvent ); + return 0; + } + + Status = IoCallDriver( TargetDeviceObject, Irp ); + + if ( Status == STATUS_PENDING ) { + + (VOID) KeWaitForSingleObject( PtrEvent, + Executive, + KernelMode, + FALSE, + (PLARGE_INTEGER)NULL ); + + Status = Iosb.Status; + } + DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [FS Ctrl]", PtrEvent); + ExFreePool( PtrEvent ); + return Status; +} + + +/************************************************************************* +* +* Function: Ext2MountVolume() +* +* Description: +* This routine is used for performing a verify read... +* +* Expected Interrupt Level (for execution) : +* IRQL_PASSIVE_LEVEL +* +* Arguments: +* TargetDeviceObject - The target of the query +* PartitionInformation - Receives the result of the query +* +* Return Value: +* NTSTATUS - The return status for the operation +* +*************************************************************************/ +BOOLEAN Ext2PerformVerifyDiskRead( + IN PDEVICE_OBJECT TargetDeviceObject, + IN PVOID Buffer, + IN LONGLONG Lbo, + IN ULONG NumberOfBytesToRead ) +{ + KEVENT Event; + PIRP Irp; + LARGE_INTEGER ByteOffset; + NTSTATUS Status; + IO_STATUS_BLOCK Iosb; + + // + // Initialize the event we're going to use + // + KeInitializeEvent( &Event, NotificationEvent, FALSE ); + + // + // Build the irp for the operation + // + ByteOffset.QuadPart = Lbo; + Irp = IoBuildSynchronousFsdRequest( IRP_MJ_READ, + TargetDeviceObject, + Buffer, + NumberOfBytesToRead, + &ByteOffset, + &Event, + &Iosb ); + + if ( Irp == NULL ) + { + Status = FALSE; + } + + Ext2SetFlag( IoGetNextIrpStackLocation( Irp )->Flags, SL_OVERRIDE_VERIFY_VOLUME ); + + // + // Call the device to do the read and wait for it to finish. + // + Status = IoCallDriver( TargetDeviceObject, Irp ); + if (Status == STATUS_PENDING) + { + (VOID)KeWaitForSingleObject( &Event, Executive, KernelMode, FALSE, (PLARGE_INTEGER)NULL ); + Status = Iosb.Status; + } + + ASSERT(Status != STATUS_VERIFY_REQUIRED); + + // + // Special case this error code because this probably means we used + // the wrong sector size and we want to reject STATUS_WRONG_VOLUME. + // + + if (Status == STATUS_INVALID_PARAMETER) + { + + return FALSE; + } + + // + // If it doesn't succeed then either return or raise the error. + // + + if (!NT_SUCCESS(Status)) + { + return FALSE; + } + + // + // And return to our caller + // + return TRUE; +} + +/************************************************************************* +* +* Function: Ext2UserFileSystemRequest() +* +* Description: +* This routine handles User File System Requests +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* +* Arguments: +* +* Irp - Supplies the Irp being processed +* IrpSp - Irp Stack Location pointer +* +* Return Value: NT_STATUS +* +*************************************************************************/ +NTSTATUS Ext2UserFileSystemRequest ( + IN PIRP Irp, + IN PIO_STACK_LOCATION IrpSp ) +{ + NTSTATUS Status = STATUS_INVALID_DEVICE_REQUEST; + ULONG FsControlCode; + + IrpSp = IoGetCurrentIrpStackLocation( Irp ); + + try + { +#ifdef _GNU_NTIFS_ + FsControlCode = ((PEXTENDED_IO_STACK_LOCATION)IrpSp)->Parameters.FileSystemControl.FsControlCode; +#else + FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode; +#endif + + switch ( FsControlCode ) + { + + case FSCTL_REQUEST_OPLOCK_LEVEL_1: + DebugTrace(DEBUG_TRACE_FSCTRL, "FSCTL_REQUEST_OPLOCK_LEVEL_1", 0); + break; + case FSCTL_REQUEST_OPLOCK_LEVEL_2: + DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL ", 0); + break; + case FSCTL_REQUEST_BATCH_OPLOCK: + DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL_REQUEST_OPLOCK_LEVEL_2 ", 0); + break; + case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE: + DebugTrace(DEBUG_TRACE_MISC, " FSCTL_OPLOCK_BREAK_ACKNOWLEDGE ", 0); + break; + case FSCTL_OPBATCH_ACK_CLOSE_PENDING: + DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL_OPBATCH_ACK_CLOSE_PENDING ", 0); + break; + case FSCTL_OPLOCK_BREAK_NOTIFY: + DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL_OPLOCK_BREAK_NOTIFY ", 0); + break; + case FSCTL_OPLOCK_BREAK_ACK_NO_2: + DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL_OPLOCK_BREAK_ACK_NO_2 ", 0); + break; + case FSCTL_LOCK_VOLUME: + DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL_LOCK_VOLUME ", 0); + break; + case FSCTL_UNLOCK_VOLUME: + DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL_UNLOCK_VOLUME ", 0); + break; + case FSCTL_DISMOUNT_VOLUME: + DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL_DISMOUNT_VOLUME ", 0); + break; + case FSCTL_MARK_VOLUME_DIRTY: + DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL_MARK_VOLUME_DIRTY ", 0); + break; + case FSCTL_IS_VOLUME_DIRTY: + DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL_IS_VOLUME_DIRTY ", 0); + break; + case FSCTL_IS_VOLUME_MOUNTED: + Status = Ext2VerifyVolume(Irp, IrpSp ); + DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL_IS_VOLUME_MOUNTED ", 0); + break; + case FSCTL_IS_PATHNAME_VALID: + DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL_IS_PATHNAME_VALID ", 0); + break; + case FSCTL_QUERY_RETRIEVAL_POINTERS: + DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL_QUERY_RETRIEVAL_POINTERS ", 0); + break; + case FSCTL_QUERY_FAT_BPB: + DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL_QUERY_FAT_BPB ", 0); + break; + case FSCTL_FILESYSTEM_GET_STATISTICS: + DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL_FILESYSTEM_GET_STATISTICS ", 0); + break; + case FSCTL_GET_VOLUME_BITMAP: + DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL_GET_VOLUME_BITMAP ", 0); + break; + case FSCTL_GET_RETRIEVAL_POINTERS: + DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL_GET_RETRIEVAL_POINTERS ", 0); + break; + case FSCTL_MOVE_FILE: + DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL_MOVE_FILE ", 0); + break; + case FSCTL_ALLOW_EXTENDED_DASD_IO: + DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL_ALLOW_EXTENDED_DASD_IO ", 0); + break; + default : + DebugTrace(DEBUG_TRACE_FSCTRL, "Unknown FSCTRL !!!", 0); + + } + + try_exit: NOTHING; + } + finally + { + + } + return Status; +} + + + +NTSTATUS Ext2VerifyVolume ( + IN PIRP Irp, + IN PIO_STACK_LOCATION IrpSp ) +{ + + PVPB PtrVPB; + + PtrVPB = IrpSp->Parameters.VerifyVolume.Vpb; + if( IrpSp->FileObject ) + { + PtrVPB = IrpSp->FileObject->Vpb; + } + if( !PtrVPB ) + { + PtrVPB = IrpSp->Parameters.VerifyVolume.Vpb; + } + + if( !PtrVPB ) + { + return STATUS_WRONG_VOLUME; + } + + + if ( Ext2IsFlagOn( PtrVPB->RealDevice->Flags, DO_VERIFY_VOLUME ) ) + { + // + // Not doing a verify! + // Just acting as if everyting is fine! + // THis should do for now + // + Ext2ClearFlag( PtrVPB->RealDevice->Flags, DO_VERIFY_VOLUME ); + + } + return STATUS_SUCCESS; +} diff --git a/reactos/drivers/fs/ext2/src/io.c b/reactos/drivers/fs/ext2/src/io.c new file mode 100644 index 00000000000..d4fba6f576a --- /dev/null +++ b/reactos/drivers/fs/ext2/src/io.c @@ -0,0 +1,543 @@ +/************************************************************************* +* +* File: io.c +* +* Module: Ext2 File System Driver (Kernel mode execution only) +* +* Description: +* This file contains low level disk io routines. +* +* Author: Manoj Paul Joseph +* +* +*************************************************************************/ + +#include "ext2fsd.h" + +// define the file specific bug-check id +#define EXT2_BUG_CHECK_ID EXT2_FILE_IO + +/************************************************************************* +* +* Function: Ext2PassDownMultiReadWriteIRP() +* +* Description: +* pass down multiple read IRPs as Associated IRPs +* +* Expected Interrupt Level (for execution) : +* +* ? +* +* Return Value: STATUS_SUCCESS / STATUS_PENDING / Error +* +*************************************************************************/ +NTSTATUS Ext2PassDownMultiReadWriteIRP( + PEXT2_IO_RUN PtrIoRuns, + UINT Count, + ULONG TotalReadWriteLength, + PtrExt2IrpContext PtrIrpContext, + PtrExt2FCB PtrFCB, + BOOLEAN SynchronousIo) +{ + PIRP PtrMasterIrp; + PIRP PtrAssociatedIrp; + PIO_STACK_LOCATION PtrIrpSp; + PMDL PtrMdl; + PtrExt2VCB PtrVCB; + UINT i; + ULONG BufferOffset; + PEXT2_IO_CONTEXT PtrIoContext = NULL; + PKEVENT PtrSyncEvent = NULL; + ULONG LogicalBlockSize; + ULONG ReadWriteLength; + + NTSTATUS RC = STATUS_SUCCESS; + + PtrVCB = PtrFCB->PtrVCB; + PtrMasterIrp = PtrIrpContext->Irp; + LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize; + + try + { + if( !SynchronousIo ) + { + IoMarkIrpPending( PtrIrpContext->Irp ); + // We will be returning STATUS_PENDING... + } + + if( !PtrMasterIrp->MdlAddress ) + { + Ext2LockCallersBuffer( PtrMasterIrp, TRUE, TotalReadWriteLength ); + } + + if( SynchronousIo ) + { + PtrSyncEvent = Ext2AllocatePool(NonPagedPool, Ext2QuadAlign( sizeof(KEVENT) ) ); + if ( !PtrSyncEvent ) + { + RC = STATUS_INSUFFICIENT_RESOURCES; + try_return ( RC ); + } + KeInitializeEvent( PtrSyncEvent, SynchronizationEvent, FALSE ); + } + // + // Allocate and initialize a completion context + // + PtrIoContext = Ext2AllocatePool(NonPagedPool, Ext2QuadAlign( sizeof(EXT2_IO_CONTEXT) ) ); + if ( !PtrIoContext ) + { + RC = STATUS_INSUFFICIENT_RESOURCES; + try_return ( RC ); + } + + RtlZeroMemory( PtrIoContext, sizeof(EXT2_IO_CONTEXT) ); + PtrIoContext->Count = Count; + PtrIoContext->NodeIdentifier.NodeType = EXT2_NODE_TYPE_IO_CONTEXT; + PtrIoContext->NodeIdentifier.NodeSize = sizeof( EXT2_IO_CONTEXT ); + PtrIoContext->PtrMasterIrp = PtrMasterIrp; + PtrIoContext->PtrSyncEvent = PtrSyncEvent; + PtrIoContext->ReadWriteLength = TotalReadWriteLength; + + + + for( ReadWriteLength = 0, BufferOffset = 0, i = 0; i < Count; i++, BufferOffset += ReadWriteLength ) + { + + ReadWriteLength = PtrIoRuns[ i].EndOffset - PtrIoRuns[ i].StartOffset; + + // + // Allocating an Associated IRP... + // + PtrAssociatedIrp = IoMakeAssociatedIrp( PtrMasterIrp, + (CCHAR) (PtrVCB->TargetDeviceObject->StackSize + 1 ) ); + PtrIoRuns[ i].PtrAssociatedIrp = PtrAssociatedIrp; + ASSERT ( PtrAssociatedIrp ); + PtrMasterIrp->AssociatedIrp.IrpCount ++; + + // + // Allocating a Memory Descriptor List... + // + PtrMdl = IoAllocateMdl( (PCHAR) PtrMasterIrp->UserBuffer + BufferOffset, // Virtual Address + ReadWriteLength, FALSE, FALSE, PtrAssociatedIrp ); + + // + // and building a partial MDL... + // + IoBuildPartialMdl( PtrMasterIrp->MdlAddress, + PtrMdl, (PCHAR)PtrMasterIrp->UserBuffer + BufferOffset, ReadWriteLength ); + + // + // Create an Irp stack location for ourselves... + // + IoSetNextIrpStackLocation( PtrAssociatedIrp ); + PtrIrpSp = IoGetCurrentIrpStackLocation( PtrAssociatedIrp ); + + // + // Setup the Stack location to describe our read. + // + PtrIrpSp->MajorFunction = PtrIrpContext->MajorFunction; + if( PtrIrpContext->MajorFunction == IRP_MJ_READ ) + { + PtrIrpSp->Parameters.Read.Length = ReadWriteLength; + PtrIrpSp->Parameters.Read.ByteOffset.QuadPart = + PtrIoRuns[i].LogicalBlock * ( LogicalBlockSize ); + } + else if( PtrIrpContext->MajorFunction == IRP_MJ_WRITE ) + { + PtrIrpSp->Parameters.Write.Length = ReadWriteLength; + PtrIrpSp->Parameters.Write.ByteOffset.QuadPart = + PtrIoRuns[i].LogicalBlock * ( LogicalBlockSize ); + } + + // PtrIrpSp->Parameters.Read.Length = ReadWriteLength; + // PtrIrpSp->Parameters.Read.ByteOffset.QuadPart = PtrIoRuns[i].LogicalBlock; + + + // + // Setup a completion routine... + // + IoSetCompletionRoutine( PtrAssociatedIrp, + SynchronousIo ? + Ext2MultiSyncCompletionRoutine : + Ext2MultiAsyncCompletionRoutine, + PtrIoContext, TRUE, TRUE, TRUE ); + + // + // Initialise the next stack location for the driver below us to use... + // + PtrIrpSp = IoGetNextIrpStackLocation( PtrAssociatedIrp ); + PtrIrpSp->MajorFunction = PtrIrpContext->MajorFunction; + if( PtrIrpContext->MajorFunction == IRP_MJ_READ ) + { + PtrIrpSp->Parameters.Read.Length = ReadWriteLength; + PtrIrpSp->Parameters.Read.ByteOffset.QuadPart = PtrIoRuns[i].LogicalBlock * ( LogicalBlockSize ); + } + else if( PtrIrpContext->MajorFunction == IRP_MJ_WRITE ) + { + PtrIrpSp->Parameters.Write.Length = ReadWriteLength; + PtrIrpSp->Parameters.Write.ByteOffset.QuadPart = PtrIoRuns[i].LogicalBlock * ( LogicalBlockSize ); + } + + // PtrIrpSp->Parameters.Read.Length = ReadWriteLength; + // PtrIrpSp->Parameters.Read.ByteOffset.QuadPart = + // PtrIoRuns[i].LogicalBlock * ( LogicalBlockSize ); + } + + for( i = 0; i < Count; i++ ) { + DbgPrint("PASSING DOWN IRP %d TO TARGET DEVICE\n", i); + IoCallDriver( PtrVCB->TargetDeviceObject, PtrIoRuns[ i].PtrAssociatedIrp ); + } + + if( SynchronousIo ) + { + // + // Synchronous IO + // Wait for the IO to complete... + // + DbgPrint("DEADLY WAIT (%d)\n", KeGetCurrentIrql()); + KeWaitForSingleObject( PtrSyncEvent, + Executive, KernelMode, FALSE, (PLARGE_INTEGER)NULL ); + DbgPrint("DEADLY WAIT DONE\n"); + try_return ( RC ); + } + else + { + // Asynchronous IO... + RC = STATUS_PENDING; + try_return ( RC ); + } + + try_exit: NOTHING; + } + finally + { + if( PtrSyncEvent ) + { + DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [io]", PtrSyncEvent ); + ExFreePool( PtrSyncEvent ); + } + if( PtrIoContext && ! ( RC == STATUS_PENDING || RC == STATUS_SUCCESS ) ) + { + // + // This means we are getting out of + // this function without doing a read + // due to an error, maybe... + // + DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [io]", PtrIoContext); + ExFreePool( PtrIoContext ); + } + } + return(RC); +} + +NTSTATUS Ext2PassDownSingleReadWriteIRP( + PtrExt2IrpContext PtrIrpContext, + PIRP PtrIrp, + PtrExt2VCB PtrVCB, + LARGE_INTEGER ByteOffset, + uint32 ReadWriteLength, + BOOLEAN SynchronousIo) +{ + NTSTATUS RC = STATUS_SUCCESS; + + PEXT2_IO_CONTEXT PtrIoContext = NULL; + PKEVENT PtrSyncEvent = NULL; + PVOID PtrReadBuffer = NULL; + ULONG ReadBufferLength = 0; + + ULONG LogicalBlockNo = 0; + ULONG LogicalBlockSize = 0; + ULONG PhysicalBlockSize = 0; + + uint32 NumberBytesRead = 0; + int i; + PIO_STACK_LOCATION PtrIrpNextSp = NULL; + + try + { + if( !PtrIrp->MdlAddress ) + { + Ext2LockCallersBuffer( PtrIrp, TRUE, ReadWriteLength ); + } + + + if( SynchronousIo ) + { + PtrSyncEvent = Ext2AllocatePool( NonPagedPool, Ext2QuadAlign( sizeof(KEVENT) ) ); + if ( !PtrSyncEvent ) + { + RC = STATUS_INSUFFICIENT_RESOURCES; + try_return ( RC ); + } + KeInitializeEvent( PtrSyncEvent, SynchronizationEvent, FALSE ); + } + + // + // Allocate and initialize a completion context + // + PtrIoContext = Ext2AllocatePool(NonPagedPool, Ext2QuadAlign( sizeof(EXT2_IO_CONTEXT) ) ); + if ( !PtrIoContext ) + { + RC = STATUS_INSUFFICIENT_RESOURCES; + try_return ( RC ); + } + + RtlZeroMemory( PtrIoContext, sizeof(EXT2_IO_CONTEXT) ); + PtrIoContext->Count = 1; + PtrIoContext->NodeIdentifier.NodeType = EXT2_NODE_TYPE_IO_CONTEXT; + PtrIoContext->NodeIdentifier.NodeSize = sizeof( EXT2_IO_CONTEXT ); + PtrIoContext->PtrMasterIrp = NULL; + PtrIoContext->PtrSyncEvent = PtrSyncEvent; + PtrIoContext->ReadWriteLength = ReadWriteLength; + + IoSetCompletionRoutine( PtrIrp, + SynchronousIo ? + Ext2SingleSyncCompletionRoutine: + Ext2SingleAsyncCompletionRoutine, + PtrIoContext, TRUE, TRUE, TRUE ); + + // + // Setup the next IRP stack location in the associated Irp for the disk + // driver beneath us. + // + PtrIrpNextSp = IoGetNextIrpStackLocation( PtrIrp ); + + // + // Setup the Stack location to do a read from the disk driver. + // + PtrIrpNextSp->MajorFunction = PtrIrpContext->MajorFunction; + if( PtrIrpContext->MajorFunction == IRP_MJ_READ ) + { + PtrIrpNextSp->Parameters.Read.Length = ReadWriteLength; + PtrIrpNextSp->Parameters.Read.ByteOffset = ByteOffset; + } + else if( PtrIrpContext->MajorFunction == IRP_MJ_WRITE ) + { + PtrIrpNextSp->Parameters.Write.Length = ReadWriteLength; + PtrIrpNextSp->Parameters.Write.ByteOffset = ByteOffset; + } + // + // Issue the read / write request + // + RC = IoCallDriver(PtrVCB->TargetDeviceObject, PtrIrp); + + if( SynchronousIo ) + { + // + // Wait for completion... + // + RC = KeWaitForSingleObject( &PtrIoContext->PtrSyncEvent, + Executive, KernelMode, FALSE, (PLARGE_INTEGER)NULL ); + + RC = STATUS_SUCCESS; + } + else + { + RC = STATUS_PENDING; + } + + try_exit: NOTHING; + } + finally + { + if( PtrSyncEvent ) + { + DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [io]", PtrSyncEvent ); + ExFreePool( PtrSyncEvent ); + } + if( PtrIoContext && !( RC == STATUS_PENDING || RC == STATUS_SUCCESS ) ) + { + // + // This means we are getting out of + // this function without doing a read / write + // due to an error, maybe... + // + DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [io]", PtrIoContext ); + ExFreePool( PtrIoContext ); + } + } + return RC; +} + + +/************************************************************************* +* +* Function: Ext2SingleSyncCompletionRoutine() +* +* Description: +* Synchronous I/O Completion Routine +* +* Expected Interrupt Level (for execution) : +* +* ? +* +* Return Value: NTSTATUS - STATUS_SUCCESS(always) +* +*************************************************************************/ +NTSTATUS Ext2SingleSyncCompletionRoutine( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID Contxt + ) +{ + PEXT2_IO_CONTEXT PtrContext = Contxt; + + if( Irp->PendingReturned ) + IoMarkIrpPending( Irp ); + + ASSERT( PtrContext ); + ASSERT( PtrContext->NodeIdentifier.NodeType == EXT2_NODE_TYPE_IO_CONTEXT ); + + KeSetEvent( PtrContext->PtrSyncEvent, 0, FALSE ); + DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [io]", PtrContext ); + ExFreePool( PtrContext ); + + return STATUS_SUCCESS; +} + +/************************************************************************* +* +* Function: Ext2SingleAsyncCompletionRoutine() +* +* Description: +* Asynchronous I/O Completion Routine +* +* Expected Interrupt Level (for execution) : +* +* ? +* +* Return Value: NTSTATUS - STATUS_SUCCESS(always) +* +*************************************************************************/ +NTSTATUS Ext2SingleAsyncCompletionRoutine( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID Contxt + ) +{ + PEXT2_IO_CONTEXT PtrContext = Contxt; + + if( Irp->PendingReturned ) + IoMarkIrpPending( Irp ); + + ASSERT( PtrContext ); + ASSERT( PtrContext->NodeIdentifier.NodeType == EXT2_NODE_TYPE_IO_CONTEXT ); + + DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [io]", PtrContext ); + ExFreePool( PtrContext ); + + return STATUS_SUCCESS; +} + +/************************************************************************* +* +* Function: Ext2MultiSyncCompletionRoutine() +* +* Description: +* Synchronous I/O Completion Routine +* +* Expected Interrupt Level (for execution) : +* +* ? +* +* Return Value: NTSTATUS - STATUS_SUCCESS(always) +* +*************************************************************************/ +NTSTATUS Ext2MultiSyncCompletionRoutine ( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID Contxt + ) +{ + + PEXT2_IO_CONTEXT PtrContext = Contxt; + ASSERT( PtrContext ); + + if( Irp->PendingReturned ) + { + IoMarkIrpPending( Irp ); + } + + if (!NT_SUCCESS( Irp->IoStatus.Status )) + { + PtrContext->PtrMasterIrp->IoStatus.Status = Irp->IoStatus.Status; + } + + if (InterlockedDecrement( &PtrContext->Count ) == 0) + { + if ( NT_SUCCESS( PtrContext->PtrMasterIrp->IoStatus.Status ) ) + { + PtrContext->PtrMasterIrp->IoStatus.Information = PtrContext->ReadWriteLength; + } + else + { + PtrContext->PtrMasterIrp->IoStatus.Information = 0; + } + + KeSetEvent( PtrContext->PtrSyncEvent, 0, FALSE ); + DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [io]", PtrContext ); + ExFreePool( PtrContext ); + } + + // + // The master Irp will be automatically completed + // when all the associated IRPs are completed + // + return STATUS_SUCCESS; +} + +/************************************************************************* +* +* Function: Ext2MultiAsyncCompletionRoutine() +* +* Description: +* Asynchronous I/O Completion Routine +* +* Expected Interrupt Level (for execution) : +* +* ? +* +* Return Value: NTSTATUS - STATUS_SUCCESS(always) +* +*************************************************************************/ +NTSTATUS Ext2MultiAsyncCompletionRoutine ( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID Contxt + ) +{ + + PEXT2_IO_CONTEXT PtrContext = Contxt; + ASSERT( PtrContext ); + + if( Irp->PendingReturned ) + { + IoMarkIrpPending( Irp ); + } + + if (!NT_SUCCESS( Irp->IoStatus.Status )) + { + PtrContext->PtrMasterIrp->IoStatus.Status = Irp->IoStatus.Status; + } + + if (InterlockedDecrement( &PtrContext->Count ) == 0) + { + if ( NT_SUCCESS( PtrContext->PtrMasterIrp->IoStatus.Status ) ) + { + PtrContext->PtrMasterIrp->IoStatus.Information = PtrContext->ReadWriteLength; + } + else + { + PtrContext->PtrMasterIrp->IoStatus.Information = 0; + } + DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [io]", PtrContext ); + ExFreePool( PtrContext ); + } + + // + // The master Irp will be automatically completed + // when all the associated IRPs are completed + // Returning STATUS_SUCCESS to continue postprocessing... + // + return STATUS_SUCCESS; +} diff --git a/reactos/drivers/fs/ext2/src/metadata.c b/reactos/drivers/fs/ext2/src/metadata.c new file mode 100644 index 00000000000..1d577d973b8 --- /dev/null +++ b/reactos/drivers/fs/ext2/src/metadata.c @@ -0,0 +1,2837 @@ +/************************************************************************* +* +* File: metadata.c +* +* Module: Ext2 File System Driver (Kernel mode execution only) +* +* Description: +* Should contain code to handle Ext2 Metadata. +* +* Author: Manoj Paul Joseph +* +* +*************************************************************************/ + +#include "ext2fsd.h" + +#define EXT2_BUG_CHECK_ID EXT2_FILE_METADATA_IO + +#define DEBUG_LEVEL ( DEBUG_TRACE_METADATA ) + +extern Ext2Data Ext2GlobalData; + +/************************************************************************* +* +* Function: Ext2ReadInode() +* +* Description: +* +* The functions will read in the specifiec inode and return it in a buffer +* +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* +* Arguements: +* +* +* +* Return Value: The Status of the Read IO +* +*************************************************************************/ + +NTSTATUS Ext2ReadInode ( + PtrExt2VCB PtrVcb, // the Volume Control Block + uint32 InodeNo, // The Inode no + PEXT2_INODE PtrInode // The Inode Buffer + ) +{ + // The Status to be returned... + NTSTATUS RC = STATUS_SUCCESS; + + // The Read Buffer Pointer + BYTE * PtrPinnedReadBuffer = NULL; + + PEXT2_INODE PtrTempInode; + + // Buffer Control Block + PBCB PtrBCB = NULL; + + LARGE_INTEGER VolumeByteOffset, TempOffset; + + ULONG LogicalBlockSize = 0; + + ULONG NumberOfBytesToRead = 0; + ULONG Difference = 0; + + ULONG GroupNo; + int Index; + + try + { + ASSERT(PtrVcb); + ASSERT(PtrVcb->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB); + + // Inode numbers start at 1 and not from 0 + // Hence 1 is subtracted from InodeNo to get a zero based index... + GroupNo = ( InodeNo - 1 ) / PtrVcb->InodesPerGroup; + + if( GroupNo >= PtrVcb->NoOfGroups ) + { + DebugTrace(DEBUG_TRACE_MISC, "&&&&&& Invalid Inode no. Group no %d - too big", GroupNo ); + DebugTrace(DEBUG_TRACE_MISC, "Only %d groups available on disk", PtrVcb->NoOfGroups ); + RC = STATUS_UNSUCCESSFUL; + try_return( RC ); + } + + //if( PtrVcb->InodeTableBlock[ GroupNo ] == 0 ) + if( PtrVcb->PtrGroupDescriptors[ GroupNo ].InodeTablesBlock == 0 ) + { + DebugTrace(DEBUG_TRACE_MISC, "&&&&&& Inode Table Group Invalid - Group no %d ", GroupNo ); + RC = STATUS_UNSUCCESSFUL; + try_return( RC ); + } + + // Inode numbers start at 1 and not from 0 + // Hence 1 is subtracted from InodeNo to get a zero based index... + Index = ( InodeNo - 1 ) - ( GroupNo * PtrVcb->InodesPerGroup ); + + LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVcb->LogBlockSize; + NumberOfBytesToRead = sizeof(EXT2_INODE); // LogicalBlockSize; + + VolumeByteOffset.QuadPart = PtrVcb->PtrGroupDescriptors[ GroupNo ].InodeTablesBlock + * LogicalBlockSize + Index * sizeof(EXT2_INODE); + //VolumeByteOffset.QuadPart = PtrVcb->InodeTableBlock[ GroupNo ] * LogicalBlockSize + + // Index * sizeof(EXT2_INODE); + + TempOffset.QuadPart = Ext2Align64( VolumeByteOffset.QuadPart, LogicalBlockSize ); + if( TempOffset.QuadPart != VolumeByteOffset.QuadPart ) + { + // TempOffset.QuadPart -= LogicalBlockSize; + Difference = (LONG) (VolumeByteOffset.QuadPart - TempOffset.QuadPart + LogicalBlockSize ); + VolumeByteOffset.QuadPart -= Difference; + NumberOfBytesToRead += Difference; + } + + NumberOfBytesToRead = Ext2Align( NumberOfBytesToRead, LogicalBlockSize ); + + if( NumberOfBytesToRead > LogicalBlockSize ) + { + // Multiple blocks being read in... + // Can cause overlap + // Watch out!!!! + Ext2BreakPoint(); + } + + + + if (!CcMapData( PtrVcb->PtrStreamFileObject, + &VolumeByteOffset, + NumberOfBytesToRead, + TRUE, + &PtrBCB, + (PVOID*)&PtrPinnedReadBuffer )) + { + RC = STATUS_UNSUCCESSFUL; + try_return( RC ); + } + else + { + PtrTempInode = (PEXT2_INODE) ( PtrPinnedReadBuffer + Difference ); + RtlCopyMemory( PtrInode, PtrTempInode , sizeof(EXT2_INODE) ); + } + + try_exit: NOTHING; + } + finally + { + if( PtrBCB ) + { + CcUnpinData( PtrBCB ); + PtrBCB = NULL; + } + + } + return RC; +} + +/************************************************************************* +* +* Function: Ext2InitializeFCBInodeInfo() +* +* Description: +* The functions will initialize the FCB with its i-node info +* provided it hasn't been initialized as yet... +* +* Expected Interrupt Level (for execution) : +* IRQL_PASSIVE_LEVEL +* +* Arguements: +* Pointer to FCB +* +* Return Value: None +* +*************************************************************************/ +void Ext2InitializeFCBInodeInfo ( + PtrExt2FCB PtrFCB ) +{ + PtrExt2VCB PtrVCB = NULL; + EXT2_INODE Inode; + int i; + ULONG LogicalBlockSize; + + PtrVCB = PtrFCB->PtrVCB; + + LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize; + + if( !Ext2IsFlagOn( PtrFCB->FCBFlags, EXT2_FCB_BLOCKS_INITIALIZED ) ) + { + DebugTrace(DEBUG_TRACE_MISC, "Reading in the i-node no %d", PtrFCB->INodeNo ); + + Ext2ReadInode( PtrVCB, PtrFCB->INodeNo, &Inode ); + + for( i = 0; i < EXT2_N_BLOCKS ; i++ ) + { + PtrFCB->IBlock[i] = Inode.i_block[ i ]; + } + + PtrFCB->CreationTime.QuadPart = ( __int64 )Inode.i_ctime * 10000000; + PtrFCB->CreationTime.QuadPart += Ext2GlobalData.TimeDiff.QuadPart; + PtrFCB->LastAccessTime.QuadPart = Ext2GlobalData.TimeDiff.QuadPart + ( ( __int64 ) Inode.i_atime * 10000000); + PtrFCB->LastWriteTime.QuadPart = Ext2GlobalData.TimeDiff.QuadPart + ( ( __int64 ) Inode.i_mtime * 10000000); + + + PtrFCB->LinkCount = Inode.i_links_count; + + // Getting the file type... + if( ! Ext2IsModeRegularFile( Inode.i_mode ) ) + { + // Not a reqular file... + if( Ext2IsModeDirectory( Inode.i_mode) ) + { + // Directory... + Ext2SetFlag( PtrFCB->FCBFlags, EXT2_FCB_DIRECTORY ); + } + else + { + // Special File... + // Treated with respect... ;) + // + Ext2SetFlag( PtrFCB->FCBFlags, EXT2_FCB_SPECIAL_FILE ); + } + + } + if( Ext2IsModeHidden( Inode.i_mode ) ) + { + Ext2SetFlag( PtrFCB->FCBFlags, EXT2_FCB_HIDDEN_FILE ); + } + if( Ext2IsModeReadOnly( Inode.i_mode ) ) + { + Ext2SetFlag( PtrFCB->FCBFlags, EXT2_FCB_READ_ONLY ); + } + + + PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart = Inode.i_size; + Ext2SetFlag( PtrFCB->FCBFlags, EXT2_FCB_BLOCKS_INITIALIZED ); + PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize.QuadPart = Inode.i_blocks * 512; + + if( PtrFCB->IBlock[ EXT2_IND_BLOCK ] ) + { + PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize.QuadPart -= LogicalBlockSize / 512; + } + DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [metadata]", Inode ); + } +} + +/************************************************************************* +* +* Function: Ext2AllocInode() +* +* Description: +* The functions will allocate a new on-disk i-node +* +* Expected Interrupt Level (for execution) : +* IRQL_PASSIVE_LEVEL +* +* +* Arguements: +* Parent Inode no +* +* Return Value: The new i-node no or zero +* +*************************************************************************/ +ULONG Ext2AllocInode( + PtrExt2IrpContext PtrIrpContext, + PtrExt2VCB PtrVCB, + ULONG ParentINodeNo ) +{ + ULONG InodeNo = 0; + + // Buffer Control Block + PBCB PtrBitmapBCB = NULL; + BYTE * PtrBitmapBuffer = NULL; + + LARGE_INTEGER VolumeByteOffset; + ULONG LogicalBlockSize = 0; + ULONG NumberOfBytesToRead = 0; + + if( PtrVCB->FreeInodesCount == 0) + { + // + // No Free Inodes left... + // Fail request... + // + return 0; + } + + try + { + // unsigned int DescIndex ; + BOOLEAN Found = FALSE; + ULONG Block; + ULONG GroupNo; + + LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize; + + for( GroupNo = 0; PtrVCB->NoOfGroups; GroupNo++ ) + { + if( PtrVCB->PtrGroupDescriptors[ GroupNo ].FreeInodesCount ) + break; + } + + VolumeByteOffset.QuadPart = + PtrVCB->PtrGroupDescriptors[ GroupNo ].InodeBitmapBlock * LogicalBlockSize; + + NumberOfBytesToRead = PtrVCB->InodesCount / PtrVCB->NoOfGroups; + + if( NumberOfBytesToRead % 8 ) + { + NumberOfBytesToRead = ( NumberOfBytesToRead / 8 ) + 1; + } + else + { + NumberOfBytesToRead = ( NumberOfBytesToRead / 8 ) ; + } + + for( Block = 0; !Found && Block < Ext2Align( NumberOfBytesToRead , LogicalBlockSize ); + Block += LogicalBlockSize, VolumeByteOffset.QuadPart += LogicalBlockSize) + { + // + // Read in the bitmap block... + // + ULONG i, j; + BYTE Bitmap; + + if( !CcPinRead( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + LogicalBlockSize, //NumberOfBytesToRead, + TRUE, + &PtrBitmapBCB, + (PVOID*)&PtrBitmapBuffer ) ) + { + DebugTrace(DEBUG_TRACE_ERROR, "Cache read failiure while reading in volume meta data", 0); + return 0; + } + + // + // Is there a free inode... + // + for( i = 0; !Found && i < LogicalBlockSize && + i + (Block * LogicalBlockSize) < NumberOfBytesToRead; i++ ) + { + Bitmap = PtrBitmapBuffer[i]; + if( Bitmap != 0xff ) + { + // + // Found a free inode... + for( j = 0; !Found && j < 8; j++ ) + { + if( ( Bitmap & 0x01 ) == 0 ) + { + // + // Found... + Found = TRUE; + + // Inode numbers start at 1 and not from 0 + // Hence 1 is addded to j + InodeNo = ( ( ( Block * LogicalBlockSize) + i ) * 8) + j + 1 + + ( GroupNo * PtrVCB->InodesPerGroup ); + + // Update the inode on the disk... + Bitmap = 1 << j; + PtrBitmapBuffer[i] |= Bitmap; + + CcSetDirtyPinnedData( PtrBitmapBCB, NULL ); + Ext2SaveBCB( PtrIrpContext, PtrBitmapBCB, PtrVCB->PtrStreamFileObject ); + + // + // Should update the bitmaps in the other groups too... + // + break; + } + Bitmap = Bitmap >> 1; + } + } + } + // + // Unpin the BCB... + // + if( PtrBitmapBCB ) + { + CcUnpinData( PtrBitmapBCB ); + PtrBitmapBCB = NULL; + } + } + + { + // + // Updating the Inode count in the Group Descriptor... + // + PBCB PtrDescriptorBCB = NULL; + PEXT2_GROUP_DESCRIPTOR PtrGroupDescriptor = NULL; + + PtrVCB->PtrGroupDescriptors[ GroupNo ].FreeInodesCount--; + + if( PtrVCB->LogBlockSize ) + { + // First block contains the descriptors... + VolumeByteOffset.QuadPart = LogicalBlockSize; + } + else + { + // Second block contains the descriptors... + VolumeByteOffset.QuadPart = LogicalBlockSize * 2; + } + NumberOfBytesToRead = PtrVCB->NoOfGroups * sizeof( struct ext2_group_desc ); + NumberOfBytesToRead = Ext2Align( NumberOfBytesToRead, LogicalBlockSize ); + + if (!CcPinRead( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + NumberOfBytesToRead, + TRUE, + &PtrDescriptorBCB , + (PVOID*)&PtrGroupDescriptor )) + { + DebugTrace(DEBUG_TRACE_ERROR, "Cache read failiure while reading in volume meta data", 0); + // + // Ignore this error... + // Not fatal... + } + else + { + PtrGroupDescriptor[ GroupNo ].bg_free_inodes_count = + PtrVCB->PtrGroupDescriptors[ GroupNo ].FreeInodesCount; + // + // Not synchronously flushing this information... + // Lazy writing will do... + // + CcSetDirtyPinnedData( PtrDescriptorBCB, NULL ); + CcUnpinData( PtrDescriptorBCB ); + PtrDescriptorBCB = NULL; + } + } + + + // + // Update the Inode count... + // in the Super Block... + // + { + // Ext2 Super Block information... + PEXT2_SUPER_BLOCK PtrSuperBlock = NULL; + PBCB PtrSuperBlockBCB = NULL; + + PtrVCB->FreeInodesCount--; + // Reading in the super block... + VolumeByteOffset.QuadPart = 1024; + + // THis shouldn't be more than a block in size... + NumberOfBytesToRead = Ext2Align( sizeof( EXT2_SUPER_BLOCK ), LogicalBlockSize ); + + if( !CcPinRead( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + NumberOfBytesToRead, + TRUE, + &PtrSuperBlockBCB, + (PVOID*)&PtrSuperBlock ) ) + { + DebugTrace(DEBUG_TRACE_ERROR, "Cache read failiure while reading in volume meta data", 0); + } + else + { + PtrSuperBlock->s_free_inodes_count = PtrVCB->FreeInodesCount; + CcSetDirtyPinnedData( PtrSuperBlockBCB, NULL ); + Ext2SaveBCB( PtrIrpContext, PtrSuperBlockBCB, PtrVCB->PtrStreamFileObject ); + if( PtrSuperBlockBCB ) + { + CcUnpinData( PtrSuperBlockBCB ); + PtrSuperBlockBCB = NULL; + } + + } + } + + try_exit: NOTHING; + } + finally + { + if( PtrBitmapBCB ) + { + CcUnpinData( PtrBitmapBCB ); + PtrBitmapBCB = NULL; + } + } + DebugTrace( DEBUG_TRACE_SPECIAL, " Allocating an inode - I-Node no : %ld", InodeNo ); + + return InodeNo; + +} + +/************************************************************************* +* +* Function: Ext2DeallocInode() +* +* Description: +* The functions will deallocate an i-node +* +* Expected Interrupt Level (for execution) : +* IRQL_PASSIVE_LEVEL +* +* Return Value: Success / Failure... +* +*************************************************************************/ +BOOLEAN Ext2DeallocInode( + PtrExt2IrpContext PtrIrpContext, + PtrExt2VCB PtrVCB, + ULONG INodeNo ) +{ + BOOLEAN RC = TRUE; + + // Buffer Control Block + PBCB PtrBitmapBCB = NULL; + BYTE * PtrBitmapBuffer = NULL; + + LARGE_INTEGER VolumeByteOffset; + ULONG LogicalBlockSize = 0; + + DebugTrace( DEBUG_TRACE_SPECIAL, " Deallocating an inode - I-Node no : %ld", INodeNo ); + + try + { + ULONG BlockIndex ; + ULONG BitmapIndex; + ULONG GroupNo; + BYTE Bitmap; + + LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize; + + GroupNo = INodeNo / PtrVCB->InodesPerGroup; + INodeNo = INodeNo % PtrVCB->InodesPerGroup; + + BitmapIndex = (INodeNo-1) / 8; + Bitmap = 1 << ( (INodeNo-1) % 8 ); + BlockIndex = BitmapIndex / LogicalBlockSize; + // Adjusting to index into the Logical block that contains the bitmap + BitmapIndex = BitmapIndex - ( BlockIndex * LogicalBlockSize ); + + VolumeByteOffset.QuadPart = + ( PtrVCB->PtrGroupDescriptors[ GroupNo ].InodeBitmapBlock + BlockIndex ) + * LogicalBlockSize; + + // + // Read in the bitmap block... + // + if( !CcPinRead( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + LogicalBlockSize, // Just the block that contains the bitmap will do... + TRUE, // Can Wait... + &PtrBitmapBCB, + (PVOID*)&PtrBitmapBuffer ) ) + { + // Unable to Pin the data into the cache... + try_return (RC = FALSE); + } + + // + // Locate the inode... + // This inode is in the byte PtrBitmapBuffer[ BitmapIndex ] + if( ( PtrBitmapBuffer[ BitmapIndex ] & Bitmap ) == 0) + { + // This shouldn't have been so... + // The inode was never allocated! + // How to deallocate something that hasn't been allocated? + // Hmmm... ;) + // Ignore this error... + try_return (RC = TRUE); + } + + + // Setting the bit for the inode... + PtrBitmapBuffer[ BitmapIndex ] &= (~Bitmap); + + // Update the cache... + CcSetDirtyPinnedData( PtrBitmapBCB, NULL ); + + // Save up the BCB for forcing a synchronous write... + // Before completing the IRP... + Ext2SaveBCB( PtrIrpContext, PtrBitmapBCB, PtrVCB->PtrStreamFileObject ); + + + if( PtrBitmapBCB ) + { + CcUnpinData( PtrBitmapBCB ); + PtrBitmapBCB = NULL; + } + + { + // + // Updating the Inode count in the Group Descriptor... + // + PBCB PtrDescriptorBCB = NULL; + PEXT2_GROUP_DESCRIPTOR PtrGroupDescriptor = NULL; + ULONG NumberOfBytesToRead = 0; + + PtrVCB->PtrGroupDescriptors[ GroupNo ].FreeInodesCount++; + + if( PtrVCB->LogBlockSize ) + { + // First block contains the descriptors... + VolumeByteOffset.QuadPart = LogicalBlockSize; + } + else + { + // Second block contains the descriptors... + VolumeByteOffset.QuadPart = LogicalBlockSize * 2; + } + NumberOfBytesToRead = PtrVCB->NoOfGroups * sizeof( struct ext2_group_desc ); + NumberOfBytesToRead = Ext2Align( NumberOfBytesToRead, LogicalBlockSize ); + + if (!CcPinRead( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + NumberOfBytesToRead, + TRUE, + &PtrDescriptorBCB , + (PVOID*)&PtrGroupDescriptor )) + { + DebugTrace(DEBUG_TRACE_ERROR, "Cache read failiure while reading in volume meta data", 0); + // + // Ignore this error... + // Not fatal... + } + else + { + PtrGroupDescriptor[ GroupNo ].bg_free_inodes_count = + PtrVCB->PtrGroupDescriptors[ GroupNo ].FreeInodesCount; + // + // Not synchronously flushing this information... + // Lazy writing will do... + // + CcSetDirtyPinnedData( PtrDescriptorBCB, NULL ); + CcUnpinData( PtrDescriptorBCB ); + PtrDescriptorBCB = NULL; + } + } + + + // + // Update the Inode count... + // in the Super Block + // and in the VCB + // + { + // Ext2 Super Block information... + PEXT2_SUPER_BLOCK PtrSuperBlock = NULL; + PBCB PtrSuperBlockBCB = NULL; + ULONG NumberOfBytesToRead = 0; + + PtrVCB->FreeInodesCount++; + + // Reading in the super block... + VolumeByteOffset.QuadPart = 1024; + NumberOfBytesToRead = Ext2Align( sizeof( EXT2_SUPER_BLOCK ), LogicalBlockSize ); + + if( !CcPinRead( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + NumberOfBytesToRead, + TRUE, + &PtrSuperBlockBCB, + (PVOID*)&PtrSuperBlock ) ) + { + DebugTrace(DEBUG_TRACE_ERROR, "Cache read failiure while reading in volume meta data", 0); + } + else + { + PtrSuperBlock->s_free_inodes_count = PtrVCB->FreeInodesCount; + CcSetDirtyPinnedData( PtrSuperBlockBCB, NULL ); + Ext2SaveBCB( PtrIrpContext, PtrSuperBlockBCB, PtrVCB->PtrStreamFileObject ); + if( PtrSuperBlockBCB ) + { + CcUnpinData( PtrSuperBlockBCB ); + PtrSuperBlockBCB = NULL; + } + + } + } + try_exit: NOTHING; + } + finally + { + if( PtrBitmapBCB ) + { + CcUnpinData( PtrBitmapBCB ); + PtrBitmapBCB = NULL; + } + } + return RC; +} + +/************************************************************************* +* +* Function: Ext2WriteInode() +* +* Description: +* The functions will write an i-node to disk +* +* Expected Interrupt Level (for execution) : +* IRQL_PASSIVE_LEVEL +* +* +* Return Value: Success / Failure... +* +*************************************************************************/ +NTSTATUS Ext2WriteInode( + PtrExt2IrpContext PtrIrpContext, + PtrExt2VCB PtrVcb, // the Volume Control Block + uint32 InodeNo, // The Inode no + PEXT2_INODE PtrInode // The Inode Buffer + ) +{ + // The Status to be returned... + NTSTATUS RC = STATUS_SUCCESS; + + // The Read Buffer Pointer + BYTE * PtrPinnedBuffer = NULL; + + PEXT2_INODE PtrTempInode; + + // Buffer Control Block + PBCB PtrBCB = NULL; + + LARGE_INTEGER VolumeByteOffset, TempOffset; + + ULONG LogicalBlockSize = 0; + ULONG NumberOfBytesToRead = 0; + ULONG Difference = 0; + ULONG GroupNo; + int Index; + + try + { + DebugTrace( DEBUG_TRACE_SPECIAL, "Writing and updating an inode - I-Node no : %ld", InodeNo ); + + ASSERT(PtrVcb); + ASSERT(PtrVcb->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB); + GroupNo = InodeNo / PtrVcb->InodesPerGroup; + + if( GroupNo >= PtrVcb->NoOfGroups ) + { + DebugTrace(DEBUG_TRACE_MISC, "&&&&&& Invalid Inode no. Group no %d - too big", GroupNo ); + DebugTrace(DEBUG_TRACE_MISC, "Only %d groups available on disk", PtrVcb->NoOfGroups ); + RC = STATUS_UNSUCCESSFUL; + try_return( RC ); + } + + if( PtrVcb->PtrGroupDescriptors[ GroupNo ].InodeTablesBlock == 0 ) + { + DebugTrace(DEBUG_TRACE_MISC, "&&&&&& Inode Table Group Invalid - Group no %d ", GroupNo ); + RC = STATUS_UNSUCCESSFUL; + try_return( RC ); + } + + Index = ( InodeNo - 1 ) - ( GroupNo * PtrVcb->InodesPerGroup ); + + LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVcb->LogBlockSize; + NumberOfBytesToRead = sizeof(EXT2_INODE); + + VolumeByteOffset.QuadPart = PtrVcb->PtrGroupDescriptors[ GroupNo ].InodeTablesBlock + * LogicalBlockSize + Index * sizeof(EXT2_INODE); + + TempOffset.QuadPart = Ext2Align64( VolumeByteOffset.QuadPart, LogicalBlockSize ); + if( TempOffset.QuadPart != VolumeByteOffset.QuadPart ) + { + // TempOffset.QuadPart -= LogicalBlockSize; + Difference = (LONG) (VolumeByteOffset.QuadPart - TempOffset.QuadPart + LogicalBlockSize ); + VolumeByteOffset.QuadPart -= Difference; + NumberOfBytesToRead += Difference; + } + + NumberOfBytesToRead = Ext2Align( NumberOfBytesToRead, LogicalBlockSize ); + + if( NumberOfBytesToRead > LogicalBlockSize ) + { + // Multiple blocks being read in... + // Can cause overlap + // Watch out!!!! + Ext2BreakPoint(); + } + + if( !CcPinRead( PtrVcb->PtrStreamFileObject, + &VolumeByteOffset, + NumberOfBytesToRead, + TRUE, // Can Wait... + &PtrBCB, + (PVOID*)&PtrPinnedBuffer ) ) + { + RC = STATUS_UNSUCCESSFUL; + try_return( RC ); + } + else + { + RtlCopyMemory( PtrPinnedBuffer + Difference, PtrInode, sizeof(EXT2_INODE) ); + CcSetDirtyPinnedData( PtrBCB, NULL ); + Ext2SaveBCB( PtrIrpContext, PtrBCB, PtrVcb->PtrStreamFileObject ); + } + + try_exit: NOTHING; + } + finally + { + if( PtrBCB ) + { + CcUnpinData( PtrBCB ); + PtrBCB = NULL; + } + + } + return RC; +} + + +/************************************************************************* +* +* Function: Ext2MakeNewDirectoryEntry() +* +* Description: +* The functions will make a new directory entry in a directory file... +* +* Expected Interrupt Level (for execution) : +* IRQL_PASSIVE_LEVEL +* +* +* Return Value: Success / Failure... +* +*************************************************************************/ +BOOLEAN Ext2MakeNewDirectoryEntry( + PtrExt2IrpContext PtrIrpContext, // The Irp context + PtrExt2FCB PtrParentFCB, // Parent Folder FCB + PFILE_OBJECT PtrFileObject, // Parent Folder Object + PUNICODE_STRING PtrName, // New entry's name + ULONG Type, // The type of the new entry + ULONG NewInodeNo) // The inode no of the new entry... +{ + PBCB PtrLastBlockBCB = NULL; + BYTE * PtrLastBlock = NULL; + EXT2_DIR_ENTRY DirEntry; + PEXT2_DIR_ENTRY PtrTempDirEntry; + + ULONG BlockNo = 0; + ULONG i; + PtrExt2VCB PtrVCB; + LARGE_INTEGER VolumeByteOffset; + unsigned long LogicalBlockSize = 0; + unsigned long NumberOfBytesToRead = 0; + BOOLEAN RC = FALSE; + + USHORT HeaderLength = sizeof( EXT2_DIR_ENTRY ); + USHORT NewEntryLength = 0; + USHORT MinLength = 0; + #define ActualLength (PtrTempDirEntry->rec_len) + #define NameLength (PtrTempDirEntry->name_len) + + try + { + ASSERT( PtrFileObject ); + + DebugTrace( DEBUG_TRACE_SPECIAL, "Making directory entry: %S", PtrName->Buffer ); + + PtrVCB = PtrParentFCB->PtrVCB; + AssertVCB( PtrVCB); + + HeaderLength = sizeof( EXT2_DIR_ENTRY ) - + (sizeof( char ) * EXT2_NAME_LEN); + // 1. Setting up the entry... + NewEntryLength = sizeof( EXT2_DIR_ENTRY ) - ( sizeof( char ) * ( EXT2_NAME_LEN - (PtrName->Length / 2) ) ); + // Length should be a multiplicant of 4 + NewEntryLength = ((NewEntryLength + 3 ) & 0xfffffffc); + + RtlZeroMemory( &DirEntry, sizeof( EXT2_DIR_ENTRY ) ); + + DirEntry.file_type = (BYTE) Type; + DirEntry.inode = NewInodeNo; + DirEntry.name_len = (BYTE)(PtrName->Length / 2 ); // Does not include a NULL + + // DirEntry.rec_len = (USHORT) NewEntryLength; + + for( i = 0; ; i++ ) + { + if( i < (ULONG)( PtrName->Length / 2 ) ) + { + DirEntry.name[i] = (CHAR) PtrName->Buffer[i]; + } + else + { + //DirEntry.name[i] = 0; // Entry need not be zero terminated... + break; + } + } + + // + // 2. Read the block in the directory... + // Initiate Caching... + if ( PtrFileObject->PrivateCacheMap == NULL ) + { + CcInitializeCacheMap( + PtrFileObject, + (PCC_FILE_SIZES)(&(PtrParentFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize)), + TRUE, // We utilize pin access for directories + &(Ext2GlobalData.CacheMgrCallBacks), // callbacks + PtrParentFCB ); // The context used in callbacks + } + + LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize; + if( PtrParentFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart > 0 ) + { + BlockNo = (ULONG) ( (PtrParentFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart - 1) / LogicalBlockSize) ; + } + else + { + // This directory doesn't have any data blocks... + // Allocate a new block... + if( !Ext2AddBlockToFile( PtrIrpContext, PtrVCB, PtrParentFCB, PtrFileObject, TRUE ) ) + { + try_return( RC = FALSE ); + } + else + { + // Bring in the newly allocated block to the cache... + VolumeByteOffset.QuadPart = 0; + + if( !CcPreparePinWrite( + PtrFileObject, + &VolumeByteOffset, + LogicalBlockSize, + TRUE, // Zero out the block... + TRUE, // Can Wait... + &PtrLastBlockBCB, + (PVOID*)&PtrLastBlock ) ) + { + try_return( RC = FALSE ); + } + + DirEntry.rec_len = (USHORT)LogicalBlockSize; + RtlCopyBytes( PtrLastBlock, &DirEntry, NewEntryLength); + CcSetDirtyPinnedData( PtrLastBlockBCB, NULL ); + Ext2SaveBCB( PtrIrpContext, PtrLastBlockBCB, PtrFileObject ); + try_return( RC = TRUE ); + } + } + + VolumeByteOffset.QuadPart = BlockNo * LogicalBlockSize; + CcMapData( PtrFileObject, + &VolumeByteOffset, + LogicalBlockSize, + TRUE, + &PtrLastBlockBCB, + (PVOID*)&PtrLastBlock ); + + for( i = 0 ; i < LogicalBlockSize; ) + { + PtrTempDirEntry = (PEXT2_DIR_ENTRY) &PtrLastBlock[ i ]; + + MinLength = HeaderLength + NameLength; + MinLength = ( HeaderLength + NameLength + 3 ) & 0xfffffffc; + + + if( PtrTempDirEntry->rec_len == 0 ) + { + if( i == 0 ) + { + // Must be an empty Block... + // Insert here... + // ---------------->>> + + CcPinMappedData( PtrFileObject, + &VolumeByteOffset, + LogicalBlockSize, + TRUE, + &PtrLastBlockBCB ); + + DirEntry.rec_len = (USHORT)LogicalBlockSize; + + RtlCopyBytes( PtrLastBlock, &DirEntry, NewEntryLength); + CcSetDirtyPinnedData( PtrLastBlockBCB, NULL ); + Ext2SaveBCB( PtrIrpContext, PtrLastBlockBCB, PtrFileObject ); + try_return( RC = TRUE ); + } + else + { + // This shouldn't be so... + // Something is wrong... + // Fail this request... + try_return( RC = FALSE ); + } + } + if( ActualLength - MinLength >= NewEntryLength ) + { + // Insert here... + // ----------------> + + // Getting ready for updation... + CcPinMappedData( PtrFileObject, + &VolumeByteOffset, + LogicalBlockSize, + TRUE, + &PtrLastBlockBCB ); + + + DirEntry.rec_len = ActualLength - MinLength; + + // Updating the current last entry + PtrTempDirEntry->rec_len = MinLength; + i += PtrTempDirEntry->rec_len; + + // Making the new entry... + RtlCopyBytes( (PtrLastBlock + i) , &DirEntry, NewEntryLength); + CcSetDirtyPinnedData( PtrLastBlockBCB, NULL ); + Ext2SaveBCB( PtrIrpContext, PtrLastBlockBCB, PtrFileObject ); + try_return( RC = TRUE ); + + } + i += PtrTempDirEntry->rec_len; + } + + // Will have to allocate a new block... + // Old block does not have enough space.. + if( !Ext2AddBlockToFile( PtrIrpContext, PtrVCB, PtrParentFCB, PtrFileObject, TRUE ) ) + { + try_return( RC = FALSE ); + } + else + { + // unpin the previously pinned block + CcUnpinData( PtrLastBlockBCB ); + PtrLastBlockBCB = NULL; + + // Bring in the newly allocated block to the cache... + VolumeByteOffset.QuadPart += LogicalBlockSize; + if( !CcPreparePinWrite( + PtrFileObject, + &VolumeByteOffset, + LogicalBlockSize, + TRUE, // Zero out the block... + TRUE, // Can Wait... + &PtrLastBlockBCB, + (PVOID*)&PtrLastBlock ) ) + { + try_return( RC = FALSE ); + } + + DirEntry.rec_len = (USHORT)LogicalBlockSize; + RtlCopyBytes( PtrLastBlock, &DirEntry, NewEntryLength); + CcSetDirtyPinnedData( PtrLastBlockBCB, NULL ); + Ext2SaveBCB( PtrIrpContext, PtrLastBlockBCB, PtrFileObject ); + try_return( RC = TRUE ); + } + try_exit: NOTHING; + } + finally + { + if( PtrLastBlockBCB ) + { + CcUnpinData( PtrLastBlockBCB ); + PtrLastBlockBCB = NULL; + } + } + if( RC == FALSE ) + { + DebugTrace( DEBUG_TRACE_ERROR, "Failed to making directory entry: %S", PtrName->Buffer ); + } + return RC; +} + + +BOOLEAN Ext2FreeDirectoryEntry( + PtrExt2IrpContext PtrIrpContext, + PtrExt2FCB PtrParentFCB, + PUNICODE_STRING PtrName) +{ + + PBCB PtrDataBlockBCB = NULL; + BYTE * PtrDataBlock = NULL; + PFILE_OBJECT PtrFileObject = NULL; + PEXT2_DIR_ENTRY PtrTempDirEntry; + LONGLONG ByteOffset = 0; + PtrExt2VCB PtrVCB; + LARGE_INTEGER VolumeByteOffset; + unsigned long LogicalBlockSize = 0; + BOOLEAN RC = FALSE; + + + try + { + DebugTrace( DEBUG_TRACE_SPECIAL, "Freeing directory entry: %S", PtrName->Buffer ); + + PtrVCB = PtrParentFCB->PtrVCB; + AssertVCB( PtrVCB); + + LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize; + + PtrFileObject = PtrParentFCB->DcbFcb.Dcb.PtrDirFileObject; + if( PtrFileObject == NULL ) + { + return FALSE; + } + + + // + // 1. Read the block in the directory... + // Initiate Caching... + if ( PtrFileObject->PrivateCacheMap == NULL ) + { + CcInitializeCacheMap( + PtrFileObject, + (PCC_FILE_SIZES)(&(PtrParentFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize)), + TRUE, // We utilize pin access for directories + &(Ext2GlobalData.CacheMgrCallBacks), // callbacks + PtrParentFCB ); // The context used in callbacks + } + + for( ByteOffset = 0; + ByteOffset < PtrParentFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart; + ByteOffset += LogicalBlockSize ) + { + ULONG Index = 0; + PEXT2_DIR_ENTRY PtrDirEntry = NULL; + + + VolumeByteOffset.QuadPart = ByteOffset; + + CcPinRead( PtrFileObject, + &VolumeByteOffset, + LogicalBlockSize, + TRUE, + &PtrDataBlockBCB, + (PVOID*)&PtrDataBlock ); + while( Index < LogicalBlockSize ) + { + ULONG i; + // Parse... + PtrDirEntry = (PEXT2_DIR_ENTRY) &PtrDataBlock[ Index ]; + Index += PtrDirEntry->rec_len; + + if( PtrDirEntry->inode == 0 ) + { + // This is a deleted entry... + continue; + } + if( ( PtrName->Length/2 ) != PtrDirEntry->name_len ) + continue; + for( i = 0; ; i++ ) + { + if( PtrDirEntry->name_len == i ) + { + // Remove the entry by setting the inode no to zero + PtrDirEntry->inode = 0; + + // Update the disk + CcSetDirtyPinnedData( PtrDataBlockBCB , NULL ); + Ext2SaveBCB( PtrIrpContext, PtrDataBlockBCB, PtrFileObject ); + CcUnpinData( PtrDataBlockBCB ); + PtrDataBlockBCB = NULL; + + // Return to caller... + try_return( RC = TRUE ); + } + if( PtrName->Buffer[i] != PtrDirEntry->name[i] ) + { + break; + } + } + } + CcUnpinData( PtrDataBlockBCB ); + PtrDataBlockBCB = NULL; + } + try_return( RC = FALSE ); + + try_exit: NOTHING; + } + finally + { + if( PtrDataBlockBCB ) + { + CcUnpinData( PtrDataBlockBCB ); + PtrDataBlockBCB = NULL; + } + } + return RC; +} + +/************************************************************************* +* +* Function: Ext2AddBlockToFile() +* +* Description: +* The functions will add a block to a file... +* It will update the allocation size but not the file size... +* +* Expected Interrupt Level (for execution) : +* IRQL_PASSIVE_LEVEL +* +* +* Return Value: Success / Failure... +* +*************************************************************************/ +BOOLEAN Ext2AddBlockToFile( + PtrExt2IrpContext PtrIrpContext, + PtrExt2VCB PtrVCB, + PtrExt2FCB PtrFCB, + PFILE_OBJECT PtrFileObject, + BOOLEAN UpdateFileSize) +{ + BOOLEAN RC = TRUE; + + ULONG NewBlockNo = 0; + LARGE_INTEGER VolumeByteOffset; + ULONG LogicalBlockSize = 0; + ULONG NoOfBlocks = 0; + EXT2_INODE Inode; + + ULONG DirectBlocks = 0; + ULONG SingleIndirectBlocks = 0; + ULONG DoubleIndirectBlocks = 0; + ULONG TripleIndirectBlocks = 0; + + ULONG *PtrSIBBuffer = NULL; + PBCB PtrSIBBCB = NULL; + ULONG *PtrDIBBuffer = NULL; + PBCB PtrDIBBCB = NULL; + + + LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize; + DirectBlocks = EXT2_NDIR_BLOCKS ; + SingleIndirectBlocks = LogicalBlockSize / sizeof( ULONG ); + DoubleIndirectBlocks = SingleIndirectBlocks * LogicalBlockSize / sizeof( ULONG ); + TripleIndirectBlocks = DoubleIndirectBlocks * LogicalBlockSize / sizeof( ULONG ); + + try + { + if( PtrFCB && PtrFCB->FCBName->ObjectName.Length ) + { + DebugTrace( DEBUG_TRACE_SPECIAL, "Adding Blocks to file %S", PtrFCB->FCBName->ObjectName.Buffer ); + } + + Ext2InitializeFCBInodeInfo( PtrFCB ); + + // Allocate a block... + NewBlockNo = Ext2AllocBlock( PtrIrpContext, PtrVCB, 1 ); + + if( NewBlockNo == 0 ) + { + try_return (RC = FALSE ); + } + + // No of blocks CURRENTLY allocated... + NoOfBlocks = (ULONG) PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize.QuadPart / LogicalBlockSize; + + + if( NoOfBlocks < EXT2_NDIR_BLOCKS ) + { + // + // A direct data block will do... + // + + PtrFCB->IBlock[ NoOfBlocks ] = NewBlockNo; + + // Update the inode... + Ext2ReadInode( PtrVCB, PtrFCB->INodeNo, &Inode ); + Inode.i_block[ NoOfBlocks ] = NewBlockNo; + Inode.i_blocks += ( LogicalBlockSize / 512 ); + PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize.QuadPart += LogicalBlockSize; + if( UpdateFileSize ) + { + Inode.i_size += LogicalBlockSize; + PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart += LogicalBlockSize; + } + + + if( PtrFileObject->PrivateCacheMap != NULL) + { + // + // Caching has been initiated... + // Let the Cache manager in on these changes... + // + CcSetFileSizes( PtrFileObject, (PCC_FILE_SIZES)&(PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize)); + } + + + // Updating the inode... + if( NT_SUCCESS( Ext2WriteInode( PtrIrpContext, PtrVCB, PtrFCB->INodeNo, &Inode ) ) ) + { + try_return (RC = TRUE); + } + else + { + try_return (RC = FALSE ); + } + + } + else if( NoOfBlocks < (DirectBlocks + SingleIndirectBlocks) ) + { + // + // A single indirect data block will do... + Ext2ReadInode( PtrVCB, PtrFCB->INodeNo, &Inode ); + + if( PtrFCB->IBlock[ EXT2_IND_BLOCK ] == 0 ) + { + // A Single Indirect block should be allocated as well!! + PtrFCB->IBlock[ EXT2_IND_BLOCK ] = Ext2AllocBlock( PtrIrpContext, PtrVCB, 1 ); + if( PtrFCB->IBlock[ EXT2_IND_BLOCK ] == 0 ) + { + try_return (RC = FALSE ); + } + Inode.i_blocks += ( LogicalBlockSize / 512 ); + + // Bring in the new block to the cache + // Zero it out + VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_IND_BLOCK ] * LogicalBlockSize; + + if( !CcPreparePinWrite( + PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + LogicalBlockSize, + TRUE, // Zero out the block... + TRUE, // Can Wait... + &PtrSIBBCB, + (PVOID*)&PtrSIBBuffer ) ) + { + try_return( RC = FALSE ); + } + } + else + { + // Just bring in the SIB to the cache + + VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_IND_BLOCK ] * LogicalBlockSize; + + if( !CcPinRead( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + LogicalBlockSize, + TRUE, // Can Wait... + &PtrSIBBCB, + (PVOID*)&PtrSIBBuffer ) ) + { + try_return( RC = FALSE ); + } + } + + // Update the inode... + + Inode.i_block[ EXT2_IND_BLOCK ] = PtrFCB->IBlock[ EXT2_IND_BLOCK ]; + Inode.i_blocks += ( LogicalBlockSize / 512 ); + PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize.QuadPart += LogicalBlockSize; + if( UpdateFileSize ) + { + Inode.i_size += LogicalBlockSize; + PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart += LogicalBlockSize; + } + if( PtrFileObject->PrivateCacheMap != NULL) + { + // + // Caching has been initiated... + // Let the Cache manager in on these changes... + // + CcSetFileSizes( PtrFileObject, (PCC_FILE_SIZES)&(PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize)); + } + + if( !NT_SUCCESS( Ext2WriteInode( + PtrIrpContext, PtrVCB, PtrFCB->INodeNo, &Inode ) ) ) + { + try_return (RC = FALSE ); + } + + + // Update the SIB... + PtrSIBBuffer[ NoOfBlocks - DirectBlocks ] = NewBlockNo; + CcSetDirtyPinnedData( PtrSIBBCB, NULL ); + Ext2SaveBCB( PtrIrpContext, PtrSIBBCB, PtrVCB->PtrStreamFileObject ); + + try_return (RC = TRUE); + + } + else if( NoOfBlocks < (DirectBlocks + SingleIndirectBlocks + DoubleIndirectBlocks ) ) + { + // + // A double indirect block will do... + // + ULONG SBlockNo; + ULONG BlockNo; + + Ext2ReadInode( PtrVCB, PtrFCB->INodeNo, &Inode ); + + if( PtrFCB->IBlock[ EXT2_DIND_BLOCK ] == 0 ) + { + // A double indirect pointer block should be allocated as well!! + PtrFCB->IBlock[ EXT2_DIND_BLOCK ] = Ext2AllocBlock( PtrIrpContext, PtrVCB, 1 ); + if( PtrFCB->IBlock[ EXT2_DIND_BLOCK ] == 0 ) + { + try_return (RC = FALSE ); + } + Inode.i_blocks += ( LogicalBlockSize / 512 ); + + // Bring in the new block to the cache + // Zero it out + VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_DIND_BLOCK ] * LogicalBlockSize; + + if( !CcPreparePinWrite( + PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + LogicalBlockSize, + TRUE, // Zero out the block... + TRUE, // Can Wait... + &PtrDIBBCB, + (PVOID*)&PtrDIBBuffer ) ) + { + try_return( RC = FALSE ); + } + } + else + { + // Just bring in the DIB to the cache + + VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_DIND_BLOCK ] * LogicalBlockSize; + + if( !CcPinRead( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + LogicalBlockSize, + TRUE, // Can Wait... + &PtrDIBBCB, + (PVOID*)&PtrDIBBuffer ) ) + { + try_return( RC = FALSE ); + } + } + + // See if a single indirect 'pointer' block + // should also be allocated... + BlockNo = ( NoOfBlocks - DirectBlocks - SingleIndirectBlocks ); + SBlockNo = BlockNo / SingleIndirectBlocks; + if( BlockNo % SingleIndirectBlocks ) + { + // A single indirect 'pointer' block + // should also be allocated... + PtrDIBBuffer[SBlockNo] = Ext2AllocBlock( PtrIrpContext, PtrVCB, 1 ); + CcSetDirtyPinnedData( PtrDIBBCB, NULL ); + VolumeByteOffset.QuadPart = PtrDIBBuffer[SBlockNo] * LogicalBlockSize; + + Inode.i_blocks += ( LogicalBlockSize / 512 ); + + if( !CcPreparePinWrite( + PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + LogicalBlockSize, + TRUE, // Zero out the block... + TRUE, // Can Wait... + &PtrSIBBCB, + (PVOID*)&PtrSIBBuffer ) ) + { + try_return( RC = FALSE ); + } + } + else + { + VolumeByteOffset.QuadPart = PtrDIBBuffer[SBlockNo] * LogicalBlockSize; + if( !CcPinRead( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + LogicalBlockSize, + TRUE, // Can Wait... + &PtrSIBBCB, + (PVOID*)&PtrSIBBuffer ) ) + { + try_return( RC = FALSE ); + } + } + BlockNo = BlockNo % SingleIndirectBlocks; + + // Update the inode... + + Inode.i_block[ EXT2_DIND_BLOCK ] = PtrFCB->IBlock[ EXT2_DIND_BLOCK ]; + Inode.i_blocks += ( LogicalBlockSize / 512 ); + PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize.QuadPart += LogicalBlockSize; + if( UpdateFileSize ) + { + Inode.i_size += LogicalBlockSize; + PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart += LogicalBlockSize; + } + if( PtrFileObject->PrivateCacheMap != NULL) + { + // + // Caching has been initiated... + // Let the Cache manager in on these changes... + // + CcSetFileSizes( PtrFileObject, (PCC_FILE_SIZES)&(PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize)); + } + + if( !NT_SUCCESS( Ext2WriteInode( + PtrIrpContext, PtrVCB, PtrFCB->INodeNo, &Inode ) ) ) + { + try_return (RC = FALSE ); + } + + + // Update the SIB... + PtrSIBBuffer[ BlockNo ] = NewBlockNo; + CcSetDirtyPinnedData( PtrSIBBCB, NULL ); + Ext2SaveBCB( PtrIrpContext, PtrSIBBCB, PtrVCB->PtrStreamFileObject ); + Ext2SaveBCB( PtrIrpContext, PtrDIBBCB, PtrVCB->PtrStreamFileObject ); + + try_return (RC = TRUE); + + } + else + { + // + // A Triple Indirect block is required + // + ULONG SBlockNo; + ULONG BlockNo; + + // This is not supported as yet... + try_return (RC = FALSE); + + Ext2ReadInode( PtrVCB, PtrFCB->INodeNo, &Inode ); + + if( PtrFCB->IBlock[ EXT2_TIND_BLOCK ] == 0 ) + { + // A double indirect pointer block should be allocated as well!! + PtrFCB->IBlock[ EXT2_DIND_BLOCK ] = Ext2AllocBlock( PtrIrpContext, PtrVCB, 1 ); + if( PtrFCB->IBlock[ EXT2_DIND_BLOCK ] == 0 ) + { + try_return (RC = FALSE ); + } + Inode.i_blocks += ( LogicalBlockSize / 512 ); + + // Bring in the new block to the cache + // Zero it out + VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_DIND_BLOCK ] * LogicalBlockSize; + + if( !CcPreparePinWrite( + PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + LogicalBlockSize, + TRUE, // Zero out the block... + TRUE, // Can Wait... + &PtrDIBBCB, + (PVOID*)&PtrDIBBuffer ) ) + { + try_return( RC = FALSE ); + } + } + else + { + // Just bring in the DIB to the cache + + VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_DIND_BLOCK ] * LogicalBlockSize; + + if( !CcPinRead( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + LogicalBlockSize, + TRUE, // Can Wait... + &PtrDIBBCB, + (PVOID*)&PtrDIBBuffer ) ) + { + try_return( RC = FALSE ); + } + } + + // See if a single indirect 'pointer' block + // should also be allocated... + BlockNo = ( NoOfBlocks - DirectBlocks - SingleIndirectBlocks ); + SBlockNo = BlockNo / SingleIndirectBlocks; + if( BlockNo % SingleIndirectBlocks ) + { + // A single indirect 'pointer' block + // should also be allocated... + PtrDIBBuffer[SBlockNo] = Ext2AllocBlock( PtrIrpContext, PtrVCB, 1 ); + CcSetDirtyPinnedData( PtrDIBBCB, NULL ); + VolumeByteOffset.QuadPart = PtrDIBBuffer[SBlockNo] * LogicalBlockSize; + + Inode.i_blocks += ( LogicalBlockSize / 512 ); + + if( !CcPreparePinWrite( + PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + LogicalBlockSize, + TRUE, // Zero out the block... + TRUE, // Can Wait... + &PtrSIBBCB, + (PVOID*)&PtrSIBBuffer ) ) + { + try_return( RC = FALSE ); + } + } + else + { + VolumeByteOffset.QuadPart = PtrDIBBuffer[SBlockNo] * LogicalBlockSize; + if( !CcPinRead( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + LogicalBlockSize, + TRUE, // Can Wait... + &PtrSIBBCB, + (PVOID*)&PtrSIBBuffer ) ) + { + try_return( RC = FALSE ); + } + } + BlockNo = BlockNo % SingleIndirectBlocks; + + // Update the inode... + + Inode.i_block[ EXT2_DIND_BLOCK ] = PtrFCB->IBlock[ EXT2_DIND_BLOCK ]; + Inode.i_blocks += ( LogicalBlockSize / 512 ); + PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize.QuadPart += LogicalBlockSize; + if( UpdateFileSize ) + { + Inode.i_size += LogicalBlockSize; + PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart += LogicalBlockSize; + } + if( PtrFileObject->PrivateCacheMap != NULL) + { + // + // Caching has been initiated... + // Let the Cache manager in on these changes... + // + CcSetFileSizes( PtrFileObject, (PCC_FILE_SIZES)&(PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize)); + } + + if( !NT_SUCCESS( Ext2WriteInode( + PtrIrpContext, PtrVCB, PtrFCB->INodeNo, &Inode ) ) ) + { + try_return (RC = FALSE ); + } + + + // Update the SIB... + PtrSIBBuffer[ BlockNo ] = NewBlockNo; + CcSetDirtyPinnedData( PtrSIBBCB, NULL ); + Ext2SaveBCB( PtrIrpContext, PtrSIBBCB, PtrVCB->PtrStreamFileObject ); + Ext2SaveBCB( PtrIrpContext, PtrDIBBCB, PtrVCB->PtrStreamFileObject ); + + try_return (RC = TRUE); + + } + + try_exit: NOTHING; + } + finally + { + if( PtrSIBBCB ) + { + CcUnpinData( PtrSIBBCB ); + PtrSIBBCB = NULL; + } + if( PtrDIBBCB ) + { + CcUnpinData( PtrDIBBCB ); + PtrDIBBCB = NULL; + } + } + return RC; +} + +/************************************************************************* +* +* Function: Ext2AllocBlock() +* +* Description: +* The functions will allocate a new block +* +* Expected Interrupt Level (for execution) : +* IRQL_PASSIVE_LEVEL +* +* +* Return Value: Success / Failure... +* +*************************************************************************/ +ULONG Ext2AllocBlock( + PtrExt2IrpContext PtrIrpContext, + PtrExt2VCB PtrVCB, + ULONG Count) +{ + // Buffer Control Block + PBCB PtrBitmapBCB = NULL; + BYTE * PtrBitmapBuffer = NULL; + ULONG BlockNo = 0; + LARGE_INTEGER VolumeByteOffset; + ULONG LogicalBlockSize = 0; + ULONG NumberOfBytesToRead = 0; + + if( PtrVCB->FreeBlocksCount == 0 ) + { + // + // No Free Block left... + // Fail request... + // + return 0; + } + + try + { + BOOLEAN Found = FALSE; + ULONG Block; + ULONG GroupNo; + LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize; + + for( GroupNo = 0; PtrVCB->NoOfGroups; GroupNo++ ) + { + if( PtrVCB->PtrGroupDescriptors[ GroupNo ].FreeBlocksCount ) + break; + } + + VolumeByteOffset.QuadPart = + PtrVCB->PtrGroupDescriptors[ GroupNo ].BlockBitmapBlock * LogicalBlockSize; + + NumberOfBytesToRead = PtrVCB->BlocksCount / PtrVCB->NoOfGroups; + + if( NumberOfBytesToRead % 8 ) + { + NumberOfBytesToRead = ( NumberOfBytesToRead / 8 ) + 1; + } + else + { + NumberOfBytesToRead = ( NumberOfBytesToRead / 8 ) ; + } + + + for( Block = 0; !Found && Block < Ext2Align( NumberOfBytesToRead , LogicalBlockSize ); + Block += LogicalBlockSize, VolumeByteOffset.QuadPart += LogicalBlockSize) + { + // + // Read in the block bitmap block... + ULONG i, j; + BYTE Bitmap; + + if( !CcPinRead( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + LogicalBlockSize, // NumberOfBytesToRead, + TRUE, + &PtrBitmapBCB, + (PVOID*)&PtrBitmapBuffer ) ) + { + DebugTrace(DEBUG_TRACE_ERROR, "Cache read failiure while reading in volume meta data", 0); + try_return( BlockNo = 0 ); + } + + // + // Is there a free block... + // + for( i = 0; !Found && i < LogicalBlockSize && + i + (Block * LogicalBlockSize) < NumberOfBytesToRead; i++ ) + { + Bitmap = PtrBitmapBuffer[i]; + if( Bitmap != 0xff ) + { + // + // Found a free block... + for( j = 0; !Found && j < 8; j++ ) + { + if( ( Bitmap & 0x01 ) == 0 ) + { + // + // Found... + Found = TRUE; + BlockNo = ( ( ( Block * LogicalBlockSize) + i ) * 8) + j + 1 + + ( GroupNo * PtrVCB->BlocksPerGroup ); + + Bitmap = 1 << j; + PtrBitmapBuffer[i] |= Bitmap; + + CcSetDirtyPinnedData( PtrBitmapBCB, NULL ); + Ext2SaveBCB( PtrIrpContext, PtrBitmapBCB, PtrVCB->PtrStreamFileObject ); + // + // Should update the bitmaps in the other groups too... + // + break; + } + Bitmap = Bitmap >> 1; + } + } + } + // + // Unpin the BCB... + // + if( PtrBitmapBCB ) + { + CcUnpinData( PtrBitmapBCB ); + PtrBitmapBCB = NULL; + } + + } + + // + // Updating the Free Block count in the Group Descriptor... + // + + { + PBCB PtrDescriptorBCB = NULL; + PEXT2_GROUP_DESCRIPTOR PtrGroupDescriptor = NULL; + // + // Updating the Free Blocks count in the Group Descriptor... + // + PtrVCB->PtrGroupDescriptors[ GroupNo ].FreeBlocksCount--; + + if( PtrVCB->LogBlockSize ) + { + // First block contains the descriptors... + VolumeByteOffset.QuadPart = LogicalBlockSize; + } + else + { + // Second block contains the descriptors... + VolumeByteOffset.QuadPart = LogicalBlockSize * 2; + } + NumberOfBytesToRead = PtrVCB->NoOfGroups * sizeof( struct ext2_group_desc ); + NumberOfBytesToRead = Ext2Align( NumberOfBytesToRead, LogicalBlockSize ); + + if (!CcPinRead( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + NumberOfBytesToRead, + TRUE, + &PtrDescriptorBCB , + (PVOID*)&PtrGroupDescriptor )) + { + DebugTrace(DEBUG_TRACE_ERROR, "Cache read failiure while reading in volume meta data", 0); + // + // Ignore this error... + // Not fatal... + } + else + { + PtrGroupDescriptor[ GroupNo ].bg_free_blocks_count= + PtrVCB->PtrGroupDescriptors[ GroupNo ].FreeBlocksCount; + + // + // Not synchronously flushing this information... + // Lazy writing will do... + // + CcSetDirtyPinnedData( PtrDescriptorBCB, NULL ); + CcUnpinData( PtrDescriptorBCB ); + PtrDescriptorBCB = NULL; + } + } + + // + // Update the Block count + // in the super block and in the VCB + // + { + // Ext2 Super Block information... + PEXT2_SUPER_BLOCK PtrSuperBlock = NULL; + PBCB PtrSuperBlockBCB = NULL; + + PtrVCB->FreeBlocksCount--; + + // Reading in the super block... + VolumeByteOffset.QuadPart = 1024; + NumberOfBytesToRead = Ext2Align( sizeof( EXT2_SUPER_BLOCK ), LogicalBlockSize ); + + if( !CcPinRead( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + NumberOfBytesToRead, + TRUE, + &PtrSuperBlockBCB, + (PVOID*)&PtrSuperBlock ) ) + { + DebugTrace(DEBUG_TRACE_ERROR, "Cache read failiure while reading in volume meta data", 0); + } + else + { + PtrSuperBlock->s_free_blocks_count = PtrVCB->FreeBlocksCount; + CcSetDirtyPinnedData( PtrSuperBlockBCB, NULL ); + Ext2SaveBCB( PtrIrpContext, PtrSuperBlockBCB, PtrVCB->PtrStreamFileObject ); + if( PtrSuperBlockBCB ) + { + CcUnpinData( PtrSuperBlockBCB ); + PtrSuperBlockBCB = NULL; + } + } + } + + try_exit: NOTHING; + } + finally + { + if( PtrBitmapBCB ) + { + CcUnpinData( PtrBitmapBCB ); + PtrBitmapBCB = NULL; + } + DebugTrace( DEBUG_TRACE_SPECIAL, " Allocating a block - Block no : %ld", BlockNo ); + } + return BlockNo; +} + +/************************************************************************* +* +* Function: Ext2DeallocBlock() +* +* Description: +* The functions will deallocate a data block +* +* Expected Interrupt Level (for execution) : +* IRQL_PASSIVE_LEVEL +* +* Return Value: Success / Failure... +* +*************************************************************************/ +BOOLEAN Ext2DeallocBlock( + PtrExt2IrpContext PtrIrpContext, + PtrExt2VCB PtrVCB, + ULONG BlockNo ) +{ + // Buffer Control Block + PBCB PtrBitmapBCB = NULL; + BYTE * PtrBitmapBuffer = NULL; + BOOLEAN RC = TRUE; + LARGE_INTEGER VolumeByteOffset; + ULONG LogicalBlockSize = 0; + // ULONG NumberOfBytesToRead = 0; + + DebugTrace( DEBUG_TRACE_SPECIAL, " Deallocating a block - Block no : %ld", BlockNo ); + + try + { + ULONG GroupNo; + ULONG BlockIndex; + ULONG BitmapIndex; + BYTE Bitmap; + + LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize; + + GroupNo = BlockNo / PtrVCB->BlocksPerGroup; + BlockNo = BlockNo % PtrVCB->BlocksPerGroup; + + Bitmap = 1 << ( (BlockNo-1) % 8 ); + BitmapIndex = (BlockNo-1) / 8; + BlockIndex = BitmapIndex / LogicalBlockSize; + // Adjusting to index into the Logical block that contains the bitmap + BitmapIndex = BitmapIndex - ( BlockIndex * LogicalBlockSize ); + + VolumeByteOffset.QuadPart = + ( PtrVCB->PtrGroupDescriptors[ GroupNo ].BlockBitmapBlock + BlockIndex ) + * LogicalBlockSize; + + // + // Read in the bitmap block... + // + if( !CcPinRead( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + LogicalBlockSize, + TRUE, // Can Wait... + &PtrBitmapBCB, + (PVOID*)&PtrBitmapBuffer ) ) + { + // Unable to Pin the data into the cache... + try_return (RC = FALSE); + } + + // + // Locate the block 'bit'... + // This block 'bit' is in the byte PtrBitmapBuffer[ BitmapIndex ] + if( ( PtrBitmapBuffer[ BitmapIndex ] & Bitmap ) == 0) + { + // This shouldn't have been so... + // The block was never allocated! + // How to deallocate something that hasn't been allocated? + // Hmmm... ;) + // Ignore this error... + try_return (RC = TRUE); + } + + // Setting the bit for the inode... + PtrBitmapBuffer[ BitmapIndex ] &= (~Bitmap); + + // Update the cache... + CcSetDirtyPinnedData( PtrBitmapBCB, NULL ); + + // Save up the BCB for forcing a synchronous write... + // Before completing the IRP... + Ext2SaveBCB( PtrIrpContext, PtrBitmapBCB, PtrVCB->PtrStreamFileObject ); + + + if( PtrBitmapBCB ) + { + CcUnpinData( PtrBitmapBCB ); + PtrBitmapBCB = NULL; + } + + // + // Updating the Block count in the Group Descriptor... + // + + { + PBCB PtrDescriptorBCB = NULL; + PEXT2_GROUP_DESCRIPTOR PtrGroupDescriptor = NULL; + ULONG NumberOfBytesToRead = 0; + // + // Updating the Free Blocks count in the Group Descriptor... + // + PtrVCB->PtrGroupDescriptors[ GroupNo ].FreeBlocksCount++; + + if( PtrVCB->LogBlockSize ) + { + // First block contains the descriptors... + VolumeByteOffset.QuadPart = LogicalBlockSize; + } + else + { + // Second block contains the descriptors... + VolumeByteOffset.QuadPart = LogicalBlockSize * 2; + } + NumberOfBytesToRead = PtrVCB->NoOfGroups * sizeof( struct ext2_group_desc ); + NumberOfBytesToRead = Ext2Align( NumberOfBytesToRead, LogicalBlockSize ); + + if (!CcPinRead( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + NumberOfBytesToRead, + TRUE, + &PtrDescriptorBCB , + (PVOID*)&PtrGroupDescriptor )) + { + DebugTrace(DEBUG_TRACE_ERROR, "Cache read failiure while reading in volume meta data", 0); + // + // Ignore this error... + // Not fatal... + } + else + { + PtrGroupDescriptor[ GroupNo ].bg_free_blocks_count= + PtrVCB->PtrGroupDescriptors[ GroupNo ].FreeBlocksCount; + + // + // Not synchronously flushing this information... + // Lazy writing will do... + // + CcSetDirtyPinnedData( PtrDescriptorBCB, NULL ); + CcUnpinData( PtrDescriptorBCB ); + PtrDescriptorBCB = NULL; + } + } + + // + // Update the Block count + // in the super block and in the VCB + // + { + // Ext2 Super Block information... + PEXT2_SUPER_BLOCK PtrSuperBlock = NULL; + PBCB PtrSuperBlockBCB = NULL; + ULONG NumberOfBytesToRead = 0; + + PtrVCB->FreeBlocksCount++; + + // Reading in the super block... + VolumeByteOffset.QuadPart = 1024; + NumberOfBytesToRead = Ext2Align( sizeof( EXT2_SUPER_BLOCK ), LogicalBlockSize ); + + if( !CcPinRead( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + NumberOfBytesToRead, + TRUE, + &PtrSuperBlockBCB, + (PVOID*)&PtrSuperBlock ) ) + { + DebugTrace(DEBUG_TRACE_ERROR, "Cache read failiure while reading in volume meta data", 0); + } + else + { + PtrSuperBlock->s_free_blocks_count = PtrVCB->FreeBlocksCount; + CcSetDirtyPinnedData( PtrSuperBlockBCB, NULL ); + Ext2SaveBCB( PtrIrpContext, PtrSuperBlockBCB, PtrVCB->PtrStreamFileObject ); + CcUnpinData( PtrSuperBlockBCB ); + PtrSuperBlockBCB = NULL; + } + } + try_exit: NOTHING; + } + finally + { + if( PtrBitmapBCB ) + { + CcUnpinData( PtrBitmapBCB ); + PtrBitmapBCB = NULL; + } + } + return RC; +} + +BOOLEAN Ext2UpdateFileSize( + PtrExt2IrpContext PtrIrpContext, + PFILE_OBJECT PtrFileObject, + PtrExt2FCB PtrFCB) +{ + EXT2_INODE Inode; + PtrExt2VCB PtrVCB = PtrFCB->PtrVCB; + + if( PtrFileObject->PrivateCacheMap ) + { + CcSetFileSizes( PtrFileObject, (PCC_FILE_SIZES)&(PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize)); + } + // Now update the size on the disk... + // Read in the inode... + if( ! NT_SUCCESS( Ext2ReadInode( PtrVCB, PtrFCB->INodeNo, &Inode ) ) ) + { + return FALSE; + } + + Inode.i_size = PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.LowPart; + // Update time also??? + + // Updating the inode... + if( NT_SUCCESS( Ext2WriteInode( PtrIrpContext, PtrVCB, PtrFCB->INodeNo, &Inode ) ) ) + { + return TRUE; + } + else + { + return FALSE; + } +} + +/************************************************************************* +* +* Function: Ext2DeleteFile() +* +* Description: +* The functions will delete a file +* +* Expected Interrupt Level (for execution) : +* IRQL_PASSIVE_LEVEL +* +* Return Value: Success / Failure... +* +*************************************************************************/ +BOOLEAN Ext2DeleteFile( + PtrExt2FCB PtrFCB, + PtrExt2IrpContext PtrIrpContext) +{ + EXT2_INODE Inode; + PtrExt2FCB PtrParentFCB = NULL; + PtrExt2VCB PtrVCB = PtrFCB->PtrVCB; + + // + // Get the Parent Directory... + PtrParentFCB = Ext2LocateFCBInCore( PtrVCB, PtrFCB->ParentINodeNo ); + Ext2InitializeFCBInodeInfo( PtrFCB ); + + // 1. + // Free up the directory entry... + if( !Ext2FreeDirectoryEntry( PtrIrpContext, + PtrParentFCB, &PtrFCB->FCBName->ObjectName ) ) + { + return FALSE; + } + + // 2. + // Decrement Link count... + if( !NT_SUCCESS( Ext2ReadInode( PtrVCB, PtrFCB->INodeNo, &Inode ) ) ) + { + return FALSE; + } + + ASSERT( Inode.i_links_count == PtrFCB->LinkCount ); + + Inode.i_links_count--; + PtrFCB->LinkCount = Inode.i_links_count; + + if( !Inode.i_links_count ) + { + // + // Setting the deletion time field in the inode... + // + ULONG Time; + Time = Ext2GetCurrentTime(); + Inode.i_dtime = Time ; + } + + // 3. + // Updating the inode... + + if( NT_SUCCESS( Ext2WriteInode( PtrIrpContext, PtrVCB, PtrFCB->INodeNo, &Inode ) ) ) + { + if( Inode.i_links_count ) + { + // Some more links to the same file are available... + // So we won't deallocate the data blocks... + return TRUE; + } + } + else + { + return FALSE; + } + + // 4. + // Free up the inode... + Ext2DeallocInode( PtrIrpContext, PtrVCB, PtrFCB->INodeNo ); + + // 5. + // Release the data blocks... + Ext2ReleaseDataBlocks( PtrFCB, PtrIrpContext); + + return TRUE; +} + + +/************************************************************************* +* +* Function: Ext2ReleaseDataBlocks() +* +* Description: +* The functions will release all the data blocks in a file +* It does NOT update the file inode... +* +* Expected Interrupt Level (for execution) : +* IRQL_PASSIVE_LEVEL +* +* Return Value: Success / Failure... +* +*************************************************************************/ +BOOLEAN Ext2ReleaseDataBlocks( + PtrExt2FCB PtrFCB, + PtrExt2IrpContext PtrIrpContext) +{ + PtrExt2VCB PtrVCB = PtrFCB->PtrVCB; + ULONG LogicalBlockSize; + ULONG i; + + + LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize; + + // Release the data blocks... + + // 1. + // Free up the triple indirect blocks... + if( PtrFCB->IBlock[ EXT2_TIND_BLOCK ] ) + { + + PBCB PtrSIBCB = NULL; + PBCB PtrDIBCB = NULL; + PBCB PtrTIBCB = NULL; + + ULONG * PtrPinnedSIndirectBlock = NULL; + ULONG * PtrPinnedDIndirectBlock = NULL; + ULONG * PtrPinnedTIndirectBlock = NULL; + + LARGE_INTEGER VolumeByteOffset; + ULONG TIndex, DIndex, SIndex; + + // Pin the Double Indirect Pointer Block... + VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_TIND_BLOCK ] * LogicalBlockSize; + if (!CcMapData( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + LogicalBlockSize, + TRUE, + &PtrTIBCB, + (PVOID*)&PtrPinnedTIndirectBlock )) + { + return FALSE; + } + + // Read the Block numbers off the Triple Indirect Pointer Block... + for( TIndex = 0; TIndex < (LogicalBlockSize/sizeof(ULONG)); TIndex++ ) + { + if( PtrPinnedTIndirectBlock[ TIndex ] ) + { + VolumeByteOffset.QuadPart = PtrPinnedTIndirectBlock[TIndex] * LogicalBlockSize; + if (!CcMapData( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + LogicalBlockSize, + TRUE, + &PtrDIBCB, + (PVOID*)&PtrPinnedDIndirectBlock )) + { + return FALSE; + } + + // Read the Block numbers off the Double Indirect Pointer Blocks... + for( DIndex = 0; DIndex < (LogicalBlockSize/sizeof(ULONG)); DIndex++ ) + { + if( PtrPinnedDIndirectBlock[DIndex] ) + { + VolumeByteOffset.QuadPart = PtrPinnedDIndirectBlock[DIndex] * LogicalBlockSize; + if (!CcMapData( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + LogicalBlockSize, + TRUE, + &PtrSIBCB, + (PVOID*)&PtrPinnedSIndirectBlock )) + { + return FALSE; + } + + // Read the Block numbers off the Single Indirect Pointer Blocks and + // free the data blocks + for( SIndex = 0; SIndex < (LogicalBlockSize/sizeof(ULONG)); SIndex++ ) + { + if( PtrPinnedSIndirectBlock[ SIndex ] ) + { + Ext2DeallocBlock( PtrIrpContext, PtrVCB, PtrPinnedSIndirectBlock[SIndex] ); + } + else + { + break; + } + } + CcUnpinData( PtrSIBCB ); + + // Deallocating + // Single Indirect Pointer Block + Ext2DeallocBlock( PtrIrpContext, PtrVCB, PtrPinnedDIndirectBlock[DIndex] ); + } + else + { + break; + } + } + } + else + { + break; + } + } + CcUnpinData( PtrTIBCB ); + // Deallocating Triple Indirect Pointer Blocks + Ext2DeallocBlock( PtrIrpContext, PtrVCB, PtrFCB->IBlock[ EXT2_TIND_BLOCK ] ); + } + + // 2. + // Free up the double indirect blocks... + if( PtrFCB->IBlock[ EXT2_DIND_BLOCK ] ) + { + PBCB PtrDIBCB = NULL; + PBCB PtrSIBCB = NULL; + ULONG * PtrPinnedSIndirectBlock = NULL; + ULONG * PtrPinnedDIndirectBlock = NULL; + + LARGE_INTEGER VolumeByteOffset; + ULONG DIndex, SIndex; + + // Pin the Double Indirect Pointer Block... + VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_DIND_BLOCK ] * LogicalBlockSize; + if (!CcMapData( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + LogicalBlockSize, + TRUE, + &PtrDIBCB, + (PVOID*)&PtrPinnedDIndirectBlock )) + { + return FALSE; + } + + // Read the Block numbers off the Double Indirect Pointer Block... + for( DIndex = 0; DIndex < (LogicalBlockSize/sizeof(ULONG)); DIndex++ ) + { + if( PtrPinnedDIndirectBlock[DIndex] ) + { + VolumeByteOffset.QuadPart = PtrPinnedDIndirectBlock[DIndex] * LogicalBlockSize; + if (!CcMapData( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + LogicalBlockSize, + TRUE, + &PtrSIBCB, + (PVOID*)&PtrPinnedSIndirectBlock )) + { + return FALSE; + } + + // Read the Block numbers off the Single Indirect Pointer Blocks and + // free the data blocks + for( SIndex = 0; SIndex < (LogicalBlockSize/sizeof(ULONG)); SIndex++ ) + { + if( PtrPinnedSIndirectBlock[ SIndex ] ) + { + Ext2DeallocBlock( PtrIrpContext, PtrVCB, PtrPinnedSIndirectBlock[SIndex] ); + } + else + { + break; + } + } + CcUnpinData( PtrSIBCB ); + + // Deallocating + // Single Indirect Pointer Block + Ext2DeallocBlock( PtrIrpContext, PtrVCB, PtrPinnedDIndirectBlock[DIndex] ); + } + else + { + break; + } + } + CcUnpinData( PtrDIBCB ); + // Deallocating Double Indirect Pointer Blocks + Ext2DeallocBlock( PtrIrpContext, PtrVCB, PtrFCB->IBlock[ EXT2_DIND_BLOCK ] ); + } + + // 3. + // Free up the single indirect blocks... + if( PtrFCB->IBlock[ EXT2_IND_BLOCK ] ) + { + PBCB PtrBCB = NULL; + ULONG * PtrPinnedSIndirectBlock = NULL; + LARGE_INTEGER VolumeByteOffset; + ULONG Index; + + // Pin the Single Indirect Pointer Block... + VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_IND_BLOCK ] * LogicalBlockSize; + if (!CcMapData( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + LogicalBlockSize, + TRUE, + &PtrBCB, + (PVOID*)&PtrPinnedSIndirectBlock )) + { + return FALSE; + } + + // Read the Block numbers off the Indirect Pointer Block and + // free the data blocks + for( Index = 0; Index < (LogicalBlockSize/sizeof(ULONG)); Index++ ) + { + if( PtrPinnedSIndirectBlock[Index] ) + { + Ext2DeallocBlock( PtrIrpContext, PtrVCB, PtrPinnedSIndirectBlock[Index] ); + } + else + { + break; + } + } + CcUnpinData( PtrBCB ); + Ext2DeallocBlock( PtrIrpContext, PtrVCB, PtrFCB->IBlock[ EXT2_IND_BLOCK ] ); + } + + // 4. + // Free up the direct blocks... + for( i = 0; i < EXT2_NDIR_BLOCKS; i++ ) + { + if( PtrFCB->IBlock[ i ] ) + { + Ext2DeallocBlock( PtrIrpContext, PtrVCB, PtrFCB->IBlock[ i ] ); + } + else + { + break; + } + } + return TRUE; +} + + +BOOLEAN Ext2TruncateFileAllocationSize( + PtrExt2IrpContext PtrIrpContext, + PtrExt2FCB PtrFCB, + PFILE_OBJECT PtrFileObject, + PLARGE_INTEGER PtrAllocationSize ) +{ + PtrExt2VCB PtrVCB = PtrFCB->PtrVCB; + ULONG LogicalBlockSize; + ULONG i; + + ULONG NoOfBlocksToBeLeft= 0; + ULONG CurrentBlockNo = 0; + + // + // This function has not been tested... + // + Ext2BreakPoint(); + + LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize; + NoOfBlocksToBeLeft = (ULONG) (PtrAllocationSize->QuadPart / LogicalBlockSize); + + + + // Release the data blocks... + + // 1. + // Free up the direct blocks... + for( i = NoOfBlocksToBeLeft; i < EXT2_NDIR_BLOCKS; i++ ) + { + if( PtrFCB->IBlock[ i ] ) + { + Ext2DeallocBlock( PtrIrpContext, PtrVCB, PtrFCB->IBlock[ i ] ); + PtrFCB->IBlock[ i ] = 0; + } + else + { + break; + } + } + + // 2. + // Free up the single indirect blocks... + CurrentBlockNo = EXT2_NDIR_BLOCKS; + + if( PtrFCB->IBlock[ EXT2_IND_BLOCK ] ) + { + PBCB PtrBCB = NULL; + ULONG * PtrPinnedSIndirectBlock = NULL; + LARGE_INTEGER VolumeByteOffset; + ULONG Index; + + // Pin the Single Indirect Pointer Block... + VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_IND_BLOCK ] * LogicalBlockSize; + if (!CcMapData( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + LogicalBlockSize, + TRUE, + &PtrBCB, + (PVOID*)&PtrPinnedSIndirectBlock )) + { + return FALSE; + } + + // Read the Block numbers off the Indirect Pointer Block and + // free the data blocks + for( Index = 0; Index < (LogicalBlockSize/sizeof(ULONG)); + Index++, CurrentBlockNo++ ) + { + if( CurrentBlockNo >= NoOfBlocksToBeLeft ) + { + if( PtrPinnedSIndirectBlock[Index] ) + { + Ext2DeallocBlock( PtrIrpContext, PtrVCB, PtrPinnedSIndirectBlock[Index] ); + } + else + { + break; + } + } + else if( !PtrPinnedSIndirectBlock[Index] ) + { + break; + } + } + if( NoOfBlocksToBeLeft <= EXT2_NDIR_BLOCKS ) + { + Ext2DeallocBlock( PtrIrpContext, PtrVCB, PtrFCB->IBlock[ EXT2_IND_BLOCK ] ); + PtrFCB->IBlock[ EXT2_IND_BLOCK ] = 0; + } + + CcUnpinData( PtrBCB ); + } + + // 3. + // Free up the double indirect blocks... + if( PtrFCB->IBlock[ EXT2_DIND_BLOCK ] ) + { + + } + + // 4. + // Free up the triple indirect blocks... + if( PtrFCB->IBlock[ EXT2_TIND_BLOCK ] ) + { + + } + + return TRUE; +} + +BOOLEAN Ext2IsDirectoryEmpty( + PtrExt2FCB PtrFCB, + PtrExt2CCB PtrCCB, + PtrExt2IrpContext PtrIrpContext) +{ + + PFILE_OBJECT PtrFileObject = NULL; + + if( !Ext2IsFlagOn(PtrFCB->FCBFlags, EXT2_FCB_DIRECTORY) ) + { + return FALSE; + } + + // 1. + // Initialize the Blocks in the FCB... + // + Ext2InitializeFCBInodeInfo( PtrFCB ); + + + // 2. + // Get hold of the file object... + // + PtrFileObject = PtrCCB->PtrFileObject; + + + // 3. + // Now initiating Caching, pinned access to be precise ... + // + if (PtrFileObject->PrivateCacheMap == NULL) + { + CcInitializeCacheMap(PtrFileObject, (PCC_FILE_SIZES)(&(PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize)), + TRUE, // We utilize pin access for directories + &(Ext2GlobalData.CacheMgrCallBacks), // callbacks + PtrFCB ); // The context used in callbacks + } + + // 4. + // Getting down to the real business now... ;) + // Read in the directory contents and do a search + // + { + LARGE_INTEGER StartBufferOffset; + ULONG PinBufferLength; + ULONG BufferIndex; + PBCB PtrBCB = NULL; + BYTE * PtrPinnedBlockBuffer = NULL; + PEXT2_DIR_ENTRY PtrDirEntry = NULL; + BOOLEAN Found = FALSE; + int i; + + + + StartBufferOffset.QuadPart = 0; + + // + // Read in the whole directory + // **Bad programming** + // Will do for now. + // + PinBufferLength = PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.LowPart; + if (!CcMapData( PtrFileObject, + &StartBufferOffset, + PinBufferLength, + TRUE, + &PtrBCB, + (PVOID*)&PtrPinnedBlockBuffer ) ) + { + return FALSE; + } + + // + // Walking through now... + // + for( BufferIndex = 0, Found = FALSE; !Found && BufferIndex < ( PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart - 1) ; BufferIndex += PtrDirEntry->rec_len ) + { + PtrDirEntry = (PEXT2_DIR_ENTRY) &PtrPinnedBlockBuffer[ BufferIndex ]; + if( PtrDirEntry->inode == 0) + { + // Deleted entry... + // Ignore... + continue; + } + if( PtrDirEntry->name[0] == '.' ) + { + if( PtrDirEntry->name_len == 1 || + ( PtrDirEntry->name_len == 2 && PtrDirEntry->name[1] == '.' ) ) + { + continue; + } + } + Found = TRUE; + } + CcUnpinData( PtrBCB ); + PtrBCB = NULL; + + return !Found; + } +} + + +NTSTATUS Ext2RenameOrLinkFile( + PtrExt2FCB PtrSourceFCB, + PFILE_OBJECT PtrSourceFileObject, + PtrExt2IrpContext PtrIrpContext, + PIRP PtrIrp, + PFILE_RENAME_INFORMATION PtrRenameInfo) +{ + PtrExt2FCB PtrParentFCB = NULL; + PtrExt2VCB PtrSourceVCB = PtrSourceFCB->PtrVCB; + + PtrExt2FCB PtrTargetFCB = NULL; + PtrExt2CCB PtrTargetCCB = NULL; + PtrExt2VCB PtrTargetVCB = NULL; + + + FILE_INFORMATION_CLASS FunctionalityRequested; + PIO_STACK_LOCATION PtrIoStackLocation = NULL; + PFILE_OBJECT TargetFileObject = NULL; + BOOLEAN ReplaceExistingFile = FALSE; + BOOLEAN Found = FALSE; + + PtrIoStackLocation = IoGetCurrentIrpStackLocation(PtrIrp); + FunctionalityRequested = PtrIoStackLocation->Parameters.SetFile.FileInformationClass; + TargetFileObject = PtrIoStackLocation->Parameters.SetFile.FileObject; + ReplaceExistingFile = PtrIoStackLocation->Parameters.SetFile.ReplaceIfExists; + + // Get the FCB and CCB pointers + Ext2GetFCB_CCB_VCB_FromFileObject ( + TargetFileObject , &PtrTargetFCB, &PtrTargetCCB, &PtrTargetVCB); + + if( !PtrTargetCCB ) + { + return STATUS_ACCESS_DENIED; + } + if( PtrTargetVCB != PtrSourceVCB ) + { + // Cannot rename across volumes... + return STATUS_ACCESS_DENIED; + } + if ( !Ext2IsFlagOn( PtrTargetFCB->FCBFlags, EXT2_FCB_DIRECTORY ) ) + { + // Target has to be a folder... + return STATUS_ACCESS_DENIED; + } + + // 1. + // Open the parent folder... + PtrParentFCB = Ext2LocateFCBInCore( PtrSourceVCB, PtrSourceFCB->ParentINodeNo ); + if( !PtrParentFCB ) + { + // Get the folder from the disk + // Use the inode no PtrSourceFCB->ParentINodeNo + // + // For now... + return STATUS_ACCESS_DENIED; + } + + // 2. + // Check if the file exists in the TargetFolder... + { + LARGE_INTEGER StartBufferOffset; + ULONG PinBufferLength; + ULONG BufferIndex; + PBCB PtrBCB = NULL; + BYTE * PtrPinnedBlockBuffer = NULL; + PEXT2_DIR_ENTRY PtrDirEntry = NULL; + int i; + + StartBufferOffset.QuadPart = 0; + + // + // Read in the whole directory + // + if ( TargetFileObject->PrivateCacheMap == NULL ) + { + CcInitializeCacheMap( + TargetFileObject, + (PCC_FILE_SIZES)(&(PtrTargetFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize)), + TRUE, // We utilize pin access for directories + &(Ext2GlobalData.CacheMgrCallBacks), // callbacks + PtrTargetCCB ); // The context used in callbacks + } + + PinBufferLength = PtrTargetFCB->NTRequiredFCB.CommonFCBHeader.FileSize.LowPart; + if (!CcMapData( TargetFileObject, + &StartBufferOffset, + PinBufferLength, + TRUE, + &PtrBCB, + (PVOID*)&PtrPinnedBlockBuffer ) ) + { + return FALSE; + } + + // + // Walking through now... + // + for( BufferIndex = 0, Found = FALSE; !Found && BufferIndex < ( PtrTargetFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart - 1) ; BufferIndex += PtrDirEntry->rec_len ) + { + PtrDirEntry = (PEXT2_DIR_ENTRY) &PtrPinnedBlockBuffer[ BufferIndex ]; + if( PtrDirEntry->inode == 0) + { + // Deleted entry... + // Ignore... + continue; + } + if( PtrDirEntry->name_len == (PtrTargetCCB->RenameLinkTargetFileName.Length/2) ) + { + Found = TRUE; + for( i =0; i < PtrDirEntry->name_len ; i++ ) + { + if( PtrDirEntry->name[i] != PtrTargetCCB->RenameLinkTargetFileName.Buffer[i] ) + { + Found = FALSE; + break; + } + } + } + } + CcUnpinData( PtrBCB ); + PtrBCB = NULL; + } + + // 3. + // If the file exists, delete it if requested.. + if( Found ) + { + if( !ReplaceExistingFile ) + { + return STATUS_OBJECT_NAME_COLLISION; + } + // Delete the file... + // Reject this for now... + return STATUS_ACCESS_DENIED; + } + + + { + ULONG Type = EXT2_FT_REG_FILE; + if( Ext2IsFlagOn( PtrSourceFCB->FCBFlags, EXT2_FCB_DIRECTORY ) ) + { + Type = EXT2_FT_DIR; + } + + ASSERT( TargetFileObject ); + + // 4. + // Remove the old entry... + Ext2FreeDirectoryEntry( PtrIrpContext, PtrParentFCB, + &PtrSourceFCB->FCBName->ObjectName); + + // 5. + // Create a new entry... + Ext2MakeNewDirectoryEntry( + PtrIrpContext, // This IRP Context + PtrTargetFCB, // Parent Folder FCB + TargetFileObject, // Parent Folder Object + &PtrTargetCCB->RenameLinkTargetFileName, // New entry's name + Type, // The type of the new entry + PtrSourceFCB->INodeNo ); // The inode no of the new entry... + + } + + // 6. + // Update the PtrSourceFCB... + { + + PtrExt2ObjectName PtrObjectName; + if( PtrSourceFCB->FCBName ) + { + Ext2ReleaseObjectName( PtrSourceFCB->FCBName ); + } + PtrObjectName = Ext2AllocateObjectName(); + Ext2CopyUnicodeString( &PtrObjectName->ObjectName, &PtrTargetCCB->RenameLinkTargetFileName ); + PtrSourceFCB->FCBName = PtrObjectName; + PtrSourceFCB->ParentINodeNo = PtrTargetFCB->INodeNo; + } + + if( PtrTargetCCB->RenameLinkTargetFileName.Length ) + { + Ext2DeallocateUnicodeString( &PtrTargetCCB->RenameLinkTargetFileName ); + } + + return STATUS_SUCCESS; +} diff --git a/reactos/drivers/fs/ext2/src/misc.c b/reactos/drivers/fs/ext2/src/misc.c new file mode 100644 index 00000000000..fd9c98099f0 --- /dev/null +++ b/reactos/drivers/fs/ext2/src/misc.c @@ -0,0 +1,2116 @@ +/************************************************************************* +* +* File: misc.c +* +* Module: Ext2 File System Driver (Kernel mode execution only) +* +* Description: +* This file contains some miscellaneous support routines. +* +* Author: Manoj Paul Joseph +* +* +*************************************************************************/ + +#include "ext2fsd.h" + +// define the file specific bug-check id +#define EXT2_BUG_CHECK_ID EXT2_FILE_MISC + +#define DEBUG_LEVEL ( DEBUG_TRACE_MISC ) + +/************************************************************************* +* +* Function: Ext2InitializeZones() +* +* Description: +* Allocates some memory for global zones used to allocate FSD structures. +* Either all memory will be allocated or we will back out gracefully. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +NTSTATUS Ext2InitializeZones( +void) +{ + NTSTATUS RC = STATUS_SUCCESS; + uint32 SizeOfZone = Ext2GlobalData.DefaultZoneSizeInNumStructs; + uint32 SizeOfObjectNameZone = 0; + uint32 SizeOfCCBZone = 0; + uint32 SizeOfFCBZone = 0; + uint32 SizeOfByteLockZone = 0; + uint32 SizeOfIrpContextZone = 0; + + try { + + // initialize the spinlock protecting the zones + KeInitializeSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock)); + + // determine memory requirements + switch (MmQuerySystemSize()) { + case MmSmallSystem: + // this is just for illustration purposes. I will multiply + // number of structures with some arbitrary amount depending + // upon available memory in the system ... You should choose a + // more intelligent method suitable to your memory consumption + // and the amount of memory available. + SizeOfObjectNameZone = (2 * SizeOfZone * Ext2QuadAlign(sizeof(Ext2ObjectName))) + sizeof(ZONE_SEGMENT_HEADER); + SizeOfCCBZone = (2 * SizeOfZone * Ext2QuadAlign(sizeof(Ext2CCB))) + sizeof(ZONE_SEGMENT_HEADER); + SizeOfFCBZone = (2 * SizeOfZone * Ext2QuadAlign(sizeof(Ext2FCB))) + sizeof(ZONE_SEGMENT_HEADER); + SizeOfByteLockZone = (2 * SizeOfZone * Ext2QuadAlign(sizeof(Ext2FileLockInfo))) + sizeof(ZONE_SEGMENT_HEADER); + SizeOfIrpContextZone = (2 * SizeOfZone * Ext2QuadAlign(sizeof(Ext2IrpContext))) + sizeof(ZONE_SEGMENT_HEADER); + break; + case MmMediumSystem: + SizeOfObjectNameZone = (4 * SizeOfZone * Ext2QuadAlign(sizeof(Ext2ObjectName))) + sizeof(ZONE_SEGMENT_HEADER); + SizeOfCCBZone = (4 * SizeOfZone * Ext2QuadAlign(sizeof(Ext2CCB))) + sizeof(ZONE_SEGMENT_HEADER); + SizeOfFCBZone = (4 * SizeOfZone * Ext2QuadAlign(sizeof(Ext2FCB))) + sizeof(ZONE_SEGMENT_HEADER); + SizeOfByteLockZone = (4 * SizeOfZone * Ext2QuadAlign(sizeof(Ext2FileLockInfo))) + sizeof(ZONE_SEGMENT_HEADER); + SizeOfIrpContextZone = (4 * SizeOfZone * Ext2QuadAlign(sizeof(Ext2IrpContext))) + sizeof(ZONE_SEGMENT_HEADER); + break; + case MmLargeSystem: + SizeOfObjectNameZone = (8 * SizeOfZone * Ext2QuadAlign(sizeof(Ext2ObjectName))) + sizeof(ZONE_SEGMENT_HEADER); + SizeOfCCBZone = (8 * SizeOfZone * Ext2QuadAlign(sizeof(Ext2CCB))) + sizeof(ZONE_SEGMENT_HEADER); + SizeOfFCBZone = (8 * SizeOfZone * Ext2QuadAlign(sizeof(Ext2FCB))) + sizeof(ZONE_SEGMENT_HEADER); + SizeOfByteLockZone = (8 * SizeOfZone * Ext2QuadAlign(sizeof(Ext2FileLockInfo))) + sizeof(ZONE_SEGMENT_HEADER); + SizeOfIrpContextZone = (8 * SizeOfZone * Ext2QuadAlign(sizeof(Ext2IrpContext))) + sizeof(ZONE_SEGMENT_HEADER); + break; + } + + // typical NT methodology (at least until *someone* exposed the "difference" between a server and workstation ;-) + if (MmIsThisAnNtAsSystem()) { + SizeOfObjectNameZone *= EXT2_NTAS_MULTIPLE; + SizeOfCCBZone *= EXT2_NTAS_MULTIPLE; + SizeOfFCBZone *= EXT2_NTAS_MULTIPLE; + SizeOfByteLockZone *= EXT2_NTAS_MULTIPLE; + SizeOfIrpContextZone *= EXT2_NTAS_MULTIPLE; + } + + // allocate memory for each of the zones and initialize the zones ... + if (!(Ext2GlobalData.ObjectNameZone = Ext2AllocatePool(NonPagedPool, SizeOfObjectNameZone ))) { + RC = STATUS_INSUFFICIENT_RESOURCES; + try_return(RC); + } + + if (!(Ext2GlobalData.CCBZone = Ext2AllocatePool(NonPagedPool, SizeOfCCBZone ))) { + RC = STATUS_INSUFFICIENT_RESOURCES; + try_return(RC); + } + + if (!(Ext2GlobalData.FCBZone = Ext2AllocatePool(NonPagedPool, SizeOfFCBZone ))) { + RC = STATUS_INSUFFICIENT_RESOURCES; + try_return(RC); + } + + if (!(Ext2GlobalData.ByteLockZone = Ext2AllocatePool(NonPagedPool, SizeOfByteLockZone ))) { + RC = STATUS_INSUFFICIENT_RESOURCES; + try_return(RC); + } + + if (!(Ext2GlobalData.IrpContextZone = Ext2AllocatePool(NonPagedPool, SizeOfIrpContextZone ))) { + RC = STATUS_INSUFFICIENT_RESOURCES; + try_return(RC); + } + + // initialize each of the zone headers ... + if (!NT_SUCCESS(RC = ExInitializeZone(&(Ext2GlobalData.ObjectNameZoneHeader), + Ext2QuadAlign(sizeof(Ext2ObjectName)), + Ext2GlobalData.ObjectNameZone, SizeOfObjectNameZone))) { + // failed the initialization, leave ... + try_return(RC); + } + + if (!NT_SUCCESS(RC = ExInitializeZone(&(Ext2GlobalData.CCBZoneHeader), + Ext2QuadAlign(sizeof(Ext2CCB)), + Ext2GlobalData.CCBZone, + SizeOfCCBZone))) { + // failed the initialization, leave ... + try_return(RC); + } + + if (!NT_SUCCESS(RC = ExInitializeZone(&(Ext2GlobalData.FCBZoneHeader), + Ext2QuadAlign(sizeof(Ext2FCB)), + Ext2GlobalData.FCBZone, + SizeOfFCBZone))) { + // failed the initialization, leave ... + try_return(RC); + } + + if (!NT_SUCCESS(RC = ExInitializeZone(&(Ext2GlobalData.ByteLockZoneHeader), + Ext2QuadAlign(sizeof(Ext2FileLockInfo)), + Ext2GlobalData.ByteLockZone, + SizeOfByteLockZone))) { + // failed the initialization, leave ... + try_return(RC); + } + + if (!NT_SUCCESS(RC = ExInitializeZone(&(Ext2GlobalData.IrpContextZoneHeader), + Ext2QuadAlign(sizeof(Ext2IrpContext)), + Ext2GlobalData.IrpContextZone, + SizeOfIrpContextZone))) { + // failed the initialization, leave ... + try_return(RC); + } + + try_exit: NOTHING; + + } finally { + if (!NT_SUCCESS(RC)) { + // invoke the destroy routine now ... + Ext2DestroyZones(); + } else { + // mark the fact that we have allocated zones ... + Ext2SetFlag(Ext2GlobalData.Ext2Flags, EXT2_DATA_FLAGS_ZONES_INITIALIZED); + } + } + + return(RC); +} + + +/************************************************************************* +* +* Function: Ext2DestroyZones() +* +* Description: +* Free up the previously allocated memory. NEVER do this once the +* driver has been successfully loaded. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: None +* +*************************************************************************/ +void Ext2DestroyZones( +void) +{ + try { + // free up each of the pools + DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [misc]", Ext2GlobalData.ObjectNameZone); + ExFreePool(Ext2GlobalData.ObjectNameZone); + + DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [misc]", Ext2GlobalData.CCBZone); + ExFreePool(Ext2GlobalData.CCBZone); + + DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [misc]", Ext2GlobalData.FCBZone); + ExFreePool(Ext2GlobalData.FCBZone); + + DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [misc]", Ext2GlobalData.ByteLockZone); + ExFreePool(Ext2GlobalData.ByteLockZone); + + DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [misc]", Ext2GlobalData.IrpContextZone); + ExFreePool(Ext2GlobalData.IrpContextZone); + + try_exit: NOTHING; + + } + finally + { + Ext2ClearFlag(Ext2GlobalData.Ext2Flags, EXT2_DATA_FLAGS_ZONES_INITIALIZED); + } + + return; +} + + +/************************************************************************* +* +* Function: Ext2IsIrpTopLevel() +* +* Description: +* Helps the FSD determine who the "top level" caller is for this +* request. A request can originate directly from a user process +* (in which case, the "top level" will be NULL when this routine +* is invoked), OR the user may have originated either from the NT +* Cache Manager/VMM ("top level" may be set), or this could be a +* recursion into our code in which we would have set the "top level" +* field the last time around. +* +* Expected Interrupt Level (for execution) : +* +* whatever level a particular dispatch routine is invoked at. +* +* Return Value: TRUE/FALSE (TRUE if top level was NULL when routine invoked) +* +*************************************************************************/ +BOOLEAN Ext2IsIrpTopLevel( +PIRP Irp) // the IRP sent to our dispatch routine +{ + BOOLEAN ReturnCode = FALSE; + + if (IoGetTopLevelIrp() == NULL) + { + // OK, so we can set ourselves to become the "top level" component + IoSetTopLevelIrp( Irp ); + ReturnCode = TRUE; + } + + return(ReturnCode); +} + + +/************************************************************************* +* +* Function: Ext2ExceptionFilter() +* +* Description: +* This routines allows the driver to determine whether the exception +* is an "allowed" exception i.e. one we should not-so-quietly consume +* ourselves, or one which should be propagated onwards in which case +* we will most likely bring down the machine. +* +* This routine employs the services of FsRtlIsNtstatusExpected(). This +* routine returns a BOOLEAN result. A RC of FALSE will cause us to return +* EXCEPTION_CONTINUE_SEARCH which will probably cause a panic. +* The FsRtl.. routine returns FALSE iff exception values are (currently) : +* STATUS_DATATYPE_MISALIGNMENT || STATUS_ACCESS_VIOLATION || +* STATUS_ILLEGAL_INSTRUCTION || STATUS_INSTRUCTION_MISALIGNMENT +* +* Expected Interrupt Level (for execution) : +* +* ? +* +* Return Value: EXCEPTION_EXECUTE_HANDLER/EXECEPTION_CONTINUE_SEARCH +* +*************************************************************************/ +long Ext2ExceptionFilter( +PtrExt2IrpContext PtrIrpContext, +PEXCEPTION_POINTERS PtrExceptionPointers ) +{ + long ReturnCode = EXCEPTION_EXECUTE_HANDLER; + NTSTATUS ExceptionCode = STATUS_SUCCESS; + + // figure out the exception code + ExceptionCode = PtrExceptionPointers->ExceptionRecord->ExceptionCode; + + if ((ExceptionCode == STATUS_IN_PAGE_ERROR) && (PtrExceptionPointers->ExceptionRecord->NumberParameters >= 3)) + { + ExceptionCode = PtrExceptionPointers->ExceptionRecord->ExceptionInformation[2]; + } + + if (PtrIrpContext) + { + PtrIrpContext->SavedExceptionCode = ExceptionCode; + Ext2SetFlag(PtrIrpContext->IrpContextFlags, EXT2_IRP_CONTEXT_EXCEPTION); + } + + // check if we should propagate this exception or not + if (!(FsRtlIsNtstatusExpected(ExceptionCode))) + { + // we are not ok, propagate this exception. + // NOTE: we will bring down the machine ... + ReturnCode = EXCEPTION_CONTINUE_SEARCH; + + // better free up the IrpContext now ... + if (PtrIrpContext) + { + Ext2ReleaseIrpContext(PtrIrpContext); + } + } + + // if you wish to perform some special processing when + // not propagating the exception, set up the state for + // special processing now ... + + // return the appropriate code + return(ReturnCode); +} + +/************************************************************************* +* +* Function: Ext2ExceptionHandler() +* +* Description: +* One of the routines in the FSD or in the modules we invoked encountered +* an exception. We have decided that we will "handle" the exception. +* Therefore we will prevent the machine from a panic ... +* You can do pretty much anything you choose to in your commercial +* driver at this point to ensure a graceful exit. In the sample +* driver, I will simply free up the IrpContext (if any), set the +* error code in the IRP and complete the IRP at this time ... +* +* Expected Interrupt Level (for execution) : +* +* ? +* +* Return Value: Error code +* +*************************************************************************/ +NTSTATUS Ext2ExceptionHandler( +PtrExt2IrpContext PtrIrpContext, +PIRP Irp) +{ + NTSTATUS RC; + + ASSERT(Irp); + + if (PtrIrpContext) + { + RC = PtrIrpContext->SavedExceptionCode; + // Free irp context here + Ext2ReleaseIrpContext(PtrIrpContext); + } + else + { + // must be insufficient resources ...? + RC = STATUS_INSUFFICIENT_RESOURCES; + } + + // set the error code in the IRP + Irp->IoStatus.Status = RC; + Irp->IoStatus.Information = 0; + + // complete the IRP + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + return(RC); +} + +/************************************************************************* +* +* Function: Ext2LogEvent() +* +* Description: +* Log a message in the NT Event Log. This is a rather simplistic log +* methodology since you can potentially utilize the event log to +* provide a lot of information to the user (and you should too!) +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: None +* +*************************************************************************/ +void Ext2LogEvent( +NTSTATUS Ext2EventLogId, // the Ext2 private message id +NTSTATUS RC) // any NT error code we wish to log ... +{ + try + { + + // Implement a call to IoAllocateErrorLogEntry() followed by a call + // to IoWriteErrorLogEntry(). You should note that the call to IoWriteErrorLogEntry() + // will free memory for the entry once the write completes (which in actuality + // is an asynchronous operation). + + } + except (EXCEPTION_EXECUTE_HANDLER) + { + // nothing really we can do here, just do not wish to crash ... + NOTHING; + } + + return; +} + +/************************************************************************* +* +* Function: Ext2AllocateObjectName() +* +* Description: +* Allocate a new ObjectName structure to represent an open on-disk object. +* Also initialize the ObjectName structure to NULL. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: A pointer to the ObjectName structure OR NULL. +* +*************************************************************************/ +PtrExt2ObjectName Ext2AllocateObjectName( +void) +{ + PtrExt2ObjectName PtrObjectName = NULL; + BOOLEAN AllocatedFromZone = TRUE; + KIRQL CurrentIrql; +/* + // first, try to allocate out of the zone + KeAcquireSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), &CurrentIrql); + if (!ExIsFullZone(&(Ext2GlobalData.ObjectNameZoneHeader))) { + // we have enough memory + PtrObjectName = (PtrExt2ObjectName)ExAllocateFromZone(&(Ext2GlobalData.ObjectNameZoneHeader)); + + // release the spinlock + KeReleaseSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), CurrentIrql); + } else { + // release the spinlock + KeReleaseSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), CurrentIrql); + + // if we failed to obtain from the zone, get it directly from the VMM +*/ + PtrObjectName = (PtrExt2ObjectName)Ext2AllocatePool(NonPagedPool, Ext2QuadAlign(sizeof(Ext2ObjectName)) ); + AllocatedFromZone = FALSE; +/* + } +*/ + // if we could not obtain the required memory, bug-check. + // Do NOT do this in your commercial driver, instead handle the error gracefully ... + if (!PtrObjectName) + { + Ext2Panic(STATUS_INSUFFICIENT_RESOURCES, Ext2QuadAlign(sizeof(Ext2ObjectName)), 0); + } + + // zero out the allocated memory block + RtlZeroMemory( PtrObjectName, Ext2QuadAlign(sizeof(Ext2ObjectName)) ); + + // set up some fields ... + PtrObjectName->NodeIdentifier.NodeType = EXT2_NODE_TYPE_OBJECT_NAME; + PtrObjectName->NodeIdentifier.NodeSize = Ext2QuadAlign(sizeof(Ext2ObjectName)); + + + if (!AllocatedFromZone) + { + Ext2SetFlag(PtrObjectName->ObjectNameFlags, EXT2_OB_NAME_NOT_FROM_ZONE); + } + + return(PtrObjectName); +} + + +/************************************************************************* +* +* Function: Ext2ReleaseObjectName() +* +* Description: +* Deallocate a previously allocated structure. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: None +* +*************************************************************************/ +void Ext2ReleaseObjectName( +PtrExt2ObjectName PtrObjectName) +{ + KIRQL CurrentIrql; + + ASSERT(PtrObjectName); + PtrObjectName->NodeIdentifier.NodeType = EXT2_NODE_TYPE_FREED; +#ifdef USE_ZONES + + // give back memory either to the zone or to the VMM + if (!(PtrObjectName->ObjectNameFlags & EXT2_OB_NAME_NOT_FROM_ZONE)) + { + // back to the zone + KeAcquireSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), &CurrentIrql); + ExFreeToZone(&(Ext2GlobalData.ObjectNameZoneHeader), PtrObjectName); + KeReleaseSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), CurrentIrql); + } + else + { +#endif + + Ext2DeallocateUnicodeString( & PtrObjectName->ObjectName ); + + DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [misc]", PtrObjectName); + ExFreePool(PtrObjectName); + +#ifdef USE_ZONES + } +#endif + return; +} + +/************************************************************************* +* +* Function: Ext2AllocateCCB() +* +* Description: +* Allocate a new CCB structure to represent an open on-disk object. +* Also initialize the CCB structure to NULL. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: A pointer to the CCB structure OR NULL. +* +*************************************************************************/ +PtrExt2CCB Ext2AllocateCCB( +void) +{ + PtrExt2CCB PtrCCB = NULL; + BOOLEAN AllocatedFromZone = TRUE; + KIRQL CurrentIrql; + + +#ifdef USE_ZONES + // first, try to allocate out of the zone + KeAcquireSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), &CurrentIrql); + if (!ExIsFullZone(&(Ext2GlobalData.CCBZoneHeader))) + { + // we have enough memory + PtrCCB = (PtrExt2CCB)ExAllocateFromZone(&(Ext2GlobalData.CCBZoneHeader)); + + // release the spinlock + KeReleaseSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), CurrentIrql); + } + else + { + // release the spinlock + KeReleaseSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), CurrentIrql); + // if we failed to obtain from the zone, get it directly from the VMM +#endif + + PtrCCB = (PtrExt2CCB)Ext2AllocatePool(NonPagedPool, Ext2QuadAlign(sizeof(Ext2CCB)) ); + AllocatedFromZone = FALSE; + +#ifdef USE_ZONES + } +#endif + + // if we could not obtain the required memory, bug-check. + // Do NOT do this in your commercial driver, instead handle the error gracefully ... + if (!PtrCCB) + { + Ext2Panic(STATUS_INSUFFICIENT_RESOURCES, Ext2QuadAlign(sizeof(Ext2CCB)), 0); + } + + // zero out the allocated memory block + RtlZeroMemory(PtrCCB, Ext2QuadAlign(sizeof(Ext2CCB))); + + // set up some fields ... + PtrCCB->NodeIdentifier.NodeType = EXT2_NODE_TYPE_CCB; + PtrCCB->NodeIdentifier.NodeSize = Ext2QuadAlign(sizeof(Ext2CCB)); + + + if (!AllocatedFromZone) + { + Ext2SetFlag(PtrCCB->CCBFlags, EXT2_CCB_NOT_FROM_ZONE); + } + + return(PtrCCB); +} + +/************************************************************************* +* +* Function: Ext2ReleaseCCB() +* +* Description: +* Deallocate a previously allocated structure. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: None +* +*************************************************************************/ +void Ext2ReleaseCCB( +PtrExt2CCB PtrCCB) +{ + KIRQL CurrentIrql; + + ASSERT( PtrCCB ); + if(PtrCCB->NodeIdentifier.NodeType != EXT2_NODE_TYPE_CCB) + { + Ext2Panic( PtrCCB, PtrCCB->NodeIdentifier.NodeType, EXT2_NODE_TYPE_CCB ) ; + } + + Ext2DeallocateUnicodeString( &PtrCCB->DirectorySearchPattern ); + Ext2DeallocateUnicodeString( &PtrCCB->AbsolutePathName ); + Ext2DeallocateUnicodeString( &PtrCCB->RenameLinkTargetFileName ); + + +#ifdef USE_ZONES + + // give back memory either to the zone or to the VMM + if (!(PtrCCB->CCBFlags & EXT2_CCB_NOT_FROM_ZONE)) + { + // back to the zone + KeAcquireSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), &CurrentIrql); + ExFreeToZone(&(Ext2GlobalData.CCBZoneHeader), PtrCCB); + KeReleaseSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), CurrentIrql); + } + else + { +#endif + PtrCCB->NodeIdentifier.NodeType = EXT2_NODE_TYPE_FREED; + DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [misc]", PtrCCB); + ExFreePool(PtrCCB); + +#ifdef USE_ZONES + } +#endif + + return; +} + +/************************************************************************* +* +* Function: Ext2AllocateFCB() +* +* Description: +* Allocate a new FCB structure to represent an open on-disk object. +* Also initialize the FCB structure to NULL. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: A pointer to the FCB structure OR NULL. +* +*************************************************************************/ +PtrExt2FCB Ext2AllocateFCB( +void) +{ + PtrExt2FCB PtrFCB = NULL; + BOOLEAN AllocatedFromZone = TRUE; + KIRQL CurrentIrql; + + // first, try to allocate out of the zone +#ifdef USE_ZONES + + KeAcquireSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), &CurrentIrql); + if (!ExIsFullZone(&(Ext2GlobalData.FCBZoneHeader))) { + // we have enough memory + PtrFCB = (PtrExt2FCB)ExAllocateFromZone(&(Ext2GlobalData.FCBZoneHeader)); + + // release the spinlock + KeReleaseSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), CurrentIrql); + } else { + // release the spinlock + KeReleaseSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), CurrentIrql); +#endif + // if we failed to obtain from the zone, get it directly from the VMM + PtrFCB = (PtrExt2FCB)Ext2AllocatePool(NonPagedPool, Ext2QuadAlign(sizeof(Ext2FCB)) ); + AllocatedFromZone = FALSE; + +#ifdef USE_ZONES + } +#endif + + // if we could not obtain the required memory, bug-check. + // Do NOT do this in your commercial driver, instead handle the error gracefully ... + if (!PtrFCB) + { + Ext2Panic(STATUS_INSUFFICIENT_RESOURCES, Ext2QuadAlign(sizeof(Ext2FCB)), 0); + } + + // zero out the allocated memory block + RtlZeroMemory(PtrFCB, Ext2QuadAlign(sizeof(Ext2FCB))); + + // set up some fields ... + PtrFCB->NodeIdentifier.NodeType = EXT2_NODE_TYPE_FCB; + PtrFCB->NodeIdentifier.NodeSize = Ext2QuadAlign(sizeof(Ext2FCB)); + + + if (!AllocatedFromZone) + { + Ext2SetFlag(PtrFCB->FCBFlags, EXT2_FCB_NOT_FROM_ZONE); + } + + return(PtrFCB); +} + + +/************************************************************************* +* +* Function: Ext2CreateNewFCB() +* +* Description: +* We want to create a new FCB. We will also create a new CCB (presumably) +* later. Simply allocate a new FCB structure and initialize fields +* appropriately. +* This function also takes the file size values that the caller must +* have obtained and will set the file size fields appropriately in the +* CommonFCBHeader. +* Finally, this routine will initialize the FileObject structure passed +* in to this function. If you decide to fail the call later, remember +* to uninitialize the fields. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: A pointer to the FCB structure OR NULL. +* +*************************************************************************/ +NTSTATUS Ext2CreateNewFCB( +PtrExt2FCB *ReturnedFCB, +LARGE_INTEGER AllocationSize, +LARGE_INTEGER EndOfFile, +PFILE_OBJECT PtrFileObject, +PtrExt2VCB PtrVCB, +PtrExt2ObjectName PtrObjectName) +{ + NTSTATUS RC = STATUS_SUCCESS; + + PtrExt2FCB PtrFCB = NULL; + PtrExt2NTRequiredFCB PtrReqdFCB = NULL; + PFSRTL_COMMON_FCB_HEADER PtrCommonFCBHeader = NULL; + + ASSERT( PtrVCB ); + + try + { + if( !PtrFileObject ) + { + PtrFCB = Ext2GetUsedFCB( PtrVCB ); + + } + else + { + // Obtain a new FCB structure. + // The function Ext2AllocateFCB() will obtain a new structure either + // from a zone or from memory requested directly from the VMM. + PtrFCB = Ext2AllocateFCB(); + } + if (!PtrFCB) + { + // Assume lack of memory. + try_return(RC = STATUS_INSUFFICIENT_RESOURCES); + } + + // Initialize fields required to interface with the NT Cache Manager. + // Note that the returned structure has already been zeroed. This means + // that the SectionObject structure has been zeroed which is a + // requirement for newly created FCB structures. + PtrReqdFCB = &(PtrFCB->NTRequiredFCB); + + // Initialize the MainResource and PagingIoResource structures now. + ExInitializeResourceLite(&(PtrReqdFCB->MainResource)); + Ext2SetFlag(PtrFCB->FCBFlags, EXT2_INITIALIZED_MAIN_RESOURCE); + + ExInitializeResourceLite(&(PtrReqdFCB->PagingIoResource)); + Ext2SetFlag(PtrFCB->FCBFlags, EXT2_INITIALIZED_PAGING_IO_RESOURCE); + + // Start initializing the fields contained in the CommonFCBHeader. + PtrCommonFCBHeader = &(PtrReqdFCB->CommonFCBHeader); + + // Disallow fast-IO for now. + PtrCommonFCBHeader->IsFastIoPossible = FastIoIsNotPossible; + + // Initialize the MainResource and PagingIoResource pointers in + // the CommonFCBHeader structure to point to the ERESOURCE structures we + // have allocated and already initialized above. + PtrCommonFCBHeader->Resource = &(PtrReqdFCB->MainResource); + PtrCommonFCBHeader->PagingIoResource = &(PtrReqdFCB->PagingIoResource); + + // Ignore the Flags field in the CommonFCBHeader for now. Part 3 + // of the book describes it in greater detail. + + // Initialize the file size values here. + PtrCommonFCBHeader->AllocationSize = AllocationSize; + PtrCommonFCBHeader->FileSize = EndOfFile; + + // The following will disable ValidDataLength support. However, your + // FSD may choose to support this concept. + PtrCommonFCBHeader->ValidDataLength.LowPart = 0xFFFFFFFF; + PtrCommonFCBHeader->ValidDataLength.HighPart = 0x7FFFFFFF; + + // Initialize other fields for the FCB here ... + PtrFCB->PtrVCB = PtrVCB; + + // caller MUST ensure that VCB has been acquired exclusively + InsertTailList(&(PtrVCB->FCBListHead), &(PtrFCB->NextFCB)); + + + InitializeListHead(&(PtrFCB->CCBListHead)); + + // Initialize fields contained in the file object now. + if( PtrFileObject ) + { + PtrFileObject->PrivateCacheMap = NULL; + // Note that we could have just as well taken the value of PtrReqdFCB + // directly below. The bottom line however is that the FsContext + // field must point to a FSRTL_COMMON_FCB_HEADER structure. + PtrFileObject->FsContext = (void *)(PtrCommonFCBHeader); + PtrFileObject->SectionObjectPointer = &(PtrFCB->NTRequiredFCB.SectionObject) ; + } + + // Initialising the object name... + PtrFCB->FCBName = PtrObjectName; + + // Returning the FCB... + *ReturnedFCB = PtrFCB; + try_exit: NOTHING; + } + + finally + { + + } + + return(RC); +} + + +/************************************************************************* +* +* Function: Ext2ReleaseFCB() +* +* Description: +* Deallocate a previously allocated structure. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: None +* +*************************************************************************/ +void Ext2ReleaseFCB( +PtrExt2FCB PtrFCB) +{ + KIRQL CurrentIrql; + + AssertFCB( PtrFCB ); + + if( PtrFCB->NodeIdentifier.NodeType != EXT2_NODE_TYPE_FCB ) + { + Ext2Panic( PtrFCB, PtrFCB->NodeIdentifier.NodeType, EXT2_NODE_TYPE_FCB ) ; + } + + + PtrFCB->NodeIdentifier.NodeType = EXT2_NODE_TYPE_FREED; + + /* + // give back memory either to the zone or to the VMM + if (!(PtrFCB->FCBFlags & EXT2_FCB_NOT_FROM_ZONE)) + { + // back to the zone + KeAcquireSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), &CurrentIrql); + ExFreeToZone(&(Ext2GlobalData.FCBZoneHeader), PtrFCB); + KeReleaseSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), CurrentIrql); + } + else + { + */ + + ExDeleteResourceLite( &PtrFCB->NTRequiredFCB.MainResource ); + ExDeleteResourceLite( &PtrFCB->NTRequiredFCB.PagingIoResource ); + + if( PtrFCB->FCBName ) + { + Ext2ReleaseObjectName( PtrFCB->FCBName ); + } + + DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [misc]", PtrFCB); + ExFreePool(PtrFCB); + + /* + } + */ + + return; +} + +/************************************************************************* +* +* Function: Ext2AllocateByteLocks() +* +* Description: +* Allocate a new byte range lock structure and initialize it to NULL. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: A pointer to the Ext2ByteLocks structure OR NULL. +* +*************************************************************************/ +PtrExt2FileLockInfo Ext2AllocateByteLocks( +void) +{ + PtrExt2FileLockInfo PtrByteLocks = NULL; + BOOLEAN AllocatedFromZone = TRUE; + KIRQL CurrentIrql; + + // first, try to allocate out of the zone + KeAcquireSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), &CurrentIrql); + if (!ExIsFullZone(&(Ext2GlobalData.ByteLockZoneHeader))) + { + // we have enough memory + PtrByteLocks = (PtrExt2FileLockInfo)ExAllocateFromZone(&(Ext2GlobalData.ByteLockZoneHeader)); + + // release the spinlock + KeReleaseSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), CurrentIrql); + } + else + { + // release the spinlock + KeReleaseSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), CurrentIrql); + + // if we failed to obtain from the zone, get it directly from the VMM + PtrByteLocks = (PtrExt2FileLockInfo)Ext2AllocatePool(NonPagedPool, Ext2QuadAlign(sizeof(Ext2FileLockInfo)) ); + AllocatedFromZone = FALSE; + } + + // if we could not obtain the required memory, bug-check. + // Do NOT do this in your commercial driver, instead handle the error gracefully ... + if (!PtrByteLocks) + { + Ext2Panic(STATUS_INSUFFICIENT_RESOURCES, Ext2QuadAlign(sizeof(Ext2FileLockInfo)), 0); + } + + // zero out the allocated memory block + RtlZeroMemory(PtrByteLocks, Ext2QuadAlign(sizeof(PtrExt2FileLockInfo))); + + if (!AllocatedFromZone) + { + Ext2SetFlag(PtrByteLocks->FileLockFlags, EXT2_BYTE_LOCK_NOT_FROM_ZONE); + } + + return(PtrByteLocks); +} + +/************************************************************************* +* +* Function: Ext2ReleaseByteLocks() +* +* Description: +* Deallocate a previously allocated structure. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: None +* +*************************************************************************/ +void Ext2ReleaseByteLocks( +PtrExt2FileLockInfo PtrByteLocks) +{ + KIRQL CurrentIrql; + + ASSERT(PtrByteLocks); + + // give back memory either to the zone or to the VMM + if (!(PtrByteLocks->FileLockFlags & EXT2_BYTE_LOCK_NOT_FROM_ZONE)) { + // back to the zone + KeAcquireSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), &CurrentIrql); + ExFreeToZone(&(Ext2GlobalData.ByteLockZoneHeader), PtrByteLocks); + KeReleaseSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), CurrentIrql); + } + else + { + DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [misc]", PtrByteLocks); + ExFreePool(PtrByteLocks); + } + + return; +} + + +/************************************************************************* +* +* Function: Ext2AllocateIrpContext() +* +* Description: +* The sample FSD creates an IRP context for each request received. This +* routine simply allocates (and initializes to NULL) a Ext2IrpContext +* structure. +* Most of the fields in the context structure are then initialized here. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: A pointer to the IrpContext structure OR NULL. +* +*************************************************************************/ +PtrExt2IrpContext Ext2AllocateIrpContext( +PIRP Irp, +PDEVICE_OBJECT PtrTargetDeviceObject) +{ + PtrExt2IrpContext PtrIrpContext = NULL; + BOOLEAN AllocatedFromZone = TRUE; + KIRQL CurrentIrql; + PIO_STACK_LOCATION PtrIoStackLocation = NULL; + + /* + // Allocation from zone not done at present... + + // first, try to allocate out of the zone + KeAcquireSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), &CurrentIrql); + if (!ExIsFullZone(&(Ext2GlobalData.IrpContextZoneHeader))) { + // we have enough memory + PtrIrpContext = (PtrExt2IrpContext)ExAllocateFromZone(&(Ext2GlobalData.IrpContextZoneHeader)); + + // release the spinlock + KeReleaseSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), CurrentIrql); + } else { + // release the spinlock + KeReleaseSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), CurrentIrql); + + + + + // if we failed to obtain from the zone, get it directly from the VMM + PtrIrpContext = (PtrExt2IrpContext)Ext2AllocatePool(NonPagedPool, Ext2QuadAlign(sizeof(Ext2IrpContext)) ); + AllocatedFromZone = FALSE; + } + + //No Zone handling for now + */ + + PtrIrpContext = (PtrExt2IrpContext)Ext2AllocatePool(NonPagedPool, Ext2QuadAlign(sizeof(Ext2IrpContext)) ); + AllocatedFromZone = FALSE; + + // if we could not obtain the required memory, bug-check. + // Do NOT do this in your commercial driver, instead handle the error gracefully ... + if (!PtrIrpContext) + { + Ext2Panic(STATUS_INSUFFICIENT_RESOURCES, Ext2QuadAlign(sizeof(Ext2IrpContext)), 0); + } + + // zero out the allocated memory block + RtlZeroMemory(PtrIrpContext, Ext2QuadAlign(sizeof(Ext2IrpContext))); + + // set up some fields ... + PtrIrpContext->NodeIdentifier.NodeType = EXT2_NODE_TYPE_IRP_CONTEXT; + PtrIrpContext->NodeIdentifier.NodeSize = Ext2QuadAlign(sizeof(Ext2IrpContext)); + + + PtrIrpContext->Irp = Irp; + PtrIrpContext->TargetDeviceObject = PtrTargetDeviceObject; + + // copy over some fields from the IRP and set appropriate flag values + if (Irp) + { + PtrIoStackLocation = IoGetCurrentIrpStackLocation(Irp); + ASSERT(PtrIoStackLocation); + + PtrIrpContext->MajorFunction = PtrIoStackLocation->MajorFunction; + PtrIrpContext->MinorFunction = PtrIoStackLocation->MinorFunction; + + // Often, a FSD cannot honor a request for asynchronous processing + // of certain critical requests. For example, a "close" request on + // a file object can typically never be deferred. Therefore, do not + // be surprised if sometimes your FSD (just like all other FSD + // implementations on the Windows NT system) has to override the flag + // below. + if( PtrIoStackLocation->FileObject ) + { + if (IoIsOperationSynchronous(Irp) ) + { + Ext2SetFlag(PtrIrpContext->IrpContextFlags, EXT2_IRP_CONTEXT_CAN_BLOCK); + } + } + else + { + Ext2SetFlag(PtrIrpContext->IrpContextFlags, EXT2_IRP_CONTEXT_CAN_BLOCK); + } + } + + if (!AllocatedFromZone) + { + Ext2SetFlag(PtrIrpContext->IrpContextFlags, EXT2_IRP_CONTEXT_NOT_FROM_ZONE); + } + + // Are we top-level ? This information is used by the dispatching code + // later (and also by the FSD dispatch routine) + if (IoGetTopLevelIrp() != Irp) + { + // We are not top-level. Note this fact in the context structure + Ext2SetFlag(PtrIrpContext->IrpContextFlags, EXT2_IRP_CONTEXT_NOT_TOP_LEVEL); + } + + InitializeListHead( &PtrIrpContext->SavedBCBsListHead ); + + return(PtrIrpContext); +} + + +/************************************************************************* +* +* Function: Ext2ReleaseIrpContext() +* +* Description: +* Deallocate a previously allocated structure. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: None +* +*************************************************************************/ +void Ext2ReleaseIrpContext( +PtrExt2IrpContext PtrIrpContext) +{ + KIRQL CurrentIrql; + + ASSERT(PtrIrpContext); + + // Flush the saved BCBs... + Ext2FlushSavedBCBs( PtrIrpContext ); + + // give back memory either to the zone or to the VMM + if (!(PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_NOT_FROM_ZONE)) + { + // back to the zone + KeAcquireSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), &CurrentIrql); + ExFreeToZone(&(Ext2GlobalData.IrpContextZoneHeader), PtrIrpContext); + KeReleaseSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), CurrentIrql); + } + else + { + DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [misc]", PtrIrpContext); + ExFreePool(PtrIrpContext); + } + + return; +} + +/************************************************************************* +* +* Function: Ext2PostRequest() +* +* Description: +* Queue up a request for deferred processing (in the context of a system +* worker thread). The caller must have locked the user buffer (if required) +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: STATUS_PENDING +* +*************************************************************************/ +NTSTATUS Ext2PostRequest( +PtrExt2IrpContext PtrIrpContext, +PIRP PtrIrp) +{ + NTSTATUS RC = STATUS_PENDING; + + DebugTrace(DEBUG_TRACE_ASYNC, " === Asynchronous request. Deferring processing", 0); + + // mark the IRP pending + IoMarkIrpPending(PtrIrp); + + // queue up the request + ExInterlockedInsertTailList( + &Ext2GlobalData.ThreadQueue.ThreadQueueListHead, + &PtrIrpContext->ThreadQueueListEntry, + &Ext2GlobalData.ThreadQueue.SpinLock ); + + KeSetEvent( &Ext2GlobalData.ThreadQueue.QueueEvent, 0, FALSE ); + + +/***************** not using system worker threads ***************** + ExInitializeWorkItem(&(PtrIrpContext->WorkQueueItem), Ext2CommonDispatch, PtrIrpContext); + ExQueueWorkItem( &( PtrIrpContext->WorkQueueItem ), DelayedWorkQueue ); + // CriticalWorkQueue +*****************************************************************************/ + + // return status pending + return(RC); +} + + +/************************************************************************* +* +* Function: Ext2CommonDispatch() +* +* Description: +* The common dispatch routine invoked in the context of a system worker +* thread. All we do here is pretty much case off the major function +* code and invoke the appropriate FSD dispatch routine for further +* processing. +* +* Expected Interrupt Level (for execution) : +* +* IRQL PASSIVE_LEVEL +* +* Return Value: None +* +*************************************************************************/ +void Ext2CommonDispatch( + void *Context ) // actually an IRPContext structure +{ + NTSTATUS RC = STATUS_SUCCESS; + PtrExt2IrpContext PtrIrpContext = NULL; + PIRP PtrIrp = NULL; + + // The context must be a pointer to an IrpContext structure + PtrIrpContext = (PtrExt2IrpContext)Context; + ASSERT(PtrIrpContext); + + // Assert that the Context is legitimate + if ((PtrIrpContext->NodeIdentifier.NodeType != EXT2_NODE_TYPE_IRP_CONTEXT) || (PtrIrpContext->NodeIdentifier.NodeSize != Ext2QuadAlign(sizeof(Ext2IrpContext)))) + { + // This does not look good + Ext2Panic(EXT2_ERROR_INTERNAL_ERROR, PtrIrpContext->NodeIdentifier.NodeType, PtrIrpContext->NodeIdentifier.NodeSize); + } + + // Get a pointer to the IRP structure + PtrIrp = PtrIrpContext->Irp; + ASSERT(PtrIrp); + + // Now, check if the FSD was top level when the IRP was originally invoked + // and set the thread context (for the worker thread) appropriately + if (PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_NOT_TOP_LEVEL) + { + // The FSD is not top level for the original request + // Set a constant value in TLS to reflect this fact + IoSetTopLevelIrp((PIRP)FSRTL_FSP_TOP_LEVEL_IRP); + } + + // Since the FSD routine will now be invoked in the context of this worker + // thread, we should inform the FSD that it is perfectly OK to block in + // the context of this thread + Ext2SetFlag(PtrIrpContext->IrpContextFlags, EXT2_IRP_CONTEXT_CAN_BLOCK); + + FsRtlEnterFileSystem(); + + try + { + + // Pre-processing has been completed; check the Major Function code value + // either in the IrpContext (copied from the IRP), or directly from the + // IRP itself (we will need a pointer to the stack location to do that), + // Then, switch based on the value on the Major Function code + switch (PtrIrpContext->MajorFunction) + { + case IRP_MJ_CREATE: + // Invoke the common create routine + DebugTrace(DEBUG_TRACE_ASYNC, " === Serviceing IRP_MJ_CREATE request asynchronously .", 0); + (void)Ext2CommonCreate(PtrIrpContext, PtrIrp, FALSE); + break; + case IRP_MJ_READ: + // Invoke the common read routine + DebugTrace(DEBUG_TRACE_ASYNC, " === Serviceing IRP_MJ_READ request asynchronously .", 0); + (void)Ext2CommonRead(PtrIrpContext, PtrIrp, FALSE); + break; + case IRP_MJ_WRITE: + // Invoke the common write routine + DebugTrace(DEBUG_TRACE_ASYNC, " === Serviceing IRP_MJ_WRITE request asynchronously .", 0); + (void)Ext2CommonWrite(PtrIrpContext, PtrIrp ); + break; + + case IRP_MJ_CLEANUP: + // Invoke the common read routine + DebugTrace(DEBUG_TRACE_ASYNC, " === Serviceing IRP_MJ_CLEANUP request asynchronously .", 0); + (void)Ext2CommonCleanup(PtrIrpContext, PtrIrp, FALSE); + break; + case IRP_MJ_CLOSE: + // Invoke the common read routine + DebugTrace(DEBUG_TRACE_ASYNC, " === Serviceing IRP_MJ_CLOSE request asynchronously .", 0); + (void)Ext2CommonClose ( PtrIrpContext, PtrIrp, FALSE ); + break; + + // Continue with the remaining possible dispatch routines below ... + default: + // This is the case where we have an invalid major function + DebugTrace(DEBUG_TRACE_ASYNC, " === Serviceing asynchronous request. \nUnable to recoganise the IRP!!! How can this be!!!", 0); + PtrIrp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST; + PtrIrp->IoStatus.Information = 0; + + Ext2BreakPoint(); + + IoCompleteRequest(PtrIrp, IO_NO_INCREMENT); + break; + } + } + except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) + { + RC = Ext2ExceptionHandler(PtrIrpContext, PtrIrp); + Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); + } + + // Enable preemption + FsRtlExitFileSystem(); + + // Ensure that the "top-level" field is cleared + IoSetTopLevelIrp(NULL); + + PsTerminateSystemThread( RC ); + + + return; +} + +/************************************************************************* +* +* Function: Ext2InitializeVCB() +* +* Description: +* Perform the initialization for a VCB structure. +* +* Expected Interrupt Level (for execution) : +* +* IRQL PASSIVE_LEVEL +* +* Return Value: None +* +*************************************************************************/ +void Ext2InitializeVCB( +PDEVICE_OBJECT PtrVolumeDeviceObject, +PDEVICE_OBJECT PtrTargetDeviceObject, +PVPB PtrVPB, +PLARGE_INTEGER AllocationSize ) +{ + NTSTATUS RC = STATUS_SUCCESS; + PtrExt2VCB PtrVCB = NULL; + BOOLEAN VCBResourceInitialized = FALSE; + + PtrVCB = (PtrExt2VCB)(PtrVolumeDeviceObject->DeviceExtension); + + // Zero it out (typically this has already been done by the I/O + // Manager but it does not hurt to do it again)! + RtlZeroMemory(PtrVCB, sizeof(Ext2VCB)); + + // Initialize the signature fields + PtrVCB->NodeIdentifier.NodeType = EXT2_NODE_TYPE_VCB; + PtrVCB->NodeIdentifier.NodeSize = sizeof(Ext2VCB); + + // Initialize the ERESOURCE objects. + RC = ExInitializeResourceLite(&(PtrVCB->VCBResource)); + RC = ExInitializeResourceLite(&(PtrVCB->PagingIoResource)); + + ASSERT(NT_SUCCESS(RC)); + VCBResourceInitialized = TRUE; + + PtrVCB->TargetDeviceObject = PtrTargetDeviceObject; + + PtrVCB->VCBDeviceObject = PtrVolumeDeviceObject; + + PtrVCB->PtrVPB = PtrVPB; + + // Initialize the list anchor (head) for some lists in this VCB. + InitializeListHead(&(PtrVCB->FCBListHead)); + InitializeListHead(&(PtrVCB->NextNotifyIRP)); + InitializeListHead(&(PtrVCB->VolumeOpenListHead)); + InitializeListHead(&(PtrVCB->ClosableFCBs.ClosableFCBListHead)); + PtrVCB->ClosableFCBs.Count = 0; + + // Initialize the notify IRP list mutex + KeInitializeMutex(&(PtrVCB->NotifyIRPMutex), 0); + + // Set the initial file size values appropriately. Note that your FSD may + // wish to guess at the initial amount of information you would like to + // read from the disk until you have really determined that this a valid + // logical volume (on disk) that you wish to mount. + PtrVCB->CommonVCBHeader.AllocationSize.QuadPart = AllocationSize->QuadPart; + + PtrVCB->CommonVCBHeader.FileSize.QuadPart = AllocationSize->QuadPart; + // You typically do not want to bother with valid data length callbacks + // from the Cache Manager for the file stream opened for volume metadata + // information + PtrVCB->CommonVCBHeader.ValidDataLength.LowPart = 0xFFFFFFFF; + PtrVCB->CommonVCBHeader.ValidDataLength.HighPart = 0x7FFFFFFF; + + PtrVCB->CommonVCBHeader.IsFastIoPossible = FastIoIsNotPossible; + + PtrVCB->CommonVCBHeader.Resource = &(PtrVCB->VCBResource); + PtrVCB->CommonVCBHeader.PagingIoResource = &(PtrVCB->PagingIoResource);; + + // Create a stream file object for this volume. + PtrVCB->PtrStreamFileObject = IoCreateStreamFileObject(NULL, + PtrVCB->PtrVPB->RealDevice); + ASSERT(PtrVCB->PtrStreamFileObject); + + // Initialize some important fields in the newly created file object. + PtrVCB->PtrStreamFileObject->FsContext = (void *)(&PtrVCB->CommonVCBHeader); + PtrVCB->PtrStreamFileObject->FsContext2 = NULL; + PtrVCB->PtrStreamFileObject->SectionObjectPointer = &(PtrVCB->SectionObject); + + PtrVCB->PtrStreamFileObject->Vpb = PtrVPB; + PtrVCB->PtrStreamFileObject->ReadAccess = TRUE; + PtrVCB->PtrStreamFileObject->WriteAccess = TRUE; + + // Link this chap onto the global linked list of all VCB structures. + DebugTrace(DEBUG_TRACE_MISC, "*** Attempting to acquire Global Resource Exclusively [FileInfo]", 0); + ExAcquireResourceExclusiveLite(&(Ext2GlobalData.GlobalDataResource), TRUE); + InsertTailList(&(Ext2GlobalData.NextVCB), &(PtrVCB->NextVCB)); + DebugTrace(DEBUG_TRACE_MISC, "*** Global Resource Acquired [FileInfo]", 0); + + + + // Initialize caching for the stream file object. + CcInitializeCacheMap(PtrVCB->PtrStreamFileObject, (PCC_FILE_SIZES)(&(PtrVCB->CommonVCBHeader.AllocationSize)), + TRUE, // We will use pinned access. + &(Ext2GlobalData.CacheMgrCallBacks), PtrVCB ); + + + Ext2ReleaseResource(&(Ext2GlobalData.GlobalDataResource)); + DebugTrace(DEBUG_TRACE_MISC, "*** Global Resource Released[FileInfo]", 0); + + // Mark the fact that this VCB structure is initialized. + Ext2SetFlag(PtrVCB->VCBFlags, EXT2_VCB_FLAGS_VCB_INITIALIZED); + PtrVCB->PtrGroupDescriptors = NULL; + PtrVCB->NoOfGroups = 0; + return; +} + + + +/************************************************************************* +* +* Function: Ext2CompleteRequest() +* +* Description: +* This routine completes a Irp. +* +* Expected Interrupt Level (for execution) : +* +* ??? +* +* Arguments: +* +* Irp - Supplies the Irp being processed +* +* Status - Supplies the status to complete the Irp with +* +* Return Value: none +* +*************************************************************************/ +void Ext2CompleteRequest( + IN PIRP Irp OPTIONAL, + IN NTSTATUS Status + ) +{ + // + // If we have an Irp then complete the irp. + // + + if (Irp != NULL) + { + + // + // We got an error, so zero out the information field before + // completing the request if this was an input operation. + // Otherwise IopCompleteRequest will try to copy to the user's buffer. + // + + if ( NT_ERROR(Status) && + FlagOn(Irp->Flags, IRP_INPUT_OPERATION) ) { + + Irp->IoStatus.Information = 0; + } + + Irp->IoStatus.Status = Status; + + IoCompleteRequest( Irp, IO_DISK_INCREMENT ); + } + return; +} + + +/************************************************************************* +* +* Function: Ext2CreateNewCCB() +* +* Description: +* We want to create a new CCB. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: A pointer to the CCB structure OR NULL. +* +*************************************************************************/ +NTSTATUS Ext2CreateNewCCB( + PtrExt2CCB *ReturnedCCB, + PtrExt2FCB PtrFCB, + PFILE_OBJECT PtrFileObject ) +{ + PtrExt2CCB PtrCCB; + NTSTATUS RC = STATUS_SUCCESS; + + try + { + + PtrCCB = Ext2AllocateCCB(); + if (!PtrFCB) + { + // Assume lack of memory. + try_return(RC = STATUS_INSUFFICIENT_RESOURCES); + } + PtrCCB->PtrFCB = PtrFCB; + + PtrCCB->PtrFileObject = PtrFileObject; + PtrCCB->CurrentByteOffset.QuadPart = 0; + + if( PtrFCB->ClosableFCBs.OnClosableFCBList ) + { + // This FCB was on the Closable List... + // Taking it off the list... + // + RemoveEntryList( &PtrFCB->ClosableFCBs.ClosableFCBList ); + PtrFCB->ClosableFCBs.OnClosableFCBList = FALSE; + PtrFCB->PtrVCB->ClosableFCBs.Count --; + } + + InterlockedIncrement( &PtrFCB->ReferenceCount ); + InterlockedIncrement( &PtrFCB->OpenHandleCount ); + + InsertTailList( &( PtrFCB->CCBListHead ), &(PtrCCB->NextCCB)); + + *ReturnedCCB = PtrCCB; + try_exit: NOTHING; + } + finally + { + + } + + return(RC); +} + + +/************************************************************************* +* +* Function: Ext2DenyAccess() +* +* Description: +* We want to deny access to an IRP +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: NTSTATUS - STATUS_ACCESS_DENIED (always) +* +*************************************************************************/ +NTSTATUS Ext2DenyAccess( IN PIRP Irp ) +{ + ASSERT( Irp ); + + // Just return Access Denied + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = STATUS_ACCESS_DENIED; + IoCompleteRequest( Irp, IO_DISK_INCREMENT ); + + DebugTrace(DEBUG_TRACE_MISC, "DENYING ACCESS (this will do for now!)...", 0); + + return STATUS_ACCESS_DENIED; +} + + + +/************************************************************************* +* +* Function: Ext2GetFCB_CCB_VCB_FromFileObject() +* +* Description: +* This routine retrieves the FCB, CCB and VCB from the File Object... +* +* Expected Interrupt Level (for execution) : +* +* ? +* +* Return Value: NTSTATUS - STATUS_SUCCESS(always) +* +*************************************************************************/ +NTSTATUS Ext2GetFCB_CCB_VCB_FromFileObject ( + IN PFILE_OBJECT PtrFileObject, + OUT PtrExt2FCB *PPtrFCB, + OUT PtrExt2CCB *PPtrCCB, + OUT PtrExt2VCB *PPtrVCB ) +{ + int Offset; + + (*PPtrCCB) = (PtrExt2CCB)(PtrFileObject->FsContext2); + if( *PPtrCCB ) + { + ASSERT((*PPtrCCB)->NodeIdentifier.NodeType == EXT2_NODE_TYPE_CCB); + (*PPtrFCB) = (*PPtrCCB)->PtrFCB; + + ASSERT((*PPtrFCB)); + + if ((*PPtrFCB)->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB) + { + (*PPtrVCB) = (PtrExt2VCB)(*PPtrFCB); + AssertVCB( (*PPtrVCB) ); + + // No FCB + (*PPtrFCB) = NULL; + //found a VCB + } + else + { + AssertFCB( (*PPtrFCB) ); + (*PPtrVCB) = (*PPtrFCB)->PtrVCB; + AssertVCB( (*PPtrVCB) ); + + } + } + else + { + // PtrFileObject->FsContext points to NTRequiredFCB + (*PPtrFCB) = CONTAINING_RECORD( PtrFileObject->FsContext, Ext2FCB, NTRequiredFCB ); + ASSERT((*PPtrFCB)); + //(*PPtrFCB) = PtrFileObject->FsContext; + + if ((*PPtrFCB)->NodeIdentifier.NodeType == EXT2_NODE_TYPE_FCB) + { + // Making sure I got it right... + AssertFCB( *PPtrFCB ); + (*PPtrVCB) = (*PPtrFCB)->PtrVCB; + AssertVCB( *PPtrVCB ); + } + else + { + // This should be a VCB + + (*PPtrVCB) = CONTAINING_RECORD( PtrFileObject->FsContext, Ext2VCB, CommonVCBHeader ); + AssertVCB( *PPtrVCB ); + + // No FCB + (*PPtrFCB) = NULL; + //found a VCB + } + + } + return STATUS_SUCCESS; +} + + +void Ext2CopyUnicodeString( PUNICODE_STRING PtrDestinationString, PUNICODE_STRING PtrSourceString ) +{ + int Count; + // Allcating space for Destination... + PtrDestinationString->Length = PtrSourceString->Length; + PtrDestinationString->MaximumLength = Ext2QuadAlign( PtrSourceString->Length + 2 ); + PtrDestinationString->Buffer = Ext2AllocatePool( NonPagedPool, PtrDestinationString->MaximumLength ); + + // RtlCopyUnicodeString( PtrDestinationString, PtrSourceString ); + + for( Count = 0 ; Count < (PtrSourceString->Length/2) ; Count++ ) + { + PtrDestinationString->Buffer[Count] = PtrSourceString->Buffer[Count]; + } + PtrDestinationString->Buffer[Count] = 0; + +} + +void Ext2CopyWideCharToUnicodeString( + PUNICODE_STRING PtrDestinationString, + PCWSTR PtrSourceString ) +{ + + int Count; + + // Determining length... + for( Count = 0 ; PtrSourceString[Count] != 0 ; Count++ ); + + // Allcating space for Destination... + PtrDestinationString->Length = Count * 2; + PtrDestinationString->MaximumLength = Ext2QuadAlign( Count * 2 + 2 ); + PtrDestinationString->Buffer = Ext2AllocatePool( NonPagedPool, PtrDestinationString->MaximumLength ); + + // Copying the string over... + for( Count = 0 ; ; Count++ ) + { + PtrDestinationString->Buffer[Count] = PtrSourceString[Count]; + if( PtrSourceString[Count] == 0 ) + break; + } +} + + +void Ext2CopyCharToUnicodeString( + PUNICODE_STRING PtrDestinationString, + PCSTR PtrSourceString, + USHORT SourceStringLength ) +{ + int Count; + // Allcating space for Destination... + PtrDestinationString->Length = SourceStringLength * 2; + PtrDestinationString->MaximumLength = Ext2QuadAlign( SourceStringLength * 2 + 2 ); + PtrDestinationString->Buffer = Ext2AllocatePool( NonPagedPool, PtrDestinationString->MaximumLength ); + + // Copying the string over... + for( Count = 0 ; Count < SourceStringLength ; Count++ ) + { + PtrDestinationString->Buffer[Count] = PtrSourceString[Count]; + } + PtrDestinationString->Buffer[Count] = 0; + +} + +void Ext2CopyZCharToUnicodeString( PUNICODE_STRING PtrDestinationString, PCSTR PtrSourceString ) +{ + + int Count; + + // Determining length... + for( Count = 0 ; PtrSourceString[Count] != 0 ; Count++ ); + + // Allcating space for Destination... + PtrDestinationString->Length = Count * 2; + PtrDestinationString->MaximumLength = Ext2QuadAlign( Count * 2 + 2 ); + PtrDestinationString->Buffer = Ext2AllocatePool( NonPagedPool, PtrDestinationString->MaximumLength ); + + // Copying the string over... + for( Count = 0 ; ; Count++ ) + { + PtrDestinationString->Buffer[Count] = PtrSourceString[Count]; + if( PtrSourceString[Count] == 0 ) + break; + } +} + +void Ext2ZerooutUnicodeString( PUNICODE_STRING PtrUnicodeString ) +{ + PtrUnicodeString->Length = 0; + PtrUnicodeString->MaximumLength =0; + PtrUnicodeString->Buffer = 0; +} + +void Ext2DeallocateUnicodeString( PUNICODE_STRING PtrUnicodeString ) +{ + if( PtrUnicodeString && PtrUnicodeString->Buffer ) + { + DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [misc]", PtrUnicodeString->Buffer ); + ExFreePool( PtrUnicodeString->Buffer ); + } + PtrUnicodeString->Length = 0; + PtrUnicodeString->MaximumLength =0; + PtrUnicodeString->Buffer = 0; +} + +PtrExt2FCB Ext2GetUsedFCB( + PtrExt2VCB PtrVCB ) +{ + + BOOLEAN AllocatedFromZone = FALSE; + PLIST_ENTRY PtrEntry = NULL; + PtrExt2FCB PtrFCB = NULL; + + ASSERT( PtrVCB ); + if( PtrVCB->ClosableFCBs.Count < EXT2_MAXCLOSABLE_FCBS_LL ) + { + // + // Too few Closable FCBs + // Will not reuse any FCBs + // Allocating a new one + // + return Ext2AllocateFCB(); + } + // + // Obtaining a used FCB... + // + + // Retrieving the first entry in the closable FCB list... + + PtrEntry = RemoveHeadList( &PtrVCB->ClosableFCBs.ClosableFCBListHead ); + + PtrFCB = CONTAINING_RECORD( PtrEntry, Ext2FCB, ClosableFCBs.ClosableFCBList ); + + // Remembering if the FCB was allocated from the Zone... + AllocatedFromZone = Ext2IsFlagOn( PtrFCB->FCBFlags, EXT2_FCB_NOT_FROM_ZONE ); + + // + // Close this FCB + // + if( !Ext2CloseClosableFCB( PtrFCB ) ) + { + // Couldn't close the FCB!! + // + InsertHeadList( &PtrVCB->ClosableFCBs.ClosableFCBListHead, + &PtrFCB->ClosableFCBs.ClosableFCBList ); + return Ext2AllocateFCB(); + } + + PtrVCB->ClosableFCBs.Count--; + DebugTrace( DEBUG_TRACE_SPECIAL, "Count = %ld [Ext2GetUsedFCB]", PtrVCB->ClosableFCBs.Count ); + + // + // Getting the FCB ready for reuse by + // zeroing it out... + // + RtlZeroMemory(PtrFCB, Ext2QuadAlign(sizeof(Ext2FCB))); + + // set up some fields ... + PtrFCB->NodeIdentifier.NodeType = EXT2_NODE_TYPE_FCB; + PtrFCB->NodeIdentifier.NodeSize = Ext2QuadAlign(sizeof(Ext2FCB)); + + + if (!AllocatedFromZone) + { + Ext2SetFlag(PtrFCB->FCBFlags, EXT2_FCB_NOT_FROM_ZONE); + } + + return PtrFCB; +} + +BOOLEAN Ext2CloseClosableFCB( + PtrExt2FCB PtrFCB) +{ + KIRQL Irql = 0; + PFILE_OBJECT PtrFileObject = NULL; + + AssertFCB( PtrFCB ); + + // Attempting to acquire the FCB Exclusively... + if(! ExAcquireResourceExclusiveLite( &(PtrFCB->NTRequiredFCB.MainResource ), FALSE ) ) + { + Ext2BreakPoint(); + return FALSE; + } + + Irql = KeGetCurrentIrql( ); + + if( PtrFCB->ReferenceCount ) + { + // How the hell can this happen!!! + Ext2BreakPoint(); + } + if( PtrFCB->OpenHandleCount ) + { + // How the hell can this happen!!! + Ext2BreakPoint(); + } + + // Deleting entry from VCB's FCB list... + RemoveEntryList( &PtrFCB->NextFCB ); + + PtrFCB->NodeIdentifier.NodeType = EXT2_NODE_TYPE_FREED; + + PtrFileObject = PtrFCB->DcbFcb.Dcb.PtrDirFileObject; + + if ( PtrFileObject ) + { + // + // Clear the Cache Map... + // + if( PtrFileObject->PrivateCacheMap != NULL) + { + IO_STATUS_BLOCK Status; + DebugTrace( DEBUG_TRACE_SPECIAL, ">>.........Flushing cache.........<<", 0 ); + CcFlushCache( PtrFileObject->SectionObjectPointer, NULL, 0, &Status ); + CcUninitializeCacheMap( PtrFileObject, NULL, NULL ); + } + // + // The File Object is no longer required... + // Close it by dereferenceing it!!! + // + PtrFileObject->FsContext = NULL; + PtrFileObject->FsContext2 = NULL; + ObDereferenceObject( PtrFileObject ); + + PtrFCB->DcbFcb.Dcb.PtrDirFileObject = NULL; + PtrFileObject = NULL; + } + + // Uninitialize the Resources... + ExDeleteResourceLite( &PtrFCB->NTRequiredFCB.MainResource ); + ExDeleteResourceLite( &PtrFCB->NTRequiredFCB.PagingIoResource ); + + // + // Releasing the FCB Name Object... + // + if( PtrFCB->FCBName ) + { + DebugTrace( DEBUG_TRACE_SPECIAL, "Reusing FCB - File Name %S", PtrFCB->FCBName->ObjectName.Buffer ); + Ext2ReleaseObjectName( PtrFCB->FCBName ); + } + else + { + DebugTrace( DEBUG_TRACE_SPECIAL, "Reusing FCB - File Name *Unknown*", 0 ); + } + return TRUE; +} + + +BOOLEAN Ext2SaveBCB( + PtrExt2IrpContext PtrIrpContext, + PBCB PtrBCB, + PFILE_OBJECT PtrFileObject) +{ + PEXT2_SAVED_BCBS PtrSavedBCB; + PLIST_ENTRY PtrEntry = NULL; + + if( !PtrIrpContext ) + { + // + // NULL passed instead of the IRP Context + // This call should be ignored... + // + return TRUE; + } + + if( !AssertBCB( PtrBCB ) ) + { + DebugTrace( DEBUG_TRACE_MISC, "Not saving BCB!!! [Ext2SaveBCB]", 0 ); + return FALSE; + } + + + DebugTrace( DEBUG_TRACE_SPECIAL, "Saving BCB [Ext2SaveBCB]", 0 ); + + // Has the BCB been saved already? + for( PtrEntry = PtrIrpContext->SavedBCBsListHead.Flink; + PtrEntry != &PtrIrpContext->SavedBCBsListHead; + PtrEntry = PtrEntry->Flink ) + { + PtrSavedBCB = CONTAINING_RECORD( PtrEntry, EXT2_SAVED_BCBS, SavedBCBsListEntry ); + ASSERT( PtrSavedBCB ); + if( PtrSavedBCB->PtrBCB == PtrBCB ) + { + + // A BCB for this file has already been saved for flushing... + // Won't resave this one... + return TRUE; + } + } + + + // Reference the BCB + CcRepinBcb( PtrBCB ); + + // Now allocate a EXT2_SAVED_BCBS + PtrSavedBCB = Ext2AllocatePool( NonPagedPool, + Ext2QuadAlign( sizeof( EXT2_SAVED_BCBS ) ) ); + if( !PtrSavedBCB ) + return FALSE; + PtrSavedBCB->NodeIdentifier.NodeSize = sizeof( EXT2_SAVED_BCBS ); + PtrSavedBCB->NodeIdentifier.NodeType = EXT2_NODE_TYPE_SAVED_BCB; + + PtrSavedBCB->PtrBCB = PtrBCB; + // PtrSavedBCB->PtrFileObject = PtrFileObject; + + // Now save it in the IRP Context + InsertHeadList( &PtrIrpContext->SavedBCBsListHead, &PtrSavedBCB->SavedBCBsListEntry ); + + PtrIrpContext->SavedCount++; + // Return success... + return TRUE; + +} + + +BOOLEAN Ext2FlushSavedBCBs( + PtrExt2IrpContext PtrIrpContext ) +{ + + PLIST_ENTRY PtrEntry = NULL; + PEXT2_SAVED_BCBS PtrSavedBCB = NULL; + IO_STATUS_BLOCK Status; + BOOLEAN RC = TRUE; + + if( !IsListEmpty( &PtrIrpContext->SavedBCBsListHead ) ) + { + DebugTrace( DEBUG_TRACE_SPECIAL, "Flushing cache... - Ext2FlushSavedBCBs", 0 ); + } + while( !IsListEmpty( &PtrIrpContext->SavedBCBsListHead ) ) + { + + PtrEntry = RemoveTailList( &PtrIrpContext->SavedBCBsListHead ); + if( !PtrEntry ) + { + // No more entries left... + break; + } + + // Get the Saved BCB + PtrSavedBCB = CONTAINING_RECORD( PtrEntry, EXT2_SAVED_BCBS, SavedBCBsListEntry ); + if( PtrSavedBCB->NodeIdentifier.NodeType != EXT2_NODE_TYPE_SAVED_BCB ) + { + // Something is wrong... + Ext2BreakPoint(); + return FALSE; + } + + if( !AssertBCB( PtrSavedBCB->PtrBCB ) ) + { + // This BCB shouldn't have been saved in the first place... + DebugTrace( DEBUG_TRACE_ERROR, "Unable to flush BCB - Skipping!!! [Ext2SaveBCB]", 0 ); + continue; + } + + // Unpin and Flush the cache... + CcUnpinRepinnedBcb( PtrSavedBCB->PtrBCB, TRUE, &Status ); + + if( !NT_SUCCESS( Status.Status ) ) + { + // Failure in flushing... + DebugTrace( DEBUG_TRACE_SPECIAL, "Failure flushing cache - Ext2FlushSavedBCBs", 0 ); + RC = FALSE; + } + + // Release the Saved BCB + PtrSavedBCB->NodeIdentifier.NodeType = EXT2_NODE_TYPE_INVALID; + + DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [misc]", PtrSavedBCB ); + ExFreePool( PtrSavedBCB ); + PtrSavedBCB = NULL; + PtrIrpContext->SavedCount--; + } + + return RC; +} + +BOOLEAN AssertBCB( PBCB PtrBCB ) +{ + PFILE_OBJECT PtrFileObject = NULL; + + /* + * This routine is simplified version of the original + * AssertBCB and doesn't make any assumptions about + * the layout of undocumented BCB structure. + * -- Filip Navara, 18/08/2004 + */ + + PtrFileObject = CcGetFileObjectFromBcb ( PtrBCB ); + if( !PtrFileObject ) + { + Ext2BreakPoint(); + return FALSE; + } + else + { + return TRUE; + } + } + + +ULONG Ext2Align( ULONG NumberToBeAligned, ULONG Alignment ) +{ + if( Alignment & ( Alignment - 1 ) ) + { + // + // Alignment not a power of 2 + // Just returning + // + return NumberToBeAligned; + } + if( ( NumberToBeAligned & ( Alignment - 1 ) ) != 0 ) + { + NumberToBeAligned = NumberToBeAligned + Alignment; + NumberToBeAligned = NumberToBeAligned & ( ~ (Alignment-1) ); + } + return NumberToBeAligned; +} + +LONGLONG Ext2Align64( LONGLONG NumberToBeAligned, LONGLONG Alignment ) +{ + if( Alignment & ( Alignment - 1 ) ) + { + // + // Alignment not a power of 2 + // Just returning + // + return NumberToBeAligned; + } + if( ( NumberToBeAligned & ( Alignment - 1 ) ) != 0 ) + { + NumberToBeAligned = NumberToBeAligned + Alignment; + NumberToBeAligned = NumberToBeAligned & ( ~ (Alignment-1) ); + } + return NumberToBeAligned; +} + + +ULONG Ext2GetCurrentTime() +{ + LARGE_INTEGER CurrentTime; + ULONG Time; + KeQuerySystemTime( &CurrentTime ); + Time = (ULONG) ( (CurrentTime.QuadPart - Ext2GlobalData.TimeDiff.QuadPart) / 10000000 ); + return Time; +} diff --git a/reactos/drivers/fs/ext2/src/read.c b/reactos/drivers/fs/ext2/src/read.c new file mode 100644 index 00000000000..e4b47de045c --- /dev/null +++ b/reactos/drivers/fs/ext2/src/read.c @@ -0,0 +1,1476 @@ +/************************************************************************* +* +* File: read.c +* +* Module: Ext2 File System Driver (Kernel mode execution only) +* +* Description: +* Contains code to handle the "Read" dispatch entry point. +* +* Author: Manoj Paul Joseph +* +* +*************************************************************************/ + +#include "ext2fsd.h" + +// define the file specific bug-check id +#define EXT2_BUG_CHECK_ID EXT2_FILE_READ + +#define DEBUG_LEVEL (DEBUG_TRACE_READ) + + +/************************************************************************* +* +* Function: Ext2Read() +* +* Description: +* The I/O Manager will invoke this routine to handle a read +* request +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution +* to be deferred to a worker thread context) +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +NTSTATUS Ext2Read( +PDEVICE_OBJECT DeviceObject, // the logical volume device object +PIRP Irp) // I/O Request Packet +{ + NTSTATUS RC = STATUS_SUCCESS; + PtrExt2IrpContext PtrIrpContext = NULL; + BOOLEAN AreWeTopLevel = FALSE; + + DebugTrace(DEBUG_TRACE_IRP_ENTRY, "Read IRP Received...", 0); + + // Ext2BreakPoint(); + + FsRtlEnterFileSystem(); + ASSERT(DeviceObject); + ASSERT(Irp); + + // set the top level context + AreWeTopLevel = Ext2IsIrpTopLevel(Irp); + + try + { + // get an IRP context structure and issue the request + PtrIrpContext = Ext2AllocateIrpContext(Irp, DeviceObject); + ASSERT(PtrIrpContext); + + RC = Ext2CommonRead(PtrIrpContext, Irp, TRUE); + + } + except ( Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation() ) ) + { + + RC = Ext2ExceptionHandler(PtrIrpContext, Irp); + + Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); + } + + if (AreWeTopLevel) + { + IoSetTopLevelIrp(NULL); + } + + FsRtlExitFileSystem(); + + return(RC); +} + + + +/************************************************************************* +* +* Function: Ext2CommonRead() +* +* Description: +* The actual work is performed here. This routine may be invoked in one +* of the two possible contexts: +* (a) in the context of a system worker thread +* (b) in the context of the original caller +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +NTSTATUS Ext2CommonRead( +PtrExt2IrpContext PtrIrpContext, +PIRP PtrIrp, +BOOLEAN FirstAttempt ) +{ + NTSTATUS RC = STATUS_SUCCESS; + PIO_STACK_LOCATION PtrIoStackLocation = NULL; + LARGE_INTEGER ByteOffset; + uint32 ReadLength = 0, TruncatedReadLength = 0; + uint32 NumberBytesRead = 0; + PFILE_OBJECT PtrFileObject = NULL; + PtrExt2FCB PtrFCB = NULL; + PtrExt2CCB PtrCCB = NULL; + PtrExt2VCB PtrVCB = NULL; + PtrExt2NTRequiredFCB PtrReqdFCB = NULL; + PERESOURCE PtrResourceAcquired = NULL; + IO_STATUS_BLOCK LocalIoStatus; + PVOID PtrSystemBuffer = NULL; + PVOID PtrPinnedReadBuffer = NULL; + uint32 KeyValue = 0; + + BOOLEAN CompleteIrp = TRUE; + BOOLEAN PostRequest = FALSE; + + BOOLEAN CanWait = FALSE; + BOOLEAN PagingIo = FALSE; + BOOLEAN NonBufferedIo = FALSE; + BOOLEAN SynchronousIo = FALSE; + BOOLEAN MdlLocked = FALSE; + BOOLEAN ReadTruncated = FALSE; + + LARGE_INTEGER StartPhysicalBlock; + ULONG NoOfBlocks = 0; + + PIO_STACK_LOCATION PtrIrpNextSp = NULL; + + // Used to cache the Single Indirect blocks pointed to by + // the Double Indirect block + PEXT2_SIBLOCKS PtrDIArray = NULL; + ULONG DIArrayCount = 0; + + // Used to cache the Single Indirect blocks pointed to by + // the Triple Indirect block + PEXT2_SIBLOCKS PtrTIArray = NULL; + ULONG TIArrayCount = 0; + + EXT2_IO_RUN * PtrIoRuns = NULL; + + ULONG Start; + ULONG End; + ULONG LogicalBlockIndex; + ULONG BytesRemaining; + ULONG BytesReadSoFar; + ULONG LeftOver; + ULONG LogicalBlockSize; + ULONG PhysicalBlockSize; + + PBCB PtrPinnedSIndirectBCB = NULL; + PBCB PtrPinnedDIndirectBCB = NULL; + PBCB PtrPinnedTIndirectBCB = NULL; + + int i, Index; + + try + { + try{ + // First, get a pointer to the current I/O stack location + PtrIoStackLocation = IoGetCurrentIrpStackLocation(PtrIrp); + ASSERT(PtrIoStackLocation); + + // If this happens to be a MDL read complete request, then + // there is not much processing that the FSD has to do. + if (PtrIoStackLocation->MinorFunction & IRP_MN_COMPLETE) + { + // Caller wants to tell the Cache Manager that a previously + // allocated MDL can be freed. + Ext2MdlComplete(PtrIrpContext, PtrIrp, PtrIoStackLocation, TRUE); + // The IRP has been completed. + CompleteIrp = FALSE; + try_return(RC = STATUS_SUCCESS); + } + + // If this is a request at IRQL DISPATCH_LEVEL, then post + // the request (your FSD may choose to process it synchronously + // if you implement the support correctly; obviously you will be + // quite constrained in what you can do at such IRQL). + if (PtrIoStackLocation->MinorFunction & IRP_MN_DPC) + { + DebugTrace(DEBUG_TRACE_MISC, " === Deferring Read ", 0 ); + CompleteIrp = FALSE; + PostRequest = TRUE; + try_return(RC = STATUS_PENDING); + } + + PtrFileObject = PtrIoStackLocation->FileObject; + ASSERT(PtrFileObject); + + // Get the FCB and CCB pointers + Ext2GetFCB_CCB_VCB_FromFileObject ( + PtrFileObject, &PtrFCB, &PtrCCB, &PtrVCB ); + + // Get some of the parameters supplied to us + ByteOffset = PtrIoStackLocation->Parameters.Read.ByteOffset; + ReadLength = PtrIoStackLocation->Parameters.Read.Length; + + CanWait = ((PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_CAN_BLOCK) ? TRUE : FALSE); + PagingIo = ((PtrIrp->Flags & IRP_PAGING_IO) ? TRUE : FALSE); + NonBufferedIo = ((PtrIrp->Flags & IRP_NOCACHE) ? TRUE : FALSE); + SynchronousIo = ((PtrFileObject->Flags & FO_SYNCHRONOUS_IO) ? TRUE : FALSE); + + if( PtrFCB && PtrFCB->FCBName && PtrFCB->FCBName->ObjectName.Length && PtrFCB->FCBName->ObjectName.Buffer ) + { + DebugTrace(DEBUG_TRACE_FILE_NAME, " === Read File Name : -%S-", PtrFCB->FCBName->ObjectName.Buffer ); + } + else + { + DebugTrace(DEBUG_TRACE_FILE_NAME, " === Read File Name : -null-", 0); + } + + DebugTrace(DEBUG_TRACE_READ_DETAILS, " ->ByteCount = 0x%8lx", PtrIoStackLocation->Parameters.Read.Length); + DebugTrace(DEBUG_TRACE_READ_DETAILS, " ->ByteOffset.LowPart = 0x%8lx", PtrIoStackLocation->Parameters.Read.ByteOffset.LowPart); + + if( CanWait ) + { + DebugTrace(DEBUG_TRACE_READ_DETAILS, " ->Can Wait ", 0 ); + } + else + { + DebugTrace(DEBUG_TRACE_READ_DETAILS, " ->Can't Wait ", 0 ); + } + + if( PagingIo ) + { + DebugTrace(DEBUG_TRACE_READ_DETAILS, " ->Paging Io ", 0 ); + } + else + { + DebugTrace(DEBUG_TRACE_READ_DETAILS, " ->Not Paging Io", 0 ); + } + + if( SynchronousIo ) + { + DebugTrace(DEBUG_TRACE_READ_DETAILS, " ->SynchronousIo ", 0 ); + } + else + { + DebugTrace(DEBUG_TRACE_READ_DETAILS, " ->ASynchronousIo ", 0 ); + } + + if( NonBufferedIo ) + { + DebugTrace(DEBUG_TRACE_READ_DETAILS, " ->NonBufferedIo", 0 ); + } + else + { + DebugTrace(DEBUG_TRACE_READ_DETAILS, " ->BufferedIo", 0 ); + } + + + if (ReadLength == 0) + { + // a 0 byte read can be immediately succeeded + try_return(RC); + } + + // Is this a read of the volume itself ? + if ( ( !PtrFCB && PtrVCB ) || PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB ) + { + // + // >>>>>>>>>>> Volume Read <<<<<<<<<<<< + // + // Yep, we need to send this on to the disk driver after + // validation of the offset and length. + + // PtrVCB = (PtrExt2VCB)(PtrFCB); + + if (PtrVCB->VCBFlags & EXT2_FCB_PAGE_FILE ) + { + DebugTrace(DEBUG_TRACE_READ_DETAILS, "[Read] *Volume Page File *", 0); + } + + // Acquire the volume resource shared ... + + if( PtrFileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Read]", PtrFileObject); + } + + if( PagingIo ) + { + DebugTrace(DEBUG_TRACE_MISC, "*** Attempting to acquire VCB Shared [Read]", 0); + DebugTraceState( "VCBPaging AC:0x%LX SW:0x%LX EX:0x%LX [Read]", PtrVCB->PagingIoResource.ActiveCount, PtrVCB->PagingIoResource.NumberOfExclusiveWaiters, PtrVCB->PagingIoResource.NumberOfSharedWaiters ); + if (!ExAcquireResourceSharedLite(&(PtrVCB->PagingIoResource), FALSE )) + { + // post the request to be processed in the context of a worker thread + DebugTrace(DEBUG_TRACE_MISC, "*** VCBPaging Acquisition FAILED [Read]", 0); + CompleteIrp = FALSE; + PostRequest = TRUE; + try_return(RC = STATUS_PENDING); + } + DebugTrace(DEBUG_TRACE_MISC, "*** VCBPaging Acquired [Read]", 0); + + PtrResourceAcquired = &(PtrVCB->PagingIoResource); + } + else + { + DebugTrace(DEBUG_TRACE_MISC, "*** Attempting to acquire VCB Shared [Read]", 0); + DebugTraceState( "VCB AC:0x%LX SW:0x%LX EX:0x%LX [Read]", PtrVCB->VCBResource.ActiveCount, + PtrVCB->VCBResource.NumberOfExclusiveWaiters, PtrVCB->VCBResource.NumberOfSharedWaiters ); + if (!ExAcquireResourceSharedLite(&(PtrVCB->VCBResource), FALSE )) + { + // post the request to be processed in the context of a worker thread + DebugTrace(DEBUG_TRACE_MISC, "*** VCB Acquisition FAILED [Read]", 0); + CompleteIrp = FALSE; + PostRequest = TRUE; + try_return(RC = STATUS_PENDING); + } + DebugTrace(DEBUG_TRACE_MISC, "*** VCB Acquired [Read]", 0); + + PtrResourceAcquired = &(PtrVCB->VCBResource); + } + if( !PagingIo ) + { + if( PtrVCB->CommonVCBHeader.AllocationSize.QuadPart < ByteOffset.QuadPart ) + { + RC = STATUS_END_OF_FILE; + NumberBytesRead = 0; + try_return( RC ); + } + } + if( PagingIo || NonBufferedIo ) + { + DebugTrace(DEBUG_TRACE_MISC, "[Volume Read] PagingIo or NonBufferedIo ", 0); + CompleteIrp = FALSE; + + RC = Ext2PassDownSingleReadWriteIRP ( + PtrIrpContext, PtrIrp, PtrVCB, + ByteOffset, ReadLength, SynchronousIo); + + try_return(RC); + } + else + { + // Buffer Control Block + PBCB PtrBCB = NULL; + DebugTrace(DEBUG_TRACE_READ_DETAILS, "[Volume Read] BufferedIo ", 0); + // + // Let the cache manager worry about this read... + // Pinned access should have been initiated. + // But checking anyway... + // + ASSERT( PtrVCB->PtrStreamFileObject ); + ASSERT( PtrVCB->PtrStreamFileObject->PrivateCacheMap ); + + if (!CcMapData( PtrVCB->PtrStreamFileObject, + &ByteOffset, + ReadLength, + TRUE, + &PtrBCB, + &PtrPinnedReadBuffer) ) + { + + RC = STATUS_UNSUCCESSFUL; + NumberBytesRead = 0; + try_return( RC ); + } + else + { + PtrSystemBuffer = Ext2GetCallersBuffer(PtrIrp); + RtlCopyBytes( PtrSystemBuffer, PtrPinnedReadBuffer, ReadLength ); + CcUnpinData( PtrBCB ); + PtrBCB = NULL; + RC = STATUS_SUCCESS; + NumberBytesRead = ReadLength; + try_return(RC); + + } + } + } + + + // If the read request is directed to a page file + // send the request directly to the disk driver. + // For requests directed to a page file, you have to trust + // that the offsets will be set correctly by the VMM. You should not + // attempt to acquire any FSD resources either. + + if (PtrFCB->FCBFlags & EXT2_FCB_PAGE_FILE) + { + IoMarkIrpPending(PtrIrp); + // You will need to set a completion routine before invoking + // a lower level driver + // forward request directly to disk driver + // Ext2PageFileIo(PtrIrpContext, PtrIrp); + DebugTrace( DEBUG_TRACE_SPECIAL, "[Read] To a *Page File* - Not handled \ngoing into a hang...", 0); + CompleteIrp = FALSE; + try_return(RC = STATUS_PENDING); + } + + + // + // If this read is directed to a directory... + // Paging IO is allowed though... + // + if ( ( PtrFCB->FCBFlags & EXT2_FCB_DIRECTORY ) && !PagingIo ) + { + RC = STATUS_INVALID_DEVICE_REQUEST; + try_return(RC); + } + + PtrReqdFCB = &(PtrFCB->NTRequiredFCB); + + // Check whether the desired read can be allowed depending + // on any byte range locks that might exist. Note that for + // paging-io, no such checks should be performed. + if (!PagingIo) + { + // Insert code to perform the check here ... + // + // if (!Ext2CheckForByteLock(PtrFCB, PtrCCB, PtrIrp, PtrCurrentIoStackLocation)) + // { + // try_return(RC = STATUS_FILE_LOCK_CONFLICT); + // } + } + + // There are certain complications that arise when the same file stream + // has been opened for cached and non-cached access. The FSD is then + // responsible for maintaining a consistent view of the data seen by + // the caller. + // Also, it is possible for file streams to be mapped in both as data files + // and as an executable. This could also lead to consistency problems since + // there now exist two separate sections (and pages) containing file + // information. + // Read Chapter 10 for more information on the issues involved in + // maintaining data consistency. + // The test below flushes the data cached in system memory if the current + // request madates non-cached access (file stream must be cached) and + // (a) the current request is not paging-io which indicates it is not + // a recursive I/O operation OR originating in the Cache Manager + // (b) OR the current request is paging-io BUT it did not originate via + // the Cache Manager (or is a recursive I/O operation) and we do + // have an image section that has been initialized. + + + + #define EXT2_REQ_NOT_VIA_CACHE_MGR(ptr) (!MmIsRecursiveIoFault() && ((ptr)->ImageSectionObject != NULL)) + + if( NonBufferedIo && (PtrReqdFCB->SectionObject.DataSectionObject != NULL) ) + { + if (!PagingIo || (EXT2_REQ_NOT_VIA_CACHE_MGR(&(PtrReqdFCB->SectionObject)))) + { + CcFlushCache(&(PtrReqdFCB->SectionObject), &ByteOffset, ReadLength, &(PtrIrp->IoStatus)); + // If the flush failed, return error to the caller + if (!NT_SUCCESS(RC = PtrIrp->IoStatus.Status)) + { + try_return(RC); + } + } + } + + // + // Synchronizing with other reads and writes... + // Acquire the appropriate FCB resource shared + // + if ( PagingIo ) + { + // Try to acquire the FCB PagingIoResource shared + if( PtrFileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Read]", PtrFileObject); + } + DebugTrace(DEBUG_TRACE_MISC, "*** Attempting to acquire FCBPaging Shared [Read]", 0); + DebugTraceState( "FCBPaging AC:0x%LX SW:0x%LX EX:0x%LX [Read]", PtrReqdFCB->PagingIoResource.ActiveCount, PtrReqdFCB->PagingIoResource.NumberOfExclusiveWaiters, PtrReqdFCB->PagingIoResource.NumberOfSharedWaiters ); + if (!ExAcquireResourceSharedLite(&(PtrReqdFCB->PagingIoResource), CanWait)) + { + DebugTrace(DEBUG_TRACE_MISC, "*** FCBPaging Acquisition FAILED [Read]", 0); + + CompleteIrp = FALSE; + PostRequest = TRUE; + try_return(RC = STATUS_PENDING); + } + + DebugTrace(DEBUG_TRACE_MISC, "*** FCBPaging Acquired [Read]", 0); + + // Remember the resource that was acquired + PtrResourceAcquired = &(PtrReqdFCB->PagingIoResource); + } + else + { + // Try to acquire the FCB MainResource shared + if( PtrFileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Read]", PtrFileObject); + } + DebugTrace(DEBUG_TRACE_MISC, "*** Attempting to acquire FCB Shared [Read]", 0); + DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [Read]", PtrReqdFCB->MainResource.ActiveCount, PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, PtrReqdFCB->MainResource.NumberOfSharedWaiters ); + if (!ExAcquireResourceSharedLite(&(PtrReqdFCB->MainResource), CanWait)) + { + DebugTrace(DEBUG_TRACE_MISC, "*** FCB Acquisition FAILED [Read]", 0); + CompleteIrp = FALSE; + PostRequest = TRUE; + try_return(RC = STATUS_PENDING); + } + DebugTrace(DEBUG_TRACE_MISC, "*** FCB Acquired [Read]", 0); + + // Remember the resource that was acquired + PtrResourceAcquired = &(PtrReqdFCB->MainResource); + } + + // Read in the File inode... + Ext2InitializeFCBInodeInfo( PtrFCB ); + + if (!PagingIo) + { + LARGE_INTEGER CurrentTime; + KeQuerySystemTime( &CurrentTime ); + PtrFCB->LastAccessTime.QuadPart = CurrentTime.QuadPart; + } + + // Validate start offset and length supplied. + if (ByteOffset.QuadPart >= PtrReqdFCB->CommonFCBHeader.FileSize.QuadPart ) + { + // Starting offset is > file size + try_return(RC = STATUS_END_OF_FILE); + } + + /* + * Round down the size of Paging I/O requests too. I'm not + * sure if the FS driver is responsible for doing that, but + * all other drivers I have seen do it. + * -- Filip Navara, 18/08/2004 + */ + if ( ByteOffset.QuadPart + ReadLength > PtrReqdFCB->CommonFCBHeader.FileSize.QuadPart ) + { + // Read going beyond the end of file... + // Adjusting the Read Length... + ReadLength = (UINT)(PtrReqdFCB->CommonFCBHeader.FileSize.QuadPart - ByteOffset.QuadPart); + if (PagingIo) + ReadLength = ROUND_TO_PAGES(ReadLength); + ReadTruncated = TRUE; + } + + // This is also a good place to set whether fast-io can be performed + // on this particular file or not. Your FSD must make it's own + // determination on whether or not to allow fast-io operations. + // Commonly, fast-io is not allowed if any byte range locks exist + // on the file or if oplocks prevent fast-io. Practically any reason + // choosen by your FSD could result in your setting FastIoIsNotPossible + // OR FastIoIsQuestionable instead of FastIoIsPossible. + // + // PtrReqdFCB->CommonFCBHeader.IsFastIoPossible = FastIoIsPossible; + + + // Branch here for cached vs non-cached I/O + + if (!NonBufferedIo) + { + DebugTrace(DEBUG_TRACE_READ_DETAILS, "[File Read] BufferedIo ", 0); + + // The caller wishes to perform cached I/O. Initiate caching if + // this is the first cached I/O operation using this file object + if (PtrFileObject->PrivateCacheMap == NULL) + { + // This is the first cached I/O operation. You must ensure + // that the FCB Common FCB Header contains valid sizes at this time + CcInitializeCacheMap(PtrFileObject, (PCC_FILE_SIZES)(&(PtrReqdFCB->CommonFCBHeader.AllocationSize)), + FALSE, // We will not utilize pin access for this file + &(Ext2GlobalData.CacheMgrCallBacks), // callbacks + PtrCCB); // The context used in callbacks + } + + // Check and see if this request requires a MDL returned to the caller + if (PtrIoStackLocation->MinorFunction & IRP_MN_MDL) + { + // Caller does want a MDL returned. Note that this mode + // implies that the caller is prepared to block + CcMdlRead(PtrFileObject, &ByteOffset, TruncatedReadLength, &(PtrIrp->MdlAddress), &(PtrIrp->IoStatus)); + NumberBytesRead = PtrIrp->IoStatus.Information; + RC = PtrIrp->IoStatus.Status; + + try_return(RC); + } + + // This is a regular run-of-the-mill cached I/O request. Let the + // Cache Manager worry about it! + // First though, we need a buffer pointer (address) that is valid + PtrSystemBuffer = Ext2GetCallersBuffer(PtrIrp); + ASSERT(PtrSystemBuffer); + + if (!CcCopyRead(PtrFileObject, &(ByteOffset), ReadLength, CanWait, PtrSystemBuffer, &(PtrIrp->IoStatus))) + { + // The caller was not prepared to block and data is not immediately + // available in the system cache + DebugTrace(DEBUG_TRACE_ASYNC, "Cache read failiure. Cannot read without blocking...", 0); + CompleteIrp = FALSE; + PostRequest = TRUE; + + // Mark Irp Pending ... + IoMarkIrpPending( PtrIrp ); + RC = STATUS_PENDING; + try_return(RC); + } + + // We have the data + RC = PtrIrp->IoStatus.Status; + NumberBytesRead = PtrIrp->IoStatus.Information; + try_return(RC); + } + else // NonBuffered or Paged IO + { + LONGLONG SingleIndirectBlockSize ; + LONGLONG DoubleIndirectBlockSize ; + LONGLONG TripleIndirectBlockSize ; + LONGLONG DirectBlockSize ; + + LONGLONG NoOfDirectBlocks ; + LONGLONG NoOfSingleIndirectBlocks ; + LONGLONG NoOfDoubleIndirectBlocks ; + LONGLONG NoOfTripleIndirectBlocks ; + + ULONG * PtrPinnedSIndirectBlock = NULL; + ULONG * PtrPinnedDIndirectBlock = NULL; + ULONG * PtrPinnedTIndirectBlock = NULL; + + // Used when reading a Triple Indirect Block... + LONGLONG FirstCachedDIBlockOffset = 0; + + // Used when reading a Double Indirect Block... + LONGLONG FirstCachedSIBlockOffset = 0; + + DebugTrace(DEBUG_TRACE_MISC, "[File Read] Paging IO or NonBufferedIo ", 0); + + // Calculating where the read should start from... + LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize; + PhysicalBlockSize = PtrVCB->TargetDeviceObject->SectorSize; + + NoOfDirectBlocks = EXT2_NDIR_BLOCKS ; + NoOfSingleIndirectBlocks = LogicalBlockSize / sizeof( ULONG ); + NoOfDoubleIndirectBlocks = NoOfSingleIndirectBlocks * LogicalBlockSize / sizeof( ULONG ); + NoOfTripleIndirectBlocks = NoOfDoubleIndirectBlocks * LogicalBlockSize / sizeof( ULONG ); + + DirectBlockSize = LogicalBlockSize * NoOfDirectBlocks; + SingleIndirectBlockSize = LogicalBlockSize * NoOfSingleIndirectBlocks; + DoubleIndirectBlockSize = LogicalBlockSize * NoOfDoubleIndirectBlocks ; + TripleIndirectBlockSize = LogicalBlockSize * NoOfTripleIndirectBlocks; + + LogicalBlockIndex = (ULONG)( ByteOffset.QuadPart / LogicalBlockSize); + + /* + if( ( ByteOffset.QuadPart + ReadLength ) > DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize ) + { + // + // Handle Triple indirect blocks? + // A Pop up will do for now... + // + UNICODE_STRING ErrorMessage; + Ext2CopyWideCharToUnicodeString( &ErrorMessage, L"Triple indirect blocks not supported as yet. - Ext2.sys" ); + DebugTrace(DEBUG_TRACE_ERROR, "@@@@@@@@ Triple indirect blocks need to be read in! \n@@@@@@@@ This is not supported as yet!", 0); + IoRaiseInformationalHardError( + IO_ERR_DRIVER_ERROR, + &ErrorMessage, + KeGetCurrentThread( ) ); + + Ext2DeallocateUnicodeString( &ErrorMessage ); + + RC = STATUS_INSUFFICIENT_RESOURCES; + try_return ( RC ); + + } + */ + if( ( ByteOffset.QuadPart + ReadLength ) > DirectBlockSize && + ( ByteOffset.QuadPart < DirectBlockSize + SingleIndirectBlockSize ) ) + { + // + // Single Indirect Blocks required... + // Read in the single indirect blocks... + // + + LARGE_INTEGER VolumeByteOffset; + + DebugTrace(DEBUG_TRACE_MISC, "Reading in some Single Indirect Blocks", 0); + + VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_IND_BLOCK ] * LogicalBlockSize; + + // + // Asking the cache manager to oblige by pinning the single indirect block... + // + if (!CcMapData( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + LogicalBlockSize, + CanWait, + &PtrPinnedSIndirectBCB, + (PVOID*)&PtrPinnedSIndirectBlock )) + { + CompleteIrp = FALSE; + PostRequest = TRUE; + + // Mark Irp Pending ... + IoMarkIrpPending( PtrIrp ); + RC = STATUS_PENDING; + try_return(RC); + DebugTrace(DEBUG_TRACE_ASYNC, "Cache read failiure while reading in volume meta data - Retrying", 0); + } + } + if( ( ByteOffset.QuadPart + ReadLength ) > DirectBlockSize + SingleIndirectBlockSize && + ( ByteOffset.QuadPart ) < DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize ) + { + // + // Double Indirect Blocks required... + // Read in the double indirect blocks... + // + + LONGLONG StartIndirectBlock; + LONGLONG EndIndirectBlock; + + + + LARGE_INTEGER VolumeByteOffset; + + DebugTrace(DEBUG_TRACE_MISC, "Reading in some Double Indirect Blocks", 0); + + VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_DIND_BLOCK ] * LogicalBlockSize; + + // + // Asking the cache manager to oblige by pinning the double indirect block... + // + if (!CcMapData( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + LogicalBlockSize, + CanWait, + &PtrPinnedDIndirectBCB, + (PVOID*)&PtrPinnedDIndirectBlock )) + { + CompleteIrp = FALSE; + PostRequest = TRUE; + + // Mark Irp Pending ... + IoMarkIrpPending( PtrIrp ); + RC = STATUS_PENDING; + try_return(RC); + DebugTrace(DEBUG_TRACE_ASYNC, "Cache read failiure while reading in volume meta data - Retrying", 0); + } + + // So far so good... + // Now determine the single indirect blocks that will have to be read in... + if( ByteOffset.QuadPart >= DirectBlockSize + SingleIndirectBlockSize ) + { + // Request doesnot require any single indirect or direct blocks + StartIndirectBlock = ByteOffset.QuadPart - (DirectBlockSize + SingleIndirectBlockSize); + StartIndirectBlock = StartIndirectBlock / LogicalBlockSize; + StartIndirectBlock = StartIndirectBlock / NoOfSingleIndirectBlocks; + } + else + { + StartIndirectBlock = 0; + } + + FirstCachedSIBlockOffset = (NoOfSingleIndirectBlocks*(StartIndirectBlock+1)) + NoOfDirectBlocks; + + if( ByteOffset.QuadPart + ReadLength >= + DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize) + { + EndIndirectBlock = DoubleIndirectBlockSize; + } + else + { + EndIndirectBlock = ByteOffset.QuadPart + ReadLength - + (DirectBlockSize + SingleIndirectBlockSize); + } + EndIndirectBlock = Ext2Align64( EndIndirectBlock, LogicalBlockSize )/LogicalBlockSize ; + EndIndirectBlock = Ext2Align64( EndIndirectBlock, NoOfSingleIndirectBlocks )/NoOfSingleIndirectBlocks; + + DIArrayCount = (ULONG)(EndIndirectBlock - StartIndirectBlock); + + PtrDIArray = Ext2AllocatePool(NonPagedPool, Ext2QuadAlign( DIArrayCount * sizeof( EXT2_SIBLOCKS ) ) ); + { + ULONG i; + + for( i = 0; i < DIArrayCount; i++ ) + { + VolumeByteOffset.QuadPart = PtrPinnedDIndirectBlock[StartIndirectBlock+i] * LogicalBlockSize; + if (!CcMapData( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + LogicalBlockSize, + CanWait, + &PtrDIArray[i].PtrBCB, + (PVOID*)&PtrDIArray[i].PtrSIBlocks)) + { + CompleteIrp = FALSE; + PostRequest = TRUE; + IoMarkIrpPending( PtrIrp ); + DIArrayCount = i; + try_return(RC = STATUS_PENDING); + + DebugTrace(DEBUG_TRACE_ASYNC, "Cache read failiure while reading in volume meta data - Retrying", 0); + } + } + } + } + + if( ( ByteOffset.QuadPart + ReadLength ) > DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize ) + { + // + // Triple Indirect Blocks required... + // Read in the triple indirect blocks... + // + LONGLONG StartTIndirectBlock; + LONGLONG EndTIndirectBlock; + + LONGLONG StartDIndirectBlock; + LONGLONG EndDIndirectBlock; + LONGLONG StartIndirectBlock; + LONGLONG EndIndirectBlock; + + LONGLONG ByteOffsetTillHere = 0; + + PBCB TempDIBCB; + LONG* TempDIBuffer; + + ULONG TIArrayIndex = 0; + + LARGE_INTEGER VolumeByteOffset; + + DebugTrace(DEBUG_TRACE_MISC, "Reading in some Triple Indirect Blocks", 0); + + VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_TIND_BLOCK ] * LogicalBlockSize; + + DebugTrace(DEBUG_TRACE_TRIPLE, "ByteOffset = 0x%I64X", ByteOffset ); + DebugTrace(DEBUG_TRACE_TRIPLE, "ReadLength = 0x%lX", ReadLength ); + DebugTrace(DEBUG_TRACE_TRIPLE, "EXT2_TIND_BLOCK = 0x%lX", PtrFCB->IBlock[ EXT2_TIND_BLOCK ] ); + // + // Asking the cache manager to oblige by pinning the triple indirect block... + // + if (!CcMapData( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + LogicalBlockSize, + CanWait, + &PtrPinnedTIndirectBCB, + (PVOID*)&PtrPinnedTIndirectBlock )) + { + CompleteIrp = FALSE; + PostRequest = TRUE; + + // Mark Irp Pending ... + IoMarkIrpPending( PtrIrp ); + RC = STATUS_PENDING; + try_return(RC); + DebugTrace(DEBUG_TRACE_ASYNC, "Cache read failiure while reading in volume meta data - Retrying", 0); + } + + // Determine the no of BCBs that need to be saved... + if( ByteOffset.QuadPart >= DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize ) + { + StartTIndirectBlock = ByteOffset.QuadPart; + } + else + { + StartTIndirectBlock = DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize; + } + EndTIndirectBlock = ByteOffset.QuadPart + ReadLength; + TIArrayCount = (ULONG)( (EndTIndirectBlock - StartTIndirectBlock) / SingleIndirectBlockSize ) + 2; + + + PtrTIArray = Ext2AllocatePool(NonPagedPool, Ext2QuadAlign( TIArrayCount * sizeof( EXT2_SIBLOCKS ) ) ); + + // Now determine the double indirect blocks that will have to be read in... + if( ByteOffset.QuadPart >= DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize ) + { + // Request doesnot require any single indirect or direct blocks + StartDIndirectBlock = ByteOffset.QuadPart - (DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize); + StartDIndirectBlock = StartDIndirectBlock / LogicalBlockSize; + StartDIndirectBlock = StartDIndirectBlock / NoOfDoubleIndirectBlocks; + + ByteOffsetTillHere = DirectBlockSize + SingleIndirectBlockSize + (DoubleIndirectBlockSize*(StartDIndirectBlock+1)) ; + //FirstCachedDIBlockOffset = ByteOffset.QuadPart / LogicalBlockSize; + FirstCachedDIBlockOffset = ByteOffsetTillHere / LogicalBlockSize; + } + else + { + ByteOffsetTillHere = DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize; + FirstCachedDIBlockOffset = ByteOffsetTillHere / LogicalBlockSize; + StartDIndirectBlock = 0; + } + + DebugTrace(DEBUG_TRACE_TRIPLE, "ByteOffsetTillHere = 0x%lX", ByteOffsetTillHere ); + + EndDIndirectBlock = ByteOffset.QuadPart + ReadLength - + (DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize); + EndDIndirectBlock = Ext2Align64( EndDIndirectBlock, LogicalBlockSize ) / LogicalBlockSize ; + EndDIndirectBlock = Ext2Align64( EndDIndirectBlock, NoOfDoubleIndirectBlocks ) / NoOfDoubleIndirectBlocks; + + { + // Reading in the necessary double indirect bocks... + ULONG i; + LONGLONG Count = EndDIndirectBlock-StartDIndirectBlock; + + for( i = 0; i < Count; i++, ByteOffsetTillHere += DoubleIndirectBlockSize) + { + VolumeByteOffset.QuadPart = PtrPinnedTIndirectBlock[StartDIndirectBlock+i] * LogicalBlockSize; + + DebugTrace(DEBUG_TRACE_TRIPLE, "Double VolOffset = 0x%I64X", VolumeByteOffset ); + + if( !CcMapData( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + LogicalBlockSize, + CanWait, + &TempDIBCB, + (PVOID*)&TempDIBuffer) ) + { + CompleteIrp = FALSE; + PostRequest = TRUE; + IoMarkIrpPending( PtrIrp ); + try_return(RC = STATUS_PENDING); + DebugTrace(DEBUG_TRACE_ASYNC, "Cache read failiure while reading in volume meta data - Retrying", 0); + } + + if( ByteOffset.QuadPart > ByteOffsetTillHere) + { + StartIndirectBlock = ByteOffset.QuadPart - (ByteOffsetTillHere); + StartIndirectBlock = StartIndirectBlock / LogicalBlockSize; + StartIndirectBlock = StartIndirectBlock / NoOfSingleIndirectBlocks; + + if( TIArrayIndex == 0 ) + { + FirstCachedDIBlockOffset += StartIndirectBlock * NoOfSingleIndirectBlocks; + } + } + else + { + StartIndirectBlock = 0; + } + + if( ByteOffset.QuadPart + ReadLength >= ByteOffsetTillHere + DoubleIndirectBlockSize) + { + EndIndirectBlock = DoubleIndirectBlockSize; + } + else + { + EndIndirectBlock = ByteOffset.QuadPart + ReadLength - ByteOffsetTillHere; + } + EndIndirectBlock = Ext2Align64( EndIndirectBlock, LogicalBlockSize )/LogicalBlockSize ; + EndIndirectBlock = Ext2Align64( EndIndirectBlock, NoOfSingleIndirectBlocks )/NoOfSingleIndirectBlocks; + + { + ULONG i; + + for( i = 0; i < (EndIndirectBlock - StartIndirectBlock); i++ ) + { + VolumeByteOffset.QuadPart = TempDIBuffer[StartIndirectBlock+i] * LogicalBlockSize; + DebugTrace(DEBUG_TRACE_TRIPLE, "Single VolOffset = 0x%I64X", VolumeByteOffset ); + + if (!CcMapData( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + LogicalBlockSize, + CanWait, + &PtrTIArray[ TIArrayIndex ].PtrBCB, + (PVOID*)&PtrTIArray[ TIArrayIndex ].PtrSIBlocks)) + { + CompleteIrp = FALSE; + PostRequest = TRUE; + IoMarkIrpPending( PtrIrp ); + DIArrayCount = i; + try_return(RC = STATUS_PENDING); + + DebugTrace(DEBUG_TRACE_ASYNC, "Cache read failiure while reading in volume meta data - Retrying", 0); + } + TIArrayIndex++; + } + } + CcUnpinData( TempDIBCB ); + TempDIBCB = NULL; + TempDIBuffer = NULL; + } + } + TIArrayCount = TIArrayIndex; + + DebugTrace(DEBUG_TRACE_TRIPLE, "TIArrayCount = %ld", TIArrayCount ); + DebugTrace(DEBUG_TRACE_TRIPLE, "FirstCachedDIBlockOffset = 0x%lX", FirstCachedDIBlockOffset ); + } + + + // + // Allocating memory for IO Runs + // + Index = ( (ReadLength - 2) / LogicalBlockSize + 2 ); + PtrIoRuns = Ext2AllocatePool(NonPagedPool, Ext2QuadAlign( Index * sizeof( EXT2_IO_RUN) ) ); + + + Start = (ULONG) ( ByteOffset.QuadPart - (LogicalBlockSize * LogicalBlockIndex) ); + BytesRemaining = (ULONG)( LogicalBlockSize * (LogicalBlockIndex +1) - ByteOffset.QuadPart ); + + if( ReadLength > BytesRemaining ) + { + End = Start + BytesRemaining; + } + else + { + End = Start + ReadLength; + } + BytesReadSoFar = 0; + + Index = 0; + DebugTrace(DEBUG_TRACE_MISC, "\nDetermining the read IRPs that have to be passed down...", 0); + + while( 1 ) + { + BytesReadSoFar += (End-Start); + if( LogicalBlockIndex < NoOfDirectBlocks ) + { + // Direct Block + PtrIoRuns[ Index ].LogicalBlock = PtrFCB->IBlock[ LogicalBlockIndex ]; + } + else if( LogicalBlockIndex < (NoOfSingleIndirectBlocks + NoOfDirectBlocks) ) + { + // Single Indirect Block + PtrIoRuns[ Index ].LogicalBlock = PtrPinnedSIndirectBlock[ LogicalBlockIndex - NoOfDirectBlocks ]; + } + else if( LogicalBlockIndex < (NoOfDoubleIndirectBlocks + NoOfSingleIndirectBlocks + NoOfDirectBlocks) ) + { + LONGLONG BlockNo; + LONGLONG IBlockIndex; + LONGLONG BlockIndex; + + BlockNo = LogicalBlockIndex - FirstCachedSIBlockOffset; + IBlockIndex = BlockNo / NoOfSingleIndirectBlocks; + BlockIndex = BlockNo % NoOfSingleIndirectBlocks; + + // Double Indirect Block + PtrIoRuns[ Index ].LogicalBlock = + PtrDIArray[ IBlockIndex ].PtrSIBlocks[ BlockIndex ]; + } + else + { + // Triple Indirect Block + LONGLONG BlockNo; + LONGLONG IBlockIndex; + LONGLONG BlockIndex; + BlockNo = LogicalBlockIndex - FirstCachedDIBlockOffset; + IBlockIndex = BlockNo / NoOfSingleIndirectBlocks; + BlockIndex = BlockNo % NoOfSingleIndirectBlocks; + + DbgPrint( "\nBlock No : 0x%I64X IBlockIndex = 0x%I64X BlockIndex = 0x%I64X", BlockNo, IBlockIndex, BlockIndex); + + if( IBlockIndex >= TIArrayCount ) + { + Ext2BreakPoint(); + } + if( BlockIndex >= LogicalBlockSize ) + { + Ext2BreakPoint(); + } + + PtrIoRuns[ Index ].LogicalBlock = PtrTIArray[ IBlockIndex ].PtrSIBlocks[ BlockIndex ];; + DbgPrint( "LogicalBlock = 0x%lX", PtrIoRuns[ Index ].LogicalBlock ); + } + + if( PtrIoRuns[ Index ].LogicalBlock == 0 ) + { + // + // Something is wrong... + // + //Ext2BreakPoint(); + Index--; + break; + + } + + + PtrIoRuns[ Index ].StartOffset = Start; + PtrIoRuns[ Index ].EndOffset = End; + PtrIoRuns[ Index ].PtrAssociatedIrp = NULL; + + DebugTrace( DEBUG_TRACE_MISC, " Index = (%ld)", LogicalBlockIndex ); + DebugTrace( DEBUG_TRACE_MISC, " Logical Block = (0x%lX)", PtrIoRuns[ Index ].LogicalBlock ); + DebugTrace( DEBUG_TRACE_MISC, " Start = (0x%lX)", Start ); + DebugTrace( DEBUG_TRACE_MISC, " End = (0x%lX) ", End ); + DebugTrace( DEBUG_TRACE_MISC, " Bytes read (0x%lX)", BytesReadSoFar ); + + + + if( BytesReadSoFar >= ReadLength ) + break; + LogicalBlockIndex++; + Start = 0; + LeftOver = ReadLength - BytesReadSoFar; + if( LeftOver > LogicalBlockSize ) + End = LogicalBlockSize; + else + End = LeftOver; + // Loop over to make the read request... + Index++; + } + // + // Unpin the Indirect Blocks + // + if( PtrPinnedSIndirectBCB ) + { + CcUnpinData( PtrPinnedSIndirectBCB ); + PtrPinnedSIndirectBCB = NULL; + PtrPinnedSIndirectBlock = NULL; + } + + if( PtrPinnedDIndirectBCB ) + { + CcUnpinData( PtrPinnedDIndirectBCB ); + PtrPinnedDIndirectBCB = NULL; + PtrPinnedDIndirectBlock = NULL; + } + + if( PtrPinnedTIndirectBCB) + { + CcUnpinData( PtrPinnedTIndirectBCB); + PtrPinnedTIndirectBCB = NULL; + PtrPinnedTIndirectBlock = NULL; + } + + if ( PtrDIArray ) + { + ULONG i; + for( i = 0; i < DIArrayCount; i++ ) + { + CcUnpinData( PtrDIArray->PtrBCB ); + } + DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [Read]", PtrDIArray ); + ExFreePool( PtrDIArray ); + PtrDIArray = NULL; + } + if ( PtrTIArray ) + { + ULONG i; + for( i = 0; i < TIArrayCount; i++ ) + { + CcUnpinData( PtrTIArray->PtrBCB ); + } + DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [Read]", PtrTIArray ); + ExFreePool( PtrTIArray ); + PtrTIArray = NULL; + } + // + // Pass down Associated IRPs to the Target Device Driver... + // + DebugTrace( DEBUG_TRACE_MISC, "Passing down the Read IRPs to the disk driver...", 0 ); + + RC = Ext2PassDownMultiReadWriteIRP( PtrIoRuns, Index+1, ReadLength, PtrIrpContext, PtrFCB, SynchronousIo ); + + // + // Irp will be completed automatically + // when all the Associated IRPs are completed + // + if( RC == STATUS_SUCCESS || RC == STATUS_PENDING ) + { + CompleteIrp = FALSE; + } + try_return( RC ); + + } + try_exit: NOTHING; + } + except (EXCEPTION_EXECUTE_HANDLER) + { + DebugTrace(DEBUG_TRACE_ERROR, "@@@@@@@@ Exception Handler", 0); + } + } + finally + { + if ( PtrIoRuns ) + { + DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [Read]", PtrIoRuns ); + ExFreePool( PtrIoRuns ); + } + // + // Unpin the Indirect Blocks + // + if( PtrPinnedSIndirectBCB ) + { + CcUnpinData( PtrPinnedSIndirectBCB ); + PtrPinnedSIndirectBCB = NULL; + } + + if( PtrPinnedDIndirectBCB ) + { + CcUnpinData( PtrPinnedDIndirectBCB ); + PtrPinnedDIndirectBCB = NULL; + } + if( PtrPinnedTIndirectBCB ) + { + CcUnpinData( PtrPinnedTIndirectBCB ); + PtrPinnedTIndirectBCB = NULL; + } + + if ( PtrDIArray ) + { + ULONG i; + for( i = 0; i < DIArrayCount; i++ ) + { + CcUnpinData( PtrDIArray->PtrBCB ); + } + DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [Read]", PtrDIArray ); + ExFreePool( PtrDIArray ); + } + + if ( PtrTIArray ) + { + ULONG i; + for( i = 0; i < TIArrayCount; i++ ) + { + CcUnpinData( PtrTIArray->PtrBCB ); + } + DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [Read]", PtrTIArray ); + ExFreePool( PtrTIArray ); + } + + // Release any resources acquired here ... + if (PtrResourceAcquired) + { + Ext2ReleaseResource(PtrResourceAcquired); + + DebugTraceState( "Resource AC:0x%LX SW:0x%LX EX:0x%LX [Read]", + PtrResourceAcquired->ActiveCount, + PtrResourceAcquired->NumberOfExclusiveWaiters, + PtrResourceAcquired->NumberOfSharedWaiters ); + + if( PtrFileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Read]", PtrFileObject); + } + if( PtrVCB && PtrResourceAcquired == &(PtrVCB->VCBResource) ) + { + DebugTrace(DEBUG_TRACE_MISC, "*** VCB Released [Read]", 0); + } + else if( PtrVCB && PtrResourceAcquired == &(PtrVCB->PagingIoResource ) ) + { + DebugTrace(DEBUG_TRACE_MISC, "*** VCBPaging Released [Read]", 0); + } + else if( PtrReqdFCB && PtrResourceAcquired == &(PtrReqdFCB->PagingIoResource) ) + { + DebugTrace(DEBUG_TRACE_MISC, "*** FCB Paging Resource Released [Read]", 0); + } + else if(PtrReqdFCB && PtrResourceAcquired == &(PtrReqdFCB->MainResource) ) + { + DebugTrace(DEBUG_TRACE_MISC, "*** FCB Resource Released [Read]", 0); + } + else + { + DebugTrace(DEBUG_TRACE_MISC, "*** Unknown Resource Released [Read]", 0); + } + + PtrResourceAcquired = NULL; + } + + // Post IRP if required + if ( PostRequest ) + { + + // Implement a routine that will queue up the request to be executed + // later (asynchronously) in the context of a system worker thread. + // See Chapter 10 for details. + + // Lock the callers buffer here. Then invoke a common routine to + // perform the post operation. + if (!(PtrIoStackLocation->MinorFunction & IRP_MN_MDL)) + { + RC = Ext2LockCallersBuffer(PtrIrp, TRUE, ReadLength); + ASSERT(NT_SUCCESS(RC)); + } + + // Perform the post operation which will mark the IRP pending + // and will return STATUS_PENDING back to us + RC = Ext2PostRequest(PtrIrpContext, PtrIrp); + } + else if (CompleteIrp && !(RC == STATUS_PENDING)) + { + // For synchronous I/O, the FSD must maintain the current byte offset + // Do not do this however, if I/O is marked as paging-io + if (SynchronousIo && !PagingIo && NT_SUCCESS(RC)) + { + PtrFileObject->CurrentByteOffset = RtlLargeIntegerAdd(ByteOffset, RtlConvertUlongToLargeInteger((unsigned long)NumberBytesRead)); + } + + // If the read completed successfully and this was not a paging-io + // operation, set a flag in the CCB that indicates that a read was + // performed and that the file time should be updated at cleanup + if (NT_SUCCESS(RC) && !PagingIo) + { + Ext2SetFlag(PtrCCB->CCBFlags, EXT2_CCB_ACCESSED); + } + + // Can complete the IRP here if no exception was encountered + if (!(PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_EXCEPTION)) + { + + PtrIrp->IoStatus.Status = RC; + PtrIrp->IoStatus.Information = NumberBytesRead; + + // Free up the Irp Context + Ext2ReleaseIrpContext(PtrIrpContext); + + // complete the IRP + IoCompleteRequest(PtrIrp, IO_DISK_INCREMENT); + } + } // can we complete the IRP ? + else + { + // Free up the Irp Context + Ext2ReleaseIrpContext(PtrIrpContext); + } + } // end of "finally" processing + + return(RC); +} + + + + +/************************************************************************* +* +* Function: Ext2GetCallersBuffer() +* +* Description: +* Obtain a pointer to the caller's buffer. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +void * Ext2GetCallersBuffer ( + PIRP PtrIrp ) +{ + void * ReturnedBuffer = NULL; + + // If an MDL is supplied, use it. + if (PtrIrp->MdlAddress) + { + ReturnedBuffer = MmGetSystemAddressForMdl(PtrIrp->MdlAddress); + } + else + { + ReturnedBuffer = PtrIrp->UserBuffer; + } + + return (ReturnedBuffer); +} + + + +/************************************************************************* +* +* Function: Ext2LockCallersBuffer() +* +* Description: +* Obtain a MDL that describes the buffer. Lock pages for I/O +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +NTSTATUS Ext2LockCallersBuffer( +PIRP PtrIrp, +BOOLEAN IsReadOperation, +uint32 Length) +{ + NTSTATUS RC = STATUS_SUCCESS; + PMDL PtrMdl = NULL; + + ASSERT(PtrIrp); + + try + { + // Is a MDL already present in the IRP + if( !(PtrIrp->MdlAddress) ) + { + // Allocate a MDL + if (!(PtrMdl = IoAllocateMdl(PtrIrp->UserBuffer, Length, FALSE, FALSE, PtrIrp))) + { + RC = STATUS_INSUFFICIENT_RESOURCES; + try_return(RC); + } + + // Probe and lock the pages described by the MDL + // We could encounter an exception doing so, swallow the exception + // NOTE: The exception could be due to an unexpected (from our + // perspective), invalidation of the virtual addresses that comprise + // the passed in buffer + try + { + MmProbeAndLockPages(PtrMdl, PtrIrp->RequestorMode, (IsReadOperation ? IoWriteAccess:IoReadAccess)); + } + except(EXCEPTION_EXECUTE_HANDLER) + { + RC = STATUS_INVALID_USER_BUFFER; + } + } + + try_exit: NOTHING; + + } + finally + { + if (!NT_SUCCESS(RC) && PtrMdl) + { + IoFreeMdl(PtrMdl); + // You MUST NULL out the MdlAddress field in the IRP after freeing + // the MDL, else the I/O Manager will also attempt to free the MDL + // pointed to by that field during I/O completion. Obviously, the + // pointer becomes invalid once you free the allocated MDL and hence + // you will encounter a system crash during IRP completion. + PtrIrp->MdlAddress = NULL; + } + } + + return(RC); +} + + + +/************************************************************************* +* +* Function: Ext2MdlComplete() +* +* Description: +* Tell Cache Manager to release MDL (and possibly flush). +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: None. +* +*************************************************************************/ +void Ext2MdlComplete( + PtrExt2IrpContext PtrIrpContext, + PIRP PtrIrp, + PIO_STACK_LOCATION PtrIoStackLocation, + BOOLEAN ReadCompletion) +{ + + NTSTATUS RC = STATUS_SUCCESS; + PFILE_OBJECT PtrFileObject = NULL; + + PtrFileObject = PtrIoStackLocation->FileObject; + ASSERT(PtrFileObject); + + // Not much to do here. + if( ReadCompletion ) + { + CcMdlReadComplete( PtrFileObject, PtrIrp->MdlAddress ); + } + else + { + // The Cache Manager needs the byte offset in the I/O stack location. + CcMdlWriteComplete( PtrFileObject, &(PtrIoStackLocation->Parameters.Write.ByteOffset), PtrIrp->MdlAddress ); + } + + // Clear the MDL address field in the IRP so the IoCompleteRequest() + // does not try to play around with the MDL. + PtrIrp->MdlAddress = NULL; + + // Free up the Irp Context. + Ext2ReleaseIrpContext(PtrIrpContext); + + // Complete the IRP. + PtrIrp->IoStatus.Status = RC; + PtrIrp->IoStatus.Information = 0; + IoCompleteRequest(PtrIrp, IO_NO_INCREMENT); + + return; +} diff --git a/reactos/drivers/fs/ext2/src/shutdown.c b/reactos/drivers/fs/ext2/src/shutdown.c new file mode 100644 index 00000000000..712e81fc30b --- /dev/null +++ b/reactos/drivers/fs/ext2/src/shutdown.c @@ -0,0 +1,211 @@ +/************************************************************************* +* +* File: shutdown.c +* +* Module: Ext2 File System Driver (Kernel mode execution only) +* +* Description: +* Contains code to handle the "shutdown notification" dispatch entry point. +* +* Author: Manoj Paul Joseph +* +* +*************************************************************************/ + +#include "ext2fsd.h" + +// define the file specific bug-check id +#define EXT2_BUG_CHECK_ID EXT2_FILE_SHUTDOWN +#define DEBUG_LEVEL (DEBUG_TRACE_SHUTDOWN) + + +/************************************************************************* +* +* Function: Ext2Shutdown() +* +* Description: +* All disk-based FSDs can expect to receive this shutdown notification +* request whenever the system is about to be halted gracefully. If you +* design and implement a network redirector, you must register explicitly +* for shutdown notification by invoking the IoRegisterShutdownNotification() +* routine from your driver entry. +* +* Note that drivers that register to receive shutdown notification get +* invoked BEFORE disk-based FSDs are told about the shutdown notification. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: Irrelevant. +* +*************************************************************************/ +NTSTATUS Ext2Shutdown( + PDEVICE_OBJECT DeviceObject, // the logical volume device object + PIRP Irp) // I/O Request Packet +{ + NTSTATUS RC = STATUS_SUCCESS; + PtrExt2IrpContext PtrIrpContext = NULL; + BOOLEAN AreWeTopLevel = FALSE; + + DebugTrace(DEBUG_TRACE_IRP_ENTRY, "Shutdown IRP received...", 0); + + FsRtlEnterFileSystem(); + ASSERT(DeviceObject); + ASSERT(Irp); + + // set the top level context + AreWeTopLevel = Ext2IsIrpTopLevel(Irp); + + try + { + + // get an IRP context structure and issue the request + PtrIrpContext = Ext2AllocateIrpContext(Irp, DeviceObject); + ASSERT(PtrIrpContext); + + RC = Ext2CommonShutdown(PtrIrpContext, Irp); + + } + except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) + { + + RC = Ext2ExceptionHandler(PtrIrpContext, Irp); + + Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); + } + + if (AreWeTopLevel) + { + IoSetTopLevelIrp(NULL); + } + + FsRtlExitFileSystem(); + + return(RC); +} + + +/************************************************************************* +* +* Function: Ext2CommonShutdown() +* +* Description: +* The actual work is performed here. Basically, all we do here is +* internally invoke a flush on all mounted logical volumes. This, in +* tuen, will result in all open file streams being flushed to disk. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: Irrelevant +* +*************************************************************************/ +NTSTATUS Ext2CommonShutdown( +PtrExt2IrpContext PtrIrpContext, +PIRP PtrIrp) +{ + NTSTATUS RC = STATUS_SUCCESS; + PIO_STACK_LOCATION PtrIoStackLocation = NULL; + IO_STATUS_BLOCK LocalIoStatus; + + try + { + // First, get a pointer to the current I/O stack location + PtrIoStackLocation = IoGetCurrentIrpStackLocation(PtrIrp); + ASSERT(PtrIoStackLocation); + + // (a) Block all new "mount volume" requests by acquiring an appropriate + // global resource/lock. + // (b) Go through your linked list of mounted logical volumes and for + // each such volume, do the following: + // (i) acquire the volume resource exclusively + // (ii) invoke Ext2FlushLogicalVolume() (internally) to flush the + // open data streams belonging to the volume from the system + // cache + // (iii) Invoke the physical/virtual/logical target device object + // on which the volume is mounted and inform this device + // about the shutdown request (Use IoBuildSynchronousFsdRequest() + // to create an IRP with MajorFunction = IRP_MJ_SHUTDOWN that you + // will then issue to the target device object). + // (iv) Wait for the completion of the shutdown processing by the target + // device object + // (v) Release the VCB resource you will have acquired in (i) above. + + // Once you have processed all the mounted logical volumes, you can release + // all acquired global resources and leave (in peace :-) + + + +/*//////////////////////////////////////////// + // + // Update the Group... + // + if( PtrVCB->LogBlockSize ) + { + // First block contains the descriptors... + VolumeByteOffset.QuadPart = LogicalBlockSize; + } + else + { + // Second block contains the descriptors... + VolumeByteOffset.QuadPart = LogicalBlockSize * 2; + } + + NumberOfBytesToRead = sizeof( struct ext2_group_desc ); + NumberOfBytesToRead = Ext2Align( NumberOfBytesToRead, LogicalBlockSize ); + + if (!CcMapData( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + NumberOfBytesToRead, + TRUE, + &PtrBCB, + &PtrCacheBuffer )) + { + DebugTrace(DEBUG_TRACE_ERROR, "Cache read failiure while reading in volume meta data", 0); + try_return( Status = STATUS_INSUFFICIENT_RESOURCES ); + } + else + { + // + // Saving up Often Used Group Descriptor Information in the VCB... + // + unsigned int DescIndex ; + + DebugTrace(DEBUG_TRACE_MISC, "Cache hit while reading in volume meta data", 0); + PtrGroupDescriptor = (PEXT2_GROUP_DESCRIPTOR )PtrCacheBuffer; + for( DescIndex = 0; DescIndex < PtrVCB->NoOfGroups; DescIndex++ ) + { + PtrVCB->PtrGroupDescriptors[ DescIndex ].InodeTablesBlock + = PtrGroupDescriptor[ DescIndex ].bg_inode_table; + + PtrVCB->PtrGroupDescriptors[ DescIndex ].InodeBitmapBlock + = PtrGroupDescriptor[ DescIndex ].bg_inode_bitmap + ; + PtrVCB->PtrGroupDescriptors[ DescIndex ].BlockBitmapBlock + = PtrGroupDescriptor[ DescIndex ].bg_block_bitmap + ; + PtrVCB->PtrGroupDescriptors[ DescIndex ].FreeBlocksCount + = PtrGroupDescriptor[ DescIndex ].bg_free_blocks_count; + + PtrVCB->PtrGroupDescriptors[ DescIndex ].FreeInodesCount + = PtrGroupDescriptor[ DescIndex ].bg_free_inodes_count; + } + CcUnpinData( PtrBCB ); + PtrBCB = NULL; + } +*///////////////////////////////////////////// + + try_exit: NOTHING; + + } + finally + { + + // See the read/write examples for how to fill in this portion + + } // end of "finally" processing + + return(RC); +} diff --git a/reactos/drivers/fs/ext2/src/volinfo.c b/reactos/drivers/fs/ext2/src/volinfo.c new file mode 100644 index 00000000000..33eb83e2c66 --- /dev/null +++ b/reactos/drivers/fs/ext2/src/volinfo.c @@ -0,0 +1,339 @@ +/************************************************************************* +* +* File: volinfo.c +* +* Module: Ext2 File System Driver (Kernel mode execution only) +* +* Description: +* Contains code to handle the various Volume Information related calls. +* +* Author: Manoj Paul Joseph +* +* +*************************************************************************/ + + + +#include "ext2fsd.h" + + + + +// define the file specific bug-check id +#define EXT2_BUG_CHECK_ID EXT2_FILE_VOL_INFORMATION +#define DEBUG_LEVEL (DEBUG_TRACE_VOLINFO) + + +/************************************************************************* +* +* Function: Ext2QueryVolInfo() +* +* Description: +* The I/O Manager will invoke this routine to handle a +* Query Volume Info IRP +* +* Expected Interrupt Level (for execution) : +* +* ??? +* +* Arguments: +* +* DeviceObject - Supplies the volume device object where the +* file exists +* +* Irp - Supplies the Irp being processed +* +* +* Return Value: +* +* NTSTATUS - The FSD status for the IRP +* +*************************************************************************/ +NTSTATUS Ext2QueryVolInfo ( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + + // The Return Status + NTSTATUS Status = STATUS_SUCCESS; + + // The IRP Stack Location + PIO_STACK_LOCATION IrpSp = NULL; + + // Volume Control Block + PtrExt2VCB PtrVCB = NULL; + + // The class of the query IRP + FS_INFORMATION_CLASS FsInformationClass; + + // The System Buffer Pointer + PVOID Buffer = NULL; + + // Parameter Length + ULONG Length = 0; + + // Bytes copied... + ULONG BytesCopied = 0; + + // Pointers to the Output Information... + PFILE_FS_VOLUME_INFORMATION PtrVolumeInformation = NULL; + PFILE_FS_SIZE_INFORMATION PtrSizeInformation = NULL; + PFILE_FS_ATTRIBUTE_INFORMATION PtrAttributeInformation = NULL; + PFILE_FS_DEVICE_INFORMATION PtrDeviceInformation = NULL; + PFILE_FS_FULL_SIZE_INFORMATION PtrFullSizeInformation = NULL; + + + // Now for the handler code... + DebugTrace(DEBUG_TRACE_IRP_ENTRY, "QueryVolumeInformation IRP", 0); + + FsRtlEnterFileSystem(); + + try + { + // Getting a pointer to the current I/O stack location + IrpSp = IoGetCurrentIrpStackLocation(Irp); + ASSERT( IrpSp ); + + // Getting the VCB and Verifying it... + PtrVCB = ( PtrExt2VCB )( DeviceObject->DeviceExtension ); + ASSERT(PtrVCB); + ASSERT(PtrVCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB); + + // Getting the query parameters... + Length = IrpSp->Parameters.QueryVolume.Length; + FsInformationClass = IrpSp->Parameters.QueryVolume.FsInformationClass; + Buffer = Irp->AssociatedIrp.SystemBuffer; + + // Now servicing the request depending on the type... + switch (FsInformationClass) + { + case FileFsVolumeInformation: + DebugTrace(DEBUG_TRACE_MISC, "Query Volume - FileFsVolumeInformation", 0); + PtrVolumeInformation = Buffer; + PtrVolumeInformation->SupportsObjects = FALSE; + PtrVolumeInformation->VolumeCreationTime.QuadPart = 0; + RtlCopyMemory( + PtrVolumeInformation->VolumeLabel, // destination + PtrVCB->PtrVPB->VolumeLabel, // source + PtrVCB->PtrVPB->VolumeLabelLength ); + PtrVolumeInformation->VolumeLabelLength = PtrVCB->PtrVPB->VolumeLabelLength; + PtrVolumeInformation->VolumeSerialNumber = PtrVCB->PtrVPB->SerialNumber; + BytesCopied = sizeof( FILE_FS_VOLUME_INFORMATION ) + PtrVolumeInformation->VolumeLabelLength - sizeof( WCHAR); + break; + + case FileFsSizeInformation: + DebugTrace(DEBUG_TRACE_MISC, "Query Volume - FileFsSizeInformation", 0); + PtrSizeInformation = Buffer; + PtrSizeInformation->BytesPerSector = DeviceObject->SectorSize; + PtrSizeInformation->AvailableAllocationUnits.QuadPart = PtrVCB->FreeBlocksCount; + PtrSizeInformation->SectorsPerAllocationUnit = ( EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize) / DeviceObject->SectorSize; + PtrSizeInformation->TotalAllocationUnits.QuadPart = PtrVCB->BlocksCount; + BytesCopied = sizeof( FILE_FS_SIZE_INFORMATION ); + break; + + case FileFsDeviceInformation: + DebugTrace(DEBUG_TRACE_MISC, "Query Volume - FileFsDeviceInformation", 0); + PtrDeviceInformation = Buffer; + PtrDeviceInformation->DeviceType = FILE_DEVICE_DISK; + PtrDeviceInformation->Characteristics = FILE_DEVICE_IS_MOUNTED; + BytesCopied = sizeof( FILE_FS_DEVICE_INFORMATION ); + break; + + case FileFsAttributeInformation: + DebugTrace(DEBUG_TRACE_MISC, "Query Volume - FileFsAttributeInformation", 0); + PtrAttributeInformation = Buffer; + RtlCopyMemory( PtrAttributeInformation->FileSystemName, L"EXT2", 10 ); + PtrAttributeInformation->FileSystemNameLength = 8; + PtrAttributeInformation->MaximumComponentNameLength = 255; + PtrAttributeInformation->FileSystemAttributes = + FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES; + BytesCopied = sizeof( FILE_FS_ATTRIBUTE_INFORMATION ) + 8; + + break; + + case FileFsFullSizeInformation: + DebugTrace(DEBUG_TRACE_MISC, "Query Volume - FileFsFullSizeInformation", 0); + PtrFullSizeInformation = Buffer; + PtrFullSizeInformation->BytesPerSector = DeviceObject->SectorSize; + PtrFullSizeInformation->ActualAvailableAllocationUnits.QuadPart = PtrVCB->FreeBlocksCount; + PtrFullSizeInformation->SectorsPerAllocationUnit = (EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize) / DeviceObject->SectorSize; + PtrFullSizeInformation->TotalAllocationUnits.QuadPart = PtrVCB->BlocksCount; + PtrFullSizeInformation->CallerAvailableAllocationUnits.QuadPart = PtrVCB->FreeBlocksCount - PtrVCB->ReservedBlocksCount; + BytesCopied = sizeof( FILE_FS_FULL_SIZE_INFORMATION ); + break; + + default: + Status = STATUS_INVALID_PARAMETER; + DebugTrace(DEBUG_TRACE_MISC, "Query Volume - STATUS_INVALID_PARAMETER", 0); + break; + } + + if( IrpSp->Parameters.QueryVolume.Length < BytesCopied ) + { + BytesCopied = IrpSp->Parameters.QueryVolume.Length; + Status = STATUS_BUFFER_OVERFLOW; + DebugTrace(DEBUG_TRACE_MISC, " === Buffer insufficient", 0); + } + try_exit: NOTHING; + } + finally + { + Irp->IoStatus.Information = BytesCopied; + Ext2CompleteRequest( Irp, Status ); + } + FsRtlExitFileSystem(); + + // + // Now return to the caller + // + + return Status; +} + + + +NTSTATUS Ext2SetVolInfo( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + // The Return Status + NTSTATUS Status = STATUS_SUCCESS; + + // The IRP Stack Location + PIO_STACK_LOCATION IrpSp = NULL; + + // Volume Control Block + PtrExt2VCB PtrVCB = NULL; + + // The class of the query IRP + FS_INFORMATION_CLASS FsInformationClass; + + // Pointers to the Output Information... + PFILE_FS_LABEL_INFORMATION PtrVolumeLabelInformation = NULL; + + // Now for the handler code... + DebugTrace(DEBUG_TRACE_IRP_ENTRY, "Set Volume Information IRP", 0); + + FsRtlEnterFileSystem(); + + try + { + // Getting a pointer to the current I/O stack location + IrpSp = IoGetCurrentIrpStackLocation(Irp); + ASSERT( IrpSp ); + + // Getting the VCB and Verifying it... + PtrVCB = ( PtrExt2VCB )( DeviceObject->DeviceExtension ); + AssertVCB(PtrVCB); + + // Getting the query parameters... + // Length = IrpSp->Parameters.SetVolume.Length; +#ifdef _GNU_NTIFS_ + FsInformationClass = ((PEXTENDED_IO_STACK_LOCATION)IrpSp)->Parameters.SetVolume.FsInformationClass; +#else + FsInformationClass = IrpSp->Parameters.SetVolume.FsInformationClass; +#endif + + // Now servicing the request depending on the type... + switch (FsInformationClass) + { + case FileFsLabelInformation: + PtrVolumeLabelInformation = Irp->AssociatedIrp.SystemBuffer; + if( PtrVolumeLabelInformation->VolumeLabelLength > MAXIMUM_VOLUME_LABEL_LENGTH || // This is the maximum that the + // VPB can take... + PtrVolumeLabelInformation->VolumeLabelLength > 32 ) // this is the maximum that Ext2 FS can support.. + { + try_return( Status = STATUS_INVALID_VOLUME_LABEL ); + } + + PtrVCB->PtrVPB->VolumeLabelLength = (USHORT)PtrVolumeLabelInformation->VolumeLabelLength ; + RtlCopyMemory( + PtrVCB->PtrVPB->VolumeLabel, // destination + PtrVolumeLabelInformation->VolumeLabel, // source + PtrVolumeLabelInformation->VolumeLabelLength ); + + { + // Now update the volume's super block... + + PEXT2_SUPER_BLOCK PtrSuperBlock = NULL; + PBCB PtrSuperBlockBCB = NULL; + LARGE_INTEGER VolumeByteOffset; + ULONG LogicalBlockSize = 0; + ULONG NumberOfBytesToRead = 0; + + + // Reading in the super block... + VolumeByteOffset.QuadPart = 1024; + + LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize; + + // THis shouldn't be more than a block in size... + NumberOfBytesToRead = Ext2Align( sizeof( EXT2_SUPER_BLOCK ), LogicalBlockSize ); + + if( !CcPinRead( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + NumberOfBytesToRead, + TRUE, + &PtrSuperBlockBCB, + (PVOID*)&PtrSuperBlock ) ) + { + DebugTrace(DEBUG_TRACE_ERROR, "Cache read failiure while reading in volume meta data", 0); + try_return( Status = STATUS_INVALID_VOLUME_LABEL ); + } + else + { + ULONG i; + for( i = 0; i < (PtrVolumeLabelInformation->VolumeLabelLength/2) ; i++ ) + { + PtrSuperBlock->s_volume_name[i] = + (char) PtrVolumeLabelInformation->VolumeLabel[i] ; + if( PtrSuperBlock->s_volume_name[i] == 0 ) + { + break; + } + } + if( i < 16 ) + { + PtrSuperBlock->s_volume_name[i] = 0; + } + + + CcSetDirtyPinnedData( PtrSuperBlockBCB, NULL ); + + // Not saving and flushing this information synchronously... + // This is not a critical information.. + // Settling for lazy writing of this information + + // Ext2SaveBCB( PtrIrpContext, PtrSuperBlockBCB, PtrVCB->PtrStreamFileObject ); + + if( PtrSuperBlockBCB ) + { + CcUnpinData( PtrSuperBlockBCB ); + PtrSuperBlockBCB = NULL; + } + + } + } + + break; + default: + Status = STATUS_INVALID_PARAMETER; + DebugTrace(DEBUG_TRACE_MISC, "Query Volume - STATUS_INVALID_PARAMETER", 0); + break; + } + + try_exit: NOTHING; + } + finally + { + Irp->IoStatus.Information = 0; + Ext2CompleteRequest( Irp, Status ); + } + FsRtlExitFileSystem(); + + // + // Now return to the caller + // + + return Status; +} diff --git a/reactos/drivers/fs/ext2/src/write.c b/reactos/drivers/fs/ext2/src/write.c new file mode 100644 index 00000000000..1fd2ce7ca3a --- /dev/null +++ b/reactos/drivers/fs/ext2/src/write.c @@ -0,0 +1,1483 @@ +/************************************************************************* +* +* File: write.c +* +* Module: Ext2 File System Driver (Kernel mode execution only) +* +* Description: +* Contains code to handle the "Write" dispatch entry point. +* +* Author: Manoj Paul Joseph +* +* +*************************************************************************/ + +#include "ext2fsd.h" + +// define the file specific bug-check id +#define EXT2_BUG_CHECK_ID EXT2_FILE_WRITE + +#define DEBUG_LEVEL (DEBUG_TRACE_WRITE) + + +/************************************************************************* +* +* Function: Ext2Write() +* +* Description: +* The I/O Manager will invoke this routine to handle a write +* request +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution +* to be deferred to a worker thread context) +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +NTSTATUS Ext2Write( +PDEVICE_OBJECT DeviceObject, // the logical volume device object +PIRP Irp) // I/O Request Packet +{ + NTSTATUS RC = STATUS_SUCCESS; + PtrExt2IrpContext PtrIrpContext = NULL; + BOOLEAN AreWeTopLevel = FALSE; + + DebugTrace(DEBUG_TRACE_IRP_ENTRY, "Write IRP Received...", 0); + + // Ext2BreakPoint(); + + FsRtlEnterFileSystem(); + ASSERT(DeviceObject); + ASSERT(Irp); + + // set the top level context + AreWeTopLevel = Ext2IsIrpTopLevel(Irp); + + try + { + // get an IRP context structure and issue the request + PtrIrpContext = Ext2AllocateIrpContext(Irp, DeviceObject); + ASSERT(PtrIrpContext); + + RC = Ext2CommonWrite(PtrIrpContext, Irp); + } + except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) + { + RC = Ext2ExceptionHandler(PtrIrpContext, Irp); + Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); + } + + if (AreWeTopLevel) + { + IoSetTopLevelIrp(NULL); + } + + FsRtlExitFileSystem(); + + return(RC); +} + + +/************************************************************************* +* +* Function: Ext2CommonWrite() +* +* Description: +* The actual work is performed here. This routine may be invoked in one' +* of the two possible contexts: +* (a) in the context of a system worker thread +* (b) in the context of the original caller +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +NTSTATUS Ext2CommonWrite( + PtrExt2IrpContext PtrIrpContext, + PIRP PtrIrp) +{ + + NTSTATUS RC = STATUS_SUCCESS; + PIO_STACK_LOCATION PtrIoStackLocation = NULL; + LARGE_INTEGER ByteOffset; + uint32 WriteLength = 0; + uint32 NumberBytesWritten = 0; + PFILE_OBJECT PtrFileObject = NULL; + PtrExt2FCB PtrFCB = NULL; + PtrExt2CCB PtrCCB = NULL; + PtrExt2VCB PtrVCB = NULL; + PtrExt2NTRequiredFCB PtrReqdFCB = NULL; + PERESOURCE PtrResourceAcquired = NULL; + IO_STATUS_BLOCK LocalIoStatus; + void *PtrSystemBuffer = NULL; + uint32 KeyValue = 0; + + BOOLEAN CompleteIrp = TRUE; + BOOLEAN PostRequest = FALSE; + + BOOLEAN CanWait = FALSE; + BOOLEAN PagingIo = FALSE; + BOOLEAN NonBufferedIo = FALSE; + BOOLEAN SynchronousIo = FALSE; + BOOLEAN IsThisADeferredWrite = FALSE; + BOOLEAN WritingAtEndOfFile = FALSE; + + EXT2_IO_RUN *PtrIoRuns = NULL; + + PBCB PtrPinnedSIndirectBCB = NULL; + PBCB PtrPinnedDIndirectBCB = NULL; + PBCB PtrPinnedTIndirectBCB = NULL; + + // Used to cache the Single Indirect blocks pointed to by + // the Double Indirect block + PEXT2_SIBLOCKS PtrDIArray = NULL; + ULONG DIArrayCount = 0; + + // Used to cache the Single Indirect blocks pointed to by + // the Triple Indirect block + PEXT2_SIBLOCKS PtrTIArray = NULL; + ULONG TIArrayCount = 0; + + + try + { + // First, get a pointer to the current I/O stack location + PtrIoStackLocation = IoGetCurrentIrpStackLocation(PtrIrp); + ASSERT(PtrIoStackLocation); + + PtrFileObject = PtrIoStackLocation->FileObject; + ASSERT(PtrFileObject); + + // If this happens to be a MDL write complete request, then + // allocated MDL can be freed. + if(PtrIoStackLocation->MinorFunction & IRP_MN_COMPLETE) + { + // Caller wants to tell the Cache Manager that a previously + // allocated MDL can be freed. + Ext2MdlComplete(PtrIrpContext, PtrIrp, PtrIoStackLocation, FALSE); + // The IRP has been completed. + CompleteIrp = FALSE; + try_return(RC = STATUS_SUCCESS); + } + + // If this is a request at IRQL DISPATCH_LEVEL, then post the request + if (PtrIoStackLocation->MinorFunction & IRP_MN_DPC) + { + CompleteIrp = FALSE; + PostRequest = TRUE; + try_return(RC = STATUS_PENDING); + } + + + // Get the FCB and CCB pointers + Ext2GetFCB_CCB_VCB_FromFileObject ( + PtrFileObject, &PtrFCB, &PtrCCB, &PtrVCB ); + + + // Get some of the parameters supplied to us + ByteOffset = PtrIoStackLocation->Parameters.Write.ByteOffset; + WriteLength = PtrIoStackLocation->Parameters.Write.Length; + + CanWait = ((PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_CAN_BLOCK) ? TRUE : FALSE); + PagingIo = ((PtrIrp->Flags & IRP_PAGING_IO) ? TRUE : FALSE); + NonBufferedIo = ((PtrIrp->Flags & IRP_NOCACHE) ? TRUE : FALSE); + SynchronousIo = ((PtrFileObject->Flags & FO_SYNCHRONOUS_IO) ? TRUE : FALSE); + + if( PtrFCB && PtrFCB->FCBName && PtrFCB->FCBName->ObjectName.Length && PtrFCB->FCBName->ObjectName.Buffer ) + { + DebugTrace(DEBUG_TRACE_FILE_NAME, " === Write File Name : -%S-", PtrFCB->FCBName->ObjectName.Buffer ); + } + else + { + DebugTrace(DEBUG_TRACE_FILE_NAME, " === Write File Name : -null-", 0); + } + + DebugTrace( DEBUG_TRACE_SPECIAL, " ->ByteCount = 0x%8lx", PtrIoStackLocation->Parameters.Read.Length); + DebugTrace( DEBUG_TRACE_SPECIAL, " ->ByteOffset.LowPart = 0x%8lx", PtrIoStackLocation->Parameters.Read.ByteOffset.LowPart); + + if( CanWait ) + { + DebugTrace(DEBUG_TRACE_WRITE_DETAILS, " ->Can Wait ", 0 ); + } + else + { + DebugTrace(DEBUG_TRACE_WRITE_DETAILS, " ->Can't Wait ", 0 ); + } + + if( PagingIo ) + { + DebugTrace(DEBUG_TRACE_WRITE_DETAILS, " ->Paging Io ", 0 ); + } + else + { + DebugTrace(DEBUG_TRACE_WRITE_DETAILS, " ->Not Paging Io", 0 ); + } + + if( SynchronousIo ) + { + DebugTrace(DEBUG_TRACE_WRITE_DETAILS, " ->SynchronousIo ", 0 ); + } + else + { + DebugTrace(DEBUG_TRACE_WRITE_DETAILS, " ->ASynchronousIo ", 0 ); + } + + if( NonBufferedIo ) + { + DebugTrace(DEBUG_TRACE_WRITE_DETAILS, " ->NonBufferedIo", 0 ); + } + else + { + DebugTrace(DEBUG_TRACE_WRITE_DETAILS, " ->BufferedIo", 0 ); + } + // Check at this point whether the file object being + // used for write really did have write permission requested when the + // create/open operation was performed. + // Don't do this for paging io... + + if (WriteLength == 0) + { + // a 0 byte write can be immediately succeeded + try_return(RC); + } + + // Is this a write of the volume itself ? + if ( ( !PtrFCB && PtrVCB ) || PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB) + { + // + // >>>>>>>>>>>>>>>>>> VOLUME WRITE <<<<<<<<<<<<<< + // + + // Validate the offset and length first... + // ....................................... + + // Acquire the volume resource exclusively + if( PtrFileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Write]", PtrFileObject); + } + + if( PagingIo ) + { + // This is Paging IO... + + DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** Attempting to acquire VCBPaging Exclusively [Write]", 0); + DebugTraceState( "VCBPaging AC:0x%LX SW:0x%LX EX:0x%LX [Write]", PtrVCB->PagingIoResource.ActiveCount, PtrVCB->PagingIoResource.NumberOfExclusiveWaiters, PtrVCB->PagingIoResource.NumberOfSharedWaiters ); + + if( !ExAcquireResourceExclusiveLite( &( PtrVCB->PagingIoResource ), FALSE ) ) + { + // post the request to be processed in the context of a worker thread + DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** VCBPaging Acquisition FAILED [Write]", 0); + CompleteIrp = FALSE; + PostRequest = TRUE; + try_return(RC = STATUS_PENDING); + } + + DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** VCBPaging Acquired [Write]", 0); + PtrResourceAcquired = &(PtrVCB->PagingIoResource); + } + else + { + // This is not Paging IO... + + DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** Attempting to acquire VCB Exclusively [Write]", 0); + DebugTraceState( "VCB AC:0x%LX SW:0x%LX EX:0x%LX [Write]", PtrVCB->VCBResource.ActiveCount, + PtrVCB->VCBResource.NumberOfExclusiveWaiters, PtrVCB->VCBResource.NumberOfSharedWaiters ); + + if( !ExAcquireResourceExclusiveLite( &(PtrVCB->VCBResource), FALSE ) ) + { + // post the request to be processed in the context of a worker thread + DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** VCB Acquisition FAILED [Write]", 0); + CompleteIrp = FALSE; + PostRequest = TRUE; + try_return(RC = STATUS_PENDING); + } + + DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** VCB Acquired [Write]", 0); + PtrResourceAcquired = &(PtrVCB->VCBResource); + } + + // Validate the caller supplied offset here + if( !PagingIo ) + { + if( PtrVCB->CommonVCBHeader.AllocationSize.QuadPart < ByteOffset.QuadPart ) + { + // Write extending beyond the end of volume. + // Deny access... + // + RC = STATUS_END_OF_FILE; + NumberBytesWritten = 0; + try_return( RC ); + } + } + + // Lock the callers buffer + if (!NT_SUCCESS(RC = Ext2LockCallersBuffer(PtrIrp, TRUE, WriteLength))) + { + try_return(RC); + } + + // Forward the request to the lower level driver + if( PagingIo || NonBufferedIo ) + { + DebugTrace(DEBUG_TRACE_WRITE_DETAILS, "[Volume Write] PagingIo or NonBufferedIo ", 0); + CompleteIrp = FALSE; + + // + // Do the write operation... + // Send down the IRP to the lower level driver... + // + // Returned Informations and Status will be set by the lower level driver... + // The IRP will also be completed by the lower level driver... + + RC = Ext2PassDownSingleReadWriteIRP ( + PtrIrpContext, PtrIrp, PtrVCB, + ByteOffset, WriteLength, SynchronousIo ); + + try_return(RC); + } + else + { + PBCB PtrBCB = NULL; + PVOID PtrBuffer = NULL; + + DebugTrace(DEBUG_TRACE_READ_DETAILS, "[Volume Write] BufferedIo ", 0); + // + // Let the cache manager worry about this write... + // Pinned access should have been initiated. + // But checking anyway... + // + ASSERT( PtrVCB->PtrStreamFileObject ); + ASSERT( PtrVCB->PtrStreamFileObject->PrivateCacheMap ); + + CcPreparePinWrite( + PtrVCB->PtrStreamFileObject, + &ByteOffset, + WriteLength, + FALSE, // Don't Zero... + TRUE, // Can Wait... + &PtrBCB, + &PtrBuffer); + + // Do the write now... + // Write to the Pinned buffer... + // Cache Manager will do the disk write... + RtlCopyBytes( PtrBuffer, PtrSystemBuffer, WriteLength ); + // CcSetDirtyPinnedData( PtrBCB, NULL ); + CcUnpinData( PtrBCB ); + PtrBuffer = NULL; + PtrBCB = NULL; + + NumberBytesWritten = WriteLength; + + // Go ahead and complete the IRP... + } + try_return(RC); + } + + + IsThisADeferredWrite = ((PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_DEFERRED_WRITE) ? TRUE : FALSE); + + if (!NonBufferedIo) + { + /**************************************************************************** + if (!CcCanIWrite(PtrFileObject, WriteLength, CanWait, IsThisADeferredWrite)) + { + // Cache Manager and/or the VMM does not want us to perform + // the write at this time. Post the request. + Ext2SetFlag(PtrIrpContext->IrpContextFlags, EXT2_IRP_CONTEXT_DEFERRED_WRITE); + CcDeferWrite( PtrFileObject, Ext2DeferredWriteCallBack, PtrIrpContext, PtrIrp, WriteLength, IsThisADeferredWrite); + CompleteIrp = FALSE; + try_return( RC = STATUS_PENDING ); + } + ****************************************************************************/ + } + + // If the write request is directed to a page file + // send the request directly to the disk + // driver. For requests directed to a page file, you have to trust + // that the offsets will be set correctly by the VMM. You should not + // attempt to acquire any FSD resources either. + if (PtrFCB->FCBFlags & EXT2_FCB_PAGE_FILE) + { + IoMarkIrpPending(PtrIrp); + + // You will need to set a completion routine before invoking a lower level driver. + // Forward request directly to disk driver. + // Ext2PageFileIo(PtrIrpContext, PtrIrp); + + CompleteIrp = FALSE; + + try_return(RC = STATUS_PENDING); + } + + // Check whether this write operation is targeted + // to a directory object... + + if (PtrFCB->FCBFlags & EXT2_FCB_DIRECTORY) + { + // + // Is this a write a result of + // cached directory manipulation operatio + // by the FSD itself? + // + if( PagingIo ) + { + // Yep! Allow it to proceed... + } + else + { + // Nope... User initiated directory writes are not allowed! + // Fail this request... + RC = STATUS_INVALID_DEVICE_REQUEST; + try_return(RC); + } + } + + PtrReqdFCB = &(PtrFCB->NTRequiredFCB); + + // + // Synchronizing with other reads and writes... + // Acquire the appropriate FCB resource exclusively + // + if (PagingIo) + { + // Try to acquire the FCB PagingIoResource exclusively + DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** Attempting to acquire FCBpaging Exclusively [Write]", 0); + + if (!ExAcquireResourceExclusiveLite(&(PtrReqdFCB->PagingIoResource), CanWait)) + { + DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** FCBpaging Acquisition FAILED [Write]", 0); + CompleteIrp = FALSE; + PostRequest = TRUE; + try_return(RC = STATUS_PENDING); + } + // Remember the resource that was acquired + DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** FCBpaging Acquired [Write]", 0); + PtrResourceAcquired = &(PtrReqdFCB->PagingIoResource); + } + else + { + // Try to acquire the FCB MainResource exclusively + DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** Attempting to acquire FCB Exclusively [Write]", 0); + if (!ExAcquireResourceExclusiveLite(&(PtrReqdFCB->MainResource), CanWait)) + { + DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** FCB Acquisition FAILED [Write]", 0); + CompleteIrp = FALSE; + PostRequest = TRUE; + try_return(RC = STATUS_PENDING); + } + // Remember the resource that was acquired + DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** FCB Acquired [Write]", 0); + PtrResourceAcquired = &(PtrReqdFCB->MainResource); + } + + // Validate start offset and length supplied. + // Here is a special check that determines whether the caller wishes to + // begin the write at current end-of-file (whatever the value of that + // offset might be) + if ((ByteOffset.LowPart == FILE_WRITE_TO_END_OF_FILE) && (ByteOffset.HighPart == 0xFFFFFFFF)) + { + WritingAtEndOfFile = TRUE; + ByteOffset.QuadPart = PtrReqdFCB->CommonFCBHeader.FileSize.QuadPart; + } + + // + // If this is a Non Cached io and if caching has been initiated, + // Flush and purge the cache + // + if (NonBufferedIo && !PagingIo && (PtrReqdFCB->SectionObject.DataSectionObject != NULL)) + { + // Flush and then attempt to purge the cache + CcFlushCache(&(PtrReqdFCB->SectionObject), &ByteOffset, WriteLength, &(PtrIrp->IoStatus)); + // If the flush failed, return error to the caller + if (!NT_SUCCESS(RC = PtrIrp->IoStatus.Status)) + { + try_return(RC); + } + + // Attempt the purge and ignore the return code + CcPurgeCacheSection( &(PtrReqdFCB->SectionObject), (WritingAtEndOfFile ? &(PtrReqdFCB->CommonFCBHeader.FileSize) : &(ByteOffset)), + WriteLength, FALSE); + // We are finished with our flushing and purging + } + + if (!PagingIo) + { + // Insert code to perform the check here ... + // + // if (!Ext2CheckForByteLock(PtrFCB, PtrCCB, PtrIrp, + // PtrCurrentIoStackLocation)) + // { + // try_return(RC = STATUS_FILE_LOCK_CONFLICT); + // } + } + + // Read in the File inode... + Ext2InitializeFCBInodeInfo( PtrFCB ); + + if (!PagingIo) + { + LARGE_INTEGER CurrentTime; + KeQuerySystemTime( &CurrentTime ); + PtrFCB->LastAccessTime.QuadPart = CurrentTime.QuadPart; + PtrFCB->LastWriteTime.QuadPart = CurrentTime.QuadPart; + } + + { + // + // Validate start offset and length supplied. + // + ULONG LogicalBlockSize = 0; + LONGLONG NoOfNewBlocksRequired = 0; + LONGLONG NoOfBytesRequired = 0; + LONGLONG i; + BOOLEAN ZeroOut = FALSE; + LARGE_INTEGER StartOffsetForZeroing; + LARGE_INTEGER EndOffsetForZeroing; + + + LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize; + + if ( ByteOffset.QuadPart + WriteLength >= PtrReqdFCB->CommonFCBHeader.FileSize.QuadPart ) + { + if( PagingIo ) + { + // + // A paging request never modifies the file size... + // + if( ByteOffset.QuadPart + >= PtrReqdFCB->CommonFCBHeader.AllocationSize.QuadPart ) + { + // Page request for writing outside the file... + // No op this IRP by completing it... + // + try_return(RC); + } + if( ByteOffset.QuadPart + WriteLength + > PtrReqdFCB->CommonFCBHeader.AllocationSize.QuadPart ) + { + // Page request for writing outside the file alocation size... + // Truncate the write size so that it is within the allocation limit... + // + WriteLength = (ULONG) (PtrReqdFCB->CommonFCBHeader.AllocationSize.QuadPart - ByteOffset.QuadPart); + } + } + else + { + + // Starting offset is > file size + // Allocate new blocks? + NoOfBytesRequired = ByteOffset.QuadPart + WriteLength + - PtrReqdFCB->CommonFCBHeader.AllocationSize.QuadPart; + + if( NoOfBytesRequired ) + { + NoOfNewBlocksRequired = Ext2Align64( NoOfBytesRequired, LogicalBlockSize ) + / LogicalBlockSize; + for( i = 0; i < NoOfNewBlocksRequired ; i++ ) + { + Ext2AddBlockToFile( PtrIrpContext, PtrVCB, PtrFCB, PtrFileObject, FALSE ); + } + + ZeroOut = TRUE; + + if( PtrReqdFCB->CommonFCBHeader.FileSize.QuadPart < ByteOffset.QuadPart ) + { + // Curr EOF --> | | <--New EOF + // ----------------------------------------------- + // | | |///////////| | + // | File Contents | Free |// Write //| Free | <- End of Allocation + // | | |///////////| | + // ----------------------------------------------- + // | | + + // Write is beyond the current end of file... + // This will create a hole... + // Will have to zero this out... + + // Start offset is the Current File size + StartOffsetForZeroing = PtrReqdFCB->CommonFCBHeader.FileSize; + // End offset is the point at which this write is going to start + EndOffsetForZeroing = ByteOffset; + } + else + { + // Curr EOF --> | | <--New EOF + // ------------------------------------------ + // | |///////////////| | + // | File Contents |//// Write ////| Free | <- End of Allocation + // | |///////////////| | + // ------------------------------------------ + // | | + + // Just zero out the end of the file + // not covered by the file size + + // Start offset is the New File size + StartOffsetForZeroing.QuadPart = + PtrReqdFCB->CommonFCBHeader.FileSize.QuadPart + WriteLength; + // End offset is the New Allocation size + EndOffsetForZeroing.QuadPart = PtrReqdFCB->CommonFCBHeader.AllocationSize.QuadPart; + } + } + + PtrReqdFCB->CommonFCBHeader.FileSize.QuadPart = + ByteOffset.QuadPart + WriteLength; + + ASSERT( PtrReqdFCB->CommonFCBHeader.FileSize.QuadPart <= PtrReqdFCB->CommonFCBHeader.AllocationSize.QuadPart ); + + Ext2UpdateFileSize( PtrIrpContext, PtrFileObject, PtrFCB ); + + try + { + // + // Zero the blocks out... + // This routine can be used even if caching has not been initiated... + // + if( ZeroOut == TRUE && StartOffsetForZeroing.QuadPart != EndOffsetForZeroing.QuadPart ) + { + CcZeroData( PtrFileObject, + &StartOffsetForZeroing, + &EndOffsetForZeroing, + FALSE ); + + if( EndOffsetForZeroing.QuadPart != PtrReqdFCB->CommonFCBHeader.AllocationSize.QuadPart ) + { + // Also zero out the file tip... + CcZeroData( PtrFileObject, + &PtrReqdFCB->CommonFCBHeader.FileSize, + &PtrReqdFCB->CommonFCBHeader.AllocationSize, + FALSE ); + } + } + } + finally + { + // Swallow an exceptions that are raised... + } + } + } + } + + // + // Branch here for cached vs non-cached I/O + // + if (!NonBufferedIo) + { + + // The caller wishes to perform cached I/O. + // Initiate caching if it hasn't been done already... + if (PtrFileObject->PrivateCacheMap == NULL) + { + CcInitializeCacheMap(PtrFileObject, (PCC_FILE_SIZES)(&(PtrReqdFCB->CommonFCBHeader.AllocationSize)), + FALSE, // We will not utilize pin access for this file + &(Ext2GlobalData.CacheMgrCallBacks), // callbacks + PtrCCB); // The context used in callbacks + } + + // Check and see if this request requires a MDL returned to the caller + if (PtrIoStackLocation->MinorFunction & IRP_MN_MDL) + { + // Caller does want a MDL returned. Note that this mode + // implies that the caller is prepared to block + CcPrepareMdlWrite(PtrFileObject, &ByteOffset, WriteLength, &(PtrIrp->MdlAddress), &(PtrIrp->IoStatus)); + NumberBytesWritten = PtrIrp->IoStatus.Information; + RC = PtrIrp->IoStatus.Status; + + try_return(RC); + } + + // This is a regular run-of-the-mill cached I/O request. Let the + // Cache Manager worry about it! + + // First though, we need a buffer pointer (address) that is valid + PtrSystemBuffer = Ext2GetCallersBuffer(PtrIrp); + ASSERT(PtrSystemBuffer); + if ( !CcCopyWrite(PtrFileObject, &(ByteOffset), WriteLength, CanWait, PtrSystemBuffer)) + { + // The caller was not prepared to block and data is not immediately + // available in the system cache + CompleteIrp = FALSE; + PostRequest = TRUE; + // Mark Irp Pending ... + try_return(RC = STATUS_PENDING); + } + else + { + // We have the data + PtrIrp->IoStatus.Status = RC; + PtrIrp->IoStatus.Information = NumberBytesWritten = WriteLength; + } + } + else // NonBuffered or Paged IO + { + + ULONG Start = 0; + ULONG End = 0; + ULONG LogicalBlockIndex = 0; + ULONG BytesRemaining = 0; + ULONG BytesWrittenSoFar = 0; + ULONG LeftOver = 0; + ULONG LogicalBlockSize = 0; + ULONG PhysicalBlockSize = 0; + ULONG Index = 0; + + LONGLONG SingleIndirectBlockSize = 0; + LONGLONG DoubleIndirectBlockSize = 0; + LONGLONG TripleIndirectBlockSize = 0; + LONGLONG DirectBlockSize = 0; + + LONGLONG NoOfDirectBlocks ; + LONGLONG NoOfSingleIndirectBlocks ; + LONGLONG NoOfDoubleIndirectBlocks ; + LONGLONG NoOfTripleIndirectBlocks ; + + ULONG * PtrPinnedSIndirectBlock = NULL; + ULONG * PtrPinnedDIndirectBlock = NULL; + ULONG * PtrPinnedTIndirectBlock = NULL; + + // Used when reading a Triple Indirect Block... + LONGLONG FirstCachedDIBlockOffset = 0; + + // Used when reading a Double Indirect Block... + LONGLONG FirstCachedSIBlockOffset = 0; + + DebugTrace(DEBUG_TRACE_WRITE_DETAILS, "[File Write] Paging IO or NonBufferedIo ", 0); + + // Calculating where the write should start from... + LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize; + PhysicalBlockSize = PtrVCB->TargetDeviceObject->SectorSize; + + NoOfDirectBlocks = EXT2_NDIR_BLOCKS ; + NoOfSingleIndirectBlocks = LogicalBlockSize / sizeof( ULONG ); + NoOfDoubleIndirectBlocks = NoOfSingleIndirectBlocks * LogicalBlockSize / sizeof( ULONG ); + NoOfTripleIndirectBlocks = NoOfDoubleIndirectBlocks * LogicalBlockSize / sizeof( ULONG ); + + DirectBlockSize = LogicalBlockSize * NoOfDirectBlocks; + SingleIndirectBlockSize = LogicalBlockSize * NoOfSingleIndirectBlocks; + DoubleIndirectBlockSize = LogicalBlockSize * NoOfDoubleIndirectBlocks ; + TripleIndirectBlockSize = LogicalBlockSize * NoOfTripleIndirectBlocks; + + LogicalBlockIndex = (ULONG)( ByteOffset.QuadPart / LogicalBlockSize); + + if( ( ByteOffset.QuadPart + WriteLength ) > DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize ) + { + // + // Handle Triple indirect blocks? + // A Pop up will do for now... + // + UNICODE_STRING ErrorMessage; + Ext2CopyWideCharToUnicodeString( &ErrorMessage, L"Triple indirect blocks not supported as yet. - Ext2.sys" ); + DebugTrace(DEBUG_TRACE_WRITE_DETAILS, "@@@@@@@@ Triple indirect blocks need to be written to! \n@@@@@@@@ This is not supported as yet!", 0); + /* REACTOS FIXME */ + IoRaiseInformationalHardError( + /* IO_ERR_DRIVER_ERROR */(NTSTATUS)0xC0040004L, + &ErrorMessage, + KeGetCurrentThread( ) ); + + Ext2DeallocateUnicodeString( &ErrorMessage ); + RC = STATUS_INSUFFICIENT_RESOURCES; + try_return ( RC ); + } + + if( ( ByteOffset.QuadPart + WriteLength ) > DirectBlockSize && + ( ByteOffset.QuadPart < DirectBlockSize + SingleIndirectBlockSize ) ) + { + LARGE_INTEGER VolumeByteOffset; + + // + // Indirect Blocks required... + // Read in the single indirect blocks... + // + DebugTrace(DEBUG_TRACE_WRITE_DETAILS, "Reading in some Indirect Blocks", 0); + + VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_NDIR_BLOCKS ] * LogicalBlockSize; + + // + // Asking the cache manager to oblige by pinning the single indirect block... + // + if (!CcMapData( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + LogicalBlockSize, + CanWait, + &PtrPinnedSIndirectBCB, + (PVOID*)&PtrPinnedSIndirectBlock )) + { + CompleteIrp = FALSE; + PostRequest = TRUE; + + // Mark Irp Pending ... + IoMarkIrpPending( PtrIrp ); + RC = STATUS_PENDING; + try_return(RC); + DebugTrace(DEBUG_TRACE_ASYNC, "Cache read failiure while reading in volume meta data", 0); + } + } + if( ( ByteOffset.QuadPart + WriteLength ) > DirectBlockSize + SingleIndirectBlockSize && + ( ByteOffset.QuadPart ) < DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize ) + { + // + // Double Indirect Blocks required... + // Read in the double indirect blocks... + // + + LONGLONG StartIndirectBlock; + LONGLONG EndIndirectBlock; + + + + LARGE_INTEGER VolumeByteOffset; + + DebugTrace(DEBUG_TRACE_MISC, "Reading in some Double Indirect Blocks", 0); + + VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_DIND_BLOCK ] * LogicalBlockSize; + + // + // Asking the cache manager to oblige by pinning the double indirect block... + // + if (!CcMapData( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + LogicalBlockSize, + CanWait, + &PtrPinnedDIndirectBCB, + (PVOID*)&PtrPinnedDIndirectBlock )) + { + CompleteIrp = FALSE; + PostRequest = TRUE; + + // Mark Irp Pending ... + IoMarkIrpPending( PtrIrp ); + RC = STATUS_PENDING; + try_return(RC); + DebugTrace(DEBUG_TRACE_ASYNC, "Cache read failiure while reading in volume meta data - Retrying", 0); + } + + // So far so good... + // Now determine the single indirect blocks that will have to be read in... + if( ByteOffset.QuadPart >= DirectBlockSize + SingleIndirectBlockSize ) + { + // Request doesnot require any single indirect or direct blocks + StartIndirectBlock = ByteOffset.QuadPart - (DirectBlockSize + SingleIndirectBlockSize); + StartIndirectBlock = StartIndirectBlock / LogicalBlockSize; + StartIndirectBlock = StartIndirectBlock / NoOfSingleIndirectBlocks; + } + else + { + StartIndirectBlock = 0; + } + + FirstCachedSIBlockOffset = (NoOfSingleIndirectBlocks*(StartIndirectBlock+1)) + NoOfDirectBlocks; + + if( ByteOffset.QuadPart + WriteLength >= + DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize) + { + EndIndirectBlock = DoubleIndirectBlockSize; + } + else + { + EndIndirectBlock = ByteOffset.QuadPart + WriteLength - + (DirectBlockSize + SingleIndirectBlockSize); + } + EndIndirectBlock = Ext2Align64( EndIndirectBlock, LogicalBlockSize )/LogicalBlockSize ; + EndIndirectBlock = Ext2Align64( EndIndirectBlock, NoOfSingleIndirectBlocks )/NoOfSingleIndirectBlocks; + + DIArrayCount = (ULONG)(EndIndirectBlock - StartIndirectBlock); + + PtrDIArray = Ext2AllocatePool(NonPagedPool, Ext2QuadAlign( DIArrayCount * sizeof( EXT2_SIBLOCKS ) ) ); + { + ULONG i; + + for( i = 0; i < DIArrayCount; i++ ) + { + VolumeByteOffset.QuadPart = PtrPinnedDIndirectBlock[StartIndirectBlock+i] * LogicalBlockSize; + if (!CcMapData( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + LogicalBlockSize, + CanWait, + &PtrDIArray[i].PtrBCB, + (PVOID*)&PtrDIArray[i].PtrSIBlocks)) + { + CompleteIrp = FALSE; + PostRequest = TRUE; + IoMarkIrpPending( PtrIrp ); + DIArrayCount = i; + try_return(RC = STATUS_PENDING); + + DebugTrace(DEBUG_TRACE_ASYNC, "Cache read failiure while reading in volume meta data - Retrying", 0); + } + } + } + } + +/* { + // + // Double Indirect Blocks required... + // Read in the double indirect blocks... + // + + LONGLONG StartIndirectBlock; + LONGLONG EndIndirectBlock; + + LARGE_INTEGER VolumeByteOffset; + + DebugTrace(DEBUG_TRACE_MISC, "Reading in some Double Indirect Blocks", 0); + + VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_DIND_BLOCK ] * LogicalBlockSize; + + // + // Asking the cache manager to oblige by pinning the double indirect block... + // + if (!CcMapData( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + LogicalBlockSize, + CanWait, + &PtrPinnedDIndirectBCB, + (PVOID*)&PtrPinnedDIndirectBlock )) + { + CompleteIrp = FALSE; + PostRequest = TRUE; + + // Mark Irp Pending ... + IoMarkIrpPending( PtrIrp ); + RC = STATUS_PENDING; + try_return(RC); + DebugTrace(DEBUG_TRACE_ASYNC, "Cache read failiure while reading in volume meta data - Retrying", 0); + } + + // So far so good... + // Now determine the single indirect blocks that will have to be read in... + if( ByteOffset.QuadPart >= DirectBlockSize + SingleIndirectBlockSize ) + { + // Request doesnot require any single indirect or direct blocks + StartIndirectBlock = ByteOffset.QuadPart - (DirectBlockSize + SingleIndirectBlockSize); + StartIndirectBlock = StartIndirectBlock / LogicalBlockSize; + StartIndirectBlock = StartIndirectBlock / NoOfSingleIndirectBlocks; + } + else + { + StartIndirectBlock = 0; + } + + if( ByteOffset.QuadPart + WriteLength >= + DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize) + { + EndIndirectBlock = DoubleIndirectBlockSize; + } + else + { + EndIndirectBlock = ByteOffset.QuadPart + WriteLength - + (DirectBlockSize + SingleIndirectBlockSize); + if( EndIndirectBlock % LogicalBlockSize ) + { + EndIndirectBlock += LogicalBlockSize; + } + EndIndirectBlock = EndIndirectBlock / LogicalBlockSize; + if( EndIndirectBlock % NoOfSingleIndirectBlocks) + { + EndIndirectBlock += NoOfSingleIndirectBlocks; + } + EndIndirectBlock = EndIndirectBlock / NoOfSingleIndirectBlocks; + } + DIArrayCount = (ULONG)(EndIndirectBlock - StartIndirectBlock); + PtrDIArray = Ext2AllocatePool(NonPagedPool, Ext2QuadAlign( DIArrayCount * sizeof( EXT2_SIBLOCKS ) ) ); + { + ULONG i; + + for( i = 0; i < DIArrayCount; i++ ) + { + VolumeByteOffset.QuadPart = PtrPinnedDIndirectBlock[StartIndirectBlock+i] * LogicalBlockSize; + if (!CcMapData( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + LogicalBlockSize, + CanWait, + &PtrDIArray[i].PtrBCB, + (PVOID*)&PtrDIArray[i].PtrSIBlocks)) + { + CompleteIrp = FALSE; + PostRequest = TRUE; + IoMarkIrpPending( PtrIrp ); + DIArrayCount = i; + try_return(RC = STATUS_PENDING); + + DebugTrace(DEBUG_TRACE_ASYNC, "Cache read failiure while reading in volume meta data - Retrying", 0); + } + } + } + } +*/ + if( ( ByteOffset.QuadPart + WriteLength ) > DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize ) + { + // + // Triple Indirect Blocks required... + // Read in the triple indirect blocks... + // + LONGLONG StartTIndirectBlock; + LONGLONG EndTIndirectBlock; + + LONGLONG StartDIndirectBlock; + LONGLONG EndDIndirectBlock; + LONGLONG StartIndirectBlock; + LONGLONG EndIndirectBlock; + + LONGLONG ByteOffsetTillHere = 0; + + PBCB TempDIBCB; + LONG* TempDIBuffer; + + ULONG TIArrayIndex = 0; + + LARGE_INTEGER VolumeByteOffset; + + DebugTrace(DEBUG_TRACE_MISC, "Reading in some Triple Indirect Blocks", 0); + + VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_TIND_BLOCK ] * LogicalBlockSize; + + DebugTrace(DEBUG_TRACE_TRIPLE, "ByteOffset = 0x%I64X", ByteOffset ); + DebugTrace(DEBUG_TRACE_TRIPLE, "WriteLength = 0x%lX", WriteLength ); + DebugTrace(DEBUG_TRACE_TRIPLE, "EXT2_TIND_BLOCK = 0x%lX", PtrFCB->IBlock[ EXT2_TIND_BLOCK ] ); + // + // Asking the cache manager to oblige by pinning the triple indirect block... + // + if (!CcMapData( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + LogicalBlockSize, + CanWait, + &PtrPinnedTIndirectBCB, + (PVOID*)&PtrPinnedTIndirectBlock )) + { + CompleteIrp = FALSE; + PostRequest = TRUE; + + // Mark Irp Pending ... + IoMarkIrpPending( PtrIrp ); + RC = STATUS_PENDING; + try_return(RC); + DebugTrace(DEBUG_TRACE_ASYNC, "Cache read failiure while reading in volume meta data - Retrying", 0); + } + + // Determine the no of BCBs that need to be saved... + if( ByteOffset.QuadPart >= DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize ) + { + StartTIndirectBlock = ByteOffset.QuadPart; + } + else + { + StartTIndirectBlock = DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize; + } + EndTIndirectBlock = ByteOffset.QuadPart + WriteLength; + TIArrayCount = (ULONG)( (EndTIndirectBlock - StartTIndirectBlock) / SingleIndirectBlockSize ) + 2; + + + PtrTIArray = Ext2AllocatePool(NonPagedPool, Ext2QuadAlign( TIArrayCount * sizeof( EXT2_SIBLOCKS ) ) ); + + // Now determine the double indirect blocks that will have to be read in... + if( ByteOffset.QuadPart >= DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize ) + { + // Request doesnot require any single indirect or direct blocks + StartDIndirectBlock = ByteOffset.QuadPart - (DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize); + StartDIndirectBlock = StartDIndirectBlock / LogicalBlockSize; + StartDIndirectBlock = StartDIndirectBlock / NoOfDoubleIndirectBlocks; + + ByteOffsetTillHere = DirectBlockSize + SingleIndirectBlockSize + (DoubleIndirectBlockSize*(StartDIndirectBlock+1)) ; + //FirstCachedDIBlockOffset = ByteOffset.QuadPart / LogicalBlockSize; + FirstCachedDIBlockOffset = ByteOffsetTillHere / LogicalBlockSize; + } + else + { + ByteOffsetTillHere = DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize; + FirstCachedDIBlockOffset = ByteOffsetTillHere / LogicalBlockSize; + StartDIndirectBlock = 0; + } + + DebugTrace(DEBUG_TRACE_TRIPLE, "ByteOffsetTillHere = 0x%lX", ByteOffsetTillHere ); + + EndDIndirectBlock = ByteOffset.QuadPart + WriteLength - + (DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize); + EndDIndirectBlock = Ext2Align64( EndDIndirectBlock, LogicalBlockSize ) / LogicalBlockSize ; + EndDIndirectBlock = Ext2Align64( EndDIndirectBlock, NoOfDoubleIndirectBlocks ) / NoOfDoubleIndirectBlocks; + + { + // Reading in the necessary double indirect bocks... + ULONG i; + LONGLONG Count = EndDIndirectBlock-StartDIndirectBlock; + + for( i = 0; i < Count; i++, ByteOffsetTillHere += DoubleIndirectBlockSize) + { + VolumeByteOffset.QuadPart = PtrPinnedTIndirectBlock[StartDIndirectBlock+i] * LogicalBlockSize; + + DebugTrace(DEBUG_TRACE_TRIPLE, "Double VolOffset = 0x%I64X", VolumeByteOffset ); + + if( !CcMapData( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + LogicalBlockSize, + CanWait, + &TempDIBCB, + (PVOID*)&TempDIBuffer) ) + { + CompleteIrp = FALSE; + PostRequest = TRUE; + IoMarkIrpPending( PtrIrp ); + try_return(RC = STATUS_PENDING); + DebugTrace(DEBUG_TRACE_ASYNC, "Cache read failiure while reading in volume meta data - Retrying", 0); + } + + if( ByteOffset.QuadPart > ByteOffsetTillHere) + { + StartIndirectBlock = ByteOffset.QuadPart - (ByteOffsetTillHere); + StartIndirectBlock = StartIndirectBlock / LogicalBlockSize; + StartIndirectBlock = StartIndirectBlock / NoOfSingleIndirectBlocks; + + if( TIArrayIndex == 0 ) + { + FirstCachedDIBlockOffset += StartIndirectBlock * NoOfSingleIndirectBlocks; + } + } + else + { + StartIndirectBlock = 0; + } + + if( ByteOffset.QuadPart + WriteLength >= ByteOffsetTillHere + DoubleIndirectBlockSize) + { + EndIndirectBlock = DoubleIndirectBlockSize; + } + else + { + EndIndirectBlock = ByteOffset.QuadPart + WriteLength - ByteOffsetTillHere; + } + EndIndirectBlock = Ext2Align64( EndIndirectBlock, LogicalBlockSize )/LogicalBlockSize ; + EndIndirectBlock = Ext2Align64( EndIndirectBlock, NoOfSingleIndirectBlocks )/NoOfSingleIndirectBlocks; + + { + ULONG i; + + for( i = 0; i < (EndIndirectBlock - StartIndirectBlock); i++ ) + { + VolumeByteOffset.QuadPart = TempDIBuffer[StartIndirectBlock+i] * LogicalBlockSize; + DebugTrace(DEBUG_TRACE_TRIPLE, "Single VolOffset = 0x%I64X", VolumeByteOffset ); + + if (!CcMapData( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + LogicalBlockSize, + CanWait, + &PtrTIArray[ TIArrayIndex ].PtrBCB, + (PVOID*)&PtrTIArray[ TIArrayIndex ].PtrSIBlocks)) + { + CompleteIrp = FALSE; + PostRequest = TRUE; + IoMarkIrpPending( PtrIrp ); + DIArrayCount = i; + try_return(RC = STATUS_PENDING); + + DebugTrace(DEBUG_TRACE_ASYNC, "Cache read failiure while reading in volume meta data - Retrying", 0); + } + TIArrayIndex++; + } + } + CcUnpinData( TempDIBCB ); + TempDIBCB = NULL; + TempDIBuffer = NULL; + } + } + TIArrayCount = TIArrayIndex; + + DebugTrace(DEBUG_TRACE_TRIPLE, "TIArrayCount = %ld", TIArrayCount ); + DebugTrace(DEBUG_TRACE_TRIPLE, "FirstCachedDIBlockOffset = 0x%lX", FirstCachedDIBlockOffset ); + } + + // + // Allocating memory for IO Runs + // + Index = ( (WriteLength - 2) / LogicalBlockSize + 2 ); + PtrIoRuns = Ext2AllocatePool(NonPagedPool, Ext2QuadAlign( Index * sizeof( EXT2_IO_RUN) ) ); + + + Start = (ULONG) ( ByteOffset.QuadPart - (LogicalBlockSize * LogicalBlockIndex) ); + BytesRemaining = (ULONG)( LogicalBlockSize * (LogicalBlockIndex +1) - ByteOffset.QuadPart ); + + if( WriteLength > BytesRemaining ) + End = Start + BytesRemaining; + else + End = Start + WriteLength; + BytesWrittenSoFar = 0; + + Index = 0; + DebugTrace(DEBUG_TRACE_WRITE_DETAILS, "\nDetermining the write IRPs that have to be passed down...", 0); + + while( 1 ) + { + BytesWrittenSoFar += (End-Start); + if( LogicalBlockIndex < EXT2_NDIR_BLOCKS ) + { + // Direct Block + PtrIoRuns[ Index ].LogicalBlock = PtrFCB->IBlock[ LogicalBlockIndex ]; + } + else if( LogicalBlockIndex < (NoOfSingleIndirectBlocks + NoOfDirectBlocks) ) + { + // Single Indirect Block + PtrIoRuns[ Index ].LogicalBlock = PtrPinnedSIndirectBlock[ LogicalBlockIndex - EXT2_NDIR_BLOCKS ]; + } + else if( LogicalBlockIndex < (NoOfDoubleIndirectBlocks + NoOfSingleIndirectBlocks + NoOfDirectBlocks) ) + { + LONGLONG BlockNo; + LONGLONG IBlockIndex; + LONGLONG BlockIndex; + + BlockNo = LogicalBlockIndex - FirstCachedSIBlockOffset; + IBlockIndex = BlockNo / NoOfSingleIndirectBlocks; + BlockIndex = BlockNo % NoOfSingleIndirectBlocks; + + // Double Indirect Block + PtrIoRuns[ Index ].LogicalBlock = + PtrDIArray[ IBlockIndex ].PtrSIBlocks[ BlockIndex ]; + } + else + { + // Triple Indirect Block + LONGLONG BlockNo; + LONGLONG IBlockIndex; + LONGLONG BlockIndex; + BlockNo = LogicalBlockIndex - FirstCachedDIBlockOffset; + IBlockIndex = BlockNo / NoOfSingleIndirectBlocks; + BlockIndex = BlockNo % NoOfSingleIndirectBlocks; + + DbgPrint( "\nBlock No : 0x%I64X IBlockIndex = 0x%I64X BlockIndex = 0x%I64X", BlockNo, IBlockIndex, BlockIndex); + + if( IBlockIndex >= TIArrayCount ) + { + Ext2BreakPoint(); + } + if( BlockIndex >= LogicalBlockSize ) + { + Ext2BreakPoint(); + } + + PtrIoRuns[ Index ].LogicalBlock = PtrTIArray[ IBlockIndex ].PtrSIBlocks[ BlockIndex ];; + DbgPrint( "LogicalBlock = 0x%lX", PtrIoRuns[ Index ].LogicalBlock ); + } + + if( PtrIoRuns[ Index ].LogicalBlock == 0 ) + { + // + // Something is wrong... + // + Ext2BreakPoint(); + break; + + } + PtrIoRuns[ Index ].StartOffset = Start; + PtrIoRuns[ Index ].EndOffset = End; + PtrIoRuns[ Index ].PtrAssociatedIrp = NULL; + + DebugTrace( DEBUG_TRACE_WRITE_DETAILS, " Index = (%ld)", LogicalBlockIndex ); + DebugTrace( DEBUG_TRACE_WRITE_DETAILS, " Logical Block = (0x%lX)", PtrFCB->IBlock[ LogicalBlockIndex ] ); + DebugTrace( DEBUG_TRACE_WRITE_DETAILS, " Start = (0x%lX)", Start ); + DebugTrace( DEBUG_TRACE_WRITE_DETAILS, " End = (0x%lX) ", End ); + DebugTrace( DEBUG_TRACE_WRITE_DETAILS, " Bytes written (0x%lX)", BytesWrittenSoFar ); + + + + if( BytesWrittenSoFar >= WriteLength ) + break; + LogicalBlockIndex++; + Start = 0; + LeftOver = WriteLength - BytesWrittenSoFar; + if( LeftOver > LogicalBlockSize ) + End = LogicalBlockSize; + else + End = LeftOver; + // Loop over to make the write request... + Index++; + } + + // + // Unpin the Indirect Blocks + // + if( PtrPinnedSIndirectBCB ) + { + CcUnpinData( PtrPinnedSIndirectBCB ); + PtrPinnedSIndirectBCB = NULL; + PtrPinnedSIndirectBlock = NULL; + } + if( PtrPinnedDIndirectBCB ) + { + CcUnpinData( PtrPinnedDIndirectBCB ); + PtrPinnedDIndirectBCB = NULL; + PtrPinnedDIndirectBlock = NULL; + } + // + // Pass down Associated IRPs to the Target Device Driver... + // + DebugTrace( DEBUG_TRACE_WRITE_DETAILS, "Passing down the Write IRPs to the disk driver...", 0 ); + + RC = Ext2PassDownMultiReadWriteIRP( PtrIoRuns, Index+1, WriteLength, PtrIrpContext, PtrFCB, SynchronousIo ); + + // + // Irp will be completed automatically + // when all the Associated IRPs are completed + // + if( RC == STATUS_SUCCESS || RC == STATUS_PENDING ) + { + CompleteIrp = FALSE; + } + try_return( RC ); + } + + try_exit: NOTHING; + + } + finally + { + if ( PtrIoRuns ) + { + DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [Write]", PtrIoRuns ); + ExFreePool( PtrIoRuns ); + } + if( PtrPinnedSIndirectBCB ) + { + CcUnpinData( PtrPinnedSIndirectBCB ); + PtrPinnedSIndirectBCB = NULL; + } + if( PtrPinnedDIndirectBCB ) + { + CcUnpinData( PtrPinnedDIndirectBCB ); + PtrPinnedDIndirectBCB = NULL; + } + if ( PtrDIArray ) + { + ULONG i; + for( i = 0; i < DIArrayCount; i++ ) + { + CcUnpinData( PtrDIArray->PtrBCB ); + } + DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [Read]", PtrDIArray ); + ExFreePool( PtrDIArray ); + PtrDIArray = NULL; + } + // Release resources ... + // + if (PtrResourceAcquired) + { + Ext2ReleaseResource(PtrResourceAcquired); + + DebugTrace(DEBUG_TRACE_RESOURCE_RELEASE, "*** Resource Released [Write]", 0); + DebugTraceState( "Resource AC:0x%LX SW:0x%LX EX:0x%LX [Write]", + PtrResourceAcquired->ActiveCount, + PtrResourceAcquired->NumberOfExclusiveWaiters, + PtrResourceAcquired->NumberOfSharedWaiters ); + + if( PtrFileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Write]", PtrFileObject); + } + if( PtrVCB && PtrResourceAcquired == &(PtrVCB->VCBResource) ) + { + DebugTrace(DEBUG_TRACE_MISC, "*** VCB Released [Write]", 0); + } + else if( PtrVCB && PtrResourceAcquired == &(PtrVCB->PagingIoResource ) ) + { + DebugTrace(DEBUG_TRACE_MISC, "*** VCBPaging Released [Write]", 0); + } + else if( PtrReqdFCB && PtrResourceAcquired == &(PtrReqdFCB->PagingIoResource) ) + { + DebugTrace(DEBUG_TRACE_MISC, "*** FCB Paging Resource Released [Write]", 0); + } + else if(PtrReqdFCB && PtrResourceAcquired == &(PtrReqdFCB->MainResource) ) + { + DebugTrace(DEBUG_TRACE_MISC, "*** FCB Resource Released [Write]", 0); + } + else + { + DebugTrace(DEBUG_TRACE_MISC, "*** Unknown Resource Released [Write]", 0); + } + + PtrResourceAcquired = NULL; + } + + if (PostRequest) + { + RC = Ext2PostRequest(PtrIrpContext, PtrIrp); + } + else if ( CompleteIrp && !(RC == STATUS_PENDING)) + { + // For synchronous I/O, the FSD must maintain the current byte offset + // Do not do this however, if I/O is marked as paging-io + if (SynchronousIo && !PagingIo && NT_SUCCESS(RC)) + { + PtrFileObject->CurrentByteOffset = RtlLargeIntegerAdd(ByteOffset, + RtlConvertUlongToLargeInteger((unsigned long)NumberBytesWritten)); + } + + // If the write completed successfully and this was not a paging-io + // operation, set a flag in the CCB that indicates that a write was + // performed and that the file time should be updated at cleanup + if (NT_SUCCESS(RC) && !PagingIo) + { + Ext2SetFlag(PtrCCB->CCBFlags, EXT2_CCB_MODIFIED); + } + + // If the file size was changed, set a flag in the FCB indicating that + // this occurred. + + // If the request failed, and we had done some nasty stuff like + // extending the file size (including informing the Cache Manager + // about the new file size), and allocating on-disk space etc., undo + // it at this time. + + // Can complete the IRP here if no exception was encountered + if (!(PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_EXCEPTION)) + { + PtrIrp->IoStatus.Status = RC; + PtrIrp->IoStatus.Information = NumberBytesWritten; + + // complete the IRP + IoCompleteRequest(PtrIrp, IO_DISK_INCREMENT); + } + + // Free up the Irp Context + Ext2ReleaseIrpContext(PtrIrpContext); + + } // can we complete the IRP ? + else + { + // Free up the Irp Context + Ext2ReleaseIrpContext(PtrIrpContext); + } + } // end of "finally" processing + return(RC); +} + + +/************************************************************************* +* +* Function: Ext2DeferredWriteCallBack() +* +* Description: +* Invoked by the cache manager in the context of a worker thread. +* Typically, you can simply post the request at this point (just +* as you would have if the original request could not block) to +* perform the write in the context of a system worker thread. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: None +* +*************************************************************************/ +void Ext2DeferredWriteCallBack ( +void *Context1, // Should be PtrIrpContext +void *Context2 ) // Should be PtrIrp +{ + // You should typically simply post the request to your internal + // queue of posted requests (just as you would if the original write + // could not be completed because the caller could not block). + // Once you post the request, return from this routine. The write + // will then be retried in the context of a system worker thread +} diff --git a/reactos/drivers/fs/ext2/super.c b/reactos/drivers/fs/ext2/super.c deleted file mode 100644 index bb1c2f0c00b..00000000000 --- a/reactos/drivers/fs/ext2/super.c +++ /dev/null @@ -1,202 +0,0 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS kernel - * FILE: services/fs/ext2/super.c - * PURPOSE: ext2 filesystem - * PROGRAMMER: David Welch (welch@mcmail.com) - * UPDATE HISTORY: - */ - -/* INCLUDES *****************************************************************/ - -#include -#include - -//#define NDEBUG -#include - -#include "ext2fs.h" - -/* GLOBALS *****************************************************************/ - -static PDRIVER_OBJECT DriverObject; - -/* FUNCTIONS ****************************************************************/ - -NTSTATUS STDCALL -Ext2Close(PDEVICE_OBJECT DeviceObject, PIRP Irp) -{ - PIO_STACK_LOCATION Stack; - PFILE_OBJECT FileObject; - PDEVICE_EXTENSION DeviceExtension; - NTSTATUS Status; - PEXT2_FCB Fcb; - - DbgPrint("Ext2Close(DeviceObject %x, Irp %x)\n",DeviceObject,Irp); - - Stack = IoGetCurrentIrpStackLocation(Irp); - FileObject = Stack->FileObject; - DeviceExtension = DeviceObject->DeviceExtension; - - if (FileObject == DeviceExtension->FileObject) - { - Status = STATUS_SUCCESS; - - Irp->IoStatus.Status = Status; - Irp->IoStatus.Information = 0; - - IoCompleteRequest(Irp, IO_NO_INCREMENT); - return(Status); - } - - Fcb = (PEXT2_FCB)FileObject->FsContext; - if (Fcb != NULL) - { - if (Fcb->Bcb != NULL) - { - CcRosReleaseFileCache(FileObject, Fcb->Bcb); - } - ExFreePool(Fcb); - FileObject->FsContext = NULL; - } - - Status = STATUS_SUCCESS; - - Irp->IoStatus.Status = Status; - Irp->IoStatus.Information = 0; - - IoCompleteRequest(Irp, IO_NO_INCREMENT); - return(Status); -} - -NTSTATUS Ext2Mount(PDEVICE_OBJECT DeviceToMount) -{ - PDEVICE_OBJECT DeviceObject; - PDEVICE_EXTENSION DeviceExt; - PVOID BlockBuffer; - struct ext2_super_block* superblock; - - DPRINT("Ext2Mount(DeviceToMount %x)\n",DeviceToMount); - - BlockBuffer = ExAllocatePool(NonPagedPool,BLOCKSIZE); - Ext2ReadSectors(DeviceToMount, - 1, - 1, - BlockBuffer); - superblock = BlockBuffer; - - if (superblock->s_magic != EXT2_SUPER_MAGIC) - { - ExFreePool(BlockBuffer); - return(STATUS_UNRECOGNIZED_VOLUME); - } - DPRINT("Volume recognized\n"); - DPRINT("s_inodes_count %d\n",superblock->s_inodes_count); - DPRINT("s_blocks_count %d\n",superblock->s_blocks_count); - - IoCreateDevice(DriverObject, - sizeof(DEVICE_EXTENSION), - NULL, - FILE_DEVICE_FILE_SYSTEM, - 0, - FALSE, - &DeviceObject); - DPRINT("DeviceObject %x\n",DeviceObject); - DeviceObject->Flags = DeviceObject->Flags | DO_DIRECT_IO; - DeviceExt = (PVOID)DeviceObject->DeviceExtension; - DPRINT("DeviceExt %x\n",DeviceExt); - - DeviceExt->StorageDevice = DeviceToMount; - DeviceExt->StorageDevice->Vpb->DeviceObject = DeviceObject; - DeviceExt->StorageDevice->Vpb->RealDevice = DeviceExt->StorageDevice; - DeviceExt->StorageDevice->Vpb->Flags |= VPB_MOUNTED; - DeviceObject->StackSize = DeviceExt->StorageDevice->StackSize + 1; - DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; - - DPRINT("DeviceExt->StorageDevice %x\n", DeviceExt->StorageDevice); - DeviceExt->FileObject = IoCreateStreamFileObject(NULL, DeviceObject); - DeviceExt->superblock = superblock; - CcRosInitializeFileCache(DeviceExt->FileObject, - &DeviceExt->Bcb, - PAGE_SIZE * 3); - - DPRINT("Ext2Mount() = STATUS_SUCCESS\n"); - - return(STATUS_SUCCESS); -} - -NTSTATUS STDCALL -Ext2FileSystemControl(PDEVICE_OBJECT DeviceObject, PIRP Irp) -{ - PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp); - PVPB vpb = Stack->Parameters.Mount.Vpb; - PDEVICE_OBJECT DeviceToMount = Stack->Parameters.Mount.DeviceObject; - NTSTATUS Status; - - Status = Ext2Mount(DeviceToMount); - - Irp->IoStatus.Status = Status; - Irp->IoStatus.Information = 0; - - IoCompleteRequest(Irp, IO_NO_INCREMENT); - return(Status); -} - -NTSTATUS STDCALL -DriverEntry(PDRIVER_OBJECT _DriverObject, - PUNICODE_STRING RegistryPath) -/* - * FUNCTION: Called by the system to initalize the driver - * ARGUMENTS: - * DriverObject = object describing this driver - * RegistryPath = path to our configuration entries - * RETURNS: Success or failure - */ -{ - PDEVICE_OBJECT DeviceObject; - NTSTATUS ret; - UNICODE_STRING DeviceName = ROS_STRING_INITIALIZER(L"\\Device\\Ext2Fsd"); - - DbgPrint("Ext2 FSD 0.0.1\n"); - - DriverObject = _DriverObject; - - ret = IoCreateDevice(DriverObject, - 0, - &DeviceName, - FILE_DEVICE_FILE_SYSTEM, - 0, - FALSE, - &DeviceObject); - if (ret!=STATUS_SUCCESS) - { - return(ret); - } - - DeviceObject->Flags=0; - DriverObject->MajorFunction[IRP_MJ_CLOSE] = Ext2Close; - DriverObject->MajorFunction[IRP_MJ_CREATE] = Ext2Create; - DriverObject->MajorFunction[IRP_MJ_READ] = Ext2Read; - DriverObject->MajorFunction[IRP_MJ_WRITE] = Ext2Write; - DriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] = - Ext2FileSystemControl; - DriverObject->MajorFunction[IRP_MJ_DIRECTORY_CONTROL] = - Ext2DirectoryControl; - DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION] = - Ext2QueryInformation; - DriverObject->MajorFunction[IRP_MJ_SET_INFORMATION] = Ext2SetInformation; - DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = Ext2FlushBuffers; - DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = Ext2Shutdown; - DriverObject->MajorFunction[IRP_MJ_CLEANUP] = Ext2Cleanup; - DriverObject->MajorFunction[IRP_MJ_QUERY_SECURITY] = Ext2QuerySecurity; - DriverObject->MajorFunction[IRP_MJ_SET_SECURITY] = Ext2SetSecurity; - DriverObject->MajorFunction[IRP_MJ_QUERY_QUOTA] = Ext2QueryQuota; - DriverObject->MajorFunction[IRP_MJ_SET_QUOTA] = Ext2SetQuota; - - DriverObject->DriverUnload = NULL; - - IoRegisterFileSystem(DeviceObject); - - return(STATUS_SUCCESS); -} - From 395064be78290e33d0cc8e80435ae92dda7a64f5 Mon Sep 17 00:00:00 2001 From: Art Yerkes Date: Thu, 13 Jan 2005 01:54:28 +0000 Subject: [PATCH 2/8] Ext2lib import by filip navara for use by usetup. svn path=/branches/ext2/; revision=13010 --- reactos/lib/fslib/ext2lib/.cvsignore | 3 + reactos/lib/fslib/ext2lib/Badblock.c | 43 + reactos/lib/fslib/ext2lib/Bitmap.c | 499 ++++++++++ reactos/lib/fslib/ext2lib/Bitmap.h | 12 + reactos/lib/fslib/ext2lib/Disk.c | 1352 ++++++++++++++++++++++++++ reactos/lib/fslib/ext2lib/Disk.h | 19 + reactos/lib/fslib/ext2lib/Group.c | 68 ++ reactos/lib/fslib/ext2lib/Inode.c | 697 +++++++++++++ reactos/lib/fslib/ext2lib/Makefile | 19 + reactos/lib/fslib/ext2lib/Memory.c | 416 ++++++++ reactos/lib/fslib/ext2lib/Mke2fs.c | 1010 +++++++++++++++++++ reactos/lib/fslib/ext2lib/Mke2fs.h | 876 +++++++++++++++++ reactos/lib/fslib/ext2lib/Super.c | 302 ++++++ reactos/lib/fslib/ext2lib/Uuid.c | 25 + reactos/lib/fslib/ext2lib/ext2_fs.h | 657 +++++++++++++ reactos/lib/fslib/ext2lib/types.h | 10 + 16 files changed, 6008 insertions(+) create mode 100644 reactos/lib/fslib/ext2lib/.cvsignore create mode 100644 reactos/lib/fslib/ext2lib/Badblock.c create mode 100644 reactos/lib/fslib/ext2lib/Bitmap.c create mode 100644 reactos/lib/fslib/ext2lib/Bitmap.h create mode 100644 reactos/lib/fslib/ext2lib/Disk.c create mode 100644 reactos/lib/fslib/ext2lib/Disk.h create mode 100644 reactos/lib/fslib/ext2lib/Group.c create mode 100644 reactos/lib/fslib/ext2lib/Inode.c create mode 100644 reactos/lib/fslib/ext2lib/Makefile create mode 100644 reactos/lib/fslib/ext2lib/Memory.c create mode 100644 reactos/lib/fslib/ext2lib/Mke2fs.c create mode 100644 reactos/lib/fslib/ext2lib/Mke2fs.h create mode 100644 reactos/lib/fslib/ext2lib/Super.c create mode 100644 reactos/lib/fslib/ext2lib/Uuid.c create mode 100644 reactos/lib/fslib/ext2lib/ext2_fs.h create mode 100644 reactos/lib/fslib/ext2lib/types.h diff --git a/reactos/lib/fslib/ext2lib/.cvsignore b/reactos/lib/fslib/ext2lib/.cvsignore new file mode 100644 index 00000000000..b0a14e25f87 --- /dev/null +++ b/reactos/lib/fslib/ext2lib/.cvsignore @@ -0,0 +1,3 @@ +*.d +*.o +*.sym diff --git a/reactos/lib/fslib/ext2lib/Badblock.c b/reactos/lib/fslib/ext2lib/Badblock.c new file mode 100644 index 00000000000..642c1bd8fd7 --- /dev/null +++ b/reactos/lib/fslib/ext2lib/Badblock.c @@ -0,0 +1,43 @@ +/* + * PROJECT: Mke2fs + * FILE: Badblock.c + * PROGRAMMER: Matt Wu + * HOMEPAGE: http://ext2.yeah.net + */ + +/* INCLUDES **************************************************************/ + +#include "Mke2fs.h" + +/* DEFINITIONS ***********************************************************/ + +/* FUNCTIONS *************************************************************/ + +bool create_bad_block_inode( PEXT2_FILESYS Ext2Sys, + PEXT2_BADBLK_LIST bb_list) +{ + bool retval; + EXT2_INODE inode; + LARGE_INTEGER SysTime; + + NtQuerySystemTime(&SysTime); + + ext2_mark_inode_bitmap(Ext2Sys->inode_map, EXT2_BAD_INO); + + Ext2Sys->group_desc[0].bg_free_inodes_count--; + Ext2Sys->ext2_sb->s_free_inodes_count--; + + memset(&inode, 0, sizeof(EXT2_INODE)); + inode.i_mode = (USHORT)((0777 & ~Ext2Sys->umask)); + inode.i_uid = inode.i_gid = 0; + inode.i_blocks = 0; + inode.i_block[0] = 0; + inode.i_links_count = 2; + RtlTimeToSecondsSince1970(&SysTime, &inode.i_mtime); + inode.i_ctime = inode.i_atime = inode.i_mtime; + inode.i_size = 0; + + retval = ext2_save_inode(Ext2Sys, EXT2_BAD_INO, &inode); + + return retval; +} diff --git a/reactos/lib/fslib/ext2lib/Bitmap.c b/reactos/lib/fslib/ext2lib/Bitmap.c new file mode 100644 index 00000000000..bc2746ad533 --- /dev/null +++ b/reactos/lib/fslib/ext2lib/Bitmap.c @@ -0,0 +1,499 @@ +/* + * PROJECT: Mke2fs + * FILE: Bitmap.c + * PROGRAMMER: Matt Wu + * HOMEPAGE: http://ext2.yeah.net + */ + +/* INCLUDES **************************************************************/ + +#include "Mke2fs.h" + +/* DEFINITIONS ***********************************************************/ + +/* FUNCTIONS *************************************************************/ + + +bool ext2_set_bit(int nr,void * addr) +{ + int mask; + unsigned char *ADDR = (unsigned char *) addr; + + ADDR += nr >> 3; + mask = 1 << (nr & 0x07); + *ADDR |= mask; + + return true; +} + +bool ext2_clear_bit(int nr, void * addr) +{ + int mask; + unsigned char *ADDR = (unsigned char *) addr; + + ADDR += nr >> 3; + mask = 1 << (nr & 0x07); + *ADDR &= ~mask; + return true; +} + +bool ext2_test_bit(int nr, void * addr) +{ + int mask; + const unsigned char *ADDR = (const unsigned char *) addr; + + ADDR += nr >> 3; + mask = 1 << (nr & 0x07); + + return ((mask & *ADDR) != 0); +} + +bool ext2_mark_bitmap(PEXT2_BITMAP bitmap, ULONG bitno) +{ + if ((bitno < bitmap->start) || (bitno > bitmap->end)) + { + return false; + } + + return ext2_set_bit(bitno - bitmap->start, bitmap->bitmap); +} + +bool ext2_unmark_bitmap(PEXT2_BITMAP bitmap, ULONG bitno) +{ + if ((bitno < bitmap->start) || (bitno > bitmap->end)) + { + return false; + } + + return ext2_clear_bit(bitno - bitmap->start, bitmap->bitmap); +} + + +bool ext2_test_block_bitmap(PEXT2_BLOCK_BITMAP bitmap, + ULONG block) +{ + return ext2_test_bit(block - bitmap->start, bitmap->bitmap); +} + + +bool ext2_test_block_bitmap_range(PEXT2_BLOCK_BITMAP bitmap, + ULONG block, int num) +{ + int i; + + for (i=0; i < num; i++) + { + if (ext2_test_block_bitmap(bitmap, block+i)) + return false; + } + return true; +} + +bool ext2_test_inode_bitmap(PEXT2_BLOCK_BITMAP bitmap, + ULONG inode) +{ + return ext2_test_bit(inode - bitmap->start, bitmap->bitmap); +} + + +bool ext2_allocate_block_bitmap(PEXT2_FILESYS Ext2Sys) +{ + ULONG size = 0; + + PEXT2_SUPER_BLOCK pExt2Sb = Ext2Sys->ext2_sb; + Ext2Sys->block_map = (PEXT2_BLOCK_BITMAP) + RtlAllocateHeap(GetProcessHeap(), 0, sizeof(EXT2_BLOCK_BITMAP)); + + if (!Ext2Sys->block_map) + { + KdPrint(("Mke2fs: error allocating block bitmap...\n")); + return false; + } + + memset(Ext2Sys->block_map, 0, sizeof(EXT2_BLOCK_BITMAP)); + + Ext2Sys->block_map->start = pExt2Sb->s_first_data_block; + Ext2Sys->block_map->end = pExt2Sb->s_blocks_count-1; + Ext2Sys->block_map->real_end = (EXT2_BLOCKS_PER_GROUP(pExt2Sb) + * Ext2Sys->group_desc_count) -1 + Ext2Sys->block_map->start; + + size = (((Ext2Sys->block_map->real_end - Ext2Sys->block_map->start) / 8) + 1); + + Ext2Sys->block_map->bitmap = + (char *)RtlAllocateHeap(GetProcessHeap(), 0, size); + + if (!Ext2Sys->block_map->bitmap) + { + RtlFreeHeap(GetProcessHeap(), 0, Ext2Sys->block_map); + Ext2Sys->block_map = NULL; + KdPrint(("Mke2fs: error allocating block bitmap...\n")); + return false; + } + + memset(Ext2Sys->block_map->bitmap, 0, size); + + return true; +} + + +bool ext2_allocate_inode_bitmap(PEXT2_FILESYS Ext2Sys) +{ + ULONG size = 0; + + PEXT2_SUPER_BLOCK pExt2Sb = Ext2Sys->ext2_sb; + + Ext2Sys->inode_map = (PEXT2_INODE_BITMAP) + RtlAllocateHeap(GetProcessHeap(), 0, sizeof(EXT2_INODE_BITMAP)); + + if (!Ext2Sys->inode_map) + { + KdPrint(("Mke2fs: error allocating inode bitmap...\n")); + return false; + } + + memset(Ext2Sys->inode_map, 0, sizeof(EXT2_INODE_BITMAP)); + + Ext2Sys->inode_map->start = 1; + Ext2Sys->inode_map->end = pExt2Sb->s_inodes_count; + Ext2Sys->inode_map->real_end = (EXT2_INODES_PER_GROUP(pExt2Sb) + * Ext2Sys->group_desc_count); + + size = (((Ext2Sys->inode_map->real_end - Ext2Sys->inode_map->start) / 8) + 1); + + Ext2Sys->inode_map->bitmap = + (char *)RtlAllocateHeap(GetProcessHeap(), 0, size); + + if (!Ext2Sys->inode_map->bitmap) + { + RtlFreeHeap(GetProcessHeap(), 0, Ext2Sys->inode_map); + Ext2Sys->inode_map = NULL; + KdPrint(("Mke2fs: error allocating block bitmap...\n")); + return false; + } + + memset(Ext2Sys->inode_map->bitmap, 0, size); + + return true; +} + +void ext2_free_generic_bitmap(PEXT2_GENERIC_BITMAP bitmap) +{ + if (!bitmap) + return; + + if (bitmap->bitmap) + { + RtlFreeHeap(GetProcessHeap(), 0, bitmap->bitmap); + bitmap->bitmap = 0; + } + + RtlFreeHeap(GetProcessHeap(), 0, bitmap); +} + +void ext2_free_inode_bitmap(PEXT2_FILESYS Ext2Sys) +{ + PEXT2_INODE_BITMAP bitmap = Ext2Sys->inode_map; + if (!bitmap) + return; + + ext2_free_generic_bitmap(bitmap); + + Ext2Sys->inode_map = NULL; +} + +void ext2_free_block_bitmap(PEXT2_FILESYS Ext2Sys) +{ + PEXT2_BLOCK_BITMAP bitmap = Ext2Sys->block_map; + if (!bitmap) + return; + + ext2_free_generic_bitmap(bitmap); + + Ext2Sys->block_map = NULL; +} + +bool ext2_write_inode_bitmap(PEXT2_FILESYS fs) +{ + ULONG i; + ULONG nbytes; + bool retval; + char *inode_bitmap = fs->inode_map->bitmap; + char *bitmap_block = NULL; + ULONG blk; + + if (!inode_bitmap) + return false; + + nbytes = (size_t) ((EXT2_INODES_PER_GROUP(fs->ext2_sb)+7) / 8); + + bitmap_block = (char *)RtlAllocateHeap(GetProcessHeap(), 0, fs->blocksize); + if (!bitmap_block) return false; + + memset(bitmap_block, 0xff, fs->blocksize); + + for (i = 0; i < fs->group_desc_count; i++) + { + memcpy(bitmap_block, inode_bitmap, nbytes); + blk = fs->group_desc[i].bg_inode_bitmap; + + if (blk) + { +/* +#ifdef EXT2_BIG_ENDIAN_BITMAPS + if (!((fs->flags & EXT2_FLAG_SWAP_BYTES) || + (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE))) + ext2_swap_bitmap(fs, bitmap_block, nbytes); +#endif +*/ + retval = NT_SUCCESS(Ext2WriteDisk( + fs, + ((ULONGLONG)blk * fs->blocksize), + fs->blocksize, + (unsigned char *)bitmap_block)); + + if (!retval) + { + RtlFreeHeap(GetProcessHeap(), 0, bitmap_block); + return false; + } + } + + inode_bitmap += nbytes; + } + + RtlFreeHeap(GetProcessHeap(), 0, bitmap_block); + + return true; +} + +bool ext2_write_block_bitmap (PEXT2_FILESYS fs) +{ + ULONG i; + int j; + int nbytes; + int nbits; + bool retval; + char *block_bitmap = fs->block_map->bitmap; + char *bitmap_block = NULL; + ULONG blk; + + if (!block_bitmap) + return false; + + nbytes = EXT2_BLOCKS_PER_GROUP(fs->ext2_sb) / 8; + + bitmap_block = (char *)RtlAllocateHeap(GetProcessHeap(), 0, fs->blocksize); + if (!bitmap_block) + return false; + + memset(bitmap_block, 0xff, fs->blocksize); + + for (i = 0; i < fs->group_desc_count; i++) + { + memcpy(bitmap_block, block_bitmap, nbytes); + + if (i == fs->group_desc_count - 1) + { + /* Force bitmap padding for the last group */ + nbits = (int) ((fs->ext2_sb->s_blocks_count + - fs->ext2_sb->s_first_data_block) + % EXT2_BLOCKS_PER_GROUP(fs->ext2_sb)); + + if (nbits) + { + for (j = nbits; j < fs->blocksize * 8; j++) + { + ext2_set_bit(j, bitmap_block); + } + } + } + + blk = fs->group_desc[i].bg_block_bitmap; + + if (blk) + { +#ifdef EXT2_BIG_ENDIAN_BITMAPS + if (!((fs->flags & EXT2_FLAG_SWAP_BYTES) || + (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE))) + ext2_swap_bitmap(fs, bitmap_block, nbytes); +#endif + retval = NT_SUCCESS(Ext2WriteDisk( + fs, + ((ULONGLONG)blk * fs->blocksize), + fs->blocksize, + (unsigned char *)bitmap_block)); + + if (!retval) + { + RtlFreeHeap(GetProcessHeap(), 0, bitmap_block); + return false; + } + } + + block_bitmap += nbytes; + } + + RtlFreeHeap(GetProcessHeap(), 0, bitmap_block); + + return true; +} + +bool ext2_write_bitmaps(PEXT2_FILESYS fs) +{ + bool retval; + + if (fs->block_map) // && ext2fs_test_bb_dirty(fs)) + { + retval = ext2_write_block_bitmap(fs); + if (!retval) + return retval; + } + + if (fs->inode_map) // && ext2fs_test_ib_dirty(fs)) + { + retval = ext2_write_inode_bitmap(fs); + if (!retval) + return retval; + } + + return true; +} + + +bool read_bitmaps(PEXT2_FILESYS fs, int do_inode, int do_block) +{ + ULONG i; + char *block_bitmap = 0, *inode_bitmap = 0; + bool retval = false; + ULONG block_nbytes = EXT2_BLOCKS_PER_GROUP(fs->ext2_sb) / 8; + ULONG inode_nbytes = EXT2_INODES_PER_GROUP(fs->ext2_sb) / 8; + ULONG blk; + +// fs->write_bitmaps = ext2_write_bitmaps; + + if (do_block) + { + if (fs->block_map) + ext2_free_block_bitmap(fs); + + retval = ext2_allocate_block_bitmap(fs); + + if (!retval) + goto cleanup; + + block_bitmap = fs->block_map->bitmap; + } + + if (do_inode) + { + if (fs->inode_map) + ext2_free_inode_bitmap(fs); + + retval = ext2_allocate_inode_bitmap(fs); + if (!retval) + goto cleanup; + + inode_bitmap = fs->inode_map->bitmap; + } + + for (i = 0; i < fs->group_desc_count; i++) + { + if (block_bitmap) + { + blk = fs->group_desc[i].bg_block_bitmap; + + if (blk) + { + retval = NT_SUCCESS(Ext2ReadDisk( + fs, + ((ULONGLONG)blk * fs->blocksize), + block_nbytes, + (unsigned char *) block_bitmap)); + + if (!retval) + { + goto cleanup; + } + +#ifdef EXT2_BIG_ENDIAN_BITMAPS + if (!((fs->flags & EXT2_FLAG_SWAP_BYTES) || + (fs->flags & EXT2_FLAG_SWAP_BYTES_READ))) + ext2_swap_bitmap(fs, block_bitmap, block_nbytes); +#endif + } + else + { + memset(block_bitmap, 0, block_nbytes); + } + + block_bitmap += block_nbytes; + } + + if (inode_bitmap) + { + blk = fs->group_desc[i].bg_inode_bitmap; + if (blk) + { + retval = NT_SUCCESS(Ext2ReadDisk( + fs, ((LONGLONG)blk * fs->blocksize), + inode_nbytes, + (unsigned char *)inode_bitmap)); + + if (!retval) + { + goto cleanup; + } + +#ifdef EXT2_BIG_ENDIAN_BITMAPS + if (!((fs->flags & EXT2_FLAG_SWAP_BYTES) || + (fs->flags & EXT2_FLAG_SWAP_BYTES_READ))) + ext2_swap_bitmap(fs, inode_bitmap, inode_nbytes); +#endif + } + else + { + memset(inode_bitmap, 0, inode_nbytes); + } + + inode_bitmap += inode_nbytes; + } + } + + return true; + +cleanup: + + if (do_block) + { + RtlFreeHeap(GetProcessHeap(), 0, fs->block_map); + fs->block_map = NULL; + } + + if (do_inode) + { + RtlFreeHeap(GetProcessHeap(), 0, fs->inode_map); + fs->inode_map = 0; + } + + return false; +} + +bool ext2_read_inode_bitmap (PEXT2_FILESYS fs) +{ + return read_bitmaps(fs, 1, 0); +} + +bool ext2_read_block_bitmap(PEXT2_FILESYS fs) +{ + return read_bitmaps(fs, 0, 1); +} + +bool ext2_read_bitmaps(PEXT2_FILESYS fs) +{ + + if (fs->inode_map && fs->block_map) + return 0; + + return read_bitmaps(fs, !fs->inode_map, !fs->block_map); +} + diff --git a/reactos/lib/fslib/ext2lib/Bitmap.h b/reactos/lib/fslib/ext2lib/Bitmap.h new file mode 100644 index 00000000000..d6569d09ca9 --- /dev/null +++ b/reactos/lib/fslib/ext2lib/Bitmap.h @@ -0,0 +1,12 @@ +#ifndef _BITMAP_H + +#include "time.h" +#include "stdio.h" +#include "stdlib.h" +#include "string.h" +#include "windows.h" + + + + +#endif // _BITMAP_H diff --git a/reactos/lib/fslib/ext2lib/Disk.c b/reactos/lib/fslib/ext2lib/Disk.c new file mode 100644 index 00000000000..ee325035002 --- /dev/null +++ b/reactos/lib/fslib/ext2lib/Disk.c @@ -0,0 +1,1352 @@ +/* + * PROJECT: Mke2fs + * FILE: Disk.c + * PROGRAMMER: Matt Wu + * HOMEPAGE: http://ext2.yeah.net + */ + +/* INCLUDES **************************************************************/ + +#include "Mke2fs.h" + +/* DEFINITIONS ***********************************************************/ + + + +/* FUNCTIONS *************************************************************/ + +PUCHAR +Ext2StatusToString ( IN NTSTATUS Status ) +{ + switch (Status) + { + case 0x00000000: return "STATUS_SUCCESS"; + case 0x00000001: return "STATUS_WAIT_1"; + case 0x00000002: return "STATUS_WAIT_2"; + case 0x00000003: return "STATUS_WAIT_3"; + case 0x0000003F: return "STATUS_WAIT_63"; + case 0x00000080: return "STATUS_ABANDONED_WAIT_0"; + case 0x000000BF: return "STATUS_ABANDONED_WAIT_63"; + case 0x000000C0: return "STATUS_USER_APC"; + case 0x00000100: return "STATUS_KERNEL_APC"; + case 0x00000101: return "STATUS_ALERTED"; + case 0x00000102: return "STATUS_TIMEOUT"; + case 0x00000103: return "STATUS_PENDING"; + case 0x00000104: return "STATUS_REPARSE"; + case 0x00000105: return "STATUS_MORE_ENTRIES"; + case 0x00000106: return "STATUS_NOT_ALL_ASSIGNED"; + case 0x00000107: return "STATUS_SOME_NOT_MAPPED"; + case 0x00000108: return "STATUS_OPLOCK_BREAK_IN_PROGRESS"; + case 0x00000109: return "STATUS_VOLUME_MOUNTED"; + case 0x0000010A: return "STATUS_RXACT_COMMITTED"; + case 0x0000010B: return "STATUS_NOTIFY_CLEANUP"; + case 0x0000010C: return "STATUS_NOTIFY_ENUM_DIR"; + case 0x0000010D: return "STATUS_NO_QUOTAS_FOR_ACCOUNT"; + case 0x0000010E: return "STATUS_PRIMARY_TRANSPORT_CONNECT_FAILED"; + case 0x00000110: return "STATUS_PAGE_FAULT_TRANSITION"; + case 0x00000111: return "STATUS_PAGE_FAULT_DEMAND_ZERO"; + case 0x00000112: return "STATUS_PAGE_FAULT_COPY_ON_WRITE"; + case 0x00000113: return "STATUS_PAGE_FAULT_GUARD_PAGE"; + case 0x00000114: return "STATUS_PAGE_FAULT_PAGING_FILE"; + case 0x00000115: return "STATUS_CACHE_PAGE_LOCKED"; + case 0x00000116: return "STATUS_CRASH_DUMP"; + case 0x00000117: return "STATUS_BUFFER_ALL_ZEROS"; + case 0x00000118: return "STATUS_REPARSE_OBJECT"; + case 0x00000119: return "STATUS_RESOURCE_REQUIREMENTS_CHANGED"; + case 0x00000120: return "STATUS_TRANSLATION_COMPLETE"; + case 0x00000121: return "STATUS_DS_MEMBERSHIP_EVALUATED_LOCALLY"; + case 0x00010001: return "DBG_EXCEPTION_HANDLED"; + case 0x00010002: return "DBG_CONTINUE"; + case 0x40000000: return "STATUS_OBJECT_NAME_EXISTS"; + case 0x40000001: return "STATUS_THREAD_WAS_SUSPENDED"; + case 0x40000002: return "STATUS_WORKING_SET_LIMIT_RANGE"; + case 0x40000003: return "STATUS_IMAGE_NOT_AT_BASE"; + case 0x40000004: return "STATUS_RXACT_STATE_CREATED"; + case 0x40000005: return "STATUS_SEGMENT_NOTIFICATION"; + case 0x40000006: return "STATUS_LOCAL_USER_SESSION_KEY"; + case 0x40000007: return "STATUS_BAD_CURRENT_DIRECTORY"; + case 0x40000008: return "STATUS_SERIAL_MORE_WRITES"; + case 0x40000009: return "STATUS_REGISTRY_RECOVERED"; + case 0x4000000A: return "STATUS_FT_READ_RECOVERY_FROM_BACKUP"; + case 0x4000000B: return "STATUS_FT_WRITE_RECOVERY"; + case 0x4000000C: return "STATUS_SERIAL_COUNTER_TIMEOUT"; + case 0x4000000D: return "STATUS_NULL_LM_PASSWORD"; + case 0x4000000E: return "STATUS_IMAGE_MACHINE_TYPE_MISMATCH"; + case 0x4000000F: return "STATUS_RECEIVE_PARTIAL"; + case 0x40000010: return "STATUS_RECEIVE_EXPEDITED"; + case 0x40000011: return "STATUS_RECEIVE_PARTIAL_EXPEDITED"; + case 0x40000012: return "STATUS_EVENT_DONE"; + case 0x40000013: return "STATUS_EVENT_PENDING"; + case 0x40000014: return "STATUS_CHECKING_FILE_SYSTEM"; + case 0x40000015: return "STATUS_FATAL_APP_EXIT"; + case 0x40000016: return "STATUS_PREDEFINED_HANDLE"; + case 0x40000017: return "STATUS_WAS_UNLOCKED"; + case 0x40000018: return "STATUS_SERVICE_NOTIFICATION"; + case 0x40000019: return "STATUS_WAS_LOCKED"; + case 0x4000001A: return "STATUS_LOG_HARD_ERROR"; + case 0x4000001B: return "STATUS_ALREADY_WIN32"; + case 0x4000001C: return "STATUS_WX86_UNSIMULATE"; + case 0x4000001D: return "STATUS_WX86_CONTINUE"; + case 0x4000001E: return "STATUS_WX86_SINGLE_STEP"; + case 0x4000001F: return "STATUS_WX86_BREAKPOINT"; + case 0x40000020: return "STATUS_WX86_EXCEPTION_CONTINUE"; + case 0x40000021: return "STATUS_WX86_EXCEPTION_LASTCHANCE"; + case 0x40000022: return "STATUS_WX86_EXCEPTION_CHAIN"; + case 0x40000023: return "STATUS_IMAGE_MACHINE_TYPE_MISMATCH_EXE"; + case 0x40000024: return "STATUS_NO_YIELD_PERFORMED"; + case 0x40000025: return "STATUS_TIMER_RESUME_IGNORED"; + case 0x40000026: return "STATUS_ARBITRATION_UNHANDLED"; + case 0x40000027: return "STATUS_CARDBUS_NOT_SUPPORTED"; + case 0x40000028: return "STATUS_WX86_CREATEWX86TIB"; + case 0x40000029: return "STATUS_MP_PROCESSOR_MISMATCH"; + case 0x40010001: return "DBG_REPLY_LATER"; + case 0x40010002: return "DBG_UNABLE_TO_PROVIDE_HANDLE"; + case 0x40010003: return "DBG_TERMINATE_THREAD"; + case 0x40010004: return "DBG_TERMINATE_PROCESS"; + case 0x40010005: return "DBG_CONTROL_C"; + case 0x40010006: return "DBG_PRINTEXCEPTION_C"; + case 0x40010007: return "DBG_RIPEXCEPTION"; + case 0x40010008: return "DBG_CONTROL_BREAK"; + case 0x80000001: return "STATUS_GUARD_PAGE_VIOLATION"; + case 0x80000002: return "STATUS_DATATYPE_MISALIGNMENT"; + case 0x80000003: return "STATUS_BREAKPOINT"; + case 0x80000004: return "STATUS_SINGLE_STEP"; + case 0x80000005: return "STATUS_BUFFER_OVERFLOW"; + case 0x80000006: return "STATUS_NO_MORE_FILES"; + case 0x80000007: return "STATUS_WAKE_SYSTEM_DEBUGGER"; + case 0x8000000A: return "STATUS_HANDLES_CLOSED"; + case 0x8000000B: return "STATUS_NO_INHERITANCE"; + case 0x8000000C: return "STATUS_GUID_SUBSTITUTION_MADE"; + case 0x8000000D: return "STATUS_PARTIAL_COPY"; + case 0x8000000E: return "STATUS_DEVICE_PAPER_EMPTY"; + case 0x8000000F: return "STATUS_DEVICE_POWERED_OFF"; + case 0x80000010: return "STATUS_DEVICE_OFF_LINE"; + case 0x80000011: return "STATUS_DEVICE_BUSY"; + case 0x80000012: return "STATUS_NO_MORE_EAS"; + case 0x80000013: return "STATUS_INVALID_EA_NAME"; + case 0x80000014: return "STATUS_EA_LIST_INCONSISTENT"; + case 0x80000015: return "STATUS_INVALID_EA_FLAG"; + case 0x80000016: return "STATUS_VERIFY_REQUIRED"; + case 0x80000017: return "STATUS_EXTRANEOUS_INFORMATION"; + case 0x80000018: return "STATUS_RXACT_COMMIT_NECESSARY"; + case 0x8000001A: return "STATUS_NO_MORE_ENTRIES"; + case 0x8000001B: return "STATUS_FILEMARK_DETECTED"; + case 0x8000001C: return "STATUS_MEDIA_CHANGED"; + case 0x8000001D: return "STATUS_BUS_RESET"; + case 0x8000001E: return "STATUS_END_OF_MEDIA"; + case 0x8000001F: return "STATUS_BEGINNING_OF_MEDIA"; + case 0x80000020: return "STATUS_MEDIA_CHECK"; + case 0x80000021: return "STATUS_SETMARK_DETECTED"; + case 0x80000022: return "STATUS_NO_DATA_DETECTED"; + case 0x80000023: return "STATUS_REDIRECTOR_HAS_OPEN_HANDLES"; + case 0x80000024: return "STATUS_SERVER_HAS_OPEN_HANDLES"; + case 0x80000025: return "STATUS_ALREADY_DISCONNECTED"; + case 0x80000026: return "STATUS_LONGJUMP"; + case 0x80010001: return "DBG_EXCEPTION_NOT_HANDLED"; + case 0xC0000001: return "STATUS_UNSUCCESSFUL"; + case 0xC0000002: return "STATUS_NOT_IMPLEMENTED"; + case 0xC0000003: return "STATUS_INVALID_INFO_CLASS"; + case 0xC0000004: return "STATUS_INFO_LENGTH_MISMATCH"; + case 0xC0000005: return "STATUS_ACCESS_VIOLATION"; + case 0xC0000006: return "STATUS_IN_PAGE_ERROR"; + case 0xC0000007: return "STATUS_PAGEFILE_QUOTA"; + case 0xC0000008: return "STATUS_INVALID_HANDLE"; + case 0xC0000009: return "STATUS_BAD_INITIAL_STACK"; + case 0xC000000A: return "STATUS_BAD_INITIAL_PC"; + case 0xC000000B: return "STATUS_INVALID_CID"; + case 0xC000000C: return "STATUS_TIMER_NOT_CANCELED"; + case 0xC000000D: return "STATUS_INVALID_PARAMETER"; + case 0xC000000E: return "STATUS_NO_SUCH_DEVICE"; + case 0xC000000F: return "STATUS_NO_SUCH_FILE"; + case 0xC0000010: return "STATUS_INVALID_DEVICE_REQUEST"; + case 0xC0000011: return "STATUS_END_OF_FILE"; + case 0xC0000012: return "STATUS_WRONG_VOLUME"; + case 0xC0000013: return "STATUS_NO_MEDIA_IN_DEVICE"; + case 0xC0000014: return "STATUS_UNRECOGNIZED_MEDIA"; + case 0xC0000015: return "STATUS_NONEXISTENT_SECTOR"; + case 0xC0000016: return "STATUS_MORE_PROCESSING_REQUIRED"; + case 0xC0000017: return "STATUS_NO_MEMORY"; + case 0xC0000018: return "STATUS_CONFLICTING_ADDRESSES"; + case 0xC0000019: return "STATUS_NOT_MAPPED_VIEW"; + case 0xC000001A: return "STATUS_UNABLE_TO_FREE_VM"; + case 0xC000001B: return "STATUS_UNABLE_TO_DELETE_SECTION"; + case 0xC000001C: return "STATUS_INVALID_SYSTEM_SERVICE"; + case 0xC000001D: return "STATUS_ILLEGAL_INSTRUCTION"; + case 0xC000001E: return "STATUS_INVALID_LOCK_SEQUENCE"; + case 0xC000001F: return "STATUS_INVALID_VIEW_SIZE"; + case 0xC0000020: return "STATUS_INVALID_FILE_FOR_SECTION"; + case 0xC0000021: return "STATUS_ALREADY_COMMITTED"; + case 0xC0000022: return "STATUS_ACCESS_DENIED"; + case 0xC0000023: return "STATUS_BUFFER_TOO_SMALL"; + case 0xC0000024: return "STATUS_OBJECT_TYPE_MISMATCH"; + case 0xC0000025: return "STATUS_NONCONTINUABLE_EXCEPTION"; + case 0xC0000026: return "STATUS_INVALID_DISPOSITION"; + case 0xC0000027: return "STATUS_UNWIND"; + case 0xC0000028: return "STATUS_BAD_STACK"; + case 0xC0000029: return "STATUS_INVALID_UNWIND_TARGET"; + case 0xC000002A: return "STATUS_NOT_LOCKED"; + case 0xC000002B: return "STATUS_PARITY_ERROR"; + case 0xC000002C: return "STATUS_UNABLE_TO_DECOMMIT_VM"; + case 0xC000002D: return "STATUS_NOT_COMMITTED"; + case 0xC000002E: return "STATUS_INVALID_PORT_ATTRIBUTES"; + case 0xC000002F: return "STATUS_PORT_MESSAGE_TOO_LONG"; + case 0xC0000030: return "STATUS_INVALID_PARAMETER_MIX"; + case 0xC0000031: return "STATUS_INVALID_QUOTA_LOWER"; + case 0xC0000032: return "STATUS_DISK_CORRUPT_ERROR"; + case 0xC0000033: return "STATUS_OBJECT_NAME_INVALID"; + case 0xC0000034: return "STATUS_OBJECT_NAME_NOT_FOUND"; + case 0xC0000035: return "STATUS_OBJECT_NAME_COLLISION"; + case 0xC0000037: return "STATUS_PORT_DISCONNECTED"; + case 0xC0000038: return "STATUS_DEVICE_ALREADY_ATTACHED"; + case 0xC0000039: return "STATUS_OBJECT_PATH_INVALID"; + case 0xC000003A: return "STATUS_OBJECT_PATH_NOT_FOUND"; + case 0xC000003B: return "STATUS_OBJECT_PATH_SYNTAX_BAD"; + case 0xC000003C: return "STATUS_DATA_OVERRUN"; + case 0xC000003D: return "STATUS_DATA_LATE_ERROR"; + case 0xC000003E: return "STATUS_DATA_ERROR"; + case 0xC000003F: return "STATUS_CRC_ERROR"; + case 0xC0000040: return "STATUS_SECTION_TOO_BIG"; + case 0xC0000041: return "STATUS_PORT_CONNECTION_REFUSED"; + case 0xC0000042: return "STATUS_INVALID_PORT_HANDLE"; + case 0xC0000043: return "STATUS_SHARING_VIOLATION"; + case 0xC0000044: return "STATUS_QUOTA_EXCEEDED"; + case 0xC0000045: return "STATUS_INVALID_PAGE_PROTECTION"; + case 0xC0000046: return "STATUS_MUTANT_NOT_OWNED"; + case 0xC0000047: return "STATUS_SEMAPHORE_LIMIT_EXCEEDED"; + case 0xC0000048: return "STATUS_PORT_ALREADY_SET"; + case 0xC0000049: return "STATUS_SECTION_NOT_IMAGE"; + case 0xC000004A: return "STATUS_SUSPEND_COUNT_EXCEEDED"; + case 0xC000004B: return "STATUS_THREAD_IS_TERMINATING"; + case 0xC000004C: return "STATUS_BAD_WORKING_SET_LIMIT"; + case 0xC000004D: return "STATUS_INCOMPATIBLE_FILE_MAP"; + case 0xC000004E: return "STATUS_SECTION_PROTECTION"; + case 0xC000004F: return "STATUS_EAS_NOT_SUPPORTED"; + case 0xC0000050: return "STATUS_EA_TOO_LARGE"; + case 0xC0000051: return "STATUS_NONEXISTENT_EA_ENTRY"; + case 0xC0000052: return "STATUS_NO_EAS_ON_FILE"; + case 0xC0000053: return "STATUS_EA_CORRUPT_ERROR"; + case 0xC0000054: return "STATUS_FILE_LOCK_CONFLICT"; + case 0xC0000055: return "STATUS_LOCK_NOT_GRANTED"; + case 0xC0000056: return "STATUS_DELETE_PENDING"; + case 0xC0000057: return "STATUS_CTL_FILE_NOT_SUPPORTED"; + case 0xC0000058: return "STATUS_UNKNOWN_REVISION"; + case 0xC0000059: return "STATUS_REVISION_MISMATCH"; + case 0xC000005A: return "STATUS_INVALID_OWNER"; + case 0xC000005B: return "STATUS_INVALID_PRIMARY_GROUP"; + case 0xC000005C: return "STATUS_NO_IMPERSONATION_TOKEN"; + case 0xC000005D: return "STATUS_CANT_DISABLE_MANDATORY"; + case 0xC000005E: return "STATUS_NO_LOGON_SERVERS"; + case 0xC000005F: return "STATUS_NO_SUCH_LOGON_SESSION"; + case 0xC0000060: return "STATUS_NO_SUCH_PRIVILEGE"; + case 0xC0000061: return "STATUS_PRIVILEGE_NOT_HELD"; + case 0xC0000062: return "STATUS_INVALID_ACCOUNT_NAME"; + case 0xC0000063: return "STATUS_USER_EXISTS"; + case 0xC0000064: return "STATUS_NO_SUCH_USER"; + case 0xC0000065: return "STATUS_GROUP_EXISTS"; + case 0xC0000066: return "STATUS_NO_SUCH_GROUP"; + case 0xC0000067: return "STATUS_MEMBER_IN_GROUP"; + case 0xC0000068: return "STATUS_MEMBER_NOT_IN_GROUP"; + case 0xC0000069: return "STATUS_LAST_ADMIN"; + case 0xC000006A: return "STATUS_WRONG_PASSWORD"; + case 0xC000006B: return "STATUS_ILL_FORMED_PASSWORD"; + case 0xC000006C: return "STATUS_PASSWORD_RESTRICTION"; + case 0xC000006D: return "STATUS_LOGON_FAILURE"; + case 0xC000006E: return "STATUS_ACCOUNT_RESTRICTION"; + case 0xC000006F: return "STATUS_INVALID_LOGON_HOURS"; + case 0xC0000070: return "STATUS_INVALID_WORKSTATION"; + case 0xC0000071: return "STATUS_PASSWORD_EXPIRED"; + case 0xC0000072: return "STATUS_ACCOUNT_DISABLED"; + case 0xC0000073: return "STATUS_NONE_MAPPED"; + case 0xC0000074: return "STATUS_TOO_MANY_LUIDS_REQUESTED"; + case 0xC0000075: return "STATUS_LUIDS_EXHAUSTED"; + case 0xC0000076: return "STATUS_INVALID_SUB_AUTHORITY"; + case 0xC0000077: return "STATUS_INVALID_ACL"; + case 0xC0000078: return "STATUS_INVALID_SID"; + case 0xC0000079: return "STATUS_INVALID_SECURITY_DESCR"; + case 0xC000007A: return "STATUS_PROCEDURE_NOT_FOUND"; + case 0xC000007B: return "STATUS_INVALID_IMAGE_FORMAT"; + case 0xC000007C: return "STATUS_NO_TOKEN"; + case 0xC000007D: return "STATUS_BAD_INHERITANCE_ACL"; + case 0xC000007E: return "STATUS_RANGE_NOT_LOCKED"; + case 0xC000007F: return "STATUS_DISK_FULL"; + case 0xC0000080: return "STATUS_SERVER_DISABLED"; + case 0xC0000081: return "STATUS_SERVER_NOT_DISABLED"; + case 0xC0000082: return "STATUS_TOO_MANY_GUIDS_REQUESTED"; + case 0xC0000083: return "STATUS_GUIDS_EXHAUSTED"; + case 0xC0000084: return "STATUS_INVALID_ID_AUTHORITY"; + case 0xC0000085: return "STATUS_AGENTS_EXHAUSTED"; + case 0xC0000086: return "STATUS_INVALID_VOLUME_LABEL"; + case 0xC0000087: return "STATUS_SECTION_NOT_EXTENDED"; + case 0xC0000088: return "STATUS_NOT_MAPPED_DATA"; + case 0xC0000089: return "STATUS_RESOURCE_DATA_NOT_FOUND"; + case 0xC000008A: return "STATUS_RESOURCE_TYPE_NOT_FOUND"; + case 0xC000008B: return "STATUS_RESOURCE_NAME_NOT_FOUND"; + case 0xC000008C: return "STATUS_ARRAY_BOUNDS_EXCEEDED"; + case 0xC000008D: return "STATUS_FLOAT_DENORMAL_OPERAND"; + case 0xC000008E: return "STATUS_FLOAT_DIVIDE_BY_ZERO"; + case 0xC000008F: return "STATUS_FLOAT_INEXACT_RESULT"; + case 0xC0000090: return "STATUS_FLOAT_INVALID_OPERATION"; + case 0xC0000091: return "STATUS_FLOAT_OVERFLOW"; + case 0xC0000092: return "STATUS_FLOAT_STACK_CHECK"; + case 0xC0000093: return "STATUS_FLOAT_UNDERFLOW"; + case 0xC0000094: return "STATUS_INTEGER_DIVIDE_BY_ZERO"; + case 0xC0000095: return "STATUS_INTEGER_OVERFLOW"; + case 0xC0000096: return "STATUS_PRIVILEGED_INSTRUCTION"; + case 0xC0000097: return "STATUS_TOO_MANY_PAGING_FILES"; + case 0xC0000098: return "STATUS_FILE_INVALID"; + case 0xC0000099: return "STATUS_ALLOTTED_SPACE_EXCEEDED"; + case 0xC000009A: return "STATUS_INSUFFICIENT_RESOURCES"; + case 0xC000009B: return "STATUS_DFS_EXIT_PATH_FOUND"; + case 0xC000009C: return "STATUS_DEVICE_DATA_ERROR"; + case 0xC000009D: return "STATUS_DEVICE_NOT_CONNECTED"; + case 0xC000009E: return "STATUS_DEVICE_POWER_FAILURE"; + case 0xC000009F: return "STATUS_FREE_VM_NOT_AT_BASE"; + case 0xC00000A0: return "STATUS_MEMORY_NOT_ALLOCATED"; + case 0xC00000A1: return "STATUS_WORKING_SET_QUOTA"; + case 0xC00000A2: return "STATUS_MEDIA_WRITE_PROTECTED"; + case 0xC00000A3: return "STATUS_DEVICE_NOT_READY"; + case 0xC00000A4: return "STATUS_INVALID_GROUP_ATTRIBUTES"; + case 0xC00000A5: return "STATUS_BAD_IMPERSONATION_LEVEL"; + case 0xC00000A6: return "STATUS_CANT_OPEN_ANONYMOUS"; + case 0xC00000A7: return "STATUS_BAD_VALIDATION_CLASS"; + case 0xC00000A8: return "STATUS_BAD_TOKEN_TYPE"; + case 0xC00000A9: return "STATUS_BAD_MASTER_BOOT_RECORD"; + case 0xC00000AA: return "STATUS_INSTRUCTION_MISALIGNMENT"; + case 0xC00000AB: return "STATUS_INSTANCE_NOT_AVAILABLE"; + case 0xC00000AC: return "STATUS_PIPE_NOT_AVAILABLE"; + case 0xC00000AD: return "STATUS_INVALID_PIPE_STATE"; + case 0xC00000AE: return "STATUS_PIPE_BUSY"; + case 0xC00000AF: return "STATUS_ILLEGAL_FUNCTION"; + case 0xC00000B0: return "STATUS_PIPE_DISCONNECTED"; + case 0xC00000B1: return "STATUS_PIPE_CLOSING"; + case 0xC00000B2: return "STATUS_PIPE_CONNECTED"; + case 0xC00000B3: return "STATUS_PIPE_LISTENING"; + case 0xC00000B4: return "STATUS_INVALID_READ_MODE"; + case 0xC00000B5: return "STATUS_IO_TIMEOUT"; + case 0xC00000B6: return "STATUS_FILE_FORCED_CLOSED"; + case 0xC00000B7: return "STATUS_PROFILING_NOT_STARTED"; + case 0xC00000B8: return "STATUS_PROFILING_NOT_STOPPED"; + case 0xC00000B9: return "STATUS_COULD_NOT_INTERPRET"; + case 0xC00000BA: return "STATUS_FILE_IS_A_DIRECTORY"; + case 0xC00000BB: return "STATUS_NOT_SUPPORTED"; + case 0xC00000BC: return "STATUS_REMOTE_NOT_LISTENING"; + case 0xC00000BD: return "STATUS_DUPLICATE_NAME"; + case 0xC00000BE: return "STATUS_BAD_NETWORK_PATH"; + case 0xC00000BF: return "STATUS_NETWORK_BUSY"; + case 0xC00000C0: return "STATUS_DEVICE_DOES_NOT_EXIST"; + case 0xC00000C1: return "STATUS_TOO_MANY_COMMANDS"; + case 0xC00000C2: return "STATUS_ADAPTER_HARDWARE_ERROR"; + case 0xC00000C3: return "STATUS_INVALID_NETWORK_RESPONSE"; + case 0xC00000C4: return "STATUS_UNEXPECTED_NETWORK_ERROR"; + case 0xC00000C5: return "STATUS_BAD_REMOTE_ADAPTER"; + case 0xC00000C6: return "STATUS_PRINT_QUEUE_FULL"; + case 0xC00000C7: return "STATUS_NO_SPOOL_SPACE"; + case 0xC00000C8: return "STATUS_PRINT_CANCELLED"; + case 0xC00000C9: return "STATUS_NETWORK_NAME_DELETED"; + case 0xC00000CA: return "STATUS_NETWORK_ACCESS_DENIED"; + case 0xC00000CB: return "STATUS_BAD_DEVICE_TYPE"; + case 0xC00000CC: return "STATUS_BAD_NETWORK_NAME"; + case 0xC00000CD: return "STATUS_TOO_MANY_NAMES"; + case 0xC00000CE: return "STATUS_TOO_MANY_SESSIONS"; + case 0xC00000CF: return "STATUS_SHARING_PAUSED"; + case 0xC00000D0: return "STATUS_REQUEST_NOT_ACCEPTED"; + case 0xC00000D1: return "STATUS_REDIRECTOR_PAUSED"; + case 0xC00000D2: return "STATUS_NET_WRITE_FAULT"; + case 0xC00000D3: return "STATUS_PROFILING_AT_LIMIT"; + case 0xC00000D4: return "STATUS_NOT_SAME_DEVICE"; + case 0xC00000D5: return "STATUS_FILE_RENAMED"; + case 0xC00000D6: return "STATUS_VIRTUAL_CIRCUIT_CLOSED"; + case 0xC00000D7: return "STATUS_NO_SECURITY_ON_OBJECT"; + case 0xC00000D8: return "STATUS_CANT_WAIT"; + case 0xC00000D9: return "STATUS_PIPE_EMPTY"; + case 0xC00000DA: return "STATUS_CANT_ACCESS_DOMAIN_INFO"; + case 0xC00000DB: return "STATUS_CANT_TERMINATE_SELF"; + case 0xC00000DC: return "STATUS_INVALID_SERVER_STATE"; + case 0xC00000DD: return "STATUS_INVALID_DOMAIN_STATE"; + case 0xC00000DE: return "STATUS_INVALID_DOMAIN_ROLE"; + case 0xC00000DF: return "STATUS_NO_SUCH_DOMAIN"; + case 0xC00000E0: return "STATUS_DOMAIN_EXISTS"; + case 0xC00000E1: return "STATUS_DOMAIN_LIMIT_EXCEEDED"; + case 0xC00000E2: return "STATUS_OPLOCK_NOT_GRANTED"; + case 0xC00000E3: return "STATUS_INVALID_OPLOCK_PROTOCOL"; + case 0xC00000E4: return "STATUS_INTERNAL_DB_CORRUPTION"; + case 0xC00000E5: return "STATUS_INTERNAL_ERROR"; + case 0xC00000E6: return "STATUS_GENERIC_NOT_MAPPED"; + case 0xC00000E7: return "STATUS_BAD_DESCRIPTOR_FORMAT"; + case 0xC00000E8: return "STATUS_INVALID_USER_BUFFER"; + case 0xC00000E9: return "STATUS_UNEXPECTED_IO_ERROR"; + case 0xC00000EA: return "STATUS_UNEXPECTED_MM_CREATE_ERR"; + case 0xC00000EB: return "STATUS_UNEXPECTED_MM_MAP_ERROR"; + case 0xC00000EC: return "STATUS_UNEXPECTED_MM_EXTEND_ERR"; + case 0xC00000ED: return "STATUS_NOT_LOGON_PROCESS"; + case 0xC00000EE: return "STATUS_LOGON_SESSION_EXISTS"; + case 0xC00000EF: return "STATUS_INVALID_PARAMETER_1"; + case 0xC00000F0: return "STATUS_INVALID_PARAMETER_2"; + case 0xC00000F1: return "STATUS_INVALID_PARAMETER_3"; + case 0xC00000F2: return "STATUS_INVALID_PARAMETER_4"; + case 0xC00000F3: return "STATUS_INVALID_PARAMETER_5"; + case 0xC00000F4: return "STATUS_INVALID_PARAMETER_6"; + case 0xC00000F5: return "STATUS_INVALID_PARAMETER_7"; + case 0xC00000F6: return "STATUS_INVALID_PARAMETER_8"; + case 0xC00000F7: return "STATUS_INVALID_PARAMETER_9"; + case 0xC00000F8: return "STATUS_INVALID_PARAMETER_10"; + case 0xC00000F9: return "STATUS_INVALID_PARAMETER_11"; + case 0xC00000FA: return "STATUS_INVALID_PARAMETER_12"; + case 0xC00000FB: return "STATUS_REDIRECTOR_NOT_STARTED"; + case 0xC00000FC: return "STATUS_REDIRECTOR_STARTED"; + case 0xC00000FD: return "STATUS_STACK_OVERFLOW"; + case 0xC00000FE: return "STATUS_NO_SUCH_PACKAGE"; + case 0xC00000FF: return "STATUS_BAD_FUNCTION_TABLE"; + case 0xC0000100: return "STATUS_VARIABLE_NOT_FOUND"; + case 0xC0000101: return "STATUS_DIRECTORY_NOT_EMPTY"; + case 0xC0000102: return "STATUS_FILE_CORRUPT_ERROR"; + case 0xC0000103: return "STATUS_NOT_A_DIRECTORY"; + case 0xC0000104: return "STATUS_BAD_LOGON_SESSION_STATE"; + case 0xC0000105: return "STATUS_LOGON_SESSION_COLLISION"; + case 0xC0000106: return "STATUS_NAME_TOO_LONG"; + case 0xC0000107: return "STATUS_FILES_OPEN"; + case 0xC0000108: return "STATUS_CONNECTION_IN_USE"; + case 0xC0000109: return "STATUS_MESSAGE_NOT_FOUND"; + case 0xC000010A: return "STATUS_PROCESS_IS_TERMINATING"; + case 0xC000010B: return "STATUS_INVALID_LOGON_TYPE"; + case 0xC000010C: return "STATUS_NO_GUID_TRANSLATION"; + case 0xC000010D: return "STATUS_CANNOT_IMPERSONATE"; + case 0xC000010E: return "STATUS_IMAGE_ALREADY_LOADED"; + case 0xC000010F: return "STATUS_ABIOS_NOT_PRESENT"; + case 0xC0000110: return "STATUS_ABIOS_LID_NOT_EXIST"; + case 0xC0000111: return "STATUS_ABIOS_LID_ALREADY_OWNED"; + case 0xC0000112: return "STATUS_ABIOS_NOT_LID_OWNER"; + case 0xC0000113: return "STATUS_ABIOS_INVALID_COMMAND"; + case 0xC0000114: return "STATUS_ABIOS_INVALID_LID"; + case 0xC0000115: return "STATUS_ABIOS_SELECTOR_NOT_AVAILABLE"; + case 0xC0000116: return "STATUS_ABIOS_INVALID_SELECTOR"; + case 0xC0000117: return "STATUS_NO_LDT"; + case 0xC0000118: return "STATUS_INVALID_LDT_SIZE"; + case 0xC0000119: return "STATUS_INVALID_LDT_OFFSET"; + case 0xC000011A: return "STATUS_INVALID_LDT_DESCRIPTOR"; + case 0xC000011B: return "STATUS_INVALID_IMAGE_NE_FORMAT"; + case 0xC000011C: return "STATUS_RXACT_INVALID_STATE"; + case 0xC000011D: return "STATUS_RXACT_COMMIT_FAILURE"; + case 0xC000011E: return "STATUS_MAPPED_FILE_SIZE_ZERO"; + case 0xC000011F: return "STATUS_TOO_MANY_OPENED_FILES"; + case 0xC0000120: return "STATUS_CANCELLED"; + case 0xC0000121: return "STATUS_CANNOT_DELETE"; + case 0xC0000122: return "STATUS_INVALID_COMPUTER_NAME"; + case 0xC0000123: return "STATUS_FILE_DELETED"; + case 0xC0000124: return "STATUS_SPECIAL_ACCOUNT"; + case 0xC0000125: return "STATUS_SPECIAL_GROUP"; + case 0xC0000126: return "STATUS_SPECIAL_USER"; + case 0xC0000127: return "STATUS_MEMBERS_PRIMARY_GROUP"; + case 0xC0000128: return "STATUS_FILE_CLOSED"; + case 0xC0000129: return "STATUS_TOO_MANY_THREADS"; + case 0xC000012A: return "STATUS_THREAD_NOT_IN_PROCESS"; + case 0xC000012B: return "STATUS_TOKEN_ALREADY_IN_USE"; + case 0xC000012C: return "STATUS_PAGEFILE_QUOTA_EXCEEDED"; + case 0xC000012D: return "STATUS_COMMITMENT_LIMIT"; + case 0xC000012E: return "STATUS_INVALID_IMAGE_LE_FORMAT"; + case 0xC000012F: return "STATUS_INVALID_IMAGE_NOT_MZ"; + case 0xC0000130: return "STATUS_INVALID_IMAGE_PROTECT"; + case 0xC0000131: return "STATUS_INVALID_IMAGE_WIN_16"; + case 0xC0000132: return "STATUS_LOGON_SERVER_CONFLICT"; + case 0xC0000133: return "STATUS_TIME_DIFFERENCE_AT_DC"; + case 0xC0000134: return "STATUS_SYNCHRONIZATION_REQUIRED"; + case 0xC0000135: return "STATUS_DLL_NOT_FOUND"; + case 0xC0000136: return "STATUS_OPEN_FAILED"; + case 0xC0000137: return "STATUS_IO_PRIVILEGE_FAILED"; + case 0xC0000138: return "STATUS_ORDINAL_NOT_FOUND"; + case 0xC0000139: return "STATUS_ENTRYPOINT_NOT_FOUND"; + case 0xC000013A: return "STATUS_CONTROL_C_EXIT"; + case 0xC000013B: return "STATUS_LOCAL_DISCONNECT"; + case 0xC000013C: return "STATUS_REMOTE_DISCONNECT"; + case 0xC000013D: return "STATUS_REMOTE_RESOURCES"; + case 0xC000013E: return "STATUS_LINK_FAILED"; + case 0xC000013F: return "STATUS_LINK_TIMEOUT"; + case 0xC0000140: return "STATUS_INVALID_CONNECTION"; + case 0xC0000141: return "STATUS_INVALID_ADDRESS"; + case 0xC0000142: return "STATUS_DLL_INIT_FAILED"; + case 0xC0000143: return "STATUS_MISSING_SYSTEMFILE"; + case 0xC0000144: return "STATUS_UNHANDLED_EXCEPTION"; + case 0xC0000145: return "STATUS_APP_INIT_FAILURE"; + case 0xC0000146: return "STATUS_PAGEFILE_CREATE_FAILED"; + case 0xC0000147: return "STATUS_NO_PAGEFILE"; + case 0xC0000148: return "STATUS_INVALID_LEVEL"; + case 0xC0000149: return "STATUS_WRONG_PASSWORD_CORE"; + case 0xC000014A: return "STATUS_ILLEGAL_FLOAT_CONTEXT"; + case 0xC000014B: return "STATUS_PIPE_BROKEN"; + case 0xC000014C: return "STATUS_REGISTRY_CORRUPT"; + case 0xC000014D: return "STATUS_REGISTRY_IO_FAILED"; + case 0xC000014E: return "STATUS_NO_EVENT_PAIR"; + case 0xC000014F: return "STATUS_UNRECOGNIZED_VOLUME"; + case 0xC0000150: return "STATUS_SERIAL_NO_DEVICE_INITED"; + case 0xC0000151: return "STATUS_NO_SUCH_ALIAS"; + case 0xC0000152: return "STATUS_MEMBER_NOT_IN_ALIAS"; + case 0xC0000153: return "STATUS_MEMBER_IN_ALIAS"; + case 0xC0000154: return "STATUS_ALIAS_EXISTS"; + case 0xC0000155: return "STATUS_LOGON_NOT_GRANTED"; + case 0xC0000156: return "STATUS_TOO_MANY_SECRETS"; + case 0xC0000157: return "STATUS_SECRET_TOO_LONG"; + case 0xC0000158: return "STATUS_INTERNAL_DB_ERROR"; + case 0xC0000159: return "STATUS_FULLSCREEN_MODE"; + case 0xC000015A: return "STATUS_TOO_MANY_CONTEXT_IDS"; + case 0xC000015B: return "STATUS_LOGON_TYPE_NOT_GRANTED"; + case 0xC000015C: return "STATUS_NOT_REGISTRY_FILE"; + case 0xC000015D: return "STATUS_NT_CROSS_ENCRYPTION_REQUIRED"; + case 0xC000015E: return "STATUS_DOMAIN_CTRLR_CONFIG_ERROR"; + case 0xC000015F: return "STATUS_FT_MISSING_MEMBER"; + case 0xC0000160: return "STATUS_ILL_FORMED_SERVICE_ENTRY"; + case 0xC0000161: return "STATUS_ILLEGAL_CHARACTER"; + case 0xC0000162: return "STATUS_UNMAPPABLE_CHARACTER"; + case 0xC0000163: return "STATUS_UNDEFINED_CHARACTER"; + case 0xC0000164: return "STATUS_FLOPPY_VOLUME"; + case 0xC0000165: return "STATUS_FLOPPY_ID_MARK_NOT_FOUND"; + case 0xC0000166: return "STATUS_FLOPPY_WRONG_CYLINDER"; + case 0xC0000167: return "STATUS_FLOPPY_UNKNOWN_ERROR"; + case 0xC0000168: return "STATUS_FLOPPY_BAD_REGISTERS"; + case 0xC0000169: return "STATUS_DISK_RECALIBRATE_FAILED"; + case 0xC000016A: return "STATUS_DISK_OPERATION_FAILED"; + case 0xC000016B: return "STATUS_DISK_RESET_FAILED"; + case 0xC000016C: return "STATUS_SHARED_IRQ_BUSY"; + case 0xC000016D: return "STATUS_FT_ORPHANING"; + case 0xC000016E: return "STATUS_BIOS_FAILED_TO_CONNECT_INTERRUPT"; + case 0xC0000172: return "STATUS_PARTITION_FAILURE"; + case 0xC0000173: return "STATUS_INVALID_BLOCK_LENGTH"; + case 0xC0000174: return "STATUS_DEVICE_NOT_PARTITIONED"; + case 0xC0000175: return "STATUS_UNABLE_TO_LOCK_MEDIA"; + case 0xC0000176: return "STATUS_UNABLE_TO_UNLOAD_MEDIA"; + case 0xC0000177: return "STATUS_EOM_OVERFLOW"; + case 0xC0000178: return "STATUS_NO_MEDIA"; + case 0xC000017A: return "STATUS_NO_SUCH_MEMBER"; + case 0xC000017B: return "STATUS_INVALID_MEMBER"; + case 0xC000017C: return "STATUS_KEY_DELETED"; + case 0xC000017D: return "STATUS_NO_LOG_SPACE"; + case 0xC000017E: return "STATUS_TOO_MANY_SIDS"; + case 0xC000017F: return "STATUS_LM_CROSS_ENCRYPTION_REQUIRED"; + case 0xC0000180: return "STATUS_KEY_HAS_CHILDREN"; + case 0xC0000181: return "STATUS_CHILD_MUST_BE_VOLATILE"; + case 0xC0000182: return "STATUS_DEVICE_CONFIGURATION_ERROR"; + case 0xC0000183: return "STATUS_DRIVER_INTERNAL_ERROR"; + case 0xC0000184: return "STATUS_INVALID_DEVICE_STATE"; + case 0xC0000185: return "STATUS_IO_DEVICE_ERROR"; + case 0xC0000186: return "STATUS_DEVICE_PROTOCOL_ERROR"; + case 0xC0000187: return "STATUS_BACKUP_CONTROLLER"; + case 0xC0000188: return "STATUS_LOG_FILE_FULL"; + case 0xC0000189: return "STATUS_TOO_LATE"; + case 0xC000018A: return "STATUS_NO_TRUST_LSA_SECRET"; + case 0xC000018B: return "STATUS_NO_TRUST_SAM_ACCOUNT"; + case 0xC000018C: return "STATUS_TRUSTED_DOMAIN_FAILURE"; + case 0xC000018D: return "STATUS_TRUSTED_RELATIONSHIP_FAILURE"; + case 0xC000018E: return "STATUS_EVENTLOG_FILE_CORRUPT"; + case 0xC000018F: return "STATUS_EVENTLOG_CANT_START"; + case 0xC0000190: return "STATUS_TRUST_FAILURE"; + case 0xC0000191: return "STATUS_MUTANT_LIMIT_EXCEEDED"; + case 0xC0000192: return "STATUS_NETLOGON_NOT_STARTED"; + case 0xC0000193: return "STATUS_ACCOUNT_EXPIRED"; + case 0xC0000194: return "STATUS_POSSIBLE_DEADLOCK"; + case 0xC0000195: return "STATUS_NETWORK_CREDENTIAL_CONFLICT"; + case 0xC0000196: return "STATUS_REMOTE_SESSION_LIMIT"; + case 0xC0000197: return "STATUS_EVENTLOG_FILE_CHANGED"; + case 0xC0000198: return "STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT"; + case 0xC0000199: return "STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT"; + case 0xC000019A: return "STATUS_NOLOGON_SERVER_TRUST_ACCOUNT"; + case 0xC000019B: return "STATUS_DOMAIN_TRUST_INCONSISTENT"; + case 0xC000019C: return "STATUS_FS_DRIVER_REQUIRED"; + case 0xC0000202: return "STATUS_NO_USER_SESSION_KEY"; + case 0xC0000203: return "STATUS_USER_SESSION_DELETED"; + case 0xC0000204: return "STATUS_RESOURCE_LANG_NOT_FOUND"; + case 0xC0000205: return "STATUS_INSUFF_SERVER_RESOURCES"; + case 0xC0000206: return "STATUS_INVALID_BUFFER_SIZE"; + case 0xC0000207: return "STATUS_INVALID_ADDRESS_COMPONENT"; + case 0xC0000208: return "STATUS_INVALID_ADDRESS_WILDCARD"; + case 0xC0000209: return "STATUS_TOO_MANY_ADDRESSES"; + case 0xC000020A: return "STATUS_ADDRESS_ALREADY_EXISTS"; + case 0xC000020B: return "STATUS_ADDRESS_CLOSED"; + case 0xC000020C: return "STATUS_CONNECTION_DISCONNECTED"; + case 0xC000020D: return "STATUS_CONNECTION_RESET"; + case 0xC000020E: return "STATUS_TOO_MANY_NODES"; + case 0xC000020F: return "STATUS_TRANSACTION_ABORTED"; + case 0xC0000210: return "STATUS_TRANSACTION_TIMED_OUT"; + case 0xC0000211: return "STATUS_TRANSACTION_NO_RELEASE"; + case 0xC0000212: return "STATUS_TRANSACTION_NO_MATCH"; + case 0xC0000213: return "STATUS_TRANSACTION_RESPONDED"; + case 0xC0000214: return "STATUS_TRANSACTION_INVALID_ID"; + case 0xC0000215: return "STATUS_TRANSACTION_INVALID_TYPE"; + case 0xC0000216: return "STATUS_NOT_SERVER_SESSION"; + case 0xC0000217: return "STATUS_NOT_CLIENT_SESSION"; + case 0xC0000218: return "STATUS_CANNOT_LOAD_REGISTRY_FILE"; + case 0xC0000219: return "STATUS_DEBUG_ATTACH_FAILED"; + case 0xC000021A: return "STATUS_SYSTEM_PROCESS_TERMINATED"; + case 0xC000021B: return "STATUS_DATA_NOT_ACCEPTED"; + case 0xC000021C: return "STATUS_NO_BROWSER_SERVERS_FOUND"; + case 0xC000021D: return "STATUS_VDM_HARD_ERROR"; + case 0xC000021E: return "STATUS_DRIVER_CANCEL_TIMEOUT"; + case 0xC000021F: return "STATUS_REPLY_MESSAGE_MISMATCH"; + case 0xC0000220: return "STATUS_MAPPED_ALIGNMENT"; + case 0xC0000221: return "STATUS_IMAGE_CHECKSUM_MISMATCH"; + case 0xC0000222: return "STATUS_LOST_WRITEBEHIND_DATA"; + case 0xC0000223: return "STATUS_CLIENT_SERVER_PARAMETERS_INVALID"; + case 0xC0000224: return "STATUS_PASSWORD_MUST_CHANGE"; + case 0xC0000225: return "STATUS_NOT_FOUND"; + case 0xC0000226: return "STATUS_NOT_TINY_STREAM"; + case 0xC0000227: return "STATUS_RECOVERY_FAILURE"; + case 0xC0000228: return "STATUS_STACK_OVERFLOW_READ"; + case 0xC0000229: return "STATUS_FAIL_CHECK"; + case 0xC000022A: return "STATUS_DUPLICATE_OBJECTID"; + case 0xC000022B: return "STATUS_OBJECTID_EXISTS"; + case 0xC000022C: return "STATUS_CONVERT_TO_LARGE"; + case 0xC000022D: return "STATUS_RETRY"; + case 0xC000022E: return "STATUS_FOUND_OUT_OF_SCOPE"; + case 0xC000022F: return "STATUS_ALLOCATE_BUCKET"; + case 0xC0000230: return "STATUS_PROPSET_NOT_FOUND"; + case 0xC0000231: return "STATUS_MARSHALL_OVERFLOW"; + case 0xC0000232: return "STATUS_INVALID_VARIANT"; + case 0xC0000233: return "STATUS_DOMAIN_CONTROLLER_NOT_FOUND"; + case 0xC0000234: return "STATUS_ACCOUNT_LOCKED_OUT"; + case 0xC0000235: return "STATUS_HANDLE_NOT_CLOSABLE"; + case 0xC0000236: return "STATUS_CONNECTION_REFUSED"; + case 0xC0000237: return "STATUS_GRACEFUL_DISCONNECT"; + case 0xC0000238: return "STATUS_ADDRESS_ALREADY_ASSOCIATED"; + case 0xC0000239: return "STATUS_ADDRESS_NOT_ASSOCIATED"; + case 0xC000023A: return "STATUS_CONNECTION_INVALID"; + case 0xC000023B: return "STATUS_CONNECTION_ACTIVE"; + case 0xC000023C: return "STATUS_NETWORK_UNREACHABLE"; + case 0xC000023D: return "STATUS_HOST_UNREACHABLE"; + case 0xC000023E: return "STATUS_PROTOCOL_UNREACHABLE"; + case 0xC000023F: return "STATUS_PORT_UNREACHABLE"; + case 0xC0000240: return "STATUS_REQUEST_ABORTED"; + case 0xC0000241: return "STATUS_CONNECTION_ABORTED"; + case 0xC0000242: return "STATUS_BAD_COMPRESSION_BUFFER"; + case 0xC0000243: return "STATUS_USER_MAPPED_FILE"; + case 0xC0000244: return "STATUS_AUDIT_FAILED"; + case 0xC0000245: return "STATUS_TIMER_RESOLUTION_NOT_SET"; + case 0xC0000246: return "STATUS_CONNECTION_COUNT_LIMIT"; + case 0xC0000247: return "STATUS_LOGIN_TIME_RESTRICTION"; + case 0xC0000248: return "STATUS_LOGIN_WKSTA_RESTRICTION"; + case 0xC0000249: return "STATUS_IMAGE_MP_UP_MISMATCH"; + case 0xC0000250: return "STATUS_INSUFFICIENT_LOGON_INFO"; + case 0xC0000251: return "STATUS_BAD_DLL_ENTRYPOINT"; + case 0xC0000252: return "STATUS_BAD_SERVICE_ENTRYPOINT"; + case 0xC0000253: return "STATUS_LPC_REPLY_LOST"; + case 0xC0000254: return "STATUS_IP_ADDRESS_CONFLICT1"; + case 0xC0000255: return "STATUS_IP_ADDRESS_CONFLICT2"; + case 0xC0000256: return "STATUS_REGISTRY_QUOTA_LIMIT"; + case 0xC0000257: return "STATUS_PATH_NOT_COVERED"; + case 0xC0000258: return "STATUS_NO_CALLBACK_ACTIVE"; + case 0xC0000259: return "STATUS_LICENSE_QUOTA_EXCEEDED"; + case 0xC000025A: return "STATUS_PWD_TOO_SHORT"; + case 0xC000025B: return "STATUS_PWD_TOO_RECENT"; + case 0xC000025C: return "STATUS_PWD_HISTORY_CONFLICT"; + case 0xC000025E: return "STATUS_PLUGPLAY_NO_DEVICE"; + case 0xC000025F: return "STATUS_UNSUPPORTED_COMPRESSION"; + case 0xC0000260: return "STATUS_INVALID_HW_PROFILE"; + case 0xC0000261: return "STATUS_INVALID_PLUGPLAY_DEVICE_PATH"; + case 0xC0000262: return "STATUS_DRIVER_ORDINAL_NOT_FOUND"; + case 0xC0000263: return "STATUS_DRIVER_ENTRYPOINT_NOT_FOUND"; + case 0xC0000264: return "STATUS_RESOURCE_NOT_OWNED"; + case 0xC0000265: return "STATUS_TOO_MANY_LINKS"; + case 0xC0000266: return "STATUS_QUOTA_LIST_INCONSISTENT"; + case 0xC0000267: return "STATUS_FILE_IS_OFFLINE"; + case 0xC0000268: return "STATUS_EVALUATION_EXPIRATION"; + case 0xC0000269: return "STATUS_ILLEGAL_DLL_RELOCATION"; + case 0xC000026A: return "STATUS_LICENSE_VIOLATION"; + case 0xC000026B: return "STATUS_DLL_INIT_FAILED_LOGOFF"; + case 0xC000026C: return "STATUS_DRIVER_UNABLE_TO_LOAD"; + case 0xC000026D: return "STATUS_DFS_UNAVAILABLE"; + case 0xC000026E: return "STATUS_VOLUME_DISMOUNTED"; + case 0xC000026F: return "STATUS_WX86_INTERNAL_ERROR"; + case 0xC0000270: return "STATUS_WX86_FLOAT_STACK_CHECK"; + case 0xC0000271: return "STATUS_VALIDATE_CONTINUE"; + case 0xC0000272: return "STATUS_NO_MATCH"; + case 0xC0000273: return "STATUS_NO_MORE_MATCHES"; + case 0xC0000275: return "STATUS_NOT_A_REPARSE_POINT"; + case 0xC0000276: return "STATUS_IO_REPARSE_TAG_INVALID"; + case 0xC0000277: return "STATUS_IO_REPARSE_TAG_MISMATCH"; + case 0xC0000278: return "STATUS_IO_REPARSE_DATA_INVALID"; + case 0xC0000279: return "STATUS_IO_REPARSE_TAG_NOT_HANDLED"; + case 0xC0000280: return "STATUS_REPARSE_POINT_NOT_RESOLVED"; + case 0xC0000281: return "STATUS_DIRECTORY_IS_A_REPARSE_POINT"; + case 0xC0000282: return "STATUS_RANGE_LIST_CONFLICT"; + case 0xC0000283: return "STATUS_SOURCE_ELEMENT_EMPTY"; + case 0xC0000284: return "STATUS_DESTINATION_ELEMENT_FULL"; + case 0xC0000285: return "STATUS_ILLEGAL_ELEMENT_ADDRESS"; + case 0xC0000286: return "STATUS_MAGAZINE_NOT_PRESENT"; + case 0xC0000287: return "STATUS_REINITIALIZATION_NEEDED"; + case 0x80000288: return "STATUS_DEVICE_REQUIRES_CLEANING"; + case 0x80000289: return "STATUS_DEVICE_DOOR_OPEN"; + case 0xC000028A: return "STATUS_ENCRYPTION_FAILED"; + case 0xC000028B: return "STATUS_DECRYPTION_FAILED"; + case 0xC000028C: return "STATUS_RANGE_NOT_FOUND"; + case 0xC000028D: return "STATUS_NO_RECOVERY_POLICY"; + case 0xC000028E: return "STATUS_NO_EFS"; + case 0xC000028F: return "STATUS_WRONG_EFS"; + case 0xC0000290: return "STATUS_NO_USER_KEYS"; + case 0xC0000291: return "STATUS_FILE_NOT_ENCRYPTED"; + case 0xC0000292: return "STATUS_NOT_EXPORT_FORMAT"; + case 0xC0000293: return "STATUS_FILE_ENCRYPTED"; + case 0x40000294: return "STATUS_WAKE_SYSTEM"; + case 0xC0000295: return "STATUS_WMI_GUID_NOT_FOUND"; + case 0xC0000296: return "STATUS_WMI_INSTANCE_NOT_FOUND"; + case 0xC0000297: return "STATUS_WMI_ITEMID_NOT_FOUND"; + case 0xC0000298: return "STATUS_WMI_TRY_AGAIN"; + case 0xC0000299: return "STATUS_SHARED_POLICY"; + case 0xC000029A: return "STATUS_POLICY_OBJECT_NOT_FOUND"; + case 0xC000029B: return "STATUS_POLICY_ONLY_IN_DS"; + case 0xC000029C: return "STATUS_VOLUME_NOT_UPGRADED"; + case 0xC000029D: return "STATUS_REMOTE_STORAGE_NOT_ACTIVE"; + case 0xC000029E: return "STATUS_REMOTE_STORAGE_MEDIA_ERROR"; + case 0xC000029F: return "STATUS_NO_TRACKING_SERVICE"; + case 0xC00002A0: return "STATUS_SERVER_SID_MISMATCH"; + case 0xC00002A1: return "STATUS_DS_NO_ATTRIBUTE_OR_VALUE"; + case 0xC00002A2: return "STATUS_DS_INVALID_ATTRIBUTE_SYNTAX"; + case 0xC00002A3: return "STATUS_DS_ATTRIBUTE_TYPE_UNDEFINED"; + case 0xC00002A4: return "STATUS_DS_ATTRIBUTE_OR_VALUE_EXISTS"; + case 0xC00002A5: return "STATUS_DS_BUSY"; + case 0xC00002A6: return "STATUS_DS_UNAVAILABLE"; + case 0xC00002A7: return "STATUS_DS_NO_RIDS_ALLOCATED"; + case 0xC00002A8: return "STATUS_DS_NO_MORE_RIDS"; + case 0xC00002A9: return "STATUS_DS_INCORRECT_ROLE_OWNER"; + case 0xC00002AA: return "STATUS_DS_RIDMGR_INIT_ERROR"; + case 0xC00002AB: return "STATUS_DS_OBJ_CLASS_VIOLATION"; + case 0xC00002AC: return "STATUS_DS_CANT_ON_NON_LEAF"; + case 0xC00002AD: return "STATUS_DS_CANT_ON_RDN"; + case 0xC00002AE: return "STATUS_DS_CANT_MOD_OBJ_CLASS"; + case 0xC00002AF: return "STATUS_DS_CROSS_DOM_MOVE_FAILED"; + case 0xC00002B0: return "STATUS_DS_GC_NOT_AVAILABLE"; + case 0xC00002B1: return "STATUS_DIRECTORY_SERVICE_REQUIRED"; + case 0xC00002B2: return "STATUS_REPARSE_ATTRIBUTE_CONFLICT"; + case 0xC00002B3: return "STATUS_CANT_ENABLE_DENY_ONLY"; + case 0xC00002B4: return "STATUS_FLOAT_MULTIPLE_FAULTS"; + case 0xC00002B5: return "STATUS_FLOAT_MULTIPLE_TRAPS"; + case 0xC00002B6: return "STATUS_DEVICE_REMOVED"; + case 0xC00002B7: return "STATUS_JOURNAL_DELETE_IN_PROGRESS"; + case 0xC00002B8: return "STATUS_JOURNAL_NOT_ACTIVE"; + case 0xC00002B9: return "STATUS_NOINTERFACE"; + case 0xC00002C1: return "STATUS_DS_ADMIN_LIMIT_EXCEEDED"; + case 0xC00002C2: return "STATUS_DRIVER_FAILED_SLEEP"; + case 0xC00002C3: return "STATUS_MUTUAL_AUTHENTICATION_FAILED"; + case 0xC00002C4: return "STATUS_CORRUPT_SYSTEM_FILE"; + case 0xC00002C5: return "STATUS_DATATYPE_MISALIGNMENT_ERROR"; + case 0xC00002C6: return "STATUS_WMI_READ_ONLY"; + case 0xC00002C7: return "STATUS_WMI_SET_FAILURE"; + case 0xC00002C8: return "STATUS_COMMITMENT_MINIMUM"; + case 0xC00002C9: return "STATUS_REG_NAT_CONSUMPTION"; + case 0xC00002CA: return "STATUS_TRANSPORT_FULL"; + case 0xC00002CB: return "STATUS_DS_SAM_INIT_FAILURE"; + case 0xC00002CC: return "STATUS_ONLY_IF_CONNECTED"; + case 0xC00002CD: return "STATUS_DS_SENSITIVE_GROUP_VIOLATION"; + case 0xC00002CE: return "STATUS_PNP_RESTART_ENUMERATION"; + case 0xC00002CF: return "STATUS_JOURNAL_ENTRY_DELETED"; + case 0xC00002D0: return "STATUS_DS_CANT_MOD_PRIMARYGROUPID"; + case 0xC00002D1: return "STATUS_SYSTEM_IMAGE_BAD_SIGNATURE"; + case 0xC00002D2: return "STATUS_PNP_REBOOT_REQUIRED"; + case 0xC00002D3: return "STATUS_POWER_STATE_INVALID"; + case 0xC00002D4: return "STATUS_DS_INVALID_GROUP_TYPE"; + case 0xC00002D5: return "STATUS_DS_NO_NEST_GLOBALGROUP_IN_MIXEDDOMAIN"; + case 0xC00002D6: return "STATUS_DS_NO_NEST_LOCALGROUP_IN_MIXEDDOMAIN"; + case 0xC00002D7: return "STATUS_DS_GLOBAL_CANT_HAVE_LOCAL_MEMBER"; + case 0xC00002D8: return "STATUS_DS_GLOBAL_CANT_HAVE_UNIVERSAL_MEMBER"; + case 0xC00002D9: return "STATUS_DS_UNIVERSAL_CANT_HAVE_LOCAL_MEMBER"; + case 0xC00002DA: return "STATUS_DS_GLOBAL_CANT_HAVE_CROSSDOMAIN_MEMBER"; + case 0xC00002DB: return "STATUS_DS_LOCAL_CANT_HAVE_CROSSDOMAIN_LOCAL_MEMBER"; + case 0xC00002DC: return "STATUS_DS_HAVE_PRIMARY_MEMBERS"; + case 0xC00002DD: return "STATUS_WMI_NOT_SUPPORTED"; + case 0xC00002DE: return "STATUS_INSUFFICIENT_POWER"; + case 0xC00002DF: return "STATUS_SAM_NEED_BOOTKEY_PASSWORD"; + case 0xC00002E0: return "STATUS_SAM_NEED_BOOTKEY_FLOPPY"; + case 0xC00002E1: return "STATUS_DS_CANT_START"; + case 0xC00002E2: return "STATUS_DS_INIT_FAILURE"; + case 0xC00002E3: return "STATUS_SAM_INIT_FAILURE"; + case 0xC00002E4: return "STATUS_DS_GC_REQUIRED"; + case 0xC00002E5: return "STATUS_DS_LOCAL_MEMBER_OF_LOCAL_ONLY"; + case 0xC00002E6: return "STATUS_DS_NO_FPO_IN_UNIVERSAL_GROUPS"; + case 0xC00002E7: return "STATUS_DS_MACHINE_ACCOUNT_QUOTA_EXCEEDED"; + case 0xC00002E8: return "STATUS_MULTIPLE_FAULT_VIOLATION"; + case 0xC0000300: return "STATUS_NOT_SUPPORTED_ON_SBS"; + case 0xC0009898: return "STATUS_WOW_ASSERTION"; + case 0xC0010001: return "DBG_NO_STATE_CHANGE"; + case 0xC0010002: return "DBG_APP_NOT_IDLE"; + case 0xC0020001: return "RPC_NT_INVALID_STRING_BINDING"; + case 0xC0020002: return "RPC_NT_WRONG_KIND_OF_BINDING"; + case 0xC0020003: return "RPC_NT_INVALID_BINDING"; + case 0xC0020004: return "RPC_NT_PROTSEQ_NOT_SUPPORTED"; + case 0xC0020005: return "RPC_NT_INVALID_RPC_PROTSEQ"; + case 0xC0020006: return "RPC_NT_INVALID_STRING_UUID"; + case 0xC0020007: return "RPC_NT_INVALID_ENDPOINT_FORMAT"; + case 0xC0020008: return "RPC_NT_INVALID_NET_ADDR"; + case 0xC0020009: return "RPC_NT_NO_ENDPOINT_FOUND"; + case 0xC002000A: return "RPC_NT_INVALID_TIMEOUT"; + case 0xC002000B: return "RPC_NT_OBJECT_NOT_FOUND"; + case 0xC002000C: return "RPC_NT_ALREADY_REGISTERED"; + case 0xC002000D: return "RPC_NT_TYPE_ALREADY_REGISTERED"; + case 0xC002000E: return "RPC_NT_ALREADY_LISTENING"; + case 0xC002000F: return "RPC_NT_NO_PROTSEQS_REGISTERED"; + case 0xC0020010: return "RPC_NT_NOT_LISTENING"; + case 0xC0020011: return "RPC_NT_UNKNOWN_MGR_TYPE"; + case 0xC0020012: return "RPC_NT_UNKNOWN_IF"; + case 0xC0020013: return "RPC_NT_NO_BINDINGS"; + case 0xC0020014: return "RPC_NT_NO_PROTSEQS"; + case 0xC0020015: return "RPC_NT_CANT_CREATE_ENDPOINT"; + case 0xC0020016: return "RPC_NT_OUT_OF_RESOURCES"; + case 0xC0020017: return "RPC_NT_SERVER_UNAVAILABLE"; + case 0xC0020018: return "RPC_NT_SERVER_TOO_BUSY"; + case 0xC0020019: return "RPC_NT_INVALID_NETWORK_OPTIONS"; + case 0xC002001A: return "RPC_NT_NO_CALL_ACTIVE"; + case 0xC002001B: return "RPC_NT_CALL_FAILED"; + case 0xC002001C: return "RPC_NT_CALL_FAILED_DNE"; + case 0xC002001D: return "RPC_NT_PROTOCOL_ERROR"; + case 0xC002001F: return "RPC_NT_UNSUPPORTED_TRANS_SYN"; + case 0xC0020021: return "RPC_NT_UNSUPPORTED_TYPE"; + case 0xC0020022: return "RPC_NT_INVALID_TAG"; + case 0xC0020023: return "RPC_NT_INVALID_BOUND"; + case 0xC0020024: return "RPC_NT_NO_ENTRY_NAME"; + case 0xC0020025: return "RPC_NT_INVALID_NAME_SYNTAX"; + case 0xC0020026: return "RPC_NT_UNSUPPORTED_NAME_SYNTAX"; + case 0xC0020028: return "RPC_NT_UUID_NO_ADDRESS"; + case 0xC0020029: return "RPC_NT_DUPLICATE_ENDPOINT"; + case 0xC002002A: return "RPC_NT_UNKNOWN_AUTHN_TYPE"; + case 0xC002002B: return "RPC_NT_MAX_CALLS_TOO_SMALL"; + case 0xC002002C: return "RPC_NT_STRING_TOO_LONG"; + case 0xC002002D: return "RPC_NT_PROTSEQ_NOT_FOUND"; + case 0xC002002E: return "RPC_NT_PROCNUM_OUT_OF_RANGE"; + case 0xC002002F: return "RPC_NT_BINDING_HAS_NO_AUTH"; + case 0xC0020030: return "RPC_NT_UNKNOWN_AUTHN_SERVICE"; + case 0xC0020031: return "RPC_NT_UNKNOWN_AUTHN_LEVEL"; + case 0xC0020032: return "RPC_NT_INVALID_AUTH_IDENTITY"; + case 0xC0020033: return "RPC_NT_UNKNOWN_AUTHZ_SERVICE"; + case 0xC0020034: return "EPT_NT_INVALID_ENTRY"; + case 0xC0020035: return "EPT_NT_CANT_PERFORM_OP"; + case 0xC0020036: return "EPT_NT_NOT_REGISTERED"; + case 0xC0020037: return "RPC_NT_NOTHING_TO_EXPORT"; + case 0xC0020038: return "RPC_NT_INCOMPLETE_NAME"; + case 0xC0020039: return "RPC_NT_INVALID_VERS_OPTION"; + case 0xC002003A: return "RPC_NT_NO_MORE_MEMBERS"; + case 0xC002003B: return "RPC_NT_NOT_ALL_OBJS_UNEXPORTED"; + case 0xC002003C: return "RPC_NT_INTERFACE_NOT_FOUND"; + case 0xC002003D: return "RPC_NT_ENTRY_ALREADY_EXISTS"; + case 0xC002003E: return "RPC_NT_ENTRY_NOT_FOUND"; + case 0xC002003F: return "RPC_NT_NAME_SERVICE_UNAVAILABLE"; + case 0xC0020040: return "RPC_NT_INVALID_NAF_ID"; + case 0xC0020041: return "RPC_NT_CANNOT_SUPPORT"; + case 0xC0020042: return "RPC_NT_NO_CONTEXT_AVAILABLE"; + case 0xC0020043: return "RPC_NT_INTERNAL_ERROR"; + case 0xC0020044: return "RPC_NT_ZERO_DIVIDE"; + case 0xC0020045: return "RPC_NT_ADDRESS_ERROR"; + case 0xC0020046: return "RPC_NT_FP_DIV_ZERO"; + case 0xC0020047: return "RPC_NT_FP_UNDERFLOW"; + case 0xC0020048: return "RPC_NT_FP_OVERFLOW"; + case 0xC0030001: return "RPC_NT_NO_MORE_ENTRIES"; + case 0xC0030002: return "RPC_NT_SS_CHAR_TRANS_OPEN_FAIL"; + case 0xC0030003: return "RPC_NT_SS_CHAR_TRANS_SHORT_FILE"; + case 0xC0030004: return "RPC_NT_SS_IN_NULL_CONTEXT"; + case 0xC0030005: return "RPC_NT_SS_CONTEXT_MISMATCH"; + case 0xC0030006: return "RPC_NT_SS_CONTEXT_DAMAGED"; + case 0xC0030007: return "RPC_NT_SS_HANDLES_MISMATCH"; + case 0xC0030008: return "RPC_NT_SS_CANNOT_GET_CALL_HANDLE"; + case 0xC0030009: return "RPC_NT_NULL_REF_POINTER"; + case 0xC003000A: return "RPC_NT_ENUM_VALUE_OUT_OF_RANGE"; + case 0xC003000B: return "RPC_NT_BYTE_COUNT_TOO_SMALL"; + case 0xC003000C: return "RPC_NT_BAD_STUB_DATA"; + case 0xC0020049: return "RPC_NT_CALL_IN_PROGRESS"; + case 0xC002004A: return "RPC_NT_NO_MORE_BINDINGS"; + case 0xC002004B: return "RPC_NT_GROUP_MEMBER_NOT_FOUND"; + case 0xC002004C: return "EPT_NT_CANT_CREATE"; + case 0xC002004D: return "RPC_NT_INVALID_OBJECT"; + case 0xC002004F: return "RPC_NT_NO_INTERFACES"; + case 0xC0020050: return "RPC_NT_CALL_CANCELLED"; + case 0xC0020051: return "RPC_NT_BINDING_INCOMPLETE"; + case 0xC0020052: return "RPC_NT_COMM_FAILURE"; + case 0xC0020053: return "RPC_NT_UNSUPPORTED_AUTHN_LEVEL"; + case 0xC0020054: return "RPC_NT_NO_PRINC_NAME"; + case 0xC0020055: return "RPC_NT_NOT_RPC_ERROR"; + case 0x40020056: return "RPC_NT_UUID_LOCAL_ONLY"; + case 0xC0020057: return "RPC_NT_SEC_PKG_ERROR"; + case 0xC0020058: return "RPC_NT_NOT_CANCELLED"; + case 0xC0030059: return "RPC_NT_INVALID_ES_ACTION"; + case 0xC003005A: return "RPC_NT_WRONG_ES_VERSION"; + case 0xC003005B: return "RPC_NT_WRONG_STUB_VERSION"; + case 0xC003005C: return "RPC_NT_INVALID_PIPE_OBJECT"; + case 0xC003005D: return "RPC_NT_INVALID_PIPE_OPERATION"; + case 0xC003005E: return "RPC_NT_WRONG_PIPE_VERSION"; + case 0xC003005F: return "RPC_NT_PIPE_CLOSED"; + case 0xC0030060: return "RPC_NT_PIPE_DISCIPLINE_ERROR"; + case 0xC0030061: return "RPC_NT_PIPE_EMPTY"; + case 0xC0020062: return "RPC_NT_INVALID_ASYNC_HANDLE"; + case 0xC0020063: return "RPC_NT_INVALID_ASYNC_CALL"; + case 0x400200AF: return "RPC_NT_SEND_INCOMPLETE"; + case 0xC0140001: return "STATUS_ACPI_INVALID_OPCODE"; + case 0xC0140002: return "STATUS_ACPI_STACK_OVERFLOW"; + case 0xC0140003: return "STATUS_ACPI_ASSERT_FAILED"; + case 0xC0140004: return "STATUS_ACPI_INVALID_INDEX"; + case 0xC0140005: return "STATUS_ACPI_INVALID_ARGUMENT"; + case 0xC0140006: return "STATUS_ACPI_FATAL"; + case 0xC0140007: return "STATUS_ACPI_INVALID_SUPERNAME"; + case 0xC0140008: return "STATUS_ACPI_INVALID_ARGTYPE"; + case 0xC0140009: return "STATUS_ACPI_INVALID_OBJTYPE"; + case 0xC014000A: return "STATUS_ACPI_INVALID_TARGETTYPE"; + case 0xC014000B: return "STATUS_ACPI_INCORRECT_ARGUMENT_COUNT"; + case 0xC014000C: return "STATUS_ACPI_ADDRESS_NOT_MAPPED"; + case 0xC014000D: return "STATUS_ACPI_INVALID_EVENTTYPE"; + case 0xC014000E: return "STATUS_ACPI_HANDLER_COLLISION"; + case 0xC014000F: return "STATUS_ACPI_INVALID_DATA"; + case 0xC0140010: return "STATUS_ACPI_INVALID_REGION"; + case 0xC0140011: return "STATUS_ACPI_INVALID_ACCESS_SIZE"; + case 0xC0140012: return "STATUS_ACPI_ACQUIRE_GLOBAL_LOCK"; + case 0xC0140013: return "STATUS_ACPI_ALREADY_INITIALIZED"; + case 0xC0140014: return "STATUS_ACPI_NOT_INITIALIZED"; + case 0xC0140015: return "STATUS_ACPI_INVALID_MUTEX_LEVEL"; + case 0xC0140016: return "STATUS_ACPI_MUTEX_NOT_OWNED"; + case 0xC0140017: return "STATUS_ACPI_MUTEX_NOT_OWNER"; + case 0xC0140018: return "STATUS_ACPI_RS_ACCESS"; + case 0xC0140019: return "STATUS_ACPI_INVALID_TABLE"; + case 0xC0140020: return "STATUS_ACPI_REG_HANDLER_FAILED"; + case 0xC0140021: return "STATUS_ACPI_POWER_REQUEST_FAILED"; + case 0xC00A0001: return "STATUS_CTX_WINSTATION_NAME_INVALID"; + case 0xC00A0002: return "STATUS_CTX_INVALID_PD"; + case 0xC00A0003: return "STATUS_CTX_PD_NOT_FOUND"; + case 0x400A0004: return "STATUS_CTX_CDM_CONNECT"; + case 0x400A0005: return "STATUS_CTX_CDM_DISCONNECT"; + case 0xC00A0006: return "STATUS_CTX_CLOSE_PENDING"; + case 0xC00A0007: return "STATUS_CTX_NO_OUTBUF"; + case 0xC00A0008: return "STATUS_CTX_MODEM_INF_NOT_FOUND"; + case 0xC00A0009: return "STATUS_CTX_INVALID_MODEMNAME"; + case 0xC00A000A: return "STATUS_CTX_RESPONSE_ERROR"; + case 0xC00A000B: return "STATUS_CTX_MODEM_RESPONSE_TIMEOUT"; + case 0xC00A000C: return "STATUS_CTX_MODEM_RESPONSE_NO_CARRIER"; + case 0xC00A000D: return "STATUS_CTX_MODEM_RESPONSE_NO_DIALTONE"; + case 0xC00A000E: return "STATUS_CTX_MODEM_RESPONSE_BUSY"; + case 0xC00A000F: return "STATUS_CTX_MODEM_RESPONSE_VOICE"; + case 0xC00A0010: return "STATUS_CTX_TD_ERROR"; + case 0xC00A0012: return "STATUS_CTX_LICENSE_CLIENT_INVALID"; + case 0xC00A0013: return "STATUS_CTX_LICENSE_NOT_AVAILABLE"; + case 0xC00A0014: return "STATUS_CTX_LICENSE_EXPIRED"; + case 0xC00A0015: return "STATUS_CTX_WINSTATION_NOT_FOUND"; + case 0xC00A0016: return "STATUS_CTX_WINSTATION_NAME_COLLISION"; + case 0xC00A0017: return "STATUS_CTX_WINSTATION_BUSY"; + case 0xC00A0018: return "STATUS_CTX_BAD_VIDEO_MODE"; + case 0xC00A0022: return "STATUS_CTX_GRAPHICS_INVALID"; + case 0xC00A0024: return "STATUS_CTX_NOT_CONSOLE"; + case 0xC00A0026: return "STATUS_CTX_CLIENT_QUERY_TIMEOUT"; + case 0xC00A0027: return "STATUS_CTX_CONSOLE_DISCONNECT"; + case 0xC00A0028: return "STATUS_CTX_CONSOLE_CONNECT"; + case 0xC00A002A: return "STATUS_CTX_SHADOW_DENIED"; + case 0xC00A002B: return "STATUS_CTX_WINSTATION_ACCESS_DENIED"; + case 0xC00A002E: return "STATUS_CTX_INVALID_WD"; + case 0xC00A002F: return "STATUS_CTX_WD_NOT_FOUND"; + case 0xC00A0030: return "STATUS_CTX_SHADOW_INVALID"; + case 0xC00A0031: return "STATUS_CTX_SHADOW_DISABLED"; + case 0xC00A0032: return "STATUS_RDP_PROTOCOL_ERROR"; + case 0xC00A0033: return "STATUS_CTX_CLIENT_LICENSE_NOT_SET"; + case 0xC00A0034: return "STATUS_CTX_CLIENT_LICENSE_IN_USE"; + case 0xC0040035: return "STATUS_PNP_BAD_MPS_TABLE"; + case 0xC0040036: return "STATUS_PNP_TRANSLATION_FAILED"; + case 0xC0040037: return "STATUS_PNP_IRQ_TRANSLATION_FAILED"; + default: return "STATUS_UNKNOWN"; + } +} + +/* + * Ext2ReadDisk + * Read data from disk ... + * + * ARGUMENTS: + * VolumeHandle: Volume Handle + * Offset : Disk Offset + * Length : Data Length to be read + * Buffer : ... + * + * RETURNS: + * Success: STATUS_SUCCESS + * Fail: ... + * + * NOTES: + * Both Length and Offset should be SECTOR_SIZE aligned. + */ +NTSTATUS +Ext2ReadDisk( PEXT2_FILESYS Ext2Sys, + ULONGLONG Offset, + ULONG Length, + PVOID Buffer ) +{ + LARGE_INTEGER Address; + NTSTATUS Status; + ULONG AlignedLength; + + IO_STATUS_BLOCK IoStatus; + + PVOID NonPagedBuffer = NULL; + + ASSERT(Buffer != NULL); + +#if 0 + if (Ext2Sys->bFile) + { + Address.QuadPart = Offset; + + Status = NtReadFile( Ext2Sys->MediaHandle, + 0, + NULL, + NULL, + &IoStatus, + Buffer, + Length, + &Address, + NULL ); + } + else +#endif + { + Address.QuadPart = Offset & (~((ULONGLONG)SECTOR_SIZE - 1)); + + AlignedLength = (Length + SECTOR_SIZE - 1)&(~(SECTOR_SIZE - 1)); + + AlignedLength += ((ULONG)(Offset - Address.QuadPart) + SECTOR_SIZE - 1) + & (~(SECTOR_SIZE - 1)); + + NonPagedBuffer = RtlAllocateHeap(GetProcessHeap(), 0, AlignedLength); + if (!NonPagedBuffer) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + goto errorout; + } + + Status = NtReadFile( Ext2Sys->MediaHandle, + 0, + NULL, + NULL, + &IoStatus, + NonPagedBuffer, + AlignedLength, + &Address, + NULL ); + + if (!NT_SUCCESS(Status)) + { + goto errorout; + } + + RtlCopyMemory( Buffer, + (PUCHAR)NonPagedBuffer + (ULONG)(Offset - Address.QuadPart), + Length ); + } + +errorout: + + if (NonPagedBuffer) + RtlFreeHeap(GetProcessHeap(), 0, NonPagedBuffer); + + return Status; +} + + +/* + * Ext2WriteDisk + * Write data to disk ... + * + * ARGUMENTS: + * VolumeHandle: Volume Handle + * Offset : Disk Offset + * Length : Data Length to be written + * Buffer : Data to be written ... + * + * RETURNS: + * Success: STATUS_SUCCESS + * Fail: ... + * + * NOTES: + * Both Length and Offset should be SECTOR_SIZE aligned. + */ + +NTSTATUS +Ext2WriteDisk( PEXT2_FILESYS Ext2Sys, + ULONGLONG Offset, + ULONG Length, + PVOID Buffer ) +{ + LARGE_INTEGER Address; + NTSTATUS Status; + ULONG AlignedLength; + + IO_STATUS_BLOCK IoStatus; + + PVOID NonPagedBuffer = NULL; + + ASSERT(Buffer != NULL); + +#if 0 + if (Ext2Sys->bFile) + { + Address.QuadPart = Offset; + + Status = NtWriteFile( Ext2Sys->MediaHandle, + 0, + NULL, + NULL, + &IoStatus, + Buffer, + Length, + &Address, + NULL ); + } + else +#endif + { + Address.QuadPart = Offset & (~((ULONGLONG)SECTOR_SIZE - 1)); + + AlignedLength = (Length + SECTOR_SIZE - 1)&(~(SECTOR_SIZE - 1)); + + AlignedLength += ((ULONG)(Offset - Address.QuadPart) + SECTOR_SIZE - 1) + & (~(SECTOR_SIZE - 1)); + + NonPagedBuffer = RtlAllocateHeap(GetProcessHeap(), 0, AlignedLength); + if (!NonPagedBuffer) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + goto errorout; + } + + if ((AlignedLength != Length) || (Address.QuadPart != (LONGLONG)Offset)) + { + Status = NtReadFile( Ext2Sys->MediaHandle, + 0, + NULL, + NULL, + &IoStatus, + NonPagedBuffer, + AlignedLength, + &Address, + NULL ); + + if (!NT_SUCCESS(Status)) + { + goto errorout; + } + } + + RtlCopyMemory( (PUCHAR)NonPagedBuffer + (ULONG)(Offset - Address.QuadPart), + Buffer, Length ); + + Status = NtWriteFile( Ext2Sys->MediaHandle, + 0, + NULL, + NULL, + &IoStatus, + NonPagedBuffer, + AlignedLength, + &Address, + NULL ); + } + +errorout: + + if (NonPagedBuffer) + RtlFreeHeap(GetProcessHeap(), 0, NonPagedBuffer); + + return Status; +} + + +/* + * Ext2GetMediaInfo + * Get volume gemmetry information ... + * + * ARGUMENTS: + * VolumeHandle: Volume handle. + * + * RETURNS: + * Success or Fail + * + * NOTES: + * N/A + */ + +NTSTATUS +Ext2GetMediaInfo( PEXT2_FILESYS Ext2Sys ) +{ + NTSTATUS Status; + IO_STATUS_BLOCK IoSb; + + Status = NtDeviceIoControlFile( Ext2Sys->MediaHandle, + NULL, NULL, NULL, &IoSb, + IOCTL_DISK_GET_DRIVE_GEOMETRY, + &(Ext2Sys->DiskGeometry), sizeof(DISK_GEOMETRY), + &(Ext2Sys->DiskGeometry), sizeof(DISK_GEOMETRY)); + + + if (!NT_SUCCESS(Status)) + { + goto errorout; + } + + Status = NtDeviceIoControlFile( Ext2Sys->MediaHandle, + NULL, NULL, NULL, &IoSb, + IOCTL_DISK_GET_PARTITION_INFO, + &(Ext2Sys->PartInfo), sizeof(PARTITION_INFORMATION), + &(Ext2Sys->PartInfo), sizeof(PARTITION_INFORMATION)); + + if (!NT_SUCCESS(Status)) + { + goto errorout; + } + +errorout: + + return Status; +} + + +/* + * Ext2LockVolume + * Lock the volume ... + * + * ARGUMENTS: + * VolumeHandle: Volume handle. + * + * RETURNS: + * Success or Fail + * + * NOTES: + * N/A + */ + + +NTSTATUS +Ext2LockVolume( PEXT2_FILESYS Ext2Sys ) +{ + NTSTATUS Status; + IO_STATUS_BLOCK IoSb; + + Status = NtFsControlFile( Ext2Sys->MediaHandle, + NULL, NULL, NULL, &IoSb, + FSCTL_LOCK_VOLUME, + NULL, 0, NULL, 0 ); + + if (!NT_SUCCESS(Status)) + { + KdPrint(("Mke2fs: Error when locking volume: Status = %lxh %s...\n", + Status, Ext2StatusToString(Status))); + + goto errorout; + } + +errorout: + + return Status; +} + + +NTSTATUS +Ext2UnLockVolume( PEXT2_FILESYS Ext2Sys ) +{ + NTSTATUS Status; + IO_STATUS_BLOCK IoSb; + + Status = NtFsControlFile( Ext2Sys->MediaHandle, + NULL, NULL, NULL, &IoSb, + FSCTL_UNLOCK_VOLUME, + NULL, 0, NULL, 0 ); + + if (!NT_SUCCESS(Status)) + { + KdPrint(("Mke2fs: Error when unlocking volume ...\n")); + goto errorout; + } + +errorout: + + return Status; +} + + +NTSTATUS +Ext2DisMountVolume( PEXT2_FILESYS Ext2Sys ) +{ + NTSTATUS Status; + IO_STATUS_BLOCK IoSb; + + Status = NtFsControlFile( Ext2Sys->MediaHandle, + NULL, NULL, NULL, &IoSb, + FSCTL_DISMOUNT_VOLUME, + NULL, 0, NULL, 0 ); + + if (!NT_SUCCESS(Status)) + { + KdPrint(("Mke2fs: Error when dismounting volume ...\n")); + goto errorout; + } + +errorout: + + return Status; +} + +NTSTATUS +Ext2OpenDevice( PEXT2_FILESYS Ext2Sys, + PUNICODE_STRING DeviceName ) +{ + NTSTATUS Status; + OBJECT_ATTRIBUTES ObjectAttributes; + HANDLE FileHandle; + IO_STATUS_BLOCK Iosb; + + // + // Setup the name in an object attributes structure. + // Note that we create a name that is case INsensitive + // + InitializeObjectAttributes(&ObjectAttributes, // ptr to structure + DeviceName, // ptr to file spec + OBJ_CASE_INSENSITIVE, // attributes + NULL, // root directory handle + NULL ); // ptr to security descriptor + + // + // Do the create. In this particular case, we'll have the I/O Manager + // make our write requests syncrhonous for our convenience. + // + Status = NtCreateFile(&FileHandle, // returned file handle + (GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE), // desired access + &ObjectAttributes, // ptr to object attributes + &Iosb, // ptr to I/O status block + 0, // allocation size + FILE_ATTRIBUTE_NORMAL, // file attributes + FILE_SHARE_WRITE | FILE_SHARE_READ, // share access + FILE_OPEN /*FILE_SUPERSEDE*/, // create disposition + FILE_SYNCHRONOUS_IO_NONALERT, // create options + NULL, // ptr to extended attributes + 0); // length of ea buffer + + // + // Check the system service status + // + if( !NT_SUCCESS(Status) ) + { + KdPrint(("Mke2fs: Create system service failed status = 0x%lx\n", Status)); + return Status; + } + + + // + // Check the returned status too... + // + if(!NT_SUCCESS(Iosb.Status) ) + { + KdPrint(("Mke2fs: Create failed with status = 0x%lx\n",Iosb.Status)); + return Status; + } + + Ext2Sys->MediaHandle = FileHandle; + + return Status; +} + + +NTSTATUS +Ext2CloseDevice( PEXT2_FILESYS Ext2Sys) +{ + NTSTATUS Status = STATUS_SUCCESS; + + if(Ext2Sys->MediaHandle) + { + Status = NtClose(Ext2Sys->MediaHandle); + } + + return Status; +} diff --git a/reactos/lib/fslib/ext2lib/Disk.h b/reactos/lib/fslib/ext2lib/Disk.h new file mode 100644 index 00000000000..f824a034edf --- /dev/null +++ b/reactos/lib/fslib/ext2lib/Disk.h @@ -0,0 +1,19 @@ +/* + * PROJECT: Mke2fs + * FILE: Disk.h + * PROGRAMMER: Matt Wu + * HOMEPAGE: http://ext2.yeah.net + */ + +#ifndef _DISK_H_ +#define _DISK_H_ + +/* INCLUDES **************************************************************/ + +#include "Stdafx.h" + +/* DEFINITIONS ***********************************************************/ + + + +#endif /* _DISK_H_ */ diff --git a/reactos/lib/fslib/ext2lib/Group.c b/reactos/lib/fslib/ext2lib/Group.c new file mode 100644 index 00000000000..9f364b3f982 --- /dev/null +++ b/reactos/lib/fslib/ext2lib/Group.c @@ -0,0 +1,68 @@ +/* + * PROJECT: Mke2fs + * FILE: Group.c + * PROGRAMMER: Matt Wu + * HOMEPAGE: http://ext2.yeah.net + */ + +/* INCLUDES **************************************************************/ + +#include "Mke2fs.h" + +/* DEFINITIONS ***********************************************************/ + +/* FUNCTIONS *************************************************************/ + +int test_root(int a, int b) +{ + if (a == 0) + return 1; + while (1) + { + if (a == 1) + return 1; + if (a % b) + return 0; + a = a / b; + } +} + +bool ext2_bg_has_super(PEXT2_SUPER_BLOCK pExt2Sb, int group_block) +{ + if (!(pExt2Sb->s_feature_ro_compat & EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER)) + return true; + + if (test_root(group_block, 3) || (test_root(group_block, 5)) || + test_root(group_block, 7)) + return true; + + return false; +} + + +bool ext2_allocate_group_desc(PEXT2_FILESYS Ext2Sys) +{ + ULONG size; + + size = Ext2Sys->desc_blocks * Ext2Sys->blocksize; + + Ext2Sys->group_desc = + (PEXT2_GROUP_DESC)RtlAllocateHeap(GetProcessHeap(), 0, size); + + if (Ext2Sys->group_desc) + { + memset(Ext2Sys->group_desc, 0, size); + return true; + } + + return false; +} + +void ext2_free_group_desc(PEXT2_FILESYS Ext2Sys) +{ + if (Ext2Sys->group_desc) + { + RtlFreeHeap(GetProcessHeap(), 0, Ext2Sys->group_desc); + Ext2Sys->group_desc = NULL; + } +} diff --git a/reactos/lib/fslib/ext2lib/Inode.c b/reactos/lib/fslib/ext2lib/Inode.c new file mode 100644 index 00000000000..64d95a9474e --- /dev/null +++ b/reactos/lib/fslib/ext2lib/Inode.c @@ -0,0 +1,697 @@ +/* + * PROJECT: Mke2fs + * FILE: Inode.c + * PROGRAMMER: Matt Wu + * HOMEPAGE: http://ext2.yeah.net + */ + +/* INCLUDES **************************************************************/ + +#include "Mke2fs.h" + +/* DEFINITIONS ***********************************************************/ + +extern char *device_name; + +/* FUNCTIONS *************************************************************/ + + +bool ext2_get_inode_lba(PEXT2_FILESYS Ext2Sys, ULONG no, LONGLONG *offset) +{ + LONGLONG loc = 0; + PEXT2_SUPER_BLOCK pExt2Sb = Ext2Sys->ext2_sb; + + if (no < 1 || no > pExt2Sb->s_inodes_count) + { + KdPrint(("Mke2fs: Inode value %lu was out of range in load_inode.(1-%ld)\n", + no, pExt2Sb->s_inodes_count)); + *offset = 0; + return false; + } + + loc = (LONGLONG)(Ext2Sys->blocksize) * Ext2Sys->group_desc[(no - 1) / pExt2Sb->s_inodes_per_group].bg_inode_table + + ((no - 1) % pExt2Sb->s_inodes_per_group) * sizeof(EXT2_INODE); + + *offset = loc; + + return true; +} + +bool ext2_load_inode(PEXT2_FILESYS Ext2Sys, ULONG no, PEXT2_INODE pInode) +{ + LONGLONG Offset; + bool bRet = false; + + if (ext2_get_inode_lba(Ext2Sys, no, &Offset)) + { + bRet = NT_SUCCESS(Ext2ReadDisk( + Ext2Sys, + Offset, + sizeof(EXT2_INODE), + (unsigned char *)pInode)); + } + + return bRet; +} + + +bool ext2_save_inode(PEXT2_FILESYS Ext2Sys, ULONG no, PEXT2_INODE pInode) +{ + LONGLONG offset; + bool bRet = false; + + if (ext2_get_inode_lba(Ext2Sys, no, &offset)) + { + bRet = NT_SUCCESS(Ext2WriteDisk( + Ext2Sys, + offset, + sizeof(EXT2_INODE), + (unsigned char *)pInode)); + } + + return bRet; +} + + +/* + * Right now, just search forward from the parent directory's block + * group to find the next free inode. + * + * Should have a special policy for directories. + */ + +bool ext2_new_inode(PEXT2_FILESYS fs, ULONG dir, int mode, + PEXT2_INODE_BITMAP map, ULONG *ret) +{ + ULONG dir_group = 0; + ULONG i; + ULONG start_inode; + + if (!map) + map = fs->inode_map; + + if (!map) + return false; + + if (dir > 0) + dir_group = (dir - 1) / EXT2_INODES_PER_GROUP(fs->ext2_sb); + + start_inode = (dir_group * EXT2_INODES_PER_GROUP(fs->ext2_sb)) + 1; + + if (start_inode < EXT2_FIRST_INODE(fs->ext2_sb)) + start_inode = EXT2_FIRST_INODE(fs->ext2_sb); + + i = start_inode; + + do + { + if (!ext2_test_inode_bitmap(map, i)) + break; + + i++; + + if (i > fs->ext2_sb->s_inodes_count) + i = EXT2_FIRST_INODE(fs->ext2_sb); + + } while (i != start_inode); + + if (ext2_test_inode_bitmap(map, i)) + return false; + + *ret = i; + + return true; +} + + +bool ext2_expand_block( PEXT2_FILESYS Ext2Sys, PEXT2_INODE Inode, + ULONG dwContent, ULONG Index, int layer, + ULONG newBlk, ULONG *dwRet, ULONG *off ) +{ + ULONG *pData = NULL; + ULONG i = 0, j = 0, temp = 1; + ULONG dwBlk; + ULONG dwNewBlk = newBlk; + bool bDirty = false; + bool bRet = true; + ULONG Offset = 0; + + PEXT2_SUPER_BLOCK pExt2Sb = Ext2Sys->ext2_sb; + + pData = (ULONG *)RtlAllocateHeap(GetProcessHeap(), 0, Ext2Sys->blocksize); + + if (!pData) + { + bRet = false; + goto errorout; + } + + if (!ext2_read_block(Ext2Sys, dwContent, (void *)pData)) + { + bRet = false; + goto errorout; + } + + if (layer == 1) + { + *dwRet = dwContent; + *off = Index; + pData[Index] = newBlk; + + bDirty = TRUE; + } + else if (layer <= 3) + { + temp = 1 << ((10 + pExt2Sb->s_log_block_size - 2) * (layer - 1)); + + i = Index / temp; + j = Index % temp; + + dwBlk = pData[i]; + + if (dwBlk == 0) + { + if (ext2_alloc_block(Ext2Sys, 0, &dwBlk) ) + { + pData[i] = dwBlk; + bDirty = true; + + Inode->i_blocks += (Ext2Sys->blocksize / SECTOR_SIZE); + } + + if (!bDirty) + goto errorout; + } + + if (!ext2_expand_block(Ext2Sys, Inode, dwBlk, j, layer - 1, bDirty, &dwNewBlk, &Offset)) + { + bRet = false; + KdPrint(("Mke2fs: ext2_expand_block: ... error recuise...\n")); + goto errorout; + } + } + + if (bDirty) + { + bRet = ext2_write_block(Ext2Sys, dwContent, (void *)pData); + } + + +errorout: + + if (pData) + RtlFreeHeap(GetProcessHeap(), 0, pData); + + if (bRet && dwRet) + *dwRet = dwNewBlk; + + return bRet; +} + +bool ext2_expand_inode( PEXT2_FILESYS Ext2Sys, + PEXT2_INODE Inode, + ULONG newBlk ) +{ + ULONG dwSizes[4] = {12, 1, 1, 1}; + ULONG Index = 0; + ULONG dwTotal = 0; + ULONG dwBlk = 0, dwNewBlk = 0, Offset = 0; + PEXT2_SUPER_BLOCK pExt2Sb = Ext2Sys->ext2_sb; + int i = 0; + bool bRet = true; + bool bDirty = false; + ULONG TotalBlocks; + + TotalBlocks = Inode->i_blocks / (Ext2Sys->blocksize / SECTOR_SIZE); + Index = Ext2DataBlocks(Ext2Sys, TotalBlocks); + + for (i = 0; i < 4; i++) + { + dwSizes[i] = dwSizes[i] << ((10 + pExt2Sb->s_log_block_size - 2) * i); + dwTotal += dwSizes[i]; + } + + if (Index >= dwTotal) + { + KdPrint(("Mke2fs: ext2_expand_inode: beyond the maxinum size of an inode.\n")); + return false; + } + + for (i = 0; i < 4; i++) + { + if (Index < dwSizes[i]) + { + if (i == 0) + { + Inode->i_block[Index] = newBlk; + bDirty = true; + } + else + { + dwBlk = Inode->i_block[(i + 12 - 1)]; + + if (dwBlk == 0) + { + if (ext2_alloc_block(Ext2Sys, 0, &dwBlk)) + { + Inode->i_block[(i + 12 - 1)] = dwBlk; + bDirty = true; + + Inode->i_blocks += (Ext2Sys->blocksize / SECTOR_SIZE); + } + else + { + break; + } + } + + dwNewBlk = 0; + bRet = ext2_expand_block( + Ext2Sys, + Inode, + dwBlk, + Index, + i, + newBlk, + &dwNewBlk, + &Offset ); + } + + break; + } + + Index -= dwSizes[i]; + } + + return bRet; +} + + +bool ext2_get_block(PEXT2_FILESYS Ext2Sys, ULONG dwContent, ULONG Index, int layer, ULONG *dwRet) +{ + ULONG *pData = NULL; + LONGLONG Offset = 0; + ULONG i = 0, j = 0, temp = 1; + ULONG dwBlk = 0; + bool bRet = true; + + PEXT2_SUPER_BLOCK pExt2Sb = Ext2Sys->ext2_sb; + + Offset = (LONGLONG) dwContent; + Offset = Offset * Ext2Sys->blocksize; + + pData = (ULONG *)RtlAllocateHeap(GetProcessHeap(), 0, Ext2Sys->blocksize); + + if (!pData) + { + return false; + } + memset(pData, 0, Ext2Sys->blocksize); + + if (layer == 0) + { + dwBlk = dwContent; + } + else if (layer <= 3) + { + + if (!ext2_read_block(Ext2Sys, dwContent, (void *)pData)) + { + bRet = false; + goto errorout; + } + + temp = 1 << ((10 + pExt2Sb->s_log_block_size - 2) * (layer - 1)); + + i = Index / temp; + j = Index % temp; + + if (!ext2_get_block(Ext2Sys, pData[i], j, layer - 1, &dwBlk)) + { + bRet = false; + KdPrint(("Mke2fs: ext2_get_block: ... error recuise...\n")); + goto errorout; + } + } + +errorout: + + if (pData) + RtlFreeHeap(GetProcessHeap(), 0, pData); + + if (bRet && dwRet) + *dwRet = dwBlk; + + return bRet; +} + +bool ext2_block_map(PEXT2_FILESYS Ext2Sys, PEXT2_INODE inode, ULONG block, ULONG *dwRet) +{ + ULONG dwSizes[4] = {12, 1, 1, 1}; + ULONG Index = 0; + ULONG dwBlk = 0; + PEXT2_SUPER_BLOCK pExt2Sb = Ext2Sys->ext2_sb; + int i; + bool bRet = false; + + Index = block; + + for (i = 0; i < 4; i++) + { + dwSizes[i] = dwSizes[i] << ((10 + pExt2Sb->s_log_block_size - 2) * i); + } + + if (Index >= inode->i_blocks / (Ext2Sys->blocksize / SECTOR_SIZE)) + { + KdPrint(("Mke2fs: ext2_block_map: beyond the size of the inode.\n")); + return false; + } + + for (i = 0; i < 4; i++) + { + if (Index < dwSizes[i]) + { + dwBlk = inode->i_block[i==0 ? (Index):(i + 12 - 1)]; + + bRet = ext2_get_block(Ext2Sys, dwBlk, Index , i, &dwBlk); + + break; + } + Index -= dwSizes[i]; + } + + if (bRet && dwBlk) + { + if (dwRet) + *dwRet = dwBlk; + + return true; + } + else + return false; +} + +ULONG ext2_build_bdl(PEXT2_FILESYS Ext2Sys, + PEXT2_INODE ext2_inode, + IN ULONG offset, + IN ULONG size, + OUT PEXT2_BDL *ext2_bdl ) +{ + ULONG nBeg, nEnd, nBlocks; + ULONG dwBlk; + ULONG i; + ULONG dwBytes = 0; + LONGLONG lba; + + PEXT2_BDL ext2bdl = NULL; + + *ext2_bdl = NULL; + + if (offset >= ext2_inode->i_size) + { + KdPrint(("Mke2fs: ext2_build_bdl: beyond the file range.\n")); + return 0; + } + +/* + if (offset + size > ext2_inode->i_size) + { + size = ext2_inode->i_size - offset; + } +*/ + + nBeg = offset / Ext2Sys->blocksize; + nEnd = (size + offset + Ext2Sys->blocksize - 1) / Ext2Sys->blocksize; + + nBlocks = nEnd - nBeg; + + if (nBlocks > 0) + { + ext2bdl = (PEXT2_BDL) + RtlAllocateHeap(GetProcessHeap(), 0, sizeof(EXT2_BDL) * nBlocks); + + if (ext2bdl) + { + + memset(ext2bdl, 0, sizeof(EXT2_BDL) * nBlocks); + + for (i = nBeg; i < nEnd; i++) + { + if (!ext2_block_map(Ext2Sys, ext2_inode, i, &dwBlk)) + { + goto fail; + } + + lba = (LONGLONG) dwBlk; + lba = lba * Ext2Sys->blocksize; + + if (nBlocks == 1) // ie. (nBeg == nEnd - 1) + { + dwBytes = size; + ext2bdl[i - nBeg].Lba = lba + (LONGLONG)(offset % (Ext2Sys->blocksize)); + ext2bdl[i - nBeg].Length = dwBytes; + ext2bdl[i - nBeg].Offset = 0; + } + else + { + if (i == nBeg) + { + dwBytes = Ext2Sys->blocksize - (offset % (Ext2Sys->blocksize)); + ext2bdl[i - nBeg].Lba = lba + (LONGLONG)(offset % (Ext2Sys->blocksize)); + ext2bdl[i - nBeg].Length = dwBytes; + ext2bdl[i - nBeg].Offset = 0; + } + else if (i == nEnd - 1) + { + ext2bdl[i - nBeg].Lba = lba; + ext2bdl[i - nBeg].Length = size - dwBytes; + ext2bdl[i - nBeg].Offset = dwBytes; + dwBytes = size; + } + else + { + ext2bdl[i - nBeg].Lba = lba; + ext2bdl[i - nBeg].Length = Ext2Sys->blocksize; + ext2bdl[i - nBeg].Offset = dwBytes; + dwBytes += Ext2Sys->blocksize; + } + } + } + + *ext2_bdl = ext2bdl; + return nBlocks; + } + } + +fail: + + if (ext2bdl) + RtlFreeHeap(GetProcessHeap(), 0, ext2bdl); + + // Error + return 0; +} + + +bool ext2_read_inode(PEXT2_FILESYS Ext2Sys, + ULONG ino, + ULONG offset, + PVOID Buffer, + ULONG size, + PULONG dwReturn) +{ + PEXT2_BDL ext2_bdl = NULL; + ULONG blocks, i; + bool bRet = true; + EXT2_INODE ext2_inode; + ULONG dwTotal = 0; + + if (!ext2_load_inode(Ext2Sys, ino, &ext2_inode)) + { + return false; + } + + blocks = ext2_build_bdl(Ext2Sys, &ext2_inode, offset, size, &ext2_bdl); + + if (blocks <= 0) + return false; + + + for(i = 0; i < blocks; i++) + { + bRet = NT_SUCCESS(Ext2ReadDisk( + Ext2Sys, + ext2_bdl[i].Lba, + ext2_bdl[i].Length, + (PUCHAR)Buffer + ext2_bdl[i].Offset + )); + + if (!bRet) + break; + dwTotal += ext2_bdl[i].Length; + } + + *dwReturn = dwTotal; + + if (ext2_bdl) + RtlFreeHeap(GetProcessHeap(), 0, ext2_bdl); + + return bRet; +} + + +bool ext2_write_inode (PEXT2_FILESYS Ext2Sys, + ULONG ino, + ULONG offset, + PVOID Buffer, + ULONG size, + PULONG dwReturn ) +{ + PEXT2_BDL ext2_bdl = NULL; + ULONG blocks, i; + bool bRet = true; + EXT2_INODE inode; + ULONG dwTotal = 0; + ULONG dwBlk = 0; + ULONG TotalBlks; + + blocks = (size + offset + Ext2Sys->blocksize - 1) / Ext2Sys->blocksize; + + if (!ext2_load_inode(Ext2Sys, ino, &inode)) + { + return false; + } + + TotalBlks = inode.i_blocks / (Ext2Sys->blocksize / SECTOR_SIZE); + TotalBlks = Ext2DataBlocks(Ext2Sys, TotalBlks); + + if (blocks > TotalBlks) + { + for (i=0; i < (blocks - TotalBlks); i++) + { + if (ext2_alloc_block(Ext2Sys, 0, &dwBlk) ) + { + ext2_expand_inode(Ext2Sys, &inode, dwBlk); + inode.i_blocks += (Ext2Sys->blocksize/SECTOR_SIZE); + } + } + } + + blocks = ext2_build_bdl(Ext2Sys, &inode, offset, size, &ext2_bdl); + + if (blocks <= 0) + return false; + + for(i = 0; i < blocks; i++) + { + bRet = NT_SUCCESS(Ext2WriteDisk( + Ext2Sys, + ext2_bdl[i].Lba, + ext2_bdl[i].Length, + (PUCHAR)Buffer + ext2_bdl[i].Offset + )); + + if (!bRet) + { + goto errorout; + } + + dwTotal += ext2_bdl[i].Length; + } + + *dwReturn = dwTotal; + + if (size + offset > inode.i_size) + { + inode.i_size = size + offset; + } + + ext2_save_inode(Ext2Sys, ino, &inode); + + +errorout: + + if (ext2_bdl) + RtlFreeHeap(GetProcessHeap(), 0, ext2_bdl); + + return bRet; +} + +bool +ext2_add_entry( PEXT2_FILESYS Ext2Sys, + ULONG parent, ULONG inode, + int filetype, char *name ) +{ + PEXT2_DIR_ENTRY2 dir = NULL, newdir = NULL; + EXT2_INODE parent_inode; + ULONG dwRet; + char *buf; + int rec_len; + bool bRet = false; + + rec_len = EXT2_DIR_REC_LEN(strlen(name)); + + if (!ext2_load_inode(Ext2Sys, parent, &parent_inode)) + { + return false; + } + + buf = (char *)RtlAllocateHeap(GetProcessHeap(), 0, parent_inode.i_size); + + if (!ext2_read_inode(Ext2Sys, parent, 0, buf, parent_inode.i_size, &dwRet)) + { + return false; + } + + dir = (PEXT2_DIR_ENTRY2) buf; + + while ((char *)dir < buf + parent_inode.i_size) + { + if ((dir->inode == 0 && dir->rec_len >= rec_len) || + (dir->rec_len >= dir->name_len + rec_len) ) + { + if (dir->inode) + { + newdir = (PEXT2_DIR_ENTRY2) ((PUCHAR)dir + EXT2_DIR_REC_LEN(dir->name_len)); + newdir->rec_len = dir->rec_len - EXT2_DIR_REC_LEN(dir->name_len); + + dir->rec_len = EXT2_DIR_REC_LEN(dir->name_len); + + dir = newdir; + } + + dir->file_type = filetype; + dir->inode = inode; + dir->name_len = strlen(name); + memcpy(dir->name, name, strlen(name)); + + bRet = true; + break; + } + + dir = (PEXT2_DIR_ENTRY2) (dir->rec_len + (PUCHAR) dir); + } + + + if (bRet) + return ext2_write_inode(Ext2Sys, parent, 0, buf, parent_inode.i_size, &dwRet); + + return bRet; +} + + +bool ext2_reserve_inodes(PEXT2_FILESYS fs) +{ + ULONG i; + int group; + + for (i = EXT2_ROOT_INO + 1; i < EXT2_FIRST_INODE(fs->ext2_sb); i++) + { + ext2_mark_inode_bitmap(fs->inode_map, i); + group = ext2_group_of_ino(fs, i); + fs->group_desc[group].bg_free_inodes_count--; + fs->ext2_sb->s_free_inodes_count--; + } + + return true; +} diff --git a/reactos/lib/fslib/ext2lib/Makefile b/reactos/lib/fslib/ext2lib/Makefile new file mode 100644 index 00000000000..2b7e732c2c3 --- /dev/null +++ b/reactos/lib/fslib/ext2lib/Makefile @@ -0,0 +1,19 @@ +# $Id: $ + +PATH_TO_TOP = ../../.. +TARGET_TYPE = library +TARGET_NAME = ext2lib +TARGET_CFLAGS = -I$(W32API_PATH)/include/ddk -D__USE_W32API -Wall -Werror -DDBG +TARGET_OBJECTS = \ + Badblock.o \ + Bitmap.o \ + Disk.o \ + Group.o \ + Inode.o \ + Memory.o \ + Mke2fs.o \ + Super.o \ + Uuid.o + +include $(PATH_TO_TOP)/rules.mak +include $(TOOLS_PATH)/helper.mk diff --git a/reactos/lib/fslib/ext2lib/Memory.c b/reactos/lib/fslib/ext2lib/Memory.c new file mode 100644 index 00000000000..c5277db6219 --- /dev/null +++ b/reactos/lib/fslib/ext2lib/Memory.c @@ -0,0 +1,416 @@ +/* + * PROJECT: Mke2fs + * FILE: Memory.c + * PROGRAMMER: Matt Wu + * HOMEPAGE: http://ext2.yeah.net + */ + +/* INCLUDES **************************************************************/ + +#include "Mke2fs.h" + +/* DEFINITIONS ***********************************************************/ + +extern char *device_name; + +/* FUNCTIONS *************************************************************/ + + +/* + * Return the group # of an inode number + */ +int ext2_group_of_ino(PEXT2_FILESYS fs, ULONG ino) +{ + return (ino - 1) / fs->ext2_sb->s_inodes_per_group; +} + +/* + * Return the group # of a block + */ +int ext2_group_of_blk(PEXT2_FILESYS fs, ULONG blk) +{ + return (blk - fs->ext2_sb->s_first_data_block) / + fs->ext2_sb->s_blocks_per_group; +} + +void ext2_inode_alloc_stats2(PEXT2_FILESYS fs, ULONG ino, + int inuse, int isdir) +{ + int group = ext2_group_of_ino(fs, ino); + + if (inuse > 0) + ext2_mark_inode_bitmap(fs->inode_map, ino); + else + ext2_unmark_inode_bitmap(fs->inode_map, ino); + + fs->group_desc[group].bg_free_inodes_count -= inuse; + + if (isdir) + fs->group_desc[group].bg_used_dirs_count += inuse; + + fs->ext2_sb->s_free_inodes_count -= inuse; +} + + +void ext2_inode_alloc_stats(PEXT2_FILESYS fs, ULONG ino, int inuse) +{ + ext2_inode_alloc_stats2(fs, ino, inuse, 0); +} + +void ext2_block_alloc_stats(PEXT2_FILESYS fs, ULONG blk, int inuse) +{ + int group = ext2_group_of_blk(fs, blk); + + if (inuse > 0) + ext2_mark_block_bitmap(fs->block_map, blk); + else + ext2_unmark_block_bitmap(fs->block_map, blk); + + fs->group_desc[group].bg_free_blocks_count -= inuse; + fs->ext2_sb->s_free_blocks_count -= inuse; +} + + +bool ext2_allocate_tables(PEXT2_FILESYS Ext2Sys) +{ + bool retval; + ULONG i; + + for (i = 0; i < Ext2Sys->group_desc_count; i++) + { + retval = ext2_allocate_group_table(Ext2Sys, i, Ext2Sys->block_map); + + if (!retval) + return retval; + } + + return true; +} + + +bool ext2_allocate_group_table(PEXT2_FILESYS fs, ULONG group, + PEXT2_BLOCK_BITMAP bmap) +{ + bool retval; + ULONG group_blk, start_blk, last_blk, new_blk, blk; + int j; + + group_blk = fs->ext2_sb->s_first_data_block + + (group * fs->ext2_sb->s_blocks_per_group); + + last_blk = group_blk + fs->ext2_sb->s_blocks_per_group; + if (last_blk >= fs->ext2_sb->s_blocks_count) + last_blk = fs->ext2_sb->s_blocks_count - 1; + + start_blk = group_blk + 3 + fs->desc_blocks; + if (start_blk > last_blk) + start_blk = group_blk; + + if (!bmap) + bmap = fs->block_map; + + /* + * Allocate the inode table + */ + if (!fs->group_desc[group].bg_inode_table) + { + retval = ext2_get_free_blocks(fs, start_blk, last_blk, + fs->inode_blocks_per_group, + bmap, &new_blk); + if (!retval) + return retval; + + for (j=0, blk = new_blk; + j < fs->inode_blocks_per_group; + j++, blk++) + ext2_mark_block_bitmap(bmap, blk); + + fs->group_desc[group].bg_inode_table = new_blk; + } + + /* + * Allocate the block and inode bitmaps, if necessary + */ + if (fs->stride) + { + start_blk += fs->inode_blocks_per_group; + start_blk += ((fs->stride * group) % + (last_blk - start_blk)); + if (start_blk > last_blk) + /* should never happen */ + start_blk = group_blk; + } + else + { + start_blk = group_blk; + } + + if (!fs->group_desc[group].bg_block_bitmap) + { + retval = ext2_get_free_blocks(fs, start_blk, last_blk, + 1, bmap, &new_blk); + + if (!retval) + retval = ext2_get_free_blocks(fs, group_blk, + last_blk, 1, bmap, &new_blk); + + if (!retval) + return retval; + + ext2_mark_block_bitmap(bmap, new_blk); + fs->group_desc[group].bg_block_bitmap = new_blk; + } + + if (!fs->group_desc[group].bg_inode_bitmap) + { + retval = ext2_get_free_blocks(fs, start_blk, last_blk, + 1, bmap, &new_blk); + if (!retval) + retval = ext2_get_free_blocks(fs, group_blk, + last_blk, 1, bmap, &new_blk); + if (!retval) + return retval; + + ext2_mark_block_bitmap(bmap, new_blk); + fs->group_desc[group].bg_inode_bitmap = new_blk; + } + + return true; +} + + +bool ext2_get_free_blocks(PEXT2_FILESYS fs, ULONG start, ULONG finish, + int num, PEXT2_BLOCK_BITMAP map, ULONG *ret) +{ + ULONG b = start; + + if (!map) + map = fs->block_map; + + if (!map) + return false; + + if (!b) + b = fs->ext2_sb->s_first_data_block; + + if (!finish) + finish = start; + + if (!num) + num = 1; + + do + { + if (b+num-1 > fs->ext2_sb->s_blocks_count) + b = fs->ext2_sb->s_first_data_block; + + if (ext2_test_block_bitmap_range(map, b, num)) + { + *ret = b; + return true; + } + + b++; + + } while (b != finish); + + return false; +} + + +bool write_inode_tables(PEXT2_FILESYS fs) +{ + bool retval; + ULONG blk, num; + int i; + + for (i = 0; (ULONG)i < fs->group_desc_count; i++) + { + blk = fs->group_desc[i].bg_inode_table; + num = fs->inode_blocks_per_group; + + retval = zero_blocks(fs, blk, num, &blk, &num); + if (!retval) + { + KdPrint(("\nMke2fs: Could not write %lu blocks " + "in inode table starting at %lu.\n", + num, blk)); + + zero_blocks(0, 0, 0, 0, 0); + return false; + } + } + + zero_blocks(0, 0, 0, 0, 0); + + return true; +} + + +/* + * Stupid algorithm --- we now just search forward starting from the + * goal. Should put in a smarter one someday.... + */ +bool ext2_new_block(PEXT2_FILESYS fs, ULONG goal, + PEXT2_BLOCK_BITMAP map, ULONG *ret) +{ + ULONG i; + + if (!map) + map = fs->block_map; + + if (!map) + return false; + + if (!goal || (goal >= fs->ext2_sb->s_blocks_count)) + goal = fs->ext2_sb->s_first_data_block; + + i = goal; + + do + { + if (!ext2_test_block_bitmap(map, i)) + { + *ret = i; + return true; + } + + i++; + + if (i >= fs->ext2_sb->s_blocks_count) + i = fs->ext2_sb->s_first_data_block; + + } while (i != goal); + + return false; +} + + +/* + * This function zeros out the allocated block, and updates all of the + * appropriate filesystem records. + */ +bool ext2_alloc_block(PEXT2_FILESYS fs, ULONG goal, ULONG *ret) +{ + bool retval; + ULONG block; + char *buf = NULL; + + buf = (char *)RtlAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, fs->blocksize); + if (!buf) + return false; + + if (!fs->block_map) + { + retval = ext2_read_block_bitmap(fs); + if (!retval) + goto fail; + } + + retval = ext2_new_block(fs, goal, 0, &block); + + if (!retval) + goto fail; + + retval = NT_SUCCESS(Ext2WriteDisk( + fs, + ((LONGLONG)block * fs->blocksize), + fs->blocksize, (unsigned char *)buf)); + + if (!retval) + { + goto fail; + } + + ext2_block_alloc_stats(fs, block, +1); + *ret = block; + + if (buf) + { + RtlFreeHeap(GetProcessHeap(), 0, buf); + } + + return true; + +fail: + + if (buf) + { + RtlFreeHeap(GetProcessHeap(), 0, buf); + } + + return false; +} + + +/* + * Create new directory block + */ +bool ext2_new_dir_block(PEXT2_FILESYS fs, ULONG dir_ino, + ULONG parent_ino, char **block) +{ + PEXT2_DIR_ENTRY dir = NULL; + char *buf; + int rec_len; + int filetype = 0; + + buf = (char *)RtlAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, fs->blocksize); + if (!buf) + return false; + + dir = (PEXT2_DIR_ENTRY) buf; + dir->rec_len = fs->blocksize; + + if (dir_ino) + { + if (fs->ext2_sb->s_feature_incompat & + EXT2_FEATURE_INCOMPAT_FILETYPE) + filetype = EXT2_FT_DIR << 8; + /* + * Set up entry for '.' + */ + dir->inode = dir_ino; + dir->name_len = 1 | filetype; + dir->name[0] = '.'; + rec_len = dir->rec_len - EXT2_DIR_REC_LEN(1); + dir->rec_len = EXT2_DIR_REC_LEN(1); + + /* + * Set up entry for '..' + */ + dir = (struct ext2_dir_entry *) (buf + dir->rec_len); + dir->rec_len = rec_len; + dir->inode = parent_ino; + dir->name_len = 2 | filetype; + dir->name[0] = '.'; + dir->name[1] = '.'; + } + + *block = buf; + + return true; +} + +bool ext2_write_block(PEXT2_FILESYS fs, ULONG block, void *inbuf) +{ + bool retval = false; + + retval = NT_SUCCESS(Ext2WriteDisk( + fs, + ((ULONGLONG)block * fs->blocksize), + fs->blocksize, (unsigned char *)inbuf)); + + return retval; +} + +bool ext2_read_block(PEXT2_FILESYS fs, ULONG block, void *inbuf) +{ + bool retval = false; + + retval = NT_SUCCESS(Ext2ReadDisk( + fs, + ((ULONGLONG)block * fs->blocksize), + fs->blocksize, (unsigned char *)inbuf)); + + return retval; +} diff --git a/reactos/lib/fslib/ext2lib/Mke2fs.c b/reactos/lib/fslib/ext2lib/Mke2fs.c new file mode 100644 index 00000000000..8608d275c20 --- /dev/null +++ b/reactos/lib/fslib/ext2lib/Mke2fs.c @@ -0,0 +1,1010 @@ +/* + * PROJECT: Mke2fs + * FILE: Disk.c + * PROGRAMMER: Matt Wu + * HOMEPAGE: http://ext2.yeah.net + */ + +/* INCLUDES **************************************************************/ + +#include "Mke2fs.h" +#include + +/* GLOBALS ***************************************************************/ + +int inode_ratio = 4096; + +BOOLEAN bLocked = FALSE; + +/* FUNCTIONS *************************************************************/ + +int int_log2(int arg) +{ + int l = 0; + + arg >>= 1; + + while (arg) + { + l++; + arg >>= 1; + } + + return l; +} + +int int_log10(unsigned int arg) +{ + int l; + + for (l=0; arg ; l++) + arg = arg / 10; + + return l; +} + + +static char default_str[] = "default"; + +struct mke2fs_defaults { + const char *type; + int size; + int blocksize; + int inode_ratio; +} settings[] = { + { default_str, 0, 4096, 8192 }, + { default_str, 512, 1024, 4096 }, + { default_str, 3, 1024, 8192 }, + { "journal", 0, 4096, 8192 }, + { "news", 0, 4096, 4096 }, + { "largefile", 0, 4096, 1024 * 1024 }, + { "largefile4", 0, 4096, 4096 * 1024 }, + { 0, 0, 0, 0}, +}; + +void set_fs_defaults(const char *fs_type, + PEXT2_SUPER_BLOCK super, + int blocksize, int *inode_ratio) +{ + int megs; + int ratio = 0; + struct mke2fs_defaults *p; + + megs = (super->s_blocks_count * (EXT2_BLOCK_SIZE(super) / 1024) / 1024); + + if (inode_ratio) + ratio = *inode_ratio; + + if (!fs_type) + fs_type = default_str; + + for (p = settings; p->type; p++) + { + if ((strcmp(p->type, fs_type) != 0) && + (strcmp(p->type, default_str) != 0)) + continue; + + if ((p->size != 0) && + (megs > p->size)) + continue; + + if (ratio == 0) + *inode_ratio = p->inode_ratio; + + if (blocksize == 0) + { + super->s_log_frag_size = super->s_log_block_size = + int_log2(p->blocksize >> EXT2_MIN_BLOCK_LOG_SIZE); + } + } + + if (blocksize == 0) + { + super->s_blocks_count /= EXT2_BLOCK_SIZE(super) / 1024; + } +} + +/* + * Helper function which zeros out _num_ blocks starting at _blk_. In + * case of an error, the details of the error is returned via _ret_blk_ + * and _ret_count_ if they are non-NULL pointers. Returns 0 on + * success, and an error code on an error. + * + * As a special case, if the first argument is NULL, then it will + * attempt to free the static zeroizing buffer. (This is to keep + * programs that check for memory leaks happy.) + */ +bool zero_blocks(PEXT2_FILESYS fs, ULONG blk, ULONG num, + ULONG *ret_blk, ULONG *ret_count) +{ + ULONG j, count, next_update, next_update_incr; + static unsigned char *buf; + bool retval; + + /* If fs is null, clean up the static buffer and return */ + if (!fs) + { + if (buf) + { + RtlFreeHeap(GetProcessHeap(), 0, buf); + buf = 0; + } + return true; + } + +#define STRIDE_LENGTH 8 + + /* Allocate the zeroizing buffer if necessary */ + if (!buf) + { + buf = (unsigned char *) + RtlAllocateHeap(GetProcessHeap(), 0, fs->blocksize * STRIDE_LENGTH); + if (!buf) + { + KdPrint(("Mke2fs: while allocating zeroizing buffer")); + return false; + } + memset(buf, 0, fs->blocksize * STRIDE_LENGTH); + } + + /* OK, do the write loop */ + next_update = 0; + next_update_incr = num / 100; + if (next_update_incr < 1) + next_update_incr = 1; + + for (j=0; j < num; j += STRIDE_LENGTH, blk += STRIDE_LENGTH) + { + if (num-j > STRIDE_LENGTH) + count = STRIDE_LENGTH; + else + count = num - j; + + retval = NT_SUCCESS(Ext2WriteDisk( + fs, + ((ULONGLONG)blk * fs->blocksize), + count * fs->blocksize, + buf)); + + if (!retval) + { + if (ret_count) + *ret_count = count; + + if (ret_blk) + *ret_blk = blk; + + return retval; + } + } + + return true; +} + + +bool zap_sector(PEXT2_FILESYS Ext2Sys, int sect, int nsect) +{ + unsigned char *buf; + ULONG *magic; + + buf = (unsigned char *) + RtlAllocateHeap(GetProcessHeap(), 0, SECTOR_SIZE*nsect); + if (!buf) + { + KdPrint(("Mke2fs: Out of memory erasing sectors %d-%d\n", + sect, sect + nsect - 1)); + return false; + } + + memset(buf, 0, (ULONG)nsect * SECTOR_SIZE); + +#define BSD_DISKMAGIC (0x82564557UL) /* The disk magic number */ +#define BSD_MAGICDISK (0x57455682UL) /* The disk magic number reversed */ +#define BSD_LABEL_OFFSET 64 + + if (sect == 0) + { + Ext2ReadDisk( + Ext2Sys, + (LONGLONG)(sect * SECTOR_SIZE), + SECTOR_SIZE, buf); + + // Check for a BSD disklabel, and don't erase it if so + magic = (ULONG *) (buf + BSD_LABEL_OFFSET); + if ((*magic == BSD_DISKMAGIC) || (*magic == BSD_MAGICDISK)) + goto clean_up; + } + + // Write buf to disk + Ext2WriteDisk( Ext2Sys, + (LONGLONG)(sect * SECTOR_SIZE), + (ULONG)nsect * SECTOR_SIZE, + buf ); + +clean_up: + + RtlFreeHeap(GetProcessHeap(), 0, buf); + + return true; +} + +bool ext2_mkdir( PEXT2_FILESYS fs, + ULONG parent, + ULONG inum, + char *name, + ULONG *no, + PEXT2_INODE pid ) +{ + bool retval; + EXT2_INODE parent_inode, inode; + ULONG ino = inum; + //ULONG scratch_ino; + ULONG blk; + char *block = 0; + int filetype = 0; + + LARGE_INTEGER SysTime; + + NtQuerySystemTime(&SysTime); + + /* + * Allocate an inode, if necessary + */ + if (!ino) + { + retval = ext2_new_inode(fs, parent, LINUX_S_IFDIR | 0755, 0, &ino); + if (!retval) + goto cleanup; + } + + if (no) + *no = ino; + + /* + * Allocate a data block for the directory + */ + retval = ext2_new_block(fs, 0, 0, &blk); + if (!retval) + goto cleanup; + + /* + * Create a scratch template for the directory + */ + retval = ext2_new_dir_block(fs, ino, parent, &block); + if (!retval) + goto cleanup; + + /* + * Get the parent's inode, if necessary + */ + if (parent != ino) + { + retval = ext2_load_inode(fs, parent, &parent_inode); + if (!retval) + goto cleanup; + } + else + { + memset(&parent_inode, 0, sizeof(parent_inode)); + } + + /* + * Create the inode structure.... + */ + memset(&inode, 0, sizeof(EXT2_INODE)); + inode.i_mode = (USHORT)(LINUX_S_IFDIR | (0777 & ~fs->umask)); + inode.i_uid = inode.i_gid = 0; + inode.i_blocks = fs->blocksize / 512; + inode.i_block[0] = blk; + inode.i_links_count = 2; + RtlTimeToSecondsSince1970(&SysTime, &inode.i_mtime); + inode.i_ctime = inode.i_atime = inode.i_mtime; + inode.i_size = fs->blocksize; + + /* + * Write out the inode and inode data block + */ + retval = ext2_write_block(fs, blk, block); + if (!retval) + goto cleanup; + + retval = ext2_save_inode(fs, ino, &inode); + if (!retval) + goto cleanup; + + if (pid) + { + *pid = inode; + } + + if (parent != ino) + { + /* + * Add entry for this inode to parent dir 's block + */ + + if (fs->ext2_sb->s_feature_incompat & EXT2_FEATURE_INCOMPAT_FILETYPE) + filetype = EXT2_FT_DIR; + + retval = ext2_add_entry(fs, parent, ino, filetype, name); + + if (!retval) + goto cleanup; + + /* + * Update parent inode's counts + */ + + parent_inode.i_links_count++; + retval = ext2_save_inode(fs, parent, &parent_inode); + if (!retval) + goto cleanup; + + } + + /* + * Update accounting.... + */ + ext2_block_alloc_stats(fs, blk, +1); + ext2_inode_alloc_stats2(fs, ino, +1, 1); + +cleanup: + + if (block) + { + RtlFreeHeap(GetProcessHeap(), 0, block); + block = NULL; + } + + return retval; +} + +bool create_root_dir(PEXT2_FILESYS fs) +{ + bool retval; + EXT2_INODE inode; + + retval = ext2_mkdir(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, 0, NULL, &inode); + + if (!retval) + { + KdPrint(("Mke2fs: while creating root dir")); + return false; + } + + { + inode.i_uid = 0; + inode.i_gid = 0; + + retval = ext2_save_inode(fs, EXT2_ROOT_INO, &inode); + if (!retval) + { + KdPrint(("Mke2fs: while setting root inode ownership")); + return false; + } + } + + return true; +} + +bool create_lost_and_found(PEXT2_FILESYS Ext2Sys) +{ + bool retval; + ULONG ino; + char *name = "lost+found"; + int lpf_size = 0; + EXT2_INODE inode; + ULONG dwBlk = 0; + BOOLEAN bExt= TRUE; + + PEXT2_DIR_ENTRY dir; + + char * buf; + + buf = (char *)RtlAllocateHeap(GetProcessHeap(), 0, Ext2Sys->blocksize); + if (!buf) + { + bExt = FALSE; + } + else + { + memset(buf, 0, Ext2Sys->blocksize); + + dir = (PEXT2_DIR_ENTRY) buf; + dir->rec_len = Ext2Sys->blocksize; + } + + Ext2Sys->umask = 077; + retval = ext2_mkdir(Ext2Sys, EXT2_ROOT_INO, 0, name, &ino, &inode); + + if (!retval) + { + KdPrint(("Mke2fs: while creating /lost+found.\n")); + return false; + } + + if (!bExt) + goto errorout; + + lpf_size = inode.i_size; + + while(TRUE) + { + if (lpf_size >= 16*1024) + break; + + retval = ext2_alloc_block(Ext2Sys, 0, &dwBlk); + + if (! retval) + { + KdPrint(("Mke2fs: create_lost_and_found: error alloc block.\n")); + break; + } + + retval = ext2_expand_inode(Ext2Sys, &inode, dwBlk); + if (!retval) + { + KdPrint(("Mke2fs: errors when expanding /lost+found.\n")); + break; + } + + ext2_write_block(Ext2Sys, dwBlk, buf); + + inode.i_blocks += (Ext2Sys->blocksize/SECTOR_SIZE); + lpf_size += Ext2Sys->blocksize; + } + + { + inode.i_size = lpf_size; + + ASSERT( (inode.i_size/Ext2Sys->blocksize) == + Ext2DataBlocks(Ext2Sys, inode.i_blocks/(Ext2Sys->blocksize/SECTOR_SIZE))); + + ASSERT( (inode.i_blocks/(Ext2Sys->blocksize/SECTOR_SIZE)) == + Ext2TotalBlocks(Ext2Sys, inode.i_size/Ext2Sys->blocksize)); + + } + + ext2_save_inode(Ext2Sys, ino, &inode); + +errorout: + + if (buf) + { + RtlFreeHeap(GetProcessHeap(), 0, buf); + } + + return true; +} + +/* + * This function forces out the primary superblock. We need to only + * write out those fields which we have changed, since if the + * filesystem is mounted, it may have changed some of the other + * fields. + * + * It takes as input a superblock which has already been byte swapped + * (if necessary). + */ + +bool write_primary_superblock(PEXT2_FILESYS Ext2Sys, PEXT2_SUPER_BLOCK super) +{ + bool bRet; + + bRet = NT_SUCCESS(Ext2WriteDisk( + Ext2Sys, + ((LONGLONG)SUPERBLOCK_OFFSET), + SUPERBLOCK_SIZE, (PUCHAR)super)); + + + + return bRet; +} + + +/* + * Updates the revision to EXT2_DYNAMIC_REV + */ +void ext2_update_dynamic_rev(PEXT2_FILESYS fs) +{ + PEXT2_SUPER_BLOCK sb = fs->ext2_sb; + + if (sb->s_rev_level > EXT2_GOOD_OLD_REV) + return; + + sb->s_rev_level = EXT2_DYNAMIC_REV; + sb->s_first_ino = EXT2_GOOD_OLD_FIRST_INO; + sb->s_inode_size = EXT2_GOOD_OLD_INODE_SIZE; + /* s_uuid is handled by e2fsck already */ + /* other fields should be left alone */ +} + + +bool ext2_flush(PEXT2_FILESYS fs) +{ + ULONG i,j,maxgroup,sgrp; + ULONG group_block; + bool retval; + char *group_ptr; + unsigned long fs_state; + PEXT2_SUPER_BLOCK super_shadow = 0; + PEXT2_GROUP_DESC group_shadow = 0; + + LARGE_INTEGER SysTime; + + NtQuerySystemTime(&SysTime); + + fs_state = fs->ext2_sb->s_state; + + RtlTimeToSecondsSince1970(&SysTime, &fs->ext2_sb->s_wtime); + fs->ext2_sb->s_block_group_nr = 0; + + super_shadow = fs->ext2_sb; + group_shadow = fs->group_desc; + + /* + * Write out master superblock. This has to be done + * separately, since it is located at a fixed location + * (SUPERBLOCK_OFFSET). + */ + retval = write_primary_superblock(fs, super_shadow); + if (!retval) + goto errout; + + /* + * If this is an external journal device, don't write out the + * block group descriptors or any of the backup superblocks + */ + if (fs->ext2_sb->s_feature_incompat & + EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) + { + retval = false; + goto errout; + } + + /* + * Set the state of the FS to be non-valid. (The state has + * already been backed up earlier, and will be restored when + * we exit.) + */ + fs->ext2_sb->s_state &= ~EXT2_VALID_FS; + + /* + * Write out the master group descriptors, and the backup + * superblocks and group descriptors. + */ + group_block = fs->ext2_sb->s_first_data_block; + maxgroup = fs->group_desc_count; + + for (i = 0; i < maxgroup; i++) + { + if (!ext2_bg_has_super(fs->ext2_sb, i)) + goto next_group; + + sgrp = i; + if (sgrp > ((1 << 16) - 1)) + sgrp = (1 << 16) - 1; + + fs->ext2_sb->s_block_group_nr = (USHORT) sgrp; + + if (i !=0 ) + { + retval = NT_SUCCESS(Ext2WriteDisk( + fs, + ((ULONGLONG)group_block * fs->blocksize), + SUPERBLOCK_SIZE, (PUCHAR)super_shadow)); + + if (!retval) + { + goto errout; + } + } + + group_ptr = (char *) group_shadow; + + for (j=0; j < fs->desc_blocks; j++) + { + + retval = NT_SUCCESS(Ext2WriteDisk( + fs, + ((ULONGLONG)(group_block+1+j) * fs->blocksize), + fs->blocksize, (PUCHAR) group_ptr)); + + if (!retval) + { + goto errout; + } + + group_ptr += fs->blocksize; + } + + next_group: + group_block += EXT2_BLOCKS_PER_GROUP(fs->ext2_sb); + + } + + fs->ext2_sb->s_block_group_nr = 0; + + /* + * If the write_bitmaps() function is present, call it to + * flush the bitmaps. This is done this way so that a simple + * program that doesn't mess with the bitmaps doesn't need to + * drag in the bitmaps.c code. + */ + retval = ext2_write_bitmaps(fs); + if (!retval) + goto errout; + + /* + * Flush the blocks out to disk + */ + + // retval = io_channel_flush(fs->io); + +errout: + + fs->ext2_sb->s_state = (USHORT) fs_state; + + return retval; +} + + +bool create_journal_dev(PEXT2_FILESYS fs) +{ + bool retval = false; + char *buf = NULL; + ULONG blk; + ULONG count; + + if (!retval) + { + KdPrint(("Mke2fs: ext2_create_journal_dev: while initializing journal superblock.\n")); + return false; + } + + KdPrint(("Mke2fs: Zeroing journal device: \n")); + + retval = zero_blocks(fs, 0, fs->ext2_sb->s_blocks_count, + &blk, &count); + + zero_blocks(0, 0, 0, 0, 0); + + if (!retval) + { + KdPrint(("Mke2fs: create_journal_dev: while zeroing journal device (block %lu, count %lu).\n", + blk, count)); + return false; + } + + retval = NT_SUCCESS(Ext2WriteDisk( + fs, + ((ULONGLONG)blk * (fs->ext2_sb->s_first_data_block+1)), + fs->blocksize, (unsigned char *)buf)); + + if (!retval) + { + KdPrint(("Mke2fs: create_journal_dev: while writing journal superblock.\n")); + return false; + } + + return true; +} + +#define BLOCK_BITS (Ext2Sys->ext2_sb->s_log_block_size + 10) + +ULONG +Ext2DataBlocks(PEXT2_FILESYS Ext2Sys, ULONG TotalBlocks) +{ + ULONG dwData[4] = {1, 1, 1, 1}; + ULONG dwMeta[4] = {0, 0, 0, 0}; + ULONG DataBlocks = 0; + ULONG i, j; + + if (TotalBlocks <= EXT2_NDIR_BLOCKS) + { + return TotalBlocks; + } + + TotalBlocks -= EXT2_NDIR_BLOCKS; + + for (i = 0; i < 4; i++) + { + dwData[i] = dwData[i] << ((BLOCK_BITS - 2) * i); + + if (i > 0) + { + dwMeta[i] = 1 + (dwMeta[i - 1] << (BLOCK_BITS - 2)); + } + } + + for( i=1; (i < 4) && (TotalBlocks > 0); i++) + { + if (TotalBlocks >= (dwData[i] + dwMeta[i])) + { + TotalBlocks -= (dwData[i] + dwMeta[i]); + DataBlocks += dwData[i]; + } + else + { + ULONG dwDivide = 0; + ULONG dwRemain = 0; + + for (j=i; (j > 0) && (TotalBlocks > 0); j--) + { + dwDivide = (TotalBlocks - 1) / (dwData[j-1] + dwMeta[j-1]); + dwRemain = (TotalBlocks - 1) % (dwData[j-1] + dwMeta[j-1]); + + DataBlocks += (dwDivide * dwData[j-1]); + TotalBlocks = dwRemain; + } + } + } + + return (DataBlocks + EXT2_NDIR_BLOCKS); +} + + +ULONG +Ext2TotalBlocks(PEXT2_FILESYS Ext2Sys, ULONG DataBlocks) +{ + ULONG dwData[4] = {1, 1, 1, 1}; + ULONG dwMeta[4] = {0, 0, 0, 0}; + ULONG TotalBlocks = 0; + ULONG i, j; + + if (DataBlocks <= EXT2_NDIR_BLOCKS) + { + return DataBlocks; + } + + DataBlocks -= EXT2_NDIR_BLOCKS; + + for (i = 0; i < 4; i++) + { + dwData[i] = dwData[i] << ((BLOCK_BITS - 2) * i); + + if (i > 0) + { + dwMeta[i] = 1 + (dwMeta[i - 1] << (BLOCK_BITS - 2)); + } + } + + for( i=1; (i < 4) && (DataBlocks > 0); i++) + { + if (DataBlocks >= dwData[i]) + { + DataBlocks -= dwData[i]; + TotalBlocks += (dwData[i] + dwMeta[i]); + } + else + { + ULONG dwDivide = 0; + ULONG dwRemain = 0; + + for (j=i; (j > 0) && (DataBlocks > 0); j--) + { + dwDivide = (DataBlocks) / (dwData[j-1]); + dwRemain = (DataBlocks) % (dwData[j-1]); + + TotalBlocks += (dwDivide * (dwData[j-1] + dwMeta[j-1]) + 1); + DataBlocks = dwRemain; + } + } + } + + return (TotalBlocks + EXT2_NDIR_BLOCKS); +} + + +NTSTATUS +Ext2Format(PUNICODE_STRING DriveRoot, + ULONG MediaFlag, + PUNICODE_STRING Label, + BOOLEAN QuickFormat, + ULONG ClusterSize, + PFMIFSCALLBACK Callback) +{ + BOOLEAN bRet = FALSE; + NTSTATUS Status = STATUS_UNSUCCESSFUL; + /* Super Block: 1024 bytes long */ + EXT2_SUPER_BLOCK Ext2Sb; + /* File Sys Structure */ + EXT2_FILESYS FileSys; + ULONG Percent; + + KdPrint(("%s:%d\n", __FILE__, __LINE__)); + + Callback(PROGRESS, 0, (PVOID)&Percent); + + KdPrint(("%s:%d\n", __FILE__, __LINE__)); + + RtlZeroMemory(&Ext2Sb, sizeof(EXT2_SUPER_BLOCK)); + RtlZeroMemory(&FileSys, sizeof(EXT2_FILESYS)); + FileSys.ext2_sb = &Ext2Sb; + + KdPrint(("%s:%d\n", __FILE__, __LINE__)); + + if (!NT_SUCCESS(Ext2OpenDevice(&FileSys, DriveRoot))) + { + KdPrint(("Mke2fs: Volume %wZ does not exist, ...\n", DriveRoot)); + goto clean_up; + } + + KdPrint(("%s:%d\n", __FILE__, __LINE__)); + + if (!NT_SUCCESS(Ext2GetMediaInfo(&FileSys))) + { + KdPrint(("Mke2fs: Can't get media information\n")); + goto clean_up; + } + + set_fs_defaults(NULL, &Ext2Sb, ClusterSize, &inode_ratio); + + Ext2Sb.s_blocks_count = FileSys.PartInfo.PartitionLength.QuadPart / + EXT2_BLOCK_SIZE(&Ext2Sb); + + KdPrint(("%s:%d\n", __FILE__, __LINE__)); + + /* + * Calculate number of inodes based on the inode ratio + */ + Ext2Sb.s_inodes_count = + (ULONG)(((LONGLONG) Ext2Sb.s_blocks_count * EXT2_BLOCK_SIZE(&Ext2Sb)) / inode_ratio); + + /* + * Calculate number of blocks to reserve + */ + Ext2Sb.s_r_blocks_count = (Ext2Sb.s_blocks_count * 5) / 100; + + KdPrint(("%s:%d\n", __FILE__, __LINE__)); + + Status = Ext2LockVolume(&FileSys); + if (NT_SUCCESS(Status)) + { + bLocked = TRUE; + } + + KdPrint(("%s:%d\n", __FILE__, __LINE__)); + + // Initialize + if (!ext2_initialize_sb(&FileSys)) + { + KdPrint(("Mke2fs: error...\n")); + goto clean_up; + } + + KdPrint(("%s:%d\n", __FILE__, __LINE__)); + + zap_sector(&FileSys, 2, 6); + + /* + * Generate a UUID for it... + */ + { + __u8 uuid[16]; + uuid_generate(&uuid[0]); + memcpy(&Ext2Sb.s_uuid[0], &uuid[0], 16); + } + + /* + * Add "jitter" to the superblock's check interval so that we + * don't check all the filesystems at the same time. We use a + * kludgy hack of using the UUID to derive a random jitter value. + */ + { + int i, val; + + for (i = 0, val = 0 ; i < sizeof(Ext2Sb.s_uuid); i++) + val += Ext2Sb.s_uuid[i]; + + Ext2Sb.s_max_mnt_count += val % EXT2_DFL_MAX_MNT_COUNT; + } + + /* + * Set the volume label... + */ + if (Label) + { + ANSI_STRING ansi_label; + ansi_label.MaximumLength = sizeof(Ext2Sb.s_volume_name); + ansi_label.Length = 0; + ansi_label.Buffer = Ext2Sb.s_volume_name; + RtlUnicodeStringToAnsiString(&ansi_label, Label, FALSE); + } + + ext2_print_super(&Ext2Sb); + + bRet = ext2_allocate_tables(&FileSys); + + if (!bRet) + { + goto clean_up; + } + + /* rsv must be a power of two (64kB is MD RAID sb alignment) */ + ULONG rsv = 65536 / FileSys.blocksize; + ULONG blocks = Ext2Sb.s_blocks_count; + ULONG start; + ULONG ret_blk; + +#ifdef ZAP_BOOTBLOCK + zap_sector(&FileSys, 0, 2); +#endif + + /* + * Wipe out any old MD RAID (or other) metadata at the end + * of the device. This will also verify that the device is + * as large as we think. Be careful with very small devices. + */ + + start = (blocks & ~(rsv - 1)); + if (start > rsv) + start -= rsv; + + if (start > 0) + bRet = zero_blocks(&FileSys, start, blocks - start, &ret_blk, NULL); + + if (!bRet) + { + KdPrint(("Mke2fs: zeroing block %lu at end of filesystem", ret_blk)); + goto clean_up; + } + + write_inode_tables(&FileSys); + + create_root_dir(&FileSys); + create_lost_and_found(&FileSys); + + ext2_reserve_inodes(&FileSys); + + create_bad_block_inode(&FileSys, NULL); + + KdPrint(("Mke2fs: Writing superblocks and filesystem accounting information ... \n")); + + if (!QuickFormat) + { + KdPrint(("Mke2fs: Slow format not supported yet\n")); + } + + if (!ext2_flush(&FileSys)) + { + bRet = false; + KdPrint(("Mke2fs: Warning, had trouble writing out superblocks.\n")); + goto clean_up; + } + + KdPrint(("Mke2fs: Writing superblocks and filesystem accounting information done!\n")); + + bRet = true; + Status = STATUS_SUCCESS; + +clean_up: + + // Clean up ... + ext2_free_group_desc(&FileSys); + + ext2_free_block_bitmap(&FileSys); + ext2_free_inode_bitmap(&FileSys); + + if (!bRet) + { + Ext2DisMountVolume(&FileSys); + } + else + { + if(bLocked) + { + Ext2UnLockVolume(&FileSys); + } + } + + KdPrint(("%s:%d\n", __FILE__, __LINE__)); + Ext2CloseDevice(&FileSys); + KdPrint(("%s:%d\n", __FILE__, __LINE__)); + + KdPrint(("%s:%d\n", __FILE__, __LINE__)); + Callback(DONE, 0, (PVOID)&bRet); + KdPrint(("%s:%d\n", __FILE__, __LINE__)); + + return Status; +} diff --git a/reactos/lib/fslib/ext2lib/Mke2fs.h b/reactos/lib/fslib/ext2lib/Mke2fs.h new file mode 100644 index 00000000000..a0353bd576c --- /dev/null +++ b/reactos/lib/fslib/ext2lib/Mke2fs.h @@ -0,0 +1,876 @@ +/* + * PROJECT: Mke2fs + * FILE: Mke2fs.h + * PROGRAMMER: Matt Wu + * HOMEPAGE: http://ext2.yeah.net + */ + +#ifndef __MKE2FS__INCLUDE__ +#define __MKE2FS__INCLUDE__ + + +/* INCLUDES **************************************************************/ + + +#include +#include +#include +#include + +#include + +#include "time.h" +#include "stdio.h" +#include "stdlib.h" +#include "string.h" +#include "ctype.h" + +#include "types.h" +#include "ext2_fs.h" + +#include "getopt.h" + +#define NTSYSAPI + +/* DEFINITIONS ***********************************************************/ + +#define SECTOR_SIZE (Ext2Sys->DiskGeometry.BytesPerSector) + +#ifndef GUID_DEFINED +#define GUID_DEFINED +typedef struct _GUID +{ + unsigned long Data1; + unsigned short Data2; + unsigned short Data3; + unsigned char Data4[8]; +} GUID; +#endif /* GUID_DEFINED */ + +#ifndef UUID_DEFINED +#define UUID_DEFINED +typedef GUID UUID; +#ifndef uuid_t +#define uuid_t UUID +#endif +#endif + +#ifndef bool +#define bool BOOLEAN +#endif + +#ifndef true +#define true TRUE +#endif + +#ifndef false +#define false FALSE +#endif + + +#define EXT2_CHECK_MAGIC(struct, code) \ + if ((struct)->magic != (code)) return (code) + +/* + * ext2fs_scan flags + */ +#define EXT2_SF_CHK_BADBLOCKS 0x0001 +#define EXT2_SF_BAD_INODE_BLK 0x0002 +#define EXT2_SF_BAD_EXTRA_BYTES 0x0004 +#define EXT2_SF_SKIP_MISSING_ITABLE 0x0008 + +/* + * ext2fs_check_if_mounted flags + */ +#define EXT2_MF_MOUNTED 1 +#define EXT2_MF_ISROOT 2 +#define EXT2_MF_READONLY 4 +#define EXT2_MF_SWAP 8 + +/* + * Ext2/linux mode flags. We define them here so that we don't need + * to depend on the OS's sys/stat.h, since we may be compiling on a + * non-Linux system. + */ + +#define LINUX_S_IFMT 00170000 +#define LINUX_S_IFSOCK 0140000 +#define LINUX_S_IFLNK 0120000 +#define LINUX_S_IFREG 0100000 +#define LINUX_S_IFBLK 0060000 +#define LINUX_S_IFDIR 0040000 +#define LINUX_S_IFCHR 0020000 +#define LINUX_S_IFIFO 0010000 +#define LINUX_S_ISUID 0004000 +#define LINUX_S_ISGID 0002000 +#define LINUX_S_ISVTX 0001000 + +#define LINUX_S_IRWXU 00700 +#define LINUX_S_IRUSR 00400 +#define LINUX_S_IWUSR 00200 +#define LINUX_S_IXUSR 00100 + +#define LINUX_S_IRWXG 00070 +#define LINUX_S_IRGRP 00040 +#define LINUX_S_IWGRP 00020 +#define LINUX_S_IXGRP 00010 + +#define LINUX_S_IRWXO 00007 +#define LINUX_S_IROTH 00004 +#define LINUX_S_IWOTH 00002 +#define LINUX_S_IXOTH 00001 + +#define LINUX_S_ISLNK(m) (((m) & LINUX_S_IFMT) == LINUX_S_IFLNK) +#define LINUX_S_ISREG(m) (((m) & LINUX_S_IFMT) == LINUX_S_IFREG) +#define LINUX_S_ISDIR(m) (((m) & LINUX_S_IFMT) == LINUX_S_IFDIR) +#define LINUX_S_ISCHR(m) (((m) & LINUX_S_IFMT) == LINUX_S_IFCHR) +#define LINUX_S_ISBLK(m) (((m) & LINUX_S_IFMT) == LINUX_S_IFBLK) +#define LINUX_S_ISFIFO(m) (((m) & LINUX_S_IFMT) == LINUX_S_IFIFO) +#define LINUX_S_ISSOCK(m) (((m) & LINUX_S_IFMT) == LINUX_S_IFSOCK) + + +#define EXT2_FIRST_INODE(s) EXT2_FIRST_INO(s) + +typedef struct _ext2fs_bitmap { + __u32 start, end; + __u32 real_end; + char* bitmap; +} EXT2_BITMAP, *PEXT2_BITMAP; + +typedef EXT2_BITMAP EXT2_GENERIC_BITMAP, *PEXT2_GENERIC_BITMAP; +typedef EXT2_BITMAP EXT2_INODE_BITMAP, *PEXT2_INODE_BITMAP; +typedef EXT2_BITMAP EXT2_BLOCK_BITMAP, *PEXT2_BLOCK_BITMAP; + +typedef struct ext2_acl_entry EXT2_ACL_ENTRY, *PEXT2_ACL_ENTRY; +typedef struct ext2_acl_header EXT2_ACL_HEADER, *PEXT2_ACL_HEADER; +typedef struct ext2_dir_entry EXT2_DIR_ENTRY, *PEXT2_DIR_ENTRY; +typedef struct ext2_dir_entry_2 EXT2_DIR_ENTRY2, *PEXT2_DIR_ENTRY2; +typedef struct ext2_dx_countlimit EXT2_DX_CL, *PEXT2_DX_CL; +typedef struct ext2_dx_entry EXT2_DX_ENTRY, *PEXT2_DX_ENTRY; +typedef struct ext2_dx_root_info EXT2_DX_RI, *PEXT2_DX_RI; +typedef struct ext2_inode EXT2_INODE, *PEXT2_INODE; +typedef struct ext2_group_desc EXT2_GROUP_DESC, *PEXT2_GROUP_DESC; +typedef struct ext2_super_block EXT2_SUPER_BLOCK, *PEXT2_SUPER_BLOCK; + +/* + * Badblocks list + */ +struct ext2_struct_badblocks_list { + int num; + int size; + ULONG *list; + int badblocks_flags; +}; + +typedef struct ext2_struct_badblocks_list EXT2_BADBLK_LIST, *PEXT2_BADBLK_LIST; + +typedef struct _ext2_filesys +{ + int flags; + int blocksize; + int fragsize; + ULONG group_desc_count; + unsigned long desc_blocks; + PEXT2_GROUP_DESC group_desc; + PEXT2_SUPER_BLOCK ext2_sb; + unsigned long inode_blocks_per_group; + PEXT2_INODE_BITMAP inode_map; + PEXT2_BLOCK_BITMAP block_map; + + EXT2_BADBLK_LIST badblocks; +/* + ext2_dblist dblist; +*/ + __u32 stride; /* for mke2fs */ + + __u32 umask; + + /* + * Reserved for future expansion + */ + __u32 reserved[8]; + + /* + * Reserved for the use of the calling application. + */ + void * priv_data; + + HANDLE MediaHandle; + + DISK_GEOMETRY DiskGeometry; + + PARTITION_INFORMATION PartInfo; + +} EXT2_FILESYS, *PEXT2_FILESYS; + +// Block Description List +typedef struct _EXT2_BDL { + LONGLONG Lba; + ULONG Offset; + ULONG Length; +} EXT2_BDL, *PEXT2_BDL; + +/* + * Where the master copy of the superblock is located, and how big + * superblocks are supposed to be. We define SUPERBLOCK_SIZE because + * the size of the superblock structure is not necessarily trustworthy + * (some versions have the padding set up so that the superblock is + * 1032 bytes long). + */ +#define SUPERBLOCK_OFFSET 1024 +#define SUPERBLOCK_SIZE 1024 + + +bool create_bad_block_inode(PEXT2_FILESYS fs, PEXT2_BADBLK_LIST bb_list); + + +// +// Definitions +// + +#define FSCTL_REQUEST_OPLOCK_LEVEL_1 CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_REQUEST_OPLOCK_LEVEL_2 CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 1, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_REQUEST_BATCH_OPLOCK CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 2, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_OPLOCK_BREAK_ACKNOWLEDGE CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 3, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_OPBATCH_ACK_CLOSE_PENDING CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 4, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_OPLOCK_BREAK_NOTIFY CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 5, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_LOCK_VOLUME CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 6, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_UNLOCK_VOLUME CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 7, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_DISMOUNT_VOLUME CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 8, METHOD_BUFFERED, FILE_ANY_ACCESS) +// decommissioned fsctl value 9 +#define FSCTL_IS_VOLUME_MOUNTED CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 10, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_IS_PATHNAME_VALID CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 11, METHOD_BUFFERED, FILE_ANY_ACCESS) // PATHNAME_BUFFER, +#define FSCTL_MARK_VOLUME_DIRTY CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 12, METHOD_BUFFERED, FILE_ANY_ACCESS) +// decommissioned fsctl value 13 +#define FSCTL_QUERY_RETRIEVAL_POINTERS CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 14, METHOD_NEITHER, FILE_ANY_ACCESS) +#define FSCTL_GET_COMPRESSION CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 15, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_SET_COMPRESSION CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 16, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA) +// decommissioned fsctl value 17 +// decommissioned fsctl value 18 +#define FSCTL_MARK_AS_SYSTEM_HIVE CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 19, METHOD_NEITHER, FILE_ANY_ACCESS) +#define FSCTL_OPLOCK_BREAK_ACK_NO_2 CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 20, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_INVALIDATE_VOLUMES CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 21, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_QUERY_FAT_BPB CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 22, METHOD_BUFFERED, FILE_ANY_ACCESS) // , FSCTL_QUERY_FAT_BPB_BUFFER +#define FSCTL_REQUEST_FILTER_OPLOCK CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 23, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_FILESYSTEM_GET_STATISTICS CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 24, METHOD_BUFFERED, FILE_ANY_ACCESS) // , FILESYSTEM_STATISTICS + + +// +// Disk I/O Routines +// + +NTSYSAPI +NTSTATUS +NTAPI +NtReadFile(HANDLE FileHandle, + HANDLE Event OPTIONAL, + PIO_APC_ROUTINE ApcRoutine OPTIONAL, + PVOID ApcContext OPTIONAL, + PIO_STATUS_BLOCK IoStatusBlock, + PVOID Buffer, + ULONG Length, + PLARGE_INTEGER ByteOffset OPTIONAL, + PULONG Key OPTIONAL); + +NTSYSAPI +NTSTATUS +NTAPI +NtWriteFile(HANDLE FileHandle, + HANDLE Event OPTIONAL, + PIO_APC_ROUTINE ApcRoutine OPTIONAL, + PVOID ApcContext OPTIONAL, + PIO_STATUS_BLOCK IoStatusBlock, + PVOID Buffer, + ULONG Length, + PLARGE_INTEGER ByteOffset OPTIONAL, + PULONG Key OPTIONAL); + +NTSYSAPI +NTSTATUS +NTAPI +NtClose(HANDLE Handle); + +NTSYSAPI +NTSTATUS +NTAPI +NtCreateFile(PHANDLE FileHandle, + ACCESS_MASK DesiredAccess, + POBJECT_ATTRIBUTES ObjectAttributes, + PIO_STATUS_BLOCK IoStatusBlock, + PLARGE_INTEGER AllocationSize OPTIONAL, + ULONG FileAttributes, + ULONG ShareAccess, + ULONG CreateDisposition, + ULONG CreateOptions, + PVOID EaBuffer OPTIONAL, + ULONG EaLength); + + +NTSYSAPI +NTSTATUS +NTAPI +NtDeviceIoControlFile( + IN HANDLE FileHandle, + IN HANDLE Event, + IN PIO_APC_ROUTINE ApcRoutine, + IN PVOID ApcContext, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN ULONG IoControlCode, + IN PVOID InputBuffer, + IN ULONG InputBufferLength, + OUT PVOID OutputBuffer, + OUT ULONG OutputBufferLength + ); + +NTSYSAPI +NTSTATUS +NTAPI +NtFsControlFile( + IN HANDLE FileHandle, + IN HANDLE Event OPTIONAL, + IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, + IN PVOID ApcContext OPTIONAL, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN ULONG FsControlCode, + IN PVOID InputBuffer OPTIONAL, + IN ULONG InputBufferLength, + OUT PVOID OutputBuffer OPTIONAL, + IN ULONG OutputBufferLength +); + + +NTSYSAPI +NTSTATUS +NTAPI +NtQueryInformationFile( + IN HANDLE FileHandle, + OUT PIO_STATUS_BLOCK IoStatusBlock, + OUT PVOID FileInformation, + IN ULONG Length, + IN FILE_INFORMATION_CLASS FileInformationClass + ); + +// +// Bitmap Routines +// + + +// +// BitMap routines. The following structure, routines, and macros are +// for manipulating bitmaps. The user is responsible for allocating a bitmap +// structure (which is really a header) and a buffer (which must be longword +// aligned and multiple longwords in size). +// + +// +// The following routine initializes a new bitmap. It does not alter the +// data currently in the bitmap. This routine must be called before +// any other bitmap routine/macro. +// + +NTSYSAPI +VOID +NTAPI +RtlInitializeBitMap ( + PRTL_BITMAP BitMapHeader, + PULONG BitMapBuffer, + ULONG SizeOfBitMap + ); + +// +// The following two routines either clear or set all of the bits +// in a bitmap. +// + +NTSYSAPI +VOID +NTAPI +RtlClearAllBits ( + PRTL_BITMAP BitMapHeader + ); + +NTSYSAPI +VOID +NTAPI +RtlSetAllBits ( + PRTL_BITMAP BitMapHeader + ); + +// +// The following two routines locate a contiguous region of either +// clear or set bits within the bitmap. The region will be at least +// as large as the number specified, and the search of the bitmap will +// begin at the specified hint index (which is a bit index within the +// bitmap, zero based). The return value is the bit index of the located +// region (zero based) or -1 (i.e., 0xffffffff) if such a region cannot +// be located +// + +NTSYSAPI +ULONG +NTAPI +RtlFindClearBits ( + PRTL_BITMAP BitMapHeader, + ULONG NumberToFind, + ULONG HintIndex + ); + +NTSYSAPI +ULONG +NTAPI +RtlFindSetBits ( + PRTL_BITMAP BitMapHeader, + ULONG NumberToFind, + ULONG HintIndex + ); + +// +// The following two routines locate a contiguous region of either +// clear or set bits within the bitmap and either set or clear the bits +// within the located region. The region will be as large as the number +// specified, and the search for the region will begin at the specified +// hint index (which is a bit index within the bitmap, zero based). The +// return value is the bit index of the located region (zero based) or +// -1 (i.e., 0xffffffff) if such a region cannot be located. If a region +// cannot be located then the setting/clearing of the bitmap is not performed. +// + +NTSYSAPI +ULONG +NTAPI +RtlFindClearBitsAndSet ( + PRTL_BITMAP BitMapHeader, + ULONG NumberToFind, + ULONG HintIndex + ); + +NTSYSAPI +ULONG +NTAPI +RtlFindSetBitsAndClear ( + PRTL_BITMAP BitMapHeader, + ULONG NumberToFind, + ULONG HintIndex + ); + +// +// The following two routines clear or set bits within a specified region +// of the bitmap. The starting index is zero based. +// + +NTSYSAPI +VOID +NTAPI +RtlClearBits ( + PRTL_BITMAP BitMapHeader, + ULONG StartingIndex, + ULONG NumberToClear + ); + +NTSYSAPI +VOID +NTAPI +RtlSetBits ( + PRTL_BITMAP BitMapHeader, + ULONG StartingIndex, + ULONG NumberToSet + ); + +// +// The following routine locates a set of contiguous regions of clear +// bits within the bitmap. The caller specifies whether to return the +// longest runs or just the first found lcoated. The following structure is +// used to denote a contiguous run of bits. The two routines return an array +// of this structure, one for each run located. +// + +NTSYSAPI +ULONG +NTAPI +RtlFindClearRuns ( + PRTL_BITMAP BitMapHeader, + PRTL_BITMAP_RUN RunArray, + ULONG SizeOfRunArray, + BOOLEAN LocateLongestRuns + ); +// +// The following routine locates the longest contiguous region of +// clear bits within the bitmap. The returned starting index value +// denotes the first contiguous region located satisfying our requirements +// The return value is the length (in bits) of the longest region found. +// + +NTSYSAPI +ULONG +NTAPI +RtlFindLongestRunClear ( + PRTL_BITMAP BitMapHeader, + PULONG StartingIndex + ); + +// +// The following routine locates the first contiguous region of +// clear bits within the bitmap. The returned starting index value +// denotes the first contiguous region located satisfying our requirements +// The return value is the length (in bits) of the region found. +// + +NTSYSAPI +ULONG +NTAPI +RtlFindFirstRunClear ( + PRTL_BITMAP BitMapHeader, + PULONG StartingIndex + ); + +// +// The following macro returns the value of the bit stored within the +// bitmap at the specified location. If the bit is set a value of 1 is +// returned otherwise a value of 0 is returned. +// +// ULONG +// RtlCheckBit ( +// PRTL_BITMAP BitMapHeader, +// ULONG BitPosition +// ); +// +// +// To implement CheckBit the macro retrieves the longword containing the +// bit in question, shifts the longword to get the bit in question into the +// low order bit position and masks out all other bits. +// + +#define RtlCheckBit(BMH,BP) ((((BMH)->Buffer[(BP) / 32]) >> ((BP) % 32)) & 0x1) + +// +// The following two procedures return to the caller the total number of +// clear or set bits within the specified bitmap. +// + +NTSYSAPI +ULONG +NTAPI +RtlNumberOfClearBits ( + PRTL_BITMAP BitMapHeader + ); + +NTSYSAPI +ULONG +NTAPI +RtlNumberOfSetBits ( + PRTL_BITMAP BitMapHeader + ); + +// +// The following two procedures return to the caller a boolean value +// indicating if the specified range of bits are all clear or set. +// + +NTSYSAPI +BOOLEAN +NTAPI +RtlAreBitsClear ( + PRTL_BITMAP BitMapHeader, + ULONG StartingIndex, + ULONG Length + ); + +NTSYSAPI +BOOLEAN +NTAPI +RtlAreBitsSet ( + PRTL_BITMAP BitMapHeader, + ULONG StartingIndex, + ULONG Length + ); + +NTSYSAPI +ULONG +NTAPI +RtlFindNextForwardRunClear ( + IN PRTL_BITMAP BitMapHeader, + IN ULONG FromIndex, + IN PULONG StartingRunIndex + ); + +NTSYSAPI +ULONG +NTAPI +RtlFindLastBackwardRunClear ( + IN PRTL_BITMAP BitMapHeader, + IN ULONG FromIndex, + IN PULONG StartingRunIndex + ); + +// +// The following two procedures return to the caller a value indicating +// the position within a ULONGLONG of the most or least significant non-zero +// bit. A value of zero results in a return value of -1. +// + +NTSYSAPI +CCHAR +NTAPI +RtlFindLeastSignificantBit ( + IN ULONGLONG Set + ); + +NTSYSAPI +CCHAR +NTAPI +RtlFindMostSignificantBit ( + IN ULONGLONG Set + ); + + +// +// Random routines ... +// + +NTSYSAPI +ULONG +NTAPI +RtlRandom( + IN OUT PULONG Seed + ); + +// +// Time routines ... +// + +NTSYSAPI +CCHAR +NTAPI +NtQuerySystemTime( + OUT PLARGE_INTEGER CurrentTime + ); + + +NTSYSAPI +BOOLEAN +NTAPI +RtlTimeToSecondsSince1970( + IN PLARGE_INTEGER Time, + OUT PULONG ElapsedSeconds + ); + + +NTSYSAPI +VOID +NTAPI +RtlSecondsSince1970ToTime( + IN ULONG ElapsedSeconds, + OUT PLARGE_INTEGER Time + ); + +// +// Heap routines... +// + +#define GetProcessHeap() (NtCurrentTeb()->Peb->ProcessHeap) + +PVOID STDCALL +RtlAllocateHeap ( + HANDLE Heap, + ULONG Flags, + ULONG Size + ); + +BOOLEAN +STDCALL +RtlFreeHeap ( + HANDLE Heap, + ULONG Flags, + PVOID Address + ); + +/* + * Bitmap.c + */ + +#define ext2_mark_block_bitmap ext2_mark_bitmap +#define ext2_mark_inode_bitmap ext2_mark_bitmap +#define ext2_unmark_block_bitmap ext2_unmark_bitmap +#define ext2_unmark_inode_bitmap ext2_unmark_bitmap + +bool ext2_set_bit(int nr, void * addr); +bool ext2_clear_bit(int nr, void * addr); +bool ext2_test_bit(int nr, void * addr); + +bool ext2_mark_bitmap(PEXT2_BITMAP bitmap, ULONG bitno); +bool ext2_unmark_bitmap(PEXT2_BITMAP bitmap, ULONG bitno); + +bool ext2_test_block_bitmap(PEXT2_BLOCK_BITMAP bitmap, + ULONG block); + +bool ext2_test_block_bitmap_range(PEXT2_BLOCK_BITMAP bitmap, + ULONG block, int num); + +bool ext2_test_inode_bitmap(PEXT2_BLOCK_BITMAP bitmap, + ULONG inode); + + +bool ext2_allocate_block_bitmap(PEXT2_FILESYS pExt2Sys); +bool ext2_allocate_inode_bitmap(PEXT2_FILESYS pExt2Sys); +void ext2_free_inode_bitmap(PEXT2_FILESYS pExt2Sys); +void ext2_free_block_bitmap(PEXT2_FILESYS pExt2Sys); + +bool ext2_write_block_bitmap (PEXT2_FILESYS fs); +bool ext2_write_inode_bitmap (PEXT2_FILESYS fs); + +bool ext2_write_bitmaps(PEXT2_FILESYS fs); + +//bool read_bitmaps(PEXT2_FILESYS fs, int do_inode, int do_block); +bool ext2_read_inode_bitmap (PEXT2_FILESYS fs); +bool ext2_read_block_bitmap(PEXT2_FILESYS fs); +bool ext2_read_bitmaps(PEXT2_FILESYS fs); + + +/* + * Disk.c + */ + +NTSTATUS +Ext2OpenDevice( PEXT2_FILESYS Ext2Sys, + PUNICODE_STRING DeviceName ); + +NTSTATUS +Ext2CloseDevice( PEXT2_FILESYS Ext2Sys); + +NTSTATUS +Ext2ReadDisk( PEXT2_FILESYS Ext2Sys, + ULONGLONG Offset, + ULONG Length, + PVOID Buffer ); + +NTSTATUS +Ext2WriteDisk( PEXT2_FILESYS Ext2Sys, + ULONGLONG Offset, + ULONG Length, + PVOID Buffer ); + +NTSTATUS +Ext2GetMediaInfo( PEXT2_FILESYS Ext2Sys ); + + +NTSTATUS +Ext2LockVolume( PEXT2_FILESYS Ext2Sys ); + +NTSTATUS +Ext2UnLockVolume( PEXT2_FILESYS Ext2Sys ); + +NTSTATUS +Ext2DisMountVolume( PEXT2_FILESYS Ext2Sys ); + + +/* + * Group.c + */ + +bool ext2_allocate_group_desc(PEXT2_FILESYS pExt2Sys); +void ext2_free_group_desc(PEXT2_FILESYS pExt2Sys); +bool ext2_bg_has_super(PEXT2_SUPER_BLOCK pExt2Sb, int group_block); + +/* + * Inode.c + */ + +bool ext2_get_inode_lba(PEXT2_FILESYS pExt2Sys, ULONG no, LONGLONG *offset); +bool ext2_load_inode(PEXT2_FILESYS pExt2Sys, ULONG no, PEXT2_INODE pInode); +bool ext2_save_inode(PEXT2_FILESYS pExt2Sys, ULONG no, PEXT2_INODE pInode); +bool ext2_new_inode(PEXT2_FILESYS fs, ULONG dir, int mode, + PEXT2_INODE_BITMAP map, ULONG *ret); +bool ext2_expand_inode(PEXT2_FILESYS pExt2Sys, PEXT2_INODE, ULONG newBlk); + +bool ext2_read_inode (PEXT2_FILESYS pExt2Sys, + ULONG ino, + ULONG offset, + PVOID Buffer, + ULONG size, + PULONG dwReturn ); +bool ext2_write_inode (PEXT2_FILESYS pExt2Sys, + ULONG ino, + ULONG offset, + PVOID Buffer, + ULONG size, + PULONG dwReturn ); + +bool ext2_add_entry(PEXT2_FILESYS pExt2Sys, ULONG parent, ULONG inode, int filetype, char *name); +bool ext2_reserve_inodes(PEXT2_FILESYS fs); +/* + * Memory.c + */ + +// +// Return the group # of an inode number +// +int ext2_group_of_ino(PEXT2_FILESYS fs, ULONG ino); + +// +// Return the group # of a block +// +int ext2_group_of_blk(PEXT2_FILESYS fs, ULONG blk); + +/* + * Badblock.c + */ + + +void ext2_inode_alloc_stats2(PEXT2_FILESYS fs, ULONG ino, int inuse, int isdir); +void ext2_inode_alloc_stats(PEXT2_FILESYS fs, ULONG ino, int inuse); +void ext2_block_alloc_stats(PEXT2_FILESYS fs, ULONG blk, int inuse); + +bool ext2_allocate_tables(PEXT2_FILESYS pExt2Sys); +bool ext2_allocate_group_table(PEXT2_FILESYS fs, ULONG group, + PEXT2_BLOCK_BITMAP bmap); +bool ext2_get_free_blocks(PEXT2_FILESYS fs, ULONG start, ULONG finish, + int num, PEXT2_BLOCK_BITMAP map, ULONG *ret); +bool write_inode_tables(PEXT2_FILESYS fs); + +bool ext2_new_block(PEXT2_FILESYS fs, ULONG goal, + PEXT2_BLOCK_BITMAP map, ULONG *ret); +bool ext2_alloc_block(PEXT2_FILESYS fs, ULONG goal, ULONG *ret); +bool ext2_new_dir_block(PEXT2_FILESYS fs, ULONG dir_ino, + ULONG parent_ino, char **block); +bool ext2_write_block(PEXT2_FILESYS fs, ULONG block, void *inbuf); +bool ext2_read_block(PEXT2_FILESYS fs, ULONG block, void *inbuf); + +/* + * Mke2fs.c + */ + +bool parase_cmd(int argc, char *argv[], PEXT2_FILESYS pExt2Sys); + +bool zero_blocks(PEXT2_FILESYS fs, ULONG blk, ULONG num, + ULONG *ret_blk, ULONG *ret_count); + +ULONG +Ext2DataBlocks(PEXT2_FILESYS Ext2Sys, ULONG TotalBlocks); + +ULONG +Ext2TotalBlocks(PEXT2_FILESYS Ext2Sys, ULONG DataBlocks); + + + +/* + * Super.c + */ + +void ext2_print_super(PEXT2_SUPER_BLOCK pExt2Sb); +bool ext2_initialize_sb(PEXT2_FILESYS pExt2Sys); + + +/* + * Super.c + */ + +LONGLONG ext2_nt_time (ULONG i_time); +ULONG ext2_unix_time (LONGLONG n_time); + +/* + * Uuid.c + */ + +void uuid_generate(__u8 * uuid); + +#endif //__MKE2FS__INCLUDE__ diff --git a/reactos/lib/fslib/ext2lib/Super.c b/reactos/lib/fslib/ext2lib/Super.c new file mode 100644 index 00000000000..8d0b36e69de --- /dev/null +++ b/reactos/lib/fslib/ext2lib/Super.c @@ -0,0 +1,302 @@ +/* + * PROJECT: Mke2fs + * FILE: Super.c + * PROGRAMMER: Matt Wu + * HOMEPAGE: http://ext2.yeah.net + */ + +/* INCLUDES **************************************************************/ + +#include "Mke2fs.h" + +/* DEFINITIONS ***********************************************************/ + +extern int inode_ratio; + + +/* FUNCTIONS *************************************************************/ + +void ext2_print_super(PEXT2_SUPER_BLOCK pExt2Sb) +{ + int i; + + KdPrint(("\nExt2 Super Block Details ...\n\n")); + KdPrint((" Inode Count: %lu\n", pExt2Sb->s_inodes_count)); + KdPrint((" Block Count: %lu\n", pExt2Sb->s_blocks_count)); + KdPrint((" Reserved Block Count: %lu\n", pExt2Sb->s_r_blocks_count)); + KdPrint((" Free Blocks: %lu\n", pExt2Sb->s_free_blocks_count)); + KdPrint((" Free Inodes: %lu\n", pExt2Sb->s_free_inodes_count)); + KdPrint((" First Data Block: %lu\n", pExt2Sb->s_first_data_block)); + KdPrint((" Log Block Size: %lu\n", pExt2Sb->s_log_block_size)); + KdPrint((" Log Frag Size: %ld\n", pExt2Sb->s_log_frag_size)); + KdPrint((" Blocks per Group: %lu\n", pExt2Sb->s_blocks_per_group)); + KdPrint((" Fragments per Group: %lu\n", pExt2Sb->s_frags_per_group)); + KdPrint((" Inodes per Group: %lu\n", pExt2Sb->s_inodes_per_group)); +// KdPrint((" Mount Time: %s", ctime((time_t *) & (pExt2Sb->s_mtime)))); +// KdPrint((" Write Time: %s", ctime((time_t *) & (pExt2Sb->s_wtime)))); + KdPrint((" Mount Count: %u\n", pExt2Sb->s_mnt_count)); + KdPrint((" Max Mount Count: %d\n", pExt2Sb->s_max_mnt_count)); + KdPrint((" Magic Number: %X (%s)\n", pExt2Sb->s_magic, + pExt2Sb->s_magic == EXT2_SUPER_MAGIC ? "OK" : "BAD")); + KdPrint((" File System State: %X\n", pExt2Sb->s_state)); + KdPrint((" Error Behaviour: %X\n", pExt2Sb->s_errors)); + KdPrint((" Minor rev: %u\n", pExt2Sb->s_minor_rev_level)); +// KdPrint((" Last Check: %s", ctime((time_t *) & (pExt2Sb->s_lastcheck)))); + KdPrint((" Check Interval: %lu\n", pExt2Sb->s_checkinterval)); + KdPrint((" Creator OS: %lu\n", pExt2Sb->s_creator_os)); + KdPrint((" Revision Level: %lu\n", pExt2Sb->s_rev_level)); + KdPrint((" Reserved Block Default UID: %u\n", pExt2Sb->s_def_resuid)); + KdPrint((" Reserved Block Default GID: %u\n", pExt2Sb->s_def_resgid)); + KdPrint((" uuid = ")); + for (i=0; i < 16; i++) + KdPrint(("%x ", pExt2Sb->s_uuid[i])); + KdPrint(("\n")); + + KdPrint((" volume label name: ")); + for (i=0; i < 16; i++) + { + if (pExt2Sb->s_volume_name[i] == 0) + break; + KdPrint(("%c", pExt2Sb->s_volume_name[i])); + } + KdPrint(("\n")); + + KdPrint(("\n\n")); +} + + +#define set_field(field, default) if (!pExt2Sb->field) pExt2Sb->field = (default); + +/* + * Initialize super block ... + */ + +bool ext2_initialize_sb(PEXT2_FILESYS Ext2Sys) +{ + int frags_per_block = 0; + ULONG overhead = 0; + int rem = 0; + ULONG i = 0; + ULONG group_block = 0; + ULONG numblocks = 0; + PEXT2_SUPER_BLOCK pExt2Sb = Ext2Sys->ext2_sb; + LARGE_INTEGER SysTime; + + NtQuerySystemTime(&SysTime); + + Ext2Sys->blocksize = EXT2_BLOCK_SIZE(pExt2Sb); + Ext2Sys->fragsize = EXT2_FRAG_SIZE(pExt2Sb); + frags_per_block = Ext2Sys->blocksize / Ext2Sys->fragsize; + + pExt2Sb->s_magic = EXT2_SUPER_MAGIC; + pExt2Sb->s_state = EXT2_VALID_FS; + + pExt2Sb->s_first_data_block = (pExt2Sb->s_log_block_size) ? 0 : 1; + pExt2Sb->s_max_mnt_count = EXT2_DFL_MAX_MNT_COUNT; + + pExt2Sb->s_errors = EXT2_ERRORS_DEFAULT; + + pExt2Sb->s_checkinterval = EXT2_DFL_CHECKINTERVAL; + + if (!pExt2Sb->s_rev_level) + pExt2Sb->s_rev_level = EXT2_GOOD_OLD_REV; + + if (pExt2Sb->s_rev_level >= EXT2_DYNAMIC_REV) + { + set_field(s_first_ino, EXT2_GOOD_OLD_FIRST_INO); + set_field(s_inode_size, EXT2_GOOD_OLD_INODE_SIZE); + } + + RtlTimeToSecondsSince1970(&SysTime, &pExt2Sb->s_wtime); + pExt2Sb->s_lastcheck = pExt2Sb->s_mtime = pExt2Sb->s_wtime; + + if (!pExt2Sb->s_blocks_per_group) + pExt2Sb->s_blocks_per_group = Ext2Sys->blocksize * 8; + + pExt2Sb->s_frags_per_group = pExt2Sb->s_blocks_per_group * frags_per_block; + pExt2Sb->s_creator_os = EXT2_OS_WINNT; + + if (pExt2Sb->s_r_blocks_count >= pExt2Sb->s_blocks_count) + { + goto cleanup; + } + + /* + * If we're creating an external journal device, we don't need + * to bother with the rest. + */ + if (pExt2Sb->s_feature_incompat & + EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) + { + Ext2Sys->group_desc_count = 0; + // ext2fs_mark_super_dirty(fs); + return true; + } + +retry: + + Ext2Sys->group_desc_count = (pExt2Sb->s_blocks_count - pExt2Sb->s_first_data_block + + EXT2_BLOCKS_PER_GROUP(pExt2Sb) - 1) / EXT2_BLOCKS_PER_GROUP(pExt2Sb); + + if (Ext2Sys->group_desc_count == 0) + return false; + + Ext2Sys->desc_blocks = (Ext2Sys->group_desc_count + EXT2_DESC_PER_BLOCK(pExt2Sb) + - 1) / EXT2_DESC_PER_BLOCK(pExt2Sb); + + if (!pExt2Sb->s_inodes_count) + pExt2Sb->s_inodes_count = pExt2Sb->s_blocks_count / ( inode_ratio /Ext2Sys->blocksize); + + /* + * Make sure we have at least EXT2_FIRST_INO + 1 inodes, so + * that we have enough inodes for the filesystem(!) + */ + if (pExt2Sb->s_inodes_count < EXT2_FIRST_INODE(pExt2Sb)+1) + pExt2Sb->s_inodes_count = EXT2_FIRST_INODE(pExt2Sb)+1; + + /* + * There should be at least as many inodes as the user + * requested. Figure out how many inodes per group that + * should be. But make sure that we don't allocate more than + * one bitmap's worth of inodes + */ + pExt2Sb->s_inodes_per_group = (pExt2Sb->s_inodes_count + Ext2Sys->group_desc_count - 1) + /Ext2Sys->group_desc_count; + + if (pExt2Sb->s_inodes_per_group > (ULONG)(Ext2Sys->blocksize*8)) + pExt2Sb->s_inodes_per_group = Ext2Sys->blocksize*8; + + /* + * Make sure the number of inodes per group completely fills + * the inode table blocks in the descriptor. If not, add some + * additional inodes/group. Waste not, want not... + */ + Ext2Sys->inode_blocks_per_group = (((pExt2Sb->s_inodes_per_group * EXT2_INODE_SIZE(pExt2Sb)) + + EXT2_BLOCK_SIZE(pExt2Sb) - 1) / EXT2_BLOCK_SIZE(pExt2Sb)); + + pExt2Sb->s_inodes_per_group = ((Ext2Sys->inode_blocks_per_group * EXT2_BLOCK_SIZE(pExt2Sb)) + / EXT2_INODE_SIZE(pExt2Sb)); + + /* + * Finally, make sure the number of inodes per group is a + * multiple of 8. This is needed to simplify the bitmap + * splicing code. + */ + pExt2Sb->s_inodes_per_group &= ~7; + Ext2Sys->inode_blocks_per_group = (((pExt2Sb->s_inodes_per_group * EXT2_INODE_SIZE(pExt2Sb)) + + EXT2_BLOCK_SIZE(pExt2Sb) - 1) / EXT2_BLOCK_SIZE(pExt2Sb)); + + /* + * adjust inode count to reflect the adjusted inodes_per_group + */ + pExt2Sb->s_inodes_count = pExt2Sb->s_inodes_per_group * Ext2Sys->group_desc_count; + pExt2Sb->s_free_inodes_count = pExt2Sb->s_inodes_count; + + /* + * Overhead is the number of bookkeeping blocks per group. It + * includes the superblock backup, the group descriptor + * backups, the inode bitmap, the block bitmap, and the inode + * table. + * + * XXX Not all block groups need the descriptor blocks, but + * being clever is tricky... + */ + overhead = (int) (3 + Ext2Sys->desc_blocks + Ext2Sys->inode_blocks_per_group); + + /* + * See if the last group is big enough to support the + * necessary data structures. If not, we need to get rid of + * it. + */ + rem = (int) ((pExt2Sb->s_blocks_count - pExt2Sb->s_first_data_block) % + pExt2Sb->s_blocks_per_group); + + if ((Ext2Sys->group_desc_count == 1) && rem && (rem < overhead)) + return false; + + if (rem && (rem < overhead+50)) + { + pExt2Sb->s_blocks_count -= rem; + goto retry; + } + + /* + * At this point we know how big the filesystem will be. So we can do + * any and all allocations that depend on the block count. + */ + + // Allocate block bitmap + if(!ext2_allocate_block_bitmap(Ext2Sys)) + { + goto cleanup; + } + + // Allocate inode bitmap + if(!ext2_allocate_inode_bitmap(Ext2Sys)) + { + goto cleanup; + } + + // Allocate gourp desc + if(!ext2_allocate_group_desc(Ext2Sys)) + { + goto cleanup; + } + + /* + * Reserve the superblock and group descriptors for each + * group, and fill in the correct group statistics for group. + * Note that although the block bitmap, inode bitmap, and + * inode table have not been allocated (and in fact won't be + * by this routine), they are accounted for nevertheless. + */ + group_block = pExt2Sb->s_first_data_block; + numblocks = 0; + + pExt2Sb->s_free_blocks_count = 0; + + for (i = 0; i < Ext2Sys->group_desc_count; i++) + { + if (i == Ext2Sys->group_desc_count-1) + { + numblocks = (pExt2Sb->s_blocks_count - pExt2Sb->s_first_data_block) + % pExt2Sb->s_blocks_per_group; + + if (!numblocks) + numblocks = pExt2Sb->s_blocks_per_group; + } + else + { + numblocks = pExt2Sb->s_blocks_per_group; + } + + if (ext2_bg_has_super(pExt2Sb, i)) + { + ULONG j; + + for (j=0; j < Ext2Sys->desc_blocks+1; j++) + ext2_mark_bitmap(Ext2Sys->block_map, group_block + j); + + numblocks -= 1 + Ext2Sys->desc_blocks; + } + + numblocks -= 2 + Ext2Sys->inode_blocks_per_group; + + pExt2Sb->s_free_blocks_count += numblocks; + Ext2Sys->group_desc[i].bg_free_blocks_count = (__u16)numblocks; + Ext2Sys->group_desc[i].bg_free_inodes_count = (__u16)pExt2Sb->s_inodes_per_group; + Ext2Sys->group_desc[i].bg_used_dirs_count = 0; + + group_block += pExt2Sb->s_blocks_per_group; + } + + return true; + +cleanup: + + ext2_free_group_desc(Ext2Sys); + ext2_free_block_bitmap(Ext2Sys); + ext2_free_inode_bitmap(Ext2Sys); + + return false; +} diff --git a/reactos/lib/fslib/ext2lib/Uuid.c b/reactos/lib/fslib/ext2lib/Uuid.c new file mode 100644 index 00000000000..1e029da18db --- /dev/null +++ b/reactos/lib/fslib/ext2lib/Uuid.c @@ -0,0 +1,25 @@ +/* + * PROJECT: Mke2fs + * FILE: Timer.c + * PROGRAMMER: Matt Wu + * HOMEPAGE: http://ext2.yeah.net + */ + +/* INCLUDES **************************************************************/ + +#include "windows.h" +#include "types.h" + +/* DEFINITIONS ***********************************************************/ + + +/* FUNCTIONS *************************************************************/ + +void uuid_generate(__u8 * uuid) +{ +#if 0 + UuidCreate((UUID *) uuid); +#else + RtlZeroMemory(uuid, 16); +#endif +} diff --git a/reactos/lib/fslib/ext2lib/ext2_fs.h b/reactos/lib/fslib/ext2lib/ext2_fs.h new file mode 100644 index 00000000000..05ab2d84420 --- /dev/null +++ b/reactos/lib/fslib/ext2lib/ext2_fs.h @@ -0,0 +1,657 @@ +/* + * linux/include/linux/ext2_fs.h + * + * Copyright (C) 1992, 1993, 1994, 1995 + * Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * from + * + * linux/include/linux/minix_fs.h + * + * Copyright f(C) 1991, 1992 Linus Torvalds + */ + +#ifndef _LINUX_EXT2_FS_H +#define _LINUX_EXT2_FS_H + +#include "types.h" /* Changed from linux/types.h */ + +/* + * The second extended filesystem constants/structures + */ + +/* + * Define EXT2FS_DEBUG to produce debug messages + */ +#undef EXT2FS_DEBUG + +/* + * Define EXT2_PREALLOCATE to preallocate data blocks for expanding files + */ +#define EXT2_PREALLOCATE +#define EXT2_DEFAULT_PREALLOC_BLOCKS 8 + +/* + * The second extended file system version + */ +#define EXT2FS_DATE "95/08/09" +#define EXT2FS_VERSION "0.5b" + +/* + * Special inodes numbers + */ +#define EXT2_BAD_INO 1 /* Bad blocks inode */ +#define EXT2_ROOT_INO 2 /* Root inode */ +#define EXT2_ACL_IDX_INO 3 /* ACL inode */ +#define EXT2_ACL_DATA_INO 4 /* ACL inode */ +#define EXT2_BOOT_LOADER_INO 5 /* Boot loader inode */ +#define EXT2_UNDEL_DIR_INO 6 /* Undelete directory inode */ +#define EXT2_RESIZE_INO 7 /* Reserved group descriptors inode */ +#define EXT2_JOURNAL_INO 8 /* Journal inode */ + +/* First non-reserved inode for old ext2 filesystems */ +#define EXT2_GOOD_OLD_FIRST_INO 11 + +/* + * The second extended file system magic number + */ +#define EXT2_SUPER_MAGIC 0xEF53 + +/* + * Maximal count of links to a file + */ +#define EXT2_LINK_MAX 32000 + +/* + * Macro-instructions used to manage several block sizes + */ +#define EXT2_MIN_BLOCK_SIZE 1024 +#define EXT2_MAX_BLOCK_SIZE 4096 +#define EXT2_MIN_BLOCK_LOG_SIZE 10 +#ifdef __KERNEL__ +# define EXT2_BLOCK_SIZE(s) ((s)->s_blocksize) +#else +# define EXT2_BLOCK_SIZE(s) (EXT2_MIN_BLOCK_SIZE << (s)->s_log_block_size) +#endif +#define EXT2_ACLE_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_acl_entry)) +#define EXT2_ADDR_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (__u32)) +#ifdef __KERNEL__ +# define EXT2_BLOCK_SIZE_BITS(s) ((s)->s_blocksize_bits) +#else +# define EXT2_BLOCK_SIZE_BITS(s) ((s)->s_log_block_size + 10) +#endif +#ifdef __KERNEL__ +#define EXT2_ADDR_PER_BLOCK_BITS(s) ((s)->u.ext2_sb.s_addr_per_block_bits) +#define EXT2_INODE_SIZE(s) ((s)->u.ext2_sb.s_inode_size) +#define EXT2_FIRST_INO(s) ((s)->u.ext2_sb.s_first_ino) +#else +#define EXT2_INODE_SIZE(s) (((s)->s_rev_level == EXT2_GOOD_OLD_REV) ? \ + EXT2_GOOD_OLD_INODE_SIZE : \ + (s)->s_inode_size) +#define EXT2_FIRST_INO(s) (((s)->s_rev_level == EXT2_GOOD_OLD_REV) ? \ + EXT2_GOOD_OLD_FIRST_INO : \ + (s)->s_first_ino) +#endif + +/* + * Macro-instructions used to manage fragments + */ +#define EXT2_MIN_FRAG_SIZE 1024 +#define EXT2_MAX_FRAG_SIZE 4096 +#define EXT2_MIN_FRAG_LOG_SIZE 10 +#ifdef __KERNEL__ +# define EXT2_FRAG_SIZE(s) ((s)->u.ext2_sb.s_frag_size) +# define EXT2_FRAGS_PER_BLOCK(s) ((s)->u.ext2_sb.s_frags_per_block) +#else +# define EXT2_FRAG_SIZE(s) (EXT2_MIN_FRAG_SIZE << (s)->s_log_frag_size) +# define EXT2_FRAGS_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / EXT2_FRAG_SIZE(s)) +#endif + +/* + * ACL structures + */ +struct ext2_acl_header /* Header of Access Control Lists */ +{ + __u32 aclh_size; + __u32 aclh_file_count; + __u32 aclh_acle_count; + __u32 aclh_first_acle; +}; + +struct ext2_acl_entry /* Access Control List Entry */ +{ + __u32 acle_size; + __u16 acle_perms; /* Access permissions */ + __u16 acle_type; /* Type of entry */ + __u16 acle_tag; /* User or group identity */ + __u16 acle_pad1; + __u32 acle_next; /* Pointer on next entry for the */ + /* same inode or on next free entry */ +}; + +/* + * Structure of a blocks group descriptor + */ +struct ext2_group_desc +{ + __u32 bg_block_bitmap; /* Blocks bitmap block */ + __u32 bg_inode_bitmap; /* Inodes bitmap block */ + __u32 bg_inode_table; /* Inodes table block */ + __u16 bg_free_blocks_count; /* Free blocks count */ + __u16 bg_free_inodes_count; /* Free inodes count */ + __u16 bg_used_dirs_count; /* Directories count */ + __u16 bg_pad; + __u32 bg_reserved[3]; +}; + +/* + * Data structures used by the directory indexing feature + * + * Note: all of the multibyte integer fields are little endian. + */ + +/* + * Note: dx_root_info is laid out so that if it should somehow get + * overlaid by a dirent the two low bits of the hash version will be + * zero. Therefore, the hash version mod 4 should never be 0. + * Sincerely, the paranoia department. + */ +struct ext2_dx_root_info { + __u32 reserved_zero; + __u8 hash_version; /* 0 now, 1 at release */ + __u8 info_length; /* 8 */ + __u8 indirect_levels; + __u8 unused_flags; +}; + +struct ext2_dx_entry { + __u32 hash; + __u32 block; +}; + +struct ext2_dx_countlimit { + __u16 limit; + __u16 count; +}; + + +/* + * Macro-instructions used to manage group descriptors + */ +#ifdef __KERNEL__ +# define EXT2_BLOCKS_PER_GROUP(s) ((s)->u.ext2_sb.s_blocks_per_group) +# define EXT2_DESC_PER_BLOCK(s) ((s)->u.ext2_sb.s_desc_per_block) +# define EXT2_INODES_PER_GROUP(s) ((s)->u.ext2_sb.s_inodes_per_group) +# define EXT2_DESC_PER_BLOCK_BITS(s) ((s)->u.ext2_sb.s_desc_per_block_bits) +#else +# define EXT2_BLOCKS_PER_GROUP(s) ((s)->s_blocks_per_group) +# define EXT2_DESC_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_group_desc)) +# define EXT2_INODES_PER_GROUP(s) ((s)->s_inodes_per_group) +#endif + +/* + * Constants relative to the data blocks + */ +#define EXT2_NDIR_BLOCKS 12 +#define EXT2_IND_BLOCK EXT2_NDIR_BLOCKS +#define EXT2_DIND_BLOCK (EXT2_IND_BLOCK + 1) +#define EXT2_TIND_BLOCK (EXT2_DIND_BLOCK + 1) +#define EXT2_N_BLOCKS (EXT2_TIND_BLOCK + 1) + +/* + * Inode flags + */ +#define EXT2_SECRM_FL 0x00000001 /* Secure deletion */ +#define EXT2_UNRM_FL 0x00000002 /* Undelete */ +#define EXT2_COMPR_FL 0x00000004 /* Compress file */ +#define EXT2_SYNC_FL 0x00000008 /* Synchronous updates */ +#define EXT2_IMMUTABLE_FL 0x00000010 /* Immutable file */ +#define EXT2_APPEND_FL 0x00000020 /* writes to file may only append */ +#define EXT2_NODUMP_FL 0x00000040 /* do not dump file */ +#define EXT2_NOATIME_FL 0x00000080 /* do not update atime */ +/* Reserved for compression usage... */ +#define EXT2_DIRTY_FL 0x00000100 +#define EXT2_COMPRBLK_FL 0x00000200 /* One or more compressed clusters */ +#define EXT2_NOCOMPR_FL 0x00000400 /* Access raw compressed data */ +#define EXT2_ECOMPR_FL 0x00000800 /* Compression error */ +/* End compression flags --- maybe not all used */ +#define EXT2_BTREE_FL 0x00001000 /* btree format dir */ +#define EXT2_INDEX_FL 0x00001000 /* hash-indexed directory */ +#define EXT2_IMAGIC_FL 0x00002000 +#define EXT3_JOURNAL_DATA_FL 0x00004000 /* file data should be journaled */ +#define EXT2_NOTAIL_FL 0x00008000 /* file tail should not be merged */ +#define EXT2_RESERVED_FL 0x80000000 /* reserved for ext2 lib */ + +#define EXT2_FL_USER_VISIBLE 0x0000DFFF /* User visible flags */ +#define EXT2_FL_USER_MODIFIABLE 0x000080FF /* User modifiable flags */ + +/* + * ioctl commands + */ +#define EXT2_IOC_GETFLAGS _IOR('f', 1, long) +#define EXT2_IOC_SETFLAGS _IOW('f', 2, long) +#define EXT2_IOC_GETVERSION _IOR('v', 1, long) +#define EXT2_IOC_SETVERSION _IOW('v', 2, long) + +/* + * Structure of an inode on the disk + */ +struct ext2_inode { + __u16 i_mode; /* File mode */ + __u16 i_uid; /* Low 16 bits of Owner Uid */ + __u32 i_size; /* Size in bytes */ + __u32 i_atime; /* Access time */ + __u32 i_ctime; /* Creation time */ + __u32 i_mtime; /* Modification time */ + __u32 i_dtime; /* Deletion Time */ + __u16 i_gid; /* Low 16 bits of Group Id */ + __u16 i_links_count; /* Links count */ + __u32 i_blocks; /* Blocks count */ + __u32 i_flags; /* File flags */ + union { + struct { + __u32 l_i_reserved1; + } linux1; + struct { + __u32 h_i_translator; + } hurd1; + struct { + __u32 m_i_reserved1; + } masix1; + } osd1; /* OS dependent 1 */ + __u32 i_block[EXT2_N_BLOCKS];/* Pointers to blocks */ + __u32 i_generation; /* File version (for NFS) */ + __u32 i_file_acl; /* File ACL */ + __u32 i_dir_acl; /* Directory ACL */ + __u32 i_faddr; /* Fragment address */ + union { + struct { + __u8 l_i_frag; /* Fragment number */ + __u8 l_i_fsize; /* Fragment size */ + __u16 i_pad1; + __u16 l_i_uid_high; /* these 2 fields */ + __u16 l_i_gid_high; /* were reserved2[0] */ + __u32 l_i_reserved2; + } linux2; + struct { + __u8 h_i_frag; /* Fragment number */ + __u8 h_i_fsize; /* Fragment size */ + __u16 h_i_mode_high; + __u16 h_i_uid_high; + __u16 h_i_gid_high; + __u32 h_i_author; + } hurd2; + struct { + __u8 m_i_frag; /* Fragment number */ + __u8 m_i_fsize; /* Fragment size */ + __u16 m_pad1; + __u32 m_i_reserved2[2]; + } masix2; + } osd2; /* OS dependent 2 */ +}; + +#define i_size_high i_dir_acl + +#if defined(__KERNEL__) || defined(__linux__) +#define i_reserved1 osd1.linux1.l_i_reserved1 +#define i_frag osd2.linux2.l_i_frag +#define i_fsize osd2.linux2.l_i_fsize +#define i_uid_low i_uid +#define i_gid_low i_gid +#define i_uid_high osd2.linux2.l_i_uid_high +#define i_gid_high osd2.linux2.l_i_gid_high +#define i_reserved2 osd2.linux2.l_i_reserved2 + +#elif defined(__GNU__) + +#define i_translator osd1.hurd1.h_i_translator +#define i_frag osd2.hurd2.h_i_frag; +#define i_fsize osd2.hurd2.h_i_fsize; +#define i_uid_high osd2.hurd2.h_i_uid_high +#define i_gid_high osd2.hurd2.h_i_gid_high +#define i_author osd2.hurd2.h_i_author + +#elif defined(__masix__) + +#define i_reserved1 osd1.masix1.m_i_reserved1 +#define i_frag osd2.masix2.m_i_frag +#define i_fsize osd2.masix2.m_i_fsize +#define i_reserved2 osd2.masix2.m_i_reserved2 + +#endif /* defined(__KERNEL) || defined(__linux__) */ + +/* + * File system states + */ +#define EXT2_VALID_FS 0x0001 /* Unmounted cleanly */ +#define EXT2_ERROR_FS 0x0002 /* Errors detected */ + +/* + * Mount flags + */ +#define EXT2_MOUNT_CHECK 0x0001 /* Do mount-time checks */ +#define EXT2_MOUNT_GRPID 0x0004 /* Create files with directory's group */ +#define EXT2_MOUNT_DEBUG 0x0008 /* Some debugging messages */ +#define EXT2_MOUNT_ERRORS_CONT 0x0010 /* Continue on errors */ +#define EXT2_MOUNT_ERRORS_RO 0x0020 /* Remount fs ro on errors */ +#define EXT2_MOUNT_ERRORS_PANIC 0x0040 /* Panic on errors */ +#define EXT2_MOUNT_MINIX_DF 0x0080 /* Mimics the Minix statfs */ +#define EXT2_MOUNT_NO_UID32 0x0200 /* Disable 32-bit UIDs */ + +#define clear_opt(o, opt) o &= ~EXT2_MOUNT_##opt +#define set_opt(o, opt) o |= EXT2_MOUNT_##opt +#define test_opt(sb, opt) ((sb)->u.ext2_sb.s_mount_opt & \ + EXT2_MOUNT_##opt) +/* + * Maximal mount counts between two filesystem checks + */ +#define EXT2_DFL_MAX_MNT_COUNT 20 /* Allow 20 mounts */ +#define EXT2_DFL_CHECKINTERVAL 0 /* Don't use interval check */ + +/* + * Behaviour when detecting errors + */ +#define EXT2_ERRORS_CONTINUE 1 /* Continue execution */ +#define EXT2_ERRORS_RO 2 /* Remount fs read-only */ +#define EXT2_ERRORS_PANIC 3 /* Panic */ +#define EXT2_ERRORS_DEFAULT EXT2_ERRORS_CONTINUE + +/* + * Structure of the super block + */ +struct ext2_super_block { + __u32 s_inodes_count; /* Inodes count */ + __u32 s_blocks_count; /* Blocks count */ + __u32 s_r_blocks_count; /* Reserved blocks count */ + __u32 s_free_blocks_count; /* Free blocks count */ + __u32 s_free_inodes_count; /* Free inodes count */ + __u32 s_first_data_block; /* First Data Block */ + __u32 s_log_block_size; /* Block size */ + __s32 s_log_frag_size; /* Fragment size */ + __u32 s_blocks_per_group; /* # Blocks per group */ + __u32 s_frags_per_group; /* # Fragments per group */ + __u32 s_inodes_per_group; /* # Inodes per group */ + __u32 s_mtime; /* Mount time */ + __u32 s_wtime; /* Write time */ + __u16 s_mnt_count; /* Mount count */ + __s16 s_max_mnt_count; /* Maximal mount count */ + __u16 s_magic; /* Magic signature */ + __u16 s_state; /* File system state */ + __u16 s_errors; /* Behaviour when detecting errors */ + __u16 s_minor_rev_level; /* minor revision level */ + __u32 s_lastcheck; /* time of last check */ + __u32 s_checkinterval; /* max. time between checks */ + __u32 s_creator_os; /* OS */ + __u32 s_rev_level; /* Revision level */ + __u16 s_def_resuid; /* Default uid for reserved blocks */ + __u16 s_def_resgid; /* Default gid for reserved blocks */ + /* + * These fields are for EXT2_DYNAMIC_REV superblocks only. + * + * Note: the difference between the compatible feature set and + * the incompatible feature set is that if there is a bit set + * in the incompatible feature set that the kernel doesn't + * know about, it should refuse to mount the filesystem. + * + * e2fsck's requirements are more strict; if it doesn't know + * about a feature in either the compatible or incompatible + * feature set, it must abort and not try to meddle with + * things it doesn't understand... + */ + __u32 s_first_ino; /* First non-reserved inode */ + __u16 s_inode_size; /* size of inode structure */ + __u16 s_block_group_nr; /* block group # of this superblock */ + __u32 s_feature_compat; /* compatible feature set */ + __u32 s_feature_incompat; /* incompatible feature set */ + __u32 s_feature_ro_compat; /* readonly-compatible feature set */ + __u8 s_uuid[16]; /* 128-bit uuid for volume */ + char s_volume_name[16]; /* volume name */ + char s_last_mounted[64]; /* directory where last mounted */ + __u32 s_algorithm_usage_bitmap; /* For compression */ + /* + * Performance hints. Directory preallocation should only + * happen if the EXT2_FEATURE_COMPAT_DIR_PREALLOC flag is on. + */ + __u8 s_prealloc_blocks; /* Nr of blocks to try to preallocate*/ + __u8 s_prealloc_dir_blocks; /* Nr to preallocate for dirs */ + __u16 s_padding1; + /* + * Journaling support valid if EXT2_FEATURE_COMPAT_HAS_JOURNAL set. + */ + __u8 s_journal_uuid[16]; /* uuid of journal superblock */ + __u32 s_journal_inum; /* inode number of journal file */ + __u32 s_journal_dev; /* device number of journal file */ + __u32 s_last_orphan; /* start of list of inodes to delete */ + + __u32 s_reserved[197]; /* Padding to the end of the block */ +}; + +#ifdef __KERNEL__ +#define EXT2_SB(sb) (&((sb)->u.ext2_sb)) +#else +/* Assume that user mode programs are passing in an ext2fs superblock, not + * a kernel struct super_block. This will allow us to call the feature-test + * macros from user land. */ +#define EXT2_SB(sb) (sb) +#endif + +/* + * Codes for operating systems + */ +#define EXT2_OS_LINUX 0 +#define EXT2_OS_HURD 1 +#define EXT2_OS_MASIX 2 +#define EXT2_OS_FREEBSD 3 +#define EXT2_OS_LITES 4 +#define EXT2_OS_WINNT 5 + +/* + * Revision levels + */ +#define EXT2_GOOD_OLD_REV 0 /* The good old (original) format */ +#define EXT2_DYNAMIC_REV 1 /* V2 format w/ dynamic inode sizes */ + +#define EXT2_CURRENT_REV EXT2_GOOD_OLD_REV +#define EXT2_MAX_SUPP_REV EXT2_DYNAMIC_REV + +#define EXT2_GOOD_OLD_INODE_SIZE 128 + +/* + * Feature set definitions + */ + +#define EXT2_HAS_COMPAT_FEATURE(sb,mask) \ + ( EXT2_SB(sb)->s_feature_compat & (mask) ) +#define EXT2_HAS_RO_COMPAT_FEATURE(sb,mask) \ + ( EXT2_SB(sb)->s_feature_ro_compat & (mask) ) +#define EXT2_HAS_INCOMPAT_FEATURE(sb,mask) \ + ( EXT2_SB(sb)->s_feature_incompat & (mask) ) + +#define EXT2_FEATURE_COMPAT_DIR_PREALLOC 0x0001 +#define EXT2_FEATURE_COMPAT_IMAGIC_INODES 0x0002 +#define EXT3_FEATURE_COMPAT_HAS_JOURNAL 0x0004 +#define EXT2_FEATURE_COMPAT_EXT_ATTR 0x0008 +#define EXT2_FEATURE_COMPAT_RESIZE_INODE 0x0010 +#define EXT2_FEATURE_COMPAT_DIR_INDEX 0x0020 + +#define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001 +#define EXT2_FEATURE_RO_COMPAT_LARGE_FILE 0x0002 +#define EXT2_FEATURE_RO_COMPAT_BTREE_DIR 0x0004 + +#define EXT2_FEATURE_INCOMPAT_COMPRESSION 0x0001 +#define EXT2_FEATURE_INCOMPAT_FILETYPE 0x0002 +#define EXT3_FEATURE_INCOMPAT_RECOVER 0x0004 /* Needs recovery */ +#define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008 /* Journal device */ + +#define EXT2_FEATURE_COMPAT_SUPP 0 +#define EXT2_FEATURE_INCOMPAT_SUPP EXT2_FEATURE_INCOMPAT_FILETYPE +#define EXT2_FEATURE_RO_COMPAT_SUPP (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \ + EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \ + EXT2_FEATURE_RO_COMPAT_BTREE_DIR) + +/* + * Default values for user and/or group using reserved blocks + */ +#define EXT2_DEF_RESUID 0 +#define EXT2_DEF_RESGID 0 + +/* + * Structure of a directory entry + */ +#define EXT2_NAME_LEN 255 + +struct ext2_dir_entry { + __u32 inode; /* Inode number */ + __u16 rec_len; /* Directory entry length */ + __u16 name_len; /* Name length */ + char name[EXT2_NAME_LEN]; /* File name */ +}; + +/* + * The new version of the directory entry. Since EXT2 structures are + * stored in intel byte order, and the name_len field could never be + * bigger than 255 chars, it's safe to reclaim the extra byte for the + * file_type field. + */ +struct ext2_dir_entry_2 { + __u32 inode; /* Inode number */ + __u16 rec_len; /* Directory entry length */ + __u8 name_len; /* Name length */ + __u8 file_type; + char name[EXT2_NAME_LEN]; /* File name */ +}; + +/* + * Ext2 directory file types. Only the low 3 bits are used. The + * other bits are reserved for now. + */ +#define EXT2_FT_UNKNOWN 0 +#define EXT2_FT_REG_FILE 1 +#define EXT2_FT_DIR 2 +#define EXT2_FT_CHRDEV 3 +#define EXT2_FT_BLKDEV 4 +#define EXT2_FT_FIFO 5 +#define EXT2_FT_SOCK 6 +#define EXT2_FT_SYMLINK 7 + +#define EXT2_FT_MAX 8 + +/* + * EXT2_DIR_PAD defines the directory entries boundaries + * + * NOTE: It must be a multiple of 4 + */ +#define EXT2_DIR_PAD 4 +#define EXT2_DIR_ROUND (EXT2_DIR_PAD - 1) +#define EXT2_DIR_REC_LEN(name_len) (((name_len) + 8 + EXT2_DIR_ROUND) & \ + ~EXT2_DIR_ROUND) + +#ifdef __KERNEL__ +/* + * Function prototypes + */ + +/* + * Ok, these declarations are also in but none of the + * ext2 source programs needs to include it so they are duplicated here. + */ +# define NORET_TYPE /**/ +# define ATTRIB_NORET __attribute__((noreturn)) +# define NORET_AND noreturn, + +/* acl.c */ +extern int ext2_permission (struct inode *, int); + +/* balloc.c */ +extern int ext2_bg_has_super(struct super_block *sb, int group); +extern unsigned long ext2_bg_num_gdb(struct super_block *sb, int group); +extern int ext2_new_block (const struct inode *, unsigned long, + __u32 *, __u32 *, int *); +extern void ext2_free_blocks (const struct inode *, unsigned long, + unsigned long); +extern unsigned long ext2_count_free_blocks (struct super_block *); +extern void ext2_check_blocks_bitmap (struct super_block *); +extern struct ext2_group_desc * ext2_get_group_desc(struct super_block * sb, + unsigned int block_group, + struct buffer_head ** bh); + +/* bitmap.c */ +extern unsigned long ext2_count_free (struct buffer_head *, unsigned); + +/* dir.c */ +extern int ext2_check_dir_entry (const char *, struct inode *, + struct ext2_dir_entry_2 *, struct buffer_head *, + unsigned long); + +/* file.c */ +extern int ext2_read (struct inode *, struct file *, char *, int); +extern int ext2_write (struct inode *, struct file *, char *, int); + +/* fsync.c */ +extern int ext2_sync_file (struct file *, struct dentry *, int); +extern int ext2_fsync_inode (struct inode *, int); + +/* ialloc.c */ +extern struct inode * ext2_new_inode (const struct inode *, int); +extern void ext2_free_inode (struct inode *); +extern unsigned long ext2_count_free_inodes (struct super_block *); +extern void ext2_check_inodes_bitmap (struct super_block *); + +/* inode.c */ + +extern struct buffer_head * ext2_getblk (struct inode *, long, int, int *); +extern struct buffer_head * ext2_bread (struct inode *, int, int, int *); + +extern void ext2_read_inode (struct inode *); +extern void ext2_write_inode (struct inode *, int); +extern void ext2_put_inode (struct inode *); +extern void ext2_delete_inode (struct inode *); +extern int ext2_sync_inode (struct inode *); +extern void ext2_discard_prealloc (struct inode *); + +/* ioctl.c */ +extern int ext2_ioctl (struct inode *, struct file *, unsigned int, + unsigned long); + +/* namei.c */ +extern struct inode_operations ext2_dir_inode_operations; + +/* super.c */ +extern void ext2_error (struct super_block *, const char *, const char *, ...) + __attribute__ ((format (printf, 3, 4))); +extern NORET_TYPE void ext2_panic (struct super_block *, const char *, + const char *, ...) + __attribute__ ((NORET_AND format (printf, 3, 4))); +extern void ext2_warning (struct super_block *, const char *, const char *, ...) + __attribute__ ((format (printf, 3, 4))); +extern void ext2_update_dynamic_rev (struct super_block *sb); +extern void ext2_put_super (struct super_block *); +extern void ext2_write_super (struct super_block *); +extern int ext2_remount (struct super_block *, int *, char *); +extern struct super_block * ext2_read_super (struct super_block *,void *,int); +extern int ext2_statfs (struct super_block *, struct statfs *); + +/* truncate.c */ +extern void ext2_truncate (struct inode *); + +/* + * Inodes and files operations + */ + +/* dir.c */ +extern struct file_operations ext2_dir_operations; + +/* file.c */ +extern struct inode_operations ext2_file_inode_operations; +extern struct file_operations ext2_file_operations; + +/* symlink.c */ +extern struct inode_operations ext2_fast_symlink_inode_operations; + +extern struct address_space_operations ext2_aops; + +#endif /* __KERNEL__ */ + +#endif /* _LINUX_EXT2_FS_H */ diff --git a/reactos/lib/fslib/ext2lib/types.h b/reactos/lib/fslib/ext2lib/types.h new file mode 100644 index 00000000000..dbc445484ec --- /dev/null +++ b/reactos/lib/fslib/ext2lib/types.h @@ -0,0 +1,10 @@ +#ifndef _LINUX_TYPES_H +#define _LINUX_TYPES_H + +typedef unsigned long __u32; +typedef signed long __s32; +typedef unsigned short int __u16; +typedef signed short int __s16; +typedef unsigned char __u8; + +#endif /* LINUX_TYPES_H */ From bebd1855eeaf9d327498c872364c5aab4f6aac22 Mon Sep 17 00:00:00 2001 From: Art Yerkes Date: Thu, 13 Jan 2005 01:59:08 +0000 Subject: [PATCH 3/8] fs_rec: add ext2 support txtsetup: add ext2 hivesys: add ext2 usetup: add formatting and installing on ext2 (by filip navara) svn path=/branches/ext2/; revision=13011 --- reactos/bootdata/hivesys.inf | 7 + reactos/bootdata/txtsetup.sif | 5 +- reactos/drivers/fs/fs_rec/fs_rec.c | 7 +- reactos/drivers/fs/fs_rec/fs_rec.h | 7 + reactos/drivers/fs/fs_rec/makefile | 1 + reactos/subsys/system/usetup/bootsup.c | 418 ++++++++++++++++++++++++ reactos/subsys/system/usetup/bootsup.h | 8 + reactos/subsys/system/usetup/format.c | 55 +++- reactos/subsys/system/usetup/format.h | 2 +- reactos/subsys/system/usetup/fslist.c | 16 +- reactos/subsys/system/usetup/fslist.h | 3 +- reactos/subsys/system/usetup/makefile | 2 +- reactos/subsys/system/usetup/partlist.c | 8 + reactos/subsys/system/usetup/usetup.c | 68 ++-- 14 files changed, 569 insertions(+), 38 deletions(-) diff --git a/reactos/bootdata/hivesys.inf b/reactos/bootdata/hivesys.inf index e82f6efe777..3f6a981c457 100644 --- a/reactos/bootdata/hivesys.inf +++ b/reactos/bootdata/hivesys.inf @@ -729,6 +729,13 @@ HKLM,"SYSTEM\CurrentControlSet\Services\Vfatfs","ImagePath",0x00020000,"system32 HKLM,"SYSTEM\CurrentControlSet\Services\Vfatfs","Start",0x00010001,0x00000000 HKLM,"SYSTEM\CurrentControlSet\Services\Vfatfs","Type",0x00010001,0x00000002 +; EXT2 Filesystem driver +HKLM,"SYSTEM\CurrentControlSet\Services\Ext2fs","ErrorControl",0x00010001,0x00000000 +HKLM,"SYSTEM\CurrentControlSet\Services\Ext2fs","Group",0x00000000,"Boot File System" +HKLM,"SYSTEM\CurrentControlSet\Services\Ext2fs","ImagePath",0x00020000,"system32\drivers\ext2.sys" +HKLM,"SYSTEM\CurrentControlSet\Services\Ext2fs","Start",0x00010001,0x00000000 +HKLM,"SYSTEM\CurrentControlSet\Services\Ext2fs","Type",0x00010001,0x00000002 + ; VBE SVGA driver HKLM,"SYSTEM\CurrentControlSet\Services\VBE","ErrorControl",0x00010001,0x00000000 HKLM,"SYSTEM\CurrentControlSet\Services\VBE","Group",0x00000000,"Video Save SVGA" diff --git a/reactos/bootdata/txtsetup.sif b/reactos/bootdata/txtsetup.sif index ba598083a4d..94b79095894 100644 --- a/reactos/bootdata/txtsetup.sif +++ b/reactos/bootdata/txtsetup.sif @@ -29,14 +29,15 @@ ntfs.sys = 3 ntoskrnl.exe = 2 scsiport.sys = 3 vfatfs.sys = 3 +ext2.sys = 3 [Cabinets] Cabinet=reactos.cab [SetupData] DefaultPath = \ReactOS -OsLoadOptions = "/NOGUIBOOT /NODEBUG" -;OsLoadOptions = "/NOGUIBOOT /DEBUGPORT=COM1" +;OsLoadOptions = "/NOGUIBOOT /NODEBUG" +OsLoadOptions = "/NOGUIBOOT /DEBUGPORT=COM1" ;OsLoadOptions = "/NOGUIBOOT /DEBUGPORT=SCREEN" ;OsLoadOptions = "/NOGUIBOOT /DEBUGPORT=BOCHS" diff --git a/reactos/drivers/fs/fs_rec/fs_rec.c b/reactos/drivers/fs/fs_rec/fs_rec.c index 1f7adca4a0a..0cc2b9bfdef 100644 --- a/reactos/drivers/fs/fs_rec/fs_rec.c +++ b/reactos/drivers/fs/fs_rec/fs_rec.c @@ -27,9 +27,10 @@ /* INCLUDES *****************************************************************/ +#include #include -#define NDEBUG +//#define NDEBUG #include #include "fs_rec.h" @@ -81,6 +82,10 @@ FsRecFsControl(IN PDEVICE_OBJECT DeviceObject, Status = FsRecVfatFsControl(DeviceObject, Irp); break; + case FS_TYPE_EXT2: + Status = FsRecExt2FsControl(DeviceObject, Irp); + break; + case FS_TYPE_NTFS: Status = FsRecNtfsFsControl(DeviceObject, Irp); break; diff --git a/reactos/drivers/fs/fs_rec/fs_rec.h b/reactos/drivers/fs/fs_rec/fs_rec.h index 31e750b1d76..ccf97c54254 100644 --- a/reactos/drivers/fs/fs_rec/fs_rec.h +++ b/reactos/drivers/fs/fs_rec/fs_rec.h @@ -33,6 +33,7 @@ #define FS_TYPE_NTFS 2 #define FS_TYPE_CDFS 3 #define FS_TYPE_UDFS 4 +#define FS_TYPE_EXT2 5 typedef struct _DEVICE_EXTENSION @@ -91,6 +92,12 @@ FsRecVfatFsControl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp); +/* ext2.c */ + +NTSTATUS +FsRecExt2FsControl(IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp); + /* ntfs.c */ NTSTATUS diff --git a/reactos/drivers/fs/fs_rec/makefile b/reactos/drivers/fs/fs_rec/makefile index 63cbe9715f9..7631191bed7 100644 --- a/reactos/drivers/fs/fs_rec/makefile +++ b/reactos/drivers/fs/fs_rec/makefile @@ -11,6 +11,7 @@ TARGET_OBJECTS = \ fs_rec.o \ cdfs.o \ fat.o \ + ext2.o \ ntfs.o \ udfs.o diff --git a/reactos/subsys/system/usetup/bootsup.c b/reactos/subsys/system/usetup/bootsup.c index 309b3ae9a57..02bd4d4aa5a 100644 --- a/reactos/subsys/system/usetup/bootsup.c +++ b/reactos/subsys/system/usetup/bootsup.c @@ -1542,6 +1542,424 @@ InstallFat32BootCodeToDisk(PWSTR SrcPath, } +NTSTATUS +InstallExt2BootCodeToDisk(PWSTR SrcPath, + PWSTR RootPath) +{ + OBJECT_ATTRIBUTES ObjectAttributes; + IO_STATUS_BLOCK IoStatusBlock; + UNICODE_STRING Name; + HANDLE FileHandle; + NTSTATUS Status; + PUCHAR OrigBootSector; + PUCHAR NewBootSector; + LARGE_INTEGER FileOffset; + USHORT BackupBootSector; + + /* Allocate buffer for original bootsector */ + OrigBootSector = (PUCHAR)RtlAllocateHeap(ProcessHeap, + 0, + SECTORSIZE); + if (OrigBootSector == NULL) + return(STATUS_INSUFFICIENT_RESOURCES); + + /* Read current boot sector into buffer */ + RtlInitUnicodeString(&Name, + RootPath); + + InitializeObjectAttributes(&ObjectAttributes, + &Name, + OBJ_CASE_INSENSITIVE, + NULL, + NULL); + + Status = NtOpenFile(&FileHandle, + FILE_READ_ACCESS, + &ObjectAttributes, + &IoStatusBlock, + 0, + FILE_SYNCHRONOUS_IO_NONALERT); + if (!NT_SUCCESS(Status)) + { + RtlFreeHeap(ProcessHeap, 0, OrigBootSector); + return(Status); + } + + Status = NtReadFile(FileHandle, + NULL, + NULL, + NULL, + &IoStatusBlock, + OrigBootSector, + SECTORSIZE, + NULL, + NULL); + NtClose(FileHandle); + if (!NT_SUCCESS(Status)) + { + RtlFreeHeap(ProcessHeap, 0, OrigBootSector); + return(Status); + } + + + /* Allocate buffer for new bootsector (2 sectors) */ + NewBootSector = (PUCHAR)RtlAllocateHeap(ProcessHeap, + 0, + 2 * SECTORSIZE); + if (NewBootSector == NULL) + { + RtlFreeHeap(ProcessHeap, 0, OrigBootSector); + return(STATUS_INSUFFICIENT_RESOURCES); + } + + /* Read new bootsector from SrcPath */ + RtlInitUnicodeString(&Name, + SrcPath); + + InitializeObjectAttributes(&ObjectAttributes, + &Name, + OBJ_CASE_INSENSITIVE, + NULL, + NULL); + + Status = NtOpenFile(&FileHandle, + FILE_READ_ACCESS, + &ObjectAttributes, + &IoStatusBlock, + 0, + FILE_SYNCHRONOUS_IO_NONALERT); + if (!NT_SUCCESS(Status)) + { + RtlFreeHeap(ProcessHeap, 0, OrigBootSector); + RtlFreeHeap(ProcessHeap, 0, NewBootSector); + return(Status); + } + + Status = NtReadFile(FileHandle, + NULL, + NULL, + NULL, + &IoStatusBlock, + NewBootSector, + 2 * SECTORSIZE, + NULL, + NULL); + NtClose(FileHandle); + if (!NT_SUCCESS(Status)) + { + RtlFreeHeap(ProcessHeap, 0, OrigBootSector); + RtlFreeHeap(ProcessHeap, 0, NewBootSector); + return(Status); + } + + /* Adjust bootsector (copy a part of the FAT32 BPB) */ + memcpy((NewBootSector + 3), + (OrigBootSector + 3), + 87); /* FAT32 BPB length */ + + /* Get the location of the backup boot sector */ + BackupBootSector = (OrigBootSector[0x33] << 8) + OrigBootSector[0x32]; + + /* Free the original boot sector */ + RtlFreeHeap(ProcessHeap, 0, OrigBootSector); + + /* Write the first sector of the new bootcode to DstPath */ + RtlInitUnicodeString(&Name, + RootPath); + + InitializeObjectAttributes(&ObjectAttributes, + &Name, + 0, + NULL, + NULL); + + Status = NtOpenFile(&FileHandle, + FILE_WRITE_ACCESS | FILE_WRITE_ATTRIBUTES, + &ObjectAttributes, + &IoStatusBlock, + 0, + FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY); + if (!NT_SUCCESS(Status)) + { + DPRINT1("NtOpenFile() failed (Status %lx)\n", Status); + RtlFreeHeap(ProcessHeap, 0, NewBootSector); + return(Status); + } + + /* Write sector 0 */ + FileOffset.QuadPart = 0ULL; + Status = NtWriteFile(FileHandle, + NULL, + NULL, + NULL, + &IoStatusBlock, + NewBootSector, + SECTORSIZE, + &FileOffset, + NULL); + if (!NT_SUCCESS(Status)) + { + DPRINT1("NtWriteFile() failed (Status %lx)\n", Status); + NtClose(FileHandle); + RtlFreeHeap(ProcessHeap, 0, NewBootSector); + return(Status); + } + + /* Write backup boot sector */ + if ((BackupBootSector != 0x0000) && (BackupBootSector != 0xFFFF)) + { + FileOffset.QuadPart = (ULONGLONG)((ULONG)BackupBootSector * SECTORSIZE); + Status = NtWriteFile(FileHandle, + NULL, + NULL, + NULL, + &IoStatusBlock, + NewBootSector, + SECTORSIZE, + &FileOffset, + NULL); + if (!NT_SUCCESS(Status)) + { + DPRINT1("NtWriteFile() failed (Status %lx)\n", Status); + NtClose(FileHandle); + RtlFreeHeap(ProcessHeap, 0, NewBootSector); + return(Status); + } + } + + /* Write sector 14 */ + FileOffset.QuadPart = (ULONGLONG)(14 * SECTORSIZE); + Status = NtWriteFile(FileHandle, + NULL, + NULL, + NULL, + &IoStatusBlock, + (NewBootSector + SECTORSIZE), + SECTORSIZE, + &FileOffset, + NULL); + if (!NT_SUCCESS(Status)) + { + DPRINT1("NtWriteFile() failed (Status %lx)\n", Status); + } + NtClose(FileHandle); + + /* Free the new boot sector */ + RtlFreeHeap(ProcessHeap, 0, NewBootSector); + + return(Status); +} + + +NTSTATUS +InstallExt2BootCodeToDisk(PWSTR SrcPath, + PWSTR RootPath) +{ + OBJECT_ATTRIBUTES ObjectAttributes; + IO_STATUS_BLOCK IoStatusBlock; + UNICODE_STRING Name; + HANDLE FileHandle; + NTSTATUS Status; + PUCHAR OrigBootSector; + PUCHAR NewBootSector; + LARGE_INTEGER FileOffset; + USHORT BackupBootSector; + + /* Allocate buffer for original bootsector */ + OrigBootSector = (PUCHAR)RtlAllocateHeap(ProcessHeap, + 0, + SECTORSIZE); + if (OrigBootSector == NULL) + return(STATUS_INSUFFICIENT_RESOURCES); + + /* Read current boot sector into buffer */ + RtlInitUnicodeString(&Name, + RootPath); + + InitializeObjectAttributes(&ObjectAttributes, + &Name, + OBJ_CASE_INSENSITIVE, + NULL, + NULL); + + Status = NtOpenFile(&FileHandle, + FILE_READ_ACCESS, + &ObjectAttributes, + &IoStatusBlock, + 0, + FILE_SYNCHRONOUS_IO_NONALERT); + if (!NT_SUCCESS(Status)) + { + RtlFreeHeap(ProcessHeap, 0, OrigBootSector); + return(Status); + } + + Status = NtReadFile(FileHandle, + NULL, + NULL, + NULL, + &IoStatusBlock, + OrigBootSector, + SECTORSIZE, + NULL, + NULL); + NtClose(FileHandle); + if (!NT_SUCCESS(Status)) + { + RtlFreeHeap(ProcessHeap, 0, OrigBootSector); + return(Status); + } + + + /* Allocate buffer for new bootsector (2 sectors) */ + NewBootSector = (PUCHAR)RtlAllocateHeap(ProcessHeap, + 0, + 2 * SECTORSIZE); + if (NewBootSector == NULL) + { + RtlFreeHeap(ProcessHeap, 0, OrigBootSector); + return(STATUS_INSUFFICIENT_RESOURCES); + } + + /* Read new bootsector from SrcPath */ + RtlInitUnicodeString(&Name, + SrcPath); + + InitializeObjectAttributes(&ObjectAttributes, + &Name, + OBJ_CASE_INSENSITIVE, + NULL, + NULL); + + Status = NtOpenFile(&FileHandle, + FILE_READ_ACCESS, + &ObjectAttributes, + &IoStatusBlock, + 0, + FILE_SYNCHRONOUS_IO_NONALERT); + if (!NT_SUCCESS(Status)) + { + RtlFreeHeap(ProcessHeap, 0, OrigBootSector); + RtlFreeHeap(ProcessHeap, 0, NewBootSector); + return(Status); + } + + Status = NtReadFile(FileHandle, + NULL, + NULL, + NULL, + &IoStatusBlock, + NewBootSector, + 2 * SECTORSIZE, + NULL, + NULL); + NtClose(FileHandle); + if (!NT_SUCCESS(Status)) + { + RtlFreeHeap(ProcessHeap, 0, OrigBootSector); + RtlFreeHeap(ProcessHeap, 0, NewBootSector); + return(Status); + } + + /* Adjust bootsector (copy a part of the FAT32 BPB) */ + memcpy((NewBootSector + 3), + (OrigBootSector + 3), + 87); /* FAT32 BPB length */ + + /* Get the location of the backup boot sector */ + BackupBootSector = (OrigBootSector[0x33] << 8) + OrigBootSector[0x32]; + + /* Free the original boot sector */ + RtlFreeHeap(ProcessHeap, 0, OrigBootSector); + + /* Write the first sector of the new bootcode to DstPath */ + RtlInitUnicodeString(&Name, + RootPath); + + InitializeObjectAttributes(&ObjectAttributes, + &Name, + 0, + NULL, + NULL); + + Status = NtOpenFile(&FileHandle, + FILE_WRITE_ACCESS | FILE_WRITE_ATTRIBUTES, + &ObjectAttributes, + &IoStatusBlock, + 0, + FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY); + if (!NT_SUCCESS(Status)) + { + DPRINT1("NtOpenFile() failed (Status %lx)\n", Status); + RtlFreeHeap(ProcessHeap, 0, NewBootSector); + return(Status); + } + + /* Write sector 0 */ + FileOffset.QuadPart = 0ULL; + Status = NtWriteFile(FileHandle, + NULL, + NULL, + NULL, + &IoStatusBlock, + NewBootSector, + SECTORSIZE, + &FileOffset, + NULL); + if (!NT_SUCCESS(Status)) + { + DPRINT1("NtWriteFile() failed (Status %lx)\n", Status); + NtClose(FileHandle); + RtlFreeHeap(ProcessHeap, 0, NewBootSector); + return(Status); + } + + /* Write backup boot sector */ + if ((BackupBootSector != 0x0000) && (BackupBootSector != 0xFFFF)) + { + FileOffset.QuadPart = (ULONGLONG)((ULONG)BackupBootSector * SECTORSIZE); + Status = NtWriteFile(FileHandle, + NULL, + NULL, + NULL, + &IoStatusBlock, + NewBootSector, + SECTORSIZE, + &FileOffset, + NULL); + if (!NT_SUCCESS(Status)) + { + DPRINT1("NtWriteFile() failed (Status %lx)\n", Status); + NtClose(FileHandle); + RtlFreeHeap(ProcessHeap, 0, NewBootSector); + return(Status); + } + } + + /* Write sector 14 */ + FileOffset.QuadPart = (ULONGLONG)(14 * SECTORSIZE); + Status = NtWriteFile(FileHandle, + NULL, + NULL, + NULL, + &IoStatusBlock, + (NewBootSector + SECTORSIZE), + SECTORSIZE, + &FileOffset, + NULL); + if (!NT_SUCCESS(Status)) + { + DPRINT1("NtWriteFile() failed (Status %lx)\n", Status); + } + NtClose(FileHandle); + + /* Free the new boot sector */ + RtlFreeHeap(ProcessHeap, 0, NewBootSector); + + return(Status); +} + + static NTSTATUS UnprotectBootIni(PWSTR FileName, PULONG Attributes) diff --git a/reactos/subsys/system/usetup/bootsup.h b/reactos/subsys/system/usetup/bootsup.h index 1b0122a783c..40ec5018a36 100644 --- a/reactos/subsys/system/usetup/bootsup.h +++ b/reactos/subsys/system/usetup/bootsup.h @@ -65,6 +65,14 @@ NTSTATUS InstallFat32BootCodeToDisk(PWSTR SrcPath, PWSTR RootPath); +NTSTATUS +InstallExt2BootCodeToDisk(PWSTR SrcPath, + PWSTR RootPath); + +NTSTATUS +InstallExt2BootCodeToDisk(PWSTR SrcPath, + PWSTR RootPath); + NTSTATUS UpdateBootIni(PWSTR BootIniPath, PWSTR EntryName, diff --git a/reactos/subsys/system/usetup/format.c b/reactos/subsys/system/usetup/format.c index cb80bccd52f..dc360fd9b43 100755 --- a/reactos/subsys/system/usetup/format.c +++ b/reactos/subsys/system/usetup/format.c @@ -29,10 +29,12 @@ #include "precomp.h" #include #include +#include #include "usetup.h" #include "console.h" #include "progress.h" +#include "fslist.h" #define NDEBUG #include @@ -96,7 +98,7 @@ FormatCallback (CALLBACKCOMMAND Command, NTSTATUS -FormatPartition (PUNICODE_STRING DriveRoot) +FormatPartition (PUNICODE_STRING DriveRoot, FILE_SYSTEM FsType) { NTSTATUS Status; SHORT xScreen; @@ -111,16 +113,26 @@ FormatPartition (PUNICODE_STRING DriveRoot) ProgressSetStepCount (ProgressBar, 100); - VfatInitialize (); - - Status = VfatFormat (DriveRoot, - 0, /* MediaFlag */ - NULL, /* Label */ - TRUE, /* QuickFormat */ - 0, /* ClusterSize */ - (PFMIFSCALLBACK)FormatCallback); /* Callback */ - - VfatCleanup (); + if (FsType == FsFat) + { + VfatInitialize (); + Status = VfatFormat (DriveRoot, + 0, /* MediaFlag */ + NULL, /* Label */ + TRUE, /* QuickFormat */ + 0, /* ClusterSize */ + FormatCallback); /* Callback */ + VfatCleanup (); + } + else if (FsType == FsExt2) + { + Status = Ext2Format (DriveRoot, + 0, /* MediaFlag */ + NULL, /* Label */ + TRUE, /* QuickFormat */ + 0, /* ClusterSize */ + FormatCallback); /* Callback */ + } DestroyProgressBar (ProgressBar); ProgressBar = NULL; @@ -130,4 +142,25 @@ FormatPartition (PUNICODE_STRING DriveRoot) return Status; } + +#if 0 +NTSTATUS STDCALL +InstallFileSystemDriver (PUNICODE_STRING Name) +{ + ULONG StartValue = 0; /* Boot start driver. */ + + Status = RtlWriteRegistryValue(RTL_REGISTRY_SERVICES, + Name, + L"Start", + REG_DWORD, + &StartValue, + sizeof(ULONG)); + if (!NT_SUCCESS(Status)) + { + DPRINT("RtlWriteRegistryValue() failed (Status %lx)\n", Status); + return FALSE; + } +} +#endif + /* EOF */ diff --git a/reactos/subsys/system/usetup/format.h b/reactos/subsys/system/usetup/format.h index 193e3d43ee0..a8784ef356a 100755 --- a/reactos/subsys/system/usetup/format.h +++ b/reactos/subsys/system/usetup/format.h @@ -28,7 +28,7 @@ #define __FORMAT_H__ NTSTATUS -FormatPartition(PUNICODE_STRING DriveRoot); +FormatPartition(PUNICODE_STRING DriveRoot, FILE_SYSTEM FsType); #endif /* __FILESUP_H__ */ diff --git a/reactos/subsys/system/usetup/fslist.c b/reactos/subsys/system/usetup/fslist.c index 2d418880f9f..30b7a9cf341 100644 --- a/reactos/subsys/system/usetup/fslist.c +++ b/reactos/subsys/system/usetup/fslist.c @@ -52,7 +52,7 @@ CreateFileSystemList (SHORT Left, List->Top = Top; List->ForceFormat = ForceFormat; - List->FileSystemCount = 1; + List->FileSystemCount = 2; if (ForceFormat) { List->CurrentFileSystem = ForceFileSystem; @@ -108,6 +108,20 @@ DrawFileSystemList (PFILE_SYSTEM_LIST List) } Index++; + if (List->CurrentFileSystem == FsExt2) + { + SetInvertedTextXY (List->Left, + List->Top + Index, + " Format partition as EXT2 file system "); + } + else + { + SetTextXY (List->Left, + List->Top + Index, + " Format partition as EXT2 file system "); + } + Index++; + if (List->ForceFormat == FALSE) { coPos.X = List->Left; diff --git a/reactos/subsys/system/usetup/fslist.h b/reactos/subsys/system/usetup/fslist.h index 94eda71da12..e2a80f3fca8 100644 --- a/reactos/subsys/system/usetup/fslist.h +++ b/reactos/subsys/system/usetup/fslist.h @@ -31,7 +31,8 @@ typedef enum { FsFat = 0, - FsKeep = 1 + FsExt2 = 1, + FsKeep = 2 } FILE_SYSTEM; typedef struct _FILE_SYSTEM_LIST diff --git a/reactos/subsys/system/usetup/makefile b/reactos/subsys/system/usetup/makefile index a51941eb83a..951305e0be4 100644 --- a/reactos/subsys/system/usetup/makefile +++ b/reactos/subsys/system/usetup/makefile @@ -14,7 +14,7 @@ TARGET_NAME = usetup TARGET_PCH = precomp.h -TARGET_SDKLIBS = zlib.a vfatlib.a ntdll.a +TARGET_SDKLIBS = zlib.a vfatlib.a ext2lib.a ntdll.a TARGET_INSTALLDIR = system32 diff --git a/reactos/subsys/system/usetup/partlist.c b/reactos/subsys/system/usetup/partlist.c index e2bf0c738bc..4fa31ee70f2 100644 --- a/reactos/subsys/system/usetup/partlist.c +++ b/reactos/subsys/system/usetup/partlist.c @@ -297,6 +297,10 @@ AddPartitionToList (ULONG DiskNumber, #endif PartEntry->FormatState = Preformatted; } + else if (PartEntry->PartInfo[0].PartitionType == PARTITION_EXT2) + { + PartEntry->FormatState = Preformatted; + } else { PartEntry->FormatState = Unknown; @@ -812,6 +816,10 @@ PrintPartitionData (PPARTLIST List, { PartType = "FAT32"; } + else if (PartEntry->PartInfo[0].PartitionType == PARTITION_EXT2) + { + PartType = "EXT2"; + } else if (PartEntry->PartInfo[0].PartitionType == PARTITION_IFS) { PartType = "NTFS"; /* FIXME: Not quite correct! */ diff --git a/reactos/subsys/system/usetup/usetup.c b/reactos/subsys/system/usetup/usetup.c index b83c859a2bb..4352a6e89b3 100644 --- a/reactos/subsys/system/usetup/usetup.c +++ b/reactos/subsys/system/usetup/usetup.c @@ -34,6 +34,7 @@ #include #include "usetup.h" +#include "bootsup.h" #include "console.h" #include "partlist.h" #include "inicache.h" @@ -42,8 +43,8 @@ #include "progress.h" #include "bootsup.h" #include "registry.h" -#include "format.h" #include "fslist.h" +#include "format.h" #include "cabinet.h" #include "filesup.h" #include "drivesup.h" @@ -2139,6 +2140,10 @@ SelectFileSystemPage (PINPUT_RECORD Ir) { PartType = "FAT32"; } + else if (PartEntry->PartInfo[0].PartitionType == PARTITION_EXT2) + { + PartType = "FAT32"; + } else if (PartEntry->PartInfo[0].PartitionType == PARTITION_IFS) { PartType = "NTFS"; /* FIXME: Not quite correct! */ @@ -2301,6 +2306,7 @@ FormatPartitionPage (PINPUT_RECORD Ir) #ifndef NDEBUG ULONG Line; ULONG i; + PLIST_ENTRY Entry; #endif @@ -2386,6 +2392,10 @@ FormatPartitionPage (PINPUT_RECORD Ir) } break; + case FsExt2: + PartEntry->PartInfo[0].PartitionType = PARTITION_EXT2; + break; + case FsKeep: break; @@ -2477,27 +2487,24 @@ FormatPartitionPage (PINPUT_RECORD Ir) PathBuffer); DPRINT ("SystemRootPath: %wZ\n", &SystemRootPath); + if (FileSystemList->CurrentFileSystem != FsKeep) + { + Status = FormatPartition (&DestinationRootPath, + FileSystemList->CurrentFileSystem); + if (!NT_SUCCESS (Status)) + { + DPRINT1 ("FormatPartition() failed with status 0x%.08x\n", Status); + /* FIXME: show an error dialog */ + return QUIT_PAGE; + } + + PartEntry->New = FALSE; + CheckActiveBootPartition (PartitionList); + } switch (FileSystemList->CurrentFileSystem) { case FsFat: - Status = FormatPartition (&DestinationRootPath); - if (!NT_SUCCESS (Status)) - { - DPRINT1 ("FormatPartition() failed with status 0x%.08x\n", Status); - /* FIXME: show an error dialog */ - return QUIT_PAGE; - } - - PartEntry->New = FALSE; - if (FileSystemList != NULL) - { - DestroyFileSystemList (FileSystemList); - FileSystemList = NULL; - } - - CheckActiveBootPartition (PartitionList); - /* FIXME: Install boot code. This is a hack! */ if ((PartEntry->PartInfo[0].PartitionType == PARTITION_FAT32_XINT13) || (PartEntry->PartInfo[0].PartitionType == PARTITION_FAT32)) @@ -2534,13 +2541,34 @@ FormatPartitionPage (PINPUT_RECORD Ir) } break; + case FsExt2: + { + wcscpy (PathBuffer, SourceRootPath.Buffer); + wcscat (PathBuffer, L"\\loader\\ext2.bin"); + + DPRINT ("Install EXT2 bootcode: %S ==> %S\n", PathBuffer, + DestinationRootPath.Buffer); + Status = InstallExt2BootCodeToDisk (PathBuffer, + DestinationRootPath.Buffer); + if (!NT_SUCCESS (Status)) + { + DPRINT1 ("InstallExt2BootCodeToDisk() failed with status 0x%.08x\n", Status); + /* FIXME: show an error dialog */ + return QUIT_PAGE; + } + } + break; + case FsKeep: break; - default: - return QUIT_PAGE; + default: + return QUIT_PAGE; } + DestroyFileSystemList (FileSystemList); + FileSystemList = NULL; + #ifndef NDEBUG SetStatusText (" Done. Press any key ..."); ConInKey(Ir); From 19a3f56aa7121bf3c8b7b027e2bbf6efc7025b52 Mon Sep 17 00:00:00 2001 From: Art Yerkes Date: Thu, 13 Jan 2005 02:39:38 +0000 Subject: [PATCH 4/8] Added forgotten ext2.c svn path=/branches/ext2/; revision=13013 --- reactos/drivers/fs/fs_rec/ext2.c | 136 +++++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 reactos/drivers/fs/fs_rec/ext2.c diff --git a/reactos/drivers/fs/fs_rec/ext2.c b/reactos/drivers/fs/fs_rec/ext2.c new file mode 100644 index 00000000000..2fa7339cadb --- /dev/null +++ b/reactos/drivers/fs/fs_rec/ext2.c @@ -0,0 +1,136 @@ +/* + * ReactOS kernel + * Copyright (C) 2002,2003 ReactOS Team + * + * 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. + */ +/* $Id: fat.c 9284 2004-05-02 20:12:38Z hbirr $ + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: drivers/fs/fs_rec/ext2.c (based on vfat.c) + * PURPOSE: Filesystem recognizer driver + * PROGRAMMER: Eric Kohl + */ + +/* INCLUDES *****************************************************************/ + +#include +#include + +#define NDEBUG +#include + +#include "fs_rec.h" + + +/* FUNCTIONS ****************************************************************/ + +static NTSTATUS +FsRecIsExt2Volume(IN PDEVICE_OBJECT DeviceObject) +{ + NTSTATUS Status; + PARTITION_INFORMATION PartitionInfo; + DISK_GEOMETRY DiskGeometry; + ULONG Size; + BOOL RecognizedFS = FALSE; + Size = sizeof(DISK_GEOMETRY); + + Status = FsRecDeviceIoControl(DeviceObject, + IOCTL_DISK_GET_DRIVE_GEOMETRY, + NULL, + 0, + &DiskGeometry, + &Size); + if (!NT_SUCCESS(Status)) + { + DPRINT("FsRecDeviceIoControl faild (%x)\n", Status); + return Status; + } + if (DiskGeometry.MediaType == FixedMedia || DiskGeometry.MediaType == RemovableMedia) + { + // We have found a hard disk + Size = sizeof(PARTITION_INFORMATION); + Status = FsRecDeviceIoControl(DeviceObject, + IOCTL_DISK_GET_PARTITION_INFO, + NULL, + 0, + &PartitionInfo, + &Size); + if (!NT_SUCCESS(Status)) + { + DPRINT("FsRecDeviceIoControl faild (%x)\n", Status); + return Status; + } + + if (PartitionInfo.PartitionType) + { + if (PartitionInfo.PartitionType == PARTITION_EXT2) + { + RecognizedFS = TRUE; + } + } + } + + return RecognizedFS ? STATUS_SUCCESS : STATUS_UNRECOGNIZED_VOLUME; +} + + +NTSTATUS +FsRecExt2FsControl(IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + PIO_STACK_LOCATION Stack; + UNICODE_STRING RegistryPath; + NTSTATUS Status; + + Stack = IoGetCurrentIrpStackLocation(Irp); + + switch (Stack->MinorFunction) + { + case IRP_MN_MOUNT_VOLUME: + DPRINT("FAT: IRP_MN_MOUNT_VOLUME\n"); + Status = FsRecIsExt2Volume(Stack->Parameters.MountVolume.DeviceObject); + if (NT_SUCCESS(Status)) + { + DPRINT("Identified FAT volume\n"); + Status = STATUS_FS_DRIVER_REQUIRED; + } + break; + + case IRP_MN_LOAD_FILE_SYSTEM: + DPRINT("FAT: IRP_MN_LOAD_FILE_SYSTEM\n"); + RtlRosInitUnicodeStringFromLiteral(&RegistryPath, + L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Ext2"); + Status = ZwLoadDriver(&RegistryPath); + if (!NT_SUCCESS(Status)) + { + DPRINT("ZwLoadDriver failed (Status %x)\n", Status); + } + else + { + IoUnregisterFileSystem(DeviceObject); + } + break; + + default: + DPRINT("FAT: Unknown minor function %lx\n", Stack->MinorFunction); + Status = STATUS_INVALID_DEVICE_REQUEST; + break; + } + return(Status); +} + +/* EOF */ From 68e05d3a8e8a2b49b11ae84ff7bf10ee8fd1e637 Mon Sep 17 00:00:00 2001 From: Art Yerkes Date: Thu, 13 Jan 2005 02:46:38 +0000 Subject: [PATCH 5/8] Added forgotten .h ext2lib.h svn path=/branches/ext2/; revision=13014 --- reactos/include/fslib/ext2lib.h | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 reactos/include/fslib/ext2lib.h diff --git a/reactos/include/fslib/ext2lib.h b/reactos/include/fslib/ext2lib.h new file mode 100644 index 00000000000..58390b0310a --- /dev/null +++ b/reactos/include/fslib/ext2lib.h @@ -0,0 +1,26 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS EXT2 filesystem library + * FILE: include/fslib/ext2lib.h + * PURPOSE: Public definitions for ext2 filesystem library + */ +#ifndef __EXT2LIB_H +#define __EXT2LIB_H + +#include + +NTSTATUS +Ext2Initialize (VOID); + +NTSTATUS +Ext2Cleanup (VOID); + +NTSTATUS +Ext2Format (PUNICODE_STRING DriveRoot, + ULONG MediaFlag, + PUNICODE_STRING Label, + BOOLEAN QuickFormat, + ULONG ClusterSize, + PFMIFSCALLBACK Callback); + +#endif /*__EXT2LIB_H */ From aa898e0ba242f2e3f4ab4b673747c3d38e74d3e0 Mon Sep 17 00:00:00 2001 From: Art Yerkes Date: Thu, 20 Jan 2005 02:09:33 +0000 Subject: [PATCH 6/8] Extras for enabling ext2 in reactos. svn path=/branches/ext2/; revision=13150 --- reactos/Makefile | 4 +- .../boot/freeldr/freeldr/reactos/setupldr.c | 3 + reactos/subsys/system/usetup/bootsup.c | 210 ------------------ 3 files changed, 5 insertions(+), 212 deletions(-) diff --git a/reactos/Makefile b/reactos/Makefile index 1ef2941fd5e..461067a8465 100644 --- a/reactos/Makefile +++ b/reactos/Makefile @@ -39,7 +39,7 @@ BUS = acpi isapnp pci # Filesystem libraries # vfatlib -LIB_FSLIB = vfatlib +LIB_FSLIB = vfatlib ext2lib # Static libraries LIB_STATIC = string rosrtl epsapi uuid libwine zlib rtl tgetopt pseh adns dxguid strmiids @@ -84,7 +84,7 @@ INPUT_DRIVERS = keyboard mouclass psaux sermouse # Kernel mode file system drivers # cdfs ext2 fs_rec ms np vfat -FS_DRIVERS = cdfs fs_rec ms np vfat mup ntfs +FS_DRIVERS = cdfs fs_rec ms np vfat ext2 mup ntfs # Kernel mode networking drivers # afd ndis npf tcpip tdi wshtcpip diff --git a/reactos/boot/freeldr/freeldr/reactos/setupldr.c b/reactos/boot/freeldr/freeldr/reactos/setupldr.c index 23db7fd56ea..6e41da06485 100644 --- a/reactos/boot/freeldr/freeldr/reactos/setupldr.c +++ b/reactos/boot/freeldr/freeldr/reactos/setupldr.c @@ -556,6 +556,9 @@ for(;;); if (!LoadDriver(SourcePath, "vfatfs.sys")) return; + /* Load ext2.sys (could be loaded by the setup prog!) */ + if (!LoadDriver(SourcePath, "ext2.sys")) + return; /* Load keyboard driver */ if (!LoadDriver(SourcePath, "keyboard.sys")) diff --git a/reactos/subsys/system/usetup/bootsup.c b/reactos/subsys/system/usetup/bootsup.c index 02bd4d4aa5a..cd7fb3e78dc 100644 --- a/reactos/subsys/system/usetup/bootsup.c +++ b/reactos/subsys/system/usetup/bootsup.c @@ -1541,216 +1541,6 @@ InstallFat32BootCodeToDisk(PWSTR SrcPath, return(Status); } - -NTSTATUS -InstallExt2BootCodeToDisk(PWSTR SrcPath, - PWSTR RootPath) -{ - OBJECT_ATTRIBUTES ObjectAttributes; - IO_STATUS_BLOCK IoStatusBlock; - UNICODE_STRING Name; - HANDLE FileHandle; - NTSTATUS Status; - PUCHAR OrigBootSector; - PUCHAR NewBootSector; - LARGE_INTEGER FileOffset; - USHORT BackupBootSector; - - /* Allocate buffer for original bootsector */ - OrigBootSector = (PUCHAR)RtlAllocateHeap(ProcessHeap, - 0, - SECTORSIZE); - if (OrigBootSector == NULL) - return(STATUS_INSUFFICIENT_RESOURCES); - - /* Read current boot sector into buffer */ - RtlInitUnicodeString(&Name, - RootPath); - - InitializeObjectAttributes(&ObjectAttributes, - &Name, - OBJ_CASE_INSENSITIVE, - NULL, - NULL); - - Status = NtOpenFile(&FileHandle, - FILE_READ_ACCESS, - &ObjectAttributes, - &IoStatusBlock, - 0, - FILE_SYNCHRONOUS_IO_NONALERT); - if (!NT_SUCCESS(Status)) - { - RtlFreeHeap(ProcessHeap, 0, OrigBootSector); - return(Status); - } - - Status = NtReadFile(FileHandle, - NULL, - NULL, - NULL, - &IoStatusBlock, - OrigBootSector, - SECTORSIZE, - NULL, - NULL); - NtClose(FileHandle); - if (!NT_SUCCESS(Status)) - { - RtlFreeHeap(ProcessHeap, 0, OrigBootSector); - return(Status); - } - - - /* Allocate buffer for new bootsector (2 sectors) */ - NewBootSector = (PUCHAR)RtlAllocateHeap(ProcessHeap, - 0, - 2 * SECTORSIZE); - if (NewBootSector == NULL) - { - RtlFreeHeap(ProcessHeap, 0, OrigBootSector); - return(STATUS_INSUFFICIENT_RESOURCES); - } - - /* Read new bootsector from SrcPath */ - RtlInitUnicodeString(&Name, - SrcPath); - - InitializeObjectAttributes(&ObjectAttributes, - &Name, - OBJ_CASE_INSENSITIVE, - NULL, - NULL); - - Status = NtOpenFile(&FileHandle, - FILE_READ_ACCESS, - &ObjectAttributes, - &IoStatusBlock, - 0, - FILE_SYNCHRONOUS_IO_NONALERT); - if (!NT_SUCCESS(Status)) - { - RtlFreeHeap(ProcessHeap, 0, OrigBootSector); - RtlFreeHeap(ProcessHeap, 0, NewBootSector); - return(Status); - } - - Status = NtReadFile(FileHandle, - NULL, - NULL, - NULL, - &IoStatusBlock, - NewBootSector, - 2 * SECTORSIZE, - NULL, - NULL); - NtClose(FileHandle); - if (!NT_SUCCESS(Status)) - { - RtlFreeHeap(ProcessHeap, 0, OrigBootSector); - RtlFreeHeap(ProcessHeap, 0, NewBootSector); - return(Status); - } - - /* Adjust bootsector (copy a part of the FAT32 BPB) */ - memcpy((NewBootSector + 3), - (OrigBootSector + 3), - 87); /* FAT32 BPB length */ - - /* Get the location of the backup boot sector */ - BackupBootSector = (OrigBootSector[0x33] << 8) + OrigBootSector[0x32]; - - /* Free the original boot sector */ - RtlFreeHeap(ProcessHeap, 0, OrigBootSector); - - /* Write the first sector of the new bootcode to DstPath */ - RtlInitUnicodeString(&Name, - RootPath); - - InitializeObjectAttributes(&ObjectAttributes, - &Name, - 0, - NULL, - NULL); - - Status = NtOpenFile(&FileHandle, - FILE_WRITE_ACCESS | FILE_WRITE_ATTRIBUTES, - &ObjectAttributes, - &IoStatusBlock, - 0, - FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY); - if (!NT_SUCCESS(Status)) - { - DPRINT1("NtOpenFile() failed (Status %lx)\n", Status); - RtlFreeHeap(ProcessHeap, 0, NewBootSector); - return(Status); - } - - /* Write sector 0 */ - FileOffset.QuadPart = 0ULL; - Status = NtWriteFile(FileHandle, - NULL, - NULL, - NULL, - &IoStatusBlock, - NewBootSector, - SECTORSIZE, - &FileOffset, - NULL); - if (!NT_SUCCESS(Status)) - { - DPRINT1("NtWriteFile() failed (Status %lx)\n", Status); - NtClose(FileHandle); - RtlFreeHeap(ProcessHeap, 0, NewBootSector); - return(Status); - } - - /* Write backup boot sector */ - if ((BackupBootSector != 0x0000) && (BackupBootSector != 0xFFFF)) - { - FileOffset.QuadPart = (ULONGLONG)((ULONG)BackupBootSector * SECTORSIZE); - Status = NtWriteFile(FileHandle, - NULL, - NULL, - NULL, - &IoStatusBlock, - NewBootSector, - SECTORSIZE, - &FileOffset, - NULL); - if (!NT_SUCCESS(Status)) - { - DPRINT1("NtWriteFile() failed (Status %lx)\n", Status); - NtClose(FileHandle); - RtlFreeHeap(ProcessHeap, 0, NewBootSector); - return(Status); - } - } - - /* Write sector 14 */ - FileOffset.QuadPart = (ULONGLONG)(14 * SECTORSIZE); - Status = NtWriteFile(FileHandle, - NULL, - NULL, - NULL, - &IoStatusBlock, - (NewBootSector + SECTORSIZE), - SECTORSIZE, - &FileOffset, - NULL); - if (!NT_SUCCESS(Status)) - { - DPRINT1("NtWriteFile() failed (Status %lx)\n", Status); - } - NtClose(FileHandle); - - /* Free the new boot sector */ - RtlFreeHeap(ProcessHeap, 0, NewBootSector); - - return(Status); -} - - NTSTATUS InstallExt2BootCodeToDisk(PWSTR SrcPath, PWSTR RootPath) From b0891d210c57dd598616b07ff0ef8c11e2032579 Mon Sep 17 00:00:00 2001 From: Hartmut Birr Date: Thu, 20 Jan 2005 23:24:51 +0000 Subject: [PATCH 7/8] Fixed the range which must be zeroed if the write starts after the end of the file. svn path=/branches/ext2/; revision=13173 --- reactos/drivers/fs/ext2/src/write.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/reactos/drivers/fs/ext2/src/write.c b/reactos/drivers/fs/ext2/src/write.c index 1fd2ce7ca3a..1725a420152 100644 --- a/reactos/drivers/fs/ext2/src/write.c +++ b/reactos/drivers/fs/ext2/src/write.c @@ -544,7 +544,7 @@ NTSTATUS Ext2CommonWrite( LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize; - if ( ByteOffset.QuadPart + WriteLength >= PtrReqdFCB->CommonFCBHeader.FileSize.QuadPart ) + if ( ByteOffset.QuadPart + WriteLength > PtrReqdFCB->CommonFCBHeader.FileSize.QuadPart ) { if( PagingIo ) { @@ -621,7 +621,7 @@ NTSTATUS Ext2CommonWrite( // Start offset is the New File size StartOffsetForZeroing.QuadPart = - PtrReqdFCB->CommonFCBHeader.FileSize.QuadPart + WriteLength; + ByteOffset.QuadPart + WriteLength; // End offset is the New Allocation size EndOffsetForZeroing.QuadPart = PtrReqdFCB->CommonFCBHeader.AllocationSize.QuadPart; } From 9e0b1f1383b96f801152c75ac45cf41e7c5b13f7 Mon Sep 17 00:00:00 2001 From: Art Yerkes Date: Thu, 27 Jan 2005 08:16:42 +0000 Subject: [PATCH 8/8] Suggested fix for atapi. The atapi driver wants whole sectors, but the ext2 driver sometimes attempts an incomplete write. Here we fill the remaineder of the sector with zeros. This isn't the most elegant way to do it but illustrates the problem. I'm committing this here because it's a branch. svn path=/branches/ext2/; revision=13336 --- reactos/drivers/storage/atapi/atapi.c | 50 +++++++++++++++++++++++---- 1 file changed, 44 insertions(+), 6 deletions(-) diff --git a/reactos/drivers/storage/atapi/atapi.c b/reactos/drivers/storage/atapi/atapi.c index 26f11ef16e6..7969f1eb61f 100644 --- a/reactos/drivers/storage/atapi/atapi.c +++ b/reactos/drivers/storage/atapi/atapi.c @@ -2000,12 +2000,12 @@ AtapiReadWrite(PATAPI_MINIPORT_EXTENSION DeviceExtension, UCHAR CylinderLow; UCHAR DrvHead; UCHAR SectorNumber; - UCHAR Command; + UCHAR Command = 0; ULONG Retries; UCHAR Status; BOOLEAN FASTCALL (*Handler)(PATAPI_MINIPORT_EXTENSION DevExt); - DPRINT("AtapiReadWrite() called!\n"); + DPRINT("AtaiReadWrite() called!\n"); DPRINT("SCSIOP_WRITE: TargetId: %lu\n", Srb->TargetId); @@ -2144,13 +2144,16 @@ AtapiReadWrite(PATAPI_MINIPORT_EXTENSION DeviceExtension, if (DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_MULTI_SECTOR_CMD) { Command = Srb->SrbFlags & SRB_FLAGS_DATA_IN ? IDE_CMD_READ_MULTIPLE : IDE_CMD_WRITE_MULTIPLE; + DPRINT("Command = %x\n", Command); } else { Command = Srb->SrbFlags & SRB_FLAGS_DATA_IN ? IDE_CMD_READ : IDE_CMD_WRITE; + DPRINT("Command = %x\n", Command); } } + DPRINT("Executing Command = %x\n", Command); AtapiExecuteCommand(DeviceExtension, Command, Handler); #ifdef ENABLE_DMA @@ -2182,7 +2185,7 @@ AtapiReadWrite(PATAPI_MINIPORT_EXTENSION DeviceExtension, } if (Retries >= IDE_MAX_WRITE_RETRIES) { - DPRINT1("Drive is BUSY for too long after sending write command\n"); + DPRINT("Drive is BUSY for too long after sending write command\n"); return(SRB_STATUS_BUSY); } @@ -2200,12 +2203,47 @@ AtapiReadWrite(PATAPI_MINIPORT_EXTENSION DeviceExtension, /* Write data block */ if (DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_DWORD_IO) { - IDEWriteBlock32(DeviceExtension->CommandPortBase, - TargetAddress, - TransferSize); + UINT Temp = 0; + UINT ExtraWord = TransferSize & (sizeof(UINT)-1); + UINT EndOfBlock; + + DPRINT("IDEWriteBlock32(%x, %d)\n", + DeviceExtension->CommandPortBase, + TransferSize); + IDEWriteBlock32(DeviceExtension->CommandPortBase, + TargetAddress, + TransferSize); + if( ExtraWord ) { + RtlCopyMemory( &Temp, + TargetAddress + + (TransferSize & (sizeof(UINT)-1)), + ExtraWord ); + IDEWriteBlock32(DeviceExtension->CommandPortBase, + &Temp, + sizeof(Temp)); + TransferSize = (TransferSize + sizeof(UINT)) & + ~(sizeof(UINT) - 1); + } + + Temp = 0; + + DPRINT("TransferSize = %d (BPS %d)\n", + TransferSize, DeviceParams->BytesPerSector); + + EndOfBlock = DeviceParams->BytesPerSector - + (TransferSize & (DeviceParams->BytesPerSector - 1)); + + while( EndOfBlock ) { + DPRINT("Zeros Remaining %d\n", EndOfBlock); + IDEWriteBlock32(DeviceExtension->CommandPortBase, + &Temp, + sizeof(Temp)); + EndOfBlock -= sizeof(Temp); + } } else { + DPRINT1("IDEWriteBlock(%x)\n", DeviceExtension->CommandPortBase); IDEWriteBlock(DeviceExtension->CommandPortBase, TargetAddress, TransferSize);