For one part of a code, I need to save both the name and the stats (user ID, group ID, modification time, permissions, etc.) of every file in a given directory into an array of self-defined structs. The saving info into the array is fine, so for clarity, I left those things out. The problem I'm having is with the pre-defined struct stat
: in testing, it prints out the same exact modification date for every file in the directory, which is one problem, and the date is from 1969, which is another problem (considering I clearly remember creating and modifying those files sometime last year). I'm not sure what's going wrong; some help would be greatly appreciated.
Note: This is my very first time coding in C, so if there are any blatant errors, please do let me know. My professor is very big on independent research and doesn't exactly cover all the important things to know. Also, I'm aware that I need to be checking for errors -- those checks have been written and will be implemented later. I just need to fix the sunny-day portion of this code before I worry about all of my error checks, so please don't tell me that that's my problem. I'm always handing it a plain ol' readable directory. It should have no trouble opening or reading.
int main ()
{
DIR *myDIR;
struct dirent *mydirent = malloc(sizeof(struct dirent)); //necessary?
struct stat mystat;
myDIR = opendir(pathname);
int count = 0;
while ((mydirent = readdir(myDIR)) != NULL)
count++;
rewinddir(myDIR);
struct file_info **file_info_array = malloc(sizeof(struct file_info*)*(count+1));
int i = 0;
while ((mydirent = readdir(myDIR)) != NULL)
{
stat(mydirent->d_name, &mystat);
printf("name: %s\n", mydirent->d_name);
printf("mod_time: %s\n", ctime(&mystat.st_mtime));
/*
... saving file info into file_info_array
*/
}
int is_closed = closedir(myDIR);
/*
... freeing pointers
*/
return 0;
}
Converting comments into an answer.
You aren't checking whether stat()
succeeds; you can't defer error checking — it isn't sane/safe. If it fails, there's no guarantee that the contents of the stat
structure are sensible. And you haven't shown how pathname
is set. If pathname is not .
(or a synonym for .
), then the stat()
calls will fail; you need to convert the name returned by readdir()
into a name relative to pathname
— for example:
char path[PATH_MAX]; /* <limits.h> - if it is defined at all */
snprintf(path, sizeof(path), "%s/%s", pathname, mydirent->d_name);
if (stat(path, &mystat) == 0)
{
…go ahead with printing, etc…
}
Oh, goodness, that's why! It needs to be a full path? That makes sense, but for some reason when other classmates coded it, they implemented it the way I originally did, as just
mydirent->d_name
, and had no problems. I wonder why?
Not necessarily a full path; just a path that can be found. If you simply do stat(mydirent->d_name, &mystat)
, you're looking for a file with the given name in the current directory — not the directory the name was read from (unless that directory happens to be .
). Maybe classmates used chdir(pathname)
? Or maybe they only used .
(or a synonym for .
) as the path name?
So then how come it successfully prints out all the names, even though they only exist in the inputted directory and not my current one? I'm not trying to argue with you; I'm just genuinely curious as to how
stat()
anddirent
actually work.
The readdir()
reads the name (only; no path information) from the directory named by pathname
. So it can be printed. The stat()
fails, in general, so you get garbage to print for the information from it.
On a side note, no, it isn't necessary to malloc() space for a struct dirent just because you declare a variable that can point to such. You do need to assign a valid value to the variable before you can safely dereference it, but you do so by assigning the return value of readdir(), supposing that readdir() succeeds. –
As John Bollinger says, the malloc()
is unnecessary, and worse, it is a memory leak.