From: Trevor Thompson Date: Fri, 12 May 2017 22:16:20 +0000 (+0000) Subject: [NTFS] - Commit early results of a small restructuring effort: X-Git-Tag: 0.4.9-dev~693^2~44 X-Git-Url: https://git.reactos.org/?p=reactos.git;a=commitdiff_plain;h=52b9f46776d9850c49976c949513fdd34a6d935f [NTFS] - Commit early results of a small restructuring effort: -Add a new member to the NTFS_ATTR_CONTEXT struct, a LARGE_MCB. This allows an attribute context to describe the cluster mapping of a non-resident file while allowing that mapping to change dynamically, without the context itself needing to be resized. This fixes problems which sometimes arose from resizing files. -Remove hacky code from NtfsWriteFile() for dealing with "stale" contexts. This fixes that issue. -Update SetDataAttributeLength(), PrepareAttributeContext(), ReleaseAttributeContext(), FreeClusters(), and AddRun() for the new member. -Update ReadAttribute() and WriteAttribute() to work with the changed structure. A very-soon-to-come commit will overhaul these functions so they'll operate directly on the LARGE_MCB, instead of converting to and from a packed list of data runs. (Sparse files are broken until then.) -Rename "RunBufferOffset" to "RunBufferSize" in several places where appropriate. -Fix, improve, and add some comments. svn path=/branches/GSoC_2016/NTFS/; revision=74523 --- diff --git a/drivers/filesystems/ntfs/attrib.c b/drivers/filesystems/ntfs/attrib.c index 2a70e8c3c8f..bb678e3ef8f 100644 --- a/drivers/filesystems/ntfs/attrib.c +++ b/drivers/filesystems/ntfs/attrib.c @@ -261,39 +261,23 @@ AddRun(PNTFS_VCB Vcb, ULONG RunLength) { NTSTATUS Status; - PUCHAR DataRun = (PUCHAR)&AttrContext->Record + AttrContext->Record.NonResident.MappingPairsOffset; int DataRunMaxLength; PNTFS_ATTR_RECORD DestinationAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + AttrOffset); - LARGE_MCB DataRunsMCB; ULONG NextAttributeOffset = AttrOffset + AttrContext->Record.Length; - ULONGLONG NextVBN = AttrContext->Record.NonResident.LowestVCN; + ULONGLONG NextVBN = 0; - // Allocate some memory for the RunBuffer PUCHAR RunBuffer; - ULONG RunBufferOffset = 0; + ULONG RunBufferSize; if (!AttrContext->Record.IsNonResident) return STATUS_INVALID_PARAMETER; - RunBuffer = ExAllocatePoolWithTag(NonPagedPool, Vcb->NtfsInfo.BytesPerFileRecord, TAG_NTFS); - if (!RunBuffer) - { - DPRINT1("ERROR: Couldn't allocate memory for data runs!\n"); - return STATUS_INSUFFICIENT_RESOURCES; - } - - // Convert the data runs to a map control block - Status = ConvertDataRunsToLargeMCB(DataRun, &DataRunsMCB, &NextVBN); - if (!NT_SUCCESS(Status)) - { - DPRINT1("Unable to convert data runs to MCB (probably ran out of memory)!\n"); - ExFreePoolWithTag(RunBuffer, TAG_NTFS); - return Status; - } + if (AttrContext->Record.NonResident.AllocatedSize != 0) + NextVBN = AttrContext->Record.NonResident.HighestVCN + 1; // Add newly-assigned clusters to mcb _SEH2_TRY{ - if (!FsRtlAddLargeMcbEntry(&DataRunsMCB, + if (!FsRtlAddLargeMcbEntry(&AttrContext->DataRunsMCB, NextVBN, NextAssignedCluster, RunLength)) @@ -301,70 +285,65 @@ AddRun(PNTFS_VCB Vcb, ExRaiseStatus(STATUS_UNSUCCESSFUL); } } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { - FsRtlUninitializeLargeMcb(&DataRunsMCB); - ExFreePoolWithTag(RunBuffer, TAG_NTFS); _SEH2_YIELD(_SEH2_GetExceptionCode()); } _SEH2_END; + RunBuffer = ExAllocatePoolWithTag(NonPagedPool, Vcb->NtfsInfo.BytesPerFileRecord, TAG_NTFS); + if (!RunBuffer) + { + DPRINT1("ERROR: Couldn't allocate memory for data runs!\n"); + return STATUS_INSUFFICIENT_RESOURCES; + } // Convert the map control block back to encoded data runs - ConvertLargeMCBToDataRuns(&DataRunsMCB, RunBuffer, Vcb->NtfsInfo.BytesPerCluster, &RunBufferOffset); + ConvertLargeMCBToDataRuns(&AttrContext->DataRunsMCB, RunBuffer, Vcb->NtfsInfo.BytesPerCluster, &RunBufferSize); // Get the amount of free space between the start of the of the first data run and the attribute end DataRunMaxLength = AttrContext->Record.Length - AttrContext->Record.NonResident.MappingPairsOffset; // Do we need to extend the attribute (or convert to attribute list)? - if (DataRunMaxLength < RunBufferOffset) + if (DataRunMaxLength < RunBufferSize) { PNTFS_ATTR_RECORD NextAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + NextAttributeOffset); DataRunMaxLength += Vcb->NtfsInfo.BytesPerFileRecord - NextAttributeOffset - (sizeof(ULONG) * 2); // Can we move the end of the attribute? - if (NextAttribute->Type != AttributeEnd || DataRunMaxLength < RunBufferOffset - 1) + if (NextAttribute->Type != AttributeEnd || DataRunMaxLength < RunBufferSize - 1) { DPRINT1("FIXME: Need to create attribute list! Max Data Run Length available: %d\n", DataRunMaxLength); if (NextAttribute->Type != AttributeEnd) DPRINT1("There's another attribute after this one with type %0xlx\n", NextAttribute->Type); ExFreePoolWithTag(RunBuffer, TAG_NTFS); - FsRtlUninitializeLargeMcb(&DataRunsMCB); return STATUS_NOT_IMPLEMENTED; } // calculate position of end markers - NextAttributeOffset = AttrOffset + AttrContext->Record.NonResident.MappingPairsOffset + RunBufferOffset; + NextAttributeOffset = AttrOffset + AttrContext->Record.NonResident.MappingPairsOffset + RunBufferSize; NextAttributeOffset = ALIGN_UP_BY(NextAttributeOffset, 8); - // Write the end markers - NextAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + NextAttributeOffset); - NextAttribute->Type = AttributeEnd; - NextAttribute->Length = FILE_RECORD_END; - // Update the length DestinationAttribute->Length = NextAttributeOffset - AttrOffset; AttrContext->Record.Length = DestinationAttribute->Length; - // We need to increase the FileRecord size - FileRecord->BytesInUse = NextAttributeOffset + (sizeof(ULONG) * 2); + // End the file record + NextAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + NextAttributeOffset); + SetFileRecordEnd(FileRecord, NextAttribute, FILE_RECORD_END); } - // NOTE: from this point on the original attribute record will contain invalid data in it's runbuffer - // TODO: Elegant fix? Could we free the old Record and allocate a new one without issue? - // Update HighestVCN DestinationAttribute->NonResident.HighestVCN = - AttrContext->Record.NonResident.HighestVCN = max(NextVBN - 1 + RunLength, + AttrContext->Record.NonResident.HighestVCN = max(NextVBN - 1 + RunLength, AttrContext->Record.NonResident.HighestVCN); // Write data runs to destination attribute RtlCopyMemory((PVOID)((ULONG_PTR)DestinationAttribute + DestinationAttribute->NonResident.MappingPairsOffset), RunBuffer, - RunBufferOffset); + RunBufferSize); // Update the file record Status = UpdateFileRecord(Vcb, AttrContext->FileMFTIndex, FileRecord); ExFreePoolWithTag(RunBuffer, TAG_NTFS); - FsRtlUninitializeLargeMcb(&DataRunsMCB); NtfsDumpDataRuns((PUCHAR)((ULONG_PTR)DestinationAttribute + DestinationAttribute->NonResident.MappingPairsOffset), 0); @@ -567,7 +546,7 @@ ConvertLargeMCBToDataRuns(PLARGE_MCB DataRunsMCB, DataRunLengthSize = GetPackedByteCount(Count, TRUE); DPRINT("%d bytes needed.\n", DataRunLengthSize); - // ensure the next data run + end marker would be > Max buffer size + // ensure the next data run + end marker would be <= Max buffer size if (RunBufferOffset + 2 + DataRunLengthSize + DataRunOffsetSize > MaxBufferSize) { Status = STATUS_BUFFER_TOO_SMALL; @@ -698,17 +677,12 @@ FreeClusters(PNTFS_VCB Vcb, NTSTATUS Status = STATUS_SUCCESS; ULONG ClustersLeftToFree = ClustersToFree; - // convert data runs to mcb - PUCHAR DataRun = (PUCHAR)&AttrContext->Record + AttrContext->Record.NonResident.MappingPairsOffset; PNTFS_ATTR_RECORD DestinationAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + AttrOffset); - LARGE_MCB DataRunsMCB; ULONG NextAttributeOffset = AttrOffset + AttrContext->Record.Length; PNTFS_ATTR_RECORD NextAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + NextAttributeOffset); - ULONGLONG NextVBN = AttrContext->Record.NonResident.LowestVCN; - // Allocate some memory for the RunBuffer PUCHAR RunBuffer; - ULONG RunBufferOffset = 0; + ULONG RunBufferSize = 0; PFILE_RECORD_HEADER BitmapRecord; PNTFS_ATTR_CONTEXT DataContext; @@ -722,30 +696,13 @@ FreeClusters(PNTFS_VCB Vcb, return STATUS_INVALID_PARAMETER; } - RunBuffer = ExAllocatePoolWithTag(NonPagedPool, Vcb->NtfsInfo.BytesPerFileRecord, TAG_NTFS); - if (!RunBuffer) - { - DPRINT1("ERROR: Couldn't allocate memory for data runs!\n"); - return STATUS_INSUFFICIENT_RESOURCES; - } - - // Convert the data runs to a map control block - Status = ConvertDataRunsToLargeMCB(DataRun, &DataRunsMCB, &NextVBN); - if (!NT_SUCCESS(Status)) - { - DPRINT1("Unable to convert data runs to MCB (probably ran out of memory)!\n"); - ExFreePoolWithTag(RunBuffer, TAG_NTFS); - return Status; - } - + // Read the $Bitmap file BitmapRecord = ExAllocatePoolWithTag(NonPagedPool, Vcb->NtfsInfo.BytesPerFileRecord, TAG_NTFS); if (BitmapRecord == NULL) { DPRINT1("Error: Unable to allocate memory for bitmap file record!\n"); - FsRtlUninitializeLargeMcb(&DataRunsMCB); - ExFreePoolWithTag(RunBuffer, TAG_NTFS); return STATUS_NO_MEMORY; } @@ -753,9 +710,7 @@ FreeClusters(PNTFS_VCB Vcb, if (!NT_SUCCESS(Status)) { DPRINT1("Error: Unable to read file record for bitmap!\n"); - FsRtlUninitializeLargeMcb(&DataRunsMCB); ExFreePoolWithTag(BitmapRecord, TAG_NTFS); - ExFreePoolWithTag(RunBuffer, TAG_NTFS); return 0; } @@ -763,9 +718,7 @@ FreeClusters(PNTFS_VCB Vcb, if (!NT_SUCCESS(Status)) { DPRINT1("Error: Unable to find data attribute for bitmap file!\n"); - FsRtlUninitializeLargeMcb(&DataRunsMCB); ExFreePoolWithTag(BitmapRecord, TAG_NTFS); - ExFreePoolWithTag(RunBuffer, TAG_NTFS); return 0; } @@ -777,9 +730,7 @@ FreeClusters(PNTFS_VCB Vcb, { DPRINT1("Error: Unable to allocate memory for bitmap file data!\n"); ReleaseAttributeContext(DataContext); - FsRtlUninitializeLargeMcb(&DataRunsMCB); ExFreePoolWithTag(BitmapRecord, TAG_NTFS); - ExFreePoolWithTag(RunBuffer, TAG_NTFS); return 0; } @@ -792,7 +743,7 @@ FreeClusters(PNTFS_VCB Vcb, { LONGLONG LargeVbn, LargeLbn; - if (!FsRtlLookupLastLargeMcbEntry(&DataRunsMCB, &LargeVbn, &LargeLbn)) + if (!FsRtlLookupLastLargeMcbEntry(&AttrContext->DataRunsMCB, &LargeVbn, &LargeLbn)) { Status = STATUS_INVALID_PARAMETER; DPRINT1("DRIVER ERROR: FreeClusters called to free %lu clusters, which is %lu more clusters than are assigned to attribute!", @@ -806,7 +757,9 @@ FreeClusters(PNTFS_VCB Vcb, // deallocate this cluster RtlClearBits(&Bitmap, LargeLbn, 1); } - FsRtlTruncateLargeMcb(&DataRunsMCB, AttrContext->Record.NonResident.HighestVCN); + FsRtlTruncateLargeMcb(&AttrContext->DataRunsMCB, AttrContext->Record.NonResident.HighestVCN); + + // decrement HighestVCN, but don't let it go below 0 AttrContext->Record.NonResident.HighestVCN = min(AttrContext->Record.NonResident.HighestVCN, AttrContext->Record.NonResident.HighestVCN - 1); ClustersLeftToFree--; } @@ -816,19 +769,27 @@ FreeClusters(PNTFS_VCB Vcb, if (!NT_SUCCESS(Status)) { ReleaseAttributeContext(DataContext); - FsRtlUninitializeLargeMcb(&DataRunsMCB); ExFreePoolWithTag(BitmapData, TAG_NTFS); ExFreePoolWithTag(BitmapRecord, TAG_NTFS); - ExFreePoolWithTag(RunBuffer, TAG_NTFS); return Status; } ReleaseAttributeContext(DataContext); ExFreePoolWithTag(BitmapData, TAG_NTFS); ExFreePoolWithTag(BitmapRecord, TAG_NTFS); + + // Save updated data runs to file record + + // Allocate some memory for a new RunBuffer + RunBuffer = ExAllocatePoolWithTag(NonPagedPool, Vcb->NtfsInfo.BytesPerFileRecord, TAG_NTFS); + if (!RunBuffer) + { + DPRINT1("ERROR: Couldn't allocate memory for data runs!\n"); + return STATUS_INSUFFICIENT_RESOURCES; + } // Convert the map control block back to encoded data runs - ConvertLargeMCBToDataRuns(&DataRunsMCB, RunBuffer, Vcb->NtfsInfo.BytesPerCluster, &RunBufferOffset); + ConvertLargeMCBToDataRuns(&AttrContext->DataRunsMCB, RunBuffer, Vcb->NtfsInfo.BytesPerCluster, &RunBufferSize); // Update HighestVCN DestinationAttribute->NonResident.HighestVCN = AttrContext->Record.NonResident.HighestVCN; @@ -836,27 +797,23 @@ FreeClusters(PNTFS_VCB Vcb, // Write data runs to destination attribute RtlCopyMemory((PVOID)((ULONG_PTR)DestinationAttribute + DestinationAttribute->NonResident.MappingPairsOffset), RunBuffer, - RunBufferOffset); + RunBufferSize); + // Is DestinationAttribute the last attribute in the file record? if (NextAttribute->Type == AttributeEnd) { // update attribute length - AttrContext->Record.Length = ALIGN_UP_BY(AttrContext->Record.NonResident.MappingPairsOffset + RunBufferOffset, 8); + AttrContext->Record.Length = ALIGN_UP_BY(AttrContext->Record.NonResident.MappingPairsOffset + RunBufferSize, 8); DestinationAttribute->Length = AttrContext->Record.Length; // write end markers NextAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)DestinationAttribute + DestinationAttribute->Length); - NextAttribute->Type = AttributeEnd; - NextAttribute->Length = FILE_RECORD_END; - - // update file record length - FileRecord->BytesInUse = AttrOffset + DestinationAttribute->Length + (sizeof(ULONG) * 2); + SetFileRecordEnd(FileRecord, NextAttribute, FILE_RECORD_END); } // Update the file record Status = UpdateFileRecord(Vcb, AttrContext->FileMFTIndex, FileRecord); - FsRtlUninitializeLargeMcb(&DataRunsMCB); ExFreePoolWithTag(RunBuffer, TAG_NTFS); NtfsDumpDataRuns((PUCHAR)((ULONG_PTR)DestinationAttribute + DestinationAttribute->NonResident.MappingPairsOffset), 0); diff --git a/drivers/filesystems/ntfs/mft.c b/drivers/filesystems/ntfs/mft.c index 8b588d760b6..e78be291844 100644 --- a/drivers/filesystems/ntfs/mft.c +++ b/drivers/filesystems/ntfs/mft.c @@ -50,8 +50,10 @@ PrepareAttributeContext(PNTFS_ATTR_RECORD AttrRecord) { LONGLONG DataRunOffset; ULONGLONG DataRunLength; + ULONGLONG NextVBN = 0; + PUCHAR DataRun = (PUCHAR)&Context->Record + Context->Record.NonResident.MappingPairsOffset; - Context->CacheRun = (PUCHAR)&Context->Record + Context->Record.NonResident.MappingPairsOffset; + Context->CacheRun = DataRun; Context->CacheRunOffset = 0; Context->CacheRun = DecodeRun(Context->CacheRun, &DataRunOffset, &DataRunLength); Context->CacheRunLength = DataRunLength; @@ -68,6 +70,14 @@ PrepareAttributeContext(PNTFS_ATTR_RECORD AttrRecord) Context->CacheRunLastLCN = 0; } Context->CacheRunCurrentOffset = 0; + + // Convert the data runs to a map control block + if (!NT_SUCCESS(ConvertDataRunsToLargeMCB(DataRun, &Context->DataRunsMCB, &NextVBN))) + { + DPRINT1("Unable to convert data runs to MCB!\n"); + ExFreePoolWithTag(Context, TAG_NTFS); + return NULL; + } } return Context; @@ -77,6 +87,11 @@ PrepareAttributeContext(PNTFS_ATTR_RECORD AttrRecord) VOID ReleaseAttributeContext(PNTFS_ATTR_CONTEXT Context) { + if (Context->Record.IsNonResident) + { + FsRtlUninitializeLargeMcb(&Context->DataRunsMCB); + } + ExFreePoolWithTag(Context, TAG_NTFS); } @@ -246,10 +261,30 @@ SetAttributeDataLength(PFILE_OBJECT FileObject, ULONG NextAssignedCluster; ULONG AssignedClusters; - NTSTATUS Status = GetLastClusterInDataRun(Fcb->Vcb, &AttrContext->Record, (PULONGLONG)&LastClusterInDataRun.QuadPart); + if (ExistingClusters == 0) + { + LastClusterInDataRun.QuadPart = 0; + } + else + { + if (!FsRtlLookupLargeMcbEntry(&AttrContext->DataRunsMCB, + (LONGLONG)AttrContext->Record.NonResident.HighestVCN, + (PLONGLONG)&LastClusterInDataRun.QuadPart, + NULL, + NULL, + NULL, + NULL)) + { + DPRINT1("Error looking up final large MCB entry!\n"); - DPRINT1("GetLastClusterInDataRun returned: %I64u\n", LastClusterInDataRun.QuadPart); - DPRINT1("Highest VCN of record: %I64u\n", AttrContext->Record.NonResident.HighestVCN); + // Most likely, HighestVCN went above the largest mapping + DPRINT1("Highest VCN of record: %I64u\n", AttrContext->Record.NonResident.HighestVCN); + return STATUS_INVALID_PARAMETER; + } + } + + DPRINT("LastClusterInDataRun: %I64u\n", LastClusterInDataRun.QuadPart); + DPRINT("Highest VCN of record: %I64u\n", AttrContext->Record.NonResident.HighestVCN); while (ClustersNeeded > 0) { @@ -405,6 +440,9 @@ ReadAttribute(PDEVICE_EXTENSION Vcb, ULONG ReadLength; ULONG AlreadyRead; NTSTATUS Status; + + //TEMPTEMP + PUCHAR TempBuffer; if (!Context->Record.IsNonResident) { @@ -438,10 +476,21 @@ ReadAttribute(PDEVICE_EXTENSION Vcb, } else { + //TEMPTEMP + ULONG UsedBufferSize; + TempBuffer = ExAllocatePoolWithTag(NonPagedPool, Vcb->NtfsInfo.BytesPerFileRecord, TAG_NTFS); + LastLCN = 0; - DataRun = (PUCHAR)&Context->Record + Context->Record.NonResident.MappingPairsOffset; CurrentOffset = 0; + // This will be rewritten in the next iteration to just use the DataRuns MCB directly + ConvertLargeMCBToDataRuns(&Context->DataRunsMCB, + TempBuffer, + Vcb->NtfsInfo.BytesPerFileRecord, + &UsedBufferSize); + + DataRun = TempBuffer; + while (1) { DataRun = DecodeRun(DataRun, &DataRunOffset, &DataRunLength); @@ -558,6 +607,10 @@ ReadAttribute(PDEVICE_EXTENSION Vcb, } /* if Disk */ + // TEMPTEMP + if (Context->Record.IsNonResident) + ExFreePoolWithTag(TempBuffer, TAG_NTFS); + Context->CacheRun = DataRun; Context->CacheRunOffset = Offset + AlreadyRead; Context->CacheRunStartLCN = DataRunStartLCN; @@ -622,6 +675,10 @@ WriteAttribute(PDEVICE_EXTENSION Vcb, NTSTATUS Status; PUCHAR SourceBuffer = Buffer; LONGLONG StartingOffset; + + //TEMPTEMP + PUCHAR TempBuffer; + DPRINT("WriteAttribute(%p, %p, %I64u, %p, %lu, %p)\n", Vcb, Context, Offset, Buffer, Length, RealLengthWritten); @@ -707,9 +764,19 @@ WriteAttribute(PDEVICE_EXTENSION Vcb, } else*/ { + ULONG UsedBufferSize; LastLCN = 0; - DataRun = (PUCHAR)&Context->Record + Context->Record.NonResident.MappingPairsOffset; - CurrentOffset = 0; + CurrentOffset = 0; + + // This will be rewritten in the next iteration to just use the DataRuns MCB directly + TempBuffer = ExAllocatePoolWithTag(NonPagedPool, Vcb->NtfsInfo.BytesPerFileRecord, TAG_NTFS); + + ConvertLargeMCBToDataRuns(&Context->DataRunsMCB, + TempBuffer, + Vcb->NtfsInfo.BytesPerFileRecord, + &UsedBufferSize); + + DataRun = TempBuffer; while (1) { @@ -864,6 +931,10 @@ WriteAttribute(PDEVICE_EXTENSION Vcb, } } // end while (Length > 0) [more data to write] + // TEMPTEMP + if(Context->Record.IsNonResident) + ExFreePoolWithTag(TempBuffer, TAG_NTFS); + Context->CacheRun = DataRun; Context->CacheRunOffset = Offset + *RealLengthWritten; Context->CacheRunStartLCN = DataRunStartLCN; diff --git a/drivers/filesystems/ntfs/ntfs.h b/drivers/filesystems/ntfs/ntfs.h index 5a36bcc9fe9..462980d45df 100644 --- a/drivers/filesystems/ntfs/ntfs.h +++ b/drivers/filesystems/ntfs/ntfs.h @@ -437,6 +437,7 @@ typedef struct _NTFS_ATTR_CONTEXT ULONGLONG CacheRunLength; LONGLONG CacheRunLastLCN; ULONGLONG CacheRunCurrentOffset; + LARGE_MCB DataRunsMCB; ULONGLONG FileMFTIndex; NTFS_ATTR_RECORD Record; } NTFS_ATTR_CONTEXT, *PNTFS_ATTR_CONTEXT; diff --git a/drivers/filesystems/ntfs/rw.c b/drivers/filesystems/ntfs/rw.c index 4db1c388153..5afb87e9e60 100644 --- a/drivers/filesystems/ntfs/rw.c +++ b/drivers/filesystems/ntfs/rw.c @@ -432,22 +432,6 @@ NTSTATUS NtfsWriteFile(PDEVICE_EXTENSION DeviceExt, return Status; } - // at this point the record in DataContext may be stale, so we need to refresh it - ReleaseAttributeContext(DataContext); - - Status = FindAttribute(DeviceExt, - FileRecord, - AttributeData, - Fcb->Stream, - wcslen(Fcb->Stream), - &DataContext, - &AttributeOffset); - if (!NT_SUCCESS(Status)) - { - DPRINT1("DRIVER ERROR: Couldn't find $DATA attribute after setting size!\n"); - return Status; - } - // now we need to update this file's size in every directory index entry that references it // TODO: put this code in its own function and adapt it to work with every filename / hardlink // stored in the file record.