Author: fireball Date: Wed Feb 25 15:25:06 2009 New Revision: 39746
URL: http://svn.reactos.org/svn/reactos?rev=39746&view=rev Log: Alex Vlasov - blockdev.c: Implement misc helper functions. - direntry.c: Some changes to query dirents info for IRP_MJ_DIRECTORY_CONTROL, and the routine that locates a single dirent for IRP_MJ_CREATE. - fastfat.c: Implement queuing support (FatQueueRequest / FatDequeueRequest). - fat.c: Cleanup, use helper functions FatPin*Page. - fcb.c: Add FCB helper routines. - Header files: Change structures for future usage. - Add PSEH2 library usage.
Modified: trunk/reactos/drivers/filesystems/fastfat_new/blockdev.c trunk/reactos/drivers/filesystems/fastfat_new/direntry.c trunk/reactos/drivers/filesystems/fastfat_new/fastfat.c trunk/reactos/drivers/filesystems/fastfat_new/fastfat.h trunk/reactos/drivers/filesystems/fastfat_new/fastfat.rbuild trunk/reactos/drivers/filesystems/fastfat_new/fat.c trunk/reactos/drivers/filesystems/fastfat_new/fat.h trunk/reactos/drivers/filesystems/fastfat_new/fatstruc.h trunk/reactos/drivers/filesystems/fastfat_new/fcb.c trunk/reactos/drivers/filesystems/fastfat_new/fsctl.c
Modified: trunk/reactos/drivers/filesystems/fastfat_new/blockdev.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/filesystems/fastfat... ============================================================================== --- trunk/reactos/drivers/filesystems/fastfat_new/blockdev.c [iso-8859-1] (original) +++ trunk/reactos/drivers/filesystems/fastfat_new/blockdev.c [iso-8859-1] Wed Feb 25 15:25:06 2009 @@ -3,7 +3,7 @@ * LICENSE: GPL - See COPYING in the top level directory * FILE: drivers/filesystems/fastfat/blockdev.c * PURPOSE: Temporary sector reading support - * PROGRAMMERS: Aleksey Bragin (aleksey@reactos.org) + * PROGRAMMERS: Alexey Vlasov */
/* INCLUDES *****************************************************************/ @@ -12,5 +12,460 @@ #include "fastfat.h"
/* FUNCTIONS ***************************************************************/ +//FIXME: There is a conflicting function FatPerformDevIoCtrl doing same thing! +NTSTATUS +FatDiskIoControl_( + IN PDEVICE_OBJECT DeviceObject, + IN ULONG IoCtlCode, + IN PVOID InputBuffer, + IN ULONG InputBufferSize, + IN OUT PVOID OutputBuffer, + IN OUT PULONG OutputBufferSize OPTIONAL) +{ + PIRP Irp; + KEVENT Event; + NTSTATUS Status; + ULONG OutBufferSize; + IO_STATUS_BLOCK IoStatus; + + /* Set out buffer size if it was supplied. */ + OutBufferSize = (ARGUMENT_PRESENT(OutputBufferSize) + ? 0 : *OutputBufferSize); + + /* Initialize event if the operation will be pended. */ + KeInitializeEvent(&Event, NotificationEvent, FALSE); + + /* Build the Irp. */ + Irp = IoBuildDeviceIoControlRequest(IoCtlCode, DeviceObject, + InputBuffer, InputBufferSize, OutputBuffer, OutBufferSize, + FALSE, &Event, &IoStatus); + if (Irp == NULL) + return STATUS_INSUFFICIENT_RESOURCES; + + /* Send IRP to Disk Device */ + Status = IoCallDriver(DeviceObject, Irp); + if (Status == STATUS_PENDING) + { + KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); + Status = IoStatus.Status; + } + + /* Return output buffer length if required. */ + if (ARGUMENT_PRESENT(OutputBufferSize)) + *OutputBufferSize = IoStatus.Information; + return Status; +} + +PVOID +FatMapUserBuffer( + IN OUT PIRP Irp) +/* + * FUNCTION: + * + * + * ARGUMENTS: + * IrpContext = Pointer to FCB structure for the file. + * Irp = Pointer to the IRP structure + * RETURNS: Status Value. + * NOTES: + */ +{ + PVOID Address; + + if (Irp->MdlAddress == NULL) + return Irp->UserBuffer; + Address = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority); + if (Address == NULL) + ExRaiseStatus( STATUS_INVALID_USER_BUFFER ); + return Address; +} + +NTSTATUS +FatLockUserBuffer ( + IN PFAT_IRP_CONTEXT IrpContext, + IN LOCK_OPERATION Operation, + IN ULONG BufferLength) +/* + * FUNCTION: + * + * + * ARGUMENTS: + * IrpContext = Pointer to FCB structure for the file. + * Operation = Type of lock operation. + * BufferLength = Buffer length to be locked. + * RETURNS: Status Value. + * NOTES: + */ +{ + PMDL Mdl; + PIRP Irp; + NTSTATUS Status; + + Mdl = NULL; + Irp = IrpContext->Irp; + Status = STATUS_SUCCESS; + if (Irp->MdlAddress == NULL) + { + NTSTATUS Status; + Mdl = IoAllocateMdl(Irp->UserBuffer, + BufferLength, FALSE, FALSE, Irp); + if (Mdl == NULL) + return STATUS_INSUFFICIENT_RESOURCES; + _SEH2_TRY + { + MmProbeAndLockPages(Mdl, + Irp->RequestorMode, Operation); + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + Status = _SEH2_GetExceptionCode(); + IoFreeMdl( Mdl ); + Irp->MdlAddress = NULL; + } _SEH2_END + } + return Status; +} + +NTSTATUS +FatIoSyncCompletionRoutine( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID Context) +{ + PFAT_IO_CONTEXT IoContext; + + IoContext = (PFAT_IO_CONTEXT) Context; + + /* Check if this is an associated irp. */ + if (Irp != IoContext->Irp) + { + if (!NT_SUCCESS(Irp->IoStatus.Status)) + IoContext->Irp->IoStatus = Irp->IoStatus; + IoFreeMdl(Irp->MdlAddress); + IoFreeIrp(Irp); + if (InterlockedDecrement(&IoContext->RunCount) != 0) + return STATUS_MORE_PROCESSING_REQUIRED; + /* This was the last run, update master irp. */ + if (NT_SUCCESS(IoContext->Irp->IoStatus.Status)) + IoContext->Irp->IoStatus.Information = IoContext->Length; + } + + /* This is the last associated irp or a single irp IO. */ + if (NT_SUCCESS(IoContext->Irp->IoStatus.Status) && + !FlagOn(IoContext->Irp->Flags, IRP_PAGING_IO)) + { + /* Maintain FileObject CurrentByteOffset */ + IoContext->FileObject->CurrentByteOffset.QuadPart = + IoContext->Offset + IoContext->Irp->IoStatus.Information; + } + + /* Signal about completion. */ + KeSetEvent(&IoContext->Wait.SyncEvent, 0, FALSE); + return STATUS_MORE_PROCESSING_REQUIRED; +} + +NTSTATUS +FatIoAsyncCompletionRoutine( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID Context) +{ + PFAT_IO_CONTEXT IoContext; + + IoContext = (PFAT_IO_CONTEXT) Context; + + /* Check if this is an associated irp. */ + if (Irp != IoContext->Irp) + { + if (!NT_SUCCESS(Irp->IoStatus.Status)) + IoContext->Irp->IoStatus = Irp->IoStatus; + IoFreeMdl(Irp->MdlAddress); + IoFreeIrp(Irp); + if (InterlockedDecrement(&IoContext->RunCount) != 0) + return STATUS_MORE_PROCESSING_REQUIRED; + /* This was the last run, update master irp. */ + if (NT_SUCCESS(IoContext->Irp->IoStatus.Status)) + IoContext->Irp->IoStatus.Information = IoContext->Length; + } + + + /* This is the last associated irp or a single irp IO. */ + if (NT_SUCCESS(IoContext->Irp->IoStatus.Status) && + !FlagOn(IoContext->Irp->Flags, IRP_PAGING_IO)) + { + /* Maintain FileObject Flags */ + if (IoGetCurrentIrpStackLocation(IoContext->Irp)->MajorFunction + == IRP_MJ_READ) + { + SetFlag(IoContext->FileObject->Flags, FO_FILE_FAST_IO_READ); + } + else + { + SetFlag(IoContext->FileObject->Flags, FO_FILE_MODIFIED); + } + } + if (IoContext->Wait.Async.Resource != NULL) + ExReleaseResourceForThreadLite( + IoContext->Wait.Async.Resource, + IoContext->Wait.Async.ResourceThreadId); + + if (IoContext->Wait.Async.PagingIoResource != NULL) + ExReleaseResourceForThreadLite( + IoContext->Wait.Async.PagingIoResource, + IoContext->Wait.Async.ResourceThreadId); + + IoMarkIrpPending(Irp); + ExFreePool(Context); + return STATUS_SUCCESS; +} + +NTSTATUS +NTAPI +FatPerformLboIo( + IN PFAT_IRP_CONTEXT IrpContext, + IN PLARGE_INTEGER Offset, + IN SIZE_T Length) +{ + BOOLEAN CanWait, ReadOperation; + PIO_STACK_LOCATION IoStack; + + CanWait = BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT); + ReadOperation = (IrpContext->Stack->MajorFunction == IRP_MJ_READ); + + /* Allocate completion context */ + IrpContext->FatIoContext = FsRtlAllocatePoolWithTag( + NonPagedPool, sizeof(FAT_IO_CONTEXT), (ULONG) 'xCoI'); + + if (IrpContext->FatIoContext == NULL) + return STATUS_INSUFFICIENT_RESOURCES; + + RtlZeroMemory(IrpContext->FatIoContext, + sizeof(FAT_IO_CONTEXT)); + + /* Initialize event if we are supposed to wait. */ + if (CanWait) + { + KeInitializeEvent( + &IrpContext->FatIoContext->Wait.SyncEvent, + NotificationEvent, FALSE); + } + + /* Set the completion routine depending on wait semantics. */ + IoSetCompletionRoutine(IrpContext->Irp, + (CanWait + ? FatIoSyncCompletionRoutine + : FatIoAsyncCompletionRoutine), + IrpContext->FatIoContext, TRUE, TRUE, TRUE); + + /* Setup stack location. */ + IoStack = IoGetNextIrpStackLocation(IrpContext->Irp); + IoStack->MajorFunction = IrpContext->MajorFunction; + IoStack->Parameters.Read.Length = (ULONG) Length; + IoStack->Parameters.Read.ByteOffset = *Offset; + if (FlagOn(IrpContext->Flags, IRPCONTEXT_WRITETHROUGH)) + SetFlag(IoStack->Flags, SL_WRITE_THROUGH); + + IoCallDriver( + IrpContext->Vcb->TargetDeviceObject, + IrpContext->Irp); + if (CanWait) + { + KeWaitForSingleObject( + &IrpContext->FatIoContext->Wait.SyncEvent, + Executive, KernelMode, FALSE, NULL); + return IrpContext->Irp->IoStatus.Status; + } + SetFlag(IrpContext->Flags, IRPCONTEXT_STACK_IO_CONTEXT); + return STATUS_PENDING; +} + + + +NTSTATUS +FatPerformVirtualNonCachedIo( + IN PFAT_IRP_CONTEXT IrpContext, + IN PFCB Fcb, + IN PLARGE_INTEGER Offset, + IN SIZE_T Length) +{ + NTSTATUS Status; + PIO_STACK_LOCATION IoStack; + LONGLONG Vbo, Lbo, RunLength; + ULONG RunCount, CleanupIndex, FirstIndex, BeyoundLastIndex; + BOOLEAN CanWait, ReadOperation; + PIRP* RunIrp; + PMDL Mdl; + + ASSERT(IrpContext->FatIoContext == NULL); + + + FirstIndex = CleanupIndex = 0; + CanWait = BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT); + ReadOperation = (IrpContext->Stack->MajorFunction == IRP_MJ_READ); + Status = FatLockUserBuffer(IrpContext, + (ReadOperation ? IoWriteAccess : IoReadAccess), + Length); + if (!NT_SUCCESS(Status)) + goto FatIoPerformNonCachedCleanup; + Vbo = Offset->QuadPart; + RunLength = Length; + _SEH2_TRY + { + BeyoundLastIndex = FatScanFat(Fcb, Vbo, + &Lbo, &RunLength, &FirstIndex, CanWait); + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + Status = _SEH2_GetExceptionCode(); + _SEH2_YIELD(goto FatIoPerformNonCachedCleanup;) + }_SEH2_END + RunCount = BeyoundLastIndex - FirstIndex; + if (RunCount == 0) + { + Status = STATUS_END_OF_FILE; + goto FatIoPerformNonCachedCleanup; + } + Length = sizeof(FAT_IO_CONTEXT); + if (RunCount > 0x1) + Length += RunCount * sizeof(PIRP); + IrpContext->FatIoContext = FsRtlAllocatePoolWithTag( + NonPagedPool, Length, (ULONG) 'xCoI'); + if (IrpContext->FatIoContext == NULL) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + goto FatIoPerformNonCachedCleanup; + } + RtlZeroMemory(IrpContext->FatIoContext, Length); + if (CanWait) + { + KeInitializeEvent( + &IrpContext->FatIoContext->Wait.SyncEvent, + NotificationEvent, FALSE); + } + if (RunCount == 0x1) + { + IoSetCompletionRoutine(IrpContext->Irp, + (CanWait ? FatIoSyncCompletionRoutine + : FatIoAsyncCompletionRoutine), + IrpContext->FatIoContext, TRUE, TRUE, TRUE); + IoStack = IoGetNextIrpStackLocation(IrpContext->Irp); + IoStack->MajorFunction = IrpContext->Stack->MajorFunction; + IoStack->Parameters.Read.Length = (ULONG) RunLength; + IoStack->Parameters.Read.ByteOffset.QuadPart = Lbo; + IoStack->Flags = FlagOn( + IrpContext->Stack->Flags, + SL_WRITE_THROUGH); + Status = IoCallDriver( + IrpContext->Vcb->TargetDeviceObject, + IrpContext->Irp); + goto FatIoPerformNonCachedComplete; + } + /* + * We already have the first run retrieved by FatiScanFat. + */ + for (RunIrp = &IrpContext->FatIoContext->Irp, + CleanupIndex = FirstIndex; + CleanupIndex < BeyoundLastIndex; + CleanupIndex ++, RunIrp ++) + { +#if DBG + LONGLONG NextVbo = Vbo + RunLength; + BOOLEAN RunExists; +#endif + /* + * Allocate Irp for the run. + */ + *RunIrp = IoMakeAssociatedIrp(IrpContext->Irp, + (CCHAR)(IrpContext->Vcb->TargetDeviceObject->StackSize + 1)); + if (*RunIrp == NULL) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + goto FatIoPerformNonCachedCleanup; + } + CleanupIndex ++; + /* + * Build Mdl for the run range. + */ + Mdl = IoAllocateMdl( + Add2Ptr(IrpContext->Irp->UserBuffer, Vbo, PVOID), + (ULONG) RunLength, FALSE, FALSE, *RunIrp); + if (Mdl == NULL) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + goto FatIoPerformNonCachedCleanup; + } + IoBuildPartialMdl(IrpContext->Irp->MdlAddress, Mdl, + Add2Ptr(IrpContext->Irp->UserBuffer, Vbo, PVOID), + (ULONG) RunLength); + /* + * Setup IRP for each run. + */ + IoSetCompletionRoutine(IrpContext->Irp, + (CanWait ? FatIoSyncCompletionRoutine + : FatIoAsyncCompletionRoutine), + IrpContext->FatIoContext, TRUE, TRUE, TRUE); + IoStack = IoGetNextIrpStackLocation(*RunIrp); + IoStack->MajorFunction = IrpContext->Stack->MajorFunction; + IoStack->Parameters.Read.Length = (ULONG) RunLength; + IoStack->Parameters.Read.ByteOffset.QuadPart = Lbo; + + /* + * Propagate write-through to the associated IRPs + */ + if (FlagOn(IrpContext->Flags, IRPCONTEXT_WRITETHROUGH)) + SetFlag(IoStack->Flags, SL_WRITE_THROUGH); + /* + * Prepare for next iteration: + */ + #if DBG + RunExists = + #endif + FsRtlGetNextLargeMcbEntry(&Fcb->Mcb, CleanupIndex, &Vbo, &Lbo, &RunLength); + ASSERT(RunExists); + ASSERT(NextVbo == Vbo); + } + /* + * Send all IRPs to the volume device, we don't need to check + * status code because cleanup will be done + * by the completion routine in any case. + */ + for (RunIrp = &IrpContext->FatIoContext->Irp, + CleanupIndex = FirstIndex; + CleanupIndex < BeyoundLastIndex; + CleanupIndex ++, RunIrp ++) + { + IoCallDriver(IrpContext->Vcb->TargetDeviceObject, *RunIrp); + } + +FatIoPerformNonCachedComplete: + if (CanWait) + { + KeWaitForSingleObject( + &IrpContext->FatIoContext->Wait.SyncEvent, + Executive, KernelMode, FALSE, NULL); + return IrpContext->Irp->IoStatus.Status; + } + SetFlag(IrpContext->Flags, IRPCONTEXT_STACK_IO_CONTEXT); + return STATUS_PENDING; + /* + * The following block of code implements unwind logic + */ +FatIoPerformNonCachedCleanup: + if (IrpContext->FatIoContext != NULL) + { + RunIrp = &IrpContext->FatIoContext->Irp; + while (FirstIndex < CleanupIndex) + { + if ((*RunIrp)->MdlAddress != NULL) + IoFreeMdl((*RunIrp)->MdlAddress); + IoFreeIrp(*RunIrp); + FirstIndex ++; + RunIrp ++; + } + ExFreePool(IrpContext->FatIoContext); + IrpContext->FatIoContext = NULL; + } + return Status; +}
/* EOF */
Modified: trunk/reactos/drivers/filesystems/fastfat_new/direntry.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/filesystems/fastfat... ============================================================================== --- trunk/reactos/drivers/filesystems/fastfat_new/direntry.c [iso-8859-1] (original) +++ trunk/reactos/drivers/filesystems/fastfat_new/direntry.c [iso-8859-1] Wed Feb 25 15:25:06 2009 @@ -12,37 +12,6 @@ #include "fastfat.h"
/* PROTOTYPES ***************************************************************/ -#define BYTES_PER_DIRENT_LOG 0x05 - -typedef struct _FAT_ENUM_DIR_CONTEXT *PFAT_ENUM_DIR_CONTEXT; - -typedef ULONG (*PFAT_COPY_DIRENT_ROUTINE) (struct _FAT_ENUM_DIR_CONTEXT *, PDIR_ENTRY, PVOID); - -typedef struct _FAT_ENUM_DIR_CONTEXT -{ - PFILE_OBJECT FileObject; - LARGE_INTEGER PageOffset; - LONGLONG BeyondLastEntryOffset; - PVOID PageBuffer; - PBCB PageBcb; - - /* - * We should always cache short file name - * because we never know if there is a long - * name for the dirent and when we find out - * that our base dirent might become unpinned. - */ - UCHAR DirentFileName[RTL_FIELD_SIZE(DIR_ENTRY, FileName) + 1]; - PFAT_COPY_DIRENT_ROUTINE CopyDirent; - LONGLONG BytesPerClusterMask; - /* - * The following fields are - * set by the copy routine - */ - PULONG NextEntryOffset; - PULONG FileNameLength; - PWCHAR FileName; -} FAT_ENUM_DIR_CONTEXT;
typedef enum _FILE_TIME_INDEX { @@ -51,10 +20,7 @@ FileLastWriteTime, FileChangeTime } FILE_TIME_INDEX; - -VOID -FatQueryFileTimes(OUT PLARGE_INTEGER FileTimes, - IN PDIR_ENTRY Dirent); +
VOID Fat8dot3ToUnicodeString(OUT PUNICODE_STRING FileName, @@ -62,41 +28,426 @@ IN UCHAR Flags);
ULONG -FatDirentToDirInfo(IN OUT PFAT_ENUM_DIR_CONTEXT Context, +FatDirentToDirInfo(IN OUT PFAT_ENUM_DIRENT_CONTEXT Context, IN PDIR_ENTRY Dirent, IN PVOID Buffer);
ULONG -FatDirentToFullDirInfo(IN OUT PFAT_ENUM_DIR_CONTEXT Context, +FatDirentToFullDirInfo(IN OUT PFAT_ENUM_DIRENT_CONTEXT Context, IN PDIR_ENTRY Dirent, IN PVOID Buffer);
ULONG -FatDirentToIdFullDirInfo(IN OUT PFAT_ENUM_DIR_CONTEXT Context, +FatDirentToIdFullDirInfo(IN OUT PFAT_ENUM_DIRENT_CONTEXT Context, IN PDIR_ENTRY Dirent, IN PVOID Buffer);
ULONG -FatDirentToBothDirInfo(IN OUT PFAT_ENUM_DIR_CONTEXT Context, +FatDirentToBothDirInfo(IN OUT PFAT_ENUM_DIRENT_CONTEXT Context, IN PDIR_ENTRY Dirent, IN PVOID Buffer);
ULONG -FatDirentToIdBothDirInfo(IN OUT PFAT_ENUM_DIR_CONTEXT Context, +FatDirentToIdBothDirInfo(IN OUT PFAT_ENUM_DIRENT_CONTEXT Context, IN PDIR_ENTRY Dirent, IN PVOID Buffer);
ULONG -FatDirentToNamesInfo(IN OUT PFAT_ENUM_DIR_CONTEXT Context, +FatDirentToNamesInfo(IN OUT PFAT_ENUM_DIRENT_CONTEXT Context, IN PDIR_ENTRY Dirent, IN PVOID Buffer);
ULONG -FatDirentToObjectIdInfo(IN OUT PFAT_ENUM_DIR_CONTEXT Context, +FatDirentToObjectIdInfo(IN OUT PFAT_ENUM_DIRENT_CONTEXT Context, IN PDIR_ENTRY Dirent, IN PVOID Buffer);
/* FUNCTIONS *****************************************************************/ + +#define FatQueryFileName(xInfo, xDirent) \ +{ \ + UNICODE_STRING FileName; \ + if (Info->FileNameLength == 0) \ + { \ + FileName.Buffer = Info->FileName; \ + FileName.MaximumLength = 0x18; \ + Fat8dot3ToUnicodeString(&FileName, \ + (xDirent)->FileName, (xDirent)->Case); \ + Info->FileNameLength = FileName.Length; \ + } \ +} + +#define FatQueryBothFileName(xInfo, xDirent) \ +{ \ + UNICODE_STRING FileName; \ + FileName.MaximumLength = 0x18; \ + if (Info->FileNameLength == 0) \ + { \ + FileName.Buffer = Info->FileName; \ + Fat8dot3ToUnicodeString(&FileName, \ + (xDirent)->FileName, (xDirent)->Case); \ + Info->FileNameLength = FileName.Length; \ + Info->ShortNameLength = 0; \ + } \ + else \ + { \ + FileName.Buffer = Info->ShortName; \ + Fat8dot3ToUnicodeString(&FileName, \ + (xDirent)->FileName, (xDirent)->Case); \ + Info->ShortNameLength = (CCHAR) FileName.Length; \ + } \ +} + +FORCEINLINE +UCHAR +FatLfnChecksum( + PUCHAR Buffer +) +{ + UCHAR Index, Chksum; + + for (Index = 0x1, Chksum = *Buffer; + Index < RTL_FIELD_SIZE(DIR_ENTRY, FileName); + Index ++) + { + Chksum = (((Chksum & 0x1) << 0x7) | (Chksum >> 0x1)) + + Buffer[Index]; + } + return Chksum; +} + +VOID +FatFindDirent(IN OUT PFAT_FIND_DIRENT_CONTEXT Context, + OUT PDIR_ENTRY* Dirent, + OUT PUNICODE_STRING LongFileName OPTIONAL) +{ + PDIR_ENTRY Entry, EndOfPage; + UCHAR SeqNum = 0, Checksum = 0; + PUNICODE_STRING FileName; + + /* Pin first page. */ + Entry = (PDIR_ENTRY) FatPinPage(&Context->Page, 0); + EndOfPage = FatPinEndOfPage(&Context->Page, PDIR_ENTRY); + + /* Run dirents. */ + FileName = NULL; + while (TRUE) + { + /* Check if we have entered the area of never used dirents */ + if (Entry->FileName[0] == FAT_DIRENT_NEVER_USED) + ExRaiseStatus(STATUS_OBJECT_NAME_NOT_FOUND); + + /* Just ignore entries marked as deleted */ + if (Entry->FileName[0] == FAT_DIRENT_DELETED) + goto FatFindDirentNext; + + /* Check if it's an lfn */ + if (Entry->Attributes == FAT_DIRENT_ATTR_LFN) + { + PLONG_FILE_NAME_ENTRY LfnEntry; + + FileName = LongFileName; + LfnEntry = (PLONG_FILE_NAME_ENTRY) Entry; + + /* Run lfns and collect file name if required */ + do { + PWSTR Lfn; + + /* Check if we just running lfn */ + if (FileName == NULL) + goto FatFindDirentRunLfn; + + /* Check for cluster index to be zero. */ + if (LfnEntry->Reserved != 0) + { + FileName = NULL; + goto FatFindDirentRunLfn; + } + + /* Check if this is the last lfn entry. */ + if (FlagOn(LfnEntry->SeqNum, FAT_FN_DIR_ENTRY_LAST)) + { + SeqNum = (LfnEntry->SeqNum & ~FAT_FN_DIR_ENTRY_LAST); + Checksum = LfnEntry->Checksum; + + /* Check if we exceed max number of lfns */ + if (SeqNum > (FAT_FN_MAX_DIR_ENTIES + 1)) + { + FileName = NULL; + goto FatFindDirentRunLfn; + } + + /* Setup maximal expected lfn length */ + FileName->Length = (SeqNum * FAT_LFN_NAME_LENGTH); + + /* Extend lfn buffer if needed */ + if (FileName->Length > FileName->MaximumLength) + { + Lfn = ExAllocatePoolWithTag(PagedPool, + LongFileName->Length, TAG_VFAT); + if (Lfn == NULL) + ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES); + if (FileName->Buffer != NULL) + ExFreePool(FileName->Buffer); + FileName->Buffer = Lfn; + FileName->MaximumLength = FileName->Length; + } + } + else if (!(LfnEntry->SeqNum == SeqNum + && LfnEntry->Checksum == Checksum)) + { + /* Wrong SeqNum or CheckSum. */ + FileName = NULL; + goto FatFindDirentRunLfn; + } + /* Gather file name */ + Lfn = Add2Ptr(FileName->Buffer, (SeqNum * FAT_LFN_NAME_LENGTH) + - sizeof(LfnEntry->NameC), PWSTR); + RtlCopyMemory(Lfn, LfnEntry->NameC, sizeof(LfnEntry->NameC)); + Lfn -= (sizeof(LfnEntry->NameB) / sizeof(WCHAR)); + RtlCopyMemory(Lfn, LfnEntry->NameB, sizeof(LfnEntry->NameB)); + Lfn -= (sizeof(LfnEntry->NameA) / sizeof(WCHAR)); + RtlCopyMemory(Lfn, LfnEntry->NameA, sizeof(LfnEntry->NameA)); + + /* If last lfn determine exact lfn length. */ + if (FlagOn(LfnEntry->SeqNum, FAT_FN_DIR_ENTRY_LAST)) + { + PWSTR LfnEnd = Add2Ptr(FileName->Buffer, + (FileName->Length - sizeof(WCHAR)), PWSTR); + + /* Trim trailing 0xffff's */ + while (LfnEnd > Lfn && *LfnEnd == 0xffff) --LfnEnd; + + /* Trim 0 terminator is the one is there. */ + if (*LfnEnd == 0x0) --LfnEnd; + + /* Set correct lfn size */ + FileName->Length = (USHORT)PtrOffset(FileName->Buffer, LfnEnd); + } + /* Setup validation for the next iteration */ + SeqNum = LfnEntry->SeqNum - 0x1; + Checksum = LfnEntry->Checksum; + +FatFindDirentRunLfn: + /* Get next dirent */ + LfnEntry ++; + if (LfnEntry > (PLONG_FILE_NAME_ENTRY) EndOfPage) + { + if (FatPinIsLastPage(&Context->Page)) + ExRaiseStatus(STATUS_OBJECT_NAME_NOT_FOUND); + LfnEntry = (PLONG_FILE_NAME_ENTRY) FatPinNextPage(&Context->Page); + EndOfPage = FatPinEndOfPage(&Context->Page, PDIR_ENTRY); + } + } + while (LfnEntry->Attributes == FAT_DIRENT_ATTR_LFN); + Entry = (PDIR_ENTRY) LfnEntry; + continue; + } + + /* If we've got here then this is a normal dirent */ + if (FileName != NULL && FileName->Length > 0) + { + /* Check if we have a correct lfn collected. */ + if (FatLfnChecksum(Entry->FileName) != Checksum) + { + FileName = NULL; + } + else + { + /* See if we were looking for this dirent. */ + if (!Context->Valid8dot3Name && + FsRtlAreNamesEqual(FileName, Context->FileName, TRUE, NULL)) + { + Fat8dot3ToUnicodeString(&Context->ShortName, Entry->FileName, Entry->Case); + *Dirent = Entry; + return; + } + } + } + + /* We surely have a short name, check if we were looking for that. */ + if (Context->Valid8dot3Name) + { + Fat8dot3ToUnicodeString(&Context->ShortName, + Entry->FileName, Entry->Case); + if (FsRtlAreNamesEqual(&Context->ShortName, Context->FileName, TRUE, NULL)) + { + if (ARGUMENT_PRESENT(LongFileName) && FileName == NULL) + LongFileName->Length = 0; + *Dirent = Entry; + return; + } + } + FileName = NULL; + +FatFindDirentNext: + Entry ++; + if (Entry > EndOfPage) + { + if (FatPinIsLastPage(&Context->Page)) + ExRaiseStatus(STATUS_OBJECT_NAME_NOT_FOUND); + Entry = (PDIR_ENTRY) FatPinNextPage(&Context->Page); + EndOfPage = FatPinEndOfPage(&Context->Page, PDIR_ENTRY); + } + } + /* Should never get here! */ + ASSERT(TRUE); +} + +VOID +FatEnumerateDirents(IN OUT PFAT_ENUM_DIRENT_CONTEXT Context, + IN SIZE_T Offset) +{ + PUCHAR Entry, EndOfPage; + PWSTR FileName; + USHORT FileNameLength; + USHORT FileNameMaximumLength; + PVOID InfoEntry; + UCHAR SeqNum = 0; + UCHAR Checksum = 0; + + /* Pin first page. */ + Entry = (PUCHAR)FatPinPage(&Context->Page, Offset); + EndOfPage = FatPinEndOfPage(&Context->Page, PUCHAR); + + /* Iterate dirents. */ + while (TRUE) + { + /* Check if we have entered the area of never used dirents */ + if (*Entry == FAT_DIRENT_NEVER_USED) + ExRaiseStatus(STATUS_NO_MORE_FILES); + + /* Just ignore entries marked as deleted */ + if (*Entry == FAT_DIRENT_DELETED) + goto FatEnumerateDirentsNext; + + /* Get info pointer. */ + InfoEntry = Add2Ptr(Context->Buffer, Context->Offset, PVOID); + + /* Check if info class has file name */ + if (Context->NameOffset == Context->LengthOffset) + { + FileName = NULL; + FileNameMaximumLength = 0; + } + else + { + FileName = Add2Ptr(InfoEntry, Context->NameOffset, PWSTR); + FileNameMaximumLength = (USHORT) (Context->Length + - Context->Offset + Context->NameOffset); + } + FileNameLength = 0; + + /* Check if it's an lfn */ + while (Entry[0xb] == FAT_DIRENT_ATTR_LFN) + { + PWSTR Lfn; + PLONG_FILE_NAME_ENTRY LfnEntry; + + /* Check if we just running lfn */ + if (FileNameMaximumLength == 0) + goto FatEnumerateDirentsRunLfn; + + LfnEntry = (PLONG_FILE_NAME_ENTRY) Entry; + + /* Check for cluster index to be zero. */ + if (LfnEntry->Reserved != 0) + { + FileNameMaximumLength = 0; + goto FatEnumerateDirentsRunLfn; + } + + /* Check if this is the last lfn entry. */ + if (FlagOn(LfnEntry->SeqNum, FAT_FN_DIR_ENTRY_LAST)) + { + SeqNum = (LfnEntry->SeqNum & ~FAT_FN_DIR_ENTRY_LAST); + Checksum = LfnEntry->Checksum; + + /* Check if we exceed max number of lfns */ + if (SeqNum > (FAT_FN_MAX_DIR_ENTIES + 1)) + { + FileNameMaximumLength = 0; + goto FatEnumerateDirentsRunLfn; + } + + /* Setup maximal expected lfn length */ + FileNameLength = SeqNum * FAT_LFN_NAME_LENGTH; + + /* Validate the maximal expected lfn length */ + if (FileNameLength > FileNameMaximumLength) + goto FatEnumerateDirentsRunLfn; + } + else if (!(LfnEntry->SeqNum == SeqNum + && LfnEntry->Checksum == Checksum)) + { + /* Wrong SeqNum or CheckSum. */ + FileNameMaximumLength = 0; + goto FatEnumerateDirentsRunLfn; + } + /* Gather file name */ + Lfn = Add2Ptr(FileName, (SeqNum * FAT_LFN_NAME_LENGTH) + - sizeof(LfnEntry->NameC), PWSTR); + RtlCopyMemory(Lfn, LfnEntry->NameC, sizeof(LfnEntry->NameC)); + Lfn -= (sizeof(LfnEntry->NameB) / sizeof(WCHAR)); + RtlCopyMemory(Lfn, LfnEntry->NameB, sizeof(LfnEntry->NameB)); + Lfn -= (sizeof(LfnEntry->NameA) / sizeof(WCHAR)); + RtlCopyMemory(Lfn, LfnEntry->NameA, sizeof(LfnEntry->NameA)); + + /* If last lfn determine exact lfn length. */ + if (FlagOn(LfnEntry->SeqNum, FAT_FN_DIR_ENTRY_LAST)) + { + PWSTR LfnEnd = Add2Ptr(FileName, FileNameLength + - sizeof(WCHAR), PWSTR); + + /* Trim trailing 0xffff's */ + while (LfnEnd > Lfn && *LfnEnd == 0xffff) --LfnEnd; + + /* Trim 0 terminator is the one is there. */ + if (*LfnEnd == 0x0) --LfnEnd; + + /* Set correct lfn size */ + FileNameLength = (USHORT)PtrOffset(FileName, LfnEnd); + } + /* Setup vaidation for the next iteration */ + SeqNum = LfnEntry->SeqNum - 0x1; + Checksum = LfnEntry->Checksum; +FatEnumerateDirentsRunLfn: + Entry = Add2Ptr(Entry, sizeof(DIR_ENTRY), PUCHAR); + if (Entry > EndOfPage) + { + if (FatPinIsLastPage(&Context->Page)) + ExRaiseStatus(STATUS_NO_MORE_FILES); + Entry = (PUCHAR) FatPinNextPage(&Context->Page); + EndOfPage = FatPinEndOfPage(&Context->Page, PUCHAR); + } + } + + /* if lfn was found, validate and commit. */ + if (FileNameLength > 0 && FatLfnChecksum(Entry) == Checksum) + { + *Add2Ptr(InfoEntry, Context->LengthOffset, PULONG) = FileNameLength; + } + else + { + *Add2Ptr(InfoEntry, Context->LengthOffset, PULONG) = 0; + } + /* TODO: Implement Filtering using Context->FileName & Context->CcbFlags. */ + + /* Copy the entry values. */ + Context->Offset += Context->CopyDirent((PFAT_ENUM_DIR_CONTEXT)Context, (PDIR_ENTRY) Entry, InfoEntry); + +FatEnumerateDirentsNext: + /* Get next entry */ + Entry = Add2Ptr(Entry, sizeof(DIR_ENTRY), PUCHAR); + if (Entry > EndOfPage) + { + if (FatPinIsLastPage(&Context->Page)) + ExRaiseStatus(STATUS_NO_MORE_FILES); + Entry = (PUCHAR) FatPinNextPage(&Context->Page); + EndOfPage = FatPinEndOfPage(&Context->Page, PUCHAR); + } + } +}
FORCEINLINE VOID @@ -280,14 +631,13 @@ }
ULONG -FatDirentToDirInfo(IN OUT PFAT_ENUM_DIR_CONTEXT Context, +FatDirentToDirInfo(IN OUT PFAT_ENUM_DIRENT_CONTEXT Context, IN PDIR_ENTRY Dirent, IN PVOID Buffer) { PFILE_DIRECTORY_INFORMATION Info; - //UNICODE_STRING FileName; - Info = (PFILE_DIRECTORY_INFORMATION) Buffer; + Info->FileIndex = 0; /* Setup Attributes */ Info->FileAttributes = Dirent->Attributes; /* Setup times */ @@ -297,29 +647,20 @@ Info->AllocationSize.QuadPart = (Context->BytesPerClusterMask + Dirent->FileSize) & ~(Context->BytesPerClusterMask); - //FileName.Buffer = Info->ShortName; - //FileName.MaximumLength = sizeof(Info->ShortName); - // FatQueryShortName(&FileName, Dirent); - // Info->ShortNameLength = (CCHAR) FileName.Length; + FatQueryFileName(Info, Dirent); Info->NextEntryOffset = sizeof(*Info); - /* Associate LFN buffer and length pointers - * of this entry with the context. - */ - Context->NextEntryOffset = &Info->NextEntryOffset; - Context->FileName = Info->FileName; - Context->FileNameLength = &Info->FileNameLength; - return Info->NextEntryOffset; -} - -ULONG -FatDirentToFullDirInfo(IN OUT PFAT_ENUM_DIR_CONTEXT Context, + return Info->NextEntryOffset + Info->FileNameLength; +} + +ULONG +FatDirentToFullDirInfo(IN OUT PFAT_ENUM_DIRENT_CONTEXT Context, IN PDIR_ENTRY Dirent, IN PVOID Buffer) { PFILE_FULL_DIR_INFORMATION Info; - //UNICODE_STRING FileName; - Info = (PFILE_FULL_DIR_INFORMATION) Buffer; + Info->FileIndex = 0; + Info->EaSize = 0; /* Setup Attributes */ Info->FileAttributes = Dirent->Attributes; /* Setup times */ @@ -329,30 +670,21 @@ Info->AllocationSize.QuadPart = (Context->BytesPerClusterMask + Dirent->FileSize) & ~(Context->BytesPerClusterMask); - //FileName.Buffer = Info->ShortName; - //FileName.MaximumLength = sizeof(Info->ShortName); - // FatQueryShortName(&FileName, Dirent); - // Info->ShortNameLength = (CCHAR) FileName.Length; + FatQueryFileName(Info, Dirent); Info->NextEntryOffset = sizeof(*Info); - /* - * Associate LFN buffer and length pointers - * of this entry with the context. - */ - Context->NextEntryOffset = &Info->NextEntryOffset; - Context->FileName = Info->FileName; - Context->FileNameLength = &Info->FileNameLength; - return Info->NextEntryOffset; -} - -ULONG -FatDirentToIdFullDirInfo(IN OUT PFAT_ENUM_DIR_CONTEXT Context, + return Info->NextEntryOffset + Info->FileNameLength; +} + +ULONG +FatDirentToIdFullDirInfo(IN OUT PFAT_ENUM_DIRENT_CONTEXT Context, IN PDIR_ENTRY Dirent, IN PVOID Buffer) { PFILE_ID_FULL_DIR_INFORMATION Info; - //UNICODE_STRING FileName; - Info = (PFILE_ID_FULL_DIR_INFORMATION) Buffer; + Info->FileId.QuadPart = 0; + Info->FileIndex = 0; + Info->EaSize = 0; /* Setup Attributes */ Info->FileAttributes = Dirent->Attributes; /* Setup times */ @@ -362,30 +694,20 @@ Info->AllocationSize.QuadPart = (Context->BytesPerClusterMask + Dirent->FileSize) & ~(Context->BytesPerClusterMask); - //FileName.Buffer = Info->ShortName; - //FileName.MaximumLength = sizeof(Info->ShortName); - // FatQueryShortName(&FileName, Dirent); - // Info->ShortNameLength = (CCHAR) FileName.Length; + FatQueryFileName(Info, Dirent); Info->NextEntryOffset = sizeof(*Info); - /* - * Associate LFN buffer and length pointers - * of this entry with the context. - */ - Context->NextEntryOffset = &Info->NextEntryOffset; - Context->FileName = Info->FileName; - Context->FileNameLength = &Info->FileNameLength; - return Info->NextEntryOffset; -} - -ULONG -FatDirentToBothDirInfo(IN OUT PFAT_ENUM_DIR_CONTEXT Context, + return Info->NextEntryOffset + Info->FileNameLength; +} + +ULONG +FatDirentToBothDirInfo(IN OUT PFAT_ENUM_DIRENT_CONTEXT Context, IN PDIR_ENTRY Dirent, IN PVOID Buffer) { PFILE_BOTH_DIR_INFORMATION Info; - UNICODE_STRING FileName; - Info = (PFILE_BOTH_DIR_INFORMATION) Buffer; + Info->FileIndex = 0; + Info->EaSize = 0; /* Setup Attributes */ Info->FileAttributes = Dirent->Attributes; /* Setup times */ @@ -395,29 +717,21 @@ Info->AllocationSize.QuadPart = (Context->BytesPerClusterMask + Dirent->FileSize) & ~(Context->BytesPerClusterMask); - FileName.Buffer = Info->ShortName; - FileName.MaximumLength = sizeof(Info->ShortName); - Fat8dot3ToUnicodeString(&FileName, Dirent->FileName, Dirent->Case); - Info->ShortNameLength = (CCHAR) FileName.Length; + FatQueryBothFileName(Info, Dirent); Info->NextEntryOffset = sizeof(*Info); - /* Associate LFN buffer and length pointers - * of this entry with the context. - */ - Context->NextEntryOffset = &Info->NextEntryOffset; - Context->FileName = Info->FileName; - Context->FileNameLength = &Info->FileNameLength; - return Info->NextEntryOffset; -} - -ULONG -FatDirentToIdBothDirInfo(IN OUT PFAT_ENUM_DIR_CONTEXT Context, + return Info->NextEntryOffset + Info->FileNameLength; +} + +ULONG +FatDirentToIdBothDirInfo(IN OUT PFAT_ENUM_DIRENT_CONTEXT Context, IN PDIR_ENTRY Dirent, IN PVOID Buffer) { PFILE_ID_BOTH_DIR_INFORMATION Info; - UNICODE_STRING FileName; - Info = (PFILE_ID_BOTH_DIR_INFORMATION) Buffer; + Info->FileId.QuadPart = 0; + Info->FileIndex = 0; + Info->EaSize = 0; /* Setup Attributes */ Info->FileAttributes = Dirent->Attributes; /* Setup times */ @@ -427,151 +741,35 @@ Info->AllocationSize.QuadPart = (Context->BytesPerClusterMask + Dirent->FileSize) & ~(Context->BytesPerClusterMask); - FileName.Buffer = Info->ShortName; - FileName.MaximumLength = sizeof(Info->ShortName); - Fat8dot3ToUnicodeString(&FileName, Dirent->FileName, Dirent->Case); - Info->ShortNameLength = (CCHAR) FileName.Length; + FatQueryBothFileName(Info, Dirent); Info->NextEntryOffset = sizeof(*Info); - /* - * Associate LFN buffer and length pointers - * of this entry with the context. - */ - Context->NextEntryOffset = &Info->NextEntryOffset; - Context->FileName = Info->FileName; - Context->FileNameLength = &Info->FileNameLength; - return Info->NextEntryOffset; -} - -ULONG -FatDirentToNamesInfo(IN OUT PFAT_ENUM_DIR_CONTEXT Context, + return Info->NextEntryOffset + Info->FileNameLength; +} + +ULONG +FatDirentToNamesInfo(IN OUT PFAT_ENUM_DIRENT_CONTEXT Context, IN PDIR_ENTRY Dirent, IN PVOID Buffer) { PFILE_NAMES_INFORMATION Info; - Info = (PFILE_NAMES_INFORMATION) Buffer; -// FatQueryShortName(&FileName, Dirent); + Info->FileIndex = 0; + FatQueryFileName(Info, Dirent); Info->NextEntryOffset = sizeof(*Info); - /* Associate LFN buffer and length pointers - * of this entry with the context. - */ - Context->NextEntryOffset = &Info->NextEntryOffset; - Context->FileName = Info->FileName; - Context->FileNameLength = &Info->FileNameLength; - return Info->NextEntryOffset; -} - -ULONG -FatDirentToObjectIdInfo(IN OUT PFAT_ENUM_DIR_CONTEXT Context, + return Info->NextEntryOffset + Info->FileNameLength; +} + +ULONG +FatDirentToObjectIdInfo(IN OUT PFAT_ENUM_DIRENT_CONTEXT Context, IN PDIR_ENTRY Dirent, IN PVOID Buffer) { PFILE_OBJECTID_INFORMATION Info; - Info = (PFILE_OBJECTID_INFORMATION) Buffer; + Info->FileReference = 0; + ((PLONGLONG)Info->ObjectId)[0] = 0LL; + ((PLONGLONG)Info->ObjectId)[1] = 0LL; return sizeof(*Info); }
-ULONG -FatEnumerateDirents(IN OUT PFAT_ENUM_DIR_CONTEXT Context, - IN ULONG Index, - IN BOOLEAN CanWait) -{ - LONGLONG PageOffset; - SIZE_T OffsetWithinPage, PageValidLength; - PUCHAR Entry, BeyondLastEntry; - /* Determine page offset and the offset within page - * for the first cluster. - */ - PageValidLength = PAGE_SIZE; - PageOffset = ((LONGLONG) Index) << BYTES_PER_DIRENT_LOG; - OffsetWithinPage = (SIZE_T) (PageOffset & (PAGE_SIZE - 1)); - PageOffset -= OffsetWithinPage; - /* Check if the context already has the required page mapped. - * Map the first page is necessary. - */ - if (PageOffset != Context->PageOffset.QuadPart) - { - Context->PageOffset.QuadPart = PageOffset; - if (Context->PageBcb != NULL) - { - CcUnpinData(Context->PageBcb); - Context->PageBcb = NULL; - } - if (!CcMapData(Context->FileObject, - &Context->PageOffset, - PAGE_SIZE, - CanWait, - &Context->PageBcb, - &Context->PageBuffer)) - { - Context->PageOffset.QuadPart = 0LL; - ExRaiseStatus(STATUS_CANT_WAIT); - } - } - Entry = Add2Ptr(Context->PageBuffer, OffsetWithinPage, PUCHAR); - /* Next Page Offset */ - PageOffset = Context->PageOffset.QuadPart + PAGE_SIZE; - if (PageOffset > Context->BeyondLastEntryOffset) - { - PageValidLength = (SIZE_T) (Context->BeyondLastEntryOffset - - Context->PageOffset.QuadPart); - } - BeyondLastEntry = Add2Ptr(Context->PageBuffer, PageValidLength, PUCHAR); - while (TRUE) - { - do - { - if (*Entry == FAT_DIRENT_NEVER_USED) - return 0; // TODO: return something reasonable. - if (*Entry == FAT_DIRENT_DELETED) - { - continue; - } - if (Entry[0x0a] == FAT_DIRENT_ATTR_LFN) - { - PLONG_FILE_NAME_ENTRY Lfnent; - Lfnent = (PLONG_FILE_NAME_ENTRY) Entry; - } - else - { - PDIR_ENTRY Dirent; - Dirent = (PDIR_ENTRY) Entry; - RtlCopyMemory(Context->DirentFileName, - Dirent->FileName, - sizeof(Dirent->FileName)); - } - } while (++Entry < BeyondLastEntry); - /* Check if this is the last available entry */ - if (PageValidLength < PAGE_SIZE) - break; - /* We are getting beyond current page and - * are still in the continous run, map the next page. - */ - Context->PageOffset.QuadPart = PageOffset; - CcUnpinData(Context->PageBcb); - if (!CcMapData(Context->FileObject, - &Context->PageOffset, - PAGE_SIZE, - CanWait, - &Context->PageBcb, - &Context->PageBuffer)) - { - Context->PageBcb = NULL; - Context->PageOffset.QuadPart = 0LL; - ExRaiseStatus(STATUS_CANT_WAIT); - } - Entry = (PUCHAR) Context->PageBuffer; - /* Next Page Offset */ - PageOffset = Context->PageOffset.QuadPart + PAGE_SIZE; - if (PageOffset > Context->BeyondLastEntryOffset) - { - PageValidLength = (SIZE_T) (Context->BeyondLastEntryOffset - - Context->PageOffset.QuadPart); - } - BeyondLastEntry = Add2Ptr(Context->PageBuffer, PageValidLength, PUCHAR); - } - return 0; -} - /* EOF */
Modified: trunk/reactos/drivers/filesystems/fastfat_new/fastfat.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/filesystems/fastfat... ============================================================================== --- trunk/reactos/drivers/filesystems/fastfat_new/fastfat.c [iso-8859-1] (original) +++ trunk/reactos/drivers/filesystems/fastfat_new/fastfat.c [iso-8859-1] Wed Feb 25 15:25:06 2009 @@ -16,6 +16,7 @@ FAT_GLOBAL_DATA FatGlobalData;
/* FUNCTIONS ****************************************************************/ +
NTSTATUS NTAPI @@ -110,7 +111,6 @@ /* Register and reference our filesystem */ IoRegisterFileSystem(DeviceObject); ObReferenceObject(DeviceObject); - return STATUS_SUCCESS; }
@@ -221,5 +221,51 @@ } }
- +VOID +NTAPI +FatDequeueRequest(IN PVOID Context) +{ + PFAT_IRP_CONTEXT IrpContext; + + IrpContext = (PFAT_IRP_CONTEXT) Context; + + /* Enter critical region. */ + FsRtlEnterFileSystem(); + + /* Handle top level IRP Correctly. */ + if (!FlagOn(IrpContext->Flags, IRPCONTEXT_TOPLEVEL)) + IoSetTopLevelIrp((PIRP) FSRTL_FSP_TOP_LEVEL_IRP); + + /* Enable Synchronous IO. */ + SetFlag(IrpContext->Flags, IRPCONTEXT_CANWAIT); + + /* Invoke the handler routine. */ + IrpContext->QueuedOperationHandler(IrpContext); + + /* Restore top level IRP. */ + IoSetTopLevelIrp(NULL); + + /* Leave critical region. */ + FsRtlExitFileSystem(); +} + +VOID +NTAPI +FatQueueRequest(IN PFAT_IRP_CONTEXT IrpContext, + IN PFAT_OPERATION_HANDLER OperationHandler) +{ + /* Save the worker routine. */ + IrpContext->QueuedOperationHandler = OperationHandler; + + /* Indicate if top level IRP was set. */ + if (IoGetTopLevelIrp() == IrpContext->Irp) + SetFlag(IrpContext->Flags, IRPCONTEXT_TOPLEVEL); + + /* Initialize work item. */ + ExInitializeWorkItem(&IrpContext->WorkQueueItem, + FatDequeueRequest, + IrpContext); + ExQueueWorkItem(&IrpContext->WorkQueueItem, + DelayedWorkQueue); +} /* EOF */
Modified: trunk/reactos/drivers/filesystems/fastfat_new/fastfat.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/filesystems/fastfat... ============================================================================== --- trunk/reactos/drivers/filesystems/fastfat_new/fastfat.h [iso-8859-1] (original) +++ trunk/reactos/drivers/filesystems/fastfat_new/fastfat.h [iso-8859-1] Wed Feb 25 15:25:06 2009 @@ -1,6 +1,7 @@ #include <ntifs.h> #include <ntdddisk.h> #include <debug.h> +#include <pseh/pseh2.h>
#ifndef TAG #define TAG(A, B, C, D) (ULONG)(((A)<<0) + ((B)<<8) + ((C)<<16) + ((D)<<24)) @@ -35,6 +36,23 @@ FatSetVolumeInfo(PDEVICE_OBJECT DeviceObject, PIRP Irp);
/* ------------------------------------------------------ blockdev.c */ +NTSTATUS +NTAPI +FatPerformLboIo( + IN PFAT_IRP_CONTEXT IrpContext, + IN PLARGE_INTEGER Offset, + IN SIZE_T Length); + +NTSTATUS +FatPerformVirtualNonCachedIo( + IN PFAT_IRP_CONTEXT IrpContext, + IN PFCB Fcb, + IN PLARGE_INTEGER Offset, + IN SIZE_T Length); + +PVOID +FatMapUserBuffer( + IN OUT PIRP Irp);
/* ----------------------------------------------------------- dir.c */
@@ -45,6 +63,7 @@
NTSTATUS NTAPI FatCreate(PDEVICE_OBJECT DeviceObject, PIRP Irp); +
/* --------------------------------------------------------- close.c */
@@ -90,6 +109,11 @@ VOID NTAPI FatDestroyIrpContext(PFAT_IRP_CONTEXT IrpContext);
+VOID +NTAPI +FatQueueRequest(IN PFAT_IRP_CONTEXT IrpContext, + IN PFAT_OPERATION_HANDLER OperationHandler); + VOID NTAPI FatCompleteRequest(PFAT_IRP_CONTEXT IrpContext OPTIONAL, PIRP Irp OPTIONAL, @@ -118,6 +142,14 @@ DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath);
/* ----------------------------------------------------------- fat.c */ +PVOID +FatPinPage( + PFAT_PAGE_CONTEXT Context, + LONGLONG ByteOffset); + +PVOID +FatPinNextPage( + PFAT_PAGE_CONTEXT Context);
NTSTATUS FatInitializeVcb( @@ -152,8 +184,50 @@ BOOLEAN Override);
/* ------------------------------------------------------ direntry.c */ +VOID +FatFindDirent(IN OUT PFAT_FIND_DIRENT_CONTEXT Context, + OUT PDIR_ENTRY* Dirent, + OUT PUNICODE_STRING LongFileName OPTIONAL); + +VOID +FatEnumerateDirents(IN OUT PFAT_ENUM_DIRENT_CONTEXT Context, + IN SIZE_T Offset); + +VOID +FatQueryFileTimes(OUT PLARGE_INTEGER FileTimes, + IN PDIR_ENTRY Dirent);
/* ----------------------------------------------------------- fcb.c */ +PFCB +FatLookupFcbByName( + IN PFCB ParentFcb, + IN PUNICODE_STRING Name); + +BOOLEAN +FatLinkFcbNames( + IN PFCB ParentFcb, + IN PFCB Fcb); + +VOID +FatUnlinkFcbNames( + IN PFCB ParentFcb, + IN PFCB Fcb); + +NTSTATUS +FatCreateFcb( + OUT PFCB* CreatedFcb, + IN PFAT_IRP_CONTEXT IrpContext, + IN PFCB ParentFcb, + IN PDIR_ENTRY Dirent, + IN PUNICODE_STRING FileName, + IN PUNICODE_STRING LongFileName OPTIONAL); + +NTSTATUS +FatOpenFcb( + OUT PFCB* Fcb, + IN PFAT_IRP_CONTEXT IrpContext, + IN PFCB ParentFcb, + IN PUNICODE_STRING FileName);
/* ------------------------------------------------------------ rw.c */
Modified: trunk/reactos/drivers/filesystems/fastfat_new/fastfat.rbuild URL: http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/filesystems/fastfat... ============================================================================== --- trunk/reactos/drivers/filesystems/fastfat_new/fastfat.rbuild [iso-8859-1] (original) +++ trunk/reactos/drivers/filesystems/fastfat_new/fastfat.rbuild [iso-8859-1] Wed Feb 25 15:25:06 2009 @@ -5,6 +5,7 @@ <include base="fastfatn">.</include> <library>ntoskrnl</library> <library>hal</library> + <library>pseh</library> <file>blockdev.c</file> <file>cleanup.c</file> <file>close.c</file>
Modified: trunk/reactos/drivers/filesystems/fastfat_new/fat.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/filesystems/fastfat... ============================================================================== --- trunk/reactos/drivers/filesystems/fastfat_new/fat.c [iso-8859-1] (original) +++ trunk/reactos/drivers/filesystems/fastfat_new/fat.c [iso-8859-1] Wed Feb 25 15:25:06 2009 @@ -28,76 +28,9 @@ ((ULONG) ((xOffset - (xVcb)->DataArea) >> (xVcb)->BytesPerClusterLog) + 0x02)
ULONG -FatScanFat12ForContinousRun(IN OUT PFAT_SCAN_CONTEXT Context, +FatScanFat32ForContinousRun(IN OUT PFAT_PAGE_CONTEXT Context, IN OUT PULONG Index, IN BOOLEAN CanWait); - -ULONG -FatSetFat12ContinousRun(IN OUT PFAT_SCAN_CONTEXT Context, - IN ULONG Index, - IN ULONG Length, - IN BOOLEAN CanWait); - -ULONG -FatScanFat12ForValueRun(IN OUT PFAT_SCAN_CONTEXT Context, - IN OUT PULONG Index, - IN ULONG IndexValue, - IN BOOLEAN CanWait); - -ULONG -FatSetFat12ValueRun(IN OUT PFAT_SCAN_CONTEXT Context, - IN ULONG Index, - IN ULONG Length, - IN ULONG IndexValue, - IN BOOLEAN CanWait); - -ULONG -FatScanFat16ForContinousRun(IN OUT PFAT_SCAN_CONTEXT Context, - IN OUT PULONG Index, - IN BOOLEAN CanWait); - -ULONG -FatSetFat16ContinousRun(IN OUT PFAT_SCAN_CONTEXT Context, - IN ULONG Index, - IN ULONG Length, - IN BOOLEAN CanWait); - -ULONG -FatScanFat16ForValueRun(IN OUT PFAT_SCAN_CONTEXT Context, - IN OUT PULONG Index, - IN ULONG IndexValue, - IN BOOLEAN CanWait); - -ULONG -FatSetFat16ValueRun(IN OUT PFAT_SCAN_CONTEXT Context, - IN ULONG Index, - IN ULONG Length, - IN ULONG IndexValue, - IN BOOLEAN CanWait); - -ULONG -FatScanFat32ForContinousRun(IN OUT PFAT_SCAN_CONTEXT Context, - IN OUT PULONG Index, - IN BOOLEAN CanWait); - -ULONG -FatSetFat32ContinousRun(IN OUT PFAT_SCAN_CONTEXT Context, - IN ULONG Index, - IN ULONG Length, - IN BOOLEAN CanWait); - -ULONG -FatScanFat32ForValueRun(IN OUT PFAT_SCAN_CONTEXT Context, - IN OUT PULONG Index, - IN ULONG IndexValue, - IN BOOLEAN CanWait); - -ULONG -FatSetFat32ValueRun(IN OUT PFAT_SCAN_CONTEXT Context, - IN ULONG Index, - IN ULONG Length, - IN ULONG IndexValue, - IN BOOLEAN CanWait);
BOOLEAN NTAPI @@ -105,27 +38,122 @@
/* VARIABLES ****************************************************************/ FAT_METHODS Fat12Methods = { - FatScanFat12ForContinousRun, - FatSetFat12ContinousRun, - FatScanFat16ForValueRun, - FatSetFat12ValueRun + NULL, + NULL, + NULL, + NULL };
FAT_METHODS Fat16Methods = { - FatScanFat16ForContinousRun, - FatSetFat16ContinousRun, - FatScanFat16ForValueRun, - FatSetFat16ValueRun + NULL, + NULL, + NULL, + NULL };
FAT_METHODS Fat32Methods = { FatScanFat32ForContinousRun, - FatSetFat32ContinousRun, - FatScanFat32ForValueRun, - FatSetFat32ValueRun + NULL, + NULL, + NULL };
/* FUNCTIONS ****************************************************************/ + +/** + * Pins the page containing ByteOffset byte. + * + * @param Context + * Keeps current BCB, Buffer pointer + * and maintains current and next page offset. + * + * @param ByteOffset + * Offset from the beginning of the data stream to be pinned. + * + * @return + * Pointer to the buffer starting with the specified ByteOffset. + */ +PVOID +FatPinPage( + PFAT_PAGE_CONTEXT Context, + LONGLONG ByteOffset) +{ + SIZE_T OffsetWithinPage; + + OffsetWithinPage = (SIZE_T) (ByteOffset & (PAGE_SIZE - 1)); + ByteOffset -= OffsetWithinPage; + if (ByteOffset != Context->Offset.QuadPart) + { + Context->Offset.QuadPart = ByteOffset; + if (Context->Bcb != NULL) + { + CcUnpinData(Context->Bcb); + Context->Bcb = NULL; + } + if (!CcMapData(Context->FileObject, + &Context->Offset, + PAGE_SIZE, + Context->CanWait, + &Context->Bcb, + &Context->Buffer)) + { + Context->Offset.QuadPart = 0LL; + ExRaiseStatus(STATUS_CANT_WAIT); + } + } + Context->EndOfPage.QuadPart = + Context->Offset.QuadPart + PAGE_SIZE; + if (Context->EndOfPage.QuadPart + > Context->EndOfData.QuadPart) + { + Context->ValidLength = (SIZE_T) + (Context->EndOfData.QuadPart + - Context->Offset.QuadPart); + } + else + { + Context->ValidLength = PAGE_SIZE; + } + return Add2Ptr(Context->Buffer, OffsetWithinPage, PVOID); +} + +/** + * Pins the next page of data stream. + * + * @param Context + * Keeps current BCB, Buffer pointer + * and maintains current and next page offset. + * + * @return + * Pointer to the buffer starting with the beginning of the next page. + */ +PVOID +FatPinNextPage( + PFAT_PAGE_CONTEXT Context) +{ + ASSERT ((Context->Offset.QuadPart % PAGE_SIZE) + != (Context->EndOfPage.QuadPart % PAGE_SIZE) + && Context->Bcb != NULL); + + ASSERT (Context->ValidLength == PAGE_SIZE); + + Context->Offset = Context->EndOfPage; + CcUnpinData(Context->Bcb); + if (!CcMapData(Context->FileObject, + &Context->Offset, + PAGE_SIZE, + Context->CanWait, + &Context->Bcb, + &Context->Buffer)) + { + Context->Bcb = NULL; + Context->Offset.QuadPart = 0LL; + ExRaiseStatus(STATUS_CANT_WAIT); + } + Context->EndOfPage.QuadPart = + Context->Offset.QuadPart + PAGE_SIZE; + return Context->Buffer; +}
/** * Determines the index of the set bit. @@ -148,83 +176,11 @@ return (((Temp + (Temp >> 3)) & 030707070707) % 63); }
-ULONG -FatScanFat12ForContinousRun(IN OUT PFAT_SCAN_CONTEXT Context, - IN OUT PULONG Index, - IN BOOLEAN CanWait) -{ - ExRaiseStatus(STATUS_NOT_IMPLEMENTED); -} - -ULONG -FatSetFat12ContinousRun(IN OUT PFAT_SCAN_CONTEXT Context, - IN ULONG Index, - IN ULONG Length, - IN BOOLEAN CanWait) -{ - ExRaiseStatus(STATUS_NOT_IMPLEMENTED); -} - -ULONG -FatScanFat12ForValueRun(IN OUT PFAT_SCAN_CONTEXT Context, - IN OUT PULONG Index, - IN ULONG IndexValue, - IN BOOLEAN CanWait) -{ - ExRaiseStatus(STATUS_NOT_IMPLEMENTED); -} - -ULONG -FatSetFat12ValueRun(IN OUT PFAT_SCAN_CONTEXT Context, - IN ULONG Index, - IN ULONG Length, - IN ULONG IndexValue, - IN BOOLEAN CanWait) -{ - ExRaiseStatus(STATUS_NOT_IMPLEMENTED); -} - -ULONG -FatScanFat16ForContinousRun(IN OUT PFAT_SCAN_CONTEXT Context, - IN OUT PULONG Index, - IN BOOLEAN CanWait) -{ - ExRaiseStatus(STATUS_NOT_IMPLEMENTED); -} - -ULONG -FatSetFat16ContinousRun(IN OUT PFAT_SCAN_CONTEXT Context, - IN ULONG Index, - IN ULONG Length, - IN BOOLEAN CanWait) -{ - ExRaiseStatus(STATUS_NOT_IMPLEMENTED); -} - -ULONG -FatScanFat16ForValueRun(IN OUT PFAT_SCAN_CONTEXT Context, - IN OUT PULONG Index, - IN ULONG IndexValue, - IN BOOLEAN CanWait) -{ - ExRaiseStatus(STATUS_NOT_IMPLEMENTED); -} - -ULONG -FatSetFat16ValueRun(IN OUT PFAT_SCAN_CONTEXT Context, - IN ULONG Index, - IN ULONG Length, - IN ULONG IndexValue, - IN BOOLEAN CanWait) -{ - ExRaiseStatus(STATUS_NOT_IMPLEMENTED); -} - /** * Scans FAT32 for continous chain of clusters * * @param Context - * Pointer to FAT_SCAN_CONTEXT. + * Pointer to FAT_PAGE_CONTEXT. * * @param Index * Supplies the Index of the first cluster @@ -241,79 +197,26 @@ * Raises STATUS_CANT_WAIT race condition. */ ULONG -FatScanFat32ForContinousRun(IN OUT PFAT_SCAN_CONTEXT Context, +FatScanFat32ForContinousRun(IN OUT PFAT_PAGE_CONTEXT Context, IN OUT PULONG Index, IN BOOLEAN CanWait) { - LONGLONG PageOffset; - SIZE_T OffsetWithinPage, PageValidLength; - PULONG Entry, BeyoudLastEntry; - /* Determine page offset and the offset within page - * for the first cluster. - */ - PageValidLength = PAGE_SIZE; - PageOffset = ((LONGLONG) *Index) << 0x2; - OffsetWithinPage = (SIZE_T) (PageOffset & (PAGE_SIZE - 1)); - PageOffset -= OffsetWithinPage; - /* Check if the context already has the required page mapped. - * Map the first page is necessary. - */ - if (PageOffset != Context->PageOffset.QuadPart) - { - Context->PageOffset.QuadPart = PageOffset; - if (Context->PageBcb != NULL) - { - CcUnpinData(Context->PageBcb); - Context->PageBcb = NULL; - } - if (!CcMapData(Context->FileObject, - &Context->PageOffset, - PAGE_SIZE, - CanWait, - &Context->PageBcb, - &Context->PageBuffer)) - { - Context->PageOffset.QuadPart = 0LL; - ExRaiseStatus(STATUS_CANT_WAIT); - } - } - Entry = Add2Ptr(Context->PageBuffer, OffsetWithinPage, PULONG); - /* Next Page Offset */ - PageOffset = Context->PageOffset.QuadPart + PAGE_SIZE; - if (PageOffset > Context->BeyondLastEntryOffset) - PageValidLength = (SIZE_T) (Context->BeyondLastEntryOffset - - Context->PageOffset.QuadPart); - BeyoudLastEntry = Add2Ptr(Context->PageBuffer, PageValidLength, PULONG); + PULONG Entry, EndOfPage; + + Entry = FatPinPage(Context, ((LONGLONG) *Index) << 0x2); + EndOfPage = FatPinEndOfPage(Context, PULONG); while (TRUE) { do { if ((*Entry & FAT_CLUSTER_LAST) != ++(*Index)) return (*Entry & FAT_CLUSTER_LAST); - } while (++Entry < BeyoudLastEntry); + } while (++Entry < EndOfPage); /* Check if this is the last available entry */ - if (PageValidLength < PAGE_SIZE) + if (FatPinIsLastPage(Context)) break; - /* We are getting beyond current page and - * are still in the continous run, map the next page. - */ - Context->PageOffset.QuadPart = PageOffset; - CcUnpinData(Context->PageBcb); - if (!CcMapData(Context->FileObject, - &Context->PageOffset, PAGE_SIZE, CanWait, - &Context->PageBcb, &Context->PageBuffer)) - { - Context->PageBcb = NULL; - Context->PageOffset.QuadPart = 0LL; - ExRaiseStatus(STATUS_CANT_WAIT); - } - Entry = (PULONG) Context->PageBuffer; - /* Next Page Offset */ - PageOffset = Context->PageOffset.QuadPart + PAGE_SIZE; - if (PageOffset > Context->BeyondLastEntryOffset) - PageValidLength = (SIZE_T) (Context->BeyondLastEntryOffset - - Context->PageOffset.QuadPart); - BeyoudLastEntry = Add2Ptr(Context->PageBuffer, PageValidLength, PULONG); + Entry = (PULONG) FatPinNextPage(Context); + EndOfPage = FatPinEndOfPage(Context, PULONG); } return (*Index - 1); } @@ -388,7 +291,7 @@ { LONGLONG CurrentLbo, CurrentVbo, BeyondLastVbo, CurrentLength; ULONG Entry, NextEntry, NumberOfEntries, CurrentIndex; - FAT_SCAN_CONTEXT Context; + FAT_PAGE_CONTEXT Context; PVCB Vcb;
/* Some often used values */ @@ -428,8 +331,11 @@ CurrentIndex = 0L; CurrentVbo = 0LL; } + /* Initialize Context */ RtlZeroMemory(&Context, sizeof(Context)); - Context.FileObject = Vcb->VolumeFileObject; + Context.FileObject = Vcb->StreamFileObject; + Context.EndOfData.QuadPart = Vcb->BeyondLastClusterInFat; + while (CurrentVbo < BeyondLastVbo) { /* Locate Continous run starting with the current entry */ @@ -532,6 +438,10 @@ Vcb->BytesPerCluster = SectorsToBytes(Vcb, Vcb->Bpb.SectorsPerCluster); Vcb->BytesPerClusterLog = FatPowerOfTwo(Vcb->BytesPerCluster); Vcb->BeyondLastClusterInFat = ((LONGLONG) Vcb->Clusters) * Vcb->IndexDepth / 0x8; + + /* Update real volume size with the real value. */ + Vcb->Header.FileSize.QuadPart = + Vcb->Header.AllocationSize.QuadPart = SectorsToBytes(Vcb, Vcb->Sectors); }
NTSTATUS @@ -558,18 +468,19 @@ /* Setup Vcb fields */ Vcb->TargetDeviceObject = TargetDeviceObject; ObReferenceObject(TargetDeviceObject); + Vcb->Vpb = Vpb;
/* Setup FCB Header */ ExInitializeFastMutex(&Vcb->HeaderMutex); FsRtlSetupAdvancedHeader(&Vcb->Header, &Vcb->HeaderMutex);
/* Create Volume File Object */ - Vcb->VolumeFileObject = IoCreateStreamFileObject(NULL, + Vcb->StreamFileObject = IoCreateStreamFileObject(NULL, Vcb->TargetDeviceObject);
/* We have to setup all FCB fields needed for CC */ - Vcb->VolumeFileObject->FsContext = Vcb; - Vcb->VolumeFileObject->SectionObjectPointer = &Vcb->SectionObjectPointers; + Vcb->StreamFileObject->FsContext = Vcb; + Vcb->StreamFileObject->SectionObjectPointer = &Vcb->SectionObjectPointers;
/* At least full boot sector should be available */ Vcb->Header.FileSize.QuadPart = sizeof(PACKED_BOOT_SECTOR); @@ -578,7 +489,7 @@ Vcb->Header.ValidDataLength.LowPart = MAXULONG;
/* Initialize CC */ - CcInitializeCacheMap(Vcb->VolumeFileObject, + CcInitializeCacheMap(Vcb->StreamFileObject, (PCC_FILE_SIZES)&Vcb->Header.AllocationSize, FALSE, &FatGlobalData.CacheMgrNoopCallbacks, @@ -592,7 +503,7 @@ * any of the parameters set further * in this routine. */ - if (CcMapData(Vcb->VolumeFileObject, + if (CcMapData(Vcb->StreamFileObject, &Offset, sizeof(PACKED_BOOT_SECTOR), TRUE, @@ -606,7 +517,7 @@ { Status = STATUS_UNRECOGNIZED_VOLUME; } - CopyUchar4(&Vpb->SerialNumber, BootSector->Id); + CopyUchar4(&Vcb->Vpb->SerialNumber, BootSector->Id); CcUnpinData(Bcb); } else @@ -641,12 +552,12 @@ ZeroSize.QuadPart = 0LL;
/* Close volume file */ - if (Vcb->VolumeFileObject != NULL) + if (Vcb->StreamFileObject != NULL) { /* Uninitialize CC. */ - CcUninitializeCacheMap(Vcb->VolumeFileObject, &ZeroSize, NULL); - ObDereferenceObject(Vcb->VolumeFileObject); - Vcb->VolumeFileObject = NULL; + CcUninitializeCacheMap(Vcb->StreamFileObject, &ZeroSize, NULL); + ObDereferenceObject(Vcb->StreamFileObject); + Vcb->StreamFileObject = NULL; }
/* Free notifications stuff */
Modified: trunk/reactos/drivers/filesystems/fastfat_new/fat.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/filesystems/fastfat... ============================================================================== --- trunk/reactos/drivers/filesystems/fastfat_new/fat.h [iso-8859-1] (original) +++ trunk/reactos/drivers/filesystems/fastfat_new/fat.h [iso-8859-1] Wed Feb 25 15:25:06 2009 @@ -248,7 +248,7 @@ // sizeof = 0x020
typedef struct _LONG_FILE_NAME_ENTRY { - UCHAR Index; + UCHAR SeqNum; UCHAR NameA[10]; UCHAR Attributes; UCHAR Type; @@ -259,7 +259,13 @@ } LONG_FILE_NAME_ENTRY, *PLONG_FILE_NAME_ENTRY; // sizeof = 0x020
-#define FAT_FN_DIR_ENTRY_TERM_INDEX 0x40 +#define FAT_LFN_NAME_LENGTH \ + (RTL_FIELD_SIZE(LONG_FILE_NAME_ENTRY, NameA) \ + + RTL_FIELD_SIZE(LONG_FILE_NAME_ENTRY, NameB) \ + + RTL_FIELD_SIZE(LONG_FILE_NAME_ENTRY, NameC)) + +#define FAT_FN_DIR_ENTRY_LAST 0x40 +#define FAT_FN_MAX_DIR_ENTIES 0x14
#define FAT_BYTES_PER_DIRENT 0x20 #define FAT_BYTES_PER_DIRENT_LOG 0x05
Modified: trunk/reactos/drivers/filesystems/fastfat_new/fatstruc.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/filesystems/fastfat... ============================================================================== --- trunk/reactos/drivers/filesystems/fastfat_new/fatstruc.h [iso-8859-1] (original) +++ trunk/reactos/drivers/filesystems/fastfat_new/fatstruc.h [iso-8859-1] Wed Feb 25 15:25:06 2009 @@ -3,7 +3,10 @@
typedef struct _FAT_SCAN_CONTEXT *PFAT_SCAN_CONTEXT; typedef struct _FAT_IO_CONTEXT *PFAT_IO_CONTEXT; +typedef struct _FAT_IRP_CONTEXT *PFAT_IRP_CONTEXT; typedef PVOID PBCB; + +typedef NTSTATUS (*PFAT_OPERATION_HANDLER) (PFAT_IRP_CONTEXT);
typedef struct _FAT_GLOBAL_DATA { @@ -22,6 +25,39 @@ LARGE_INTEGER DefaultFileTime; } FAT_GLOBAL_DATA;
+typedef struct _FAT_PAGE_CONTEXT +{ + PFILE_OBJECT FileObject; + LARGE_INTEGER EndOfData; + LARGE_INTEGER Offset; + LARGE_INTEGER EndOfPage; + SIZE_T ValidLength; + PVOID Buffer; + PBCB Bcb; + BOOLEAN CanWait; +} FAT_PAGE_CONTEXT, *PFAT_PAGE_CONTEXT; + +#define FatPinSetupContext(xContext, xFcb, CanWait) \ +{ \ + (xContext)->FileObject = (xFcb)->StreamFileObject; \ + (xContext)->EndOfData = (xFcb)->Header.FileSize; \ + (xContext)->Offset.QuadPart = -1LL; \ + (xContext)->Bcb = NULL; \ + (xContext)->CanWait = CanWait; \ +} + +#define FatPinCleanupContext(xContext) \ + if ((xContext)->Bcb != NULL) { \ + CcUnpinData((xContext)->Bcb); \ + (xContext)->Bcb = NULL; \ + } \ + +#define FatPinEndOfPage(xContext, xType) \ + Add2Ptr((xContext)->Buffer, (xContext)->ValidLength, xType) + +#define FatPinIsLastPage(xContext) \ + ((xContext)->ValidLength != PAGE_SIZE) + #define IRPCONTEXT_CANWAIT 0x0001 #define IRPCONTEXT_PENDINGRETURNED 0x0002 #define IRPCONTEXT_STACK_IO_CONTEXT 0x0004 @@ -38,18 +74,23 @@ ULONG Flags; struct _VCB *Vcb; ULONG PinCount; + FAT_PAGE_CONTEXT Page; struct _FAT_IO_CONTEXT *FatIoContext; - WORK_QUEUE_ITEM WorkQueueItem; + PFAT_OPERATION_HANDLER QueuedOperationHandler; PIO_STACK_LOCATION Stack; KEVENT Event; -} FAT_IRP_CONTEXT, *PFAT_IRP_CONTEXT; +} FAT_IRP_CONTEXT;
typedef struct _FAT_IO_CONTEXT { PMDL ZeroMdl; - PIRP MasterIrp; - LONG IrpCount; + PIRP Irp; + LONG RunCount; + SIZE_T Length; + LONGLONG Offset; + PFILE_OBJECT FileObject; + union { struct @@ -57,19 +98,16 @@ PERESOURCE Resource; PERESOURCE PagingIoResource; ERESOURCE_THREAD ResourceThreadId; - ULONG RequestedByteCount; - PFILE_OBJECT FileObject; - BOOLEAN ReadOperation; } Async; KEVENT SyncEvent; } Wait; - PIRP Irp[0]; + PIRP AssociatedIrp[0]; } FAT_IO_CONTEXT;
-typedef ULONG (*PFAT_SCANFAT_FOR_CONTINOUS_RUN_ROUTINE) (struct _FAT_SCAN_CONTEXT*, PULONG, BOOLEAN); -typedef ULONG (*PFAT_SETFAT_CONTINOUS_RUN_ROUTINE) (PFAT_SCAN_CONTEXT, ULONG, ULONG, BOOLEAN); -typedef ULONG (*PFAT_SCANFAT_FOR_VALUE_RUN_ROUTINE) (PFAT_SCAN_CONTEXT, PULONG, ULONG, BOOLEAN); -typedef ULONG (*PFAT_SETFAT_VALUE_RUN_ROUTINE) (PFAT_SCAN_CONTEXT, ULONG, ULONG, ULONG, BOOLEAN); +typedef ULONG (*PFAT_SCANFAT_FOR_CONTINOUS_RUN_ROUTINE) (PFAT_PAGE_CONTEXT, PULONG, BOOLEAN); +typedef ULONG (*PFAT_SETFAT_CONTINOUS_RUN_ROUTINE) (PFAT_PAGE_CONTEXT, ULONG, ULONG, BOOLEAN); +typedef ULONG (*PFAT_SCANFAT_FOR_VALUE_RUN_ROUTINE) (PFAT_PAGE_CONTEXT, PULONG, ULONG, BOOLEAN); +typedef ULONG (*PFAT_SETFAT_VALUE_RUN_ROUTINE) (PFAT_PAGE_CONTEXT, ULONG, ULONG, ULONG, BOOLEAN);
typedef struct _FAT_METHODS { PFAT_SCANFAT_FOR_CONTINOUS_RUN_ROUTINE ScanContinousRun; @@ -78,7 +116,7 @@ PFAT_SETFAT_VALUE_RUN_ROUTINE SetValueRun; } FAT_METHODS, *PFAT_METHODS;
-#define FAT_NTC_VCB (USHORT)TAG('F', 'V', 0, 0); +#define FAT_NTC_VCB (USHORT) TAG('F', 'V', 0, 0)
/* Volume Control Block */ typedef struct _VCB @@ -87,9 +125,10 @@ FAST_MUTEX HeaderMutex; SECTION_OBJECT_POINTERS SectionObjectPointers;
- PFILE_OBJECT VolumeFileObject; + PFILE_OBJECT StreamFileObject; PDEVICE_OBJECT TargetDeviceObject; LIST_ENTRY VcbLinks; + PVPB Vpb;
/* Notifications support */ PNOTIFY_SYNC NotifySync; @@ -186,10 +225,14 @@ FCB_NAME_LINK FileName[0x2]; /* Buffer for the short name */ WCHAR ShortNameBuffer[0xc]; + /* File basic info */ + FILE_BASIC_INFORMATION BasicInfo; union { struct { + /* Directory data stream (just handy to have it). */ + PFILE_OBJECT StreamFileObject; /* Bitmap to search for free dirents. */ /* RTL_BITMAP Bitmap; */ PRTL_SPLAY_LINKS SplayLinks; @@ -197,13 +240,56 @@ }; } FCB, *PFCB;
+typedef struct _FAT_ENUM_DIRENT_CONTEXT *PFAT_ENUM_DIRENT_CONTEXT; +typedef struct _FAT_ENUM_DIR_CONTEXT *PFAT_ENUM_DIR_CONTEXT; + +typedef ULONG (*PFAT_COPY_DIRENT_ROUTINE) (PFAT_ENUM_DIR_CONTEXT, PDIR_ENTRY, PVOID); + +typedef struct _FAT_ENUM_DIRENT_CONTEXT +{ + FAT_PAGE_CONTEXT Page; + + /* Copy dirent to dirinfo */ + PFAT_COPY_DIRENT_ROUTINE CopyDirent; + LONGLONG BytesPerClusterMask; + + /* Info buffer characteristics */ + PVOID Buffer; + SIZE_T Offset; + SIZE_T Length; + + /* Criteria */ + PUNICODE_STRING FileName; + UCHAR CcbFlags; + + /* Lfn buffer/length offsets */ + ULONG LengthOffset; + ULONG NameOffset; +} FAT_ENUM_DIRENT_CONTEXT; + +typedef struct _FAT_FIND_DIRENT_CONTEXT +{ + FAT_PAGE_CONTEXT Page; + UNICODE_STRING ShortName; + WCHAR ShortNameBuffer[0x18]; + /* Criteria */ + PUNICODE_STRING FileName; + BOOLEAN Valid8dot3Name; +} FAT_FIND_DIRENT_CONTEXT, *PFAT_FIND_DIRENT_CONTEXT; + typedef struct _CCB { LARGE_INTEGER CurrentByteOffset; ULONG Entry; UNICODE_STRING SearchPattern; + UCHAR Flags; } CCB, *PCCB;
+ +#define CCB_SEARCH_RETURN_SINGLE_ENTRY 0x01 +#define CCB_SEARCH_PATTERN_LEGAL_8DOT3 0x02 +#define CCB_SEARCH_PATTERN_HAS_WILD_CARD 0x04 +#define CCB_DASD_IO 0x10 extern FAT_GLOBAL_DATA FatGlobalData;
#endif//__STRUCT_H__
Modified: trunk/reactos/drivers/filesystems/fastfat_new/fcb.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/filesystems/fastfat... ============================================================================== --- trunk/reactos/drivers/filesystems/fastfat_new/fcb.c [iso-8859-1] (original) +++ trunk/reactos/drivers/filesystems/fastfat_new/fcb.c [iso-8859-1] Wed Feb 25 15:25:06 2009 @@ -1,9 +1,9 @@ /* * PROJECT: ReactOS FAT file system driver * LICENSE: GPL - See COPYING in the top level directory - * FILE: drivers/filesystems/fastfat/rw.c - * PURPOSE: Read/write support - * PROGRAMMERS: + * FILE: drivers/filesystems/fastfat/fcb.c + * PURPOSE: FCB manipulation routines. + * PROGRAMMERS: Alexey Vlasov */
/* INCLUDES *****************************************************************/ @@ -13,5 +13,316 @@
/* FUNCTIONS ****************************************************************/
- +/** + * Locates FCB by the supplied name in the cache trie of fcbs. + * + * @param ParentFcb + * Supplies a pointer to the parent FCB + * + * @param Name + * Supplied a name of the FCB to be located in cache. + * + * @return + * Pointer to the found FCB or NULL. + */ +PFCB +FatLookupFcbByName( + IN PFCB ParentFcb, + IN PUNICODE_STRING Name) +{ + PFCB_NAME_LINK Node; + PRTL_SPLAY_LINKS Links; + + /* Get sub-trie root node from the parent FCB */ + Links = ParentFcb->Dcb.SplayLinks; + while (Links != NULL) + { + LONG Comparison; + + Node = CONTAINING_RECORD(Links, FCB_NAME_LINK, Links); + + /* + * Compare the name stored in the node + * and determine the direction to walk. + */ + Comparison = RtlCompareUnicodeString(&Node->String, Name, TRUE); + if (Comparison > 0) { + /* Left child */ + Links = RtlLeftChild(&Node->Links); + } + else if (Comparison < 0) + { + /* Right child */ + Links = RtlRightChild(&Node->Links); + } + else + { + /* Strings are equal, we have found the node! */ + break; + } + } + + /* The case when nothing was found. */ + if (Links == NULL) + return NULL; + + /* Cast node to the FCB structure. */ + return CONTAINING_RECORD(Links, FCB, FileName[Node->Type]); +} + +/** + * Inserts FCB into FCBs cache trie. + * + * @param ParentFcb + * Supplies a pointer to the parent FCB + * + * @param Fcb + * Supplied a pointer to the being inserted FCB. + * + * @return + * TRUE if the FCB was successfully inserted, + * FASLE in the case of name collision. + */ +BOOLEAN +FatLinkFcbNames( + IN PFCB ParentFcb, + IN PFCB Fcb) +{ + PFCB_NAME_LINK Name; + PRTL_SPLAY_LINKS Links; + + /* None of the parameters can be NULL */ + ASSERT(ParentFcb != NULL && Fcb != NULL); + + /* Get root links of the parent FCB. */ + Links = ParentFcb->Dcb.SplayLinks; + + /* + * Get first file name + * (short name for FAT because it's always there. + */ + Name = Fcb->FileName; + + /* + * Check if ParentDcb links are initialized, + * at least one child FCB is cached. + */ + if (Links == NULL) + { + ParentFcb->Dcb.SplayLinks = Links = &Name->Links; + RtlInitializeSplayLinks(Links); + + /* Check if we have more names to cache. */ + if ((++Name)->String.Length == 0) + return TRUE; + } + /* Lookup for the insertion point in the trie. */ + do + { + LONG Comparison; + PFCB_NAME_LINK Node; + PRTL_SPLAY_LINKS PrevLinks; + + PrevLinks = Links; + Node = CONTAINING_RECORD(Links, FCB_NAME_LINK, Links); + Comparison = RtlCompareUnicodeString(&Node->String, &Name->String, TRUE); + if (Comparison > 0) { + Links = RtlLeftChild(&Node->Links); + if (Links == NULL) + { + RtlInsertAsLeftChild(PrevLinks, &Name->Links); + break; + } + } + else if (Comparison < 0) + { + Links = RtlRightChild(&Node->Links); + if (Links == NULL) + { + RtlInsertAsRightChild(PrevLinks, &Name->Links); + break; + } + } + else + { + return FALSE; + } + + /* Possibly switch to the second (lfn) name and cache that. */ + } while (Name == Fcb->FileName && (++Name)->String.Length > 0); + return TRUE; +} + +/** + * Unlinks FCB from the FCBs cache trie. + * + * @param ParentFcb + * Supplies a pointer to the parent FCB + * + * @param Fcb + * Supplied a pointer to the being unlinked FCB. + * + * @return + * VOID + */ +VOID +FatUnlinkFcbNames( + IN PFCB ParentFcb, + IN PFCB Fcb) +{ + /* See if there is an lfn and unlink that. */ + if (Fcb->FileName[FcbLongName].String.Length > 0) + ParentFcb->Dcb.SplayLinks = + RtlDelete(&Fcb->FileName[FcbLongName].Links); + + /* See if there is a short name and unlink that. */ + if (Fcb->FileName[FcbShortName].String.Length > 0) + ParentFcb->Dcb.SplayLinks = + RtlDelete(&Fcb->FileName[FcbShortName].Links); +} + +NTSTATUS +FatCreateFcb( + OUT PFCB* CreatedFcb, + IN PFAT_IRP_CONTEXT IrpContext, + IN PFCB ParentFcb, + IN PDIR_ENTRY Dirent, + IN PUNICODE_STRING FileName, + IN PUNICODE_STRING LongFileName OPTIONAL) +{ + NTSTATUS Status; + PFCB Fcb; + + /* Allocate FCB structure. */ + Fcb = (PFCB) ExAllocateFromNPagedLookasideList(&FatGlobalData.NonPagedFcbList); + if (Fcb == NULL) + return STATUS_INSUFFICIENT_RESOURCES; + RtlZeroMemory(Fcb, sizeof(FCB)); + + /* Setup FCB Advanced Header. */ + Fcb->Header.NodeTypeCode = FAT_NTC_FCB; + Fcb->Header.NodeByteSize = sizeof(*Fcb); + ExInitializeResourceLite(&Fcb->Resource); + Fcb->Header.Resource = &Fcb->Resource; + ExInitializeResourceLite(&Fcb->PagingIoResource); + Fcb->Header.PagingIoResource = &Fcb->PagingIoResource; + ExInitializeFastMutex(&Fcb->HeaderMutex); + FsRtlSetupAdvancedHeader(&Fcb->Header, &Fcb->HeaderMutex); + Fcb->Header.FileSize.QuadPart = Dirent->FileSize; + Fcb->Header.ValidDataLength.QuadPart = Dirent->FileSize; + Fcb->Header.IsFastIoPossible = FastIoIsNotPossible; + + /* Setup main fields. */ + FsRtlInitializeFileLock(&Fcb->Lock, NULL, NULL); + FsRtlInitializeLargeMcb(&Fcb->Mcb, PagedPool); + Fcb->Vcb = IrpContext->Vcb; + Fcb->ParentFcb = ParentFcb; + Fcb->FirstCluster = Dirent->FirstCluster + | (Dirent->FirstClusterOfFileHi << 0x10); + + /* Setup basic info. */ + Fcb->BasicInfo.FileAttributes = Dirent->Attributes; + FatQueryFileTimes(&Fcb->BasicInfo.CreationTime, Dirent); + + /* Setup short name since always present in FAT. */ + Fcb->FileName[FcbShortName].Type = FcbShortName; + Fcb->FileName[FcbShortName].String.Buffer = Fcb->ShortNameBuffer; + Fcb->FileName[FcbShortName].String.MaximumLength = 0x0c; + Fcb->FileName[FcbShortName].String.Length = FileName->Length; + RtlCopyMemory(Fcb->ShortNameBuffer, FileName->Buffer, FileName->Length); + + /* Just swap optional lfn. */ + if (ARGUMENT_PRESENT(LongFileName) && LongFileName->Length > 0) + { + Fcb->FileName[FcbLongName].Type = FcbLongName; + Fcb->FileName[FcbLongName].String = *LongFileName; + RtlZeroMemory(LongFileName, sizeof(UNICODE_STRING)); + } + + /* Put FCB into cache trie. */ + if (!FatLinkFcbNames(ParentFcb, Fcb)) + { + Status = STATUS_OBJECT_NAME_COLLISION; + goto FsdFatCreateFcbCleanup; + } + *CreatedFcb = Fcb; + + /* We are done! */ + return STATUS_SUCCESS; + +FsdFatCreateFcbCleanup: + if (ARGUMENT_PRESENT(LongFileName) && + Fcb->FileName[FcbLongName].String.Buffer != NULL) + { + /* Swap lfn back to the input parameter */ + *LongFileName = Fcb->FileName[FcbLongName].String; + } + ExFreeToNPagedLookasideList(&FatGlobalData.NonPagedFcbList, Fcb); + return Status; +} + +NTSTATUS +FatOpenFcb( + OUT PFCB* Fcb, + IN PFAT_IRP_CONTEXT IrpContext, + IN PFCB ParentFcb, + IN PUNICODE_STRING FileName) +{ + FAT_FIND_DIRENT_CONTEXT Context; + UNICODE_STRING LongFileName; + PDIR_ENTRY Dirent; + NTSTATUS Status; + + // TODO: _SEH_TRY { + if (ParentFcb->Dcb.StreamFileObject == NULL) + { + PFILE_OBJECT FileObject; + PVPB Vpb; + + Vpb = IrpContext->Vcb->Vpb; + + /* Create stream file object */ + FileObject = IoCreateStreamFileObject(NULL, Vpb->RealDevice); + FileObject->Vpb = Vpb; + FileObject->SectionObjectPointer = &ParentFcb->SectionObjectPointers; + FileObject->FsContext = ParentFcb; + FileObject->FsContext2 = NULL; + + /* Store it in parent fcb */ + ParentFcb->Dcb.StreamFileObject = FileObject; + + } + + /* Check if cache is initialized. */ + if (ParentFcb->Dcb.StreamFileObject->PrivateCacheMap == NULL ) + { + CcInitializeCacheMap(ParentFcb->Dcb.StreamFileObject, + (PCC_FILE_SIZES) &ParentFcb->Header.AllocationSize, + TRUE, + &FatGlobalData.CacheMgrNoopCallbacks, + ParentFcb); + } + + /* Page context */ + Context.Page.FileObject = ParentFcb->Dcb.StreamFileObject; + Context.Page.EndOfData = ParentFcb->Header.FileSize; + Context.Page.Offset.QuadPart = -1LL; + Context.Page.Bcb = NULL; + Context.Page.CanWait = BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT); + Context.Page.EndOfData = ParentFcb->Header.FileSize; + + /* Search context */ + Context.ShortName.Length = 0; + Context.ShortName.Buffer = Context.ShortNameBuffer; + Context.ShortName.MaximumLength = sizeof(Context.ShortNameBuffer); + Context.FileName = FileName; + Context.Valid8dot3Name = RtlIsNameLegalDOS8Dot3(FileName, NULL, NULL); + + /* Locate the dirent */ + FatFindDirent(&Context, &Dirent, &LongFileName); + + Status = FatCreateFcb(Fcb, IrpContext, ParentFcb, Dirent, + &Context.ShortName, &LongFileName); + return Status; +} /* EOF */
Modified: trunk/reactos/drivers/filesystems/fastfat_new/fsctl.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/filesystems/fastfat... ============================================================================== --- trunk/reactos/drivers/filesystems/fastfat_new/fsctl.c [iso-8859-1] (original) +++ trunk/reactos/drivers/filesystems/fastfat_new/fsctl.c [iso-8859-1] Wed Feb 25 15:25:06 2009 @@ -112,7 +112,7 @@
if (!NT_SUCCESS(Status)) goto FatMountVolumeCleanup;
- VolumeDevice->DeviceObject.SectorSize = DiskGeometry.BytesPerSector; + VolumeDevice->DeviceObject.SectorSize = (USHORT) DiskGeometry.BytesPerSector;
/* Signal we're done with initializing */ VolumeDevice->DeviceObject.Flags &= ~DO_DEVICE_INITIALIZING; @@ -128,7 +128,7 @@ VolumeDevice->Vcb.MediaChangeCount = MediaChangeCount;
/* Notify about volume mount */ - FsRtlNotifyVolumeEvent(VolumeDevice->Vcb.VolumeFileObject, FSRTL_VOLUME_MOUNT); + FsRtlNotifyVolumeEvent(VolumeDevice->Vcb.StreamFileObject, FSRTL_VOLUME_MOUNT);
/* Return success */ return STATUS_SUCCESS;