Summary: When thinking about the filepath ..
, remember symlinks, or you will trip yourself up.
As the maintainer of the Haskell filepath package, one common path-related mistake I see is the assumption that filepaths have the invariant:
/bob/home/../cookies == /bob/cookies
I can see the conceptual appeal - go down one directory, go up one directory, end up where you started. Unfortunately, it's not true. Consider the case where home
is a symlink to tony/home
. Now, applying the symlink leaves us with the case:
/tony/home/../cookies == /bob/cookies
And, assuming /tony/home
is itself not a symlink, that reduces to:
/tony/cookies == /bob/cookies
This is clearly incorrect (assuming no symlinks), so the original invariant was also incorrect, and cannot be relied upon in general. The subtle bit is that descending into a directory might move somewhere else, so it's not an operation that can be undone with ..
. Each step of the path is interpreted based on where it ends up, not based on the path it took to the current point.
While this property isn't true in general, there are many special cases where it is reasonable to assume. For example, the shake package contains a normaliseEx function that normalises under this assumption, but nothing in the standard filepath package assumes it.
The full example/ [DIR] bob [DIR] tony /bob [LINK] home -> /tony/home [FILE] cookies /tony [DIR] home /tony/home [FILE] cookies