Boost logo

Boost :

From: Jeff Garland (jeff_at_[hidden])
Date: 2005-03-20 21:28:40


On Sun, 20 Mar 2005 20:29:13 -0500, Beman Dawes wrote
> At 09:15 PM 3/19/2005, Jeff Garland wrote:
> Here is the rationale given in the documentation at
> http://www.boost.org/libs/filesystem/doc/operations.htm#symbolic_link_exists

I guess I really should read the documentation...it's bad when you get caught
not reading the manual twice in one day ;-)
 
> Rationale: The function does not throw if ph is not present, and
> is accordingly named symbolic_link_exists rather than is_symbolic_link.
> Non-throwing behavior permits testing for all four possible conditions:
>
> * ph not present: !exists(ph) && !symbolic_link_exists(ph)
> * ph present and is not a symbolic link: exists(ph)
> && !symbolic_link_exists(ph)
> * ph present and is a symbolic link to a non-existent file or
> directory: !exists(ph) && symbolic_link_exists(ph)
> * ph present and is a symbolic link to an existing file or
> directory: exists(ph) && symbolic_link_exists(ph)
>
> In other words, the current naming and semantics (not throwing), is
> both logically consistent and allows all possible conditions to be
> tested for.

Ok, I see. It's a bit non-intuitive that exists returns false when the
symbolic link is there, but it does work as documented.

> I guess you could make an argument that the name is_symbolic_link()
> with non-throwing semantics would be more satisfying in some sense
> even if less logically consistent.

I think it would be a better name. It basically tells you if the file is a
symbolic link -- it doesn't tell you that the target of the link exists which
is what I thought from the name.

> The original rationale for not supplying is_file() was (1) concern
> over devices, which are treated as files in some operating systems,
> but not in other operating systems, and (2) minimalism, since it
> was trivial to code !directory() directly.
>
> That was before the issue of symbolic links came up, so it might be
> worth revisiting.

Yep...

> But why do you add "&& !is_symlink(p)"? My
> expectation for a function named is_file() would be that it be
> "deep" and ignore the fact that the file was reached via a
> symbolic_link. In other works, the implementation would just be
>
> {
> return !directory(ph); // note that this may throw
> }

No I don't want the function to be 'deep' because I'm changing the names of
the only the actual files and I want to sidestep the symlinks in the directory.

Here's how I implemented it:

    BOOST_FILESYSTEM_DECL bool is_file( const path & ph )
    {
# ifdef BOOST_POSIX
      struct stat path_stat;
      if ( ::lstat( ph.native_directory_string().c_str(), &path_stat ) != 0 )
        boost::throw_exception( filesystem_error(
          "boost::filesystem::is_file",
          ph, fs::detail::system_error_code() ) );
      return S_ISREG( path_stat.st_mode );
# else
      //No such thing as a symbolic link on windows so it's a file if its not
a directory
      return !is_directory(ph);
# endif
    }

Now we certainly could implement this on top of the existing library
functions, but it would require 2 calls to stat/lstat. That combined with the
fact that both C and perl have a special function is enough to convince me of
it's need. Finally, I tried out this implementation against one of those
device files and it reports 'exists' true and 'is_file' false -- which is
makes sense since it's a device not a file...

If you think it's a good idea I can just check in the change.

Jeff


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