errore stat () ‘Nessun file o directory’ quando il nome del file viene restituito da readdir ()

Non sono in grado di identificare l’errore generato dalle statistiche. Il seguente programma legge tutti i file in una directory e stampa il nome del file:

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

Uscita di esempio:

 /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 

Ecco i contenuti:

 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 è il nome del file nella directory : ad esempio, "udpclient.c" . Il nome completo del file è quindi "/home/eipe/c/udpclient.c" – ma la directory di lavoro corrente è /home/eipe , quindi stat() sta tentando di accedere a "/home/eipe/udpclient.c" , che non esiste.

Puoi cambiare la tua directory di lavoro in argv[1] usando chdir() , oppure puoi anteporre argv[1] a ciascun nome di file prima di chiamare stat() .

Si noti che POSIX 2008 introduce fstatat() e funzioni correlate (chiamate di sistema), tutte contraddistinte dal suffisso a un nome di funzione familiare. Queste funzioni accettano uno (o due nel caso di renameat() ) descrittori di file aperti che fanno riferimento a una directory. Ciò significa che un altro modo di codificare questo, su un sistema che supporta fstatat() sarebbe:

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

L’uso di fstatat() e delle funzioni correlate ti permette di usare i relativi nomi di percorso senza usare chdir() (che è pericoloso, è difficile tornare a dove hai iniziato senza usare fchdir() ), o concatenare i nomi come mostrato nella risposta accettata principale . Per quanto riguarda la portabilità, è comunque consigliabile comunque utilizzare la concatenazione – ma sono stato in grado di testarlo su Mac OS X (10.10.1) e Linux (Ubuntu 14.04), utilizzando il codice seguente.

Sviluppato in un programma 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; } 

Esempio di esecuzione:

 $ 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 $