Каталог рекурсии и символические ссылки - PullRequest
7 голосов
/ 11 сентября 2011

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

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

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

Считают ли пользователи Unix второе решение менее удивительным?

Если так, есть ли способ получить такое каноническое представление / идентичность каталога, который переносим в системах Unix? (Я бы хотел, чтобы он работал в Linux, BSD, Mac OS, Solaris и т. Д. Я ожидаю, что придется написать отдельный код для Windows.)

Ответы [ 5 ]

4 голосов
/ 11 сентября 2011

Наиболее часто игнорируемым API в этом поле будет

nftw

В Nftw есть опции, позволяющие избежать прохождения символических ссылок. У этого есть намного более продвинутые способности чем это. Вот простой пример самой страницы руководства:

#define _XOPEN_SOURCE 500
#include <ftw.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>

static int
display_info(const char *fpath, const struct stat *sb,
             int tflag, struct FTW *ftwbuf)
{
    printf("%-3s %2d %7jd   %-40s %d %s\n",
           (tflag == FTW_D) ?   "d"   : (tflag == FTW_DNR) ? "dnr" :
           (tflag == FTW_DP) ?  "dp"  : (tflag == FTW_F) ?   "f" :
           (tflag == FTW_NS) ?  "ns"  : (tflag == FTW_SL) ?  "sl" :
           (tflag == FTW_SLN) ? "sln" : "???",
           ftwbuf->level, (intmax_t) sb->st_size,
           fpath, ftwbuf->base, fpath + ftwbuf->base);
    return 0;           /* To tell nftw() to continue */
}

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

    if (argc > 2 && strchr(argv[2], 'd') != NULL)
        flags |= FTW_DEPTH;
    if (argc > 2 && strchr(argv[2], 'p') != NULL)
        flags |= FTW_PHYS;

    if (nftw((argc < 2) ? "." : argv[1], display_info, 20, flags)
            == -1)
    {
        perror("nftw");
        exit(EXIT_FAILURE);
    }
    exit(EXIT_SUCCESS);
}

Смотри также

3 голосов
/ 11 сентября 2011

Абсолютный путь к каталогу является таким представлением.Вы можете получить его с помощью функции realpath, которая определена в стандарте POSIX, поэтому она будет работать в любой POSIX-совместимой системе.Смотри man 3 realpath.

2 голосов
/ 11 сентября 2011

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

Хорошая реализация не хотела бы давать ложные срабатывания для жестко связанных файлов и символических ссылок, либо через символические ссылки на родительские каталоги, либо на файлы.

Самый переносимый подход для решения этой проблемы - это идентификация файлов с помощью функций stat / fstat POSIX и struct stat, которые они заполняют элементами st_dev и st_ino. Реальная реализация проверки на наличие дубликатов файлов в C, использующая эту стратегию, - samefile (другая реализация которой была выигрышной записью 1998 IOCCC : -)

2 голосов
/ 11 сентября 2011

Не только символические ссылки, но и жесткие ссылки.Не очень часто, но не запрещено.(Только корневые каталоги могут содержать жесткие ссылки). Единственное, что канонично, это {номер_устройства, номер_узла}.Но сетевые файловые системы могут плохо себя вести.

1 голос
/ 11 сентября 2011

Поскольку вы не указали, с каким языком вы работаете (если есть), давайте начнем только с оболочки: если вы работаете в системе с GNU readlink, просто используйте readlink -f <path>, чтобы канонизировать его.

Если вы работаете на Mac (с не-GNU readlink, который ведет себя по-другому), см. Как узнать поведение readlink -f GNU на Mac? для способа выполнить ту же задачу.

Другой вариант - использовать идентификаторы inode для отслеживания уникальных файлов (через stat или аналогичные), но для этого потребуется в любом случае сначала следовать всем символическим ссылкам (так какСами символические ссылки имеют свой собственный уникальный идентификатор (inode id), и простейший способ следовать всем символическим ссылкам - это, readlink.


В качестве альтернативы, многие языки программирования имеют привязки к POSIX * 1015.* функция, которая, по сути, выполняет ту же функцию, что и readlink -f (но при вызове библиотеки).Например, в Python есть os.path.realpath(), в C она есть как функция в stdlib.h, и так далее.

Если вы уже работаете на языке, который имеет такую ​​функцию,настоятельно рекомендуется использовать его, поскольку вы часто получаете кросс-платформенную совместимость бесплатно (при условии, что ваш язык кросс-платформенный).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...