- Delete old source code (only fastio.c and DriverEntry remain for now).

- Create a base for a future skeleton.

svn path=/trunk/; revision=38698
This commit is contained in:
Aleksey Bragin 2009-01-11 14:10:54 +00:00
parent dd4b33c2a6
commit 6094202983
20 changed files with 133 additions and 8349 deletions

View file

@ -1,10 +1,9 @@
/*
* 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:
* PROJECT: ReactOS FAT file system driver
* LICENSE: GPL - See COPYING in the top level directory
* FILE: drivers/filesystems/fastfat/blockdev.c
* PURPOSE: Temporary sector reading support
* PROGRAMMERS: Aleksey Bragin (aleksey@reactos.org)
*/
/* INCLUDES *****************************************************************/
@ -14,44 +13,6 @@
/* 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,
@ -59,58 +20,7 @@ VfatReadDisk (IN PDEVICE_OBJECT pDeviceObject,
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);
return STATUS_NOT_IMPLEMENTED;
}
NTSTATUS
@ -120,76 +30,7 @@ VfatReadDiskPartial (IN PVFAT_IRP_CONTEXT IrpContext,
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;
return STATUS_NOT_IMPLEMENTED;
}
@ -200,73 +41,7 @@ VfatWriteDiskPartial (IN PVFAT_IRP_CONTEXT IrpContext,
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;
return STATUS_NOT_IMPLEMENTED;
}
NTSTATUS
@ -278,61 +53,5 @@ VfatBlockDeviceIoControl (IN PDEVICE_OBJECT DeviceObject,
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;
return STATUS_NOT_IMPLEMENTED;
}

View file

@ -1,9 +1,9 @@
/*
* 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)
* PROJECT: ReactOS FAT file system driver
* LICENSE: GPL - See COPYING in the top level directory
* FILE: drivers/filesystems/fastfat/cleanup.c
* PURPOSE: Cleanup routines
* PROGRAMMERS: Aleksey Bragin (aleksey@reactos.org)
*/
/* INCLUDES *****************************************************************/
@ -13,132 +13,12 @@
/* FUNCTIONS ****************************************************************/
/*
* FUNCTION: Cleans up after a file has been closed.
*/
static NTSTATUS
VfatCleanupFile(PVFAT_IRP_CONTEXT IrpContext)
NTSTATUS
VfatCleanup(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);
return STATUS_NOT_IMPLEMENTED;
}
/* EOF */

View file

@ -1,9 +1,9 @@
/*
* 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)
* PROJECT: ReactOS FAT file system driver
* LICENSE: GPL - See COPYING in the top level directory
* FILE: drivers/filesystems/fastfat/cleanup.c
* PURPOSE: Closing routines
* PROGRAMMERS: Aleksey Bragin (aleksey@reactos.org)
*/
/* INCLUDES *****************************************************************/
@ -14,97 +14,11 @@
/* FUNCTIONS ****************************************************************/
NTSTATUS
VfatCloseFile (PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject)
/*
* FUNCTION: Closes a file
*/
VfatClose(PVFAT_IRP_CONTEXT IrpContext)
{
PVFATFCB pFcb;
PVFATCCB pCcb;
NTSTATUS Status = STATUS_SUCCESS;
DPRINT("VfatClose(DeviceObject %p, Irp %p)\n", IrpContext->DeviceObject, IrpContext->Irp);
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);
return STATUS_NOT_IMPLEMENTED;
}
/* EOF */

View file

@ -1,26 +1,9 @@
/*
* 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)
* PROJECT: ReactOS FAT file system driver
* LICENSE: GPL - See COPYING in the top level directory
* FILE: drivers/filesystems/fastfat/create.c
* PURPOSE: Create routines
* PROGRAMMERS: Aleksey Bragin (aleksey@reactos.org)
*/
/* INCLUDES *****************************************************************/
@ -30,772 +13,10 @@
/* 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
*/
VfatCreate(PVFAT_IRP_CONTEXT IrpContext)
{
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);
return STATUS_NOT_IMPLEMENTED;
}
/* EOF */

View file

@ -1,511 +1,22 @@
/*
* 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
* PROJECT: ReactOS FAT file system driver
* LICENSE: GPL - See COPYING in the top level directory
* FILE: drivers/filesystems/fastfat/dir.c
* PURPOSE: Directory Control
* PROGRAMMERS: Aleksey Bragin (aleksey@reactos.org)
*/
*/
/* INCLUDES *****************************************************************/
#define NDEBUG
#include "fastfat.h"
/* FUNCTIONS *****************************************************************/
// function like DosDateTimeToFileTime
BOOLEAN
FsdDosDateTimeToSystemTime (PDEVICE_EXTENSION DeviceExt, USHORT DosDate, USHORT DosTime, PLARGE_INTEGER SystemTime)
NTSTATUS
VfatDirectoryControl(PVFAT_IRP_CONTEXT IrpContext)
{
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;
return STATUS_NOT_IMPLEMENTED;
}
// 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;
}
/* EOF */

