I have created a small framework that provides a unified API to multiple file systems/APIs (namely Win32, Posix, NFS). Said API is somewhat similar to Posix -- to access a file you need to "open" it providing a hint for intended purpose (r
, w
or rw
). Something like open_file("/abc/log.txt", access::rw)
.
Supporting Win32 API in this framework gives me a headache due to "declarative" nature of Win32 -- you are supposed to know upfront which operations you plan to perform on given handle and pass related dwDesiredAccess
into related (Nt)CreateFile()
call. Unfortunately framework has no idea what operation client is going to perform (i.e. change-owner, write-attributes, etc) besides generic r/w/rw
hint. And I am not willing to let Win32 concepts to leak into my framework (i.e. I don't like adding dwDesiredAccess
equivalent into my open_file()
).
Here is what I've tried:
1. MAXIMUM_ALLOWED
Idea: Open related handles with MAXIMUM_ALLOWED -- I'll get everything I could and if some right is missing, related operation (e.g. set_mime()
) will simply fail with access denied
.
Problems:
- it doesn't work with read-only files or volumes (
(Nt)CreateFile()
fails withaccess denied
) - MSDN warns that if defragmentation is in progress on FAT volume -- trying to open a directory this way will fail
- in general it seems that using
MAXIMUM_ALLOWED
is frowned upon for some reason
2. Reopen object when necessary
Idea: Represent r/w/rw
though GENERIC_READ
and GENERIC_WRITE
and for all operations that require additional access (e.g. delete()
requires DELETE
) reopen the object with required access.
Problems:
- Reopening object is not cheap
- changes made via second object can be silently overwritten, for example:
set_mtime()
reopens the file withFILE_WRITE_ATTRIBUTES|SYNCHRONIZE
- calls
NtSetInformationFile(... FileBasicInformation)
to update metadata and closes the handle - later original handle gets closed, it causes data flush and silently overwrites
ModifiedTime
previously set byset_mtime()
3. Duplicate handle instead of reopening object
Idea: same as in previous section, but instead of reopening object -- duplicate original handle (asking for new access):
HANDLE h;
HANDLE hp = GetCurrentProcess();
CHECK_WIN32( DuplicateHandle(hp, hFile, hp, &h, FILE_WRITE_ATTRIBUTES|SYNCHRONIZE, FALSE, 0) );
Problems:
- Duplicating (and closing) file handle every time I need to perform (a non-plain-read/write) operation seem to be excessive and somewhat expensive
DuplicateHandle()
documentation warns (without giving any details) that asking for additional access may fail. It has been working fine in all use cases I checked it for (typically asking for things likeDELETE
/FILE_WRITE_ATTRIBUTES
on handles opened withGENERIC_READ
), but apparently Win32 API provides no guarantees :-/
... otherwise approach seem to be working.
Bottomline:
I am looking for a way to address MAXIMUM_ALLOWED
issues. (Or suggestions for alternative approach, maybe?)