51 min read

> Where you are: Part I, Chapter 4 of 40. Chapter 2 taught you that a drive is a flat array of numbered sectors and clusters, and that "deleted" means a pointer was removed. Chapter 3 taught you the physical media those sectors live on — platters...

Chapter 4: File Systems — The Software Layer That Organizes Everything

Where you are: Part I, Chapter 4 of 40. Chapter 2 taught you that a drive is a flat array of numbered sectors and clusters, and that "deleted" means a pointer was removed. Chapter 3 taught you the physical media those sectors live on — platters, NAND, RAID. This chapter is the bridge between them: the file system is the software layer that turns a featureless ocean of clusters into named files in folders, with timestamps, owners, and permissions. Understand it and you understand exactly what survives a deletion, a format, or a crash — and exactly where to look for it. The wedding-photos anchor from Chapter 1 gets its mechanical explanation here.

Learning paths: Everyone needs this chapter — it is the most load-bearing in Part I. 💾 Data Recovery practitioners live inside these structures; the difference between a five-minute recovery and a failed one is whether the file system's bookkeeping survived. 🔍 Forensic Examiners treat file-system metadata as sworn evidence: timestamps, ownership, and change journals are the backbone of a timeline. 🛡️ Incident Response uses file-system artifacts (the NTFS change journal, the ext4 journal) to reconstruct what an attacker did. 📜 Legal/eDiscovery readers can move faster through the hex but should not skip the "what deleted means" sections — that vocabulary appears in every spoliation argument.


What a file system actually does

A client walks into the shop with a 2 TB external drive and a sick expression. Ten years of family photographs lived on that drive — a wedding, two newborns coming home, a parent's last birthday. While trying to "make space," they reformatted it. The reformat finished in four seconds. Four seconds, a decade of memories, gone.

Except they are almost certainly not gone. They are sitting right where they always were, in the same clusters they have occupied for years. What changed in those four seconds was not the photographs — it was the file system, the index that told the operating system where the photographs were. The reformat threw away the index and printed a fresh, empty one. The books are still on the shelves; someone just burned the library's card catalog and put out a blank one. To get the photographs back, you do not need to recover data so much as you need to understand the catalog that was destroyed, find its remnants, and read the shelves directly. That is what this chapter is about.

A file system is a data structure — a very large, very specific arrangement of bytes — written onto the storage device that organizes its raw clusters into something humans and programs can use. Strip away every feature and a file system does four jobs:

  1. Namespace management. It maps human-readable names (taxes_2023.xlsx, /home/alex/.ssh/id_rsa, \Users\Public\IMG_0423.JPG) to physical locations on the device. This is the "where does this file's data live?" map.
  2. Space management. It tracks which clusters are allocated (in use by a file) and which are free (available). Without this, the system would overwrite live files when creating new ones.
  3. Metadata management. It records everything about each file that is not the file's content: size, the famous timestamps (created, modified, accessed, and more), ownership, permissions, and flags (hidden, system, read-only, compressed, encrypted).
  4. Integrity management. Modern file systems keep a journal or use copy-on-write so that a power loss in the middle of a write does not corrupt the whole volume.

The single most important fact in this entire chapter — the one that makes both data recovery and digital forensics possible — is this: a file's content, its metadata, and its directory name are stored in three separate structures. The content is one thing. The record describing it (size, timestamps, location map) is another. The entry in a folder that gives it a name is a third. Deletion almost never erases all three. Usually it severs the links between them while leaving the structures themselves intact, sitting in space the system now considers "free" but has not yet reused.

Why This Matters. This is theme #1 of the book — deleted ≠ destroyed — expressed at the structural level. When you "delete" a file, the operating system does the cheapest possible thing: it flips a few bits to say "this space is available again." It does not scrub the content, because scrubbing 4 GB of video would take real time and wear, and the OS has no reason to bother. The content persists until something else needs that space and overwrites it. Everything you will do in Part II (recovery) and much of what you do in Part III (forensics) depends on the gap between marked free and actually overwritten. Different file systems leave different-sized gaps. Knowing which is which is the whole game.

Clusters, allocation, and slack — a quick recall

From Chapter 2 you know the unit math: a disk exposes 512-byte (or 4096-byte "Advanced Format") sectors, and the file system groups them into clusters (NTFS) or blocks (ext4) — typically 4096 bytes, or eight 512-byte sectors. The file system always allocates whole clusters. A 100-byte file consumes a full 4096-byte cluster, leaving 3996 bytes of slack space — the leftover tail of the last cluster, which still contains whatever was there before. Slack space is a recurring goldmine: fragments of older, deleted files hide in the tail ends of currently-allocated ones, where no normal tool ever looks.

To convert a cluster number to a byte offset on the disk, you need three numbers the file system records for you: the partition's starting sector, the cluster size, and the sectors per cluster. The arithmetic is simply byte_offset = (partition_start_sector + cluster_number × sectors_per_cluster) × bytes_per_sector. Write that formula on a sticky note. You will use it constantly, and getting the cluster size wrong is the single most common reason a hand-calculated offset lands in the wrong place.


The partition table: where file systems live

Before a file system exists, the disk must be carved into partitions — contiguous ranges of sectors, each of which can hold one file system. The map of those ranges is the partition table, and it lives in the very first sectors of the disk. There are two schemes you will meet: the legacy MBR and the modern GPT. Recognizing and parsing both by hand is a baseline skill, because the first question on any new piece of media is "what's the layout?" — and sometimes the partition table is the very thing that has been damaged.

MBR (Master Boot Record)

The MBR occupies the first 512-byte sector of the disk — LBA 0, the absolute beginning. Its 512 bytes are divided cleanly:

  • Bytes 0–445 (446 bytes): bootstrap code, the tiny program a BIOS jumps to at power-on.
  • Bytes 446–509 (64 bytes): the partition table — exactly four entries of 16 bytes each.
  • Bytes 510–511 (2 bytes): the boot signature, always 0x55 0xAA. If those two bytes are not present, no BIOS will treat the sector as a valid MBR.

Each 16-byte partition entry has a rigid structure:

MBR partition entry (16 bytes)
Offset  Size  Field
  0      1    Boot indicator   (0x80 = bootable, 0x00 = not)
  1      3    CHS address of first sector (legacy; ignored on modern disks)
  4      1    Partition type   (0x07 NTFS/exFAT, 0x0B/0x0C FAT32,
                                0x83 Linux, 0x82 Linux swap,
                                0x05/0x0F extended, 0xEE GPT protective)
  5      3    CHS address of last sector (legacy)
  8      4    LBA of first sector   (little-endian)
 12      4    Number of sectors     (little-endian)

Here is an annotated hex dump of a real MBR partition table region, as you would see it in xxd:

000001b0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000001c0: 2021 0007 feff ff00 0008 0000 00f8 1f00  .!..............
000001d0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000001e0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000001f0: 0000 0000 0000 0000 0000 0000 0000 55aa  ..............U.

  Partition entry 1 begins at offset 0x1BE (446). Reading across:
    80              -> boot indicator: bootable
    20 21 00        -> CHS start (legacy, ignore)
    07              -> type 0x07 = NTFS / exFAT
    fe ff ff        -> CHS end (legacy, ignore)
    00 08 00 00     -> LBA start = 0x00000800 = 2048   (the partition begins at sector 2048)
    00 f8 1f 00     -> sector count = 0x001FF800 = 2,095,104 sectors (~1.0 GB)
  Entries 2–4 are all zero (unused).
  Bytes 510–511 = 55 AA -> valid MBR signature.

Two MBR limits matter forensically. First, because the LBA fields are 32 bits and sectors are 512 bytes, MBR cannot address beyond 2^32 × 512 bytes ≈ 2.2 TB. Disks larger than that need GPT. Second, MBR allows only four primary partitions; to get more, one entry is typed 0x05/0x0F (extended) and points to a chain of logical partitions, each described by its own little embedded partition table. That chain is fragile and a frequent recovery target when someone "loses a drive letter."

A minimal parser makes the structure concrete. The following is illustrative Python — like all code in this book it is meant to be read and adapted, never executed in a forensic workflow without testing on a copy:

import struct

