[FASTFAT]
[reactos.git] / reactos / drivers / filesystems / fastfat / finfo.c
index a8c8e3d..cdadc87 100644 (file)
@@ -91,7 +91,7 @@ VfatGetStandardInformation(PVFATFCB FCB,
       StandardInfo->EndOfFile = FCB->RFCB.FileSize;
       StandardInfo->Directory = FALSE;
     }
-  StandardInfo->NumberOfLinks = 0;
+  StandardInfo->NumberOfLinks = 1;
   StandardInfo->DeletePending = FCB->Flags & FCB_DELETE_PENDING ? TRUE : FALSE;
 
   *BufferLength -= sizeof(FILE_STANDARD_INFORMATION);
@@ -120,6 +120,10 @@ VfatGetPositionInformation(PFILE_OBJECT FileObject,
                           PFILE_POSITION_INFORMATION PositionInfo,
                           PULONG BufferLength)
 {
+  UNREFERENCED_PARAMETER(FileObject);
+  UNREFERENCED_PARAMETER(FCB);
+  UNREFERENCED_PARAMETER(DeviceObject);
+
   DPRINT ("VfatGetPositionInformation()\n");
 
   if (*BufferLength < sizeof(FILE_POSITION_INFORMATION))
@@ -148,47 +152,72 @@ VfatSetBasicInformation(PFILE_OBJECT FileObject,
   ASSERT(NULL != DeviceExt);
   ASSERT(NULL != BasicInfo);
   /* Check volume label bit */
-  ASSERT(0 == (*FCB->Attributes & 0x08));
+  ASSERT(0 == (*FCB->Attributes & _A_VOLID));
 
   if (FCB->Flags & FCB_IS_FATX_ENTRY)
   {
-    FsdSystemTimeToDosDateTime(DeviceExt,
-                             &BasicInfo->CreationTime,
-                             &FCB->entry.FatX.CreationDate,
-                             &FCB->entry.FatX.CreationTime);
-    FsdSystemTimeToDosDateTime(DeviceExt,
-                             &BasicInfo->LastAccessTime,
-                             &FCB->entry.FatX.AccessDate,
-                             &FCB->entry.FatX.AccessTime);
-    FsdSystemTimeToDosDateTime(DeviceExt,
-                             &BasicInfo->LastWriteTime,
-                             &FCB->entry.FatX.UpdateDate,
-                             &FCB->entry.FatX.UpdateTime);
+    if (BasicInfo->CreationTime.QuadPart != 0 && BasicInfo->CreationTime.QuadPart != -1)
+    {
+      FsdSystemTimeToDosDateTime(DeviceExt,
+                                 &BasicInfo->CreationTime,
+                                 &FCB->entry.FatX.CreationDate,
+                                 &FCB->entry.FatX.CreationTime);
+    }
+
+    if (BasicInfo->LastAccessTime.QuadPart != 0 && BasicInfo->LastAccessTime.QuadPart != -1)
+    {
+      FsdSystemTimeToDosDateTime(DeviceExt,
+                                 &BasicInfo->LastAccessTime,
+                                 &FCB->entry.FatX.AccessDate,
+                                 &FCB->entry.FatX.AccessTime);
+    }
+
+    if (BasicInfo->LastWriteTime.QuadPart != 0 && BasicInfo->LastWriteTime.QuadPart != -1)
+    {
+      FsdSystemTimeToDosDateTime(DeviceExt,
+                                 &BasicInfo->LastWriteTime,
+                                 &FCB->entry.FatX.UpdateDate,
+                                 &FCB->entry.FatX.UpdateTime);
+    }
   }
   else
   {
-    FsdSystemTimeToDosDateTime(DeviceExt,
-                             &BasicInfo->CreationTime,
-                             &FCB->entry.Fat.CreationDate,
-                             &FCB->entry.Fat.CreationTime);
-    FsdSystemTimeToDosDateTime(DeviceExt,
-                             &BasicInfo->LastAccessTime,
-                             &FCB->entry.Fat.AccessDate,
-                             NULL);
-    FsdSystemTimeToDosDateTime(DeviceExt,
-                             &BasicInfo->LastWriteTime,
-                             &FCB->entry.Fat.UpdateDate,
-                             &FCB->entry.Fat.UpdateTime);
+    if (BasicInfo->CreationTime.QuadPart != 0 && BasicInfo->CreationTime.QuadPart != -1)
+    {
+      FsdSystemTimeToDosDateTime(DeviceExt,
+                                 &BasicInfo->CreationTime,
+                                 &FCB->entry.Fat.CreationDate,
+                                 &FCB->entry.Fat.CreationTime);
+    }
+
+    if (BasicInfo->LastAccessTime.QuadPart != 0 && BasicInfo->LastAccessTime.QuadPart != -1)
+    {
+      FsdSystemTimeToDosDateTime(DeviceExt,
+                                 &BasicInfo->LastAccessTime,
+                                 &FCB->entry.Fat.AccessDate,
+                                 NULL);
+    }
+
+    if (BasicInfo->LastWriteTime.QuadPart != 0 && BasicInfo->LastWriteTime.QuadPart != -1)
+    {
+      FsdSystemTimeToDosDateTime(DeviceExt,
+                                 &BasicInfo->LastWriteTime,
+                                 &FCB->entry.Fat.UpdateDate,
+                                 &FCB->entry.Fat.UpdateTime);
+    }
   }
 
-  *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);
+  if (BasicInfo->FileAttributes)
+  {
+    *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);
+  }
 
   VfatUpdateEntry(FCB);
 
