Dokan 库
Copyright(c) Hiroki Asakawa http://dokan-dev.net/en

什么是Dokan库
=====================================================================
当你想要在Windows下创建一个新的文件系统的时候,比如,改进FAT或者NTFS,你需要开发一个文件系统驱动。在内核模式开发一个设备驱动是一个非常棘手的问题。通过使用Dokan库,你可以很轻松地创建一个属于你自己的文件系统,而不需要写一个设备驱动。Dokan库非常相思雨FUSE(Linux用户下的文件系统),但是工作在Windows环境下。

许可声明
===================================================================
Dokan库包括LGPL(宽松的GPL授权声明,表示开源代码可以用到非开源私有程序,译者注),MIT许可程序(和LGPL有些类似,编者注)

- 用户模式库(dokan.dll)          LGPL
- 驱动(dokan.sys)   LGPL
- 控制程序(dokanctl.exe)  MIT
- 挂载服务(mounter.exe)  MIT
- 样本程序(mirror.c)   MIT

需要进一步的细节,请查看许可文件。
LGPL license.lgpl.txt
GPL  license.gpl.txt
MIT  license.mit.txt

你可以通过以下网址获取源码 http://dokan-dev.net/en/download

环境
====================================================================
Dokan库运行在 Windowx XP,2003,Vista,2008,7 x86 和 Windows 2003,Vista,2008,7 x64.

它是怎么工作的
====================================================================
Dokan库包括一个用户态DLL(dokan.dll)和一个内核模式文件系统驱动(dokan.sys)。一旦Dokan文件系统驱动安装好之后,你就可以创建和Windows下可以看见的普通的文件系统一样的文件系统了。这个被我们称之为文件系统级的应用程序可以利用Dokan库来创建文件系统。
用户态程序的文件操作请求(比如创建文件,读取文件,写文件。。。)将会被发送到Windows I/O子系统(运行在内核态),紧接着送到Dokan文件系统驱动(dokan.sys)。
通过使用Dokan用户态库(dokan.dll)提供的函数,文件系统程序能够注册回调函数到文件系统驱动中。
文件系统驱动将会调用这些回调例程(routines),为了能够响应它收到的请求。回调例程的结果会被送回到用户态程序。
比如,当Windows浏览器请求打开一个目录的时候,OpenDirectory请求会被送到Dokan文件系统驱动并且驱动会调用文件系统程序提供的OpenDirectory回调函数。这个例程的结果将被送到Windows浏览器,作为OpenDirectory请求的响应。因此,Dokan文件系统驱动扮演者一个基于用户程序和文件系统程序之间的一个代理角色。
这种处理方式的优点就是它允许开发者在用户态下开发文件系统,这样安全并且容易调试。

库的部件组成和安装
=======================================================================
当我们运行安装程序是,它会安装Dokan文件系统驱动(dokan.sys),注册Dokan挂载服务(mounter.exe)和一系列库。安装的文件详细清单如下:

系统文件夹/dokan.dll                                Dokan用户态库
系统文件夹/drivers/dokan.sys                   Dokan挂载服务
ProgramFiles文件夹/Dokan/DokanLibrary/mounter.exe           Dokan挂载服务
ProgramFiles文件夹/Dokan/DokanLibrary/dokanctl.exe           Dokan控制程序
ProgramFiles文件夹/Dokan/DokanLibrary/dokan.lib                 Dokan导入库
ProgramFiles文件夹\Dokan\DokanLibrary\dokan.h                   Dokan库头文件
ProgramFiles文件夹\Dokan\DokanLibrary\readme.txt              这个文件(你正在读的,译者注)

你可以使用控制面板的 Add/Remove 程序来卸载Dokan。卸载后,需要重启你的电脑。

怎样创建你的文件系统
======================================================================
创建文件系统,一个应用程序需要在DOKAN_OPERATIONS结构实现函数(在dokan.h中声明)。函数一旦实现,你就可以把DOKAN_OPERRATIONS作为参数调用DokanMain函数。
为了挂载文件系统,在DOKAN_OPERATIONS中的函数语义和WindowsAPI语义相似并且有相同的名字。这些函数的参数和相应的WindowsAPI相同。这些函数被很多的线程调用,所以他们需要保证线程安全,否则很多问题可能产生。

这些函数典型的以下面的顺序调用:
1、创建文件CreatFile(打开文件)
2、其他函数
3、清除Cleanup
4、关闭文件CloseFile

文件访问操作(展现目录,读取文件属性。。。)之前,经常需要调用文件创建函数(打开目录,创建文件。。。)。在另一方面,当CloseFile Windows API关闭文件的时候,Dokan文件系统驱动会调用清除函数Cleanup。当操作成功结束,每一个函数应该返回0,否则返回一个负数表示错误码。错误码和Windows系统错误码相反。比如当CreatFile不能打开文件,你应该返回-2(-1*ERROR_FILE_NOT_FOUND)。

每一个函数的最后一个参数是一个DOKAN_FILE_INFO结构:
   typedef struct _DOKAN_FILE_INFO {

ULONG64 Context;
       ULONG64 DokanContext;
       ULONG   ProcessId;
       BOOL    IsDirectory;

} DOKAN_FILE_INFO, *PDOKAN_FILE_INFO;

每个用户态的文件句柄(file handle)都和DOKAN_FILE_INFO结构相关。因此,如果相同的文件句柄已经使用,结构内容就不会改变。当CreatFile系统调用打开文件时,DOKAN_FILE_INFO结构就会创建;当CloseFile系统调用关闭文件时,这个结构就会销毁。
这个结构中每一个成员的意义如下:
Context:一个指定的值,由文件系统应用程序指定。文件系统程序可以自由的使用这个变量来存储在文件访问阶段的固定值(从创建文件到关闭文件)比如文件句柄等等。
DokanContext:保留,Dokan库使用。
ProcessId:打开文件进程的进程ID。
IsDirectory:判断打开的文件是否是一个目录。

其他的如下
   int (*CreateFile) (
       LPCWSTR,      // FileName,文件名
       DWORD,        // DesiredAccess,需要访问
       DWORD,        // ShareMode,共享模式
       DWORD,        // CreationDisposition,创建意向
       DWORD,        // FlagsAndAttributes,标识和属性
       PDOKAN_FILE_INFO);

int (*OpenDirectory) (
       LPCWSTR,          // FileName
       PDOKAN_FILE_INFO);

int (*CreateDirectory) (
       LPCWSTR,          // FileName
       PDOKAN_FILE_INFO);

当变量IsDirectory设置为TRUE,操作的文件是目录。当IsDirectory时FALSE时,如果当前的操作是对目录操作,则写文件系统程序的程序员需要把它设置为TRUE。如果IsDirectory的值是FALSE,但是当前操作不是对目录操作,则程序员不需要更变该值。需要注意的是,当访问目录时,把IsDirectory的值设置为TRUE对于Dokan库而言是非常重要的。如果它没有被准确的设定,那么Dokan库将不知道这个操作是作用于目录,会带来许多问题。如果CreationDisposition 设定为 CREATE_ALWAYS 或者OPEN_ALWAYS 并且当前文件已经存在,那么CreatFile函数需要返回ERROR_ALEADY_EXISTS(183)

int (*Cleanup) (
       LPCWSTR,      // FileName
       PDOKAN_FILE_INFO);

int (*CloseFile) (
       LPCWSTR,      // FileName
       PDOKAN_FILE_INFO);

当Windows API提供的CloseHandle函数一旦执行,Cleanup函数将被调用。当函数CreateFile被调用的时候,如果文件系统程序在Context变量中存放了文件句柄,这个将在Cleanup函数中关闭,而不是CloseFile函数。
如果用户态程序调用CloseHandle,并且马上打开相同的文件,那么文件系统程序CloseFile函数在CreatFile API被调用之前可能不会被调用。这有可能引发共享问题。

值得注意的是:当用户使用内存映射文件时,WriteFile或者ReadFile函数可能Cleanup之后会被调用,这是为了完成I/O操作。文件系统应用也应该在这种情况下正常运行。

int (*FindFiles) (
       LPCWSTR,           // PathName,路径名
       PFillFindData,     //调用此函数时, 使用PWIN32_FIND_DATAW作为参数
       PDOKAN_FILE_INFO); //  (see PFillFindData definition)

// 你应该实现 FindFiles 或者 FindFilesWithPattern
   int (*FindFilesWithPattern) (
       LPCWSTR,           // PathName,路径名
       LPCWSTR,           // SearchPattern,查询方式
       PFillFindData,     // call this function with PWIN32_FIND_DATAW
       PDOKAN_FILE_INFO);

调用FindFiles或者FindFilesWithPattern函数是为了相应目录列表请求。你应该实现FindFiles或者FindFilesWithPattern(其中一个,译者注)。对于每一个目录入口(entry),文件系统程序都应该调用FillFindData函数(作为一个函数参数供 FindFiles, FindFilesWithPattern调用),FillFindData会使用包含目录信息的WIN32_FIND_DATAW结构:
FillFindData( &win32FindDataw, DokanFileInfo )。
处理通配符模式(wildcard patterns)是文件系统的责任,因为Windows命令终端(shells)不能够很好地处理模式匹配。当文件系统程序提供FindFiles,通配符模式将会通过Dokan库来自动的处理。你可以通过实现FindFilesWithPattern函数来控制通配符匹配的过程。Dokan库(dokan.dll)提供的DokanIsNameInExpression函数接口可以用来处理通配符匹配。

挂载
====================================================================
#define DOKAN_OPTION_DEBUG       1 // 输出调试信息
   #define DOKAN_OPTION_STDERR      2 // 输出调试信息到标准错误输出
   #define DOKAN_OPTION_ALT_STREAM  4 // use alternate stream
   #define DOKAN_OPTION_KEEP_ALIVE  8 // 使用自动卸载
   #define DOKAN_OPTION_NETWORK    16 // 使用网络驱动
                               //你需要安装Dokan网络提供器(provider)
   #define DOKAN_OPTION_REMOVABLE  32 // 使用可移除驱动

typedef struct _DOKAN_OPTIONS {
       USHORT  Version;  // 支持的Dokan版本, 比如. "530" (Dokan ver 0.5.3)
       ULONG   ThreadCount;  // 使用的线程数
       ULONG   Options;  // combination of DOKAN_OPTIONS_*
       ULONG64 GlobalContext;  // FileSystem 可以使用这个
       LPCWSTR MountPoint;  // 挂载点 "M:\" (驱动字符) 或者
                            // "C:\mount\dokan" (NTFS中的路径名)
   } DOKAN_OPTIONS, *PDOKAN_OPTIONS;

int DOKANAPI DokanMain(
       PDOKAN_OPTIONS    DokanOptions,
       PDOKAN_OPERATIONS DokanOperations);

如上所述,文件系统可以通过DokanMain函数挂载。函数一直阻塞(block)直到文件系统卸载。再把这些参数传递给DokanMain 函数之前,文件系统程序应该为Dokan运行库填写满DokanOptions中的选项,为文件系统操作填写满DokanOperations中的函数指针(比如CreateFile, ReadFile, CloseHandle, ...)。DokanOperations结构中的函数需要保证线程安全,因为他们都被执行不同上下文(contexts)的多线程调用(不是调用DokanMain的线程)。

Dokan选项如下:
 版本:Dokan库的版本号。你需要一个支持的版本。Dokan库可能因为版本号的不同改变一些行为(behavior)。比如ie.530(Dokan 0.5.3)
 线程数:Dokan库内部的线程数。如果这个值设定为0,那么将使用默认的值。当我们调试文件系统的时候,文件系统程序应该设定为1来避免多线程的并发冲突。
 选项:DOKAN_OPTION_*常量的结合。
 全局域:你的文件系统可以使用这个变量来存放一个挂载特定的结构。
 挂载点:一个挂载点挂载点 "M:\" (驱动字符) 或者 "C:\mount\dokan" (需要是空的)NTFS中的路径名。

如果挂载成功,那么返回值是DOKAN_SUCCESS,否则返回值如下。
 #define DOKAN_SUCCESS                0
   #define DOKAN_ERROR                 -1 /* 普通错误 */
   #define DOKAN_DRIVE_LETTER_ERROR    -2 /* 坏的驱动字符 */
   #define DOKAN_DRIVER_INSTALL_ERROR  -3 /* 不能安装驱动 */
   #define DOKAN_START_ERROR           -4 /* 驱动出了某个问题 */
   #define DOKAN_MOUNT_ERROR           -5 /* 不能分配驱动字符或者挂载点 */
   #define DOKAN_MOUNT_POINT_ERROR     -6 /* 挂载点无效 */

卸载
=======================================================================
文件系统可以通过调用DokanUnmount函数来卸载。大部分情况下,程序或者shell使用文件系统挂起,卸载操作来解决问题。因为当文件系统卸载的时候,我们可以把系统恢复到原来的状态。
用户可能使用DokanCtl来卸载文件系统:
 > dokanctl.exe /u DriveLetter

杂项:
======================================================================
如果在Dokan库或者使用库的文件系统程序中有bug,那么你的Windows系统将会蓝屏。因此,我们强烈建议你使用虚拟机来开发文件系统应用程序。

Dokan官方说明文档的更多相关文章

  1. SWFUpload 2.5.0版 官方说明文档 中文翻译版

    原文地址:http://www.cnblogs.com/youring2/archive/2012/07/13/2590010.html#setFileUploadLimit SWFUpload v2 ...

  2. SpringMVC的API和Spring的官方说明文档的地址。

    SpringMVC的API和Spring的官方说明文档的地址. 1.SpringMVC的API的URL: http://docs.spring.io/spring/docs/current/javad ...

  3. 【转】SWFUpload 官方说明文档(2.5.0版)

    原文出自:http://www.runoob.com/w3cnote/swfupload-document.html SWFUpload使用指南请查阅:http://www.w3cschool.cc/ ...

  4. locust===官方说明文档,关于tasks

    安装: >>> pip  install locust locust在官方simple_code中如下: from locust import HttpLocust, TaskSet ...

  5. ICE中间件说明文档

    ICE中间件说明文档 1       ICE中间件简介 2       平台核心功能 2.1        接口描述语言(Slice) 2.2        ICE运行时 2.2.1         ...

  6. BasicExcel说明文档

    BasicExcel说明文档 BasicExcel原始链接:http://www.codeproject.com/Articles/13852/BasicExcel-A-Class-to-Read-a ...

  7. 为ASP.NET WEB API生成人性化说明文档

    一.为什么要生成说明文档 我们大家都知道,自己写的API要供他人调用,就需要用文字的方式将调用方法和注意事项等写成一个文档以更好的展示我们设计时的想法和思路,便于调用者更加高效的使用我们的API. 当 ...

  8. 【腾讯GAD暑期训练营游戏程序班】游戏场景管理作业说明文档

    场景管理作业说明文档                              用了八叉树的算法,测出三层时最快,区域范围内物体数量为21块,控制台打印出的结果如图所示: 场景物体:游戏中,所有具有空 ...

  9. 浏览器内核控制Meta标签说明文档

    浏览器内核控制Meta标签说明文档 原文链接 背景介绍 由于众所周知的情况,国内的主流浏览器都是双核浏览器:基于Webkit内核用于常用网站的高速浏览.基于IE的内核用于兼容网银.旧版网站.以360的 ...

随机推荐

  1. Linux 编译安装 源代码

    编译安装 源代码包的安装一般为下载软件源代码,然后编译安装. 常见的C程序软件的安装步骤是 configure, make, make install三部曲,大致是下面这样操作: 首先得安装gcc.m ...

  2. 借助OpenOffice实现office转pdf(Java)的.exe小程序

    原料:OpenOffice4.1.2(之所以选OpenOffice是因为可以跨平台,下载后直接安装),jodconverter-core-3.0-beta-4-dist.zip(可以搜博客园),Exe ...

  3. 反编译与调试APK

    0×01前言 这年头,apk全都是加密啊,加壳啊,反调试啊,小伙伴们表示已经不能愉快的玩耍了.静态分析越来越不靠谱了,apktool.ApkIDE.jd GUI.dex2jar等已经无法满足大家的需求 ...

  4. USB硬盘 raw之后,DiskGenius 恢复

    最近,为了在E560上安装LINUX(先是gentoo,后是rhel7,最后是 centos7),用UltralISO 把一块移动硬盘给写成RAW格式了.现在又想把移动硬盘给恢复回去.采用一些方法,效 ...

  5. hdu 5207 BestCoder Round #38 ($) Greatest Greatest Common Divisor

    #include<stdio.h> #include<string.h> #include<math.h> ]; ]; int main() { int sb; s ...

  6. 更改系统相机UIImagePickerController导航栏的cancle为自定义按钮

    有时候需要对系统相册里面的取消按钮进行自定义,并获取点击事件做一些操作,那么你可以这样做. 第一:实现navigationController代理 - (void)navigationControll ...

  7. 总结:liunx常见命令集合

    没有系统学习过liunx,把工作中遇到的liunx命令集合信息如下: 1.nc传送文件 之前总是用rsync, 今天遇到了一个从阿里云服务器传送文件到我们公司的内网服务器,这就不能传了,又想用一致的文 ...

  8. hdu 3507 Print Article(斜率优化DP)

    题目链接:hdu 3507 Print Article 题意: 每个字有一个值,现在让你分成k段打印,每段打印需要消耗的值用那个公式计算,现在让你求最小值 题解: 设dp[i]表示前i个字符需要消耗的 ...

  9. stm32

    GPIO NVIC TIME USART ONE WIRE IIC SPI PWM ADC LCD XPT UCOSiii移植 定时器 蓝牙 陀螺仪

  10. 特性(Attributes)

    用以将元数据或声明信息与代码(程序集.类型.方法.属性等)相关联.特性与程序实体相关联后,即可在运行时用反射技术查询特性. 例如,在一个方法前标注[Obsolete]特性,则调用该方法时VS则会提示该 ...