with open("disk.dd", "rb") as f:
    mbr = f.read(512)

if mbr[510:512] != b"\x55\xAA":
    raise ValueError("No MBR signature (0x55AA) at offset 510 — not an MBR")

for i in range(4):
    entry = mbr[446 + i * 16 : 446 + (i + 1) * 16]
    boot, ptype = entry[0], entry[4]
    lba_start, n_sectors = struct.unpack("<II", entry[8:16])
    if ptype == 0x00:
        continue  # unused slot
    print(f"Partition {i+1}: type=0x{ptype:02X}  "
          f"start_LBA={lba_start}  sectors={n_sectors}  "
          f"size={n_sectors * 512 / 1e9:.2f} GB  "
          f"bootable={boot == 0x80}")

GPT (GUID Partition Table)

GPT is the modern scheme, mandatory for UEFI boot and for disks over 2.2 TB. It is more robust by design — it stores a backup copy of itself at the end of the disk, and it checksums everything with CRC32. The layout:

  • LBA 0: a protective MBR. This is a real, valid MBR containing one partition of type 0xEE that spans the whole disk. Its only job is to stop old MBR-only tools from seeing the disk as empty and "helpfully" reinitializing it.
  • LBA 1: the primary GPT header, which begins with the ASCII signature EFI PART (45 46 49 20 50 41 52 54).
  • LBA 2 onward: the partition entry array — usually 128 entries of 128 bytes each, occupying 32 sectors.
  • Last LBA / preceding sectors: the backup GPT header and a second copy of the entry array.

The GPT header's important fields:

GPT header (at LBA 1)
Offset  Size  Field
  0      8    Signature  "EFI PART"  (45 46 49 20 50 41 52 54)
  8      4    Revision   (00 00 01 00 = v1.0)
 12      4    Header size (usually 92 = 0x5C)
 16      4    CRC32 of header
 24      8    Current LBA (location of this header)
 32      8    Backup LBA  (location of the backup header)
 40      8    First usable LBA
 48      8    Last usable LBA
 56     16    Disk GUID
 72      8    Starting LBA of the partition entry array (usually 2)
 80      4    Number of partition entries (usually 128)
 84      4    Size of each entry (usually 128)
 88      4    CRC32 of the partition entry array
00000200: 4546 4920 5041 5254 0000 0100 5c00 0000  EFI PART....\...
          \________________/ \_______/ \_______/
           "EFI PART"          rev 1.0   hdr size 0x5C = 92

Each 128-byte GPT entry leads with a partition type GUID that tells you, before you even read the file system, what is supposed to live there. A few you will memorize:

EBD0A0A2-B9E5-4433-87C0-68B6B72699C7  Microsoft Basic Data (NTFS/exFAT/FAT)
0FC63DAF-8483-4772-8E79-3D69D8477DE4  Linux filesystem
C12A7328-F81F-11D2-BA4B-00A0C93EC93B  EFI System Partition (FAT32)
7C3457EF-0000-11AA-AA11-00306543ECAC  Apple APFS
48465300-0000-11AA-AA11-00306543ECAC  Apple HFS+
E6D6D379-F507-44C2-A23C-238F2A3DF928  Linux LVM

Recovery vs. Forensics. The partition table is the first artifact where the dual-purpose lens snaps into focus. The recovery technician whose goal is to get a customer working again reaches for testdisk, which scans the disk for orphaned boot sectors and file-system signatures, rebuilds the partition table, and writes a corrected one — fast restoration. The forensic examiner does the opposite: never write to the evidence. The examiner documents the partition layout (mmls output, hashed and noted), works from a verified image, and treats a missing or altered partition table as a finding in itself — sometimes evidence of an attempt to hide a volume. Same structure, opposite reflexes: one rebuilds it, the other preserves and interprets it. Imaging-first discipline (theme #2, the original is sacred) is what lets the examiner be patient where the recovery tech must be fast.


NTFS: the file system that is made of files

NTFS — the New Technology File System — has been the default on Windows since Windows NT and is the file system you will encounter most in both corporate forensics and consumer recovery. Its central design idea is elegant and, for an examiner, wonderful: everything is a file, including the file system's own metadata. The list of files, the free-space bitmap, the transaction log, the boot code — all of them are real files with real entries, which means you can image them, hash them, and read them with the same tools you use for user data.

The boot sector and the metafiles

The first sector of an NTFS partition is the Volume Boot Record (VBR). After a 3-byte jump instruction, offset 3 holds the OEM ID NTFS (4E 54 46 53 20 20 20 20) — your instant signature that you are looking at NTFS. The VBR's BPB (BIOS Parameter Block) gives you the geometry you need for all later offset math:

NTFS boot sector (first sector of the partition)
Offset  Size  Field                         Typical value
 0x03    8    OEM ID                        "NTFS    "
 0x0B    2    Bytes per sector              512
 0x0D    1    Sectors per cluster           8        (=> 4096-byte clusters)
 0x30    8    Starting cluster of $MFT      786432
 0x38    8    Starting cluster of $MFTMirr  2
 0x40    1    Clusters per MFT record       0xF6 = -10  (=> 2^10 = 1024-byte records)
 0x48    1    Clusters per index buffer     0x01
 0x50    8    Volume serial number

That 0xF6 at offset 0x40 deserves a note: it is a signed byte. When negative, the MFT record size is 2^|value| bytes, so 0xF6 (−10) means 1024-byte records — the near-universal default. When positive, it would mean that many clusters per record. Tiny detail, real consequences if you compute it wrong.

The NTFS metadata files occupy the first reserved MFT entries (numbers 0–11, with 12–15 reserved):

Entry  Name        Purpose
  0    $MFT        the Master File Table itself
  1    $MFTMirr    backup of the first MFT records (disaster recovery)
  2    $LogFile    transaction journal (metadata redo/undo)
  3    $Volume     volume name, version, dirty flag
  4    $AttrDef    attribute definitions
  5    .  (dot)    the root directory
  6    $Bitmap     cluster allocation bitmap (free vs. used)
  7    $Boot       the boot sector / bootstrap
  8    $BadClus    map of bad clusters
  9    $Secure     security descriptors (ACLs)
 10    $UpCase     uppercase translation table
 11    $Extend     directory of optional extensions
                   ($UsnJrnl, $ObjId, $Quota, $Reparse)

The MFT and the anatomy of a record

The Master File Table is the heart of NTFS. It is an array of fixed-size records — 1024 bytes by default — and every file and directory on the volume has at least one record. The MFT entry number is the file's identity, the way the inode number is on Linux. To recover a deleted file on NTFS, your job is, fundamentally, to find its MFT record and read what it still says.

Each record begins with the ASCII signature FILE (46 49 4C 45) and a header that tells you the record's state. Here is the annotated structure — this is the diagram to internalize:

+=============================================================+
|                 NTFS MFT RECORD (1024 bytes)                |
+=============================================================+
| 0x00  "FILE"  (46 49 4C 45)  signature                      |
| 0x04  Offset to update sequence (fixup) array               |
| 0x06  Size of fixup array (in words)                        |
| 0x08  $LogFile sequence number (LSN)                        |
| 0x10  Sequence number  (incremented each time entry reused) |
| 0x12  Hard-link count                                       |
| 0x14  Offset to first attribute  (e.g. 0x38)                |
| 0x16  FLAGS  <-- 0x01 = IN USE,  0x02 = DIRECTORY           |
| 0x18  Used size of this record   (e.g. 416 bytes)           |
| 0x1C  Allocated size of record   (1024 bytes)               |
| 0x20  Base record reference (0 if this IS the base)         |
| 0x28  Next attribute ID                                     |
+-------------------------------------------------------------+
|  ATTRIBUTES (variable, packed back-to-back):                |
|    [0x10] $STANDARD_INFORMATION   timestamps, DOS perms     |
|    [0x30] $FILE_NAME              name + parent + timestamps |
|    [0x80] $DATA                   the file's content        |
|    ...    (more attributes as needed)                       |
|    0xFFFFFFFF  end-of-attributes marker                     |
+-------------------------------------------------------------+
|  ...unused space to 1024 bytes (old data may linger here)...|
+=============================================================+

The byte at offset 0x16, the flags field, is the one that decides "deleted or not." If bit 0 (0x01) is set, the record is in use — a live file. If it is clear, the record is free — but, crucially, the rest of the record is left exactly as it was. The deleted file's name, timestamps, and pointer to its data all remain until the OS recycles that MFT entry for a new file. That single bit is the difference between a file the OS shows you and a file that is sitting there, fully described, waiting to be recovered.

Attributes: a file is a bag of attributes

NTFS does not store "a file" as one blob. It stores a set of typed attributes, each with a type code, and the file is that set. The ones you must know:

  • $STANDARD_INFORMATION (type 0x10) — always resident. Holds the four timestamps that Windows Explorer shows, plus DOS-style flags and owner/security IDs. These are the timestamps malware and insiders manipulate, because they are the ones the OS updates and displays.
  • $FILE_NAME (type 0x30) — holds the file's name (in UTF-16), a reference to the parent directory's MFT entry, and a second, independent set of four timestamps. This duplicate timestamp set is one of the most valuable artifacts in Windows forensics, for reasons we will hit in a moment.
  • $DATA (type 0x80) — the actual content. A file can have more than one (see Alternate Data Streams below).
  • $INDEX_ROOT` (0x90) and `$INDEX_ALLOCATION (0xA0) — present on directories; they implement the B-tree that maps child names to MFT entries.
  • $ATTRIBUTE_LIST` (0x20), `$BITMAP (0xB0), $SECURITY_DESCRIPTOR` (0x50), `$OBJECT_ID (0x40), $REPARSE_POINT (0xC0) — used as needed.

The two timestamp sets — $STANDARD_INFORMATION` (call it `$SI) and $FILE_NAME` (call it `$FN) — are the examiner's secret weapon. Windows freely updates the $SI` timestamps during normal operation, and user-space tools can set them to anything (a single Windows API call, no special privilege). The `$FN timestamps, by contrast, are normally written by the kernel only when the file is created, moved, or renamed, and are not exposed to ordinary user-space timestamp-setting calls. So when an insider runs a tool to backdate a file's "modified" date — to make it look like a sensitive document was last touched months before they actually exfiltrated it — they change $SI`, but `$FN keeps the truth.

