Deleted File Recovery in Ext4

 


The ext4 filesystem—the default choice for most modern Linux distributions—is a robust evolution of its predecessors, ext2 and ext3. While it brings significant improvements in performance, reliability, and scalability, one question continues to fascinate both system administrators and digital forensics enthusiasts: What actually occurs when you delete a file in ext4? When you hit the rm command, it feels instantaneous and final. Yet beneath the surface, the filesystem does not immediately erase your data. Instead, it performs a carefully coordinated sequence of metadata updates, block freeing, and journal transactions. Understanding this delicate process is key to mastering file recovery — and knowing exactly when (and how) your “deleted” files can still be rescued. In this article, we will dive deep into the internals of the ext4 filesystem to uncover exactly how file deletion works, why recovery is sometimes possible, and what techniques you can use to maximize your chances of successfully recovering deleted files.


Ext4 File Deletion Process

When a file is deleted in ext4, the process begins with removing the directory entry that links the filename to its inode. This renders the file inaccessible by name/path. The inode's link count is then decremented, and once it reaches zero (with no open file descriptors), the inode is marked free in the inode bitmap. Crucially, the inode's extent tree (mapping to data blocks) is zeroed out (cleared), the file size and block count are zeroed, and the deletion time (i_dtime) is recorded—but the inode structure itself is not fully erased and remains reusable.


Simultaneously, the associated data blocks are marked free in the block bitmap and returned to the pool of available space. However, the actual data content in those blocks is left untouched. It will only be overwritten when the blocks are later reallocated to new files. This design—where metadata is updated, but raw data persists until reuse—is exactly why deleted file recovery is frequently possible on ext4, provided action is taken before the blocks are overwritten.


Ext4 Journaling

One of ext4’s most important features is its journaling capability, which protects file system integrity by logging metadata changes before they are applied to the main structures. This mechanism also plays a supporting role in understanding (and sometimes assisting) deleted file recovery. When a file is deleted in ext4, the operation is wrapped in a journal transaction. The journal records the following key metadata updates to ensure atomicity and consistency in case of a crash or power failure:


  • Inode update → The inode’s link count is decremented. When it reaches zero, the inode is marked free in the inode bitmap, its extent tree is cleared, the file size and block count are zeroed, and the deletion timestamp (i_dtime) is set. This inode update is journaled.
  • Directory entry modification The link between the filename and inode is removed from the parent directory (typically by adjusting record lengths (rec_len) in the directory block rather than zeroing the entry). This directory block change is also journaled.

  • Block bitmap update → The data blocks previously allocated to the file are marked free in the block bitmap(s). The block bitmap changes are journaled, and revoke records or descriptor blocks may reference the affected blocks. But the journal does not typically log the list of every data block number being freed (especially for files using extents). It journals the bitmap block(s) and inode changes.


Importantly, the actual contents of the file’s data blocks are not written to the journal (in default metadata-journaling mode) and are not erased at deletion time. Only in the much slower data=journal mode (full data + metadata journaling) would file contents also go through the journal—and even then, only for new writes, not retroactively for deletions. They remain on disk until those blocks are reallocated and overwritten by new data. Each transaction is bounded by descriptor and commit records, tagged with sequence numbers to maintain proper ordering during replay. Once the changes are safely written to their final locations on disk, the transaction is checkpointed, allowing the journal space to be reused.


The data recorded in the ext4 journal during file deletion is critical to preserving file system integrity after a crash or power failure, but it does not typically include the actual file content. While the journal logs important metadata changes — such as inode updates, directory entry modifications, and block/inode bitmap adjustments — the raw data blocks of the deleted file remain untouched on the disk. This means that successful recovery of file content relies primarily on the fact that those blocks have not yet been reallocated and overwritten by new data, rather than on information stored in the journal itself.


In summary, the ext4 journal records critical changes to filesystem metadata and block allocation status during deletion. This information is essential for ensuring consistency and can sometimes assist recovery tools in locating old inodes or directory entries. However, it is important to note that the journal does not store the actual content of deleted files.


The Role Of System Calls

File deletion in Linux is typically initiated by the unlink() or unlinkat() system calls. These calls instruct the kernel to remove the directory entry that associates the filename with its inode. The operation flows through the Virtual File System (VFS) layer, which provides a generic interface for file operations regardless of the underlying file system (in this case, ext4).


Changes made during deletion — such as updating the directory block, modifying the inode, and adjusting allocation bitmaps — are first applied in the kernel’s page cache (also known as the buffer cache). These dirty pages are not immediately flushed to disk; they may remain in memory for a short time before being written back. This caching layer introduces a small delay between the rm command and the actual disk updates.


It is worth distinguishing deletion from truncation (via the truncate() or ftruncate() syscalls). Truncation reduces or removes a file’s data content while leaving the directory entry and inode intact. Deletion, by contrast, removes the name-to-inode link and eventually frees the inode once its link count reaches zero.


Because ext4 does not immediately overwrite the inode metadata or the contents of the data blocks, a recovery window exists. During this period, specialized tools can scan the filesystem for residual inode information (often recovered from the journal or unallocated inode table slots) and read the still-intact data blocks before they are reallocated to new files.


To understand the file deletion process in ext4, consider the inode that represents an allocated file, as shown in the figure below.


Figure 1: Inode hexdump before file deletion


