Deletion only removes a name and frees the data blocks; the blocks themselves survive until new writes overwrite them. Whether a file can still be recovered comes down to two questions: is the name still there, and have the blocks been reused?
First check whether recovery is still possible
stat -c 'blocks=%b size=%s' big.log
truncate -s 0 big.log
stat -c 'blocks=%b size=%s' big.log
“Emptying a file” and “deleting a file” are two different things. Once truncate sets the size to zero and the data blocks are freed, the file itself reads as nothing. In my test (WSL Ubuntu 24.04.4), a 15-byte file went from blocks=8 to blocks=0 and cat returned empty output — the content can only be brought back by scanning free blocks.
At the metadata level, CGSecurity states that after a file is deleted the name, timestamps, size and the position of the first data block are all lost (on ext3/ext4 the name in the directory entry often survives, but the block positions are wiped), and the data is only still there until new data overwrites it [2]. So there are two routes: name-based recovery with filesystem tools, and content-based recovery with signature carving. The Ubuntu noble testdisk package description reads exactly “Partition scanner and disk recovery tool, and PhotoRec file recovery tool”, and dpkg -L testdisk lists /usr/bin/photorec — the package does ship photorec [3].
If a process still has the file open: go through /proc/PID/fd
unlink(2) says only the name is removed, and the file continues to exist while any process still has it open, until the last file descriptor referencing it is closed [4]; proc(5) says each entry under /proc/PID/fd is a symlink to the actual file [5]. That is the window in which deleted content can still be pulled back immediately.
ls -l /proc/PID/fd/0
readlink /proc/PID/fd/0
cat /proc/PID/fd/0 > /other-disk/recovered.txt
Test: after the file was unlinked, readlink /proc/PID/fd/0 showed “… (deleted)”, and both cat and cp returned the original content. The moment the process exits, the same entry disappears and this route is gone. On permissions, reading these symlinks is subject to the ptrace read check, so an unprivileged process may not be able to read another user’s fd [5].
Stop writing immediately and write the recovered files to a different device
sudo umount /data
dd if=/dev/sda2 of=/mnt/other-disk/sda2.img bs=4M
photorec /log /d /mnt/other-disk/recoup /cmd /mnt/other-disk/sda2.img fileopt,everything,enable,freespace,search
The CGSecurity manual says the /d output directory “should be on a device different from the one you are recovering from” [1] — writing on the partition that still holds the deleted data means recovered files can overwrite data that has not been scanned yet.
mount -o remount,ro on an in-use partition often fails: on the WSL ext4 root partition my attempt returned mount point is busy, so you have to unmount first or boot from another medium. Worth noting: that root partition is mounted with discard, and ext4(5) says discard controls whether the device receives discard/TRIM commands when blocks are freed [8] — blocks already TRIMmed on an SSD should not be expected to be scannable (this is an inference from the docs, not tested here).
PhotoRec: signature carving, names mostly lost
The CGSecurity manual gives the non-interactive form photorec /log /d DIR /cmd DEVICE command-list, with the commands comma-separated in order [1].
Test (PhotoRec 7.1, 8 MB raw image, a real PNG written into free space, then scanning freespace): 1 file recovered, named f0004096.png — the original filename was completely lost. The output directory I specified came back with a numeric suffix as recoup.1; the manual says PhotoRec appends a number to the directory starting at .1 [1]. A report.xml listing the recovery results is generated in the same directory. Two more observed details: structurally incomplete files are rejected (log line 1 invalid files found and rejected), and after overwriting the first 8 bytes of the signature, rescanning the same image returned 0 files.
extundelete: journal-based, names may survive but nothing is promised
extundelete /mnt/other-disk/sda2.img --restore-all
extundelete handles only ext3/ext4 and uses information stored in the partition journal to attempt recovery; the manual is explicit: “There is no guarantee that any particular file will be able to be undeleted”. --restore-all tries to restore the pre-deletion names and writes whatever it cannot as file.NNNN [6]. It also accepts a dd image, so making an image first and then running it is the safer path. Test (0.2.4-3build2): running it on a non-ext filesystem fails immediately with Bad magic number in super-block.
The debugfs list_deleted_inodes command (lsdel) can only list freed inodes, and the manual states plainly that it helps with ext2 deletions but not with ext3/ext4, because once an inode is freed its data block positions are no longer usable [7] (docs checked only, not executed).
Rollback, quick troubleshooting and limits
| Symptom | Cause | What to do | |—|—|—| | Recovered files all look like f0001234.png | carving only recognizes signatures | take the name route: extundelete / TestDisk | | Recovery returns nothing | blocks already overwritten or TRIMmed | scan the image, not the device being written to | | Output directory shows .1, .2 | a directory of that name already exists, PhotoRec appends a suffix | use a fresh output directory each run | | remount ro reports busy | filesystem is in use | umount first, or boot from another medium | | File recovered only halfway | fragmentation or structural validation failure | check against report.xml and rescan |
Rollback basis: the dd image taken before recovery is the rollback point — reruns scan only the image and never touch the original device; recovered files go to a different device while the original partition stays read-only.
Four common questions: can a truncated file still be saved? Possibly, through signature carving, if the blocks were not reused — the file itself reads as nothing. The sooner you stop writing after rm, the better, because the blocks have not been overwritten yet. TRIMmed blocks on an SSD should not be trusted. Recovery tools must never run on a partition that is being written to.
Status: draft pending review. Test environment: WSL2 Ubuntu 24.04.4 (kernel 6.6.114.1-microsoft-standard-WSL2), PhotoRec/TestDisk 7.1, extundelete 0.2.4, e2fsprogs 1.47.0, date 2026-10-26. Verified: recovering a deleted file through /proc/PID/fd, block count going to zero after truncate, scripted PhotoRec carving (including the .1 output directory, rejected invalid files, no hit after the signature was overwritten), extundelete failing on a non-ext filesystem, remount ro failing when busy, and testdisk containing photorec. Docs-checked only, not executed: name-based recovery on ext3/ext4, unrecoverability after TRIM, debugfs lsdel, a real reboot, a real SSD.
References
- [1] TestDisk and PhotoRec manual – Scripted run (CGSecurity manual)
- [2] PhotoRec – Digital Picture and File Recovery (official PhotoRec page)
- [3] testdisk — Ubuntu (noble) packages (Ubuntu package page)
- [4] unlink(2) – Linux manual page
- [5] proc(5) – File Formats Manual – Debian man page
- [6] extundelete(1) – utility to undelete files from an ext3 or ext4 partition
- [7] debugfs(8) – Linux manual page
- [8] ext4(5) — e2fsprogs — Debian bookworm
The main commands in this article were tested on WSL Ubuntu (24.04); some items (tools not installed / install-type commands) were only checked against official docs, not executed.