Dia cung - 14 - NTFS - sparse - compressed attribute

(tiếp theo của Dia cung - 13)



Thêm một số khái niệm về attribute

Ở phần trên đã đề cập đến các khái niệm tổng quan về attribute. Phần tiếp theo sẽ trình bày thêm một số khái niệm liên quan đến attribute trong một số tình huống sử dụng cụ thể: ví dụ, hệ thống sẽ xử lý như thế nào khi tập tin có quá nhiều attribute, việc nén và mã hóa nội dung của attribute được thực hiện như thế nào.
Base MFT entry
Một tập tin có thể có tới 65 536 attribute (vì mã định danh attribute là một số 16 bit), giả sử, tất cả các MFT entry đều thuộc kiểu non-resident, tức là MFT entry chỉ cần lưu header của các attribute, thì kích thước cần dùng tới là 65 536 * 42 = 2 752 512 byte. Trong khi kích thước của một MFT entry chỉ có 1024 byte
Như vậy, trong nhiều trường hợp, một tập tin cần nhiều hơn một MFT entry để lưu trữ các attribute của nó.
Khi có hơn một MFT entry được cấp cho một tập tin, MFT entry đầu tiên của tập tin sẽ được chuyển thành base MFT entry. Các MFT entry còn lại thuộc về tập tin này được gọi là non-base MFT entry (gọi tắt là non-base entry). Khi đó, các non-base entry sẽ có một trường để lưu địa chỉ tham chiếu tới base entry của nó.
Base MFT entry sử dụng attribute $ATTRIBUTE_LIST để chứa: tất cả các attribute thuộc về một tập tin, địa chỉ của attribute trong MFT. Các non-base entry không có chứa hai attribute: $FILE_NAME và $STANDARD_INFORMATION.
Sparse Attribute (attribute “thưa”)
NTFS có thể giảm không gian đĩa thực tế cần thiết để lưu một tập tin bằng cách lưu attribute $DATA dạng non-resident theo kiểu sparse attribute.
Sparse attribute là attribute có chứa các cluster mang giá trị 0 (tại sao lại có các cluster chứa giá trị 0?), các cluster này sẽ không được ghi vào đĩa. Trong trường hợp có sparse attribute, một run (đường chạy) đặc biệt sẽ được tạo cho các cluster mang giá trị 0.
Một run thông thường sẽ có hai thông tin: cluster bắt đầu và kích thước của run (số cluster thuộc về run). Với sparse run, sẽ chỉ có một thông tin là kích thước của run mà không có thông tin về cluster bắt đầu. NTFS sử dụng “cờ” để báo một attribute là sparse hay không sparse.
Ví dụ, xét một tập tin cần sử dụng 12 cluster để lưu trữ, trong đó 5 cluster đầu có giá trị khác 0, 3 cluster tiếp theo chứa giá trị 0, và 4 cluster cuối cùng có giá trị khác 0. Để lưu tập tin này lên trên đĩa, nếu sử dụng attribute thông thường, sẽ cần một run có chiều dài là 12, nghĩa là cần ghi 12 cluster lên đĩa. Tuy nhiên, nếu sử dụng sparse attribute sẽ cần 3 run, nhưng tổng số cluster cần ghi lên đĩa là 9. Xem hình minh họa bên dưới.

