Список каталогов в Linux из C - PullRequest
1 голос
/ 09 апреля 2010

Я пытаюсь смоделировать команду linux ls, используя linux api из c. Глядя на код, он имеет смысл, но когда я его запускаю, я получаю «stat error: Нет такого файла или каталога». Я проверил, что opendir работает нормально. Я думаю, что проблема в stat, который возвращает -1, хотя я думаю, что он должен возвращать 0.

Чего мне не хватает?

Спасибо за вашу помощь.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <sys/stat.h>
#include <errno.h>

int main(int argc, char *argv[])
{
 DIR *dirp;
 struct dirent *direntp;
 struct stat stat_buf;
 char *str;

 if (argc != 2)
 {
  fprintf( stderr, "Usage: %s dir_name\n", argv[0]);
  exit(1);
 }

 if ((dirp = opendir( argv[1])) == NULL)
 {
  perror(argv[1]);
  exit(2);
 }

 while ((direntp = readdir( dirp)) != NULL)
 {
  if (stat(direntp->d_name, &stat_buf)==-1)
  {
   perror("stat ERROR");
   exit(3);
  }
  if (S_ISREG(stat_buf.st_mode)) str = "regular";
  else if (S_ISDIR(stat_buf.st_mode)) str = "directory";
  else str = "other";
  printf("%-25s - %s\n", direntp->d_name, str);
 }

 closedir(dirp);
 exit(0);
}

Ответы [ 5 ]

3 голосов
/ 09 апреля 2010

Это потому, что вы не указали фактический файл.Это в другом каталоге.Если вы хотите получить реальное имя файла, объедините argv[1] и direntp->d_name с '/' между ними.

Кроме того, венгерское именование является странным, даже младший бит, такой как 'p' в конце.Если у вас так много переменных, что вам нужно отслеживать их типы в их именах, вы делаете что-то не так.

Вот пересмотренная версия вашей программы:

#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <dirent.h>
#include <sys/stat.h>
#include <errno.h>
#include <limits.h>
#include <sys/param.h>

int main(int argc, char *argv[])
{
 DIR *dirp;
 struct dirent *direntp;
 struct stat stat_buf;
 char *str;
 char fullpath[MAXPATHLEN + 1];
 size_t dirnamelen;

 if (argc != 2)
 {
  fprintf( stderr, "Usage: %s dir_name\n", argv[0]);
  exit(1);
 }
 strncpy(fullpath, argv[1], MAXPATHLEN - 1); /* account for trailing '/' */
 fullpath[MAXPATHLEN - 1] = '\0';
 dirnamelen = strlen(fullpath);
 if (strlen(argv[1]) > dirnamelen) {
  fprintf( stderr, "Directory name is too long: %s", argv[1] );
  exit(2);
 }

 fullpath[dirnamelen++] = '/';
 fullpath[dirnamelen] = '\0';

 if ((dirp = opendir( argv[1])) == NULL)
 {
  perror(argv[1]);
  exit(2);
 }

 while ((direntp = readdir( dirp)) != NULL)
 {
  fullpath[dirnamelen] = '\0';
  if ((dirnamelen + strlen(direntp->d_name)) > MAXPATHLEN) {
   fprintf(stderr, "File %s + directory %s is too long.", direntp->d_name, fullpath);
   continue;
  } else {
   /* strncpy is mild overkill because the if statement has verified that
      there's enough space.  */
   strncpy(fullpath + dirnamelen, direntp->d_name, MAXPATHLEN - dirnamelen);
   fullpath[MAXPATHLEN] = '\0';
  }
  if (stat(fullpath, &stat_buf)==-1)
  {
   perror("stat ERROR");
   exit(3);
  }
  if (S_ISREG(stat_buf.st_mode)) str = "regular";
  else if (S_ISDIR(stat_buf.st_mode)) str = "directory";
  else str = "other";
  printf("%-25s - %s\n", direntp->d_name, str);
 }

 closedir(dirp);
 exit(0);
}

Обратите внимание, чтоЯ использую MAXPATHLEN (из <limits.h>) и тщательно проверяю, чтобы убедиться в отсутствии переполнения буфера.Вы должны сделать то же самое в своем коде.

Редактировать: Изменен код, чтобы использовать strn семейные функции для дополнительной безопасности.

2 голосов
/ 09 апреля 2010

Добавить

#include <unistd.h>
...
chdir(argv[1]);

или вызовите статистику с полным путем *

...
char fullpath[MAXPATHLEN];
snprintf(fullpath, sizeof(fullpath), "%s/%s", argv[1], direntp->d_name);
if (stat(fullpath, &stat_buf) == -1)
...
1 голос
/ 03 апреля 2013

Почему бы вам не попробовать это? Просто укажите путь к argv[1] вот так /home/sabri/Desktop/Test

int main(int argc, char *argv[]) 
{
    struct dirent *direntp;
    DIR *dirp;

    if (argc != 2) 
    {
       fprintf(stderr, "Usage: %s directory_name\n", argv[0]);
       return 1;
    }

if ((dirp = opendir(argv[1])) == NULL) 
{
    perror ("Failed to open directory");
    return 1;
}

while ((direntp = readdir(dirp)) != NULL)
    printf("%s\n", direntp->d_name);

while ((closedir(dirp) == -1) && (errno == EINTR)) ;

return 0;

}

0 голосов
/ 10 апреля 2010

Другие предложили построить полный путь для stat() или использовать chdir(). Оба они будут работать (хотя они и находятся в состоянии гонки, если каталог переименован, когда вы находитесь в процессе его чтения).

Альтернативой, которая не зависит от состояния гонки и, следовательно, возможно, является более "правильной", является использование fstatat(). Просто замените ваш существующий stat() вызов на:

fstatat(dirfd(dirp), direntp->d_name, &stat_buf, 0)

(Метод chdir() можно также сделать свободным от состояния гонки: либо используя fchdir(dirfd(dirp)) вместо chdir(), либо изменив каталог на argv[1], а затем открыв "." с помощью opendir(). Метод построения пути не может быть освобожден от состояния гонки).

0 голосов
/ 09 апреля 2010

Если вы используете Unix, вы можете использовать системную команду.

system("ls -ltr | grep -d");
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...