[FASTFAT] Don't add an extra \, when renaming a file at root.
[reactos.git] / drivers / filesystems / fastfat / finfo.c
index 87a3084..a19c21d 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,
@@ -96,7 +97,7 @@ VfatGetStandardInformation(
         StandardInfo->Directory = FALSE;
     }
     StandardInfo->NumberOfLinks = 1;
-    StandardInfo->DeletePending = FCB->Flags & FCB_DELETE_PENDING ? TRUE : FALSE;
+    StandardInfo->DeletePending = BooleanFlagOn(FCB->Flags, FCB_DELETE_PENDING);
 
     *BufferLength -= sizeof(FILE_STANDARD_INFORMATION);
     return STATUS_SUCCESS;
@@ -124,13 +125,13 @@ NTSTATUS
 VfatGetPositionInformation(
     PFILE_OBJECT FileObject,
     PVFATFCB FCB,
-    PDEVICE_OBJECT DeviceObject,
+    PDEVICE_EXTENSION DeviceExt,
     PFILE_POSITION_INFORMATION PositionInfo,
     PULONG BufferLength)
 {
     UNREFERENCED_PARAMETER(FileObject);
     UNREFERENCED_PARAMETER(FCB);
-    UNREFERENCED_PARAMETER(DeviceObject);
+    UNREFERENCED_PARAMETER(DeviceExt);
 
     DPRINT("VfatGetPositionInformation()\n");
 
@@ -155,6 +156,8 @@ VfatSetBasicInformation(
     PDEVICE_EXTENSION DeviceExt,
     PFILE_BASIC_INFORMATION BasicInfo)
 {
+    ULONG NotifyFilter;
+
     DPRINT("VfatSetBasicInformation()\n");
 
     ASSERT(NULL != FileObject);
@@ -164,7 +167,46 @@ VfatSetBasicInformation(
     /* Check volume label bit */
     ASSERT(0 == (*FCB->Attributes & _A_VOLID));
 
-    if (FCB->Flags & FCB_IS_FATX_ENTRY)
+    NotifyFilter = 0;
+
+    if (BasicInfo->FileAttributes != 0)
+    {
+        UCHAR Attributes;
+
+        Attributes = (BasicInfo->FileAttributes & (FILE_ATTRIBUTE_ARCHIVE |
+                                                   FILE_ATTRIBUTE_SYSTEM |
+                                                   FILE_ATTRIBUTE_HIDDEN |
+                                                   FILE_ATTRIBUTE_DIRECTORY |
+                                                   FILE_ATTRIBUTE_READONLY));
+
+        if (vfatFCBIsDirectory(FCB))
+        {
+            if (BooleanFlagOn(BasicInfo->FileAttributes, FILE_ATTRIBUTE_TEMPORARY))
+            {
+                DPRINT("Setting temporary attribute on a directory!\n");
+                return STATUS_INVALID_PARAMETER;
+            }
+
+            Attributes |= FILE_ATTRIBUTE_DIRECTORY;
+        }
+        else
+        {
+            if (BooleanFlagOn(BasicInfo->FileAttributes, FILE_ATTRIBUTE_DIRECTORY))
+            {
+                DPRINT("Setting directory attribute on a file!\n");
+                return STATUS_INVALID_PARAMETER;
+            }
+        }
+
+        if (Attributes != *FCB->Attributes)
+        {
+            *FCB->Attributes = Attributes;
+            DPRINT("Setting attributes 0x%02x\n", *FCB->Attributes);
+            NotifyFilter |= FILE_NOTIFY_CHANGE_ATTRIBUTES;
+        }
+    }
+
+    if (vfatVolumeIsFatX(DeviceExt))
     {
         if (BasicInfo->CreationTime.QuadPart != 0 && BasicInfo->CreationTime.QuadPart != -1)
         {
@@ -172,6 +214,7 @@ VfatSetBasicInformation(
                                        &BasicInfo->CreationTime,
                                        &FCB->entry.FatX.CreationDate,
                                        &FCB->entry.FatX.CreationTime);
+            NotifyFilter |= FILE_NOTIFY_CHANGE_CREATION;
         }
 
         if (BasicInfo->LastAccessTime.QuadPart != 0 && BasicInfo->LastAccessTime.QuadPart != -1)
@@ -180,6 +223,7 @@ VfatSetBasicInformation(
                                        &BasicInfo->LastAccessTime,
                                        &FCB->entry.FatX.AccessDate,
                                        &FCB->entry.FatX.AccessTime);
+            NotifyFilter |= FILE_NOTIFY_CHANGE_LAST_ACCESS;
         }
 
         if (BasicInfo->LastWriteTime.QuadPart != 0 && BasicInfo->LastWriteTime.QuadPart != -1)
@@ -188,6 +232,7 @@ VfatSetBasicInformation(
                                        &BasicInfo->LastWriteTime,
                                        &FCB->entry.FatX.UpdateDate,
                                        &FCB->entry.FatX.UpdateTime);
+            NotifyFilter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
         }
     }
     else
@@ -198,6 +243,7 @@ VfatSetBasicInformation(
                                        &BasicInfo->CreationTime,
                                        &FCB->entry.Fat.CreationDate,
                                        &FCB->entry.Fat.CreationTime);
+            NotifyFilter |= FILE_NOTIFY_CHANGE_CREATION;
         }
 
         if (BasicInfo->LastAccessTime.QuadPart != 0 && BasicInfo->LastAccessTime.QuadPart != -1)
