/* FUNCTIONS ****************************************************************/
+// TEMP FUNCTION for diagnostic purposes.
+// Prints VCN of every node in an index allocation
+VOID
+PrintAllVCNs(PDEVICE_EXTENSION Vcb,
+ PNTFS_ATTR_CONTEXT IndexAllocationContext,
+ ULONG NodeSize)
+{
+ ULONGLONG CurrentOffset = 0;
+ PINDEX_BUFFER CurrentNode, Buffer;
+ ULONGLONG BufferSize = AttributeDataLength(&IndexAllocationContext->Record);
+ ULONGLONG i;
+ int Count = 0;
+
+ Buffer = ExAllocatePoolWithTag(NonPagedPool, BufferSize, TAG_NTFS);
+
+ ULONG BytesRead = ReadAttribute(Vcb, IndexAllocationContext, 0, (PCHAR)Buffer, BufferSize);
+
+ ASSERT(BytesRead = BufferSize);
+
+ CurrentNode = Buffer;
+
+ // loop through all the nodes
+ for (i = 0; i < BufferSize; i += NodeSize)
+ {
+ NTSTATUS Status = FixupUpdateSequenceArray(Vcb, &CurrentNode->Ntfs);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("ERROR: Fixing fixup failed!\n");
+ continue;
+ }
+
+ DPRINT1("Node #%d, VCN: %I64u\n", Count, CurrentNode->VCN);
+
+ CurrentNode = (PINDEX_BUFFER)((ULONG_PTR)CurrentNode + NodeSize);
+ CurrentOffset += NodeSize;
+ Count++;
+ }
+
+ ExFreePoolWithTag(Buffer, TAG_NTFS);
+}
+
/**
* @name CompareTreeKeys
* @implemented
UNICODE_STRING Key1Name, Key2Name;
LONG Comparison;
+ // Key1 must not be the final key (AKA the dummy key)
ASSERT(!(Key1->IndexEntry->Flags & NTFS_INDEX_ENTRY_END));
// If Key2 is the "dummy key", key 1 will always come first
// Compare the names of the same length
Comparison = RtlCompareUnicodeString(&Key1Name, &Key2Name, !CaseSensitive);
- // If the truncated files are the same length, the shorter one comes first
+ // If the truncated names are the same length, the shorter one comes first
if (Comparison == 0)
return -1;
}
// Compare the names of the same length
Comparison = RtlCompareUnicodeString(&Key1Name, &Key2Name, !CaseSensitive);
- // If the truncated files are the same length, the shorter one comes first
+ // If the truncated names are the same length, the shorter one comes first
if (Comparison == 0)
return 1;
}
return Status;
}
+// Convert enum value to friendly name
+const PCSTR
+GetInfoClassName(FILE_INFORMATION_CLASS infoClass)
+{
+ const PCSTR fileInfoClassNames[] = { "???????",
+ "FileDirectoryInformation",
+ "FileFullDirectoryInformation",
+ "FileBothDirectoryInformation",
+ "FileBasicInformation",
+ "FileStandardInformation",
+ "FileInternalInformation",
+ "FileEaInformation",
+ "FileAccessInformation",
+ "FileNameInformation",
+ "FileRenameInformation",
+ "FileLinkInformation",
+ "FileNamesInformation",
+ "FileDispositionInformation",
+ "FilePositionInformation",
+ "FileFullEaInformation",
+ "FileModeInformation",
+ "FileAlignmentInformation",
+ "FileAllInformation",
+ "FileAllocationInformation",
+ "FileEndOfFileInformation",
+ "FileAlternateNameInformation",
+ "FileStreamInformation",
+ "FilePipeInformation",
+ "FilePipeLocalInformation",
+ "FilePipeRemoteInformation",
+ "FileMailslotQueryInformation",
+ "FileMailslotSetInformation",
+ "FileCompressionInformation",
+ "FileObjectIdInformation",
+ "FileCompletionInformation",
+ "FileMoveClusterInformation",
+ "FileQuotaInformation",
+ "FileReparsePointInformation",
+ "FileNetworkOpenInformation",
+ "FileAttributeTagInformation",
+ "FileTrackingInformation",
+ "FileIdBothDirectoryInformation",
+ "FileIdFullDirectoryInformation",
+ "FileValidDataLengthInformation",
+ "FileShortNameInformation",
+ "FileIoCompletionNotificationInformation",
+ "FileIoStatusBlockRangeInformation",
+ "FileIoPriorityHintInformation",
+ "FileSfioReserveInformation",
+ "FileSfioVolumeInformation",
+ "FileHardLinkInformation",
+ "FileProcessIdsUsingFileInformation",
+ "FileNormalizedNameInformation",
+ "FileNetworkPhysicalNameInformation",
+ "FileIdGlobalTxDirectoryInformation",
+ "FileIsRemoteDeviceInformation",
+ "FileAttributeCacheInformation",
+ "FileNumaNodeInformation",
+ "FileStandardLinkInformation",
+ "FileRemoteProtocolInformation",
+ "FileReplaceCompletionInformation",
+ "FileMaximumInformation",
+ "FileDirectoryInformation",
+ "FileFullDirectoryInformation",
+ "FileBothDirectoryInformation",
+ "FileBasicInformation",
+ "FileStandardInformation",
+ "FileInternalInformation",
+ "FileEaInformation",
+ "FileAccessInformation",
+ "FileNameInformation",
+ "FileRenameInformation",
+ "FileLinkInformation",
+ "FileNamesInformation",
+ "FileDispositionInformation",
+ "FilePositionInformation",
+ "FileFullEaInformation",
+ "FileModeInformation",
+ "FileAlignmentInformation",
+ "FileAllInformation",
+ "FileAllocationInformation",
+ "FileEndOfFileInformation",
+ "FileAlternateNameInformation",
+ "FileStreamInformation",
+ "FilePipeInformation",
+ "FilePipeLocalInformation",
+ "FilePipeRemoteInformation",
+ "FileMailslotQueryInformation",
+ "FileMailslotSetInformation",
+ "FileCompressionInformation",
+ "FileObjectIdInformation",
+ "FileCompletionInformation",
+ "FileMoveClusterInformation",
+ "FileQuotaInformation",
+ "FileReparsePointInformation",
+ "FileNetworkOpenInformation",
+ "FileAttributeTagInformation",
+ "FileTrackingInformation",
+ "FileIdBothDirectoryInformation",
+ "FileIdFullDirectoryInformation",
+ "FileValidDataLengthInformation",
+ "FileShortNameInformation",
+ "FileIoCompletionNotificationInformation",
+ "FileIoStatusBlockRangeInformation",
+ "FileIoPriorityHintInformation",
+ "FileSfioReserveInformation",
+ "FileSfioVolumeInformation",
+ "FileHardLinkInformation",
+ "FileProcessIdsUsingFileInformation",
+ "FileNormalizedNameInformation",
+ "FileNetworkPhysicalNameInformation",
+ "FileIdGlobalTxDirectoryInformation",
+ "FileIsRemoteDeviceInformation",
+ "FileAttributeCacheInformation",
+ "FileNumaNodeInformation",
+ "FileStandardLinkInformation",
+ "FileRemoteProtocolInformation",
+ "FileReplaceCompletionInformation",
+ "FileMaximumInformation" };
+ return fileInfoClassNames[infoClass];
+}
+
/*
* FUNCTION: Retrieve the specified file information
*/
case FileAlternateNameInformation:
case FileAllInformation:
- DPRINT1("Unimplemented information class %u\n", FileInformationClass);
+ DPRINT1("Unimplemented information class: %s\n", GetInfoClassName(FileInformationClass));
Status = STATUS_NOT_IMPLEMENTED;
break;
default:
- DPRINT1("Unimplemented information class %u\n", FileInformationClass);
+ DPRINT1("Unimplemented information class: %s\n", GetInfoClassName(FileInformationClass));
Status = STATUS_INVALID_PARAMETER;
}
// TODO: all other information classes
default:
- DPRINT1("FIXME: Unimplemented information class %u\n", FileInformationClass);
+ DPRINT1("FIXME: Unimplemented information class: %s\n", GetInfoClassName(FileInformationClass));
Status = STATUS_NOT_IMPLEMENTED;
}
// we must create an index allocation and index bitmap (TODO). Also TODO: support file records with
// $ATTRIBUTE_LIST's.
AttributeLength = NewIndexRoot->Header.AllocatedSize + FIELD_OFFSET(INDEX_ROOT_ATTRIBUTE, Header);
- DestinationAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)ParentFileRecord + IndexRootOffset);
-
- // Find the attribute (or attribute-end marker) after the index root
- NextAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)DestinationAttribute + DestinationAttribute->Length);
- if (NextAttribute->Type != AttributeEnd)
+
+ if (AttributeLength != IndexRootContext->Record.Resident.ValueLength)
{
- DPRINT1("FIXME: For now, only resizing index root at the end of a file record is supported!\n");
- ExFreePoolWithTag(NewIndexRoot, TAG_NTFS);
- ReleaseAttributeContext(IndexRootContext);
- ExFreePoolWithTag(I30IndexRoot, TAG_NTFS);
- ExFreePoolWithTag(ParentFileRecord, TAG_NTFS);
- return STATUS_NOT_IMPLEMENTED;
- }
+ DestinationAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)ParentFileRecord + IndexRootOffset);
- // Update the length of the attribute in the file record of the parent directory
- InternalSetResidentAttributeLength(IndexRootContext,
- ParentFileRecord,
- IndexRootOffset,
- AttributeLength);
+ // Find the attribute (or attribute-end marker) after the index root
+ NextAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)DestinationAttribute + DestinationAttribute->Length);
+ if (NextAttribute->Type != AttributeEnd)
+ {
+ DPRINT1("FIXME: For now, only resizing index root at the end of a file record is supported!\n");
+ ExFreePoolWithTag(NewIndexRoot, TAG_NTFS);
+ ReleaseAttributeContext(IndexRootContext);
+ ExFreePoolWithTag(I30IndexRoot, TAG_NTFS);
+ ExFreePoolWithTag(ParentFileRecord, TAG_NTFS);
+ return STATUS_NOT_IMPLEMENTED;
+ }
+
+ // Update the length of the attribute in the file record of the parent directory
+ InternalSetResidentAttributeLength(IndexRootContext,
+ ParentFileRecord,
+ IndexRootOffset,
+ AttributeLength);
+ }
NT_ASSERT(ParentFileRecord->BytesInUse <= DeviceExt->NtfsInfo.BytesPerFileRecord);