我正在使用循环将目录中每个文件的信息打印出来,以将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
这是运行程序的结果:
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)
调用将失败。您要做的是通过将filepath
和dir->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)
可以正确地使用相对路径,即仅文件名。
如果您的平台对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]
子目录中的文件SOQ和stderr.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
。
fstatat()
应该是
dirfd()
仅在出现错误时才打印内容。
stat(dir->d_name, &fileStats) < 0
返回:
成功时返回零。发生错误时,返回-1,而errno为设置适当。