有不少好电影(大雾)想加密存放,但是心疼硬盘肿么办,加密盘没有填满的空间都浪费了肿么办!
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 失效了…
没有啊,你看我用的好好的 🙂
这不科学…