[NTFS]
authorPierre Schweitzer <pierre@reactos.org>
Sun, 2 Nov 2014 19:55:22 +0000 (19:55 +0000)
committerPierre Schweitzer <pierre@reactos.org>
Sun, 2 Nov 2014 19:55:22 +0000 (19:55 +0000)
Quickly implement NtfsReadFile().

By quickly, I mean that it works but is under optimal in many ways, and also doesn't support any caching. So, don't expect breaking performances.

BUUUUUUT... This implements reading a file on a NTFS volume on ReactOS! And it works!
Here is a picture of all the achievements of ReactOS with NTFS lately: http://www.heisspiter.net/~Pierre/rostests/NTFS_all.png
-> Volume information
-> Displaying files in explorer
-> Moving across directories
-> Reading a file (with more here)

That's all folks! (for now ;-))

svn path=/trunk/; revision=65192

reactos/drivers/filesystems/ntfs/rw.c

index ba60de0..2518ea0 100644 (file)
@@ -52,84 +52,116 @@ NtfsReadFile(PDEVICE_EXTENSION DeviceExt,
              ULONG IrpFlags,
              PULONG LengthRead)
 {
-#if 0
-  NTSTATUS Status = STATUS_SUCCESS;
-  PUCHAR TempBuffer;
-  ULONG TempLength;
-  PCCB Ccb;
-  PFCB Fcb;
+    NTSTATUS Status = STATUS_SUCCESS;
+    PNTFS_FCB Fcb;
+    PFILE_RECORD_HEADER FileRecord;
+    PNTFS_ATTR_CONTEXT DataContext;
+    ULONG RealLength;
+    ULONG RealReadOffset;
+    ULONG RealLengthRead;
+    ULONG ToRead;
+    BOOLEAN AllocatedBuffer = FALSE;
+    PCHAR ReadBuffer = (PCHAR)Buffer;
+
+    DPRINT1("NtfsReadFile(%p, %p, %p, %u, %u, %x, %p)\n", DeviceExt, FileObject, Buffer, Length, ReadOffset, IrpFlags, LengthRead);
+
+    *LengthRead = 0;
+
+    if (Length == 0)
+    {
+        DPRINT1("Null read!\n");
+        return STATUS_SUCCESS;
+    }
 
-  DPRINT("CdfsReadFile(ReadOffset %lu  Length %lu)\n", ReadOffset, Length);
+    Fcb = (PNTFS_FCB)FileObject->FsContext;
 
-  *LengthRead = 0;
+    if (ReadOffset >= Fcb->Entry.AllocatedSize)
+    {
+        DPRINT1("Reading beyond file end!\n");
+        return STATUS_END_OF_FILE;
+    }
 
-  if (Length == 0)
-    return(STATUS_SUCCESS);
+    ToRead = Length;
+    if (ReadOffset + Length > Fcb->Entry.AllocatedSize)
+        ToRead = Fcb->Entry.AllocatedSize - ReadOffset;
 
-  Ccb = (PCCB)FileObject->FsContext2;
-  Fcb = (PFCB)FileObject->FsContext;
+    RealReadOffset = ReadOffset;
+    RealLength = ToRead;
 
-  if (ReadOffset >= Fcb->Entry.DataLengthL)
-    return(STATUS_END_OF_FILE);
+    if ((ReadOffset % DeviceExt->NtfsInfo.BytesPerSector) != 0 || (ToRead % DeviceExt->NtfsInfo.BytesPerSector) != 0)
+    {
+        RealReadOffset = ROUND_DOWN(ReadOffset, DeviceExt->NtfsInfo.BytesPerSector);
+        RealLength = ROUND_UP(ToRead, DeviceExt->NtfsInfo.BytesPerSector);
 
-  DPRINT("Reading %d bytes at %d\n", Length, ReadOffset);
+        ReadBuffer = ExAllocatePoolWithTag(NonPagedPool, RealLength + DeviceExt->NtfsInfo.BytesPerSector, TAG_NTFS);
+        if (ReadBuffer == NULL)
+        {
+            DPRINT1("Not enough memory!\n");
+            return STATUS_INSUFFICIENT_RESOURCES;
+        }
+        AllocatedBuffer = TRUE;
+    }
 
-  if (!(IrpFlags & (IRP_NOCACHE|IRP_PAGING_IO)))
+    FileRecord = ExAllocatePoolWithTag(NonPagedPool, DeviceExt->NtfsInfo.BytesPerFileRecord, TAG_NTFS);
+    if (FileRecord == NULL)
     {
-      LARGE_INTEGER FileOffset;
-      IO_STATUS_BLOCK IoStatus;
-
-      if (ReadOffset + Length > Fcb->Entry.DataLengthL)
-         Length = Fcb->Entry.DataLengthL - ReadOffset;
-      if (FileObject->PrivateCacheMap == NULL)
-      {
-         CcRosInitializeFileCache(FileObject, PAGE_SIZE);
-      }
-
-      FileOffset.QuadPart = (LONGLONG)ReadOffset;
-      CcCopyRead(FileObject,
-                &FileOffset,
-                Length,
-                TRUE,
-                Buffer,
-                &IoStatus);
-      *LengthRead = IoStatus.Information;
-
-      return(IoStatus.Status);
+        DPRINT1("Not enough memory!\n");
+        return STATUS_INSUFFICIENT_RESOURCES;
     }
 
-  if ((ReadOffset % BLOCKSIZE) != 0 || (Length % BLOCKSIZE) != 0)
+    Status = ReadFileRecord(DeviceExt, Fcb->MFTIndex, FileRecord);
+    if (!NT_SUCCESS(Status))
     {
-      return STATUS_INVALID_PARAMETER;
+        DPRINT1("Can't find record!\n");
+        ExFreePoolWithTag(FileRecord, TAG_NTFS);
+        return Status;
     }
-  if (ReadOffset + Length > ROUND_UP(Fcb->Entry.DataLengthL, BLOCKSIZE))
-    Length = ROUND_UP(Fcb->Entry.DataLengthL, BLOCKSIZE) - ReadOffset;
-
-  Status = CdfsReadSectors(DeviceExt->StorageDevice,
-                          Fcb->Entry.ExtentLocationL + (ReadOffset / BLOCKSIZE),
-                          Length / BLOCKSIZE,
-                          Buffer);
-  if (NT_SUCCESS(Status))
+
+    Status = FindAttribute(DeviceExt, FileRecord, AttributeData, L"", 0, &DataContext);
+    if (!NT_SUCCESS(Status))
     {
-      *LengthRead = Length;
-      if (Length + ReadOffset > Fcb->Entry.DataLengthL)
-      {
-       memset(Buffer + Fcb->Entry.DataLengthL - ReadOffset,
-              0, Length + ReadOffset - Fcb->Entry.DataLengthL);
-      }
+        DPRINT1("No data associated with file!\n");
+        ExFreePoolWithTag(FileRecord, TAG_NTFS);
+        return Status;
     }
 
-  return(Status);
-#else
-    UNREFERENCED_PARAMETER(DeviceExt);
-    UNREFERENCED_PARAMETER(FileObject);
-    UNREFERENCED_PARAMETER(Buffer);
-    UNREFERENCED_PARAMETER(Length);
-    UNREFERENCED_PARAMETER(ReadOffset);
-    UNREFERENCED_PARAMETER(IrpFlags);
-    *LengthRead = 0;
-    return STATUS_END_OF_FILE;
-#endif
+    DPRINT1("Effective read: %lu at %lu\n", RealLength, RealReadOffset);
+    RealLengthRead = ReadAttribute(DeviceExt, DataContext, RealReadOffset, (PCHAR)ReadBuffer, RealLength);
+    if (RealLengthRead != RealLength)
+    {
+        DPRINT1("Read failure!\n");
+        ReleaseAttributeContext(DataContext);
+        ExFreePoolWithTag(FileRecord, TAG_NTFS);
+        if (AllocatedBuffer)
+        {
+            ExFreePoolWithTag(ReadBuffer, TAG_NTFS);
+        }
+        return Status;
+    }
+
+    ReleaseAttributeContext(DataContext);
+    ExFreePoolWithTag(FileRecord, TAG_NTFS);
+
+    *LengthRead = ToRead;
+
+    DPRINT1("%lu got read\n", *LengthRead);
+
+    if (AllocatedBuffer)
+    {
+        RtlCopyMemory(Buffer, ReadBuffer + (ReadOffset - RealReadOffset), ToRead);
+    }
+
+    if (ToRead != Length)
+    {
+        RtlZeroMemory(Buffer + ToRead, Length - ToRead);
+    }
+
+    if (AllocatedBuffer)
+    {
+        ExFreePoolWithTag(ReadBuffer, TAG_NTFS);
+    }
+
+    return STATUS_SUCCESS;
 }