Why does boost::filesystem::canonical() require the target path to exist?

Jeremy picture Jeremy · Jul 10, 2015 · Viewed 9.5k times · Source

The documentation for boost::filesystem::canonical(const path& p) states:

Overview: Converts p, which must exist, to an absolute path that has no symbolic link, dot, or dot-dot elements.
...
Remarks: !exists(p) is an error.

The consequence of this is that if p identifies a symbolic link whose target does not exist, the function fails with file not found and does not return a path.

This seems overly restrictive to me: just because the target of the link doesn't exist, I see no reason why the function can't resolve the path of that non-existent target. (In comparison, absolute() imposes no such restriction.)

(Clearly, if a symbolic link within the path is broken, the target path can't be resolved.)

So, is there a legitimate justification for this restriction?

And even if there is, is there not also justification for the creation of a variant of the function that does not have this restriction? (Without such a variant, obtaining the path requires error-prone manual replication of 99% of what canonical() already does.)

I appreciate that the semantic subtleties that exist between stat() and lstat() apply equally to this case - which is precisely why I think a variant of the function is equally justified.

NB: This question is equally applicable to the std::experimental::filesystem library (n4100), which is based on boost::filesystem.

EDIT:

After @Jonathan Wakeley's very knowledgeable answer below, I'm still left with the essence of my original questions, which I'll reframe slightly:

  • Is there an underlying technical or logical reason why boost::filesystem::canonical() requires the target to exist? By that I mean, does the non-existence of the target somehow make it impossible to resolve the path to canonical form?

  • If not, is there any technical or logical reason not to propose a variation of the function that differs only from the existing form in that it does not require the target to exist?

  • In the transformation (as I understand to be the case) of boost::filesystem into the proposed N4100 std::experimental::filesystem, has this restriction on canonical() been adopted after due consideration, or is it just 'falling through' from the Boost definition?

EDIT 2:

I notice that Boost 1.60 now provides the function weakly_canonical(): "Returns p with symlinks resolved and the result normalized. Returns: A path composed of the result of calling the canonical() function on a path composed of the leading elements of p that exist, if any, followed by the elements of p that do not exist, if any."

EDIT 3:

More discussion of this in relation to std::filesystem.

Answer

apiashko picture apiashko · Apr 7, 2017

try weakly_canonical() it does not require path to exist on mac