【问题标题】:How to create a hard link to an existing file or directory in C?如何在 C 中创建指向现有文件或目录的硬链接?
【发布时间】:2018-12-06 03:24:10
【问题描述】:

我希望创建一个指向已经存在的文件或目录的硬链接。例如,用户选择创建指向名为“pathname”的文件的硬链接,并且用户可以选择链接文件的名称。

【问题讨论】:

  • 欢迎来到 StackOverFlow.. 使用 libc 函数 link 14.4 Hard Links
  • @ThiruShetty 回答?
  • @immibis 是的,这是实现方法之一,它的标准 libc 调用。

标签: c hardlink


【解决方案1】:

在大多数现代版本的 Unix(或 Unix 变体)上,您无法创建指向目录的硬链接。如果您有足够的权限并且系统支持,POSIX 允许它,但某些(我相信大多数)系统不允许它。

要创建硬链接,需要使用link()函数(系统调用):

if (link(existing_file, new_name) != 0)
    …link failed…

请注意,与ln 命令不同,新名称必须完整。您不能将目录指定为新名称;您必须在目录中指定文件名。


您能否更具体地了解link() 函数的工作原理?

如果以link(source, target) 调用,则必须存在名称为source 的某种文件(它不能是目录,除非您可能具有“适当的权限”——这意味着超级用户或root 权限),并且不能有名称在target 中的文件,但指向target 名称的文件的所有目录都必须存在。假设前提条件满足,系统调用成功后,可以通过source中的名称或target中的名称来引用相同的文件内容。

例如,如果我要求用户选择现有路径,然后为正在创建的硬链接选择一个名称,我将如何处理?

FWIW,不要打扰提示 - 使用命令行参数,就像 ln 命令一样。

我还读到我必须取消链接原始文件。

您可能不会,但这取决于您想要实现的语义以及“原始文件”的含义。如果目标文件已经存在,则可以编写删除目标文件的代码(如ln -f source target 将删除目标文件,如果它已经存在)。可以编写在链接成功后删除源文件名的代码(如mv source target——注意不同的命令名)。可以编写代码来尝试确保创建通向目标的所有目录(如果它们尚不存在)(如mkdir -p $(dirname target))。等等。您可以决定允许通过命令行选项指定目标目录,而不是仅使用最后一个参数作为目标目录。等等。有很多可能性——你只需要决定你想要什么语义并实现它们。请注意,符号(软)链接和symlink() 函数的规则与硬链接的规则不同。

这是一些代码(源文件link37.c):

#include "stderr.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>

int main(int argc, char **argv)
{
    err_setarg0(argv[0]);

    if (argc != 3)
        err_usage("source target");
    char *source = argv[1];
    char *target = argv[2];
    struct stat sb;
    if (stat(source, &sb) != 0)
        err_syserr("cannot access source file '%s': ", source);
    if (stat(target, &sb) == 0)
    {
        if (!S_ISDIR(sb.st_mode))
            err_error("name '%s' exists and is not a directory\n", target);
        else
        {
            char *slash = strrchr(source, '/');
            if (slash == 0)
                slash = source;
            else
                slash++;
            if (*slash == '\0')
                err_error("name '%s' cannot end with a slash\n", source);
            size_t baselen = strlen(target);
            size_t filelen = strlen(slash);
            size_t namelen = baselen + filelen + 2;
            char *name = malloc(namelen);
            if (name == 0)
                err_syserr("failed to allocate %zu bytes memory: ", namelen);
            memmove(name, target, baselen);
            memmove(name + baselen, "/", 1);
            memmove(name + baselen + 1, slash, filelen + 1);
            target = name;
        }
    }
    if (link(source, target) != 0)
        err_syserr("failed to link '%s' to '%s': ", source, target);
    if (target != argv[2])
        free(target);
    return 0;
}

最后的free() 并不是必须的。以 err_ 开头的函数在我的 GitHub 上的 SOQ(堆栈溢出问题)存储库中作为文件 stderr.cstderr.hsrc/libsoq 子目录中提供。它们是我报告程序错误的方式。一些系统有一个标题&lt;err.h&gt; 和各种各样的功能,这些功能可以完成我的包所做的一些事情——玩得开心(我不喜欢它们,但也有很强的 NIH 综合症案例)。还有其他方法可以连接文件名组件;一种是使用 sprintf(name, "%s/%s", target, slash) 而不是 3 个 memmove() 操作。

示例运行:

$ link37 link37.c chameleon
$ mkdir -p doc
$ link37 link37.c doc
$ link37 /Users/jonathanleffler/soq/ src
link37: name '/Users/jonathanleffler/soq/' cannot end with a slash
$ link37 /Users/jonathanleffler/soq src
link37: failed to link '/Users/jonathanleffler/soq' to 'src/soq': error (1) Operation not permitted
$ link37 link37.c chameleon
link37: name 'chameleon' exists and is not a directory
$ link37 /no/where/file.c /some/where/
link37: cannot access source file '/no/where/file.c': error (2) No such file or directory
$ link37 link37.c /some/where/
link37: failed to link 'link37.c' to '/some/where/': error (2) No such file or directory
$ rm -f doc/link37.c chameleon
$ rmdir doc 2>/dev/null
$

我有一个目录doc 已经存在(所以mkdir -p doc 没有做任何事情),但最后的rmdir doc 也没有损坏。这就是我没有使用rm -fr doc 的原因——我有一些信息想保留在doc 中。

【讨论】:

  • 您能否更具体地了解一下 link() 函数的工作原理?例如,如果我要求用户选择现有路径,然后为正在创建的硬链接选择一个名称,我将如何处理?我还读到我必须取消链接原始文件。我只是在理解这一点时遇到了问题。谢谢!
  • 在更新的答案中查看大量额外信息。
猜你喜欢
  • 1970-01-01
  • 2012-03-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-12
  • 2015-08-17
  • 1970-01-01
  • 2018-07-09
相关资源
最近更新 更多