Ошибка stat() «Нет такого файла или каталога», когда имя файла возвращается функцией readdir()

Я не могу определить ошибку, выдаваемую stat. Следующая программа читает все файлы в каталоге и печатает имя файла:

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

Пример вывода:

/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 

Вот содержание:

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

person John    schedule 26.02.2011    source источник
comment
Можете ли вы распечатать d_name для недопустимых файлов? Кроме того, что это за файлы в этом каталоге? Т.е. мы должны увидеть, каких файлов не хватает.   -  person chrisaycock    schedule 26.02.2011
comment
я изменил вопрос. У меня есть вывод команды ls.   -  person John    schedule 26.02.2011
comment
См. также Как я могу получить список файлов в каталоге, используя C или C++.   -  person Jonathan Leffler    schedule 25.12.2014


Ответы (2)


dirp->d_name — это имя файла в каталоге: например, "udpclient.c". Таким образом, полное имя файла — "/home/eipe/c/udpclient.c", но ваш текущий рабочий каталог — /home/eipe, поэтому stat() пытается получить доступ к несуществующему "/home/eipe/udpclient.c".

Вы можете либо изменить свой рабочий каталог на argv[1], используя chdir(), либо добавить argv[1] к каждому имени файла перед вызовом stat().

person caf    schedule 26.02.2011

Обратите внимание, что в POSIX 2008 представлены fstatat() и связанные с ними функции (системные вызовы), все они отличаются суффиксом at к знакомому имени функции. Он также определяет dirfd() для получения дескриптора файла, связанного с потоком каталога. .

Функции *at() принимают один (или два в случае renameat()) дескриптора открытого файла, который ссылается на каталог. Это означает, что другим способом кодирования этого в системе, поддерживающей fstatat(), будет:

const char *name = argv[i];

DIR *dp = opendir(dirname);
if (dp == NULL)
{
    fprintf(stderr, "failed to open directory %s (%d: %s)\n",
            name, errno, strerror(errno));
    return -1;
}

int dfd = dirfd(dp);    /* Very, very unlikely to fail */

struct dirent *dirp;
while ((dirp = readdir(dp)) != NULL)
{
    struct stat sb;
    if (fstatat(dfd, dirp->d_name, &sb, 0) == -1) {
        fprintf(stderr, "fstatat(\"%s/%s\") failed (%d: %s)\n",
                name, dirp->d_name, errno, strerror(errno));
    }
    else
        printf("%-20s %s/%s\n", "File name:", name, dirp->d_name);
}

Использование fstatat() и связанных функций позволяет использовать относительные пути без использования chdir() (что опасно; трудно вернуться к тому, с чего вы начали, не используя fchdir() ) или объединение имен, как показано в основном принятом ответе. Для переносимости в любом случае рекомендуется использовать конкатенацию, но я смог протестировать это на Mac OS X (10.10.1) и Linux (Ubuntu 14.04), используя приведенный ниже код.

Превратилась в полную программу (test-fstatat.c):

/* SO 0512-5919 */
#define _XOPEN_SOURCE 700   /* POSIX 2008 plus ... */
#include <dirent.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>

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++)
    {
        const char *name = argv[i];

        DIR *dp = opendir(name);
        if (dp == NULL)
        {
            fprintf(stderr, "failed to open directory %s (%d: %s)\n",
                    name, errno, strerror(errno));
            return -1;
        }

        int dfd = dirfd(dp);    /* Very, very unlikely to fail */

        printf("%-20s %s\n", "Directory:", name);

        struct dirent *dirp;
        while ((dirp = readdir(dp)) != NULL)
        {
            struct stat sb;
            if (fstatat(dfd, dirp->d_name, &sb, 0) == -1) {
                fprintf(stderr, "fstatat(\"%s/%s\") failed (%d: %s)\n",
                        name, dirp->d_name, errno, strerror(errno));
            }
            else
                printf("%-20s %s/%s\n", "File name:", name, dirp->d_name);
        }

        closedir(dp);
    }
    return 0;
}

Пример запуска:

