NTSTATUS FFSLockVcb( IN PFFS_VCB Vcb, IN PFILE_OBJECT FileObject) { NTSTATUS Status; PAGED_CODE(); _SEH2_TRY { if (FlagOn(Vcb->Flags, VCB_VOLUME_LOCKED)) { FFSPrint((DBG_INFO, "FFSLockVolume: Volume is already locked.\n")); Status = STATUS_ACCESS_DENIED; _SEH2_LEAVE; } if (Vcb->OpenFileHandleCount > (ULONG)(FileObject ? 1 : 0)) { FFSPrint((DBG_INFO, "FFSLockVcb: There are still opened files.\n")); Status = STATUS_ACCESS_DENIED; _SEH2_LEAVE; } if (!FFSIsHandleCountZero(Vcb)) { FFSPrint((DBG_INFO, "FFSLockVcb: Thare are still opened files.\n")); Status = STATUS_ACCESS_DENIED; _SEH2_LEAVE; } SetFlag(Vcb->Flags, VCB_VOLUME_LOCKED); FFSSetVpbFlag(Vcb->Vpb, VPB_LOCKED); Vcb->LockFile = FileObject; FFSPrint((DBG_INFO, "FFSLockVcb: Volume locked.\n")); Status = STATUS_SUCCESS; } _SEH2_FINALLY { // Nothing } _SEH2_END; return Status; }
__drv_mustHoldCriticalRegion NTSTATUS FFSPurgeFile( IN PFFS_FCB Fcb, IN BOOLEAN FlushBeforePurge) { IO_STATUS_BLOCK IoStatus; PAGED_CODE(); ASSERT(Fcb != NULL); ASSERT((Fcb->Identifier.Type == FFSFCB) && (Fcb->Identifier.Size == sizeof(FFS_FCB))); if(!IsFlagOn(Fcb->Vcb->Flags, VCB_READ_ONLY) && FlushBeforePurge && !IsFlagOn(Fcb->Vcb->Flags, VCB_WRITE_PROTECTED)) { FFSPrint((DBG_INFO, "FFSPurgeFile: CcFlushCache on %s.\n", Fcb->AnsiFileName.Buffer)); ExAcquireSharedStarveExclusive(&Fcb->PagingIoResource, TRUE); ExReleaseResourceLite(&Fcb->PagingIoResource); CcFlushCache(&Fcb->SectionObject, NULL, 0, &IoStatus); ClearFlag(Fcb->Flags, FCB_FILE_MODIFIED); } if (Fcb->SectionObject.ImageSectionObject) { FFSPrint((DBG_INFO, "FFSPurgeFile: MmFlushImageSection on %s.\n", Fcb->AnsiFileName.Buffer)); MmFlushImageSection(&Fcb->SectionObject, MmFlushForWrite); } if (Fcb->SectionObject.DataSectionObject) { FFSPrint((DBG_INFO, "FFSPurgeFile: CcPurgeCacheSection on %s.\n", Fcb->AnsiFileName.Buffer)); CcPurgeCacheSection(&Fcb->SectionObject, NULL, 0, FALSE); } return STATUS_SUCCESS; }
BOOLEAN FFSIsHandleCountZero( IN PFFS_VCB Vcb) { PFFS_FCB Fcb; PLIST_ENTRY List; PAGED_CODE(); for(List = Vcb->FcbList.Flink; List != &Vcb->FcbList; List = List->Flink) { Fcb = CONTAINING_RECORD(List, FFS_FCB, Next); ASSERT((Fcb->Identifier.Type == FFSFCB) && (Fcb->Identifier.Size == sizeof(FFS_FCB))); FFSPrint((DBG_INFO, "FFSIsHandleCountZero: Inode:%xh File:%S OpenHandleCount=%xh\n", Fcb->FFSMcb->Inode, Fcb->FFSMcb->ShortName.Buffer, Fcb->OpenHandleCount)); if (Fcb->OpenHandleCount) { return FALSE; } } return TRUE; }
NTSTATUS FFSUnlockVcb( IN PFFS_VCB Vcb, IN PFILE_OBJECT FileObject) { NTSTATUS Status; PAGED_CODE(); _SEH2_TRY { if (FileObject && FileObject->FsContext != Vcb) { Status = STATUS_NOT_LOCKED; _SEH2_LEAVE; } if (!FlagOn(Vcb->Flags, VCB_VOLUME_LOCKED)) { FFSPrint((DBG_ERROR, ": FFSUnlockVcb: Volume is not locked.\n")); Status = STATUS_NOT_LOCKED; _SEH2_LEAVE; } if (Vcb->LockFile == FileObject) { ClearFlag(Vcb->Flags, VCB_VOLUME_LOCKED); FFSClearVpbFlag(Vcb->Vpb, VPB_LOCKED); FFSPrint((DBG_INFO, "FFSUnlockVcb: Volume unlocked.\n")); Status = STATUS_SUCCESS; } else { Status = STATUS_NOT_LOCKED; } } _SEH2_FINALLY { // Nothing } _SEH2_END; return Status; }
__drv_mustHoldCriticalRegion VOID FFSFreeMcb( IN PFFS_MCB Mcb) { #ifndef __REACTOS__ PFFS_MCB Parent = Mcb->Parent; #endif PAGED_CODE(); ASSERT(Mcb != NULL); ASSERT((Mcb->Identifier.Type == FFSMCB) && (Mcb->Identifier.Size == sizeof(FFS_MCB))); FFSPrint((DBG_INFO, "FFSFreeMcb: Mcb %S will be freed.\n", Mcb->ShortName.Buffer)); if (Mcb->ShortName.Buffer) ExFreePool(Mcb->ShortName.Buffer); if (FlagOn(Mcb->Flags, MCB_FROM_POOL)) { ExFreePool(Mcb); } else { ExAcquireResourceExclusiveLite( &FFSGlobal->LAResource, TRUE); ExFreeToPagedLookasideList(&(FFSGlobal->FFSMcbLookasideList), Mcb); ExReleaseResourceForThreadLite( &FFSGlobal->LAResource, ExGetCurrentResourceThread()); } ExAcquireResourceExclusiveLite( &FFSGlobal->CountResource, TRUE); FFSGlobal->McbAllocated--; ExReleaseResourceForThreadLite( &FFSGlobal->CountResource, ExGetCurrentResourceThread()); }
VOID FFSFloppyFlushDpc( IN PKDPC Dpc, IN PVOID DeferredContext, IN PVOID SystemArgument1, IN PVOID SystemArgument2) { PFFS_FLPFLUSH_CONTEXT Context; Context = (PFFS_FLPFLUSH_CONTEXT)DeferredContext; FFSPrint((DBG_USER, "FFSFloppyFlushDpc is to be started...\n")); ExInitializeWorkItem(&Context->Item, FFSFloppyFlush, Context); ExQueueWorkItem(&Context->Item, CriticalWorkQueue); }
VOID FFSFloppyFlush( IN PVOID Parameter) { PFFS_FLPFLUSH_CONTEXT Context; PFILE_OBJECT FileObject; PFFS_FCB Fcb; PFFS_VCB Vcb; Context = (PFFS_FLPFLUSH_CONTEXT) Parameter; FileObject = Context->FileObject; Fcb = Context->Fcb; Vcb = Context->Vcb; FFSPrint((DBG_USER, "FFSFloppyFlushing ...\n")); IoSetTopLevelIrp((PIRP)FSRTL_FSP_TOP_LEVEL_IRP); if (Vcb) { ExAcquireSharedStarveExclusive(&Vcb->PagingIoResource, TRUE); ExReleaseResource(&Vcb->PagingIoResource); CcFlushCache(&(Vcb->SectionObject), NULL, 0, NULL); } if (FileObject) { ASSERT(Fcb == (PFFS_FCB)FileObject->FsContext); ExAcquireSharedStarveExclusive(&Fcb->PagingIoResource, TRUE); ExReleaseResource(&Fcb->PagingIoResource); CcFlushCache(&(Fcb->SectionObject), NULL, 0, NULL); ObDereferenceObject(FileObject); } IoSetTopLevelIrp(NULL); ExFreePool(Parameter); }
VOID FFSAddMcbNode( PFFS_VCB Vcb, PFFS_MCB Parent, PFFS_MCB Child) { PFFS_MCB TmpMcb = Parent->Child; PAGED_CODE(); if(IsFlagOn(Child->Flags, MCB_IN_TREE)) { FFSBreakPoint(); FFSPrint((DBG_ERROR, "FFSAddMcbNode: Child Mcb is alreay in the tree.\n")); return; } if (TmpMcb) { ASSERT(TmpMcb->Parent == Parent); while (TmpMcb->Next) { TmpMcb = TmpMcb->Next; ASSERT(TmpMcb->Parent == Parent); } TmpMcb->Next = Child; Child->Parent = Parent; Child->Next = NULL; } else { Parent->Child = Child; Child->Parent = Parent; Child->Next = NULL; } InsertTailList(&(Vcb->McbList), &(Child->Link)); SetFlag(Child->Flags, MCB_IN_TREE); }
__drv_mustHoldCriticalRegion NTSTATUS FFSFileSystemControl( IN PFFS_IRP_CONTEXT IrpContext) { NTSTATUS Status; PAGED_CODE(); ASSERT(IrpContext); ASSERT((IrpContext->Identifier.Type == FFSICX) && (IrpContext->Identifier.Size == sizeof(FFS_IRP_CONTEXT))); switch (IrpContext->MinorFunction) { case IRP_MN_USER_FS_REQUEST: Status = FFSUserFsRequest(IrpContext); break; case IRP_MN_MOUNT_VOLUME: Status = FFSMountVolume(IrpContext); break; case IRP_MN_VERIFY_VOLUME: Status = FFSVerifyVolume(IrpContext); break; default: FFSPrint((DBG_ERROR, "FFSFilsSystemControl: Invalid Device Request.\n")); Status = STATUS_INVALID_DEVICE_REQUEST; FFSCompleteIrpContext(IrpContext, Status); } return Status; }
NTSTATUS FFSDispatchRequest( IN PFFS_IRP_CONTEXT IrpContext) { ASSERT(IrpContext); ASSERT((IrpContext->Identifier.Type == FFSICX) && (IrpContext->Identifier.Size == sizeof(FFS_IRP_CONTEXT))); switch (IrpContext->MajorFunction) { case IRP_MJ_CREATE: return FFSCreate(IrpContext); case IRP_MJ_CLOSE: return FFSClose(IrpContext); case IRP_MJ_READ: return FFSRead(IrpContext); case IRP_MJ_WRITE: return FFSWrite(IrpContext); case IRP_MJ_FLUSH_BUFFERS: return FFSFlush(IrpContext); case IRP_MJ_QUERY_INFORMATION: return FFSQueryInformation(IrpContext); case IRP_MJ_SET_INFORMATION: return FFSSetInformation(IrpContext); case IRP_MJ_QUERY_VOLUME_INFORMATION: return FFSQueryVolumeInformation(IrpContext); case IRP_MJ_SET_VOLUME_INFORMATION: return FFSSetVolumeInformation(IrpContext); case IRP_MJ_DIRECTORY_CONTROL: return FFSDirectoryControl(IrpContext); case IRP_MJ_FILE_SYSTEM_CONTROL: return FFSFileSystemControl(IrpContext); case IRP_MJ_DEVICE_CONTROL: return FFSDeviceControl(IrpContext); case IRP_MJ_LOCK_CONTROL: return FFSLockControl(IrpContext); case IRP_MJ_CLEANUP: return FFSCleanup(IrpContext); case IRP_MJ_SHUTDOWN: return FFSShutDown(IrpContext); #if (_WIN32_WINNT >= 0x0500) case IRP_MJ_PNP: return FFSPnp(IrpContext); #endif //(_WIN32_WINNT >= 0x0500) default: FFSPrint((DBG_ERROR, "FFSDispatchRequest: Unexpected major function: %xh\n", IrpContext->MajorFunction)); FFSCompleteIrpContext(IrpContext, STATUS_DRIVER_INTERNAL_ERROR); return STATUS_DRIVER_INTERNAL_ERROR; } }
PFFS_MCB FFSAllocateMcb( PFFS_VCB Vcb, PUNICODE_STRING FileName, ULONG FileAttr) { PFFS_MCB Mcb = NULL; PLIST_ENTRY List = NULL; ULONG Extra = 0; #define MCB_NUM_SHIFT 0x04 if (FFSGlobal->McbAllocated > (FFSGlobal->MaxDepth << MCB_NUM_SHIFT)) Extra = FFSGlobal->McbAllocated - (FFSGlobal->MaxDepth << MCB_NUM_SHIFT) + FFSGlobal->MaxDepth; FFSPrint((DBG_INFO, "FFSAllocateMcb: CurrDepth=%xh/%xh/%xh FileName=%S\n", FFSGlobal->McbAllocated, FFSGlobal->MaxDepth << MCB_NUM_SHIFT, FFSGlobal->FcbAllocated, FileName->Buffer)); List = Vcb->McbList.Flink; while ((List != &(Vcb->McbList)) && (Extra > 0)) { Mcb = CONTAINING_RECORD(List, FFS_MCB, Link); List = List->Flink; if ((Mcb->Inode != 2) && (Mcb->Child == NULL) && (Mcb->FFSFcb == NULL) && (!IsMcbUsed(Mcb))) { FFSPrint((DBG_INFO, "FFSAllocateMcb: Mcb %S will be freed.\n", Mcb->ShortName.Buffer)); if (FFSDeleteMcbNode(Vcb, Vcb->McbTree, Mcb)) { FFSFreeMcb(Mcb); Extra--; } } } ExAcquireResourceExclusiveLite( &FFSGlobal->LAResource, TRUE); Mcb = (PFFS_MCB)(ExAllocateFromPagedLookasideList( &(FFSGlobal->FFSMcbLookasideList))); ExReleaseResourceForThreadLite( &FFSGlobal->LAResource, ExGetCurrentResourceThread()); if (Mcb == NULL) { Mcb = (PFFS_MCB)ExAllocatePool(PagedPool, sizeof(FFS_MCB)); RtlZeroMemory(Mcb, sizeof(FFS_MCB)); SetFlag(Mcb->Flags, MCB_FROM_POOL); } else { RtlZeroMemory(Mcb, sizeof(FFS_MCB)); } if (!Mcb) { return NULL; } Mcb->Identifier.Type = FFSMCB; Mcb->Identifier.Size = sizeof(FFS_MCB); if (FileName && FileName->Length) { Mcb->ShortName.Length = FileName->Length; Mcb->ShortName.MaximumLength = Mcb->ShortName.Length + 2; Mcb->ShortName.Buffer = ExAllocatePool(PagedPool, Mcb->ShortName.MaximumLength); if (!Mcb->ShortName.Buffer) goto errorout; RtlZeroMemory(Mcb->ShortName.Buffer, Mcb->ShortName.MaximumLength); RtlCopyMemory(Mcb->ShortName.Buffer, FileName->Buffer, Mcb->ShortName.Length); } Mcb->FileAttr = FileAttr; ExAcquireResourceExclusiveLite( &FFSGlobal->CountResource, TRUE); FFSGlobal->McbAllocated++; ExReleaseResourceForThreadLite( &FFSGlobal->CountResource, ExGetCurrentResourceThread()); return Mcb; errorout: if (Mcb) { if (Mcb->ShortName.Buffer) ExFreePool(Mcb->ShortName.Buffer); if (FlagOn(Mcb->Flags, MCB_FROM_POOL)) { ExFreePool(Mcb); } else { ExAcquireResourceExclusiveLite( &FFSGlobal->LAResource, TRUE); ExFreeToPagedLookasideList(&(FFSGlobal->FFSMcbLookasideList), Mcb); ExReleaseResourceForThreadLite( &FFSGlobal->LAResource, ExGetCurrentResourceThread()); } } return NULL; }
VOID FFSFreeVcb( IN PFFS_VCB Vcb) { ASSERT(Vcb != NULL); ASSERT((Vcb->Identifier.Type == FFSVCB) && (Vcb->Identifier.Size == sizeof(FFS_VCB))); FsRtlNotifyUninitializeSync(&Vcb->NotifySync); if (Vcb->StreamObj) { if (IsFlagOn(Vcb->StreamObj->Flags, FO_FILE_MODIFIED)) { IO_STATUS_BLOCK IoStatus; CcFlushCache(&(Vcb->SectionObject), NULL, 0, &IoStatus); ClearFlag(Vcb->StreamObj->Flags, FO_FILE_MODIFIED); } if (Vcb->StreamObj->PrivateCacheMap) FFSSyncUninitializeCacheMap(Vcb->StreamObj); ObDereferenceObject(Vcb->StreamObj); Vcb->StreamObj = NULL; } #if DBG if (FsRtlNumberOfRunsInLargeMcb(&(Vcb->DirtyMcbs)) != 0) { LONGLONG DirtyVba; LONGLONG DirtyLba; LONGLONG DirtyLength; int i; for (i = 0; FsRtlGetNextLargeMcbEntry (&(Vcb->DirtyMcbs), i, &DirtyVba, &DirtyLba, &DirtyLength); i++) { FFSPrint((DBG_INFO, "DirtyVba = %I64xh\n", DirtyVba)); FFSPrint((DBG_INFO, "DirtyLba = %I64xh\n", DirtyLba)); FFSPrint((DBG_INFO, "DirtyLen = %I64xh\n\n", DirtyLength)); } FFSBreakPoint(); } #endif FsRtlUninitializeLargeMcb(&(Vcb->DirtyMcbs)); FFSFreeMcbTree(Vcb->McbTree); if (Vcb->ffs_super_block) { ExFreePool(Vcb->ffs_super_block); Vcb->ffs_super_block = NULL; } ExDeleteResourceLite(&Vcb->McbResource); ExDeleteResourceLite(&Vcb->PagingIoResource); ExDeleteResourceLite(&Vcb->MainResource); IoDeleteDevice(Vcb->DeviceObject); }
BOOLEAN FFSCheckSetBlock( PFFS_IRP_CONTEXT IrpContext, PFFS_VCB Vcb, ULONG Block) { #if 0 ULONG Group, dwBlk, Length; RTL_BITMAP BlockBitmap; PVOID BitmapCache; PBCB BitmapBcb; LARGE_INTEGER Offset; BOOLEAN bModified = FALSE; //Group = (Block - FFS_FIRST_DATA_BLOCK) / BLOCKS_PER_GROUP; dwBlk = (Block - FFS_FIRST_DATA_BLOCK) % BLOCKS_PER_GROUP; Offset.QuadPart = (LONGLONG) Vcb->BlockSize; Offset.QuadPart = Offset.QuadPart * Vcb->ffs_group_desc[Group].bg_block_bitmap; if (Group == Vcb->ffs_groups - 1) { Length = TOTAL_BLOCKS % BLOCKS_PER_GROUP; /* s_blocks_count is integer multiple of s_blocks_per_group */ if (Length == 0) Length = BLOCKS_PER_GROUP; } else { Length = BLOCKS_PER_GROUP; } if (dwBlk >= Length) return FALSE; if (!CcPinRead(Vcb->StreamObj, &Offset, Vcb->BlockSize, PIN_WAIT, &BitmapBcb, &BitmapCache)) { FFSPrint((DBG_ERROR, "FFSDeleteBlock: PinReading error ...\n")); return FALSE; } RtlInitializeBitMap(&BlockBitmap, BitmapCache, Length); if (RtlCheckBit(&BlockBitmap, dwBlk) == 0) { FFSBreakPoint(); RtlSetBits(&BlockBitmap, dwBlk, 1); bModified = TRUE; } if (bModified) { CcSetDirtyPinnedData(BitmapBcb, NULL); FFSRepinBcb(IrpContext, BitmapBcb); FFSAddMcbEntry(Vcb, Offset.QuadPart, (LONGLONG)Vcb->BlockSize); } { CcUnpinData(BitmapBcb); BitmapBcb = NULL; BitmapCache = NULL; RtlZeroMemory(&BlockBitmap, sizeof(RTL_BITMAP)); } return (!bModified); #endif return FALSE; }
ULONG FFSProcessDirEntry( IN PFFS_VCB Vcb, IN FILE_INFORMATION_CLASS FileInformationClass, IN ULONG in, IN PVOID Buffer, IN ULONG UsedLength, IN ULONG Length, IN ULONG FileIndex, IN PUNICODE_STRING pName, IN BOOLEAN Single) { FFSv1_INODE dinode1; FFSv2_INODE dinode2; PFILE_DIRECTORY_INFORMATION FDI; PFILE_FULL_DIR_INFORMATION FFI; PFILE_BOTH_DIR_INFORMATION FBI; PFILE_NAMES_INFORMATION FNI; ULONG InfoLength = 0; ULONG NameLength = 0; ULONG dwBytes = 0; PAGED_CODE(); NameLength = pName->Length; if (!in) { FFSPrint((DBG_ERROR, "FFSPricessDirEntry: ffs_dir_entry is empty.\n")); return 0; } InfoLength = FFSGetInfoLength(FileInformationClass); if (!InfoLength || InfoLength + NameLength - sizeof(WCHAR) > Length) { FFSPrint((DBG_INFO, "FFSPricessDirEntry: Buffer is not enough.\n")); return 0; } if (FS_VERSION == 1) { if(!FFSv1LoadInode(Vcb, in, &dinode1)) { FFSPrint((DBG_ERROR, "FFSPricessDirEntry: Loading inode %xh error.\n", in)); FFSBreakPoint(); return 0; } } else { if(!FFSv2LoadInode(Vcb, in, &dinode2)) { FFSPrint((DBG_ERROR, "FFSPricessDirEntry: Loading inode %xh error.\n", in)); FFSBreakPoint(); return 0; } } switch(FileInformationClass) { case FileDirectoryInformation: FDI = (PFILE_DIRECTORY_INFORMATION) ((PUCHAR)Buffer + UsedLength); if (!Single) FDI->NextEntryOffset = InfoLength + NameLength - sizeof(WCHAR); else FDI->NextEntryOffset = 0; FDI->FileIndex = FileIndex; if (FS_VERSION == 1) { FDI->CreationTime = FFSSysTime(dinode1.di_ctime); FDI->LastAccessTime = FFSSysTime(dinode1.di_atime); FDI->LastWriteTime = FFSSysTime(dinode1.di_mtime); FDI->ChangeTime = FFSSysTime(dinode1.di_mtime); FDI->EndOfFile.QuadPart = dinode1.di_size; FDI->AllocationSize.QuadPart = dinode1.di_size; FDI->FileAttributes = FILE_ATTRIBUTE_NORMAL; if (FlagOn(Vcb->Flags, VCB_READ_ONLY) || FFSIsReadOnly(dinode1.di_mode)) { SetFlag(FDI->FileAttributes, FILE_ATTRIBUTE_READONLY); } if ((dinode1.di_mode & IFMT) == IFDIR) FDI->FileAttributes |= FILE_ATTRIBUTE_DIRECTORY; FDI->FileNameLength = NameLength; RtlCopyMemory(FDI->FileName, pName->Buffer, NameLength); dwBytes = InfoLength + NameLength - sizeof(WCHAR); break; } else { FDI->CreationTime = FFSSysTime((ULONG)dinode2.di_ctime); FDI->LastAccessTime = FFSSysTime((ULONG)dinode2.di_atime); FDI->LastWriteTime = FFSSysTime((ULONG)dinode2.di_mtime); FDI->ChangeTime = FFSSysTime((ULONG)dinode2.di_mtime); FDI->EndOfFile.QuadPart = dinode2.di_size; FDI->AllocationSize.QuadPart = dinode2.di_size; FDI->FileAttributes = FILE_ATTRIBUTE_NORMAL; if (FlagOn(Vcb->Flags, VCB_READ_ONLY) || FFSIsReadOnly(dinode2.di_mode)) { SetFlag(FDI->FileAttributes, FILE_ATTRIBUTE_READONLY); } if ((dinode2.di_mode & IFMT) == IFDIR) FDI->FileAttributes |= FILE_ATTRIBUTE_DIRECTORY; FDI->FileNameLength = NameLength; RtlCopyMemory(FDI->FileName, pName->Buffer, NameLength); dwBytes = InfoLength + NameLength - sizeof(WCHAR); break; } case FileFullDirectoryInformation: FFI = (PFILE_FULL_DIR_INFORMATION) ((PUCHAR)Buffer + UsedLength); if (!Single) FFI->NextEntryOffset = InfoLength + NameLength - sizeof(WCHAR); else FFI->NextEntryOffset = 0; FFI->FileIndex = FileIndex; if (FS_VERSION == 1) { FFI->CreationTime = FFSSysTime(dinode1.di_ctime); FFI->LastAccessTime = FFSSysTime(dinode1.di_atime); FFI->LastWriteTime = FFSSysTime(dinode1.di_mtime); FFI->ChangeTime = FFSSysTime(dinode1.di_mtime); FFI->EndOfFile.QuadPart = dinode1.di_size; FFI->AllocationSize.QuadPart = dinode1.di_size; FFI->FileAttributes = FILE_ATTRIBUTE_NORMAL; if (IsFlagOn(Vcb->Flags, VCB_READ_ONLY) || FFSIsReadOnly(dinode1.di_mode)) { SetFlag(FFI->FileAttributes, FILE_ATTRIBUTE_READONLY); } if ((dinode1.di_mode & IFMT) == IFDIR) FFI->FileAttributes |= FILE_ATTRIBUTE_DIRECTORY; FFI->FileNameLength = NameLength; RtlCopyMemory(FFI->FileName, pName->Buffer, NameLength); dwBytes = InfoLength + NameLength - sizeof(WCHAR); break; } else { FFI->CreationTime = FFSSysTime((ULONG)dinode2.di_ctime); FFI->LastAccessTime = FFSSysTime((ULONG)dinode2.di_atime); FFI->LastWriteTime = FFSSysTime((ULONG)dinode2.di_mtime); FFI->ChangeTime = FFSSysTime((ULONG)dinode2.di_mtime); FFI->EndOfFile.QuadPart = dinode2.di_size; FFI->AllocationSize.QuadPart = dinode2.di_size; FFI->FileAttributes = FILE_ATTRIBUTE_NORMAL; if (IsFlagOn(Vcb->Flags, VCB_READ_ONLY) || FFSIsReadOnly(dinode2.di_mode)) { SetFlag(FFI->FileAttributes, FILE_ATTRIBUTE_READONLY); } if ((dinode2.di_mode & IFMT) == IFDIR) FFI->FileAttributes |= FILE_ATTRIBUTE_DIRECTORY; FFI->FileNameLength = NameLength; RtlCopyMemory(FFI->FileName, pName->Buffer, NameLength); dwBytes = InfoLength + NameLength - sizeof(WCHAR); break; } case FileBothDirectoryInformation: FBI = (PFILE_BOTH_DIR_INFORMATION) ((PUCHAR)Buffer + UsedLength); if (!Single) FBI->NextEntryOffset = InfoLength + NameLength - sizeof(WCHAR); else FBI->NextEntryOffset = 0; if (FS_VERSION == 1) { FBI->CreationTime = FFSSysTime(dinode1.di_ctime); FBI->LastAccessTime = FFSSysTime(dinode1.di_atime); FBI->LastWriteTime = FFSSysTime(dinode1.di_mtime); FBI->ChangeTime = FFSSysTime(dinode1.di_mtime); FBI->FileIndex = FileIndex; FBI->EndOfFile.QuadPart = dinode1.di_size; FBI->AllocationSize.QuadPart = dinode1.di_size; FBI->FileAttributes = FILE_ATTRIBUTE_NORMAL; if (FlagOn(Vcb->Flags, VCB_READ_ONLY) || FFSIsReadOnly(dinode1.di_mode)) { SetFlag(FBI->FileAttributes, FILE_ATTRIBUTE_READONLY); } if ((dinode1.di_mode & IFMT) == IFDIR) FBI->FileAttributes |= FILE_ATTRIBUTE_DIRECTORY; FBI->FileNameLength = NameLength; RtlCopyMemory(FBI->FileName, pName->Buffer, NameLength); dwBytes = InfoLength + NameLength - sizeof(WCHAR); break; } else { FBI->CreationTime = FFSSysTime((ULONG)dinode2.di_ctime); FBI->LastAccessTime = FFSSysTime((ULONG)dinode2.di_atime); FBI->LastWriteTime = FFSSysTime((ULONG)dinode2.di_mtime); FBI->ChangeTime = FFSSysTime((ULONG)dinode2.di_mtime); FBI->FileIndex = FileIndex; FBI->EndOfFile.QuadPart = dinode2.di_size; FBI->AllocationSize.QuadPart = dinode2.di_size; FBI->FileAttributes = FILE_ATTRIBUTE_NORMAL; if (FlagOn(Vcb->Flags, VCB_READ_ONLY) || FFSIsReadOnly(dinode2.di_mode)) { SetFlag(FBI->FileAttributes, FILE_ATTRIBUTE_READONLY); } if ((dinode2.di_mode & IFMT) == IFDIR) FBI->FileAttributes |= FILE_ATTRIBUTE_DIRECTORY; FBI->FileNameLength = NameLength; RtlCopyMemory(FBI->FileName, pName->Buffer, NameLength); dwBytes = InfoLength + NameLength - sizeof(WCHAR); break; } case FileNamesInformation: FNI = (PFILE_NAMES_INFORMATION) ((PUCHAR)Buffer + UsedLength); if (!Single) FNI->NextEntryOffset = InfoLength + NameLength - sizeof(WCHAR); else FNI->NextEntryOffset = 0; FNI->FileNameLength = NameLength; RtlCopyMemory(FNI->FileName, pName->Buffer, NameLength); dwBytes = InfoLength + NameLength - sizeof(WCHAR); break; default: break; } return dwBytes; }
NTSTATUS FFSLoadDiskLabel( PDEVICE_OBJECT DeviceObject, IN PFFS_VCB Vcb) { NTSTATUS Status; PFFS_SUPER_BLOCK FFSSb; PDISKLABEL Disklabel; int i; int RootFS_VERSION; ULONGLONG StartOffset = 0; ULONGLONG FSOffset = 0; ULONGLONG FSRootOffset = 0; PAGED_CODE(); Disklabel = (PDISKLABEL)ExAllocatePoolWithTag(PagedPool, sizeof(DISKLABEL), FFS_POOL_TAG); FFSReadDisk(Vcb, (LABELSECTOR * SECTOR_SIZE + LABELOFFSET), sizeof(DISKLABEL), (PVOID)Disklabel, FALSE); if (Disklabel->d_magic == DISKMAGIC) { KdPrint(("FFSLoadDiskLabel() Disklabel magic ok\n")); Status = STATUS_SUCCESS; } else { KdPrint(("FFSLoadDiskLabel() No BSD disklabel found, trying to find BSD file system on \"normal\" partition.\n")); if ((FFSSb = FFSLoadSuper(Vcb, FALSE, FSOffset + SBLOCK_UFS1)) && (FFSSb->fs_magic == FS_UFS1_MAGIC)) { FFSPrint((DBG_VITAL, "FFSLoadDiskLabel() \"normal\" partition of FFSv1 file system is found.\n")); /* if ((FFSSb->fs_fsmnt[0] == '/') && (FFSSb->fs_fsmnt[1] == '\0')) { FFSGlobal->RootPartition = i; FSRootOffset = FSOffset; RootFS_VERSION = 1; } */ FS_VERSION = 1; Vcb->FSOffset[0] = 0; Vcb->PartitionNumber = 0; Vcb->ffs_super_block = FFSSb; Status = STATUS_SUCCESS; return Status; } else if ((FFSSb = FFSLoadSuper(Vcb, FALSE, FSOffset + SBLOCK_UFS2)) && (FFSSb->fs_magic == FS_UFS2_MAGIC)) { FFSPrint((DBG_VITAL, "FFSLoadDiskLabel() \"normal\" partition of FFSv2 file system is found.\n")); /* if ((FFSSb->fs_fsmnt[0] == '/') && (FFSSb->fs_fsmnt[1] == '\0')) { FFSGlobal->RootPartition = i; FSRootOffset = FSOffset; RootFS_VERSION = 2; } */ FS_VERSION = 2; Vcb->FSOffset[0] = 0; Vcb->PartitionNumber = 0; Vcb->ffs_super_block = FFSSb; Status = STATUS_SUCCESS; return Status; } else { KdPrint(("FFSLoadDiskLabel() No BSD file system was found on the \"normal\" partition.\n")); Status = STATUS_UNRECOGNIZED_VOLUME; return Status; } } Status = FFSGetPartition(DeviceObject, &StartOffset); if (!NT_SUCCESS(Status)) { KdPrint(("FFSLoadDiskLabel() Slice info failed, Status %u\n", Status)); return Status; } Vcb->PartitionNumber = FFSGlobal->PartitionNumber; KdPrint(("FFSLoadDiskLabel() Selected BSD Label : %d, StartOffset : %x\n", Vcb->PartitionNumber, StartOffset)); for (i = 0; i < MAXPARTITIONS; i++) { if (Disklabel->d_partitions[i].p_fstype == FS_BSDFFS) { /* Important */ FSOffset = Disklabel->d_partitions[i].p_offset; FSOffset = FSOffset * SECTOR_SIZE; //FSOffset = FSOffset - StartOffset; Vcb->FSOffset[i] = FSOffset; /* Important */ KdPrint(("FFSLoadDiskLabel() Label %d, FS_BSDFFS, %x\n", i, Vcb->FSOffset[i])); if ((FFSSb = FFSLoadSuper(Vcb, FALSE, FSOffset + SBLOCK_UFS1)) && (FFSSb->fs_magic == FS_UFS1_MAGIC)) { FFSPrint((DBG_VITAL, "FFSLoadDiskLabel() Label %d of FFSv1 file system is found.\n", i)); if ((FFSSb->fs_fsmnt[0] == '/') && (FFSSb->fs_fsmnt[1] == '\0')) { Vcb->RootPartition = i; FSRootOffset = FSOffset; RootFS_VERSION = 1; } FS_VERSION = 1; if (i == (int)Vcb->PartitionNumber) { Vcb->ffs_super_block = FFSSb; } Status = STATUS_SUCCESS; } else if ((FFSSb = FFSLoadSuper(Vcb, FALSE, FSOffset + SBLOCK_UFS2)) && (FFSSb->fs_magic == FS_UFS2_MAGIC)) { FFSPrint((DBG_VITAL, "FFSLoadDiskLabel() Label %d of FFSv2 file system is found.\n", i)); if ((FFSSb->fs_fsmnt[0] == '/') && (FFSSb->fs_fsmnt[1] == '\0')) { Vcb->RootPartition = i; FSRootOffset = FSOffset; RootFS_VERSION = 2; } FS_VERSION = 2; if (i == (int)Vcb->PartitionNumber) { Vcb->ffs_super_block = FFSSb; } Status = STATUS_SUCCESS; } } #if 0 else if (i == (int)FFSGlobal->PartitionNumber) { /* 선택된 BSD 파티션이 디스크에 없을 경우 Root 파티션으로 대체 */ if (RootFS_VERSION == 1) { FFSSb = FFSLoadSuper(Vcb, FALSE, FSRootOffset + SBLOCK_UFS1); Vcb->ffs_super_block = FFSSb; FFSGlobal->PartitionNumber = FFSGlobal->RootPartition; } else { FFSSb = FFSLoadSuper(Vcb, FALSE, FSRootOffset + SBLOCK_UFS2); Vcb->ffs_super_block = FFSSb; FFSGlobal->PartitionNumber = FFSGlobal->RootPartition; } } #endif } if (Vcb->ffs_super_block == NULL) Status = STATUS_UNRECOGNIZED_VOLUME; return Status; }
__drv_mustHoldCriticalRegion NTSTATUS FFSUserFsRequest( IN PFFS_IRP_CONTEXT IrpContext) { PIRP Irp; PIO_STACK_LOCATION IoStackLocation; ULONG FsControlCode; NTSTATUS Status; PAGED_CODE(); ASSERT(IrpContext); ASSERT((IrpContext->Identifier.Type == FFSICX) && (IrpContext->Identifier.Size == sizeof(FFS_IRP_CONTEXT))); Irp = IrpContext->Irp; IoStackLocation = IoGetCurrentIrpStackLocation(Irp); #if !defined(_GNU_NTIFS_) || defined(__REACTOS__) FsControlCode = IoStackLocation->Parameters.FileSystemControl.FsControlCode; #else FsControlCode = ((PEXTENDED_IO_STACK_LOCATION) IoStackLocation)->Parameters.FileSystemControl.FsControlCode; #endif switch (FsControlCode) { case FSCTL_LOCK_VOLUME: Status = FFSLockVolume(IrpContext); break; case FSCTL_UNLOCK_VOLUME: Status = FFSUnlockVolume(IrpContext); break; case FSCTL_DISMOUNT_VOLUME: Status = FFSDismountVolume(IrpContext); break; case FSCTL_IS_VOLUME_MOUNTED: Status = FFSIsVolumeMounted(IrpContext); break; case FSCTL_INVALIDATE_VOLUMES: Status = FFSInvalidateVolumes(IrpContext); break; #if (_WIN32_WINNT >= 0x0500) case FSCTL_ALLOW_EXTENDED_DASD_IO: Status = FFSAllowExtendedDasdIo(IrpContext); break; #endif //(_WIN32_WINNT >= 0x0500) default: FFSPrint((DBG_ERROR, "FFSUserFsRequest: Invalid User Request: %xh.\n", FsControlCode)); Status = STATUS_INVALID_DEVICE_REQUEST; FFSCompleteIrpContext(IrpContext, Status); } return Status; }
__drv_mustHoldCriticalRegion NTSTATUS FFSCleanup( IN PFFS_IRP_CONTEXT IrpContext) { PDEVICE_OBJECT DeviceObject; NTSTATUS Status = STATUS_SUCCESS; PFFS_VCB Vcb = 0; BOOLEAN VcbResourceAcquired = FALSE; PFILE_OBJECT FileObject; PFFS_FCB Fcb = 0; BOOLEAN FcbResourceAcquired = FALSE; BOOLEAN FcbPagingIoAcquired = FALSE; PFFS_CCB Ccb; PIRP Irp; PAGED_CODE(); _SEH2_TRY { ASSERT(IrpContext != NULL); ASSERT((IrpContext->Identifier.Type == FFSICX) && (IrpContext->Identifier.Size == sizeof(FFS_IRP_CONTEXT))); DeviceObject = IrpContext->DeviceObject; if (DeviceObject == FFSGlobal->DeviceObject) { Status = STATUS_SUCCESS; _SEH2_LEAVE; } Vcb = (PFFS_VCB)DeviceObject->DeviceExtension; ASSERT(Vcb != NULL); ASSERT((Vcb->Identifier.Type == FFSVCB) && (Vcb->Identifier.Size == sizeof(FFS_VCB))); if (!IsFlagOn(Vcb->Flags, VCB_INITIALIZED)) { Status = STATUS_SUCCESS; _SEH2_LEAVE; } #ifdef _MSC_VER #pragma prefast( suppress: 28137, "by design" ) #endif if (!ExAcquireResourceExclusiveLite( &Vcb->MainResource, IrpContext->IsSynchronous)) { Status = STATUS_PENDING; _SEH2_LEAVE; } VcbResourceAcquired = TRUE; FileObject = IrpContext->FileObject; Fcb = (PFFS_FCB)FileObject->FsContext; if (!Fcb) { Status = STATUS_SUCCESS; _SEH2_LEAVE; } if (Fcb->Identifier.Type == FFSVCB) { if (IsFlagOn(Vcb->Flags, VCB_VOLUME_LOCKED) && (Vcb->LockFile == FileObject)) { ClearFlag(Vcb->Flags, VCB_VOLUME_LOCKED); Vcb->LockFile = NULL; FFSClearVpbFlag(Vcb->Vpb, VPB_LOCKED); } Vcb->OpenHandleCount--; if (!Vcb->OpenHandleCount) { IoRemoveShareAccess(FileObject, &Vcb->ShareAccess); } Status = STATUS_SUCCESS; _SEH2_LEAVE; } ASSERT((Fcb->Identifier.Type == FFSFCB) && (Fcb->Identifier.Size == sizeof(FFS_FCB))); /* if (!IsFlagOn(Vcb->Flags, VCB_READ_ONLY) && !IsFlagOn(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; } FcbResourceAcquired = TRUE; } Ccb = (PFFS_CCB)FileObject->FsContext2; if (!Ccb) { Status = STATUS_SUCCESS; _SEH2_LEAVE; } if (IsFlagOn(FileObject->Flags, FO_CLEANUP_COMPLETE)) { if (IsFlagOn(FileObject->Flags, FO_FILE_MODIFIED) && IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK) && !IsFlagOn(Vcb->Flags, VCB_WRITE_PROTECTED)) { Status = FFSFlushFile(Fcb); } _SEH2_LEAVE; } ASSERT((Ccb->Identifier.Type == FFSCCB) && (Ccb->Identifier.Size == sizeof(FFS_CCB))); Irp = IrpContext->Irp; Fcb->OpenHandleCount--; if (!IsFlagOn(FileObject->Flags, FO_CACHE_SUPPORTED)) { Fcb->NonCachedOpenCount--; } Vcb->OpenFileHandleCount--; if (IsFlagOn(Fcb->Flags, FCB_DELETE_ON_CLOSE)) { SetFlag(Fcb->Flags, FCB_DELETE_PENDING); if (IsDirectory(Fcb)) { FsRtlNotifyFullChangeDirectory( Vcb->NotifySync, &Vcb->NotifyList, Fcb, NULL, FALSE, FALSE, 0, NULL, NULL, NULL); } } if (IsDirectory(Fcb)) { FsRtlNotifyCleanup( Vcb->NotifySync, &Vcb->NotifyList, Ccb); } else { // // Drop any byte range locks this process may have on the file. // FsRtlFastUnlockAll( &Fcb->FileLockAnchor, FileObject, IoGetRequestorProcess(Irp), NULL); // // If there are no byte range locks owned by other processes on the // file the fast I/O read/write functions doesn't have to check for // locks so we set IsFastIoPossible to FastIoIsPossible again. // if (!FsRtlGetNextFileLock(&Fcb->FileLockAnchor, TRUE)) { if (Fcb->Header.IsFastIoPossible != FastIoIsPossible) { FFSPrint(( DBG_INFO, ": %-16.16s %-31s %s\n", FFSGetCurrentProcessName(), "FastIoIsPossible", Fcb->AnsiFileName.Buffer)); Fcb->Header.IsFastIoPossible = FastIoIsPossible; } } } if (IsFlagOn(FileObject->Flags, FO_CACHE_SUPPORTED) && (Fcb->NonCachedOpenCount != 0) && (Fcb->NonCachedOpenCount == Fcb->ReferenceCount) && (Fcb->SectionObject.DataSectionObject != NULL)) { if(!IsFlagOn(Vcb->Flags, VCB_READ_ONLY) && !IsFlagOn(Vcb->Flags, VCB_WRITE_PROTECTED)) { CcFlushCache(&Fcb->SectionObject, NULL, 0, NULL); } ExAcquireResourceExclusiveLite(&(Fcb->PagingIoResource), TRUE); ExReleaseResourceLite(&(Fcb->PagingIoResource)); CcPurgeCacheSection(&Fcb->SectionObject, NULL, 0, FALSE); } #if !FFS_READ_ONLY if (Fcb->OpenHandleCount == 0) { if (IsFlagOn(Fcb->Flags, FCB_DELETE_PENDING)) { BOOLEAN bDeleted = FALSE; // // Have to delete this file... // #ifdef _MSC_VER #pragma prefast( suppress: 28137, "by design" ) #endif if (!ExAcquireResourceExclusiveLite( &Fcb->PagingIoResource, IrpContext->IsSynchronous)) { Status = STATUS_PENDING; _SEH2_LEAVE; } FcbPagingIoAcquired = TRUE; bDeleted = FFSDeleteFile(IrpContext, Vcb, Fcb); if (bDeleted) { if (IsDirectory(Fcb)) { FFSNotifyReportChange(IrpContext, Vcb, Fcb, FILE_NOTIFY_CHANGE_DIR_NAME, FILE_ACTION_REMOVED); } else { FFSNotifyReportChange(IrpContext, Vcb, Fcb, FILE_NOTIFY_CHANGE_FILE_NAME, FILE_ACTION_REMOVED); } } if (FcbPagingIoAcquired) { ExReleaseResourceForThreadLite( &Fcb->PagingIoResource, ExGetCurrentResourceThread()); FcbPagingIoAcquired = FALSE; } /* if (bDeleted) { FFSPurgeFile(Fcb, FALSE); } */ } } #endif // !FFS_READ_ONLY if (!IsDirectory(Fcb) && FileObject->PrivateCacheMap) { FFSPrint((DBG_INFO, "FFSCleanup: CcUninitializeCacheMap is called for %s.\n", Fcb->AnsiFileName.Buffer)); CcUninitializeCacheMap( FileObject, (PLARGE_INTEGER)(&(Fcb->Header.FileSize)), NULL); } if (!Fcb->OpenHandleCount) { IoRemoveShareAccess(FileObject, &Fcb->ShareAccess); } FFSPrint((DBG_INFO, "FFSCleanup: OpenCount: %u ReferCount: %u %s\n", Fcb->OpenHandleCount, Fcb->ReferenceCount, Fcb->AnsiFileName.Buffer)); Status = STATUS_SUCCESS; if (FileObject) { SetFlag(FileObject->Flags, FO_CLEANUP_COMPLETE); } } _SEH2_FINALLY { if (FcbPagingIoAcquired) { ExReleaseResourceForThreadLite( &Fcb->PagingIoResource, ExGetCurrentResourceThread()); } if (FcbResourceAcquired) { ExReleaseResourceForThreadLite( &Fcb->MainResource, ExGetCurrentResourceThread()); } if (VcbResourceAcquired) { ExReleaseResourceForThreadLite( &Vcb->MainResource, ExGetCurrentResourceThread()); } if (!IrpContext->ExceptionInProgress) { if (Status == STATUS_PENDING) { FFSQueueRequest(IrpContext); } else { IrpContext->Irp->IoStatus.Status = Status; FFSCompleteIrpContext(IrpContext, Status); } } } _SEH2_END; return Status; }
NTSTATUS FFSv1WriteInode( IN PFFS_IRP_CONTEXT IrpContext, IN PFFS_VCB Vcb, IN PFFSv1_INODE dinode1, IN ULONGLONG offset, IN PVOID Buffer, IN ULONG size, IN BOOLEAN bWriteToDisk, OUT PULONG dwRet) { PFFS_BDL ffs_bdl = NULL; ULONG blocks, i; NTSTATUS Status = STATUS_UNSUCCESSFUL; ULONG Totalblocks; LONGLONG AllocSize; if (dwRet) { *dwRet = 0; } Totalblocks = (dinode1->di_blocks); AllocSize = ((LONGLONG)(FFSDataBlocks(Vcb, Totalblocks)) << BLOCK_BITS); if ((LONGLONG)offset >= AllocSize) { FFSPrint((DBG_ERROR, "FFSv1WriteInode: beyond the file range.\n")); return STATUS_SUCCESS; } if ((LONGLONG)offset + size > AllocSize) { size = (ULONG)(AllocSize - offset); } blocks = FFSv1BuildBDL(IrpContext, Vcb, dinode1, offset, size, &ffs_bdl); if (blocks <= 0) { return STATUS_SUCCESS; } #if DBG { ULONG dwTotal = 0; FFSPrint((DBG_INFO, "FFSv1WriteInode: BDLCount = %xh Size=%xh Off=%xh\n", blocks, size, offset)); for(i = 0; i < blocks; i++) { FFSPrint((DBG_INFO, "FFSv1WriteInode: Lba=%I64xh Len=%xh Off=%xh\n", ffs_bdl[i].Lba, ffs_bdl[i].Length, ffs_bdl[i].Offset)); dwTotal += ffs_bdl[i].Length; } if (dwTotal != size) { FFSBreakPoint(); } FFSPrint((DBG_INFO, "FFSv1WriteInode: Total = %xh (WriteToDisk=%x)\n", dwTotal, bWriteToDisk)); } #endif if (bWriteToDisk) { #if 0 for(i = 0; i < blocks; i++) { { CcFlushCache(&(Vcb->SectionObject), (PLARGE_INTEGER)&(ffs_bdl[i].Lba), ffs_bdl[i].Length, NULL); if (Vcb->SectionObject.DataSectionObject != NULL) { ExAcquireSharedStarveExclusive(&Vcb->PagingIoResource, TRUE); ExReleaseResource(&Vcb->PagingIoResource); CcPurgeCacheSection(&(Vcb->SectionObject), (PLARGE_INTEGER)&(ffs_bdl[i].Lba), ffs_bdl[i].Length, FALSE); } } } #endif // assume offset is aligned. Status = FFSReadWriteBlocks(IrpContext, Vcb, ffs_bdl, size, blocks, FALSE); } else { for(i = 0; i < blocks; i++) { if(!FFSSaveBuffer(IrpContext, Vcb, ffs_bdl[i].Lba, ffs_bdl[i].Length, (PVOID)((PUCHAR)Buffer + ffs_bdl[i].Offset))) goto errorout; } if (IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK)) { FFSPrint((DBG_USER, "FFSv1WriteInode is starting FlushingDpc...\n")); FFSStartFloppyFlushDpc(Vcb, NULL, NULL); } Status = STATUS_SUCCESS; } errorout: if (ffs_bdl) ExFreePool(ffs_bdl); if (NT_SUCCESS(Status)) { if (dwRet) *dwRet = size; } return Status; }
__drv_mustHoldCriticalRegion NTSTATUS FFSVerifyVolume( IN PFFS_IRP_CONTEXT IrpContext) { PDEVICE_OBJECT DeviceObject; NTSTATUS Status = STATUS_UNSUCCESSFUL; PFFS_SUPER_BLOCK FFSSb = NULL; PFFS_VCB Vcb = 0; BOOLEAN VcbResourceAcquired = FALSE; BOOLEAN GlobalResourceAcquired = FALSE; PIRP Irp; PIO_STACK_LOCATION IoStackLocation; ULONG ChangeCount; ULONG dwReturn; PAGED_CODE(); _SEH2_TRY { ASSERT(IrpContext != NULL); ASSERT((IrpContext->Identifier.Type == FFSICX) && (IrpContext->Identifier.Size == sizeof(FFS_IRP_CONTEXT))); DeviceObject = IrpContext->DeviceObject; // // This request is not allowed on the main device object // if (DeviceObject == FFSGlobal->DeviceObject) { Status = STATUS_INVALID_DEVICE_REQUEST; _SEH2_LEAVE; } ExAcquireResourceExclusiveLite( &FFSGlobal->Resource, TRUE); GlobalResourceAcquired = TRUE; Vcb = (PFFS_VCB)DeviceObject->DeviceExtension; ASSERT(Vcb != NULL); ASSERT((Vcb->Identifier.Type == FFSVCB) && (Vcb->Identifier.Size == sizeof(FFS_VCB))); ExAcquireResourceExclusiveLite( &Vcb->MainResource, TRUE); VcbResourceAcquired = TRUE; if (!FlagOn(Vcb->TargetDeviceObject->Flags, DO_VERIFY_VOLUME)) { Status = STATUS_SUCCESS; _SEH2_LEAVE; } if (!IsMounted(Vcb)) { Status = STATUS_WRONG_VOLUME; _SEH2_LEAVE; } dwReturn = sizeof(ULONG); Status = FFSDiskIoControl( Vcb->TargetDeviceObject, IOCTL_DISK_CHECK_VERIFY, NULL, 0, &ChangeCount, &dwReturn); if (ChangeCount != Vcb->ChangeCount) { Status = STATUS_WRONG_VOLUME; _SEH2_LEAVE; } Irp = IrpContext->Irp; IoStackLocation = IoGetCurrentIrpStackLocation(Irp); if (((((FFSSb = FFSLoadSuper(Vcb, TRUE, SBLOCK_UFS1)) != NULL) && (FFSSb->fs_magic == FS_UFS1_MAGIC)) || (((FFSSb = FFSLoadSuper(Vcb, TRUE, SBLOCK_UFS2)) != NULL) && (FFSSb->fs_magic == FS_UFS2_MAGIC))) && (memcmp(FFSSb->fs_id, SUPER_BLOCK->fs_id, 8) == 0) && (memcmp(FFSSb->fs_volname, SUPER_BLOCK->fs_volname, 16) == 0)) { ClearFlag(Vcb->TargetDeviceObject->Flags, DO_VERIFY_VOLUME); if (FFSIsMediaWriteProtected(IrpContext, Vcb->TargetDeviceObject)) { SetFlag(Vcb->Flags, VCB_WRITE_PROTECTED); } else { ClearFlag(Vcb->Flags, VCB_WRITE_PROTECTED); } FFSPrint((DBG_INFO, "FFSVerifyVolume: Volume verify succeeded.\n")); Status = STATUS_SUCCESS; } else { Status = STATUS_WRONG_VOLUME; FFSPurgeVolume(Vcb, FALSE); SetFlag(Vcb->Flags, VCB_DISMOUNT_PENDING); ClearFlag(Vcb->TargetDeviceObject->Flags, DO_VERIFY_VOLUME); FFSPrint((DBG_INFO, "FFSVerifyVolume: Volume verify failed.\n")); } } _SEH2_FINALLY { if (FFSSb) ExFreePool(FFSSb); if (VcbResourceAcquired) { ExReleaseResourceForThreadLite( &Vcb->MainResource, ExGetCurrentResourceThread()); } if (GlobalResourceAcquired) { ExReleaseResourceForThreadLite( &FFSGlobal->Resource, ExGetCurrentResourceThread()); } if (!IrpContext->ExceptionInProgress) { FFSCompleteIrpContext(IrpContext, Status); } } _SEH2_END; return Status; }
__drv_mustHoldCriticalRegion NTSTATUS FFSDismountVolume( IN PFFS_IRP_CONTEXT IrpContext) { PDEVICE_OBJECT DeviceObject; NTSTATUS Status = STATUS_UNSUCCESSFUL; PFFS_VCB Vcb = 0; BOOLEAN VcbResourceAcquired = FALSE; PAGED_CODE(); _SEH2_TRY { ASSERT(IrpContext != NULL); ASSERT((IrpContext->Identifier.Type == FFSICX) && (IrpContext->Identifier.Size == sizeof(FFS_IRP_CONTEXT))); DeviceObject = IrpContext->DeviceObject; // // This request is not allowed on the main device object // if (DeviceObject == FFSGlobal->DeviceObject) { Status = STATUS_INVALID_DEVICE_REQUEST; _SEH2_LEAVE; } Vcb = (PFFS_VCB)DeviceObject->DeviceExtension; ASSERT(Vcb != NULL); ASSERT((Vcb->Identifier.Type == FFSVCB) && (Vcb->Identifier.Size == sizeof(FFS_VCB))); ASSERT(IsMounted(Vcb)); ExAcquireResourceExclusiveLite( &Vcb->MainResource, TRUE); VcbResourceAcquired = TRUE; if (IsFlagOn(Vcb->Flags, VCB_DISMOUNT_PENDING)) { Status = STATUS_VOLUME_DISMOUNTED; _SEH2_LEAVE; } /* if (!FlagOn(Vcb->Flags, VCB_VOLUME_LOCKED)) { FFSPrint((DBG_ERROR, "FFSDismount: Volume is not locked.\n")); Status = STATUS_ACCESS_DENIED; _SEH2_LEAVE; } */ FFSFlushFiles(Vcb, FALSE); FFSFlushVolume(Vcb, FALSE); FFSPurgeVolume(Vcb, TRUE); ExReleaseResourceForThreadLite( &Vcb->MainResource, ExGetCurrentResourceThread()); VcbResourceAcquired = FALSE; FFSCheckDismount(IrpContext, Vcb, TRUE); FFSPrint((DBG_INFO, "FFSDismount: Volume dismount pending.\n")); Status = STATUS_SUCCESS; } _SEH2_FINALLY { if (VcbResourceAcquired) { ExReleaseResourceForThreadLite( &Vcb->MainResource, ExGetCurrentResourceThread()); } if (!IrpContext->ExceptionInProgress) { FFSCompleteIrpContext(IrpContext, Status); } } _SEH2_END; return Status; }
NTSTATUS FFSWriteVolume( IN PFFS_IRP_CONTEXT IrpContext) { NTSTATUS Status = STATUS_UNSUCCESSFUL; PFFS_VCB Vcb = NULL; PFFS_CCB Ccb = NULL; PFFS_FCBVCB FcbOrVcb = NULL; PFILE_OBJECT FileObject = NULL; PDEVICE_OBJECT DeviceObject = NULL; PIRP Irp = NULL; PIO_STACK_LOCATION IoStackLocation = NULL; ULONG Length; LARGE_INTEGER ByteOffset; BOOLEAN PagingIo; BOOLEAN Nocache; BOOLEAN SynchronousIo; BOOLEAN MainResourceAcquired = FALSE; BOOLEAN PagingIoResourceAcquired = FALSE; BOOLEAN bDeferred = FALSE; PUCHAR Buffer = NULL; __try { ASSERT(IrpContext); ASSERT((IrpContext->Identifier.Type == FFSICX) && (IrpContext->Identifier.Size == sizeof(FFS_IRP_CONTEXT))); DeviceObject = IrpContext->DeviceObject; Vcb = (PFFS_VCB)DeviceObject->DeviceExtension; ASSERT(Vcb != NULL); ASSERT((Vcb->Identifier.Type == FFSVCB) && (Vcb->Identifier.Size == sizeof(FFS_VCB))); FileObject = IrpContext->FileObject; FcbOrVcb = (PFFS_FCBVCB)FileObject->FsContext; ASSERT(FcbOrVcb); if (!(FcbOrVcb->Identifier.Type == FFSVCB && (PVOID)FcbOrVcb == (PVOID)Vcb)) { Status = STATUS_INVALID_DEVICE_REQUEST; __leave; } Ccb = (PFFS_CCB)FileObject->FsContext2; Irp = IrpContext->Irp; IoStackLocation = IoGetCurrentIrpStackLocation(Irp); Length = IoStackLocation->Parameters.Write.Length; ByteOffset = IoStackLocation->Parameters.Write.ByteOffset; PagingIo = (Irp->Flags & IRP_PAGING_IO ? TRUE : FALSE); Nocache = (Irp->Flags & IRP_NOCACHE ? TRUE : FALSE); SynchronousIo = (FileObject->Flags & FO_SYNCHRONOUS_IO ? TRUE : FALSE); FFSPrint((DBG_INFO, "FFSWriteVolume: Off=%I64xh Len=%xh Paging=%xh Nocache=%xh\n", ByteOffset.QuadPart, Length, PagingIo, Nocache)); if (Length == 0) { Irp->IoStatus.Information = 0; Status = STATUS_SUCCESS; __leave; } // For the case of "Direct Access Storage Device", we // need flush/purge the cache if (Ccb != NULL) { ExAcquireResourceExclusive(&Vcb->MainResource, TRUE); MainResourceAcquired = TRUE; Status = FFSPurgeVolume(Vcb, TRUE); ExReleaseResource(&Vcb->MainResource); MainResourceAcquired = FALSE; if(!IsFlagOn(Ccb->Flags, CCB_ALLOW_EXTENDED_DASD_IO)) { if (ByteOffset.QuadPart + Length > Vcb->Header.FileSize.QuadPart) { Length = (ULONG)(Vcb->Header.FileSize.QuadPart - ByteOffset.QuadPart); } } { FFS_BDL BlockArray; if ((ByteOffset.LowPart & (SECTOR_SIZE - 1)) || (Length & (SECTOR_SIZE - 1))) { Status = STATUS_INVALID_PARAMETER; __leave; } Status = FFSLockUserBuffer( IrpContext->Irp, Length, IoReadAccess); if (!NT_SUCCESS(Status)) { __leave; } BlockArray.Irp = NULL; BlockArray.Lba = ByteOffset.QuadPart;; BlockArray.Offset = 0; BlockArray.Length = Length; Status = FFSReadWriteBlocks(IrpContext, Vcb, &BlockArray, Length, 1, FALSE); Irp = IrpContext->Irp; __leave; } } if (Nocache && (ByteOffset.LowPart & (SECTOR_SIZE - 1) || Length & (SECTOR_SIZE - 1))) { Status = STATUS_INVALID_PARAMETER; __leave; } if (FlagOn(IrpContext->MinorFunction, IRP_MN_DPC)) { ClearFlag(IrpContext->MinorFunction, IRP_MN_DPC); Status = STATUS_PENDING; __leave; } if (ByteOffset.QuadPart >= Vcb->PartitionInformation.PartitionLength.QuadPart) { Irp->IoStatus.Information = 0; Status = STATUS_END_OF_FILE; __leave; } #if FALSE if (!Nocache) { BOOLEAN bAgain = IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_DEFERRED); BOOLEAN bWait = IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT); BOOLEAN bQueue = IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_REQUEUED); if (!CcCanIWrite( FileObject, Length, (bWait && bQueue), bAgain)) { SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_DEFERRED); CcDeferWrite(FileObject, (PCC_POST_DEFERRED_WRITE)FFSDeferWrite, IrpContext, Irp, Length, bAgain); bDeferred = TRUE; FFSBreakPoint(); Status = STATUS_PENDING; __leave; } } #endif if (Nocache && !PagingIo && (Vcb->SectionObject.DataSectionObject != NULL)) { ExAcquireResourceExclusive(&Vcb->MainResource, TRUE); MainResourceAcquired = TRUE; ExAcquireSharedStarveExclusive(&Vcb->PagingIoResource, TRUE); ExReleaseResource(&Vcb->PagingIoResource); CcFlushCache(&(Vcb->SectionObject), &ByteOffset, Length, &(Irp->IoStatus)); if (!NT_SUCCESS(Irp->IoStatus.Status)) { Status = Irp->IoStatus.Status; __leave; } ExAcquireSharedStarveExclusive(&Vcb->PagingIoResource, TRUE); ExReleaseResource(&Vcb->PagingIoResource); CcPurgeCacheSection(&(Vcb->SectionObject), (PLARGE_INTEGER)&(ByteOffset), Length, FALSE); ExReleaseResource(&Vcb->MainResource); MainResourceAcquired = FALSE; } if (!PagingIo) { if (!ExAcquireResourceExclusiveLite( &Vcb->MainResource, IrpContext->IsSynchronous)) { Status = STATUS_PENDING; __leave; } MainResourceAcquired = TRUE; } else { /* ULONG ResShCnt, ResExCnt; ResShCnt = ExIsResourceAcquiredSharedLite(&Vcb->PagingIoResource); ResExCnt = ExIsResourceAcquiredExclusiveLite(&Vcb->PagingIoResource); FFSPrint((DBG_USER, "PagingIoRes: %xh:%xh Synchronous=%xh\n", ResShCnt, ResExCnt, IrpContext->IsSynchronous)); */ if (Ccb) { if (!ExAcquireResourceSharedLite( &Vcb->PagingIoResource, IrpContext->IsSynchronous)) { Status = STATUS_PENDING; __leave; } PagingIoResourceAcquired = TRUE; } } if (!Nocache) { if ((ByteOffset.QuadPart + Length) > Vcb->PartitionInformation.PartitionLength.QuadPart ) { Length = (ULONG) ( Vcb->PartitionInformation.PartitionLength.QuadPart - ByteOffset.QuadPart); Length &= ~((ULONG)SECTOR_SIZE - 1); } if (FlagOn(IrpContext->MinorFunction, IRP_MN_MDL)) { CcPrepareMdlWrite( Vcb->StreamObj, &ByteOffset, Length, &Irp->MdlAddress, &Irp->IoStatus); Status = Irp->IoStatus.Status; } else { Buffer = FFSGetUserBuffer(Irp); if (Buffer == NULL) { FFSBreakPoint(); Status = STATUS_INVALID_USER_BUFFER; __leave; } if (!CcCopyWrite(Vcb->StreamObj, (PLARGE_INTEGER)(&ByteOffset), Length, TRUE, Buffer)) { Status = STATUS_PENDING; __leave; } Status = Irp->IoStatus.Status; FFSAddMcbEntry(Vcb, ByteOffset.QuadPart, (LONGLONG)Length); } if (NT_SUCCESS(Status)) { Irp->IoStatus.Information = Length; } } else { PFFS_BDL ffs_bdl = NULL; ULONG Blocks = 0; LONGLONG DirtyStart; LONGLONG DirtyLba; LONGLONG DirtyLength; LONGLONG RemainLength; if ((ByteOffset.QuadPart + Length) > Vcb->PartitionInformation.PartitionLength.QuadPart) { Length = (ULONG)( Vcb->PartitionInformation.PartitionLength.QuadPart - ByteOffset.QuadPart); Length &= ~((ULONG)SECTOR_SIZE - 1); } Status = FFSLockUserBuffer( IrpContext->Irp, Length, IoReadAccess); if (!NT_SUCCESS(Status)) { __leave; } ffs_bdl = ExAllocatePool(PagedPool, (Length / Vcb->BlockSize) * sizeof(FFS_BDL)); if (!ffs_bdl) { Status = STATUS_INSUFFICIENT_RESOURCES; __leave; } DirtyLba = ByteOffset.QuadPart; RemainLength = (LONGLONG)Length; while (RemainLength > 0) { DirtyStart = DirtyLba; if (FFSLookupMcbEntry(Vcb, DirtyStart, &DirtyLba, &DirtyLength, (PLONGLONG)NULL, (PLONGLONG)NULL, (PULONG)NULL)) { if (DirtyLba == -1) { DirtyLba = DirtyStart + DirtyLength; RemainLength = ByteOffset.QuadPart + (LONGLONG)Length - DirtyLba; continue; } ffs_bdl[Blocks].Irp = NULL; ffs_bdl[Blocks].Lba = DirtyLba; ffs_bdl[Blocks].Offset = (ULONG)((LONGLONG)Length + DirtyStart - RemainLength - DirtyLba); if (DirtyLba + DirtyLength > DirtyStart + RemainLength) { ffs_bdl[Blocks].Length = (ULONG)(DirtyStart + RemainLength - DirtyLba); RemainLength = 0; } else { ffs_bdl[Blocks].Length = (ULONG)DirtyLength; RemainLength = (DirtyStart + RemainLength) - (DirtyLba + DirtyLength); } DirtyLba = DirtyStart + DirtyLength; Blocks++; } else { if (Blocks == 0) { if (ffs_bdl) ExFreePool(ffs_bdl); // // Lookup fails at the first time, ie. // no dirty blocks in the run // FFSBreakPoint(); if (RemainLength == (LONGLONG)Length) Status = STATUS_SUCCESS; else Status = STATUS_UNSUCCESSFUL; __leave; } else { break; } } } if (Blocks > 0) { Status = FFSReadWriteBlocks(IrpContext, Vcb, ffs_bdl, Length, Blocks, FALSE); Irp = IrpContext->Irp; if (NT_SUCCESS(Status)) { ULONG i; for (i = 0; i < Blocks; i++) { FFSRemoveMcbEntry(Vcb, ffs_bdl[i].Lba, ffs_bdl[i].Length); } } if (ffs_bdl) ExFreePool(ffs_bdl); if (!Irp) __leave; } else { if (ffs_bdl) ExFreePool(ffs_bdl); Irp->IoStatus.Information = Length; Status = STATUS_SUCCESS; __leave; } } } __finally { if (PagingIoResourceAcquired) { ExReleaseResourceForThreadLite( &Vcb->PagingIoResource, ExGetCurrentResourceThread()); } if (MainResourceAcquired) { ExReleaseResourceForThreadLite( &Vcb->MainResource, ExGetCurrentResourceThread()); } if (!IrpContext->ExceptionInProgress) { if (Irp) { if (Status == STATUS_PENDING) { if(!bDeferred) { Status = FFSLockUserBuffer( IrpContext->Irp, Length, IoReadAccess); if (NT_SUCCESS(Status)) { Status = FFSQueueRequest(IrpContext); } else { FFSCompleteIrpContext(IrpContext, Status); } } } else { if (NT_SUCCESS(Status)) { if (SynchronousIo && !PagingIo) { FileObject->CurrentByteOffset.QuadPart = ByteOffset.QuadPart + Irp->IoStatus.Information; } if (!PagingIo) { SetFlag(FileObject->Flags, FO_FILE_MODIFIED); } } FFSCompleteIrpContext(IrpContext, Status); } } else { FFSFreeIrpContext(IrpContext); } } } return Status; }
BOOLEAN FFSIsDirectoryEmpty( PFFS_VCB Vcb, PFFS_FCB Dcb) { NTSTATUS Status = STATUS_UNSUCCESSFUL; PFFS_DIR_ENTRY pTarget = NULL; ULONG dwBytes = 0; ULONG dwRet; BOOLEAN bRet = TRUE; PAGED_CODE(); if (!IsFlagOn(Dcb->FFSMcb->FileAttr, FILE_ATTRIBUTE_DIRECTORY)) return TRUE; _SEH2_TRY { pTarget = (PFFS_DIR_ENTRY)ExAllocatePoolWithTag(PagedPool, FFS_DIR_REC_LEN(FFS_NAME_LEN), FFS_POOL_TAG); if (!pTarget) { Status = STATUS_INSUFFICIENT_RESOURCES; _SEH2_LEAVE; } dwBytes = 0; while ((LONGLONG)dwBytes < Dcb->Header.AllocationSize.QuadPart) { RtlZeroMemory(pTarget, FFS_DIR_REC_LEN(FFS_NAME_LEN)); if (FS_VERSION == 1) { Status = FFSv1ReadInode( NULL, Vcb, Dcb->dinode1, dwBytes, (PVOID)pTarget, FFS_DIR_REC_LEN(FFS_NAME_LEN), &dwRet); } else { Status = FFSv2ReadInode( NULL, Vcb, Dcb->dinode2, dwBytes, (PVOID)pTarget, FFS_DIR_REC_LEN(FFS_NAME_LEN), &dwRet); } if (!NT_SUCCESS(Status)) { FFSPrint((DBG_ERROR, "FFSRemoveEntry: Reading Directory Content error.\n")); _SEH2_LEAVE; } if (pTarget->d_ino) { if (pTarget->d_namlen == 1 && pTarget->d_name[0] == '.') { } else if (pTarget->d_namlen == 2 && pTarget->d_name[0] == '.' && pTarget->d_name[1] == '.') { } else { bRet = FALSE; break; } } else { break; } dwBytes += pTarget->d_reclen; } } _SEH2_FINALLY { if (pTarget != NULL) { ExFreePool(pTarget); } } _SEH2_END; return bRet; }
__drv_mustHoldCriticalRegion NTSTATUS FFSInvalidateVolumes( IN PFFS_IRP_CONTEXT IrpContext) { NTSTATUS Status; PIRP Irp; PIO_STACK_LOCATION IrpSp; HANDLE Handle; PLIST_ENTRY ListEntry; PFILE_OBJECT FileObject; PDEVICE_OBJECT DeviceObject; BOOLEAN GlobalResourceAcquired = FALSE; LUID Privilege = {SE_TCB_PRIVILEGE, 0}; _SEH2_TRY { Irp = IrpContext->Irp; IrpSp = IoGetCurrentIrpStackLocation(Irp); if (!SeSinglePrivilegeCheck(Privilege, Irp->RequestorMode)) { Status = STATUS_PRIVILEGE_NOT_HELD; _SEH2_LEAVE; } if ( #if !defined(_GNU_NTIFS_) || defined(__REACTOS__) IrpSp->Parameters.FileSystemControl.InputBufferLength #else ((PEXTENDED_IO_STACK_LOCATION)(IrpSp))-> Parameters.FileSystemControl.InputBufferLength #endif != sizeof(HANDLE)) { Status = STATUS_INVALID_PARAMETER; _SEH2_LEAVE; } Handle = *(PHANDLE)Irp->AssociatedIrp.SystemBuffer; Status = ObReferenceObjectByHandle(Handle, 0, *IoFileObjectType, KernelMode, (void **)&FileObject, NULL); if (!NT_SUCCESS(Status)) { _SEH2_LEAVE; } else { ObDereferenceObject(FileObject); DeviceObject = FileObject->DeviceObject; } FFSPrint((DBG_INFO, "FFSInvalidateVolumes: FileObject=%xh ...\n", FileObject)); ExAcquireResourceExclusiveLite( &FFSGlobal->Resource, TRUE); GlobalResourceAcquired = TRUE; ListEntry = FFSGlobal->VcbList.Flink; while (ListEntry != &FFSGlobal->VcbList) { PFFS_VCB Vcb; Vcb = CONTAINING_RECORD(ListEntry, FFS_VCB, Next); ListEntry = ListEntry->Flink; FFSPrint((DBG_INFO, "FFSInvalidateVolumes: Vcb=%xh Vcb->Vpb=%xh...\n", Vcb, Vcb->Vpb)); if (Vcb->Vpb && (Vcb->Vpb->RealDevice == DeviceObject)) { ExAcquireResourceExclusiveLite(&Vcb->MainResource, TRUE); FFSPrint((DBG_INFO, "FFSInvalidateVolumes: FFSPurgeVolume...\n")); FFSPurgeVolume(Vcb, FALSE); ClearFlag(Vcb->Flags, VCB_MOUNTED); ExReleaseResourceLite(&Vcb->MainResource); // // Vcb is still attached on the list ...... // if (ListEntry->Blink == &Vcb->Next) { FFSPrint((DBG_INFO, "FFSInvalidateVolumes: FFSCheckDismount...\n")); FFSCheckDismount(IrpContext, Vcb, FALSE); } } } } _SEH2_FINALLY { if (GlobalResourceAcquired) { ExReleaseResourceForThreadLite( &FFSGlobal->Resource, ExGetCurrentResourceThread()); } FFSCompleteIrpContext(IrpContext, Status); } _SEH2_END; return Status; }
__drv_mustHoldCriticalRegion NTSTATUS FFSPurgeVolume( IN PFFS_VCB Vcb, IN BOOLEAN FlushBeforePurge) { PFFS_FCB Fcb; LIST_ENTRY FcbList; PLIST_ENTRY ListEntry; PFCB_LIST_ENTRY FcbListEntry; PAGED_CODE(); _SEH2_TRY { ASSERT(Vcb != NULL); ASSERT((Vcb->Identifier.Type == FFSVCB) && (Vcb->Identifier.Size == sizeof(FFS_VCB))); if (IsFlagOn(Vcb->Flags, VCB_READ_ONLY) || IsFlagOn(Vcb->Flags, VCB_WRITE_PROTECTED)) { FlushBeforePurge = FALSE; } FcbListEntry= NULL; InitializeListHead(&FcbList); for (ListEntry = Vcb->FcbList.Flink; ListEntry != &Vcb->FcbList; ListEntry = ListEntry->Flink) { Fcb = CONTAINING_RECORD(ListEntry, FFS_FCB, Next); Fcb->ReferenceCount++; FFSPrint((DBG_INFO, "FFSPurgeVolume: %s refercount=%xh\n", Fcb->AnsiFileName.Buffer, Fcb->ReferenceCount)); FcbListEntry = ExAllocatePoolWithTag(PagedPool, sizeof(FCB_LIST_ENTRY), FFS_POOL_TAG); if (FcbListEntry) { FcbListEntry->Fcb = Fcb; InsertTailList(&FcbList, &FcbListEntry->Next); } else { FFSPrint((DBG_ERROR, "FFSPurgeVolume: Error allocating FcbListEntry ...\n")); } } while (!IsListEmpty(&FcbList)) { ListEntry = RemoveHeadList(&FcbList); FcbListEntry = CONTAINING_RECORD(ListEntry, FCB_LIST_ENTRY, Next); Fcb = FcbListEntry->Fcb; if (ExAcquireResourceExclusiveLite( &Fcb->MainResource, TRUE)) { FFSPurgeFile(Fcb, FlushBeforePurge); if (!Fcb->OpenHandleCount && Fcb->ReferenceCount == 1) { RemoveEntryList(&Fcb->Next); FFSFreeFcb(Fcb); } else { ExReleaseResourceForThreadLite( &Fcb->MainResource, ExGetCurrentResourceThread()); } } ExFreePool(FcbListEntry); } if (FlushBeforePurge) { ExAcquireSharedStarveExclusive(&Vcb->PagingIoResource, TRUE); ExReleaseResourceLite(&Vcb->PagingIoResource); CcFlushCache(&Vcb->SectionObject, NULL, 0, NULL); } if (Vcb->SectionObject.ImageSectionObject) { MmFlushImageSection(&Vcb->SectionObject, MmFlushForWrite); } if (Vcb->SectionObject.DataSectionObject) { CcPurgeCacheSection(&Vcb->SectionObject, NULL, 0, FALSE); } FFSPrint((DBG_INFO, "FFSPurgeVolume: Volume flushed and purged.\n")); } _SEH2_FINALLY { // Nothing } _SEH2_END; return STATUS_SUCCESS; }
NTSTATUS FFSWriteFile( IN PFFS_IRP_CONTEXT IrpContext) { NTSTATUS Status = STATUS_UNSUCCESSFUL; PFFS_VCB Vcb = NULL; PFFS_FCB Fcb = NULL; PFFS_CCB Ccb = NULL; PFILE_OBJECT FileObject = NULL; PFILE_OBJECT CacheObject; PDEVICE_OBJECT DeviceObject = NULL; PIRP Irp = NULL; PIO_STACK_LOCATION IoStackLocation = NULL; ULONG Length; ULONG ReturnedLength = 0; LARGE_INTEGER ByteOffset; BOOLEAN PagingIo; BOOLEAN Nocache; BOOLEAN SynchronousIo; BOOLEAN MainResourceAcquired = FALSE; BOOLEAN PagingIoResourceAcquired = FALSE; BOOLEAN bNeedExtending = FALSE; BOOLEAN bAppendFile = FALSE; BOOLEAN bDeferred = FALSE; PUCHAR Buffer = NULL; __try { ASSERT(IrpContext); ASSERT((IrpContext->Identifier.Type == FFSICX) && (IrpContext->Identifier.Size == sizeof(FFS_IRP_CONTEXT))); DeviceObject = IrpContext->DeviceObject; Vcb = (PFFS_VCB)DeviceObject->DeviceExtension; ASSERT(Vcb != NULL); ASSERT((Vcb->Identifier.Type == FFSVCB) && (Vcb->Identifier.Size == sizeof(FFS_VCB))); FileObject = IrpContext->FileObject; Fcb = (PFFS_FCB)FileObject->FsContext; ASSERT(Fcb); ASSERT((Fcb->Identifier.Type == FFSFCB) && (Fcb->Identifier.Size == sizeof(FFS_FCB))); Ccb = (PFFS_CCB)FileObject->FsContext2; Irp = IrpContext->Irp; IoStackLocation = IoGetCurrentIrpStackLocation(Irp); Length = IoStackLocation->Parameters.Write.Length; ByteOffset = IoStackLocation->Parameters.Write.ByteOffset; PagingIo = (Irp->Flags & IRP_PAGING_IO ? TRUE : FALSE); Nocache = (Irp->Flags & IRP_NOCACHE ? TRUE : FALSE); SynchronousIo = (FileObject->Flags & FO_SYNCHRONOUS_IO ? TRUE : FALSE); FFSPrint((DBG_INFO, "FFSWriteFile: Off=%I64xh Len=%xh Paging=%xh Nocache=%xh\n", ByteOffset.QuadPart, Length, PagingIo, Nocache)); /* if (IsFlagOn(Fcb->Flags, FCB_FILE_DELETED)) { Status = STATUS_FILE_DELETED; __leave; } if (IsFlagOn(Fcb->Flags, FCB_DELETE_PENDING)) { Status = STATUS_DELETE_PENDING; __leave; } */ if (Length == 0) { Irp->IoStatus.Information = 0; Status = STATUS_SUCCESS; __leave; } if (Nocache && (ByteOffset.LowPart & (SECTOR_SIZE - 1) || Length & (SECTOR_SIZE - 1))) { Status = STATUS_INVALID_PARAMETER; __leave; } if (FlagOn(IrpContext->MinorFunction, IRP_MN_DPC)) { ClearFlag(IrpContext->MinorFunction, IRP_MN_DPC); Status = STATUS_PENDING; __leave; } #if FALSE if (!Nocache) { BOOLEAN bAgain = IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_DEFERRED); BOOLEAN bWait = IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT); BOOLEAN bQueue = IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_REQUEUED); if (!CcCanIWrite( FileObject, Length, (bWait && bQueue), bAgain)) { SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_DEFERRED); CcDeferWrite(FileObject, (PCC_POST_DEFERRED_WRITE)FFSDeferWrite, IrpContext, Irp, Length, bAgain); bDeferred = TRUE; FFSBreakPoint(); Status = STATUS_PENDING; __leave; } } #endif if (IsEndOfFile(ByteOffset)) { bAppendFile = TRUE; ByteOffset.QuadPart = Fcb->Header.FileSize.QuadPart; } if (FlagOn(Fcb->FFSMcb->FileAttr, FILE_ATTRIBUTE_DIRECTORY) && !PagingIo) { Status = STATUS_INVALID_DEVICE_REQUEST; __leave; } // // Do flushing for such cases // if (Nocache && !PagingIo && (Fcb->SectionObject.DataSectionObject != NULL)) { ExAcquireResourceExclusive(&Fcb->MainResource, IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT)); MainResourceAcquired = TRUE; ExAcquireSharedStarveExclusive(&Fcb->PagingIoResource, TRUE); ExReleaseResource(&Fcb->PagingIoResource); CcFlushCache(&(Fcb->SectionObject), &ByteOffset, Length, &(Irp->IoStatus)); ClearFlag(Fcb->Flags, FCB_FILE_MODIFIED); if (!NT_SUCCESS(Irp->IoStatus.Status)) { Status = Irp->IoStatus.Status; __leave; } ExAcquireSharedStarveExclusive(&Fcb->PagingIoResource, TRUE); ExReleaseResource(&Fcb->PagingIoResource); CcPurgeCacheSection(&(Fcb->SectionObject), (PLARGE_INTEGER)&(ByteOffset), Length, FALSE); ExReleaseResource(&Fcb->MainResource); MainResourceAcquired = FALSE; } if (!PagingIo) { if (!ExAcquireResourceExclusiveLite( &Fcb->MainResource, IrpContext->IsSynchronous)) { Status = STATUS_PENDING; __leave; } MainResourceAcquired = TRUE; } else { /* ULONG ResShCnt, ResExCnt; ResShCnt = ExIsResourceAcquiredSharedLite(&Fcb->PagingIoResource); ResExCnt = ExIsResourceAcquiredExclusiveLite(&Fcb->PagingIoResource); FFSPrint((DBG_USER, "FFSWriteFile: Inode=%xh %S PagingIo: %xh:%xh Synchronous=%xh\n", Fcb->FFSMcb->Inode, Fcb->FFSMcb->ShortName.Buffer, ResShCnt, ResExCnt, IrpContext->IsSynchronous)); */ if (!ExAcquireResourceSharedLite( &Fcb->PagingIoResource, IrpContext->IsSynchronous)) { Status = STATUS_PENDING; __leave; } PagingIoResourceAcquired = TRUE; } if (!PagingIo) { if (!FsRtlCheckLockForWriteAccess( &Fcb->FileLockAnchor, Irp)) { Status = STATUS_FILE_LOCK_CONFLICT; __leave; } } if (Nocache) { if ((ByteOffset.QuadPart + Length) > Fcb->Header.AllocationSize.QuadPart) { if (ByteOffset.QuadPart >= Fcb->Header.AllocationSize.QuadPart) { Status = STATUS_SUCCESS; Irp->IoStatus.Information = 0; __leave; } else { if (Length > (ULONG)(Fcb->Header.AllocationSize.QuadPart - ByteOffset.QuadPart)) { Length = (ULONG)(Fcb->Header.AllocationSize.QuadPart - ByteOffset.QuadPart); } } } } if (!Nocache) { if (FlagOn(Fcb->FFSMcb->FileAttr, FILE_ATTRIBUTE_DIRECTORY)) { __leave; } if (FileObject->PrivateCacheMap == NULL) { CcInitializeCacheMap( FileObject, (PCC_FILE_SIZES)(&Fcb->Header.AllocationSize), FALSE, &FFSGlobal->CacheManagerCallbacks, Fcb); CcSetReadAheadGranularity( FileObject, READ_AHEAD_GRANULARITY); CcSetFileSizes( FileObject, (PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize))); } CacheObject = FileObject; // // Need extending the size of inode ? // if ((bAppendFile) || ((ULONG)(ByteOffset.QuadPart + Length) > (ULONG)(Fcb->Header.FileSize.QuadPart))) { LARGE_INTEGER ExtendSize; LARGE_INTEGER FileSize; bNeedExtending = TRUE; FileSize = Fcb->Header.FileSize; ExtendSize.QuadPart = (LONGLONG)(ByteOffset.QuadPart + Length); if (ExtendSize.QuadPart > Fcb->Header.AllocationSize.QuadPart) { if (!FFSExpandFile(IrpContext, Vcb, Fcb, &ExtendSize)) { Status = STATUS_INSUFFICIENT_RESOURCES; __leave; } } { Fcb->Header.FileSize.QuadPart = ExtendSize.QuadPart; Fcb->dinode1->di_size = (ULONG)ExtendSize.QuadPart; } if (FileObject->PrivateCacheMap) { CcSetFileSizes(FileObject, (PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize))); if (ByteOffset.QuadPart > FileSize.QuadPart) { FFSZeroHoles(IrpContext, Vcb, FileObject, FileSize.QuadPart, ByteOffset.QuadPart - FileSize.QuadPart); } if (Fcb->Header.AllocationSize.QuadPart > ExtendSize.QuadPart) { FFSZeroHoles(IrpContext, Vcb, FileObject, ExtendSize.QuadPart, Fcb->Header.AllocationSize.QuadPart - ExtendSize.QuadPart); } } if (FFSv1SaveInode(IrpContext, Vcb, Fcb->FFSMcb->Inode, Fcb->dinode1)) { Status = STATUS_SUCCESS; } FFSNotifyReportChange( IrpContext, Vcb, Fcb, FILE_NOTIFY_CHANGE_SIZE, FILE_ACTION_MODIFIED); } if (FlagOn(IrpContext->MinorFunction, IRP_MN_MDL)) { CcPrepareMdlWrite( CacheObject, (&ByteOffset), Length, &Irp->MdlAddress, &Irp->IoStatus); Status = Irp->IoStatus.Status; } else { Buffer = FFSGetUserBuffer(Irp); if (Buffer == NULL) { FFSBreakPoint(); Status = STATUS_INVALID_USER_BUFFER; __leave; } if (!CcCopyWrite( CacheObject, (PLARGE_INTEGER)&ByteOffset, Length, IrpContext->IsSynchronous, Buffer)) { Status = STATUS_PENDING; __leave; } Status = Irp->IoStatus.Status; } if (NT_SUCCESS(Status)) { Irp->IoStatus.Information = Length; if (IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK)) { FFSPrint((DBG_USER, "FFSWriteFile is starting FlushingDpc...\n")); FFSStartFloppyFlushDpc(Vcb, Fcb, FileObject); } } } else { ReturnedLength = Length; Status = FFSLockUserBuffer( IrpContext->Irp, Length, IoReadAccess); if (!NT_SUCCESS(Status)) { __leave; } Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = Length; Status = FFSv1WriteInode( IrpContext, Vcb, Fcb->dinode1, (ULONGLONG)(ByteOffset.QuadPart), NULL, Length, TRUE, &ReturnedLength); Irp = IrpContext->Irp; } } __finally { if (PagingIoResourceAcquired) { ExReleaseResourceForThreadLite( &Fcb->PagingIoResource, ExGetCurrentResourceThread()); } if (MainResourceAcquired) { ExReleaseResourceForThreadLite( &Fcb->MainResource, ExGetCurrentResourceThread()); } if (!IrpContext->ExceptionInProgress) { if (Irp) { if (Status == STATUS_PENDING) { if (!bDeferred) { Status = FFSLockUserBuffer( IrpContext->Irp, Length, IoReadAccess); if (NT_SUCCESS(Status)) { Status = FFSQueueRequest(IrpContext); } else { FFSCompleteIrpContext(IrpContext, Status); } } } else { if (NT_SUCCESS(Status)) { if (SynchronousIo && !PagingIo) { FileObject->CurrentByteOffset.QuadPart = ByteOffset.QuadPart + Irp->IoStatus.Information; } if (!PagingIo) { SetFlag(FileObject->Flags, FO_FILE_MODIFIED); SetFlag(Fcb->Flags, FCB_FILE_MODIFIED); } } FFSCompleteIrpContext(IrpContext, Status); } } else { FFSFreeIrpContext(IrpContext); } } } return Status; }
__drv_mustHoldCriticalRegion NTSTATUS FFSClose( IN PFFS_IRP_CONTEXT IrpContext) { PDEVICE_OBJECT DeviceObject; NTSTATUS Status = STATUS_SUCCESS; PFFS_VCB Vcb = 0; BOOLEAN VcbResourceAcquired = FALSE; PFILE_OBJECT FileObject; PFFS_FCB Fcb = 0; BOOLEAN FcbResourceAcquired = FALSE; PFFS_CCB Ccb; BOOLEAN FreeVcb = FALSE; PAGED_CODE(); _SEH2_TRY { ASSERT(IrpContext != NULL); ASSERT((IrpContext->Identifier.Type == FFSICX) && (IrpContext->Identifier.Size == sizeof(FFS_IRP_CONTEXT))); DeviceObject = IrpContext->DeviceObject; if (DeviceObject == FFSGlobal->DeviceObject) { Status = STATUS_SUCCESS; _SEH2_LEAVE; } Vcb = (PFFS_VCB) DeviceObject->DeviceExtension; ASSERT(Vcb != NULL); ASSERT((Vcb->Identifier.Type == FFSVCB) && (Vcb->Identifier.Size == sizeof(FFS_VCB))); ASSERT(IsMounted(Vcb)); if (!ExAcquireResourceExclusiveLite( &Vcb->MainResource, IrpContext->IsSynchronous)) { FFSPrint((DBG_INFO, "FFSClose: PENDING ... Vcb: %xh/%xh\n", Vcb->OpenFileHandleCount, Vcb->ReferenceCount)); Status = STATUS_PENDING; _SEH2_LEAVE; } VcbResourceAcquired = TRUE; FileObject = IrpContext->FileObject; if (IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_DELAY_CLOSE)) { Fcb = IrpContext->Fcb; Ccb = IrpContext->Ccb; } else { Fcb = (PFFS_FCB)FileObject->FsContext; if (!Fcb) { Status = STATUS_SUCCESS; _SEH2_LEAVE; } ASSERT(Fcb != NULL); Ccb = (PFFS_CCB)FileObject->FsContext2; } if (Fcb->Identifier.Type == FFSVCB) { Vcb->ReferenceCount--; if (!Vcb->ReferenceCount && FlagOn(Vcb->Flags, VCB_DISMOUNT_PENDING)) { FreeVcb = TRUE; } if (Ccb) { FFSFreeCcb(Ccb); if (FileObject) { FileObject->FsContext2 = Ccb = NULL; } } Status = STATUS_SUCCESS; _SEH2_LEAVE; } if (Fcb->Identifier.Type != FFSFCB || Fcb->Identifier.Size != sizeof(FFS_FCB)) { #if DBG FFSPrint((DBG_ERROR, "FFSClose: Strange IRP_MJ_CLOSE by system!\n")); ExAcquireResourceExclusiveLite( &FFSGlobal->CountResource, TRUE); FFSGlobal->IRPCloseCount++; ExReleaseResourceForThreadLite( &FFSGlobal->CountResource, ExGetCurrentResourceThread()); #endif _SEH2_LEAVE; } ASSERT((Fcb->Identifier.Type == FFSFCB) && (Fcb->Identifier.Size == sizeof(FFS_FCB))); /* if ((!IsFlagOn(Vcb->Flags, VCB_READ_ONLY)) && (!IsFlagOn(Fcb->Flags, FCB_PAGE_FILE))) */ { if (!ExAcquireResourceExclusiveLite( &Fcb->MainResource, IrpContext->IsSynchronous)) { Status = STATUS_PENDING; _SEH2_LEAVE; } FcbResourceAcquired = TRUE; } if (!Ccb) { Status = STATUS_SUCCESS; _SEH2_LEAVE; } ASSERT((Ccb->Identifier.Type == FFSCCB) && (Ccb->Identifier.Size == sizeof(FFS_CCB))); Fcb->ReferenceCount--; Vcb->ReferenceCount--; if (!Vcb->ReferenceCount && IsFlagOn(Vcb->Flags, VCB_DISMOUNT_PENDING)) { FreeVcb = TRUE; } FFSPrint((DBG_INFO, "FFSClose: OpenHandleCount: %u ReferenceCount: %u %s\n", Fcb->OpenHandleCount, Fcb->ReferenceCount, Fcb->AnsiFileName.Buffer)); if (Ccb) { FFSFreeCcb(Ccb); if (FileObject) { FileObject->FsContext2 = Ccb = NULL; } } if (!Fcb->ReferenceCount) { // // Remove Fcb from Vcb->FcbList ... // RemoveEntryList(&Fcb->Next); FFSFreeFcb(Fcb); FcbResourceAcquired = FALSE; } Status = STATUS_SUCCESS; } _SEH2_FINALLY { if (FcbResourceAcquired) { ExReleaseResourceForThreadLite( &Fcb->MainResource, ExGetCurrentResourceThread()); } if (VcbResourceAcquired) { ExReleaseResourceForThreadLite( &Vcb->MainResource, ExGetCurrentResourceThread()); } if (!IrpContext->ExceptionInProgress) { if (Status == STATUS_PENDING) { FFSQueueCloseRequest(IrpContext); #if 0 /* Status = STATUS_SUCCESS; if (IrpContext->Irp != NULL) { IrpContext->Irp->IoStatus.Status = Status; FFSCompleteRequest( IrpContext->Irp, (BOOLEAN)!IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_REQUEUED), (CCHAR) (NT_SUCCESS(Status) ? IO_DISK_INCREMENT : IO_NO_INCREMENT)); IrpContext->Irp = NULL; } */ #endif } else { FFSCompleteIrpContext(IrpContext, Status); if (FreeVcb) { ExAcquireResourceExclusiveLite( &FFSGlobal->Resource, TRUE); FFSClearVpbFlag(Vcb->Vpb, VPB_MOUNTED); FFSRemoveVcb(Vcb); ExReleaseResourceForThreadLite( &FFSGlobal->Resource, ExGetCurrentResourceThread()); FFSFreeVcb(Vcb); } } } } _SEH2_END; return Status; }