stat()提供错误的信息

问题描述 投票:0回答:3

我正在使用循环将目录中每个文件的信息打印出来,以将ls shell函数重新创建为C程序。将程序中的信息与ls命令中的正确信息进行比较时,程序的结果(使用stat())非常错误。

这里是程序的所有代码:

#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <unistd.h>

int main(int argc, char* params[])
{
  void printTable(char filepath[], int s, int b);

    // If no modifiers, send error
    if(argc == 1) {
      printf("Error: no directory specified. \n");
      exit(1);
      return 0;
    }
    // If only a directory is provided
    if(argc ==2) {
      printTable(params[1], 0, 0);
    } // end of argc == 2

    // If there are 4 modifiers
    else if(argc == 4) {
    }
    return 0;
}

void printTable (char filepath[], int s, int b) {
  DIR *dp;
  struct dirent *dir;
  struct stat fileStats;
  if((dp = opendir(filepath)) == NULL) {
    fprintf(stderr, "Cannot open directory. \n");
    exit(1);
  }
  printf("Processing files in the directory: %s\n", filepath);
  printf("inode \t Type \t UID \t GID \t SIZE \t       Filename \t                 Modification date \n");
  while((dir = readdir(dp)) != NULL ) {
    if(dir->d_ino != 0 && fileStats.st_ino > 0 && stat(dir->d_name, &fileStats) < 0) {
      // Print the inode
      printf("%d \t ", fileStats.st_ino);
      // Print type
      if(dir->d_type == DT_BLK)
        printf("BLK \t ");
      else if(dir->d_type == DT_CHR)
        printf("CHR \t ");
      else if(dir->d_type == DT_DIR)
        printf("DIR \t ");
      else if(dir->d_type == DT_FIFO)
        printf("FIFO \t ");
      else if(dir->d_type == DT_LNK)
        printf("LNK \t ");
      else if(dir->d_type == DT_SOCK)
        printf("SOCK \t ");
      else if(dir->d_type == DT_REG)
        printf("REG \t ");
      else
        printf("UNKOWN \t ");
      // Print UID
      printf("%d \t ", fileStats.st_uid);
      // Print GID
      printf("%d \t ", fileStats.st_gid);
      // Print SIZE
      printf("%jd bytes \t ", fileStats.st_size);
      // Print file name
      printf("%25s \t ", dir->d_name);
      // Print date modified
      printf("%20s \n", ctime(&fileStats.st_mtime));
    }
  }
  struct tm *lt = localtime(&fileStats.st_mtime);
  int diff = difftime(time(NULL), mktime(lt));
  printf("%d \n", diff);
  closedir(dp);
}

这是shell命令的结果(此目录与该程序无关):shell output

这是运行程序的结果:

“程序输出”

c directory ls stat
3个回答
0
投票

stat(2)成功返回0,但您正在测试是否为stat(dir->d_name, &fileStats) < 0。因此,每当stat(2) 失败实际统计文件时,您的代码就会输出某些内容。同样,条件的链接方式,fileStats.st_ino > 0是在第一次迭代中涉及未初始化变量的表达式。

stat(2)失败的最可行的原因是您没有列出当前目录。 d_name结构的dirent成员是目录中文件的名称,它不是完整路径,而是相对于目录路径的路径。当您将其传递给stat(2)时,它仅在文件位于进程的当前工作目录(cwd)中时才起作用。如果不是这样,则与您的情况相同,stat(2)调用将失败。您要做的是通过将filepathdir->d_name与路径分隔符/之间的连接来建立完整路径:

char fullpath[PATH_MAX];

sprintf(fullpath, "%s/%s", filepath, dir->d_name);
stat(fullpath, &fileStats);

或者,也可以使用chdir(2)在循环之前更改工作目录:

char olddir[PATH_MAX];

// Save current working directory
getcwd(olddir, PATH_MAX);
// Change working directory to `filepath`
chdir(filepath);

// Do your loop here

// Restore old working directory
chdir(olddir);

现在stat(2)可以正确地使用相对路径,即仅文件名。


2
投票

如果您的平台对POSIX 2008具有足够的支持,则可以使用fstatat()fstatat()函数达到良好的效果。至少在当前版本的BSD,macOS,Linux,AIX,HP-UX,Solaris上有效。

此代码与问题中的代码相似,但是它不会尝试复制其解码文件类型的方式,等等。

