[NTFS]
authorPierre Schweitzer <pierre@reactos.org>
Mon, 24 Aug 2015 08:36:58 +0000 (08:36 +0000)
committerPierre Schweitzer <pierre@reactos.org>
Mon, 24 Aug 2015 08:36:58 +0000 (08:36 +0000)
Implement FileStreamInformation class for IRP_MJ_QUERY_INFORMATION.
It allows enumerating streams for a given file

svn path=/trunk/; revision=68808

reactos/drivers/filesystems/ntfs/finfo.c

index 63365af..9c3424c 100644 (file)
@@ -218,6 +218,74 @@ NtfsGetNetworkOpenInformation(PNTFS_FCB Fcb,
     return STATUS_SUCCESS;
 }
 
+static
+NTSTATUS
+NtfsGetSteamInformation(PNTFS_FCB Fcb,
+                        PDEVICE_EXTENSION DeviceExt,
+                        PFILE_STREAM_INFORMATION StreamInfo,
+                        PULONG BufferLength)
+{
+    NTSTATUS Status;
+    ULONG CurrentSize;
+    PNTFS_ATTR_RECORD Attribute;
+    PFILE_RECORD_HEADER FileRecord;
+    PFILE_STREAM_INFORMATION CurrentInfo = StreamInfo, Previous = NULL;
+
+    if (*BufferLength < sizeof(FILE_STREAM_INFORMATION))
+        return STATUS_BUFFER_OVERFLOW;
+
+    FileRecord = ExAllocatePoolWithTag(NonPagedPool, DeviceExt->NtfsInfo.BytesPerFileRecord, TAG_NTFS);
+    if (FileRecord == NULL)
+    {
+        DPRINT1("Not enough memory!\n");
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    Status = ReadFileRecord(DeviceExt, Fcb->MFTIndex, FileRecord);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Can't find record!\n");
+        ExFreePoolWithTag(FileRecord, TAG_NTFS);
+        return Status;
+    }
+
+    Status = STATUS_SUCCESS;
+    Attribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + FileRecord->AttributeOffset);
+    while (Attribute < (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + FileRecord->BytesInUse) &&
+           Attribute->Type != AttributeEnd)
+    {
+        if (Attribute->Type == AttributeData)
+        {
+            CurrentSize = FIELD_OFFSET(FILE_STREAM_INFORMATION, StreamName) + Attribute->NameLength * sizeof(WCHAR);
+
+            if (CurrentSize > *BufferLength)
+            {
+                Status = STATUS_BUFFER_OVERFLOW;
+                break;
+            }
+
+            CurrentInfo->NextEntryOffset = 0;
+            CurrentInfo->StreamNameLength = Attribute->NameLength * sizeof(WCHAR);
+            CurrentInfo->StreamSize.QuadPart = AttributeDataLength(Attribute);
+            CurrentInfo->StreamAllocationSize.QuadPart = AttributeAllocatedLength(Attribute);
+            RtlMoveMemory(CurrentInfo->StreamName, (PWCHAR)((ULONG_PTR)Attribute + Attribute->NameOffset), CurrentInfo->StreamNameLength);
+
+            if (Previous != NULL)
+            {
+                Previous->NextEntryOffset = (ULONG_PTR)CurrentInfo - (ULONG_PTR)Previous;
+            }
+            Previous = CurrentInfo;
+            CurrentInfo = (PFILE_STREAM_INFORMATION)((ULONG_PTR)CurrentInfo + CurrentSize);
+            *BufferLength -= CurrentSize;
+        }
+
+        Attribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)Attribute + Attribute->Length);
+    }
+
+    ExFreePoolWithTag(FileRecord, TAG_NTFS);
+    return Status;
+}
+
 /*
  * FUNCTION: Retrieve the specified file information
  */
@@ -296,6 +364,13 @@ NtfsQueryInformation(PNTFS_IRP_CONTEXT IrpContext)
                                                    &BufferLength);
             break;
 
+        case FileStreamInformation:
+            Status = NtfsGetSteamInformation(Fcb,
+                                             DeviceObject->DeviceExtension,
+                                             SystemBuffer,
+                                             &BufferLength);
+            break;
+
         case FileAlternateNameInformation:
         case FileAllInformation:
             DPRINT1("Unimplemented information class %u\n", FileInformationClass);