View file

@ -1,490 +1,17 @@
/*
* 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)
* PROJECT: ReactOS FAT file system driver
* LICENSE: GPL - See COPYING in the top level directory
* FILE: drivers/filesystems/fastfat/direntry.c
* PURPOSE: Directory entries
* PROGRAMMERS:
*/
/* ------------------------------------------------------- INCLUDES */
/* INCLUDES *****************************************************************/
#define NDEBUG
#include "fastfat.h"
ULONG
vfatDirEntryGetFirstCluster (PDEVICE_EXTENSION pDeviceExt,
PDIR_ENTRY pFatDirEntry)
{
ULONG cluster;
/* FUNCTIONS *****************************************************************/
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;
}
/* EOF */

View file

@ -1,722 +0,0 @@
/*
* 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 "fastfat.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 */

View file

@ -1,27 +1,9 @@
/*
* 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)
* PROJECT: ReactOS FAT file system driver
* LICENSE: GPL - See COPYING in the top level directory
* FILE: drivers/filesystems/fastfat/ea.c
* PURPOSE: Extended Attributes support
* PROGRAMMERS: Aleksey Bragin (aleksey@reactos.org)
*/
/* INCLUDES *****************************************************************/
@ -33,8 +15,8 @@
NTSTATUS
VfatSetExtendedAttributes(PFILE_OBJECT FileObject,
PVOID Ea,
ULONG EaLength)
PVOID Ea,
ULONG EaLength)
{
return(STATUS_EAS_NOT_SUPPORTED);
return STATUS_EAS_NOT_SUPPORTED;
}

View file

@ -84,7 +84,7 @@ DriverEntry(PDRIVER_OBJECT DriverObject,
VfatGlobalData->DeviceObject = DeviceObject;
DeviceObject->Flags |= DO_DIRECT_IO;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = VfatBuildRequest;
/*DriverObject->MajorFunction[IRP_MJ_CLOSE] = VfatBuildRequest;
DriverObject->MajorFunction[IRP_MJ_CREATE] = VfatBuildRequest;
DriverObject->MajorFunction[IRP_MJ_READ] = VfatBuildRequest;
DriverObject->MajorFunction[IRP_MJ_WRITE] = VfatBuildRequest;
@ -95,11 +95,11 @@ DriverEntry(PDRIVER_OBJECT DriverObject,
DriverObject->MajorFunction[IRP_MJ_QUERY_VOLUME_INFORMATION] =
VfatBuildRequest;
DriverObject->MajorFunction[IRP_MJ_SET_VOLUME_INFORMATION] =
VfatBuildRequest;
VfatBuildRequest;*/
DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = VfatShutdown;
DriverObject->MajorFunction[IRP_MJ_LOCK_CONTROL] = VfatBuildRequest;
/*DriverObject->MajorFunction[IRP_MJ_LOCK_CONTROL] = VfatBuildRequest;
DriverObject->MajorFunction[IRP_MJ_CLEANUP] = VfatBuildRequest;
DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = VfatBuildRequest;
DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = VfatBuildRequest;*/
DriverObject->DriverUnload = NULL;

View file

@ -11,19 +11,16 @@
<file>create.c</file>
<file>dir.c</file>
<file>direntry.c</file>
<file>dirwr.c</file>
<file>ea.c</file>
<file>fastfat.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>fastfat.rc</file>
<pch>fastfat.h</pch>

View file

@ -1,10 +1,9 @@
/*
* 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)
*
* PROJECT: ReactOS FAT file system driver
* LICENSE: GPL - See COPYING in the top level directory
* FILE: drivers/filesystems/fastfat/fat.c
* PURPOSE: FAT support routines
* PROGRAMMERS:
*/
/* INCLUDES *****************************************************************/
@ -12,698 +11,7 @@
#define NDEBUG
#include "fastfat.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 */

View file

@ -1,821 +1,17 @@
/*
* 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)
*/
* PROJECT: ReactOS FAT file system driver
* LICENSE: GPL - See COPYING in the top level directory
* FILE: drivers/filesystems/fastfat/rw.c
* PURPOSE: Read/write support
* PROGRAMMERS:
*/
/* ------------------------------------------------------- INCLUDES */
#ifdef __GNUC__
#include <wctype.h> /* towlower prototype */
#endif
/* INCLUDES *****************************************************************/
#define NDEBUG
#include "fastfat.h"
/* -------------------------------------------------------- DEFINES */
/* FUNCTIONS ****************************************************************/
#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;
}
/* EOF */