War Story. This is the mechanical core of the book's anchor #2 — the employee who covered their tracks. In a real IP-theft matter, a departing engineer used a timestamp tool to make a stolen design document appear untouched for a year. Windows Explorer dutifully showed the faked date. But the $FN` creation timestamp in the MFT record showed the file had been copied to a USB-staging folder three days before resignation, and the `$STANDARD_INFORMATION "modified" time was earlier than the $FN` "created" time — a logical impossibility that only happens when someone rolls `$SI back by hand. The contradiction between the two timestamp sets did not just recover the truth; it proved tampering, which is often more damning than the underlying act. We return to this in depth in Chapter 21 — Timeline Analysis. For now, remember: NTFS records the truth twice, and liars usually only edit one copy.

Resident vs. non-resident data

Where does the content actually live? It depends on size. A small file's $DATA attribute is resident — the content sits inside the MFT record itself, right after the attribute header. For files under roughly 700–900 bytes (whatever fits in the leftover space of the 1024-byte record), the entire file is the MFT entry. This has a delightful recovery consequence: recovering a small deleted text file may require nothing more than reading its still-marked-free MFT record.

When the content is too big to fit, the $DATA attribute becomes non-resident. Now the MFT record holds only a map to clusters out in the data area, encoded as data runs. A data run is a compact run-length description: a header byte whose low nibble is the byte-count of the run's length and whose high nibble is the byte-count of the starting cluster offset, followed by those bytes. Offsets after the first are stored as signed deltas from the previous run, which is how NTFS describes a fragmented file compactly.

Decoding a data run:  21 18 34 56 00

  21   -> header. low nibble 1 = length field is 1 byte
                   high nibble 2 = offset field is 2 bytes
  18   -> run length = 0x18 = 24 clusters
  34 56-> starting cluster (LCN) = 0x5634 = 22,068  (little-endian)
  00   -> end-of-runs marker

  Meaning: "this file occupies 24 clusters starting at cluster 22,068."
  With 4096-byte clusters that's 24 × 4096 = 98,304 bytes mapped here.
  A fragmented file would have several runs; each subsequent offset is a
  signed delta from the previous run's start.

The forensic and recovery payoff: as long as the MFT record survives and is readable, the data runs tell you precisely which clusters to read, in order, to reassemble even a badly fragmented deleted file — no guessing required. This is why NTFS recovery is so much more reliable than recovery on file systems that throw the map away (you will meet one next: ext4).

Alternate Data Streams (ADS)

Because a file is a bag of attributes, NTFS happily lets a file have more than one $DATA attribute. The default (unnamed) stream is the content you see; additional named streams hang off the same file invisibly. You reference them with the colon syntax file.txt:streamname. Legitimately, Windows uses this for the Mark of the Web: when you download a file, Windows attaches a Zone.Identifier stream recording that the file came from the internet (zone 3), which is why you see the "this file came from another computer" warning. Illegitimately, an attacker can hide an entire executable inside report.docx:payload.exe, and it will not show in Explorer, in dir, or in the file's reported size.

# List all data streams on a file (PowerShell)
Get-Item -Path .\installer.exe -Stream *

# Read the Mark-of-the-Web stream — proves an internet download and its source URL
Get-Content -Path .\installer.exe -Stream Zone.Identifier

# Hunt for hidden non-default streams across a tree
Get-ChildItem -Recurse -File |
    ForEach-Object { Get-Item $_.FullName -Stream * } |
    Where-Object { $_.Stream -ne ':$DATA' } |
    Select-Object FileName, Stream, Length

The classic command-line tell is dir /r, which reveals streams that plain dir hides. The Sleuth Kit's fls will list streams as separate attribute IDs. The lesson for theme #3 — every action leaves a trace — is that hiding data in an ADS is itself a trace: the presence of an unexpected named stream, and the Mark-of-the-Web's recorded source URL, are findings.

$LogFile and $UsnJrnl: NTFS keeps a diary

Two NTFS metadata files turn the file system into a witness to its own history.

$LogFile (MFT entry 2) is the transaction journal. Before NTFS changes metadata, it records redo/undo information here so a crash mid-update can be rolled forward or back. For you, it is a short-window record of recent metadata operations — file creations, deletions, renames — often complete enough to reconstruct the last few minutes or hours of activity even after the MFT itself has moved on.

$UsnJrnl`** — the Update Sequence Number journal, found at `$Extend\$UsnJrnl` and read from its `:$J stream — is even better for investigation. When enabled (it is, by default, on modern Windows), it logs every change to every file: an Update Sequence Number, a timestamp, the file's MFT reference, and reason flags (FILE_CREATE, FILE_DELETE, DATA_OVERWRITE, RENAME_OLD_NAME, RENAME_NEW_NAME, and more). Its forensic power is enormous: the $UsnJrnl can prove that a file named clientlist_final.xlsx was created, renamed, and then deleted — even if its MFT entry has since been reused and the file is otherwise unrecoverable. The journal remembers the name and the act of deletion when nothing else does.

# Query the USN change journal on C: (Windows, admin)
fsutil usn readjournal C: csv | Select-Object -First 20

# Confirm the journal exists and see its parameters
fsutil usn queryjournal C:

Recovery vs. Forensics. On NTFS the MFT serves both masters but differently. For recovery, the deleted record's data runs are a treasure map: follow them and pull the file back, fast, no court in the picture. For forensics, the same record is sworn evidence — its two timestamp sets, its hard-link count, its $LogFile` sequence number, and its parent reference all corroborate (or contradict) a story, and they must be read from a hashed image and documented, never from a live mounted disk. The recovery tech asks "can I get the bytes back?"; the examiner asks "what does this record let me *prove*, and can I show it was unaltered?" The `$UsnJrnl is the purest example of the dual lens: a recovery tech rarely needs it, but for an examiner it is sometimes the only thing that survives.

NTFS: create, delete, format — exactly what happens

