In the Linux world, a deleted file which is still open isn’t actually removed from a disk. Instead, it’s just unlinked from the directory structure. This is why a system call used to remove files is named “unlink”.
unlink() deletes a name from the filesystem. If that name was the last link to a file and no processes have the file open, the file is deleted and the space it was using is made available for reuse.
If the name was the last link to a file but any processes still have the file open, the file will remain in existence until the last file descriptor referring to it is closed.
The same behavior can be observed in other Unix-like operating systems.
But in Windows 10, similar behavior can be seen too!
If a file is opened in a way that allows to delete this file from another process (this can be achieved by specifying the FILE_SHARE_DELETE flag for the CreateFile function) and that process tries to delete it, the file is actually moved to the “\$Extend\$Deleted” directory on the same volume.
When the last handle to such a file is closed, it’s deleted as usual. When the file system is mounted, all existing files in the “\$Extend\$Deleted” directory (if any) are deleted (thus, a system crash won’t result in leftover files being stored forever).
The same logic also applies to “deleted” directories.
During usual operations of the operating system, such “deleted” files constantly appear and disappear on the system volume. Here is a listing from the “\$Extend\$Deleted” directory of a Windows 10 installation in a virtual machine (this is the output of the fls tool, each entry is marked as deleted, you can see both files and directories):
-/d * 21437-144-6: 000C0000000053BD1204FEEF -/r * 21440-128-1: 000C0000000053BD1204FEEF/summary.txt -/r * 21441-128-4: 000C0000000053BD1204FEEF/summary.json -/r * 21442-128-4: 000C0000000053BD1204FEEF/scenario_data.xml -/d * 21439-144-1: 000C0000000053BF535BA4C6 -/d * 21443-144-1: 000B0000000053C3193045B7 -/d * 21444-144-1: 000B0000000053C446D7B136 -/d * 21445-144-1: 000B0000000053C502CAB389 -/d * 21446-144-1: 000B0000000053C63BFD74DD -/d * 21447-144-1: 000B0000000053C70AB5A416 -/d * 21448-144-1: 000B0000000053C81DACF52E -/d * 21449-144-1: 000C0000000053C93E41B172 -/d * 21450-144-1: 000B0000000053CA3F1165AD -/d * 21451-144-1: 000B0000000053CB557B3B43 -/r * 21493-128-4: 00150000000053F54ED9BE0B -/d * 85145-144-1: 0015000000014C9976249331 -/r * 85149-128-1: 0015000000014C9976249331/container.dat
All file names in the “\$Extend\$Deleted” directory are munged (this doesn’t apply to files in subdirectories). The format of a munged file name is:
<a file reference number (of this file) as a HEX string><four random bytes as a HEX string)>
For example: “0015000000014C9976249331″. The file reference number is shown in bold (the file record number is 85145, the sequence number is 21), the last 8 characters are a random 32-bit integer.
It’s interesting that this feature isn’t implemented in the same way in previous versions of Windows (8.1 and below). In Windows 7, a deleted file which is still open remains in its original directory (just like any normal file), but it can’t be opened anymore.