Boost logo

Boost :

From: Rob Stewart (stewart_at_[hidden])
Date: 2005-04-01 10:07:18


From: Beman Dawes <bdawes_at_[hidden]>
> At 01:06 PM 3/31/2005, Rob Stewart wrote:
> >From: Beman Dawes <bdawes_at_[hidden]>
> >>
> >> But with the following errors I can't see any way to know if the path
> >> actually exists or not:
> >>
> >> [EACCES] Search permission is denied for a component of the path
> >prefix.
> >
> >Peter's query is key here: what does it mean for exist() to
> >return true or false? You could say that returning false here is
> >appropriate because, as far as the current user is concerned, the
> >file doesn't exist.
>
> I also think that Peter's query is key. To try to answer that, I looked at
> about 25 uses of exists() in .cpp files in the boost/tools hierarchy.
>
> Perhaps a third of the uses would still make total sense if [EACCES] was
> treated as false. Perhaps another third of the uses (like using exists() to

Good.

> see if create_directories() needs to be called) might technically be harmed
> returning false, but no harm would actually be done because some other call
> (create_directories() in the above case) would soon fail.

Right.

> But perhaps a third of uses were simply to tell if some file system entry
> was present as part of determining control flow within the code. There
> wasn't an immediate use of the path after the exists() test, so it is very
> hard to tell what the effect of returning false would be. Even when you can
> see the immediate affect, it isn't always clear what is best. For example,
> link_check.cpp uses exist() tell if an HTML link is broken. Seems to me
> [EACCES] is an error condition - the link_check is being run with the wrong
> permissions or something.

I can tell you that bash, and other *nix shells which follow
test(1)'s behavior, doesn't fail a script when you test with
"-e pathname." It simply succeeds or fails. When you need to
know more, you can use stat(1). I've never found that behavior
problematic in any script I've written (and that's a lot).

Based upon that experience, I think exists() should not throw
exceptions. There are other tools to determine why. Thus, when
it matters to the logic of the program why a file doesn't exist,
you won't rely on the simply answer of exists().

> >> [EIO] An error occurred while reading from the file system.
> >
> >Is this a permanent failure?
>
> There is no way to tell. POSIX doesn't give any indication. So it seems to
> me it should be treated as an error causing exception.

I think it should return false.

> > If so, it is reasonable to return
> >false: at this time, the file doesn't exist, even if the
> >intention is that it does. If it is a temporary failure, then a
> >retry might succeed in finding the real answer. In that case, it
> >is appropriate that the caller know that a retry is in order.
> >
> >> [ELOOP] A loop exists in symbolic links encountered during
> resolution
> >> of the path argument.
> >
> >While that is an error condition, it doesn't prevent declaring
> >that the file, as given by the supplied pathname, doesn't exist.
>
> While it doesn't prevent us declaring it doesn't exist, something is
> clearly rotten so I'm much more comfortable throwing an exception (or doing
> something else that doesn't gloss over the fact that a possilbe error has
> occurred.)

The question asked of exists() is whether the supplied pathname
exists. It doesn't, in this case. The logic error can be
determined through other means. For example, when I write a
script and -e doesn't find a file I'm expecting, the script
fails. When I investigate why it failed, I track down the file
it was looking for and figure out why the pathname is bad.

> >> [ENAMETOOLONG] The length of the path argument exceeds {PATH_MAX} or
> >> a pathname component is longer than {NAME_MAX}.
> >
> >The pathname clearly doesn't exist because it is invalid.
>
> What if the pathname was too long because of a long prefix of
> "foo/../foo/../foo/../foo" eventually ending in a valid "/real-file"?

The *pathname* does not exist. You can't be prescient and figure
out what the caller really meant.

> >Whether the file the caller is interested in actually exists is a
> >separate question. You can only answer whether the supplied
> >pathname refers to an existing file.

Like I said.

> >> If you agree with that analysis, then it looks like exists() should be
> >> changed to throw on those last four errors. is_accessible() would have
> a
> >
> >I disagree. All the caller wants to know is whether the supplied
> >pathname refers to an existing file.
>
> But if it isn't possible to reliably answer that query, shouldn't it be an
> error?

I think it is reliable and reasonable to return false in those
error conditions.

> OTOH, if there is a way (perhaps a status() function returning a bitmap as
> you suggested in an earlier post) to detect these probably rare error
> cases, then it would seem more acceptable for exists() to treat these
> errors as false. An application which had more stringent requirements can
> avoid exists() and use an explicit test of status() results.

Bingo!

-- 
Rob Stewart                           stewart_at_[hidden]
Software Engineer                     http://www.sig.com
Susquehanna International Group, LLP  using std::disclaimer;

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk