PNTFS_FCB
NtfsCreateFCB(PCWSTR FileName,
+ PCWSTR Stream,
PNTFS_VCB Vcb)
{
PNTFS_FCB Fcb;
}
}
+ if (Stream)
+ {
+ wcscpy(Fcb->Stream, Stream);
+ }
+ else
+ {
+ Fcb->Stream[0] = UNICODE_NULL;
+ }
+
ExInitializeResourceLite(&Fcb->MainResource);
Fcb->RFCB.Resource = &(Fcb->MainResource);
return NULL;
}
- Fcb = NtfsCreateFCB(L"\\", Vcb);
+ Fcb = NtfsCreateFCB(L"\\", NULL, Vcb);
if (!Fcb)
{
ExFreePoolWithTag(MftRecord, TAG_NTFS);
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)
pathName[FileName->NameLength] = UNICODE_NULL;
}
- rcFCB = NtfsCreateFCB(pathName, Vcb);
+ rcFCB = NtfsCreateFCB(pathName, Stream, Vcb);
if (!rcFCB)
{
return STATUS_INSUFFICIENT_RESOURCES;
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);
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;
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);
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)
{
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) &&
{
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);
Attribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)Attribute + Attribute->Length);
}
+ ReleaseAttributeContext(DataContext);
ExFreePoolWithTag(FileRecord, TAG_NTFS);
- if (AllocatedBuffer)
+ return Status;
+ }
+
+ 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)
{
- ExFreePoolWithTag(ReadBuffer, TAG_NTFS);
+ DPRINT1("Not enough memory!\n");
+ ReleaseAttributeContext(DataContext);
+ ExFreePoolWithTag(FileRecord, TAG_NTFS);
+ return STATUS_INSUFFICIENT_RESOURCES;
}
- return Status;
+ AllocatedBuffer = TRUE;
}
- DPRINT1("Effective read: %lu at %lu\n", RealLength, RealReadOffset);
+ 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);