Creating a file on NTFS: the OS finds a free MFT record (or extends $MFT`), sets the in-use flag at offset 0x16, writes `$STANDARD_INFORMATION and $FILE_NAME` attributes (stamping both timestamp sets), writes `$DATA (resident if small, otherwise allocating clusters via $Bitmap` and recording data runs), inserts an index entry into the parent directory's B-tree so the name resolves, and logs the whole transaction in `$LogFile and $UsnJrnl.

Deleting a file (a real delete — Shift+Delete or emptying the Recycle Bin; ordinary delete just moves it to $Recycle.Bin, covered in Chapter 16) does only three cheap things:

  1. Clears the in-use flag (offset 0x16) in the MFT record — the record is now "free."
  2. Removes the file's entry from the parent directory's index B-tree — the name no longer resolves.
  3. Marks the file's clusters free in $Bitmap.

What it does not do: it does not erase the MFT record's contents, does not wipe the $DATA clusters, and does not touch the data runs. The deleted file's complete description — name, timestamps, parent, and the exact cluster map — sits intact in a "free" MFT record, and the content sits intact in "free" clusters. This is why NTFS recovery is the most forgiving of the major file systems. A deleted file remains fully recoverable until (a) its MFT entry is reused for a new file, or (b) its clusters are overwritten — and on a drive with free space, both can take a long time.

So, what does "deleted" mean on NTFS? The pointers are removed (the directory index entry and the allocation bits), and one flag is cleared (in-use). The record and the content persist until reused. Deleted, here, means "unlinked and marked free" — not "gone."

Formatting is the wedding-photos scenario. A quick format writes a brand-new, nearly empty $MFT containing only the metadata files and a fresh root directory; it does not zero the old data area, and it usually does not zero the old MFT either — both linger in what the new file system considers unallocated space. So after a quick format, recovery proceeds on two fronts: where the new MFT overlaps the old one, the old records are lost, but everywhere else the old MFT records and the old file content remain and can be recovered by metadata analysis or, where the MFT is gone, by file carving (Chapter 7). A full format, by contrast, writes zeros (or verifies every sector) across the whole volume — that one genuinely destroys the old data, a distinction we will return to under Limitations.


ext4: the Linux workhorse that burns its own map

ext4 is the default on most Linux distributions and therefore on a huge fraction of servers, embedded devices, and Android's userdata partition. Its design is a study in contrast with NTFS, and the contrast is exactly the kind of thing that separates a practitioner who understands file systems from one who merely runs tools: on ext4, deletion destroys the file's block map. Recovery here is fundamentally harder, and knowing why tells you where to look instead.

Layout: block groups, superblock, inodes

An ext4 volume is divided into block groups, each a chunk of blocks (default 4096-byte blocks). The volume begins with (after a 1024-byte boot area) the superblock, the master record of the file system's parameters, with backup copies scattered in later block groups. The superblock's magic number lives at byte offset 1080 (that is offset 0x38 within the 1024-byte superblock, which itself starts at byte 1024) and reads 0xEF53, stored little-endian as 53 EF:

ext4 superblock (begins at byte offset 1024 from start of volume)
Offset(in SB)  Disk byte  Field
   0x00          1024      s_inodes_count       total inodes
   0x04          1028      s_blocks_count_lo    total blocks
   0x18          1048      s_log_block_size     block size = 1024 << this
   0x38          1080      s_magic = 0xEF53     ("53 EF" little-endian)
   0x58          1112      s_feature_incompat   bit 0x40 = EXTENTS in use

After the superblock come the block group descriptors, and within each group: a block bitmap (which blocks in this group are free), an inode bitmap (which inodes are free), the inode table (the inodes themselves), and the data blocks. The inode and block bitmaps are ext4's equivalent of NTFS's $Bitmap — one bit per object, set when allocated.

The inode — and the critical thing it lacks

The inode is ext4's per-file metadata structure, default 256 bytes. It is the analog of the NTFS MFT record with one enormous difference you must commit to memory: the inode does not contain the file's name. The name lives only in the directory entry that points to the inode by number. One inode can be pointed to by several names (hard links); the inode counts how many via i_links_count. Here is the inode anatomy — the second diagram to internalize, alongside the MFT record:

+=====================================================================+
|                       ext4 INODE (256 bytes)                        |
+=====================================================================+
| 0x00  i_mode          file type (high bits) + permissions (low 12)  |
| 0x02  i_uid           owner user ID                                 |
| 0x04  i_size_lo       file size in bytes (low 32 bits)              |
| 0x08  i_atime         last ACCESS time   (Unix epoch seconds)       |
| 0x0C  i_ctime         inode CHANGE time                             |
| 0x10  i_mtime         content MODIFY time                           |
| 0x14  i_dtime         DELETION time  <-- 0 while live; set on delete|
| 0x18  i_gid           group ID                                      |
| 0x1A  i_links_count   hard-link count  <-- 0 means "freed"          |
| 0x1C  i_blocks_lo     number of 512-byte blocks used                |
| 0x28  i_block[15]     60 bytes: EXTENT TREE (ext4)                  |
|                        OR 12 direct + 1 indirect + 1 double +       |
|                        1 triple block pointers (legacy ext2/3)      |
| ...   i_crtime        CREATION time (in the extra inode fields,     |
|                        present when inode size > 128 bytes)          |
+=====================================================================+
   NOTE: no filename here. The name is in the directory entry that
   references this inode's number.

Two timestamp notes for the timeline-minded. ext4 tracks atime (access), mtime (content modify), ctime (inode metadata change — not creation), and, uniquely versus ext2/3, crtime (true creation) stored in the extended inode fields. And i_dtime (deletion time) is normally zero on a live file and gets stamped with the moment of deletion — so a nonzero i_dtime on an inode whose bitmap bit is clear is your flag for "this inode used to hold a file that was deleted at this time."

Extents: the modern block map

Legacy ext2/ext3 mapped a file's blocks with block pointers: twelve direct pointers, then single/double/triple indirect blocks for larger files. ext4 replaced this with extents — far more efficient for big, contiguous files. The i_block area holds an extent tree: a 12-byte header (magic 0xF30A) followed by up to four inline extent entries, each describing a contiguous range as (logical_block, length, physical_block). Large or fragmented files push the tree into separate index blocks.

ext4 extent (12 bytes)
  ee_block   (4)  first logical block this extent covers
  ee_len     (2)  number of blocks (contiguous)
  ee_start_hi(2)  high 16 bits of physical start
  ee_start_lo(4)  low 32 bits of physical start
  Extent header magic = 0xF30A  ("0A F3" little-endian)

Directory entries and the journal

A directory is a file whose content is a chain of variable-length directory entries: inode number (4) | record length (2) | name length (1) | file type (1) | name. The record length lets entries be skipped — which matters for deletion, below.

The journal (jbd2, occupying reserved inode 8) is ext4's crash-safety mechanism and your recovery lifeline. It runs in one of three modes: journal (both metadata and data are journaled — safest, slowest), ordered (the default — metadata is journaled, data is forced to disk before its metadata commits), and writeback (metadata only, loosest). Because the journal records metadata changes before they are committed, it frequently holds a recent past copy of an inode — including, critically, that inode's block map from before the file was deleted.

ext4: create, delete — and why recovery is hard

Creating a file: allocate a free inode (clear its bit in the inode bitmap), populate the inode fields and timestamps, allocate data blocks (clear bits in the block bitmap) and record them in the extent tree, add a directory entry to the parent linking the new name to the inode number, and journal the metadata.

Deleting a file (unlink): the directory entry is removed — but usually by extending the previous entry's record length to swallow it, which means the deleted name often still sits, readable, in the directory block's slack until that block is rewritten. The inode's i_links_count is decremented; when it reaches zero, the inode bit is cleared in the inode bitmap, i_dtime is stamped, and the data blocks are freed in the block bitmap. So far this resembles NTFS. Here is the divergence that defines ext-family recovery:

ext2 left the inode's block pointers intact on deletion, so the classic debugfs undelete could read a deleted inode and follow its pointers straight to the data. ext3 deliberately zeroed those block pointers on delete — a change made for filesystem consistency that, as a side effect, broke easy undeletion: the deleted inode no longer pointed anywhere. ext4 with extents is similarly hostile to inode-based recovery — the live deleted inode typically cannot be trusted to still map to the file's blocks.

The consequence is a completely different recovery strategy than NTFS:

  1. The journal first. Tools such as extundelete and ext4magic reconstruct deleted files primarily by mining the journal for an older copy of the inode whose extent map was still populated — then following that recovered map to the (still-present) data blocks. The recovery window is "as long as the journal still holds that transaction."
  2. Directory-entry name salvage. Even when the inode is unrecoverable, the deleted name lingering in directory slack can tell you what existed.
  3. Carving. When the map is gone everywhere, fall back to file carving: the data blocks themselves remain until overwritten, so signature-based recovery can still pull files back — without their names or original paths.

Recovery vs. Forensics. The NTFS-vs-ext4 contrast is the cleanest illustration of theme #4 — technology changes, principles don't — and it changes how both disciplines work. NTFS keeps the map after deletion; ext4 burns it. So on NTFS, recovery and forensics both start at the metadata (the surviving MFT record) and only fall back to carving when the record is gone. On ext4, recovery often begins at the journal and carving, and the forensic value shifts toward the journal's transaction history and the deleted names stranded in directory slack. The method is identical at altitude — understand the structure, image first, analyze systematically, document — but the specific structure you mine is dictated by how that file system handles deletion. A practitioner who only memorized "deleted files are recoverable from the file table" would simply fail on ext4. Understanding the why is what transfers.

Limitation. ext4 recovery is time-critical in a way NTFS recovery often is not. The journal is a fixed-size ring buffer; once it wraps, the old inode copy your recovery depended on is overwritten by newer transactions — even if you never touched the disk. On a busy server, that can be minutes. The instinct from theme #2 applies with extra urgency: stop writing to the volume immediately (ideally pull power and image), because every second the system runs, the journal you need is being consumed.


APFS: Apple's copy-on-write, snapshot-native file system

APFS (Apple File System) replaced HFS+ across Apple's lineup in 2017 and is what you will find on essentially every modern Mac, iPhone, and iPad. It is built for flash, designed around copy-on-write, and organized as a forest of checksummed B-trees of objects. It also bakes encryption in at the design level — which, as you will see, is both an APFS topic and a forward pointer to Chapter 29.

Containers and volumes

APFS separates the container from the volume. A container occupies a partition and is described by a container superblock whose magic is NXSB (4E 58 53 42). Inside one container live one or more volumes, each with its own volume superblock, magic APSB (41 50 53 42). The clever part is space sharing: all volumes in a container draw from the same free pool, so a Mac's "Macintosh HD" (system) and "Macintosh HD - Data" (user) volumes share space without fixed partition sizes. Every object block carries a Fletcher-64 checksum, so APFS can detect (though, without redundancy, not always repair) corruption — and so an examiner can detect tampering.

Copy-on-write, clones, and snapshots

APFS never overwrites live data in place. When you modify a file, the changed blocks are written to new locations and the metadata is updated to point at them; the old blocks are only freed afterward. This copy-on-write (COW) discipline has three consequences that matter enormously:

  • Clones are instant, space-free copies. Duplicate a 4 GB video and APFS writes no new data — it just creates a second file referencing the same blocks, splitting them only when one copy is modified. (When you carve or analyze, two "files" may share physical blocks.)
  • Snapshots are point-in-time, read-only images of an entire volume, created near-instantly by retaining the current metadata tree and letting COW preserve the referenced blocks. macOS uses local APFS snapshots constantly — Time Machine takes hourly local snapshots, and the installer takes one before major updates. For an examiner, snapshots are a gift: a snapshot can preserve the state of files (including ones later "deleted") as they existed hours or days earlier, fully intact and mountable.
  • Checkpoints. The container periodically writes its superblock and metadata as a checkpoint in a ring of checkpoint blocks. Superseded checkpoints can linger, sometimes letting an examiner reconstruct a prior state of the file-system B-trees.

APFS: create, delete, and what survives

APFS stores a file as a set of records in the volume's file-system B-tree — an inode record, directory-entry records, and extent records — all keyed by object identifiers. Creating a file adds these records and updates the space manager's allocation bitmap; the change lands in a new checkpoint. Deleting removes the directory-entry record and, when the link count hits zero, the inode and extent records, returning the blocks to the space manager.

What survives a deletion on APFS is a more pessimistic story than NTFS, for one overriding reason: APFS lives on SSDs, and SSDs run TRIM. When APFS frees blocks, the underlying flash is typically told (via TRIM) that those blocks are discardable, and the SSD controller may zero or discard them within seconds — physically, irreversibly, at the FTL level you met in Chapter 3. The full treatment of why TRIM is the recovery-killer waits for Chapter 9, but the headline for APFS is: do not count on freed blocks persisting. Instead, your best recovery and forensic sources on APFS are snapshots (which deliberately retain the old state) and, for very recent changes, superseded checkpoints holding prior B-tree states.

So, what does "deleted" mean on APFS? The B-tree records are removed and blocks returned to the space manager. Copy-on-write means prior metadata states may briefly linger in old checkpoints, and snapshots may preserve the file outright — but TRIM on the underlying SSD usually zeroes freed content fast. Deleted here trends toward genuinely gone unless a snapshot saved it. The recovery window is short; the snapshot is your friend.

Limitation. Two APFS realities will end an investigation that a Windows-trained examiner expects to succeed. First, TRIM (above) collapses the recovery window for freed data to near zero. Second, APFS volumes are frequently encrypted — FileVault on a Mac, and hardware encryption that is effectively always-on for iOS devices. Without the key or passphrase, the on-disk bytes are ciphertext and no file-system knowledge helps. Recognizing these limits early (theme #5) means you pivot to the sources that do survive — snapshots, Time Machine backups, iCloud, and live acquisition of an unlocked device — instead of grinding on unallocated space that TRIM emptied an hour ago.


FAT32 and exFAT: simple, ubiquitous, and friendly to recovery

For all the sophistication of NTFS, ext4, and APFS, the file system on the SD card in a camera, the thumb drive on a keychain, the dashcam, and a thousand embedded gadgets is usually one of the two simplest: FAT32 or its large-media successor exFAT. Their simplicity makes them the easiest file systems to understand by hand and, often, the easiest to recover from — but with one specific, famous trap.

The FAT structure and the cluster chain

A FAT volume has four regions: a reserved region (boot sector plus, on FAT32, an FSInfo sector), the File Allocation Table itself (kept in two redundant copies), the root directory, and the data region. The boot sector identifies the type: FAT32 carries the string FAT32 at offset 0x52, while FAT12/16 carry FAT at offset 0x36; exFAT carries EXFAT at offset 3.

The File Allocation Table is the heart of the design and its name's source. It is an array indexed by cluster number, where each entry tells you the next cluster in that file's chain — a singly linked list embedded in a table:

The FAT as a cluster chain. Suppose a file starts at cluster 5:

  Directory entry says: first cluster = 5, size = 13,000 bytes

  FAT array:
    index:   ...  5     6     7     8     9    10   ...
    value:   ...  6     7     9     0    EOC   0    ...
                  |     |     |           |
                  v     v     v           v
  Chain: 5 -> 6 -> 7 -> 9 -> EOC   (clusters 5,6,7,9 hold the data, in order)
                              (note: cluster 8 is skipped -> fragmentation)
  0   = free cluster
  EOC = 0x0FFFFFF8..0x0FFFFFFF (end of chain) on FAT32

The directory tells you where a file starts; the FAT tells you the rest of the chain. Hold that division in mind — it is the key to FAT deletion.

The 32-byte directory entry

FAT directories are arrays of 32-byte entries:

FAT 8.3 directory entry (32 bytes)
Offset  Size  Field
 0x00    11   Name (8.3 format; first byte 0xE5 = DELETED)
 0x0B     1   Attributes (0x10 dir, 0x20 archive, 0x0F = long-name entry)
 0x0D     1   Creation time, tenths of a second
 0x0E     2   Creation time
 0x10     2   Creation date
 0x12     2   Last access date
 0x14     2   First cluster, HIGH 16 bits
 0x16     2   Last write time
 0x18     2   Last write date
 0x1A     2   First cluster, LOW 16 bits
 0x1C     4   File size in bytes

Long file names are stored in extra entries (attribute 0x0F) that chain before the short 8.3 entry, each holding 13 UTF-16 characters. A short worked read of a live entry:

00000000: 4956 4143 4154 494f 4e20 4a50 4720 0000  IVACATION JPG ..
00000010: 0000 0000 0000 8c5a 1500 0c00 b81e 0000  .......Z........
          name = "IVACATIO" + ext "JPG"   (a long-name entry precedes it
          with the full "MY_VACATION.JPG")
          first cluster high (0x14) = 0x0000
          first cluster low  (0x1A) = 0x000C = 12
          size (0x1C)               = 0x00001EB8 = 7,864 bytes

FAT: create, delete — and the 0xE5 trap

Creating a file: find a free 32-byte directory entry, write the name/attributes/timestamps/first-cluster/size, then walk the FAT looking for free (0) clusters, chaining them together and marking the last EOC.

Deleting a file does two things, and the second is the trap:

  1. The first byte of the directory entry is replaced with 0xE5, marking the entry available. (This is why undeleted FAT files often show as _ILENAME.JPG — the recovery tool cannot know the original first character, which 0xE5 overwrote.)
  2. The file's FAT chain entries are all set to 0 (free).

Here is the consequence that makes FAT recovery a coin flip on fragmented files. The directory entry keeps the first cluster and the size — so you always know where the file began and how big it was. But the chain is gone. For a contiguous file, that is no problem: start at the first cluster, read size bytes' worth of consecutive clusters, done — trivial, reliable recovery. For a fragmented file, you have lost the map of which clusters after the first belong to the file and in what order. You know the start and the length but not the path between. Recovery then degrades to heuristics or carving, exactly as in Chapter 7.

So, what does "deleted" mean on FAT? The directory entry's first byte becomes 0xE5 and the FAT chain is zeroed — but the start cluster and size survive in the directory entry. Deleted means "name partly clobbered, map erased, start and size known." Contiguous files recover easily; fragmented files are hard. (And because FAT keeps the start cluster, recovery tools can often relink contiguous files instantly — which is why a thumb drive of vacation photos usually comes back clean.)

exFAT: built for big flash

exFAT is Microsoft's successor for large removable media — SDXC cards are exFAT by spec — and it fixes several FAT32 limits (the 4 GB per-file ceiling, the 2 TB volume ceiling). Two design changes affect recovery. First, exFAT uses an allocation bitmap (like NTFS/ext4) to find free space, rather than scanning the FAT. Second, and helpfully for recovery, contiguous files set a "no FAT chain" flag (the NoFatChain bit in the stream-extension entry); for such files the FAT is not consulted at all — the file is described entirely by its start cluster and length. Since most files on a freshly formatted card are written contiguously, this means many exFAT files carry their full block map in the directory entry alone, surviving deletion better than FAT32's zeroed chain would suggest.

exFAT directory records come in typed sets: a File Directory Entry (type byte 0x85), a Stream Extension (0xC0) holding the start cluster, length, and the NoFatChain flag, and one or more File Name entries (0xC1). The high bit (0x80) of the type byte is the "in use" bit; on deletion it is cleared, so 0x85 becomes 0x05, 0xC0 becomes 0x40, 0xC1 becomes 0x41. Recovery tools scan for these cleared-bit signatures to rebuild deleted entry sets — and because the stream-extension entry still holds the start cluster and length, contiguous exFAT files recover cleanly.


HFS+ (briefly): the file system you will still meet

Before APFS, Apple used HFS+ (Mac OS Extended) from 1998 until 2017, and you will still encounter it on older Macs, on Time Machine backup hard drives (which remained HFS+ long after Macs moved to APFS internally), and on legacy external disks. A working familiarity is enough.

HFS+ is B-tree based. Its Volume Header, at byte offset 1024, carries the signature H+ (0x482B) for HFS+ or HX (0x4858) for the case-sensitive variant HFSX. The structure rests on a handful of special files: the Catalog File (a B-tree mapping every file and folder, by Catalog Node ID / CNID, to its metadata — the master index), the Extents Overflow File (block maps for fragmented files that overflow the catalog record), the Allocation File (the free-space bitmap), and the Attributes File (extended attributes). HFS+ added optional journaling in 2002.

Deletion on HFS+ removes the file's records from the Catalog B-tree and clears its bits in the Allocation File; the journal may briefly retain prior state. Recovery typically works by harvesting orphaned leaf nodes from the Catalog and Extents B-trees (which often persist in unallocated space) or by carving. Because Time Machine drives are HFS+, an HFS+ recovery is frequently how you reach back into a household's or company's history — which makes it more relevant than its retirement date suggests.


What "deleted" means: the master comparison

Because the per-file-system meaning of deletion is the conceptual payload of this chapter, here it is in one place. Memorize this table; it dictates your first move on any deleted-file job.

File system On delete, the system… What survives (recoverable) Primary recovery route The gotcha
NTFS clears the MFT in-use flag, removes the directory index entry, frees clusters in $Bitmap the full MFT record incl. data runs, timestamps, name; the content clusters read the deleted MFT record; follow data runs (icat) record reuse and cluster overwrite; quick-format overlap
FAT32 sets directory entry's first byte to 0xE5, zeroes the FAT chain directory entry with start cluster + size; lost 1st name char contiguous: start+size; fragmented: carve the chain is gone → fragmented files are guesswork
exFAT clears the 0x80 "in use" bit on the entry set entry set with start cluster + length; NoFatChain files fully mapped rebuild entry set; contiguous files map directly fragmented non-contiguous files still need the chain
ext4 unlinks dir entry, decrements links; at 0 frees inode/blocks, stamps i_dtime, strips the inode's block map data blocks; journal copy of old inode; deleted name in dir slack mine the journal (extundelete/ext4magic), else carve live deleted inode no longer maps to data; journal wraps fast
APFS removes B-tree records, returns blocks to space manager snapshots (best); maybe superseded checkpoints snapshots, Time Machine, then carve TRIM + encryption usually destroy/obscure freed data fast
HFS+ removes Catalog/Extents B-tree records, clears Allocation bits orphaned B-tree leaf nodes; journal remnants salvage Catalog/Extents leaf nodes, else carve B-tree node reuse; carving loses names/paths

Read down the "what survives" column and you see the spectrum: NTFS keeps the entire map (most recoverable), FAT keeps the start but burns the chain, ext4 and APFS burn the map and rely on a journal or snapshot, and APFS-on-SSD with TRIM is the harshest. Deleted ≠ destroyed is universally true, but the size of the gap between "deleted" and "destroyed" is set by the file system — and, increasingly, by the storage technology underneath it.


Recovery in practice: The Sleuth Kit, end to end

Time to turn structure into recovered files. The Sleuth Kit (TSK) is the open-source toolset that lets you walk every layer you just learned — partition table, file system, metadata, content — from the command line, and it is the engine inside the Autopsy GUI you will meet in Chapter 36. Crucially for our purposes, TSK reads images read-only — it never modifies the evidence, satisfying theme #2 by design. The workflow on a disk image (.dd/.raw) follows the layers top-down.

Step 1 — Find the partitions with mmls:

mmls wedding_drive.dd
DOS Partition Table
Offset Sector: 0
Units are in 512-byte sectors

      Slot      Start        End          Length       Description
000:  Meta      0000000000   0000000000   0000000001   Primary Table (#0)
001:  -------   0000000000   0000002047   0000002048   Unallocated
002:  000:000   0000002048   3907028991   3907026944   NTFS / exFAT (0x07)

The NTFS partition starts at sector 2048 — that offset feeds every later command via -o 2048.

Step 2 — Confirm the file system with fsstat, which also hands you the cluster size you need for offset math:

fsstat -o 2048 wedding_drive.dd
FILE SYSTEM INFORMATION
--------------------------------------------
File System Type: NTFS
Volume Serial Number: 7A3C9F1E2B6D4A08
OEM Name: NTFS
Version: Windows XP

METADATA INFORMATION
--------------------------------------------
First Cluster of MFT: 786432
First Cluster of MFT Mirror: 2
Range: 0 - 131072

CONTENT INFORMATION
--------------------------------------------
Sector Size: 512
Cluster Size: 4096
Total Cluster Range: 0 - 488377617

Step 3 — List files, including deleted ones, with fls. Deleted entries are flagged with *:

fls -o 2048 -r -p wedding_drive.dd
r/r 64-128-1:    Documents/wedding_invite.docx
r/r * 9871-128-4:    Pictures/2014_Wedding/IMG_0423.JPG   <- deleted
r/r * 9872-128-4:    Pictures/2014_Wedding/IMG_0424.JPG   <- deleted
r/r * 9873-128-4:    Pictures/2014_Wedding/IMG_0425.JPG   <- deleted
d/d * 9999-144-6:    Pictures/2014_Honeymoon              <- deleted directory

The address 9871-128-4 reads as MFT entry 9871, attribute type 128 ($DATA), attribute id 4. The * says the MFT record's in-use flag is clear — deleted, but its record (and data runs) survive.

Step 4 — Recover content by metadata address with icat, which follows the data runs and writes the file's bytes to standard output:

icat -o 2048 wedding_drive.dd 9871 > recovered/IMG_0423.JPG

Step 5 — Verify what you pulled. Confirm the type matches the extension (a header check, foreshadowing carving) and hash it for your records:

file recovered/IMG_0423.JPG
#   recovered/IMG_0423.JPG: JPEG image data, Exif standard, 4032x3024
sha256sum recovered/IMG_0423.JPG
#   3f8a...e1  recovered/IMG_0423.JPG

That five-step pipeline — mmls → fsstat → fls → icat → verifyis logical recovery on an intact-but-deleted NTFS file, and it is exactly how the wedding photos come home when the MFT survives. When the MFT does not survive (heavy overwrite, or a full format), the same fls will come up empty and you escalate to carving in Chapter 7. The full command reference is in Appendix H, and the structure cheat-sheets are in Appendix G.

Tool Tip. Always run fls with -r (recurse) and let it show deleted directories — a deleted folder (d/d *) is a map to a whole tree of deleted children. When a parent directory's MFT entry is gone but its children's entries survive, TSK lists them as orphan files under a synthetic $OrphanFiles folder; do not skip it, because in a reformat the orphans are frequently the files the client cares about.


Forensics in practice: the file system as a witness

The same structures that power recovery are, for the examiner, a sworn record. Three disciplines turn file-system metadata into defensible evidence.

Image first, analyze the copy, prove it is unaltered. Before any analysis you create a forensic image and compute its hash (the full process is Chapter 5's subject). You then run every TSK command above against the image, never the original media, and you re-hash to show nothing changed. This is theme #2 made procedural: "I found this" becomes "I can prove I found this, on this evidence, unaltered." Note fsstat's Volume Serial Number above — record it; it ties a file system to a specific volume and can link an image to other evidence.

Read both NTFS timestamp sets. Use istat to dump a single MFT record's full metadata, and compare $STANDARD_INFORMATION` against `$FILE_NAME:

istat -o 2048 wedding_drive.dd 9871
$STANDARD_INFORMATION Times:
Created:   2014-06-21 14:02:11 (EDT)
File Modified: 2014-06-21 14:02:11 (EDT)
MFT Modified:  2024-03-02 22:17:54 (EDT)
Accessed:  2024-03-02 22:17:54 (EDT)

$FILE_NAME Times:
Created:   2014-06-21 14:02:11 (EDT)
File Modified: 2014-06-21 14:02:11 (EDT)
MFT Modified:  2014-06-21 14:02:11 (EDT)
Accessed:  2014-06-21 14:02:11 (EDT)

When $SI` and `$FN agree, the timeline is consistent. When they diverge — especially when a $SI` time is *earlier* than the corresponding `$FN time, or when $SI` times are suspiciously round (`12:00:00.0000000`) while `$FN is precise — you are looking at probable timestomping. That comparison is the spine of anti-forensic detection in Chapter 30 and timeline-building in Chapter 21.

Mine the journals. The $UsnJrnl` and `$LogFile (NTFS) and the jbd2 journal (ext4) are change-history evidence. The $UsnJrnl can establish that a file existed and was deleted at a specific time even when its MFT entry was reused — the kind of fact that turns "the document is missing" into "the document was deliberately deleted at 22:14 on the night before the audit." These journals are also where you look when a suspect thinks they covered their tracks: deleting files leaves journal entries about the deletions (theme #3 — the act of erasure is itself recorded).

Recovery vs. Forensics. Bring the chapter's two disciplines together on one artifact, the deleted MFT record. The recovery technician reads its data runs and icats the bytes back — mission accomplished the moment the file opens. The examiner reads the same record but treats every field as testimony: the two timestamp sets (was it tampered?), the parent reference (where did it live?), the sequence number (how many times has this slot been reused?), the $LogFile` LSN (when was it last touched in the journal?), and the `$UsnJrnl (was its deletion logged?). The recovery tech's deliverable is a working file; the examiner's is a defensible statement about what happened and when, sourced to a hashed image and documented in a chain of custody (Appendix F). Same bytes; one restores, one proves.

Legal Note. File-system timestamps are persuasive in court precisely because juries understand "when was this file created?" — but they are also attackable on cross-examination. Timestamps reflect the system clock, which can be wrong, skewed by time zone or daylight-saving, or deliberately changed. A careful examiner corroborates a file-system timestamp with an independent source (a server log, an email header, the $UsnJrnl, an EXIF timestamp) before resting a conclusion on it. "The metadata says X" is a hypothesis; "three independent artifacts agree on X" is a finding. The legal weight of timestamps and the standards for admitting this analysis (Daubert/Frye) are Chapter 25's subject.


Worked example: the wedding photos, in full

Now run the anchor end to end with the structures in hand. The client quick-formatted a 2 TB NTFS external drive holding ten years of photographs. Here is what happened and how the chapter's knowledge recovers it.

What the quick format did. It wrote a fresh, nearly empty $MFT` at the volume's default MFT location and a clean root directory, then declared the volume "ready." It did *not* zero the 2 TB data area, and it wrote only enough new MFT records to describe an empty file system. The old `$MFT — thousands of records describing the photographs, each with intact data runs — still sits on disk except where the new (small) $MFT was written over the old one's first records.

Step 1: protect the original (theme #2, theme #6). This drive is irreplaceable — there is no "re-shoot the 2014 wedding." Before touching anything, attach the drive through a hardware write-blocker, image it with dd/dcfldd to a working file, and hash both. Every later step runs on the copy. The human cost is exactly why the discipline is non-negotiable: a careless write that overwrites cluster 3,808,891 could be the cluster holding the only photo of a grandparent who has since passed.

Step 2: try metadata recovery. Run the TSK pipeline on the image. mmls finds the NTFS partition; fsstat confirms NTFS and a 4096-byte cluster size; fls -r -p lists the new (empty) file system's handful of files — but, critically, also surfaces hundreds of orphan entries: old MFT records whose data runs survived the format, listed under $OrphanFiles`. For each surviving record, `icat` follows the data runs straight to the original photo clusters and writes the file back, perfectly intact, fragmentation and all — because the data runs preserved the exact cluster map. This recovers every photo whose old MFT record escaped being overwritten by the new `$MFT.

Step 3: carve where the MFT was overwritten. The new $MFT clobbered the first slice of the old one, so a band of early photos has no surviving record — icat cannot reach them because the map is gone. Those are not lost; their content still sits in the data area. So you escalate to file carving (Chapter 7): scan unallocated clusters for JPEG headers (FF D8 FF) and footers (FF D9) and reconstruct files by signature, independent of any file-system metadata. Carving recovers content but loses names, folders, and timestamps — IMG_0423.JPG comes back as f0042312.jpg.

Step 4: selective recovery — the human service. Carving 2 TB yields tens of thousands of fragments, including every cached thumbnail and web image the drive ever held. The skill is not pulling everything; it is pulling what matters. You sort by size and type, preview, and work with the client to identify the wedding, the homecomings, the birthday — the few hundred photographs that are the whole point. Recovery is a technical craft in service of a human need; the data structures are the means, not the end.

This single case touches every theme: deleted ≠ destroyed (the format removed the catalog, not the photos), the original is sacred (write-block and image first), every action leaves a trace (the surviving MFT records and orphans), technology changes, principles don't (NTFS-specific tactics, universal method), know your limitations (where the new MFT overwrote the old, metadata recovery ends and carving begins), and the human cost is real (these are not files; they are a family's memory).


Common mistakes

  • Computing offsets with the wrong cluster size. The single most common hand-analysis error. NTFS clusters are usually 4096 bytes but can be 512, 1024, 2048, or larger; exFAT on big cards uses 128 KB clusters. Always read the actual sectors per cluster from the boot sector (or fsstat) before doing cluster × size math. A 4096-vs-512 mistake puts you eight times too far into the disk.
  • Assuming "deleted" means the same thing on every file system. It does not, and acting as if it does will fail you on ext4 and APFS. On NTFS you read the surviving record; on ext4 the inode's map is gone and you mine the journal; on APFS-on-SSD, TRIM may have already zeroed the blocks. Match the technique to the file system.
  • Mounting the evidence read-write "just to look." Even browsing a live NTFS volume updates $STANDARD_INFORMATION` access times, the `$LogFile, and the $UsnJrnl; mounting ext4 can replay the journal and destroy the very transactions you needed for recovery. Image first; mount the image read-only (mount -o ro,loop,noload for ext4 to skip journal replay).
  • Trusting Explorer timestamps as ground truth. Those are the $SI` set — the ones any user-space tool can forge. Always corroborate against `$FN, the $UsnJrnl, and independent sources.
  • Forgetting GPT's backup. When a primary partition table is wiped, examiners new to GPT declare the disk blank. The backup GPT at the end of the disk frequently survives and reconstructs the layout in seconds.
  • Carving when metadata recovery would have worked (and vice versa). Carving a deleted NTFS file you could have icated throws away its name, path, timestamps, and exact fragmentation. Conversely, trying metadata recovery on a fragmented FAT file whose chain was zeroed wastes time. Run fls first; let the file system tell you which approach it supports.
  • Ignoring slack and the old MFT after a format. A quick format leaves the old MFT and old data largely intact; treating a "formatted" drive as empty leaves the client's data on the table.

Limitations: knowing when to stop

File-system knowledge is powerful, but it has hard edges, and recognizing them (theme #5) is a professional skill, not an admission of defeat.

Overwriting is final. Once new data occupies a cluster, the previous contents are gone — no file-system cleverness recovers them, because the bytes are physically different. A drive that has been in heavy use since the deletion, or one written end-to-end by a full format, may simply have nothing left. "The clusters were overwritten; the data is unrecoverable" is a complete and professional finding.

SSDs and TRIM collapse the recovery window. Everything in this chapter about "deleted but still present" assumes the storage holds freed blocks until reused. On SSDs with TRIM — which is to say most modern laptops, all iPhones, and APFS Macs — the controller may zero or discard freed blocks within seconds, before you ever connect a write-blocker. Knowing this is what stops you from grinding pointlessly on unallocated space that the FTL emptied an hour ago, and redirects you to sources that survive: snapshots, backups, and live acquisition. The mechanism is Chapter 9's subject.

Encryption ends file-system analysis. If the volume is BitLocker, FileVault, LUKS, or VeraCrypt encrypted and you do not have the key, the on-disk bytes are ciphertext; the MFT, inodes, and B-trees you would parse are simply not there in readable form. No amount of structure knowledge substitutes for the key. Where the key might come from — and the legal landscape around compelling it — is Chapter 29.

Journals and snapshots expire. The ext4 journal is a fixed-size ring that wraps; APFS checkpoints get reclaimed; snapshots get deleted on a schedule. The artifacts you depend on for deleted-file recovery on these file systems have a lifetime, and on a busy system that lifetime can be minutes. Speed and the decision to pull power become part of the technique.

Physical destruction is physical. A drive that has been degaussed, shredded, or had its platters scored is beyond any file-system technique. There is no software path through a physical hole.

The mature posture is to know, going in, which limit you are likely to hit on this media and this file system — and to set the client's or the court's expectations honestly. Overpromising recovery is how you lose trust; "here is exactly what is recoverable, why, and what is not" is how you keep it.


Progressive project: identify your evidence's file system and partition map

The first analytical step in your Forensic Case File is to characterize the media you have been handed before you analyze a single user file. Working only from the verified image you will acquire in Chapter 5 (for now, use any practice image from Appendix J):

  1. Run mmls and record the partition scheme (MBR or GPT), every partition's start sector, length, and type. Note whether a backup GPT is present.
  2. For each partition, run fsstat and record the file-system type, the cluster/block size, the volume serial number, and (NTFS) the first cluster of the MFT or (ext4) the superblock magic and feature flags.
  3. Write a one-paragraph media profile: "Evidence item 1 is a [GPT/MBR] disk containing N partitions; partition 2 is [NTFS/ext4/APFS/exFAT] with X-byte clusters, volume serial Y." This paragraph is the opening of your eventual report's "Examined Media" section.
  4. State, in one sentence each, what "deleted" will mean on each file system you found — i.e., which recovery route (surviving-record, start+size, journal/snapshot, or carving) you expect to use. You are pre-committing your method before you touch user data, which is exactly how a defensible examination begins.

Keep this profile; Chapter 6 builds directly on it to recover the case's deleted files.


Summary

A file system is the software layer that turns a flat sea of clusters into named, time-stamped, owned files — doing four jobs: mapping names to locations, tracking free space, holding metadata, and protecting integrity through journaling or copy-on-write. The chapter's central insight is that content, metadata, and directory name are separate structures, so deletion almost never erases all three at once — it severs links and marks space free, leaving the data until it is overwritten. That gap is what makes recovery and forensics possible, and its size depends on the file system. You learned to read the partition table (MBR's four 16-byte entries and 0x55AA signature; GPT's EFI PART header, type GUIDs, and life-saving backup). You learned NTFS as a file system made of files: the MFT, the 1024-byte record keyed on the in-use flag at offset 0x16, the attributes ($STANDARD_INFORMATION`, `$FILE_NAME with its second, harder-to-forge timestamp set, and $DATA` whether resident or mapped by data runs), alternate data streams, and the `$LogFile/$UsnJrnl journals that turn the file system into a witness. You learned ext4 as the contrast that proves you must understand mechanism, not memorize tools: inodes that hold no name, extent trees, and a deletion that strips the block map so recovery runs through the journal or carving. You met APFS (containers, volumes, copy-on-write, and snapshots — your best friend on a TRIM-aggressive SSD), FAT32/exFAT (the cluster chain, the 0xE5 deletion trap that keeps the start but burns the chain, and exFAT's contiguous-by-default helpfulness), and HFS+ on the Time Machine drives you will still meet. The master comparison table is the operational takeaway: deleted ≠ destroyed everywhere, but the route back differs by file system. Finally, you ran TSK end to end — mmls → fsstat → fls → icat → verify — recovered the wedding photos where the MFT survived and carved where the format had overwritten it, and saw the same MFT record serve recovery (the data runs) and forensics (the timestamps and journals) at once.

You can now: - Parse an MBR and a GPT partition table by hand from a hex dump, and identify the file system before mounting anything. - Read an NTFS MFT record — its in-use flag, attributes, resident vs. non-resident $DATA`, data runs, and the dual `$SI/$FN timestamps — and explain exactly what a deletion leaves behind. - Read an ext4 inode and extent tree, explain why ext4 deletion defeats inode-based recovery, and name the journal as the recovery route. - State precisely what "deleted" means on NTFS, FAT/exFAT, ext4, APFS, and HFS+, and choose the matching recovery technique for each. - Recover a deleted file from an image with The Sleuth Kit (mmls/fsstat/fls/istat/icat) and verify it with file and a hash. - Recognize when TRIM, encryption, overwriting, or journal expiry has put data genuinely out of reach — and say so.

What's next. Chapter 5 — The Forensic Process — turns the recovery instincts you just built into a defensible methodology: acquisition with write-blocking, preservation with hashing and chain of custody, systematic analysis, and reporting. It is where the court-bound anchor case (#4) is introduced and where "I found this" becomes "I can prove I found this, and it is unaltered."


Practice in exercises.md, test yourself with the quiz, apply it in the case studies, review the key takeaways, and go deeper with further reading.