#define NDEBUG
#include <debug.h>
+#define NASSERTS_RENAME
+
/* GLOBALS ******************************************************************/
const char* FileInformationClassNames[] =
/*
* FUNCTION: Retrieve the standard file information
*/
-static
NTSTATUS
VfatGetStandardInformation(
PVFATFCB FCB,
return STATUS_SUCCESS;
}
-static
NTSTATUS
VfatGetBasicInformation(
PFILE_OBJECT FileObject,
(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
+ /* 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 */
/* If it exists */
if (NT_SUCCESS(Status))
{
+ DPRINT("Target file %wZ exists. FCB Flags %08x\n", NewName, TargetFcb->Flags);
/* Check whether we are allowed to replace */
if (ReplaceIfExists)
{
/* If that's a directory or a read-only file, we're not allowed */
- if (vfatFCBIsDirectory(TargetFcb) || ((*TargetFcb->Attributes & FILE_ATTRIBUTE_READONLY) == FILE_ATTRIBUTE_READONLY));
+ if (vfatFCBIsDirectory(TargetFcb) || ((*TargetFcb->Attributes & FILE_ATTRIBUTE_READONLY) == FILE_ATTRIBUTE_READONLY))
{
+ DPRINT("And this is a readonly file!\n");
vfatReleaseFCB(DeviceExt, *ParentFCB);
*ParentFCB = NULL;
vfatReleaseFCB(DeviceExt, TargetFcb);
return STATUS_OBJECT_NAME_COLLISION;
}
- /* Attempt to flush (might close the file) */
- if (!MmFlushImageSection(TargetFcb->FileObject->SectionObjectPointer, MmFlushForDelete))
+
+ /* If we still have a file object, close it. */
+ if (TargetFcb->FileObject)
{
- vfatReleaseFCB(DeviceExt, *ParentFCB);
- *ParentFCB = NULL;
- vfatReleaseFCB(DeviceExt, TargetFcb);
- return STATUS_ACCESS_DENIED;
+ if (!MmFlushImageSection(TargetFcb->FileObject->SectionObjectPointer, MmFlushForDelete))
+ {
+ DPRINT("MmFlushImageSection failed.\n");
+ vfatReleaseFCB(DeviceExt, *ParentFCB);
+ *ParentFCB = NULL;
+ vfatReleaseFCB(DeviceExt, TargetFcb);
+ return STATUS_ACCESS_DENIED;
+ }
+
+ TargetFcb->FileObject->DeletePending = TRUE;
+ VfatCloseFile(DeviceExt, TargetFcb->FileObject);
}
- /* If we are, ensure the file isn't open by anyone! */
+ /* If we are here, ensure the file isn't open by anyone! */
if (TargetFcb->OpenHandleCount != 0)
{
+ DPRINT("There are still open handles for this file.\n");
vfatReleaseFCB(DeviceExt, *ParentFCB);
*ParentFCB = NULL;
vfatReleaseFCB(DeviceExt, TargetFcb);
}
/* Effectively delete old file to allow renaming */
+ DPRINT("Effectively deleting the file.\n");
VfatDelEntry(DeviceExt, TargetFcb, NULL);
- (*ParentFCB)->RefCount++;
vfatReleaseFCB(DeviceExt, TargetFcb);
*Deleted = TRUE;
+ return STATUS_SUCCESS;
}
else
{
VfatSetRenameInformation(
PFILE_OBJECT FileObject,
PVFATFCB FCB,
- PDEVICE_EXTENSION DeviceObject,
+ PDEVICE_EXTENSION DeviceExt,
PFILE_RENAME_INFORMATION RenameInfo,
PFILE_OBJECT TargetFileObject)
{
+#ifdef NASSERTS_RENAME
+#pragma push_macro("ASSERT")
+#undef ASSERT
+#define ASSERT(x) ((VOID) 0)
+#endif
NTSTATUS Status;
UNICODE_STRING NewName;
UNICODE_STRING SourcePath;
OBJECT_ATTRIBUTES ObjectAttributes;
HANDLE TargetHandle;
BOOLEAN DeletedTarget;
+ ULONG OldReferences, NewReferences;
+ PVFATFCB OldParent;
- DPRINT("VfatSetRenameInfo(%p, %p, %p, %p, %p)\n", FileObject, FCB, DeviceObject, RenameInfo, TargetFileObject);
+ DPRINT("VfatSetRenameInfo(%p, %p, %p, %p, %p)\n", FileObject, FCB, DeviceExt, RenameInfo, TargetFileObject);
/* Disallow renaming root */
if (vfatFCBIsRoot(FCB))
return STATUS_INVALID_PARAMETER;
}
+ OldReferences = FCB->parentFcb->RefCount;
+#ifdef NASSERTS_RENAME
+ UNREFERENCED_PARAMETER(OldReferences);
+#endif
+
/* If we are performing relative opening for rename, get FO for getting FCB and path name */
if (RenameInfo->RootDirectory != NULL)
{
RootFCB = RootFileObject->FsContext;
}
+ RtlInitEmptyUnicodeString(&NewName, NULL, 0);
ParentFCB = NULL;
if (TargetFileObject == NULL)
vfatSplitPathName(&NewName, &NewPath, &NewFile);
DPRINT("New dir: %wZ, New file: %wZ\n", &NewPath, &NewFile);
+ /* FIXME: Do it in a more efficient way, like linking FCBs to their parent FCB so that we browse less FCBs
+ * Note: The FIXME is the way MS FastFAT seems to do it
+ */
+ if (vfatFCBIsDirectory(FCB))
+ {
+ PLIST_ENTRY Entry;
+ PVFATFCB VolFCB;
+
+ for (Entry = DeviceExt->FcbListHead.Flink; Entry != &DeviceExt->FcbListHead; Entry = Entry->Flink)
+ {
+ VolFCB = CONTAINING_RECORD(Entry, VFATFCB, FcbListEntry);
+ if (VolFCB->parentFcb == FCB && VolFCB->OpenHandleCount != 0)
+ {
+ DPRINT1("At least one children file opened! %wZ (%u, %u)\n", &VolFCB->PathNameU, VolFCB->RefCount, VolFCB->OpenHandleCount);
+ Status = STATUS_ACCESS_DENIED;
+ ASSERT(OldReferences == FCB->parentFcb->RefCount);
+ goto Cleanup;
+ }
+ }
+ }
+
/* Are we working in place? */
if (FsRtlAreNamesEqual(&SourcePath, &NewPath, TRUE, NULL))
{
if (FsRtlAreNamesEqual(&SourceFile, &NewFile, FALSE, NULL))
{
Status = STATUS_SUCCESS;
+ ASSERT(OldReferences == FCB->parentFcb->RefCount);
goto Cleanup;
}
if (FsRtlAreNamesEqual(&SourceFile, &NewFile, TRUE, NULL))
{
- FsRtlNotifyFullReportChange(DeviceObject->NotifySync,
- &(DeviceObject->NotifyList),
+ FsRtlNotifyFullReportChange(DeviceExt->NotifySync,
+ &(DeviceExt->NotifyList),
(PSTRING)&FCB->PathNameU,
FCB->PathNameU.Length - FCB->LongNameU.Length,
NULL,
FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME),
FILE_ACTION_RENAMED_OLD_NAME,
NULL);
- Status = vfatRenameEntry(DeviceObject, FCB, &NewFile, TRUE);
+ Status = vfatRenameEntry(DeviceExt, FCB, &NewFile, TRUE);
if (NT_SUCCESS(Status))
{
- FsRtlNotifyFullReportChange(DeviceObject->NotifySync,
- &(DeviceObject->NotifyList),
+ FsRtlNotifyFullReportChange(DeviceExt->NotifySync,
+ &(DeviceExt->NotifyList),
(PSTRING)&FCB->PathNameU,
FCB->PathNameU.Length - FCB->LongNameU.Length,
NULL,
{
/* Try to find target */
ParentFCB = FCB->parentFcb;
- ParentFCB->RefCount++;
- Status = vfatPrepareTargetForRename(DeviceObject,
+ vfatGrabFCB(DeviceExt, ParentFCB);
+ Status = vfatPrepareTargetForRename(DeviceExt,
&ParentFCB,
&NewFile,
RenameInfo->ReplaceIfExists,
&DeletedTarget);
if (!NT_SUCCESS(Status))
{
+ ASSERT(OldReferences == FCB->parentFcb->RefCount - 1);
+ ASSERT(OldReferences == ParentFCB->RefCount - 1);
goto Cleanup;
}
- FsRtlNotifyFullReportChange(DeviceObject->NotifySync,
- &(DeviceObject->NotifyList),
+ FsRtlNotifyFullReportChange(DeviceExt->NotifySync,
+ &(DeviceExt->NotifyList),
(PSTRING)&FCB->PathNameU,
FCB->PathNameU.Length - FCB->LongNameU.Length,
NULL,
FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME),
(DeletedTarget ? FILE_ACTION_REMOVED : FILE_ACTION_RENAMED_OLD_NAME),
NULL);
- Status = vfatRenameEntry(DeviceObject, FCB, &NewFile, FALSE);
+ Status = vfatRenameEntry(DeviceExt, FCB, &NewFile, FALSE);
if (NT_SUCCESS(Status))
{
if (DeletedTarget)
{
- FsRtlNotifyFullReportChange(DeviceObject->NotifySync,
- &(DeviceObject->NotifyList),
+ FsRtlNotifyFullReportChange(DeviceExt->NotifySync,
+ &(DeviceExt->NotifyList),
(PSTRING)&FCB->PathNameU,
FCB->PathNameU.Length - FCB->LongNameU.Length,
NULL,
}
else
{
- FsRtlNotifyFullReportChange(DeviceObject->NotifySync,
- &(DeviceObject->NotifyList),
+ FsRtlNotifyFullReportChange(DeviceExt->NotifySync,
+ &(DeviceExt->NotifyList),
(PSTRING)&FCB->PathNameU,
FCB->PathNameU.Length - FCB->LongNameU.Length,
NULL,
}
}
}
+
+ ASSERT(OldReferences == FCB->parentFcb->RefCount - 1); // extra grab
+ ASSERT(OldReferences == ParentFCB->RefCount - 1); // extra grab
}
else
{
+
/* Try to find target */
ParentFCB = NULL;
- Status = vfatPrepareTargetForRename(DeviceObject,
+ OldParent = FCB->parentFcb;
+#ifdef NASSERTS_RENAME
+ UNREFERENCED_PARAMETER(OldParent);
+#endif
+ Status = vfatPrepareTargetForRename(DeviceExt,
&ParentFCB,
&NewName,
RenameInfo->ReplaceIfExists,
&DeletedTarget);
if (!NT_SUCCESS(Status))
{
+ ASSERT(OldReferences == FCB->parentFcb->RefCount);
goto Cleanup;
}
- FsRtlNotifyFullReportChange(DeviceObject->NotifySync,
- &(DeviceObject->NotifyList),
+ NewReferences = ParentFCB->RefCount;
+#ifdef NASSERTS_RENAME
+ UNREFERENCED_PARAMETER(NewReferences);
+#endif
+
+ FsRtlNotifyFullReportChange(DeviceExt->NotifySync,
+ &(DeviceExt->NotifyList),
(PSTRING)&FCB->PathNameU,
FCB->PathNameU.Length - FCB->LongNameU.Length,
NULL,
FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME),
FILE_ACTION_REMOVED,
NULL);
- Status = VfatMoveEntry(DeviceObject, FCB, &NewFile, ParentFCB);
+ Status = VfatMoveEntry(DeviceExt, FCB, &NewFile, ParentFCB);
if (NT_SUCCESS(Status))
{
if (DeletedTarget)
{
- FsRtlNotifyFullReportChange(DeviceObject->NotifySync,
- &(DeviceObject->NotifyList),
+ FsRtlNotifyFullReportChange(DeviceExt->NotifySync,
+ &(DeviceExt->NotifyList),
(PSTRING)&FCB->PathNameU,
FCB->PathNameU.Length - FCB->LongNameU.Length,
NULL,
}
else
{
- FsRtlNotifyFullReportChange(DeviceObject->NotifySync,
- &(DeviceObject->NotifyList),
+ FsRtlNotifyFullReportChange(DeviceExt->NotifySync,
+ &(DeviceExt->NotifyList),
(PSTRING)&FCB->PathNameU,
FCB->PathNameU.Length - FCB->LongNameU.Length,
NULL,
}
}
+ ASSERT(OldReferences == OldParent->RefCount + 1); // removed file
+ ASSERT(NewReferences == ParentFCB->RefCount - 1); // new file
Cleanup:
- if (ParentFCB != NULL) vfatReleaseFCB(DeviceObject, ParentFCB);
+ if (ParentFCB != NULL) vfatReleaseFCB(DeviceExt, ParentFCB);
if (NewName.Buffer != NULL) ExFreePoolWithTag(NewName.Buffer, TAG_VFAT);
if (RenameInfo->RootDirectory != NULL) ObDereferenceObject(RootFileObject);
return Status;
+#ifdef NASSERTS_RENAME
+#pragma pop_macro("ASSERT")
+#endif
}
/*
PULONG BufferLength)
{
NTSTATUS Status;
- ULONG InitialBufferLength = *BufferLength;
ASSERT(Info);
ASSERT(Fcb);
- if (*BufferLength < sizeof(FILE_ALL_INFORMATION) + Fcb->PathNameU.Length + sizeof(WCHAR))
- return(STATUS_BUFFER_OVERFLOW);
+ if (*BufferLength < FIELD_OFFSET(FILE_ALL_INFORMATION, NameInformation.FileName))
+ return STATUS_BUFFER_OVERFLOW;
/* Basic Information */
Status = VfatGetBasicInformation(FileObject, Fcb, DeviceObject, &Info->BasicInformation, BufferLength);
Status = VfatGetInternalInformation(Fcb, &Info->InternalInformation, BufferLength);
if (!NT_SUCCESS(Status)) return Status;
/* EA Information */
- Info->EaInformation.EaSize = 0;
+ Status = VfatGetEaInformation(FileObject, Fcb, DeviceObject, &Info->EaInformation, BufferLength);
+ if (!NT_SUCCESS(Status)) return Status;
/* Access Information: The IO-Manager adds this information */
+ *BufferLength -= sizeof(FILE_ACCESS_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 */
+ *BufferLength -= sizeof(FILE_MODE_INFORMATION);
/* Alignment Information: The IO-Manager adds this information */
+ *BufferLength -= sizeof(FILE_ALIGNMENT_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;
+ return Status;
}
static
{
if (Size > 0)
{
- Fcb->RFCB.AllocationSize.QuadPart = ROUND_UP(Size, ClusterSize);
+ Fcb->RFCB.AllocationSize.QuadPart = ROUND_UP_64(Size, ClusterSize);
}
else
{
if (!(FCB->Flags & FCB_IS_PAGE_FILE))
{
if (!ExAcquireResourceSharedLite(&FCB->MainResource,
- (BOOLEAN)(IrpContext->Flags & IRPCONTEXT_CANWAIT)))
+ BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT)))
{
- return VfatQueueRequest(IrpContext);
+ return VfatMarkIrpContextForQueue(IrpContext);
}
}
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;
}
(PLARGE_INTEGER)SystemBuffer))
{
DPRINT("Couldn't set file size!\n");
- IrpContext->Irp->IoStatus.Status = STATUS_USER_MAPPED_FILE;
IrpContext->Irp->IoStatus.Information = 0;
- IoCompleteRequest(IrpContext->Irp, IO_NO_INCREMENT);
- VfatFreeIrpContext(IrpContext);
return STATUS_USER_MAPPED_FILE;
}
DPRINT("Can set file size\n");
if (FileInformationClass == FileRenameInformation)
{
if (!ExAcquireResourceExclusiveLite(&((PDEVICE_EXTENSION)IrpContext->DeviceObject->DeviceExtension)->DirResource,
- (BOOLEAN)(IrpContext->Flags & IRPCONTEXT_CANWAIT)))
+ BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT)))
{
- return VfatQueueRequest(IrpContext);
+ return VfatMarkIrpContextForQueue(IrpContext);
}
}
if (!(FCB->Flags & FCB_IS_PAGE_FILE))
{
if (!ExAcquireResourceExclusiveLite(&FCB->MainResource,
- (BOOLEAN)(IrpContext->Flags & IRPCONTEXT_CANWAIT)))
+ BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT)))
{
if (FileInformationClass == FileRenameInformation)
{
ExReleaseResourceLite(&((PDEVICE_EXTENSION)IrpContext->DeviceObject->DeviceExtension)->DirResource);
}
- return VfatQueueRequest(IrpContext);
+
+ return VfatMarkIrpContextForQueue(IrpContext);
}
}
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;
}