error stat () ‘No such archivo or directory’ cuando el nombre de archivo es devuelto por readdir ()

No puedo identificar el error arrojado por stat. El siguiente progtwig lee todos los archivos en un directorio e imprime el nombre del archivo:

DIR *dp; struct dirent *dirp; struct stat sb; if((dp = opendir(argv[1]))==NULL) { perror("can't open dir"); } while((dirp = readdir(dp))!=NULL) { if (stat(dirp->d_name, &sb) == -1) { perror("stat"); } printf("File name: %s \n",dirp->d_name); } 

Muestra de salida:

 /home/eipe stat error: No such file or directory File name: copyofsample File name: a.out File name: . stat error: No such file or directory File name: udpclient.c File name: .. stat error: No such file or directory File name: client.c stat error: No such file or directory File name: ftpclient.c 

Aquí están los contenidos:

 ls -l /home/eipe/c -rwxr-xr-x 1 eipe egroup 7751 2011-02-24 15:18 a.out -rw-r--r-- 1 eipe egroup 798 2011-02-24 13:50 client.c -rw-r--r-- 1 eipe egroup 15 2011-02-24 15:34 copyofsample -rw-r--r-- 1 eipe egroup 1795 2011-02-24 15:33 ftpclient.c -rw-r--r-- 1 eipe egroup 929 2011-02-24 13:34 udpclient.c 

dirp->d_name es el nombre del archivo en el directorio : por ejemplo, "udpclient.c" . El nombre completo del archivo es así "/home/eipe/c/udpclient.c" – pero su directorio de trabajo actual es /home/eipe , por lo que stat() está intentando acceder a "/home/eipe/udpclient.c" que no existe

Puede cambiar su directorio de trabajo a argv[1] usando chdir() , o puede anteponer argv[1] a cada nombre de archivo antes de llamar a stat() .

Tenga en cuenta que POSIX 2008 presenta fstatat() y funciones relacionadas (llamadas al sistema), todas ellas distinguidas por el sufijo at en un nombre de función familiar. Estas funciones toman uno (o dos en el caso de renameat() ) abren descriptores de archivo que hacen referencia a un directorio. Esto significa que otra forma de codificar esto, en un sistema que admite fstatat() sería:

 DIR *dp; struct dirent *dirp; struct stat sb; int dfd = open(argv[1], O_RDONLY); if (dfd == -1) { fprintf(stderr, "Failed to open directory %s for reading (%d: %s)\n", argv[1], errno, strerror(errno)); return -1; } if ((dp = opendir(argv[1]))==NULL) { perror("can't open dir"); return -1; } while ((dirp = readdir(dp)) != NULL) { if (fstatat(dfd, dirp->d_name, &sb, 9) == -1) { fprintf(stderr, "fstatat(\"%s\") failed (%d: %s)\n", dirp->d_name, errno, strerror(errno)); } printf("%-20s %s\n", "File name:", dirp->d_name); } 

El uso de fstatat() y funciones relacionadas le permite usar nombres de ruta relativos sin usar chdir() (que es peligroso; es difícil volver a donde comenzó sin usar fchdir() ), o concatenar nombres como se muestra en la respuesta principal aceptada . Para la portabilidad, probablemente sea aconsejable utilizar la concatenación de todos modos, pero pude probar esto en Mac OS X (10.10.1) y Linux (Ubuntu 14.04), usando el siguiente código.

Desarrollado en un progtwig completo ( test-fstatat.c ):

 #define _XOPEN_SOURCE 700 #include  #include  #include  #include  #include  #include  #include  int main(int argc, char **argv) { if (argc < 2) { fprintf(stderr, "Usage: %s directory [...]\n", argv[0]); return -1; } for (int i = 1; i < argc; i++) { DIR *dp; struct dirent *dirp; struct stat sb; int dfd = open(argv[i], O_RDONLY); if (dfd == -1) { fprintf(stderr, "Failed to open directory %s for reading (%d: %s)\n", argv[i], errno, strerror(errno)); continue; } if (fstat(dfd, &sb) != 0 || !S_ISDIR(sb.st_mode)) { errno = ENOTDIR; fprintf(stderr, "%s: %d %s\n", argv[i], errno, strerror(errno)); continue; } if ((dp = opendir(argv[i]))==NULL) { perror("can't open dir"); continue; } printf("%-20s %s\n", "Directory:", argv[i]); while ((dirp = readdir(dp)) != NULL) { if (fstatat(dfd, dirp->d_name, &sb, 0) == -1) { fprintf(stderr, "fstatat(\"%s\") failed (%d: %s)\n", dirp->d_name, errno, strerror(errno)); continue; } printf("%-20s %s\n", "File name:", dirp->d_name); } closedir(dp); close(dfd); } return 0; } 

Muestra de ejecución:

 $ test-fstatat ~/bin/JLSS-Dist/RCS ../src/sqltools/idsmon Directory: /Users/jleffler/bin/JLSS-Dist/RCS File name: . File name: .. File name: bomrelease.pl,v File name: chkbodlst.sh,v File name: chkmsdnmd.sh,v File name: chksumtool.pl,v File name: jdcrelease.sh,v File name: JLSS-Dist.mk,v File name: jlss.sh,v File name: mkbod.sh,v File name: mkmsd.sh,v File name: mknmd.sh,v File name: msd.create.sh,v File name: MSD.sh,v File name: prodverstamp.sh,v File name: publictimestamp.sh,v File name: redonmd.sh,v Directory: ../src/sqltools/idsmon File name: . File name: .. File name: acsetup.sh File name: dumpdblflt File name: dumpdblflt.c File name: idsmon File name: idsmon.o File name: idspacket File name: idspacket.c File name: idspacket.o File name: idstest File name: idstest.c File name: idstest.o $