$ test-fstatat ~/bin/JLSS-Dist/RCS ../../../src/sqltools/idsmon
Directory:           /Users/jonathanleffler/bin/JLSS-Dist/RCS
File name:           /Users/jonathanleffler/bin/JLSS-Dist/RCS/.
File name:           /Users/jonathanleffler/bin/JLSS-Dist/RCS/..
File name:           /Users/jonathanleffler/bin/JLSS-Dist/RCS/mkbod.sh,v
File name:           /Users/jonathanleffler/bin/JLSS-Dist/RCS/jlssdist.jdc,v
File name:           /Users/jonathanleffler/bin/JLSS-Dist/RCS/old.msd.sh,v
File name:           /Users/jonathanleffler/bin/JLSS-Dist/RCS/chksumtool.pl,v
File name:           /Users/jonathanleffler/bin/JLSS-Dist/RCS/msd2nmd.pl,v
File name:           /Users/jonathanleffler/bin/JLSS-Dist/RCS/mknmd.sh,v
File name:           /Users/jonathanleffler/bin/JLSS-Dist/RCS/publictimestamp.sh,v
File name:           /Users/jonathanleffler/bin/JLSS-Dist/RCS/new.mknmd.sh,v
File name:           /Users/jonathanleffler/bin/JLSS-Dist/RCS/PRODCODE,v
File name:           /Users/jonathanleffler/bin/JLSS-Dist/RCS/prodverstamp.sh,v
File name:           /Users/jonathanleffler/bin/JLSS-Dist/RCS/md5.create.pl,v
File name:           /Users/jonathanleffler/bin/JLSS-Dist/RCS/jdcrelease.sh,v
File name:           /Users/jonathanleffler/bin/JLSS-Dist/RCS/JLSS-Dist.mk,v
File name:           /Users/jonathanleffler/bin/JLSS-Dist/RCS/PRODUCT,v
File name:           /Users/jonathanleffler/bin/JLSS-Dist/RCS/msd.create.sh,v
File name:           /Users/jonathanleffler/bin/JLSS-Dist/RCS/distribution.mk,v
File name:           /Users/jonathanleffler/bin/JLSS-Dist/RCS/nmd.create.sh,v
File name:           /Users/jonathanleffler/bin/JLSS-Dist/RCS/jlss.sh,v
File name:           /Users/jonathanleffler/bin/JLSS-Dist/RCS/VERSION,v
File name:           /Users/jonathanleffler/bin/JLSS-Dist/RCS/cvtjdc.sh,v
File name:           /Users/jonathanleffler/bin/JLSS-Dist/RCS/redonmd.sh,v
File name:           /Users/jonathanleffler/bin/JLSS-Dist/RCS/updmsd.sh,v
File name:           /Users/jonathanleffler/bin/JLSS-Dist/RCS/setnmd.sh,v
File name:           /Users/jonathanleffler/bin/JLSS-Dist/RCS/list2msd.pl,v
File name:           /Users/jonathanleffler/bin/JLSS-Dist/RCS/chkmsdnmd.sh,v
File name:           /Users/jonathanleffler/bin/JLSS-Dist/RCS/vercmp.pl,v
File name:           /Users/jonathanleffler/bin/JLSS-Dist/RCS/MSD.sh,v
File name:           /Users/jonathanleffler/bin/JLSS-Dist/RCS/setjdcversion.sh,v
File name:           /Users/jonathanleffler/bin/JLSS-Dist/RCS/sortnmd.sh,v
File name:           /Users/jonathanleffler/bin/JLSS-Dist/RCS/gennmd.sh,v
File name:           /Users/jonathanleffler/bin/JLSS-Dist/RCS/md5.verify.pl,v
File name:           /Users/jonathanleffler/bin/JLSS-Dist/RCS/setbomversion.sh,v
File name:           /Users/jonathanleffler/bin/JLSS-Dist/RCS/chkbodlst.sh,v
File name:           /Users/jonathanleffler/bin/JLSS-Dist/RCS/updnmd.sh,v
File name:           /Users/jonathanleffler/bin/JLSS-Dist/RCS/domsd.sh,v
File name:           /Users/jonathanleffler/bin/JLSS-Dist/RCS/md5.chksum.pl,v
File name:           /Users/jonathanleffler/bin/JLSS-Dist/RCS/bomrelease.pl,v
File name:           /Users/jonathanleffler/bin/JLSS-Dist/RCS/mkmsd.sh,v
File name:           /Users/jonathanleffler/bin/JLSS-Dist/RCS/fixnmd.sh,v
Directory:           ../../../src/sqltools/idsmon
File name:           ../../../src/sqltools/idsmon/.
File name:           ../../../src/sqltools/idsmon/..
File name:           ../../../src/sqltools/idsmon/idstest.c
File name:           ../../../src/sqltools/idsmon/idslen
File name:           ../../../src/sqltools/idsmon/install-sh
File name:           ../../../src/sqltools/idsmon/scatterinfo
File name:           ../../../src/sqltools/idsmon/ltmain.sh
File name:           ../../../src/sqltools/idsmon/idsmon.msd
File name:           ../../../src/sqltools/idsmon/idsmon.o
File name:           ../../../src/sqltools/idsmon/configure
File name:           ../../../src/sqltools/idsmon/genscatter
File name:           ../../../src/sqltools/idsmon/config
File name:           ../../../src/sqltools/idsmon/idspacket
File name:           ../../../src/sqltools/idsmon/genconnpacket
File name:           ../../../src/sqltools/idsmon/Makefile
File name:           ../../../src/sqltools/idsmon/config.h.in
File name:           ../../../src/sqltools/idsmon/config.guess
File name:           ../../../src/sqltools/idsmon/depcomp
File name:           ../../../src/sqltools/idsmon/sqlihexdump.o
File name:           ../../../src/sqltools/idsmon/missing
File name:           ../../../src/sqltools/idsmon/install.mk
File name:           ../../../src/sqltools/idsmon/sqlihexdump
File name:           ../../../src/sqltools/idsmon/RCS
File name:           ../../../src/sqltools/idsmon/Makefile.am
File name:           ../../../src/sqltools/idsmon/test.istar.logs.tar.gz
File name:           ../../../src/sqltools/idsmon/idstest.o
File name:           ../../../src/sqltools/idsmon/esqlc.mk
File name:           ../../../src/sqltools/idsmon/config.sub
File name:           ../../../src/sqltools/idsmon/idspacket.o
File name:           ../../../src/sqltools/idsmon/compile
File name:           ../../../src/sqltools/idsmon/Old.Releases
File name:           ../../../src/sqltools/idsmon/esqlc-nosfx.mk
File name:           ../../../src/sqltools/idsmon/osiris_11
File name:           ../../../src/sqltools/idsmon/config.h.in~
File name:           ../../../src/sqltools/idsmon/idstest
File name:           ../../../src/sqltools/idsmon/idsmon.c
File name:           ../../../src/sqltools/idsmon/acr.decode
File name:           ../../../src/sqltools/idsmon/sqlihexdump.dSYM
File name:           ../../../src/sqltools/idsmon/toru.istar
File name:           ../../../src/sqltools/idsmon/dumpdblflt
File name:           ../../../src/sqltools/idsmon/sqlipacket.c
File name:           ../../../src/sqltools/idsmon/toru
File name:           ../../../src/sqltools/idsmon/data.info.tgz
File name:           ../../../src/sqltools/idsmon/idsmon.nmd
File name:           ../../../src/sqltools/idsmon/idsmon.jdc
File name:           ../../../src/sqltools/idsmon/idsmon
File name:           ../../../src/sqltools/idsmon/idsmon.black_19
File name:           ../../../src/sqltools/idsmon/Makefile.in
File name:           ../../../src/sqltools/idsmon/aclocal.m4
File name:           ../../../src/sqltools/idsmon/sqlihexdump.c
File name:           ../../../src/sqltools/idsmon/dumpdblflt.dSYM
File name:           ../../../src/sqltools/idsmon/dumpdblflt.c
$
person Jonathan Leffler    schedule 24.12.2014