Как создать жесткую ссылку на существующий файл или каталог в C?
Я ищу, чтобы создать жесткую ссылку на файл или каталог, который уже существует. Например, пользователь решает создать жесткую ссылку на файл с именем "pathname", и пользователь может выбрать имя файла ссылки.
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_
доступны в моем репозитории SOQ (вопросы о переполнении стека) на GitHub в виде файлов stderr.c
а также stderr.h
в подкаталоге src / libsoq. Они, как я сообщаю об ошибках в программах. Некоторые системы имеют заголовок <err.h>
и пестрый набор функций, которые делают то, что делает мой пакет - развлекайтесь с ними (они мне не нравятся, но есть и сильный случай синдрома 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
,