如何使用C/C++单遍快速用0x00覆盖磁盘空闲空间(类似Windows系统的cipher命令)
Hey there! Let's walk through how to implement a fast, single-pass 0x00 overwrite of a disk's free space in C/C++—similar to Windows' cipher /w command, but optimized for speed by sticking to just one pass of zeros.
The idea here is straightforward: fill the disk's free space with a temporary file full of 0x00 bytes until the disk is completely full, then delete that file. The file system will allocate all available free blocks to this temporary file, overwriting any residual data left from deleted files. Once deleted, those blocks are back to being free—but now they're filled with zeros.
1. Get Available Free Space
First, you need to know how much space you can fill to avoid unnecessary writes. This is platform-specific:
- Windows: Use
GetDiskFreeSpaceEx()to retrieve the total free bytes on the target drive. - Linux/macOS: Use
statvfs()(portable) to get free space details for the target mount point.
2. Create a Temporary File
Use a hidden, temporary file (e.g., .zero_fill_temp) on the target drive's root directory.
- On Windows, add flags like
FILE_ATTRIBUTE_TEMPORARYandFILE_FLAG_DELETE_ON_CLOSEto ensure the file is automatically deleted if your program crashes. - On Linux/macOS, delete the file immediately after opening it with
unlink()—this way it doesn't appear in directory listings and is cleaned up even if the program exits abruptly.
3. Optimize Write Speed
To maximize speed, focus on minimizing I/O system calls and leveraging efficient buffering:
- Use a large buffer: Allocate a buffer of 1MB (or even 4MB, depending on your system) filled with 0x00 bytes. This reduces the number of write operations the OS has to handle.
- Sequential writes: Stick to single-threaded sequential writing. Disk drives (even SSDs) perform best with sequential I/O; multi-threaded writes can cause unnecessary seek time or contention.
- Leverage OS caching: For most cases, letting the OS handle write caching is optimal. If you use direct I/O (like
FILE_FLAG_NO_BUFFERINGon Windows), ensure your buffer and file offsets are aligned to the disk's sector size.
Windows Implementation
#include <windows.h> #include <iostream> constexpr size_t BUFFER_SIZE = 1024 * 1024; // 1MB buffer int main() { const wchar_t* targetDrive = L"C:\\"; // Update to your target drive const wchar_t* tempFilePath = L"C:\\.zero_fill_temp"; // Retrieve free disk space ULARGE_INTEGER freeBytesAvailable; if (!GetDiskFreeSpaceEx(targetDrive, &freeBytesAvailable, nullptr, nullptr)) { std::cerr << "Failed to get disk free space. Error: " << GetLastError() << std::endl; return 1; } // Create auto-deleting temporary file HANDLE hFile = CreateFile( tempFilePath, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE | FILE_FLAG_SEQUENTIAL_SCAN, nullptr ); if (hFile == INVALID_HANDLE_VALUE) { std::cerr << "Failed to create temporary file. Error: " << GetLastError() << std::endl; return 1; } // Allocate and zero out buffer char* buffer = new (std::nothrow) char[BUFFER_SIZE]; if (!buffer) { std::cerr << "Failed to allocate buffer" << std::endl; CloseHandle(hFile); return 1; } memset(buffer, 0, BUFFER_SIZE); DWORD bytesWritten; bool diskFull = false; while (!diskFull) { if (!WriteFile(hFile, buffer, BUFFER_SIZE, &bytesWritten, nullptr)) { DWORD err = GetLastError(); if (err == ERROR_DISK_FULL || err == ERROR_HANDLE_EOF) { diskFull = true; std::cout << "Disk full, stopping write." << std::endl; } else { std::cerr << "Write failed. Error: " << err << std::endl; break; } } } // Cleanup resources delete[] buffer; CloseHandle(hFile); std::cout << "Free space zero fill completed successfully!" << std::endl; return 0; }
Linux/macOS Implementation
#include <iostream> #include <fcntl.h> #include <unistd.h> #include <sys/statvfs.h> #include <cstring> #include <errno.h> constexpr size_t BUFFER_SIZE = 1024 * 1024; // 1MB buffer int main() { const char* targetPath = "/"; // Update to your target mount point const char* tempFilePath = "/.zero_fill_temp"; // Retrieve free disk space struct statvfs fsInfo; if (statvfs(targetPath, &fsInfo) != 0) { std::cerr << "Failed to get disk free space. Error: " << strerror(errno) << std::endl; return 1; } unsigned long long freeBytes = static_cast<unsigned long long>(fsInfo.f_bfree) * fsInfo.f_bsize; std::cout << "Free space available: " << freeBytes / (1024*1024) << " MB" << std::endl; // Create temporary file int fd = open(tempFilePath, O_WRONLY | O_CREAT | O_TRUNC, 0600); if (fd == -1) { std::cerr << "Failed to create temporary file. Error: " << strerror(errno) << std::endl; return 1; } // Delete file immediately to avoid directory clutter unlink(tempFilePath); // Allocate and zero out buffer char* buffer = new (std::nothrow) char[BUFFER_SIZE]; if (!buffer) { std::cerr << "Failed to allocate buffer" << std::endl; close(fd); return 1; } memset(buffer, 0, BUFFER_SIZE); ssize_t bytesWritten; bool diskFull = false; while (!diskFull) { bytesWritten = write(fd, buffer, BUFFER_SIZE); if (bytesWritten == -1) { if (errno == ENOSPC) { diskFull = true; std::cout << "Disk full, stopping write." << std::endl; } else { std::cerr << "Write failed. Error: " << strerror(errno) << std::endl; break; } } } // Cleanup resources delete[] buffer; close(fd); std::cout << "Free space zero fill completed successfully!" << std::endl; return 0; }
- Permissions: On Windows, run the program as an administrator to write large files to system drives. On Linux/macOS, ensure you have write permissions for the target directory.
- SSD Considerations: Unlike HDDs, SSDs don't require multiple overwrites to erase data (due to wear leveling and block erase mechanisms). A single pass of zeros is sufficient and avoids unnecessary drive wear.
- Avoid Raw Disk Access: Never write directly to raw disk devices (e.g.,
\\.\C:on Windows or/dev/sdaon Linux)—this will overwrite your entire disk, including the OS and all files. Always use the file system method described here. - Crash Safety: The temporary file flags ensure the file is cleaned up even if your program crashes unexpectedly.
Hope this gives you a solid, fast implementation for zero-filling free disk space! If you have questions about specific parts or need help adapting it to your use case, feel free to ask.
内容的提问来源于stack exchange,提问作者Sofia

