利用dokan作虚拟磁盘开发
语无伦次,仅做为备忘。
dokan是用户态的文件系统驱动,可以称之为fuse for windows。可以用来开发虚拟磁盘,即在“我的电脑”中虚拟出一个硬盘来,可以是硬盘,也可以是可移动磁盘或者网络硬盘。
CreateFile、FindFiles、GetFileInformation需要最优先实现,有了这两个接口,就可以浏览目录了。
进入CreateFile,需要判断请求的虚拟文件是目录还是文件,如果是目录,则需要设置DokanFileInfo->IsDirectory为True,并直接返回成功。虚拟文件的打开可以根据CreationDisposition、AccessMode、ShareMode三者组合。最简单的做法是在最开始处对做判断,因为它只有五种可能性,把文件不存在,但却需要以只读打开的都排除,然后就可以放心地应用:读使用”rb+”, 写使用”wb+”。
Create中返回的文件描述符或者类似的数据可以保存DokanFileInfo->context中,这个值可以在以后的其它函数调用中访问到:比如CloseFile, CleanUp, DeleteFile, ReadFile, WriteFile等等。
CreateDirectory和实际的文件操作一致。
OpenDirectory一般直接返回成功,除非目录无访问权限,可以人为地返回-1。
CloseFile用处不大,因为在CloseFile之前,有一道CleanUp调用,已经清除了打开的文件。
CleanUp和CloseFile好像会被一前一后地调用,在CleanUp中需要做的事情是根据DokanFileInfo->context保存的值关闭虚拟文件。并且DokanFileInfo->DeleteOnClose如果为True,则需要把当前请求的文件或者目录删除。文件删除的动作实际是在Cleanup中实现的。
DeleteDirectory和DeleteFile两个接口实现中,不能够真正去删除文件,而是在文件或者目录需要删除时,返回0即可,系统会继续调用上面说的cleanup来处理删除事件。
在文件的删除时,有可能操作系统传递过来的请求文件并未被关闭,但好在同时DokanFileInfo->context也会被一同传递来,所以可以先强行关闭打开的文件,然后做删除操作。
操作系统的应用程序每次读写文件都是通过ReadFile、WriteFile接口完成的,一般情况下一次求请的大小比较小,比如65535Bytes等,但也有例外,比如使用FastCopy等多线程文件快速复制工具时,它会直接向ReadFile请求32MB的大小。
ReadFile WriteFile一般情况下都会有DokanFileInfo->context参数传进来,就像平常我们写文件读写的代码一样,总是先fopen个FILE*出来,然后再读写。 但是也有例外,比如记事本在读文件的时候,就只是给个路径+文件名。 这个时候,需要在ReadFile WriteFile临时专门为这一次请求打开文件,在退出函数时,一定要关闭它。
FlushFileBuffers是个没用的东西,可以不实现。
GetFileInformation非常重要,资源管理器每次打开目录时,会查询当前目录每个文件的信息。如果给出的信息不恰当,比如文件时间如果是个变化的值(比如图省事,将所以文件的时间设置为当前时间),这样会导致系统不断地查询,非常的恐怖。 在返回的dwFileAttributes中,需要小心地设置文件类型,文件和目录千万要区别正确。 试过FILE_ATTRIBUTE_NORMAL+FILE_ATTRIBUTE_ARCHIVE-FILE_ATTRIBUTE_ENCRYPTED以及FILE_ATTRIBUTE_DIRECTORY就基本正常工作了,FILE_ATTRIBUTE_ENCRYPTED一定要去掉,不然系统会认为你虚拟出来的盘符是加密的,往其它盘复制文件时会提示不能处理加密文件而直接失败。
FindFiles函数中,我们需要用传递进来的函数指针FillFindData将我们需要显示的目录和文件填充到系统为我们准备好的地方。只要文件的属性dwFileAttributes像样,可以构造虚拟文件和目录(比如可以将数据库里的用户和组记录读出来,表示成一层层的目录)。
MoveFile就是移动文件及改名,没什么特殊的地方。
SetEndOfFile一般情况下使用不到,但是如果有软件调用了这个API则还是有用的,比如像fastCopy,为了尽可能地加快复制速度,它每次从内存将固定大小的数据保存到硬盘,比如大小为31MB的文件,实际上它写了32MB(文件尾部的数据其实是多余的),这是用readFile WriteFile实现的。但它最后会根据原文件的真实大小来做一次setEndOfFile将其裁剪到正确的大小。如果不实现setEndOfFile,fastcopy就没用了。
SetFileAttributes和SetFileTime如果不想实现,就让它返回0,最好不要为了禁用这两个api.因为像Word之类的软件,它很在意这两个函数,在保存文件时候不厌其烦地调用,所以为了让Word在虚拟盘上工作正常,必须忽悠它,否则不能保存做过编辑的文档。
GetDiskFreeSpace是返回驱动器的容量信息的,比如虚拟盘可以做容量限制。
GetVolumeInformation返回驱动器的卷标和文件系统类型,可以随便设置,文件类型可以随便取名,比如“XX文件系统”,和NTFS/FAT32是同等地位的。
GetFileInformation 有时候传递过来的DokanFileInfo->context不是空的,所以一定要使用它来查询文件大小。 假设DokanFileInfo->context保存的是fopen打开的fd, 如果使用传递过来的文件名去GetFileAttribute或者Stat()真实文件,有可能会因为缓存的缘故查询到的文件大小不是实时的。这一点在对文件大小变化敏感的软件上特别重要,比较变态的Word,在保存的时候,它会先保存到临时文件,保存过程中,写一点数据,马上查询文件大小是否有变化是否和写的数据大小一致。如果这时GetFIleInformation马马虎虎地返回个大小,Word就罢工了,它会以为当前磁盘是不稳定的,或者容量比较用光,而拒绝保存。


