/* * COPYRIGHT: GNU GENERAL PUBLIC LICENSE VERSION 2 * PROJECT: ReiserFs file system driver for Windows NT/2000/XP/Vista. * FILE: fileinfo.c * PURPOSE: * PROGRAMMER: Mark Piper, Matt Wu, Bo Brantén. * HOMEPAGE: * UPDATE HISTORY: */ /* INCLUDES *****************************************************************/ #include "rfsd.h" /* GLOBALS ***************************************************************/ extern PRFSD_GLOBAL RfsdGlobal; /* DEFINITIONS *************************************************************/ #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGE, RfsdQueryInformation) #pragma alloc_text(PAGE, RfsdSetInformation) #if !RFSD_READ_ONLY #pragma alloc_text(PAGE, RfsdExpandFile) #pragma alloc_text(PAGE, RfsdTruncateFile) #pragma alloc_text(PAGE, RfsdSetDispositionInfo) #pragma alloc_text(PAGE, RfsdSetRenameInfo) #pragma alloc_text(PAGE, RfsdDeleteFile) #endif // !RFSD_READ_ONLY #endif __drv_mustHoldCriticalRegion NTSTATUS RfsdQueryInformation (IN PRFSD_IRP_CONTEXT IrpContext) { PDEVICE_OBJECT DeviceObject; NTSTATUS Status = STATUS_UNSUCCESSFUL; PFILE_OBJECT FileObject; PRFSD_VCB Vcb; PRFSD_FCB Fcb = 0; PRFSD_CCB Ccb; PIRP Irp; PIO_STACK_LOCATION IoStackLocation; FILE_INFORMATION_CLASS FileInformationClass; ULONG Length; PVOID Buffer; BOOLEAN FcbResourceAcquired = FALSE; LONGLONG FileSize; LONGLONG AllocationSize; PAGED_CODE(); _SEH2_TRY { ASSERT(IrpContext != NULL); ASSERT((IrpContext->Identifier.Type == RFSDICX) && (IrpContext->Identifier.Size == sizeof(RFSD_IRP_CONTEXT))); DeviceObject = IrpContext->DeviceObject; // // This request is not allowed on the main device object // if (DeviceObject == RfsdGlobal->DeviceObject) { Status = STATUS_INVALID_DEVICE_REQUEST; _SEH2_LEAVE; } FileObject = IrpContext->FileObject; Fcb = (PRFSD_FCB) FileObject->FsContext; ASSERT(Fcb != NULL); // // This request is not allowed on volumes // if (Fcb->Identifier.Type == RFSDVCB) { Status = STATUS_INVALID_PARAMETER; _SEH2_LEAVE; } ASSERT((Fcb->Identifier.Type == RFSDFCB) && (Fcb->Identifier.Size == sizeof(RFSD_FCB))); Vcb = Fcb->Vcb; /* if ( !IsFlagOn(Fcb->Vcb->Flags, VCB_READ_ONLY) && !FlagOn(Fcb->Flags, FCB_PAGE_FILE)) */ { if (!ExAcquireResourceSharedLite( &Fcb->MainResource, IrpContext->IsSynchronous )) { Status = STATUS_PENDING; _SEH2_LEAVE; } FcbResourceAcquired = TRUE; } Ccb = (PRFSD_CCB) FileObject->FsContext2; ASSERT(Ccb != NULL); ASSERT((Ccb->Identifier.Type == RFSDCCB) && (Ccb->Identifier.Size == sizeof(RFSD_CCB))); Irp = IrpContext->Irp; IoStackLocation = IoGetCurrentIrpStackLocation(Irp); FileInformationClass = IoStackLocation->Parameters.QueryFile.FileInformationClass; Length = IoStackLocation->Parameters.QueryFile.Length; Buffer = Irp->AssociatedIrp.SystemBuffer; RtlZeroMemory(Buffer, Length); FileSize = (LONGLONG) Fcb->Inode->i_size; AllocationSize = CEILING_ALIGNED(FileSize, (ULONGLONG)Vcb->BlockSize); switch (FileInformationClass) { case FileBasicInformation: { PFILE_BASIC_INFORMATION FileBasicInformation; if (Length < sizeof(FILE_BASIC_INFORMATION)) { Status = STATUS_INFO_LENGTH_MISMATCH; _SEH2_LEAVE; } FileBasicInformation = (PFILE_BASIC_INFORMATION) Buffer; FileBasicInformation->CreationTime = RfsdSysTime(Fcb->Inode->i_ctime); FileBasicInformation->LastAccessTime = RfsdSysTime(Fcb->Inode->i_atime); FileBasicInformation->LastWriteTime = RfsdSysTime(Fcb->Inode->i_mtime); FileBasicInformation->ChangeTime = RfsdSysTime(Fcb->Inode->i_mtime); FileBasicInformation->FileAttributes = Fcb->RfsdMcb->FileAttr; Irp->IoStatus.Information = sizeof(FILE_BASIC_INFORMATION); Status = STATUS_SUCCESS; _SEH2_LEAVE; } #if (_WIN32_WINNT >= 0x0500) case FileAttributeTagInformation: { PFILE_ATTRIBUTE_TAG_INFORMATION FATI; if (Length < sizeof(FILE_ATTRIBUTE_TAG_INFORMATION)) { Status = STATUS_INFO_LENGTH_MISMATCH; _SEH2_LEAVE; } FATI = (PFILE_ATTRIBUTE_TAG_INFORMATION) Buffer; FATI->FileAttributes = Fcb->RfsdMcb->FileAttr; FATI->ReparseTag = 0; Irp->IoStatus.Information = sizeof(FILE_ATTRIBUTE_TAG_INFORMATION); Status = STATUS_SUCCESS; _SEH2_LEAVE; } #endif // (_WIN32_WINNT >= 0x0500) case FileStandardInformation: { PFILE_STANDARD_INFORMATION FileStandardInformation; if (Length < sizeof(FILE_STANDARD_INFORMATION)) { Status = STATUS_INFO_LENGTH_MISMATCH; _SEH2_LEAVE; } FileStandardInformation = (PFILE_STANDARD_INFORMATION) Buffer; FileStandardInformation->AllocationSize.QuadPart = AllocationSize; FileStandardInformation->EndOfFile.QuadPart = FileSize; FileStandardInformation->NumberOfLinks = Fcb->Inode->i_links_count; if (IsFlagOn(Fcb->Vcb->Flags, VCB_READ_ONLY)) FileStandardInformation->DeletePending = FALSE; else FileStandardInformation->DeletePending = IsFlagOn(Fcb->Flags, FCB_DELETE_PENDING); if (Fcb->RfsdMcb->FileAttr & FILE_ATTRIBUTE_DIRECTORY) { FileStandardInformation->Directory = TRUE; } else { FileStandardInformation->Directory = FALSE; } Irp->IoStatus.Information = sizeof(FILE_STANDARD_INFORMATION); Status = STATUS_SUCCESS; _SEH2_LEAVE; } case FileInternalInformation: { PFILE_INTERNAL_INFORMATION FileInternalInformation; if (Length < sizeof(FILE_INTERNAL_INFORMATION)) { Status = STATUS_INFO_LENGTH_MISMATCH; _SEH2_LEAVE; } FileInternalInformation = (PFILE_INTERNAL_INFORMATION) Buffer; // The "inode number" FileInternalInformation->IndexNumber.LowPart = Fcb->RfsdMcb->Key.k_dir_id; FileInternalInformation->IndexNumber.HighPart = Fcb->RfsdMcb->Key.k_objectid; Irp->IoStatus.Information = sizeof(FILE_INTERNAL_INFORMATION); Status = STATUS_SUCCESS; _SEH2_LEAVE; } case FileEaInformation: { PFILE_EA_INFORMATION FileEaInformation; if (Length < sizeof(FILE_EA_INFORMATION)) { Status = STATUS_INFO_LENGTH_MISMATCH; _SEH2_LEAVE; } FileEaInformation = (PFILE_EA_INFORMATION) Buffer; // Romfs doesn't have any extended attributes FileEaInformation->EaSize = 0; Irp->IoStatus.Information = sizeof(FILE_EA_INFORMATION); Status = STATUS_SUCCESS; _SEH2_LEAVE; } case FileNameInformation: { PFILE_NAME_INFORMATION FileNameInformation; if (Length < sizeof(FILE_NAME_INFORMATION) + Fcb->RfsdMcb->ShortName.Length - sizeof(WCHAR)) { Status = STATUS_INFO_LENGTH_MISMATCH; _SEH2_LEAVE; } FileNameInformation = (PFILE_NAME_INFORMATION) Buffer; FileNameInformation->FileNameLength = Fcb->RfsdMcb->ShortName.Length; RtlCopyMemory( FileNameInformation->FileName, Fcb->RfsdMcb->ShortName.Buffer, Fcb->RfsdMcb->ShortName.Length ); Irp->IoStatus.Information = sizeof(FILE_NAME_INFORMATION) + Fcb->RfsdMcb->ShortName.Length - sizeof(WCHAR); Status = STATUS_SUCCESS; _SEH2_LEAVE; } case FilePositionInformation: { PFILE_POSITION_INFORMATION FilePositionInformation; if (Length < sizeof(FILE_POSITION_INFORMATION)) { Status = STATUS_INFO_LENGTH_MISMATCH; _SEH2_LEAVE; } FilePositionInformation = (PFILE_POSITION_INFORMATION) Buffer; FilePositionInformation->CurrentByteOffset = FileObject->CurrentByteOffset; Irp->IoStatus.Information = sizeof(FILE_POSITION_INFORMATION); Status = STATUS_SUCCESS; _SEH2_LEAVE; } case FileAllInformation: { PFILE_ALL_INFORMATION FileAllInformation; PFILE_BASIC_INFORMATION FileBasicInformation; PFILE_STANDARD_INFORMATION FileStandardInformation; PFILE_INTERNAL_INFORMATION FileInternalInformation; PFILE_EA_INFORMATION FileEaInformation; PFILE_POSITION_INFORMATION FilePositionInformation; PFILE_NAME_INFORMATION FileNameInformation; if (Length < sizeof(FILE_ALL_INFORMATION)) { Status = STATUS_INFO_LENGTH_MISMATCH; _SEH2_LEAVE; } FileAllInformation = (PFILE_ALL_INFORMATION) Buffer; FileBasicInformation = &FileAllInformation->BasicInformation; FileStandardInformation = &FileAllInformation->StandardInformation; FileInternalInformation = &FileAllInformation->InternalInformation; FileEaInformation = &FileAllInformation->EaInformation; FilePositionInformation = &FileAllInformation->PositionInformation; FileNameInformation = &FileAllInformation->NameInformation; FileBasicInformation->CreationTime = RfsdSysTime(Fcb->Inode->i_ctime); FileBasicInformation->LastAccessTime = RfsdSysTime(Fcb->Inode->i_atime); FileBasicInformation->LastWriteTime = RfsdSysTime(Fcb->Inode->i_mtime); FileBasicInformation->ChangeTime = RfsdSysTime(Fcb->Inode->i_mtime); FileBasicInformation->FileAttributes = Fcb->RfsdMcb->FileAttr; FileStandardInformation->AllocationSize.QuadPart = AllocationSize; FileStandardInformation->EndOfFile.QuadPart = FileSize; FileStandardInformation->NumberOfLinks = Fcb->Inode->i_links_count; if (IsFlagOn(Fcb->Vcb->Flags, VCB_READ_ONLY)) FileStandardInformation->DeletePending = FALSE; else FileStandardInformation->DeletePending = IsFlagOn(Fcb->Flags, FCB_DELETE_PENDING); if (FlagOn(Fcb->RfsdMcb->FileAttr, FILE_ATTRIBUTE_DIRECTORY)) { FileStandardInformation->Directory = TRUE; } else { FileStandardInformation->Directory = FALSE; } // The "inode number" FileInternalInformation->IndexNumber.LowPart = Fcb->RfsdMcb->Key.k_dir_id; FileInternalInformation->IndexNumber.HighPart = Fcb->RfsdMcb->Key.k_objectid; // Romfs doesn't have any extended attributes FileEaInformation->EaSize = 0; FilePositionInformation->CurrentByteOffset = FileObject->CurrentByteOffset; if (Length < sizeof(FILE_ALL_INFORMATION) + Fcb->RfsdMcb->ShortName.Length - sizeof(WCHAR)) { Irp->IoStatus.Information = sizeof(FILE_ALL_INFORMATION); Status = STATUS_BUFFER_OVERFLOW; _SEH2_LEAVE; } FileNameInformation->FileNameLength = Fcb->RfsdMcb->ShortName.Length; RtlCopyMemory( FileNameInformation->FileName, Fcb->RfsdMcb->ShortName.Buffer, Fcb->RfsdMcb->ShortName.Length ); Irp->IoStatus.Information = sizeof(FILE_ALL_INFORMATION) + Fcb->RfsdMcb->ShortName.Length - sizeof(WCHAR); Status = STATUS_SUCCESS; _SEH2_LEAVE; } /* case FileAlternateNameInformation: { // TODO: [ext2fsd] Handle FileAlternateNameInformation // Here we would like to use RtlGenerate8dot3Name but I don't // know how to use the argument PGENERATE_NAME_CONTEXT } */ case FileNetworkOpenInformation: { PFILE_NETWORK_OPEN_INFORMATION FileNetworkOpenInformation; if (Length < sizeof(FILE_NETWORK_OPEN_INFORMATION)) { Status = STATUS_INFO_LENGTH_MISMATCH; _SEH2_LEAVE; } FileNetworkOpenInformation = (PFILE_NETWORK_OPEN_INFORMATION) Buffer; FileNetworkOpenInformation->CreationTime = RfsdSysTime(Fcb->Inode->i_ctime); FileNetworkOpenInformation->LastAccessTime = RfsdSysTime(Fcb->Inode->i_atime); FileNetworkOpenInformation->LastWriteTime = RfsdSysTime(Fcb->Inode->i_mtime); FileNetworkOpenInformation->ChangeTime = RfsdSysTime(Fcb->Inode->i_mtime); FileNetworkOpenInformation->AllocationSize.QuadPart = AllocationSize; FileNetworkOpenInformation->EndOfFile.QuadPart = FileSize; FileNetworkOpenInformation->FileAttributes = Fcb->RfsdMcb->FileAttr; Irp->IoStatus.Information = sizeof(FILE_NETWORK_OPEN_INFORMATION); Status = STATUS_SUCCESS; _SEH2_LEAVE; } default: Status = STATUS_INVALID_INFO_CLASS; } } _SEH2_FINALLY { if (FcbResourceAcquired) { ExReleaseResourceForThreadLite( &Fcb->MainResource, ExGetCurrentResourceThread()); } if (!IrpContext->ExceptionInProgress) { if (Status == STATUS_PENDING) { RfsdQueueRequest(IrpContext); } else { RfsdCompleteIrpContext(IrpContext, Status); } } } _SEH2_END; return Status; } __drv_mustHoldCriticalRegion NTSTATUS RfsdSetInformation (IN PRFSD_IRP_CONTEXT IrpContext) { PDEVICE_OBJECT DeviceObject; NTSTATUS Status = STATUS_UNSUCCESSFUL; PRFSD_VCB Vcb = 0; PFILE_OBJECT FileObject; PRFSD_FCB Fcb = 0; PRFSD_CCB Ccb; PIRP Irp; PIO_STACK_LOCATION IoStackLocation; FILE_INFORMATION_CLASS FileInformationClass; ULONG NotifyFilter = 0; ULONG Length; PVOID Buffer; BOOLEAN FcbMainResourceAcquired = FALSE; BOOLEAN VcbResourceAcquired = FALSE; BOOLEAN FcbPagingIoResourceAcquired = FALSE; PAGED_CODE(); _SEH2_TRY { ASSERT(IrpContext != NULL); ASSERT((IrpContext->Identifier.Type == RFSDICX) && (IrpContext->Identifier.Size == sizeof(RFSD_IRP_CONTEXT))); DeviceObject = IrpContext->DeviceObject; // // This request is not allowed on the main device object // if (DeviceObject == RfsdGlobal->DeviceObject) { Status = STATUS_INVALID_DEVICE_REQUEST; _SEH2_LEAVE; } Vcb = (PRFSD_VCB) DeviceObject->DeviceExtension; ASSERT(Vcb != NULL); ASSERT((Vcb->Identifier.Type == RFSDVCB) && (Vcb->Identifier.Size == sizeof(RFSD_VCB))); ASSERT(IsMounted(Vcb)); FileObject = IrpContext->FileObject; Fcb = (PRFSD_FCB) FileObject->FsContext; ASSERT(Fcb != NULL); // // This request is not allowed on volumes // if (Fcb->Identifier.Type == RFSDVCB) { DbgBreak(); Status = STATUS_INVALID_PARAMETER; _SEH2_LEAVE; } ASSERT((Fcb->Identifier.Type == RFSDFCB) && (Fcb->Identifier.Size == sizeof(RFSD_FCB))); if (IsFlagOn(Fcb->Flags, FCB_FILE_DELETED)) { Status = STATUS_FILE_DELETED; _SEH2_LEAVE; } Ccb = (PRFSD_CCB) FileObject->FsContext2; ASSERT(Ccb != NULL); ASSERT((Ccb->Identifier.Type == RFSDCCB) && (Ccb->Identifier.Size == sizeof(RFSD_CCB))); Irp = IrpContext->Irp; IoStackLocation = IoGetCurrentIrpStackLocation(Irp); FileInformationClass = IoStackLocation->Parameters.SetFile.FileInformationClass; Length = IoStackLocation->Parameters.SetFile.Length; Buffer = Irp->AssociatedIrp.SystemBuffer; if (IsFlagOn(Vcb->Flags, VCB_READ_ONLY)) { if (FileInformationClass == FileDispositionInformation || FileInformationClass == FileRenameInformation || FileInformationClass == FileLinkInformation) { #ifdef _MSC_VER #pragma prefast( suppress: 28137, "by design" ) #endif if (!ExAcquireResourceExclusiveLite( &Vcb->MainResource, IrpContext->IsSynchronous )) { Status = STATUS_PENDING; _SEH2_LEAVE; } VcbResourceAcquired = TRUE; } } else if (!FlagOn(Fcb->Flags, FCB_PAGE_FILE)) { #ifdef _MSC_VER #pragma prefast( suppress: 28137, "by design" ) #endif if (!ExAcquireResourceExclusiveLite( &Fcb->MainResource, IrpContext->IsSynchronous )) { Status = STATUS_PENDING; _SEH2_LEAVE; } FcbMainResourceAcquired = TRUE; } if (IsFlagOn(Vcb->Flags, VCB_READ_ONLY)) { if (FileInformationClass != FilePositionInformation) { Status = STATUS_MEDIA_WRITE_PROTECTED; _SEH2_LEAVE; } } if (FileInformationClass == FileDispositionInformation || FileInformationClass == FileRenameInformation || FileInformationClass == FileLinkInformation || FileInformationClass == FileAllocationInformation || FileInformationClass == FileEndOfFileInformation) { #ifdef _MSC_VER #pragma prefast( suppress: 28137, "by design" ) #endif if (!ExAcquireResourceExclusiveLite( &Fcb->PagingIoResource, IrpContext->IsSynchronous )) { Status = STATUS_PENDING; _SEH2_LEAVE; } FcbPagingIoResourceAcquired = TRUE; } /* if (FileInformationClass != FileDispositionInformation && FlagOn(Fcb->Flags, FCB_DELETE_PENDING)) { Status = STATUS_DELETE_PENDING; _SEH2_LEAVE; } */ switch (FileInformationClass) { #if !RFSD_READ_ONLY #if 0 case FileBasicInformation: { PFILE_BASIC_INFORMATION FBI = (PFILE_BASIC_INFORMATION) Buffer; PRFSD_INODE RfsdInode = Fcb->Inode; if (FBI->CreationTime.QuadPart) { RfsdInode->i_ctime = (ULONG)(RfsdInodeTime(FBI->CreationTime)); } if (FBI->LastAccessTime.QuadPart) { RfsdInode->i_atime = (ULONG)(RfsdInodeTime(FBI->LastAccessTime)); } if (FBI->LastWriteTime.QuadPart) { RfsdInode->i_mtime = (ULONG)(RfsdInodeTime(FBI->LastWriteTime)); } if (IsFlagOn(FBI->FileAttributes, FILE_ATTRIBUTE_READONLY)) { RfsdSetReadOnly(Fcb->Inode->i_mode); SetFlag(Fcb->RfsdMcb->FileAttr, FILE_ATTRIBUTE_READONLY); } else { RfsdSetWritable(Fcb->Inode->i_mode); ClearFlag(Fcb->RfsdMcb->FileAttr, FILE_ATTRIBUTE_READONLY); } if(RfsdSaveInode(IrpContext, Vcb, Fcb->RfsdMcb->Inode, RfsdInode)) { Status = STATUS_SUCCESS; } if (FBI->FileAttributes & FILE_ATTRIBUTE_TEMPORARY) { SetFlag(FileObject->Flags, FO_TEMPORARY_FILE); } else { ClearFlag(FileObject->Flags, FO_TEMPORARY_FILE); } NotifyFilter = FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_CREATION | FILE_NOTIFY_CHANGE_LAST_ACCESS | FILE_NOTIFY_CHANGE_LAST_WRITE ; Status = STATUS_SUCCESS; } break; case FileAllocationInformation: { PFILE_ALLOCATION_INFORMATION FAI = (PFILE_ALLOCATION_INFORMATION)Buffer; if (FlagOn(Fcb->RfsdMcb->FileAttr, FILE_ATTRIBUTE_DIRECTORY)) { Status = STATUS_INVALID_DEVICE_REQUEST; _SEH2_LEAVE; } if ( FAI->AllocationSize.QuadPart == Fcb->Header.AllocationSize.QuadPart) { Status = STATUS_SUCCESS; } else if ( FAI->AllocationSize.QuadPart > Fcb->Header.AllocationSize.QuadPart ) { Status = RfsdExpandFile( IrpContext, Vcb, Fcb, &(FAI->AllocationSize)); if (NT_SUCCESS(Status)) { RfsdSaveInode( IrpContext, Vcb, Fcb->RfsdMcb->Inode, Fcb->Inode ); } } else { if (MmCanFileBeTruncated(&(Fcb->SectionObject), &(FAI->AllocationSize))) { LARGE_INTEGER EndOfFile; EndOfFile.QuadPart = FAI->AllocationSize.QuadPart + (LONGLONG)(Vcb->BlockSize - 1); Status = RfsdTruncateFile(IrpContext, Vcb, Fcb, &(EndOfFile)); if (NT_SUCCESS(Status)) { if ( FAI->AllocationSize.QuadPart < Fcb->Header.FileSize.QuadPart) { Fcb->Header.FileSize.QuadPart = FAI->AllocationSize.QuadPart; } RfsdSaveInode( IrpContext, Vcb, Fcb->RfsdMcb->Inode, Fcb->Inode); } } else { Status = STATUS_USER_MAPPED_FILE; _SEH2_LEAVE; } } if (NT_SUCCESS(Status)) { CcSetFileSizes(FileObject, (PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize))); SetFlag(FileObject->Flags, FO_FILE_MODIFIED); NotifyFilter = FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE ; } } break; case FileEndOfFileInformation: { PFILE_END_OF_FILE_INFORMATION FEOFI = (PFILE_END_OF_FILE_INFORMATION) Buffer; BOOLEAN CacheInitialized = FALSE; if (IsDirectory(Fcb)) { Status = STATUS_INVALID_DEVICE_REQUEST; _SEH2_LEAVE; } if (FEOFI->EndOfFile.HighPart != 0) { Status = STATUS_INVALID_PARAMETER; _SEH2_LEAVE; } if (IoStackLocation->Parameters.SetFile.AdvanceOnly) { Status = STATUS_SUCCESS; _SEH2_LEAVE; } if ((FileObject->SectionObjectPointer->DataSectionObject != NULL) && (FileObject->SectionObjectPointer->SharedCacheMap == NULL) && !FlagOn(Irp->Flags, IRP_PAGING_IO)) { ASSERT( !FlagOn( FileObject->Flags, FO_CLEANUP_COMPLETE ) ); CcInitializeCacheMap( FileObject, (PCC_FILE_SIZES)&(Fcb->Header.AllocationSize), FALSE, &(RfsdGlobal->CacheManagerNoOpCallbacks), Fcb ); CacheInitialized = TRUE; } if ( FEOFI->EndOfFile.QuadPart == Fcb->Header.AllocationSize.QuadPart) { Status = STATUS_SUCCESS; } else if ( FEOFI->EndOfFile.QuadPart > Fcb->Header.AllocationSize.QuadPart) { LARGE_INTEGER FileSize = Fcb->Header.FileSize; Status = RfsdExpandFile(IrpContext, Vcb, Fcb, &(FEOFI->EndOfFile)); if (NT_SUCCESS(Status)) { Fcb->Header.FileSize.QuadPart = FEOFI->EndOfFile.QuadPart; Fcb->Inode->i_size = FEOFI->EndOfFile.QuadPart; Fcb->Header.ValidDataLength.QuadPart = (LONGLONG)(0x7fffffffffffffff); RfsdSaveInode( IrpContext, Vcb, Fcb->RfsdMcb->Inode, Fcb->Inode); CcSetFileSizes(FileObject, (PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize))); SetFlag(FileObject->Flags, FO_FILE_MODIFIED); RfsdZeroHoles( IrpContext, Vcb, FileObject, FileSize.QuadPart, Fcb->Header.AllocationSize.QuadPart - FileSize.QuadPart ); NotifyFilter = FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE ; } } else { if (MmCanFileBeTruncated(&(Fcb->SectionObject), &(FEOFI->EndOfFile))) { LARGE_INTEGER EndOfFile = FEOFI->EndOfFile; EndOfFile.QuadPart = EndOfFile.QuadPart + (LONGLONG)(Vcb->BlockSize - 1); Status = RfsdTruncateFile(IrpContext, Vcb, Fcb, &(EndOfFile)); if (NT_SUCCESS(Status)) { Fcb->Header.FileSize.QuadPart = FEOFI->EndOfFile.QuadPart; Fcb->Inode->i_size = FEOFI->EndOfFile.QuadPart; RfsdSaveInode( IrpContext, Vcb, Fcb->RfsdMcb->Inode, Fcb->Inode); CcSetFileSizes(FileObject, (PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize))); SetFlag(FileObject->Flags, FO_FILE_MODIFIED); NotifyFilter = FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE ; } } else { Status = STATUS_USER_MAPPED_FILE; _SEH2_LEAVE; } } } break; case FileDispositionInformation: { PFILE_DISPOSITION_INFORMATION FDI = (PFILE_DISPOSITION_INFORMATION)Buffer; Status = RfsdSetDispositionInfo(IrpContext, Vcb, Fcb, FDI->DeleteFile); } break; case FileRenameInformation: { Status = RfsdSetRenameInfo(IrpContext, Vcb, Fcb); } break; #endif // 0 #endif // !RFSD_READ_ONLY // // This is the only set file information request supported on read // only file systems // case FilePositionInformation: { PFILE_POSITION_INFORMATION FilePositionInformation; if (Length < sizeof(FILE_POSITION_INFORMATION)) { Status = STATUS_INVALID_PARAMETER; _SEH2_LEAVE; } FilePositionInformation = (PFILE_POSITION_INFORMATION) Buffer; if ((FlagOn(FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING)) && (FilePositionInformation->CurrentByteOffset.LowPart & DeviceObject->AlignmentRequirement) ) { Status = STATUS_INVALID_PARAMETER; _SEH2_LEAVE; } FileObject->CurrentByteOffset = FilePositionInformation->CurrentByteOffset; Status = STATUS_SUCCESS; _SEH2_LEAVE; } break; default: Status = STATUS_INVALID_INFO_CLASS; } } _SEH2_FINALLY { if (FcbPagingIoResourceAcquired) { ExReleaseResourceForThreadLite( &Fcb->PagingIoResource, ExGetCurrentResourceThread() ); } if (NT_SUCCESS(Status) && (NotifyFilter != 0)) { RfsdNotifyReportChange( IrpContext, Vcb, Fcb, NotifyFilter, FILE_ACTION_MODIFIED ); } if (FcbMainResourceAcquired) { ExReleaseResourceForThreadLite( &Fcb->MainResource, ExGetCurrentResourceThread() ); } if (VcbResourceAcquired) { ExReleaseResourceForThreadLite( &Vcb->MainResource, ExGetCurrentResourceThread() ); } if (!IrpContext->ExceptionInProgress) { if (Status == STATUS_PENDING) { RfsdQueueRequest(IrpContext); } else { RfsdCompleteIrpContext(IrpContext, Status); } } } _SEH2_END; return Status; } #if !RFSD_READ_ONLY NTSTATUS RfsdExpandFile( PRFSD_IRP_CONTEXT IrpContext, PRFSD_VCB Vcb, PRFSD_FCB Fcb, PLARGE_INTEGER AllocationSize) { ULONG dwRet = 0; NTSTATUS Status = STATUS_SUCCESS; PAGED_CODE(); if (AllocationSize->QuadPart <= Fcb->Header.AllocationSize.QuadPart) { return Status; } if (((LONGLONG)SUPER_BLOCK->s_free_blocks_count) * Vcb->BlockSize <= (AllocationSize->QuadPart - Fcb->Header.AllocationSize.QuadPart) ) { RfsdPrint((DBG_ERROR, "RfsdExpandFile: There is no enough disk space available.\n")); return STATUS_DISK_FULL; } while (NT_SUCCESS(Status) && (AllocationSize->QuadPart > Fcb->Header.AllocationSize.QuadPart)) { Status = RfsdExpandInode(IrpContext, Vcb, Fcb, &dwRet); } return Status; } NTSTATUS RfsdTruncateFile( PRFSD_IRP_CONTEXT IrpContext, PRFSD_VCB Vcb, PRFSD_FCB Fcb, PLARGE_INTEGER AllocationSize) { NTSTATUS Status = STATUS_SUCCESS; PAGED_CODE(); while (NT_SUCCESS(Status) && (AllocationSize->QuadPart < Fcb->Header.AllocationSize.QuadPart)) { Status= RfsdTruncateInode(IrpContext, Vcb, Fcb); } return Status; } NTSTATUS RfsdSetDispositionInfo( PRFSD_IRP_CONTEXT IrpContext, PRFSD_VCB Vcb, PRFSD_FCB Fcb, BOOLEAN bDelete) { PIRP Irp = IrpContext->Irp; PIO_STACK_LOCATION IrpSp; PAGED_CODE(); IrpSp = IoGetCurrentIrpStackLocation(Irp); RfsdPrint((DBG_INFO, "RfsdSetDispositionInfo: bDelete=%x\n", bDelete)); if (bDelete) { RfsdPrint((DBG_INFO, "RfsdSetDispositionInformation: MmFlushImageSection on %s.\n", Fcb->AnsiFileName.Buffer)); if (!MmFlushImageSection( &Fcb->SectionObject, MmFlushForDelete )) { return STATUS_CANNOT_DELETE; } if (RFSD_IS_ROOT_KEY(Fcb->RfsdMcb->Key)) { return STATUS_CANNOT_DELETE; } if (IsDirectory(Fcb)) { if (!RfsdIsDirectoryEmpty(Vcb, Fcb)) { return STATUS_DIRECTORY_NOT_EMPTY; } } SetFlag(Fcb->Flags, FCB_DELETE_PENDING); IrpSp->FileObject->DeletePending = TRUE; if (IsDirectory(Fcb)) { FsRtlNotifyFullChangeDirectory( Vcb->NotifySync, &Vcb->NotifyList, Fcb, NULL, FALSE, FALSE, 0, NULL, NULL, NULL ); } } else { ClearFlag(Fcb->Flags, FCB_DELETE_PENDING); IrpSp->FileObject->DeletePending = FALSE; } return STATUS_SUCCESS; } NTSTATUS RfsdSetRenameInfo( PRFSD_IRP_CONTEXT IrpContext, PRFSD_VCB Vcb, PRFSD_FCB Fcb ) { PRFSD_FCB TargetDcb; PRFSD_MCB TargetMcb; PRFSD_MCB Mcb; RFSD_INODE Inode; UNICODE_STRING FileName; NTSTATUS Status; PIRP Irp; PIO_STACK_LOCATION IrpSp; PFILE_OBJECT FileObject; PFILE_OBJECT TargetObject; BOOLEAN ReplaceIfExists; BOOLEAN bMove = FALSE; PFILE_RENAME_INFORMATION FRI; PAGED_CODE(); #if 0 if (Fcb->RfsdMcb->Inode == RFSD_ROOT_INO) { Status = STATUS_INVALID_PARAMETER; goto errorout; } Irp = IrpContext->Irp; IrpSp = IoGetCurrentIrpStackLocation(Irp); FileObject = IrpSp->FileObject; TargetObject = IrpSp->Parameters.SetFile.FileObject; ReplaceIfExists = IrpSp->Parameters.SetFile.ReplaceIfExists; FRI = (PFILE_RENAME_INFORMATION)Irp->AssociatedIrp.SystemBuffer; if (TargetObject == NULL) { UNICODE_STRING NewName; NewName.Buffer = FRI->FileName; NewName.MaximumLength = NewName.Length = (USHORT)FRI->FileNameLength; while (NewName.Length > 0 && NewName.Buffer[NewName.Length/2 - 1] == L'\\') { NewName.Buffer[NewName.Length/2 - 1] = 0; NewName.Length -= 2; } while (NewName.Length > 0 && NewName.Buffer[NewName.Length/2 - 1] != L'\\') { NewName.Length -= 2; } NewName.Buffer = (USHORT *)((UCHAR *)NewName.Buffer + NewName.Length); NewName.Length = (USHORT)(FRI->FileNameLength - NewName.Length); FileName = NewName; TargetDcb = NULL; TargetMcb = Fcb->RfsdMcb->Parent; if (FileName.Length >= RFSD_NAME_LEN*sizeof(USHORT)) { Status = STATUS_OBJECT_NAME_INVALID; goto errorout; } } else { TargetDcb = (PRFSD_FCB)(TargetObject->FsContext); if (!TargetDcb || TargetDcb->Vcb != Vcb) { DbgBreak(); Status = STATUS_INVALID_PARAMETER; goto errorout; } TargetMcb = TargetDcb->RfsdMcb; FileName = TargetObject->FileName; } if (FsRtlDoesNameContainWildCards(&FileName)) { Status = STATUS_OBJECT_NAME_INVALID; goto errorout; } if (TargetMcb->Inode == Fcb->RfsdMcb->Parent->Inode) { if (FsRtlAreNamesEqual( &FileName, &(Fcb->RfsdMcb->ShortName), FALSE, NULL )) { Status = STATUS_SUCCESS; goto errorout; } } else { bMove = TRUE; } TargetDcb = TargetMcb->RfsdFcb; if (!TargetDcb) TargetDcb = RfsdCreateFcbFromMcb(Vcb, TargetMcb); if ((TargetMcb->Inode != Fcb->RfsdMcb->Parent->Inode) && (Fcb->RfsdMcb->Parent->RfsdFcb == NULL) ) { RfsdCreateFcbFromMcb(Vcb, Fcb->RfsdMcb->Parent); } if (!TargetDcb || !(Fcb->RfsdMcb->Parent->RfsdFcb)) { Status = STATUS_UNSUCCESSFUL; goto errorout; } Mcb = NULL; Status = RfsdLookupFileName( Vcb, &FileName, TargetMcb, &Mcb, &Inode ); if (NT_SUCCESS(Status)) { if ( (!ReplaceIfExists) || (IsFlagOn(Mcb->FileAttr, FILE_ATTRIBUTE_DIRECTORY)) || (IsFlagOn(Mcb->FileAttr, FILE_ATTRIBUTE_READONLY))) { Status = STATUS_OBJECT_NAME_COLLISION; goto errorout; } if (ReplaceIfExists) { Status = STATUS_NOT_IMPLEMENTED; goto errorout; } } if (IsDirectory(Fcb)) { Status = RfsdRemoveEntry( IrpContext, Vcb, Fcb->RfsdMcb->Parent->RfsdFcb, RFSD_FT_DIR, Fcb->RfsdMcb->Inode ); if (!NT_SUCCESS(Status)) { DbgBreak(); goto errorout; } Status = RfsdAddEntry( IrpContext, Vcb, TargetDcb, RFSD_FT_DIR, Fcb->RfsdMcb->Inode, &FileName ); if (!NT_SUCCESS(Status)) { DbgBreak(); RfsdAddEntry( IrpContext, Vcb, Fcb->RfsdMcb->Parent->RfsdFcb, RFSD_FT_DIR, Fcb->RfsdMcb->Inode, &Fcb->RfsdMcb->ShortName ); goto errorout; } if( !RfsdSaveInode( IrpContext, Vcb, TargetMcb->Inode, TargetDcb->Inode)) { Status = STATUS_UNSUCCESSFUL; DbgBreak(); goto errorout; } if( !RfsdSaveInode( IrpContext, Vcb, Fcb->RfsdMcb->Parent->Inode, Fcb->RfsdMcb->Parent->RfsdFcb->Inode)) { Status = STATUS_UNSUCCESSFUL; DbgBreak(); goto errorout; } Status = RfsdSetParentEntry( IrpContext, Vcb, Fcb, Fcb->RfsdMcb->Parent->Inode, TargetDcb->RfsdMcb->Inode ); if (!NT_SUCCESS(Status)) { DbgBreak(); goto errorout; } } else { Status = RfsdRemoveEntry( IrpContext, Vcb, Fcb->RfsdMcb->Parent->RfsdFcb, RFSD_FT_REG_FILE, Fcb->RfsdMcb->Inode ); if (!NT_SUCCESS(Status)) { DbgBreak(); goto errorout; } Status = RfsdAddEntry( IrpContext, Vcb, TargetDcb, RFSD_FT_REG_FILE, Fcb->RfsdMcb->Inode, &FileName ); if (!NT_SUCCESS(Status)) { DbgBreak(); RfsdAddEntry( IrpContext, Vcb, Fcb->RfsdMcb->Parent->RfsdFcb, RFSD_FT_REG_FILE, Fcb->RfsdMcb->Inode, &Fcb->RfsdMcb->ShortName ); goto errorout; } } if (NT_SUCCESS(Status)) { if (Fcb->RfsdMcb->ShortName.MaximumLength < (FileName.Length + 2)) { ExFreePool(Fcb->RfsdMcb->ShortName.Buffer); Fcb->RfsdMcb->ShortName.Buffer = ExAllocatePoolWithTag(PagedPool, FileName.Length + 2, RFSD_POOL_TAG); if (!Fcb->RfsdMcb->ShortName.Buffer) { Status = STATUS_INSUFFICIENT_RESOURCES; goto errorout; } Fcb->RfsdMcb->ShortName.MaximumLength = FileName.Length + 2; } { RtlZeroMemory( Fcb->RfsdMcb->ShortName.Buffer, Fcb->RfsdMcb->ShortName.MaximumLength); RtlCopyMemory( Fcb->RfsdMcb->ShortName.Buffer, FileName.Buffer, FileName.Length); Fcb->RfsdMcb->ShortName.Length = FileName.Length; } #if DBG Fcb->AnsiFileName.Length = (USHORT) RfsdUnicodeToOEMSize(&FileName) + 1; if (Fcb->AnsiFileName.MaximumLength < FileName.Length) { ExFreePool(Fcb->AnsiFileName.Buffer); Fcb->AnsiFileName.Buffer = ExAllocatePoolWithTag(PagedPool, Fcb->AnsiFileName.Length + 1, RFSD_POOL_TAG); if (!Fcb->AnsiFileName.Buffer) { Status = STATUS_INSUFFICIENT_RESOURCES; goto errorout; } RtlZeroMemory( Fcb->AnsiFileName.Buffer, Fcb->AnsiFileName.Length + 1); Fcb->AnsiFileName.MaximumLength = Fcb->AnsiFileName.Length + 1; } RfsdUnicodeToOEM( &(Fcb->AnsiFileName), &FileName ); #endif if (bMove) { RfsdNotifyReportChange( IrpContext, Vcb, Fcb, (IsDirectory(Fcb) ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME ), FILE_ACTION_REMOVED); } else { RfsdNotifyReportChange( IrpContext, Vcb, Fcb, (IsDirectory(Fcb) ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME ), FILE_ACTION_RENAMED_OLD_NAME); } RfsdDeleteMcbNode(Vcb, Fcb->RfsdMcb->Parent, Fcb->RfsdMcb); RfsdAddMcbNode(Vcb, TargetMcb, Fcb->RfsdMcb); if (bMove) { RfsdNotifyReportChange( IrpContext, Vcb, Fcb, (IsDirectory(Fcb) ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME ), FILE_ACTION_ADDED); } else { RfsdNotifyReportChange( IrpContext, Vcb, Fcb, (IsDirectory(Fcb) ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME ), FILE_ACTION_RENAMED_NEW_NAME ); } } errorout: #endif // 0 return 0;//Status; } NTSTATUS RfsdDeleteFile( PRFSD_IRP_CONTEXT IrpContext, PRFSD_VCB Vcb, PRFSD_FCB Fcb ) { BOOLEAN bRet = FALSE; LARGE_INTEGER AllocationSize; PRFSD_FCB Dcb = NULL; NTSTATUS Status = STATUS_SUCCESS; PAGED_CODE(); #if 0 RfsdPrint((DBG_INFO, "RfsdDeleteFile: File %S (%xh) will be deleted!\n", Fcb->RfsdMcb->ShortName.Buffer, Fcb->RfsdMcb->Inode)); if (IsFlagOn(Fcb->Flags, FCB_FILE_DELETED)) { return Status; } if (FlagOn(Fcb->RfsdMcb->FileAttr, FILE_ATTRIBUTE_DIRECTORY)) { if (!RfsdIsDirectoryEmpty(Vcb, Fcb)) { ClearFlag(Fcb->Flags, FCB_DELETE_PENDING); return STATUS_DIRECTORY_NOT_EMPTY; } } RfsdPrint((DBG_INFO, "RfsdDeleteFile: RFSDSB->S_FREE_BLOCKS = %xh .\n", Vcb->SuperBlock->s_free_blocks_count)); if (IsDirectory(Fcb)) { if (Fcb->Inode->i_links_count <= 2) { } else { Status = STATUS_CANNOT_DELETE; } } else { if (Fcb->Inode->i_links_count <= 1) { } else { Status = STATUS_CANNOT_DELETE; } } if (!NT_SUCCESS(Status)) { DbgBreak(); return Status; } if (Fcb->RfsdMcb->Parent->RfsdFcb) { Status = RfsdRemoveEntry( IrpContext, Vcb, Fcb->RfsdMcb->Parent->RfsdFcb, (FlagOn(Fcb->RfsdMcb->FileAttr, FILE_ATTRIBUTE_DIRECTORY) ? RFSD_FT_DIR : RFSD_FT_REG_FILE), Fcb->RfsdMcb->Inode); } else { Dcb = RfsdCreateFcbFromMcb(Vcb, Fcb->RfsdMcb->Parent); if (Dcb) { Status = RfsdRemoveEntry( IrpContext, Vcb, Dcb, (FlagOn(Fcb->RfsdMcb->FileAttr, FILE_ATTRIBUTE_DIRECTORY) ? RFSD_FT_DIR : RFSD_FT_REG_FILE), Fcb->RfsdMcb->Inode); } } if (NT_SUCCESS(Status)) { LARGE_INTEGER SysTime; KeQuerySystemTime(&SysTime); AllocationSize.QuadPart = (LONGLONG)0; Status = RfsdTruncateFile(IrpContext, Vcb, Fcb, &AllocationSize); // // Update the inode's data length . It should be ZERO if succeeds. // if (Fcb->Header.FileSize.QuadPart > Fcb->Header.AllocationSize.QuadPart) { Fcb->Header.FileSize.QuadPart = Fcb->Header.AllocationSize.QuadPart; Fcb->Inode->i_size = Fcb->Header.AllocationSize.QuadPart; } Fcb->Inode->i_links_count = 0; RfsdSaveInode(IrpContext, Vcb, Fcb->RfsdMcb->Inode, Fcb->Inode); if (IsDirectory(Fcb)) { bRet = RfsdFreeInode(IrpContext, Vcb, Fcb->RfsdMcb->Inode, RFSD_FT_DIR); } else { bRet = RfsdFreeInode(IrpContext, Vcb, Fcb->RfsdMcb->Inode, RFSD_FT_REG_FILE); } SetFlag(Fcb->Flags, FCB_FILE_DELETED); RfsdDeleteMcbNode(Vcb, Fcb->RfsdMcb->Parent, Fcb->RfsdMcb); } else { DbgBreak(); RfsdSaveInode(IrpContext, Vcb, Fcb->RfsdMcb->Inode, Fcb->Inode); } RfsdPrint((DBG_INFO, "RfsdDeleteFile: Succeed... RFSDSB->S_FREE_BLOCKS = %xh .\n", Vcb->SuperBlock->s_free_blocks_count)); #endif // 0 return Status; } #endif // !RFSD_READ_ONLY