【问题标题】:Why does boost::filesystem::canonical() require the target path to exist?为什么 boost::filesystem::canonical() 需要目标路径存在?
【发布时间】:2015-09-29 00:42:31
【问题描述】:

boost::filesystem::canonical(const path& p) 的文档指出:

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

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

这对我来说似乎过于严格:仅仅因为链接的目标不存在,我看不出函数无法解析该不存在目标的 path 的原因。 (相比之下,absolute() 没有这样的限制。)

(显然,如果路径的符号链接被破坏,则无法解析目标路径。)

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

即使有,是否也有理由创建一个没有此限制的函数变体? (如果没有这样的变体,获取路径需要手动复制 canonical() 已经完成的 99% 的错误。)

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

注意:这个问题同样适用于基于boost::filesystemstd::experimental::filesystem 库(n4100)。

编辑:

在下面@Jonathan Wakeley 的知识渊博的回答之后,我仍然保留了我最初问题的本质,我将稍微重新构建:

  • boost::filesystem::canonical() 要求目标存在是否有潜在的技术或逻辑原因?我的意思是,目标的不存在是否会导致无法解析规范形式的路径?

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

  • boost::filesystem 到提议的N4100 std::experimental::filesystem 的转换(据我了解是这种情况)中,是否经过适当考虑采用了对canonical() 的限制,或者只是“落空” ' 来自 Boost 定义?

编辑 2:

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

编辑 3:

More discussion of thisstd::filesystem 相关。

【问题讨论】:

  • 来晚了,但是...如果canonical() 给出了指向那个不存在的符号链接目标的路径,一秒钟后目标 gets 创建了 作为指向不同位置的符号链接canonical() 早先返回的路径会违反canonical() 的约定,不是吗? (只是问。)
  • 是的,但canonical() 返回的any 结果可能会立即过期。例如,如果canonical() 返回现有 文件的路径并且路径的任何部分随后被更改或删除,也可以这样说。事实上,由于它是作为每个路径组件的迭代解析实现的,canonical() 容易受到文件系统更改在进行中的影响。
  • 复制一下,谢谢你的澄清。

标签: c++ boost boost-filesystem c++17


【解决方案1】:

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

【讨论】:

  • 是的。请参阅问题的编辑 2。
【解决方案2】:

基本上是因为它是 realpath 的包装器,具有相同的要求。

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

下面的 OP 评论质疑我关于 filesystem::canonicalrealpath 实现相同操作的说法,但 N4100 和 POSIX 中的定义似乎与我几乎相同,比较:

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

和:

将必须存在的p 转换为没有符号链接、"."".." 元素的绝对路径。

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

  • 无符号链接,如果它返回最后一个组件是符号链接的路径,则不满足要求。

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

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

[注意:规范路径名允许对路径进行安全检查(例如,该路径是否存在于/home/goodguy/home/badguy?)—结束说明]

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

即使有,是否也有理由创建一个没有此限制的函数变体? (如果没有这样的变体,获取路径需要手动复制 99% 的 canonical() 已经完成的操作,容易出错。)

可以说,该变体不太常用,因此不应该是默认值,但如果您需要它,那么它并不难做到:

// 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);
}

【讨论】:

  • Boost(至少是 1.55 版)没有在 realpath() 方面实现它,即使在 posix 下也是如此。
  • 并且规范路径的概念与真实的物理文件或目录的路径不同。
  • @Jeremy,感谢您提供有关 Boost 的信息,我认为它会使用 realpath(这就是我为 GCC 的 N4100 实现所做的,也是我所知道的唯一其他基于 POSIX 的 N4100 实现) . Boost 是使用其他操作系统功能还是手动完成?
  • 至于您的第二条评论,N4100 将 canonical 定义为“没有符号链接元素的绝对路径,也没有点或点点元素”,POSIX 将 realpath 定义为派生“解析为同一目录条目的绝对路径名,其解析不涉及'.'、'..'或符号链接”......所以无论你想赋予“规范路径”或“真实的、物理的”什么语义文件或目录”并没有改变 canonicalrealpath 被定义为做同样事情的事实(无论是提供规范路径,还是指向真实文件的路径,或其他)。
  • 忽略由 goodguy/badguy 用例代表的可疑安全检查方法,确定 p 是否解析为真实文件是 exists(p) 已经解决的一个单独问题。
猜你喜欢
  • 1970-01-01
  • 2011-04-25
  • 1970-01-01
  • 2012-04-27
  • 2011-02-15
  • 1970-01-01
  • 2011-03-10
  • 1970-01-01
  • 2018-02-18
相关资源
最近更新 更多