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); -} -