update for HEAD-2003021201
[reactos.git] / drivers / fs / vfat / finfo.c
index 2917a50..cccbfd6 100644 (file)
 
 static NTSTATUS
 VfatGetStandardInformation(PVFATFCB FCB,
-                          PDEVICE_OBJECT DeviceObject,
                           PFILE_STANDARD_INFORMATION StandardInfo,
                           PULONG BufferLength)
 /*
  * FUNCTION: Retrieve the standard file information
  */
 {
-  PDEVICE_EXTENSION DeviceExtension;
 
   if (*BufferLength < sizeof(FILE_STANDARD_INFORMATION))
     return STATUS_BUFFER_OVERFLOW;
 
-  DeviceExtension = DeviceObject->DeviceExtension;
   /* PRECONDITION */
-  assert (DeviceExtension != NULL);
-  assert (DeviceExtension->FatInfo.BytesPerCluster != 0);
   assert (StandardInfo != NULL);
   assert (FCB != NULL);
 
@@ -56,8 +51,6 @@ VfatGetStandardInformation(PVFATFCB FCB,
 
 static NTSTATUS
 VfatSetPositionInformation(PFILE_OBJECT FileObject,
-                          PVFATFCB FCB,
-                          PDEVICE_OBJECT DeviceObject,
                           PFILE_POSITION_INFORMATION PositionInfo)
 {
   DPRINT ("FsdSetPositionInformation()\n");
@@ -93,6 +86,45 @@ VfatGetPositionInformation(PFILE_OBJECT FileObject,
 }
 
 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->entry.Attrib & 0x08));
+
+  FsdFileTimeToDosDateTime(&(BasicInfo->CreationTime),
+                           &(FCB->entry.CreationDate),  
+                           &(FCB->entry.CreationTime));
+  FsdFileTimeToDosDateTime(&(BasicInfo->LastAccessTime),
+                           &(FCB->entry.AccessDate),  
+                           NULL);
+  FsdFileTimeToDosDateTime(&(BasicInfo->LastWriteTime),
+                           &(FCB->entry.UpdateDate),
+                           &(FCB->entry.UpdateTime));
+
+  FCB->entry.Attrib = (FCB->entry.Attrib &
+                       (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->entry.Attrib);
+
+  VfatUpdateEntry(DeviceExt, FileObject);
+
+  return(STATUS_SUCCESS);
+}
+
+static NTSTATUS
 VfatGetBasicInformation(PFILE_OBJECT FileObject,
                        PVFATFCB FCB,
                        PDEVICE_OBJECT DeviceObject,
@@ -113,12 +145,19 @@ VfatGetBasicInformation(PFILE_OBJECT FileObject,
   FsdDosDateTimeToFileTime(FCB->entry.UpdateDate,
                           FCB->entry.UpdateTime,
                           &BasicInfo->LastWriteTime);
-  FsdDosDateTimeToFileTime(FCB->entry.UpdateDate,
-                          FCB->entry.UpdateTime,
-                          &BasicInfo->ChangeTime);
+  BasicInfo->ChangeTime = BasicInfo->LastWriteTime;
 
   BasicInfo->FileAttributes = FCB->entry.Attrib;
-  DPRINT("Getting attributes %x\n", BasicInfo->FileAttributes);
+  /* Synthesize FILE_ATTRIBUTE_NORMAL */
+  if (0 == (BasicInfo->FileAttributes & (FILE_ATTRIBUTE_DIRECTORY |
+                                         FILE_ATTRIBUTE_ARCHIVE |
+                                         FILE_ATTRIBUTE_SYSTEM |
+                                         FILE_ATTRIBUTE_HIDDEN |
+                                         FILE_ATTRIBUTE_READONLY)))
+  {
+    BasicInfo->FileAttributes |= FILE_ATTRIBUTE_NORMAL;
+  }
+  DPRINT("Getting attributes 0x%02x\n", BasicInfo->FileAttributes);
 
   *BufferLength -= sizeof(FILE_BASIC_INFORMATION);
   return(STATUS_SUCCESS);
@@ -154,18 +193,29 @@ VfatSetDispositionInformation(PFILE_OBJECT FileObject,
   }
   if (DispositionInfo->DoDeleteFile)
   {
-    KeAcquireSpinLock (&DeviceExt->FcbListLock, &oldIrql);
-    count = FCB->RefCount;
-    if (FCB->RefCount > 1)
-      Status = STATUS_ACCESS_DENIED;
+    if (MmFlushImageSection (FileObject->SectionObjectPointers, MmFlushForDelete))
+    {
+      KeAcquireSpinLock (&DeviceExt->FcbListLock, &oldIrql);
+      count = FCB->RefCount;
+      if (FCB->RefCount > 1)
+      {
+       DPRINT1("%d %x\n", FCB->RefCount, CcGetFileObjectFromSectionPtrs(FileObject->SectionObjectPointers));
+        Status = STATUS_ACCESS_DENIED;
+      }
+      else
+      {
+        FCB->Flags |= FCB_DELETE_PENDING;
+        FileObject->DeletePending = TRUE;
+      }
+      KeReleaseSpinLock(&DeviceExt->FcbListLock, oldIrql);
+    }
     else
     {
-      FCB->Flags |= FCB_DELETE_PENDING;
-      FileObject->DeletePending = TRUE;
+      DPRINT1("MmFlushImageSection returned FALSE\n");
+      Status = STATUS_ACCESS_DENIED;
     }
-    KeReleaseSpinLock(&DeviceExt->FcbListLock, oldIrql);
     DPRINT("RefCount:%d\n", count);
-    if (NT_SUCCESS(Status) && vfatFCBIsDirectory(DeviceExt, FCB))
+    if (NT_SUCCESS(Status) && vfatFCBIsDirectory(FCB))
     {
       memset (&tmpFcb, 0, sizeof(VFATFCB));
       tmpFcb.ObjectName = tmpFcb.PathName;
@@ -208,16 +258,13 @@ VfatGetNameInformation(PFILE_OBJECT FileObject,
   assert (FCB != NULL);
 
   NameLength = wcslen(FCB->PathName) * sizeof(WCHAR);
-  if (*BufferLength < sizeof(FILE_NAME_INFORMATION) + NameLength)
+  if (*BufferLength < sizeof(FILE_NAME_INFORMATION) + NameLength + sizeof(WCHAR))
     return STATUS_BUFFER_OVERFLOW;
 
   NameInfo->FileNameLength = NameLength;
-  memcpy(NameInfo->FileName,
-        FCB->PathName,
-        NameLength + sizeof(WCHAR));
+  memcpy(NameInfo->FileName, FCB->PathName, NameLength + sizeof(WCHAR));
 
-  *BufferLength -=
-    (sizeof(FILE_NAME_INFORMATION) + NameLength + sizeof(WCHAR));
+  *BufferLength -= (sizeof(FILE_NAME_INFORMATION) + NameLength + sizeof(WCHAR));
 
   return STATUS_SUCCESS;
 }
@@ -262,9 +309,7 @@ VfatGetNetworkOpenInformation(PVFATFCB Fcb,
   FsdDosDateTimeToFileTime(Fcb->entry.UpdateDate,
                           Fcb->entry.UpdateTime,
                           &NetworkInfo->LastWriteTime);
-  FsdDosDateTimeToFileTime(Fcb->entry.UpdateDate,
-                          Fcb->entry.UpdateTime,
-                          &NetworkInfo->ChangeTime);
+  NetworkInfo->ChangeTime = NetworkInfo->LastWriteTime;
   NetworkInfo->AllocationSize = Fcb->RFCB.AllocationSize;
   NetworkInfo->EndOfFile = Fcb->RFCB.FileSize;
   NetworkInfo->FileAttributes = Fcb->entry.Attrib;
@@ -289,7 +334,7 @@ VfatGetAllInformation(PFILE_OBJECT FileObject,
   assert (Fcb);
 
   NameLength = wcslen(Fcb->PathName) * sizeof(WCHAR);
-  if (*BufferLength < sizeof(FILE_ALL_INFORMATION) + NameLength)
+  if (*BufferLength < sizeof(FILE_ALL_INFORMATION) + NameLength + sizeof(WCHAR))
     return(STATUS_BUFFER_OVERFLOW);
 
   /* Basic Information */
@@ -302,9 +347,7 @@ VfatGetAllInformation(PFILE_OBJECT FileObject,
   FsdDosDateTimeToFileTime(Fcb->entry.UpdateDate,
                           Fcb->entry.UpdateTime,
                           &Info->BasicInformation.LastWriteTime);
-  FsdDosDateTimeToFileTime(Fcb->entry.UpdateDate,
-                          Fcb->entry.UpdateTime,
-                          &Info->BasicInformation.ChangeTime);
+  Info->BasicInformation.ChangeTime = Info->BasicInformation.LastWriteTime;
   Info->BasicInformation.FileAttributes = Fcb->entry.Attrib;
 
   /* Standard Information */
@@ -335,15 +378,36 @@ VfatGetAllInformation(PFILE_OBJECT FileObject,
 
   /* Name Information */
   Info->NameInformation.FileNameLength = NameLength;
-  RtlCopyMemory(Info->NameInformation.FileName,
-               Fcb->PathName,
-               NameLength + sizeof(WCHAR));
+  RtlCopyMemory(Info->NameInformation.FileName, Fcb->PathName, NameLength + sizeof(WCHAR));
 
   *BufferLength -= (sizeof(FILE_ALL_INFORMATION) + NameLength + sizeof(WCHAR));
 
   return STATUS_SUCCESS;
 }
 
+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 = 0LL;
+   }
+   if (!vfatFCBIsDirectory(Fcb))
+   {
+      Fcb->entry.FileSize = Size;  
+   }
+   Fcb->RFCB.FileSize.QuadPart = Size;
+   Fcb->RFCB.ValidDataLength.QuadPart = Size;
+
+   if (FileObject->SectionObjectPointers->SharedCacheMap != NULL)
+   {
+      CcSetFileSizes(FileObject, (PCC_FILE_SIZES)&Fcb->RFCB.AllocationSize);
+   }
+}
+
 NTSTATUS
 VfatSetAllocationSizeInformation(PFILE_OBJECT FileObject, 
                                 PVFATFCB Fcb,
@@ -380,7 +444,7 @@ VfatSetAllocationSizeInformation(PFILE_OBJECT FileObject,
       Status = NextCluster (DeviceExt, Fcb, FirstCluster, &FirstCluster, TRUE);
       if (!NT_SUCCESS(Status))
       {
-       DPRINT1("NextCluster failed.\n");
+       DPRINT1("NextCluster failed. Status = %x\n", Status);
        return Status;
       }
       if (FirstCluster == 0xffffffff)
@@ -390,13 +454,14 @@ VfatSetAllocationSizeInformation(PFILE_OBJECT FileObject,
       Status = OffsetToCluster(DeviceExt, Fcb, FirstCluster, 
                 ROUND_DOWN(NewSize - 1, ClusterSize),
                  &NCluster, TRUE);
-      if (NCluster == 0xffffffff)
+      if (NCluster == 0xffffffff || !NT_SUCCESS(Status))
       {
         /* disk is full */
          NCluster = Cluster = FirstCluster;
-         while (Cluster != 0xffffffff)
+        Status = STATUS_SUCCESS;
+         while (NT_SUCCESS(Status) && Cluster != 0xffffffff && Cluster > 1)
         {
-           NextCluster (DeviceExt, Fcb, Cluster, &NCluster, FALSE);
+           Status = NextCluster (DeviceExt, Fcb, FirstCluster, &NCluster, FALSE);
             WriteCluster (DeviceExt, Cluster, 0);
            Cluster = NCluster;
         }
@@ -410,67 +475,61 @@ VfatSetAllocationSizeInformation(PFILE_OBJECT FileObject,
        Status = OffsetToCluster(DeviceExt, Fcb, FirstCluster, 
                  Fcb->RFCB.AllocationSize.u.LowPart - ClusterSize,
                  &Cluster, FALSE);
+       /* FIXME: Check status */
        /* Cluster points now to the last cluster within the chain */
        Status = OffsetToCluster(DeviceExt, Fcb, FirstCluster, 
                 ROUND_DOWN(NewSize - 1, ClusterSize),
                  &NCluster, TRUE);
-       if (NCluster == 0xffffffff)
+       if (NCluster == 0xffffffff || !NT_SUCCESS(Status))
        {
          /* disk is full */
          NCluster = Cluster; 
-          NextCluster (DeviceExt, Fcb, Cluster, &NCluster, FALSE);
+          Status = NextCluster (DeviceExt, Fcb, FirstCluster, &NCluster, FALSE);
          WriteCluster(DeviceExt, Cluster, 0xffffffff);
          Cluster = NCluster;
-          while (Cluster != 0xffffffff)
+          while (NT_SUCCESS(Status) && Cluster != 0xffffffff && Cluster > 1)
          {
-            NextCluster (DeviceExt, Fcb, Cluster, &NCluster, FALSE);
-             WriteCluster (DeviceExt, Cluster, 0);
-            Cluster = NCluster;
+           Status = NextCluster (DeviceExt, Fcb, FirstCluster, &NCluster, FALSE);
+            WriteCluster (DeviceExt, Cluster, 0);
+           Cluster = NCluster;
          }
          return STATUS_DISK_FULL;
        }
     }
+    UpdateFileSize(FileObject, Fcb, NewSize, ClusterSize);
   }
-  else if (NewSize <= Fcb->RFCB.AllocationSize.u.LowPart - ClusterSize)
+  else if (NewSize + ClusterSize <= Fcb->RFCB.AllocationSize.u.LowPart)
   {
-     if (NewSize > 0)
-     {
-       Status = OffsetToCluster(DeviceExt, Fcb, Cluster, 
+    UpdateFileSize(FileObject, Fcb, NewSize, ClusterSize);
+    if (NewSize > 0)
+    {
+      Status = OffsetToCluster(DeviceExt, Fcb, Cluster, 
                  ROUND_DOWN(NewSize - 1, ClusterSize),
                  &Cluster, FALSE);
 
-     }
-     NCluster = Cluster;
-     Status = NextCluster (DeviceExt, Fcb, Cluster, &NCluster, FALSE);
-     WriteCluster(DeviceExt, Cluster, 0xffffffff);
-     Cluster = NCluster;
-     while (Cluster != 0xffffffff)
-     {
-        NextCluster (DeviceExt, Fcb, Cluster, &NCluster, FALSE);
-        WriteCluster (DeviceExt, Cluster, 0);
-       Cluster = NCluster;
-     }
-  }
-  if (!vfatFCBIsDirectory(DeviceExt, Fcb))
-  {
-    Fcb->entry.FileSize = NewSize;  
-  }
-  if (NewSize > 0)
-  {
-    Fcb->RFCB.AllocationSize.QuadPart = ROUND_UP(NewSize - 1, ClusterSize);
+      NCluster = Cluster;
+      Status = NextCluster (DeviceExt, Fcb, FirstCluster, &NCluster, FALSE);
+      WriteCluster(DeviceExt, Cluster, 0xffffffff);
+      Cluster = NCluster;
+    }
+    else
+    {
+      Fcb->entry.FirstCluster = 0;
+      Fcb->entry.FirstClusterHigh = 0;
+
+      NCluster = Cluster = FirstCluster;
+      Status = STATUS_SUCCESS;
+    }
+    while (NT_SUCCESS(Status) && 0xffffffff != Cluster && Cluster > 1)
+    {
+       Status = NextCluster (DeviceExt, Fcb, FirstCluster, &NCluster, FALSE);
+       WriteCluster (DeviceExt, Cluster, 0);
+       Cluster = NCluster;
+    }
   }
   else
   {
-    Fcb->RFCB.AllocationSize.QuadPart = 0LL;
-    Fcb->entry.FirstCluster = 0;
-    Fcb->entry.FirstClusterHigh = 0;
-  }
-  Fcb->RFCB.FileSize.QuadPart = NewSize;
-  Fcb->RFCB.ValidDataLength.QuadPart = NewSize;
-
-  if (FileObject->SectionObjectPointers->SharedCacheMap != NULL)
-  {
-     CcSetFileSizes(FileObject, (PCC_FILE_SIZES)&Fcb->RFCB.AllocationSize);
+     UpdateFileSize(FileObject, Fcb, NewSize, ClusterSize);
   }
   /* Update the on-disk directory entry */
   VfatUpdateEntry(DeviceExt, FileObject);
@@ -512,7 +571,6 @@ NTSTATUS VfatQueryInformation(PVFAT_IRP_CONTEXT IrpContext)
     {
     case FileStandardInformation:
       RC = VfatGetStandardInformation(FCB,
-                                     IrpContext->DeviceObject,
                                      SystemBuffer,
                                      &BufferLength);
       break;
@@ -621,8 +679,6 @@ NTSTATUS VfatSetInformation(PVFAT_IRP_CONTEXT IrpContext)
     {
     case FilePositionInformation:
       RC = VfatSetPositionInformation(IrpContext->FileObject,
-                                     FCB,
-                                     IrpContext->DeviceObject,
                                      SystemBuffer);
       break;
     case FileDispositionInformation:
@@ -639,6 +695,11 @@ NTSTATUS VfatSetInformation(PVFAT_IRP_CONTEXT IrpContext)
                                            (PLARGE_INTEGER)SystemBuffer);
       break;    
     case FileBasicInformation:
+      RC = VfatSetBasicInformation(IrpContext->FileObject,
+                                  FCB,
+                                  IrpContext->DeviceExt,
+                                  SystemBuffer);
+      break;
     case FileRenameInformation:
       RC = STATUS_NOT_IMPLEMENTED;
       break;