View file

@ -1,11 +1,9 @@
/*
* 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)
*
* PROJECT: ReactOS FAT file system driver
* LICENSE: GPL - See COPYING in the top level directory
* FILE: drivers/filesystems/fastfat/finfo.c
* PURPOSE: File Information support routines
* PROGRAMMERS: Aleksey Bragin (aleksey@reactos.org)
*/
/* INCLUDES *****************************************************************/
@ -13,936 +11,16 @@
#define NDEBUG
#include "fastfat.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;
return STATUS_NOT_IMPLEMENTED;
}
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;
return STATUS_NOT_IMPLEMENTED;
}
/* EOF */

View file

@ -1,11 +1,12 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* FILE: drivers/fs/vfat/flush.c
* PURPOSE: VFAT Filesystem
* PROGRAMMER:
* PROJECT: ReactOS FAT file system driver
* LICENSE: GPL - See COPYING in the top level directory
* FILE: drivers/filesystems/fastfat/flush.c
* PURPOSE: Flushing routines
* PROGRAMMERS: Aleksey Bragin (aleksey@reactos.org)
*/
/* INCLUDES *****************************************************************/
#define NDEBUG
@ -13,128 +14,16 @@
/* 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);
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;
return STATUS_NOT_IMPLEMENTED;
}
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);
return STATUS_NOT_IMPLEMENTED;
}
/* EOF */

View file

@ -1,26 +1,9 @@
/*
* 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
* PROJECT: ReactOS FAT file system driver
* LICENSE: GPL - See COPYING in the top level directory
* FILE: drivers/filesystems/fastfat/fsctl.c
* PURPOSE: Filesystem control
* PROGRAMMERS: Aleksey Bragin (aleksey@reactos.org)
*/
/* INCLUDES *****************************************************************/
@ -30,887 +13,10 @@
/* 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
VfatFileSystemControl(PVFAT_IRP_CONTEXT IrpContext)
{
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("VfatFileSystemControl(IrpContext %p)\n", IrpContext);
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);
return STATUS_NOT_IMPLEMENTED;
}

View file

@ -1,275 +0,0 @@
/*
* 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 "fastfat.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;
}

File diff suppressed because it is too large Load diff

View file

@ -1,9 +1,9 @@
/*
* 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)
* PROJECT: ReactOS FAT file system driver
* LICENSE: GPL - See COPYING in the top level directory
* FILE: drivers/filesystems/fastfat/shutdown.c
* PURPOSE: Shutdown support routines
* PROGRAMMERS: Aleksey Bragin (aleksey@reactos.org)
*/
/* INCLUDES *****************************************************************/
@ -13,106 +13,13 @@
/* 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
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);
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);
return STATUS_NOT_IMPLEMENTED;
}
/* EOF */

View file

@ -1,23 +0,0 @@
/*
* 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 "fastfat.h"
/* FUNCTIONS ****************************************************************/
const WCHAR *long_illegals = L"\"*\\<>/?:|";
BOOLEAN
vfatIsLongIllegal(WCHAR c)
{
return wcschr(long_illegals, c) ? TRUE : FALSE;
}

View file

@ -1,10 +1,9 @@
/*
* 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)
* PROJECT: ReactOS FAT file system driver
* LICENSE: GPL - See COPYING in the top level directory
* FILE: drivers/filesystems/fastfat/volume.c
* PURPOSE: Volume information
* PROGRAMMERS: Aleksey Bragin (aleksey@reactos.org)
*/
/* INCLUDES *****************************************************************/
@ -14,405 +13,16 @@
/* FUNCTIONS ****************************************************************/
static NTSTATUS
FsdGetFsVolumeInformation(PDEVICE_OBJECT DeviceObject,
PFILE_FS_VOLUME_INFORMATION FsVolumeInfo,
PULONG BufferLength)
NTSTATUS
VfatQueryVolumeInformation(PVFAT_IRP_CONTEXT IrpContext)
{
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);
return STATUS_NOT_IMPLEMENTED;
}
static NTSTATUS
FsdGetFsAttributeInformation(PDEVICE_EXTENSION DeviceExt,
PFILE_FS_ATTRIBUTE_INFORMATION FsAttributeInfo,
PULONG BufferLength)
NTSTATUS
VfatSetVolumeInformation(PVFAT_IRP_CONTEXT IrpContext)
{
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);
return STATUS_NOT_IMPLEMENTED;
}
/* EOF */