std::filesystem::copy_file() 为什么忽略了 create_hard_links 选项标志?

huangapple go评论67阅读模式
英文:

Why does std::filesystem::copy_file() ignore the create_hard_links option flag?

问题

我正在编写一个函数来复制大型二进制图像。首先,我尝试通过硬链接进行复制。如果失败,然后我回退到普通复制。

最初,我编写了一个使用std::filesystem::copy_file()的函数,如下所示:

public bool CopyLargeStaticFile(const path& source, const path& dest)
{
    // 首先尝试硬链接。

    std::error_code ec;
    copy_file(source, dest, copy_options::create_hard_links, ec);

    if (ec)
    {
        // 出现错误时,回退到常规复制。当复制到不同的磁盘时,我希望会出现这个错误,但实际上不会发生,因为copy_file会忽略'create_hard_links'标志,而只会进行常规复制

        ec.clear();
        copy_file(source, dest, ec);
    }

    return !ec;
}

但后来我发现,当调用copy_file时,create_hard_link标志并不被遵守。如果要使其生效,你必须调用filesystem::copy

有没有人知道为什么?是否有技术原因?这是文件系统规范的疏忽吗?还是Visual Studio的实现有问题?对我来说毫无意义。

编辑以补充:在发现这一点之后,我在copy_options枚举中找到了提到这个标志只适用于copy()的说明。只是不理解其中的"为什么"。

英文:

I am writing a function to copy large binary images around. I first try to copy them by hard link. If that fails, then I fallback to copying them normally.

I initially wrote the function to use std::filesystem::copy_file(), like this:

public bool CopyLargeStaticFile(const path& source, const path& dest)
{
    // First try a hard-link.

    std::error_code ec;
    copy_file(source, dest, copy_options::create_hard_links, ec);

    if (ec)
    {
        // On error, fall-back to a regular copy.  When copying to a different
        // disk, I would expect this error but it does not happen because copy_file
        // ignores the 'create_hard_links' flag and just makes a regular copy

        ec.clear();
        copy_file(source, dest, ec);
    }

    return !ec;
}

But then I discovered that the create_hard_link flag is not honored when you call copy_file. If you want it to be honored, you must instead call filesystem::copy.

Does anyone know why? Is there some technical reason? Is it an oversight of the filesystem spec? Something wrong with the Visual Studio implementation? It just makes no sense to me.

Editing to add: After I discovered this, I did come across the mention in the copy_options enum that the flag only applies to copy(). Just don't understand the "why" of it.

答案1

得分: 4

如果您查看C++标准中的copy_options,您将看到create_hard_links 仅设计用于影响copy(),而不是copy_file()。如果您查看Microsoft的实现 中的copy_file(),您将看到它只查看了copy_options 中属于“如何处理现有文件”的逻辑部分。

所以不幸的是,对于您来说,Microsoft的STL遵循了这里的标准,您尝试的操作将不起作用。

从技术上讲,您甚至在这里绕过了未定义的行为:

如果在选项(options)中存在属于任何copy_options选项组的多个选项,那么其行为是未定义的(即使是与filesystem::copy_file不相关的组)。

由于您只指定了create_hard_links,您从技术上讲还没有触发未定义行为(而且Microsoft的实现在这方面可能会宽松一些),但它实际上不会产生任何效果。

我不能确定,但我猜想这里的原因可能是copy_file 专门设计用于复制文件的内容(而不关心复杂的文件系统功能),而copy 是一个更高级的例程。(标准本身表示,在某些情况下copy 可能会调用copy_file。)

因此,如果您想要硬链接,只需使用copy

英文:

If you look at the C++ standard for copy_options, you'll see that create_hard_links is designed to only affect copy() and not copy_file(). If you look at Microsoft's implementation of copy_file(), you'll see that it only looks at the bits of copy_options that are part of the "what to do with existing files" logic.

So unfortunately for you, Microsoft's STL follows the standard here, and what you're trying to do simply won't work.

Technically you're even skirting around undefined behavior here:

> The behavior is undefined if there is more than one option in any of the copy_options option group present in options (even in the groups not relevant to filesystem::copy_file)

Since you only specify create_hard_links you're still technically not invoking UB (and Microsoft's implementation would be lenient here anyway), but it simply won't have any effect.

I don't know for sure, but my guess is that the reasoning here would be that copy_file is designed to explicitly copy the contents of a file (and not care about fancy filesystem features), while copy is a higher-level routine. (The standard itself says that copy may call copy_file in some cases.)

Hence, if you want hard links, simply use copy.

huangapple
  • 本文由 发表于 2023年3月7日 05:51:43
  • 转载请务必保留本文链接:https://go.coder-hub.com/75656164.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定