28

I want to write a unit test that checks that two file paths are equivalent, but I don't want to assume that the string representation is the same.

For example, on Linux there could be symlinks in the path in one case and not in the other. On Windows, there could be drive notation on one (X:\foo) and network notation on the other (//serverX/foo). And most complicated, the file may have been written on Linux on an NFS share (in /path/to/file syntax) and verified on Windows using DOS syntax (X:\to\file) where X: is a NFS mount to /path.

Some ideas (found here on Stack Overflow, but not unified):

  1. On Linux, compare the inode from stat
  2. Use realpath (Is this Platform independent?)
  3. On Windows, compare strings on GetFullPathName
  4. On Windows, compare serial numbers and file index from GetFileInformationByHandle

What would be the cross-platform best solution? I'm writing this in C++, but I can drop down to C obviously.

Community
  • 1
  • 1
Mark Lakata
  • 19,989
  • 5
  • 106
  • 123
  • not sure if it addresses your problem, but did you take a look at Boost::Filesystem? http://www.boost.org/doc/libs/1_57_0/libs/filesystem/doc/index.htm – vsoftco Apr 07 '15 at 17:08
  • @JossefHarush that wouldn't tell you if you're looking at two different copies of the same file. – Mark Ransom Apr 07 '15 at 17:13

2 Answers2

20

You could check out the Boost.Filesystem library. Specifically, there is a method equivalent that seems to do exactly what you are looking for:

using namespace boost::filesystem;

path p("/path/to/file/one");
path q("/sym_link/to/one");
assert(equivalent(p, q));
Barry
  • 286,269
  • 29
  • 621
  • 977
  • 6
    Thanks, that's what I was looking for. For reference, the boost implementation uses inode comparisons on Linux and serial number/file index comparions on Windows. – Mark Lakata Apr 07 '15 at 18:20
3

Filesystem library

Since C++17 you can use the standard <filesystem> library. The function you are looking for is equivalent, under namespace std::filesystem:

bool std::filesystem::equivalent(const std::filesystem::path& p1, const filesystem::path& p2);

To summarize from the documentation: this function takes two paths as parameters and returns true if they reference the same file or directory, false otherwise. There is also a noexcept overload that takes a third parameter: an std::error_code in which to save any possible error.

For more information take a look at my complete answer to another stack overflow question.

Stypox
  • 963
  • 11
  • 18