Storage Reserve is a relatively new feature that keeps some disk space in a system volume available for downloading and installing Windows updates. Its implementation is simple – the current amount of free space visible to applications is decreased, so the “no space left” condition occurs before the space is really exhausted.
Take a look at these screenshots:
Both of them illustrate the same drive. On the first screenshot, this drive is attached to a Windows 8.1 installation. On the second one, the same drive (actually, exactly the same image of a virtual drive) is attached to a Windows 10 “20H1” installation. And the amount of free space reported by these operating systems is different!
The reason is that the Storage Reserve feature isn’t supported in Windows 8.1. Thus, the real amount of free space is reported to a user.
Now, let’s fill those mounted volumes (“F:”) with many files containing a fixed byte pattern (using Python running from installations of Windows 10 “20H1” and Windows 8.1). When there is no space left on the volume, try to do the same with smaller files (without deleting anything). Finally, when there is no space left again, let’s try to fill the volume with even smaller files, each one occupying exactly one cluster (in order to allocate as many clusters as possible, because the first “no space left” condition reported doesn’t really mean that there are no free clusters left).
After this, let’s check the amount of free space reported by a Linux-based operating system:
We can see that some amount of free space has been left unallocated by a Windows 10 installation (gigabytes instead of megabytes as in Windows 8.1). So, how much space is actually reserved? On my machines (and as shown on the screenshot above), this is more than 6 GB. (Run the “fsutil storagereserve query C:” command to see the amount on your machine.)
It should be noted that the reserved space isn’t preallocated within a volume. There are no explicitly reserved clusters, only the amount of free space is adjusted. So, free areas on a volume can include deleted user files when the “no space left” condition is reported to a user.
Also, the reserved space is expected to exist on system volumes only.
According to the documentation, there are three types of reserved areas:
- StorageReserveIdHard (the “Hard” storage reserve area, which is used by the system to help ensure there is sufficient disk space to download and install updates),
- StorageReserveIdSoft (the “Soft” storage reserve area, which is used by the system to help ensure there is sufficient disk space to install updates),
- StorageReserveIdUpdateScratch (not documented).
- Warning: A file or directory marked as StorageReserveIdHard may be deleted automatically by the system at any time, without user consent.
- Warning: A file or directory marked as StorageReserveIdSoft may be deleted automatically by the system at any time, without user consent.
On a test system, event logs, temporary files, thumbcache files, and many other files are assigned to StorageReserveIdSoft. It seems that the Storage Reserve component additionally marks files that can be safely deleted when needed.
So, what does this mean?
An ordinary application can’t create files large enough to occupy all (or almost all) unallocated clusters. Since such large files are used by multiple tools to wipe unallocated space, there is no easy way to thoroughly wipe all (or almost all) unallocated clusters within a system volume of Windows 10.
I did multiple tests of the following tools:
- CCleaner, version: 5.68;
- SDelete, version: 2.02;
- Cipher (as included into the operating system installations used).
The tests were conducted against a drive with a Windows 10 “20H1” installation. Some tests involved running the tools from a live system, while others were conducted with this drive attached as secondary (and the tools were running from another operating system installation, either Windows 8.1 or Windows 10 “20H1”).
The drive to be wiped was filled with files containing two fixed byte patterns. This was done from a running operating system installed on that drive. No attempts have been made to fill areas beyond the reserved limit. Then, these files were deleted.
CCleaner and SDelete were configured to perform a single pass, Cipher doesn’t allow a user to specify the number of passes, the tool performs three passes (0x00, 0xFF, random bytes).
The results are:
- CCleaner, SDelete, Cipher were unable to completely wipe the free space of the “C:” volume when running on a live machine. (This means that a fixed byte pattern has been found in unallocated clusters after the wipe.)
- CCleaner, SDelete were unable to completely wipe the free space of the “F:” volume when running on a different Windows 10 machine (the drive to be wiped is attached as secondary).
- CCleaner, SDelete were able to completely wipe the free space of the “F:” volume when running on a Windows 8.1 machine.
- Cipher was able to completely wipe the free space of the “F:” volume when running on a different Windows 10 machine.
It seems that the Storage Reserve feature blocks CCleaner and SDelete from thoroughly wiping unallocated space. And since the feature isn’t supported in Windows 8.1, CCleaner and SDelete operate properly in that cases.
Note that I don’t specify how much unallocated data has been recovered after each wipe. I believe that these numbers are inconclusive in such tests.
And there is something with the Cipher tool, because it’s the only tool capable of thoroughly wiping unallocated clusters when running from a different Windows 10 machine. My first guess was that the number of passes matters in this case (it allows a tool to cover more unallocated clusters, because the allocation layout of a large file can be different during each pass).
While trying to validate this theory, I found that Cipher doesn’t limit itself to large files. It also wipes unallocated clusters by copying data of a cluster into every unallocated cluster using the defragmentation API. This feature can be found even in the Windows XP SP2 (64-bit) version of the tool, but it’s not mentioned in this paper (“One big file is not enough: a critical evaluation of the dominant free-space sanitization technique“).
The effects can be observed in the $LogFile journal as a lengthy series of UpdateMappingPairs operations, with new mapping pairs pointing to a higher cluster. In the code, the feature is implemented inside the SecureProcessFreeClusters function:
And I’m sure that such cluster moves work well even when Storage Reserve is enabled.