dirfd()

请注意,这根本不需要(因此也不需要)使用dirfd()。使用#include <dirent.h> #include <errno.h> #include <fcntl.h> #include <stdio.h> #include <string.h> #include <sys/stat.h> #include <unistd.h> int main(int argc, char **argv) { for (int i = 1; i < argc; i++) { const char *dir = argv[i]; DIR *dp = opendir(dir); if (dp == 0) { fprintf(stderr, "%s: failed to open directory %s: %d %s\n", argv[0], dir, errno, strerror(errno)); continue; } /* dirfd(): POSIX 2008 - OK on BSD, macOS, Linux, AIX, HP-UX, Solaris */ int fd = dirfd(dp); struct dirent *file; while ((file = readdir(dp)) != 0) { struct stat sb; /* 0 argument could be AT_SYMLINK_NOFOLLOW */ if (fstatat(fd, file->d_name, &sb, 0) == 0) { /* Some of the conversion specifiers may be incorrect for some systems */ /* Inode number, size, time in particular */ printf("%10llu %5d %5d %7o %3d %9lld %10ld %10ld %10ld %s/%s\n", sb.st_ino, sb.st_uid, sb.st_gid, sb.st_mode, sb.st_nlink, sb.st_size, sb.st_mtime, sb.st_atime, sb.st_ctime, dir, file->d_name); } else fprintf(stderr, "%s: failed to stat() %s/%s: %d %s\n", argv[0], dir, file->d_name, errno, strerror(errno)); } closedir(dp); } return 0; } 可以指定“解释相对于给定目录的文件名”,其中目录由文件描述符标识。

给出了适当的错误报告程序包(因此程序名称将自动包含在错误中),我将循环体作为函数进行打包。但是,错误消息中的chdir()参考使您感到不便。对于错误报告,我将使用GitHub上fstatat()(堆栈溢出问题)存储库中可用的代码作为argv[0]子目录中的文件SOQstderr.c

示例输出(从Mac上输出-10位inode数大于大多数系统上的数:]

stderr.h

