Run List 是 Non-Resident Attribute 的 Attribute Record 裡的一段資料。
以一般檔案內容來說,最常見的是:
MFT Record
└── $DATA
└── Non-Resident Attribute
├── Lowest VCN
├── Highest VCN
├── MappingPairsOffset
└── Mapping Pairs
↓
Run List
其中 MappingPairsOffset 會告訴我們:
從這個 Attribute Record 的開頭算起,要往後多少 Bytes,才是 Mapping Pairs。
而 Mapping Pairs 就是我們這篇要解析的 Run List。
如果 Mapping Pairs 太多,塞不進原本的 MFT Record,也可能需要使用其他 MFT Record Segment;這時可以透過 $ATTRIBUTE_LIST 找到其他 Attribute Record。
假設我們找到這一段 Run List:
21 03 64 00 21 02 90 01 00
第一個 Byte 是:
21
把它拆成兩個 4-bit:
21
↓
2 1
↑ ↑
LCN Length
代表此 LCN Offset 使用 2 Bytes,Length 使用 1 Byte。
所以接下來的資料格式會是:
21 | 03 | 64 00
↑ ↑ ↑
Header Length LCN Offset
接下來看到:
03
剛剛 Header 告訴我們 Length 使用 1 Byte。
所以:
03 = 3
代表這個 Run 的 Length 是:
3 Clusters
因為 Header 的前 4 bits 是 2,所以 LCN Offset 使用 2 Bytes。
接下來兩個 Byte 是:
64 00
這裡使用 Little Endian,因此:
64 00
↓
0x0064
↓
100
這是第一個 Run,所以目前的 LCN 是:
100
因此第一個 Run 可以得到:
Length = 3
LCN = 100
如果從 Lowest VCN = 0 開始,就是:
VCN 0 → LCN 100
VCN 1 → LCN 101
VCN 2 → LCN 102
也就是:
VCN 0~2 → LCN 100~102
第一個 Run 解完後,下一個 Byte 又是:
21
所以又重新從 Header 開始。
21 02 90 01
21
├── Length:1 Byte
└── LCN Offset:2 Bytes
02 = 2
所以這個 Run 有:
2 Clusters
90 01
Little Endian:
90 01
↓
0x0190
↓
400
LCN Offset 不是給你新的 LCN,而是相對於前一個 Current LCN 的變化量。
上一個 LCN 是:
100
這次 Offset 是:
+400
所以:
100 + 400 = 500
第二個 Run 就是:
VCN 3~4 → LCN 500~501
解碼完前面那些,剩下:
00
00 是 Run List 的結束標記。
所以整串:
21 03 64 00 21 02 90 01 00
最後可以整理成:
21 03 64 00
└── Run 1
├── Length = 3
└── LCN = 100
21 02 90 01
└── Run 2
├── Length = 2
└── LCN = 500
00
└── End
最後結果:
| Run | VCN | Length | LCN |
|---|---|---|---|
| 1 | 0~2 | 3 | 100~102 |
| 2 | 3~4 | 2 | 500~501 |
① 找 Header
↓
② 前 4 bits → LCN Offset 有幾個 Byte
後 4 bits → Length 有幾個 Byte
↓
③ 讀 Length
↓
④ 讀 LCN Offset
↓
⑤ Little Endian 解碼
↓
⑥ 累加 Current LCN
↓
⑦ 下一個 Header
↓
⑧ 遇到 00 → 結束
MFT
↓
$DATA
↓
Non-Resident Attribute
↓
MappingPairsOffset
↓
Run List
↓
Header
↓
Length + LCN Offset
↓
VCN / LCN