path::lexically_relative
causes surprising results if a filename can also be a
root-nameSection: 31.12.6.5.11 [fs.path.gen] Status: C++20 Submitter: Billy O'Neal III Opened: 2018-02-23 Last modified: 2021-02-25
Priority: 2
View all other issues in [fs.path.gen].
View all issues with C++20 status.
Discussion:
path::lexically_relative
constructs the resulting path with operator/=
. If any of
the filename elements from *this
are themselves acceptable root-names, operator/=
will destroy any previous value, and take that root_name()
. For example:
path("/a:/b:").lexically_relative("/a:/c:")
On a POSIX implementation, this would return path("../b:")
, but on a Windows implementation, the
"b:"
element is interpreted as a root-name, and clobbers the entire result path
,
giving path("b:")
. We should detect this problematic condition and fail (by returning path()
).
[2019-01-20 Reflector prioritization]
Set Priority to 2
[2019 Cologne Wednesday night]
Status to Ready
Proposed resolution:
This wording is relative to N4727.
Change 31.12.6.5.11 [fs.path.gen] as indicated:
path lexically_relative(const path& base) const;-3- […]
-4- Effects: Ifroot_name() != base.root_name()
istrue
oris_absolute() != base.is_absolute()
istrue
or!has_root_directory() && base.has_root_directory()
istrue
or if any filename inrelative_path()
orbase.relative_path()
can be interpreted as a root-name, returnspath()
. [Note: On a POSIX implementation, no filename in a relative-path is acceptable as a root-name — end note] Determines the first mismatched element of*this
andbase
as if by:auto [a, b] = mismatch(begin(), end(), base.begin(), base.end());Then,
(4.1) — if
a == end()
andb == base.end()
, returnspath(".")
; otherwise(4.2) — let
n
be the number of filename elements in[b, base.end())
that are not dot or dot-dot minus the number that are dot-dot. Ifn < 0
, returnspath()
; otherwise(4.3) — returns an object of class
path
that is default-constructed, followed by
(4.3.1) — application of
operator/=(path(".."))
n
times, and then(4.3.2) — application of
operator/=
for each element in[a, end())
.