mirror of
https://github.com/reactos/reactos.git
synced 2025-02-23 17:05:46 +00:00
- Branch existing fastfat driver.
svn path=/trunk/; revision=38693
This commit is contained in:
parent
ea8ef6ce87
commit
885a5b68c8
25 changed files with 10067 additions and 0 deletions
338
reactos/drivers/filesystems/fastfat_new/blockdev.c
Normal file
338
reactos/drivers/filesystems/fastfat_new/blockdev.c
Normal file
|
@ -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;
|
||||
}
|
144
reactos/drivers/filesystems/fastfat_new/cleanup.c
Normal file
144
reactos/drivers/filesystems/fastfat_new/cleanup.c
Normal file
|
@ -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 */
|
110
reactos/drivers/filesystems/fastfat_new/close.c
Normal file
110
reactos/drivers/filesystems/fastfat_new/close.c
Normal file
|
@ -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 */
|
801
reactos/drivers/filesystems/fastfat_new/create.c
Normal file
801
reactos/drivers/filesystems/fastfat_new/create.c
Normal file
|
@ -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 */
|
511
reactos/drivers/filesystems/fastfat_new/dir.c
Normal file
511
reactos/drivers/filesystems/fastfat_new/dir.c
Normal file
|
@ -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;
|
||||
}
|
||||
|
||||
|
490
reactos/drivers/filesystems/fastfat_new/direntry.c
Normal file
490
reactos/drivers/filesystems/fastfat_new/direntry.c
Normal file
|
@ -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;
|
||||
}
|
722
reactos/drivers/filesystems/fastfat_new/dirwr.c
Normal file
722
reactos/drivers/filesystems/fastfat_new/dirwr.c
Normal file
|
@ -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 */
|
40
reactos/drivers/filesystems/fastfat_new/ea.c
Normal file
40
reactos/drivers/filesystems/fastfat_new/ea.c
Normal file
|
@ -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);
|
||||
}
|
413
reactos/drivers/filesystems/fastfat_new/fastio.c
Normal file
413
reactos/drivers/filesystems/fastfat_new/fastio.c
Normal file
|
@ -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;
|
||||
}
|
||||
|
709
reactos/drivers/filesystems/fastfat_new/fat.c
Normal file
709
reactos/drivers/filesystems/fastfat_new/fat.c
Normal file
|
@ -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 */
|
821
reactos/drivers/filesystems/fastfat_new/fcb.c
Normal file
821
reactos/drivers/filesystems/fastfat_new/fcb.c
Normal file
|
@ -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 <wctype.h> /* 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;
|
||||
}
|
||||
|
948
reactos/drivers/filesystems/fastfat_new/finfo.c
Normal file
948
reactos/drivers/filesystems/fastfat_new/finfo.c
Normal file
|
@ -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 */
|
140
reactos/drivers/filesystems/fastfat_new/flush.c
Normal file
140
reactos/drivers/filesystems/fastfat_new/flush.c
Normal file
|
@ -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 */
|
916
reactos/drivers/filesystems/fastfat_new/fsctl.c
Normal file
916
reactos/drivers/filesystems/fastfat_new/fsctl.c
Normal file
|
@ -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);
|
||||
}
|
131
reactos/drivers/filesystems/fastfat_new/iface.c
Normal file
131
reactos/drivers/filesystems/fastfat_new/iface.c
Normal file
|
@ -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 */
|
||||
|
275
reactos/drivers/filesystems/fastfat_new/misc.c
Normal file
275
reactos/drivers/filesystems/fastfat_new/misc.c
Normal file
|
@ -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;
|
||||
}
|
||||
|
||||
|
1069
reactos/drivers/filesystems/fastfat_new/rw.c
Normal file
1069
reactos/drivers/filesystems/fastfat_new/rw.c
Normal file
File diff suppressed because it is too large
Load diff
118
reactos/drivers/filesystems/fastfat_new/shutdown.c
Normal file
118
reactos/drivers/filesystems/fastfat_new/shutdown.c
Normal file
|
@ -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 */
|
23
reactos/drivers/filesystems/fastfat_new/string.c
Normal file
23
reactos/drivers/filesystems/fastfat_new/string.c
Normal file
|
@ -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;
|
||||
}
|
786
reactos/drivers/filesystems/fastfat_new/vfat.h
Normal file
786
reactos/drivers/filesystems/fastfat_new/vfat.h
Normal file
|
@ -0,0 +1,786 @@
|
|||
#include <ntifs.h>
|
||||
#include <ntdddisk.h>
|
||||
#include <reactos/helper.h>
|
||||
#include <debug.h>
|
||||
|
||||
#ifdef __GNUC__
|
||||
#include <ccros.h>
|
||||
|
||||
#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 <pshpack1.h>
|
||||
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 <poppack.h>
|
||||
|
||||
#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 */
|
12
reactos/drivers/filesystems/fastfat_new/vfat005.1st
Normal file
12
reactos/drivers/filesystems/fastfat_new/vfat005.1st
Normal file
|
@ -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)
|
97
reactos/drivers/filesystems/fastfat_new/vfat_fr.txt
Normal file
97
reactos/drivers/filesystems/fastfat_new/vfat_fr.txt
Normal file
|
@ -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);
|
||||
|
30
reactos/drivers/filesystems/fastfat_new/vfatfs.rbuild
Normal file
30
reactos/drivers/filesystems/fastfat_new/vfatfs.rbuild
Normal file
|
@ -0,0 +1,30 @@
|
|||
<?xml version="1.0"?>
|
||||
<!DOCTYPE module SYSTEM "../../../tools/rbuild/project.dtd">
|
||||
<module name="fastfat" type="kernelmodedriver" installbase="system32/drivers" installname="fastfat.sys">
|
||||
<bootstrap installbase="$(CDOUTPUT)" />
|
||||
<include base="fastfat">.</include>
|
||||
<library>ntoskrnl</library>
|
||||
<library>hal</library>
|
||||
<file>blockdev.c</file>
|
||||
<file>cleanup.c</file>
|
||||
<file>close.c</file>
|
||||
<file>create.c</file>
|
||||
<file>dir.c</file>
|
||||
<file>direntry.c</file>
|
||||
<file>dirwr.c</file>
|
||||
<file>ea.c</file>
|
||||
<file>fat.c</file>
|
||||
<file>fastio.c</file>
|
||||
<file>fcb.c</file>
|
||||
<file>finfo.c</file>
|
||||
<file>flush.c</file>
|
||||
<file>fsctl.c</file>
|
||||
<file>iface.c</file>
|
||||
<file>misc.c</file>
|
||||
<file>rw.c</file>
|
||||
<file>shutdown.c</file>
|
||||
<file>string.c</file>
|
||||
<file>volume.c</file>
|
||||
<file>vfatfs.rc</file>
|
||||
<pch>vfat.h</pch>
|
||||
</module>
|
5
reactos/drivers/filesystems/fastfat_new/vfatfs.rc
Normal file
5
reactos/drivers/filesystems/fastfat_new/vfatfs.rc
Normal file
|
@ -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 <reactos/version.rc>
|
418
reactos/drivers/filesystems/fastfat_new/volume.c
Normal file
418
reactos/drivers/filesystems/fastfat_new/volume.c
Normal file
|
@ -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 */
|
Loading…
Reference in a new issue