@@ -206,6 +252,7 @@ VfatSetBasicInformation(
                                        &BasicInfo->LastAccessTime,
                                        &FCB->entry.Fat.AccessDate,
                                        NULL);
+            NotifyFilter |= FILE_NOTIFY_CHANGE_LAST_ACCESS;
         }
 
         if (BasicInfo->LastWriteTime.QuadPart != 0 && BasicInfo->LastWriteTime.QuadPart != -1)
@@ -214,47 +261,39 @@ VfatSetBasicInformation(
                                        &BasicInfo->LastWriteTime,
                                        &FCB->entry.Fat.UpdateDate,
                                        &FCB->entry.Fat.UpdateTime);
+            NotifyFilter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
         }
     }
 
-    if (BasicInfo->FileAttributes)
+    VfatUpdateEntry(DeviceExt, FCB);
+
+    if (NotifyFilter != 0)
     {
-        *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);
+        vfatReportChange(DeviceExt,
+                         FCB,
+                         NotifyFilter,
+                         FILE_ACTION_MODIFIED);
     }
 
-    VfatUpdateEntry(FCB);
-
     return STATUS_SUCCESS;
 }
 
-static
 NTSTATUS
 VfatGetBasicInformation(
     PFILE_OBJECT FileObject,
     PVFATFCB FCB,
-    PDEVICE_OBJECT DeviceObject,
+    PDEVICE_EXTENSION DeviceExt,
     PFILE_BASIC_INFORMATION BasicInfo,
     PULONG BufferLength)
 {
-    PDEVICE_EXTENSION DeviceExt;
-
     UNREFERENCED_PARAMETER(FileObject);
 
     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)