Next, we examine the physical block number of the start of the extent tree (i.e., block number 0x98815C) as shown in the figure below.


Figure 2: Hexdump of the extent block before file deletion


Now, let us consider the changes made to the same inode when the associated file is deleted, as seen in the image below.


Figure 3: Inode hexdump after file deletion


Upon deletion, the file size (stored in bytes 0x04–0x07 of the inode, i_size_lo) is reset to zero, and the block count is typically zeroed as well. In the extent header (located at the start of the i_block field), the number of entries (eh_entries) is set to zero, and the depth of the tree (eh_depth) is reset to zero, while the magic number and maximum entries (eh_max) usually remain intact. The i_mtime (modification time) and i_ctime (inode change time) fields are updated to the time of deletion. The i_atime (access time) is usually left untouched. The i_crtime (creation/birth time, located later in the extended inode) remains unchanged and can serve as a useful forensic artifact. Note that ext4 also stores a dedicated 32-bit deletion time field (i_dtime) at bytes 0x14–0x17 (seconds resolution only) in the inode, which is set to the time of deletion. A non-zero i_dtime on an unallocated inode is a strong indicator that the inode has been deleted. Next, we examine the content of the physical block 0x98815C.


Figure 4: Hexdump of the extent block after file deletion


If you look at the extent header structure at the start of the block, the "number of extents" field has been set to zero (everything else remains the same). The first extent entry is often fully zeroed (or heavily overwritten), as is the case here. Subsequent extent entries (especially in leaf or index nodes) are not always fully zeroed. The logical block fields (ee_block / logical offset in the file) may remain, as is the case in the above figure, while the physical block information (ee_start_lo + ee_start_hi and ee_len) gets overwritten or zeroed.


The handling of the extent entries themselves varies: for small files using inline extents in the inode, the first extent (including physical block information) is often fully or partially zeroed. For larger files using a deeper extent tree, the root header in the inode is cleared as described, but some subsequent extent or index nodes on disk may retain partial information—typically the logical block offsets—while the physical block numbers (starting block and length) are frequently overwritten or zeroed. This often makes full metadata-based reconstruction of the file's data locations unreliable.


Deleted File Recovery In Ext4

When a file is deleted in ext4, the filesystem clears (zeros out) the extent information stored in the inode (though not every part of the extent tree is always fully zeroed in the same way as we had earlier seen). The inode itself is marked as free (by updating the deletion time i_dtime and setting the link count to 0), which removes the direct mapping to the file's data blocks. This is one of the main reasons standard "undelete" methods that rely on metadata become ineffective. Deletion also involves removing (or effectively hiding by adjusting record lengths) the directory entry that links the filename to the inode. This breaks the name-to-inode connection. The actual data blocks remain on disk (marked as free in the block bitmap) until they are reallocated to new files and overwritten. This is why recovery is sometimes still possible if you act quickly. Because the extents in the inode are zeroed, you can no longer easily follow the normal filesystem structures to locate the data. Recovery tools must either carve data blindly or find alternative sources of metadata.


The ext4 journal exists primarily for crash consistency and metadata integrity (ensuring the filesystem can recover after a power failure or crash). It is not designed for file undeletion. However, it often temporarily contains copies of recent metadata changes, including information about deleted files and directories. Tools like ext4magic (and to some extent extundelete) parse the journal to extract this information for recovery when possible. Success is time-limited and depends on journal size, journaling mode (data=ordered, data=writeback, etc.), and how much new activity has occurred on the filesystem.


The tool ext4magic can analyze the journal and recover files — including entire directory trees — when sufficient data remains. It can restore many file types, including large and sparse files, while preserving the original filename, ownership, group, permission bits, and the original access and modification timestamps (atime/mtime). If the data blocks themselves get overwritten (by new files), even journal information won't help—recovery then falls back to general carving tools (e.g., PhotoRec), which lose metadata such as names and timestamps. The first step to ext4 deleted file recovery is to dump the journal as shown below.




In this analysis, I wish to filter by time and recover files deleted between the period stated in the command below.



Below is a hierarchical structure of the recovered files.



ext4magic has been abandoned for over a decade. Its official SourceForge page now marks the project as abandoned, noting that it no longer works reliably with modern ext4 filesystems due to changes in e2fsprogs and related libraries. extundelete can sometimes recover recently deleted files on ext3/ext4 by reading the journal, but it is not a universal solution. It is unmaintained, often fails to compile or run on current distributions, and is difficult to deploy on minimal/custom Linux setups or systems without internet access for package installation.

For most users, the best practical options are the actively maintained, free, and open-source tools TestDisk and its companion PhotoRec (both available from CGSecurity). These utilities offer portable binaries for Linux, Windows, and macOS, so they can run directly from a USB drive without installation. They come with good documentation and support a wide range of file systems.

  • If the deletion occurred on a live/mounted filesystem (or if any overwriting is suspected), use PhotoRec. It performs signature-based file carving, which gives it a higher chance of recovering data even when filesystem metadata is damaged or partially overwritten. The downside is that recovered files lose their original names, timestamps, and directory structure—they are saved in numbered folders organized by file type.
  • If the deletion was recent and the filesystem was quickly unmounted (with minimal subsequent writes), TestDisk is often worth trying first. It can sometimes recover files with their original names and directory layout more easily, though its ext4 undelete support is more limited than on filesystems like FAT or NTFS.


Post a Comment

Previous Post Next Post