[FASTFAT]
[reactos.git] / reactos / drivers / filesystems / fastfat / finfo.c
index 87a3084..d4ddcc8 100644 (file)
@@ -16,6 +16,8 @@
 #define NDEBUG
 #include <debug.h>
 
+#define NASSERTS_RENAME
+
 /* GLOBALS ******************************************************************/
 
 const char* FileInformationClassNames[] =
@@ -69,7 +71,6 @@ const char* FileInformationClassNames[] =
 /*
  * FUNCTION: Retrieve the standard file information
  */
-static
 NTSTATUS
 VfatGetStandardInformation(
     PVFATFCB FCB,
@@ -234,7 +235,6 @@ VfatSetBasicInformation(
     return STATUS_SUCCESS;
 }
 
-static
 NTSTATUS
 VfatGetBasicInformation(
     PFILE_OBJECT FileObject,
@@ -347,11 +347,10 @@ VfatSetDispositionInformation(
         (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 */
@@ -394,41 +393,57 @@ vfatPrepareTargetForRename(
     /* 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)
             {
-                *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);
                 return STATUS_ACCESS_DENIED;
             }
 
             /* 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
         {
+            vfatReleaseFCB(DeviceExt, *ParentFCB);
             *ParentFCB = NULL;
             vfatReleaseFCB(DeviceExt, TargetFcb);
             return STATUS_OBJECT_NAME_COLLISION;
@@ -451,10 +466,15 @@ NTSTATUS
 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;
@@ -469,8 +489,10 @@ VfatSetRenameInformation(
     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))
@@ -478,6 +500,11 @@ VfatSetRenameInformation(
         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)
     {
@@ -501,6 +528,7 @@ VfatSetRenameInformation(
         RootFCB = RootFileObject->FsContext;
     }
 
+    RtlInitEmptyUnicodeString(&NewName, NULL, 0);
     ParentFCB = NULL;
 
     if (TargetFileObject == NULL)
@@ -682,13 +710,14 @@ VfatSetRenameInformation(
         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,
@@ -697,11 +726,11 @@ VfatSetRenameInformation(
                                         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,
@@ -716,8 +745,8 @@ VfatSetRenameInformation(
         {
             /* Try to find target */
             ParentFCB = FCB->parentFcb;
-            ParentFCB->RefCount++;
-            Status = vfatPrepareTargetForRename(DeviceObject,
+            vfatGrabFCB(DeviceExt, ParentFCB);
+            Status = vfatPrepareTargetForRename(DeviceExt,
                                                 &ParentFCB,
                                                 &NewFile,
                                                 RenameInfo->ReplaceIfExists,
@@ -725,11 +754,13 @@ VfatSetRenameInformation(
                                                 &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,
@@ -738,13 +769,13 @@ VfatSetRenameInformation(
                                         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,
@@ -756,8 +787,8 @@ VfatSetRenameInformation(
                 }
                 else
                 {
-                    FsRtlNotifyFullReportChange(DeviceObject->NotifySync,
-                                                &(DeviceObject->NotifyList),
+                    FsRtlNotifyFullReportChange(DeviceExt->NotifySync,
+                                                &(DeviceExt->NotifyList),
                                                 (PSTRING)&FCB->PathNameU,
                                                 FCB->PathNameU.Length - FCB->LongNameU.Length,
                                                 NULL,
@@ -769,12 +800,20 @@ VfatSetRenameInformation(
                 }
             }
         }
+
+        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,
@@ -782,11 +821,17 @@ VfatSetRenameInformation(
                                             &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,
@@ -795,13 +840,13 @@ VfatSetRenameInformation(
                                     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,
@@ -813,8 +858,8 @@ VfatSetRenameInformation(
             }
             else
             {
-                FsRtlNotifyFullReportChange(DeviceObject->NotifySync,
-                                            &(DeviceObject->NotifyList),
+                FsRtlNotifyFullReportChange(DeviceExt->NotifySync,
+                                            &(DeviceExt->NotifyList),
                                             (PSTRING)&FCB->PathNameU,
                                             FCB->PathNameU.Length - FCB->LongNameU.Length,
                                             NULL,
@@ -827,12 +872,17 @@ VfatSetRenameInformation(
         }
     }
 
+    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
 }
 
 /*
@@ -1025,8 +1075,8 @@ VfatGetAllInformation(
     ASSERT(Info);
     ASSERT(Fcb);
 
-    if (*BufferLength < sizeof(FILE_ALL_INFORMATION) + Fcb->PathNameU.Length + sizeof(WCHAR))
-        return(STATUS_BUFFER_OVERFLOW);
+    if (*BufferLength < sizeof(FILE_ALL_INFORMATION))
+        return STATUS_BUFFER_OVERFLOW;
 
     /* Basic Information */
     Status = VfatGetBasicInformation(FileObject, Fcb, DeviceObject, &Info->BasicInformation, BufferLength);
@@ -1047,11 +1097,12 @@ VfatGetAllInformation(
     /* 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));
+    *BufferLength = InitialBufferLength - sizeof(FILE_ALL_INFORMATION);
+    if (InitialBufferLength > sizeof(FILE_ALL_INFORMATION))
+        *BufferLength -= min(InitialBufferLength - sizeof(FILE_ALL_INFORMATION), Fcb->PathNameU.Length);
 
-    return STATUS_SUCCESS;
+    return Status;
 }
 
 static
@@ -1327,9 +1378,9 @@ VfatQueryInformation(
     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);
         }
     }
 
@@ -1407,14 +1458,11 @@ VfatQueryInformation(
         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;
 }
@@ -1458,10 +1506,7 @@ VfatSetInformation(
                                   (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");
@@ -1470,22 +1515,23 @@ VfatSetInformation(
     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);
         }
     }
 
@@ -1540,11 +1586,7 @@ VfatSetInformation(
         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;
 }