* Pointer to the FILE_OBJECT which represents the new name.
* This parameter is used to determine the filename and parent directory.
*
+* @param ParentMftIndex
+* Pointer to a ULONGLONG which will receive the index of the parent directory.
+*
* @return
* STATUS_SUCCESS on success. STATUS_NOT_IMPLEMENTED if target address isn't at the end
* of the given file record.
AddFileName(PFILE_RECORD_HEADER FileRecord,
PNTFS_ATTR_RECORD AttributeAddress,
PDEVICE_EXTENSION DeviceExt,
- PFILE_OBJECT FileObject)
+ PFILE_OBJECT FileObject,
+ PULONGLONG ParentMftIndex)
{
ULONG ResidentHeaderLength = FIELD_OFFSET(NTFS_ATTR_RECORD, Resident.Reserved) + sizeof(UCHAR);
PFILENAME_ATTRIBUTE FileNameAttribute;
LARGE_INTEGER SystemTime;
ULONG FileRecordEnd = AttributeAddress->Length;
ULONGLONG CurrentMFTIndex = NTFS_FILE_ROOT;
- UNICODE_STRING Current, Remaining;
+ UNICODE_STRING Current, Remaining, FilenameNoPath;
NTSTATUS Status = STATUS_SUCCESS;
ULONG FirstEntry = 0;
+ WCHAR Buffer[MAX_PATH];
if (AttributeAddress->Type != AttributeEnd)
{
// we need to extract the filename from the path
DPRINT1("Pathname: %wZ\n", &FileObject->FileName);
+ RtlZeroMemory(&FilenameNoPath, sizeof(UNICODE_STRING));
+ FilenameNoPath.Buffer = Buffer;
+ FilenameNoPath.MaximumLength = MAX_PATH;
+
FsRtlDissectName(FileObject->FileName, &Current, &Remaining);
while (Current.Length != 0)
{
DPRINT1("Current: %wZ\n", &Current);
+ if(Remaining.Length != 0)
+ RtlCopyUnicodeString(&FilenameNoPath, &Remaining);
+
Status = NtfsFindMftRecord(DeviceExt, CurrentMFTIndex, &Current, &FirstEntry, FALSE, &CurrentMFTIndex);
if (!NT_SUCCESS(Status))
- {
break;
- }
- if (Remaining.Length == 0)
+ if (Remaining.Length == 0 )
+ {
+ if(Current.Length != 0)
+ RtlCopyUnicodeString(&FilenameNoPath, &Current);
break;
+ }
FsRtlDissectName(Current, &Current, &Remaining);
}
// set reference to parent directory
FileNameAttribute->DirectoryFileReferenceNumber = CurrentMFTIndex;
+ *ParentMftIndex = CurrentMFTIndex;
+
+ DPRINT1("SequenceNumber: 0x%02x\n", FileRecord->SequenceNumber);
// The highest 2 bytes should be the sequence number, unless the parent happens to be root
if (CurrentMFTIndex == NTFS_FILE_ROOT)
else
FileNameAttribute->DirectoryFileReferenceNumber |= (ULONGLONG)FileRecord->SequenceNumber << 48;
- DPRINT1("FileNameAttribute->DirectoryFileReferenceNumber: 0x%I64x\n", FileNameAttribute->DirectoryFileReferenceNumber);
+ DPRINT1("FileNameAttribute->DirectoryFileReferenceNumber: 0x%016I64x\n", FileNameAttribute->DirectoryFileReferenceNumber);
- FileNameAttribute->NameLength = Current.Length / 2;
+ FileNameAttribute->NameLength = FilenameNoPath.Length / 2;
// TODO: Get proper nametype, add DOS links as needed
FileNameAttribute->NameType = NTFS_FILE_NAME_WIN32_AND_DOS;
- RtlCopyMemory(FileNameAttribute->Name, Current.Buffer, Current.Length);
+ RtlCopyMemory(FileNameAttribute->Name, FilenameNoPath.Buffer, FilenameNoPath.Length);
FileRecord->LinkCount++;
AttributeAddress->Length = ResidentHeaderLength +
- FIELD_OFFSET(FILENAME_ATTRIBUTE, Name) + Current.Length;
+ FIELD_OFFSET(FILENAME_ATTRIBUTE, Name) + FilenameNoPath.Length;
AttributeAddress->Length = ALIGN_UP_BY(AttributeAddress->Length, 8);
- AttributeAddress->Resident.ValueLength = FIELD_OFFSET(FILENAME_ATTRIBUTE, Name) + Current.Length;
+ AttributeAddress->Resident.ValueLength = FIELD_OFFSET(FILENAME_ATTRIBUTE, Name) + FilenameNoPath.Length;
AttributeAddress->Resident.ValueOffset = ResidentHeaderLength;
AttributeAddress->Resident.Flags = 1; // indexed
DbgPrint(" (%x) '%.*S' ", FileNameAttr->NameType, FileNameAttr->NameLength, FileNameAttr->Name);
DbgPrint(" '%x' \n", FileNameAttr->FileAttributes);
DbgPrint(" AllocatedSize: %I64u\nDataSize: %I64u\n", FileNameAttr->AllocatedSize, FileNameAttr->DataSize);
+ DbgPrint(" File reference: 0x%016I64x\n", FileNameAttr->DirectoryFileReferenceNumber);
}
NtfsDumpIndexRootAttribute(PNTFS_ATTR_RECORD Attribute)
{
PINDEX_ROOT_ATTRIBUTE IndexRootAttr;
+ ULONG currentOffset;
+ ULONG currentNode;
IndexRootAttr = (PINDEX_ROOT_ATTRIBUTE)((ULONG_PTR)Attribute + Attribute->Resident.ValueOffset);
if (IndexRootAttr->AttributeType == AttributeFileName)
ASSERT(IndexRootAttr->CollationRule == COLLATION_FILE_NAME);
- DbgPrint(" $INDEX_ROOT (%uB, %u) ", IndexRootAttr->SizeOfEntry, IndexRootAttr->ClustersPerIndexRecord);
+ DbgPrint(" $INDEX_ROOT (%u bytes per index record, %u clusters) ", IndexRootAttr->SizeOfEntry, IndexRootAttr->ClustersPerIndexRecord);
if (IndexRootAttr->Header.Flags == INDEX_ROOT_SMALL)
{
- DbgPrint(" (small) ");
+ DbgPrint(" (small)\n");
}
else
{
ASSERT(IndexRootAttr->Header.Flags == INDEX_ROOT_LARGE);
- DbgPrint(" (large) ");
+ DbgPrint(" (large)\n");
}
+
+ DbgPrint(" Offset to first index: 0x%lx\n Total size of index entries: 0x%lx\n Allocated size of node: 0x%lx\n",
+ IndexRootAttr->Header.FirstEntryOffset,
+ IndexRootAttr->Header.TotalSizeOfEntries,
+ IndexRootAttr->Header.AllocatedSize);
+ currentOffset = IndexRootAttr->Header.FirstEntryOffset;
+ currentNode = 0;
+ // print details of every node in the index
+ while (currentOffset < IndexRootAttr->Header.TotalSizeOfEntries)
+ {
+ PINDEX_ENTRY_ATTRIBUTE currentIndexExtry = (PINDEX_ENTRY_ATTRIBUTE)((ULONG_PTR)IndexRootAttr + 0x10 + currentOffset);
+ DbgPrint(" Index Node Entry %u", currentNode++);
+ if (currentIndexExtry->Flags & NTFS_INDEX_ENTRY_NODE)
+ DbgPrint(" (Branch)");
+ else
+ DbgPrint(" (Leaf)");
+ if((currentIndexExtry->Flags & NTFS_INDEX_ENTRY_END))
+ {
+ DbgPrint(" (Dummy Key)");
+ }
+ DbgPrint("\n File Reference: 0x%016I64x\n", currentIndexExtry->Data.Directory.IndexedFile);
+ DbgPrint(" Index Entry Length: 0x%x\n", currentIndexExtry->Length);
+ DbgPrint(" Index Key Length: 0x%x\n", currentIndexExtry->KeyLength);
+
+ // if this isn't the final (dummy) node, print info about the key (Filename attribute)
+ if (!(currentIndexExtry->Flags & NTFS_INDEX_ENTRY_END))
+ {
+ UNICODE_STRING Name;
+ DbgPrint(" Parent File Reference: 0x%016I64x\n", currentIndexExtry->FileName.DirectoryFileReferenceNumber);
+ DbgPrint(" $FILENAME indexed: ");
+ Name.Length = currentIndexExtry->FileName.NameLength * sizeof(WCHAR);
+ Name.MaximumLength = Name.Length;
+ Name.Buffer = currentIndexExtry->FileName.Name;
+ DbgPrint("'%wZ'\n", &Name);
+ }
+
+ // if this node has a sub-node beneath it
+ if (currentIndexExtry->Flags & NTFS_INDEX_ENTRY_NODE)
+ {
+ // Print the VCN of the sub-node
+ PULONGLONG SubNodeVCN = (PULONGLONG)((ULONG_PTR)currentIndexExtry + currentIndexExtry->Length - 8);
+ DbgPrint(" VCN of sub-node: 0x%llx\n", *SubNodeVCN);
+ }
+
+ currentOffset += currentIndexExtry->Length;
+ ASSERT(currentIndexExtry->Length);
+ }
+
}