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/c…
==============================================================================
--- 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/f…
==============================================================================
--- 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/f…
==============================================================================
--- 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/n…
==============================================================================
--- 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/r…
==============================================================================
--- 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);