20 条评论
牛比
即使写完了问题还是很多,有时候连自己怎么解决的都不知道,真郁闷。
dokan是不太稳定,目前只在0.5.2版,更新忒慢了…
Eldos的CallBack FileSystem看起来不错,可惜要钱…
Eldos看起来很牛。。。
另有一款Virturl Disk SDK (http://www.eterlogic.com/)
稳定性不错,有详细的帮助和例子,可以申请到免费的license,
不过它不像 dokan 是file system级别的驱动,它更底层,是“文件设备”级别的,
类似 filedisk,提供的回调函数只有 针对虚拟磁盘的扇区/簇 的 OnRead, OnWrite函数…
用来做 文件或内存虚拟盘、加密盘很好,但无法从文件、目录方面做控制.
最近也在从事相关方面的研究,希望与博主多交流经验: gmxyb@163.com
大家好,小弟想移植一个文件系统到Windows下,现在调研到的相对不错的方法有两即Total Commander 和 Dokan。Total Commander 好用但是收费。Dokan没用过,也不知道其稳定性怎么样?还有别的好用的免费软件吗?希望能得到答复。谢谢。avibird@163.com
to myy:
非常感谢提供的信息!
to avibird:
我也是刚接触,只用过dokan,不是太稳定,其自身发布的示例程序mirror在某些情况下都不能正常工作(比如svn checkout)。
我照你的提醒点亦步亦趋的做了, word 还是拒绝保存文件. 郁闷.
小心翼翼的按你的提示做了, word 还是拒绝保存文件.
这篇文章仅仅是个记录,也许说的是有问题的,我没仔细研究过,实在抱歉。
to free2000fly:
我还是等稳定版出来再研究它。。。
请问下,虚拟出来的磁盘,如何屏蔽回收站。每次按delete都会提示是否移入回收站,我想让他直接删除,请问如何实现。谢谢
to gingerjym:
回收站也是一个目录,你在CreateDirectory回调中处理一下,如果发现名字是RECYCLER,就拒绝建立。
我之前试过是可以的,呵呵。
我按照mirror的例子写的代码,不过word还是不能保存,你能不能详细给说一下,到底要怎么做,才可以保存word呢。谢谢啊!
@天涯
已经很久没做这方面的东西了,无法帮到您,十分抱歉。
不好意思,那你当时成功保存word了吗,只是想确认下能不能保存。呵呵,多有讨扰,敬请谅解!
嗯,当时确实是可以正常使用Word。
好的,谢谢了。
你好,请问你最近还在使用DOKAN吗?
我最近使用的时候,发现部分WORD文档无法保存,提示类似“未授权的许可”的错误,之后文档无法被打开。不过也不是所有WORD文档都不行,不知道楼主有没有遇到这个问题。
求教!