Windows资源pipe理器目录作为包

我一直在调查一段时间,以防止我的用户意外地进入我的应用程序的数据目录

我的应用程序使用一个文件夹来存储结构化项目。 文件夹的内部结构是批评者,不应该搞砸了。 我想让我的用户看到这个文件夹作为一个整体,不能打开它(如Mac软件)。

有没有办法在Windows上做到这一点?

从当前答案编辑

当然,我并没有试图阻止我的用户访问他们的数据,只是为了防止他们意外地破坏数据的完整性。 所以不需要encryption或密码保护。

谢谢大家.Net的答案,但不幸的是,这主要是一个C + +的项目没有任何依赖于.NET框架。

我提到的数据并不轻,它们是从电子显微镜获得的图像。 这些数据可能很大(〜100 MiB到〜1 GiB),所以将所有内容加载到内存中不是一个选项。 这些是巨大的图像,因此存储必须提供一种方法来逐个访问一个文件,而不需要将整个存档加载到内存中,从而逐步读取数据。

此外,应用程序主要是遗留下来的,有些组件我们甚至没有责任。 一个解决scheme,让我保持当前的IO代码是可取的。

shell扩展看起来很有趣,我会进一步调查解决scheme。

LarryF,你能详细介绍Filter Driver还是DefineDOSDevice? 我不熟悉这些概念。

有几件事你可以做:

有一件事是,你可以创建一个FolderView的Windows外壳扩展,将创建一个自定义视图为您的关键文件夹。 通过创建一个自定义的FolderView,你可以使文件夹变成白色,只需要一行文字“Nothing to see here”,或者你可以做一些更复杂的事情,比如使用同样方法的GAC查看器。 这个方法相当复杂,但是这种复杂性可以通过使用像这个CodeProject文章的库作为基础来缓解。

另一个解决办法是做ZIP虚拟文件系统,这将需要你直接替换使用System.IO的任何代码来使用别的东西。 ASP.NET 2.0这样做是出于这个原因,你可以很容易地构建ontop,看看这个MSDN文章实现一个VirtualPathProvider。

结构化存储是为您描述的场景而设计的:

结构化存储通过将单个文件作为结构化的对象集合(称为存储和流)进行处理来在COM中提供文件和数据持久性。

“存储”类似于文件夹,“流”类似于文件。 基本上你有一个文件,当使用结构化存储API进行访问时,它的行为看起来像一个完整的自包含文件系统。

但请注意,

对COM技术的深入理解是结构化存储开发应用的先决条件。

在你的程序内部还是外部?

有办法,但没有一个容易。 您可能要在文件系统上查看过滤器驱动程序。

如果你把ZIP文件的aproach,(我认为你,但没有提到它),我会建议使用deflate算法,但使用自己的文件系统…看看像TAR格式的东西。 然后,只需编写代码,将所有I / O通过Inflate / Deflate算法传递到磁盘。 我不会使用ZIP“格式”,因为它太容易看文件,找到PK作为前两个字节,并解压缩文件….

我最喜欢Joshperry的建议。

当然,你也可以编写一个设备驱动程序,把所有的数据存储在一个单独的文件中,但是我们再次看到一个驱动程序。 (我不确定你可以在驱动之外实现它..你可能会在你的程序中调用DefineDOSDevice,给它一个只有你的代码有权访问的名字,它将被看作是一个普通的文件系统。 )。 我会玩一些想法,如果他们工作,我会给你拍一个样品。 现在你让我感兴趣。

你可以将你的项目目录打包成一个.zip文件,并将数据存储在那里,就像使用了一个.jar(我知道一个.jar几乎是只读的,这是为了这个例子)。 做一个非标准的扩展,以便双击不会立即生效。 😉

当然,这意味着你将不得不将所有的文件IO包装到使用.zip文件中,这取决于你的程序是如何构建的,这可能是很乏味的。 Java已经完成了: TrueZip 。 也许你可以用它作为一个灵感?

如果你已经被诱惑 – 我不会建议摆弄文件夹的权限,因为显而易见的原因,这不会有帮助。

