Reputation: 79665
I was writing a custom write-locking class when I noticed it. My class has no reason to actually write to the file, only to deny others the ability to write, so naturally I tried this:
lockHandle = CreateFileW(fileName, 0, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
As you can see, I set dwDesiredAccess=0
and dwShareMode=FILE_SHARE_READ
. But other processes can still write to the file. It took me some time to realize I need to set dwDesiredAccess=GENERIC_WRITE
, or else my dwShareMode
has no effect.
It seems I can deny others permissions only if I grant them to myself as well. Is that correct? If so, why is that?
Upvotes: 2
Views: 276
Reputation: 36348
It isn't true that you need to request the access you are attempting to "not share"; for example, GENERIC_READ and FILE_SHARE_READ will successfully prevent write access - that's a very common case, and an essential one. However, it appears that the access rights you have requested do need to be "significant enough" for the sharing mode to count.
It turns out that all of these access rights are not considered significant: READ_CONTROL, WRITE_DAC, WRITE_OWNER, FILE_READ_ATTRIBUTES, FILE_READ_EA, FILE_WRITE_ATTRIBUTES, and FILE_WRITE_EA.
All of these access rights are considered significant: DELETE, FILE_EXECUTE, FILE_APPEND_DATA, FILE_READ_DATA, and FILE_WRITE_DATA.
In order for the sharing mode to count, you need to have requested at least one access right from the "significant" list. This means that you could, for example, choose FILE_EXECUTE, which has no practical impact on the handle; if you accidentally attempted to read from the file, the call would fail. However, since this behaviour does not appear to be documented, I do not recommend that you depend upon it. Instead, in your scenario, open the file for GENERIC_READ and FILE_SHARE_READ, as this can be depended upon to work.
If you absolutely need a handle to the file that does not have GENERIC_READ access (I can't think of any good reason for this, but there may be edge cases) you can use DuplicateHandle to create a new handle with no access rights. This even keeps working after the original handle is closed, but again, that's undocumented, so I would recommend against relying upon it.
Notes:
Tested on Windows 7 x64 SP1, on NTFS.
I only tested a couple of access rights that don't actually apply to files, SYNCHRONIZE and FILE_DELETE_CHILD; neither were considered significant.
At a guess, the difference between the two lists is that the "significant" rights all apply to the file itself, whereas the "insignificant" rights apply to metadata or are not applicable at all.
This might be because the "insignificant" rights don't require NTFS to open the underlying file object, which is what the sharing mode actually applies to. That's pure speculation, mind you.
Upvotes: 1