如果您的系统没有src/libsoq,但确实有$ at67 bin ~/src/ule 4296808809 501 20 40755 33 1056 1577029162 1583165629 1577029162 bin/. 4296808746 501 20 40755 208 6656 1583164216 1583165629 1583164216 bin/.. 4296811200 501 20 100755 1 1266 1515986057 1582224384 1582216636 bin/rfn 4296811205 501 20 100755 1 1266 1515986057 1583164235 1582216636 bin/rfn-c 4305347192 501 20 100755 1 246 1524096284 1582224384 1582216636 bin/soqvg 4297537255 501 20 100755 1 3813 1579639563 1582830967 1582216636 bin/pipe-rot 4296811199 501 20 100755 1 233 1515695843 1582224384 1582216636 bin/sow 4298720660 501 20 100755 1 627 1517875149 1582224384 1582216636 bin/so-getchar 4296811201 501 20 100755 1 218 1515695843 1582224384 1582216636 bin/ddpr 4296811210 501 20 100755 1 1266 1515986057 1582224384 1582216636 bin/rfn-pl 4296808811 501 20 100644 1 490 1510874880 1578595253 1510874880 bin/README.md 4296811204 501 20 100755 1 2278 1515695843 1582224384 1582216636 bin/fixin 4296811203 501 20 100755 1 2835 1576997332 1582224384 1582216636 bin/so-books 4296811196 501 20 100755 1 617 1515695843 1582224388 1582216636 bin/wso 4296811197 501 20 100755 1 85 1515695843 1583165629 1582216636 bin/so 4296808810 501 20 100644 1 92 1510874880 1579561480 1510874880 bin/.gitignore 4296811193 501 20 100755 1 200 1515695843 1582224388 1582216636 bin/posixcmd 4296811206 501 20 100755 1 1266 1515986057 1582224384 1582216636 bin/rfn-h 4451766334 501 20 100755 1 507 1576997332 1582224384 1582216636 bin/so-esql 4297012073 501 20 100755 1 937 1582216633 1583164235 1582216636 bin/sscce 4296811202 501 20 100755 1 522 1515695843 1582224384 1582216636 bin/so-late 4296811209 501 20 100755 1 1266 1515986057 1582224384 1582216636 bin/rfn-sql 4297507309 501 20 100755 1 848 1526264352 1582224384 1582216636 bin/so-stderr 4296811194 501 20 100755 1 206 1515695843 1582224388 1582216636 bin/posixfun 4342190418 501 20 100755 1 1227 1541833786 1582224384 1582216636 bin/so-quotes 4298078558 501 20 100755 1 722 1515695843 1582224384 1582216636 bin/soa 4296811198 501 20 100755 1 92 1515695843 1582224384 1582216636 bin/sops 4356366344 501 20 100755 1 454 1545845134 1582644937 1582216636 bin/so-reformat-c 4296811208 501 20 100755 1 1266 1515986057 1582224384 1582216636 bin/rfn-cpp 4298720661 501 20 100755 1 700 1576997332 1582224384 1582216636 bin/so-c-reserved 4296811207 501 20 100755 1 1266 1515986057 1582656633 1582216636 bin/rfn-sh 4296811195 501 20 100755 1 255 1515695843 1582224388 1582216636 bin/posixhdr 4451855327 501 20 100755 1 780 1577029658 1582224384 1582216636 bin/so-dotarrow 4296916142 501 20 40755 15 480 1574117045 1583165629 1574117045 /Users/jonathanleffler/src/ule/. 4296713088 501 20 40755 97 3104 1575746582 1583165539 1575746582 /Users/jonathanleffler/src/ule/.. 4296917945 501 20 100444 1 7 1473056744 1578608259 1510993969 /Users/jonathanleffler/src/ule/ule-test-nnl 4296917947 501 20 100644 1 6148 1418098863 1578608259 1510994007 /Users/jonathanleffler/src/ule/.DS_Store 4296917957 501 20 100755 1 44824 1473056806 1578608437 1513032846 /Users/jonathanleffler/src/ule/ule-v1.4 4296917948 501 20 100444 1 15 1473056679 1578608259 1510993969 /Users/jonathanleffler/src/ule/ule-test-nul 4296917949 501 20 100640 1 43 1418023230 1578608259 1510993969 /Users/jonathanleffler/src/ule/ule-test-mix 4296917951 501 20 100644 1 745 1436058130 1578608259 1510993969 /Users/jonathanleffler/src/ule/ule.notes 4296917952 501 20 100640 1 33 1418023230 1578608259 1510993969 /Users/jonathanleffler/src/ule/ule-test-unx 4296917953 501 20 100640 1 33 1418023230 1578608259 1510993969 /Users/jonathanleffler/src/ule/ule-test-dos 4296917954 501 20 40755 11 352 1541802114 1578608839 1541802114 /Users/jonathanleffler/src/ule/RCS 4441180506 501 20 100444 1 6726 1574116649 1578608259 1574117045 /Users/jonathanleffler/src/ule/ule.c 4296917956 501 20 40755 3 96 1437532230 1578611808 1510994007 /Users/jonathanleffler/src/ule/ule.dSYM 4297282884 501 20 100755 1 60160 1513033250 1582552763 1513033250 /Users/jonathanleffler/src/ule/ule 4296917958 501 20 100640 1 30 1425237329 1578608259 1510993969 /Users/jonathanleffler/src/ule/ule-test-mac $ ,则可以使用这些功能来打开和关闭目录。 (上面代码的早期修订版使用了此代码的变体-但配置起来很快会很混乱,并且dirfd()使得所有这些都不必要。)您可以使用fstatat()代替dirfd(),并在dir_open(dir)之前或之后添加dirfd(dp)

dir_close(fd)

[如果您的系统具有closedir(dp),请使用它代替#include <fcntl.h> #include <unistd.h> int dir_open(const char *name) { return open(name, O_RDONLY | O_DIRECTORY); } int dir_close(int fd) { return close(fd); } (例如,在我进行测试的macOS Mojave 10.14.6中,O_SEARCH不可用)。如果您的系统没有O_RDONLY,请省略该术语。这些只是使配置变得混乱的一些细节。

[总体来说,如果您有O_SEARCH,您也可能也有O_DIRECTORY


0
投票
fstatat()

应该是

dirfd()

仅在出现错误时才打印内容。

stat(dir->d_name, &fileStats) < 0 返回:

成功时返回零。发生错误时,返回-1,而errno为设置适当。

© www.soinside.com 2019 - 2024. All rights reserved.