diff --git a/reactos/drivers/filesystems/fastfat_new/blockdev.c b/reactos/drivers/filesystems/fastfat_new/blockdev.c new file mode 100644 index 00000000000..cada3d81421 --- /dev/null +++ b/reactos/drivers/filesystems/fastfat_new/blockdev.c @@ -0,0 +1,338 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: drivers/fs/vfat/blockdev.c + * PURPOSE: Temporary sector reading support + * PROGRAMMER: David Welch (welch@cwcom.net) + * UPDATE HISTORY: + */ + +/* INCLUDES *****************************************************************/ + +#define NDEBUG +#include "vfat.h" + +/* FUNCTIONS ***************************************************************/ + +static IO_COMPLETION_ROUTINE VfatReadWritePartialCompletion; +static NTSTATUS NTAPI +VfatReadWritePartialCompletion (IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID Context) +{ + PVFAT_IRP_CONTEXT IrpContext; + PMDL Mdl; + + DPRINT("VfatReadWritePartialCompletion() called\n"); + + IrpContext = (PVFAT_IRP_CONTEXT)Context; + + while ((Mdl = Irp->MdlAddress)) + { + Irp->MdlAddress = Mdl->Next; + IoFreeMdl(Mdl); + } + if (Irp->PendingReturned) + { + IrpContext->Flags |= IRPCONTEXT_PENDINGRETURNED; + } + if (!NT_SUCCESS(Irp->IoStatus.Status)) + { + IrpContext->Irp->IoStatus.Status = Irp->IoStatus.Status; + } + if (0 == InterlockedDecrement((PLONG)&IrpContext->RefCount) && + IrpContext->Flags & IRPCONTEXT_PENDINGRETURNED) + { + KeSetEvent(&IrpContext->Event, IO_NO_INCREMENT, FALSE); + } + IoFreeIrp(Irp); + + DPRINT("VfatReadWritePartialCompletion() done\n"); + + return STATUS_MORE_PROCESSING_REQUIRED; +} + +NTSTATUS +VfatReadDisk (IN PDEVICE_OBJECT pDeviceObject, + IN PLARGE_INTEGER ReadOffset, + IN ULONG ReadLength, + IN OUT PUCHAR Buffer, + IN BOOLEAN Override) +{ + PIO_STACK_LOCATION Stack; + PIRP Irp; + IO_STATUS_BLOCK IoStatus; + KEVENT event; + NTSTATUS Status; + + KeInitializeEvent (&event, NotificationEvent, FALSE); + + DPRINT ("VfatReadDisk(pDeviceObject %p, Offset %I64x, Length %d, Buffer %p)\n", + pDeviceObject, ReadOffset->QuadPart, ReadLength, Buffer); + + DPRINT ("Building synchronous FSD Request...\n"); + Irp = IoBuildSynchronousFsdRequest (IRP_MJ_READ, + pDeviceObject, + Buffer, + ReadLength, + ReadOffset, + &event, + &IoStatus); + if (Irp == NULL) + { + DPRINT("IoBuildSynchronousFsdRequest failed\n"); + return(STATUS_UNSUCCESSFUL); + } + + if (Override) + { + Stack = IoGetNextIrpStackLocation(Irp); + Stack->Flags |= SL_OVERRIDE_VERIFY_VOLUME; + } + + DPRINT ("Calling IO Driver... with irp %p\n", Irp); + Status = IoCallDriver (pDeviceObject, Irp); + + DPRINT ("Waiting for IO Operation for %p\n", Irp); + if (Status == STATUS_PENDING) + { + DPRINT ("Operation pending\n"); + KeWaitForSingleObject (&event, Suspended, KernelMode, FALSE, NULL); + DPRINT ("Getting IO Status... for %p\n", Irp); + Status = IoStatus.Status; + } + + if (!NT_SUCCESS (Status)) + { + DPRINT ("IO failed!!! VfatReadDisk : Error code: %x\n", Status); + DPRINT ("(pDeviceObject %p, Offset %I64x, Size %d, Buffer %p\n", + pDeviceObject, ReadOffset->QuadPart, ReadLength, Buffer); + return (Status); + } + DPRINT ("Block request succeeded for %p\n", Irp); + return (STATUS_SUCCESS); +} + +NTSTATUS +VfatReadDiskPartial (IN PVFAT_IRP_CONTEXT IrpContext, + IN PLARGE_INTEGER ReadOffset, + IN ULONG ReadLength, + ULONG BufferOffset, + IN BOOLEAN Wait) +{ + PIRP Irp; + PIO_STACK_LOCATION StackPtr; + NTSTATUS Status; + PVOID Buffer; + + DPRINT ("VfatReadDiskPartial(IrpContext %p, ReadOffset %I64x, ReadLength %d, BufferOffset %x, Wait %d)\n", + IrpContext, ReadOffset->QuadPart, ReadLength, BufferOffset, Wait); + + DPRINT ("Building asynchronous FSD Request...\n"); + + Buffer = (PCHAR)MmGetMdlVirtualAddress(IrpContext->Irp->MdlAddress) + BufferOffset; + + Irp = IoAllocateIrp(IrpContext->DeviceExt->StorageDevice->StackSize, TRUE); + if (Irp == NULL) + { + DPRINT("IoAllocateIrp failed\n"); + return(STATUS_UNSUCCESSFUL); + } + + Irp->UserIosb = NULL; + Irp->Tail.Overlay.Thread = PsGetCurrentThread(); + + StackPtr = IoGetNextIrpStackLocation(Irp); + StackPtr->MajorFunction = IRP_MJ_READ; + StackPtr->MinorFunction = 0; + StackPtr->Flags = 0; + StackPtr->Control = 0; + StackPtr->DeviceObject = IrpContext->DeviceExt->StorageDevice; + StackPtr->FileObject = NULL; + StackPtr->CompletionRoutine = NULL; + StackPtr->Parameters.Read.Length = ReadLength; + StackPtr->Parameters.Read.ByteOffset = *ReadOffset; + + if (!IoAllocateMdl(Buffer, ReadLength, FALSE, FALSE, Irp)) + { + DPRINT("IoAllocateMdl failed\n"); + IoFreeIrp(Irp); + return STATUS_UNSUCCESSFUL; + } + + IoBuildPartialMdl(IrpContext->Irp->MdlAddress, Irp->MdlAddress, Buffer, ReadLength); + + IoSetCompletionRoutine(Irp, + VfatReadWritePartialCompletion, + IrpContext, + TRUE, + TRUE, + TRUE); + + if (Wait) + { + KeInitializeEvent(&IrpContext->Event, NotificationEvent, FALSE); + IrpContext->RefCount = 1; + } + else + { + InterlockedIncrement((PLONG)&IrpContext->RefCount); + } + + DPRINT ("Calling IO Driver... with irp %p\n", Irp); + Status = IoCallDriver (IrpContext->DeviceExt->StorageDevice, Irp); + + if (Wait && Status == STATUS_PENDING) + { + KeWaitForSingleObject(&IrpContext->Event, Executive, KernelMode, FALSE, NULL); + Status = IrpContext->Irp->IoStatus.Status; + } + + DPRINT("%x\n", Status); + return Status; +} + + +NTSTATUS +VfatWriteDiskPartial (IN PVFAT_IRP_CONTEXT IrpContext, + IN PLARGE_INTEGER WriteOffset, + IN ULONG WriteLength, + IN ULONG BufferOffset, + IN BOOLEAN Wait) +{ + PIRP Irp; + PIO_STACK_LOCATION StackPtr; + NTSTATUS Status; + PVOID Buffer; + + DPRINT ("VfatWriteDiskPartial(IrpContext %p, WriteOffset %I64x, WriteLength %d, BufferOffset %x, Wait %d)\n", + IrpContext, WriteOffset->QuadPart, WriteLength, BufferOffset, Wait); + + Buffer = (PCHAR)MmGetMdlVirtualAddress(IrpContext->Irp->MdlAddress) + BufferOffset; + + DPRINT ("Building asynchronous FSD Request...\n"); + Irp = IoAllocateIrp(IrpContext->DeviceExt->StorageDevice->StackSize, TRUE); + if (Irp == NULL) + { + DPRINT("IoAllocateIrp failed\n"); + return(STATUS_UNSUCCESSFUL); + } + + Irp->UserIosb = NULL; + Irp->Tail.Overlay.Thread = PsGetCurrentThread(); + + StackPtr = IoGetNextIrpStackLocation(Irp); + StackPtr->MajorFunction = IRP_MJ_WRITE; + StackPtr->MinorFunction = 0; + StackPtr->Flags = 0; + StackPtr->Control = 0; + StackPtr->DeviceObject = IrpContext->DeviceExt->StorageDevice; + StackPtr->FileObject = NULL; + StackPtr->CompletionRoutine = NULL; + StackPtr->Parameters.Read.Length = WriteLength; + StackPtr->Parameters.Read.ByteOffset = *WriteOffset; + + if (!IoAllocateMdl(Buffer, WriteLength, FALSE, FALSE, Irp)) + { + DPRINT("IoAllocateMdl failed\n"); + IoFreeIrp(Irp); + return STATUS_UNSUCCESSFUL; + } + IoBuildPartialMdl(IrpContext->Irp->MdlAddress, Irp->MdlAddress, Buffer, WriteLength); + + IoSetCompletionRoutine(Irp, + VfatReadWritePartialCompletion, + IrpContext, + TRUE, + TRUE, + TRUE); + + if (Wait) + { + KeInitializeEvent(&IrpContext->Event, NotificationEvent, FALSE); + IrpContext->RefCount = 1; + } + else + { + InterlockedIncrement((PLONG)&IrpContext->RefCount); + } + + + DPRINT ("Calling IO Driver...\n"); + Status = IoCallDriver (IrpContext->DeviceExt->StorageDevice, Irp); + if (Wait && Status == STATUS_PENDING) + { + KeWaitForSingleObject(&IrpContext->Event, Executive, KernelMode, FALSE, NULL); + Status = IrpContext->Irp->IoStatus.Status; + } + + return Status; +} + +NTSTATUS +VfatBlockDeviceIoControl (IN PDEVICE_OBJECT DeviceObject, + IN ULONG CtlCode, + IN PVOID InputBuffer OPTIONAL, + IN ULONG InputBufferSize, + IN OUT PVOID OutputBuffer OPTIONAL, + IN OUT PULONG OutputBufferSize, + IN BOOLEAN Override) +{ + PIO_STACK_LOCATION Stack; + KEVENT Event; + PIRP Irp; + IO_STATUS_BLOCK IoStatus; + NTSTATUS Status; + + DPRINT("VfatBlockDeviceIoControl(DeviceObject %p, CtlCode %x, " + "InputBuffer %p, InputBufferSize %x, OutputBuffer %p, " + "OutputBufferSize %p (%x)\n", DeviceObject, CtlCode, + InputBuffer, InputBufferSize, OutputBuffer, OutputBufferSize, + OutputBufferSize ? *OutputBufferSize : 0); + + KeInitializeEvent (&Event, NotificationEvent, FALSE); + + DPRINT("Building device I/O control request ...\n"); + Irp = IoBuildDeviceIoControlRequest(CtlCode, + DeviceObject, + InputBuffer, + InputBufferSize, + OutputBuffer, + (OutputBufferSize) ? *OutputBufferSize : 0, + FALSE, + &Event, + &IoStatus); + if (Irp == NULL) + { + DPRINT("IoBuildDeviceIoControlRequest failed\n"); + return STATUS_INSUFFICIENT_RESOURCES; + } + + if (Override) + { + Stack = IoGetNextIrpStackLocation(Irp); + Stack->Flags |= SL_OVERRIDE_VERIFY_VOLUME; + } + + DPRINT ("Calling IO Driver... with irp %p\n", Irp); + Status = IoCallDriver(DeviceObject, Irp); + + DPRINT ("Waiting for IO Operation for %p\n", Irp); + if (Status == STATUS_PENDING) + { + DPRINT ("Operation pending\n"); + KeWaitForSingleObject (&Event, Suspended, KernelMode, FALSE, NULL); + DPRINT ("Getting IO Status... for %p\n", Irp); + + Status = IoStatus.Status; + } + + if (OutputBufferSize) + { + *OutputBufferSize = IoStatus.Information; + } + + DPRINT("Returning Status %x\n", Status); + + return Status; +} diff --git a/reactos/drivers/filesystems/fastfat_new/cleanup.c b/reactos/drivers/filesystems/fastfat_new/cleanup.c new file mode 100644 index 00000000000..f05c116c418 --- /dev/null +++ b/reactos/drivers/filesystems/fastfat_new/cleanup.c @@ -0,0 +1,144 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: drivers/fs/vfat/cleanup.c + * PURPOSE: VFAT Filesystem + * PROGRAMMER: Jason Filby (jasonfilby@yahoo.com) + */ + +/* INCLUDES *****************************************************************/ + +#define NDEBUG +#include "vfat.h" + +/* FUNCTIONS ****************************************************************/ + +/* + * FUNCTION: Cleans up after a file has been closed. + */ +static NTSTATUS +VfatCleanupFile(PVFAT_IRP_CONTEXT IrpContext) +{ + PVFATFCB pFcb; + PFILE_OBJECT FileObject = IrpContext->FileObject; + + DPRINT("VfatCleanupFile(DeviceExt %p, FileObject %p)\n", + IrpContext->DeviceExt, FileObject); + + /* FIXME: handle file/directory deletion here */ + pFcb = (PVFATFCB) FileObject->FsContext; + if (!pFcb) + return STATUS_SUCCESS; + + if (pFcb->Flags & FCB_IS_VOLUME) + { + pFcb->OpenHandleCount--; + + if (pFcb->OpenHandleCount != 0) + { + IoRemoveShareAccess(FileObject, &pFcb->FCBShareAccess); + } + } + else + { + if(!ExAcquireResourceExclusiveLite (&pFcb->MainResource, + (BOOLEAN)(IrpContext->Flags & IRPCONTEXT_CANWAIT))) + { + return STATUS_PENDING; + } + if(!ExAcquireResourceExclusiveLite (&pFcb->PagingIoResource, + (BOOLEAN)(IrpContext->Flags & IRPCONTEXT_CANWAIT))) + { + ExReleaseResourceLite (&pFcb->MainResource); + return STATUS_PENDING; + } + + pFcb->OpenHandleCount--; + + if (!(*pFcb->Attributes & FILE_ATTRIBUTE_DIRECTORY) && + FsRtlAreThereCurrentFileLocks(&pFcb->FileLock)) + { + /* remove all locks this process have on this file */ + FsRtlFastUnlockAll(&pFcb->FileLock, + FileObject, + IoGetRequestorProcess(IrpContext->Irp), + NULL); + } + + if (pFcb->Flags & FCB_IS_DIRTY) + { + VfatUpdateEntry (pFcb); + } + + if (pFcb->Flags & FCB_DELETE_PENDING && + pFcb->OpenHandleCount == 0) + { + PFILE_OBJECT tmpFileObject; + tmpFileObject = pFcb->FileObject; + if (tmpFileObject != NULL) + { + pFcb->FileObject = NULL; + CcUninitializeCacheMap(tmpFileObject, NULL, NULL); + ObDereferenceObject(tmpFileObject); + } + + CcPurgeCacheSection(FileObject->SectionObjectPointer, NULL, 0, FALSE); + } + + /* Uninitialize the cache (should be done even if caching was never initialized) */ + CcUninitializeCacheMap(FileObject, &pFcb->RFCB.FileSize, NULL); + + if (pFcb->OpenHandleCount != 0) + { + IoRemoveShareAccess(FileObject, &pFcb->FCBShareAccess); + } + + FileObject->Flags |= FO_CLEANUP_COMPLETE; + + ExReleaseResourceLite (&pFcb->PagingIoResource); + ExReleaseResourceLite (&pFcb->MainResource); + } + + return STATUS_SUCCESS; +} + +/* + * FUNCTION: Cleans up after a file has been closed. + */ +NTSTATUS VfatCleanup(PVFAT_IRP_CONTEXT IrpContext) +{ + NTSTATUS Status; + + DPRINT("VfatCleanup(DeviceObject %p, Irp %p)\n", IrpContext->DeviceObject, IrpContext->Irp); + + if (IrpContext->DeviceObject == VfatGlobalData->DeviceObject) + { + Status = STATUS_SUCCESS; + goto ByeBye; + } + + if (!ExAcquireResourceExclusiveLite (&IrpContext->DeviceExt->DirResource, + (BOOLEAN)(IrpContext->Flags & IRPCONTEXT_CANWAIT))) + { + return VfatQueueRequest (IrpContext); + } + + Status = VfatCleanupFile(IrpContext); + + ExReleaseResourceLite (&IrpContext->DeviceExt->DirResource); + + if (Status == STATUS_PENDING) + { + return VfatQueueRequest(IrpContext); + } + +ByeBye: + IrpContext->Irp->IoStatus.Status = Status; + IrpContext->Irp->IoStatus.Information = 0; + + IoCompleteRequest (IrpContext->Irp, IO_NO_INCREMENT); + VfatFreeIrpContext(IrpContext); + return (Status); +} + +/* EOF */ diff --git a/reactos/drivers/filesystems/fastfat_new/close.c b/reactos/drivers/filesystems/fastfat_new/close.c new file mode 100644 index 00000000000..61c4707a300 --- /dev/null +++ b/reactos/drivers/filesystems/fastfat_new/close.c @@ -0,0 +1,110 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: drivers/fs/vfat/close.c + * PURPOSE: VFAT Filesystem + * PROGRAMMER: Jason Filby (jasonfilby@yahoo.com) + */ + +/* INCLUDES *****************************************************************/ + +#define NDEBUG +#include "vfat.h" + +/* FUNCTIONS ****************************************************************/ + +NTSTATUS +VfatCloseFile (PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject) +/* + * FUNCTION: Closes a file + */ +{ + PVFATFCB pFcb; + PVFATCCB pCcb; + NTSTATUS Status = STATUS_SUCCESS; + + DPRINT ("VfatCloseFile(DeviceExt %p, FileObject %p)\n", + DeviceExt, FileObject); + + /* FIXME : update entry in directory? */ + pCcb = (PVFATCCB) (FileObject->FsContext2); + pFcb = (PVFATFCB) (FileObject->FsContext); + + if (pFcb == NULL) + { + return STATUS_SUCCESS; + } + + if (pFcb->Flags & FCB_IS_VOLUME) + { + DPRINT1("Volume\n"); + pFcb->RefCount--; + FileObject->FsContext2 = NULL; + } + else + { + if (FileObject->DeletePending) + { + if (pFcb->Flags & FCB_DELETE_PENDING) + { + VfatDelEntry (DeviceExt, pFcb); + } + else + { + Status = STATUS_DELETE_PENDING; + } + } + vfatReleaseFCB (DeviceExt, pFcb); + } + + FileObject->FsContext2 = NULL; + FileObject->FsContext = NULL; + FileObject->SectionObjectPointer = NULL; + + if (pCcb) + { + vfatDestroyCCB(pCcb); + } + + return Status; +} + +NTSTATUS VfatClose (PVFAT_IRP_CONTEXT IrpContext) +/* + * FUNCTION: Closes a file + */ +{ + NTSTATUS Status; + + DPRINT ("VfatClose(DeviceObject %p, Irp %p)\n", IrpContext->DeviceObject, IrpContext->Irp); + + if (IrpContext->DeviceObject == VfatGlobalData->DeviceObject) + { + DPRINT("Closing file system\n"); + Status = STATUS_SUCCESS; + goto ByeBye; + } +#if 0 + /* There occurs a dead look at the call to CcRosDeleteFileCache/ObDereferenceObject/VfatClose + in CmLazyCloseThreadMain if VfatClose is execute asynchronous in a worker thread. */ + if (!ExAcquireResourceExclusiveLite (&IrpContext->DeviceExt->DirResource, IrpContext->Flags & IRPCONTEXT_CANWAIT)) +#else + if (!ExAcquireResourceExclusiveLite (&IrpContext->DeviceExt->DirResource, TRUE)) +#endif + { + return VfatQueueRequest (IrpContext); + } + + Status = VfatCloseFile (IrpContext->DeviceExt, IrpContext->FileObject); + ExReleaseResourceLite (&IrpContext->DeviceExt->DirResource); + +ByeBye: + IrpContext->Irp->IoStatus.Status = Status; + IrpContext->Irp->IoStatus.Information = 0; + IoCompleteRequest (IrpContext->Irp, IO_NO_INCREMENT); + VfatFreeIrpContext(IrpContext); + + return (Status); +} + +/* EOF */ diff --git a/reactos/drivers/filesystems/fastfat_new/create.c b/reactos/drivers/filesystems/fastfat_new/create.c new file mode 100644 index 00000000000..664eec21ed2 --- /dev/null +++ b/reactos/drivers/filesystems/fastfat_new/create.c @@ -0,0 +1,801 @@ +/* + * ReactOS kernel + * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/* + * PROJECT: ReactOS kernel + * FILE: drivers/fs/vfat/create.c + * PURPOSE: VFAT Filesystem + * PROGRAMMER: Jason Filby (jasonfilby@yahoo.com) + */ + +/* INCLUDES *****************************************************************/ + +#define NDEBUG +#include "vfat.h" + +/* FUNCTIONS *****************************************************************/ + +void +vfat8Dot3ToString (PFAT_DIR_ENTRY pEntry, PUNICODE_STRING NameU) +{ + OEM_STRING StringA; + USHORT Length; + CHAR cString[12]; + + RtlCopyMemory(cString, pEntry->ShortName, 11); + cString[11] = 0; + if (cString[0] == 0x05) + { + cString[0] = 0xe5; + } + + StringA.Buffer = cString; + for (StringA.Length = 0; + StringA.Length < 8 && StringA.Buffer[StringA.Length] != ' '; + StringA.Length++); + StringA.MaximumLength = StringA.Length; + + RtlOemStringToUnicodeString(NameU, &StringA, FALSE); + + if (pEntry->lCase & VFAT_CASE_LOWER_BASE) + { + RtlDowncaseUnicodeString(NameU, NameU, FALSE); + } + if (cString[8] != ' ') + { + Length = NameU->Length; + NameU->Buffer += Length / sizeof(WCHAR); + if (!FAT_ENTRY_VOLUME(pEntry)) + { + Length += sizeof(WCHAR); + NameU->Buffer[0] = L'.'; + NameU->Buffer++; + } + NameU->Length = 0; + NameU->MaximumLength -= Length; + + StringA.Buffer = &cString[8]; + for (StringA.Length = 0; + StringA.Length < 3 && StringA.Buffer[StringA.Length] != ' '; + StringA.Length++); + StringA.MaximumLength = StringA.Length; + RtlOemStringToUnicodeString(NameU, &StringA, FALSE); + if (pEntry->lCase & VFAT_CASE_LOWER_EXT) + { + RtlDowncaseUnicodeString(NameU, NameU, FALSE); + } + NameU->Buffer -= Length / sizeof(WCHAR); + NameU->Length += Length; + NameU->MaximumLength += Length; + } + NameU->Buffer[NameU->Length / sizeof(WCHAR)] = 0; + DPRINT("'%wZ'\n", NameU); +} + +NTSTATUS +ReadVolumeLabel (PDEVICE_EXTENSION DeviceExt, PVPB Vpb) +/* + * FUNCTION: Read the volume label + */ +{ + PVOID Context = NULL; + ULONG DirIndex = 0; + PDIR_ENTRY Entry; + PVFATFCB pFcb; + LARGE_INTEGER FileOffset; + UNICODE_STRING NameU; + ULONG SizeDirEntry; + ULONG EntriesPerPage; + OEM_STRING StringO; + + NameU.Buffer = Vpb->VolumeLabel; + NameU.Length = 0; + NameU.MaximumLength = sizeof(Vpb->VolumeLabel); + *(Vpb->VolumeLabel) = 0; + Vpb->VolumeLabelLength = 0; + + if (DeviceExt->Flags & VCB_IS_FATX) + { + SizeDirEntry = sizeof(FATX_DIR_ENTRY); + EntriesPerPage = FATX_ENTRIES_PER_PAGE; + } + else + { + SizeDirEntry = sizeof(FAT_DIR_ENTRY); + EntriesPerPage = FAT_ENTRIES_PER_PAGE; + } + + ExAcquireResourceExclusiveLite (&DeviceExt->DirResource, TRUE); + pFcb = vfatOpenRootFCB (DeviceExt); + ExReleaseResourceLite (&DeviceExt->DirResource); + + FileOffset.QuadPart = 0; + if (CcMapData(pFcb->FileObject, &FileOffset, PAGE_SIZE, TRUE, &Context, (PVOID*)&Entry)) + { + while (TRUE) + { + if (ENTRY_VOLUME(DeviceExt, Entry)) + { + /* copy volume label */ + if (DeviceExt->Flags & VCB_IS_FATX) + { + StringO.Buffer = (PCHAR)Entry->FatX.Filename; + StringO.MaximumLength = StringO.Length = Entry->FatX.FilenameLength; + RtlOemStringToUnicodeString(&NameU, &StringO, FALSE); + } + else + { + vfat8Dot3ToString (&Entry->Fat, &NameU); + } + Vpb->VolumeLabelLength = NameU.Length; + break; + } + if (ENTRY_END(DeviceExt, Entry)) + { + break; + } + DirIndex++; + Entry = (PDIR_ENTRY)((ULONG_PTR)Entry + SizeDirEntry); + if ((DirIndex % EntriesPerPage) == 0) + { + CcUnpinData(Context); + FileOffset.u.LowPart += PAGE_SIZE; + if (!CcMapData(pFcb->FileObject, &FileOffset, PAGE_SIZE, TRUE, &Context, (PVOID*)&Entry)) + { + Context = NULL; + break; + } + } + } + if (Context) + { + CcUnpinData(Context); + } + } + ExAcquireResourceExclusiveLite (&DeviceExt->DirResource, TRUE); + vfatReleaseFCB (DeviceExt, pFcb); + ExReleaseResourceLite (&DeviceExt->DirResource); + + return STATUS_SUCCESS; +} + +NTSTATUS +FindFile ( + PDEVICE_EXTENSION DeviceExt, + PVFATFCB Parent, + PUNICODE_STRING FileToFindU, + PVFAT_DIRENTRY_CONTEXT DirContext, + BOOLEAN First) +/* + * FUNCTION: Find a file + */ +{ + PWCHAR PathNameBuffer; + USHORT PathNameBufferLength; + NTSTATUS Status; + PVOID Context = NULL; + PVOID Page; + PVFATFCB rcFcb; + BOOLEAN Found; + UNICODE_STRING PathNameU; + UNICODE_STRING FileToFindUpcase; + BOOLEAN WildCard; + + DPRINT ("FindFile(Parent %p, FileToFind '%wZ', DirIndex: %d)\n", + Parent, FileToFindU, DirContext->DirIndex); + DPRINT ("FindFile: Path %wZ\n",&Parent->PathNameU); + + PathNameBufferLength = LONGNAME_MAX_LENGTH * sizeof(WCHAR); + PathNameBuffer = ExAllocatePoolWithTag(NonPagedPool, PathNameBufferLength + sizeof(WCHAR), TAG_VFAT); + if (!PathNameBuffer) + { + return STATUS_INSUFFICIENT_RESOURCES; + } + + PathNameU.Buffer = PathNameBuffer; + PathNameU.Length = 0; + PathNameU.MaximumLength = PathNameBufferLength; + + DirContext->LongNameU.Length = 0; + DirContext->ShortNameU.Length = 0; + + WildCard = FsRtlDoesNameContainWildCards(FileToFindU); + + if (WildCard == FALSE) + { + /* if there is no '*?' in the search name, than look first for an existing fcb */ + RtlCopyUnicodeString(&PathNameU, &Parent->PathNameU); + if (!vfatFCBIsRoot(Parent)) + { + PathNameU.Buffer[PathNameU.Length / sizeof(WCHAR)] = L'\\'; + PathNameU.Length += sizeof(WCHAR); + } + RtlAppendUnicodeStringToString(&PathNameU, FileToFindU); + PathNameU.Buffer[PathNameU.Length / sizeof(WCHAR)] = 0; + rcFcb = vfatGrabFCBFromTable(DeviceExt, &PathNameU); + if (rcFcb) + { + ULONG startIndex = rcFcb->startIndex; + if ((rcFcb->Flags & FCB_IS_FATX_ENTRY) && !vfatFCBIsRoot(Parent)) + { + startIndex += 2; + } + if(startIndex >= DirContext->DirIndex) + { + RtlCopyUnicodeString(&DirContext->LongNameU, &rcFcb->LongNameU); + RtlCopyUnicodeString(&DirContext->ShortNameU, &rcFcb->ShortNameU); + RtlCopyMemory(&DirContext->DirEntry, &rcFcb->entry, sizeof(DIR_ENTRY)); + DirContext->StartIndex = rcFcb->startIndex; + DirContext->DirIndex = rcFcb->dirIndex; + DPRINT("FindFile: new Name %wZ, DirIndex %d (%d)\n", + &DirContext->LongNameU, DirContext->DirIndex, DirContext->StartIndex); + Status = STATUS_SUCCESS; + } + else + { + DPRINT("FCB not found for %wZ\n", &PathNameU); + Status = STATUS_UNSUCCESSFUL; + } + vfatReleaseFCB(DeviceExt, rcFcb); + ExFreePool(PathNameBuffer); + return Status; + } + } + + /* FsRtlIsNameInExpression need the searched string to be upcase, + * even if IgnoreCase is specified */ + Status = RtlUpcaseUnicodeString(&FileToFindUpcase, FileToFindU, TRUE); + if (!NT_SUCCESS(Status)) + { + ExFreePool(PathNameBuffer); + return Status; + } + + while(TRUE) + { + Status = DeviceExt->GetNextDirEntry(&Context, &Page, Parent, DirContext, First); + First = FALSE; + if (Status == STATUS_NO_MORE_ENTRIES) + { + break; + } + if (ENTRY_VOLUME(DeviceExt, &DirContext->DirEntry)) + { + DirContext->DirIndex++; + continue; + } + if (WildCard) + { + Found = FsRtlIsNameInExpression(&FileToFindUpcase, &DirContext->LongNameU, TRUE, NULL) || + FsRtlIsNameInExpression(&FileToFindUpcase, &DirContext->ShortNameU, TRUE, NULL); + } + else + { + Found = FsRtlAreNamesEqual(&DirContext->LongNameU, FileToFindU, TRUE, NULL) || + FsRtlAreNamesEqual(&DirContext->ShortNameU, FileToFindU, TRUE, NULL); + } + + if (Found) + { + if (WildCard) + { + RtlCopyUnicodeString(&PathNameU, &Parent->PathNameU); + if (!vfatFCBIsRoot(Parent)) + { + PathNameU.Buffer[PathNameU.Length / sizeof(WCHAR)] = L'\\'; + PathNameU.Length += sizeof(WCHAR); + } + RtlAppendUnicodeStringToString(&PathNameU, &DirContext->LongNameU); + PathNameU.Buffer[PathNameU.Length / sizeof(WCHAR)] = 0; + rcFcb = vfatGrabFCBFromTable(DeviceExt, &PathNameU); + if (rcFcb != NULL) + { + RtlCopyMemory(&DirContext->DirEntry, &rcFcb->entry, sizeof(DIR_ENTRY)); + vfatReleaseFCB(DeviceExt, rcFcb); + } + } + DPRINT("%d\n", DirContext->LongNameU.Length); + DPRINT("FindFile: new Name %wZ, DirIndex %d\n", + &DirContext->LongNameU, DirContext->DirIndex); + + if (Context) + { + CcUnpinData(Context); + } + RtlFreeUnicodeString(&FileToFindUpcase); + ExFreePool(PathNameBuffer); + return STATUS_SUCCESS; + } + DirContext->DirIndex++; + } + + if (Context) + { + CcUnpinData(Context); + } + + RtlFreeUnicodeString(&FileToFindUpcase); + ExFreePool(PathNameBuffer); + return Status; +} + +static +NTSTATUS +VfatOpenFile ( + PDEVICE_EXTENSION DeviceExt, + PUNICODE_STRING PathNameU, + PFILE_OBJECT FileObject, + PVFATFCB* ParentFcb ) +/* + * FUNCTION: Opens a file + */ +{ + PVFATFCB Fcb; + NTSTATUS Status; + + DPRINT ("VfatOpenFile(%p, '%wZ', %p, %p)\n", DeviceExt, PathNameU, FileObject, ParentFcb); + + if (FileObject->RelatedFileObject) + { + DPRINT ("'%wZ'\n", &FileObject->RelatedFileObject->FileName); + + *ParentFcb = FileObject->RelatedFileObject->FsContext; + (*ParentFcb)->RefCount++; + } + else + { + *ParentFcb = NULL; + } + + if (!DeviceExt->FatInfo.FixedMedia) + { + Status = VfatBlockDeviceIoControl (DeviceExt->StorageDevice, + IOCTL_DISK_CHECK_VERIFY, + NULL, + 0, + NULL, + 0, + FALSE); + + if (Status == STATUS_VERIFY_REQUIRED) + + { + PDEVICE_OBJECT DeviceToVerify; + + DPRINT ("Media change detected!\n"); + DPRINT ("Device %p\n", DeviceExt->StorageDevice); + + /* Find the device to verify and reset the thread field to empty value again. */ + DeviceToVerify = IoGetDeviceToVerify (PsGetCurrentThread ()); + IoSetDeviceToVerify (PsGetCurrentThread (), NULL); + Status = IoVerifyVolume (DeviceToVerify, + FALSE); + } + if (!NT_SUCCESS(Status)) + { + DPRINT ("Status %lx\n", Status); + *ParentFcb = NULL; + return Status; + } + } + + if (*ParentFcb) + { + (*ParentFcb)->RefCount++; + } + + /* try first to find an existing FCB in memory */ + DPRINT ("Checking for existing FCB in memory\n"); + + Status = vfatGetFCBForFile (DeviceExt, ParentFcb, &Fcb, PathNameU); + if (!NT_SUCCESS (Status)) + { + DPRINT ("Could not make a new FCB, status: %x\n", Status); + return Status; + } + if (Fcb->Flags & FCB_DELETE_PENDING) + { + vfatReleaseFCB (DeviceExt, Fcb); + return STATUS_DELETE_PENDING; + } + DPRINT ("Attaching FCB to fileObject\n"); + Status = vfatAttachFCBToFileObject (DeviceExt, Fcb, FileObject); + if (!NT_SUCCESS(Status)) + { + vfatReleaseFCB (DeviceExt, Fcb); + } + return Status; +} + +static NTSTATUS +VfatCreateFile ( PDEVICE_OBJECT DeviceObject, PIRP Irp ) +/* + * FUNCTION: Create or open a file + */ +{ + PIO_STACK_LOCATION Stack; + PFILE_OBJECT FileObject; + NTSTATUS Status = STATUS_SUCCESS; + PDEVICE_EXTENSION DeviceExt; + ULONG RequestedDisposition, RequestedOptions; + PVFATCCB pCcb; + PVFATFCB pFcb = NULL; + PVFATFCB ParentFcb = NULL; + PWCHAR c, last; + BOOLEAN PagingFileCreate = FALSE; + BOOLEAN Dots; + UNICODE_STRING FileNameU; + UNICODE_STRING PathNameU; + + /* Unpack the various parameters. */ + Stack = IoGetCurrentIrpStackLocation (Irp); + RequestedDisposition = ((Stack->Parameters.Create.Options >> 24) & 0xff); + RequestedOptions = + Stack->Parameters.Create.Options & FILE_VALID_OPTION_FLAGS; + PagingFileCreate = (Stack->Flags & SL_OPEN_PAGING_FILE) ? TRUE : FALSE; + FileObject = Stack->FileObject; + DeviceExt = DeviceObject->DeviceExtension; + + /* Check their validity. */ + if (RequestedOptions & FILE_DIRECTORY_FILE && + RequestedDisposition == FILE_SUPERSEDE) + { + return(STATUS_INVALID_PARAMETER); + } + + if (RequestedOptions & FILE_DIRECTORY_FILE && + RequestedOptions & FILE_NON_DIRECTORY_FILE) + { + return(STATUS_INVALID_PARAMETER); + } + + /* This a open operation for the volume itself */ + if (FileObject->FileName.Length == 0 && + FileObject->RelatedFileObject == NULL) + { + if (RequestedDisposition == FILE_CREATE || + RequestedDisposition == FILE_OVERWRITE_IF || + RequestedDisposition == FILE_SUPERSEDE) + { + return(STATUS_ACCESS_DENIED); + } + if (RequestedOptions & FILE_DIRECTORY_FILE) + { + return(STATUS_NOT_A_DIRECTORY); + } + pFcb = DeviceExt->VolumeFcb; + pCcb = ExAllocateFromNPagedLookasideList(&VfatGlobalData->CcbLookasideList); + if (pCcb == NULL) + { + return (STATUS_INSUFFICIENT_RESOURCES); + } + RtlZeroMemory(pCcb, sizeof(VFATCCB)); + FileObject->SectionObjectPointer = &pFcb->SectionObjectPointers; + FileObject->FsContext = pFcb; + FileObject->FsContext2 = pCcb; + pFcb->RefCount++; + + Irp->IoStatus.Information = FILE_OPENED; + return(STATUS_SUCCESS); + } + + /* + * Check for illegal characters and illegale dot sequences in the file name + */ + PathNameU = FileObject->FileName; + c = PathNameU.Buffer + PathNameU.Length / sizeof(WCHAR); + last = c - 1; + Dots = TRUE; + while (c-- > PathNameU.Buffer) + { + if (*c == L'\\' || c == PathNameU.Buffer) + { + if (Dots && last > c) + { + return(STATUS_OBJECT_NAME_INVALID); + } + last = c - 1; + Dots = TRUE; + } + else if (*c != L'.') + { + Dots = FALSE; + } + + if (*c != '\\' && vfatIsLongIllegal(*c)) + { + return(STATUS_OBJECT_NAME_INVALID); + } + } + if (FileObject->RelatedFileObject && PathNameU.Buffer[0] == L'\\') + { + return(STATUS_OBJECT_NAME_INVALID); + } + if (PathNameU.Length > sizeof(WCHAR) && PathNameU.Buffer[PathNameU.Length/sizeof(WCHAR)-1] == L'\\') + { + PathNameU.Length -= sizeof(WCHAR); + } + + /* Try opening the file. */ + Status = VfatOpenFile (DeviceExt, &PathNameU, FileObject, &ParentFcb); + + /* + * If the directory containing the file to open doesn't exist then + * fail immediately + */ + if (Status == STATUS_OBJECT_PATH_NOT_FOUND || + Status == STATUS_INVALID_PARAMETER || + Status == STATUS_DELETE_PENDING) + { + if (ParentFcb) + { + vfatReleaseFCB (DeviceExt, ParentFcb); + } + return(Status); + } + if (!NT_SUCCESS(Status) && ParentFcb == NULL) + { + DPRINT1("VfatOpenFile faild for '%wZ', status %x\n", &PathNameU, Status); + return Status; + } + + /* + * If the file open failed then create the required file + */ + if (!NT_SUCCESS (Status)) + { + if (RequestedDisposition == FILE_CREATE || + RequestedDisposition == FILE_OPEN_IF || + RequestedDisposition == FILE_OVERWRITE_IF || + RequestedDisposition == FILE_SUPERSEDE) + { + ULONG Attributes; + Attributes = Stack->Parameters.Create.FileAttributes; + + vfatSplitPathName(&PathNameU, NULL, &FileNameU); + Status = VfatAddEntry (DeviceExt, &FileNameU, &pFcb, ParentFcb, RequestedOptions, + (UCHAR)(Attributes & FILE_ATTRIBUTE_VALID_FLAGS)); + vfatReleaseFCB (DeviceExt, ParentFcb); + if (NT_SUCCESS (Status)) + { + Status = vfatAttachFCBToFileObject (DeviceExt, pFcb, FileObject); + if ( !NT_SUCCESS(Status) ) + { + vfatReleaseFCB (DeviceExt, pFcb); + return Status; + } + + Irp->IoStatus.Information = FILE_CREATED; + VfatSetAllocationSizeInformation(FileObject, + pFcb, + DeviceExt, + &Irp->Overlay.AllocationSize); + VfatSetExtendedAttributes(FileObject, + Irp->AssociatedIrp.SystemBuffer, + Stack->Parameters.Create.EaLength); + + if (PagingFileCreate) + { + pFcb->Flags |= FCB_IS_PAGE_FILE; + } + } + else + { + return(Status); + } + } + else + { + if (ParentFcb) + { + vfatReleaseFCB (DeviceExt, ParentFcb); + } + return(Status); + } + } + else + { + if (ParentFcb) + { + vfatReleaseFCB (DeviceExt, ParentFcb); + } + /* Otherwise fail if the caller wanted to create a new file */ + if (RequestedDisposition == FILE_CREATE) + { + Irp->IoStatus.Information = FILE_EXISTS; + VfatCloseFile (DeviceExt, FileObject); + return(STATUS_OBJECT_NAME_COLLISION); + } + + pFcb = FileObject->FsContext; + + if (pFcb->OpenHandleCount != 0) + { + Status = IoCheckShareAccess(Stack->Parameters.Create.SecurityContext->DesiredAccess, + Stack->Parameters.Create.ShareAccess, + FileObject, + &pFcb->FCBShareAccess, + FALSE); + if (!NT_SUCCESS(Status)) + { + VfatCloseFile (DeviceExt, FileObject); + return(Status); + } + } + + /* + * Check the file has the requested attributes + */ + if (RequestedOptions & FILE_NON_DIRECTORY_FILE && + *pFcb->Attributes & FILE_ATTRIBUTE_DIRECTORY) + { + VfatCloseFile (DeviceExt, FileObject); + return(STATUS_FILE_IS_A_DIRECTORY); + } + if (RequestedOptions & FILE_DIRECTORY_FILE && + !(*pFcb->Attributes & FILE_ATTRIBUTE_DIRECTORY)) + { + VfatCloseFile (DeviceExt, FileObject); + return(STATUS_NOT_A_DIRECTORY); + } +#ifndef USE_ROS_CC_AND_FS + if (!(*pFcb->Attributes & FILE_ATTRIBUTE_DIRECTORY)) + { + if (Stack->Parameters.Create.SecurityContext->DesiredAccess & FILE_WRITE_DATA || + RequestedDisposition == FILE_OVERWRITE || + RequestedDisposition == FILE_OVERWRITE_IF) + { + if (!MmFlushImageSection(&pFcb->SectionObjectPointers, MmFlushForWrite)) + { + DPRINT1("%wZ\n", &pFcb->PathNameU); + DPRINT1("%d %d %d\n", Stack->Parameters.Create.SecurityContext->DesiredAccess & FILE_WRITE_DATA, + RequestedDisposition == FILE_OVERWRITE, RequestedDisposition == FILE_OVERWRITE_IF); + VfatCloseFile (DeviceExt, FileObject); + return STATUS_SHARING_VIOLATION; + } + } + } +#endif + if (PagingFileCreate) + { + /* FIXME: + * Do more checking for page files. It is possible, + * that the file was opened and closed previously + * as a normal cached file. In this case, the cache + * manager has referenced the fileobject and the fcb + * is held in memory. Try to remove the fileobject + * from cache manager and use the fcb. + */ + if (pFcb->RefCount > 1) + { + if(!(pFcb->Flags & FCB_IS_PAGE_FILE)) + { + VfatCloseFile(DeviceExt, FileObject); + return(STATUS_INVALID_PARAMETER); + } + } + else + { + pFcb->Flags |= FCB_IS_PAGE_FILE; + } + } + else + { + if (pFcb->Flags & FCB_IS_PAGE_FILE) + { + VfatCloseFile(DeviceExt, FileObject); + return(STATUS_INVALID_PARAMETER); + } + } + + + if (RequestedDisposition == FILE_OVERWRITE || + RequestedDisposition == FILE_OVERWRITE_IF || + RequestedDisposition == FILE_SUPERSEDE) + { + ExAcquireResourceExclusiveLite(&(pFcb->MainResource), TRUE); + Status = VfatSetAllocationSizeInformation (FileObject, + pFcb, + DeviceExt, + &Irp->Overlay.AllocationSize); + ExReleaseResourceLite(&(pFcb->MainResource)); + if (!NT_SUCCESS (Status)) + { + VfatCloseFile (DeviceExt, FileObject); + return(Status); + } + } + + if (RequestedDisposition == FILE_SUPERSEDE) + { + Irp->IoStatus.Information = FILE_SUPERSEDED; + } + else if (RequestedDisposition == FILE_OVERWRITE || + RequestedDisposition == FILE_OVERWRITE_IF) + { + Irp->IoStatus.Information = FILE_OVERWRITTEN; + } + else + { + Irp->IoStatus.Information = FILE_OPENED; + } + } + + if (pFcb->OpenHandleCount == 0) + { + IoSetShareAccess(Stack->Parameters.Create.SecurityContext->DesiredAccess, + Stack->Parameters.Create.ShareAccess, + FileObject, + &pFcb->FCBShareAccess); + } + else + { + IoUpdateShareAccess( + FileObject, + &pFcb->FCBShareAccess + ); + + } + + pFcb->OpenHandleCount++; + + /* FIXME : test write access if requested */ + + return(Status); +} + + +NTSTATUS +VfatCreate (PVFAT_IRP_CONTEXT IrpContext) +/* + * FUNCTION: Create or open a file + */ +{ + NTSTATUS Status; + + ASSERT(IrpContext); + + if (IrpContext->DeviceObject == VfatGlobalData->DeviceObject) + { + /* DeviceObject represents FileSystem instead of logical volume */ + DPRINT ("FsdCreate called with file system\n"); + IrpContext->Irp->IoStatus.Information = FILE_OPENED; + IrpContext->Irp->IoStatus.Status = STATUS_SUCCESS; + IoCompleteRequest (IrpContext->Irp, IO_DISK_INCREMENT); + VfatFreeIrpContext(IrpContext); + return(STATUS_SUCCESS); + } + + if (!(IrpContext->Flags & IRPCONTEXT_CANWAIT)) + { + return(VfatQueueRequest (IrpContext)); + } + + IrpContext->Irp->IoStatus.Information = 0; + ExAcquireResourceExclusiveLite (&IrpContext->DeviceExt->DirResource, TRUE); + Status = VfatCreateFile (IrpContext->DeviceObject, IrpContext->Irp); + ExReleaseResourceLite (&IrpContext->DeviceExt->DirResource); + + IrpContext->Irp->IoStatus.Status = Status; + IoCompleteRequest (IrpContext->Irp, + (CCHAR)(NT_SUCCESS(Status) ? IO_DISK_INCREMENT : IO_NO_INCREMENT)); + VfatFreeIrpContext(IrpContext); + return(Status); +} + +/* EOF */ diff --git a/reactos/drivers/filesystems/fastfat_new/dir.c b/reactos/drivers/filesystems/fastfat_new/dir.c new file mode 100644 index 00000000000..e94546e6657 --- /dev/null +++ b/reactos/drivers/filesystems/fastfat_new/dir.c @@ -0,0 +1,511 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: drivers/fs/vfat/dir.c + * PURPOSE: VFAT Filesystem : directory control + * UPDATE HISTORY: + 19-12-1998 : created + +*/ + +#define NDEBUG +#include "vfat.h" + + +// function like DosDateTimeToFileTime +BOOLEAN +FsdDosDateTimeToSystemTime (PDEVICE_EXTENSION DeviceExt, USHORT DosDate, USHORT DosTime, PLARGE_INTEGER SystemTime) +{ + PDOSTIME pdtime = (PDOSTIME) &DosTime; + PDOSDATE pddate = (PDOSDATE) &DosDate; + TIME_FIELDS TimeFields; + LARGE_INTEGER LocalTime; + + if (SystemTime == NULL) + return FALSE; + + TimeFields.Milliseconds = 0; + TimeFields.Second = pdtime->Second * 2; + TimeFields.Minute = pdtime->Minute; + TimeFields.Hour = pdtime->Hour; + + TimeFields.Day = pddate->Day; + TimeFields.Month = pddate->Month; + TimeFields.Year = (CSHORT)(DeviceExt->BaseDateYear + pddate->Year); + + RtlTimeFieldsToTime (&TimeFields, &LocalTime); + ExLocalTimeToSystemTime(&LocalTime, SystemTime); + + return TRUE; +} + +// function like FileTimeToDosDateTime +BOOLEAN +FsdSystemTimeToDosDateTime (PDEVICE_EXTENSION DeviceExt, PLARGE_INTEGER SystemTime, USHORT *pDosDate, USHORT *pDosTime) +{ + PDOSTIME pdtime = (PDOSTIME) pDosTime; + PDOSDATE pddate = (PDOSDATE) pDosDate; + TIME_FIELDS TimeFields; + LARGE_INTEGER LocalTime; + + if (SystemTime == NULL) + return FALSE; + + ExSystemTimeToLocalTime (SystemTime, &LocalTime); + RtlTimeToTimeFields (&LocalTime, &TimeFields); + + if (pdtime) + { + pdtime->Second = TimeFields.Second / 2; + pdtime->Minute = TimeFields.Minute; + pdtime->Hour = TimeFields.Hour; + } + + if (pddate) + { + pddate->Day = TimeFields.Day; + pddate->Month = TimeFields.Month; + pddate->Year = (USHORT) (TimeFields.Year - DeviceExt->BaseDateYear); + } + + return TRUE; +} + +#define ULONG_ROUND_UP(x) ROUND_UP((x), (sizeof(ULONG))) + +static NTSTATUS +VfatGetFileNameInformation (PVFAT_DIRENTRY_CONTEXT DirContext, + PFILE_NAMES_INFORMATION pInfo, ULONG BufferLength) +{ + if ((sizeof (FILE_DIRECTORY_INFORMATION) + DirContext->LongNameU.Length) > BufferLength) + return STATUS_BUFFER_OVERFLOW; + pInfo->FileNameLength = DirContext->LongNameU.Length; + pInfo->NextEntryOffset = + ULONG_ROUND_UP (sizeof (FILE_DIRECTORY_INFORMATION) + DirContext->LongNameU.Length); + RtlCopyMemory (pInfo->FileName, DirContext->LongNameU.Buffer, DirContext->LongNameU.Length); + return STATUS_SUCCESS; +} + +static NTSTATUS +VfatGetFileDirectoryInformation (PVFAT_DIRENTRY_CONTEXT DirContext, + PDEVICE_EXTENSION DeviceExt, + PFILE_DIRECTORY_INFORMATION pInfo, + ULONG BufferLength) +{ + if ((sizeof (FILE_DIRECTORY_INFORMATION) + DirContext->LongNameU.Length) > BufferLength) + return STATUS_BUFFER_OVERFLOW; + pInfo->FileNameLength = DirContext->LongNameU.Length; + pInfo->NextEntryOffset = + ULONG_ROUND_UP (sizeof (FILE_DIRECTORY_INFORMATION) + DirContext->LongNameU.Length); + RtlCopyMemory (pInfo->FileName, DirContext->LongNameU.Buffer, DirContext->LongNameU.Length); +// pInfo->FileIndex=; + if (DeviceExt->Flags & VCB_IS_FATX) + { + FsdDosDateTimeToSystemTime (DeviceExt, DirContext->DirEntry.FatX.CreationDate, + DirContext->DirEntry.FatX.CreationTime, + &pInfo->CreationTime); + FsdDosDateTimeToSystemTime (DeviceExt, DirContext->DirEntry.FatX.AccessDate, + DirContext->DirEntry.FatX.AccessTime, + &pInfo->LastAccessTime); + FsdDosDateTimeToSystemTime (DeviceExt, DirContext->DirEntry.FatX.UpdateDate, + DirContext->DirEntry.FatX.UpdateTime, + &pInfo->LastWriteTime); + pInfo->ChangeTime = pInfo->LastWriteTime; + if (DirContext->DirEntry.FatX.Attrib & FILE_ATTRIBUTE_DIRECTORY) + { + pInfo->EndOfFile.QuadPart = 0; + pInfo->AllocationSize.QuadPart = 0; + } + else + { + pInfo->EndOfFile.u.HighPart = 0; + pInfo->EndOfFile.u.LowPart = DirContext->DirEntry.FatX.FileSize; + /* Make allocsize a rounded up multiple of BytesPerCluster */ + pInfo->AllocationSize.u.HighPart = 0; + pInfo->AllocationSize.u.LowPart = ROUND_UP(DirContext->DirEntry.FatX.FileSize, DeviceExt->FatInfo.BytesPerCluster); + } + pInfo->FileAttributes = DirContext->DirEntry.FatX.Attrib & 0x3f; + } + else + { + FsdDosDateTimeToSystemTime (DeviceExt, DirContext->DirEntry.Fat.CreationDate, + DirContext->DirEntry.Fat.CreationTime, + &pInfo->CreationTime); + FsdDosDateTimeToSystemTime (DeviceExt, DirContext->DirEntry.Fat.AccessDate, 0, + &pInfo->LastAccessTime); + FsdDosDateTimeToSystemTime (DeviceExt, DirContext->DirEntry.Fat.UpdateDate, + DirContext->DirEntry.Fat.UpdateTime, + &pInfo->LastWriteTime); + pInfo->ChangeTime = pInfo->LastWriteTime; + if (DirContext->DirEntry.Fat.Attrib & FILE_ATTRIBUTE_DIRECTORY) + { + pInfo->EndOfFile.QuadPart = 0; + pInfo->AllocationSize.QuadPart = 0; + } + else + { + pInfo->EndOfFile.u.HighPart = 0; + pInfo->EndOfFile.u.LowPart = DirContext->DirEntry.Fat.FileSize; + /* Make allocsize a rounded up multiple of BytesPerCluster */ + pInfo->AllocationSize.u.HighPart = 0; + pInfo->AllocationSize.u.LowPart = ROUND_UP(DirContext->DirEntry.Fat.FileSize, DeviceExt->FatInfo.BytesPerCluster); + } + pInfo->FileAttributes = DirContext->DirEntry.Fat.Attrib & 0x3f; + } + + return STATUS_SUCCESS; +} + +static NTSTATUS +VfatGetFileFullDirectoryInformation (PVFAT_DIRENTRY_CONTEXT DirContext, + PDEVICE_EXTENSION DeviceExt, + PFILE_FULL_DIR_INFORMATION pInfo, + ULONG BufferLength) +{ + if ((sizeof (FILE_FULL_DIR_INFORMATION) + DirContext->LongNameU.Length) > BufferLength) + return STATUS_BUFFER_OVERFLOW; + pInfo->FileNameLength = DirContext->LongNameU.Length; + pInfo->NextEntryOffset = + ULONG_ROUND_UP (sizeof (FILE_FULL_DIR_INFORMATION) + DirContext->LongNameU.Length); + RtlCopyMemory (pInfo->FileName, DirContext->LongNameU.Buffer, DirContext->LongNameU.Length); +// pInfo->FileIndex=; + if (DeviceExt->Flags & VCB_IS_FATX) + { + FsdDosDateTimeToSystemTime (DeviceExt, DirContext->DirEntry.FatX.CreationDate, + DirContext->DirEntry.FatX.CreationTime, + &pInfo->CreationTime); + FsdDosDateTimeToSystemTime (DeviceExt, DirContext->DirEntry.FatX.AccessDate, + DirContext->DirEntry.FatX.AccessTime, + &pInfo->LastAccessTime); + FsdDosDateTimeToSystemTime (DeviceExt, DirContext->DirEntry.FatX.UpdateDate, + DirContext->DirEntry.FatX.UpdateTime, + &pInfo->LastWriteTime); + pInfo->ChangeTime = pInfo->LastWriteTime; + pInfo->EndOfFile.u.HighPart = 0; + pInfo->EndOfFile.u.LowPart = DirContext->DirEntry.FatX.FileSize; + /* Make allocsize a rounded up multiple of BytesPerCluster */ + pInfo->AllocationSize.u.HighPart = 0; + pInfo->AllocationSize.u.LowPart = ROUND_UP(DirContext->DirEntry.FatX.FileSize, DeviceExt->FatInfo.BytesPerCluster); + pInfo->FileAttributes = DirContext->DirEntry.FatX.Attrib & 0x3f; + } + else + { + FsdDosDateTimeToSystemTime (DeviceExt, DirContext->DirEntry.Fat.CreationDate, + DirContext->DirEntry.Fat.CreationTime, + &pInfo->CreationTime); + FsdDosDateTimeToSystemTime (DeviceExt, DirContext->DirEntry.Fat.AccessDate, + 0, &pInfo->LastAccessTime); + FsdDosDateTimeToSystemTime (DeviceExt, DirContext->DirEntry.Fat.UpdateDate, + DirContext->DirEntry.Fat.UpdateTime, + &pInfo->LastWriteTime); + pInfo->ChangeTime = pInfo->LastWriteTime; + pInfo->EndOfFile.u.HighPart = 0; + pInfo->EndOfFile.u.LowPart = DirContext->DirEntry.Fat.FileSize; + /* Make allocsize a rounded up multiple of BytesPerCluster */ + pInfo->AllocationSize.u.HighPart = 0; + pInfo->AllocationSize.u.LowPart = ROUND_UP(DirContext->DirEntry.Fat.FileSize, DeviceExt->FatInfo.BytesPerCluster); + pInfo->FileAttributes = DirContext->DirEntry.Fat.Attrib & 0x3f; + } +// pInfo->EaSize=; + return STATUS_SUCCESS; +} + +static NTSTATUS +VfatGetFileBothInformation (PVFAT_DIRENTRY_CONTEXT DirContext, + PDEVICE_EXTENSION DeviceExt, + PFILE_BOTH_DIR_INFORMATION pInfo, + ULONG BufferLength) +{ + if ((sizeof (FILE_BOTH_DIR_INFORMATION) + DirContext->LongNameU.Length) > BufferLength) + return STATUS_BUFFER_OVERFLOW; + + if (DeviceExt->Flags & VCB_IS_FATX) + { + pInfo->FileNameLength = DirContext->LongNameU.Length; + RtlCopyMemory(pInfo->FileName, DirContext->LongNameU.Buffer, DirContext->LongNameU.Length); + pInfo->NextEntryOffset = + ULONG_ROUND_UP (sizeof (FILE_BOTH_DIR_INFORMATION) + DirContext->LongNameU.Length); + pInfo->ShortName[0] = 0; + pInfo->ShortNameLength = 0; + // pInfo->FileIndex=; + FsdDosDateTimeToSystemTime (DeviceExt, DirContext->DirEntry.FatX.CreationDate, + DirContext->DirEntry.FatX.CreationTime, + &pInfo->CreationTime); + FsdDosDateTimeToSystemTime (DeviceExt, DirContext->DirEntry.FatX.AccessDate, + DirContext->DirEntry.FatX.AccessTime, + &pInfo->LastAccessTime); + FsdDosDateTimeToSystemTime (DeviceExt, DirContext->DirEntry.FatX.UpdateDate, + DirContext->DirEntry.FatX.UpdateTime, + &pInfo->LastWriteTime); + pInfo->ChangeTime = pInfo->LastWriteTime; + if (DirContext->DirEntry.FatX.Attrib & FILE_ATTRIBUTE_DIRECTORY) + { + pInfo->EndOfFile.QuadPart = 0; + pInfo->AllocationSize.QuadPart = 0; + } + else + { + pInfo->EndOfFile.u.HighPart = 0; + pInfo->EndOfFile.u.LowPart = DirContext->DirEntry.FatX.FileSize; + /* Make allocsize a rounded up multiple of BytesPerCluster */ + pInfo->AllocationSize.u.HighPart = 0; + pInfo->AllocationSize.u.LowPart = ROUND_UP(DirContext->DirEntry.FatX.FileSize, DeviceExt->FatInfo.BytesPerCluster); + } + pInfo->FileAttributes = DirContext->DirEntry.FatX.Attrib & 0x3f; + } + else + { + pInfo->FileNameLength = DirContext->LongNameU.Length; + pInfo->NextEntryOffset = + ULONG_ROUND_UP (sizeof (FILE_BOTH_DIR_INFORMATION) + DirContext->LongNameU.Length); + RtlCopyMemory(pInfo->ShortName, DirContext->ShortNameU.Buffer, DirContext->ShortNameU.Length); + pInfo->ShortNameLength = (CCHAR)DirContext->ShortNameU.Length; + RtlCopyMemory (pInfo->FileName, DirContext->LongNameU.Buffer, DirContext->LongNameU.Length); + // pInfo->FileIndex=; + FsdDosDateTimeToSystemTime (DeviceExt, DirContext->DirEntry.Fat.CreationDate, + DirContext->DirEntry.Fat.CreationTime, + &pInfo->CreationTime); + FsdDosDateTimeToSystemTime (DeviceExt, DirContext->DirEntry.Fat.AccessDate, 0, + &pInfo->LastAccessTime); + FsdDosDateTimeToSystemTime (DeviceExt, DirContext->DirEntry.Fat.UpdateDate, + DirContext->DirEntry.Fat.UpdateTime, + &pInfo->LastWriteTime); + pInfo->ChangeTime = pInfo->LastWriteTime; + if (DirContext->DirEntry.Fat.Attrib & FILE_ATTRIBUTE_DIRECTORY) + { + pInfo->EndOfFile.QuadPart = 0; + pInfo->AllocationSize.QuadPart = 0; + } + else + { + pInfo->EndOfFile.u.HighPart = 0; + pInfo->EndOfFile.u.LowPart = DirContext->DirEntry.Fat.FileSize; + /* Make allocsize a rounded up multiple of BytesPerCluster */ + pInfo->AllocationSize.u.HighPart = 0; + pInfo->AllocationSize.u.LowPart = ROUND_UP(DirContext->DirEntry.Fat.FileSize, DeviceExt->FatInfo.BytesPerCluster); + } + pInfo->FileAttributes = DirContext->DirEntry.Fat.Attrib & 0x3f; + } + pInfo->EaSize=0; + return STATUS_SUCCESS; +} + +static NTSTATUS DoQuery (PVFAT_IRP_CONTEXT IrpContext) +{ + NTSTATUS RC = STATUS_SUCCESS; + long BufferLength = 0; + PUNICODE_STRING pSearchPattern = NULL; + FILE_INFORMATION_CLASS FileInformationClass; + unsigned char *Buffer = NULL; + PFILE_NAMES_INFORMATION Buffer0 = NULL; + PVFATFCB pFcb; + PVFATCCB pCcb; + BOOLEAN FirstQuery = FALSE; + BOOLEAN FirstCall = TRUE; + VFAT_DIRENTRY_CONTEXT DirContext; + WCHAR LongNameBuffer[LONGNAME_MAX_LENGTH + 1]; + WCHAR ShortNameBuffer[13]; + + PIO_STACK_LOCATION Stack = IrpContext->Stack; + + pCcb = (PVFATCCB) IrpContext->FileObject->FsContext2; + pFcb = (PVFATFCB) IrpContext->FileObject->FsContext; + + // determine Buffer for result : + BufferLength = Stack->Parameters.QueryDirectory.Length; +#if 0 + /* Do not probe the user buffer until SEH is available */ + if (IrpContext->Irp->RequestorMode != KernelMode && + IrpContext->Irp->MdlAddress == NULL && + IrpContext->Irp->UserBuffer != NULL) + { + ProbeForWrite(IrpContext->Irp->UserBuffer, BufferLength, 1); + } +#endif + Buffer = VfatGetUserBuffer(IrpContext->Irp); + + if (!ExAcquireResourceSharedLite(&pFcb->MainResource, + (BOOLEAN)(IrpContext->Flags & IRPCONTEXT_CANWAIT))) + { + RC = VfatLockUserBuffer(IrpContext->Irp, BufferLength, IoWriteAccess); + if (NT_SUCCESS(RC)) + { + RC = STATUS_PENDING; + } + return RC; + } + + /* Obtain the callers parameters */ +#ifdef _MSC_VER + /* HACKHACK: Bug in the MS ntifs.h header: + * FileName is really a PUNICODE_STRING, not a PSTRING */ + pSearchPattern = (PUNICODE_STRING)Stack->Parameters.QueryDirectory.FileName; +#else + pSearchPattern = Stack->Parameters.QueryDirectory.FileName; +#endif + FileInformationClass = + Stack->Parameters.QueryDirectory.FileInformationClass; + if (pSearchPattern) + { + if (!pCcb->SearchPattern.Buffer) + { + FirstQuery = TRUE; + pCcb->SearchPattern.MaximumLength = pSearchPattern->Length + sizeof(WCHAR); + pCcb->SearchPattern.Buffer = ExAllocatePoolWithTag(NonPagedPool, pCcb->SearchPattern.MaximumLength, TAG_VFAT); + if (!pCcb->SearchPattern.Buffer) + { + ExReleaseResourceLite(&pFcb->MainResource); + return STATUS_INSUFFICIENT_RESOURCES; + } + RtlCopyUnicodeString(&pCcb->SearchPattern, pSearchPattern); + pCcb->SearchPattern.Buffer[pCcb->SearchPattern.Length / sizeof(WCHAR)] = 0; + } + } + else if (!pCcb->SearchPattern.Buffer) + { + FirstQuery = TRUE; + pCcb->SearchPattern.MaximumLength = 2 * sizeof(WCHAR); + pCcb->SearchPattern.Buffer = ExAllocatePoolWithTag(NonPagedPool, 2 * sizeof(WCHAR), TAG_VFAT); + if (!pCcb->SearchPattern.Buffer) + { + ExReleaseResourceLite(&pFcb->MainResource); + return STATUS_INSUFFICIENT_RESOURCES; + } + pCcb->SearchPattern.Buffer[0] = L'*'; + pCcb->SearchPattern.Buffer[1] = 0; + pCcb->SearchPattern.Length = sizeof(WCHAR); + } + + if (IrpContext->Stack->Flags & SL_INDEX_SPECIFIED) + { + DirContext.DirIndex = pCcb->Entry = Stack->Parameters.QueryDirectory.FileIndex; + } + else if (FirstQuery || (IrpContext->Stack->Flags & SL_RESTART_SCAN)) + { + DirContext.DirIndex = pCcb->Entry = 0; + } + else + { + DirContext.DirIndex = pCcb->Entry; + } + + DPRINT ("Buffer=%p tofind=%wZ\n", Buffer, &pCcb->SearchPattern); + + DirContext.LongNameU.Buffer = LongNameBuffer; + DirContext.LongNameU.MaximumLength = sizeof(LongNameBuffer); + DirContext.ShortNameU.Buffer = ShortNameBuffer; + DirContext.ShortNameU.MaximumLength = sizeof(ShortNameBuffer); + + while (RC == STATUS_SUCCESS && BufferLength > 0) + { + RC = FindFile (IrpContext->DeviceExt, pFcb, + &pCcb->SearchPattern, &DirContext, FirstCall); + pCcb->Entry = DirContext.DirIndex; + DPRINT ("Found %wZ, RC=%x, entry %x\n", &DirContext.LongNameU, RC, pCcb->Entry); + FirstCall = FALSE; + if (NT_SUCCESS (RC)) + { + switch (FileInformationClass) + { + case FileNameInformation: + RC = VfatGetFileNameInformation (&DirContext, + (PFILE_NAMES_INFORMATION) Buffer, + BufferLength); + break; + case FileDirectoryInformation: + RC = VfatGetFileDirectoryInformation (&DirContext, + IrpContext->DeviceExt, + (PFILE_DIRECTORY_INFORMATION) Buffer, + BufferLength); + break; + case FileFullDirectoryInformation: + RC = VfatGetFileFullDirectoryInformation (&DirContext, + IrpContext->DeviceExt, + (PFILE_FULL_DIR_INFORMATION) Buffer, + BufferLength); + break; + case FileBothDirectoryInformation: + RC = VfatGetFileBothInformation (&DirContext, + IrpContext->DeviceExt, + (PFILE_BOTH_DIR_INFORMATION) Buffer, + BufferLength); + break; + default: + RC = STATUS_INVALID_INFO_CLASS; + } + if (RC == STATUS_BUFFER_OVERFLOW) + { + break; + } + } + else + { + if (FirstQuery) + { + RC = STATUS_NO_SUCH_FILE; + } + else + { + RC = STATUS_NO_MORE_FILES; + } + break; + } + Buffer0 = (PFILE_NAMES_INFORMATION) Buffer; + Buffer0->FileIndex = DirContext.DirIndex; + pCcb->Entry = ++DirContext.DirIndex; + BufferLength -= Buffer0->NextEntryOffset; + if (IrpContext->Stack->Flags & SL_RETURN_SINGLE_ENTRY) + { + break; + } + Buffer += Buffer0->NextEntryOffset; + } + if (Buffer0) + { + Buffer0->NextEntryOffset = 0; + RC = STATUS_SUCCESS; + IrpContext->Irp->IoStatus.Information = Stack->Parameters.QueryDirectory.Length - BufferLength; + + } + ExReleaseResourceLite(&pFcb->MainResource); + return RC; +} + + +NTSTATUS VfatDirectoryControl (PVFAT_IRP_CONTEXT IrpContext) +/* + * FUNCTION: directory control : read/write directory informations + */ +{ + NTSTATUS RC = STATUS_SUCCESS; + IrpContext->Irp->IoStatus.Information = 0; + switch (IrpContext->MinorFunction) + { + case IRP_MN_QUERY_DIRECTORY: + RC = DoQuery (IrpContext); + break; + case IRP_MN_NOTIFY_CHANGE_DIRECTORY: + DPRINT (" vfat, dir : change\n"); + RC = STATUS_NOT_IMPLEMENTED; + break; + default: + // error + DbgPrint ("unexpected minor function %x in VFAT driver\n", + IrpContext->MinorFunction); + RC = STATUS_INVALID_DEVICE_REQUEST; + break; + } + if (RC == STATUS_PENDING) + { + RC = VfatQueueRequest(IrpContext); + } + else + { + IrpContext->Irp->IoStatus.Status = RC; + IoCompleteRequest (IrpContext->Irp, IO_NO_INCREMENT); + VfatFreeIrpContext(IrpContext); + } + return RC; +} + + diff --git a/reactos/drivers/filesystems/fastfat_new/direntry.c b/reactos/drivers/filesystems/fastfat_new/direntry.c new file mode 100644 index 00000000000..3aa2a60986e --- /dev/null +++ b/reactos/drivers/filesystems/fastfat_new/direntry.c @@ -0,0 +1,490 @@ +/* + * FILE: DirEntry.c + * PURPOSE: Routines to manipulate directory entries. + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * PROGRAMMER: Jason Filby (jasonfilby@yahoo.com) + * Rex Jolliff (rex@lvcablemodem.com) + * Herve Poussineau (reactos@poussine.freesurf.fr) + */ + +/* ------------------------------------------------------- INCLUDES */ + +#define NDEBUG +#include "vfat.h" + +ULONG +vfatDirEntryGetFirstCluster (PDEVICE_EXTENSION pDeviceExt, + PDIR_ENTRY pFatDirEntry) +{ + ULONG cluster; + + if (pDeviceExt->FatInfo.FatType == FAT32) + { + cluster = pFatDirEntry->Fat.FirstCluster | + (pFatDirEntry->Fat.FirstClusterHigh << 16); + } + else if (pDeviceExt->Flags & VCB_IS_FATX) + { + cluster = pFatDirEntry->FatX.FirstCluster; + } + else + { + cluster = pFatDirEntry->Fat.FirstCluster; + } + + return cluster; +} + +static +BOOLEAN +FATIsDirectoryEmpty(PVFATFCB Fcb) +{ + LARGE_INTEGER FileOffset; + PVOID Context = NULL; + PFAT_DIR_ENTRY FatDirEntry; + ULONG Index, MaxIndex; + + if (vfatFCBIsRoot(Fcb)) + { + Index = 0; + } + else + { + Index = 2; + } + + FileOffset.QuadPart = 0; + MaxIndex = Fcb->RFCB.FileSize.u.LowPart / sizeof(FAT_DIR_ENTRY); + + while (Index < MaxIndex) + { + if (Context == NULL || (Index % FAT_ENTRIES_PER_PAGE) == 0) + { + if (Context != NULL) + { + CcUnpinData(Context); + } + + if (!CcMapData(Fcb->FileObject, &FileOffset, PAGE_SIZE, TRUE, &Context, (PVOID*)&FatDirEntry)) + { + return TRUE; + } + + FatDirEntry += Index % FAT_ENTRIES_PER_PAGE; + } + + if (FAT_ENTRY_END(FatDirEntry)) + { + CcUnpinData(Context); + return TRUE; + } + + if (!FAT_ENTRY_DELETED(FatDirEntry)) + { + CcUnpinData(Context); + return FALSE; + } + + Index++; + FatDirEntry++; + } + + if (Context) + { + CcUnpinData(Context); + } + + return TRUE; +} + +static +BOOLEAN +FATXIsDirectoryEmpty(PVFATFCB Fcb) +{ + LARGE_INTEGER FileOffset; + PVOID Context = NULL; + PFATX_DIR_ENTRY FatXDirEntry; + ULONG Index = 0, MaxIndex; + + FileOffset.QuadPart = 0; + MaxIndex = Fcb->RFCB.FileSize.u.LowPart / sizeof(FATX_DIR_ENTRY); + + while (Index < MaxIndex) + { + if (Context == NULL || (Index % FATX_ENTRIES_PER_PAGE) == 0) + { + if (Context != NULL) + { + CcUnpinData(Context); + } + + if (!CcMapData(Fcb->FileObject, &FileOffset, PAGE_SIZE, TRUE, &Context, (PVOID*)&FatXDirEntry)) + { + return TRUE; + } + + FatXDirEntry += Index % FATX_ENTRIES_PER_PAGE; + } + + if (FATX_ENTRY_END(FatXDirEntry)) + { + CcUnpinData(Context); + return TRUE; + } + + if (!FATX_ENTRY_DELETED(FatXDirEntry)) + { + CcUnpinData(Context); + return FALSE; + } + + Index++; + FatXDirEntry++; + } + + if (Context) + { + CcUnpinData(Context); + } + + return TRUE; +} + +BOOLEAN +VfatIsDirectoryEmpty(PVFATFCB Fcb) +{ + if (Fcb->Flags & FCB_IS_FATX_ENTRY) + return FATXIsDirectoryEmpty(Fcb); + else + return FATIsDirectoryEmpty(Fcb); +} + +NTSTATUS +FATGetNextDirEntry(PVOID *pContext, + PVOID *pPage, + IN PVFATFCB pDirFcb, + PVFAT_DIRENTRY_CONTEXT DirContext, + BOOLEAN First) +{ + ULONG dirMap; + PWCHAR pName; + LARGE_INTEGER FileOffset; + PFAT_DIR_ENTRY fatDirEntry; + slot * longNameEntry; + ULONG index; + + UCHAR CheckSum, shortCheckSum; + USHORT i; + BOOLEAN Valid = TRUE; + BOOLEAN Back = FALSE; + + DirContext->LongNameU.Buffer[0] = 0; + + FileOffset.u.HighPart = 0; + FileOffset.u.LowPart = ROUND_DOWN(DirContext->DirIndex * sizeof(FAT_DIR_ENTRY), PAGE_SIZE); + + if (*pContext == NULL || (DirContext->DirIndex % FAT_ENTRIES_PER_PAGE) == 0) + { + if (*pContext != NULL) + { + CcUnpinData(*pContext); + } + + if (FileOffset.u.LowPart >= pDirFcb->RFCB.FileSize.u.LowPart || + !CcMapData(pDirFcb->FileObject, &FileOffset, PAGE_SIZE, TRUE, pContext, pPage)) + { + *pContext = NULL; + return STATUS_NO_MORE_ENTRIES; + } + } + + fatDirEntry = (PFAT_DIR_ENTRY)(*pPage) + DirContext->DirIndex % FAT_ENTRIES_PER_PAGE; + longNameEntry = (slot*) fatDirEntry; + dirMap = 0; + + if (First) + { + /* This is the first call to vfatGetNextDirEntry. Possible the start index points + * into a long name or points to a short name with an assigned long name. + * We must go back to the real start of the entry */ + while (DirContext->DirIndex > 0 && + !FAT_ENTRY_END(fatDirEntry) && + !FAT_ENTRY_DELETED(fatDirEntry) && + ((!FAT_ENTRY_LONG(fatDirEntry) && !Back) || + (FAT_ENTRY_LONG(fatDirEntry) && !(longNameEntry->id & 0x40)))) + { + DirContext->DirIndex--; + Back = TRUE; + + if ((DirContext->DirIndex % FAT_ENTRIES_PER_PAGE) == FAT_ENTRIES_PER_PAGE - 1) + { + CcUnpinData(*pContext); + FileOffset.u.LowPart -= PAGE_SIZE; + + if (FileOffset.u.LowPart >= pDirFcb->RFCB.FileSize.u.LowPart || + !CcMapData(pDirFcb->FileObject, &FileOffset, PAGE_SIZE, TRUE, pContext, pPage)) + { + *pContext = NULL; + return STATUS_NO_MORE_ENTRIES; + } + + fatDirEntry = (PFAT_DIR_ENTRY)(*pPage) + DirContext->DirIndex % FAT_ENTRIES_PER_PAGE; + longNameEntry = (slot*) fatDirEntry; + } + else + { + fatDirEntry--; + longNameEntry--; + } + } + + if (Back && !FAT_ENTRY_END(fatDirEntry) && + (FAT_ENTRY_DELETED(fatDirEntry) || !FAT_ENTRY_LONG(fatDirEntry))) + { + DirContext->DirIndex++; + + if ((DirContext->DirIndex % FAT_ENTRIES_PER_PAGE) == 0) + { + CcUnpinData(*pContext); + FileOffset.u.LowPart += PAGE_SIZE; + + if (FileOffset.u.LowPart >= pDirFcb->RFCB.FileSize.u.LowPart || + !CcMapData(pDirFcb->FileObject, &FileOffset, PAGE_SIZE, TRUE, pContext, pPage)) + { + *pContext = NULL; + return STATUS_NO_MORE_ENTRIES; + } + + fatDirEntry = (PFAT_DIR_ENTRY)*pPage; + longNameEntry = (slot*) *pPage; + } + else + { + fatDirEntry++; + longNameEntry++; + } + } + } + + DirContext->StartIndex = DirContext->DirIndex; + CheckSum = 0; + + while (TRUE) + { + if (FAT_ENTRY_END(fatDirEntry)) + { + CcUnpinData(*pContext); + *pContext = NULL; + return STATUS_NO_MORE_ENTRIES; + } + + if (FAT_ENTRY_DELETED(fatDirEntry)) + { + dirMap = 0; + DirContext->LongNameU.Buffer[0] = 0; + DirContext->StartIndex = DirContext->DirIndex + 1; + } + else + { + if (FAT_ENTRY_LONG(fatDirEntry)) + { + if (dirMap == 0) + { + DPRINT (" long name entry found at %d\n", DirContext->DirIndex); + RtlZeroMemory(DirContext->LongNameU.Buffer, DirContext->LongNameU.MaximumLength); + CheckSum = longNameEntry->alias_checksum; + Valid = TRUE; + } + + DPRINT(" name chunk1:[%.*S] chunk2:[%.*S] chunk3:[%.*S]\n", + 5, longNameEntry->name0_4, + 6, longNameEntry->name5_10, + 2, longNameEntry->name11_12); + + index = (longNameEntry->id & 0x1f) - 1; + dirMap |= 1 << index; + pName = DirContext->LongNameU.Buffer + 13 * index; + + RtlCopyMemory(pName, longNameEntry->name0_4, 5 * sizeof(WCHAR)); + RtlCopyMemory(pName + 5, longNameEntry->name5_10, 6 * sizeof(WCHAR)); + RtlCopyMemory(pName + 11, longNameEntry->name11_12, 2 * sizeof(WCHAR)); + + DPRINT (" longName: [%S]\n", DirContext->LongNameU.Buffer); + + if (CheckSum != longNameEntry->alias_checksum) + { + DPRINT1("Found wrong alias checksum in long name entry (first %x, current %x, %S)\n", + CheckSum, longNameEntry->alias_checksum, DirContext->LongNameU.Buffer); + Valid = FALSE; + } + } + else + { + shortCheckSum = 0; + for (i = 0; i < 11; i++) + { + shortCheckSum = (((shortCheckSum & 1) << 7) + | ((shortCheckSum & 0xfe) >> 1)) + + fatDirEntry->ShortName[i]; + } + + if (shortCheckSum != CheckSum && DirContext->LongNameU.Buffer[0]) + { + DPRINT1("Checksum from long and short name is not equal (short: %x, long: %x, %S)\n", + shortCheckSum, CheckSum, DirContext->LongNameU.Buffer); + DirContext->LongNameU.Buffer[0] = 0; + } + + if (Valid == FALSE) + { + DirContext->LongNameU.Buffer[0] = 0; + } + + RtlCopyMemory (&DirContext->DirEntry.Fat, fatDirEntry, sizeof (FAT_DIR_ENTRY)); + break; + } + } + + DirContext->DirIndex++; + + if ((DirContext->DirIndex % FAT_ENTRIES_PER_PAGE) == 0) + { + CcUnpinData(*pContext); + FileOffset.u.LowPart += PAGE_SIZE; + + if (FileOffset.u.LowPart >= pDirFcb->RFCB.FileSize.u.LowPart || + !CcMapData(pDirFcb->FileObject, &FileOffset, PAGE_SIZE, TRUE, pContext, pPage)) + { + *pContext = NULL; + return STATUS_NO_MORE_ENTRIES; + } + + fatDirEntry = (PFAT_DIR_ENTRY)*pPage; + longNameEntry = (slot*) *pPage; + } + else + { + fatDirEntry++; + longNameEntry++; + } + } + + DirContext->LongNameU.Length = wcslen(DirContext->LongNameU.Buffer) * sizeof(WCHAR); + vfat8Dot3ToString(&DirContext->DirEntry.Fat, &DirContext->ShortNameU); + + if (DirContext->LongNameU.Length == 0) + { + RtlCopyUnicodeString(&DirContext->LongNameU, &DirContext->ShortNameU); + } + + return STATUS_SUCCESS; +} + +NTSTATUS FATXGetNextDirEntry(PVOID * pContext, + PVOID * pPage, + IN PVFATFCB pDirFcb, + PVFAT_DIRENTRY_CONTEXT DirContext, + BOOLEAN First) +{ + LARGE_INTEGER FileOffset; + PFATX_DIR_ENTRY fatxDirEntry; + OEM_STRING StringO; + ULONG DirIndex = DirContext->DirIndex; + + FileOffset.u.HighPart = 0; + + if (!vfatFCBIsRoot(pDirFcb)) + { + /* need to add . and .. entries */ + switch (DirContext->DirIndex) + { + case 0: /* entry . */ + { + DirContext->ShortNameU.Buffer[0] = 0; + DirContext->ShortNameU.Length = 0; + DirContext->LongNameU.Buffer[0] = L'.'; + DirContext->LongNameU.Length = sizeof(WCHAR); + RtlCopyMemory(&DirContext->DirEntry.FatX, &pDirFcb->entry.FatX, sizeof(FATX_DIR_ENTRY)); + DirContext->DirEntry.FatX.Filename[0] = '.'; + DirContext->DirEntry.FatX.FilenameLength = 1; + DirContext->StartIndex = 0; + return STATUS_SUCCESS; + } + case 1: /* entry .. */ + { + DirContext->ShortNameU.Buffer[0] = 0; + DirContext->ShortNameU.Length = 0; + DirContext->LongNameU.Buffer[0] = DirContext->LongNameU.Buffer[1] = L'.'; + DirContext->LongNameU.Length = 2 * sizeof(WCHAR); + RtlCopyMemory(&DirContext->DirEntry.FatX, &pDirFcb->entry.FatX, sizeof(FATX_DIR_ENTRY)); + DirContext->DirEntry.FatX.Filename[0] = DirContext->DirEntry.FatX.Filename[1] = '.'; + DirContext->DirEntry.FatX.FilenameLength = 2; + DirContext->StartIndex = 1; + return STATUS_SUCCESS; + } + default: + DirIndex -= 2; + } + } + + if (*pContext == NULL || (DirIndex % FATX_ENTRIES_PER_PAGE) == 0) + { + if (*pContext != NULL) + { + CcUnpinData(*pContext); + } + FileOffset.u.LowPart = ROUND_DOWN(DirIndex * sizeof(FATX_DIR_ENTRY), PAGE_SIZE); + if (FileOffset.u.LowPart >= pDirFcb->RFCB.FileSize.u.LowPart || + !CcMapData(pDirFcb->FileObject, &FileOffset, PAGE_SIZE, TRUE, pContext, pPage)) + { + *pContext = NULL; + return STATUS_NO_MORE_ENTRIES; + } + } + + fatxDirEntry = (PFATX_DIR_ENTRY)(*pPage) + DirIndex % FATX_ENTRIES_PER_PAGE; + + DirContext->StartIndex = DirContext->DirIndex; + + while (TRUE) + { + if (FATX_ENTRY_END(fatxDirEntry)) + { + CcUnpinData(*pContext); + *pContext = NULL; + return STATUS_NO_MORE_ENTRIES; + } + + if (!FATX_ENTRY_DELETED(fatxDirEntry)) + { + RtlCopyMemory(&DirContext->DirEntry.FatX, fatxDirEntry, sizeof(FATX_DIR_ENTRY)); + break; + } + DirContext->DirIndex++; + DirContext->StartIndex++; + DirIndex++; + if ((DirIndex % FATX_ENTRIES_PER_PAGE) == 0) + { + CcUnpinData(*pContext); + FileOffset.u.LowPart += PAGE_SIZE; + if (FileOffset.u.LowPart >= pDirFcb->RFCB.FileSize.u.LowPart || + !CcMapData(pDirFcb->FileObject, &FileOffset, PAGE_SIZE, TRUE, pContext, pPage)) + { + *pContext = NULL; + return STATUS_NO_MORE_ENTRIES; + } + fatxDirEntry = (PFATX_DIR_ENTRY)*pPage; + } + else + { + fatxDirEntry++; + } + } + DirContext->ShortNameU.Buffer[0] = 0; + DirContext->ShortNameU.Length = 0; + StringO.Buffer = (PCHAR)fatxDirEntry->Filename; + StringO.Length = StringO.MaximumLength = fatxDirEntry->FilenameLength; + RtlOemStringToUnicodeString(&DirContext->LongNameU, &StringO, FALSE); + return STATUS_SUCCESS; +} diff --git a/reactos/drivers/filesystems/fastfat_new/dirwr.c b/reactos/drivers/filesystems/fastfat_new/dirwr.c new file mode 100644 index 00000000000..c2f3168c0f5 --- /dev/null +++ b/reactos/drivers/filesystems/fastfat_new/dirwr.c @@ -0,0 +1,722 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: drivers/fs/vfat/dirwr.c + * PURPOSE: VFAT Filesystem : write in directory + * + */ + +/* INCLUDES *****************************************************************/ + +#define NDEBUG +#include "vfat.h" + +/* + * update an existing FAT entry + */ +NTSTATUS +VfatUpdateEntry( + IN PVFATFCB pFcb) +{ + PVOID Context; + PDIR_ENTRY PinEntry; + LARGE_INTEGER Offset; + ULONG SizeDirEntry; + ULONG dirIndex; + + ASSERT(pFcb); + + if (pFcb->Flags & FCB_IS_FATX_ENTRY) + { + SizeDirEntry = sizeof(FATX_DIR_ENTRY); + dirIndex = pFcb->startIndex; + } + else + { + SizeDirEntry = sizeof(FAT_DIR_ENTRY); + dirIndex = pFcb->dirIndex; + } + + DPRINT("updEntry dirIndex %d, PathName \'%wZ\'\n", dirIndex, &pFcb->PathNameU); + + if (vfatFCBIsRoot(pFcb) || (pFcb->Flags & (FCB_IS_FAT|FCB_IS_VOLUME))) + { + return STATUS_SUCCESS; + } + + ASSERT(pFcb->parentFcb); + + Offset.u.HighPart = 0; + Offset.u.LowPart = dirIndex * SizeDirEntry; + if (CcPinRead(pFcb->parentFcb->FileObject, &Offset, SizeDirEntry, + TRUE, &Context, (PVOID*)&PinEntry)) + { + pFcb->Flags &= ~FCB_IS_DIRTY; + RtlCopyMemory(PinEntry, &pFcb->entry, SizeDirEntry); + CcSetDirtyPinnedData(Context, NULL); + CcUnpinData(Context); + return STATUS_SUCCESS; + } + else + { + DPRINT1("Failed write to \'%wZ\'.\n", &pFcb->parentFcb->PathNameU); + return STATUS_UNSUCCESSFUL; + } +} + +/* + * try to find contiguous entries frees in directory, + * extend a directory if is neccesary + */ +BOOLEAN +vfatFindDirSpace( + IN PDEVICE_EXTENSION DeviceExt, + IN PVFATFCB pDirFcb, + IN ULONG nbSlots, + OUT PULONG start) +{ + LARGE_INTEGER FileOffset; + ULONG i, count, size, nbFree = 0; + PDIR_ENTRY pFatEntry; + PVOID Context = NULL; + NTSTATUS Status; + ULONG SizeDirEntry; + FileOffset.QuadPart = 0; + + if (DeviceExt->Flags & VCB_IS_FATX) + SizeDirEntry = sizeof(FATX_DIR_ENTRY); + else + SizeDirEntry = sizeof(FAT_DIR_ENTRY); + + count = pDirFcb->RFCB.FileSize.u.LowPart / SizeDirEntry; + size = DeviceExt->FatInfo.BytesPerCluster / SizeDirEntry; + for (i = 0; i < count; i++, pFatEntry = (PDIR_ENTRY)((ULONG_PTR)pFatEntry + SizeDirEntry)) + { + if (Context == NULL || (i % size) == 0) + { + if (Context) + { + CcUnpinData(Context); + } + /* FIXME: check return value */ + CcPinRead(pDirFcb->FileObject, &FileOffset, DeviceExt->FatInfo.BytesPerCluster, + TRUE, &Context, (PVOID*)&pFatEntry); + FileOffset.u.LowPart += DeviceExt->FatInfo.BytesPerCluster; + } + if (ENTRY_END(DeviceExt, pFatEntry)) + { + break; + } + if (ENTRY_DELETED(DeviceExt, pFatEntry)) + { + nbFree++; + } + else + { + nbFree = 0; + } + if (nbFree == nbSlots) + { + break; + } + } + if (Context) + { + CcUnpinData(Context); + Context = NULL; + } + if (nbFree == nbSlots) + { + /* found enough contiguous free slots */ + *start = i - nbSlots + 1; + } + else + { + *start = i - nbFree; + if (*start + nbSlots > count) + { + LARGE_INTEGER AllocationSize; + /* extend the directory */ + if (vfatFCBIsRoot(pDirFcb) && DeviceExt->FatInfo.FatType != FAT32) + { + /* We can't extend a root directory on a FAT12/FAT16/FATX partition */ + return FALSE; + } + AllocationSize.QuadPart = pDirFcb->RFCB.FileSize.u.LowPart + DeviceExt->FatInfo.BytesPerCluster; + Status = VfatSetAllocationSizeInformation(pDirFcb->FileObject, pDirFcb, + DeviceExt, &AllocationSize); + if (!NT_SUCCESS(Status)) + { + return FALSE; + } + /* clear the new dir cluster */ + FileOffset.u.LowPart = (ULONG)(pDirFcb->RFCB.FileSize.QuadPart - + DeviceExt->FatInfo.BytesPerCluster); + CcPinRead(pDirFcb->FileObject, &FileOffset, DeviceExt->FatInfo.BytesPerCluster, + TRUE, &Context, (PVOID*)&pFatEntry); + if (DeviceExt->Flags & VCB_IS_FATX) + memset(pFatEntry, 0xff, DeviceExt->FatInfo.BytesPerCluster); + else + RtlZeroMemory(pFatEntry, DeviceExt->FatInfo.BytesPerCluster); + } + else if (*start + nbSlots < count) + { + /* clear the entry after the last new entry */ + FileOffset.u.LowPart = (*start + nbSlots) * SizeDirEntry; + CcPinRead(pDirFcb->FileObject, &FileOffset, SizeDirEntry, + TRUE, &Context, (PVOID*)&pFatEntry); + if (DeviceExt->Flags & VCB_IS_FATX) + memset(pFatEntry, 0xff, SizeDirEntry); + else + RtlZeroMemory(pFatEntry, SizeDirEntry); + } + if (Context) + { + CcSetDirtyPinnedData(Context, NULL); + CcUnpinData(Context); + } + } + DPRINT("nbSlots %d nbFree %d, entry number %d\n", nbSlots, nbFree, *start); + return TRUE; +} + +/* + create a new FAT entry +*/ +static NTSTATUS +FATAddEntry( + IN PDEVICE_EXTENSION DeviceExt, + IN PUNICODE_STRING NameU, + IN PVFATFCB* Fcb, + IN PVFATFCB ParentFcb, + IN ULONG RequestedOptions, + IN UCHAR ReqAttr) +{ + PVOID Context = NULL; + PFAT_DIR_ENTRY pFatEntry; + slot *pSlots; + USHORT nbSlots = 0, j, posCar; + PUCHAR Buffer; + BOOLEAN needTilde = FALSE, needLong = FALSE; + BOOLEAN lCaseBase = FALSE, uCaseBase, lCaseExt = FALSE, uCaseExt; + ULONG CurrentCluster; + LARGE_INTEGER SystemTime, FileOffset; + NTSTATUS Status = STATUS_SUCCESS; + ULONG size; + long i; + + OEM_STRING NameA; + CHAR aName[13]; + BOOLEAN IsNameLegal; + BOOLEAN SpacesFound; + + VFAT_DIRENTRY_CONTEXT DirContext; + WCHAR LongNameBuffer[LONGNAME_MAX_LENGTH + 1]; + WCHAR ShortNameBuffer[13]; + + DPRINT("addEntry: Name='%wZ', Dir='%wZ'\n", NameU, &ParentFcb->PathNameU); + + DirContext.LongNameU = *NameU; + + /* nb of entry needed for long name+normal entry */ + nbSlots = (DirContext.LongNameU.Length / sizeof(WCHAR) + 12) / 13 + 1; + DPRINT("NameLen= %d, nbSlots =%d\n", DirContext.LongNameU.Length / sizeof(WCHAR), nbSlots); + Buffer = ExAllocatePoolWithTag(NonPagedPool, (nbSlots - 1) * sizeof(FAT_DIR_ENTRY), TAG_VFAT); + if (Buffer == NULL) + { + return STATUS_INSUFFICIENT_RESOURCES; + } + RtlZeroMemory(Buffer, (nbSlots - 1) * sizeof(FAT_DIR_ENTRY)); + pSlots = (slot *) Buffer; + + NameA.Buffer = aName; + NameA.Length = 0; + NameA.MaximumLength = sizeof(aName); + + DirContext.ShortNameU.Buffer = ShortNameBuffer; + DirContext.ShortNameU.Length = 0; + DirContext.ShortNameU.MaximumLength = sizeof(ShortNameBuffer); + + RtlZeroMemory(&DirContext.DirEntry.Fat, sizeof(FAT_DIR_ENTRY)); + + IsNameLegal = RtlIsNameLegalDOS8Dot3(&DirContext.LongNameU, &NameA, &SpacesFound); + + if (!IsNameLegal || SpacesFound) + { + GENERATE_NAME_CONTEXT NameContext; + VFAT_DIRENTRY_CONTEXT SearchContext; + WCHAR ShortSearchName[13]; + needTilde = TRUE; + needLong = TRUE; + RtlZeroMemory(&NameContext, sizeof(GENERATE_NAME_CONTEXT)); + SearchContext.LongNameU.Buffer = LongNameBuffer; + SearchContext.LongNameU.MaximumLength = sizeof(LongNameBuffer); + SearchContext.ShortNameU.Buffer = ShortSearchName; + SearchContext.ShortNameU.MaximumLength = sizeof(ShortSearchName); + + for (i = 0; i < 100; i++) + { + RtlGenerate8dot3Name(&DirContext.LongNameU, FALSE, &NameContext, &DirContext.ShortNameU); + DirContext.ShortNameU.Buffer[DirContext.ShortNameU.Length / sizeof(WCHAR)] = 0; + SearchContext.DirIndex = 0; + Status = FindFile(DeviceExt, ParentFcb, &DirContext.ShortNameU, &SearchContext, TRUE); + if (!NT_SUCCESS(Status)) + { + break; + } + } + if (i == 100) /* FIXME : what to do after this ? */ + { + ExFreePoolWithTag(Buffer, TAG_VFAT); + return STATUS_UNSUCCESSFUL; + } + IsNameLegal = RtlIsNameLegalDOS8Dot3(&DirContext.ShortNameU, &NameA, &SpacesFound); + aName[NameA.Length]=0; + } + else + { + aName[NameA.Length] = 0; + for (posCar = 0; posCar < DirContext.LongNameU.Length / sizeof(WCHAR); posCar++) + { + if (DirContext.LongNameU.Buffer[posCar] == L'.') + { + break; + } + } + /* check if the name and the extension contains upper case characters */ + RtlDowncaseUnicodeString(&DirContext.ShortNameU, &DirContext.LongNameU, FALSE); + DirContext.ShortNameU.Buffer[DirContext.ShortNameU.Length / sizeof(WCHAR)] = 0; + uCaseBase = wcsncmp(DirContext.LongNameU.Buffer, + DirContext.ShortNameU.Buffer, posCar) ? TRUE : FALSE; + if (posCar < DirContext.LongNameU.Length/sizeof(WCHAR)) + { + i = DirContext.LongNameU.Length / sizeof(WCHAR) - posCar; + uCaseExt = wcsncmp(DirContext.LongNameU.Buffer + posCar, + DirContext.ShortNameU.Buffer + posCar, i) ? TRUE : FALSE; + } + else + { + uCaseExt = FALSE; + } + /* check if the name and the extension contains lower case characters */ + RtlUpcaseUnicodeString(&DirContext.ShortNameU, &DirContext.LongNameU, FALSE); + DirContext.ShortNameU.Buffer[DirContext.ShortNameU.Length / sizeof(WCHAR)] = 0; + lCaseBase = wcsncmp(DirContext.LongNameU.Buffer, + DirContext.ShortNameU.Buffer, posCar) ? TRUE : FALSE; + if (posCar < DirContext.LongNameU.Length / sizeof(WCHAR)) + { + i = DirContext.LongNameU.Length / sizeof(WCHAR) - posCar; + lCaseExt = wcsncmp(DirContext.LongNameU.Buffer + posCar, + DirContext.ShortNameU.Buffer + posCar, i) ? TRUE : FALSE; + } + else + { + lCaseExt = FALSE; + } + if ((lCaseBase && uCaseBase) || (lCaseExt && uCaseExt)) + { + needLong = TRUE; + } + } + DPRINT("'%s', '%wZ', needTilde=%d, needLong=%d\n", + aName, &DirContext.LongNameU, needTilde, needLong); + memset(DirContext.DirEntry.Fat.ShortName, ' ', 11); + for (i = 0; i < 8 && aName[i] && aName[i] != '.'; i++) + { + DirContext.DirEntry.Fat.Filename[i] = aName[i]; + } + if (aName[i] == '.') + { + i++; + for (j = 0; j < 3 && aName[i]; j++, i++) + { + DirContext.DirEntry.Fat.Ext[j] = aName[i]; + } + } + if (DirContext.DirEntry.Fat.Filename[0] == 0xe5) + { + DirContext.DirEntry.Fat.Filename[0] = 0x05; + } + + if (needLong) + { + RtlCopyMemory(LongNameBuffer, DirContext.LongNameU.Buffer, DirContext.LongNameU.Length); + DirContext.LongNameU.Buffer = LongNameBuffer; + DirContext.LongNameU.MaximumLength = sizeof(LongNameBuffer); + DirContext.LongNameU.Buffer[DirContext.LongNameU.Length / sizeof(WCHAR)] = 0; + memset(DirContext.LongNameU.Buffer + DirContext.LongNameU.Length / sizeof(WCHAR) + 1, 0xff, + DirContext.LongNameU.MaximumLength - DirContext.LongNameU.Length - sizeof(WCHAR)); + } + else + { + nbSlots = 1; + if (lCaseBase) + { + DirContext.DirEntry.Fat.lCase |= VFAT_CASE_LOWER_BASE; + } + if (lCaseExt) + { + DirContext.DirEntry.Fat.lCase |= VFAT_CASE_LOWER_EXT; + } + } + + DPRINT ("dos name=%11.11s\n", DirContext.DirEntry.Fat.Filename); + + /* set attributes */ + DirContext.DirEntry.Fat.Attrib = ReqAttr; + if (RequestedOptions & FILE_DIRECTORY_FILE) + { + DirContext.DirEntry.Fat.Attrib |= FILE_ATTRIBUTE_DIRECTORY; + } + /* set dates and times */ + KeQuerySystemTime(&SystemTime); + FsdSystemTimeToDosDateTime(DeviceExt, &SystemTime, &DirContext.DirEntry.Fat.CreationDate, + &DirContext.DirEntry.Fat.CreationTime); + DirContext.DirEntry.Fat.UpdateDate = DirContext.DirEntry.Fat.CreationDate; + DirContext.DirEntry.Fat.UpdateTime = DirContext.DirEntry.Fat.CreationTime; + DirContext.DirEntry.Fat.AccessDate = DirContext.DirEntry.Fat.CreationDate; + + if (needLong) + { + /* calculate checksum for 8.3 name */ + for (pSlots[0].alias_checksum = 0, i = 0; i < 11; i++) + { + pSlots[0].alias_checksum = (((pSlots[0].alias_checksum & 1) << 7 + | ((pSlots[0].alias_checksum & 0xfe) >> 1)) + + DirContext.DirEntry.Fat.ShortName[i]); + } + /* construct slots and entry */ + for (i = nbSlots - 2; i >= 0; i--) + { + DPRINT("construct slot %d\n", i); + pSlots[i].attr = 0xf; + if (i) + { + pSlots[i].id = (unsigned char)(nbSlots - i - 1); + } + else + { + pSlots[i].id = (unsigned char)(nbSlots - i - 1 + 0x40); + } + pSlots[i].alias_checksum = pSlots[0].alias_checksum; + RtlCopyMemory(pSlots[i].name0_4, DirContext.LongNameU.Buffer + (nbSlots - i - 2) * 13, 10); + RtlCopyMemory(pSlots[i].name5_10, DirContext.LongNameU.Buffer + (nbSlots - i - 2) * 13 + 5, 12); + RtlCopyMemory(pSlots[i].name11_12, DirContext.LongNameU.Buffer + (nbSlots - i - 2) * 13 + 11, 4); + } + } + /* try to find nbSlots contiguous entries frees in directory */ + if (!vfatFindDirSpace(DeviceExt, ParentFcb, nbSlots, &DirContext.StartIndex)) + { + ExFreePoolWithTag(Buffer, TAG_VFAT); + return STATUS_DISK_FULL; + } + DirContext.DirIndex = DirContext.StartIndex + nbSlots - 1; + if (RequestedOptions & FILE_DIRECTORY_FILE) + { + CurrentCluster = 0; + Status = NextCluster(DeviceExt, 0, &CurrentCluster, TRUE); + if (CurrentCluster == 0xffffffff || !NT_SUCCESS(Status)) + { + ExFreePoolWithTag(Buffer, TAG_VFAT); + if (!NT_SUCCESS(Status)) + { + return Status; + } + return STATUS_DISK_FULL; + } + if (DeviceExt->FatInfo.FatType == FAT32) + { + DirContext.DirEntry.Fat.FirstClusterHigh = (unsigned short)(CurrentCluster >> 16); + } + DirContext.DirEntry.Fat.FirstCluster = (unsigned short)CurrentCluster; + } + + i = DeviceExt->FatInfo.BytesPerCluster / sizeof(FAT_DIR_ENTRY); + FileOffset.u.HighPart = 0; + FileOffset.u.LowPart = DirContext.StartIndex * sizeof(FAT_DIR_ENTRY); + if (DirContext.StartIndex / i == DirContext.DirIndex / i) + { + /* one cluster */ + CcPinRead(ParentFcb->FileObject, &FileOffset, nbSlots * sizeof(FAT_DIR_ENTRY), + TRUE, &Context, (PVOID*)&pFatEntry); + if (nbSlots > 1) + { + RtlCopyMemory(pFatEntry, Buffer, (nbSlots - 1) * sizeof(FAT_DIR_ENTRY)); + } + RtlCopyMemory(pFatEntry + (nbSlots - 1), &DirContext.DirEntry.Fat, sizeof(FAT_DIR_ENTRY)); + } + else + { + /* two clusters */ + size = DeviceExt->FatInfo.BytesPerCluster - + (DirContext.StartIndex * sizeof(FAT_DIR_ENTRY)) % DeviceExt->FatInfo.BytesPerCluster; + i = size / sizeof(FAT_DIR_ENTRY); + CcPinRead(ParentFcb->FileObject, &FileOffset, size, TRUE, + &Context, (PVOID*)&pFatEntry); + RtlCopyMemory(pFatEntry, Buffer, size); + CcSetDirtyPinnedData(Context, NULL); + CcUnpinData(Context); + FileOffset.u.LowPart += size; + CcPinRead(ParentFcb->FileObject, &FileOffset, + nbSlots * sizeof(FAT_DIR_ENTRY) - size, + TRUE, &Context, (PVOID*)&pFatEntry); + if (nbSlots - 1 > i) + { + RtlCopyMemory(pFatEntry, (PVOID)(Buffer + size), (nbSlots - 1 - i) * sizeof(FAT_DIR_ENTRY)); + } + RtlCopyMemory(pFatEntry + nbSlots - 1 - i, &DirContext.DirEntry.Fat, sizeof(FAT_DIR_ENTRY)); + } + CcSetDirtyPinnedData(Context, NULL); + CcUnpinData(Context); + + /* FIXME: check status */ + vfatMakeFCBFromDirEntry(DeviceExt, ParentFcb, &DirContext, Fcb); + + DPRINT("new : entry=%11.11s\n", (*Fcb)->entry.Fat.Filename); + DPRINT("new : entry=%11.11s\n", DirContext.DirEntry.Fat.Filename); + + if (RequestedOptions & FILE_DIRECTORY_FILE) + { + FileOffset.QuadPart = 0; + CcPinRead((*Fcb)->FileObject, &FileOffset, DeviceExt->FatInfo.BytesPerCluster, TRUE, + &Context, (PVOID*)&pFatEntry); + /* clear the new directory cluster */ + RtlZeroMemory(pFatEntry, DeviceExt->FatInfo.BytesPerCluster); + /* create '.' and '..' */ + RtlCopyMemory(&pFatEntry[0].Attrib, &DirContext.DirEntry.Fat.Attrib, sizeof(FAT_DIR_ENTRY) - 11); + RtlCopyMemory(pFatEntry[0].ShortName, ". ", 11); + RtlCopyMemory(&pFatEntry[1].Attrib, &DirContext.DirEntry.Fat.Attrib, sizeof(FAT_DIR_ENTRY) - 11); + RtlCopyMemory(pFatEntry[1].ShortName, ".. ", 11); + pFatEntry[1].FirstCluster = ParentFcb->entry.Fat.FirstCluster; + pFatEntry[1].FirstClusterHigh = ParentFcb->entry.Fat.FirstClusterHigh; + if (vfatFCBIsRoot(ParentFcb)) + { + pFatEntry[1].FirstCluster = 0; + pFatEntry[1].FirstClusterHigh = 0; + } + CcSetDirtyPinnedData(Context, NULL); + CcUnpinData(Context); + } + ExFreePoolWithTag(Buffer, TAG_VFAT); + DPRINT("addentry ok\n"); + return STATUS_SUCCESS; +} + +/* + create a new FAT entry +*/ +static NTSTATUS +FATXAddEntry( + IN PDEVICE_EXTENSION DeviceExt, + IN PUNICODE_STRING NameU, + IN PVFATFCB* Fcb, + IN PVFATFCB ParentFcb, + IN ULONG RequestedOptions, + IN UCHAR ReqAttr) +{ + PVOID Context = NULL; + LARGE_INTEGER SystemTime, FileOffset; + OEM_STRING NameA; + VFAT_DIRENTRY_CONTEXT DirContext; + PFATX_DIR_ENTRY pFatXDirEntry; + ULONG Index; + + DPRINT("addEntry: Name='%wZ', Dir='%wZ'\n", NameU, &ParentFcb->PathNameU); + + DirContext.LongNameU = *NameU; + + if (DirContext.LongNameU.Length / sizeof(WCHAR) > 42) + { + /* name too long */ + return STATUS_NAME_TOO_LONG; + } + + /* try to find 1 entry free in directory */ + if (!vfatFindDirSpace(DeviceExt, ParentFcb, 1, &DirContext.StartIndex)) + { + return STATUS_DISK_FULL; + } + Index = DirContext.DirIndex = DirContext.StartIndex; + if (!vfatFCBIsRoot(ParentFcb)) + { + DirContext.DirIndex += 2; + DirContext.StartIndex += 2; + } + + DirContext.ShortNameU.Buffer = 0; + DirContext.ShortNameU.Length = 0; + DirContext.ShortNameU.MaximumLength = 0; + RtlZeroMemory(&DirContext.DirEntry.FatX, sizeof(FATX_DIR_ENTRY)); + memset(DirContext.DirEntry.FatX.Filename, 0xff, 42); + DirContext.DirEntry.FatX.FirstCluster = 0; + DirContext.DirEntry.FatX.FileSize = 0; + + /* set file name */ + NameA.Buffer = (PCHAR)DirContext.DirEntry.FatX.Filename; + NameA.Length = 0; + NameA.MaximumLength = 42; + RtlUnicodeStringToOemString(&NameA, &DirContext.LongNameU, FALSE); + DirContext.DirEntry.FatX.FilenameLength = (unsigned char)NameA.Length; + + /* set attributes */ + DirContext.DirEntry.FatX.Attrib = ReqAttr; + if (RequestedOptions & FILE_DIRECTORY_FILE) + { + DirContext.DirEntry.FatX.Attrib |= FILE_ATTRIBUTE_DIRECTORY; + } + + /* set dates and times */ + KeQuerySystemTime(&SystemTime); + FsdSystemTimeToDosDateTime(DeviceExt, &SystemTime, &DirContext.DirEntry.FatX.CreationDate, + &DirContext.DirEntry.FatX.CreationTime); + DirContext.DirEntry.FatX.UpdateDate = DirContext.DirEntry.FatX.CreationDate; + DirContext.DirEntry.FatX.UpdateTime = DirContext.DirEntry.FatX.CreationTime; + DirContext.DirEntry.FatX.AccessDate = DirContext.DirEntry.FatX.CreationDate; + DirContext.DirEntry.FatX.AccessTime = DirContext.DirEntry.FatX.CreationTime; + + /* add entry into parent directory */ + FileOffset.u.HighPart = 0; + FileOffset.u.LowPart = Index * sizeof(FATX_DIR_ENTRY); + CcPinRead(ParentFcb->FileObject, &FileOffset, sizeof(FATX_DIR_ENTRY), + TRUE, &Context, (PVOID*)&pFatXDirEntry); + RtlCopyMemory(pFatXDirEntry, &DirContext.DirEntry.FatX, sizeof(FATX_DIR_ENTRY)); + CcSetDirtyPinnedData(Context, NULL); + CcUnpinData(Context); + + /* FIXME: check status */ + vfatMakeFCBFromDirEntry(DeviceExt, ParentFcb, &DirContext, Fcb); + + DPRINT("addentry ok\n"); + return STATUS_SUCCESS; +} + +NTSTATUS +VfatAddEntry( + IN PDEVICE_EXTENSION DeviceExt, + IN PUNICODE_STRING NameU, + IN PVFATFCB *Fcb, + IN PVFATFCB ParentFcb, + IN ULONG RequestedOptions, + IN UCHAR ReqAttr) +{ + if (DeviceExt->Flags & VCB_IS_FATX) + return FATXAddEntry(DeviceExt, NameU, Fcb, ParentFcb, RequestedOptions, ReqAttr); + else + return FATAddEntry(DeviceExt, NameU, Fcb, ParentFcb, RequestedOptions, ReqAttr); +} + +/* + * deleting an existing FAT entry + */ +static NTSTATUS +FATDelEntry( + IN PDEVICE_EXTENSION DeviceExt, + IN PVFATFCB pFcb) +{ + ULONG CurrentCluster = 0, NextCluster, i; + PVOID Context = NULL; + LARGE_INTEGER Offset; + PFAT_DIR_ENTRY pDirEntry; + + ASSERT(pFcb); + ASSERT(pFcb->parentFcb); + + DPRINT("delEntry PathName \'%wZ\'\n", &pFcb->PathNameU); + DPRINT("delete entry: %d to %d\n", pFcb->startIndex, pFcb->dirIndex); + Offset.u.HighPart = 0; + for (i = pFcb->startIndex; i <= pFcb->dirIndex; i++) + { + if (Context == NULL || ((i * sizeof(FAT_DIR_ENTRY)) % PAGE_SIZE) == 0) + { + if (Context) + { + CcSetDirtyPinnedData(Context, NULL); + CcUnpinData(Context); + } + Offset.u.LowPart = (i * sizeof(FAT_DIR_ENTRY) / PAGE_SIZE) * PAGE_SIZE; + CcPinRead(pFcb->parentFcb->FileObject, &Offset, PAGE_SIZE, TRUE, + &Context, (PVOID*)&pDirEntry); + } + pDirEntry[i % (PAGE_SIZE / sizeof(FAT_DIR_ENTRY))].Filename[0] = 0xe5; + if (i == pFcb->dirIndex) + { + CurrentCluster = + vfatDirEntryGetFirstCluster(DeviceExt, + (PDIR_ENTRY)&pDirEntry[i % (PAGE_SIZE / sizeof(FAT_DIR_ENTRY))]); + } + } + if (Context) + { + CcSetDirtyPinnedData(Context, NULL); + CcUnpinData(Context); + } + + while (CurrentCluster && CurrentCluster != 0xffffffff) + { + GetNextCluster(DeviceExt, CurrentCluster, &NextCluster); + /* FIXME: check status */ + WriteCluster(DeviceExt, CurrentCluster, 0); + CurrentCluster = NextCluster; + } + return STATUS_SUCCESS; +} + +/* + * deleting an existing FAT entry + */ +static NTSTATUS +FATXDelEntry( + IN PDEVICE_EXTENSION DeviceExt, + IN PVFATFCB pFcb) +{ + ULONG CurrentCluster = 0, NextCluster; + PVOID Context = NULL; + LARGE_INTEGER Offset; + PFATX_DIR_ENTRY pDirEntry; + ULONG StartIndex; + + ASSERT(pFcb); + ASSERT(pFcb->parentFcb); + ASSERT(pFcb->Flags & FCB_IS_FATX_ENTRY); + + StartIndex = pFcb->startIndex; + + DPRINT("delEntry PathName \'%wZ\'\n", &pFcb->PathNameU); + DPRINT("delete entry: %d\n", StartIndex); + Offset.u.HighPart = 0; + Offset.u.LowPart = (StartIndex * sizeof(FATX_DIR_ENTRY) / PAGE_SIZE) * PAGE_SIZE; + if (!CcPinRead(pFcb->parentFcb->FileObject, &Offset, PAGE_SIZE, TRUE, + &Context, (PVOID*)&pDirEntry)) + { + DPRINT1("CcPinRead(Offset %x:%x, Length %d) failed\n", Offset.u.HighPart, Offset.u.LowPart, PAGE_SIZE); + return STATUS_UNSUCCESSFUL; + } + pDirEntry = &pDirEntry[StartIndex % (PAGE_SIZE / sizeof(FATX_DIR_ENTRY))]; + pDirEntry->FilenameLength = 0xe5; + CurrentCluster = vfatDirEntryGetFirstCluster(DeviceExt, + (PDIR_ENTRY)pDirEntry); + CcSetDirtyPinnedData(Context, NULL); + CcUnpinData(Context); + + while (CurrentCluster && CurrentCluster != 0xffffffff) + { + GetNextCluster(DeviceExt, CurrentCluster, &NextCluster); + /* FIXME: check status */ + WriteCluster(DeviceExt, CurrentCluster, 0); + CurrentCluster = NextCluster; + } + return STATUS_SUCCESS; +} + +NTSTATUS +VfatDelEntry( + IN PDEVICE_EXTENSION DeviceExt, + IN PVFATFCB pFcb) +{ + if (DeviceExt->Flags & VCB_IS_FATX) + return FATXDelEntry(DeviceExt, pFcb); + else + return FATDelEntry(DeviceExt, pFcb); +} + +/* EOF */ diff --git a/reactos/drivers/filesystems/fastfat_new/ea.c b/reactos/drivers/filesystems/fastfat_new/ea.c new file mode 100644 index 00000000000..5bf25f39d64 --- /dev/null +++ b/reactos/drivers/filesystems/fastfat_new/ea.c @@ -0,0 +1,40 @@ +/* + * ReactOS kernel + * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/* + * PROJECT: ReactOS kernel + * FILE: drivers/fs/vfat/ea.c + * PURPOSE: VFAT Filesystem + * PROGRAMMER: Jason Filby (jasonfilby@yahoo.com) + + */ + +/* INCLUDES *****************************************************************/ + +#define NDEBUG +#include "vfat.h" + +/* FUNCTIONS *****************************************************************/ + +NTSTATUS +VfatSetExtendedAttributes(PFILE_OBJECT FileObject, + PVOID Ea, + ULONG EaLength) +{ + return(STATUS_EAS_NOT_SUPPORTED); +} diff --git a/reactos/drivers/filesystems/fastfat_new/fastio.c b/reactos/drivers/filesystems/fastfat_new/fastio.c new file mode 100644 index 00000000000..8e511cf85e6 --- /dev/null +++ b/reactos/drivers/filesystems/fastfat_new/fastio.c @@ -0,0 +1,413 @@ +/* + * FILE: drivers/fs/vfat/fastio.c + * PURPOSE: Fast IO routines. + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * PROGRAMMER: Herve Poussineau (hpoussin@reactos.org) + */ + +#define NDEBUG +#include "vfat.h" + +static BOOLEAN NTAPI +VfatFastIoCheckIfPossible(IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER FileOffset, + IN ULONG Lenght, + IN BOOLEAN Wait, + IN ULONG LockKey, + IN BOOLEAN CheckForReadOperation, + OUT PIO_STATUS_BLOCK IoStatus, + IN PDEVICE_OBJECT DeviceObject) +{ + /* Prevent all Fast I/O requests */ + DPRINT("VfatFastIoCheckIfPossible(): returning FALSE.\n"); + return FALSE; +} + +static BOOLEAN NTAPI +VfatFastIoRead(IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER FileOffset, + IN ULONG Length, + IN BOOLEAN Wait, + IN ULONG LockKey, + OUT PVOID Buffer, + OUT PIO_STATUS_BLOCK IoStatus, + IN PDEVICE_OBJECT DeviceObject) +{ + DPRINT("VfatFastIoRead()\n"); + return FALSE; +} + +static BOOLEAN NTAPI +VfatFastIoWrite(IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER FileOffset, + IN ULONG Length, + IN BOOLEAN Wait, + IN ULONG LockKey, + OUT PVOID Buffer, + OUT PIO_STATUS_BLOCK IoStatus, + IN PDEVICE_OBJECT DeviceObject) +{ + DPRINT("VfatFastIoWrite()\n"); + return FALSE; +} + +static BOOLEAN NTAPI +VfatFastIoQueryBasicInfo(IN PFILE_OBJECT FileObject, + IN BOOLEAN Wait, + OUT PFILE_BASIC_INFORMATION Buffer, + OUT PIO_STATUS_BLOCK IoStatus, + IN PDEVICE_OBJECT DeviceObject) +{ + DPRINT("VfatFastIoQueryBasicInfo()\n"); + return FALSE; +} + +static BOOLEAN NTAPI +VfatFastIoQueryStandardInfo(IN PFILE_OBJECT FileObject, + IN BOOLEAN Wait, + OUT PFILE_STANDARD_INFORMATION Buffer, + OUT PIO_STATUS_BLOCK IoStatus, + IN PDEVICE_OBJECT DeviceObject) +{ + DPRINT("VfatFastIoQueryStandardInfo\n"); + return FALSE; +} + +static BOOLEAN NTAPI +VfatFastIoLock(IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER FileOffset, + IN PLARGE_INTEGER Length, + PEPROCESS ProcessId, + ULONG Key, + BOOLEAN FailImmediately, + BOOLEAN ExclusiveLock, + OUT PIO_STATUS_BLOCK IoStatus, + IN PDEVICE_OBJECT DeviceObject) +{ + DPRINT("VfatFastIoLock\n"); + return FALSE; +} + +static BOOLEAN NTAPI +VfatFastIoUnlockSingle(IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER FileOffset, + IN PLARGE_INTEGER Length, + PEPROCESS ProcessId, + ULONG Key, + OUT PIO_STATUS_BLOCK IoStatus, + IN PDEVICE_OBJECT DeviceObject) +{ + DPRINT("VfatFastIoUnlockSingle\n"); + return FALSE; +} + +static BOOLEAN NTAPI +VfatFastIoUnlockAll(IN PFILE_OBJECT FileObject, + PEPROCESS ProcessId, + OUT PIO_STATUS_BLOCK IoStatus, + IN PDEVICE_OBJECT DeviceObject) +{ + DPRINT("VfatFastIoUnlockAll\n"); + return FALSE; +} + +static BOOLEAN NTAPI +VfatFastIoUnlockAllByKey(IN PFILE_OBJECT FileObject, + PVOID ProcessId, + ULONG Key, + OUT PIO_STATUS_BLOCK IoStatus, + IN PDEVICE_OBJECT DeviceObject) +{ + DPRINT("VfatFastIoUnlockAllByKey\n"); + return FALSE; +} + +static BOOLEAN NTAPI +VfatFastIoDeviceControl(IN PFILE_OBJECT FileObject, + IN BOOLEAN Wait, + IN PVOID InputBuffer OPTIONAL, + IN ULONG InputBufferLength, + OUT PVOID OutputBuffer OPTIONAL, + IN ULONG OutputBufferLength, + IN ULONG IoControlCode, + OUT PIO_STATUS_BLOCK IoStatus, + IN PDEVICE_OBJECT DeviceObject) +{ + DPRINT("VfatFastIoDeviceControl\n"); + return FALSE; +} + +static VOID NTAPI +VfatAcquireFileForNtCreateSection(IN PFILE_OBJECT FileObject) +{ + DPRINT("VfatAcquireFileForNtCreateSection\n"); +} + +static VOID NTAPI +VfatReleaseFileForNtCreateSection(IN PFILE_OBJECT FileObject) +{ + DPRINT("VfatReleaseFileForNtCreateSection\n"); +} + +static VOID NTAPI +VfatFastIoDetachDevice(IN PDEVICE_OBJECT SourceDevice, + IN PDEVICE_OBJECT TargetDevice) +{ + DPRINT("VfatFastIoDetachDevice\n"); +} + +static BOOLEAN NTAPI +VfatFastIoQueryNetworkOpenInfo(IN PFILE_OBJECT FileObject, + IN BOOLEAN Wait, + OUT PFILE_NETWORK_OPEN_INFORMATION Buffer, + OUT PIO_STATUS_BLOCK IoStatus, + IN PDEVICE_OBJECT DeviceObject) +{ + DPRINT("VfatFastIoQueryNetworkOpenInfo\n"); + return FALSE; +} + +static NTSTATUS NTAPI +VfatAcquireForModWrite(IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER EndingOffset, + OUT PERESOURCE* ResourceToRelease, + IN PDEVICE_OBJECT DeviceObject) +{ + DPRINT("VfatAcquireForModWrite\n"); + return STATUS_INVALID_DEVICE_REQUEST; +} + +static BOOLEAN NTAPI +VfatMdlRead(IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER FileOffset, + IN ULONG Length, + IN ULONG LockKey, + OUT PMDL* MdlChain, + OUT PIO_STATUS_BLOCK IoStatus, + IN PDEVICE_OBJECT DeviceObject) +{ + DPRINT("VfatMdlRead\n"); + return FALSE; +} + +static BOOLEAN NTAPI +VfatMdlReadComplete(IN PFILE_OBJECT FileObject, + IN PMDL MdlChain, + IN PDEVICE_OBJECT DeviceObject) +{ + DPRINT("VfatMdlReadComplete\n"); + return FALSE; +} + +static BOOLEAN NTAPI +VfatPrepareMdlWrite(IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER FileOffset, + IN ULONG Length, + IN ULONG LockKey, + OUT PMDL* MdlChain, + OUT PIO_STATUS_BLOCK IoStatus, + IN PDEVICE_OBJECT DeviceObject) +{ + DPRINT("VfatPrepareMdlWrite\n"); + return FALSE; +} + +static BOOLEAN NTAPI +VfatMdlWriteComplete(IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER FileOffset, + IN PMDL MdlChain, + IN PDEVICE_OBJECT DeviceObject) +{ + DPRINT("VfatMdlWriteComplete\n"); + return FALSE; +} + +static BOOLEAN NTAPI +VfatFastIoReadCompressed(IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER FileOffset, + IN ULONG Length, + IN ULONG LockKey, + OUT PVOID Buffer, + OUT PMDL* MdlChain, + OUT PIO_STATUS_BLOCK IoStatus, + OUT PCOMPRESSED_DATA_INFO CompressedDataInfo, + IN ULONG CompressedDataInfoLength, + IN PDEVICE_OBJECT DeviceObject) +{ + DPRINT("VfatFastIoReadCompressed\n"); + return FALSE; +} + +static BOOLEAN NTAPI +VfatFastIoWriteCompressed(IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER FileOffset, + IN ULONG Length, + IN ULONG LockKey, + IN PVOID Buffer, + OUT PMDL* MdlChain, + OUT PIO_STATUS_BLOCK IoStatus, + IN PCOMPRESSED_DATA_INFO CompressedDataInfo, + IN ULONG CompressedDataInfoLength, + IN PDEVICE_OBJECT DeviceObject) +{ + DPRINT("VfatFastIoWriteCompressed\n"); + return FALSE; +} + +static BOOLEAN NTAPI +VfatMdlReadCompleteCompressed(IN PFILE_OBJECT FileObject, + IN PMDL MdlChain, + IN PDEVICE_OBJECT DeviceObject) +{ + DPRINT("VfatMdlReadCompleteCompressed\n"); + return FALSE; +} + +static BOOLEAN NTAPI +VfatMdlWriteCompleteCompressed(IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER FileOffset, + IN PMDL MdlChain, + IN PDEVICE_OBJECT DeviceObject) +{ + DPRINT("VfatMdlWriteCompleteCompressed\n"); + return FALSE; +} + +static BOOLEAN NTAPI +VfatFastIoQueryOpen(IN PIRP Irp, + OUT PFILE_NETWORK_OPEN_INFORMATION NetworkInformation, + IN PDEVICE_OBJECT DeviceObject) +{ + DPRINT("VfatFastIoQueryOpen\n"); + return FALSE; +} + +static NTSTATUS NTAPI +VfatReleaseForModWrite(IN PFILE_OBJECT FileObject, + IN PERESOURCE ResourceToRelease, + IN PDEVICE_OBJECT DeviceObject) +{ + DPRINT("VfatReleaseForModWrite\n"); + return STATUS_INVALID_DEVICE_REQUEST; +} + +static NTSTATUS NTAPI +VfatAcquireForCcFlush(IN PFILE_OBJECT FileObject, + IN PDEVICE_OBJECT DeviceObject) +{ + PVFATFCB Fcb = (PVFATFCB)FileObject->FsContext; + + DPRINT("VfatAcquireForCcFlush\n"); + + /* Make sure it is not a volume lock */ + ASSERT(!(Fcb->Flags & FCB_IS_VOLUME)); + + /* Acquire the resource */ + ExAcquireResourceExclusiveLite(&(Fcb->MainResource), TRUE); + + return STATUS_SUCCESS; +} + +static NTSTATUS NTAPI +VfatReleaseForCcFlush(IN PFILE_OBJECT FileObject, + IN PDEVICE_OBJECT DeviceObject) +{ + PVFATFCB Fcb = (PVFATFCB)FileObject->FsContext; + + DPRINT("VfatReleaseForCcFlush\n"); + + /* Make sure it is not a volume lock */ + ASSERT(!(Fcb->Flags & FCB_IS_VOLUME)); + + /* Release the resource */ + ExReleaseResourceLite(&(Fcb->MainResource)); + + return STATUS_SUCCESS; +} + +BOOLEAN NTAPI +VfatAcquireForLazyWrite(IN PVOID Context, + IN BOOLEAN Wait) +{ + PVFATFCB Fcb = (PVFATFCB)Context; + ASSERT(Fcb); + DPRINT("VfatAcquireForLazyWrite(): Fcb %p\n", Fcb); + + if (!ExAcquireResourceExclusiveLite(&(Fcb->MainResource), Wait)) + { + DPRINT("VfatAcquireForLazyWrite(): ExReleaseResourceLite failed.\n"); + return FALSE; + } + return TRUE; +} + +VOID NTAPI +VfatReleaseFromLazyWrite(IN PVOID Context) +{ + PVFATFCB Fcb = (PVFATFCB)Context; + ASSERT(Fcb); + DPRINT("VfatReleaseFromLazyWrite(): Fcb %p\n", Fcb); + + ExReleaseResourceLite(&(Fcb->MainResource)); +} + +BOOLEAN NTAPI +VfatAcquireForReadAhead(IN PVOID Context, + IN BOOLEAN Wait) +{ + PVFATFCB Fcb = (PVFATFCB)Context; + ASSERT(Fcb); + DPRINT("VfatAcquireForReadAhead(): Fcb %p\n", Fcb); + + if (!ExAcquireResourceExclusiveLite(&(Fcb->MainResource), Wait)) + { + DPRINT("VfatAcquireForReadAhead(): ExReleaseResourceLite failed.\n"); + return FALSE; + } + return TRUE; +} + +VOID NTAPI +VfatReleaseFromReadAhead(IN PVOID Context) +{ + PVFATFCB Fcb = (PVFATFCB)Context; + ASSERT(Fcb); + DPRINT("VfatReleaseFromReadAhead(): Fcb %p\n", Fcb); + + ExReleaseResourceLite(&(Fcb->MainResource)); +} + +VOID +VfatInitFastIoRoutines(PFAST_IO_DISPATCH FastIoDispatch) +{ + FastIoDispatch->SizeOfFastIoDispatch = sizeof(FAST_IO_DISPATCH); + FastIoDispatch->FastIoCheckIfPossible = VfatFastIoCheckIfPossible; + FastIoDispatch->FastIoRead = VfatFastIoRead; + FastIoDispatch->FastIoWrite = VfatFastIoWrite; + FastIoDispatch->FastIoQueryBasicInfo = VfatFastIoQueryBasicInfo; + FastIoDispatch->FastIoQueryStandardInfo = VfatFastIoQueryStandardInfo; + FastIoDispatch->FastIoLock = VfatFastIoLock; + FastIoDispatch->FastIoUnlockSingle = VfatFastIoUnlockSingle; + FastIoDispatch->FastIoUnlockAll = VfatFastIoUnlockAll; + FastIoDispatch->FastIoUnlockAllByKey = VfatFastIoUnlockAllByKey; + FastIoDispatch->FastIoDeviceControl = VfatFastIoDeviceControl; + FastIoDispatch->AcquireFileForNtCreateSection = VfatAcquireFileForNtCreateSection; + FastIoDispatch->ReleaseFileForNtCreateSection = VfatReleaseFileForNtCreateSection; + FastIoDispatch->FastIoDetachDevice = VfatFastIoDetachDevice; + FastIoDispatch->FastIoQueryNetworkOpenInfo = VfatFastIoQueryNetworkOpenInfo; + FastIoDispatch->MdlRead = VfatMdlRead; + FastIoDispatch->MdlReadComplete = VfatMdlReadComplete; + FastIoDispatch->PrepareMdlWrite = VfatPrepareMdlWrite; + FastIoDispatch->MdlWriteComplete = VfatMdlWriteComplete; + FastIoDispatch->FastIoReadCompressed = VfatFastIoReadCompressed; + FastIoDispatch->FastIoWriteCompressed = VfatFastIoWriteCompressed; + FastIoDispatch->MdlReadCompleteCompressed = VfatMdlReadCompleteCompressed; + FastIoDispatch->MdlWriteCompleteCompressed = VfatMdlWriteCompleteCompressed; + FastIoDispatch->FastIoQueryOpen = VfatFastIoQueryOpen; + FastIoDispatch->AcquireForModWrite = VfatAcquireForModWrite; + FastIoDispatch->ReleaseForModWrite = VfatReleaseForModWrite; + FastIoDispatch->AcquireForCcFlush = VfatAcquireForCcFlush; + FastIoDispatch->ReleaseForCcFlush = VfatReleaseForCcFlush; +} + diff --git a/reactos/drivers/filesystems/fastfat_new/fat.c b/reactos/drivers/filesystems/fastfat_new/fat.c new file mode 100644 index 00000000000..8ff955a4fbd --- /dev/null +++ b/reactos/drivers/filesystems/fastfat_new/fat.c @@ -0,0 +1,709 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: drivers/fs/vfat/fat.c + * PURPOSE: VFAT Filesystem + * PROGRAMMER: Jason Filby (jasonfilby@yahoo.com) + * + */ + +/* INCLUDES *****************************************************************/ + +#define NDEBUG +#include "vfat.h" + +/* GLOBALS ******************************************************************/ + +#define CACHEPAGESIZE(pDeviceExt) ((pDeviceExt)->FatInfo.BytesPerCluster > PAGE_SIZE ? \ + (pDeviceExt)->FatInfo.BytesPerCluster : PAGE_SIZE) + +/* FUNCTIONS ****************************************************************/ + +NTSTATUS +FAT32GetNextCluster(PDEVICE_EXTENSION DeviceExt, + ULONG CurrentCluster, + PULONG NextCluster) +/* + * FUNCTION: Retrieve the next FAT32 cluster from the FAT table via a physical + * disk read + */ +{ + PVOID BaseAddress; + ULONG FATOffset; + ULONG ChunkSize; + PVOID Context; + LARGE_INTEGER Offset; + + ChunkSize = CACHEPAGESIZE(DeviceExt); + FATOffset = CurrentCluster * sizeof(ULONG); + Offset.QuadPart = ROUND_DOWN(FATOffset, ChunkSize); + if(!CcMapData(DeviceExt->FATFileObject, &Offset, ChunkSize, 1, &Context, &BaseAddress)) + { + return STATUS_UNSUCCESSFUL; + } + CurrentCluster = (*(PULONG)((char*)BaseAddress + (FATOffset % ChunkSize))) & 0x0fffffff; + if (CurrentCluster >= 0xffffff8 && CurrentCluster <= 0xfffffff) + CurrentCluster = 0xffffffff; + CcUnpinData(Context); + *NextCluster = CurrentCluster; + return (STATUS_SUCCESS); +} + +NTSTATUS +FAT16GetNextCluster(PDEVICE_EXTENSION DeviceExt, + ULONG CurrentCluster, + PULONG NextCluster) +/* + * FUNCTION: Retrieve the next FAT16 cluster from the FAT table + */ +{ + PVOID BaseAddress; + ULONG FATOffset; + ULONG ChunkSize; + PVOID Context; + LARGE_INTEGER Offset; + + ChunkSize = CACHEPAGESIZE(DeviceExt); + FATOffset = CurrentCluster * 2; + Offset.QuadPart = ROUND_DOWN(FATOffset, ChunkSize); + if(!CcMapData(DeviceExt->FATFileObject, &Offset, ChunkSize, 1, &Context, &BaseAddress)) + { + return STATUS_UNSUCCESSFUL; + } + CurrentCluster = *((PUSHORT)((char*)BaseAddress + (FATOffset % ChunkSize))); + if (CurrentCluster >= 0xfff8 && CurrentCluster <= 0xffff) + CurrentCluster = 0xffffffff; + CcUnpinData(Context); + *NextCluster = CurrentCluster; + return (STATUS_SUCCESS); +} + +NTSTATUS +FAT12GetNextCluster(PDEVICE_EXTENSION DeviceExt, + ULONG CurrentCluster, + PULONG NextCluster) +/* + * FUNCTION: Retrieve the next FAT12 cluster from the FAT table + */ +{ + PUSHORT CBlock; + ULONG Entry; + PVOID BaseAddress; + PVOID Context; + LARGE_INTEGER Offset; + + + *NextCluster = 0; + + Offset.QuadPart = 0; + if(!CcMapData(DeviceExt->FATFileObject, &Offset, DeviceExt->FatInfo.FATSectors * DeviceExt->FatInfo.BytesPerSector, 1, &Context, &BaseAddress)) + { + return STATUS_UNSUCCESSFUL; + } + CBlock = (PUSHORT)((char*)BaseAddress + (CurrentCluster * 12) / 8); + if ((CurrentCluster % 2) == 0) + { + Entry = *CBlock & 0x0fff; + } + else + { + Entry = *CBlock >> 4; + } +// DPRINT("Entry %x\n",Entry); + if (Entry >= 0xff8 && Entry <= 0xfff) + Entry = 0xffffffff; +// DPRINT("Returning %x\n",Entry); + *NextCluster = Entry; + CcUnpinData(Context); +// return Entry == 0xffffffff ? STATUS_END_OF_FILE : STATUS_SUCCESS; + return STATUS_SUCCESS; +} + +NTSTATUS +FAT16FindAndMarkAvailableCluster(PDEVICE_EXTENSION DeviceExt, + PULONG Cluster) +/* + * FUNCTION: Finds the first available cluster in a FAT16 table + */ +{ + ULONG FatLength; + ULONG StartCluster; + ULONG i, j; + PVOID BaseAddress; + ULONG ChunkSize; + PVOID Context = 0; + LARGE_INTEGER Offset; + PUSHORT Block; + PUSHORT BlockEnd; + + ChunkSize = CACHEPAGESIZE(DeviceExt); + FatLength = (DeviceExt->FatInfo.NumberOfClusters + 2); + *Cluster = 0; + StartCluster = DeviceExt->LastAvailableCluster; + + for (j = 0; j < 2; j++) + { + for (i = StartCluster; i < FatLength; ) + { + Offset.QuadPart = ROUND_DOWN(i * 2, ChunkSize); + if(!CcPinRead(DeviceExt->FATFileObject, &Offset, ChunkSize, 1, &Context, &BaseAddress)) + { + DPRINT1("CcMapData(Offset %x, Length %d) failed\n", (ULONG)Offset.QuadPart, ChunkSize); + return STATUS_UNSUCCESSFUL; + } + Block = (PUSHORT)((ULONG_PTR)BaseAddress + (i * 2) % ChunkSize); + BlockEnd = (PUSHORT)((ULONG_PTR)BaseAddress + ChunkSize); + + /* Now process the whole block */ + while (Block < BlockEnd && i < FatLength) + { + if (*Block == 0) + { + DPRINT("Found available cluster 0x%x\n", i); + DeviceExt->LastAvailableCluster = *Cluster = i; + *Block = 0xffff; + CcSetDirtyPinnedData(Context, NULL); + CcUnpinData(Context); + if (DeviceExt->AvailableClustersValid) + InterlockedDecrement((PLONG)&DeviceExt->AvailableClusters); + return(STATUS_SUCCESS); + } + + Block++; + i++; + } + + CcUnpinData(Context); + } + FatLength = StartCluster; + StartCluster = 2; + } + return(STATUS_DISK_FULL); +} + +NTSTATUS +FAT12FindAndMarkAvailableCluster(PDEVICE_EXTENSION DeviceExt, PULONG Cluster) +/* + * FUNCTION: Finds the first available cluster in a FAT12 table + */ +{ + ULONG FatLength; + ULONG StartCluster; + ULONG Entry; + PUSHORT CBlock; + ULONG i, j; + PVOID BaseAddress; + PVOID Context; + LARGE_INTEGER Offset; + + FatLength = DeviceExt->FatInfo.NumberOfClusters + 2; + *Cluster = 0; + StartCluster = DeviceExt->LastAvailableCluster; + Offset.QuadPart = 0; + if(!CcPinRead(DeviceExt->FATFileObject, &Offset, DeviceExt->FatInfo.FATSectors * DeviceExt->FatInfo.BytesPerSector, 1, &Context, &BaseAddress)) + { + DPRINT1("CcMapData(Offset %x, Length %d) failed\n", (ULONG)Offset.QuadPart, DeviceExt->FatInfo.FATSectors * DeviceExt->FatInfo.BytesPerSector); + return STATUS_UNSUCCESSFUL; + } + + for (j = 0; j < 2; j++) + { + for (i = StartCluster; i < FatLength; i++) + { + CBlock = (PUSHORT)((char*)BaseAddress + (i * 12) / 8); + if ((i % 2) == 0) + { + Entry = *CBlock & 0xfff; + } + else + { + Entry = *CBlock >> 4; + } + if (Entry == 0) + { + DPRINT("Found available cluster 0x%x\n", i); + DeviceExt->LastAvailableCluster = *Cluster = i; + if ((i % 2) == 0) + *CBlock = (*CBlock & 0xf000) | 0xfff; + else + *CBlock = (*CBlock & 0xf) | 0xfff0; + CcSetDirtyPinnedData(Context, NULL); + CcUnpinData(Context); + if (DeviceExt->AvailableClustersValid) + InterlockedDecrement((PLONG)&DeviceExt->AvailableClusters); + return(STATUS_SUCCESS); + } + } + FatLength = StartCluster; + StartCluster = 2; + } + CcUnpinData(Context); + return (STATUS_DISK_FULL); +} + +NTSTATUS +FAT32FindAndMarkAvailableCluster (PDEVICE_EXTENSION DeviceExt, PULONG Cluster) +/* + * FUNCTION: Finds the first available cluster in a FAT32 table + */ +{ + ULONG FatLength; + ULONG StartCluster; + ULONG i, j; + PVOID BaseAddress; + ULONG ChunkSize; + PVOID Context; + LARGE_INTEGER Offset; + PULONG Block; + PULONG BlockEnd; + + ChunkSize = CACHEPAGESIZE(DeviceExt); + FatLength = (DeviceExt->FatInfo.NumberOfClusters + 2); + *Cluster = 0; + StartCluster = DeviceExt->LastAvailableCluster; + + for (j = 0; j < 2; j++) + { + for (i = StartCluster; i < FatLength;) + { + Offset.QuadPart = ROUND_DOWN(i * 4, ChunkSize); + if(!CcPinRead(DeviceExt->FATFileObject, &Offset, ChunkSize, 1, &Context, &BaseAddress)) + { + DPRINT1("CcMapData(Offset %x, Length %d) failed\n", (ULONG)Offset.QuadPart, ChunkSize); + return STATUS_UNSUCCESSFUL; + } + Block = (PULONG)((ULONG_PTR)BaseAddress + (i * 4) % ChunkSize); + BlockEnd = (PULONG)((ULONG_PTR)BaseAddress + ChunkSize); + + /* Now process the whole block */ + while (Block < BlockEnd && i < FatLength) + { + if ((*Block & 0x0fffffff) == 0) + { + DPRINT("Found available cluster 0x%x\n", i); + DeviceExt->LastAvailableCluster = *Cluster = i; + *Block = 0x0fffffff; + CcSetDirtyPinnedData(Context, NULL); + CcUnpinData(Context); + if (DeviceExt->AvailableClustersValid) + InterlockedDecrement((PLONG)&DeviceExt->AvailableClusters); + return(STATUS_SUCCESS); + } + + Block++; + i++; + } + + CcUnpinData(Context); + } + FatLength = StartCluster; + StartCluster = 2; + } + return (STATUS_DISK_FULL); +} + +static NTSTATUS +FAT12CountAvailableClusters(PDEVICE_EXTENSION DeviceExt) +/* + * FUNCTION: Counts free cluster in a FAT12 table + */ +{ + ULONG Entry; + PVOID BaseAddress; + ULONG ulCount = 0; + ULONG i; + ULONG numberofclusters; + LARGE_INTEGER Offset; + PVOID Context; + PUSHORT CBlock; + + Offset.QuadPart = 0; + if(!CcMapData(DeviceExt->FATFileObject, &Offset, DeviceExt->FatInfo.FATSectors * DeviceExt->FatInfo.BytesPerSector, 1, &Context, &BaseAddress)) + { + return STATUS_UNSUCCESSFUL; + } + + numberofclusters = DeviceExt->FatInfo.NumberOfClusters + 2; + + for (i = 2; i < numberofclusters; i++) + { + CBlock = (PUSHORT)((char*)BaseAddress + (i * 12) / 8); + if ((i % 2) == 0) + { + Entry = *CBlock & 0x0fff; + } + else + { + Entry = *CBlock >> 4; + } + if (Entry == 0) + ulCount++; + } + + CcUnpinData(Context); + DeviceExt->AvailableClusters = ulCount; + DeviceExt->AvailableClustersValid = TRUE; + + return(STATUS_SUCCESS); +} + + +static NTSTATUS +FAT16CountAvailableClusters(PDEVICE_EXTENSION DeviceExt) +/* + * FUNCTION: Counts free clusters in a FAT16 table + */ +{ + PUSHORT Block; + PUSHORT BlockEnd; + PVOID BaseAddress = NULL; + ULONG ulCount = 0; + ULONG i; + ULONG ChunkSize; + PVOID Context = NULL; + LARGE_INTEGER Offset; + ULONG FatLength; + + ChunkSize = CACHEPAGESIZE(DeviceExt); + FatLength = (DeviceExt->FatInfo.NumberOfClusters + 2); + + for (i = 2; i < FatLength; ) + { + Offset.QuadPart = ROUND_DOWN(i * 2, ChunkSize); + if(!CcMapData(DeviceExt->FATFileObject, &Offset, ChunkSize, 1, &Context, &BaseAddress)) + { + return STATUS_UNSUCCESSFUL; + } + Block = (PUSHORT)((ULONG_PTR)BaseAddress + (i * 2) % ChunkSize); + BlockEnd = (PUSHORT)((ULONG_PTR)BaseAddress + ChunkSize); + + /* Now process the whole block */ + while (Block < BlockEnd && i < FatLength) + { + if (*Block == 0) + ulCount++; + Block++; + i++; + } + + CcUnpinData(Context); + } + + DeviceExt->AvailableClusters = ulCount; + DeviceExt->AvailableClustersValid = TRUE; + + return(STATUS_SUCCESS); +} + + +static NTSTATUS +FAT32CountAvailableClusters(PDEVICE_EXTENSION DeviceExt) +/* + * FUNCTION: Counts free clusters in a FAT32 table + */ +{ + PULONG Block; + PULONG BlockEnd; + PVOID BaseAddress = NULL; + ULONG ulCount = 0; + ULONG i; + ULONG ChunkSize; + PVOID Context = NULL; + LARGE_INTEGER Offset; + ULONG FatLength; + + ChunkSize = CACHEPAGESIZE(DeviceExt); + FatLength = (DeviceExt->FatInfo.NumberOfClusters + 2); + + for (i = 2; i < FatLength; ) + { + Offset.QuadPart = ROUND_DOWN(i * 4, ChunkSize); + if(!CcMapData(DeviceExt->FATFileObject, &Offset, ChunkSize, 1, &Context, &BaseAddress)) + { + DPRINT1("CcMapData(Offset %x, Length %d) failed\n", (ULONG)Offset.QuadPart, ChunkSize); + return STATUS_UNSUCCESSFUL; + } + Block = (PULONG)((ULONG_PTR)BaseAddress + (i * 4) % ChunkSize); + BlockEnd = (PULONG)((ULONG_PTR)BaseAddress + ChunkSize); + + /* Now process the whole block */ + while (Block < BlockEnd && i < FatLength) + { + if ((*Block & 0x0fffffff) == 0) + ulCount++; + Block++; + i++; + } + + CcUnpinData(Context); + } + + DeviceExt->AvailableClusters = ulCount; + DeviceExt->AvailableClustersValid = TRUE; + + return(STATUS_SUCCESS); +} + +NTSTATUS +CountAvailableClusters(PDEVICE_EXTENSION DeviceExt, + PLARGE_INTEGER Clusters) +{ + NTSTATUS Status = STATUS_SUCCESS; + ExAcquireResourceExclusiveLite (&DeviceExt->FatResource, TRUE); + if (!DeviceExt->AvailableClustersValid) + { + if (DeviceExt->FatInfo.FatType == FAT12) + Status = FAT12CountAvailableClusters(DeviceExt); + else if (DeviceExt->FatInfo.FatType == FAT16 || DeviceExt->FatInfo.FatType == FATX16) + Status = FAT16CountAvailableClusters(DeviceExt); + else + Status = FAT32CountAvailableClusters(DeviceExt); + } + Clusters->QuadPart = DeviceExt->AvailableClusters; + ExReleaseResourceLite (&DeviceExt->FatResource); + + return Status; +} + + + + + +NTSTATUS +FAT12WriteCluster(PDEVICE_EXTENSION DeviceExt, + ULONG ClusterToWrite, + ULONG NewValue, + PULONG OldValue) +/* + * FUNCTION: Writes a cluster to the FAT12 physical and in-memory tables + */ +{ + ULONG FATsector; + ULONG FATOffset; + PUCHAR CBlock; + PVOID BaseAddress; + PVOID Context; + LARGE_INTEGER Offset; + + Offset.QuadPart = 0; + if(!CcPinRead(DeviceExt->FATFileObject, &Offset, DeviceExt->FatInfo.FATSectors * DeviceExt->FatInfo.BytesPerSector, 1, &Context, &BaseAddress)) + { + return STATUS_UNSUCCESSFUL; + } + CBlock = (PUCHAR)BaseAddress; + + FATOffset = (ClusterToWrite * 12) / 8; + DPRINT("Writing 0x%x for 0x%x at 0x%x\n", + NewValue, ClusterToWrite, FATOffset); + if ((ClusterToWrite % 2) == 0) + { + *OldValue = CBlock[FATOffset] + ((CBlock[FATOffset + 1] & 0x0f) << 8); + CBlock[FATOffset] = (UCHAR)NewValue; + CBlock[FATOffset + 1] &= 0xf0; + CBlock[FATOffset + 1] |= (NewValue & 0xf00) >> 8; + } + else + { + *OldValue = (CBlock[FATOffset] >> 4) + (CBlock[FATOffset + 1] << 4); + CBlock[FATOffset] &= 0x0f; + CBlock[FATOffset] |= (NewValue & 0xf) << 4; + CBlock[FATOffset + 1] = (UCHAR)(NewValue >> 4); + } + /* Write the changed FAT sector(s) to disk */ + FATsector = FATOffset / DeviceExt->FatInfo.BytesPerSector; + CcSetDirtyPinnedData(Context, NULL); + CcUnpinData(Context); + return(STATUS_SUCCESS); +} + +NTSTATUS +FAT16WriteCluster(PDEVICE_EXTENSION DeviceExt, + ULONG ClusterToWrite, + ULONG NewValue, + PULONG OldValue) +/* + * FUNCTION: Writes a cluster to the FAT16 physical and in-memory tables + */ +{ + PVOID BaseAddress; + ULONG FATOffset; + ULONG ChunkSize; + PVOID Context; + LARGE_INTEGER Offset; + PUSHORT Cluster; + + ChunkSize = CACHEPAGESIZE(DeviceExt); + FATOffset = ClusterToWrite * 2; + Offset.QuadPart = ROUND_DOWN(FATOffset, ChunkSize); + if(!CcPinRead(DeviceExt->FATFileObject, &Offset, ChunkSize, 1, &Context, &BaseAddress)) + { + return STATUS_UNSUCCESSFUL; + } + DPRINT("Writing 0x%x for offset 0x%x 0x%x\n", NewValue, FATOffset, + ClusterToWrite); + Cluster = ((PUSHORT)((char*)BaseAddress + (FATOffset % ChunkSize))); + *OldValue = *Cluster; + *Cluster = (USHORT)NewValue; + CcSetDirtyPinnedData(Context, NULL); + CcUnpinData(Context); + return(STATUS_SUCCESS); +} + +NTSTATUS +FAT32WriteCluster(PDEVICE_EXTENSION DeviceExt, + ULONG ClusterToWrite, + ULONG NewValue, + PULONG OldValue) +/* + * FUNCTION: Writes a cluster to the FAT32 physical tables + */ +{ + PVOID BaseAddress; + ULONG FATOffset; + ULONG ChunkSize; + PVOID Context; + LARGE_INTEGER Offset; + PULONG Cluster; + + ChunkSize = CACHEPAGESIZE(DeviceExt); + + FATOffset = (ClusterToWrite * 4); + Offset.QuadPart = ROUND_DOWN(FATOffset, ChunkSize); + if(!CcPinRead(DeviceExt->FATFileObject, &Offset, ChunkSize, 1, &Context, &BaseAddress)) + { + return STATUS_UNSUCCESSFUL; + } + DPRINT("Writing 0x%x for offset 0x%x 0x%x\n", NewValue, FATOffset, + ClusterToWrite); + Cluster = ((PULONG)((char*)BaseAddress + (FATOffset % ChunkSize))); + *OldValue = *Cluster & 0x0fffffff; + *Cluster = (*Cluster & 0xf0000000) | (NewValue & 0x0fffffff); + + CcSetDirtyPinnedData(Context, NULL); + CcUnpinData(Context); + + return(STATUS_SUCCESS); +} + + +NTSTATUS +WriteCluster(PDEVICE_EXTENSION DeviceExt, + ULONG ClusterToWrite, + ULONG NewValue) +/* + * FUNCTION: Write a changed FAT entry + */ +{ + NTSTATUS Status; + ULONG OldValue; + ExAcquireResourceExclusiveLite (&DeviceExt->FatResource, TRUE); + Status = DeviceExt->WriteCluster(DeviceExt, ClusterToWrite, NewValue, &OldValue); + if (DeviceExt->AvailableClustersValid) + { + if (OldValue && NewValue == 0) + InterlockedIncrement((PLONG)&DeviceExt->AvailableClusters); + else if (OldValue == 0 && NewValue) + InterlockedDecrement((PLONG)&DeviceExt->AvailableClusters); + } + ExReleaseResourceLite(&DeviceExt->FatResource); + return(Status); +} + +ULONGLONG +ClusterToSector(PDEVICE_EXTENSION DeviceExt, + ULONG Cluster) +/* + * FUNCTION: Converts the cluster number to a sector number for this physical + * device + */ +{ + return DeviceExt->FatInfo.dataStart + + ((ULONGLONG)(Cluster - 2) * DeviceExt->FatInfo.SectorsPerCluster); + +} + +NTSTATUS +GetNextCluster(PDEVICE_EXTENSION DeviceExt, + ULONG CurrentCluster, + PULONG NextCluster) +/* + * FUNCTION: Retrieve the next cluster depending on the FAT type + */ +{ + NTSTATUS Status; + + DPRINT ("GetNextCluster(DeviceExt %p, CurrentCluster %x)\n", + DeviceExt, CurrentCluster); + + if (CurrentCluster == 0) + return(STATUS_INVALID_PARAMETER); + + ExAcquireResourceSharedLite(&DeviceExt->FatResource, TRUE); + Status = DeviceExt->GetNextCluster(DeviceExt, CurrentCluster, NextCluster); + ExReleaseResourceLite(&DeviceExt->FatResource); + + return(Status); +} + +NTSTATUS +GetNextClusterExtend(PDEVICE_EXTENSION DeviceExt, + ULONG CurrentCluster, + PULONG NextCluster) +/* + * FUNCTION: Retrieve the next cluster depending on the FAT type + */ +{ + NTSTATUS Status; + + DPRINT ("GetNextClusterExtend(DeviceExt %p, CurrentCluster %x)\n", + DeviceExt, CurrentCluster); + + ExAcquireResourceExclusiveLite(&DeviceExt->FatResource, TRUE); + /* + * If the file hasn't any clusters allocated then we need special + * handling + */ + if (CurrentCluster == 0) + { + ULONG NewCluster; + + Status = DeviceExt->FindAndMarkAvailableCluster(DeviceExt, &NewCluster); + if (!NT_SUCCESS(Status)) + { + ExReleaseResourceLite(&DeviceExt->FatResource); + return Status; + } + + *NextCluster = NewCluster; + ExReleaseResourceLite(&DeviceExt->FatResource); + return(STATUS_SUCCESS); + } + + Status = DeviceExt->GetNextCluster(DeviceExt, CurrentCluster, NextCluster); + + if ((*NextCluster) == 0xFFFFFFFF) + { + ULONG NewCluster; + + /* We are after last existing cluster, we must add one to file */ + /* Firstly, find the next available open allocation unit and + mark it as end of file */ + Status = DeviceExt->FindAndMarkAvailableCluster(DeviceExt, &NewCluster); + if (!NT_SUCCESS(Status)) + { + ExReleaseResourceLite(&DeviceExt->FatResource); + return Status; + } + + /* Now, write the AU of the LastCluster with the value of the newly + found AU */ + WriteCluster(DeviceExt, CurrentCluster, NewCluster); + *NextCluster = NewCluster; + } + + ExReleaseResourceLite(&DeviceExt->FatResource); + + return(Status); +} + +/* EOF */ diff --git a/reactos/drivers/filesystems/fastfat_new/fcb.c b/reactos/drivers/filesystems/fastfat_new/fcb.c new file mode 100644 index 00000000000..7ebee47f0b8 --- /dev/null +++ b/reactos/drivers/filesystems/fastfat_new/fcb.c @@ -0,0 +1,821 @@ +/* +* FILE: drivers/fs/vfat/fcb.c +* PURPOSE: Routines to manipulate FCBs. +* COPYRIGHT: See COPYING in the top level directory +* PROJECT: ReactOS kernel +* PROGRAMMER: Jason Filby (jasonfilby@yahoo.com) +* Rex Jolliff (rex@lvcablemodem.com) +* Herve Poussineau (reactos@poussine.freesurf.fr) +*/ + +/* ------------------------------------------------------- INCLUDES */ + +#ifdef __GNUC__ +#include /* towlower prototype */ +#endif + +#define NDEBUG +#include "vfat.h" + +/* -------------------------------------------------------- DEFINES */ + +#define TAG_FCB TAG('V', 'F', 'C', 'B') + +/* -------------------------------------------------------- PUBLICS */ + +static ULONG vfatNameHash(ULONG hash, PUNICODE_STRING NameU) +{ + PWCHAR last; + PWCHAR curr; + register WCHAR c; + + ASSERT(NameU->Buffer[0] != L'.'); + curr = NameU->Buffer; + last = NameU->Buffer + NameU->Length / sizeof(WCHAR); + + while(curr < last) + { + c = towlower(*curr++); + hash = (hash + (c << 4) + (c >> 4)) * 11; + } + return hash; +} + +VOID +vfatSplitPathName(PUNICODE_STRING PathNameU, PUNICODE_STRING DirNameU, PUNICODE_STRING FileNameU) +{ + PWCHAR pName; + USHORT Length = 0; + pName = PathNameU->Buffer + PathNameU->Length / sizeof(WCHAR) - 1; + while (*pName != L'\\' && pName >= PathNameU->Buffer) + { + pName--; + Length++; + } + ASSERT(*pName == L'\\' || pName < PathNameU->Buffer); + if (FileNameU) + { + FileNameU->Buffer = pName + 1; + FileNameU->Length = FileNameU->MaximumLength = Length * sizeof(WCHAR); + } + if (DirNameU) + { + DirNameU->Buffer = PathNameU->Buffer; + DirNameU->Length = (pName + 1 - PathNameU->Buffer) * sizeof(WCHAR); + DirNameU->MaximumLength = DirNameU->Length; + } +} + +static VOID +vfatInitFcb(PVFATFCB Fcb, PUNICODE_STRING NameU) +{ + USHORT PathNameBufferLength; + + if (NameU) + PathNameBufferLength = NameU->Length + sizeof(WCHAR); + else + PathNameBufferLength = 0; + + Fcb->PathNameBuffer = ExAllocatePoolWithTag(NonPagedPool, PathNameBufferLength, TAG_FCB); + if (!Fcb->PathNameBuffer) + { + /* FIXME: what to do if no more memory? */ + DPRINT1("Unable to initialize FCB for filename '%wZ'\n", NameU); + KeBugCheckEx(0, (ULONG_PTR)Fcb, (ULONG_PTR)NameU, 0, 0); + } + + Fcb->PathNameU.Length = 0; + Fcb->PathNameU.Buffer = Fcb->PathNameBuffer; + Fcb->PathNameU.MaximumLength = PathNameBufferLength; + Fcb->ShortNameU.Length = 0; + Fcb->ShortNameU.Buffer = Fcb->ShortNameBuffer; + Fcb->ShortNameU.MaximumLength = sizeof(Fcb->ShortNameBuffer); + Fcb->DirNameU.Buffer = Fcb->PathNameU.Buffer; + if (NameU && NameU->Length) + { + RtlCopyUnicodeString(&Fcb->PathNameU, NameU); + vfatSplitPathName(&Fcb->PathNameU, &Fcb->DirNameU, &Fcb->LongNameU); + } + else + { + Fcb->DirNameU.Buffer = Fcb->LongNameU.Buffer = NULL; + Fcb->DirNameU.MaximumLength = Fcb->DirNameU.Length = 0; + Fcb->LongNameU.MaximumLength = Fcb->LongNameU.Length = 0; + } + RtlZeroMemory(&Fcb->FCBShareAccess, sizeof(SHARE_ACCESS)); + Fcb->OpenHandleCount = 0; +} + +PVFATFCB +vfatNewFCB(PDEVICE_EXTENSION pVCB, PUNICODE_STRING pFileNameU) +{ + PVFATFCB rcFCB; + + DPRINT("'%wZ'\n", pFileNameU); + + rcFCB = ExAllocateFromNPagedLookasideList(&VfatGlobalData->FcbLookasideList); + if (rcFCB == NULL) + { + return NULL; + } + RtlZeroMemory(rcFCB, sizeof(VFATFCB)); + vfatInitFcb(rcFCB, pFileNameU); + if (pVCB->Flags & VCB_IS_FATX) + { + rcFCB->Flags |= FCB_IS_FATX_ENTRY; + rcFCB->Attributes = &rcFCB->entry.FatX.Attrib; + } + else + rcFCB->Attributes = &rcFCB->entry.Fat.Attrib; + rcFCB->Hash.Hash = vfatNameHash(0, &rcFCB->PathNameU); + rcFCB->Hash.self = rcFCB; + rcFCB->ShortHash.self = rcFCB; + ExInitializeResourceLite(&rcFCB->PagingIoResource); + ExInitializeResourceLite(&rcFCB->MainResource); + FsRtlInitializeFileLock(&rcFCB->FileLock, NULL, NULL); + ExInitializeFastMutex(&rcFCB->LastMutex); + rcFCB->RFCB.PagingIoResource = &rcFCB->PagingIoResource; + rcFCB->RFCB.Resource = &rcFCB->MainResource; + rcFCB->RFCB.IsFastIoPossible = FastIoIsNotPossible; + + return rcFCB; +} + +VOID +vfatDestroyCCB(PVFATCCB pCcb) +{ + if (pCcb->SearchPattern.Buffer) + { + ExFreePool(pCcb->SearchPattern.Buffer); + } + ExFreeToNPagedLookasideList(&VfatGlobalData->CcbLookasideList, pCcb); +} + +VOID +vfatDestroyFCB(PVFATFCB pFCB) +{ + FsRtlUninitializeFileLock(&pFCB->FileLock); + ExFreePool(pFCB->PathNameBuffer); + ExDeleteResourceLite(&pFCB->PagingIoResource); + ExDeleteResourceLite(&pFCB->MainResource); + ExFreeToNPagedLookasideList(&VfatGlobalData->FcbLookasideList, pFCB); +} + +BOOLEAN +vfatFCBIsDirectory(PVFATFCB FCB) +{ + return *FCB->Attributes & FILE_ATTRIBUTE_DIRECTORY; +} + +BOOLEAN +vfatFCBIsRoot(PVFATFCB FCB) +{ + return FCB->PathNameU.Length == sizeof(WCHAR) && FCB->PathNameU.Buffer[0] == L'\\' ? TRUE : FALSE; +} + +VOID +vfatReleaseFCB(PDEVICE_EXTENSION pVCB, PVFATFCB pFCB) +{ + HASHENTRY* entry; + ULONG Index; + ULONG ShortIndex; + PVFATFCB tmpFcb; + + DPRINT ("releasing FCB at %p: %wZ, refCount:%d\n", + pFCB, + &pFCB->PathNameU, + pFCB->RefCount); + + while (pFCB) + { + Index = pFCB->Hash.Hash % pVCB->HashTableSize; + ShortIndex = pFCB->ShortHash.Hash % pVCB->HashTableSize; + pFCB->RefCount--; + if (pFCB->RefCount == 0) + { + tmpFcb = pFCB->parentFcb; + RemoveEntryList (&pFCB->FcbListEntry); + if (pFCB->Hash.Hash != pFCB->ShortHash.Hash) + { + entry = pVCB->FcbHashTable[ShortIndex]; + if (entry->self == pFCB) + { + pVCB->FcbHashTable[ShortIndex] = entry->next; + } + else + { + while (entry->next->self != pFCB) + { + entry = entry->next; + } + entry->next = pFCB->ShortHash.next; + } + } + entry = pVCB->FcbHashTable[Index]; + if (entry->self == pFCB) + { + pVCB->FcbHashTable[Index] = entry->next; + } + else + { + while (entry->next->self != pFCB) + { + entry = entry->next; + } + entry->next = pFCB->Hash.next; + } + vfatDestroyFCB (pFCB); + } + else + { + tmpFcb = NULL; + } + pFCB = tmpFcb; + } +} + +VOID +vfatAddFCBToTable(PDEVICE_EXTENSION pVCB, PVFATFCB pFCB) +{ + ULONG Index; + ULONG ShortIndex; + + Index = pFCB->Hash.Hash % pVCB->HashTableSize; + ShortIndex = pFCB->ShortHash.Hash % pVCB->HashTableSize; + + InsertTailList (&pVCB->FcbListHead, &pFCB->FcbListEntry); + + pFCB->Hash.next = pVCB->FcbHashTable[Index]; + pVCB->FcbHashTable[Index] = &pFCB->Hash; + if (pFCB->Hash.Hash != pFCB->ShortHash.Hash) + { + pFCB->ShortHash.next = pVCB->FcbHashTable[ShortIndex]; + pVCB->FcbHashTable[ShortIndex] = &pFCB->ShortHash; + } + if (pFCB->parentFcb) + { + pFCB->parentFcb->RefCount++; + } +} + +PVFATFCB +vfatGrabFCBFromTable(PDEVICE_EXTENSION pVCB, PUNICODE_STRING PathNameU) +{ + PVFATFCB rcFCB; + ULONG Hash; + UNICODE_STRING DirNameU; + UNICODE_STRING FileNameU; + PUNICODE_STRING FcbNameU; + + HASHENTRY* entry; + + DPRINT("'%wZ'\n", PathNameU); + + Hash = vfatNameHash(0, PathNameU); + + entry = pVCB->FcbHashTable[Hash % pVCB->HashTableSize]; + if (entry) + { + vfatSplitPathName(PathNameU, &DirNameU, &FileNameU); + } + + while (entry) + { + if (entry->Hash == Hash) + { + rcFCB = entry->self; + DPRINT("'%wZ' '%wZ'\n", &DirNameU, &rcFCB->DirNameU); + if (RtlEqualUnicodeString(&DirNameU, &rcFCB->DirNameU, TRUE)) + { + if (rcFCB->Hash.Hash == Hash) + { + FcbNameU = &rcFCB->LongNameU; + } + else + { + FcbNameU = &rcFCB->ShortNameU; + } + /* compare the file name */ + DPRINT("'%wZ' '%wZ'\n", &FileNameU, FcbNameU); + if (RtlEqualUnicodeString(&FileNameU, FcbNameU, TRUE)) + { + rcFCB->RefCount++; + return rcFCB; + } + } + } + entry = entry->next; + } + return NULL; +} + +static NTSTATUS +vfatFCBInitializeCacheFromVolume (PVCB vcb, PVFATFCB fcb) +{ + PFILE_OBJECT fileObject; + PVFATCCB newCCB; + + fileObject = IoCreateStreamFileObject (NULL, vcb->StorageDevice); + + newCCB = ExAllocateFromNPagedLookasideList(&VfatGlobalData->CcbLookasideList); + if (newCCB == NULL) + { + return STATUS_INSUFFICIENT_RESOURCES; + } + RtlZeroMemory(newCCB, sizeof (VFATCCB)); + + fileObject->SectionObjectPointer = &fcb->SectionObjectPointers; + fileObject->FsContext = fcb; + fileObject->FsContext2 = newCCB; + fcb->FileObject = fileObject; + fcb->RefCount++; + + CcInitializeCacheMap(fileObject, + (PCC_FILE_SIZES)(&fcb->RFCB.AllocationSize), + TRUE, + &VfatGlobalData->CacheMgrCallbacks, + fcb); + + fcb->Flags |= FCB_CACHE_INITIALIZED; + return STATUS_SUCCESS; +} + +PVFATFCB +vfatMakeRootFCB(PDEVICE_EXTENSION pVCB) +{ + PVFATFCB FCB; + ULONG FirstCluster, CurrentCluster, Size = 0; + NTSTATUS Status = STATUS_SUCCESS; + UNICODE_STRING NameU = RTL_CONSTANT_STRING(L"\\"); + + FCB = vfatNewFCB(pVCB, &NameU); + if (FCB->Flags & FCB_IS_FATX_ENTRY) + { + memset(FCB->entry.FatX.Filename, ' ', 42); + FCB->entry.FatX.FileSize = pVCB->FatInfo.rootDirectorySectors * pVCB->FatInfo.BytesPerSector; + FCB->entry.FatX.Attrib = FILE_ATTRIBUTE_DIRECTORY; + FCB->entry.FatX.FirstCluster = 1; + Size = pVCB->FatInfo.rootDirectorySectors * pVCB->FatInfo.BytesPerSector; + } + else + { + memset(FCB->entry.Fat.ShortName, ' ', 11); + FCB->entry.Fat.FileSize = pVCB->FatInfo.rootDirectorySectors * pVCB->FatInfo.BytesPerSector; + FCB->entry.Fat.Attrib = FILE_ATTRIBUTE_DIRECTORY; + if (pVCB->FatInfo.FatType == FAT32) + { + CurrentCluster = FirstCluster = pVCB->FatInfo.RootCluster; + FCB->entry.Fat.FirstCluster = (unsigned short)(FirstCluster & 0xffff); + FCB->entry.Fat.FirstClusterHigh = (unsigned short)(FirstCluster >> 16); + + while (CurrentCluster != 0xffffffff && NT_SUCCESS(Status)) + { + Size += pVCB->FatInfo.BytesPerCluster; + Status = NextCluster (pVCB, FirstCluster, &CurrentCluster, FALSE); + } + } + else + { + FCB->entry.Fat.FirstCluster = 1; + Size = pVCB->FatInfo.rootDirectorySectors * pVCB->FatInfo.BytesPerSector; + } + } + FCB->ShortHash.Hash = FCB->Hash.Hash; + FCB->RefCount = 2; + FCB->dirIndex = 0; + FCB->RFCB.FileSize.QuadPart = Size; + FCB->RFCB.ValidDataLength.QuadPart = Size; + FCB->RFCB.AllocationSize.QuadPart = Size; + FCB->RFCB.IsFastIoPossible = FastIoIsNotPossible; + + vfatFCBInitializeCacheFromVolume(pVCB, FCB); + vfatAddFCBToTable(pVCB, FCB); + + return(FCB); +} + +PVFATFCB +vfatOpenRootFCB(PDEVICE_EXTENSION pVCB) +{ + PVFATFCB FCB; + UNICODE_STRING NameU = RTL_CONSTANT_STRING(L"\\"); + + FCB = vfatGrabFCBFromTable (pVCB, &NameU); + if (FCB == NULL) + { + FCB = vfatMakeRootFCB (pVCB); + } + + return FCB; +} + +NTSTATUS +vfatMakeFCBFromDirEntry( + PVCB vcb, + PVFATFCB directoryFCB, + PVFAT_DIRENTRY_CONTEXT DirContext, + PVFATFCB* fileFCB) +{ + PVFATFCB rcFCB; + PWCHAR PathNameBuffer; + USHORT PathNameLength; + ULONG Size; + ULONG hash; + + UNICODE_STRING NameU; + + PathNameLength = directoryFCB->PathNameU.Length + max(DirContext->LongNameU.Length, DirContext->ShortNameU.Length); + if (!vfatFCBIsRoot (directoryFCB)) + { + PathNameLength += sizeof(WCHAR); + } + + if (PathNameLength > LONGNAME_MAX_LENGTH * sizeof(WCHAR)) + { + return STATUS_OBJECT_NAME_INVALID; + } + PathNameBuffer = ExAllocatePoolWithTag(NonPagedPool, PathNameLength + sizeof(WCHAR), TAG_FCB); + if (!PathNameBuffer) + { + return STATUS_INSUFFICIENT_RESOURCES; + } + NameU.Buffer = PathNameBuffer; + NameU.Length = 0; + NameU.MaximumLength = PathNameLength; + + RtlCopyUnicodeString(&NameU, &directoryFCB->PathNameU); + if (!vfatFCBIsRoot (directoryFCB)) + { + RtlAppendUnicodeToString(&NameU, L"\\"); + } + hash = vfatNameHash(0, &NameU); + if (DirContext->LongNameU.Length > 0) + { + RtlAppendUnicodeStringToString(&NameU, &DirContext->LongNameU); + } + else + { + RtlAppendUnicodeStringToString(&NameU, &DirContext->ShortNameU); + } + NameU.Buffer[NameU.Length / sizeof(WCHAR)] = 0; + + rcFCB = vfatNewFCB (vcb, &NameU); + RtlCopyMemory (&rcFCB->entry, &DirContext->DirEntry, sizeof (DIR_ENTRY)); + RtlCopyUnicodeString(&rcFCB->ShortNameU, &DirContext->ShortNameU); + if (vcb->Flags & VCB_IS_FATX) + { + rcFCB->ShortHash.Hash = rcFCB->Hash.Hash; + } + else + { + rcFCB->ShortHash.Hash = vfatNameHash(hash, &rcFCB->ShortNameU); + } + + if (vfatFCBIsDirectory(rcFCB)) + { + ULONG FirstCluster, CurrentCluster; + NTSTATUS Status; + Size = 0; + FirstCluster = vfatDirEntryGetFirstCluster (vcb, &rcFCB->entry); + if (FirstCluster == 1) + { + Size = vcb->FatInfo.rootDirectorySectors * vcb->FatInfo.BytesPerSector; + } + else if (FirstCluster != 0) + { + CurrentCluster = FirstCluster; + while (CurrentCluster != 0xffffffff) + { + Size += vcb->FatInfo.BytesPerCluster; + Status = NextCluster (vcb, FirstCluster, &CurrentCluster, FALSE); + } + } + } + else if (rcFCB->Flags & FCB_IS_FATX_ENTRY) + { + Size = rcFCB->entry.FatX.FileSize; + } + else + { + Size = rcFCB->entry.Fat.FileSize; + } + rcFCB->dirIndex = DirContext->DirIndex; + rcFCB->startIndex = DirContext->StartIndex; + if ((rcFCB->Flags & FCB_IS_FATX_ENTRY) && !vfatFCBIsRoot (directoryFCB)) + { + ASSERT(DirContext->DirIndex >= 2 && DirContext->StartIndex >= 2); + rcFCB->dirIndex = DirContext->DirIndex-2; + rcFCB->startIndex = DirContext->StartIndex-2; + } + rcFCB->RFCB.FileSize.QuadPart = Size; + rcFCB->RFCB.ValidDataLength.QuadPart = Size; + rcFCB->RFCB.AllocationSize.QuadPart = ROUND_UP(Size, vcb->FatInfo.BytesPerCluster); + rcFCB->RefCount++; + if (vfatFCBIsDirectory(rcFCB)) + { + vfatFCBInitializeCacheFromVolume(vcb, rcFCB); + } + rcFCB->parentFcb = directoryFCB; + vfatAddFCBToTable (vcb, rcFCB); + *fileFCB = rcFCB; + + ExFreePool(PathNameBuffer); + return STATUS_SUCCESS; +} + +NTSTATUS +vfatAttachFCBToFileObject ( + PDEVICE_EXTENSION vcb, + PVFATFCB fcb, + PFILE_OBJECT fileObject) +{ + PVFATCCB newCCB; + + newCCB = ExAllocateFromNPagedLookasideList(&VfatGlobalData->CcbLookasideList); + if (newCCB == NULL) + { + return STATUS_INSUFFICIENT_RESOURCES; + } + RtlZeroMemory (newCCB, sizeof (VFATCCB)); + + fileObject->SectionObjectPointer = &fcb->SectionObjectPointers; + fileObject->FsContext = fcb; + fileObject->FsContext2 = newCCB; + DPRINT ("file open: fcb:%p PathName:%wZ\n", fcb, &fcb->PathNameU); + + return STATUS_SUCCESS; +} + +NTSTATUS +vfatDirFindFile ( + PDEVICE_EXTENSION pDeviceExt, + PVFATFCB pDirectoryFCB, + PUNICODE_STRING FileToFindU, + PVFATFCB * pFoundFCB) +{ + NTSTATUS status; + PVOID Context = NULL; + PVOID Page = NULL; + BOOLEAN First = TRUE; + VFAT_DIRENTRY_CONTEXT DirContext; + /* This buffer must have a size of 260 characters, because + vfatMakeFCBFromDirEntry can copy 20 name entries with 13 characters. */ + WCHAR LongNameBuffer[260]; + WCHAR ShortNameBuffer[13]; + BOOLEAN FoundLong = FALSE; + BOOLEAN FoundShort = FALSE; + + ASSERT(pDeviceExt); + ASSERT(pDirectoryFCB); + ASSERT(FileToFindU); + + DPRINT ("vfatDirFindFile(VCB:%p, dirFCB:%p, File:%wZ)\n", + pDeviceExt, + pDirectoryFCB, + FileToFindU); + DPRINT ("Dir Path:%wZ\n", &pDirectoryFCB->PathNameU); + + DirContext.DirIndex = 0; + DirContext.LongNameU.Buffer = LongNameBuffer; + DirContext.LongNameU.Length = 0; + DirContext.LongNameU.MaximumLength = sizeof(LongNameBuffer); + DirContext.ShortNameU.Buffer = ShortNameBuffer; + DirContext.ShortNameU.Length = 0; + DirContext.ShortNameU.MaximumLength = sizeof(ShortNameBuffer); + + while (TRUE) + { + status = pDeviceExt->GetNextDirEntry(&Context, + &Page, + pDirectoryFCB, + &DirContext, + First); + First = FALSE; + if (status == STATUS_NO_MORE_ENTRIES) + { + return STATUS_OBJECT_NAME_NOT_FOUND; + } + if (!NT_SUCCESS(status)) + { + return status; + } + + DPRINT (" Index:%d longName:%wZ\n", + DirContext.DirIndex, + &DirContext.LongNameU); + DirContext.LongNameU.Buffer[DirContext.LongNameU.Length / sizeof(WCHAR)] = 0; + DirContext.ShortNameU.Buffer[DirContext.ShortNameU.Length / sizeof(WCHAR)] = 0; + if (!ENTRY_VOLUME(pDeviceExt, &DirContext.DirEntry)) + { + FoundLong = RtlEqualUnicodeString(FileToFindU, &DirContext.LongNameU, TRUE); + if (FoundLong == FALSE) + { + FoundShort = RtlEqualUnicodeString(FileToFindU, &DirContext.ShortNameU, TRUE); + } + if (FoundLong || FoundShort) + { + status = vfatMakeFCBFromDirEntry (pDeviceExt, + pDirectoryFCB, + &DirContext, + pFoundFCB); + CcUnpinData(Context); + return status; + } + } + DirContext.DirIndex++; + } + + return STATUS_OBJECT_NAME_NOT_FOUND; +} + +NTSTATUS +vfatGetFCBForFile ( + PDEVICE_EXTENSION pVCB, + PVFATFCB *pParentFCB, + PVFATFCB *pFCB, + PUNICODE_STRING pFileNameU) +{ + NTSTATUS status; + PVFATFCB FCB = NULL; + PVFATFCB parentFCB; + UNICODE_STRING NameU; + UNICODE_STRING RootNameU = RTL_CONSTANT_STRING(L"\\"); + UNICODE_STRING FileNameU; + WCHAR NameBuffer[260]; + PWCHAR curr, prev, last; + ULONG Length; + + DPRINT ("vfatGetFCBForFile (%p,%p,%p,%wZ)\n", + pVCB, + pParentFCB, + pFCB, + pFileNameU); + + FileNameU.Buffer = NameBuffer; + FileNameU.MaximumLength = sizeof(NameBuffer); + RtlCopyUnicodeString(&FileNameU, pFileNameU); + + parentFCB = *pParentFCB; + + if (parentFCB == NULL) + { + // Trivial case, open of the root directory on volume + if (RtlEqualUnicodeString(&FileNameU, &RootNameU, FALSE)) + { + DPRINT ("returning root FCB\n"); + + FCB = vfatOpenRootFCB (pVCB); + *pFCB = FCB; + *pParentFCB = NULL; + + return (FCB != NULL) ? STATUS_SUCCESS : STATUS_OBJECT_PATH_NOT_FOUND; + } + + /* Check for an existing FCB */ + FCB = vfatGrabFCBFromTable (pVCB, &FileNameU); + if (FCB) + { + *pFCB = FCB; + *pParentFCB = FCB->parentFcb; + (*pParentFCB)->RefCount++; + return STATUS_SUCCESS; + } + + last = curr = FileNameU.Buffer + FileNameU.Length / sizeof(WCHAR) - 1; + while (*curr != L'\\' && curr > FileNameU.Buffer) + { + curr--; + } + + if (curr > FileNameU.Buffer) + { + NameU.Buffer = FileNameU.Buffer; + NameU.MaximumLength = NameU.Length = (curr - FileNameU.Buffer) * sizeof(WCHAR); + FCB = vfatGrabFCBFromTable(pVCB, &NameU); + if (FCB) + { + Length = (curr - FileNameU.Buffer) * sizeof(WCHAR); + if (Length != FCB->PathNameU.Length) + { + if (FileNameU.Length + FCB->PathNameU.Length - Length > FileNameU.MaximumLength) + { + vfatReleaseFCB (pVCB, FCB); + return STATUS_OBJECT_NAME_INVALID; + } + RtlMoveMemory(FileNameU.Buffer + FCB->PathNameU.Length / sizeof(WCHAR), + curr, FileNameU.Length - Length); + FileNameU.Length += (USHORT)(FCB->PathNameU.Length - Length); + curr = FileNameU.Buffer + FCB->PathNameU.Length / sizeof(WCHAR); + last = FileNameU.Buffer + FileNameU.Length / sizeof(WCHAR) - 1; + } + RtlCopyMemory(FileNameU.Buffer, FCB->PathNameU.Buffer, FCB->PathNameU.Length); + } + } + else + { + FCB = NULL; + } + + if (FCB == NULL) + { + FCB = vfatOpenRootFCB(pVCB); + curr = FileNameU.Buffer; + } + + parentFCB = NULL; + prev = curr; + } + else + { + FCB = parentFCB; + parentFCB = NULL; + prev = curr = FileNameU.Buffer - 1; + last = FileNameU.Buffer + FileNameU.Length / sizeof(WCHAR) - 1; + } + + while (curr <= last) + { + if (parentFCB) + { + vfatReleaseFCB (pVCB, parentFCB); + parentFCB = 0; + } + // fail if element in FCB is not a directory + if (!vfatFCBIsDirectory (FCB)) + { + DPRINT ("Element in requested path is not a directory\n"); + + vfatReleaseFCB (pVCB, FCB); + FCB = NULL; + *pParentFCB = NULL; + *pFCB = NULL; + + return STATUS_OBJECT_PATH_NOT_FOUND; + } + parentFCB = FCB; + if (prev < curr) + { + Length = (curr - prev) * sizeof(WCHAR); + if (Length != parentFCB->LongNameU.Length) + { + if (FileNameU.Length + parentFCB->LongNameU.Length - Length > FileNameU.MaximumLength) + { + vfatReleaseFCB (pVCB, parentFCB); + return STATUS_OBJECT_NAME_INVALID; + } + RtlMoveMemory(prev + parentFCB->LongNameU.Length / sizeof(WCHAR), curr, + FileNameU.Length - (curr - FileNameU.Buffer) * sizeof(WCHAR)); + FileNameU.Length += (USHORT)(parentFCB->LongNameU.Length - Length); + curr = prev + parentFCB->LongNameU.Length / sizeof(WCHAR); + last = FileNameU.Buffer + FileNameU.Length / sizeof(WCHAR) - 1; + } + RtlCopyMemory(prev, parentFCB->LongNameU.Buffer, parentFCB->LongNameU.Length); + } + curr++; + prev = curr; + while (*curr != L'\\' && curr <= last) + { + curr++; + } + NameU.Buffer = FileNameU.Buffer; + NameU.Length = (curr - NameU.Buffer) * sizeof(WCHAR); + NameU.MaximumLength = FileNameU.MaximumLength; + DPRINT("%wZ\n", &NameU); + FCB = vfatGrabFCBFromTable(pVCB, &NameU); + if (FCB == NULL) + { + NameU.Buffer = prev; + NameU.MaximumLength = NameU.Length = (curr - prev) * sizeof(WCHAR); + status = vfatDirFindFile(pVCB, parentFCB, &NameU, &FCB); + if (status == STATUS_OBJECT_NAME_NOT_FOUND) + { + *pFCB = NULL; + if (curr > last) + { + *pParentFCB = parentFCB; + return STATUS_OBJECT_NAME_NOT_FOUND; + } + else + { + vfatReleaseFCB (pVCB, parentFCB); + *pParentFCB = NULL; + return STATUS_OBJECT_PATH_NOT_FOUND; + } + } + else if (!NT_SUCCESS (status)) + { + vfatReleaseFCB (pVCB, parentFCB); + *pParentFCB = NULL; + *pFCB = NULL; + + return status; + } + } + } + + *pParentFCB = parentFCB; + *pFCB = FCB; + + return STATUS_SUCCESS; +} + diff --git a/reactos/drivers/filesystems/fastfat_new/finfo.c b/reactos/drivers/filesystems/fastfat_new/finfo.c new file mode 100644 index 00000000000..6864a2d4dcb --- /dev/null +++ b/reactos/drivers/filesystems/fastfat_new/finfo.c @@ -0,0 +1,948 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: drivers/fs/vfat/finfo.c + * PURPOSE: VFAT Filesystem + * PROGRAMMER: Jason Filby (jasonfilby@yahoo.com) + * Herve Poussineau (reactos@poussine.freesurf.fr) + * + */ + +/* INCLUDES *****************************************************************/ + +#define NDEBUG +#include "vfat.h" + +/* GLOBALS ******************************************************************/ + +const char* FileInformationClassNames[] = +{ + "??????", + "FileDirectoryInformation", + "FileFullDirectoryInformation", + "FileBothDirectoryInformation", + "FileBasicInformation", + "FileStandardInformation", + "FileInternalInformation", + "FileEaInformation", + "FileAccessInformation", + "FileNameInformation", + "FileRenameInformation", + "FileLinkInformation", + "FileNamesInformation", + "FileDispositionInformation", + "FilePositionInformation", + "FileFullEaInformation", + "FileModeInformation", + "FileAlignmentInformation", + "FileAllInformation", + "FileAllocationInformation", + "FileEndOfFileInformation", + "FileAlternateNameInformation", + "FileStreamInformation", + "FilePipeInformation", + "FilePipeLocalInformation", + "FilePipeRemoteInformation", + "FileMailslotQueryInformation", + "FileMailslotSetInformation", + "FileCompressionInformation", + "FileObjectIdInformation", + "FileCompletionInformation", + "FileMoveClusterInformation", + "FileQuotaInformation", + "FileReparsePointInformation", + "FileNetworkOpenInformation", + "FileAttributeTagInformation", + "FileTrackingInformation", + "FileIdBothDirectoryInformation", + "FileIdFullDirectoryInformation", + "FileValidDataLengthInformation", + "FileShortNameInformation", + "FileMaximumInformation" +}; + +/* FUNCTIONS ****************************************************************/ + +static NTSTATUS +VfatGetStandardInformation(PVFATFCB FCB, + PFILE_STANDARD_INFORMATION StandardInfo, + PULONG BufferLength) +/* + * FUNCTION: Retrieve the standard file information + */ +{ + + if (*BufferLength < sizeof(FILE_STANDARD_INFORMATION)) + return STATUS_BUFFER_OVERFLOW; + + /* PRECONDITION */ + ASSERT(StandardInfo != NULL); + ASSERT(FCB != NULL); + + if (vfatFCBIsDirectory(FCB)) + { + StandardInfo->AllocationSize.QuadPart = 0; + StandardInfo->EndOfFile.QuadPart = 0; + StandardInfo->Directory = TRUE; + } + else + { + StandardInfo->AllocationSize = FCB->RFCB.AllocationSize; + StandardInfo->EndOfFile = FCB->RFCB.FileSize; + StandardInfo->Directory = FALSE; + } + StandardInfo->NumberOfLinks = 1; + StandardInfo->DeletePending = FCB->Flags & FCB_DELETE_PENDING ? TRUE : FALSE; + + *BufferLength -= sizeof(FILE_STANDARD_INFORMATION); + return(STATUS_SUCCESS); +} + +static NTSTATUS +VfatSetPositionInformation(PFILE_OBJECT FileObject, + PFILE_POSITION_INFORMATION PositionInfo) +{ + DPRINT ("FsdSetPositionInformation()\n"); + + DPRINT ("PositionInfo %p\n", PositionInfo); + DPRINT ("Setting position %d\n", PositionInfo->CurrentByteOffset.u.LowPart); + + FileObject->CurrentByteOffset.QuadPart = + PositionInfo->CurrentByteOffset.QuadPart; + + return (STATUS_SUCCESS); +} + +static NTSTATUS +VfatGetPositionInformation(PFILE_OBJECT FileObject, + PVFATFCB FCB, + PDEVICE_OBJECT DeviceObject, + PFILE_POSITION_INFORMATION PositionInfo, + PULONG BufferLength) +{ + DPRINT ("VfatGetPositionInformation()\n"); + + if (*BufferLength < sizeof(FILE_POSITION_INFORMATION)) + return STATUS_BUFFER_OVERFLOW; + + PositionInfo->CurrentByteOffset.QuadPart = + FileObject->CurrentByteOffset.QuadPart; + + DPRINT("Getting position %I64x\n", + PositionInfo->CurrentByteOffset.QuadPart); + + *BufferLength -= sizeof(FILE_POSITION_INFORMATION); + return(STATUS_SUCCESS); +} + +static NTSTATUS +VfatSetBasicInformation(PFILE_OBJECT FileObject, + PVFATFCB FCB, + PDEVICE_EXTENSION DeviceExt, + PFILE_BASIC_INFORMATION BasicInfo) +{ + DPRINT("VfatSetBasicInformation()\n"); + + ASSERT(NULL != FileObject); + ASSERT(NULL != FCB); + ASSERT(NULL != DeviceExt); + ASSERT(NULL != BasicInfo); + /* Check volume label bit */ + ASSERT(0 == (*FCB->Attributes & 0x08)); + + if (FCB->Flags & FCB_IS_FATX_ENTRY) + { + FsdSystemTimeToDosDateTime(DeviceExt, + &BasicInfo->CreationTime, + &FCB->entry.FatX.CreationDate, + &FCB->entry.FatX.CreationTime); + FsdSystemTimeToDosDateTime(DeviceExt, + &BasicInfo->LastAccessTime, + &FCB->entry.FatX.AccessDate, + &FCB->entry.FatX.AccessTime); + FsdSystemTimeToDosDateTime(DeviceExt, + &BasicInfo->LastWriteTime, + &FCB->entry.FatX.UpdateDate, + &FCB->entry.FatX.UpdateTime); + } + else + { + FsdSystemTimeToDosDateTime(DeviceExt, + &BasicInfo->CreationTime, + &FCB->entry.Fat.CreationDate, + &FCB->entry.Fat.CreationTime); + FsdSystemTimeToDosDateTime(DeviceExt, + &BasicInfo->LastAccessTime, + &FCB->entry.Fat.AccessDate, + NULL); + FsdSystemTimeToDosDateTime(DeviceExt, + &BasicInfo->LastWriteTime, + &FCB->entry.Fat.UpdateDate, + &FCB->entry.Fat.UpdateTime); + } + + *FCB->Attributes = (unsigned char)((*FCB->Attributes & + (FILE_ATTRIBUTE_DIRECTORY | 0x48)) | + (BasicInfo->FileAttributes & + (FILE_ATTRIBUTE_ARCHIVE | + FILE_ATTRIBUTE_SYSTEM | + FILE_ATTRIBUTE_HIDDEN | + FILE_ATTRIBUTE_READONLY))); + DPRINT("Setting attributes 0x%02x\n", *FCB->Attributes); + + VfatUpdateEntry(FCB); + + return(STATUS_SUCCESS); +} + +static NTSTATUS +VfatGetBasicInformation(PFILE_OBJECT FileObject, + PVFATFCB FCB, + PDEVICE_OBJECT DeviceObject, + PFILE_BASIC_INFORMATION BasicInfo, + PULONG BufferLength) +{ + PDEVICE_EXTENSION DeviceExt; + DPRINT("VfatGetBasicInformation()\n"); + + DeviceExt = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension; + + if (*BufferLength < sizeof(FILE_BASIC_INFORMATION)) + return STATUS_BUFFER_OVERFLOW; + + if (FCB->Flags & FCB_IS_FATX_ENTRY) + { + FsdDosDateTimeToSystemTime(DeviceExt, + FCB->entry.FatX.CreationDate, + FCB->entry.FatX.CreationTime, + &BasicInfo->CreationTime); + FsdDosDateTimeToSystemTime(DeviceExt, + FCB->entry.FatX.AccessDate, + FCB->entry.FatX.AccessTime, + &BasicInfo->LastAccessTime); + FsdDosDateTimeToSystemTime(DeviceExt, + FCB->entry.FatX.UpdateDate, + FCB->entry.FatX.UpdateTime, + &BasicInfo->LastWriteTime); + BasicInfo->ChangeTime = BasicInfo->LastWriteTime; + } + else + { + FsdDosDateTimeToSystemTime(DeviceExt, + FCB->entry.Fat.CreationDate, + FCB->entry.Fat.CreationTime, + &BasicInfo->CreationTime); + FsdDosDateTimeToSystemTime(DeviceExt, + FCB->entry.Fat.AccessDate, + 0, + &BasicInfo->LastAccessTime); + FsdDosDateTimeToSystemTime(DeviceExt, + FCB->entry.Fat.UpdateDate, + FCB->entry.Fat.UpdateTime, + &BasicInfo->LastWriteTime); + BasicInfo->ChangeTime = BasicInfo->LastWriteTime; + } + + BasicInfo->FileAttributes = *FCB->Attributes & 0x3f; + /* Synthesize FILE_ATTRIBUTE_NORMAL */ + if (0 == (BasicInfo->FileAttributes & (FILE_ATTRIBUTE_DIRECTORY | + FILE_ATTRIBUTE_ARCHIVE | + FILE_ATTRIBUTE_SYSTEM | + FILE_ATTRIBUTE_HIDDEN | + FILE_ATTRIBUTE_READONLY))) + { + DPRINT("Synthesizing FILE_ATTRIBUTE_NORMAL\n"); + BasicInfo->FileAttributes |= FILE_ATTRIBUTE_NORMAL; + } + DPRINT("Getting attributes 0x%02x\n", BasicInfo->FileAttributes); + + *BufferLength -= sizeof(FILE_BASIC_INFORMATION); + return(STATUS_SUCCESS); +} + + +static NTSTATUS +VfatSetDispositionInformation(PFILE_OBJECT FileObject, + PVFATFCB FCB, + PDEVICE_OBJECT DeviceObject, + PFILE_DISPOSITION_INFORMATION DispositionInfo) +{ +#ifdef DBG + PDEVICE_EXTENSION DeviceExt = DeviceObject->DeviceExtension; +#endif + + DPRINT ("FsdSetDispositionInformation(<%wZ>, Delete %d)\n", &FCB->PathNameU, DispositionInfo->DeleteFile); + + ASSERT(DeviceExt != NULL); + ASSERT(DeviceExt->FatInfo.BytesPerCluster != 0); + ASSERT(FCB != NULL); + + if (!DispositionInfo->DeleteFile) + { + /* undelete the file */ + FCB->Flags &= ~FCB_DELETE_PENDING; + FileObject->DeletePending = FALSE; + return STATUS_SUCCESS; + } + + if (FCB->Flags & FCB_DELETE_PENDING) + { + /* stream already marked for deletion. just update the file object */ + FileObject->DeletePending = TRUE; + return STATUS_SUCCESS; + } + + if (*FCB->Attributes & FILE_ATTRIBUTE_READONLY) + { + return STATUS_CANNOT_DELETE; + } + + if (vfatFCBIsRoot(FCB) || + (FCB->LongNameU.Length == sizeof(WCHAR) && FCB->LongNameU.Buffer[0] == L'.') || + (FCB->LongNameU.Length == 2 * sizeof(WCHAR) && FCB->LongNameU.Buffer[0] == L'.' && FCB->LongNameU.Buffer[1] == L'.')) + { + // we cannot delete a '.', '..' or the root directory + return STATUS_ACCESS_DENIED; + } + + + if (!MmFlushImageSection (FileObject->SectionObjectPointer, MmFlushForDelete)) + { + /* can't delete a file if its mapped into a process */ + + DPRINT("MmFlushImageSection returned FALSE\n"); + return STATUS_CANNOT_DELETE; + } + + if (vfatFCBIsDirectory(FCB) && !VfatIsDirectoryEmpty(FCB)) + { + /* can't delete a non-empty directory */ + + return STATUS_DIRECTORY_NOT_EMPTY; + } + + /* all good */ + FCB->Flags |= FCB_DELETE_PENDING; + FileObject->DeletePending = TRUE; + + return STATUS_SUCCESS; +} + +static NTSTATUS +VfatGetNameInformation(PFILE_OBJECT FileObject, + PVFATFCB FCB, + PDEVICE_OBJECT DeviceObject, + PFILE_NAME_INFORMATION NameInfo, + PULONG BufferLength) +/* + * FUNCTION: Retrieve the file name information + */ +{ + ULONG BytesToCopy; + ASSERT(NameInfo != NULL); + ASSERT(FCB != NULL); + + /* If buffer can't hold at least the file name length, bail out */ + if (*BufferLength < FIELD_OFFSET(FILE_NAME_INFORMATION, FileName[0])) + return STATUS_BUFFER_OVERFLOW; + + /* Save file name length, and as much file len, as buffer length allows */ + NameInfo->FileNameLength = FCB->PathNameU.Length; + + /* Calculate amount of bytes to copy not to overflow the buffer */ + BytesToCopy = min(FCB->PathNameU.Length, + *BufferLength - FIELD_OFFSET(FILE_NAME_INFORMATION, FileName[0])); + + /* Fill in the bytes */ + RtlCopyMemory(NameInfo->FileName, FCB->PathNameU.Buffer, BytesToCopy); + + /* Check if we could write more but are not able to */ + if (*BufferLength < FCB->PathNameU.Length + (ULONG)FIELD_OFFSET(FILE_NAME_INFORMATION, FileName[0])) + { + /* Return number of bytes written */ + *BufferLength -= FIELD_OFFSET(FILE_NAME_INFORMATION, FileName[0]) + BytesToCopy; + return STATUS_BUFFER_OVERFLOW; + } + + /* We filled up as many bytes, as needed */ + *BufferLength -= (FIELD_OFFSET(FILE_NAME_INFORMATION, FileName[0]) + FCB->PathNameU.Length); + + return STATUS_SUCCESS; +} + +static NTSTATUS +VfatGetInternalInformation(PVFATFCB Fcb, + PFILE_INTERNAL_INFORMATION InternalInfo, + PULONG BufferLength) +{ + ASSERT(InternalInfo); + ASSERT(Fcb); + + if (*BufferLength < sizeof(FILE_INTERNAL_INFORMATION)) + return STATUS_BUFFER_OVERFLOW; + // FIXME: get a real index, that can be used in a create operation + InternalInfo->IndexNumber.QuadPart = 0; + *BufferLength -= sizeof(FILE_INTERNAL_INFORMATION); + return STATUS_SUCCESS; +} + + +static NTSTATUS +VfatGetNetworkOpenInformation(PVFATFCB Fcb, + PDEVICE_EXTENSION DeviceExt, + PFILE_NETWORK_OPEN_INFORMATION NetworkInfo, + PULONG BufferLength) +/* + * FUNCTION: Retrieve the file network open information + */ +{ + ASSERT(NetworkInfo); + ASSERT(Fcb); + + if (*BufferLength < sizeof(FILE_NETWORK_OPEN_INFORMATION)) + return(STATUS_BUFFER_OVERFLOW); + + if (Fcb->Flags & FCB_IS_FATX_ENTRY) + { + FsdDosDateTimeToSystemTime(DeviceExt, + Fcb->entry.FatX.CreationDate, + Fcb->entry.FatX.CreationTime, + &NetworkInfo->CreationTime); + FsdDosDateTimeToSystemTime(DeviceExt, + Fcb->entry.FatX.AccessDate, + Fcb->entry.FatX.AccessTime, + &NetworkInfo->LastAccessTime); + FsdDosDateTimeToSystemTime(DeviceExt, + Fcb->entry.FatX.UpdateDate, + Fcb->entry.FatX.UpdateTime, + &NetworkInfo->LastWriteTime); + NetworkInfo->ChangeTime.QuadPart = NetworkInfo->LastWriteTime.QuadPart; + } + else + { + FsdDosDateTimeToSystemTime(DeviceExt, + Fcb->entry.Fat.CreationDate, + Fcb->entry.Fat.CreationTime, + &NetworkInfo->CreationTime); + FsdDosDateTimeToSystemTime(DeviceExt, + Fcb->entry.Fat.AccessDate, + 0, + &NetworkInfo->LastAccessTime); + FsdDosDateTimeToSystemTime(DeviceExt, + Fcb->entry.Fat.UpdateDate, + Fcb->entry.Fat.UpdateTime, + &NetworkInfo->LastWriteTime); + NetworkInfo->ChangeTime.QuadPart = NetworkInfo->LastWriteTime.QuadPart; + } + if (vfatFCBIsDirectory(Fcb)) + { + NetworkInfo->EndOfFile.QuadPart = 0L; + NetworkInfo->AllocationSize.QuadPart = 0L; + } + else + { + NetworkInfo->AllocationSize = Fcb->RFCB.AllocationSize; + NetworkInfo->EndOfFile = Fcb->RFCB.FileSize; + } + NetworkInfo->FileAttributes = *Fcb->Attributes & 0x3f; + /* Synthesize FILE_ATTRIBUTE_NORMAL */ + if (0 == (NetworkInfo->FileAttributes & (FILE_ATTRIBUTE_DIRECTORY | + FILE_ATTRIBUTE_ARCHIVE | + FILE_ATTRIBUTE_SYSTEM | + FILE_ATTRIBUTE_HIDDEN | + FILE_ATTRIBUTE_READONLY))) + { + DPRINT("Synthesizing FILE_ATTRIBUTE_NORMAL\n"); + NetworkInfo->FileAttributes |= FILE_ATTRIBUTE_NORMAL; + } + + *BufferLength -= sizeof(FILE_NETWORK_OPEN_INFORMATION); + return STATUS_SUCCESS; +} + + +static NTSTATUS +VfatGetEaInformation(PFILE_OBJECT FileObject, + PVFATFCB Fcb, + PDEVICE_OBJECT DeviceObject, + PFILE_EA_INFORMATION Info, + PULONG BufferLength) +{ + PDEVICE_EXTENSION DeviceExt = DeviceObject->DeviceExtension; + + /* FIXME - use SEH to access the buffer! */ + Info->EaSize = 0; + *BufferLength -= sizeof(*Info); + if (DeviceExt->FatInfo.FatType == FAT12 || + DeviceExt->FatInfo.FatType == FAT16) + { + /* FIXME */ + DPRINT1("VFAT: FileEaInformation not implemented!\n"); + } + return STATUS_SUCCESS; +} + + +static NTSTATUS +VfatGetAllInformation(PFILE_OBJECT FileObject, + PVFATFCB Fcb, + PDEVICE_OBJECT DeviceObject, + PFILE_ALL_INFORMATION Info, + PULONG BufferLength) +/* + * FUNCTION: Retrieve the all file information + */ +{ + NTSTATUS Status; + ULONG InitialBufferLength = *BufferLength; + + ASSERT(Info); + ASSERT(Fcb); + + if (*BufferLength < sizeof(FILE_ALL_INFORMATION) + Fcb->PathNameU.Length + sizeof(WCHAR)) + return(STATUS_BUFFER_OVERFLOW); + + /* Basic Information */ + Status = VfatGetBasicInformation(FileObject, Fcb, DeviceObject, &Info->BasicInformation, BufferLength); + if (!NT_SUCCESS(Status)) return Status; + /* Standard Information */ + Status = VfatGetStandardInformation(Fcb, &Info->StandardInformation, BufferLength); + if (!NT_SUCCESS(Status)) return Status; + /* Internal Information */ + Status = VfatGetInternalInformation(Fcb, &Info->InternalInformation, BufferLength); + if (!NT_SUCCESS(Status)) return Status; + /* EA Information */ + Info->EaInformation.EaSize = 0; + /* Access Information: The IO-Manager adds this information */ + /* Position Information */ + Status = VfatGetPositionInformation(FileObject, Fcb, DeviceObject, &Info->PositionInformation, BufferLength); + if (!NT_SUCCESS(Status)) return Status; + /* Mode Information: The IO-Manager adds this information */ + /* Alignment Information: The IO-Manager adds this information */ + /* Name Information */ + Status = VfatGetNameInformation(FileObject, Fcb, DeviceObject, &Info->NameInformation, BufferLength); + if (!NT_SUCCESS(Status)) return Status; + + *BufferLength = InitialBufferLength - (sizeof(FILE_ALL_INFORMATION) + Fcb->PathNameU.Length + sizeof(WCHAR)); + + return STATUS_SUCCESS; +} + +static VOID UpdateFileSize(PFILE_OBJECT FileObject, PVFATFCB Fcb, ULONG Size, ULONG ClusterSize) +{ + if (Size > 0) + { + Fcb->RFCB.AllocationSize.QuadPart = ROUND_UP(Size, ClusterSize); + } + else + { + Fcb->RFCB.AllocationSize.QuadPart = (LONGLONG)0; + } + if (!vfatFCBIsDirectory(Fcb)) + { + if (Fcb->Flags & FCB_IS_FATX_ENTRY) + Fcb->entry.FatX.FileSize = Size; + else + Fcb->entry.Fat.FileSize = Size; + } + Fcb->RFCB.FileSize.QuadPart = Size; + Fcb->RFCB.ValidDataLength.QuadPart = Size; + + if (FileObject->SectionObjectPointer->SharedCacheMap != NULL) + { + CcSetFileSizes(FileObject, (PCC_FILE_SIZES)&Fcb->RFCB.AllocationSize); + } +} + +NTSTATUS +VfatSetAllocationSizeInformation(PFILE_OBJECT FileObject, + PVFATFCB Fcb, + PDEVICE_EXTENSION DeviceExt, + PLARGE_INTEGER AllocationSize) +{ + ULONG OldSize; + ULONG Cluster, FirstCluster; + NTSTATUS Status; + + ULONG ClusterSize = DeviceExt->FatInfo.BytesPerCluster; + ULONG NewSize = AllocationSize->u.LowPart; + ULONG NCluster; + BOOLEAN AllocSizeChanged = FALSE; + + DPRINT("VfatSetAllocationSizeInformation(File <%wZ>, AllocationSize %d %d)\n", &Fcb->PathNameU, + AllocationSize->HighPart, AllocationSize->LowPart); + + if (Fcb->Flags & FCB_IS_FATX_ENTRY) + OldSize = Fcb->entry.FatX.FileSize; + else + OldSize = Fcb->entry.Fat.FileSize; + if (AllocationSize->u.HighPart > 0) + { + return STATUS_INVALID_PARAMETER; + } + if (OldSize == NewSize) + { + return(STATUS_SUCCESS); + } + + FirstCluster = vfatDirEntryGetFirstCluster (DeviceExt, &Fcb->entry); + + if (NewSize > Fcb->RFCB.AllocationSize.u.LowPart) + { + AllocSizeChanged = TRUE; + if (FirstCluster == 0) + { + Fcb->LastCluster = Fcb->LastOffset = 0; + Status = NextCluster (DeviceExt, FirstCluster, &FirstCluster, TRUE); + if (!NT_SUCCESS(Status)) + { + DPRINT1("NextCluster failed. Status = %x\n", Status); + return Status; + } + if (FirstCluster == 0xffffffff) + { + return STATUS_DISK_FULL; + } + Status = OffsetToCluster(DeviceExt, FirstCluster, + ROUND_DOWN(NewSize - 1, ClusterSize), + &NCluster, TRUE); + if (NCluster == 0xffffffff || !NT_SUCCESS(Status)) + { + /* disk is full */ + NCluster = Cluster = FirstCluster; + Status = STATUS_SUCCESS; + while (NT_SUCCESS(Status) && Cluster != 0xffffffff && Cluster > 1) + { + Status = NextCluster (DeviceExt, FirstCluster, &NCluster, FALSE); + WriteCluster (DeviceExt, Cluster, 0); + Cluster = NCluster; + } + return STATUS_DISK_FULL; + } + if (Fcb->Flags & FCB_IS_FATX_ENTRY) + { + Fcb->entry.FatX.FirstCluster = FirstCluster; + } + else + { + if (DeviceExt->FatInfo.FatType == FAT32) + { + Fcb->entry.Fat.FirstCluster = (unsigned short)(FirstCluster & 0x0000FFFF); + Fcb->entry.Fat.FirstClusterHigh = FirstCluster >> 16; + } + else + { + ASSERT((FirstCluster >> 16) == 0); + Fcb->entry.Fat.FirstCluster = (unsigned short)(FirstCluster & 0x0000FFFF); + } + } + } + else + { + if (Fcb->LastCluster > 0) + { + if (Fcb->RFCB.AllocationSize.u.LowPart - ClusterSize == Fcb->LastOffset) + { + Cluster = Fcb->LastCluster; + Status = STATUS_SUCCESS; + } + else + { + Status = OffsetToCluster(DeviceExt, Fcb->LastCluster, + Fcb->RFCB.AllocationSize.u.LowPart - ClusterSize - Fcb->LastOffset, + &Cluster, FALSE); + } + } + else + { + Status = OffsetToCluster(DeviceExt, FirstCluster, + Fcb->RFCB.AllocationSize.u.LowPart - ClusterSize, + &Cluster, FALSE); + } + if (!NT_SUCCESS(Status)) + { + return Status; + } + + Fcb->LastCluster = Cluster; + Fcb->LastOffset = Fcb->RFCB.AllocationSize.u.LowPart - ClusterSize; + + /* FIXME: Check status */ + /* Cluster points now to the last cluster within the chain */ + Status = OffsetToCluster(DeviceExt, Cluster, + ROUND_DOWN(NewSize - 1, ClusterSize) - Fcb->LastOffset, + &NCluster, TRUE); + if (NCluster == 0xffffffff || !NT_SUCCESS(Status)) + { + /* disk is full */ + NCluster = Cluster; + Status = NextCluster (DeviceExt, FirstCluster, &NCluster, FALSE); + WriteCluster(DeviceExt, Cluster, 0xffffffff); + Cluster = NCluster; + while (NT_SUCCESS(Status) && Cluster != 0xffffffff && Cluster > 1) + { + Status = NextCluster (DeviceExt, FirstCluster, &NCluster, FALSE); + WriteCluster (DeviceExt, Cluster, 0); + Cluster = NCluster; + } + return STATUS_DISK_FULL; + } + } + UpdateFileSize(FileObject, Fcb, NewSize, ClusterSize); + } + else if (NewSize + ClusterSize <= Fcb->RFCB.AllocationSize.u.LowPart) + { + AllocSizeChanged = TRUE; + /* FIXME: Use the cached cluster/offset better way. */ + Fcb->LastCluster = Fcb->LastOffset = 0; + UpdateFileSize(FileObject, Fcb, NewSize, ClusterSize); + if (NewSize > 0) + { + Status = OffsetToCluster(DeviceExt, FirstCluster, + ROUND_DOWN(NewSize - 1, ClusterSize), + &Cluster, FALSE); + + NCluster = Cluster; + Status = NextCluster (DeviceExt, FirstCluster, &NCluster, FALSE); + WriteCluster(DeviceExt, Cluster, 0xffffffff); + Cluster = NCluster; + } + else + { + if (Fcb->Flags & FCB_IS_FATX_ENTRY) + { + Fcb->entry.FatX.FirstCluster = 0; + } + else + { + if (DeviceExt->FatInfo.FatType == FAT32) + { + Fcb->entry.Fat.FirstCluster = 0; + Fcb->entry.Fat.FirstClusterHigh = 0; + } + else + { + Fcb->entry.Fat.FirstCluster = 0; + } + } + + NCluster = Cluster = FirstCluster; + Status = STATUS_SUCCESS; + } + while (NT_SUCCESS(Status) && 0xffffffff != Cluster && Cluster > 1) + { + Status = NextCluster (DeviceExt, FirstCluster, &NCluster, FALSE); + WriteCluster (DeviceExt, Cluster, 0); + Cluster = NCluster; + } + } + else + { + UpdateFileSize(FileObject, Fcb, NewSize, ClusterSize); + } + /* Update the on-disk directory entry */ + Fcb->Flags |= FCB_IS_DIRTY; + if (AllocSizeChanged) + { + VfatUpdateEntry(Fcb); + } + return STATUS_SUCCESS; +} + +NTSTATUS VfatQueryInformation(PVFAT_IRP_CONTEXT IrpContext) +/* + * FUNCTION: Retrieve the specified file information + */ +{ + FILE_INFORMATION_CLASS FileInformationClass; + PVFATFCB FCB = NULL; + + NTSTATUS Status = STATUS_SUCCESS; + PVOID SystemBuffer; + ULONG BufferLength; + + /* PRECONDITION */ + ASSERT(IrpContext); + + /* INITIALIZATION */ + FileInformationClass = IrpContext->Stack->Parameters.QueryFile.FileInformationClass; + FCB = (PVFATFCB) IrpContext->FileObject->FsContext; + + DPRINT("VfatQueryInformation is called for '%s'\n", + FileInformationClass >= FileMaximumInformation - 1 ? "????" : FileInformationClassNames[FileInformationClass]); + + + SystemBuffer = IrpContext->Irp->AssociatedIrp.SystemBuffer; + BufferLength = IrpContext->Stack->Parameters.QueryFile.Length; + + if (!(FCB->Flags & FCB_IS_PAGE_FILE)) + { + if (!ExAcquireResourceSharedLite(&FCB->MainResource, + (BOOLEAN)(IrpContext->Flags & IRPCONTEXT_CANWAIT))) + { + return VfatQueueRequest (IrpContext); + } + } + + + switch (FileInformationClass) + { + case FileStandardInformation: + Status = VfatGetStandardInformation(FCB, + SystemBuffer, + &BufferLength); + break; + case FilePositionInformation: + Status = VfatGetPositionInformation(IrpContext->FileObject, + FCB, + IrpContext->DeviceObject, + SystemBuffer, + &BufferLength); + break; + case FileBasicInformation: + Status = VfatGetBasicInformation(IrpContext->FileObject, + FCB, + IrpContext->DeviceObject, + SystemBuffer, + &BufferLength); + break; + case FileNameInformation: + Status = VfatGetNameInformation(IrpContext->FileObject, + FCB, + IrpContext->DeviceObject, + SystemBuffer, + &BufferLength); + break; + case FileInternalInformation: + Status = VfatGetInternalInformation(FCB, + SystemBuffer, + &BufferLength); + break; + case FileNetworkOpenInformation: + Status = VfatGetNetworkOpenInformation(FCB, + IrpContext->DeviceExt, + SystemBuffer, + &BufferLength); + break; + case FileAllInformation: + Status = VfatGetAllInformation(IrpContext->FileObject, + FCB, + IrpContext->DeviceObject, + SystemBuffer, + &BufferLength); + break; + + case FileEaInformation: + Status = VfatGetEaInformation(IrpContext->FileObject, + FCB, + IrpContext->DeviceObject, + SystemBuffer, + &BufferLength); + break; + + case FileAlternateNameInformation: + Status = STATUS_NOT_IMPLEMENTED; + break; + default: + Status = STATUS_INVALID_PARAMETER; + } + + if (!(FCB->Flags & FCB_IS_PAGE_FILE)) + { + ExReleaseResourceLite(&FCB->MainResource); + } + IrpContext->Irp->IoStatus.Status = Status; + if (NT_SUCCESS(Status) || Status == STATUS_BUFFER_OVERFLOW) + IrpContext->Irp->IoStatus.Information = + IrpContext->Stack->Parameters.QueryFile.Length - BufferLength; + else + IrpContext->Irp->IoStatus.Information = 0; + IoCompleteRequest(IrpContext->Irp, IO_NO_INCREMENT); + VfatFreeIrpContext(IrpContext); + + return Status; +} + +NTSTATUS VfatSetInformation(PVFAT_IRP_CONTEXT IrpContext) +/* + * FUNCTION: Retrieve the specified file information + */ +{ + FILE_INFORMATION_CLASS FileInformationClass; + PVFATFCB FCB = NULL; + NTSTATUS RC = STATUS_SUCCESS; + PVOID SystemBuffer; + BOOLEAN CanWait = (IrpContext->Flags & IRPCONTEXT_CANWAIT) != 0; + + /* PRECONDITION */ + ASSERT(IrpContext); + + DPRINT("VfatSetInformation(IrpContext %p)\n", IrpContext); + + /* INITIALIZATION */ + FileInformationClass = + IrpContext->Stack->Parameters.SetFile.FileInformationClass; + FCB = (PVFATFCB) IrpContext->FileObject->FsContext; + SystemBuffer = IrpContext->Irp->AssociatedIrp.SystemBuffer; + + DPRINT("VfatSetInformation is called for '%s'\n", + FileInformationClass >= FileMaximumInformation - 1 ? "????" : FileInformationClassNames[ FileInformationClass]); + + DPRINT("FileInformationClass %d\n", FileInformationClass); + DPRINT("SystemBuffer %p\n", SystemBuffer); + + if (!(FCB->Flags & FCB_IS_PAGE_FILE)) + { + if (!ExAcquireResourceExclusiveLite(&FCB->MainResource, + (BOOLEAN)CanWait)) + { + return(VfatQueueRequest (IrpContext)); + } + } + + switch (FileInformationClass) + { + case FilePositionInformation: + RC = VfatSetPositionInformation(IrpContext->FileObject, + SystemBuffer); + break; + case FileDispositionInformation: + RC = VfatSetDispositionInformation(IrpContext->FileObject, + FCB, + IrpContext->DeviceObject, + SystemBuffer); + break; + case FileAllocationInformation: + case FileEndOfFileInformation: + RC = VfatSetAllocationSizeInformation(IrpContext->FileObject, + FCB, + IrpContext->DeviceExt, + (PLARGE_INTEGER)SystemBuffer); + break; + case FileBasicInformation: + RC = VfatSetBasicInformation(IrpContext->FileObject, + FCB, + IrpContext->DeviceExt, + SystemBuffer); + break; + case FileRenameInformation: + RC = STATUS_NOT_IMPLEMENTED; + break; + default: + RC = STATUS_NOT_SUPPORTED; + } + + if (!(FCB->Flags & FCB_IS_PAGE_FILE)) + { + ExReleaseResourceLite(&FCB->MainResource); + } + + IrpContext->Irp->IoStatus.Status = RC; + IrpContext->Irp->IoStatus.Information = 0; + IoCompleteRequest(IrpContext->Irp, IO_NO_INCREMENT); + VfatFreeIrpContext(IrpContext); + + return RC; +} + +/* EOF */ diff --git a/reactos/drivers/filesystems/fastfat_new/flush.c b/reactos/drivers/filesystems/fastfat_new/flush.c new file mode 100644 index 00000000000..76a3c5d2cbc --- /dev/null +++ b/reactos/drivers/filesystems/fastfat_new/flush.c @@ -0,0 +1,140 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: drivers/fs/vfat/flush.c + * PURPOSE: VFAT Filesystem + * PROGRAMMER: + */ + +/* INCLUDES *****************************************************************/ + +#define NDEBUG +#include "vfat.h" + +/* FUNCTIONS ****************************************************************/ + +static NTSTATUS VfatFlushFile(PDEVICE_EXTENSION DeviceExt, PVFATFCB Fcb) +{ + IO_STATUS_BLOCK IoStatus; + NTSTATUS Status; + + DPRINT("VfatFlushFile(DeviceExt %p, Fcb %p) for '%wZ'\n", DeviceExt, Fcb, &Fcb->PathNameU); + + CcFlushCache(&Fcb->SectionObjectPointers, NULL, 0, &IoStatus); + if (IoStatus.Status == STATUS_INVALID_PARAMETER) + { + /* FIXME: Caching was possible not initialized */ + IoStatus.Status = STATUS_SUCCESS; + } + if (Fcb->Flags & FCB_IS_DIRTY) + { + Status = VfatUpdateEntry(Fcb); + if (!NT_SUCCESS(Status)) + { + IoStatus.Status = Status; + } + } + return IoStatus.Status; +} + +NTSTATUS VfatFlushVolume(PDEVICE_EXTENSION DeviceExt, PVFATFCB VolumeFcb) +{ + PLIST_ENTRY ListEntry; + PVFATFCB Fcb; + NTSTATUS Status, ReturnStatus = STATUS_SUCCESS; + + DPRINT("VfatFlushVolume(DeviceExt %p, FatFcb %p)\n", DeviceExt, VolumeFcb); + + ListEntry = DeviceExt->FcbListHead.Flink; + while (ListEntry != &DeviceExt->FcbListHead) + { + Fcb = CONTAINING_RECORD(ListEntry, VFATFCB, FcbListEntry); + ListEntry = ListEntry->Flink; + if (!vfatFCBIsDirectory(Fcb)) + { + ExAcquireResourceExclusiveLite(&Fcb->MainResource, TRUE); + Status = VfatFlushFile(DeviceExt, Fcb); + ExReleaseResourceLite (&Fcb->MainResource); + if (!NT_SUCCESS(Status)) + { + DPRINT1("VfatFlushFile failed, status = %x\n", Status); + ReturnStatus = Status; + } + } + /* FIXME: Stop flushing if this is a removable media and the media was removed */ + } + ListEntry = DeviceExt->FcbListHead.Flink; + while (ListEntry != &DeviceExt->FcbListHead) + { + Fcb = CONTAINING_RECORD(ListEntry, VFATFCB, FcbListEntry); + ListEntry = ListEntry->Flink; + if (vfatFCBIsDirectory(Fcb)) + { + ExAcquireResourceExclusiveLite(&Fcb->MainResource, TRUE); + Status = VfatFlushFile(DeviceExt, Fcb); + ExReleaseResourceLite (&Fcb->MainResource); + if (!NT_SUCCESS(Status)) + { + DPRINT1("VfatFlushFile failed, status = %x\n", Status); + ReturnStatus = Status; + } + } + /* FIXME: Stop flushing if this is a removable media and the media was removed */ + } + + Fcb = (PVFATFCB) DeviceExt->FATFileObject->FsContext; + + ExAcquireResourceExclusiveLite(&DeviceExt->FatResource, TRUE); + Status = VfatFlushFile(DeviceExt, Fcb); + ExReleaseResourceLite(&DeviceExt->FatResource); + + /* FIXME: Flush the buffers from storage device */ + + if (!NT_SUCCESS(Status)) + { + DPRINT1("VfatFlushFile failed, status = %x\n", Status); + ReturnStatus = Status; + } + + return ReturnStatus; +} + +NTSTATUS VfatFlush(PVFAT_IRP_CONTEXT IrpContext) +{ + NTSTATUS Status; + PVFATFCB Fcb; + /* + * This request is not allowed on the main device object. + */ + if (IrpContext->DeviceObject == VfatGlobalData->DeviceObject) + { + Status = STATUS_INVALID_DEVICE_REQUEST; + goto ByeBye; + } + + Fcb = (PVFATFCB)IrpContext->FileObject->FsContext; + ASSERT(Fcb); + + if (Fcb->Flags & FCB_IS_VOLUME) + { + ExAcquireResourceExclusiveLite(&IrpContext->DeviceExt->DirResource, TRUE); + Status = VfatFlushVolume(IrpContext->DeviceExt, Fcb); + ExReleaseResourceLite(&IrpContext->DeviceExt->DirResource); + } + else + { + ExAcquireResourceExclusiveLite(&Fcb->MainResource, TRUE); + Status = VfatFlushFile(IrpContext->DeviceExt, Fcb); + ExReleaseResourceLite (&Fcb->MainResource); + } + +ByeBye: + IrpContext->Irp->IoStatus.Status = Status; + IrpContext->Irp->IoStatus.Information = 0; + IoCompleteRequest (IrpContext->Irp, IO_NO_INCREMENT); + VfatFreeIrpContext(IrpContext); + + return (Status); +} + +/* EOF */ diff --git a/reactos/drivers/filesystems/fastfat_new/fsctl.c b/reactos/drivers/filesystems/fastfat_new/fsctl.c new file mode 100644 index 00000000000..05e26293863 --- /dev/null +++ b/reactos/drivers/filesystems/fastfat_new/fsctl.c @@ -0,0 +1,916 @@ +/* + * ReactOS kernel + * Copyright (C) 2002 ReactOS Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: drivers/fs/vfat/fsctl.c + * PURPOSE: VFAT Filesystem + */ + +/* INCLUDES *****************************************************************/ + +#define NDEBUG +#include "vfat.h" + +/* FUNCTIONS ****************************************************************/ + +#define CACHEPAGESIZE(pDeviceExt) ((pDeviceExt)->FatInfo.BytesPerCluster > PAGE_SIZE ? \ + (pDeviceExt)->FatInfo.BytesPerCluster : PAGE_SIZE) + +#define VOLUME_IS_DIRTY 0x00000001 + +static NTSTATUS +VfatHasFileSystem(PDEVICE_OBJECT DeviceToMount, + PBOOLEAN RecognizedFS, + PFATINFO pFatInfo) +{ + NTSTATUS Status; + PARTITION_INFORMATION PartitionInfo; + DISK_GEOMETRY DiskGeometry; + FATINFO FatInfo; + ULONG Size; + ULONG Sectors; + LARGE_INTEGER Offset; + struct _BootSector* Boot; + struct _BootSectorFatX* BootFatX; + BOOLEAN PartitionInfoIsValid = FALSE; + + DPRINT("VfatHasFileSystem\n"); + + *RecognizedFS = FALSE; + + Size = sizeof(DISK_GEOMETRY); + Status = VfatBlockDeviceIoControl(DeviceToMount, + IOCTL_DISK_GET_DRIVE_GEOMETRY, + NULL, + 0, + &DiskGeometry, + &Size, + FALSE); + if (!NT_SUCCESS(Status)) + { + DPRINT("VfatBlockDeviceIoControl faild (%x)\n", Status); + return Status; + } + FatInfo.FixedMedia = DiskGeometry.MediaType == FixedMedia ? TRUE : FALSE; + if (DiskGeometry.MediaType == FixedMedia || DiskGeometry.MediaType == RemovableMedia) + { + // We have found a hard disk + Size = sizeof(PARTITION_INFORMATION); + Status = VfatBlockDeviceIoControl(DeviceToMount, + IOCTL_DISK_GET_PARTITION_INFO, + NULL, + 0, + &PartitionInfo, + &Size, + FALSE); + if (!NT_SUCCESS(Status)) + { + DPRINT("VfatBlockDeviceIoControl faild (%x)\n", Status); + return Status; + } + PartitionInfoIsValid = TRUE; + DPRINT("Partition Information:\n"); + DPRINT("StartingOffset %u\n", PartitionInfo.StartingOffset.QuadPart / 512); + DPRINT("PartitionLength %u\n", PartitionInfo.PartitionLength.QuadPart / 512); + DPRINT("HiddenSectors %u\n", PartitionInfo.HiddenSectors); + DPRINT("PartitionNumber %u\n", PartitionInfo.PartitionNumber); + DPRINT("PartitionType %u\n", PartitionInfo.PartitionType); + DPRINT("BootIndicator %u\n", PartitionInfo.BootIndicator); + DPRINT("RecognizedPartition %u\n", PartitionInfo.RecognizedPartition); + DPRINT("RewritePartition %u\n", PartitionInfo.RewritePartition); + if (PartitionInfo.PartitionType) + { + if (PartitionInfo.PartitionType == PARTITION_FAT_12 || + PartitionInfo.PartitionType == PARTITION_FAT_16 || + PartitionInfo.PartitionType == PARTITION_HUGE || + PartitionInfo.PartitionType == PARTITION_FAT32 || + PartitionInfo.PartitionType == PARTITION_FAT32_XINT13 || + PartitionInfo.PartitionType == PARTITION_XINT13) + { + *RecognizedFS = TRUE; + } + } + else if (DiskGeometry.MediaType == RemovableMedia && + PartitionInfo.PartitionNumber > 0 && + PartitionInfo.StartingOffset.QuadPart == 0 && + PartitionInfo.PartitionLength.QuadPart > 0) + { + /* This is possible a removable media formated as super floppy */ + *RecognizedFS = TRUE; + } + } + else if (DiskGeometry.MediaType == Unknown) + { + /* + * Floppy disk driver can return Unknown as media type if it + * doesn't know yet what floppy in the drive really is. This is + * perfectly correct to do under Windows. + */ + *RecognizedFS = TRUE; + DiskGeometry.BytesPerSector = 512; + } + else + { + *RecognizedFS = TRUE; + } + if (*RecognizedFS) + { + + Boot = ExAllocatePoolWithTag(NonPagedPool, DiskGeometry.BytesPerSector, TAG_VFAT); + if (Boot == NULL) + { + return STATUS_INSUFFICIENT_RESOURCES; + } + + Offset.QuadPart = 0; + + /* Try to recognize FAT12/FAT16/FAT32 partitions */ + Status = VfatReadDisk(DeviceToMount, &Offset, DiskGeometry.BytesPerSector, (PUCHAR) Boot, FALSE); + if (NT_SUCCESS(Status)) + { + if (Boot->Signatur1 != 0xaa55) + { + *RecognizedFS = FALSE; + } + if (*RecognizedFS && + Boot->BytesPerSector != 512 && + Boot->BytesPerSector != 1024 && + Boot->BytesPerSector != 2048 && + Boot->BytesPerSector != 4096) + { + DPRINT1("BytesPerSector %d\n", Boot->BytesPerSector); + *RecognizedFS = FALSE; + } + + if (*RecognizedFS && + Boot->FATCount != 1 && + Boot->FATCount != 2) + { + DPRINT1("FATCount %d\n", Boot->FATCount); + *RecognizedFS = FALSE; + } + + if (*RecognizedFS && + Boot->Media != 0xf0 && + Boot->Media != 0xf8 && + Boot->Media != 0xf9 && + Boot->Media != 0xfa && + Boot->Media != 0xfb && + Boot->Media != 0xfc && + Boot->Media != 0xfd && + Boot->Media != 0xfe && + Boot->Media != 0xff) + { + DPRINT1("Media %02x\n", Boot->Media); + *RecognizedFS = FALSE; + } + + if (*RecognizedFS && + Boot->SectorsPerCluster != 1 && + Boot->SectorsPerCluster != 2 && + Boot->SectorsPerCluster != 4 && + Boot->SectorsPerCluster != 8 && + Boot->SectorsPerCluster != 16 && + Boot->SectorsPerCluster != 32 && + Boot->SectorsPerCluster != 64 && + Boot->SectorsPerCluster != 128) + { + DPRINT1("SectorsPerCluster %02x\n", Boot->SectorsPerCluster); + *RecognizedFS = FALSE; + } + + if (*RecognizedFS && + Boot->BytesPerSector * Boot->SectorsPerCluster > 32 * 1024) + { + DPRINT1("ClusterSize %dx\n", Boot->BytesPerSector * Boot->SectorsPerCluster); + *RecognizedFS = FALSE; + } + + if (*RecognizedFS) + { + FatInfo.VolumeID = Boot->VolumeID; + FatInfo.FATStart = Boot->ReservedSectors; + FatInfo.FATCount = Boot->FATCount; + FatInfo.FATSectors = Boot->FATSectors ? Boot->FATSectors : ((struct _BootSector32*) Boot)->FATSectors32; + FatInfo.BytesPerSector = Boot->BytesPerSector; + FatInfo.SectorsPerCluster = Boot->SectorsPerCluster; + FatInfo.BytesPerCluster = FatInfo.BytesPerSector * FatInfo.SectorsPerCluster; + FatInfo.rootDirectorySectors = ((Boot->RootEntries * 32) + Boot->BytesPerSector - 1) / Boot->BytesPerSector; + FatInfo.rootStart = FatInfo.FATStart + FatInfo.FATCount * FatInfo.FATSectors; + FatInfo.dataStart = FatInfo.rootStart + FatInfo.rootDirectorySectors; + FatInfo.Sectors = Sectors = Boot->Sectors ? Boot->Sectors : Boot->SectorsHuge; + Sectors -= Boot->ReservedSectors + FatInfo.FATCount * FatInfo.FATSectors + FatInfo.rootDirectorySectors; + FatInfo.NumberOfClusters = Sectors / Boot->SectorsPerCluster; + if (FatInfo.NumberOfClusters < 4085) + { + DPRINT("FAT12\n"); + FatInfo.FatType = FAT12; + FatInfo.RootCluster = (FatInfo.rootStart - 1) / FatInfo.SectorsPerCluster; + } + else if (FatInfo.NumberOfClusters >= 65525) + { + DPRINT("FAT32\n"); + FatInfo.FatType = FAT32; + FatInfo.RootCluster = ((struct _BootSector32*) Boot)->RootCluster; + FatInfo.rootStart = FatInfo.dataStart + ((FatInfo.RootCluster - 2) * FatInfo.SectorsPerCluster); + FatInfo.VolumeID = ((struct _BootSector32*) Boot)->VolumeID; + } + else + { + DPRINT("FAT16\n"); + FatInfo.FatType = FAT16; + FatInfo.RootCluster = FatInfo.rootStart / FatInfo.SectorsPerCluster; + } + if (PartitionInfoIsValid && + FatInfo.Sectors > PartitionInfo.PartitionLength.QuadPart / FatInfo.BytesPerSector) + { + *RecognizedFS = FALSE; + } + + if (pFatInfo && *RecognizedFS) + { + *pFatInfo = FatInfo; + } + } + } + + ExFreePool(Boot); + } + + if (!*RecognizedFS && PartitionInfoIsValid) + { + BootFatX = ExAllocatePoolWithTag(NonPagedPool, sizeof(struct _BootSectorFatX), TAG_VFAT); + if (BootFatX == NULL) + { + *RecognizedFS=FALSE; + return STATUS_INSUFFICIENT_RESOURCES; + } + + Offset.QuadPart = 0; + + /* Try to recognize FATX16/FATX32 partitions (Xbox) */ + Status = VfatReadDisk(DeviceToMount, &Offset, sizeof(struct _BootSectorFatX), (PUCHAR) BootFatX, FALSE); + if (NT_SUCCESS(Status)) + { + *RecognizedFS = TRUE; + if (BootFatX->SysType[0] != 'F' || + BootFatX->SysType[1] != 'A' || + BootFatX->SysType[2] != 'T' || + BootFatX->SysType[3] != 'X') + { + DPRINT1("SysType %c%c%c%c\n", BootFatX->SysType[0], BootFatX->SysType[1], BootFatX->SysType[2], BootFatX->SysType[3]); + *RecognizedFS=FALSE; + } + + if (*RecognizedFS && + BootFatX->SectorsPerCluster != 1 && + BootFatX->SectorsPerCluster != 2 && + BootFatX->SectorsPerCluster != 4 && + BootFatX->SectorsPerCluster != 8 && + BootFatX->SectorsPerCluster != 16 && + BootFatX->SectorsPerCluster != 32 && + BootFatX->SectorsPerCluster != 64 && + BootFatX->SectorsPerCluster != 128) + { + DPRINT1("SectorsPerCluster %lu\n", BootFatX->SectorsPerCluster); + *RecognizedFS=FALSE; + } + + if (*RecognizedFS) + { + FatInfo.BytesPerSector = DiskGeometry.BytesPerSector; + FatInfo.SectorsPerCluster = BootFatX->SectorsPerCluster; + FatInfo.rootDirectorySectors = BootFatX->SectorsPerCluster; + FatInfo.BytesPerCluster = BootFatX->SectorsPerCluster * DiskGeometry.BytesPerSector; + FatInfo.Sectors = (ULONG)(PartitionInfo.PartitionLength.QuadPart / DiskGeometry.BytesPerSector); + if (FatInfo.Sectors / FatInfo.SectorsPerCluster < 65525) + { + DPRINT("FATX16\n"); + FatInfo.FatType = FATX16; + } + else + { + DPRINT("FATX32\n"); + FatInfo.FatType = FATX32; + } + FatInfo.VolumeID = BootFatX->VolumeID; + FatInfo.FATStart = sizeof(struct _BootSectorFatX) / DiskGeometry.BytesPerSector; + FatInfo.FATCount = BootFatX->FATCount; + FatInfo.FATSectors = + ROUND_UP(FatInfo.Sectors / FatInfo.SectorsPerCluster * (FatInfo.FatType == FATX16 ? 2 : 4), 4096) / + FatInfo.BytesPerSector; + FatInfo.rootStart = FatInfo.FATStart + FatInfo.FATCount * FatInfo.FATSectors; + FatInfo.RootCluster = (FatInfo.rootStart - 1) / FatInfo.SectorsPerCluster; + FatInfo.dataStart = FatInfo.rootStart + FatInfo.rootDirectorySectors; + FatInfo.NumberOfClusters = (FatInfo.Sectors - FatInfo.dataStart) / FatInfo.SectorsPerCluster; + + if (pFatInfo && *RecognizedFS) + { + *pFatInfo = FatInfo; + } + } + } + ExFreePool(BootFatX); + } + + DPRINT("VfatHasFileSystem done\n"); + return Status; +} + +static NTSTATUS +VfatMountDevice(PDEVICE_EXTENSION DeviceExt, + PDEVICE_OBJECT DeviceToMount) +/* + * FUNCTION: Mounts the device + */ +{ + NTSTATUS Status; + BOOLEAN RecognizedFS; + + DPRINT("Mounting VFAT device...\n"); + + Status = VfatHasFileSystem(DeviceToMount, &RecognizedFS, &DeviceExt->FatInfo); + if (!NT_SUCCESS(Status)) + { + return(Status); + } + DPRINT("MountVfatdev %d, PAGE_SIZE = %d\n", DeviceExt->FatInfo.BytesPerCluster, PAGE_SIZE); + + + return(STATUS_SUCCESS); +} + + +static NTSTATUS +VfatMount (PVFAT_IRP_CONTEXT IrpContext) +/* + * FUNCTION: Mount the filesystem + */ +{ + PDEVICE_OBJECT DeviceObject = NULL; + PDEVICE_EXTENSION DeviceExt = NULL; + BOOLEAN RecognizedFS; + NTSTATUS Status; + PVFATFCB Fcb = NULL; + PVFATFCB VolumeFcb = NULL; + PVFATCCB Ccb = NULL; + PDEVICE_OBJECT DeviceToMount; + PVPB Vpb; + UNICODE_STRING NameU = RTL_CONSTANT_STRING(L"\\$$Fat$$"); + UNICODE_STRING VolumeNameU = RTL_CONSTANT_STRING(L"\\$$Volume$$"); + ULONG HashTableSize; + ULONG eocMark; + FATINFO FatInfo; + + DPRINT("VfatMount(IrpContext %p)\n", IrpContext); + + ASSERT(IrpContext); + + if (IrpContext->DeviceObject != VfatGlobalData->DeviceObject) + { + Status = STATUS_INVALID_DEVICE_REQUEST; + goto ByeBye; + } + + DeviceToMount = IrpContext->Stack->Parameters.MountVolume.DeviceObject; + Vpb = IrpContext->Stack->Parameters.MountVolume.Vpb; + + Status = VfatHasFileSystem (DeviceToMount, &RecognizedFS, &FatInfo); + if (!NT_SUCCESS(Status)) + { + goto ByeBye; + } + + if (RecognizedFS == FALSE) + { + DPRINT("VFAT: Unrecognized Volume\n"); + Status = STATUS_UNRECOGNIZED_VOLUME; + goto ByeBye; + } + + /* Use prime numbers for the table size */ + if (FatInfo.FatType == FAT12) + { + HashTableSize = 4099; // 4096 = 4 * 1024 + } + else if (FatInfo.FatType == FAT16 || + FatInfo.FatType == FATX16) + { + HashTableSize = 16411; // 16384 = 16 * 1024 + } + else + { + HashTableSize = 65537; // 65536 = 64 * 1024; + } + HashTableSize = FCB_HASH_TABLE_SIZE; + DPRINT("VFAT: Recognized volume\n"); + Status = IoCreateDevice(VfatGlobalData->DriverObject, + ROUND_UP(sizeof (DEVICE_EXTENSION), sizeof(ULONG)) + sizeof(HASHENTRY*) * HashTableSize, + NULL, + FILE_DEVICE_DISK_FILE_SYSTEM, + 0, + FALSE, + &DeviceObject); + if (!NT_SUCCESS(Status)) + { + goto ByeBye; + } + + DeviceObject->Flags = DeviceObject->Flags | DO_DIRECT_IO; + DeviceExt = (PVOID) DeviceObject->DeviceExtension; + RtlZeroMemory(DeviceExt, ROUND_UP(sizeof(DEVICE_EXTENSION), sizeof(ULONG)) + sizeof(HASHENTRY*) * HashTableSize); + DeviceExt->FcbHashTable = (HASHENTRY**)((ULONG_PTR)DeviceExt + ROUND_UP(sizeof(DEVICE_EXTENSION), sizeof(ULONG))); + DeviceExt->HashTableSize = HashTableSize; + + /* use same vpb as device disk */ + DeviceObject->Vpb = Vpb; + DeviceToMount->Vpb = Vpb; + + Status = VfatMountDevice(DeviceExt, DeviceToMount); + if (!NT_SUCCESS(Status)) + { + /* FIXME: delete device object */ + goto ByeBye; + } + + DPRINT("BytesPerSector: %d\n", DeviceExt->FatInfo.BytesPerSector); + DPRINT("SectorsPerCluster: %d\n", DeviceExt->FatInfo.SectorsPerCluster); + DPRINT("FATCount: %d\n", DeviceExt->FatInfo.FATCount); + DPRINT("FATSectors: %d\n", DeviceExt->FatInfo.FATSectors); + DPRINT("RootStart: %d\n", DeviceExt->FatInfo.rootStart); + DPRINT("DataStart: %d\n", DeviceExt->FatInfo.dataStart); + if (DeviceExt->FatInfo.FatType == FAT32) + { + DPRINT("RootCluster: %d\n", DeviceExt->FatInfo.RootCluster); + } + + switch (DeviceExt->FatInfo.FatType) + { + case FAT12: + DeviceExt->GetNextCluster = FAT12GetNextCluster; + DeviceExt->FindAndMarkAvailableCluster = FAT12FindAndMarkAvailableCluster; + DeviceExt->WriteCluster = FAT12WriteCluster; + DeviceExt->CleanShutBitMask = 0; + break; + + case FAT16: + case FATX16: + DeviceExt->GetNextCluster = FAT16GetNextCluster; + DeviceExt->FindAndMarkAvailableCluster = FAT16FindAndMarkAvailableCluster; + DeviceExt->WriteCluster = FAT16WriteCluster; + DeviceExt->CleanShutBitMask = 0x8000; + break; + + case FAT32: + case FATX32: + DeviceExt->GetNextCluster = FAT32GetNextCluster; + DeviceExt->FindAndMarkAvailableCluster = FAT32FindAndMarkAvailableCluster; + DeviceExt->WriteCluster = FAT32WriteCluster; + DeviceExt->CleanShutBitMask = 0x80000000; + break; + } + + if (DeviceExt->FatInfo.FatType == FATX16 + || DeviceExt->FatInfo.FatType == FATX32) + { + DeviceExt->Flags |= VCB_IS_FATX; + DeviceExt->GetNextDirEntry = FATXGetNextDirEntry; + DeviceExt->BaseDateYear = 2000; + } + else + { + DeviceExt->GetNextDirEntry = FATGetNextDirEntry; + DeviceExt->BaseDateYear = 1980; + } + + DeviceExt->StorageDevice = DeviceToMount; + DeviceExt->StorageDevice->Vpb->DeviceObject = DeviceObject; + DeviceExt->StorageDevice->Vpb->RealDevice = DeviceExt->StorageDevice; + DeviceExt->StorageDevice->Vpb->Flags |= VPB_MOUNTED; + DeviceObject->StackSize = DeviceExt->StorageDevice->StackSize + 1; + DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; + + DPRINT("FsDeviceObject %p\n", DeviceObject); + + /* Initialize this resource early ... it's used in VfatCleanup */ + ExInitializeResourceLite(&DeviceExt->DirResource); + + DeviceExt->FATFileObject = IoCreateStreamFileObject(NULL, DeviceExt->StorageDevice); + Fcb = vfatNewFCB(DeviceExt, &NameU); + if (Fcb == NULL) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + goto ByeBye; + } + Ccb = ExAllocateFromNPagedLookasideList(&VfatGlobalData->CcbLookasideList); + if (Ccb == NULL) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + goto ByeBye; + } + + RtlZeroMemory(Ccb, sizeof (VFATCCB)); + DeviceExt->FATFileObject->FsContext = Fcb; + DeviceExt->FATFileObject->FsContext2 = Ccb; + DeviceExt->FATFileObject->SectionObjectPointer = &Fcb->SectionObjectPointers; + DeviceExt->FATFileObject->PrivateCacheMap = NULL; + DeviceExt->FATFileObject->Vpb = DeviceObject->Vpb; + Fcb->FileObject = DeviceExt->FATFileObject; + + Fcb->Flags |= FCB_IS_FAT; + + Fcb->RFCB.FileSize.QuadPart = DeviceExt->FatInfo.FATSectors * DeviceExt->FatInfo.BytesPerSector; + Fcb->RFCB.ValidDataLength = Fcb->RFCB.FileSize; + Fcb->RFCB.AllocationSize = Fcb->RFCB.FileSize; + + CcInitializeCacheMap(DeviceExt->FATFileObject, + (PCC_FILE_SIZES)(&Fcb->RFCB.AllocationSize), + TRUE, + &VfatGlobalData->CacheMgrCallbacks, + Fcb); + + DeviceExt->LastAvailableCluster = 2; + ExInitializeResourceLite(&DeviceExt->FatResource); + + InitializeListHead(&DeviceExt->FcbListHead); + + VolumeFcb = vfatNewFCB(DeviceExt, &VolumeNameU); + if (VolumeFcb == NULL) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + goto ByeBye; + } + VolumeFcb->Flags = FCB_IS_VOLUME; + VolumeFcb->RFCB.FileSize.QuadPart = DeviceExt->FatInfo.Sectors * DeviceExt->FatInfo.BytesPerSector; + VolumeFcb->RFCB.ValidDataLength = VolumeFcb->RFCB.FileSize; + VolumeFcb->RFCB.AllocationSize = VolumeFcb->RFCB.FileSize; + DeviceExt->VolumeFcb = VolumeFcb; + + ExAcquireResourceExclusiveLite(&VfatGlobalData->VolumeListLock, TRUE); + InsertHeadList(&VfatGlobalData->VolumeListHead, &DeviceExt->VolumeListEntry); + ExReleaseResourceLite(&VfatGlobalData->VolumeListLock); + + /* read serial number */ + DeviceObject->Vpb->SerialNumber = DeviceExt->FatInfo.VolumeID; + + /* read volume label */ + ReadVolumeLabel(DeviceExt, DeviceObject->Vpb); + + /* read clean shutdown bit status */ + Status = GetNextCluster(DeviceExt, 1, &eocMark); + if (NT_SUCCESS(Status)) + { + if (eocMark & DeviceExt->CleanShutBitMask) + { + /* unset clean shutdown bit */ + eocMark &= ~DeviceExt->CleanShutBitMask; + WriteCluster(DeviceExt, 1, eocMark); + VolumeFcb->Flags |= VCB_CLEAR_DIRTY; + } + } + VolumeFcb->Flags |= VCB_IS_DIRTY; + + Status = STATUS_SUCCESS; +ByeBye: + + if (!NT_SUCCESS(Status)) + { + // cleanup + if (DeviceExt && DeviceExt->FATFileObject) + ObDereferenceObject (DeviceExt->FATFileObject); + if (Fcb) + vfatDestroyFCB(Fcb); + if (Ccb) + vfatDestroyCCB(Ccb); + if (DeviceObject) + IoDeleteDevice(DeviceObject); + if (VolumeFcb) + vfatDestroyFCB(VolumeFcb); + } + return Status; +} + + +static NTSTATUS +VfatVerify (PVFAT_IRP_CONTEXT IrpContext) +/* + * FUNCTION: Verify the filesystem + */ +{ + PDEVICE_OBJECT DeviceToVerify; + NTSTATUS Status = STATUS_SUCCESS; + FATINFO FatInfo; + BOOLEAN RecognizedFS; + PDEVICE_EXTENSION DeviceExt = IrpContext->DeviceExt; + + DPRINT("VfatVerify(IrpContext %p)\n", IrpContext); + + DeviceToVerify = IrpContext->Stack->Parameters.VerifyVolume.DeviceObject; + Status = VfatBlockDeviceIoControl(DeviceToVerify, + IOCTL_DISK_CHECK_VERIFY, + NULL, + 0, + NULL, + 0, + TRUE); + DeviceToVerify->Flags &= ~DO_VERIFY_VOLUME; + if (!NT_SUCCESS(Status) && Status != STATUS_VERIFY_REQUIRED) + { + DPRINT("VfatBlockDeviceIoControl() failed (Status %lx)\n", Status); + Status = STATUS_WRONG_VOLUME; + } + else + { + Status = VfatHasFileSystem(DeviceToVerify, &RecognizedFS, &FatInfo); + if (!NT_SUCCESS(Status) || RecognizedFS == FALSE) + { + Status = STATUS_WRONG_VOLUME; + } + else if (sizeof(FATINFO) == RtlCompareMemory(&FatInfo, &DeviceExt->FatInfo, sizeof(FATINFO))) + { + /* + * FIXME: + * Preformated floppy disks have very often a serial number of 0000:0000. + * We should calculate a crc sum over the sectors from the root directory as secondary volume number. + * Each write to the root directory must update this crc sum. + */ + + } + else + { + Status = STATUS_WRONG_VOLUME; + } + } + + return Status; +} + + +static NTSTATUS +VfatGetVolumeBitmap(PVFAT_IRP_CONTEXT IrpContext) +{ + DPRINT("VfatGetVolumeBitmap (IrpContext %p)\n", IrpContext); + + return STATUS_INVALID_DEVICE_REQUEST; +} + + +static NTSTATUS +VfatGetRetrievalPointers(PVFAT_IRP_CONTEXT IrpContext) +{ + PIO_STACK_LOCATION Stack; + LARGE_INTEGER Vcn; + PRETRIEVAL_POINTERS_BUFFER RetrievalPointers; + PFILE_OBJECT FileObject; + ULONG MaxExtentCount; + PVFATFCB Fcb; + PDEVICE_EXTENSION DeviceExt; + ULONG FirstCluster; + ULONG CurrentCluster; + ULONG LastCluster; + NTSTATUS Status; + + DPRINT("VfatGetRetrievalPointers(IrpContext %p)\n", IrpContext); + + DeviceExt = IrpContext->DeviceExt; + FileObject = IrpContext->FileObject; + Stack = IrpContext->Stack; + if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(STARTING_VCN_INPUT_BUFFER) || + Stack->Parameters.DeviceIoControl.Type3InputBuffer == NULL) + { + return STATUS_INVALID_PARAMETER; + } + if (IrpContext->Irp->UserBuffer == NULL || + Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(RETRIEVAL_POINTERS_BUFFER)) + { + return STATUS_BUFFER_TOO_SMALL; + } + + Fcb = FileObject->FsContext; + + ExAcquireResourceSharedLite(&Fcb->MainResource, TRUE); + + Vcn = ((PSTARTING_VCN_INPUT_BUFFER)Stack->Parameters.DeviceIoControl.Type3InputBuffer)->StartingVcn; + RetrievalPointers = IrpContext->Irp->UserBuffer; + + MaxExtentCount = ((Stack->Parameters.DeviceIoControl.OutputBufferLength - sizeof(RetrievalPointers->ExtentCount) - sizeof(RetrievalPointers->StartingVcn)) / sizeof(RetrievalPointers->Extents[0])); + + + if (Vcn.QuadPart >= Fcb->RFCB.AllocationSize.QuadPart / DeviceExt->FatInfo.BytesPerCluster) + { + Status = STATUS_INVALID_PARAMETER; + goto ByeBye; + } + + CurrentCluster = FirstCluster = vfatDirEntryGetFirstCluster(DeviceExt, &Fcb->entry); + Status = OffsetToCluster(DeviceExt, FirstCluster, + Vcn.u.LowPart * DeviceExt->FatInfo.BytesPerCluster, + &CurrentCluster, FALSE); + if (!NT_SUCCESS(Status)) + { + goto ByeBye; + } + + RetrievalPointers->StartingVcn = Vcn; + RetrievalPointers->ExtentCount = 0; + RetrievalPointers->Extents[0].Lcn.u.HighPart = 0; + RetrievalPointers->Extents[0].Lcn.u.LowPart = CurrentCluster - 2; + LastCluster = 0; + while (CurrentCluster != 0xffffffff && RetrievalPointers->ExtentCount < MaxExtentCount) + { + + LastCluster = CurrentCluster; + Status = NextCluster(DeviceExt, CurrentCluster, &CurrentCluster, FALSE); + Vcn.QuadPart++; + if (!NT_SUCCESS(Status)) + { + goto ByeBye; + } + + if (LastCluster + 1 != CurrentCluster) + { + RetrievalPointers->Extents[RetrievalPointers->ExtentCount].NextVcn = Vcn; + RetrievalPointers->ExtentCount++; + if (RetrievalPointers->ExtentCount < MaxExtentCount) + { + RetrievalPointers->Extents[RetrievalPointers->ExtentCount].Lcn.u.HighPart = 0; + RetrievalPointers->Extents[RetrievalPointers->ExtentCount].Lcn.u.LowPart = CurrentCluster - 2; + } + } + } + + IrpContext->Irp->IoStatus.Information = sizeof(RETRIEVAL_POINTERS_BUFFER) + (sizeof(RetrievalPointers->Extents[0]) * (RetrievalPointers->ExtentCount - 1)); + Status = STATUS_SUCCESS; + +ByeBye: + ExReleaseResourceLite(&Fcb->MainResource); + + return Status; +} + +static NTSTATUS +VfatMoveFile(PVFAT_IRP_CONTEXT IrpContext) +{ + DPRINT("VfatMoveFile(IrpContext %p)\n", IrpContext); + + return STATUS_INVALID_DEVICE_REQUEST; +} + +#ifdef USE_ROS_CC_AND_FS +static NTSTATUS +VfatRosQueryLcnMapping(PVFAT_IRP_CONTEXT IrpContext) +{ + PDEVICE_EXTENSION DeviceExt; + PROS_QUERY_LCN_MAPPING LcnQuery; + PIO_STACK_LOCATION Stack; + + DPRINT("VfatRosQueryLcnMapping(IrpContext %p)\n", IrpContext); + + DeviceExt = IrpContext->DeviceExt; + Stack = IrpContext->Stack; + if (IrpContext->Irp->AssociatedIrp.SystemBuffer == NULL || + Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ROS_QUERY_LCN_MAPPING)) + { + return STATUS_BUFFER_TOO_SMALL; + } + LcnQuery = (PROS_QUERY_LCN_MAPPING)(IrpContext->Irp->AssociatedIrp.SystemBuffer); + LcnQuery->LcnDiskOffset.QuadPart = DeviceExt->FatInfo.dataStart * DeviceExt->FatInfo.BytesPerSector; + IrpContext->Irp->IoStatus.Information = sizeof(ROS_QUERY_LCN_MAPPING); + return(STATUS_SUCCESS); +} +#endif + +static NTSTATUS +VfatIsVolumeDirty(PVFAT_IRP_CONTEXT IrpContext) +{ + PULONG Flags; + + DPRINT("VfatIsVolumeDirty(IrpContext %p)\n", IrpContext); + + if (IrpContext->Stack->Parameters.FileSystemControl.OutputBufferLength != sizeof(ULONG)) + return STATUS_INVALID_BUFFER_SIZE; + else if (!IrpContext->Irp->AssociatedIrp.SystemBuffer) + return STATUS_INVALID_USER_BUFFER; + + Flags = (PULONG)IrpContext->Irp->AssociatedIrp.SystemBuffer; + *Flags = 0; + + if (IrpContext->DeviceExt->VolumeFcb->Flags & VCB_IS_DIRTY + && !(IrpContext->DeviceExt->VolumeFcb->Flags & VCB_CLEAR_DIRTY)) + { + *Flags |= VOLUME_IS_DIRTY; + } + + return STATUS_SUCCESS; +} + +static NTSTATUS +VfatMarkVolumeDirty(PVFAT_IRP_CONTEXT IrpContext) +{ + ULONG eocMark; + PDEVICE_EXTENSION DeviceExt; + NTSTATUS Status = STATUS_SUCCESS; + + DPRINT("VfatMarkVolumeDirty(IrpContext %p)\n", IrpContext); + DeviceExt = IrpContext->DeviceExt; + + if (!(DeviceExt->VolumeFcb->Flags & VCB_IS_DIRTY)) + { + Status = GetNextCluster(DeviceExt, 1, &eocMark); + if (NT_SUCCESS(Status)) + { + /* unset clean shutdown bit */ + eocMark &= ~DeviceExt->CleanShutBitMask; + Status = WriteCluster(DeviceExt, 1, eocMark); + } + } + + DeviceExt->VolumeFcb->Flags &= ~VCB_CLEAR_DIRTY; + + return Status; +} + +NTSTATUS VfatFileSystemControl(PVFAT_IRP_CONTEXT IrpContext) +/* + * FUNCTION: File system control + */ +{ + + NTSTATUS Status; + + DPRINT("VfatFileSystemControl(IrpContext %p)\n", IrpContext); + + ASSERT(IrpContext); + ASSERT(IrpContext->Irp); + ASSERT(IrpContext->Stack); + + IrpContext->Irp->IoStatus.Information = 0; + + switch (IrpContext->MinorFunction) + { + case IRP_MN_USER_FS_REQUEST: + switch(IrpContext->Stack->Parameters.DeviceIoControl.IoControlCode) + { + case FSCTL_GET_VOLUME_BITMAP: + Status = VfatGetVolumeBitmap(IrpContext); + break; + case FSCTL_GET_RETRIEVAL_POINTERS: + Status = VfatGetRetrievalPointers(IrpContext); + break; + case FSCTL_MOVE_FILE: + Status = VfatMoveFile(IrpContext); + break; +#ifdef USE_ROS_CC_AND_FS + case FSCTL_ROS_QUERY_LCN_MAPPING: + Status = VfatRosQueryLcnMapping(IrpContext); + break; +#endif + case FSCTL_IS_VOLUME_DIRTY: + Status = VfatIsVolumeDirty(IrpContext); + break; + case FSCTL_MARK_VOLUME_DIRTY: + Status = VfatMarkVolumeDirty(IrpContext); + break; + default: + Status = STATUS_INVALID_DEVICE_REQUEST; + } + break; + + case IRP_MN_MOUNT_VOLUME: + Status = VfatMount(IrpContext); + break; + + case IRP_MN_VERIFY_VOLUME: + DPRINT("VFATFS: IRP_MN_VERIFY_VOLUME\n"); + Status = VfatVerify(IrpContext); + break; + + default: + DPRINT("VFAT FSC: MinorFunction %d\n", IrpContext->MinorFunction); + Status = STATUS_INVALID_DEVICE_REQUEST; + break; + } + + IrpContext->Irp->IoStatus.Status = Status; + + IoCompleteRequest (IrpContext->Irp, IO_NO_INCREMENT); + VfatFreeIrpContext(IrpContext); + return (Status); +} diff --git a/reactos/drivers/filesystems/fastfat_new/iface.c b/reactos/drivers/filesystems/fastfat_new/iface.c new file mode 100644 index 00000000000..83affd72147 --- /dev/null +++ b/reactos/drivers/filesystems/fastfat_new/iface.c @@ -0,0 +1,131 @@ +/* + * ReactOS kernel + * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/* + * PROJECT: ReactOS kernel + * FILE: drivers/fs/vfat/iface.c + * PURPOSE: VFAT Filesystem + * PROGRAMMER: Jason Filby (jasonfilby@yahoo.com) + */ + +/* INCLUDES *****************************************************************/ + +#define NDEBUG +#include "vfat.h" + +/* GLOBALS *****************************************************************/ + +PVFAT_GLOBAL_DATA VfatGlobalData; + +/* FUNCTIONS ****************************************************************/ + +NTSTATUS NTAPI +DriverEntry(PDRIVER_OBJECT DriverObject, + PUNICODE_STRING RegistryPath) +/* + * FUNCTION: Called by the system to initialize the driver + * ARGUMENTS: + * DriverObject = object describing this driver + * RegistryPath = path to our configuration entries + * RETURNS: Success or failure + */ +{ + PDEVICE_OBJECT DeviceObject; + UNICODE_STRING DeviceName = RTL_CONSTANT_STRING(L"\\Fat"); + NTSTATUS Status; + + Status = IoCreateDevice(DriverObject, + sizeof(VFAT_GLOBAL_DATA), + &DeviceName, + FILE_DEVICE_DISK_FILE_SYSTEM, + 0, + FALSE, + &DeviceObject); + + if (Status == STATUS_OBJECT_NAME_EXISTS || + Status == STATUS_OBJECT_NAME_COLLISION) + { + /* Try an other name, if 'Fat' is already in use. 'Fat' is also used by fastfat.sys on W2K */ + RtlInitUnicodeString(&DeviceName, L"\\RosFat"); + Status = IoCreateDevice(DriverObject, + sizeof(VFAT_GLOBAL_DATA), + &DeviceName, + FILE_DEVICE_DISK_FILE_SYSTEM, + 0, + FALSE, + &DeviceObject); + } + + + + if (!NT_SUCCESS(Status)) + { + return (Status); + } + + VfatGlobalData = DeviceObject->DeviceExtension; + RtlZeroMemory (VfatGlobalData, sizeof(VFAT_GLOBAL_DATA)); + VfatGlobalData->DriverObject = DriverObject; + VfatGlobalData->DeviceObject = DeviceObject; + + DeviceObject->Flags |= DO_DIRECT_IO; + DriverObject->MajorFunction[IRP_MJ_CLOSE] = VfatBuildRequest; + DriverObject->MajorFunction[IRP_MJ_CREATE] = VfatBuildRequest; + DriverObject->MajorFunction[IRP_MJ_READ] = VfatBuildRequest; + DriverObject->MajorFunction[IRP_MJ_WRITE] = VfatBuildRequest; + DriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] = VfatBuildRequest; + DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION] = VfatBuildRequest; + DriverObject->MajorFunction[IRP_MJ_SET_INFORMATION] = VfatBuildRequest; + DriverObject->MajorFunction[IRP_MJ_DIRECTORY_CONTROL] = VfatBuildRequest; + DriverObject->MajorFunction[IRP_MJ_QUERY_VOLUME_INFORMATION] = + VfatBuildRequest; + DriverObject->MajorFunction[IRP_MJ_SET_VOLUME_INFORMATION] = + VfatBuildRequest; + DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = VfatShutdown; + DriverObject->MajorFunction[IRP_MJ_LOCK_CONTROL] = VfatBuildRequest; + DriverObject->MajorFunction[IRP_MJ_CLEANUP] = VfatBuildRequest; + DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = VfatBuildRequest; + + DriverObject->DriverUnload = NULL; + + /* Cache manager */ + VfatGlobalData->CacheMgrCallbacks.AcquireForLazyWrite = VfatAcquireForLazyWrite; + VfatGlobalData->CacheMgrCallbacks.ReleaseFromLazyWrite = VfatReleaseFromLazyWrite; + VfatGlobalData->CacheMgrCallbacks.AcquireForReadAhead = VfatAcquireForReadAhead; + VfatGlobalData->CacheMgrCallbacks.ReleaseFromReadAhead = VfatReleaseFromReadAhead; + + /* Fast I/O */ + VfatInitFastIoRoutines(&VfatGlobalData->FastIoDispatch); + DriverObject->FastIoDispatch = &VfatGlobalData->FastIoDispatch; + + /* Private lists */ + ExInitializeNPagedLookasideList(&VfatGlobalData->FcbLookasideList, + NULL, NULL, 0, sizeof(VFATFCB), TAG_FCB, 0); + ExInitializeNPagedLookasideList(&VfatGlobalData->CcbLookasideList, + NULL, NULL, 0, sizeof(VFATCCB), TAG_CCB, 0); + ExInitializeNPagedLookasideList(&VfatGlobalData->IrpContextLookasideList, + NULL, NULL, 0, sizeof(VFAT_IRP_CONTEXT), TAG_IRP, 0); + + ExInitializeResourceLite(&VfatGlobalData->VolumeListLock); + InitializeListHead(&VfatGlobalData->VolumeListHead); + IoRegisterFileSystem(DeviceObject); + return(STATUS_SUCCESS); +} + +/* EOF */ + diff --git a/reactos/drivers/filesystems/fastfat_new/misc.c b/reactos/drivers/filesystems/fastfat_new/misc.c new file mode 100644 index 00000000000..977da8aeda2 --- /dev/null +++ b/reactos/drivers/filesystems/fastfat_new/misc.c @@ -0,0 +1,275 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: drivers/fs/vfat/misc.c + * PURPOSE: VFAT Filesystem + * PROGRAMMER: + * + */ + +/* INCLUDES *****************************************************************/ + +#define NDEBUG +#include "vfat.h" + +/* GLOBALS ******************************************************************/ + +const char* MajorFunctionNames[] = +{ + "IRP_MJ_CREATE", + "IRP_MJ_CREATE_NAMED_PIPE", + "IRP_MJ_CLOSE", + "IRP_MJ_READ", + "IRP_MJ_WRITE", + "IRP_MJ_QUERY_INFORMATION", + "IRP_MJ_SET_INFORMATION", + "IRP_MJ_QUERY_EA", + "IRP_MJ_SET_EA", + "IRP_MJ_FLUSH_BUFFERS", + "IRP_MJ_QUERY_VOLUME_INFORMATION", + "IRP_MJ_SET_VOLUME_INFORMATION", + "IRP_MJ_DIRECTORY_CONTROL", + "IRP_MJ_FILE_SYSTEM_CONTROL", + "IRP_MJ_DEVICE_CONTROL", + "IRP_MJ_INTERNAL_DEVICE_CONTROL", + "IRP_MJ_SHUTDOWN", + "IRP_MJ_LOCK_CONTROL", + "IRP_MJ_CLEANUP", + "IRP_MJ_CREATE_MAILSLOT", + "IRP_MJ_QUERY_SECURITY", + "IRP_MJ_SET_SECURITY", + "IRP_MJ_POWER", + "IRP_MJ_SYSTEM_CONTROL", + "IRP_MJ_DEVICE_CHANGE", + "IRP_MJ_QUERY_QUOTA", + "IRP_MJ_SET_QUOTA", + "IRP_MJ_PNP", + "IRP_MJ_MAXIMUM_FUNCTION" +}; + +/* FUNCTIONS ****************************************************************/ + +static LONG QueueCount = 0; + +static NTSTATUS VfatLockControl( + IN PVFAT_IRP_CONTEXT IrpContext + ) +{ + PVFATFCB Fcb; + NTSTATUS Status; + + DPRINT("VfatLockControl(IrpContext %p)\n", IrpContext); + + ASSERT(IrpContext); + + Fcb = (PVFATFCB)IrpContext->FileObject->FsContext; + + if (IrpContext->DeviceObject == VfatGlobalData->DeviceObject) + { + Status = STATUS_INVALID_DEVICE_REQUEST; + goto Fail; + } + + if (*Fcb->Attributes & FILE_ATTRIBUTE_DIRECTORY) + { + Status = STATUS_INVALID_PARAMETER; + goto Fail; + } + + Status = FsRtlProcessFileLock(&Fcb->FileLock, + IrpContext->Irp, + NULL + ); + + VfatFreeIrpContext(IrpContext); + return Status; + +Fail:; + IrpContext->Irp->IoStatus.Status = Status; + IofCompleteRequest(IrpContext->Irp, (CCHAR)(NT_SUCCESS(Status) ? IO_DISK_INCREMENT : IO_NO_INCREMENT)); + VfatFreeIrpContext(IrpContext); + return Status; +} + +static NTSTATUS +VfatDispatchRequest (IN PVFAT_IRP_CONTEXT IrpContext) +{ + DPRINT ("VfatDispatchRequest (IrpContext %p), is called for %s\n", IrpContext, + IrpContext->MajorFunction >= IRP_MJ_MAXIMUM_FUNCTION ? "????" : MajorFunctionNames[IrpContext->MajorFunction]); + + ASSERT(IrpContext); + + switch (IrpContext->MajorFunction) + { + case IRP_MJ_CLOSE: + return VfatClose (IrpContext); + case IRP_MJ_CREATE: + return VfatCreate (IrpContext); + case IRP_MJ_READ: + return VfatRead (IrpContext); + case IRP_MJ_WRITE: + return VfatWrite (IrpContext); + case IRP_MJ_FILE_SYSTEM_CONTROL: + return VfatFileSystemControl(IrpContext); + case IRP_MJ_QUERY_INFORMATION: + return VfatQueryInformation (IrpContext); + case IRP_MJ_SET_INFORMATION: + return VfatSetInformation (IrpContext); + case IRP_MJ_DIRECTORY_CONTROL: + return VfatDirectoryControl(IrpContext); + case IRP_MJ_QUERY_VOLUME_INFORMATION: + return VfatQueryVolumeInformation(IrpContext); + case IRP_MJ_SET_VOLUME_INFORMATION: + return VfatSetVolumeInformation(IrpContext); + case IRP_MJ_LOCK_CONTROL: + return VfatLockControl(IrpContext); + case IRP_MJ_CLEANUP: + return VfatCleanup(IrpContext); + case IRP_MJ_FLUSH_BUFFERS: + return VfatFlush(IrpContext); + default: + DPRINT1 ("Unexpected major function %x\n", IrpContext->MajorFunction); + IrpContext->Irp->IoStatus.Status = STATUS_DRIVER_INTERNAL_ERROR; + IoCompleteRequest(IrpContext->Irp, IO_NO_INCREMENT); + VfatFreeIrpContext(IrpContext); + return STATUS_DRIVER_INTERNAL_ERROR; + } +} + +NTSTATUS NTAPI VfatBuildRequest ( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + NTSTATUS Status; + PVFAT_IRP_CONTEXT IrpContext; + + DPRINT ("VfatBuildRequest (DeviceObject %p, Irp %p)\n", DeviceObject, Irp); + + ASSERT(DeviceObject); + ASSERT(Irp); + IrpContext = VfatAllocateIrpContext(DeviceObject, Irp); + if (IrpContext == NULL) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + Irp->IoStatus.Status = Status; + IoCompleteRequest (Irp, IO_NO_INCREMENT); + } + else + { + FsRtlEnterFileSystem(); + Status = VfatDispatchRequest (IrpContext); + FsRtlExitFileSystem(); + } + return Status; +} + +VOID VfatFreeIrpContext (PVFAT_IRP_CONTEXT IrpContext) +{ + ASSERT(IrpContext); + ExFreeToNPagedLookasideList(&VfatGlobalData->IrpContextLookasideList, IrpContext); +} + +PVFAT_IRP_CONTEXT VfatAllocateIrpContext(PDEVICE_OBJECT DeviceObject, PIRP Irp) +{ + PVFAT_IRP_CONTEXT IrpContext; + /*PIO_STACK_LOCATION Stack;*/ + UCHAR MajorFunction; + DPRINT ("VfatAllocateIrpContext(DeviceObject %p, Irp %p)\n", DeviceObject, Irp); + + ASSERT(DeviceObject); + ASSERT(Irp); + + IrpContext = ExAllocateFromNPagedLookasideList(&VfatGlobalData->IrpContextLookasideList); + if (IrpContext) + { + RtlZeroMemory(IrpContext, sizeof(VFAT_IRP_CONTEXT)); + IrpContext->Irp = Irp; + IrpContext->DeviceObject = DeviceObject; + IrpContext->DeviceExt = DeviceObject->DeviceExtension; + IrpContext->Stack = IoGetCurrentIrpStackLocation(Irp); + ASSERT(IrpContext->Stack); + MajorFunction = IrpContext->MajorFunction = IrpContext->Stack->MajorFunction; + IrpContext->MinorFunction = IrpContext->Stack->MinorFunction; + IrpContext->FileObject = IrpContext->Stack->FileObject; + IrpContext->Flags = 0; + if (MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL || + MajorFunction == IRP_MJ_DEVICE_CONTROL || + MajorFunction == IRP_MJ_SHUTDOWN) + { + IrpContext->Flags |= IRPCONTEXT_CANWAIT; + } + else if (MajorFunction != IRP_MJ_CLEANUP && + MajorFunction != IRP_MJ_CLOSE && + IoIsOperationSynchronous(Irp)) + { + IrpContext->Flags |= IRPCONTEXT_CANWAIT; + } + KeInitializeEvent(&IrpContext->Event, NotificationEvent, FALSE); + IrpContext->RefCount = 0; + } + return IrpContext; +} + +static VOID NTAPI VfatDoRequest (PVOID IrpContext) +{ + InterlockedDecrement(&QueueCount); + DPRINT ("VfatDoRequest (IrpContext %p), MajorFunction %x, %d\n", IrpContext, ((PVFAT_IRP_CONTEXT)IrpContext)->MajorFunction, QueueCount); + FsRtlEnterFileSystem(); + VfatDispatchRequest((PVFAT_IRP_CONTEXT)IrpContext); + FsRtlExitFileSystem(); + +} + +NTSTATUS VfatQueueRequest(PVFAT_IRP_CONTEXT IrpContext) +{ + InterlockedIncrement(&QueueCount); + DPRINT ("VfatQueueRequest (IrpContext %p), %d\n", IrpContext, QueueCount); + + ASSERT(IrpContext != NULL); + ASSERT(IrpContext->Irp != NULL); + + IrpContext->Flags |= IRPCONTEXT_CANWAIT; + IoMarkIrpPending (IrpContext->Irp); + ExInitializeWorkItem (&IrpContext->WorkQueueItem, VfatDoRequest, IrpContext); + ExQueueWorkItem(&IrpContext->WorkQueueItem, CriticalWorkQueue); + return STATUS_PENDING; +} + +PVOID VfatGetUserBuffer(IN PIRP Irp) +{ + ASSERT(Irp); + + if (Irp->MdlAddress) + { + /* This call may be in the paging path, so use maximum priority */ + /* FIXME: call with normal priority in the non-paging path */ + return MmGetSystemAddressForMdlSafe(Irp->MdlAddress, HighPagePriority); + } + else + { + return Irp->UserBuffer; + } +} + +NTSTATUS VfatLockUserBuffer(IN PIRP Irp, IN ULONG Length, IN LOCK_OPERATION Operation) +{ + ASSERT(Irp); + + if (Irp->MdlAddress) + { + return STATUS_SUCCESS; + } + + IoAllocateMdl(Irp->UserBuffer, Length, FALSE, FALSE, Irp); + + if (!Irp->MdlAddress) + { + return STATUS_INSUFFICIENT_RESOURCES; + } + + MmProbeAndLockPages(Irp->MdlAddress, Irp->RequestorMode, Operation); + + return STATUS_SUCCESS; +} + + diff --git a/reactos/drivers/filesystems/fastfat_new/rw.c b/reactos/drivers/filesystems/fastfat_new/rw.c new file mode 100644 index 00000000000..519ef128e32 --- /dev/null +++ b/reactos/drivers/filesystems/fastfat_new/rw.c @@ -0,0 +1,1069 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: drivers/fs/vfat/rw.c + * PURPOSE: VFAT Filesystem + * PROGRAMMER: Jason Filby (jasonfilby@yahoo.com) + * + */ + +/* INCLUDES *****************************************************************/ + +#define NDEBUG +#include "vfat.h" + +/* + * Uncomment to enable strict verification of cluster/offset pair + * caching. If this option is enabled you lose all the benefits of + * the caching and the read/write operations will actually be + * slower. It's meant only for debugging!!! + * - Filip Navara, 26/07/2004 + */ +/* #define DEBUG_VERIFY_OFFSET_CACHING */ + +/* FUNCTIONS *****************************************************************/ + +NTSTATUS +NextCluster(PDEVICE_EXTENSION DeviceExt, + ULONG FirstCluster, + PULONG CurrentCluster, + BOOLEAN Extend) + /* + * Return the next cluster in a FAT chain, possibly extending the chain if + * necessary + */ +{ + if (FirstCluster == 1) + { + (*CurrentCluster) += DeviceExt->FatInfo.SectorsPerCluster; + return(STATUS_SUCCESS); + } + else + { + if (Extend) + return GetNextClusterExtend(DeviceExt, (*CurrentCluster), CurrentCluster); + else + return GetNextCluster(DeviceExt, (*CurrentCluster), CurrentCluster); + } +} + +NTSTATUS +OffsetToCluster(PDEVICE_EXTENSION DeviceExt, + ULONG FirstCluster, + ULONG FileOffset, + PULONG Cluster, + BOOLEAN Extend) + /* + * Return the cluster corresponding to an offset within a file, + * possibly extending the file if necessary + */ +{ + ULONG CurrentCluster; + ULONG i; + NTSTATUS Status; +/* + DPRINT("OffsetToCluster(DeviceExt %x, Fcb %x, FirstCluster %x," + " FileOffset %x, Cluster %x, Extend %d)\n", DeviceExt, + Fcb, FirstCluster, FileOffset, Cluster, Extend); +*/ + if (FirstCluster == 0) + { + DbgPrint("OffsetToCluster is called with FirstCluster = 0!\n"); + ASSERT(FALSE); + } + + if (FirstCluster == 1) + { + /* root of FAT16 or FAT12 */ + *Cluster = DeviceExt->FatInfo.rootStart + FileOffset + / (DeviceExt->FatInfo.BytesPerCluster) * DeviceExt->FatInfo.SectorsPerCluster; + return(STATUS_SUCCESS); + } + else + { + CurrentCluster = FirstCluster; + if (Extend) + { + for (i = 0; i < FileOffset / DeviceExt->FatInfo.BytesPerCluster; i++) + { + Status = GetNextClusterExtend (DeviceExt, CurrentCluster, &CurrentCluster); + if (!NT_SUCCESS(Status)) + return(Status); + } + *Cluster = CurrentCluster; + } + else + { + for (i = 0; i < FileOffset / DeviceExt->FatInfo.BytesPerCluster; i++) + { + Status = GetNextCluster (DeviceExt, CurrentCluster, &CurrentCluster); + if (!NT_SUCCESS(Status)) + return(Status); + } + *Cluster = CurrentCluster; + } + return(STATUS_SUCCESS); + } +} + +static NTSTATUS +VfatReadFileData (PVFAT_IRP_CONTEXT IrpContext, + ULONG Length, + LARGE_INTEGER ReadOffset, + PULONG LengthRead) +/* + * FUNCTION: Reads data from a file + */ +{ + ULONG CurrentCluster; + ULONG FirstCluster; + ULONG StartCluster; + ULONG ClusterCount; + LARGE_INTEGER StartOffset; + PDEVICE_EXTENSION DeviceExt; + BOOLEAN First = TRUE; + PVFATFCB Fcb; + PVFATCCB Ccb; + NTSTATUS Status; + ULONG BytesDone; + ULONG BytesPerSector; + ULONG BytesPerCluster; + ULONG LastCluster; + ULONG LastOffset; + + /* PRECONDITION */ + ASSERT(IrpContext); + DeviceExt = IrpContext->DeviceExt; + ASSERT(DeviceExt); + ASSERT(DeviceExt->FatInfo.BytesPerCluster); + ASSERT(IrpContext->FileObject); + ASSERT(IrpContext->FileObject->FsContext2 != NULL); + + DPRINT("VfatReadFileData(DeviceExt %p, FileObject %p, " + "Length %d, ReadOffset 0x%I64x)\n", DeviceExt, + IrpContext->FileObject, Length, ReadOffset.QuadPart); + + *LengthRead = 0; + + Ccb = (PVFATCCB)IrpContext->FileObject->FsContext2; + Fcb = IrpContext->FileObject->FsContext; + BytesPerSector = DeviceExt->FatInfo.BytesPerSector; + BytesPerCluster = DeviceExt->FatInfo.BytesPerCluster; + + ASSERT(ReadOffset.QuadPart + Length <= ROUND_UP(Fcb->RFCB.FileSize.QuadPart, BytesPerSector)); + ASSERT(ReadOffset.u.LowPart % BytesPerSector == 0); + ASSERT(Length % BytesPerSector == 0); + + /* Is this a read of the FAT? */ + if (Fcb->Flags & FCB_IS_FAT) + { + ReadOffset.QuadPart += DeviceExt->FatInfo.FATStart * BytesPerSector; + Status = VfatReadDiskPartial(IrpContext, &ReadOffset, Length, 0, TRUE); + + if (NT_SUCCESS(Status)) + { + *LengthRead = Length; + } + else + { + DPRINT1("FAT reading failed, Status %x\n", Status); + } + return Status; + } + /* Is this a read of the Volume ? */ + if (Fcb->Flags & FCB_IS_VOLUME) + { + Status = VfatReadDiskPartial(IrpContext, &ReadOffset, Length, 0, TRUE); + if (NT_SUCCESS(Status)) + { + *LengthRead = Length; + } + else + { + DPRINT1("Volume reading failed, Status %x\n", Status); + } + return Status; + } + + /* + * Find the first cluster + */ + FirstCluster = CurrentCluster = + vfatDirEntryGetFirstCluster (DeviceExt, &Fcb->entry); + + if (FirstCluster == 1) + { + // Directory of FAT12/16 needs a special handling + if (ReadOffset.u.LowPart + Length > DeviceExt->FatInfo.rootDirectorySectors * BytesPerSector) + { + Length = DeviceExt->FatInfo.rootDirectorySectors * BytesPerSector - ReadOffset.u.LowPart; + } + ReadOffset.u.LowPart += DeviceExt->FatInfo.rootStart * BytesPerSector; + + // Fire up the read command + + Status = VfatReadDiskPartial (IrpContext, &ReadOffset, Length, 0, TRUE); + if (NT_SUCCESS(Status)) + { + *LengthRead = Length; + } + return Status; + } + + ExAcquireFastMutex(&Fcb->LastMutex); + LastCluster = Fcb->LastCluster; + LastOffset = Fcb->LastOffset; + ExReleaseFastMutex(&Fcb->LastMutex); + + /* + * Find the cluster to start the read from + */ + if (LastCluster > 0 && ReadOffset.u.LowPart >= LastOffset) + { + Status = OffsetToCluster(DeviceExt, LastCluster, + ROUND_DOWN(ReadOffset.u.LowPart, BytesPerCluster) - + LastOffset, + &CurrentCluster, FALSE); +#ifdef DEBUG_VERIFY_OFFSET_CACHING + /* DEBUG VERIFICATION */ + { + ULONG CorrectCluster; + OffsetToCluster(DeviceExt, FirstCluster, + ROUND_DOWN(ReadOffset.u.LowPart, BytesPerCluster), + &CorrectCluster, FALSE); + if (CorrectCluster != CurrentCluster) + KeBugCheck(FAT_FILE_SYSTEM); + } +#endif + } + else + { + Status = OffsetToCluster(DeviceExt, FirstCluster, + ROUND_DOWN(ReadOffset.u.LowPart, BytesPerCluster), + &CurrentCluster, FALSE); + } + if (!NT_SUCCESS(Status)) + { + return(Status); + } + + ExAcquireFastMutex(&Fcb->LastMutex); + Fcb->LastCluster = CurrentCluster; + Fcb->LastOffset = ROUND_DOWN (ReadOffset.u.LowPart, BytesPerCluster); + ExReleaseFastMutex(&Fcb->LastMutex); + + KeInitializeEvent(&IrpContext->Event, NotificationEvent, FALSE); + IrpContext->RefCount = 1; + + while (Length > 0 && CurrentCluster != 0xffffffff) + { + StartCluster = CurrentCluster; + StartOffset.QuadPart = ClusterToSector(DeviceExt, StartCluster) * BytesPerSector; + BytesDone = 0; + ClusterCount = 0; + + do + { + ClusterCount++; + if (First) + { + BytesDone = min (Length, BytesPerCluster - (ReadOffset.u.LowPart % BytesPerCluster)); + StartOffset.QuadPart += ReadOffset.u.LowPart % BytesPerCluster; + First = FALSE; + } + else + { + if (Length - BytesDone > BytesPerCluster) + { + BytesDone += BytesPerCluster; + } + else + { + BytesDone = Length; + } + } + Status = NextCluster(DeviceExt, FirstCluster, &CurrentCluster, FALSE); + } + while (StartCluster + ClusterCount == CurrentCluster && NT_SUCCESS(Status) && Length > BytesDone); + DPRINT("start %08x, next %08x, count %d\n", + StartCluster, CurrentCluster, ClusterCount); + + ExAcquireFastMutex(&Fcb->LastMutex); + Fcb->LastCluster = StartCluster + (ClusterCount - 1); + Fcb->LastOffset = ROUND_DOWN(ReadOffset.u.LowPart, BytesPerCluster) + (ClusterCount - 1) * BytesPerCluster; + ExReleaseFastMutex(&Fcb->LastMutex); + + // Fire up the read command + Status = VfatReadDiskPartial (IrpContext, &StartOffset, BytesDone, *LengthRead, FALSE); + if (!NT_SUCCESS(Status) && Status != STATUS_PENDING) + { + break; + } + *LengthRead += BytesDone; + Length -= BytesDone; + ReadOffset.u.LowPart += BytesDone; + } + if (0 != InterlockedDecrement((PLONG)&IrpContext->RefCount)) + { + KeWaitForSingleObject(&IrpContext->Event, Executive, KernelMode, FALSE, NULL); + } + if (NT_SUCCESS(Status) || Status == STATUS_PENDING) + { + if (Length > 0) + { + Status = STATUS_UNSUCCESSFUL; + } + else + { + Status = IrpContext->Irp->IoStatus.Status; + } + } + return Status; +} + +static NTSTATUS +VfatWriteFileData(PVFAT_IRP_CONTEXT IrpContext, + ULONG Length, + LARGE_INTEGER WriteOffset) +{ + PDEVICE_EXTENSION DeviceExt; + PVFATFCB Fcb; + PVFATCCB Ccb; + ULONG Count; + ULONG FirstCluster; + ULONG CurrentCluster; + ULONG BytesDone; + ULONG StartCluster; + ULONG ClusterCount; + NTSTATUS Status = STATUS_SUCCESS; + BOOLEAN First = TRUE; + ULONG BytesPerSector; + ULONG BytesPerCluster; + LARGE_INTEGER StartOffset; + ULONG BufferOffset; + ULONG LastCluster; + ULONG LastOffset; + + /* PRECONDITION */ + ASSERT(IrpContext); + DeviceExt = IrpContext->DeviceExt; + ASSERT(DeviceExt); + ASSERT(DeviceExt->FatInfo.BytesPerCluster); + ASSERT(IrpContext->FileObject); + ASSERT(IrpContext->FileObject->FsContext2 != NULL); + + Ccb = (PVFATCCB)IrpContext->FileObject->FsContext2; + Fcb = IrpContext->FileObject->FsContext; + BytesPerCluster = DeviceExt->FatInfo.BytesPerCluster; + BytesPerSector = DeviceExt->FatInfo.BytesPerSector; + + DPRINT("VfatWriteFileData(DeviceExt %p, FileObject %p, " + "Length %d, WriteOffset 0x%I64x), '%wZ'\n", DeviceExt, + IrpContext->FileObject, Length, WriteOffset, + &Fcb->PathNameU); + + ASSERT(WriteOffset.QuadPart + Length <= Fcb->RFCB.AllocationSize.QuadPart); + ASSERT(WriteOffset.u.LowPart % BytesPerSector == 0); + ASSERT(Length % BytesPerSector == 0); + + // Is this a write of the volume ? + if (Fcb->Flags & FCB_IS_VOLUME) + { + Status = VfatWriteDiskPartial(IrpContext, &WriteOffset, Length, 0, TRUE); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Volume writing failed, Status %x\n", Status); + } + return Status; + } + + // Is this a write to the FAT ? + if (Fcb->Flags & FCB_IS_FAT) + { + WriteOffset.u.LowPart += DeviceExt->FatInfo.FATStart * BytesPerSector; + IrpContext->RefCount = 1; + for (Count = 0; Count < DeviceExt->FatInfo.FATCount; Count++) + { + Status = VfatWriteDiskPartial(IrpContext, &WriteOffset, Length, 0, FALSE); + if (!NT_SUCCESS(Status) && Status != STATUS_PENDING) + { + DPRINT1("FAT writing failed, Status %x\n", Status); + break; + } + WriteOffset.u.LowPart += Fcb->RFCB.FileSize.u.LowPart; + } + if (0 != InterlockedDecrement((PLONG)&IrpContext->RefCount)) + { + KeWaitForSingleObject(&IrpContext->Event, Executive, KernelMode, FALSE, NULL); + } + if (NT_SUCCESS(Status) || Status == STATUS_PENDING) + { + Status = IrpContext->Irp->IoStatus.Status; + } + return Status; + } + + /* + * Find the first cluster + */ + FirstCluster = CurrentCluster = + vfatDirEntryGetFirstCluster (DeviceExt, &Fcb->entry); + + if (FirstCluster == 1) + { + ASSERT(WriteOffset.u.LowPart + Length <= DeviceExt->FatInfo.rootDirectorySectors * BytesPerSector); + // Directory of FAT12/16 needs a special handling + WriteOffset.u.LowPart += DeviceExt->FatInfo.rootStart * BytesPerSector; + // Fire up the write command + Status = VfatWriteDiskPartial (IrpContext, &WriteOffset, Length, 0, TRUE); + return Status; + } + + ExAcquireFastMutex(&Fcb->LastMutex); + LastCluster = Fcb->LastCluster; + LastOffset = Fcb->LastOffset; + ExReleaseFastMutex(&Fcb->LastMutex); + + /* + * Find the cluster to start the write from + */ + if (LastCluster > 0 && WriteOffset.u.LowPart >= LastOffset) + { + Status = OffsetToCluster(DeviceExt, LastCluster, + ROUND_DOWN(WriteOffset.u.LowPart, BytesPerCluster) - + LastOffset, + &CurrentCluster, FALSE); +#ifdef DEBUG_VERIFY_OFFSET_CACHING + /* DEBUG VERIFICATION */ + { + ULONG CorrectCluster; + OffsetToCluster(DeviceExt, FirstCluster, + ROUND_DOWN(WriteOffset.u.LowPart, BytesPerCluster), + &CorrectCluster, FALSE); + if (CorrectCluster != CurrentCluster) + KeBugCheck(FAT_FILE_SYSTEM); + } +#endif + } + else + { + Status = OffsetToCluster(DeviceExt, FirstCluster, + ROUND_DOWN(WriteOffset.u.LowPart, BytesPerCluster), + &CurrentCluster, FALSE); + } + + if (!NT_SUCCESS(Status)) + { + return(Status); + } + + ExAcquireFastMutex(&Fcb->LastMutex); + Fcb->LastCluster = CurrentCluster; + Fcb->LastOffset = ROUND_DOWN (WriteOffset.u.LowPart, BytesPerCluster); + ExReleaseFastMutex(&Fcb->LastMutex); + + IrpContext->RefCount = 1; + BufferOffset = 0; + + while (Length > 0 && CurrentCluster != 0xffffffff) + { + StartCluster = CurrentCluster; + StartOffset.QuadPart = ClusterToSector(DeviceExt, StartCluster) * BytesPerSector; + BytesDone = 0; + ClusterCount = 0; + + do + { + ClusterCount++; + if (First) + { + BytesDone = min (Length, BytesPerCluster - (WriteOffset.u.LowPart % BytesPerCluster)); + StartOffset.QuadPart += WriteOffset.u.LowPart % BytesPerCluster; + First = FALSE; + } + else + { + if (Length - BytesDone > BytesPerCluster) + { + BytesDone += BytesPerCluster; + } + else + { + BytesDone = Length; + } + } + Status = NextCluster(DeviceExt, FirstCluster, &CurrentCluster, FALSE); + } + while (StartCluster + ClusterCount == CurrentCluster && NT_SUCCESS(Status) && Length > BytesDone); + DPRINT("start %08x, next %08x, count %d\n", + StartCluster, CurrentCluster, ClusterCount); + + ExAcquireFastMutex(&Fcb->LastMutex); + Fcb->LastCluster = StartCluster + (ClusterCount - 1); + Fcb->LastOffset = ROUND_DOWN(WriteOffset.u.LowPart, BytesPerCluster) + (ClusterCount - 1) * BytesPerCluster; + ExReleaseFastMutex(&Fcb->LastMutex); + + // Fire up the write command + Status = VfatWriteDiskPartial (IrpContext, &StartOffset, BytesDone, BufferOffset, FALSE); + if (!NT_SUCCESS(Status) && Status != STATUS_PENDING) + { + break; + } + BufferOffset += BytesDone; + Length -= BytesDone; + WriteOffset.u.LowPart += BytesDone; + } + if (0 != InterlockedDecrement((PLONG)&IrpContext->RefCount)) + { + KeWaitForSingleObject(&IrpContext->Event, Executive, KernelMode, FALSE, NULL); + } + if (NT_SUCCESS(Status) || Status == STATUS_PENDING) + { + if (Length > 0) + { + Status = STATUS_UNSUCCESSFUL; + } + else + { + Status = IrpContext->Irp->IoStatus.Status; + } + } + return Status; +} + +NTSTATUS +VfatRead(PVFAT_IRP_CONTEXT IrpContext) +{ + NTSTATUS Status; + PVFATFCB Fcb; + ULONG Length = 0; + ULONG ReturnedLength = 0; + PERESOURCE Resource = NULL; + LARGE_INTEGER ByteOffset; + PVOID Buffer; + PDEVICE_OBJECT DeviceToVerify; + ULONG BytesPerSector; + + ASSERT(IrpContext); + + DPRINT("VfatRead(IrpContext %p)\n", IrpContext); + + ASSERT(IrpContext->DeviceObject); + + // This request is not allowed on the main device object + if (IrpContext->DeviceObject == VfatGlobalData->DeviceObject) + { + DPRINT("VfatRead is called with the main device object.\n"); + Status = STATUS_INVALID_DEVICE_REQUEST; + goto ByeBye; + } + + ASSERT(IrpContext->DeviceExt); + ASSERT(IrpContext->FileObject); + Fcb = IrpContext->FileObject->FsContext; + ASSERT(Fcb); + + DPRINT("<%wZ>\n", &Fcb->PathNameU); + + if (Fcb->Flags & FCB_IS_PAGE_FILE) + { + PFATINFO FatInfo = &IrpContext->DeviceExt->FatInfo; + IrpContext->Stack->Parameters.Read.ByteOffset.QuadPart += FatInfo->dataStart * FatInfo->BytesPerSector; + IoSkipCurrentIrpStackLocation(IrpContext->Irp); + DPRINT("Read from page file, disk offset %I64x\n", IrpContext->Stack->Parameters.Read.ByteOffset.QuadPart); + Status = IoCallDriver(IrpContext->DeviceExt->StorageDevice, IrpContext->Irp); + VfatFreeIrpContext(IrpContext); + return Status; + } + + ByteOffset = IrpContext->Stack->Parameters.Read.ByteOffset; + Length = IrpContext->Stack->Parameters.Read.Length; + BytesPerSector = IrpContext->DeviceExt->FatInfo.BytesPerSector; + + /* fail if file is a directory and no paged read */ + if (*Fcb->Attributes & FILE_ATTRIBUTE_DIRECTORY && !(IrpContext->Irp->Flags & IRP_PAGING_IO)) + { + Status = STATUS_INVALID_PARAMETER; + goto ByeBye; + } + + + DPRINT("'%wZ', Offset: %d, Length %d\n", &Fcb->PathNameU, ByteOffset.u.LowPart, Length); + + if (ByteOffset.u.HighPart && !(Fcb->Flags & FCB_IS_VOLUME)) + { + Status = STATUS_INVALID_PARAMETER; + goto ByeBye; + } + if (ByteOffset.QuadPart >= Fcb->RFCB.FileSize.QuadPart) + { + IrpContext->Irp->IoStatus.Information = 0; + Status = STATUS_END_OF_FILE; + goto ByeBye; + } + if (IrpContext->Irp->Flags & (IRP_PAGING_IO | IRP_NOCACHE) || (Fcb->Flags & FCB_IS_VOLUME)) + { + if (ByteOffset.u.LowPart % BytesPerSector != 0 || Length % BytesPerSector != 0) + { + DPRINT("%d %d\n", ByteOffset.u.LowPart, Length); + // non cached read must be sector aligned + Status = STATUS_INVALID_PARAMETER; + goto ByeBye; + } + } + if (Length == 0) + { + IrpContext->Irp->IoStatus.Information = 0; + Status = STATUS_SUCCESS; + goto ByeBye; + } + + if (Fcb->Flags & FCB_IS_VOLUME) + { + Resource = &IrpContext->DeviceExt->DirResource; + } + else if (IrpContext->Irp->Flags & IRP_PAGING_IO) + { + Resource = &Fcb->PagingIoResource; + } + else + { + Resource = &Fcb->MainResource; + } + if (!ExAcquireResourceSharedLite(Resource, + IrpContext->Flags & IRPCONTEXT_CANWAIT ? TRUE : FALSE)) + { + Resource = NULL; + Status = STATUS_PENDING; + goto ByeBye; + } + + if (!(IrpContext->Irp->Flags & IRP_PAGING_IO) && + FsRtlAreThereCurrentFileLocks(&Fcb->FileLock)) + { + if (!FsRtlCheckLockForReadAccess(&Fcb->FileLock, IrpContext->Irp)) + { + Status = STATUS_FILE_LOCK_CONFLICT; + goto ByeBye; + } + } + + Buffer = VfatGetUserBuffer(IrpContext->Irp); + if (!Buffer) + { + Status = STATUS_INVALID_USER_BUFFER; + goto ByeBye; + } + + if (!(IrpContext->Irp->Flags & (IRP_NOCACHE|IRP_PAGING_IO)) && + !(Fcb->Flags & (FCB_IS_PAGE_FILE|FCB_IS_VOLUME))) + { + // cached read + Status = STATUS_SUCCESS; + if (ByteOffset.u.LowPart + Length > Fcb->RFCB.FileSize.u.LowPart) + { + Length = Fcb->RFCB.FileSize.u.LowPart - ByteOffset.u.LowPart; + Status = /*STATUS_END_OF_FILE*/STATUS_SUCCESS; + } + + if (IrpContext->FileObject->PrivateCacheMap == NULL) + { + CcInitializeCacheMap(IrpContext->FileObject, + (PCC_FILE_SIZES)(&Fcb->RFCB.AllocationSize), + FALSE, + &(VfatGlobalData->CacheMgrCallbacks), + Fcb); + } + if (!CcCopyRead(IrpContext->FileObject, &ByteOffset, Length, + (BOOLEAN)(IrpContext->Flags & IRPCONTEXT_CANWAIT), Buffer, + &IrpContext->Irp->IoStatus)) + { + Status = STATUS_PENDING; + goto ByeBye; + } + if (!NT_SUCCESS(IrpContext->Irp->IoStatus.Status)) + { + Status = IrpContext->Irp->IoStatus.Status; + } + } + else + { + // non cached read + if (ByteOffset.QuadPart + Length > ROUND_UP(Fcb->RFCB.FileSize.QuadPart, BytesPerSector)) + { + Length = (ULONG)(ROUND_UP(Fcb->RFCB.FileSize.QuadPart, BytesPerSector) - ByteOffset.QuadPart); + } + + Status = VfatLockUserBuffer(IrpContext->Irp, Length, IoWriteAccess); + if (!NT_SUCCESS(Status)) + { + goto ByeBye; + } + + Status = VfatReadFileData(IrpContext, Length, ByteOffset, &ReturnedLength); +/**/ + if (Status == STATUS_VERIFY_REQUIRED) + { + DPRINT("VfatReadFile returned STATUS_VERIFY_REQUIRED\n"); + DeviceToVerify = IoGetDeviceToVerify(PsGetCurrentThread()); + IoSetDeviceToVerify(PsGetCurrentThread(), DeviceToVerify); + Status = IoVerifyVolume (DeviceToVerify, FALSE); + + if (NT_SUCCESS(Status)) + { + Status = VfatReadFileData(IrpContext, Length, + ByteOffset, &ReturnedLength); + } + + } +/**/ + if (NT_SUCCESS(Status)) + { + IrpContext->Irp->IoStatus.Information = ReturnedLength; + } + } + +ByeBye: + if (Resource) + { + ExReleaseResourceLite(Resource); + } + + if (Status == STATUS_PENDING) + { + Status = VfatLockUserBuffer(IrpContext->Irp, Length, IoWriteAccess); + if (NT_SUCCESS(Status)) + { + Status = VfatQueueRequest(IrpContext); + } + else + { + IrpContext->Irp->IoStatus.Status = Status; + IoCompleteRequest(IrpContext->Irp, IO_NO_INCREMENT); + VfatFreeIrpContext(IrpContext); + } + } + else + { + IrpContext->Irp->IoStatus.Status = Status; + if (IrpContext->FileObject->Flags & FO_SYNCHRONOUS_IO && + !(IrpContext->Irp->Flags & IRP_PAGING_IO) && + (NT_SUCCESS(Status) || Status==STATUS_END_OF_FILE)) + { + IrpContext->FileObject->CurrentByteOffset.QuadPart = + ByteOffset.QuadPart + IrpContext->Irp->IoStatus.Information; + } + + IoCompleteRequest(IrpContext->Irp, + (CCHAR)(NT_SUCCESS(Status) ? IO_DISK_INCREMENT : IO_NO_INCREMENT)); + VfatFreeIrpContext(IrpContext); + } + DPRINT("%x\n", Status); + return Status; +} + +NTSTATUS VfatWrite (PVFAT_IRP_CONTEXT IrpContext) +{ + PVFATFCB Fcb; + PERESOURCE Resource = NULL; + LARGE_INTEGER ByteOffset; + LARGE_INTEGER OldFileSize; + NTSTATUS Status = STATUS_SUCCESS; + ULONG Length = 0; + ULONG OldAllocationSize; + PVOID Buffer; + ULONG BytesPerSector; + + ASSERT(IrpContext); + + DPRINT("VfatWrite(IrpContext %p)\n", IrpContext); + + ASSERT(IrpContext->DeviceObject); + + // This request is not allowed on the main device object + if (IrpContext->DeviceObject == VfatGlobalData->DeviceObject) + { + DPRINT("VfatWrite is called with the main device object.\n"); + Status = STATUS_INVALID_DEVICE_REQUEST; + goto ByeBye; + } + + ASSERT(IrpContext->DeviceExt); + ASSERT(IrpContext->FileObject); + Fcb = IrpContext->FileObject->FsContext; + ASSERT(Fcb); + + DPRINT("<%wZ>\n", &Fcb->PathNameU); + + if (Fcb->Flags & FCB_IS_PAGE_FILE) + { + PFATINFO FatInfo = &IrpContext->DeviceExt->FatInfo; + IrpContext->Stack->Parameters.Write.ByteOffset.QuadPart += FatInfo->dataStart * FatInfo->BytesPerSector; + IoSkipCurrentIrpStackLocation(IrpContext->Irp); + DPRINT("Write to page file, disk offset %I64x\n", IrpContext->Stack->Parameters.Write.ByteOffset.QuadPart); + Status = IoCallDriver(IrpContext->DeviceExt->StorageDevice, IrpContext->Irp); + VfatFreeIrpContext(IrpContext); + return Status; + } + + /* fail if file is a directory and no paged read */ + if (*Fcb->Attributes & FILE_ATTRIBUTE_DIRECTORY && !(IrpContext->Irp->Flags & IRP_PAGING_IO)) + { + Status = STATUS_INVALID_PARAMETER; + goto ByeBye; + } + + ByteOffset = IrpContext->Stack->Parameters.Write.ByteOffset; + if (ByteOffset.u.LowPart == FILE_WRITE_TO_END_OF_FILE && + ByteOffset.u.HighPart == -1) + { + ByteOffset.QuadPart = Fcb->RFCB.FileSize.QuadPart; + } + Length = IrpContext->Stack->Parameters.Write.Length; + BytesPerSector = IrpContext->DeviceExt->FatInfo.BytesPerSector; + + if (ByteOffset.u.HighPart && !(Fcb->Flags & FCB_IS_VOLUME)) + { + Status = STATUS_INVALID_PARAMETER; + goto ByeBye; + } + + if (Fcb->Flags & (FCB_IS_FAT | FCB_IS_VOLUME) || + 1 == vfatDirEntryGetFirstCluster (IrpContext->DeviceExt, &Fcb->entry)) + { + if (ByteOffset.QuadPart + Length > Fcb->RFCB.FileSize.QuadPart) + { + // we can't extend the FAT, the volume or the root on FAT12/FAT16 + Status = STATUS_END_OF_FILE; + goto ByeBye; + } + } + + if (IrpContext->Irp->Flags & (IRP_PAGING_IO|IRP_NOCACHE) || (Fcb->Flags & FCB_IS_VOLUME)) + { + if (ByteOffset.u.LowPart % BytesPerSector != 0 || Length % BytesPerSector != 0) + { + // non cached write must be sector aligned + Status = STATUS_INVALID_PARAMETER; + goto ByeBye; + } + } + + if (Length == 0) + { + /* FIXME: + * Update last write time + */ + IrpContext->Irp->IoStatus.Information = 0; + Status = STATUS_SUCCESS; + goto ByeBye; + } + + if (IrpContext->Irp->Flags & IRP_PAGING_IO) + { + if (ByteOffset.u.LowPart + Length > Fcb->RFCB.AllocationSize.u.LowPart) + { + Status = STATUS_INVALID_PARAMETER; + goto ByeBye; + } + if (ByteOffset.u.LowPart + Length > ROUND_UP(Fcb->RFCB.AllocationSize.u.LowPart, BytesPerSector)) + { + Length = ROUND_UP(Fcb->RFCB.FileSize.u.LowPart, BytesPerSector) - ByteOffset.u.LowPart; + } + } + + if (Fcb->Flags & FCB_IS_VOLUME) + { + Resource = &IrpContext->DeviceExt->DirResource; + } + else if (IrpContext->Irp->Flags & IRP_PAGING_IO) + { + Resource = &Fcb->PagingIoResource; + } + else + { + Resource = &Fcb->MainResource; + } + + if (Fcb->Flags & FCB_IS_PAGE_FILE) + { + if (!ExAcquireResourceSharedLite(Resource, + (BOOLEAN)(IrpContext->Flags & IRPCONTEXT_CANWAIT))) + { + Resource = NULL; + Status = STATUS_PENDING; + goto ByeBye; + } + } + else + { + if (!ExAcquireResourceExclusiveLite(Resource, + (BOOLEAN)(IrpContext->Flags & IRPCONTEXT_CANWAIT))) + { + Resource = NULL; + Status = STATUS_PENDING; + goto ByeBye; + } + } + + if (!(IrpContext->Irp->Flags & IRP_PAGING_IO) && + FsRtlAreThereCurrentFileLocks(&Fcb->FileLock)) + { + if (!FsRtlCheckLockForWriteAccess(&Fcb->FileLock, IrpContext->Irp)) + { + Status = STATUS_FILE_LOCK_CONFLICT; + goto ByeBye; + } + } + + if (!(IrpContext->Flags & IRPCONTEXT_CANWAIT) && !(Fcb->Flags & FCB_IS_VOLUME)) + { + if (ByteOffset.u.LowPart + Length > Fcb->RFCB.AllocationSize.u.LowPart) + { + Status = STATUS_PENDING; + goto ByeBye; + } + } + + OldFileSize = Fcb->RFCB.FileSize; + OldAllocationSize = Fcb->RFCB.AllocationSize.u.LowPart; + + Buffer = VfatGetUserBuffer(IrpContext->Irp); + if (!Buffer) + { + Status = STATUS_INVALID_USER_BUFFER; + goto ByeBye; + } + + + if (!(Fcb->Flags & (FCB_IS_FAT|FCB_IS_VOLUME)) && + !(IrpContext->Irp->Flags & IRP_PAGING_IO) && + ByteOffset.u.LowPart + Length > Fcb->RFCB.FileSize.u.LowPart) + { + LARGE_INTEGER AllocationSize; + AllocationSize.QuadPart = ByteOffset.u.LowPart + Length; + Status = VfatSetAllocationSizeInformation(IrpContext->FileObject, Fcb, + IrpContext->DeviceExt, &AllocationSize); + if (!NT_SUCCESS (Status)) + { + goto ByeBye; + } + } + + if (!(IrpContext->Irp->Flags & (IRP_NOCACHE|IRP_PAGING_IO)) && + !(Fcb->Flags & (FCB_IS_PAGE_FILE|FCB_IS_VOLUME))) + { + // cached write + + if (IrpContext->FileObject->PrivateCacheMap == NULL) + { + CcInitializeCacheMap(IrpContext->FileObject, + (PCC_FILE_SIZES)(&Fcb->RFCB.AllocationSize), + FALSE, + &VfatGlobalData->CacheMgrCallbacks, + Fcb); + } + if (ByteOffset.QuadPart > OldFileSize.QuadPart) + { + CcZeroData(IrpContext->FileObject, &OldFileSize, &ByteOffset, TRUE); + } + if (CcCopyWrite(IrpContext->FileObject, &ByteOffset, Length, + 1 /*IrpContext->Flags & IRPCONTEXT_CANWAIT*/, Buffer)) + { + IrpContext->Irp->IoStatus.Information = Length; + Status = STATUS_SUCCESS; + } + else + { + Status = STATUS_UNSUCCESSFUL; + } + } + else + { + // non cached write + + if (ByteOffset.QuadPart > OldFileSize.QuadPart) + { + CcZeroData(IrpContext->FileObject, &OldFileSize, &ByteOffset, TRUE); + } + + Status = VfatLockUserBuffer(IrpContext->Irp, Length, IoReadAccess); + if (!NT_SUCCESS(Status)) + { + goto ByeBye; + } + + Status = VfatWriteFileData(IrpContext, Length, ByteOffset); + if (NT_SUCCESS(Status)) + { + IrpContext->Irp->IoStatus.Information = Length; + } + } + + if (!(IrpContext->Irp->Flags & IRP_PAGING_IO) && + !(Fcb->Flags & (FCB_IS_FAT|FCB_IS_VOLUME))) + { + if(!(*Fcb->Attributes & FILE_ATTRIBUTE_DIRECTORY)) + { + LARGE_INTEGER SystemTime; + // set dates and times + KeQuerySystemTime (&SystemTime); + if (Fcb->Flags & FCB_IS_FATX_ENTRY) + { + FsdSystemTimeToDosDateTime (IrpContext->DeviceExt, + &SystemTime, &Fcb->entry.FatX.UpdateDate, + &Fcb->entry.FatX.UpdateTime); + Fcb->entry.FatX.AccessDate = Fcb->entry.FatX.UpdateDate; + Fcb->entry.FatX.AccessTime = Fcb->entry.FatX.UpdateTime; + } + else + { + FsdSystemTimeToDosDateTime (IrpContext->DeviceExt, + &SystemTime, &Fcb->entry.Fat.UpdateDate, + &Fcb->entry.Fat.UpdateTime); + Fcb->entry.Fat.AccessDate = Fcb->entry.Fat.UpdateDate; + } + /* set date and times to dirty */ + Fcb->Flags |= FCB_IS_DIRTY; + } + } + +ByeBye: + if (Resource) + { + ExReleaseResourceLite(Resource); + } + + if (Status == STATUS_PENDING) + { + Status = VfatLockUserBuffer(IrpContext->Irp, Length, IoReadAccess); + if (NT_SUCCESS(Status)) + { + Status = VfatQueueRequest(IrpContext); + } + else + { + IrpContext->Irp->IoStatus.Status = Status; + IoCompleteRequest(IrpContext->Irp, IO_NO_INCREMENT); + VfatFreeIrpContext(IrpContext); + } + } + else + { + IrpContext->Irp->IoStatus.Status = Status; + if (IrpContext->FileObject->Flags & FO_SYNCHRONOUS_IO && + !(IrpContext->Irp->Flags & IRP_PAGING_IO) && NT_SUCCESS(Status)) + { + IrpContext->FileObject->CurrentByteOffset.QuadPart = + ByteOffset.QuadPart + IrpContext->Irp->IoStatus.Information; + } + + IoCompleteRequest(IrpContext->Irp, + (CCHAR)(NT_SUCCESS(Status) ? IO_DISK_INCREMENT : IO_NO_INCREMENT)); + VfatFreeIrpContext(IrpContext); + } + DPRINT("%x\n", Status); + return Status; +} + + diff --git a/reactos/drivers/filesystems/fastfat_new/shutdown.c b/reactos/drivers/filesystems/fastfat_new/shutdown.c new file mode 100644 index 00000000000..b3f677a4f18 --- /dev/null +++ b/reactos/drivers/filesystems/fastfat_new/shutdown.c @@ -0,0 +1,118 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: drivers/fs/vfat/shutdown.c + * PURPOSE: VFAT Filesystem + * PROGRAMMER: Eric Kohl (ekohl@rz-online.de) + */ + +/* INCLUDES *****************************************************************/ + +#define NDEBUG +#include "vfat.h" + +/* FUNCTIONS ****************************************************************/ + +static NTSTATUS +VfatDiskShutDown(PVCB Vcb) +{ + PIRP Irp; + KEVENT Event; + NTSTATUS Status; + IO_STATUS_BLOCK IoStatus; + + KeInitializeEvent(&Event, NotificationEvent, FALSE); + Irp = IoBuildSynchronousFsdRequest(IRP_MJ_SHUTDOWN, Vcb->StorageDevice, + NULL, 0, NULL, &Event, &IoStatus); + if (Irp) + { + Status = IoCallDriver(Vcb->StorageDevice, Irp); + if (Status == STATUS_PENDING) + { + KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); + Status = IoStatus.Status; + } + } + else + { + Status = IoStatus.Status; + } + + return Status; +} + +NTSTATUS NTAPI +VfatShutdown(PDEVICE_OBJECT DeviceObject, PIRP Irp) +{ + NTSTATUS Status; + PLIST_ENTRY ListEntry; + PDEVICE_EXTENSION DeviceExt; + ULONG eocMark; + + DPRINT("VfatShutdown(DeviceObject %p, Irp %p)\n",DeviceObject, Irp); + + FsRtlEnterFileSystem(); + + /* FIXME: block new mount requests */ + + if (DeviceObject == VfatGlobalData->DeviceObject) + { + Irp->IoStatus.Status = STATUS_SUCCESS; + ExAcquireResourceExclusiveLite(&VfatGlobalData->VolumeListLock, TRUE); + ListEntry = VfatGlobalData->VolumeListHead.Flink; + while (ListEntry != &VfatGlobalData->VolumeListHead) + { + DeviceExt = CONTAINING_RECORD(ListEntry, VCB, VolumeListEntry); + ListEntry = ListEntry->Flink; + + ExAcquireResourceExclusiveLite(&DeviceExt->DirResource, TRUE); + if (DeviceExt->VolumeFcb->Flags & VCB_CLEAR_DIRTY) + { + /* set clean shutdown bit */ + Status = GetNextCluster(DeviceExt, 1, &eocMark); + if (NT_SUCCESS(Status)) + { + eocMark |= DeviceExt->CleanShutBitMask; + if (NT_SUCCESS(WriteCluster(DeviceExt, 1, eocMark))) + DeviceExt->VolumeFcb->Flags &= ~VCB_IS_DIRTY; + } + } + Status = VfatFlushVolume(DeviceExt, DeviceExt->VolumeFcb); + if (NT_SUCCESS(Status)) + { + Status = VfatDiskShutDown(DeviceExt); + if (!NT_SUCCESS(Status)) + DPRINT1("VfatDiskShutDown failed, status = %x\n", Status); + } + else + { + DPRINT1("VfatFlushVolume failed, status = %x\n", Status); + } + ExReleaseResourceLite(&DeviceExt->DirResource); + + /* FIXME: Unmount the logical volume */ + + if (!NT_SUCCESS(Status)) + Irp->IoStatus.Status = Status; + } + ExReleaseResourceLite(&VfatGlobalData->VolumeListLock); + + /* FIXME: Free all global acquired resources */ + + Status = Irp->IoStatus.Status; + } + else + { + Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST; + Status = STATUS_INVALID_DEVICE_REQUEST; + } + + Irp->IoStatus.Information = 0; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + FsRtlExitFileSystem(); + + return(Status); +} + +/* EOF */ diff --git a/reactos/drivers/filesystems/fastfat_new/string.c b/reactos/drivers/filesystems/fastfat_new/string.c new file mode 100644 index 00000000000..e6fe6e54439 --- /dev/null +++ b/reactos/drivers/filesystems/fastfat_new/string.c @@ -0,0 +1,23 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: drivers/fs/vfat/string.c + * PURPOSE: VFAT Filesystem + * PROGRAMMER: Jason Filby (jasonfilby@yahoo.com) + * + */ + +/* INCLUDES *****************************************************************/ + +#define NDEBUG +#include "vfat.h" + +/* FUNCTIONS ****************************************************************/ + +const WCHAR *long_illegals = L"\"*\\<>/?:|"; + +BOOLEAN +vfatIsLongIllegal(WCHAR c) +{ + return wcschr(long_illegals, c) ? TRUE : FALSE; +} diff --git a/reactos/drivers/filesystems/fastfat_new/vfat.h b/reactos/drivers/filesystems/fastfat_new/vfat.h new file mode 100644 index 00000000000..43f222b680c --- /dev/null +++ b/reactos/drivers/filesystems/fastfat_new/vfat.h @@ -0,0 +1,786 @@ +#include +#include +#include +#include + +#ifdef __GNUC__ +#include + +#define USE_ROS_CC_AND_FS +#else +#define KEBUGCHECK KeBugCheck +#define KEBUGCHECKEX KeBugCheckEx +#define ROUND_DOWN(N, S) ((N) - ((N) % (S))) +#define ROUND_UP(N, S) ROUND_DOWN((N) + (S) - 1, (S)) +#endif + +#include +struct _BootSector +{ + unsigned char magic0, res0, magic1; + unsigned char OEMName[8]; + unsigned short BytesPerSector; + unsigned char SectorsPerCluster; + unsigned short ReservedSectors; + unsigned char FATCount; + unsigned short RootEntries, Sectors; + unsigned char Media; + unsigned short FATSectors, SectorsPerTrack, Heads; + unsigned long HiddenSectors, SectorsHuge; + unsigned char Drive, Res1, Sig; + unsigned long VolumeID; + unsigned char VolumeLabel[11], SysType[8]; + unsigned char Res2[448]; + unsigned short Signatur1; +}; + +struct _BootSector32 +{ + unsigned char magic0, res0, magic1; // 0 + unsigned char OEMName[8]; // 3 + unsigned short BytesPerSector; // 11 + unsigned char SectorsPerCluster; // 13 + unsigned short ReservedSectors; // 14 + unsigned char FATCount; // 16 + unsigned short RootEntries, Sectors; // 17 + unsigned char Media; // 21 + unsigned short FATSectors, SectorsPerTrack, Heads; // 22 + unsigned long HiddenSectors, SectorsHuge; // 28 + unsigned long FATSectors32; // 36 + unsigned short ExtFlag; // 40 + unsigned short FSVersion; // 42 + unsigned long RootCluster; // 44 + unsigned short FSInfoSector; // 48 + unsigned short BootBackup; // 50 + unsigned char Res3[12]; // 52 + unsigned char Drive; // 64 + unsigned char Res4; // 65 + unsigned char ExtBootSignature; // 66 + unsigned long VolumeID; // 67 + unsigned char VolumeLabel[11], SysType[8]; // 71 + unsigned char Res2[420]; // 90 + unsigned short Signature1; // 510 +}; + +struct _BootSectorFatX +{ + unsigned char SysType[4]; // 0 + unsigned long VolumeID; // 4 + unsigned long SectorsPerCluster; // 8 + unsigned short FATCount; // 12 + unsigned long Unknown; // 14 + unsigned char Unused[4078]; // 18 +}; + +struct _FsInfoSector +{ + unsigned long ExtBootSignature2; // 0 + unsigned char Res6[480]; // 4 + unsigned long FSINFOSignature; // 484 + unsigned long FreeCluster; // 488 + unsigned long NextCluster; // 492 + unsigned char Res7[12]; // 496 + unsigned long Signatur2; // 508 +}; + +typedef struct _BootSector BootSector; + +struct _FATDirEntry +{ + union + { + struct { unsigned char Filename[8], Ext[3]; }; + unsigned char ShortName[11]; + }; + unsigned char Attrib; + unsigned char lCase; + unsigned char CreationTimeMs; + unsigned short CreationTime,CreationDate,AccessDate; + union + { + unsigned short FirstClusterHigh; // FAT32 + unsigned short ExtendedAttributes; // FAT12/FAT16 + }; + unsigned short UpdateTime; //time create/update + unsigned short UpdateDate; //date create/update + unsigned short FirstCluster; + unsigned long FileSize; +}; + +#define FAT_EAFILE "EA DATA. SF" + +typedef struct _EAFileHeader FAT_EA_FILE_HEADER, *PFAT_EA_FILE_HEADER; + +struct _EAFileHeader +{ + unsigned short Signature; // ED + unsigned short Unknown[15]; + unsigned short EASetTable[240]; +}; + +typedef struct _EASetHeader FAT_EA_SET_HEADER, *PFAT_EA_SET_HEADER; + +struct _EASetHeader +{ + unsigned short Signature; // EA + unsigned short Offset; // relative offset, same value as in the EASetTable + unsigned short Unknown1[2]; + char TargetFileName[12]; + unsigned short Unknown2[3]; + unsigned int EALength; + // EA Header +}; + +typedef struct _EAHeader FAT_EA_HEADER, *PFAT_EA_HEADER; + +struct _EAHeader +{ + unsigned char Unknown; + unsigned char EANameLength; + unsigned short EAValueLength; + // Name Data + // Value Data +}; + +typedef struct _FATDirEntry FAT_DIR_ENTRY, *PFAT_DIR_ENTRY; + +struct _FATXDirEntry +{ + unsigned char FilenameLength; // 0 + unsigned char Attrib; // 1 + unsigned char Filename[42]; // 2 + unsigned long FirstCluster; // 44 + unsigned long FileSize; // 48 + unsigned short UpdateTime; // 52 + unsigned short UpdateDate; // 54 + unsigned short CreationTime; // 56 + unsigned short CreationDate; // 58 + unsigned short AccessTime; // 60 + unsigned short AccessDate; // 62 +}; + +struct _slot +{ + unsigned char id; // sequence number for slot + WCHAR name0_4[5]; // first 5 characters in name + unsigned char attr; // attribute byte + unsigned char reserved; // always 0 + unsigned char alias_checksum; // checksum for 8.3 alias + WCHAR name5_10[6]; // 6 more characters in name + unsigned char start[2]; // starting cluster number + WCHAR name11_12[2]; // last 2 characters in name +}; + +typedef struct _slot slot; + +#include + +#define VFAT_CASE_LOWER_BASE 8 // base is lower case +#define VFAT_CASE_LOWER_EXT 16 // extension is lower case + +#define LONGNAME_MAX_LENGTH 256 // max length for a long filename + +#define ENTRY_DELETED(DeviceExt, DirEntry) ((DeviceExt)->Flags & VCB_IS_FATX ? FATX_ENTRY_DELETED(&((DirEntry)->FatX)) : FAT_ENTRY_DELETED(&((DirEntry)->Fat))) +#define ENTRY_VOLUME(DeviceExt, DirEntry) ((DeviceExt)->Flags & VCB_IS_FATX ? FATX_ENTRY_VOLUME(&((DirEntry)->FatX)) : FAT_ENTRY_VOLUME(&((DirEntry)->Fat))) +#define ENTRY_END(DeviceExt, DirEntry) ((DeviceExt)->Flags & VCB_IS_FATX ? FATX_ENTRY_END(&((DirEntry)->FatX)) : FAT_ENTRY_END(&((DirEntry)->Fat))) + +#define FAT_ENTRY_DELETED(DirEntry) ((DirEntry)->Filename[0] == 0xe5) +#define FAT_ENTRY_END(DirEntry) ((DirEntry)->Filename[0] == 0) +#define FAT_ENTRY_LONG(DirEntry) (((DirEntry)->Attrib & 0x3f) == 0x0f) +#define FAT_ENTRY_VOLUME(DirEntry) (((DirEntry)->Attrib & 0x1f) == 0x08) + +#define FATX_ENTRY_DELETED(DirEntry) ((DirEntry)->FilenameLength == 0xe5) +#define FATX_ENTRY_END(DirEntry) ((DirEntry)->FilenameLength == 0xff) +#define FATX_ENTRY_LONG(DirEntry) (FALSE) +#define FATX_ENTRY_VOLUME(DirEntry) (((DirEntry)->Attrib & 0x1f) == 0x08) + +#define FAT_ENTRIES_PER_PAGE (PAGE_SIZE / sizeof (FAT_DIR_ENTRY)) +#define FATX_ENTRIES_PER_PAGE (PAGE_SIZE / sizeof (FATX_DIR_ENTRY)) + +typedef struct _FATXDirEntry FATX_DIR_ENTRY, *PFATX_DIR_ENTRY; + +union _DIR_ENTRY +{ + FAT_DIR_ENTRY Fat; + FATX_DIR_ENTRY FatX; +}; + +typedef union _DIR_ENTRY DIR_ENTRY, *PDIR_ENTRY; + +#define BLOCKSIZE 512 + +#define FAT16 (1) +#define FAT12 (2) +#define FAT32 (3) +#define FATX16 (4) +#define FATX32 (5) + +#define VCB_VOLUME_LOCKED 0x0001 +#define VCB_DISMOUNT_PENDING 0x0002 +#define VCB_IS_FATX 0x0004 +#define VCB_IS_DIRTY 0x4000 /* Volume is dirty */ +#define VCB_CLEAR_DIRTY 0x8000 /* Clean dirty flag at shutdown */ + +typedef struct +{ + ULONG VolumeID; + ULONG FATStart; + ULONG FATCount; + ULONG FATSectors; + ULONG rootDirectorySectors; + ULONG rootStart; + ULONG dataStart; + ULONG RootCluster; + ULONG SectorsPerCluster; + ULONG BytesPerSector; + ULONG BytesPerCluster; + ULONG NumberOfClusters; + ULONG FatType; + ULONG Sectors; + BOOLEAN FixedMedia; +} FATINFO, *PFATINFO; + +struct _VFATFCB; +struct _VFAT_DIRENTRY_CONTEXT; + +typedef struct _HASHENTRY +{ + ULONG Hash; + struct _VFATFCB* self; + struct _HASHENTRY* next; +} +HASHENTRY; + +#define FCB_HASH_TABLE_SIZE 65536 + +typedef struct DEVICE_EXTENSION *PDEVICE_EXTENSION; + +typedef NTSTATUS (*PGET_NEXT_CLUSTER)(PDEVICE_EXTENSION,ULONG,PULONG); +typedef NTSTATUS (*PFIND_AND_MARK_AVAILABLE_CLUSTER)(PDEVICE_EXTENSION,PULONG); +typedef NTSTATUS (*PWRITE_CLUSTER)(PDEVICE_EXTENSION,ULONG,ULONG,PULONG); + +typedef NTSTATUS (*PGET_NEXT_DIR_ENTRY)(PVOID*,PVOID*,struct _VFATFCB*,struct _VFAT_DIRENTRY_CONTEXT*,BOOLEAN); + +typedef struct DEVICE_EXTENSION +{ + ERESOURCE DirResource; + ERESOURCE FatResource; + + KSPIN_LOCK FcbListLock; + LIST_ENTRY FcbListHead; + ULONG HashTableSize; + struct _HASHENTRY** FcbHashTable; + + PDEVICE_OBJECT StorageDevice; + PFILE_OBJECT FATFileObject; + FATINFO FatInfo; + ULONG LastAvailableCluster; + ULONG AvailableClusters; + BOOLEAN AvailableClustersValid; + ULONG Flags; + struct _VFATFCB * VolumeFcb; + + /* Pointers to functions for manipulating FAT. */ + PGET_NEXT_CLUSTER GetNextCluster; + PFIND_AND_MARK_AVAILABLE_CLUSTER FindAndMarkAvailableCluster; + PWRITE_CLUSTER WriteCluster; + ULONG CleanShutBitMask; + + /* Pointers to functions for manipulating directory entries. */ + PGET_NEXT_DIR_ENTRY GetNextDirEntry; + + ULONG BaseDateYear; + + LIST_ENTRY VolumeListEntry; +} DEVICE_EXTENSION, VCB, *PVCB; + +typedef struct +{ + PDRIVER_OBJECT DriverObject; + PDEVICE_OBJECT DeviceObject; + ULONG Flags; + ERESOURCE VolumeListLock; + LIST_ENTRY VolumeListHead; + NPAGED_LOOKASIDE_LIST FcbLookasideList; + NPAGED_LOOKASIDE_LIST CcbLookasideList; + NPAGED_LOOKASIDE_LIST IrpContextLookasideList; + FAST_IO_DISPATCH FastIoDispatch; + CACHE_MANAGER_CALLBACKS CacheMgrCallbacks; +} VFAT_GLOBAL_DATA, *PVFAT_GLOBAL_DATA; + +extern PVFAT_GLOBAL_DATA VfatGlobalData; + +#define FCB_CACHE_INITIALIZED 0x0001 +#define FCB_DELETE_PENDING 0x0002 +#define FCB_IS_FAT 0x0004 +#define FCB_IS_PAGE_FILE 0x0008 +#define FCB_IS_VOLUME 0x0010 +#define FCB_IS_DIRTY 0x0020 +#define FCB_IS_FATX_ENTRY 0x0040 + +typedef struct _VFATFCB +{ + /* FCB header required by ROS/NT */ + FSRTL_COMMON_FCB_HEADER RFCB; + SECTION_OBJECT_POINTERS SectionObjectPointers; + ERESOURCE MainResource; + ERESOURCE PagingIoResource; + /* end FCB header required by ROS/NT */ + + /* directory entry for this file or directory */ + DIR_ENTRY entry; + + /* Pointer to attributes in entry */ + PUCHAR Attributes; + + /* long file name, points into PathNameBuffer */ + UNICODE_STRING LongNameU; + + /* short file name */ + UNICODE_STRING ShortNameU; + + /* directory name, points into PathNameBuffer */ + UNICODE_STRING DirNameU; + + /* path + long file name 260 max*/ + UNICODE_STRING PathNameU; + + /* buffer for PathNameU */ + PWCHAR PathNameBuffer; + + /* buffer for ShortNameU */ + WCHAR ShortNameBuffer[13]; + + /* */ + LONG RefCount; + + /* List of FCB's for this volume */ + LIST_ENTRY FcbListEntry; + + /* pointer to the parent fcb */ + struct _VFATFCB* parentFcb; + + /* Flags for the fcb */ + ULONG Flags; + + /* pointer to the file object which has initialized the fcb */ + PFILE_OBJECT FileObject; + + /* Directory index for the short name entry */ + ULONG dirIndex; + + /* Directory index where the long name starts */ + ULONG startIndex; + + /* Share access for the file object */ + SHARE_ACCESS FCBShareAccess; + + /* Incremented on IRP_MJ_CREATE, decremented on IRP_MJ_CLEANUP */ + ULONG OpenHandleCount; + + /* Entry into the hash table for the path + long name */ + HASHENTRY Hash; + + /* Entry into the hash table for the path + short name */ + HASHENTRY ShortHash; + + /* List of byte-range locks for this file */ + FILE_LOCK FileLock; + + /* + * Optimalization: caching of last read/write cluster+offset pair. Can't + * be in VFATCCB because it must be reset everytime the allocated clusters + * change. + */ + FAST_MUTEX LastMutex; + ULONG LastCluster; + ULONG LastOffset; +} VFATFCB, *PVFATFCB; + +typedef struct _VFATCCB +{ + LARGE_INTEGER CurrentByteOffset; + /* for DirectoryControl */ + ULONG Entry; + /* for DirectoryControl */ + UNICODE_STRING SearchPattern; +} VFATCCB, *PVFATCCB; + +#ifndef TAG +#define TAG(A, B, C, D) (ULONG)(((A)<<0) + ((B)<<8) + ((C)<<16) + ((D)<<24)) +#endif + +#define TAG_CCB TAG('V', 'C', 'C', 'B') +#define TAG_FCB TAG('V', 'F', 'C', 'B') +#define TAG_IRP TAG('V', 'I', 'R', 'P') +#define TAG_VFAT TAG('V', 'F', 'A', 'T') + +#define ENTRIES_PER_SECTOR (BLOCKSIZE / sizeof(FATDirEntry)) + +typedef struct __DOSTIME +{ + USHORT Second:5; + USHORT Minute:6; + USHORT Hour:5; +} +DOSTIME, *PDOSTIME; + +typedef struct __DOSDATE +{ + USHORT Day:5; + USHORT Month:4; + USHORT Year:5; +} +DOSDATE, *PDOSDATE; + +#define IRPCONTEXT_CANWAIT 0x0001 +#define IRPCONTEXT_PENDINGRETURNED 0x0002 + +typedef struct +{ + PIRP Irp; + PDEVICE_OBJECT DeviceObject; + PDEVICE_EXTENSION DeviceExt; + ULONG Flags; + WORK_QUEUE_ITEM WorkQueueItem; + PIO_STACK_LOCATION Stack; + UCHAR MajorFunction; + UCHAR MinorFunction; + PFILE_OBJECT FileObject; + ULONG RefCount; + KEVENT Event; +} VFAT_IRP_CONTEXT, *PVFAT_IRP_CONTEXT; + +typedef struct _VFAT_DIRENTRY_CONTEXT +{ + ULONG StartIndex; + ULONG DirIndex; + DIR_ENTRY DirEntry; + UNICODE_STRING LongNameU; + UNICODE_STRING ShortNameU; +} VFAT_DIRENTRY_CONTEXT, *PVFAT_DIRENTRY_CONTEXT; + + +/* ------------------------------------------------------ shutdown.c */ + +DRIVER_DISPATCH VfatShutdown; +NTSTATUS NTAPI VfatShutdown (PDEVICE_OBJECT DeviceObject, + PIRP Irp); + +/* -------------------------------------------------------- volume.c */ + +NTSTATUS VfatQueryVolumeInformation (PVFAT_IRP_CONTEXT IrpContext); + +NTSTATUS VfatSetVolumeInformation (PVFAT_IRP_CONTEXT IrpContext); + +/* ------------------------------------------------------ blockdev.c */ + +NTSTATUS VfatReadDisk(IN PDEVICE_OBJECT pDeviceObject, + IN PLARGE_INTEGER ReadOffset, + IN ULONG ReadLength, + IN PUCHAR Buffer, + IN BOOLEAN Override); + +NTSTATUS VfatReadDiskPartial (IN PVFAT_IRP_CONTEXT IrpContext, + IN PLARGE_INTEGER ReadOffset, + IN ULONG ReadLength, + IN ULONG BufferOffset, + IN BOOLEAN Wait); + +NTSTATUS VfatWriteDiskPartial(IN PVFAT_IRP_CONTEXT IrpContext, + IN PLARGE_INTEGER WriteOffset, + IN ULONG WriteLength, + IN ULONG BufferOffset, + IN BOOLEAN Wait); + +NTSTATUS VfatBlockDeviceIoControl (IN PDEVICE_OBJECT DeviceObject, + IN ULONG CtlCode, + IN PVOID InputBuffer, + IN ULONG InputBufferSize, + IN OUT PVOID OutputBuffer, + IN OUT PULONG pOutputBufferSize, + IN BOOLEAN Override); + +/* ----------------------------------------------------------- dir.c */ + +NTSTATUS VfatDirectoryControl (PVFAT_IRP_CONTEXT); + +BOOLEAN FsdDosDateTimeToSystemTime (PDEVICE_EXTENSION DeviceExt, + USHORT DosDate, + USHORT DosTime, + PLARGE_INTEGER SystemTime); + +BOOLEAN FsdSystemTimeToDosDateTime (PDEVICE_EXTENSION DeviceExt, + PLARGE_INTEGER SystemTime, + USHORT *pDosDate, + USHORT *pDosTime); + +/* -------------------------------------------------------- create.c */ + +NTSTATUS VfatCreate (PVFAT_IRP_CONTEXT IrpContext); + +NTSTATUS FindFile (PDEVICE_EXTENSION DeviceExt, + PVFATFCB Parent, + PUNICODE_STRING FileToFindU, + PVFAT_DIRENTRY_CONTEXT DirContext, + BOOLEAN First); + +VOID vfat8Dot3ToString (PFAT_DIR_ENTRY pEntry, + PUNICODE_STRING NameU); + +NTSTATUS ReadVolumeLabel(PDEVICE_EXTENSION DeviceExt, + PVPB Vpb); + +/* --------------------------------------------------------- close.c */ + +NTSTATUS VfatClose (PVFAT_IRP_CONTEXT IrpContext); + +NTSTATUS VfatCloseFile(PDEVICE_EXTENSION DeviceExt, + PFILE_OBJECT FileObject); + +/* ------------------------------------------------------- cleanup.c */ + +NTSTATUS VfatCleanup (PVFAT_IRP_CONTEXT IrpContext); + +/* --------------------------------------------------------- fastio.c */ + +VOID +VfatInitFastIoRoutines(PFAST_IO_DISPATCH FastIoDispatch); + +BOOLEAN NTAPI +VfatAcquireForLazyWrite(IN PVOID Context, + IN BOOLEAN Wait); + +VOID NTAPI +VfatReleaseFromLazyWrite(IN PVOID Context); + +BOOLEAN NTAPI +VfatAcquireForReadAhead(IN PVOID Context, + IN BOOLEAN Wait); + +VOID NTAPI +VfatReleaseFromReadAhead(IN PVOID Context); + +/* --------------------------------------------------------- fsctl.c */ + +NTSTATUS VfatFileSystemControl (PVFAT_IRP_CONTEXT IrpContext); + +/* --------------------------------------------------------- finfo.c */ + +NTSTATUS VfatQueryInformation (PVFAT_IRP_CONTEXT IrpContext); + +NTSTATUS VfatSetInformation (PVFAT_IRP_CONTEXT IrpContext); + +NTSTATUS +VfatSetAllocationSizeInformation(PFILE_OBJECT FileObject, + PVFATFCB Fcb, + PDEVICE_EXTENSION DeviceExt, + PLARGE_INTEGER AllocationSize); + +/* --------------------------------------------------------- iface.c */ + +NTSTATUS NTAPI DriverEntry (PDRIVER_OBJECT DriverObject, + PUNICODE_STRING RegistryPath); + +/* --------------------------------------------------------- dirwr.c */ + +NTSTATUS VfatAddEntry (PDEVICE_EXTENSION DeviceExt, + PUNICODE_STRING PathNameU, + PVFATFCB* Fcb, + PVFATFCB ParentFcb, + ULONG RequestedOptions, + UCHAR ReqAttr); + +NTSTATUS VfatUpdateEntry (PVFATFCB pFcb); + +NTSTATUS VfatDelEntry(PDEVICE_EXTENSION, PVFATFCB); + +BOOLEAN +vfatFindDirSpace(PDEVICE_EXTENSION DeviceExt, + PVFATFCB pDirFcb, + ULONG nbSlots, + PULONG start); + +/* -------------------------------------------------------- string.c */ + +VOID +vfatSplitPathName(PUNICODE_STRING PathNameU, + PUNICODE_STRING DirNameU, + PUNICODE_STRING FileNameU); + +BOOLEAN vfatIsLongIllegal(WCHAR c); + +BOOLEAN wstrcmpjoki (PWSTR s1, + PWSTR s2); + +/* ----------------------------------------------------------- fat.c */ + +NTSTATUS FAT12GetNextCluster(PDEVICE_EXTENSION DeviceExt, + ULONG CurrentCluster, + PULONG NextCluster); + +NTSTATUS FAT12FindAndMarkAvailableCluster(PDEVICE_EXTENSION DeviceExt, + PULONG Cluster); + +NTSTATUS FAT12WriteCluster(PDEVICE_EXTENSION DeviceExt, + ULONG ClusterToWrite, + ULONG NewValue, + PULONG OldValue); + +NTSTATUS FAT16GetNextCluster(PDEVICE_EXTENSION DeviceExt, + ULONG CurrentCluster, + PULONG NextCluster); + +NTSTATUS FAT16FindAndMarkAvailableCluster(PDEVICE_EXTENSION DeviceExt, + PULONG Cluster); + +NTSTATUS FAT16WriteCluster(PDEVICE_EXTENSION DeviceExt, + ULONG ClusterToWrite, + ULONG NewValue, + PULONG OldValue); + +NTSTATUS FAT32GetNextCluster(PDEVICE_EXTENSION DeviceExt, + ULONG CurrentCluster, + PULONG NextCluster); + +NTSTATUS FAT32FindAndMarkAvailableCluster(PDEVICE_EXTENSION DeviceExt, + PULONG Cluster); + +NTSTATUS FAT32WriteCluster(PDEVICE_EXTENSION DeviceExt, + ULONG ClusterToWrite, + ULONG NewValue, + PULONG OldValue); + +NTSTATUS OffsetToCluster (PDEVICE_EXTENSION DeviceExt, + ULONG FirstCluster, + ULONG FileOffset, + PULONG Cluster, + BOOLEAN Extend); + +ULONGLONG ClusterToSector (PDEVICE_EXTENSION DeviceExt, + ULONG Cluster); + +NTSTATUS GetNextCluster (PDEVICE_EXTENSION DeviceExt, + ULONG CurrentCluster, + PULONG NextCluster); + +NTSTATUS GetNextClusterExtend (PDEVICE_EXTENSION DeviceExt, + ULONG CurrentCluster, + PULONG NextCluster); + +NTSTATUS CountAvailableClusters (PDEVICE_EXTENSION DeviceExt, + PLARGE_INTEGER Clusters); + +NTSTATUS +WriteCluster(PDEVICE_EXTENSION DeviceExt, + ULONG ClusterToWrite, + ULONG NewValue); + +/* ------------------------------------------------------ direntry.c */ + +ULONG vfatDirEntryGetFirstCluster (PDEVICE_EXTENSION pDeviceExt, + PDIR_ENTRY pDirEntry); + +BOOLEAN VfatIsDirectoryEmpty(PVFATFCB Fcb); + +NTSTATUS FATGetNextDirEntry(PVOID * pContext, + PVOID * pPage, + IN PVFATFCB pDirFcb, + IN PVFAT_DIRENTRY_CONTEXT DirContext, + BOOLEAN First); + +NTSTATUS FATXGetNextDirEntry(PVOID * pContext, + PVOID * pPage, + IN PVFATFCB pDirFcb, + IN PVFAT_DIRENTRY_CONTEXT DirContext, + BOOLEAN First); + +/* ----------------------------------------------------------- fcb.c */ + +PVFATFCB vfatNewFCB (PDEVICE_EXTENSION pVCB, + PUNICODE_STRING pFileNameU); + +VOID vfatDestroyFCB (PVFATFCB pFCB); + +VOID vfatDestroyCCB(PVFATCCB pCcb); + +VOID vfatGrabFCB (PDEVICE_EXTENSION pVCB, + PVFATFCB pFCB); + +VOID vfatReleaseFCB (PDEVICE_EXTENSION pVCB, + PVFATFCB pFCB); + +VOID vfatAddFCBToTable (PDEVICE_EXTENSION pVCB, + PVFATFCB pFCB); + +PVFATFCB vfatGrabFCBFromTable (PDEVICE_EXTENSION pDeviceExt, + PUNICODE_STRING pFileNameU); + +PVFATFCB vfatMakeRootFCB (PDEVICE_EXTENSION pVCB); + +PVFATFCB vfatOpenRootFCB (PDEVICE_EXTENSION pVCB); + +BOOLEAN vfatFCBIsDirectory (PVFATFCB FCB); + +BOOLEAN vfatFCBIsRoot(PVFATFCB FCB); + +NTSTATUS vfatAttachFCBToFileObject (PDEVICE_EXTENSION vcb, + PVFATFCB fcb, + PFILE_OBJECT fileObject); + +NTSTATUS vfatDirFindFile (PDEVICE_EXTENSION pVCB, + PVFATFCB parentFCB, + PUNICODE_STRING FileToFindU, + PVFATFCB * fileFCB); + +NTSTATUS vfatGetFCBForFile (PDEVICE_EXTENSION pVCB, + PVFATFCB *pParentFCB, + PVFATFCB *pFCB, + PUNICODE_STRING pFileNameU); + +NTSTATUS vfatMakeFCBFromDirEntry (PVCB vcb, + PVFATFCB directoryFCB, + PVFAT_DIRENTRY_CONTEXT DirContext, + PVFATFCB * fileFCB); + +/* ------------------------------------------------------------ rw.c */ + +NTSTATUS VfatRead (PVFAT_IRP_CONTEXT IrpContext); + +NTSTATUS VfatWrite (PVFAT_IRP_CONTEXT IrpContext); + +NTSTATUS NextCluster(PDEVICE_EXTENSION DeviceExt, + ULONG FirstCluster, + PULONG CurrentCluster, + BOOLEAN Extend); + +/* ----------------------------------------------------------- misc.c */ + +NTSTATUS VfatQueueRequest(PVFAT_IRP_CONTEXT IrpContext); + +PVFAT_IRP_CONTEXT VfatAllocateIrpContext(PDEVICE_OBJECT DeviceObject, + PIRP Irp); + +VOID VfatFreeIrpContext(PVFAT_IRP_CONTEXT IrpContext); + +DRIVER_DISPATCH VfatBuildRequest; +NTSTATUS NTAPI VfatBuildRequest (PDEVICE_OBJECT DeviceObject, + PIRP Irp); + +PVOID VfatGetUserBuffer(IN PIRP); + +NTSTATUS VfatLockUserBuffer(IN PIRP, IN ULONG, + IN LOCK_OPERATION); + +NTSTATUS +VfatSetExtendedAttributes(PFILE_OBJECT FileObject, + PVOID Ea, + ULONG EaLength); +/* ------------------------------------------------------------- flush.c */ + +NTSTATUS VfatFlush(PVFAT_IRP_CONTEXT IrpContext); + +NTSTATUS VfatFlushVolume(PDEVICE_EXTENSION DeviceExt, PVFATFCB VolumeFcb); + + +/* EOF */ diff --git a/reactos/drivers/filesystems/fastfat_new/vfat005.1st b/reactos/drivers/filesystems/fastfat_new/vfat005.1st new file mode 100644 index 00000000000..71af436576d --- /dev/null +++ b/reactos/drivers/filesystems/fastfat_new/vfat005.1st @@ -0,0 +1,12 @@ +This is VFAT driver release 0.0.5 + +To install : + extract files + delete all object files (*.o) in all subdirectories + (because include file include/ddk/iotypes.h is modified and is used by many files) + recompile reactos + +What's new : + - some bugfixes + - support for IRP_MJ_DIRECTORY_CONTROL + (see reactos/tst/sshell.c for use of ZwQueryDirectoryFile) diff --git a/reactos/drivers/filesystems/fastfat_new/vfat_fr.txt b/reactos/drivers/filesystems/fastfat_new/vfat_fr.txt new file mode 100644 index 00000000000..af4e0edb86a --- /dev/null +++ b/reactos/drivers/filesystems/fastfat_new/vfat_fr.txt @@ -0,0 +1,97 @@ +A Faire : + finir FsdDirectoryControl. + tester les écritures. + FsdCreate doit créer le fichier s'il n'existe pas et que le répertoire parent existe, + et que les options d'appel lee demandent. + + +fichiers sources : + +iface.c +dir.c +blockdev.c +vfat.h + + + +fonctions visibles de l'extérieur (appelées par IoCallDriver): + DriverEntry : iface.c + initialisation du driver + rend visibles les fonctions suivantes : + FsdFileSystemControl + répond aux demandes IRP_MJ_FILE_SYSTEM_CONTROL + monte les filesystems qu'il reconnait + appelle FsdHasFileSystem pour voir si le driver reconnait le filesystem. + puis appelle FsdMount. + NTSTATUS FsdCreate(PDEVICE_OBJECT DeviceObject, PIRP Irp) + répond aux demandes IRP_MJ_CREATE : + appelle FsdOpenFile, qui remplit IoGetCurrentIrpStackLocation(Irp)->FileObject->Fcb + remplit Irp->IoStatus + appelle IoCompleteRequest + FsdClose + répond aux demandes IRP_MJ_CLOSE + appelle FsdCloseFile, qui ne fait rien actuellement. + remplit Irp->IoStatus + appelle IoCompleteRequest + FsdRead + répond aux demandes IRP_MJ_READ + FsdWrite + répond aux demandes IRP_MJ_WRITE + FsdQueryInformation + répond aux demandes IRP_MJ_QUERY_INFORMATION + FsdDirectoryControl + répond aux demandes IRP_MJ_DIRECTORY_CONTROL + + +fonctions strictement internes dans iface.c : + ULONG Fat32GetNextCluster(PDEVICE_EXTENSION DeviceExt, ULONG CurrentCluster) + ULONG Fat16GetNextCluster(PDEVICE_EXTENSION DeviceExt, ULONG CurrentCluster) + ULONG Fat12GetNextCluster(PDEVICE_EXTENSION DeviceExt, ULONG CurrentCluster) + ULONG GetNextCluster(PDEVICE_EXTENSION DeviceExt, ULONG CurrentCluster) + ULONG FAT16FindAvailableCluster(PDEVICE_EXTENSION DeviceExt) + void FAT16WriteCluster(PDEVICE_EXTENSION DeviceExt, ULONG ClusterToWrite, + ULONG NewValue) + void WriteCluster(PDEVICE_EXTENSION DeviceExt, ULONG ClusterToWrite, + ULONG NewValue) + ULONG GetNextWriteCluster(PDEVICE_EXTENSION DeviceExt, ULONG CurrentCluster) + unsigned long ClusterToSector(PDEVICE_EXTENSION DeviceExt, + unsigned long Cluster) + void RtlAnsiToUnicode(PWSTR Dest, PCH Source, ULONG Length) + void vfat_initstr(wchar_t *wstr, ULONG wsize) + wchar_t * vfat_wcsncat(wchar_t * dest, const wchar_t * src,size_t wstart, size_t wcount) + wchar_t * vfat_wcsncpy(wchar_t * dest, const wchar_t *src,size_t wcount) + wchar_t * vfat_movstr(wchar_t * dest, const wchar_t *src, ULONG dpos, + ULONG spos, ULONG len) + BOOLEAN IsLastEntry(PVOID Block, ULONG Offset) + BOOLEAN IsDeletedEntry(PVOID Block, ULONG Offset) + BOOLEAN GetEntryName(PVOID Block, PULONG _Offset, PWSTR Name, PULONG _jloop, + PDEVICE_EXTENSION DeviceExt, PULONG _StartingSector) + BOOLEAN wstrcmpi(PWSTR s1, PWSTR s2) + BOOLEAN wstrcmpjoki(PWSTR s1, PWSTR s2) + NTSTATUS FindFile(PDEVICE_EXTENSION DeviceExt, PFCB Fcb, + PFCB Parent, PWSTR FileToFind) + parcourt le répertoire décrit par Parent pour trouver un fichier dans le filesystem + décrit par DeviceExt.Si Parent==NULL : part de la racine du filesystem. + remplit Fcb si trouve elle le fichier, et renvoie STATUS_SUCCESS. + renvoie STATUS_UNSUCCESSFUL sinon. + NTSTATUS FsdCloseFile(PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject) + ne fait rien, renvoie STATUS_SUCCESS. + NTSTATUS FsdOpenFile(PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject, + PWSTR FileName) + parcourt l'arborescence pour trouver le fichier(appelle FindFile à chaque niveau) + si trouvé : FileObject->FsContext = Fcb du fichier, renvoie STATUS_SUCCESS + sinon : renvoie STATUS_UNSUCCESSFULL + BOOLEAN FsdHasFileSystem(PDEVICE_OBJECT DeviceToMount) + NTSTATUS FsdMountDevice(PDEVICE_EXTENSION DeviceExt, + PDEVICE_OBJECT DeviceToMount) + void VFATLoadCluster(PDEVICE_EXTENSION DeviceExt, PVOID Buffer, ULONG Cluster) + void VFATWriteCluster(PDEVICE_EXTENSION DeviceExt, PVOID Buffer, ULONG Cluster) + NTSTATUS FsdReadFile(PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject, + PVOID Buffer, ULONG Length, ULONG ReadOffset) + lit Length octets d'un fichier + NTSTATUS FsdWriteFile(PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject, + PVOID Buffer, ULONG Length, ULONG WriteOffset) + NTSTATUS FsdMount(PDEVICE_OBJECT DeviceToMount) + NTSTATUS FsdGetStandardInformation(PFCB FCB, PDEVICE_OBJECT DeviceObject, + PFILE_STANDARD_INFORMATION StandardInfo); + diff --git a/reactos/drivers/filesystems/fastfat_new/vfatfs.rbuild b/reactos/drivers/filesystems/fastfat_new/vfatfs.rbuild new file mode 100644 index 00000000000..56ca836973c --- /dev/null +++ b/reactos/drivers/filesystems/fastfat_new/vfatfs.rbuild @@ -0,0 +1,30 @@ + + + + + . + ntoskrnl + hal + blockdev.c + cleanup.c + close.c + create.c + dir.c + direntry.c + dirwr.c + ea.c + fat.c + fastio.c + fcb.c + finfo.c + flush.c + fsctl.c + iface.c + misc.c + rw.c + shutdown.c + string.c + volume.c + vfatfs.rc + vfat.h + diff --git a/reactos/drivers/filesystems/fastfat_new/vfatfs.rc b/reactos/drivers/filesystems/fastfat_new/vfatfs.rc new file mode 100644 index 00000000000..0559ee6c343 --- /dev/null +++ b/reactos/drivers/filesystems/fastfat_new/vfatfs.rc @@ -0,0 +1,5 @@ +#define REACTOS_VERSION_DLL +#define REACTOS_STR_FILE_DESCRIPTION "VFAT IFS Driver\0" +#define REACTOS_STR_INTERNAL_NAME "vfatfs\0" +#define REACTOS_STR_ORIGINAL_FILENAME "vfatfs.sys\0" +#include diff --git a/reactos/drivers/filesystems/fastfat_new/volume.c b/reactos/drivers/filesystems/fastfat_new/volume.c new file mode 100644 index 00000000000..4bf4ffeea40 --- /dev/null +++ b/reactos/drivers/filesystems/fastfat_new/volume.c @@ -0,0 +1,418 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: drivers/fs/vfat/volume.c + * PURPOSE: VFAT Filesystem + * PROGRAMMER: Jason Filby (jasonfilby@yahoo.com) + * Herve Poussineau (reactos@poussine.freesurf.fr) + */ + +/* INCLUDES *****************************************************************/ + +#define NDEBUG +#include "vfat.h" + +/* FUNCTIONS ****************************************************************/ + +static NTSTATUS +FsdGetFsVolumeInformation(PDEVICE_OBJECT DeviceObject, + PFILE_FS_VOLUME_INFORMATION FsVolumeInfo, + PULONG BufferLength) +{ + DPRINT("FsdGetFsVolumeInformation()\n"); + DPRINT("FsVolumeInfo = %p\n", FsVolumeInfo); + DPRINT("BufferLength %lu\n", *BufferLength); + + DPRINT("Required length %lu\n", (sizeof(FILE_FS_VOLUME_INFORMATION) + DeviceObject->Vpb->VolumeLabelLength)); + DPRINT("LabelLength %hu\n", DeviceObject->Vpb->VolumeLabelLength); + DPRINT("Label %*.S\n", DeviceObject->Vpb->VolumeLabelLength / sizeof(WCHAR), DeviceObject->Vpb->VolumeLabel); + + if (*BufferLength < sizeof(FILE_FS_VOLUME_INFORMATION)) + return STATUS_INFO_LENGTH_MISMATCH; + + if (*BufferLength < (sizeof(FILE_FS_VOLUME_INFORMATION) + DeviceObject->Vpb->VolumeLabelLength)) + return STATUS_BUFFER_OVERFLOW; + + /* valid entries */ + FsVolumeInfo->VolumeSerialNumber = DeviceObject->Vpb->SerialNumber; + FsVolumeInfo->VolumeLabelLength = DeviceObject->Vpb->VolumeLabelLength; + RtlCopyMemory(FsVolumeInfo->VolumeLabel, DeviceObject->Vpb->VolumeLabel, FsVolumeInfo->VolumeLabelLength); + + /* dummy entries */ + FsVolumeInfo->VolumeCreationTime.QuadPart = 0; + FsVolumeInfo->SupportsObjects = FALSE; + + DPRINT("Finished FsdGetFsVolumeInformation()\n"); + + *BufferLength -= (sizeof(FILE_FS_VOLUME_INFORMATION) + DeviceObject->Vpb->VolumeLabelLength); + + DPRINT("BufferLength %lu\n", *BufferLength); + + return(STATUS_SUCCESS); +} + + +static NTSTATUS +FsdGetFsAttributeInformation(PDEVICE_EXTENSION DeviceExt, + PFILE_FS_ATTRIBUTE_INFORMATION FsAttributeInfo, + PULONG BufferLength) +{ + PCWSTR pName; ULONG Length; + DPRINT("FsdGetFsAttributeInformation()\n"); + DPRINT("FsAttributeInfo = %p\n", FsAttributeInfo); + DPRINT("BufferLength %lu\n", *BufferLength); + + if (*BufferLength < sizeof (FILE_FS_ATTRIBUTE_INFORMATION)) + return STATUS_INFO_LENGTH_MISMATCH; + + if (DeviceExt->FatInfo.FatType == FAT32) + { + Length = 10; + pName = L"FAT32"; + } + else + { + Length = 6; + pName = L"FAT"; + } + + DPRINT("Required length %lu\n", (sizeof(FILE_FS_ATTRIBUTE_INFORMATION) + Length)); + + if (*BufferLength < (sizeof(FILE_FS_ATTRIBUTE_INFORMATION) + Length)) + return STATUS_BUFFER_OVERFLOW; + + FsAttributeInfo->FileSystemAttributes = + FILE_CASE_PRESERVED_NAMES | FILE_UNICODE_ON_DISK; + + FsAttributeInfo->MaximumComponentNameLength = 255; + + FsAttributeInfo->FileSystemNameLength = Length; + + RtlCopyMemory(FsAttributeInfo->FileSystemName, pName, Length ); + + DPRINT("Finished FsdGetFsAttributeInformation()\n"); + + *BufferLength -= (sizeof(FILE_FS_ATTRIBUTE_INFORMATION) + Length); + DPRINT("BufferLength %lu\n", *BufferLength); + + return(STATUS_SUCCESS); +} + + +static NTSTATUS +FsdGetFsSizeInformation(PDEVICE_OBJECT DeviceObject, + PFILE_FS_SIZE_INFORMATION FsSizeInfo, + PULONG BufferLength) +{ + PDEVICE_EXTENSION DeviceExt; + NTSTATUS Status; + + DPRINT("FsdGetFsSizeInformation()\n"); + DPRINT("FsSizeInfo = %p\n", FsSizeInfo); + + if (*BufferLength < sizeof(FILE_FS_SIZE_INFORMATION)) + return(STATUS_BUFFER_OVERFLOW); + + DeviceExt = DeviceObject->DeviceExtension; + Status = CountAvailableClusters(DeviceExt, &FsSizeInfo->AvailableAllocationUnits); + + FsSizeInfo->TotalAllocationUnits.QuadPart = DeviceExt->FatInfo.NumberOfClusters; + FsSizeInfo->SectorsPerAllocationUnit = DeviceExt->FatInfo.SectorsPerCluster; + FsSizeInfo->BytesPerSector = DeviceExt->FatInfo.BytesPerSector; + + DPRINT("Finished FsdGetFsSizeInformation()\n"); + if (NT_SUCCESS(Status)) + *BufferLength -= sizeof(FILE_FS_SIZE_INFORMATION); + + return(Status); +} + + +static NTSTATUS +FsdGetFsDeviceInformation(PFILE_FS_DEVICE_INFORMATION FsDeviceInfo, + PULONG BufferLength) +{ + DPRINT("FsdGetFsDeviceInformation()\n"); + DPRINT("FsDeviceInfo = %p\n", FsDeviceInfo); + DPRINT("BufferLength %lu\n", *BufferLength); + DPRINT("Required length %lu\n", sizeof(FILE_FS_DEVICE_INFORMATION)); + + if (*BufferLength < sizeof(FILE_FS_DEVICE_INFORMATION)) + return(STATUS_BUFFER_OVERFLOW); + + FsDeviceInfo->DeviceType = FILE_DEVICE_DISK; + FsDeviceInfo->Characteristics = 0; /* FIXME: fix this !! */ + + DPRINT("FsdGetFsDeviceInformation() finished.\n"); + + *BufferLength -= sizeof(FILE_FS_DEVICE_INFORMATION); + DPRINT("BufferLength %lu\n", *BufferLength); + + return(STATUS_SUCCESS); +} + + +static NTSTATUS +FsdSetFsLabelInformation(PDEVICE_OBJECT DeviceObject, + PFILE_FS_LABEL_INFORMATION FsLabelInfo) +{ + PDEVICE_EXTENSION DeviceExt; + PVOID Context = NULL; + ULONG DirIndex = 0; + PDIR_ENTRY Entry; + PVFATFCB pRootFcb; + LARGE_INTEGER FileOffset; + BOOLEAN LabelFound = FALSE; + DIR_ENTRY VolumeLabelDirEntry; + ULONG VolumeLabelDirIndex; + ULONG LabelLen; + NTSTATUS Status = STATUS_UNSUCCESSFUL; + OEM_STRING StringO; + UNICODE_STRING StringW; + CHAR cString[43]; + ULONG SizeDirEntry; + ULONG EntriesPerPage; + + DPRINT("FsdSetFsLabelInformation()\n"); + + DeviceExt = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension; + + if (sizeof(DeviceObject->Vpb->VolumeLabel) < FsLabelInfo->VolumeLabelLength) + { + return STATUS_NAME_TOO_LONG; + } + + if (DeviceExt->Flags & VCB_IS_FATX) + { + if (FsLabelInfo->VolumeLabelLength / sizeof(WCHAR) > 42) + return STATUS_NAME_TOO_LONG; + SizeDirEntry = sizeof(FATX_DIR_ENTRY); + EntriesPerPage = FATX_ENTRIES_PER_PAGE; + } + else + { + if (FsLabelInfo->VolumeLabelLength / sizeof(WCHAR) > 11) + return STATUS_NAME_TOO_LONG; + SizeDirEntry = sizeof(FAT_DIR_ENTRY); + EntriesPerPage = FAT_ENTRIES_PER_PAGE; + } + + /* Create Volume label dir entry */ + LabelLen = FsLabelInfo->VolumeLabelLength / sizeof(WCHAR); + RtlZeroMemory(&VolumeLabelDirEntry, SizeDirEntry); + StringW.Buffer = FsLabelInfo->VolumeLabel; + StringW.Length = StringW.MaximumLength = (USHORT)FsLabelInfo->VolumeLabelLength; + StringO.Buffer = cString; + StringO.Length = 0; + StringO.MaximumLength = 42; + Status = RtlUnicodeStringToOemString(&StringO, &StringW, FALSE); + if (!NT_SUCCESS(Status)) + return Status; + if (DeviceExt->Flags & VCB_IS_FATX) + { + RtlCopyMemory(VolumeLabelDirEntry.FatX.Filename, cString, LabelLen); + memset(&VolumeLabelDirEntry.FatX.Filename[LabelLen], ' ', 42 - LabelLen); + VolumeLabelDirEntry.FatX.Attrib = 0x08; + } + else + { + RtlCopyMemory(VolumeLabelDirEntry.Fat.Filename, cString, LabelLen); + memset(&VolumeLabelDirEntry.Fat.Filename[LabelLen], ' ', 11 - LabelLen); + VolumeLabelDirEntry.Fat.Attrib = 0x08; + } + + pRootFcb = vfatOpenRootFCB(DeviceExt); + + /* Search existing volume entry on disk */ + FileOffset.QuadPart = 0; + if (CcPinRead(pRootFcb->FileObject, &FileOffset, PAGE_SIZE, TRUE, &Context, (PVOID*)&Entry)) + { + while (TRUE) + { + if (ENTRY_VOLUME(DeviceExt, Entry)) + { + /* Update entry */ + LabelFound = TRUE; + RtlCopyMemory(Entry, &VolumeLabelDirEntry, SizeDirEntry); + CcSetDirtyPinnedData(Context, NULL); + Status = STATUS_SUCCESS; + break; + } + if (ENTRY_END(DeviceExt, Entry)) + { + break; + } + DirIndex++; + Entry = (PDIR_ENTRY)((ULONG_PTR)Entry + SizeDirEntry); + if ((DirIndex % EntriesPerPage) == 0) + { + CcUnpinData(Context); + FileOffset.u.LowPart += PAGE_SIZE; + if (!CcPinRead(pRootFcb->FileObject, &FileOffset, PAGE_SIZE, TRUE, &Context, (PVOID*)&Entry)) + { + Context = NULL; + break; + } + } + } + if (Context) + { + CcUnpinData(Context); + } + } + if (!LabelFound) + { + /* Add new entry for label */ + if (!vfatFindDirSpace(DeviceExt, pRootFcb, 1, &VolumeLabelDirIndex)) + Status = STATUS_DISK_FULL; + else + { + FileOffset.u.HighPart = 0; + FileOffset.u.LowPart = VolumeLabelDirIndex * SizeDirEntry; + CcPinRead(pRootFcb->FileObject, &FileOffset, SizeDirEntry, + TRUE, &Context, (PVOID*)&Entry); + RtlCopyMemory(Entry, &VolumeLabelDirEntry, SizeDirEntry); + CcSetDirtyPinnedData(Context, NULL); + CcUnpinData(Context); + Status = STATUS_SUCCESS; + } + } + + vfatReleaseFCB(DeviceExt, pRootFcb); + if (!NT_SUCCESS(Status)) + { + return Status; + } + + /* Update volume label in memory */ + DeviceObject->Vpb->VolumeLabelLength = (USHORT)FsLabelInfo->VolumeLabelLength; + RtlCopyMemory(DeviceObject->Vpb->VolumeLabel, FsLabelInfo->VolumeLabel, DeviceObject->Vpb->VolumeLabelLength); + + return Status; +} + + +NTSTATUS VfatQueryVolumeInformation(PVFAT_IRP_CONTEXT IrpContext) +/* + * FUNCTION: Retrieve the specified volume information + */ +{ + FS_INFORMATION_CLASS FsInformationClass; + NTSTATUS RC = STATUS_SUCCESS; + PVOID SystemBuffer; + ULONG BufferLength; + + /* PRECONDITION */ + ASSERT(IrpContext); + + DPRINT("VfatQueryVolumeInformation(IrpContext %p)\n", IrpContext); + + if (!ExAcquireResourceSharedLite(&((PDEVICE_EXTENSION)IrpContext->DeviceObject->DeviceExtension)->DirResource, + (BOOLEAN)(IrpContext->Flags & IRPCONTEXT_CANWAIT))) + { + return VfatQueueRequest (IrpContext); + } + + /* INITIALIZATION */ + FsInformationClass = IrpContext->Stack->Parameters.QueryVolume.FsInformationClass; + BufferLength = IrpContext->Stack->Parameters.QueryVolume.Length; + SystemBuffer = IrpContext->Irp->AssociatedIrp.SystemBuffer; + + + DPRINT ("FsInformationClass %d\n", FsInformationClass); + DPRINT ("SystemBuffer %p\n", SystemBuffer); + + switch (FsInformationClass) + { + case FileFsVolumeInformation: + RC = FsdGetFsVolumeInformation(IrpContext->DeviceObject, + SystemBuffer, + &BufferLength); + break; + + case FileFsAttributeInformation: + RC = FsdGetFsAttributeInformation(IrpContext->DeviceObject->DeviceExtension, + SystemBuffer, + &BufferLength); + break; + + case FileFsSizeInformation: + RC = FsdGetFsSizeInformation(IrpContext->DeviceObject, + SystemBuffer, + &BufferLength); + break; + + case FileFsDeviceInformation: + RC = FsdGetFsDeviceInformation(SystemBuffer, + &BufferLength); + break; + + default: + RC = STATUS_NOT_SUPPORTED; + } + + ExReleaseResourceLite(&((PDEVICE_EXTENSION)IrpContext->DeviceObject->DeviceExtension)->DirResource); + IrpContext->Irp->IoStatus.Status = RC; + if (NT_SUCCESS(RC)) + IrpContext->Irp->IoStatus.Information = + IrpContext->Stack->Parameters.QueryVolume.Length - BufferLength; + else + IrpContext->Irp->IoStatus.Information = 0; + IoCompleteRequest(IrpContext->Irp, IO_NO_INCREMENT); + VfatFreeIrpContext(IrpContext); + + return RC; +} + + +NTSTATUS VfatSetVolumeInformation(PVFAT_IRP_CONTEXT IrpContext) +/* + * FUNCTION: Set the specified volume information + */ +{ + FS_INFORMATION_CLASS FsInformationClass; + NTSTATUS Status = STATUS_SUCCESS; + PVOID SystemBuffer; + ULONG BufferLength; + PIO_STACK_LOCATION Stack = IrpContext->Stack; + + /* PRECONDITION */ + ASSERT(IrpContext); + + DPRINT ("VfatSetVolumeInformation(IrpContext %p)\n", IrpContext); + + if (!ExAcquireResourceExclusiveLite(&((PDEVICE_EXTENSION)IrpContext->DeviceObject->DeviceExtension)->DirResource, + (BOOLEAN)(IrpContext->Flags & IRPCONTEXT_CANWAIT))) + { + return VfatQueueRequest (IrpContext); + } + + FsInformationClass = Stack->Parameters.SetVolume.FsInformationClass; + BufferLength = Stack->Parameters.SetVolume.Length; + SystemBuffer = IrpContext->Irp->AssociatedIrp.SystemBuffer; + + DPRINT ("FsInformationClass %d\n", FsInformationClass); + DPRINT ("BufferLength %d\n", BufferLength); + DPRINT ("SystemBuffer %p\n", SystemBuffer); + + switch(FsInformationClass) + { + case FileFsLabelInformation: + Status = FsdSetFsLabelInformation(IrpContext->DeviceObject, + SystemBuffer); + break; + + default: + Status = STATUS_NOT_SUPPORTED; + } + + ExReleaseResourceLite(&((PDEVICE_EXTENSION)IrpContext->DeviceObject->DeviceExtension)->DirResource); + IrpContext->Irp->IoStatus.Status = Status; + IrpContext->Irp->IoStatus.Information = 0; + IoCompleteRequest(IrpContext->Irp, IO_NO_INCREMENT); + VfatFreeIrpContext(IrpContext); + + return(Status); +} + +/* EOF */