Fix NTFS $MFTMirr to stay in sync with $MFT#72
Conversation
bbd1fea to
ec0eb17
Compare
|
@Olof-Lagerkvist wait one moment with merging this PR untill I've finished my last tests |
|
Thanks a lot! I'll just push a small change first that should avoid the errors you got here. After that, I'll merge it. |
ec0eb17 to
0fc6f5f
Compare
External validation with
|
|
Yes, for some reason |
|
Yeah so again most of this stuff just came up with AI, so I depend mainly on your knowledge of this to verify the changes :) -Comment not made by AI |
Before/after
|
|
I think I need to remove the dependency on: Let me verify that, I'll let you know once it's ready to merge from my side. |
MasterFileTable.WriteRecord serialized the record twice: once into the $MFT stream and once into the $MFTMirr copy for records 0-3. FixupRecordBase.ToBytes calls ProtectBuffer, which increments the update sequence number on every serialization, so the mirror copy was always written with a USN one higher than the $MFT copy. The divergence is at the USN field (offset 0x30) and the fixup bytes at the end of every 512-byte sector of the record. NTFS implementations compare $MFTMirr to $MFT verbatim at mount time, so ntfs-3g failed with "$MFTMirr does not match $MFT (record 0)" and chkdsk reported corruption. Any operation that grows the MFT rewrites record 0 and triggered this. Serialize the record exactly once into a buffer and write those identical bytes to both streams, keeping the existing method structure. Adds a MftMirrorStaysInSyncWithMft unit test that formats a volume, writes 400 files to grow the MFT, and byte-compares records 0-3 of $MFT and $MFTMirr.
0fc6f5f to
417747a
Compare
Yes that is not needed now. |
|
It should be okay from my side now. If you can do one more review after the builds complete then hopefully it's ready to merge 😄. |
35319d2
into
LTRData:LTRData.DiscUtils-initial
Problem
MasterFileTable.WriteRecordserialized each MFT record twice — once into the$MFTstream and, for records 0-3, once again into the$MFTMirrcopy:FixupRecordBase.ToBytescallsProtectBuffer, which doesUpdateSequenceNumber++on every serialization. So the mirror copy was always written with a USN one higher than the$MFTcopy. The two copies therefore differ at:0x30in the record header), andNTFS implementations compare
$MFTMirrto$MFTverbatim at mount time, so:Any operation that grows the MFT rewrites the MFT's own record 0 and triggers this.
Wrong vs. right (record 0 header, USN field at offset
0x30)Wrong (before — mirror serialized separately, USN bumped again):
Right (after — one serialization, identical bytes to both):
Fix
Serialize the record exactly once into a buffer and write those same bytes to both streams, keeping the existing method structure (main write →
MftRecordIsDirtyhandling → mirror write):How to reproduce / test
Unit test added (
MftMirrorStaysInSyncWithMftinTests/LibraryTests/Ntfs/NtfsFileSystemTest.cs): formats a 64 MB NTFS volume, reopens it, creates a directory and 400 files of 4096 bytes (which grows the MFT and rewrites record 0), then parses the boot sector to locate$MFTand$MFTMirrand byte-compares records 0-3 of each, asserting they are identical.The test fails on the unpatched library with exactly:
(Verified by stashing the
MasterFileTable.cschange, running the single test, observing the record-0 failure, then unstashing.)Manual reproduction with ntfs-3g tools (Linux):