简体   繁体   中英

Infinite recursion while listing directories in linux

I try to write program where part of it is listing all directories (especially starting from /), but I have a problem with /proc/self which is infinitely recursive (I get /proc/self/task/4300/fd/3/proc/self/task/4300/fd/3/proc/self/task/4300/fd/3/proc/... and so on). What is nice way to deal with it?

EDIT: Program is written in C language and I use opendir(), readdir()

You can use the S_ISLNK macro to test the st_mode field returned by a call to lstat. If the file is a symbolic link, do not try to follow it.

[user@machine:~]:./list | grep link
/proc/mounts is a symbolic link
/proc/self is a symbolic link

Example code

#include <stdio.h>     // For perror
#include <stdlib.h>
#include <sys/types.h> // For stat, opendir, readdir
#include <sys/stat.h>  // For stat
#include <unistd.h>    // For stat
#include <dirent.h>    // For opendir, readdir

const char *prefix = "/proc";

int main(void)
{
    DIR *dir;
    struct dirent *entry;
    int result;
    struct stat status;
    char path[PATH_MAX];

    dir = opendir(prefix);
    if (!dir)
    {
        perror("opendir");
        exit(1);
    }

    entry = readdir(dir);
    while (entry)
    {
        result = snprintf(path, sizeof(path), "%s", prefix);
        snprintf(&path[result], sizeof(path) - result, "/%s", entry->d_name);
        printf("%s", path);

        result = lstat(path, &status);
        if (-1 == result)
        {
            printf("\n");
            perror("stat");
            exit(2);
        }

        if (S_ISLNK(status.st_mode))
        {
            printf("%s", " is a symbolic link");
        }

        printf("\n");

        entry = readdir(dir);
    }

    return(0);
}

From path_resolution(7) :

Length limit
   There  is  a maximum length for pathnames.  If the pathname (or some intermediate pathname obtained while resolving symbolic links) is too long, an ENAMETOOLONG error
   is returned ("File name too long").

I think you should employ similar behaviour: check for too long pathnames.

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/param.h>

/*  Short & sweet recursive directory scan, finds regular files only.
    Good starting point, should work on Linux OS.
    Pass the root path, and returns number of dirs and number of files
    found.
*/
char *tree_scan( const char *path, int *ndirs, int *nfiles){

    DIR             *dir;
    struct dirent   *entry;
    char            spath[MAXPATHLEN] = "";

    if( !(dir = opendir( path))){ perror("opendir"); exit(1);}

    for( entry = readdir( dir); entry; entry = readdir( dir)){

        sprintf( spath, "%s/%s", path, entry->d_name);
        if( entry->d_type == DT_REG){ (*nfiles)++; printf( "%s\n", spath);}
        if( entry->d_type == DT_DIR &&
            (strcmp( ".", entry->d_name)) &&
            (strcmp( "..", entry->d_name))){
            (*ndirs)++; tree_scan( spath, ndirs, nfiles);
        }
    }

closedir( dir);

return(0);

}

/* Call it like so */

int i = 0, l = 0;
tree_scan( "/path", &i, &l);
printf("Scanned %d directories, %d files.\n", i, l);

I don't have a *nix terminal handy, but you could always take a look at the source for ls.c and see how it's done.

The source as part of the gnu core utils can be found here .

I created a ls clone a few years ago in school, and I think I got around it by watching the pathname size as ulidtko mentioned.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM