文件的共享模式和访问权限
有用户反馈了这样一个问题:当Word或者Excel打开了一个文件时,无法用我们的程序打开该文件,而用其它程序却能够正常打开。经检查,这是由于在打开文件时CreateFile
函数失败了,错误码是32,“另一个程序正在使用此文件,进程无法访问”。
我检查了一遍代码,“看上去”似乎一切正常。但是为什么其它程序可以正常打开,就只有我们的程序不行呢?为了对比两者在打开文件上的差异,我使用ProcessMonitor来观察分别用Notepad++和我们程序打开同一个文件的过程。
经过对比,可以发现两者在执行CreateFile操作时,共享模式(ShareMode)的值明显不一样,如下所示:
左图是Notepad++的CreateFile操作,ShareMode包含了Read和Write,操作结果为SUCCESS;右图是我们程序的CreateFile操作,ShareMode只有Read,操作结果为SHARING_VIOLATION。显然,问题出在调用CreateFile
函数时传入的dwShareMode
参数上,我们对该参数只传入了FILE_SHARE_READ
。尝试加上FILE_SHARE_WRITE
之后,问题解决了。
我又仔细阅读了一遍文档,发现一直以来我对共享模式的理解都不够全面(通过与其他人的交流,可以肯定不止我一个人是这样)。
共享模式实际上是用来与文件的访问权限进行校验的。假设进程A要打开一个文件,而该文件已经被进程B打开了,那么系统会进行以下校验:
- 进程A传入的共享模式与进程B对该文件的访问权限(即打开文件时传入的
dwDesiredAccess
参数)是否一致; - 进程A传入的访问权限与进程B的共享模式是否一致。
共享模式与访问权限的一致性判断方式:
- 如果共享模式包含读取,那么访问权限也必须包含读取;
- 如果共享模式包含写入,那么访问权限也必须包含写入。
也就是说,系统会对双方的共享模式和访问权限进行交叉校验,只有两个校验都通过了,进程A才能打开文件,否则就会出现共享冲突错误。
所以,现在已不难理解为什么之前我们的程序打不开被Word和Excel打开的文件。Word和Excel必然对文件有写入权限,而我们的程序在打开文件时,共享模式只设置了读取,这意味着“我希望其它人只能读取该文件”,显然这是不可能的。
注意,为了便于理解,上面用了进程做例子,但实际上共享模式和访问权限都属于文件句柄的一部分,权限校验是针对句柄的。在一个进程中多次打开同一个文件,也会在文件句柄之间进行这些校验。