Как превратить обычный файл в символическую ссылку в Linux - PullRequest
7 голосов
/ 25 февраля 2010

Я пишу (не) инструмент архивации и, как он спроектирован, он сначала создает обычный файл из архива, прежде чем проверяет специальные атрибуты и может решить, что этот элемент фактически является символической ссылкой.

Примечание. Прежде чем другие люди не поймут меня неправильно, я хочу создать символическую ссылку из файла. Нет, я записываю данные символической ссылки, то есть ее путь, в файл, а затем хочу сообщить файловой системе, что это символическая ссылка

Я разрабатывал это на OS X, где можно превратить обычный файл в символическую ссылку, просто установив соответствующие коды Type и Creator.

Теперь мне нравится, что этот код работает и в Linux. Поэтому мне нравится находить подобный путь там.

Я знаю, что нормальный способ создания символической ссылки - это вызов функции symlink (), но мне интересно, есть ли способ также преобразовать обычный файл в символическую ссылку, как это возможно в системе BSD OSX, чтобы мне не пришлось слишком много реорганизовывать мой рабочий код?

Существует lstat (), который возвращает тип файла в старших битах st_mode. Теперь мне интересно, есть ли аналогичная функция для этого поля режима.

Ответы [ 3 ]

4 голосов
/ 25 февраля 2010

Я не верю, что в Linux есть способ сделать это, как вы описываете. IIRC, файловая система хранит информацию о символических ссылках в таблице inode, а не в обычном файле, поэтому прямого преобразования файла в ссылку нет.

Если путь к символической ссылке хранится внутри файла, почему бы не прочитать путь, удалить файл и создать вместо него символическую ссылку?

3 голосов
/ 25 февраля 2010

Демонстрация того, что я написал в качестве комментария к ответу bmarguiles,

#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, char **argv) {
    char *buffer = 0, *name = 0;
    int i;
    for (i = 1; i < argc; i++) {
        struct stat st;
        int fd = open(argv[i], O_RDONLY);
        fstat(fd, &st);
        buffer = realloc(buffer, st.st_size + 1);
        read(fd, buffer, st.st_size);
        close(fd);
        buffer[st.st_size] = '\0';
        name = realloc(name, strlen(argv[i]) + 2);
        sprintf(name, "%s~", argv[i]);
        symlink(buffer, name);
        rename(name, argv[i]);
    }
    free(buffer);
    free(name);
    return 0;
}
$ vi f2s.c
...
$ cc -o f2s f2s.c
$ echo -n / > test
$ ./f2s test
$ ls -l test
lrwxrwxrwx 1 me me 1 Feb 24 23:17 test -> /
$ echo -n / > test2
$ strace ./f2s test2
open("test2", O_RDONLY)                 = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=1, ...}) = 0
read(3, "/", 1)                         = 1
close(3)                                = 0
symlink("/", "test2~")                  = 0
rename("test2~", "test2")               = 0

Это просто демонстрация; это действительно требует большей обработки ошибок и, возможно, лучшего временного имени файла.

1 голос
/ 25 февраля 2010

Нет, вы не можете превратить одно в другое. Вы должны отменить ссылку, чтобы убить файл, а затем символическую ссылку, чтобы создать символическую ссылку в качестве замены.

...