我正在尝试编写类似 ls 的程序,该程序会产生ls -l
带有权限、所有者、时间和文件名称的输出。如果我通过.
(或什么都不通过),它会很好用,所以它适用于当前目录。但是,如果我将任何其他目录传入或传出当前目录,则perror
表示它“无法访问”这些文件。
请帮我弄清楚是什么阻止lstat
了访问另一个目录中的文件。
我使用 gcc 和一个文本编辑器,没有 IDE,开始学习使用 gdb(尝试调试但没有找到可以指出我应该寻找哪种解决方案的东西)。这就是为什么我决定把所有代码放在这里,这样任何人都可以运行它。也许我传递了错误的论点,也许是某种lstat
错误的行为,我不知道。我一直试图在网上找到一些关于它的东西,但没有结果。
这是我到目前为止所做的:
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h> // open()
#include <unistd.h> // close()
#include <sys/param.h>
#include <string.h>
#include <limits.h> // PATH_MAX
#include <pwd.h> // structure for getpwuid()
#include <grp.h> // structure for getgrgid()
#include <time.h> // ctime()
static void ls(const char *dir);
void get_info(const char *name, int offset);
int get_maxsize(const char *name);
int main(int argc, char ** argv)
{
if (argc == 1)
ls(".");
else
while (--argc > 0)
ls(*++argv);
return 0;
}
static void ls(const char *dir)
{
struct dirent * entry;
DIR *d = opendir(dir);
char pathbuf[PATH_MAX + 1];
int offset = 0;
if (d == 0) {
perror("ls");
return;
}
/* find max file size for better ls-alike output */
while ((entry = readdir(d)) != NULL) {
realpath(entry->d_name, pathbuf);
/* pathbuf OR entry->d_name here: */
if (get_maxsize(entry->d_name) > offset)
offset = get_maxsize(pathbuf);
}
closedir(d);
d = opendir(dir);
while ((entry = readdir(d)) != NULL) {
/* pathbuf OR entry->d_name here: */
realpath(entry->d_name, pathbuf);
get_info(entry->d_name, offset);
}
closedir(d);
}
void get_info(const char *name, int offset)
{
struct stat statbuf;
struct passwd *pwdPtr;
struct group *grpPtr;
int length = 0;
char *time = NULL;
/* skip . and .. dirs */
if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
return;
if (lstat(name, &statbuf) == -1) {
fprintf(stderr, "can't access %s\n", name);
perror("get_info");
return;
}
else
switch (statbuf.st_mode & S_IFMT) {
case S_IFREG: printf("-"); break;
case S_IFDIR: printf("d"); break;
case S_IFCHR: printf("c"); break;
case S_IFBLK: printf("b"); break;
case S_IFLNK: printf("l"); break;
case S_IFSOCK: printf("s"); break;
case S_IFIFO: printf("p"); break;
}
/* owner */
if (statbuf.st_mode & S_IREAD) printf("r");
else printf("-");
if (statbuf.st_mode & S_IWRITE) printf("w");
else printf("-");
if (statbuf.st_mode & S_IEXEC) printf("x");
else printf("-");
/* group */
if (statbuf.st_mode & S_IRGRP) printf("r");
else printf("-");
if (statbuf.st_mode & S_IWGRP) printf("w");
else printf("-");
if (statbuf.st_mode & S_IXGRP) printf("x");
else printf("-");
/* other users */
if (statbuf.st_mode & S_IROTH) printf("r");
else printf("-");
if (statbuf.st_mode & S_IWOTH) printf("w");
else printf("-");
if (statbuf.st_mode & S_IXOTH) printf("x");
else printf("-");
/* hard links */
printf(" %2zu", statbuf.st_nlink);
/* owner name */
if ((pwdPtr = getpwuid(statbuf.st_uid)) == NULL) {
perror("getpwuid");
exit(EXIT_FAILURE);
}
else {
printf(" %s", pwdPtr->pw_name);
}
/* gruop name */
if ((grpPtr = getgrgid(statbuf.st_gid)) == NULL) {
perror("getgrgid");
exit(EXIT_FAILURE);
}
else {
printf(" %s", grpPtr->gr_name);
}
/* size in bytes */
/* "C uses an asterisk in the position of the field
width specifier to indicate to printf that it will
find the variable that contains the value of the field
width as an additional parameter."
http://www.eecs.wsu.edu/~cs150/reading/printf.htm */
while(offset != 0)
{
offset /= 10; /* n=n/10 */
++length;
}
printf(" %*d", length, (int)statbuf.st_size);
/* last modifying time */
time = ctime(&statbuf.st_mtime);
time[strlen(time) - 1] = 0;
printf(" %s", time);
/* index */
// ToDo
/* filename */
printf(" %s", name);
printf("\n");
// -,d,c,b,l,s,p
//if ((statbuf.st_mode & S_IFMT) == S_IFREG)
// printf("- %8ld %s\n", statbuf.st_size, name);
}
int get_maxsize(const char *name)
{
struct stat statbuf;
if (lstat(name, &statbuf) == -1) {
fprintf(stderr, "can't access %s\n", name);
perror("get_maxsize");
return -1;
}
return statbuf.st_size;
}
正常工作时输出(仅适用于当前目录):
yulian@deb:~/programming/os$ ./readDir .
-rw-rw-rw- 1 yulian yulian 4387 Mon Nov 30 06:31:51 2015 readDir.c
-rw-rw-rw- 1 yulian yulian 282 Sun Nov 29 04:43:03 2015 sometext.txt
-rwxr-xr-x 1 yulian yulian 13792 Sat Nov 28 11:54:09 2015 readDir
drwxr-xr-x 2 yulian yulian 4096 Fri Nov 27 05:26:42 2015 testDir
// there is test dir called `testDir` where it fails
失败时输出:
yulian@deb:~/programming/os$ ./readDir testDir/
can't access 2.jpg
get_maxsize: No such file or directory
can't access ETicket_edc7cb12cdc23e6c04a308f34fd31c28.pdf
get_maxsize: No such file or directory
更新:使用我添加到的建议解决方案get_info
:
....
char *filemane = NULL;
filemane = strrchr(name, '/') + 1;
/* to prevent . and .. from output */
if (strcmp(filemane, ".") == 0 || strcmp(filemane, "..") == 0)
return;
...
/* filename */
printf(" %s", filemane); // and changed the argument here
所以输出现在产生的文件名与 完全一样ls -l
,而不是它们的完整路径。