How to check if a file is a regular file or a symlink, using boost::filesystem?

boost, boost-filesystem, c++

Solution

As of Boost.Filesystem v3, checking if it is a regular file already does what you want. The following is a simple code:

#include <boost/filesystem.hpp>

#include <iostream>

namespace fs = boost::filesystem;

int main(int argc, char* argv[]) {
  if (argc > 1) {
    auto status = fs::status(argv[1]);

    if (status.type() == fs::regular_file)
      std::cout << argv[1] << " is a valid path." << std::endl;
    else
      std::cout << argv[1] << " is not a valid path." << std::endl;

    if (fs::symlink_status(argv[1]).type() == fs::symlink_file)
      std::cout << "It is also a symlink." << std::endl;

  } else {
    std::cerr << "A path must be given." << std::endl;
  }

  return 0;
}

Here are some outputs:

% ./fstest /bin # it is a symlink path
/bin is not a valid path.
It is also a symlink.
% ./fstest /bin/ # it is a symlink path but dereferenced? (trailing /)
/bin/ is not a valid path.
% ./fstest /bin/zsoelim # it is a symlink                                                                                                               
/bin/zsoelim is a valid path.
It is also a symlink.
% ./fstest /bin/soelim # it is not a symlink 
/bin/soelim is a valid path.

So as you can see, `boost::filesystem::status(path)` returns the information about the actual path whether it is a symlink (followed to the real location) or not. On the other hand, `boost::filesystem::symlink_status(path)` returns the information if the file itself is symlink or not.

More information can be found on boost docs.

Problem

I would like to check if the string `name` refers to a file that I can open and read from, so it can be a regular file or a symlink. I first used this: ``` std::ifstream in(name.c_str()); if (!in.is_open()) { // throw exception! } ``` but it didn't throw an exception when `name` referred to a directory name. Now I'm using this: ``` if (!fs::exists(name) || fs::is_directory(name)) { // throw exception! } ``` But it will (presumably) not throw if it's a symlink to a directory. The same is true for this: ``` if (!fs::is_regular_file(name) && !fs::is_symlink(name)) { // throw exception! } ``` Is there a better way?

Original source