2
votes

I am trying to get the correct error code out of errno when opening a directory as a file, both with fopen as well as with ifstream.open(). I expect EISDIR, I get EACCES.

I am compiling (and executing) with the MSVC 12.0 toolchain on Windows 7 x64.

I have been reading in article (https://gehrcke.de/2011/06/reading-files-in-c-using-ifstream-dealing-correctly-with-badbit-failbit-eofbit-and-perror/) where the author got the output "stream failbit (or badbit). error state: Is a directory".

I compiled the authors files with GCC 4.6 (or above, not sure atm) and on passing a directory as argument I get EACCES as well.

I know there is no easy way of telling whether a disk object is a directory on windows, so not getting EISDIR is not too surprising.

Is there anything that can be done about it (getting EISDIR on windows, that is)? Are there other errno's that behave in a similar (unexpected) way?

2
Provide a minimal reproducible example as usual please. Also you can't open directoies as a file.πάντα ῥεῖ
I think you're out of luck - I could find neither the EINVAL nor is_a_directory symbols referenced in the Microsoft C libraries (I've checked the VS 12.0 one and the Universal CRT as used by VS 14.0) anywhere but the definitions themselves, i.e. they're there but they are not used. Alternatives (MinGW etc.) link to the msvcrt.dll and you've already confirmed that it doesn't behave the way you want either.cynic
I think it is not a good choice to use errno for checking a device object is a file or a directory. It's unstable since this method depends on platform and compiler, and C++ standard doesn't state the behavior of processing ifstream error.very hit
"no easy way of telling whether a disk object is a directory on windows" - There's the rather straightforward GetFileAttributes( object ) & FILE_ATTRIBUTE_DIRECTORY. And MSVC has _stat() or _fstat, see st_mode & _S_IFDIR.MSalters
@πάνταῥεῖ Please use the source code from the link of the OP. If you get different results I'd be very interested to know.alexander remus

2 Answers

3
votes

Microsoft's C runtime libraries define, but do not use the EISDIR symbol. So you won't get that error code from them. To get the answer to your other question, you need to look in the C library source code. It ships with Visual Studio and, in case of Visual Studio 2015 and later, Windows SDK.

In Visual Studio 2015 (14.0), which uses the Universal CRT, the file you want is called errno.cpp and it's included in the Windows SDK, I have it in c:\Program Files (x86)\Windows Kits\10\Source\10.0.10586.0\ucrt\misc\errno.cpp.

In Visual Studio 2013 (12.0), the file you want is called dosmap.c and it's included in the VC subdirectory of the Visual Studio installation directory, I have it in C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\crt\src\dosmap.c.

Both of those files contain an error table mapping OS error codes to C library error codes. You can use it to confirm whether a particular mapping conforms to your expectations.

-1
votes

The fopen function isn't a part of the Windows API; it comes from the run-time support library from some given C or C++ development environment.

This EISDIR error works in a C application built for Cygwin and shipped with Cygnal:

c:\users\kaz>txr
This is the TXR Lisp interactive listener of TXR 148.
Use the :quit command or type Ctrl-D on empty line to exit.
1> (open-file ".")
#<file-stream . 6fffff00738>
2> (get-string *1)
** error reading #<file-stream . 6fffff00738>: 21/"Is a directory"
** during evaluation at expr-2:1 of form (get-string *1)
3>

The open-file function in this language uses fopen, and get-string ultimately relies on C stdio.h functions. The fopen succeeds, but the subsequent input attempt receives the EISDIR error. (Mapped to the same traditional 21 code as on Linux and other platforms). That is turned into an exception. The "Is a directory" string is from strerror.

You just need a more richly featured C run-time library with better POSIX support than the paltry offering provided with Microsoft Visual Studio.