从C列出Linux中的目录
我正在尝试使用c中的LinuxAPI模拟linux命令ls。看看代码,它确实有道理,但当我运行它时,我得到了stat错误:没有这样的文件或目录。我已经检查了opendir是否正常工作。我认为问题在于stat,它返回-1,尽管我认为它应该返回0 我错过了什么 谢谢你的帮助从C列出Linux中的目录,c,linux,C,Linux,我正在尝试使用c中的LinuxAPI模拟linux命令ls。看看代码,它确实有道理,但当我运行它时,我得到了stat错误:没有这样的文件或目录。我已经检查了opendir是否正常工作。我认为问题在于stat,它返回-1,尽管我认为它应该返回0 我错过了什么 谢谢你的帮助 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <dirent.h> #include &l
#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);
}
加
加
这是因为您没有说明实际的文件。它在另一个目录中。如果需要真实的文件名,请将argv[1]和direntp->d_名称与“/”组合在一起 此外,匈牙利人的名字也很讨厌,甚至连结尾的小调都有点像“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并仔细检查以确保没有任何缓冲区溢出。在代码中也应该这样做
编辑:更改代码以使用strn系列函数以增加安全性。这是因为您没有说明实际的文件。它在另一个目录中。如果需要真实的文件名,请将argv[1]和direntp->d_名称与“/”组合在一起 此外,匈牙利人的名字也很讨厌,甚至连结尾的小调都有点像“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并仔细检查以确保没有任何缓冲区溢出。在代码中也应该这样做
编辑:更改代码以使用strn系列函数以增加安全性。如果在unix上使用,则可以使用system命令
system("ls -ltr | grep -d");
如果在unix上使用,则可以使用system命令
system("ls -ltr | grep -d");
其他人建议为stat构建完整路径,或者使用chdir。这两种方法都会起作用,尽管它们是受竞争条件影响的,如果目录在读的时候被重命名。 另一种选择是使用fstatat,它不受竞争条件的约束,因此可以说更为正确。只需将现有的stat调用替换为:
fstatat(dirfd(dirp), direntp->d_name, &stat_buf, 0)
chdir方法也可以不受竞争条件的限制:使用fchdirfddirp代替chdir,或者将目录更改为argv[1],然后打开。使用opendir。路径名构造方法不能成为无竞争条件的。其他人建议为stat构建完整路径,或者使用chdir。这两种方法都会起作用,尽管它们是受竞争条件影响的,如果目录在读的时候被重命名。 另一种选择是使用fstatat,它不受竞争条件的约束,因此可以说更为正确。只需将现有的stat调用替换为:
fstatat(dirfd(dirp), direntp->d_name, &stat_buf, 0)
chdir方法也可以不受竞争条件的限制:使用fchdirfddirp代替chdir,或者将目录更改为argv[1],然后打开。使用opendir。路径名构造方法不能成为无竞争条件。为什么不试试这个?只需像下面这样给出argv[1]的路径/home/sabri/Desktop/Test
}你为什么不试试这个?只需像下面这样给出argv[1]的路径/home/sabri/Desktop/Test
}为什么不使用snprintf而不是strcpy?@Thomas,原因有二。首先,我可以更准确地报告错误,其次我的方法效率更高。我理解你的观点,但我不认为效率上的微小提高比代码可读性更重要。除了手动处理字符串之外,总是会增加引入错误的风险;更多代码行>更多bug……托马斯,我多年来一直是C++程序员,而且还没有习惯使用STRN函数,因为C++不需要这样的东西::STD::string类型。@ Tuomas,笑错了,这就是我是一个可怕的拷贝编辑器的原因。很抱歉。为什么不使用snprintf而不是strcpy呢?@Thomas,原因有二。首先,我可以更准确地报告错误,其次我的方法效率更高。我理解你的观点,但我不认为效率上的微小提高比代码可读性更重要。除了手动处理字符串之外,总是会增加引入错误的风险;更多代码行>更多bug……托马斯,我多年来一直是C++程序员,而且还没有习惯使用STRN函数,因为C++不需要这样的东西::STD::string类型。@ Tuomas,笑错了,这就是我是一个可怕的拷贝编辑器的原因。很抱歉。可能strn系列功能更适合使用。更少的错误检查。当然,这也使得正确报告一个公认罕见的错误情况变得困难。使用chdir似乎要简单得多。使用它是一种坏习惯吗?@nunos,我不喜欢使用它。这是一种全局变量,我避免使用