有不少好电影(大雾)想加密存放,但是心疼硬盘肿么办,加密盘没有填满的空间都浪费了肿么办!
TrueCrypt支持创建文件大小动态增长的加密盘,其原理是基于NTFS稀疏文件,建立时为0字节大小,有数据写入时才真正往硬盘写文件。
但是这样还不够。如果删除了加密盘中的文件,已经分配的空间并不会自动释放。VHD倒是支持先进行碎片整理,然后压缩以释放浪费的空间,但这样显然就和加密无缘了。
能想到的方法很简单,读取加密盘的空间分配信息,然后将加密盘文件对应的区域释放掉。查阅MSDN发现可以对NTFS稀疏文件使用FSCTL_SET_ZERO_DATA将指定区域设为稀疏并释放占用。
简单写了一段小程序,风格很烂(懒),目前只支持标准512扇区磁盘、FAT32分区。NTFS处理太复杂,需要处理MFT、$Bitmap可能的分块,对于开启NTFS压缩的还需要考虑忽略零碎的簇,写起来起码要1000行。
#include <Windows.h> #include <stdio.h> #include <string.h> void error(char* str) { printf(str); printf("按回车键退出。"); getchar(); getchar(); exit(-1); } void main() { printf("TrueCrypt稀疏文件释放工具v0.1 by gmsj0001\n"); char buf[64]; printf("输入加密卷挂载盘符,带冒号:"); scanf("%s", buf); char file[64]; sprintf(file, "\\\\.\\%s", buf); //打开分区,读取FAT表 HANDLE hDevice = CreateFile(file, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0); if (hDevice == INVALID_HANDLE_VALUE) error("分区打开失败!"); char boot[512]; DWORD dwRead; ReadFile(hDevice, boot, 512, &dwRead, NULL); if (memcmp(&boot[0x52], "FAT32 ", 8)) error("不是FAT32分区!"); int fat_addr = *(short*)&boot[0xe] * 512; int fat_size = *(int*)&boot[0x24] * 512; int clu_num = (*(int*)&boot[0x20] - *(short*)&boot[0xe] - *(char*)&boot[0x10] * *(int*)&boot[0x24]) / *(char*)&boot[0xd]; int data_addr = (*(short*)&boot[0xe] + *(char*)&boot[0x10] * *(int*)&boot[0x24]) * 512; int clu_size = *(char*)&boot[0xd] * 512; int* fat = (int*)malloc(fat_size); printf("读取FAT表。。。\n"); SetFilePointer(hDevice, fat_addr, 0, FILE_BEGIN); //操作磁盘设备必须是扇区对齐 ReadFile(hDevice, fat, fat_size, &dwRead, NULL); CloseHandle(hDevice); //打开文件 printf("请卸载加密卷,然后输入加密卷文件名:"); scanf("%s", file); hDevice = CreateFile(file, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0); if (hDevice == INVALID_HANDLE_VALUE) error("打开文件失败!"); printf("正在释放空间,请祈祷本软件没有bug。。。\n"); FILE_ZERO_DATA_INFORMATION zero; int i; for (i = 0; i < clu_num; ++i) { if (fat[i + 2] == 0) { zero.FileOffset.QuadPart = 0x20000 + data_addr + (LONGLONG)i * clu_size; //0x20000为TrueCrypt文件头的长度 for (; i < clu_num; ++i) if (fat[i + 2] != 0) break; zero.BeyondFinalZero.QuadPart = 0x20000 + data_addr + (LONGLONG)i * clu_size; DeviceIoControl(hDevice, FSCTL_SET_ZERO_DATA, &zero, sizeof(zero), NULL, 0, &dwRead, 0); } } CloseHandle(hDevice); free(fat); printf("搞定,按回车键退出。"); getchar(); getchar(); }
暂不提供二进制程序,因为我不完全保证此工具是完全bug free的,万一被转载到天涯海角出了问题我扶不起。
使用效果:
以后建立加密盘可以大胆地开空间(当然FAT32不能超过32G),再也不用担心填满后删除造成空间浪费了。
PO主雄起!
啊哈?emoji 失效了…
没有啊,你看我用的好好的 🙂
这不科学…