Как создать жесткую ссылку на существующий файл или каталог в 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,

Другие вопросы по тегам