+    if (vfatVolumeIsFatX(DeviceExt))
     {
         FsdDosDateTimeToSystemTime(DeviceExt,
                                    FCB->entry.FatX.CreationDate,
@@ -310,13 +349,9 @@ NTSTATUS
 VfatSetDispositionInformation(
     PFILE_OBJECT FileObject,
     PVFATFCB FCB,
-    PDEVICE_OBJECT DeviceObject,
+    PDEVICE_EXTENSION DeviceExt,
     PFILE_DISPOSITION_INFORMATION DispositionInfo)
 {
-#if DBG
-    PDEVICE_EXTENSION DeviceExt = DeviceObject->DeviceExtension;
-#endif
-
     DPRINT("FsdSetDispositionInformation(<%wZ>, Delete %u)\n", &FCB->PathNameU, DispositionInfo->DeleteFile);
 
     ASSERT(DeviceExt != NULL);
@@ -331,14 +366,14 @@ VfatSetDispositionInformation(
         return STATUS_SUCCESS;
     }
 
-    if (FCB->Flags & FCB_DELETE_PENDING)
+    if (BooleanFlagOn(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)
+    if (vfatFCBIsReadOnly(FCB))
     {
         return STATUS_CANNOT_DELETE;
     }
@@ -347,11 +382,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 */
@@ -360,7 +394,7 @@ VfatSetDispositionInformation(
         return STATUS_CANNOT_DELETE;
     }
 
-    if (vfatFCBIsDirectory(FCB) && !VfatIsDirectoryEmpty(FCB))
+    if (vfatFCBIsDirectory(FCB) && !VfatIsDirectoryEmpty(DeviceExt, FCB))
     {
         /* can't delete a non-empty directory */
 
@@ -394,41 +428,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) || vfatFCBIsReadOnly(TargetFcb))
             {
+                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;
@@ -443,6 +493,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
  */
@@ -451,10 +560,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 +583,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 +594,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 +622,7 @@ VfatSetRenameInformation(
         RootFCB = RootFileObject->FsContext;
     }
 
+    RtlInitEmptyUnicodeString(&NewName, NULL, 0);
     ParentFCB = NULL;
 
     if (TargetFileObject == NULL)
@@ -665,8 +787,12 @@ VfatSetRenameInformation(
         }
 
         RtlCopyUnicodeString(&NewName, &((PVFATFCB)TargetFileObject->FsContext)->PathNameU);
-        NewName.Buffer[NewName.Length / sizeof(WCHAR)] = L'\\';
-        NewName.Length += sizeof(WCHAR);
+        /* If \, it's already backslash terminated, don't add it */
+        if (!vfatFCBIsRoot(TargetFileObject->FsContext))
+        {
+            NewName.Buffer[NewName.Length / sizeof(WCHAR)] = L'\\';
+            NewName.Length += sizeof(WCHAR);
+        }
         RtlAppendUnicodeStringToString(&NewName, &TargetFileObject->FileName);
     }
 
@@ -676,48 +802,49 @@ 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))
     {
         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),
-                                        (PSTRING)&FCB->PathNameU,
-                                        FCB->PathNameU.Length - FCB->LongNameU.Length,
-                                        NULL,
-                                        NULL,
-                                        ((*FCB->Attributes & FILE_ATTRIBUTE_DIRECTORY) ?
-                                        FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME),
-                                        FILE_ACTION_RENAMED_OLD_NAME,
-                                        NULL);
-            Status = vfatRenameEntry(DeviceObject, FCB, &NewFile, TRUE);
+            vfatReportChange(DeviceExt,
+                             FCB,
+                             (vfatFCBIsDirectory(FCB) ?
+                              FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME),
+                             FILE_ACTION_RENAMED_OLD_NAME);
+            Status = vfatRenameEntry(DeviceExt, FCB, &NewFile, TRUE);
             if (NT_SUCCESS(Status))
             {
-                FsRtlNotifyFullReportChange(DeviceObject->NotifySync,
-                                            &(DeviceObject->NotifyList),
-                                            (PSTRING)&FCB->PathNameU,
-                                            FCB->PathNameU.Length - FCB->LongNameU.Length,
-                                            NULL,
-                                            NULL,
-                                            ((*FCB->Attributes & FILE_ATTRIBUTE_DIRECTORY) ?
-                                            FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME),
-                                            FILE_ACTION_RENAMED_NEW_NAME,
-                                            NULL);
+                vfatReportChange(DeviceExt,
+                                 FCB,
+                                 (vfatFCBIsDirectory(FCB) ?
+                                  FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME),
+                                 FILE_ACTION_RENAMED_NEW_NAME);
             }
         }
         else
         {
             /* Try to find target */
             ParentFCB = FCB->parentFcb;
-            ParentFCB->RefCount++;
-            Status = vfatPrepareTargetForRename(DeviceObject,
+            vfatGrabFCB(DeviceExt, ParentFCB);
+            Status = vfatPrepareTargetForRename(DeviceExt,
                                                 &ParentFCB,
                                                 &NewFile,
                                                 RenameInfo->ReplaceIfExists,
@@ -725,56 +852,51 @@ VfatSetRenameInformation(
                                                 &DeletedTarget);
             if (!NT_SUCCESS(Status))
             {
+                ASSERT(OldReferences == FCB->parentFcb->RefCount - 1);
+                ASSERT(OldReferences == ParentFCB->RefCount - 1);
                 goto Cleanup;
             }
 
-            FsRtlNotifyFullReportChange(DeviceObject->NotifySync,
-                                        &(DeviceObject->NotifyList),
-                                        (PSTRING)&FCB->PathNameU,
-                                        FCB->PathNameU.Length - FCB->LongNameU.Length,
-                                        NULL,
-                                        NULL,
-                                        ((*FCB->Attributes & FILE_ATTRIBUTE_DIRECTORY) ?
-                                        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);
+            vfatReportChange(DeviceExt,
+                             FCB,
+                             (vfatFCBIsDirectory(FCB) ?
+                              FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME),
+                             (DeletedTarget ? FILE_ACTION_REMOVED : FILE_ACTION_RENAMED_OLD_NAME));
+            Status = vfatRenameEntry(DeviceExt, FCB, &NewFile, FALSE);
             if (NT_SUCCESS(Status))
             {
                 if (DeletedTarget)
                 {
-                    FsRtlNotifyFullReportChange(DeviceObject->NotifySync,
-                                                &(DeviceObject->NotifyList),
-                                                (PSTRING)&FCB->PathNameU,
-                                                FCB->PathNameU.Length - FCB->LongNameU.Length,
-                                                NULL,
-                                                NULL,
-                                                FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE
-                                                | FILE_NOTIFY_CHANGE_LAST_ACCESS | FILE_NOTIFY_CHANGE_CREATION | FILE_NOTIFY_CHANGE_EA,
-                                                FILE_ACTION_MODIFIED,
-                                                NULL);
+                    vfatReportChange(DeviceExt,
+                                     FCB,
+                                     FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE
+                                     | FILE_NOTIFY_CHANGE_LAST_ACCESS | FILE_NOTIFY_CHANGE_CREATION | FILE_NOTIFY_CHANGE_EA,
+                                     FILE_ACTION_MODIFIED);
                 }
                 else
                 {
-                    FsRtlNotifyFullReportChange(DeviceObject->NotifySync,
-                                                &(DeviceObject->NotifyList),
-                                                (PSTRING)&FCB->PathNameU,
-                                                FCB->PathNameU.Length - FCB->LongNameU.Length,
-                                                NULL,
-                                                NULL,
-                                                ((*FCB->Attributes & FILE_ATTRIBUTE_DIRECTORY) ?
-                                                FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME),
-                                                FILE_ACTION_RENAMED_NEW_NAME,
-                                                NULL);
+                    vfatReportChange(DeviceExt,
+                                     FCB,
+                                     (vfatFCBIsDirectory(FCB) ?
+                                      FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME),
+                                     FILE_ACTION_RENAMED_NEW_NAME);
                 }
             }
         }
+
+        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,57 +904,58 @@ VfatSetRenameInformation(
                                             &DeletedTarget);
         if (!NT_SUCCESS(Status))
         {
+            ASSERT(OldReferences == FCB->parentFcb->RefCount);
             goto Cleanup;
         }
 
-        FsRtlNotifyFullReportChange(DeviceObject->NotifySync,
-                                    &(DeviceObject->NotifyList),
-                                    (PSTRING)&FCB->PathNameU,
-                                    FCB->PathNameU.Length - FCB->LongNameU.Length,
-                                    NULL,
-                                    NULL,
-                                    ((*FCB->Attributes & FILE_ATTRIBUTE_DIRECTORY) ?
-                                    FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME),
-                                    FILE_ACTION_REMOVED,
-                                    NULL);
-        Status = VfatMoveEntry(DeviceObject, FCB, &NewFile, ParentFCB);
+        NewReferences = ParentFCB->RefCount;
+#ifdef NASSERTS_RENAME
+        UNREFERENCED_PARAMETER(NewReferences);
+#endif
+
+        vfatReportChange(DeviceExt,
+                         FCB,
+                         (vfatFCBIsDirectory(FCB) ?
+                          FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME),
+                         FILE_ACTION_REMOVED);
+        Status = VfatMoveEntry(DeviceExt, FCB, &NewFile, ParentFCB);
         if (NT_SUCCESS(Status))
         {
             if (DeletedTarget)
             {
-                FsRtlNotifyFullReportChange(DeviceObject->NotifySync,
-                                            &(DeviceObject->NotifyList),
-                                            (PSTRING)&FCB->PathNameU,
-                                            FCB->PathNameU.Length - FCB->LongNameU.Length,
-                                            NULL,
-                                            NULL,
-                                            FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE
-                                            | FILE_NOTIFY_CHANGE_LAST_ACCESS | FILE_NOTIFY_CHANGE_CREATION | FILE_NOTIFY_CHANGE_EA,
-                                            FILE_ACTION_MODIFIED,
-                                            NULL);
+                vfatReportChange(DeviceExt,
+                                 FCB,
+                                 FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE
+                                 | FILE_NOTIFY_CHANGE_LAST_ACCESS | FILE_NOTIFY_CHANGE_CREATION | FILE_NOTIFY_CHANGE_EA,
+                                 FILE_ACTION_MODIFIED);
             }
             else
             {
-                FsRtlNotifyFullReportChange(DeviceObject->NotifySync,
-                                            &(DeviceObject->NotifyList),
-                                            (PSTRING)&FCB->PathNameU,
-                                            FCB->PathNameU.Length - FCB->LongNameU.Length,
-                                            NULL,
-                                            NULL,
-                                            ((*FCB->Attributes & FILE_ATTRIBUTE_DIRECTORY) ?
-                                            FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME),
-                                            FILE_ACTION_ADDED,
-                                            NULL);
+                vfatReportChange(DeviceExt,
+                                 FCB,
+                                 (vfatFCBIsDirectory(FCB) ?
+                                  FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME),
+                                 FILE_ACTION_ADDED);
             }
         }
     }
 
+    if (NT_SUCCESS(Status) && vfatFCBIsDirectory(FCB))
+    {
+        VfatRenameChildFCB(DeviceExt, FCB);
+    }
+
+    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
 }
 
 /*
@@ -843,14 +966,14 @@ NTSTATUS
 VfatGetNameInformation(
     PFILE_OBJECT FileObject,
     PVFATFCB FCB,
-    PDEVICE_OBJECT DeviceObject,
+    PDEVICE_EXTENSION DeviceExt,
     PFILE_NAME_INFORMATION NameInfo,
     PULONG BufferLength)
 {
     ULONG BytesToCopy;
 
     UNREFERENCED_PARAMETER(FileObject);
-    UNREFERENCED_PARAMETER(DeviceObject);
+    UNREFERENCED_PARAMETER(DeviceExt);
 
     ASSERT(NameInfo != NULL);
     ASSERT(FCB != NULL);
@@ -887,6 +1010,7 @@ static
 NTSTATUS
 VfatGetInternalInformation(
     PVFATFCB Fcb,
+    PDEVICE_EXTENSION DeviceExt,
     PFILE_INTERNAL_INFORMATION InternalInfo,
     PULONG BufferLength)
 {
@@ -895,8 +1019,9 @@ VfatGetInternalInformation(
 
     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;
+
+    InternalInfo->IndexNumber.QuadPart = (LONGLONG)vfatDirEntryGetFirstCluster(DeviceExt, &Fcb->entry) * DeviceExt->FatInfo.BytesPerCluster;
+
     *BufferLength -= sizeof(FILE_INTERNAL_INFORMATION);
     return STATUS_SUCCESS;
 }
@@ -919,7 +1044,7 @@ VfatGetNetworkOpenInformation(
     if (*BufferLength < sizeof(FILE_NETWORK_OPEN_INFORMATION))
         return(STATUS_BUFFER_OVERFLOW);
 
-    if (Fcb->Flags & FCB_IS_FATX_ENTRY)
+    if (vfatVolumeIsFatX(DeviceExt))
     {
         FsdDosDateTimeToSystemTime(DeviceExt,
                                    Fcb->entry.FatX.CreationDate,
@@ -985,12 +1110,10 @@ NTSTATUS
 VfatGetEaInformation(
     PFILE_OBJECT FileObject,
     PVFATFCB Fcb,
-    PDEVICE_OBJECT DeviceObject,
+    PDEVICE_EXTENSION DeviceExt,
     PFILE_EA_INFORMATION Info,
     PULONG BufferLength)
 {
-    PDEVICE_EXTENSION DeviceExt = DeviceObject->DeviceExtension;
-
     UNREFERENCED_PARAMETER(FileObject);
     UNREFERENCED_PARAMETER(Fcb);
 
@@ -1015,43 +1138,39 @@ NTSTATUS
 VfatGetAllInformation(
     PFILE_OBJECT FileObject,
     PVFATFCB Fcb,
-    PDEVICE_OBJECT DeviceObject,
+    PDEVICE_EXTENSION DeviceExt,
     PFILE_ALL_INFORMATION Info,
     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;
+
+    *BufferLength -= (sizeof(FILE_ACCESS_INFORMATION) + sizeof(FILE_MODE_INFORMATION) + sizeof(FILE_ALIGNMENT_INFORMATION));
 
     /* Basic Information */
-    Status = VfatGetBasicInformation(FileObject, Fcb, DeviceObject, &Info->BasicInformation, BufferLength);
+    Status = VfatGetBasicInformation(FileObject, Fcb, DeviceExt, &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);
+    Status = VfatGetInternalInformation(Fcb, DeviceExt, &Info->InternalInformation, BufferLength);
     if (!NT_SUCCESS(Status)) return Status;
     /* EA Information */
-    Info->EaInformation.EaSize = 0;
-    /* Access Information: The IO-Manager adds this information */
+    Status = VfatGetEaInformation(FileObject, Fcb, DeviceExt, &Info->EaInformation, BufferLength);
+    if (!NT_SUCCESS(Status)) return Status;
     /* Position Information */
-    Status = VfatGetPositionInformation(FileObject, Fcb, DeviceObject, &Info->PositionInformation, BufferLength);
+    Status = VfatGetPositionInformation(FileObject, Fcb, DeviceExt, &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));
+    Status = VfatGetNameInformation(FileObject, Fcb, DeviceExt, &Info->NameInformation, BufferLength);
 
