c - 如何在 C 中创建指向现有文件或目录的硬链接?
问题描述
我正在寻找一个指向已经存在的文件或目录的硬链接。例如,用户选择创建指向名为“路径名”的文件的硬链接,并且用户可以选择链接文件的名称。
解决方案
在大多数现代版本的 Unix(或 Unix 变体)上,您不能创建指向目录的硬链接。如果您有足够的权限并且系统支持它,POSIX 允许它,但某些(我相信大多数)系统不允许它。
要创建硬链接,需要使用link()
函数(系统调用):
if (link(existing_file, new_name) != 0)
…link failed…
ln
请注意,与命令不同,新名称必须完整。您不能将目录指定为新名称;您必须在目录中指定文件名。
您能否更具体地了解该
link()
功能的工作原理?
如果调用 as ,则link(source, target)
某种文件必须存在,名称为in ,但指向文件的所有目录都必须存在。假设前提条件满足,系统调用成功后,可以通过 in或 in 的名称来引用相同的文件内容。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.c
和src/libsoq子目录stderr.h
中可用。它们是我报告程序错误的方式。一些系统有一个头文件和各种各样的功能,这些功能可以完成我的包所做的一些事情——玩得开心(我不喜欢它们,但也有一个强烈的 NIH 综合症案例)。还有其他方法可以连接文件名组件;一种是使用而不是 3次操作。<err.h>
sprintf(name, "%s/%s", target, slash)
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
。
推荐阅读
- astropy - 将 3D 笛卡尔地图转换为 Healpix 投影
- reactjs - 无法对未安装的组件错误执行反应状态更新
- angular - 获取特定的 Observable 值
- java - 做while循环和用户输入问题
- django - 如何过滤由另一个超级用户创建的用户以便它可以发送通知
- mysql - SQL: INSERT INTO table(...) VALUES (...) 与从其他表中检索的数据
- c# - 如何在 Teams 中为连接器卡设置 webhook 参数
- asp.net-core - 带有文件的 Blazor 数据发布到 .net 核心 API
- php - 如何将 1 项添加到数组数组中的每个数组
- python - 如何在SQL中定义的时间间隔内获取随机数据样本