Compressed attribute (tạm dịch “thuộc tính nén”)
NTFS cho phép ghi các attribute lên đĩa dưới dạng nén, tuy nhiên, thuật toán nén không được công bố. Chú ý, đây là nén tập tin ở mức hệ thống (system-level compression) chứ không phải nén tập tin bằng các ứng dụng (application-level compression) như zip, gzip.
Microsoft chỉ thực hiện nén các attribute kiểu $DATA dạng non-resident.
NTFS sử dụng cả sparse run và nén dữ liệu để giảm không gian lưu trữ trên đĩa. Trong header của attribute $DATA có “cờ báo” cho biết attribute có được nén hay không, các “cờ báo” trong attribute $STANDARD_INFORMATION và $FILE_NAME cũng cho biết tập tin có chứa attribute được nén hay không.
Trước khi thực hiện nén, dữ liệu được chia nhỏ thành các khối có kích thước bằng nhau, gọi là các đơn vị nén (compression unit). Kích thước của đơn vị nén được lưu trong header của attribute. Có ba trường hợp xảy ra với mỗi đơn vị nén:
  1. Nếu đơn vị nén chỉ chứa giá trị 0, một run kiểu sparse sẽ được tạo ra, và không cấp phát đĩa cho đơn vị nén này.
  2. Nếu kích thước của dữ liệu sau khi nén cũng bằng kích thước của dữ liệu gốc thì sẽ không thực hiện nén dữ liệu và run sẽ được tạo dựa trên dữ liệu gốc.
  3. Nếu kích thước của dữ liệu sau khi nén nhỏ hơn kích thước của dữ liệu gốc, một run sẽ được tạo ra để lưu dữ liệu đã được nén, đồng thời một sparse run cũng sẽ được tạo, để đảm bảo tổng số cluster của run và sparse run bằng với số cluster của đơn vị nén ban đầu.
Ví dụ, quan sát tình huống sau. Giả sử, đơn vị nén có kích thước 16 cluster, chúng ta có một attribute kiểu $DATA kích thước 64 cluster. Như vậy, sẽ chia dữ liệu ra thành 4 đơn vị nén.
    • Đơn vị nén đầu tiên và thứ tư không được nén, vì sau khi thực hiện nén, kích thước vẫn là 16 cluster. Tạo hai run tương ứng cho hai đơn vị nén.
    • Đơn vị nén thứ hai chỉ chứa giá trị 0, do vậy sẽ tạo một sparse run và không cấp phát không gian đĩa.
    • Đơn vị nén thứ ba, sau khi thực hiện nén xong, còn lại kích thước 10 cluster, vì vậy, sẽ thực hiện nén đơn vị này, tạo run có kích thước 10 cluster để lưu trữ, đồng thời tạo một sparse run kích thước 6 cluster.
Xem hình minh họa dưới đây.

Khi hệ điều hành đọc các attribute $DATA đã được nén, nó thấy “cờ báo” nén được thiết lập, đồng thời thấy kích thước của các run được thiết lập dựa trên kích thước của đơn vị nén. Run đầu tiên có kích thước bằng đơn vị nén, vì vậy, nó biết run này không bị nén. Run thứ hai, có kích thước bằng đơn vị nén, và nó là một sparse, vì vậy, đây sẽ là 16 cluster mang giá trị 0; Kết hợp run thứ ba và run thứ tư sẽ tạo thành một đơn vị nén, trong đó chỉ có 10 cluster cần giải nén; run cuối cùng có kích thước bằng đơn vị nén, nên hệ điều hành cũng biết run này không bị nén.
Với các attribute $DATA đã được nén, nhưng các run lại bị phân mảnh, dẫn tới kích thước của các run không bằng nhau, không dựa trên kích thước của đơn vị nén. Trong trường hợp này, việc giải nén sẽ phức tạp hơn. Để giải nén, hệ điều hành cần thực hiện các việc sau: trộn các run lại thành một khối, chia lại khối dữ liệu thành các khối nhỏ hơn có kích thước bằng kích thước của đơn vị nén, thực hiện giải nén. Quan sát ví dụ ở hình dưới đây.

Ở hình trên, sau khi trộn run sẽ tạo thành bốn run: bắt đầu là run dữ liệu bình thường, theo sau là một sparse run, tiếp theo là một run dữ liệu bình thường, cuối cùng là một sparse run.
Thực hiện chia lại bốn run thành các run mới, với kích thước của run mới là kích thước của đơn vị nén. Kích thước của các run ban đầu: 20 + 14 + 2 + 28 + 4 + 12 = 80. Kích thước của đơn vị nén là 16. Vậy số run mới là: 80/16 = 5 run.
Thực hiện giải nén: hai run đầu tiên không có sparse run, không cần giải nén. Run thứ ba và thứ năm có sparse run, thực hiện giải nén. Run thứ tư là sparse run, tất cả mang giá trị 0.
----------------------

Tham khảo
[1] Brian Carrie, File System Forensic Analysis, Addison Wesley Professional, 2005
----------------------
Cập nhật: 2013/9/30