-    return STATUS_SUCCESS;
+    return Status;
 }
 
 static
@@ -1060,11 +1179,12 @@ UpdateFileSize(
     PFILE_OBJECT FileObject,
     PVFATFCB Fcb,
     ULONG Size,
-    ULONG ClusterSize)
+    ULONG ClusterSize,
+    BOOLEAN IsFatX)
 {
     if (Size > 0)
     {
-        Fcb->RFCB.AllocationSize.QuadPart = ROUND_UP(Size, ClusterSize);
+        Fcb->RFCB.AllocationSize.QuadPart = ROUND_UP_64(Size, ClusterSize);
     }
     else
     {
@@ -1072,7 +1192,7 @@ UpdateFileSize(
     }
     if (!vfatFCBIsDirectory(Fcb))
     {
-        if (Fcb->Flags & FCB_IS_FATX_ENTRY)
+        if (IsFatX)
             Fcb->entry.FatX.FileSize = Size;
         else
             Fcb->entry.Fat.FileSize = Size;
@@ -1097,12 +1217,12 @@ VfatSetAllocationSizeInformation(
     ULONG ClusterSize = DeviceExt->FatInfo.BytesPerCluster;
     ULONG NewSize = AllocationSize->u.LowPart;
     ULONG NCluster;
-    BOOLEAN AllocSizeChanged = FALSE;
+    BOOLEAN AllocSizeChanged = FALSE, IsFatX = vfatVolumeIsFatX(DeviceExt);
 
     DPRINT("VfatSetAllocationSizeInformation(File <%wZ>, AllocationSize %d %u)\n",
            &Fcb->PathNameU, AllocationSize->HighPart, AllocationSize->LowPart);
 
-    if (Fcb->Flags & FCB_IS_FATX_ENTRY)
+    if (IsFatX)
         OldSize = Fcb->entry.FatX.FileSize;
     else
         OldSize = Fcb->entry.Fat.FileSize;
@@ -1154,7 +1274,7 @@ VfatSetAllocationSizeInformation(
                 return STATUS_DISK_FULL;
             }
 
-            if (Fcb->Flags & FCB_IS_FATX_ENTRY)
+            if (IsFatX)
             {
                 Fcb->entry.FatX.FirstCluster = FirstCluster;
             }
@@ -1224,7 +1344,7 @@ VfatSetAllocationSizeInformation(
                 return STATUS_DISK_FULL;
             }
         }
-        UpdateFileSize(FileObject, Fcb, NewSize, ClusterSize);
+        UpdateFileSize(FileObject, Fcb, NewSize, ClusterSize, vfatVolumeIsFatX(DeviceExt));
     }
     else if (NewSize + ClusterSize <= Fcb->RFCB.AllocationSize.u.LowPart)
     {
@@ -1240,7 +1360,7 @@ VfatSetAllocationSizeInformation(
         AllocSizeChanged = TRUE;
         /* FIXME: Use the cached cluster/offset better way. */
         Fcb->LastCluster = Fcb->LastOffset = 0;
-        UpdateFileSize(FileObject, Fcb, NewSize, ClusterSize);
+        UpdateFileSize(FileObject, Fcb, NewSize, ClusterSize, vfatVolumeIsFatX(DeviceExt));
         if (NewSize > 0)
         {
             Status = OffsetToCluster(DeviceExt, FirstCluster,
@@ -1254,7 +1374,7 @@ VfatSetAllocationSizeInformation(
         }
         else
         {
-            if (Fcb->Flags & FCB_IS_FATX_ENTRY)
+            if (IsFatX)
             {
                 Fcb->entry.FatX.FirstCluster = 0;
             }
@@ -1281,17 +1401,24 @@ VfatSetAllocationSizeInformation(
             WriteCluster(DeviceExt, Cluster, 0);
             Cluster = NCluster;
         }
+
+        if (DeviceExt->FatInfo.FatType == FAT32)
+        {
+            FAT32UpdateFreeClustersCount(DeviceExt);
+        }
     }
     else
     {
-        UpdateFileSize(FileObject, Fcb, NewSize, ClusterSize);
+        UpdateFileSize(FileObject, Fcb, NewSize, ClusterSize, vfatVolumeIsFatX(DeviceExt));
     }
 
     /* Update the on-disk directory entry */
     Fcb->Flags |= FCB_IS_DIRTY;
     if (AllocSizeChanged)
     {
-        VfatUpdateEntry(Fcb);
+        VfatUpdateEntry(DeviceExt, Fcb);
+
+        vfatReportChange(DeviceExt, Fcb, FILE_NOTIFY_CHANGE_SIZE, FILE_ACTION_MODIFIED);
     }
     return STATUS_SUCCESS;
 }
@@ -1304,7 +1431,7 @@ VfatQueryInformation(
     PVFAT_IRP_CONTEXT IrpContext)
 {
     FILE_INFORMATION_CLASS FileInformationClass;
-    PVFATFCB FCB = NULL;
+    PVFATFCB FCB;
 
     NTSTATUS Status = STATUS_SUCCESS;
     PVOID SystemBuffer;
@@ -1320,16 +1447,22 @@ 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;
 
-    if (!(FCB->Flags & FCB_IS_PAGE_FILE))
+    if (!BooleanFlagOn(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);
         }
     }
 
@@ -1344,7 +1477,7 @@ VfatQueryInformation(
         case FilePositionInformation:
             Status = VfatGetPositionInformation(IrpContext->FileObject,
                                                 FCB,
-                                                IrpContext->DeviceObject,
+                                                IrpContext->DeviceExt,
                                                 SystemBuffer,
                                                 &BufferLength);
             break;
@@ -1352,7 +1485,7 @@ VfatQueryInformation(
         case FileBasicInformation:
             Status = VfatGetBasicInformation(IrpContext->FileObject,
                                              FCB,
-                                             IrpContext->DeviceObject,
+                                             IrpContext->DeviceExt,
                                              SystemBuffer,
                                              &BufferLength);
             break;
@@ -1360,13 +1493,14 @@ VfatQueryInformation(
         case FileNameInformation:
             Status = VfatGetNameInformation(IrpContext->FileObject,
                                             FCB,
-                                            IrpContext->DeviceObject,
+                                            IrpContext->DeviceExt,
                                             SystemBuffer,
                                             &BufferLength);
             break;
 
         case FileInternalInformation:
             Status = VfatGetInternalInformation(FCB,
+                                                IrpContext->DeviceExt,
                                                 SystemBuffer,
                                                 &BufferLength);
             break;
@@ -1381,7 +1515,7 @@ VfatQueryInformation(
         case FileAllInformation:
             Status = VfatGetAllInformation(IrpContext->FileObject,
                                            FCB,
-                                           IrpContext->DeviceObject,
+                                           IrpContext->DeviceExt,
                                            SystemBuffer,
                                            &BufferLength);
             break;
@@ -1389,7 +1523,7 @@ VfatQueryInformation(
         case FileEaInformation:
             Status = VfatGetEaInformation(IrpContext->FileObject,
                                           FCB,
-                                          IrpContext->DeviceObject,
+                                          IrpContext->DeviceExt,
                                           SystemBuffer,
                                           &BufferLength);
             break;
@@ -1402,19 +1536,16 @@ VfatQueryInformation(
             Status = STATUS_INVALID_PARAMETER;
     }
 
-    if (!(FCB->Flags & FCB_IS_PAGE_FILE))
+    if (!BooleanFlagOn(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;
 }
@@ -1427,9 +1558,10 @@ VfatSetInformation(
     PVFAT_IRP_CONTEXT IrpContext)
 {
     FILE_INFORMATION_CLASS FileInformationClass;
-    PVFATFCB FCB = NULL;
+    PVFATFCB FCB;
     NTSTATUS Status = STATUS_SUCCESS;
     PVOID SystemBuffer;
+    BOOLEAN LockDir;
 
     /* PRECONDITION */
     ASSERT(IrpContext);
@@ -1448,6 +1580,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. */
@@ -1458,34 +1597,39 @@ 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");
     }
 
-    if (FileInformationClass == FileRenameInformation)
+    LockDir = FALSE;
+    if (FileInformationClass == FileRenameInformation || FileInformationClass == FileAllocationInformation ||
+        FileInformationClass == FileEndOfFileInformation || FileInformationClass == FileBasicInformation)
+    {
+        LockDir = TRUE;
+    }
+
+    if (LockDir)
     {
         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 (!BooleanFlagOn(FCB->Flags, FCB_IS_PAGE_FILE))
     {
         if (!ExAcquireResourceExclusiveLite(&FCB->MainResource,
-                                            (BOOLEAN)(IrpContext->Flags & IRPCONTEXT_CANWAIT)))
+                                            BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT)))
         {
-            if (FileInformationClass == FileRenameInformation)
+            if (LockDir)
             {
                 ExReleaseResourceLite(&((PDEVICE_EXTENSION)IrpContext->DeviceObject->DeviceExtension)->DirResource);
             }
-            return VfatQueueRequest(IrpContext);
+
+            return VfatMarkIrpContextForQueue(IrpContext);
         }
     }
 
@@ -1499,7 +1643,7 @@ VfatSetInformation(
         case FileDispositionInformation:
             Status = VfatSetDispositionInformation(IrpContext->FileObject,
                                                    FCB,
-                                                   IrpContext->DeviceObject,
+                                                   IrpContext->DeviceExt,
                                                    SystemBuffer);
             break;
 
@@ -1530,21 +1674,17 @@ VfatSetInformation(
             Status = STATUS_NOT_SUPPORTED;
     }
 
-    if (!(FCB->Flags & FCB_IS_PAGE_FILE))
+    if (!BooleanFlagOn(FCB->Flags, FCB_IS_PAGE_FILE))
     {
         ExReleaseResourceLite(&FCB->MainResource);
     }
 
-    if (FileInformationClass == FileRenameInformation)
+    if (LockDir)
     {
         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;
 }