FIND_ATTR_CONTXT Context;
PNTFS_ATTR_RECORD Attribute;
- DPRINT("FindAttribute(%p, %p, 0x%x, %S, %u, %p)\n", Vcb, MftRecord, Type, Name, NameLength, AttrCtx);
+ DPRINT("FindAttribute(%p, %p, 0x%x, %S, %lu, %p, %p)\n", Vcb, MftRecord, Type, Name, NameLength, AttrCtx, Offset);
Found = FALSE;
Status = FindFirstAttribute(&Context, Vcb, MftRecord, FALSE, &Attribute);
AttrName = (PWCHAR)((PCHAR)Attribute + Attribute->NameOffset);
DPRINT("%.*S, %.*S\n", Attribute->NameLength, AttrName, NameLength, Name);
- if (RtlCompareMemory(AttrName, Name, NameLength << 1) == (NameLength << 1))
+ if (RtlCompareMemory(AttrName, Name, NameLength * sizeof(WCHAR)) == (NameLength * sizeof(WCHAR)))
{
Found = TRUE;
}
}
// Zero the bytes we'll be adding
- RtlZeroMemory((PUCHAR)((ULONG_PTR)BitmapBuffer), NewBitmapSize);
+ RtlZeroMemory(BitmapBuffer, NewBitmapSize);
// Read the bitmap attribute
BytesRead = ReadAttribute(Vcb,
ExFreePoolWithTag(BitmapBuffer, TAG_NTFS);
ReleaseAttributeContext(BitmapContext);
DPRINT1("ERROR: Couldn't write to bitmap attribute of $MFT!\n");
+ return Status;
}
// Cleanup
DPRINT("InternalSetResidentAttributeLength( %p, %p, %lu, %lu )\n", AttrContext, FileRecord, AttrOffset, DataSize);
+ ASSERT(!AttrContext->Record.IsNonResident);
+
// update ValueLength Field
AttrContext->Record.Resident.ValueLength =
Destination->Resident.ValueLength = DataSize;
{
NTSTATUS Status = STATUS_SUCCESS;
+ DPRINT1("SetAttributeDataLenth(%p, %p, %p, %lu, %p, %I64u)\n",
+ FileObject,
+ Fcb,
+ AttrContext,
+ AttrOffset,
+ FileRecord,
+ DataSize->QuadPart);
+
// are we truncating the file?
if (DataSize->QuadPart < AttributeDataLength(&AttrContext->Record))
{
PNTFS_ATTR_RECORD DestinationAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + AttrOffset);
ULONG ExistingClusters = AttrContext->Record.NonResident.AllocatedSize / BytesPerCluster;
- if (!AttrContext->Record.IsNonResident)
- {
- DPRINT1("ERROR: SetNonResidentAttributeDataLength() called for resident attribute!\n");
- return STATUS_INVALID_PARAMETER;
- }
+ ASSERT(AttrContext->Record.IsNonResident);
// do we need to increase the allocation size?
if (AttrContext->Record.NonResident.AllocatedSize < AllocationSize)
ULONG NextAttributeOffset = AttrOffset + AttrContext->Record.Length;
PNTFS_ATTR_RECORD NextAttribute = (PNTFS_ATTR_RECORD)((PCHAR)FileRecord + NextAttributeOffset);
- if (AttrContext->Record.IsNonResident)
- {
- DPRINT1("ERROR: SetResidentAttributeDataLength() called for non-resident attribute!\n");
- return STATUS_INVALID_PARAMETER;
- }
+ ASSERT(!AttrContext->Record.IsNonResident);
//NtfsDumpFileAttributes(Vcb, FileRecord);
// 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);
- // mark the attribute as non-resident
- AttrContext->Record.IsNonResident = Destination->IsNonResident = 1;
-
// 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;
(PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + EndAttributeOffset),
FILE_RECORD_END);
- // update file record on disk
+ // Initialize the MCB, potentially catch an exception
+ _SEH2_TRY
+ {
+ FsRtlInitializeLargeMcb(&AttrContext->DataRunsMCB, NonPagedPool);
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ DPRINT1("Unable to create LargeMcb!\n");
+ ExFreePoolWithTag(AttribData, TAG_NTFS);
+ _SEH2_YIELD(return _SEH2_GetExceptionCode());
+ } _SEH2_END;
+
+ // Mark the attribute as non-resident (we wait until after we know the LargeMcb was initialized)
+ AttrContext->Record.IsNonResident = Destination->IsNonResident = 1;
+
+ // Update file record on disk
Status = UpdateFileRecord(Vcb, AttrContext->FileMFTIndex, FileRecord);
if (!NT_SUCCESS(Status))
{
return Status;
}
- // Initialize the MCB, potentially catch an exception
- _SEH2_TRY{
- FsRtlInitializeLargeMcb(&AttrContext->DataRunsMCB, NonPagedPool);
- } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
- _SEH2_YIELD(return _SEH2_GetExceptionCode());
- } _SEH2_END;
-
// Now we can treat the attribute as non-resident and enlarge it normally
Status = SetNonResidentAttributeDataLength(Vcb, AttrContext, AttrOffset, FileRecord, DataSize);
if (!NT_SUCCESS(Status))
BytesRead = ReadAttribute(Vcb, Vcb->MFTContext, index * Vcb->NtfsInfo.BytesPerFileRecord, (PCHAR)file, Vcb->NtfsInfo.BytesPerFileRecord);
if (BytesRead != Vcb->NtfsInfo.BytesPerFileRecord)
{
- DPRINT1("ReadFileRecord failed: %I64u read, %u expected\n", BytesRead, Vcb->NtfsInfo.BytesPerFileRecord);
+ DPRINT1("ReadFileRecord failed: %I64u read, %lu expected\n", BytesRead, Vcb->NtfsInfo.BytesPerFileRecord);
return STATUS_PARTIAL_COPY;
}
NTSTATUS Status;
ULONG CurrentEntry = 0;
- DPRINT("UpdateFileNameRecord(%p, %I64d, %wZ, %u, %I64u, %I64u, %s)\n",
+ DPRINT("UpdateFileNameRecord(%p, %I64d, %wZ, %s, %I64u, %I64u, %s)\n",
Vcb,
ParentMFTIndex,
FileName,
- DirSearch,
+ DirSearch ? "TRUE" : "FALSE",
NewDataSize,
NewAllocationSize,
CaseSensitive ? "TRUE" : "FALSE");
return STATUS_INSUFFICIENT_RESOURCES;
}
- ReadAttribute(Vcb, IndexRootCtx, 0, IndexRecord, Vcb->NtfsInfo.BytesPerIndexRecord);
+ Status = ReadAttribute(Vcb, IndexRootCtx, 0, IndexRecord, AttributeDataLength(&IndexRootCtx->Record));
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("ERROR: Failed to read Index Root!\n");
+ ExFreePoolWithTag(IndexRecord, TAG_NTFS);
+ ReleaseAttributeContext(IndexRootCtx);
+ ExFreePoolWithTag(MftRecord, TAG_NTFS);
+ }
+
IndexRoot = (PINDEX_ROOT_ATTRIBUTE)IndexRecord;
IndexEntry = (PINDEX_ENTRY_ATTRIBUTE)((PCHAR)&IndexRoot->Header + IndexRoot->Header.FirstEntryOffset);
// Index root is always resident.
NewAllocationSize,
CaseSensitive);
+ if (Status == STATUS_PENDING)
+ {
+ // we need to write the index root attribute back to disk
+ ULONG LengthWritten;
+ Status = WriteAttribute(Vcb, IndexRootCtx, 0, IndexRecord, AttributeDataLength(&IndexRootCtx->Record), &LengthWritten);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("ERROR: Couldn't update Index Root!\n");
+ }
+
+ }
+
ReleaseAttributeContext(IndexRootCtx);
ExFreePoolWithTag(IndexRecord, TAG_NTFS);
ExFreePoolWithTag(MftRecord, TAG_NTFS);
ULONGLONG IndexAllocationSize;
PINDEX_BUFFER IndexBuffer;
- DPRINT("UpdateIndexEntrySize(%p, %p, %p, %u, %p, %p, %wZ, %u, %u, %u, %I64u, %I64u)\n", Vcb, MftRecord, IndexRecord, IndexBlockSize, FirstEntry, LastEntry, FileName, *StartEntry, *CurrentEntry, DirSearch, NewDataSize, NewAllocatedSize);
+ DPRINT("UpdateIndexEntrySize(%p, %p, %p, %lu, %p, %p, %wZ, %lu, %lu, %s, %I64u, %I64u, %s)\n",
+ Vcb,
+ MftRecord,
+ IndexRecord,
+ IndexBlockSize,
+ FirstEntry,
+ LastEntry,
+ FileName,
+ *StartEntry,
+ *CurrentEntry,
+ DirSearch ? "TRUE" : "FALSE",
+ NewDataSize,
+ NewAllocatedSize,
+ CaseSensitive ? "TRUE" : "FALSE");
// find the index entry responsible for the file we're trying to update
IndexEntry = FirstEntry;
RTL_BITMAP Bitmap;
ULONGLONG BitmapDataSize;
ULONGLONG AttrBytesRead;
- PVOID BitmapData;
+ PUCHAR BitmapData;
ULONG LengthWritten;
PNTFS_ATTR_CONTEXT BitmapContext;
LARGE_INTEGER BitmapBits;
return STATUS_OBJECT_NAME_NOT_FOUND;
}
- // we need to backup the bits for records 0x10 - 0x17 and leave them unassigned if they aren't assigned
- RtlCopyMemory(&SystemReservedBits, (PVOID)((ULONG_PTR)BitmapData + 2), 1);
- RtlFillMemory((PVOID)((ULONG_PTR)BitmapData + 2), 1, (UCHAR)0xFF);
+ // We need to backup the bits for records 0x10 - 0x17 (3rd byte of bitmap) and mark these records
+ // as in-use so we don't assign files to those indices. They're reserved for the system (e.g. ChkDsk).
+ SystemReservedBits = BitmapData[2];
+ BitmapData[2] = 0xff;
// Calculate bit count
BitmapBits.QuadPart = AttributeDataLength(&(DeviceExt->MFTContext->Record)) /
DeviceExt->NtfsInfo.BytesPerFileRecord;
if (BitmapBits.HighPart != 0)
{
- DPRINT1("\tFIXME: bitmap sizes beyond 32bits are not yet supported!\n");
- BitmapBits.LowPart = 0xFFFFFFFF;
+ DPRINT1("\tFIXME: bitmap sizes beyond 32bits are not yet supported! (Your NTFS volume is too large)\n");
+ ExFreePoolWithTag(BitmapData, TAG_NTFS);
+ ReleaseAttributeContext(BitmapContext);
+ return STATUS_NOT_IMPLEMENTED;
}
// convert buffer into bitmap
// [BitmapData should have been updated via RtlFindClearBitsAndSet()]
// Restore the system reserved bits
- RtlCopyMemory((PVOID)((ULONG_PTR)BitmapData + 2), &SystemReservedBits, 1);
+ BitmapData[2] = SystemReservedBits;
// write the bitmap back to the MFT's $Bitmap attribute
Status = WriteAttribute(DeviceExt, BitmapContext, 0, BitmapData, BitmapDataSize, &LengthWritten);
PNTFS_RECORD_HEADER Record)
{
USHORT *pShortToFixUp;
- unsigned int ArrayEntryCount = Record->UsaCount - 1;
- unsigned int Offset = Vcb->NtfsInfo.BytesPerSector - 2;
- int i;
+ ULONG ArrayEntryCount = Record->UsaCount - 1;
+ ULONG Offset = Vcb->NtfsInfo.BytesPerSector - 2;
+ ULONG i;
PFIXUP_ARRAY fixupArray = (PFIXUP_ARRAY)((UCHAR*)Record + Record->UsaOffset);
ULONGLONG IndexAllocationSize;
PINDEX_BUFFER IndexBuffer;
- DPRINT("BrowseIndexEntries(%p, %p, %p, %u, %p, %p, %wZ, %u, %u, %s, %s, %p)\n",
+ DPRINT("BrowseIndexEntries(%p, %p, %p, %lu, %p, %p, %wZ, %lu, %lu, %s, %s, %p)\n",
Vcb,
MftRecord,
IndexRecord,
Status = FindAttribute(Vcb, MftRecord, AttributeIndexAllocation, L"$I30", 4, &IndexAllocationCtx, NULL);
if (!NT_SUCCESS(Status))
{
- DPRINT("Corrupted filesystem!\n");
+ DPRINT1("Corrupted filesystem!\n");
return Status;
}
PUNICODE_STRING FileName,
PULONG FirstEntry,
BOOLEAN DirSearch,
- ULONGLONG *OutMFTIndex,
- BOOLEAN CaseSensitive)
+ BOOLEAN CaseSensitive,
+ ULONGLONG *OutMFTIndex)
{
PFILE_RECORD_HEADER MftRecord;
PNTFS_ATTR_CONTEXT IndexRootCtx;
NTSTATUS Status;
ULONG CurrentEntry = 0;
- DPRINT("NtfsFindMftRecord(%p, %I64d, %wZ, %u, %u, %p)\n", Vcb, MFTIndex, FileName, *FirstEntry, DirSearch, OutMFTIndex);
+ DPRINT("NtfsFindMftRecord(%p, %I64d, %wZ, %lu, %s, %s, %p)\n",
+ Vcb,
+ MFTIndex,
+ FileName,
+ *FirstEntry,
+ DirSearch ? "TRUE" : "FALSE",
+ CaseSensitive ? "TRUE" : "FALSE",
+ OutMFTIndex);
MftRecord = ExAllocatePoolWithTag(NonPagedPool,
Vcb->NtfsInfo.BytesPerFileRecord,
{
DPRINT("Current: %wZ\n", &Current);
- Status = NtfsFindMftRecord(Vcb, CurrentMFTIndex, &Current, &FirstEntry, FALSE, &CurrentMFTIndex, CaseSensitive);
+ Status = NtfsFindMftRecord(Vcb, CurrentMFTIndex, &Current, &FirstEntry, FALSE, CaseSensitive, &CurrentMFTIndex);
if (!NT_SUCCESS(Status))
{
return Status;
{
NTSTATUS Status;
- DPRINT("NtfsFindFileAt(%p, %wZ, %u, %p, %p, %I64x, %s)\n",
+ DPRINT("NtfsFindFileAt(%p, %wZ, %lu, %p, %p, %I64x, %s)\n",
Vcb,
SearchPattern,
*FirstEntry,
CurrentMFTIndex,
(CaseSensitive ? "TRUE" : "FALSE"));
- Status = NtfsFindMftRecord(Vcb, CurrentMFTIndex, SearchPattern, FirstEntry, TRUE, &CurrentMFTIndex, CaseSensitive);
+ Status = NtfsFindMftRecord(Vcb, CurrentMFTIndex, SearchPattern, FirstEntry, TRUE, CaseSensitive, &CurrentMFTIndex);
if (!NT_SUCCESS(Status))
{
DPRINT("NtfsFindFileAt: NtfsFindMftRecord() failed with status 0x%08lx\n", Status);