Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I determine if a file was opened for append on Windows?

In UNIX if I open a file in append mode like

fd = open("filename", O_APPEND);

then given such a file descriptor one can easily find out what flags it was opened with using fcntl:

fcntl(fd, F_GETFL) & O_APPEND

I know that fcntl is not available on Windows, but I wonder if there is some way to determine this. Windows does clearly support an append mode for example when creating a file with CreateFile and passing in the FILE_APPEND_DATA flag.

But if all I have is a handle to an already opened file I cannot for the life of me find a way to determine what access rights were requested when the file was first opened. This question provides a basic recipe for checking the access rights to a specific file, but that doesn't seem to help. I tried it and even if I open a file with read-only mode it still tells me I have the FILE_APPEND_DATA access to the file, if I were to request it. In other words, this method only tells me what access rights the process has to a particular file (as inherited from the user who started the process). It says nothing about what exact access was requested when the file was opened.

This has nothing to do with how Windows keeps track of whether the file should only be appended to. And it's that latter question that I can't find an answer to anywhere. The closest thing I've found is GetFileInformationByHandleEx but after combing through the docs there's not one file attribute that can be returned through that API that suggests "append mode".

Update: To clarify my question a bit better, this question really just applies to the MS VC runtime library--files opened with the POSIX-like functions _open and written to with fwrite and the like. It appears that the native win32 file handles have no notion of "append mode".

like image 673
Iguananaut Avatar asked Dec 07 '25 03:12

Iguananaut


2 Answers

For a file that Windows sees as being in "append" mode, this will work:

Use the semi-documented NtQueryInformationFile system call (exported from ntdll.dll) to query for FILE_ACCESS_INFORMATION. That should tell you the access mask that the file was opened with, which should contain FILE_APPEND_DATA.

For a file that the C runtime opens in "append" mode, however, this won't work, because Windows doesn't actually open it in append mode. The way to do this is to somehow translate the file descriptor into the file object, and check the flag there -- but there's no documented way to do this.

You can look at the Visual C++ CRT source code to figure out how to do it... there might be some way to access the array that the descriptor indexes in, but I'm not sure how.
The code in the CRT seems to be _pioinfo(fd)->osfile |= FAPPEND so hopefully that helps.

like image 73
user541686 Avatar answered Dec 09 '25 13:12

user541686


FileMode.Append is a figment of the .NET Framework team's imagination. It is not a mode that Windows supports. They added it to make the wrapper for the native winapi CreateFile() function (FileStream) easier to use. FileMode is the enum wrapper for its dwCreationDisposition argument. Which does not have a CREATE_APPEND option.

The most relevant code from the FileStream.Init() method is:

   bool seekToEnd = (mode==FileMode.Append);
   // Must use a valid Win32 constant here...
   if (mode == FileMode.Append)
       mode = FileMode.OpenOrCreate;

In other words, FileMode.Append does not match a valid CreateFile() option and has to be mapped. The file will be opened if exists, created if it doesn't. And it takes care of an extra operation, after opening the file, it will seek to the end of the file. Which you'd of course expect when you append to an existing file. Some additional error checking exists, it also makes sure you opened the file for writing.

So that rather shoots a hole in your quest to detect this back. The GetFileInformationByHandleEx() winapi function is available to recover the file state. The documented function for Mehrdad's undocumented native api call. You can get the dwCreationDisposition argument back from FileDispositionInfo to check that it was OpenOrCreate. That is however not unique, it could have also started from the file being opened with FileMode.OpenOrCreate from the client code. Rare, but possible.

What you've lost is the memory of it seeking to the end of the file. You could use the FileStream.Position property but that of course will be affected by any writes in the mean time. If this really matters then you do have to preserve the FileMode value that was used.

like image 34
Hans Passant Avatar answered Dec 09 '25 14:12

Hans Passant



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!