问题 为什么boost :: filesystem :: canonical()要求目标路径存在?


的文档 boost::filesystem::canonical(const path& p) 状态:

概述:将必须存在的p转换为没有符号链接,点或点点元素的绝对路径。
  ...
  备注:!exists(p)是一个错误。

其结果是,如果p标识其目标不存在的符号链接,则该函数将失败 file not found 并且不会返回路径。

这对我来说似乎过于严格:只是因为链接的目标不存在,我认为没有理由为什么函数无法解决 路径 那个不存在的目标。 (相比下, absolute() 没有这样的限制。)

(显然,如果是符号链接  路径坏了,目标路径无法解析。)

那么,这种限制是否有正当理由?

即使存在,是否也没有理由创建没有此限制的函数变体? (没有这样的变体,获得路径需要容易出错的99%的手动复制 canonical() 已经。)

我欣赏它之间存在的语义细微之处 stat() 和 lstat() 同样适用于这种情况 - 这正是我认为函数的变体同样合理的原因。

注意:这个问题同样适用于 std::experimental::filesystem 图书馆 (N4100),这是基于 boost::filesystem

编辑:

在@Jonathan Wakeley下面非常知识渊博的答案之后,我仍然留下了原始问题的精髓,我将稍微重新思考:

  • 有没有 潜在的技术或逻辑原因 为什么 boost::filesystem::canonical() 要求目标存在吗?我的意思是,目标的不存在是否会使得无法解决规范形式的路径?

  • 如果没有,是否有任何技术或逻辑原因  提出一个与现有形式不同的功能变体  要求目标存在吗?

  • 在转型中(据我理解的情况而定) boost::filesystem 进入提议的N4100 std::experimental::filesystem,有这个限制 canonical() 经过适当考虑后被采纳,还是仅仅是从Boost定义中“落伍”?

编辑2:

我注意到Boost 1.60现在提供了这个功能 weakly_canonical():“返回p,解析符号链接并将结果标准化。返回:由调用结果组成的路径 canonical() 在由p的前导元素组成的路径上起作用,如果有的话,后跟p不存在的元素,如果有的话。“

编辑3:

对此进行更多讨论 和---关联 std::filesystem


12865
2017-07-10 09:54


起源

来晚了,但是...如果 canonical() 作为结果,给出了该不存在的符号链接目标的路径,并且在该第二个目标之后 得到 创建 作为不同位置的符号链接,返回的路径 canonical() 早些时候会破坏合同 canonical(),不是吗? (只是问问。) - DevSolar
是的,除此之外 任何 结果返回 canonical() 可能会立即过时。例如,如果相同也可以这样说 canonical() 返回路径 现有 然后更改或删除文件和路径的任何部分。实际上,由于它是作为每个路径组件的迭代分辨率实现的, canonical() 容易受到文件系统更改的影响 虽然它正在进行中。 - Jeremy
复制一遍,谢谢你的澄清。 - DevSolar


答案:


基本上因为它是一个包装 真实路径 具有相同的要求。

你可以问同样的问题 realpath,但我认为答案是,如果你试图找出路径名所指的真实的物理文件或目录,那么如果它是一个破碎的符号链接,那么就没有答案,它  引用一个真实的文件或目录,所以你想要一个错误。

以下OP的评论质疑我的主张 filesystem::canonical 和 realpath 实现相同的操作,但N4100和POSIX中的定义看起来几乎与我相同,比较:

realpath() 函数应从指向的路径名派生 file_name,一个绝对路径名,解析为同一目录条目,其分辨率不涉及 '.''..'或符号链接。

和:

转换 p,必须存在,到一个没有符号链接的绝对路径, ".", 要么 ".." 元素。

在这两种情况下,要求是:

  • 没有符号链接,如果它返回了一个路径,其中最后一个组件是符号链接,不符合要求。

  • 规范路径指的是存在的东西,这在N4100中是明确的,并且在POSIX中隐含,因为它指向某个目录条目(即存在的东西)并且目录条目不是符号链接(因为第一个要求)。

至于 为什么 那些应该是要求,N4100中的注释是有帮助的:

[注意: 规范路径名允许对路径进行安全检查(例如,此路径是否存在 /home/goodguy 要么 /home/badguy?) - 注意]

正如我上面已经说过的,即使路径是符号链接,它也会成功返回  实际上指向任何东西,然后你需要做额外的工作来检查它是否解析为真实文件,使预期的用例不太方便。

即使存在,是否也没有理由创建没有此限制的函数变体? (没有这样的变体,获取路径需要容易出错的手动复制99%的规范()已经做了。)

可以说这个变体不太常用,所以不应该是默认的,但如果你需要它,那么就不难做到:

// like canonical() but allows the last component of p to be a broken symlink
filesystem::path
resolve_most_symlinks(filesystem::path const& p, filesystem::path const& base = filesystem::current_path())
{
  if (is_symlink(p) && !exists(p))
    return canonical(absolute(p, base).remove_filename()) / p.filename();
  return canonical(p);
}

5
2017-07-10 10:20



Boost(版本1.55,至少)在realpath()方面没有实现它,即使在posix下也是如此。 - Jeremy
规范路径的概念与真实的物理文件或目录的路径不同。 - Jeremy
@Jeremy,感谢关于Boost的信息,我认为它会使用 realpath (这就是我为GCC的N4100实现所做的,以及我所知道的唯一其他基于POSIX的N4100实现)。 Boost是否使用其他操作系统功能或手动操作? - Jonathan Wakely
至于你的第二个评论,N4100定义 canonical as“绝对路径没有符号链接的元素,没有点或点点元素”和POSIX定义 realpath 导出“解析为同一目录条目的绝对路径名,其分辨率不涉及'。','..'或符号链接”......所以你想要给“规范路径”或“真实路径”的语义,物理文件或目录“不会改变这一事实 canonical 和 realpath 被定义为做同样的事情(无论是给出规范路径,还是给真实文件的路径,或其他东西)。 - Jonathan Wakely
忽略由goodguy / badguy用例表示的安全检查的可疑方法,确定是否 p 解析为真实文件与否是已经解决的单独问题 exists(p)。 - Jeremy


尝试 weakly_canonical() 它不需要mac上存在路径


5
2018-04-07 16:11



是。请参阅问题的编辑2。 - Jeremy