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

nnsrf1az  于 2023-01-03  发布在  其他
关注(0)|答案(2)|浏览(222)

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的关系。

am46iovg

am46iovg1#

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

gtlvzcf8

gtlvzcf82#

基本上是因为它是具有相同要求的realpath的 Package 器。
你可以问realpath同样的问题,但我认为答案是,如果你试图找出一个路径名所指的真实的物理文件或目录,那么如果它是一个断开的符号链接,那么就没有答案,它 * 不 * 指一个真实的文件或目录,所以你想得到一个错误。
下面OP的评论质疑了我关于filesystem::canonicalrealpath实现相同操作的说法,但N4100和POSIX中的定义在我看来几乎相同,请比较:
realpath()函数应从file_name指向的路径名派生解析为相同目录条目的绝对路径名,其解析不涉及'.''..'或符号链接。
以及:
将必须存在的p转换为不含符号链接、"."".."元素的绝对路径。
在这两种情况下,要求是:

      • 无符号链接**,如果返回的路径中最后一个组件是符号链接,则不满足要求。
      • 规范路径指的是存在的东西**,这在N4100中是显式的,而在POSIX中是隐式的,因为它指向某个目录条目(即存在的东西),并且目录条目不是符号链接(因为第一个要求)。

至于 * 为什么 * 这些应该是要求,N4100中的注解很有帮助:
[* 注意:* 规范路径名允许对路径进行安全检查(例如,此路径位于/home/goodguy还是/home/badguy中?)*-end note *]
正如我在上面所说的,如果它成功返回,即使路径是一个符号链接,实际上并不指向任何东西,那么您需要做额外的工作来检查它是否解析为一个真正的文件,这会使预期的用例不那么方便。
即使有,创建一个没有这个限制的函数变体难道不也是合理的吗?(如果没有这样的变体,获取路径需要手动复制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);
}

相关问题