سؤال

I am writing a program to mimic some of the behavior of find that walks a directory tree and calls lstat on the files it finds there to determine their type. The real find will ignore files where the user does not have R or X access in that directory. I can't seem to replicate this behavior; my code will go ahead and make the lstat call and get an Illegal seek error (which is what I'm trying to prevent) even though the code that performs this is inside a block that checks access().

My first thought was that perhaps the second access() call should be on the path and not path/filename, but that didn't seem to work either (and isn't it redundant anyway?)

Any guidance would be greatly appreciated.

My code (I'm cutting out error catching and other stuff for brevity):

    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;
    }
هل كانت مفيدة؟

المحلول

lstat() should never return ESPIPE (Illegal seek). Are you sure it isn't another syscall that is returning that, or a unchanged errno value after a successful lstat()? (In other words, the bug may actually be in your error-checking code that you've elided).

That said, there is no point in using access() in this way anyway - it just introduces a race condition (because the file permissions could change between the access() call and the opendir() / lstat() call), and doesn't gain anything. Simply check the return value of opendir() and lstat() instead:

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;
}

This is generally the right pattern - rather than checking to see if the operation might work and then trying the operation, instead try the operation unconditionally and then check why it failed.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top