Linux, C: access () не улавливает проблемы с разрешениями, или что-то - PullRequest
3 голосов
/ 27 февраля 2012

Я пишу программу, имитирующую некоторые действия find, которая обходит дерево каталогов и вызывает lstat для файлов, которые там находят, чтобы определить их тип.Реальный find будет игнорировать файлы, в которых у пользователя нет доступа R или X в этом каталоге.Я не могу воспроизвести это поведение;мой код выполнит вызов lstat и получит ошибку незаконного поиска (что я и пытаюсь предотвратить), даже если код, выполняющий это, находится внутри блока, проверяющего access().

Моей первой мыслью было, что, возможно, второй access() вызов должен быть по пути, а не по пути / имени файла, но, похоже, это тоже не сработало (и разве это не избыточно?)

Будем весьма благодарны за любые указания.

Мой код (я сокращаю ошибки и другие мелочи для краткости):

    void open_dir( char *dir, char *pattern, char type )
    {
        DIR *d;
        struct dirent *de;

        if ( access(dir, (R_OK | X_OK)) == 0 )
        {
            d = opendir(dir);

            while( ( de = readdir(d) ) )
                examine_de( de, dir, pattern, type );

            closedir(d);
        }
    }

    void examine_de( struct dirent *de, char *dir, char *pattern, char type )
    {
        char fn[ _POSIX_PATH_MAX ];
        strcpy(fn, dir);
        strcat(fn, "/");
        strcat(fn, de->d_name);

        if ( access(fn, (R_OK | X_OK)) == 0 )
        {
            struct stat buf;
            lstat(fn, &buf);
            //check pattern matches, etc., printf fn if appropriate
            if ( ( S_ISDIR(buf.st_mode) ) &&
                 ( strcmp(de->d_name, ".") != 0 ) &&
                 ( strcmp(de->d_name, "..") != 0 ) )
                open_dir(fn, pattern, type);
        }
        return;
    }

1 Ответ

4 голосов
/ 27 февраля 2012

lstat() следует никогда вернуть ESPIPE (незаконный поиск).Вы уверены, что это не другой системный вызов, который возвращает это, или неизменное значение errno после успешного lstat()?(Другими словами, ошибка может на самом деле быть в вашем коде проверки ошибок, который вы удалили).

Тем не менее, нет никакого смысла использовать access() в любом случае - он просто вводитсостояние гонки (поскольку права доступа к файлу могут меняться между вызовом access() и вызовом opendir() / lstat()), и ничего не получает.Просто проверьте возвращаемое значение opendir() и lstat() вместо:

void open_dir( char *dir, char *pattern, char type )
{
    DIR *d;
    struct dirent *de;

    if (d = opendir(dir))
    {
        while( ( de = readdir(d) ) )
            examine_de( de, dir, pattern, type );

        closedir(d);
    }
}

void examine_de( struct dirent *de, char *dir, char *pattern, char type )
{
    char fn[ _POSIX_PATH_MAX ];
    struct stat buf;

    strcpy(fn, dir);
    strcat(fn, "/");
    strcat(fn, de->d_name);

    if (lstat(fn, &buf) == 0)
    {
        //check pattern matches, etc., printf fn if appropriate
        if ( ( S_ISDIR(buf.st_mode) ) &&
             ( strcmp(de->d_name, ".") != 0 ) &&
             ( strcmp(de->d_name, "..") != 0 ) )
            open_dir(fn, pattern, type);
    }
    return;
}

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

...