mirror of
https://github.com/reactos/reactos.git
synced 2025-07-31 18:11:57 +00:00
[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 svn path=/trunk/; revision=68302
This commit is contained in:
parent
ec8ef644e3
commit
fbff7e0e47
5 changed files with 82 additions and 47 deletions
|
@ -218,7 +218,7 @@ NtfsOpenFileById(PDEVICE_EXTENSION DeviceExt,
|
|||
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);
|
||||
|
|
|
@ -65,6 +65,7 @@ NtfsWSubString(PWCHAR pTarget,
|
|||
|
||||
PNTFS_FCB
|
||||
NtfsCreateFCB(PCWSTR FileName,
|
||||
PCWSTR Stream,
|
||||
PNTFS_VCB Vcb)
|
||||
{
|
||||
PNTFS_FCB Fcb;
|
||||
|
@ -93,6 +94,15 @@ NtfsCreateFCB(PCWSTR FileName,
|
|||
}
|
||||
}
|
||||
|
||||
if (Stream)
|
||||
{
|
||||
wcscpy(Fcb->Stream, Stream);
|
||||
}
|
||||
else
|
||||
{
|
||||
Fcb->Stream[0] = UNICODE_NULL;
|
||||
}
|
||||
|
||||
ExInitializeResourceLite(&Fcb->MainResource);
|
||||
|
||||
Fcb->RFCB.Resource = &(Fcb->MainResource);
|
||||
|
@ -316,7 +326,7 @@ NtfsMakeRootFCB(PNTFS_VCB Vcb)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
Fcb = NtfsCreateFCB(L"\\", Vcb);
|
||||
Fcb = NtfsCreateFCB(L"\\", NULL, Vcb);
|
||||
if (!Fcb)
|
||||
{
|
||||
ExFreePoolWithTag(MftRecord, TAG_NTFS);
|
||||
|
@ -400,18 +410,19 @@ NtfsGetDirEntryName(PDEVICE_EXTENSION DeviceExt,
|
|||
|
||||
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 @@ NtfsMakeFCBFromDirEntry(PNTFS_VCB Vcb,
|
|||
pathName[FileName->NameLength] = UNICODE_NULL;
|
||||
}
|
||||
|
||||
rcFCB = NtfsCreateFCB(pathName, Vcb);
|
||||
rcFCB = NtfsCreateFCB(pathName, Stream, Vcb);
|
||||
if (!rcFCB)
|
||||
{
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
|
@ -531,6 +542,8 @@ NtfsDirFindFile(PNTFS_VCB Vcb,
|
|||
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 @@ NtfsDirFindFile(PNTFS_VCB Vcb,
|
|||
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;
|
||||
|
|
|
@ -352,7 +352,7 @@ NtfsGetVolumeData(PDEVICE_OBJECT DeviceObject,
|
|||
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 @@ NtfsMountVolume(PDEVICE_OBJECT DeviceObject,
|
|||
|
||||
InitializeListHead(&Vcb->FcbListHead);
|
||||
|
||||
Fcb = NtfsCreateFCB(NULL, Vcb);
|
||||
Fcb = NtfsCreateFCB(NULL, NULL, Vcb);
|
||||
if (Fcb == NULL)
|
||||
{
|
||||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
|
|
|
@ -440,6 +440,7 @@ typedef struct _FCB
|
|||
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 @@ FAST_IO_WRITE NtfsFastIoWrite;
|
|||
|
||||
PNTFS_FCB
|
||||
NtfsCreateFCB(PCWSTR FileName,
|
||||
PCWSTR Stream,
|
||||
PNTFS_VCB Vcb);
|
||||
|
||||
VOID
|
||||
|
@ -649,6 +651,7 @@ NTSTATUS
|
|||
NtfsMakeFCBFromDirEntry(PNTFS_VCB Vcb,
|
||||
PNTFS_FCB DirectoryFCB,
|
||||
PUNICODE_STRING Name,
|
||||
PCWSTR Stream,
|
||||
PFILE_RECORD_HEADER Record,
|
||||
ULONGLONG MFTIndex,
|
||||
PNTFS_FCB * fileFCB);
|
||||
|
|
|
@ -57,6 +57,7 @@ NtfsReadFile(PDEVICE_EXTENSION DeviceExt,
|
|||
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 @@ NtfsReadFile(PDEVICE_EXTENSION DeviceExt,
|
|||
|
||||
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 @@ NtfsReadFile(PDEVICE_EXTENSION DeviceExt,
|
|||
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 @@ NtfsReadFile(PDEVICE_EXTENSION DeviceExt,
|
|||
{
|
||||
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 @@ NtfsReadFile(PDEVICE_EXTENSION DeviceExt,
|
|||
Attribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)Attribute + Attribute->Length);
|
||||
}
|
||||
|
||||
ReleaseAttributeContext(DataContext);
|
||||
ExFreePoolWithTag(FileRecord, TAG_NTFS);
|
||||
if (AllocatedBuffer)
|
||||
{
|
||||
ExFreePoolWithTag(ReadBuffer, 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);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue