Author: tthompson Date: Sun Aug 6 02:54:15 2017 New Revision: 75493 URL: http://svn.reactos.org/svn/reactos?rev=75493&view=rev Log: [NTFS] - Refactor to allow the copy of the attribute stored in NTFS_ATTR_CONTEXT to have a dynamic length; change Record member from an NTFS_ATTR_RECORD to a PNTFS_ATTR_RECORD. Rename it pRecord to reinforce the change. Fix some bugs related to the record size changing. -PrepareAttributeContext() - update to allocate memory for pRecord. Don't assume allocations are succeeding. -ReleaseAttributeContext() - update to free memory for pRecord. -InternalSetResidentAttributeLength() - Increase size of AttrContext->pRecord as needed. Update to return an NTSTATUS. -SetResidentAttributeDataLength() - Fix bug that could occur when migrating resident attributes to non-resident if AttrContext->pRecord is too small for the new attribute. -AddRun() - Fix a bug by reallocating AttrContext->pRecord if the record needs to be enlarged.
Modified: branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/attrib.c branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/btree.c branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/dirctl.c branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/fcb.c branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/finfo.c branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/fsctl.c branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/mft.c branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/ntfs.h branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/rw.c branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/volinfo.c Modified: branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/attrib.c URL: http://svn.reactos.org/svn/reactos/branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/attrib.c?rev=75493&r1=75492&r2=75493&view=diff ============================================================================== --- branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/attrib.c [iso-8859-1] (original) +++ branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/attrib.c [iso-8859-1] Sun Aug 6 02:54:15 2017 @@ -303,17 +303,17 @@ NTSTATUS Status; int DataRunMaxLength; PNTFS_ATTR_RECORD DestinationAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + AttrOffset); - ULONG NextAttributeOffset = AttrOffset + AttrContext->Record.Length; + ULONG NextAttributeOffset = AttrOffset + AttrContext->pRecord->Length; ULONGLONG NextVBN = 0; PUCHAR RunBuffer; ULONG RunBufferSize; - if (!AttrContext->Record.IsNonResident) + if (!AttrContext->pRecord->IsNonResident) return STATUS_INVALID_PARAMETER; - if (AttrContext->Record.NonResident.AllocatedSize != 0) - NextVBN = AttrContext->Record.NonResident.HighestVCN + 1; + if (AttrContext->pRecord->NonResident.AllocatedSize != 0) + NextVBN = AttrContext->pRecord->NonResident.HighestVCN + 1; // Add newly-assigned clusters to mcb _SEH2_TRY @@ -344,12 +344,14 @@ 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; + DataRunMaxLength = AttrContext->pRecord->Length - AttrContext->pRecord->NonResident.MappingPairsOffset; // Do we need to extend the attribute (or convert to attribute list)? if (DataRunMaxLength < RunBufferSize) { PNTFS_ATTR_RECORD NextAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + NextAttributeOffset); + PNTFS_ATTR_RECORD NewRecord; + DataRunMaxLength += Vcb->NtfsInfo.BytesPerFileRecord - NextAttributeOffset - (sizeof(ULONG) * 2); // Can we move the end of the attribute? @@ -363,12 +365,22 @@ } // calculate position of end markers - NextAttributeOffset = AttrOffset + AttrContext->Record.NonResident.MappingPairsOffset + RunBufferSize; + NextAttributeOffset = AttrOffset + AttrContext->pRecord->NonResident.MappingPairsOffset + RunBufferSize; NextAttributeOffset = ALIGN_UP_BY(NextAttributeOffset, ATTR_RECORD_ALIGNMENT); - // Update the length + // Update the length of the destination attribute DestinationAttribute->Length = NextAttributeOffset - AttrOffset; - AttrContext->Record.Length = DestinationAttribute->Length; + + // Create a new copy of the attribute + NewRecord = ExAllocatePoolWithTag(NonPagedPool, DestinationAttribute->Length, TAG_NTFS); + RtlCopyMemory(NewRecord, AttrContext->pRecord, AttrContext->pRecord->Length); + NewRecord->Length = DestinationAttribute->Length; + + // Free the old copy of the attribute, which won't be large enough + ExFreePoolWithTag(AttrContext->pRecord, TAG_NTFS); + + // Set the attribute context's record to the new copy + AttrContext->pRecord = NewRecord; // End the file record NextAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + NextAttributeOffset); @@ -377,12 +389,17 @@ // Update HighestVCN DestinationAttribute->NonResident.HighestVCN = - AttrContext->Record.NonResident.HighestVCN = max(NextVBN - 1 + RunLength, - AttrContext->Record.NonResident.HighestVCN); + AttrContext->pRecord->NonResident.HighestVCN = max(NextVBN - 1 + RunLength, + AttrContext->pRecord->NonResident.HighestVCN); // Write data runs to destination attribute RtlCopyMemory((PVOID)((ULONG_PTR)DestinationAttribute + DestinationAttribute->NonResident.MappingPairsOffset), RunBuffer, + RunBufferSize); + + // Update the attribute copy in the attribute context + RtlCopyMemory((PVOID)((ULONG_PTR)AttrContext->pRecord + AttrContext->pRecord->NonResident.MappingPairsOffset), + RunBuffer, RunBufferSize); // Update the file record @@ -723,7 +740,7 @@ ULONG ClustersLeftToFree = ClustersToFree; PNTFS_ATTR_RECORD DestinationAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + AttrOffset); - ULONG NextAttributeOffset = AttrOffset + AttrContext->Record.Length; + ULONG NextAttributeOffset = AttrOffset + AttrContext->pRecord->Length; PNTFS_ATTR_RECORD NextAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + NextAttributeOffset); PUCHAR RunBuffer; @@ -736,7 +753,7 @@ RTL_BITMAP Bitmap; ULONG LengthWritten; - if (!AttrContext->Record.IsNonResident) + if (!AttrContext->pRecord->IsNonResident) { return STATUS_INVALID_PARAMETER; } @@ -767,7 +784,7 @@ return 0; } - BitmapDataSize = AttributeDataLength(&DataContext->Record); + BitmapDataSize = AttributeDataLength(DataContext->pRecord); BitmapDataSize = min(BitmapDataSize, ULONG_MAX); ASSERT((BitmapDataSize * 8) >= Vcb->NtfsInfo.ClusterCount); BitmapData = ExAllocatePoolWithTag(NonPagedPool, ROUND_UP(BitmapDataSize, Vcb->NtfsInfo.BytesPerSector), TAG_NTFS); @@ -802,10 +819,10 @@ // deallocate this cluster RtlClearBits(&Bitmap, LargeLbn, 1); } - FsRtlTruncateLargeMcb(&AttrContext->DataRunsMCB, AttrContext->Record.NonResident.HighestVCN); + FsRtlTruncateLargeMcb(&AttrContext->DataRunsMCB, AttrContext->pRecord->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); + AttrContext->pRecord->NonResident.HighestVCN = min(AttrContext->pRecord->NonResident.HighestVCN, AttrContext->pRecord->NonResident.HighestVCN - 1); ClustersLeftToFree--; } @@ -837,7 +854,7 @@ ConvertLargeMCBToDataRuns(&AttrContext->DataRunsMCB, RunBuffer, Vcb->NtfsInfo.BytesPerCluster, &RunBufferSize); // Update HighestVCN - DestinationAttribute->NonResident.HighestVCN = AttrContext->Record.NonResident.HighestVCN; + DestinationAttribute->NonResident.HighestVCN = AttrContext->pRecord->NonResident.HighestVCN; // Write data runs to destination attribute RtlCopyMemory((PVOID)((ULONG_PTR)DestinationAttribute + DestinationAttribute->NonResident.MappingPairsOffset), @@ -848,9 +865,12 @@ if (NextAttribute->Type == AttributeEnd) { // update attribute length - AttrContext->Record.Length = ALIGN_UP_BY(AttrContext->Record.NonResident.MappingPairsOffset + RunBufferSize, + DestinationAttribute->Length = ALIGN_UP_BY(AttrContext->pRecord->NonResident.MappingPairsOffset + RunBufferSize, ATTR_RECORD_ALIGNMENT); - DestinationAttribute->Length = AttrContext->Record.Length; + + ASSERT(DestinationAttribute->Length <= AttrContext->pRecord->Length); + + AttrContext->pRecord->Length = DestinationAttribute->Length; // write end markers NextAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)DestinationAttribute + DestinationAttribute->Length); @@ -893,7 +913,7 @@ } ListContext = PrepareAttributeContext(Attribute); - ListSize = AttributeDataLength(&ListContext->Record); + ListSize = AttributeDataLength(ListContext->pRecord); if (ListSize > 0xFFFFFFFF) { ReleaseAttributeContext(ListContext); Modified: branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/btree.c URL: http://svn.reactos.org/svn/reactos/branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/btree.c?rev=75493&r1=75492&r2=75493&view=diff ============================================================================== --- branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/btree.c [iso-8859-1] (original) +++ branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/btree.c [iso-8859-1] Sun Aug 6 02:54:15 2017 @@ -41,7 +41,7 @@ { ULONGLONG CurrentOffset = 0; PINDEX_BUFFER CurrentNode, Buffer; - ULONGLONG BufferSize = AttributeDataLength(&IndexAllocationContext->Record); + ULONGLONG BufferSize = AttributeDataLength(IndexAllocationContext->pRecord); ULONG BytesRead; ULONGLONG i; int Count = 0; @@ -393,7 +393,7 @@ Tree->RootNode = RootNode; // Make sure we won't try reading past the attribute-end - if (FIELD_OFFSET(INDEX_ROOT_ATTRIBUTE, Header) + IndexRoot->Header.TotalSizeOfEntries > IndexRootContext->Record.Resident.ValueLength) + if (FIELD_OFFSET(INDEX_ROOT_ATTRIBUTE, Header) + IndexRoot->Header.TotalSizeOfEntries > IndexRootContext->pRecord->Resident.ValueLength) { DPRINT1("Filesystem corruption detected!\n"); DestroyBTree(Tree); Modified: branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/dirctl.c URL: http://svn.reactos.org/svn/reactos/branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/dirctl.c?rev=75493&r1=75492&r2=75493&view=diff ============================================================================== --- branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/dirctl.c [iso-8859-1] (original) +++ branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/dirctl.c [iso-8859-1] Sun Aug 6 02:54:15 2017 @@ -49,8 +49,8 @@ Status = FindAttribute(DeviceExt, FileRecord, AttributeData, Stream, StreamLength, &DataContext, NULL); if (NT_SUCCESS(Status)) { - Size = AttributeDataLength(&DataContext->Record); - Allocated = AttributeAllocatedLength(&DataContext->Record); + Size = AttributeDataLength(DataContext->pRecord); + Allocated = AttributeAllocatedLength(DataContext->pRecord); ReleaseAttributeContext(DataContext); } Modified: branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/fcb.c URL: http://svn.reactos.org/svn/reactos/branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/fcb.c?rev=75493&r1=75492&r2=75493&view=diff ============================================================================== --- branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/fcb.c [iso-8859-1] (original) +++ branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/fcb.c [iso-8859-1] Sun Aug 6 02:54:15 2017 @@ -756,7 +756,7 @@ return Status; } - AttrLength = AttributeDataLength(&AttrCtxt->Record); + AttrLength = AttributeDataLength(AttrCtxt->pRecord); *Data = ExAllocatePoolWithTag(NonPagedPool, AttrLength, TAG_NTFS); if (*Data == NULL) { Modified: branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/finfo.c URL: http://svn.reactos.org/svn/reactos/branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/finfo.c?rev=75493&r1=75492&r2=75493&view=diff ============================================================================== --- branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/finfo.c [iso-8859-1] (original) +++ branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/finfo.c [iso-8859-1] Sun Aug 6 02:54:15 2017 @@ -631,7 +631,7 @@ } // Get the size of the data attribute - CurrentFileSize.QuadPart = AttributeDataLength(&DataContext->Record); + CurrentFileSize.QuadPart = AttributeDataLength(DataContext->pRecord); // Are we enlarging the attribute? if (NewFileSize->QuadPart > CurrentFileSize.QuadPart) @@ -673,7 +673,7 @@ FileName.Length = FileNameAttribute->NameLength * sizeof(WCHAR); FileName.MaximumLength = FileName.Length; - AllocationSize = AttributeAllocatedLength(&DataContext->Record); + AllocationSize = AttributeAllocatedLength(DataContext->pRecord); Status = UpdateFileNameRecord(Fcb->Vcb, ParentMFTId, Modified: branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/fsctl.c URL: http://svn.reactos.org/svn/reactos/branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/fsctl.c?rev=75493&r1=75492&r2=75493&view=diff ============================================================================== --- branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/fsctl.c [iso-8859-1] (original) +++ branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/fsctl.c [iso-8859-1] Sun Aug 6 02:54:15 2017 @@ -341,9 +341,9 @@ /* Get volume name */ Status = FindAttribute(DeviceExt, VolumeRecord, AttributeVolumeName, L"", 0, &AttrCtxt, NULL); - if (NT_SUCCESS(Status) && AttrCtxt->Record.Resident.ValueLength != 0) - { - Attribute = &AttrCtxt->Record; + if (NT_SUCCESS(Status) && AttrCtxt->pRecord->Resident.ValueLength != 0) + { + Attribute = AttrCtxt->pRecord; DPRINT("Data length %lu\n", AttributeDataLength(Attribute)); NtfsInfo->VolumeLabelLength = min (Attribute->Resident.ValueLength, MAXIMUM_VOLUME_LABEL_LENGTH); @@ -382,9 +382,9 @@ /* Get volume information */ Status = FindAttribute(DeviceExt, VolumeRecord, AttributeVolumeInformation, L"", 0, &AttrCtxt, NULL); - if (NT_SUCCESS(Status) && AttrCtxt->Record.Resident.ValueLength != 0) - { - Attribute = &AttrCtxt->Record; + if (NT_SUCCESS(Status) && AttrCtxt->pRecord->Resident.ValueLength != 0) + { + Attribute = AttrCtxt->pRecord; DPRINT("Data length %lu\n", AttributeDataLength (Attribute)); VolumeInfo = (PVOID)((ULONG_PTR)Attribute + Attribute->Resident.ValueOffset); Modified: branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/mft.c URL: http://svn.reactos.org/svn/reactos/branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/mft.c?rev=75493&r1=75492&r2=75493&view=diff ============================================================================== --- branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/mft.c [iso-8859-1] (original) +++ branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/mft.c [iso-8859-1] Sun Aug 6 02:54:15 2017 @@ -42,15 +42,32 @@ PNTFS_ATTR_CONTEXT Context; Context = ExAllocatePoolWithTag(NonPagedPool, - FIELD_OFFSET(NTFS_ATTR_CONTEXT, Record) + AttrRecord->Length, + sizeof(NTFS_ATTR_CONTEXT), TAG_NTFS); - RtlCopyMemory(&Context->Record, AttrRecord, AttrRecord->Length); + if(!Context) + { + DPRINT1("Error: Unable to allocate memory for context!\n"); + return NULL; + } + + // Allocate memory for a copy of the attribute + Context->pRecord = ExAllocatePoolWithTag(NonPagedPool, AttrRecord->Length, TAG_NTFS); + if(!Context->pRecord) + { + DPRINT1("Error: Unable to allocate memory for attribute record!\n"); + ExFreePoolWithTag(Context, TAG_NTFS); + return NULL; + } + + // Copy the attribute + RtlCopyMemory(Context->pRecord, AttrRecord, AttrRecord->Length); + if (AttrRecord->IsNonResident) { LONGLONG DataRunOffset; ULONGLONG DataRunLength; ULONGLONG NextVBN = 0; - PUCHAR DataRun = (PUCHAR)&Context->Record + Context->Record.NonResident.MappingPairsOffset; + PUCHAR DataRun = (PUCHAR)((ULONG_PTR)Context->pRecord + Context->pRecord->NonResident.MappingPairsOffset); Context->CacheRun = DataRun; Context->CacheRunOffset = 0; @@ -74,6 +91,7 @@ if (!NT_SUCCESS(ConvertDataRunsToLargeMCB(DataRun, &Context->DataRunsMCB, &NextVBN))) { DPRINT1("Unable to convert data runs to MCB!\n"); + ExFreePoolWithTag(Context->pRecord, TAG_NTFS); ExFreePoolWithTag(Context, TAG_NTFS); return NULL; } @@ -86,10 +104,13 @@ VOID ReleaseAttributeContext(PNTFS_ATTR_CONTEXT Context) { - if (Context->Record.IsNonResident) + if (Context->pRecord->IsNonResident) { FsRtlUninitializeLargeMcb(&Context->DataRunsMCB); } + + if(Context->pRecord) + ExFreePoolWithTag(Context->pRecord, TAG_NTFS); ExFreePoolWithTag(Context, TAG_NTFS); } @@ -245,10 +266,10 @@ } // Get size of Bitmap Attribute - BitmapSize.QuadPart = AttributeDataLength(&BitmapContext->Record); + BitmapSize.QuadPart = AttributeDataLength(BitmapContext->pRecord); // Calculate the new mft size - DataSize.QuadPart = AttributeDataLength(&(Vcb->MFTContext->Record)) + DataSizeDifference; + DataSize.QuadPart = AttributeDataLength(Vcb->MFTContext->pRecord) + DataSizeDifference; // Determine how many bytes will make up the bitmap BitmapBytes = DataSize.QuadPart / Vcb->NtfsInfo.BytesPerFileRecord / 8; @@ -301,7 +322,7 @@ { // Set the new bitmap size BitmapSize.QuadPart += BitmapSizeDifference; - if (BitmapContext->Record.IsNonResident) + if (BitmapContext->pRecord->IsNonResident) Status = SetNonResidentAttributeDataLength(Vcb, BitmapContext, BitmapOffset, Vcb->MasterFileTable, &BitmapSize); else Status = SetResidentAttributeDataLength(Vcb, BitmapContext, BitmapOffset, Vcb->MasterFileTable, &BitmapSize); @@ -348,7 +369,7 @@ return STATUS_SUCCESS; } -VOID +NTSTATUS InternalSetResidentAttributeLength(PNTFS_ATTR_CONTEXT AttrContext, PFILE_RECORD_HEADER FileRecord, ULONG AttrOffset, @@ -356,32 +377,45 @@ { PNTFS_ATTR_RECORD Destination = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + AttrOffset); ULONG NextAttributeOffset; + USHORT ValueOffset; DPRINT("InternalSetResidentAttributeLength( %p, %p, %lu, %lu )\n", AttrContext, FileRecord, AttrOffset, DataSize); - ASSERT(!AttrContext->Record.IsNonResident); - - // update ValueLength Field - AttrContext->Record.Resident.ValueLength = + ASSERT(!AttrContext->pRecord->IsNonResident); + + // Update ValueLength Field Destination->Resident.ValueLength = DataSize; - // calculate the record length and end marker offset - AttrContext->Record.Length = - Destination->Length = DataSize + AttrContext->Record.Resident.ValueOffset; - NextAttributeOffset = AttrOffset + AttrContext->Record.Length; + // Calculate the record length and end marker offset + Destination->Length = ALIGN_UP_BY(DataSize + AttrContext->pRecord->Resident.ValueOffset, ATTR_RECORD_ALIGNMENT); + NextAttributeOffset = AttrOffset + Destination->Length; + + // Ensure FileRecord has an up-to-date copy of the attribute + ValueOffset = AttrContext->pRecord->Resident.ValueOffset; + RtlCopyMemory((PCHAR)((ULONG_PTR)FileRecord + AttrOffset + ValueOffset), + (PCHAR)((ULONG_PTR)AttrContext->pRecord + ValueOffset), + min(DataSize, AttrContext->pRecord->Resident.ValueLength)); + + // Free the old copy of the attribute in the context, as it will be the wrong length + ExFreePoolWithTag(AttrContext->pRecord, TAG_NTFS); + + // Create a new copy of the attribute for the context + AttrContext->pRecord = ExAllocatePoolWithTag(NonPagedPool, Destination->Length, TAG_NTFS); + if (!AttrContext->pRecord) + { + DPRINT1("Unable to allocate memory for attribute!\n"); + return STATUS_INSUFFICIENT_RESOURCES; + } + RtlCopyMemory(AttrContext->pRecord, Destination, Destination->Length); // Ensure NextAttributeOffset is aligned to an 8-byte boundary - if (NextAttributeOffset % 8 != 0) - { - USHORT Padding = ATTR_RECORD_ALIGNMENT - (NextAttributeOffset % ATTR_RECORD_ALIGNMENT); - NextAttributeOffset += Padding; - AttrContext->Record.Length += Padding; - Destination->Length += Padding; - } + ASSERT(NextAttributeOffset % ATTR_RECORD_ALIGNMENT == 0); // advance Destination to the final "attribute" and set the file record end Destination = (PNTFS_ATTR_RECORD)((ULONG_PTR)Destination + Destination->Length); SetFileRecordEnd(FileRecord, Destination, FILE_RECORD_END); + + return STATUS_SUCCESS; } /** @@ -408,7 +442,7 @@ DataSize->QuadPart); // are we truncating the file? - if (DataSize->QuadPart < AttributeDataLength(&AttrContext->Record)) + if (DataSize->QuadPart < AttributeDataLength(AttrContext->pRecord)) { if (!MmCanFileBeTruncated(FileObject->SectionObjectPointer, DataSize)) { @@ -417,7 +451,7 @@ } } - if (AttrContext->Record.IsNonResident) + if (AttrContext->pRecord->IsNonResident) { Status = SetNonResidentAttributeDataLength(Fcb->Vcb, AttrContext, @@ -448,8 +482,8 @@ if (NT_SUCCESS(Status)) { - if (AttrContext->Record.IsNonResident) - Fcb->RFCB.AllocationSize.QuadPart = AttrContext->Record.NonResident.AllocatedSize; + if (AttrContext->pRecord->IsNonResident) + Fcb->RFCB.AllocationSize.QuadPart = AttrContext->pRecord->NonResident.AllocatedSize; else Fcb->RFCB.AllocationSize = *DataSize; Fcb->RFCB.FileSize = *DataSize; @@ -538,12 +572,12 @@ ULONG BytesPerCluster = Vcb->NtfsInfo.BytesPerCluster; ULONGLONG AllocationSize = ROUND_UP(DataSize->QuadPart, BytesPerCluster); PNTFS_ATTR_RECORD DestinationAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + AttrOffset); - ULONG ExistingClusters = AttrContext->Record.NonResident.AllocatedSize / BytesPerCluster; - - ASSERT(AttrContext->Record.IsNonResident); + ULONG ExistingClusters = AttrContext->pRecord->NonResident.AllocatedSize / BytesPerCluster; + + ASSERT(AttrContext->pRecord->IsNonResident); // do we need to increase the allocation size? - if (AttrContext->Record.NonResident.AllocatedSize < AllocationSize) + if (AttrContext->pRecord->NonResident.AllocatedSize < AllocationSize) { ULONG ClustersNeeded = (AllocationSize / BytesPerCluster) - ExistingClusters; LARGE_INTEGER LastClusterInDataRun; @@ -557,7 +591,7 @@ else { if (!FsRtlLookupLargeMcbEntry(&AttrContext->DataRunsMCB, - (LONGLONG)AttrContext->Record.NonResident.HighestVCN, + (LONGLONG)AttrContext->pRecord->NonResident.HighestVCN, (PLONGLONG)&LastClusterInDataRun.QuadPart, NULL, NULL, @@ -567,13 +601,13 @@ DPRINT1("Error looking up final large MCB entry!\n"); // Most likely, HighestVCN went above the largest mapping - DPRINT1("Highest VCN of record: %I64u\n", AttrContext->Record.NonResident.HighestVCN); + DPRINT1("Highest VCN of record: %I64u\n", AttrContext->pRecord->NonResident.HighestVCN); return STATUS_INVALID_PARAMETER; } } DPRINT("LastClusterInDataRun: %I64u\n", LastClusterInDataRun.QuadPart); - DPRINT("Highest VCN of record: %I64u\n", AttrContext->Record.NonResident.HighestVCN); + DPRINT("Highest VCN of record: %I64u\n", AttrContext->pRecord->NonResident.HighestVCN); while (ClustersNeeded > 0) { @@ -601,7 +635,7 @@ LastClusterInDataRun.LowPart = NextAssignedCluster + AssignedClusters - 1; } } - else if (AttrContext->Record.NonResident.AllocatedSize > AllocationSize) + else if (AttrContext->pRecord->NonResident.AllocatedSize > AllocationSize) { // shrink allocation size ULONG ClustersToFree = ExistingClusters - (AllocationSize / BytesPerCluster); @@ -610,9 +644,9 @@ // TODO: is the file compressed, encrypted, or sparse? - AttrContext->Record.NonResident.AllocatedSize = AllocationSize; - AttrContext->Record.NonResident.DataSize = DataSize->QuadPart; - AttrContext->Record.NonResident.InitializedSize = DataSize->QuadPart; + AttrContext->pRecord->NonResident.AllocatedSize = AllocationSize; + AttrContext->pRecord->NonResident.DataSize = DataSize->QuadPart; + AttrContext->pRecord->NonResident.InitializedSize = DataSize->QuadPart; DestinationAttribute->NonResident.AllocatedSize = AllocationSize; DestinationAttribute->NonResident.DataSize = DataSize->QuadPart; @@ -667,18 +701,18 @@ NTSTATUS Status; // find the next attribute - ULONG NextAttributeOffset = AttrOffset + AttrContext->Record.Length; + ULONG NextAttributeOffset = AttrOffset + AttrContext->pRecord->Length; PNTFS_ATTR_RECORD NextAttribute = (PNTFS_ATTR_RECORD)((PCHAR)FileRecord + NextAttributeOffset); - ASSERT(!AttrContext->Record.IsNonResident); + ASSERT(!AttrContext->pRecord->IsNonResident); //NtfsDumpFileAttributes(Vcb, FileRecord); // Do we need to increase the data length? - if (DataSize->QuadPart > AttrContext->Record.Resident.ValueLength) + if (DataSize->QuadPart > AttrContext->pRecord->Resident.ValueLength) { // There's usually padding at the end of a record. Do we need to extend past it? - ULONG MaxValueLength = AttrContext->Record.Length - AttrContext->Record.Resident.ValueOffset; + ULONG MaxValueLength = AttrContext->pRecord->Length - AttrContext->pRecord->Resident.ValueOffset; if (MaxValueLength < DataSize->LowPart) { // If this is the last attribute, we could move the end marker to the very end of the file record @@ -688,14 +722,16 @@ { // convert attribute to non-resident PNTFS_ATTR_RECORD Destination = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + AttrOffset); + PNTFS_ATTR_RECORD NewRecord; LARGE_INTEGER AttribDataSize; PVOID AttribData; + ULONG NewRecordLength; ULONG EndAttributeOffset; ULONG LengthWritten; DPRINT1("Converting attribute to non-resident.\n"); - AttribDataSize.QuadPart = AttrContext->Record.Resident.ValueLength; + AttribDataSize.QuadPart = AttrContext->pRecord->Resident.ValueLength; // Is there existing data we need to back-up? if (AttribDataSize.QuadPart > 0) @@ -719,23 +755,43 @@ // Start by turning this attribute into a 0-length, non-resident attribute, then enlarge it. + // The size of a 0-length, non-resident attribute will be 0x41 + the size of the attribute name, aligned to an 8-byte boundary + NewRecordLength = ALIGN_UP_BY(0x41 + (AttrContext->pRecord->NameLength * sizeof(WCHAR)), ATTR_RECORD_ALIGNMENT); + + // Create a new attribute record that will store the 0-length, non-resident attribute + NewRecord = ExAllocatePoolWithTag(NonPagedPool, NewRecordLength, TAG_NTFS); + // Zero out the NonResident structure - RtlZeroMemory(&AttrContext->Record.NonResident.LowestVCN, - FIELD_OFFSET(NTFS_ATTR_RECORD, NonResident.CompressedSize) - FIELD_OFFSET(NTFS_ATTR_RECORD, NonResident.LowestVCN)); - RtlZeroMemory(&Destination->NonResident.LowestVCN, - FIELD_OFFSET(NTFS_ATTR_RECORD, NonResident.CompressedSize) - FIELD_OFFSET(NTFS_ATTR_RECORD, NonResident.LowestVCN)); - - // update the mapping pairs offset, which will be 0x40 + length in bytes of the name - AttrContext->Record.NonResident.MappingPairsOffset = Destination->NonResident.MappingPairsOffset = 0x40 + (Destination->NameLength * 2); + RtlZeroMemory(NewRecord, NewRecordLength); + + // Copy the data that's common to both non-resident and resident attributes + RtlCopyMemory(NewRecord, AttrContext->pRecord, FIELD_OFFSET(NTFS_ATTR_RECORD, Resident.ValueLength)); + + // if there's a name + if (AttrContext->pRecord->NameLength != 0) + { + // copy the name + // An attribute name will be located at offset 0x18 for a resident attribute, 0x40 for non-resident + RtlCopyMemory((PCHAR)((ULONG_PTR)NewRecord + 0x40), + (PCHAR)((ULONG_PTR)AttrContext->pRecord + 0x18), + AttrContext->pRecord->NameLength * sizeof(WCHAR)); + } + + // update the mapping pairs offset, which will be 0x40 (size of a non-resident header) + length in bytes of the name + NewRecord->NonResident.MappingPairsOffset = 0x40 + (AttrContext->pRecord->NameLength * sizeof(WCHAR)); // update the end of the file record // calculate position of end markers (1 byte for empty data run) - EndAttributeOffset = AttrOffset + AttrContext->Record.NonResident.MappingPairsOffset + 1; + EndAttributeOffset = AttrOffset + NewRecord->NonResident.MappingPairsOffset + 1; EndAttributeOffset = ALIGN_UP_BY(EndAttributeOffset, ATTR_RECORD_ALIGNMENT); // Update the length - Destination->Length = EndAttributeOffset - AttrOffset; - AttrContext->Record.Length = Destination->Length; + NewRecord->Length = EndAttributeOffset - AttrOffset; + + ASSERT(NewRecord->Length == NewRecordLength); + + // Copy the new attribute record into the file record + RtlCopyMemory(Destination, NewRecord, NewRecord->Length); // Update the file record end SetFileRecordEnd(FileRecord, @@ -756,7 +812,7 @@ } _SEH2_END; // Mark the attribute as non-resident (we wait until after we know the LargeMcb was initialized) - AttrContext->Record.IsNonResident = Destination->IsNonResident = 1; + NewRecord->IsNonResident = Destination->IsNonResident = 1; // Update file record on disk Status = UpdateFileRecord(Vcb, AttrContext->FileMFTIndex, FileRecord); @@ -767,6 +823,10 @@ ExFreePoolWithTag(AttribData, TAG_NTFS); return Status; } + + // Now we need to free the old copy of the attribute record in the context and replace it with the new one + ExFreePoolWithTag(AttrContext->pRecord, TAG_NTFS); + AttrContext->pRecord = NewRecord; // Now we can treat the attribute as non-resident and enlarge it normally Status = SetNonResidentAttributeDataLength(Vcb, AttrContext, AttrOffset, FileRecord, DataSize); @@ -795,7 +855,7 @@ } } } - else if (DataSize->LowPart < AttrContext->Record.Resident.ValueLength) + else if (DataSize->LowPart < AttrContext->pRecord->Resident.ValueLength) { // we need to decrease the length if (NextAttribute->Type != AttributeEnd) @@ -806,8 +866,8 @@ } // set the new length of the resident attribute (if we didn't migrate it) - if (!AttrContext->Record.IsNonResident) - InternalSetResidentAttributeLength(AttrContext, FileRecord, AttrOffset, DataSize->LowPart); + if (!AttrContext->pRecord->IsNonResident) + return InternalSetResidentAttributeLength(AttrContext, FileRecord, AttrOffset, DataSize->LowPart); return STATUS_SUCCESS; } @@ -832,13 +892,19 @@ //TEMPTEMP PUCHAR TempBuffer; - if (!Context->Record.IsNonResident) - { - if (Offset > Context->Record.Resident.ValueLength) + if (!Context->pRecord->IsNonResident) + { + // We need to truncate Offset to a ULONG for pointer arithmetic + // The check below should ensure that Offset is well within the range of 32 bits + ULONG LittleOffset = (ULONG)Offset; + + // Ensure that offset isn't beyond the end of the attribute + if (Offset > Context->pRecord->Resident.ValueLength) return 0; - if (Offset + Length > Context->Record.Resident.ValueLength) - Length = (ULONG)(Context->Record.Resident.ValueLength - Offset); - RtlCopyMemory(Buffer, (PCHAR)&Context->Record + Context->Record.Resident.ValueOffset + Offset, Length); + if (Offset + Length > Context->pRecord->Resident.ValueLength) + Length = (ULONG)(Context->pRecord->Resident.ValueLength - Offset); + + RtlCopyMemory(Buffer, (PVOID)((ULONG_PTR)Context->pRecord + Context->pRecord->Resident.ValueOffset + LittleOffset), Length); return Length; } @@ -996,7 +1062,7 @@ } /* if Disk */ // TEMPTEMP - if (Context->Record.IsNonResident) + if (Context->pRecord->IsNonResident) ExFreePoolWithTag(TempBuffer, TAG_NTFS); Context->CacheRun = DataRun; @@ -1073,13 +1139,13 @@ *RealLengthWritten = 0; // is this a resident attribute? - if (!Context->Record.IsNonResident) + if (!Context->pRecord->IsNonResident) { ULONG AttributeOffset; PNTFS_ATTR_CONTEXT FoundContext; PFILE_RECORD_HEADER FileRecord; - if (Offset + Length > Context->Record.Resident.ValueLength) + if (Offset + Length > Context->pRecord->Resident.ValueLength) { DPRINT1("DRIVER ERROR: Attribute is too small!\n"); return STATUS_INVALID_PARAMETER; @@ -1098,9 +1164,9 @@ // find where to write the attribute data to Status = FindAttribute(Vcb, FileRecord, - Context->Record.Type, - (PCWSTR)((PCHAR)&Context->Record + Context->Record.NameOffset), - Context->Record.NameLength, + Context->pRecord->Type, + (PCWSTR)((ULONG_PTR)Context->pRecord + Context->pRecord->NameOffset), + Context->pRecord->NameLength, &FoundContext, &AttributeOffset); @@ -1111,8 +1177,8 @@ return Status; } - DPRINT("Offset: %I64u, AttributeOffset: %u, ValueOffset: %u\n", Offset, AttributeOffset, Context->Record.Resident.ValueLength); - Offset += AttributeOffset + Context->Record.Resident.ValueOffset; + DPRINT("Offset: %I64u, AttributeOffset: %u, ValueOffset: %u\n", Offset, AttributeOffset, Context->pRecord->Resident.ValueLength); + Offset += AttributeOffset + Context->pRecord->Resident.ValueOffset; if (Offset + Length > Vcb->NtfsInfo.BytesPerFileRecord) { @@ -1320,7 +1386,7 @@ } // end while (Length > 0) [more data to write] // TEMPTEMP - if (Context->Record.IsNonResident) + if (Context->pRecord->IsNonResident) ExFreePoolWithTag(TempBuffer, TAG_NTFS); Context->CacheRun = DataRun; @@ -1419,7 +1485,7 @@ return STATUS_INSUFFICIENT_RESOURCES; } - Status = ReadAttribute(Vcb, IndexRootCtx, 0, IndexRecord, AttributeDataLength(&IndexRootCtx->Record)); + Status = ReadAttribute(Vcb, IndexRootCtx, 0, IndexRecord, AttributeDataLength(IndexRootCtx->pRecord)); if (!NT_SUCCESS(Status)) { DPRINT1("ERROR: Failed to read Index Root!\n"); @@ -1453,7 +1519,7 @@ { // we need to write the index root attribute back to disk ULONG LengthWritten; - Status = WriteAttribute(Vcb, IndexRootCtx, 0, (PUCHAR)IndexRecord, AttributeDataLength(&IndexRootCtx->Record), &LengthWritten); + Status = WriteAttribute(Vcb, IndexRootCtx, 0, (PUCHAR)IndexRecord, AttributeDataLength(IndexRootCtx->pRecord), &LengthWritten); if (!NT_SUCCESS(Status)) { DPRINT1("ERROR: Couldn't update Index Root!\n"); @@ -1551,7 +1617,7 @@ return Status; } - IndexAllocationSize = AttributeDataLength(&IndexAllocationCtx->Record); + IndexAllocationSize = AttributeDataLength(IndexAllocationCtx->pRecord); Status = STATUS_OBJECT_PATH_NOT_FOUND; for (RecordOffset = 0; RecordOffset < IndexAllocationSize; RecordOffset += IndexBlockSize) { @@ -1747,7 +1813,7 @@ } // allocate a buffer for the $Bitmap attribute - BitmapDataSize = AttributeDataLength(&BitmapContext->Record); + BitmapDataSize = AttributeDataLength(BitmapContext->pRecord); BitmapData = ExAllocatePoolWithTag(NonPagedPool, BitmapDataSize, TAG_NTFS); if (!BitmapData) { @@ -1772,7 +1838,7 @@ BitmapData[2] = 0xff; // Calculate bit count - BitmapBits.QuadPart = AttributeDataLength(&(DeviceExt->MFTContext->Record)) / + BitmapBits.QuadPart = AttributeDataLength(DeviceExt->MFTContext->pRecord) / DeviceExt->NtfsInfo.BytesPerFileRecord; if (BitmapBits.HighPart != 0) { @@ -1942,12 +2008,12 @@ // Find the maximum index size given what the file record can hold MaxIndexSize = DeviceExt->NtfsInfo.BytesPerFileRecord - IndexRootOffset - - IndexRootContext->Record.Resident.ValueOffset + - IndexRootContext->pRecord->Resident.ValueOffset - FIELD_OFFSET(INDEX_ROOT_ATTRIBUTE, Header) - (sizeof(ULONG) * 2); // Allocate memory for the index root data - I30IndexRootLength = AttributeDataLength(&IndexRootContext->Record); + I30IndexRootLength = AttributeDataLength(IndexRootContext->pRecord); I30IndexRoot = ExAllocatePoolWithTag(NonPagedPool, I30IndexRootLength, TAG_NTFS); if (!I30IndexRoot) { @@ -2035,7 +2101,7 @@ // $ATTRIBUTE_LIST's. AttributeLength = NewIndexRoot->Header.AllocatedSize + FIELD_OFFSET(INDEX_ROOT_ATTRIBUTE, Header); - if (AttributeLength != IndexRootContext->Record.Resident.ValueLength) + if (AttributeLength != IndexRootContext->pRecord->Resident.ValueLength) { DestinationAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)ParentFileRecord + IndexRootOffset); @@ -2052,10 +2118,20 @@ } // Update the length of the attribute in the file record of the parent directory - InternalSetResidentAttributeLength(IndexRootContext, - ParentFileRecord, - IndexRootOffset, - AttributeLength); + Status = InternalSetResidentAttributeLength(IndexRootContext, + ParentFileRecord, + IndexRootOffset, + AttributeLength); + if (!NT_SUCCESS(Status)) + { + ExFreePoolWithTag(NewIndexRoot, TAG_NTFS); + ReleaseAttributeContext(IndexRootContext); + ExFreePoolWithTag(I30IndexRoot, TAG_NTFS); + ExFreePoolWithTag(ParentFileRecord, TAG_NTFS); + DPRINT1("ERROR: Unable to set resident attribute length!\n"); + return Status; + } + } NT_ASSERT(ParentFileRecord->BytesInUse <= DeviceExt->NtfsInfo.BytesPerFileRecord); @@ -2295,7 +2371,7 @@ return Status; } - IndexAllocationSize = AttributeDataLength(&IndexAllocationCtx->Record); + IndexAllocationSize = AttributeDataLength(IndexAllocationCtx->pRecord); Status = STATUS_OBJECT_PATH_NOT_FOUND; for (RecordOffset = 0; RecordOffset < IndexAllocationSize; RecordOffset += IndexBlockSize) { Modified: branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/ntfs.h URL: http://svn.reactos.org/svn/reactos/branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/ntfs.h?rev=75493&r1=75492&r2=75493&view=diff ============================================================================== --- branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/ntfs.h [iso-8859-1] (original) +++ branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/ntfs.h [iso-8859-1] Sun Aug 6 02:54:15 2017 @@ -480,7 +480,7 @@ ULONGLONG CacheRunCurrentOffset; LARGE_MCB DataRunsMCB; ULONGLONG FileMFTIndex; - NTFS_ATTR_RECORD Record; + PNTFS_ATTR_RECORD pRecord; } NTFS_ATTR_CONTEXT, *PNTFS_ATTR_CONTEXT; #define FCB_CACHE_INITIALIZED 0x0001 @@ -959,7 +959,7 @@ ULONGLONG AttributeDataLength(PNTFS_ATTR_RECORD AttrRecord); -VOID +NTSTATUS InternalSetResidentAttributeLength(PNTFS_ATTR_CONTEXT AttrContext, PFILE_RECORD_HEADER FileRecord, ULONG AttrOffset, Modified: branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/rw.c URL: http://svn.reactos.org/svn/reactos/branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/rw.c?rev=75493&r1=75492&r2=75493&view=diff ============================================================================== --- branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/rw.c [iso-8859-1] (original) +++ branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/rw.c [iso-8859-1] Sun Aug 6 02:54:15 2017 @@ -126,7 +126,7 @@ return Status; } - StreamSize = AttributeDataLength(&DataContext->Record); + StreamSize = AttributeDataLength(DataContext->pRecord); if (ReadOffset >= StreamSize) { DPRINT1("Reading beyond stream end!\n"); @@ -149,7 +149,7 @@ /* do we need to extend RealLength by one sector? */ if (RealLength + RealReadOffset < ReadOffset + Length) { - if (RealReadOffset + RealLength + DeviceExt->NtfsInfo.BytesPerSector <= AttributeAllocatedLength(&DataContext->Record)) + if (RealReadOffset + RealLength + DeviceExt->NtfsInfo.BytesPerSector <= AttributeAllocatedLength(DataContext->pRecord)) RealLength += DeviceExt->NtfsInfo.BytesPerSector; } @@ -413,7 +413,7 @@ } // Get the size of the stream on disk - StreamSize = AttributeDataLength(&DataContext->Record); + StreamSize = AttributeDataLength(DataContext->pRecord); DPRINT("WriteOffset: %lu\tStreamSize: %I64u\n", WriteOffset, StreamSize); @@ -442,7 +442,7 @@ return Status; } - AllocationSize = AttributeAllocatedLength(&DataContext->Record); + AllocationSize = AttributeAllocatedLength(DataContext->pRecord); // 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 Modified: branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/volinfo.c URL: http://svn.reactos.org/svn/reactos/branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/volinfo.c?rev=75493&r1=75492&r2=75493&view=diff ============================================================================== --- branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/volinfo.c [iso-8859-1] (original) +++ branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/volinfo.c [iso-8859-1] Sun Aug 6 02:54:15 2017 @@ -69,7 +69,7 @@ return 0; } - BitmapDataSize = AttributeDataLength(&DataContext->Record); + BitmapDataSize = AttributeDataLength(DataContext->pRecord); ASSERT((BitmapDataSize * 8) >= DeviceExt->NtfsInfo.ClusterCount); BitmapData = ExAllocatePoolWithTag(NonPagedPool, ROUND_UP(BitmapDataSize, DeviceExt->NtfsInfo.BytesPerSector), TAG_NTFS); if (BitmapData == NULL) @@ -144,7 +144,7 @@ return Status; } - BitmapDataSize = AttributeDataLength(&DataContext->Record); + BitmapDataSize = AttributeDataLength(DataContext->pRecord); BitmapDataSize = min(BitmapDataSize, 0xffffffff); ASSERT((BitmapDataSize * 8) >= DeviceExt->NtfsInfo.ClusterCount); BitmapData = ExAllocatePoolWithTag(NonPagedPool, ROUND_UP(BitmapDataSize, DeviceExt->NtfsInfo.BytesPerSector), TAG_NTFS);