你可以使用独立存储。

http://www.ondotnet.com/pub/a/dotnet/2003/04/21/isolatedstorage.html

它并没有解决所有的问题,但它确实把应用程序数据摆脱了危害。

请记住:如果将其存储在文件系统中,用户将始终能够看到它。 篡改浏览器,我使用cmd.exe。 或总指挥官。 还是别的什么

如果你不想让人们弄乱你的文件,我会建议

  • 加密它们以防止篡改文件
  • 把它们放在一个档案(即ZIP),可能是密码保护它,然后在运行时压缩/解压缩(我会查找快速修改档案的算法)

这当然不是全面的保护,但是实现起来相当直接,不需要你在操作系统中安装时髦的东西,并且应该远离大多数好奇的用户。

当然,如果不控制计算机本身,您将永远无法完全控制用户计算机上的文件。

我见过使用Tomalak建议使用zip压缩文件的软件(Visual Paradigm的Agilian)作为“项目文件”。 Zip文件是很好理解的,使用非标准的文件扩展名可以防止偶然用户搞乱'文件'。 这样做的一大优势是,如果发生腐败,可以使用标准工具来解决问题,而且您不必担心创建专用工具来支持您的主应用程序。

看起来像FUSE的一些Windows端口正在开始出现。 我认为这将是最好的解决方案,因为它可以让我保持遗留代码(非常大)不变。

我很高兴听到你在C ++中这样做。 看来,没有人再把C ++视为“必要”了。 这些都是C#和ASP.NET,即使我在一个C#的房子里工作,当我发誓我永远不会切换,因为C ++做我需要做的一切,然后一些。 我足够成年,清理自己的记忆! 嘿..不管怎样,回到手头的问题…

DefineDOSDevice()是一种用于分配驱动器号,端口名称(LPT1,COM1等)的方法。 你传递一个名字,一些标志和一个处理这个设备的“路径”。 但是,不要让这个骗过你。 这不是一个文件系统路径,它是一个NT对象路径。 我相信你已经把它们看作是“\ Device \ HardDisk0”等。你可以使用sysinternals中的WinObj.exe来查看我的意思。 无论如何,你可以创建一个设备驱动程序,然后指向一个MSDOS符号链接,然后关闭并运行。 但是,对于原来的问题来说,这看起来像是很多工作。

这些兆字节到千兆字节文件在典型目录中有多少个? 将所有文件粘贴到一个巨型文件中,然后在其旁边存储一个索引文件(或指向每个文件的头文件),指向“虚拟文件系统”文件中的下一个“文件”即可。

一个很好的例子可能是查看Microsoft MSN Archive格式。 当我在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安全系统一起使用,它使用了与智能卡相似的东西,使用起来更方便,重用/重发,不可能(读起来非常困难,不太可能)破解,我可以在家里使用我自己的孩子! (因为总是争夺谁在计算机上获得时间,谁获得了最多,最多,最多,最多,最多,

唷..我想我在这里得到了主题。 无论如何,这里是一个微软的MSN档案格式的例子。 看看你是否能够使用类似的东西,知道你可以随时在文件中的偏移量“跳过”右边的文件,当你解析/搜索主文件中的请求的文件; 或者保存在内存中的预解析数据。 而且由于你不会在内存中加载原始的二进制文件数据,你唯一的限制可能是在32位机器上的4GB文件限制。

MARC(Microsoft MSN Archive)格式(松散地)是这样布置的:

  • 12字节标题(只有一个)
    • 文件魔术
    • MARC版本
    • 文件数量(在下表中)
  • 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; }; 

这给你一个我为他们写的标题的想法,这里是开放的功能。 是的,它缺少所有的支持电话,错误例程等,但你明白了。 请原谅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; } 

然后,你有简单的提取方法。 请记住,这是严格的病毒扫描,所以没有搜索例程等,这是为了简单地转储出一个文件,扫描,然后继续前进。 下面是我相信微软使用的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; } 

那么,我觉得这个帖子现在够长了…如果你需要帮助,或者有问题,请联系我。