VitualBox не обнаруживает мои USB-устройства с Linux-хостом [дубликат]

Члены findutils знают об этом, это для совместимости с *BSD:

Одна из причин, по которой мы пропускаем удаление "." - это совместимость с *BSD, где это действие возникло.

NEWS в исходном коде findutils показывает, что они решили сохранить такое поведение:

#20802: Если -delete не удается, статус выхода find теперь будет ненулевым. Однако find по-прежнему пропускает попытку удалить ".".

[UPDATE]

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

Давайте посмотрим на исходный код утилиты find во FreeBSD:

int
f_delete(PLAN *plan __unused, FTSENT *entry)
{
    /* ignore these from fts */
    if (strcmp(entry->fts_accpath, ".") == 0 ||
        strcmp(entry->fts_accpath, "..") == 0)
        return 1;
...
    /* rmdir directories, unlink everything else */
    if (S_ISDIR(entry->fts_statp->st_mode)) {
        if (rmdir(entry->fts_accpath) < 0 && errno != ENOTEMPTY)
            warn("-delete: rmdir(%s)", entry->fts_path);
    } else {
        if (unlink(entry->fts_accpath) < 0)
            warn("-delete: unlink(%s)", entry->fts_path);
    }
...

Как вы видите, если она не отфильтрует точки и dot-dot, то дойдет до rmdir() C-функции, определенной в unistd.h POSIX.

Проведите простой тест, rmdir с аргументом dot/dot-dot вернет -1:

printf("%d\n", rmdir(".."));

Давайте посмотрим, как POSIX описывает rmdir:

Если аргумент path ссылается на путь, конечным компонентом которого является либо dot, либо dot-dot. dot или dot-dot, rmdir() завершится неудачей.

Причина отказа не была указана.

Я нашел rename объяснение некоторых причинn:

Переименование точек или dot-dot запрещено для предотвращения циклических пути файловой системы.

Циклические пути файловой системы ?

Я просматриваю The C Programming Language (2nd Edition) и ищу тему каталога, на удивление я нашел код похожий:

if(strcmp(dp->name,".") == 0 || strcmp(dp->name,"..") == 0)
    continue;

И комментарий !

Каждый каталог всегда содержит записи для себя, называемые ".", и своего родителя, "."; их нужно пропускать, иначе программа будет циклиться вечно.

"вечный цикл", это похоже на то, как rename описывает "циклические пути файловой системы" выше.

Я немного изменил код и заставил его работать в Kali Linux на основе этого ответа:

#include 
#include 
#include 
#include  
#include 
#include 

void fsize(char *);
void dirwalk(char *, void (*fcn)(char *));

int
main(int argc, char **argv) {
    if (argc == 1)
        fsize(".");
    else
        while (--argc > 0) {
            printf("start\n");
            fsize(*++argv);
        }
    return 0;
}

void fsize(char *name) {
    struct stat stbuf;
    if (stat(name, &stbuf) == -1 )  {
        fprintf(stderr, "fsize: can't access %s\n", name);
        return;
    }
    if ((stbuf.st_mode & S_IFMT) == S_IFDIR)
        dirwalk(name, fsize);
    printf("%81d %s\n", stbuf.st_size, name);
}

#define MAX_PATH 1024
void dirwalk(char *dir, void (*fcn)(char *))
{
    char name[MAX_PATH];
    struct dirent *dp;

    DIR *dfd;

    if ((dfd = opendir(dir)) == NULL) {
            fprintf(stderr, "dirwalk: can't open %s\n", dir);
            return;
    }

    while ((dp = readdir(dfd)) != NULL) {
            sleep(1);
            printf("d_name: S%sG\n", dp->d_name);
            if (strcmp(dp->d_name, ".") == 0
                            || strcmp(dp->d_name, "..") == 0) {
                    printf("hole dot\n");
                    continue;
                    }
            if (strlen(dir)+strlen(dp->d_name)+2 > sizeof(name)) {
                    printf("mocha\n");
                    fprintf(stderr, "dirwalk: name %s/%s too long\n",
                                    dir, dp->d_name);
                    }
            else {
                    printf("ice\n");
                    (*fcn)(dp->d_name);
            }
    }
    closedir(dfd);
}

Давайте посмотрим:

xb@dnxb:/test/dot$ ls -la
total 8
drwxr-xr-x 2 xiaobai xiaobai 4096 Nov 20 04:14 .
drwxr-xr-x 3 xiaobai xiaobai 4096 Nov 20 04:14 ..
xb@dnxb:/test/dot$ 
xb@dnxb:/test/dot$ cc /tmp/kr/fsize.c -o /tmp/kr/a.out 
xb@dnxb:/test/dot$ /tmp/kr/a.out .                     
start
d_name: S..G
hole dot
d_name: S.G
hole dot
                                                                             4096 .
xb@dnxb:/test/dot$ 

Он работает правильно, теперь что если я закомментирую инструкцию continue:

xb@dnxb:/test/dot$ cc /tmp/kr/fsize.c -o /tmp/kr/a.out 
xb@dnxb:/test/dot$ /tmp/kr/a.out .
start
d_name: S..G
hole dot
ice
d_name: S..G
hole dot
ice
d_name: S..G
hole dot
ice
^C
xb@dnxb:/test/dot$

Как вы можете видеть, я должен использовать Ctrl+C, чтобы убить эту программу бесконечного цикла.

Директория '.' считывает свою первую запись '.' и зацикливается до бесконечности.

Вывод:

  1. GNU findutils пытается совместить с find утилитой в *BSD.

  2. find утилита в *BSD внутренне использует rmdir POSIX-совместимую C функцию, которая точка/точка не разрешена.

  3. Причина, по которой rmdir не разрешает точку/точку, заключается в предотвращении циклических путей файловой системы.

  4. Язык программирования C, написанный K&R, показывает пример того, как точка/dot-dot приведет к вечному циклу программы.

2
23.11.2017, 01:35
0 ответов

Теги

Похожие вопросы