[FASTFAT]
[reactos.git] / reactos / drivers / filesystems / fastfat / finfo.c
index 1dbe8f6..976822f 100644 (file)
@@ -71,7 +71,6 @@ const char* FileInformationClassNames[] =
 /*
  * FUNCTION: Retrieve the standard file information
  */
-static
 NTSTATUS
 VfatGetStandardInformation(
     PVFATFCB FCB,
@@ -236,7 +235,6 @@ VfatSetBasicInformation(
     return STATUS_SUCCESS;
 }
 
-static
 NTSTATUS
 VfatGetBasicInformation(
     PFILE_OBJECT FileObject,
@@ -349,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 */
@@ -461,6 +458,65 @@ vfatPrepareTargetForRename(
     return Status;
 }
 
+static
+BOOLEAN
+IsThereAChildOpened(PVFATFCB FCB)
+{
+    PLIST_ENTRY Entry;
+    PVFATFCB VolFCB;
+
+    for (Entry = FCB->ParentListHead.Flink; Entry != &FCB->ParentListHead; Entry = Entry->Flink)
+    {
+        VolFCB = CONTAINING_RECORD(Entry, VFATFCB, ParentListEntry);
+        if (VolFCB->OpenHandleCount != 0)
+        {
+            ASSERT(VolFCB->parentFcb == FCB);
+            DPRINT1("At least one children file opened! %wZ (%u, %u)\n", &VolFCB->PathNameU, VolFCB->RefCount, VolFCB->OpenHandleCount);
+            return TRUE;
+        }
+
+        if (vfatFCBIsDirectory(VolFCB) && !IsListEmpty(&VolFCB->ParentListHead))
+        {
+            if (IsThereAChildOpened(VolFCB))
+            {
+                return TRUE;
+            }
+        }
+    }
+
+    return FALSE;
+}
+
+static
+VOID
+VfatRenameChildFCB(
+    PDEVICE_EXTENSION DeviceExt,
+    PVFATFCB FCB)
+{
+    PLIST_ENTRY Entry;
+    PVFATFCB Child;
+
+    if (IsListEmpty(&FCB->ParentListHead))
+        return;
+
+    for (Entry = FCB->ParentListHead.Flink; Entry != &FCB->ParentListHead; Entry = Entry->Flink)
+    {
+        NTSTATUS Status;
+
+        Child = CONTAINING_RECORD(Entry, VFATFCB, ParentListEntry);
+        DPRINT("Found %wZ with still %lu references (parent: %lu)!\n", &Child->PathNameU, Child->RefCount, FCB->RefCount);
+
+        Status = vfatSetFCBNewDirName(DeviceExt, Child, FCB);
+        if (!NT_SUCCESS(Status))
+            continue;
+
+        if (vfatFCBIsDirectory(Child))
+        {
+            VfatRenameChildFCB(DeviceExt, Child);
+        }
+    }
+}
+
 /*
  * FUNCTION: Set the file name information
  */
@@ -531,6 +587,7 @@ VfatSetRenameInformation(
         RootFCB = RootFileObject->FsContext;
     }
 
+    RtlInitEmptyUnicodeString(&NewName, NULL, 0);
     ParentFCB = NULL;
 
     if (TargetFileObject == NULL)
@@ -706,6 +763,16 @@ VfatSetRenameInformation(
     vfatSplitPathName(&NewName, &NewPath, &NewFile);
     DPRINT("New dir: %wZ, New file: %wZ\n", &NewPath, &NewFile);
 
+    if (vfatFCBIsDirectory(FCB) && !IsListEmpty(&FCB->ParentListHead))
+    {
+        if (IsThereAChildOpened(FCB))
+        {
+            Status = STATUS_ACCESS_DENIED;
+            ASSERT(OldReferences == FCB->parentFcb->RefCount);
+            goto Cleanup;
+        }
+    }
+
     /* Are we working in place? */
     if (FsRtlAreNamesEqual(&SourcePath, &NewPath, TRUE, NULL))
     {
@@ -874,6 +941,11 @@ VfatSetRenameInformation(
         }
     }
 
+    if (NT_SUCCESS(Status) && vfatFCBIsDirectory(FCB))
+    {
+        VfatRenameChildFCB(DeviceExt, FCB);
+    }
+
     ASSERT(OldReferences == OldParent->RefCount + 1); // removed file
     ASSERT(NewReferences == ParentFCB->RefCount - 1); // new file
 Cleanup:
@@ -1072,13 +1144,12 @@ VfatGetAllInformation(
     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);
@@ -1090,20 +1161,21 @@ VfatGetAllInformation(
     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
@@ -1116,7 +1188,7 @@ UpdateFileSize(
 {
     if (Size > 0)
     {
-        Fcb->RFCB.AllocationSize.QuadPart = ROUND_UP(Size, ClusterSize);
+        Fcb->RFCB.AllocationSize.QuadPart = ROUND_UP_64(Size, ClusterSize);
     }
     else
     {
@@ -1356,7 +1428,7 @@ VfatQueryInformation(
     PVFAT_IRP_CONTEXT IrpContext)
 {
     FILE_INFORMATION_CLASS FileInformationClass;
-    PVFATFCB FCB = NULL;
+    PVFATFCB FCB;
 
     NTSTATUS Status = STATUS_SUCCESS;
     PVOID SystemBuffer;
@@ -1372,6 +1444,12 @@ VfatQueryInformation(
     DPRINT("VfatQueryInformation is called for '%s'\n",
            FileInformationClass >= FileMaximumInformation - 1 ? "????" : FileInformationClassNames[FileInformationClass]);
 
+    if (FCB == NULL)
+    {
+        DPRINT1("IRP_MJ_QUERY_INFORMATION without FCB!\n");
+        IrpContext->Irp->IoStatus.Information = 0;
+        return STATUS_INVALID_PARAMETER;
+    }
 
     SystemBuffer = IrpContext->Irp->AssociatedIrp.SystemBuffer;
     BufferLength = IrpContext->Stack->Parameters.QueryFile.Length;
@@ -1379,9 +1457,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);
         }
     }
 
@@ -1459,14 +1537,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;
 }
@@ -1479,7 +1554,7 @@ VfatSetInformation(
     PVFAT_IRP_CONTEXT IrpContext)
 {
     FILE_INFORMATION_CLASS FileInformationClass;
-    PVFATFCB FCB = NULL;
+    PVFATFCB FCB;
     NTSTATUS Status = STATUS_SUCCESS;
     PVOID SystemBuffer;
 
@@ -1500,6 +1575,13 @@ VfatSetInformation(
     DPRINT("FileInformationClass %d\n", FileInformationClass);
     DPRINT("SystemBuffer %p\n", SystemBuffer);
 
+    if (FCB == NULL)
+    {
+        DPRINT1("IRP_MJ_SET_INFORMATION without FCB!\n");
+        IrpContext->Irp->IoStatus.Information = 0;
+        return STATUS_INVALID_PARAMETER;
+    }
+
     /* Special: We should call MmCanFileBeTruncated here to determine if changing
        the file size would be allowed.  If not, we bail with the right error.
        We must do this before acquiring the lock. */
@@ -1510,10 +1592,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");
@@ -1522,22 +1601,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);
         }
     }
 
@@ -1592,11 +1672,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;
 }