我很高兴听到您在 C++ 中执行此操作。似乎没有人认为 C++ 是“必要的”了。这都是 C# 和 ASP.NET ......即使我在一个全 C# 的房子里工作,当我发誓我永远不会切换时,因为 C++ 做了我曾经需要做的所有事情,然后是一些。我已经成年了,可以清理自己的记忆了!呵呵..无论如何,回到手头的问题...
这DefineDOSDevice()
是一种用于分配驱动器号、端口名称(LPT1、COM1 等)的方法。你给它一个名字,一些标志和一个处理这个设备的“路径”。但是,不要让它愚弄你。它不是文件系统路径,而是 NT 对象路径。我确定您已经将它们视为“\Device\HardDisk0”等。您可以使用 sysinternals 中的 WinObj.exe 来了解我的意思。无论如何,您可以创建一个设备驱动程序,然后将 MSDOS 符号链接指向它,然后您就可以关闭并运行了。但是,对于最初的问题,这似乎需要做很多工作。
一个典型的目录中有多少这些兆到千兆字节的文件?您最好将所有文件粘贴在一个巨型文件中,并在其旁边存储一个索引文件(或每个文件的标题),该文件指向“虚拟文件系统”文件中的下一个“文件”。
一个很好的例子可能是查看 Microsoft MSN 存档格式。当我在一家 AV 公司工作时,我颠倒了这种存档格式,它实际上非常有创意,但非常简单。可以在一个文件中完成所有操作,如果您想要花哨,您可以将数据存储在 RAID 5 类型配置中的 3 个文件中,因此如果 3 个文件中的任何一个被冲洗掉,您可以重建其他文件。另外,用户只会在一个目录中看到 3 个非常大的文件,并且无法访问单个(内部)文件。
我为您提供了解压缩这些 MSN 存档格式之一的代码。我没有创建一个的代码,但是从提取源中,您可以毫无问题地构建/编写一个。如果文件被删除和/或经常重命名,则可能会导致文件中的已用空间出现问题,必须不时进行修剪。
这种格式甚至支持 CRC 字段,因此您可以测试文件是否正常。我永远无法完全逆转微软用来对数据进行 CRC 校验的算法,但我有一个很好的主意。
您将无法保留当前的 I/O 例程,这意味着 CreateFile() 不仅能够打开存档中的任何文件,但是,凭借 C++ 的超酷,您可以覆盖 CreateFile 调用来实现您的存档格式。
如果您需要他的帮助,并且这是一个足够大的问题,也许我们可以离线讨论并为您找到解决方案。
我不反对给你写一个 FileSystemDriver,但为此,我们必须开始谈论补偿。就像我现在所做的那样,我非常乐意免费为您提供指导和想法。
我不确定在这里给你我的电子邮件地址是否符合犹太教规,我不确定 SO 在这方面的政策,因为我们可能会谈论潜在的工作/征集,但这不是我唯一的意图。我宁愿先帮你找到自己的解决方案。
在查看设备驱动程序之前,请下载 WinDDK。它到处都是驱动程序示例。
如果你想知道我为什么这么关心这个,那是因为我多年来一直在写一个类似于这个的驱动程序,它必须是 Windows和与 OSX 兼容,这将允许用户保护驱动器卷(USB 密钥、可移动卷),而无需安装任何驱动程序或复杂(而且体积庞大,有时令人讨厌)的软件。近年来,很多硬件制造商都在做类似的事情,但我认为安全性并不是那么安全。我正在研究使用 RSA 和 AES,与 GPG 和 PGP 的工作方式完全相同。最初,我被告知(我相信,但没有证据)将用于保护 MP3 文件的内容。由于它们将以加密格式存储,因此如果没有正确的密码短语,它们根本无法工作。但是,我也看到了它的其他用途。(当一个 16 兆(是 MEG)USB 密钥的成本超过 100 美元左右时,这又回来了)。
该项目还与我的石油和天然气行业 PC 安全系统一起使用,该系统使用类似于智能卡的东西,只是更容易使用、重复使用/重新发行、不可能(阅读:非常困难和不太可能)破解,并且我可以在家里自己的孩子身上使用它!(因为总是争论谁在电脑上的时间,谁得到的最多,等等,等等,等等……)
呼……我想我在这里跑题了。无论如何,这里是 Microsoft MSN 存档格式的示例。看看你是否可以使用这样的东西,知道你总是可以通过在主文件中解析/搜索请求的文件时跟踪文件中的偏移量来“跳过”文件;或在内存中保存的预解析数据中。而且由于您不会在内存中加载原始二进制文件数据,因此您唯一的限制可能是 32 位机器上的 4gb 文件限制。
MARC(Microsoft MSN 存档)格式的布局(松散)如下:
- 12字节头(只有一个)
- 68 字节文件表头(其中 1 到 Header.NumFiles)
现在,在 12 字节文件表条目中,32 位用于文件长度和偏移量。对于非常大的文件,您可能必须将其增加到 48 或 64 位整数。
这是我为处理这些而编写的一些代码。
#define MARC_FILE_MAGIC 0x4352414D // In Little Endian
#define MARC_FILENAME_LEN 56 //(You'll notice this is rather small)
#define MARC_HEADER_SIZE 12
#define MARC_FILE_ENT_SIZE 68
#define MARC_DATA_SIZE 1024 * 128 // 128k Read Buffer should be enough.
#define MARC_ERR_OK 0 // No error
#define MARC_ERR_OOD 314 // Out of data error
#define MARC_ERR_OS 315 // Error returned by the OS
#define MARC_ERR_CRC 316 // CRC error
struct marc_file_hdr
{
ULONG h_magic;
ULONG h_version;
ULONG h_files;
int h_fd;
struct marc_dir *h_dir;
};
struct marc_file
{
char f_filename[MARC_FILENAME_LEN];
long f_filesize;
unsigned long f_checksum;
long f_offset;
};
struct marc_dir
{
struct marc_file *dir_file;
ULONG dir_filenum;
struct marc_dir *dir_next;
};
这让您了解我为它们编写的标题,这里是 open 函数。是的,它缺少所有的支持电话、错误例程等,但你明白了。请原谅 C 和 C++ 代码风格的混合。我们的扫描仪是由许多类似这样的问题组成的集群……我使用了诸如 open()、fopen() 之类的古老调用,以与代码库的其余部分保持标准。
struct marc_file_hdr *marc_open(char *filename)
{
struct marc_file_hdr *fhdr = (struct marc_file_hdr*)malloc(sizeof(marc_file_hdr));
fhdr->h_dir = NULL;
#if defined(_sopen_s)
int errno = _sopen_s(fhdr->h_fd, filename, _O_BINARY | _O_RDONLY, _SH_DENYWR, _S_IREAD | _S_IWRITE);
#else
fhdr->h_fd = open(filename, _O_BINARY | _O_RDONLY);
#endif
if(fhdr->h_fd < 0)
{
marc_close(fhdr);
return NULL;
}
//Once we have the file open, read all the file headers, and populate our main headers linked list.
if(read(fhdr->h_fd, fhdr, MARC_HEADER_SIZE) != MARC_HEADER_SIZE)
{
errmsg("MARC: Could not read MARC header from file %s.\n", filename);
marc_close(fhdr);
return NULL;
}
// Verify the file magic
if(fhdr->h_magic != MARC_FILE_MAGIC)
{
errmsg("MARC: Incorrect file magic %x found in MARC file.", fhdr->h_magic);
marc_close(fhdr);
return NULL;
}
if(fhdr->h_files <= 0)
{
errmsg("MARC: No files found in archive.\n");
marc_close(fhdr);
return NULL;
}
// Get all the file headers from this archive, and link them to the main header.
struct marc_dir *lastdir = NULL, *curdir = NULL;
curdir = (struct marc_dir*)malloc(sizeof(marc_dir));
fhdr->h_dir = curdir;
for(int x = 0;x < fhdr->h_files;x++)
{
if(lastdir)
{
lastdir->dir_next = (struct marc_dir*)malloc(sizeof(marc_dir));
lastdir->dir_next->dir_next = NULL;
curdir = lastdir->dir_next;
}
curdir->dir_file = (struct marc_file*)malloc(sizeof(marc_file));
curdir->dir_filenum = x + 1;
if(read(fhdr->h_fd, curdir->dir_file, MARC_FILE_ENT_SIZE) != MARC_FILE_ENT_SIZE)
{
errmsg("MARC: Could not read file header for file %d\n", x);
marc_close(fhdr);
return NULL;
}
// LEF: Just a little extra insurance...
curdir->dir_file->f_filename[MARC_FILENAME_LEN] = NULL;
lastdir = curdir;
}
lastdir->dir_next = NULL;
return fhdr;
}
然后,您有简单的提取方法。请记住,这仅用于病毒扫描,因此没有搜索例程等。这旨在简单地转储文件,对其进行扫描,然后继续。下面是我相信 Microsoft 使用的 CRC 代码例程,但我不确定他们 CRC 到底是什么。它可能包括标题数据+文件数据等。我只是没有足够的心思回去尝试扭转它。无论如何,如您所见,这种存档格式没有压缩,但添加起来非常容易。如果您愿意,可以提供完整的源代码。(我认为剩下的就是 close() 例程,以及调用和提取每个文件的代码等!!)
bool marc_extract(struct marc_file_hdr *marc, struct marc_file *marcfile, char *file, int &err)
{
// Create the file from marcfile, in *file's location, return any errors.
int ofd = 0;
#if defined(_sopen_s)
err = _sopen_s(ofd, filename, _O_CREAT | _O_SHORT_LIVED | _O_BINARY | _O_RDWR, _SH_DENYNO, _S_IREAD | _S_IWRITE);
#else
ofd = open(file, _O_CREAT | _O_SHORT_LIVED | _O_BINARY | _O_RDWR);
#endif
// Seek to the offset of the file to extract
if(lseek(marc->h_fd, marcfile->f_offset, SEEK_SET) != marcfile->f_offset)
{
errmsg("MARC: Could not seek to offset 0x%04x for file %s.\n", marcfile->f_offset, marcfile->f_filename);
close(ofd);
err = MARC_ERR_OS; // Get the last error from the OS.
return false;
}
unsigned char *buffer = (unsigned char*)malloc(MARC_DATA_SIZE);
long bytesleft = marcfile->f_filesize;
long readsize = MARC_DATA_SIZE >= marcfile->f_filesize ? marcfile->f_filesize : MARC_DATA_SIZE;
unsigned long crc = 0;
while(bytesleft)
{
if(read(marc->h_fd, buffer, readsize) != readsize)
{
errmsg("MARC: Failed to extract data from MARC archive.\n");
free(buffer);
close(ofd);
err = MARC_ERR_OOD;
return false;
}
crc = marc_checksum(buffer, readsize, crc);
if(write(ofd, buffer, readsize) != readsize)
{
errmsg("MARC: Failed to write data to file.\n");
free(buffer);
close(ofd);
err = MARC_ERR_OS; // Get the last error from the OS.
return false;
}
bytesleft -= readsize;
readsize = MARC_DATA_SIZE >= bytesleft ? bytesleft : MARC_DATA_SIZE;
}
// LEF: I can't quite figure out how the checksum is computed, but I think it has to do with the file header, PLUS the data in the file, or it's checked on the data in the file
// minus any BOM's at the start... So, we'll just rem out this code for now, but I wrote it anyways.
//if(crc != marcfile->f_checksum)
//{
// warningmsg("MARC: File CRC does not match. File could be corrupt, or altered. CRC=0x%08X, expected 0x%08X\n", crc, marcfile->f_checksum);
// err = MARC_ERR_CRC;
//}
free(buffer);
close(ofd);
return true;
}
这是我假设的 CRC 例程(我可能从 Stuart Caie 和libmspack偷了这个,我不记得了):
static unsigned long marc_checksum(void *pv, UINT cb, unsigned long seed)
{
int count = cb / 4;
unsigned long csum = seed;
BYTE *p = (BYTE*)pv;
unsigned long ul;
while(count-- > 0)
{
ul = *p++;
ul |= (((unsigned long)(*p++)) << 8);
ul |= (((unsigned long)(*p++)) << 16);
ul |= (((unsigned long)(*p++)) << 24);
csum ^= ul;
}
ul = 0;
switch(cb % 4)
{
case 3: ul |= (((unsigned long)(*p++)) << 16);
case 2: ul |= (((unsigned long)(*p++)) << 8);
case 1: ul |= *p++;
default: break;
}
csum ^= ul;
return csum;
}
好吧,我认为这篇文章现在已经够长了……如果您需要帮助或有任何问题,请联系我。