9

In a C++ program, using std::ifstream, I'm attempting to open a user-specified file -- so far so good. However, I accidentally entered a filename that's actually a directory, and I was quite surprised to see that attempting to open() that directory didn't generate any errors.

Here's a minimal example:

std::ifstream f;
f.open("..");
if(!f.is_open() || !f.good() || f.bad() || f.fail()) {
    std::cout << "error bit set on open" << std::endl;
    return 1;
}

No sign of error here. If I go on and attempt to getline(), getline() sets an error bit all right.

std::string str;
getline(f, str);

if(f.eof()) std::cout << "getline set eofbit" << std::endl;
else if(f.bad()) std::cout << "getline set badbit" << std::endl;
else if(f.fail()) std::cout << "getline set failbit" << std::endl;

This outputs "getline set badbit", which is reasonable. Using the >> operator throws an underflow exception, which is also okay.

Now, my question is, how could I detect that the user entered a directory name instead of a proper filename? Is there any way to do that? Getting and ungetting bytes from the stream seem tedious and error-prone.

Also, why is this so? I realize that it's all just the same data from the point of view of the program, but I'd assume the OS would also send some "hey, this is a directory" kind of message.

SáT
  • 3,633
  • 2
  • 33
  • 51

1 Answers1

4

You don't say what your system is, so it's hard to say, but generally, filebuf::open will only return an error if your system level open fails. And I've worked on Unix systems where you could open() a directory; I've even worked on some where you could read it after the open (at least if it was a locally mounted filesystem).

As to what to do about it: about all I can think of is to try to get the first character, then put it back. But this fails if the file is empty, so it's not really a solution either. At the system level (and from a QoI point of view, I'd expect filebuf::open to do this if the system did allow opening a directory), you can use a system level call (stat in Unix) to determine whether the file is a directory or not. (There's a race condition, of course: between the moment you detect that it's a normal file, and the moment you do the open, another process could delete the file and create a directory. It's probably not a frequent occurance, however.)

James Kanze
  • 150,581
  • 18
  • 184
  • 329
  • Oh, so it IS platform-specific, after all, I could have guessed. Thanks for the explanation. Yes, this is on Linux (Ubuntu, same happens on Debian, unsurprisingly). Since I'm just trying to ensure that it's a valid and readable filestream from which I can read stuff, getting and ungetting is reasonable, though I hoped for a cleaner solution. Dependencies and system calls seem like overkill. I mean, I can live with the error, but, um, it just looked strange. – SáT Mar 06 '12 at 20:30
  • 1
    @SáT: I would also guess it is specific to the underlying file system used on the hardware (note: some OS allow you to choose the filesystem used on disks). – Martin York Mar 06 '12 at 21:02
  • 1
    @LokiAstari I think so. IIRC (it has been some time since I tried it), under Solaris, `open` on a directory worked on locally mounted disks (UFS), but not if the filesystem was NFS. – James Kanze Mar 07 '12 at 08:24
  • Suggest to reedit: "I've even worked on somewhere you could read from it(i.e. the opened folder) after the open (at least if it was a locally mounted filesystem)." – John Oct 08 '21 at 13:21