- Thread Author
- #1
Hello everyone,
I'm working on a low-level NTFS parser in C++ and have run into a question about the most robust way to compare file identifiers. I am currently on windows 11 but the software I'm making is for Windows 10 and 11.
My goal is to check if an attribute in an $ATTRIBUTE_LIST is a self-reference (i.e., it points back to the MFT record it's in).
The MFT_RECORD_ATTRIBUTE (structure for each attribute in the $ATTRIBUTE_LIST) structure from an $ATTRIBUTE_LIST provides a full 64-bit File Reference Number (recordNumber), where the lower 48 bits are the inode and the upper 16 are a sequence number.
However, the MFT_RECORD_HEADER structure on disk stores the record's own index in a 32-bit DWORD field (MFTRecordIndex).
I have seen two approaches in an existing codebase:
here recordNumber, a 64 bit int is AND'ed and compared directly with a 32 bit uint/DWORD
here both the numbers are AND'ed and compared.
My question is: What is the safest and most correct way to compare these two different-sized identifiers to check for equality of the inode part?
Is there a canonical "right way" to do this that is guaranteed to be safe from compiler quirks or unexpected behavior, especially considering that NTFS inodes can theoretically exceed 32 bits? Is Approach A sufficient, or is the explicit cast in B (or another method) strongly recommended for correctness and clarity?
Thanks for your insights!
I'm working on a low-level NTFS parser in C++ and have run into a question about the most robust way to compare file identifiers. I am currently on windows 11 but the software I'm making is for Windows 10 and 11.
My goal is to check if an attribute in an $ATTRIBUTE_LIST is a self-reference (i.e., it points back to the MFT record it's in).
The MFT_RECORD_ATTRIBUTE (structure for each attribute in the $ATTRIBUTE_LIST) structure from an $ATTRIBUTE_LIST provides a full 64-bit File Reference Number (recordNumber), where the lower 48 bits are the inode and the upper 16 are a sequence number.
However, the MFT_RECORD_HEADER structure on disk stores the record's own index in a 32-bit DWORD field (MFTRecordIndex).
I have seen two approaches in an existing codebase:
C++:
DWORD64 next_inode = pAttrListI->recordNumber & 0xffffffffffff;
if (next_inode != _record->data()->MFTRecordIndex) {}
Code:
if ((pAttr->recordNumber & 0xffffffffffff) != (header()->MFTRecordIndex & 0xffffffffffff)) {}
My question is: What is the safest and most correct way to compare these two different-sized identifiers to check for equality of the inode part?
Is there a canonical "right way" to do this that is guaranteed to be safe from compiler quirks or unexpected behavior, especially considering that NTFS inodes can theoretically exceed 32 bits? Is Approach A sufficient, or is the explicit cast in B (or another method) strongly recommended for correctness and clarity?
Thanks for your insights!