@@ -203,6 +232,9 @@ VfatGetBasicInformation(PFILE_OBJECT FileObject,
                        PULONG BufferLength)
 {
   PDEVICE_EXTENSION DeviceExt;
+  
+  UNREFERENCED_PARAMETER(FileObject);
+  
   DPRINT("VfatGetBasicInformation()\n");
 
   DeviceExt = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
@@ -267,11 +299,11 @@ VfatSetDispositionInformation(PFILE_OBJECT FileObject,
                              PDEVICE_OBJECT DeviceObject,
                              PFILE_DISPOSITION_INFORMATION DispositionInfo)
 {
-#ifdef DBG
+#if DBG
    PDEVICE_EXTENSION DeviceExt = DeviceObject->DeviceExtension;
 #endif
 
-   DPRINT ("FsdSetDispositionInformation()\n");
+   DPRINT ("FsdSetDispositionInformation(<%wZ>, Delete %d)\n", &FCB->PathNameU, DispositionInfo->DeleteFile);
 
    ASSERT(DeviceExt != NULL);
    ASSERT(DeviceExt->FatInfo.BytesPerCluster != 0);
@@ -338,15 +370,37 @@ VfatGetNameInformation(PFILE_OBJECT FileObject,
  * FUNCTION: Retrieve the file name information
  */
 {
+  ULONG BytesToCopy;
+
+  UNREFERENCED_PARAMETER(FileObject);
+  UNREFERENCED_PARAMETER(DeviceObject);
+
   ASSERT(NameInfo != NULL);
   ASSERT(FCB != NULL);
 
-  NameInfo->FileNameLength = FCB->PathNameU.Length;
-  if (*BufferLength < FIELD_OFFSET(FILE_NAME_INFORMATION, FileName[0]) + FCB->PathNameU.Length)
+  /* If buffer can't hold at least the file name length, bail out */
+  if (*BufferLength < FIELD_OFFSET(FILE_NAME_INFORMATION, FileName[0]))
     return STATUS_BUFFER_OVERFLOW;
 
-  RtlCopyMemory(NameInfo->FileName, FCB->PathNameU.Buffer, FCB->PathNameU.Length);
+  /* Save file name length, and as much file len, as buffer length allows */
+  NameInfo->FileNameLength = FCB->PathNameU.Length;
+
+  /* Calculate amount of bytes to copy not to overflow the buffer */
+  BytesToCopy = min(FCB->PathNameU.Length,
+                    *BufferLength - FIELD_OFFSET(FILE_NAME_INFORMATION, FileName[0]));
 
+  /* Fill in the bytes */
+  RtlCopyMemory(NameInfo->FileName, FCB->PathNameU.Buffer, BytesToCopy);
+
+  /* Check if we could write more but are not able to */
+  if (*BufferLength < FCB->PathNameU.Length + (ULONG)FIELD_OFFSET(FILE_NAME_INFORMATION, FileName[0]))
+  {
+    /* Return number of bytes written */
+    *BufferLength -= FIELD_OFFSET(FILE_NAME_INFORMATION, FileName[0]) + BytesToCopy;
+    return STATUS_BUFFER_OVERFLOW;
+  }
+
+  /* We filled up as many bytes, as needed */
   *BufferLength -= (FIELD_OFFSET(FILE_NAME_INFORMATION, FileName[0]) + FCB->PathNameU.Length);
 
   return STATUS_SUCCESS;
@@ -452,6 +506,9 @@ VfatGetEaInformation(PFILE_OBJECT FileObject,
 {
     PDEVICE_EXTENSION DeviceExt = DeviceObject->DeviceExtension;
 
+    UNREFERENCED_PARAMETER(FileObject);
+    UNREFERENCED_PARAMETER(Fcb);
+
     /* FIXME - use SEH to access the buffer! */
     Info->EaSize = 0;
     *BufferLength -= sizeof(*Info);
@@ -530,10 +587,7 @@ static VOID UpdateFileSize(PFILE_OBJECT FileObject, PVFATFCB Fcb, ULONG Size, UL
    Fcb->RFCB.FileSize.QuadPart = Size;
    Fcb->RFCB.ValidDataLength.QuadPart = Size;
 
-   if (FileObject->SectionObjectPointer->SharedCacheMap != NULL)
-   {
-      CcSetFileSizes(FileObject, (PCC_FILE_SIZES)&Fcb->RFCB.AllocationSize);
-   }
+   CcSetFileSizes(FileObject, (PCC_FILE_SIZES)&Fcb->RFCB.AllocationSize);
 }
 
 NTSTATUS
@@ -551,7 +605,8 @@ VfatSetAllocationSizeInformation(PFILE_OBJECT FileObject,
   ULONG NCluster;
   BOOLEAN AllocSizeChanged = FALSE;
 
-  DPRINT("VfatSetAllocationSizeInformation()\n");
+  DPRINT("VfatSetAllocationSizeInformation(File <%wZ>, AllocationSize %d %d)\n", &Fcb->PathNameU,
+      AllocationSize->HighPart, AllocationSize->LowPart);
 
   if (Fcb->Flags & FCB_IS_FATX_ENTRY)
     OldSize = Fcb->entry.FatX.FileSize;
@@ -620,7 +675,6 @@ VfatSetAllocationSizeInformation(PFILE_OBJECT FileObject,
     }
     else
     {
-#if 0 /* FIXME */
        if (Fcb->LastCluster > 0)
        {
           if (Fcb->RFCB.AllocationSize.u.LowPart - ClusterSize == Fcb->LastOffset)
@@ -646,23 +700,14 @@ VfatSetAllocationSizeInformation(PFILE_OBJECT FileObject,
           return Status;
        }
 
-       if (Fcb->LastCluster == 0)
-       {
-          Fcb->LastCluster = Cluster;
-          Fcb->LastOffset = Fcb->RFCB.AllocationSize.u.LowPart - ClusterSize;
-       }
+       Fcb->LastCluster = Cluster;
+       Fcb->LastOffset = Fcb->RFCB.AllocationSize.u.LowPart - ClusterSize;
 
        /* FIXME: Check status */
        /* Cluster points now to the last cluster within the chain */
        Status = OffsetToCluster(DeviceExt, Cluster,
                                ROUND_DOWN(NewSize - 1, ClusterSize) - Fcb->LastOffset,
                                 &NCluster, TRUE);
-#else
-       Status = OffsetToCluster(DeviceExt, FirstCluster,
-                               ROUND_DOWN(NewSize - 1, ClusterSize),
-                                &Cluster, TRUE);
-       NCluster = Cluster;
-#endif
        if (NCluster == 0xffffffff || !NT_SUCCESS(Status))
        {
          /* disk is full */
@@ -683,6 +728,17 @@ VfatSetAllocationSizeInformation(PFILE_OBJECT FileObject,
   }
   else if (NewSize + ClusterSize <= Fcb->RFCB.AllocationSize.u.LowPart)
   {
+
+    DPRINT("Check for the ability to set file size\n");
+    if (!MmCanFileBeTruncated
+      (FileObject->SectionObjectPointer,
+      (PLARGE_INTEGER)AllocationSize))
+    {
+      DPRINT("Couldn't set file size!\n");
+      return STATUS_USER_MAPPED_FILE;
+    }
+    DPRINT("Can set file size\n");
+
     AllocSizeChanged = TRUE;
     /* FIXME: Use the cached cluster/offset better way. */
     Fcb->LastCluster = Fcb->LastOffset = 0;
@@ -748,7 +804,7 @@ NTSTATUS VfatQueryInformation(PVFAT_IRP_CONTEXT IrpContext)
   FILE_INFORMATION_CLASS FileInformationClass;
   PVFATFCB FCB = NULL;
 
-  NTSTATUS RC = STATUS_SUCCESS;
+  NTSTATUS Status = STATUS_SUCCESS;
   PVOID SystemBuffer;
   ULONG BufferLength;
 
@@ -779,44 +835,44 @@ NTSTATUS VfatQueryInformation(PVFAT_IRP_CONTEXT IrpContext)
   switch (FileInformationClass)
     {
     case FileStandardInformation:
-      RC = VfatGetStandardInformation(FCB,
+      Status = VfatGetStandardInformation(FCB,
                                      SystemBuffer,
                                      &BufferLength);
       break;
     case FilePositionInformation:
-      RC = VfatGetPositionInformation(IrpContext->FileObject,
+      Status = VfatGetPositionInformation(IrpContext->FileObject,
                                      FCB,
                                      IrpContext->DeviceObject,
                                      SystemBuffer,
                                      &BufferLength);
       break;
     case FileBasicInformation:
-      RC = VfatGetBasicInformation(IrpContext->FileObject,
+      Status = VfatGetBasicInformation(IrpContext->FileObject,
                                   FCB,
                                   IrpContext->DeviceObject,
                                   SystemBuffer,
                                   &BufferLength);
       break;
     case FileNameInformation:
-      RC = VfatGetNameInformation(IrpContext->FileObject,
+      Status = VfatGetNameInformation(IrpContext->FileObject,
                                  FCB,
                                  IrpContext->DeviceObject,
                                  SystemBuffer,
                                  &BufferLength);
       break;
     case FileInternalInformation:
-      RC = VfatGetInternalInformation(FCB,
+      Status = VfatGetInternalInformation(FCB,
                                      SystemBuffer,
                                      &BufferLength);
       break;
     case FileNetworkOpenInformation:
-      RC = VfatGetNetworkOpenInformation(FCB,
+      Status = VfatGetNetworkOpenInformation(FCB,
                                         IrpContext->DeviceExt,
                                         SystemBuffer,
                                         &BufferLength);
       break;
     case FileAllInformation:
-      RC = VfatGetAllInformation(IrpContext->FileObject,
+      Status = VfatGetAllInformation(IrpContext->FileObject,
                                 FCB,
                                 IrpContext->DeviceObject,
                                 SystemBuffer,
@@ -824,7 +880,7 @@ NTSTATUS VfatQueryInformation(PVFAT_IRP_CONTEXT IrpContext)
       break;
 
     case FileEaInformation:
-      RC = VfatGetEaInformation(IrpContext->FileObject,
+      Status = VfatGetEaInformation(IrpContext->FileObject,
                                FCB,
                                IrpContext->DeviceObject,
                                SystemBuffer,
@@ -832,18 +888,18 @@ NTSTATUS VfatQueryInformation(PVFAT_IRP_CONTEXT IrpContext)
       break;
 
     case FileAlternateNameInformation:
-      RC = STATUS_NOT_IMPLEMENTED;
+      Status = STATUS_NOT_IMPLEMENTED;
       break;
     default:
-      RC = STATUS_INVALID_PARAMETER;
+      Status = STATUS_INVALID_PARAMETER;
     }
 
   if (!(FCB->Flags & FCB_IS_PAGE_FILE))
   {
      ExReleaseResourceLite(&FCB->MainResource);
   }
-  IrpContext->Irp->IoStatus.Status = RC;
-  if (NT_SUCCESS(RC))
+  IrpContext->Irp->IoStatus.Status = Status;
+  if (NT_SUCCESS(Status) || Status == STATUS_BUFFER_OVERFLOW)
     IrpContext->Irp->IoStatus.Information =
       IrpContext->Stack->Parameters.QueryFile.Length - BufferLength;
   else
@@ -851,7 +907,7 @@ NTSTATUS VfatQueryInformation(PVFAT_IRP_CONTEXT IrpContext)
   IoCompleteRequest(IrpContext->Irp, IO_NO_INCREMENT);
   VfatFreeIrpContext(IrpContext);
 
-  return RC;
+  return Status;
 }
 
 NTSTATUS VfatSetInformation(PVFAT_IRP_CONTEXT IrpContext)
@@ -882,6 +938,26 @@ NTSTATUS VfatSetInformation(PVFAT_IRP_CONTEXT IrpContext)
   DPRINT("FileInformationClass %d\n", FileInformationClass);
   DPRINT("SystemBuffer %p\n", SystemBuffer);
 
+  /* 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. */
+  if (FileInformationClass == FileEndOfFileInformation)
+  {
+      DPRINT("Check for the ability to set file size\n");
+      if (!MmCanFileBeTruncated
+         (IrpContext->FileObject->SectionObjectPointer,
+          (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 (!(FCB->Flags & FCB_IS_PAGE_FILE))
     {
       if (!ExAcquireResourceExclusiveLite(&FCB->MainResource,