【问题标题】:std::filesystem "root_name" definition broken on windowsWindows 上的 std::filesystem "root_name" 定义被破坏
【发布时间】:2019-02-02 16:10:27
【问题描述】:

我感觉 C++ 文件系统标准在 Windows 上被破坏了。它在很大程度上基于 Boost.filesystem,我刚刚发现了一个严重的问题,它(可能)也存在于 std::filesystem 中:https://github.com/boostorg/filesystem/issues/99

本质是“root_name”和“root_directory”的定义:

root-name(可选):标识具有多个根的文件系统上的根(例如“C:”​​或“//myserver”)。在有歧义的情况下,形成有效根名称的最长字符序列被视为根名称。除了 OS API 可以理解的根名称之外,标准库还可以定义其他根名称。

root-directory(可选):目录分隔符,如果存在,则将此路径标记为绝对路径。如果它丢失(并且除根名称之外的第一个元素是文件名),则路径是相对的,并且需要另一个路径作为起始位置才能解析为文件名。

这需要例如"C:\foo\bar.txt" 被分解成:

  • root_name: "C:"
  • root_directory:“\”或“/”(这有意义吗?)
  • 目录:“foo”
  • 文件名“bar.txt”

现在的问题:这条路径的第一部分不是路径,至少不是原来的路径。这来自windows上的解释:

  • “C:\”是驱动器“C”
  • “C:”是驱动器“C”上的当前工作目录

Minor:“\foo\bar.txt”应该如何在windows上按照上面的解释?你有一个“root_directory”(奇怪的是它不是一个目录,而是一个目录分隔符)但没有“root_name”,因此路径不能是绝对的,所以你也没有“root_directory”。叹息。

因此,我觉得“root_name”和“root_directory”不能分解(在Windows上)。在“C:\foo”中,您将拥有“C:\”,在“C:foo”中,您将拥有“C:”。或者要保留(奇怪定义的)“root_directory”,您需要将分解“C:\ foo”设置为“C:\”,“\”和“foo”并与后者斗争:这是绝对路径吗?其实就是:“C盘当前工作目录下的文件夹‘foo’”,很绝对吧?

但是你可以说“absolute==independent of current working dir”,那么“root_directory”是有意义的:“C:\foo”是“\”,“C:foo”是空的。

所以问题:在像“C:\foo”这样的路径中将“C:”定义为“root_name”而不是“C:\”是标准错误,还是迭代路径的组件只是无效的用法期望前缀总和是“有效的”?

【问题讨论】:

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


    【解决方案1】:

    您对 Windows 文件系统的解释不正确。目录C:\ 是“C”驱动器的根目录,而不是“驱动器'C'”。这与C: 不同,后者是“C”驱动器的当前目录。只需尝试使用 Windows shell 并查看C:<stuff> 相对于C:\<stuff> 的行为。两者都将访问该驱动器上的内容,但都将从不同的目录开始。

    在 Windows 上用这些术语来考虑它:

    • C: 表示“转到C盘的当前目录”。
    • \ 在路径开头(在任何根名称之后)表示“转到当前驱动器的根目录”。
    • foo\ 的意思是“进入我们当前所在目录中名为 'foo' 的目录”。
    • bar.txt 表示“我们当前所在目录中名为‘bar.txt’的文件。”

    所以C:\foo\bar.txt"的意思是:进入C盘当前目录,然后进入C盘根目录,然后进入C盘根目录的'foo'目录,然后访问文件'bar C的根目录的'foo'目录下的.txt'。

    同理C:foo\bar.txt的意思是:进入C盘当前目录,然后进入C盘当前目录的'foo'目录,然后访问'foo'目录下的文件'bar.txt' C的当前目录。

    这就是 Windows 路径的工作方式。这就是在 Windows shell 中键入这些内容的含义。因此,这就是 Boost/std 文件系统路径的设计方式。

    但是你可以说“absolute==independent of current working dir”

    但这不是标准文件系统定义the concept of "absolute path"的方式:

    绝对路径 明确标识文件位置的路径,无需参考其他起始位置。确定路径是否为绝对路径的元素取决于操作系统。

    所以“相对”和“绝对”是依赖于实现的。在 Windows 中,路径不是绝对的,除非它包含 both 根名称和根目录。在 Windows 文件系统实现中,path("\foo\bar.txt").is_absolute() 将为 false。

    【讨论】:

    • 很好的解释谢谢。这是一个重大缺陷,甚至会导致(至少)1 个 boost 错误......请注意:我认为我对绝对路径的解释仍然抓住了本质,尽管它有点不那么普遍。
    • 卷设备名称是“C:”,而不是“C”,即我们以“\\.\C:”或“\\?\C:”(或“ \??\C:" in NT),它链接到枚举卷,例如 "\Device\HarddiskVolume2"。 Windows 首先通过RtlDetermineDosPathNameType_Ustr 将路径分类为8 个RTL_PATH_TYPE 类别之一。
    • 另请注意,“C:\”是绝对的,但不完全限定为跨整个系统的路径,即如果传递给另一个进程,它不一定会引用同一个设备。全局“C:”对象链接可以隐藏在登录会话的本地设备中。我们需要 "\\?\Global\C:\" 使其在登录会话中完全合格。
    【解决方案2】:

    您要查找的是root_path,请参阅Filesystem TS § 8.4.9,路径分解

    path root_path() const;

    返回:root_name()/root_directory()

    这是微软defines it

    这两个系统的共同点是一旦你使用了路径名的结构 越过根名称。对于路径名c:/abc/xyz/def.ext

    • 根名称是c:
    • 根目录为/
    • 根路径为c:/
    • 相对路径为abc/xyz/def.ext
    • 父路径是c:/abc/xyz
    • 文件名为def.ext
    • 主干是def
    • 分机号是.ext

    因此,真正的绝对路径应以root_name + root_directoryroot_path 开头。

    另请参阅system_complete(p) 以解析其他驱动器上的当前目录:

    效果:p 组成一个绝对路径,使用操作系统使用的相同规则来解析作为文件名参数传递给标准库打开函数的路径。

    [示例:对于基于 POSIX 的操作系统,system_complete(p)absolute(p, current_path()). 具有相同的语义

    对于基于 Windows 的操作系统,system_complete(p) 的语义与 absolute(p, current_path()) 如果p.is_absolute() || !p.has_root_name()p 和 基地有相同的root_name()。否则它就像absolute(p, cwd)p.root_name() 驱动器的当前目录一样。这将是该驱动器上次设置时的当前目录,因此可能是命令处理器运行的先前程序留下的残留物。尽管这些语义很有用,但它们可能令人惊讶。 ——结束示例]

    【讨论】:

    • 需要注意的是standard definesroot_path总是root_­name() / root_­directory()。此外,system_complete不是标准文件系统 API 的一部分。
    猜你喜欢
    • 1970-01-01
    • 2021-01-02
    • 2013-03-10
    • 2011-12-19
    • 2014-10-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多