Проверьте, является ли файл каталогом или нет

Программа:

#include<stdio.h>
#include<stdlib.h>
#include<dirent.h>
#include<sys/stat.h>
int main(int argc, char *argv[])
{
    DIR *dp;
    struct dirent *dirp;
    struct stat stbuf;
    if (argc != 2)
        printf("usage: ls directory_name\n");

    if ((dp = opendir(argv[1])) == NULL)
        printf("can’t open %s", argv[1]);

    while ((dirp = readdir(dp)) != NULL){
        stat(dirp->d_name,&stbuf);
        if(S_ISDIR(stbuf.st_mode)){
            printf("Directory: ");
        }
        printf("%s\n",dirp->d_name);
    }

    closedir(dp);
    exit(0);
}

Вывод:

$ ./a.out test/
dir3
d
c
Directory: .
Directory: a
Directory: ..
Directory: dir4
Directory: dir2
Directory: dir0
Directory: b
Directory: e
Directory: dir1
$

Ниже приведен список файлов, которые содержит каталог «test».

$ ls -F test/
a  b  c  d  dir0/  dir1/  dir2/  dir3/  dir4/  e
$ 

Ожидаемый вывод: если файл является каталогом, вывод будет «Каталог: dir1/». Остальное только имя файла. Но вывод программы не такой, как ожидалось. Программа содержит какую-либо ошибку?. Есть ли дайте мне знать.

Заранее спасибо...


c ls
person mohangraj    schedule 18.08.2015    source источник
comment
возможный дубликат Доступ к каталогам в C   -  person Kninnug    schedule 18.08.2015
comment
(1) Вам нужно проверить возвращаемое значение из stat(), чтобы увидеть, есть ли какие-либо ошибки. (2) Вы звоните stat() (например) dir2, но вам нужно передать test/dir2.   -  person psmears    schedule 18.08.2015
comment
Я предлагаю вам проверить, что stat возвращает, я готов поспорить, что это -1 (что означает, что это не удалось) для большинства имен.   -  person Some programmer dude    schedule 18.08.2015
comment
@JoachimPileborg Да, статистика возвращает -1. Но тест каталога доступен в моем текущем рабочем каталоге. Тогда как стат возвращает -1.   -  person mohangraj    schedule 18.08.2015
comment
@mohanraj Да, но это потому, что вы пытаетесь получить доступ, например. файл a в рабочем каталоге процесса (в котором вы запустили программу), а не в каталоге test. Прочитайте комментарий psmears более внимательно.   -  person Some programmer dude    schedule 18.08.2015


Ответы (1)


Разобьем на этапы:

  1. Вы запускаете свою программу из некоторого каталога. Этот каталог станет текущим рабочим каталогом процесса (CWD).

  2. Вы звоните opendir в каталог test. На самом деле это каталог test в CWD.

  3. Вы вызываете readdir, чтобы получить первую запись в справочнике.

  4. Эта первая запись — это каталог ., который является сокращением от текущий каталог, он есть во всех каталогах.

  5. Вы звоните stat с помощью ., то есть звоните stat по CWD. Это, конечно, удается, и stat заполняет структуру всеми деталями CWD.

  6. На следующей итерации вы получаете запись a и вызываете stat для этой записи. Однако, поскольку в CWD нет a, вызов stat завершается ошибкой. Однако вы не проверяете это и используете структуру stat, которая была заполнена из предыдущего вызова (из успешного stat каталога .).

И так далее...

Вам нужно указать stat искать записи в заданном каталоге, а не в CWD. В основном это можно сделать только двумя способами:

  • Отформатируйте строку так, чтобы перед записью стоял каталог, который вы передали opendir. Например.

    char path[PATH_MAX];
    snprintf(path, sizeof(path), "%s/%s", argv[1] ,dirp->p_name);
    if (stat(path, &stbuf) != -1)
    {
        // `stat` call succeeded, do something
    }
    
  • После вызова opendir, но до зацикливания этого каталога, измените CWD:

    // Opendir call etc...
    
    chdir(argv[1]);
    
    // Loop using readdir etc.
    

В качестве альтернативы запустите программу из каталога, который вы хотите проверить:

$ cd test
$ ../a.out .
person Some programmer dude    schedule 18.08.2015