TL;DR
On an SSD, the record that a file existed often outlives its content.
Deleting a file changes little and destroys less. Deleted from Explorer, the file is renamed into the user's Recycle Bin as an $R file, with an $I file recording the original path, size and deletion time. When the bin is emptied, or on shift-delete, two fields in the MFT record header change: the in-use flag is cleared and the sequence number is incremented. $LogFile and $UsnJrnl journal the change, $Bitmap frees the clusters unless the data was resident, and $I30 slack frequently keeps the name. Shadow copies may keep the whole file.
The textbook answer breaks in several places. The deletion path changed in Windows 10 1709, when POSIX delete semantics began removing the name as soon as the deleting handle closes. The $I file has two versions, and a parser written for one silently misreads the other. And on an SSD where discards reach the drive, the content is usually gone while the MFT record, with its name, size and timestamps, can persist, so you can prove a file existed and be unable to recover a byte of it. Say what you could not have seen.
The million dollar question of any interview for a DFIR role. What happens when a file is deleted, what changes occur, and how one can still find evidence of the file's existence after the file was deleted.
I personally heard this question in interviews for every role that required experience in digital forensics. Next, by frequency, are "the meaning of file timestamps" and "how to detect file timestamp tampering", which I plan to cover in future posts.
Technical assumptions
Before we dive into the details, this article assumes a fair level of familiarity with NTFS data structures and with the digital forensic field. If you find terms or concepts here that you do not understand, check the references at the end, where I list the books I have used many times during investigations.
Since the question was always asked about Windows, I will limit the scope to Windows 7 and later with NTFS 3.1.
One caveat before we start: the deletion path changed in Windows 10 1709. If you are testing this on a modern build you will see different behavior than the classic answer describes. I cover that below.
Deep dive
First let us review how a file can be removed. In the first scenario a logged-on user deletes the file by selecting it and pressing delete, or right-clicks and deletes it, sending it to the Recycle Bin folder for that user account.
In the second scenario the file is deleted with shift and delete, or cut and paste to a different volume. This is also how most desktop applications, and the operating system itself, transparently delete files that never appear in the user's Recycle Bin. Files on network shares and on most removable drives, and files larger than the bin's maximum size, skip it as well.
The first scenario is the more complex, so let us take that one. Our user has just deleted secret_file.txt from the Desktop.
The Recycle Bin: the $R file
The original file is renamed and moved to the Recycle Bin folder corresponding to the account used to delete it.
At NTFS level this is a modification of the $FILE_NAME attribute, to reflect the new parent folder (now that user's Recycle Bin) and the new name, $R followed by six characters, retaining the original extension. That naming applies only when the file was deleted directly. If the file sat inside a folder structure and one of the parent folders was deleted, it keeps its original name.
Note that the file is moved, not copied, so the $MFT entry and the data clusters are the same ones. This matters: at this point nothing has been destroyed.
The Recycle Bin: the $I file
At the same time a $I file, the pair of the $R file above, is created in the same folder. It records the original path, the original size, and the deletion timestamp, so the OS can put the file back if the user restores it.
The format has two versions and it is worth knowing which you are looking at. Version 1, on Vista through Windows 8.1, is a fixed 544 bytes with the original path in a fixed-size field. Version 2, from Windows 10, is variable length and carries an explicit path-length field. A parser written for one will silently misread the other.
Traces of what caused the deletion will also appear in Explorer shellbags, registry entries and event logs. We will not cover those here, but keep them in the picture.
What happens at NTFS level
From the moment the user empties the Recycle Bin, the following steps are also valid for the second scenario, the shift and delete.
$MFT: the in-use flag
The in-use flag, bytes 22 to 23 of the $MFT entry header, is set to zero to indicate the entry is no longer allocated. Bit 0 is the in-use bit and bit 1 marks a directory, so a deleted directory reads 0x02 rather than 0x00.
$MFT: the sequence number
The sequence number, bytes 16 to 17 of the same header, is incremented.
This is more useful than it first appears. Directory index entries and other references store a file reference made of the record number plus the sequence number. When you find an index entry whose sequence number no longer matches the record it points at, you are looking at a record that has since been reused by a different file. That single comparison tells you whether the metadata you are reading still belongs to the file you are chasing.
$MFT: resident data
If the file is small enough, its content lives inside the MFT record itself rather than in clusters on disk. The record is typically 1024 bytes, but after the header and the $STANDARD_INFORMATION and $FILE_NAME attributes, the space left for resident $DATA is a few hundred bytes in practice, not the full 1024.
For those files, recovering the record recovers the file. Not the name and the timestamps, the actual content.
$LogFile
The $LogFile records the change. The operation used for file deletion is DeallocateFileRecordSegment.
Read it in pairs. NTFS journals redo and undo for each operation, and the deletion of a file appears alongside DeleteIndexEntryAllocation or DeleteIndexEntryRoot for the parent directory, and bitmap operations for the freed clusters. Taken together those give you the order of events, not just the fact of them.
The $LogFile can also hold resident file content, in one case: if the file was created within the log's window, the record of its creation (InitializeFileRecordSegment) carries its original content. On modern Windows, later changes to resident content are not logged, only the fact that a change happened.
The limitation is time. $LogFile normally holds minutes or hours, a few hours at most on a busy system drive, depending on how busy the system is.
$UsnJrnl:$J
The USN journal is far more verbose than $LogFile and normally covers one or more days.
When exporting the alternate data stream $J, make sure you specify the full path including the attribute name. To find deleted files after parsing, look for the reason flags FILE_DELETE (0x00000200) and CLOSE (0x80000000).
One detail that trips people up: USN reason flags accumulate across the life of a handle and are written out together. You are usually looking for a single record carrying FILE_DELETE|CLOSE, not two separate events.
Delete on close, and what changed in Windows 10
Using Procmon you can see that for file deletion the operation executed is CreateFile with the Delete on Close option set. The classic behavior is that the file enters a delete-pending state: the directory entry survives until the last handle closes, and any attempt to open it in the meantime returns access denied.
From Windows 10 1709 this is no longer the whole story. Windows added POSIX delete semantics, FILE_DISPOSITION_POSIX_SEMANTICS, which remove the name as soon as the deleting handle closes, while other open handles keep the data until the last of them closes. On current builds DeleteFileW tries a POSIX delete first and falls back to the classic one; Microsoft documents the flag but not that default, which developers observed. If you are reproducing the classic answer on a current build and the behavior does not match the textbook, this is why.
$Bitmap
For an ordinary file, $Bitmap is modified to mark the clusters it used as available again. Sparse, compressed and multi-stream files follow the same principle with more complicated bookkeeping. If the file was resident there are no clusters to free, so $Bitmap is not touched, which is itself a small signal about the size of what was deleted.
$I30: where the names survive
The $I30 index allocation and index root attribute of the parent folder may change, because the directory contents are stored as a B-tree. Depending on where the entry sat in the tree, the filename may or may not be removed from the index on deletion.
This is the part I would want a candidate to reach on their own: even when the entry is removed from the tree, the bytes frequently remain in the slack of the index allocation buffers. The resident index root is resized as the directory changes and keeps no slack.
INDX records are allocated in fixed-size blocks and the tree only rewrites what it needs to. Entries that were logically removed, and entries from earlier states of the directory, sit in the unused space after the last valid entry. Parsing that slack recovers filenames, sizes and the full set of $FILE_NAME timestamps for files whose MFT records were reused long ago.
In practice this is often the last place a deleted filename survives on a busy system.
Volume Shadow Copies
Everything above concerns the live volume. Shadow copies preserve earlier states of the same structures, so a file deleted after the last snapshot still exists, intact, inside it. Worth checking before concluding that something is unrecoverable.
SSD and TRIM: what actually happens
Most laptops now use solid state disks, and from Windows 7 the OS issues the TRIM command when a file is deleted. This is where the classic answer is most often stated incorrectly, including in my own earlier version of it.
TRIM does not remove anything from the $MFT. It informs the SSD controller that a set of logical block addresses is no longer in use. The controller is then free to erase those blocks during garbage collection. Most current drives, NVMe models especially, are deterministic after TRIM: a read of a trimmed block returns the same result, usually zeros, from the moment of the TRIM, whether or not the cells have been erased. The content is then beyond a normal read, and whatever remains in the flash can only be reached at chip level, until garbage collection erases it.
The MFT record is a separate matter. It is marked unallocated exactly as described above and it persists until the file system reuses it, which can take minutes on a busy volume or months on a quiet one. So on an SSD you will often find yourself able to prove that a file existed, with its name, size and timestamps, while being unable to recover a single byte of its content. That asymmetry is the answer worth giving.
Before assuming any of it, check whether TRIM was actually enabled: fsutil behavior query DisableDeleteNotify. A returned value of 0 means Windows sends delete notifications for NTFS volumes. Whether a given deletion reached the drive also depends on the drive reporting TRIM support and on every layer in between, such as a USB bridge, a RAID controller or a hypervisor, passing it on. It is off more often than people expect, and it does not apply at all to volumes reached over the network or to some virtual disk configurations.
HDD
On a spinning disk the file may still be present, with the modifications described above, for far longer. Seconds, minutes, hours or days, depending on how busy the system is, which is what gives a forensic examination room to work.
Putting it together
If I had to answer this in an interview in one breath, in the order I would actually pull the evidence: $MFT for the record and the sequence number, $I30 including slack for names the MFT no longer holds, $UsnJrnl for the day, $LogFile for the minutes, and for resident content if the file's creation is still in the log, $I files in the Recycle Bin for original paths, and shadow copies for anything that predates all of it.
And then the part that separates a good answer from a complete one: say what you could not have seen. On an SSD with TRIM enabled, the absence of content is not evidence that the file was empty.
Conclusion
There are a number of implications when deleting a file in a Windows system. Answering a question like this is meant to show a sound understanding of how NTFS works at a deep level, and knowing where the standard answer is wrong is a large part of that.
I hope you found it useful. If you have questions, or would like to see more content like this, get in touch.
Key takeaways
- An Explorer delete is a rename first. The file moves to the user's Recycle Bin as an $R file, with the same MFT entry and clusters, and an $I file records the original path, size and deletion time. Nothing has been destroyed yet. Shift+Delete, programmatic deletion and moves to another volume skip this stage.
- Two header fields change. The in-use flag is cleared and the sequence number is incremented. The sequence number tells you whether an index entry still points at the file you are chasing or at a record since reused by another.
- A small file is recovered with its record. Resident $DATA lives inside the MFT record, so recovering the record recovers the content, and $Bitmap is not touched, which is itself a signal about the size of what was deleted.
- Read the journals in pairs. $LogFile records DeallocateFileRecordSegment alongside the index-entry deletions and typically holds minutes to hours, and holds a resident file's original content only if the file's creation is still in the log. $UsnJrnl:$J covers a day or more, and the record to look for carries FILE_DELETE and CLOSE together.
- $I30 slack is often the last place a name survives. Entries removed from the B-tree stay in the unused space after the last valid entry, with sizes and the full $FILE_NAME timestamps, long after the MFT record was reused.
- The deletion path changed in Windows 10 1709. POSIX delete semantics remove the name when the deleting handle closes, while the data persists until the last handle closes, so a test on a current build will not match the classic delete-on-close answer.
- TRIM targets content, not the MFT record. On an SSD the controller can erase the blocks while the record keeps the name, size and timestamps. Check fsutil behavior query DisableDeleteNotify first: 0 means Windows issues discards. It does not show that the storage stack passed them on or that the drive erased the blocks.
- Parse the $I file by version. Version 1 is a fixed 544 bytes and version 2, from Windows 10, is variable length with an explicit path length. A parser written for one misreads the other without an error.
- Say what you could not have seen. On an SSD with TRIM the absence of content is not evidence that the file was empty. Check shadow copies before concluding that something is unrecoverable, and pull evidence from the sources that survive longest first.
References
- Windows forensics Forensic Examination of Windows Supported File Systems amazon.com/dp/1497358353
- Windows forensics Brian Carrier, File System Forensic Analysis amazon.com/dp/0321268172
- NTFS structures Microsoft, FILE_RECORD_SEGMENT_HEADER: sequence number and in-use flag learn.microsoft.com/windows/win32/devnotes/file-record-segment-header
- Journals Microsoft, USN_RECORD_V2: reason flags and how they accumulate learn.microsoft.com/windows/win32/api/winioctl/ns-winioctl-usn_record_v2
- Journals Linux ntfs3 driver: NTFS log operation codes, including InitializeFileRecordSegment and DeallocateFileRecordSegment github.com/torvalds/linux/blob/master/fs/ntfs3/fslog.c
- Journals Joakim Schicht, LogFileParser: what $LogFile keeps of resident data github.com/jschicht/LogFileParser
- Delete semantics Microsoft, FILE_DISPOSITION_INFORMATION_EX: POSIX delete semantics learn.microsoft.com/windows-hardware/drivers/ddi/ntddk/ns-ntddk-_file_disposition_information_ex
- Delete semantics CPython issue 84324: DeleteFileW tries a POSIX delete first, undocumented github.com/python/cpython/issues/84324
- Recycle Bin Joachim Metz, libyal: Windows Recycle.Bin file formats, $I versions 1 and 2 github.com/libyal/dtformats
- Recycle Bin Parsons and Reichert, Champlain College: Windows 10 Recycle Bin $I layout against Windows 8.1 leahycenterblog.champlain.edu/?p=1250
- Index slack Willi Ballenthin, INDXParse: recovering entries from INDX slack github.com/williballenthin/INDXParse
- TRIM General presentation en.wikipedia.org/wiki/Trim_(computing)
- TRIM Windows API: sending TRIM and UNMAP hints to storage media learn.microsoft.com/windows/win32/w8cookbook
- TRIM Activate, deactivate and query TRIM status with fsutil behavior learn.microsoft.com/windows-server/administration/windows-commands/fsutil-behavior
- TRIM Elcomsoft, What TRIM, DRAT and DZAT really mean for SSD forensics (2025) blog.elcomsoft.com/2025/06/what-trim-drat-and-dzat-really-mean-for-ssd-forensics