Author: pschweitzer Date: Sun Jun 28 13:14:07 2015 New Revision: 68302
URL: http://svn.reactos.org/svn/reactos?rev=68302&view=rev Log: [NTFS] Implement support for NTFS $DATA streams: - The driver is now able to read various streams for a same file, using the same syntax as Windows. - This fixes to read (in general) files with multiple streams where reading unnamed stream was leading to read beyond file end - Also fix reading small files which are smaller than a sector
For demo, see: http://www.heisspiter.net/~Pierre/rostests/NTFS_Streams.png
Modified: trunk/reactos/drivers/filesystems/ntfs/create.c trunk/reactos/drivers/filesystems/ntfs/fcb.c trunk/reactos/drivers/filesystems/ntfs/fsctl.c trunk/reactos/drivers/filesystems/ntfs/ntfs.h trunk/reactos/drivers/filesystems/ntfs/rw.c
Modified: trunk/reactos/drivers/filesystems/ntfs/create.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/filesystems/ntfs/cr... ============================================================================== --- trunk/reactos/drivers/filesystems/ntfs/create.c [iso-8859-1] (original) +++ trunk/reactos/drivers/filesystems/ntfs/create.c [iso-8859-1] Sun Jun 28 13:14:07 2015 @@ -218,7 +218,7 @@ UNICODE_STRING Name;
RtlInitUnicodeString(&Name, MftIdToName[MftId]); - Status = NtfsMakeFCBFromDirEntry(DeviceExt, NULL, &Name, MftRecord, MftId, &FCB); + Status = NtfsMakeFCBFromDirEntry(DeviceExt, NULL, &Name, NULL, MftRecord, MftId, &FCB); if (!NT_SUCCESS(Status)) { ExFreePoolWithTag(MftRecord, TAG_NTFS);
Modified: trunk/reactos/drivers/filesystems/ntfs/fcb.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/filesystems/ntfs/fc... ============================================================================== --- trunk/reactos/drivers/filesystems/ntfs/fcb.c [iso-8859-1] (original) +++ trunk/reactos/drivers/filesystems/ntfs/fcb.c [iso-8859-1] Sun Jun 28 13:14:07 2015 @@ -65,6 +65,7 @@
PNTFS_FCB NtfsCreateFCB(PCWSTR FileName, + PCWSTR Stream, PNTFS_VCB Vcb) { PNTFS_FCB Fcb; @@ -91,6 +92,15 @@ { Fcb->ObjectName = Fcb->PathName; } + } + + if (Stream) + { + wcscpy(Fcb->Stream, Stream); + } + else + { + Fcb->Stream[0] = UNICODE_NULL; }
ExInitializeResourceLite(&Fcb->MainResource); @@ -316,7 +326,7 @@ return NULL; }
- Fcb = NtfsCreateFCB(L"\", Vcb); + Fcb = NtfsCreateFCB(L"\", NULL, Vcb); if (!Fcb) { ExFreePoolWithTag(MftRecord, TAG_NTFS); @@ -400,18 +410,19 @@
NTSTATUS NtfsMakeFCBFromDirEntry(PNTFS_VCB Vcb, - PNTFS_FCB DirectoryFCB, - PUNICODE_STRING Name, - PFILE_RECORD_HEADER Record, + PNTFS_FCB DirectoryFCB, + PUNICODE_STRING Name, + PCWSTR Stream, + PFILE_RECORD_HEADER Record, ULONGLONG MFTIndex, - PNTFS_FCB * fileFCB) + PNTFS_FCB * fileFCB) { WCHAR pathName[MAX_PATH]; PFILENAME_ATTRIBUTE FileName; PSTANDARD_INFORMATION StdInfo; PNTFS_FCB rcFCB;
- DPRINT1("NtfsMakeFCBFromDirEntry(%p, %p, %wZ, %p, %p)\n", Vcb, DirectoryFCB, Name, Record, fileFCB); + DPRINT1("NtfsMakeFCBFromDirEntry(%p, %p, %wZ, %p, %p, %p)\n", Vcb, DirectoryFCB, Name, Stream, Record, fileFCB);
FileName = GetBestFileNameFromRecord(Record); if (!FileName) @@ -440,7 +451,7 @@ pathName[FileName->NameLength] = UNICODE_NULL; }
- rcFCB = NtfsCreateFCB(pathName, Vcb); + rcFCB = NtfsCreateFCB(pathName, Stream, Vcb); if (!rcFCB) { return STATUS_INSUFFICIENT_RESOURCES; @@ -531,6 +542,8 @@ UNICODE_STRING File; PFILE_RECORD_HEADER FileRecord; ULONGLONG MFTIndex; + PWSTR Colon; + USHORT Length = 0;
DPRINT1("NtfsDirFindFile(%p, %p, %S, %p)\n", Vcb, DirectoryFcb, FileToFind, FoundFCB);
@@ -538,13 +551,29 @@ RtlInitUnicodeString(&File, FileToFind); CurrentDir = DirectoryFcb->MFTIndex;
+ Colon = wcsrchr(FileToFind, L':'); + if (Colon != NULL) + { + Length = File.Length; + File.Length = (Colon - FileToFind) * sizeof(WCHAR); + + /* Skip colon */ + ++Colon; + DPRINT1("Will now look for file '%wZ' with stream '%S'\n", &File, Colon); + } + Status = NtfsLookupFileAt(Vcb, &File, &FileRecord, &MFTIndex, CurrentDir); if (!NT_SUCCESS(Status)) { return Status; }
- Status = NtfsMakeFCBFromDirEntry(Vcb, DirectoryFcb, &File, FileRecord, MFTIndex, FoundFCB); + if (Length != 0) + { + File.Length = Length; + } + + Status = NtfsMakeFCBFromDirEntry(Vcb, DirectoryFcb, &File, Colon, FileRecord, MFTIndex, FoundFCB); ExFreePoolWithTag(FileRecord, TAG_NTFS);
return Status;
Modified: trunk/reactos/drivers/filesystems/ntfs/fsctl.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/filesystems/ntfs/fs... ============================================================================== --- trunk/reactos/drivers/filesystems/ntfs/fsctl.c [iso-8859-1] (original) +++ trunk/reactos/drivers/filesystems/ntfs/fsctl.c [iso-8859-1] Sun Jun 28 13:14:07 2015 @@ -352,7 +352,7 @@ VolumeNameU = L"\0"; }
- VolumeFcb = NtfsCreateFCB(VolumeNameU, DeviceExt); + VolumeFcb = NtfsCreateFCB(VolumeNameU, NULL, DeviceExt); if (VolumeFcb == NULL) { DPRINT1("Failed allocating volume FCB\n"); @@ -456,7 +456,7 @@
InitializeListHead(&Vcb->FcbListHead);
- Fcb = NtfsCreateFCB(NULL, Vcb); + Fcb = NtfsCreateFCB(NULL, NULL, Vcb); if (Fcb == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES;
Modified: trunk/reactos/drivers/filesystems/ntfs/ntfs.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/filesystems/ntfs/nt... ============================================================================== --- trunk/reactos/drivers/filesystems/ntfs/ntfs.h [iso-8859-1] (original) +++ trunk/reactos/drivers/filesystems/ntfs/ntfs.h [iso-8859-1] Sun Jun 28 13:14:07 2015 @@ -440,6 +440,7 @@ PFILE_OBJECT FileObject; PNTFS_VCB Vcb;
+ WCHAR Stream[MAX_PATH]; WCHAR *ObjectName; /* point on filename (250 chars max) in PathName */ WCHAR PathName[MAX_PATH]; /* path+filename 260 max */
@@ -586,6 +587,7 @@
PNTFS_FCB NtfsCreateFCB(PCWSTR FileName, + PCWSTR Stream, PNTFS_VCB Vcb);
VOID @@ -649,6 +651,7 @@ NtfsMakeFCBFromDirEntry(PNTFS_VCB Vcb, PNTFS_FCB DirectoryFCB, PUNICODE_STRING Name, + PCWSTR Stream, PFILE_RECORD_HEADER Record, ULONGLONG MFTIndex, PNTFS_FCB * fileFCB);
Modified: trunk/reactos/drivers/filesystems/ntfs/rw.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/filesystems/ntfs/rw... ============================================================================== --- trunk/reactos/drivers/filesystems/ntfs/rw.c [iso-8859-1] (original) +++ trunk/reactos/drivers/filesystems/ntfs/rw.c [iso-8859-1] Sun Jun 28 13:14:07 2015 @@ -57,6 +57,7 @@ ULONG ToRead; BOOLEAN AllocatedBuffer = FALSE; PCHAR ReadBuffer = (PCHAR)Buffer; + ULONGLONG StreamSize;
DPRINT1("NtfsReadFile(%p, %p, %p, %u, %u, %x, %p)\n", DeviceExt, FileObject, Buffer, Length, ReadOffset, IrpFlags, LengthRead);
@@ -70,33 +71,6 @@
Fcb = (PNTFS_FCB)FileObject->FsContext;
- if (ReadOffset >= Fcb->Entry.AllocatedSize) - { - DPRINT1("Reading beyond file end!\n"); - return STATUS_END_OF_FILE; - } - - ToRead = Length; - if (ReadOffset + Length > Fcb->Entry.AllocatedSize) - ToRead = Fcb->Entry.AllocatedSize - ReadOffset; - - RealReadOffset = ReadOffset; - RealLength = ToRead; - - 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); - - ReadBuffer = ExAllocatePoolWithTag(NonPagedPool, RealLength + DeviceExt->NtfsInfo.BytesPerSector, TAG_NTFS); - if (ReadBuffer == NULL) - { - DPRINT1("Not enough memory!\n"); - return STATUS_INSUFFICIENT_RESOURCES; - } - AllocatedBuffer = TRUE; - } - FileRecord = ExAllocatePoolWithTag(NonPagedPool, DeviceExt->NtfsInfo.BytesPerFileRecord, TAG_NTFS); if (FileRecord == NULL) { @@ -120,12 +94,13 @@ return Status; }
- Status = FindAttribute(DeviceExt, FileRecord, AttributeData, L"", 0, &DataContext); + + Status = FindAttribute(DeviceExt, FileRecord, AttributeData, Fcb->Stream, wcslen(Fcb->Stream), &DataContext); if (!NT_SUCCESS(Status)) { PNTFS_ATTR_RECORD Attribute;
- DPRINT1("No unnamed data stream associated with file!\n"); + DPRINT1("No '%S' data stream associated with file!\n", Fcb->Stream);
Attribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + FileRecord->AttributeOffset); while (Attribute < (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + FileRecord->BytesInUse) && @@ -135,7 +110,6 @@ { UNICODE_STRING Name;
- ASSERT(Attribute->NameLength != 0); Name.Length = Attribute->NameLength * sizeof(WCHAR); Name.MaximumLength = Name.Length; Name.Buffer = (PWCHAR)((ULONG_PTR)Attribute + Attribute->NameOffset); @@ -145,17 +119,46 @@ Attribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)Attribute + Attribute->Length); }
- ExFreePoolWithTag(FileRecord, TAG_NTFS); - if (AllocatedBuffer) - { - ExFreePoolWithTag(ReadBuffer, TAG_NTFS); - } + ReleaseAttributeContext(DataContext); + ExFreePoolWithTag(FileRecord, TAG_NTFS); return Status; }
- DPRINT1("Effective read: %lu at %lu\n", RealLength, RealReadOffset); + StreamSize = AttributeDataLength(&DataContext->Record); + if (ReadOffset >= StreamSize) + { + DPRINT1("Reading beyond stream end!\n"); + ReleaseAttributeContext(DataContext); + ExFreePoolWithTag(FileRecord, TAG_NTFS); + return STATUS_END_OF_FILE; + } + + ToRead = Length; + if (ReadOffset + Length > StreamSize) + ToRead = StreamSize - ReadOffset; + + RealReadOffset = ReadOffset; + RealLength = ToRead; + + 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); + + ReadBuffer = ExAllocatePoolWithTag(NonPagedPool, RealLength + DeviceExt->NtfsInfo.BytesPerSector, TAG_NTFS); + if (ReadBuffer == NULL) + { + DPRINT1("Not enough memory!\n"); + ReleaseAttributeContext(DataContext); + ExFreePoolWithTag(FileRecord, TAG_NTFS); + return STATUS_INSUFFICIENT_RESOURCES; + } + AllocatedBuffer = TRUE; + } + + DPRINT1("Effective read: %lu at %lu for stream '%S'\n", RealLength, RealReadOffset, Fcb->Stream); RealLengthRead = ReadAttribute(DeviceExt, DataContext, RealReadOffset, (PCHAR)ReadBuffer, RealLength); - if (RealLengthRead != RealLength) + if (RealLengthRead == 0) { DPRINT1("Read failure!\n"); ReleaseAttributeContext(DataContext);