小工具:释放TrueCrypt加密卷占用空间

有不少好电影(大雾)想加密存放,但是心疼硬盘肿么办,加密盘没有填满的空间都浪费了肿么办!

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),再也不用担心填满后删除造成空间浪费了。

5 Replies to “小工具:释放TrueCrypt加密卷占用空间”

Leave a Reply

Your email address will not be published. Required fields are marked *