问题
I have for homework to write a C program, which is acting like the Linux "ls -al" command. I know that there are a lot of example programs over the internet, which are doing the thing that I need, but I have a specific problem, to which I can't find a solution. I also want to mention, that I am new to C programming. Here is my code :
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <time.h>
#include <pwd.h>
int list_dir(const char *dirname) {
struct dirent* current_directory;
struct stat my_stat;
struct tm lt;
struct passwd *pwd; // For User-ID
DIR* directory = opendir(dirname);
if(directory == NULL) {
printf("list_dir : %s : %s \n", dirname, strerror(errno));
return 0;
}
printf("Directory : %s\n", dirname);
printf("\n");
while( (current_directory = readdir(directory) ) ) {
stat(current_directory->d_name, &my_stat);
if ( (stat(current_directory->d_name, &my_stat) ) == 0 ) {
pwd = getpwuid(my_stat.st_uid); // Get User-ID
}
// Last Modified
time_t t = my_stat.st_mtime;
localtime_r(&t, <);
char timebuf[80];
strftime(timebuf, sizeof(timebuf), "%c", <);
if (pwd != 0) {
printf("%s \t %ld \t %s \t %s", pwd->pw_name, (long)my_stat.st_size, timebuf, current_directory->d_name);
printf("\n");
} else {
printf("%d \t %ld \t %s \t %s", my_stat.st_uid, (long)my_stat.st_size, timebuf, current_directory->d_name);
printf("\n");
}
}
closedir(directory);
return 0;
}
int main(int argc, char* argv[]) {
if ( argc == 1 ) {
return list_dir ( "." );
} else {
int ret = 0;
for (int i = 1; i < argc; i += 1 ) {
if ( list_dir ( argv[i] ) != 0 ) {
ret = 1;
}
}
return ret;
}
}
The program has to display the same things (without the permissions) as "ls -al". So far so good, if I compile it with "gcc -std=gnu99 -o list_dir list_dir.c" and execute the program with "./list_dir" I am getting the same result as "ls -al" and it looks like this :
username 1599 Fri May 1 20:43:57 2015 list_dir.c
However if I run the program with something like : "./list_dir /home/username/Downloads/" I am getting this :
32727 0 Sun May 8 07:09:04 4461391 selection_sort.c
As you can see, the program can't get the right information about the Username, the size of the file and the year. Also this information is appearing thanks to the else case of the if(pwd != 0) statement. If I don't have the else case, the program is printing out only the files, for which it can get the correct information. Also if I remove this if statement and also the if statement :
if ( (stat(current_directory->d_name, &my_stat) ) == 0 )
I am getting a segmentation fault.
So my questions are : 1.What am I doing wrong. I know that I am doing something wrong, because as a hint for the homework I have an example run of the program and also a hint that I can use "stat, lstat, readlink, getpwnam, getpwuid, strftime".
2.Is there any way to get the username with stat() and with the User-ID only, or it's only possible with getpwuid?
回答1:
Here,
if ( (stat(current_directory->d_name, &my_stat) ) == 0 ) {
pwd = getpwuid(my_stat.st_uid); // Get User-ID
}
What happens if stat()
fails? pwd
would have uninitialized value or incorrect value set from previous iteration.
The reason why stat
would fail, current_directory->d_name
contains only the file name whereas stat
expects a fullpath. So you need to prepend the directory name to the file and pass it to stat()
. You are only passing the filename right now.
Something like:
char buf[1024];
errno = 0;
snprintf(buf, sizeof buf, "%s/%s", dirname, current_directory->d_name);
if ( (stat(buf, &my_stat) ) == 0 ) {
...
}
else {
printf("%s: %s\n", buf, strerror(errno));
// exit here or continue to the next entry in the directory
//depending how you wish to handle failure
}
and handle the error in case stat()
fails.
You also have one other stat()
inside the loop which doesn't do anything.
来源:https://stackoverflow.com/questions/29993653/linux-ls-al-like-program-in-c