C Programm of "ls -aln" but not working good - c

I've done a C program that does what the ls -aln command does, but I have a problem.
I expect this results :
drwxr-xr-x# 6 seven staff 192 19 fév 18:58 .
drwxr-xr-x# 4 seven staff 128 6 fév 00:37 ..
drwxr-xr-x# 7 seven staff 224 17 fév 15:00 .idea
-rw-r--r--# 1 seven staff 104 5 fév 17:37 CMakeLists.txt
drwxr-xr-x# 11 seven staff 352 19 fév 18:58 cmake-build-debug
-rw-r--r--# 1 seven staff 2144 19 fév 18:58 main.c
but instead I'm having this:
d-----rwxr-xr-x 11 352 seven staff .
d-----rwxr-xr-x 6 192 seven staff ..
d-----rwxr-xr-x 6 192 seven staff cmake-build-debug
d-----rwxr-xr-x 6 192 seven staff CMakeLists.txt
d-----rwxr-xr-x 6 192 seven staff main.c
d-----rwxr-xr-x 6 192 seven staff .idea
Basically my number of links is not what I expected, size of files is not what I expected, the permissions are not all what I expected and then it says that all files are directory and add a "-" after that. I know it's probably caused by all the printf but I don't know how to fix this.
here is my code:
int main() {
char* curr_dir = NULL;
DIR* dir = NULL;
struct dirent* entity = NULL;
struct stat fileStat;
struct passwd* pwd;
struct group* gid;
curr_dir = getenv("PWD");//current directory with PWD
if (curr_dir==NULL){
printf("ERROR: j'ai pas pris le repertoire courrant");
}
dir = opendir("/Users/seven/Desktop/Programmazione/TP");
if(dir == NULL) {
printf("ERROR: j'ai pas pue ouvrir le repertoire");
}
while((entity = readdir(dir)) != NULL){
stat(entity->d_name, &fileStat);
printf((S_ISDIR(fileStat.st_mode)) ? "d" : "-");
printf((S_ISLNK(fileStat.st_mode)) ? "l" : "-");
printf((S_ISSOCK(fileStat.st_mode)) ? "s" : "-");
printf((S_ISFIFO(fileStat.st_mode)) ? "p" : "-");
printf((S_ISBLK(fileStat.st_mode)) ? "b" : "-");
printf((S_ISCHR(fileStat.st_mode)) ? "c" : "-");
printf((fileStat.st_mode & S_IRUSR) ? "r" : "-");
printf((fileStat.st_mode & S_IWUSR) ? "w" : "-");
printf((fileStat.st_mode & S_IXUSR) ? "x" : "-");
printf((fileStat.st_mode & S_IRGRP) ? "r" : "-");
printf((fileStat.st_mode & S_IWGRP) ? "w" : "-");
printf((fileStat.st_mode & S_IXGRP) ? "x" : "-");
printf((fileStat.st_mode & S_IROTH) ? "r" : "-");
printf((fileStat.st_mode & S_IWOTH) ? "w" : "-");
printf((fileStat.st_mode & S_IXOTH) ? "x" : "-");
printf("\t %u", fileStat.st_nlink);
printf("\t %lld", fileStat.st_size);
pwd = getpwuid(fileStat.st_uid);
gid = getgrgid(fileStat.st_gid);
if(pwd != NULL && gid != NULL ){
printf("\t %s", pwd->pw_name);
printf("\t %s", gid->gr_name);
}
printf("\t %s\n", entity->d_name);
}
closedir(dir);
}

The entity->d_name doesn't contain the full path of the file. All files you try to stat will be relative to the current working directory, not the one you passed to opendir. So some files will not exist and stat will silently fail (since you don't check for that).
Two possible solutions:
Change working directory to the one you use for the opendir call; Or
Append the directory and the entity->d_name (with path separator) and pass that appended name to stat.
And of course, add error checking for all calls.

Related

st_mode not returning expected values for S_IXXX comparison

I have a function that (ideally) would merely simulate a portion of the ls -l command. It is meant to return permissions for the file, and the name of the file. I don't really care about any other information. It also is not the cleanest, as I am stuck using the VIM editor, and it is significantly less user friendly than modern IDEs.
Code:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <fcntl.h>
void ls_l(const char *path){
DIR *dir;
struct dirent *file;
struct stat fileStat;
dir = opendir(path);
if(!dir) {
printf("opendir failed\n");
return;
}
while (((file = readdir(dir)) != NULL)){
char path2[255];
sprintf(path2, "%s/%s", path, file->d_name);
printf("%s\n", path2);
if(lstat(path2, &fileStat)) {
printf("lstat failed\n");
return;
}
//User permissions
printf( (fileStat.st_mode & S_IRUSR) ? " r" : " -");
printf( (fileStat.st_mode & S_IWUSR) ? "w" : "-");
printf( (fileStat.st_mode & S_IXUSR) ? "x" : "-");
//Group permissions
printf( (fileStat.st_mode & S_IRGRP) ? "r" : "-");
printf( (fileStat.st_mode & S_IWGRP) ? "w" : "-");
printf( (fileStat.st_mode & S_IXGRP) ? "x" : "-");
//Other permissions
printf( (fileStat.st_mode & S_IROTH) ? "r" : "-");
printf( (fileStat.st_mode & S_IWOTH) ? "w" : "-");
printf( (fileStat.st_mode & S_IXOTH) ? "x | " : "- | ");
}
}
void doStep(int stepNum){
chdir("dir0");
char cwd[PATH_MAX];
if(getcwd(cwd, sizeof(cwd)) != NULL){
printf("CWD: %s\n", cwd);
}
else{
printf("getcwd() error");
}
switch (stepNum){
case 1:
printf("Display files and permissions for ./dir0\n");
ls_l(cwd);
break;
case 2:
printf("Change permission for file6.txt to -rwxrwx---\n");
chmod("./file6.txt", S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP |
S_IWGRP | S_IXGRP);
break;
case 3:
printf("Remove file1.txt and file2.txt from directory dir1\n");
break;
case 4:
printf("Remove dir1 directory\n");
break;
case 5:
printf("Display files and permission for ./dir0\n");
break;
}
}
int main(){
int i;
for (i = 1; i < 2; i++){
doStep(i);
}
return 0;
}
I am only through the user and group permissions and I already have noticed a serious problem with the code. For whatever reason, the group permissions fail to change with each file, and thus do not return the correct values. I am only aware of this because because changing the permissions of a file and checking the return with ls -l gives me different values that that of my code.
I am aware that this isn't a complete program, as I am not finished with it, but it can compile and run on my school UNIX server, so it should suffice for any testing.
I would also like to not that case 2 never functioned before I noticed this error, so if you'd like to help with that as well I would appreciate it.
Edit: I use this to compile:
'''
gcc task13prog.c -o task13prog
'''
File structure is /dir0, which contains directories /dir1 and /dir2, a regular file called file6.txt, and a symbolic link called link5. I am more or less entirely concerned with this file structure, and only this file structure.
Output as requested by Allan Wind
Slightly edited to remove username data
{cslinux1:~/cs3377/project2} pwd
/home/013/t/tm/***/cs3377/project2
{cslinux1:~/cs3377/project2} ./task13prog
CWD: /home/013/t/tm/***/cs3377/project2/dir0
Display files and permissions for ./dir0
/home/013/t/tm/***/cs3377/project2/dir0/.
rwx--x--x | /home/013/t/tm/***/cs3377/project2/dir0/..
rwx--x--x | /home/013/t/tm/***/cs3377/project2/dir0/link5
rwxrwxrwx | /home/013/t/tm/***/cs3377/project2/dir0/dir2
rwx--x--x | /home/013/t/tm/***/cs3377/project2/dir0/file6.txt
rwxrwxrwx | /home/013/t/tm/***/cs3377/project2/dir0/dir1
rwx--x--x | {cslinux1:~/cs3377/project2} ls -l dir0
total 112
drwx--x--x 2 *** sn 54 Apr 3 18:38 dir1
drwx--x--x 2 *** sn 54 Apr 3 18:38 dir2
-rwxrwxrwx 1 *** sn 0 Apr 3 18:38 file6.txt
lrwxrwxrwx 1 *** sn 14 Apr 3 18:38 link5 -> dir2/file4.txt
{cslinux1:~/cs3377/project2}
Final edit:
The solution marked as correct was in fact, correct. Upon testing on a fresh linux system the solution functioned as expected. It appears that there was an error in the original environment that prevented me from making changes to permissions and reading permissions accurately.
I modified your program to pass in the path, checked return values of the functions you call and implemented the suggestion offered up by #MarkPlotnick which is the root cause of your trouble:
#include <limits.h>
void ls_l(const char *path){
DIR *dir;
struct dirent *file;
struct stat fileStat;
dir = opendir(path);
if(!dir) {
printf("opendir failed\n");
return;
}
while (((file = readdir(dir)) != NULL)){
char path2[PATH_MAX];
// if path contains a trailing /, you will end up with //
// in path2 which is ugly but works fine. You could special case that,
// and also special case ./ not being copied into path2
snprintf(path2, PATH_MAX, "%s/%s", path, file->d_name);
printf("%s\n", path2);
if(lstat(path2, &fileStat)) {
printf("lstat failed\n");
return;
}
...
As for step 2, it works for me, so you just need to ensure that file6.txt is in the dir0/ directory.

problem scanning and scanning data from file

I'm having some trouble in extracting data from a file, I don't understand what's wrong, it works fine for single digit integers, but when the input is double digit, it doesn't scan the integers. Everything else is working.
Suppose the input is:
abc de,1,2,y
then the output is:
"abc de" 1 2 y
but when the input is
cde abc,21.31,y
the scan fails on %d:
fin1 = fscanf(fp1, "%20[^,]%*c%d %*c %d%*c %c%*c", name1, &code1, &season, &relevant);
Help would be nice. Also some input as you asked:
Input:
The Universe,2,3,Y|Zoo,7,3,N|The Hobbit,10,2,Y|True Lies,12,25,N|Animals,22,2,Y| Euphoria,35,5,Y
Code:
FILE *fp1, *fserie;
char file1name[256], name1[21], relevant = 0, active = 0;
int code1, seasons, fin = 0,
while (1) {
puts("Enter First File Name:");
scanf("%s", file1name);
if (!(fp1 = fopen(file1name, "r")))
{
printf("error in opening file %s !!!\n", file1name);
continue;
} else break;
}
if (!(fserie = fopen("series.txt", "w")))
{
fclose(fp1);
exit(1);
}
do
{
fin1 = fscanf(fp1,"%20[^,]%*c %d%*c %d%*c %c%*c", name1, &code1, &season, &active1);
if (relevant == 'y')
fprintf(fserie,"%s,%d,%d\n", name1, code1, season);
} while (fin1 != EOF && fin2 != EOF);
The problem you are having is your format string and your failure to validate the read against all 4 successful conversions per iteration. For your format string you can use:
" %20[^,],%d,%d,%c|"
(the leading space is optional, but required if you have space following the '|' before the next name. Also note, if you have the potential for space surrounding the final active character, you can handle that by including a space in your format string to consume any-and-all whitespace, e.g. " %20[^,],%d,%d, %c |")
An example reading a line with multiple sets of movie information could be:
#include <stdio.h>
#define MAXN 21 /* if you need a constant, #define one (or more) */
int main (int argc, char **argv) {
char name[MAXN], active;
int code, seasons;
/* use filename provided as 1st argument (stdin by default) */
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open for reading */
perror ("file open failed");
return 1;
}
while (fscanf (fp, " %20[^,],%d,%d,%c|",
name, &code, &seasons, &active) == 4) {
printf ("\nname : %s\ncode : %d\nseason : %d\nactive : %c\n",
name, code, seasons, active);
}
if (fp != stdin) /* close file if not stdin */
fclose (fp);
}
Example Input File
$ cat dat/movies.txt
The Universe,2,3,Y|Zoo,7,3,N|The Hobbit,10,2,Y|True Lies,12,25,N|Animals,22,2,Y| Euphoria,35,5,Y
Example Use/Output
$ ./bin/readmovies dat/movies.txt
name : The Universe
code : 2
season : 3
active : Y
name : Zoo
code : 7
season : 3
active : N
name : The Hobbit
code : 10
season : 2
active : Y
name : True Lies
code : 12
season : 25
active : N
name : Animals
code : 22
season : 2
active : Y
name : Euphoria
code : 35
season : 5
active : Y
Look things over and let me know if you have further questions. There is more than one way to do this, but this is the closest to your original.

New at C and working with directories: Trouble opening files within subdirectories

I'm working with directories for the first time and am running into some difficulties. I wrote the following function to explore a directory, display the filesizes and permissions, then recurse on any subdirectories.
void exploreDIR (DIR* dir, char cwd[], int tab)
{
struct dirent* ent;
while ((ent = readdir(dir)) != NULL)
{
if(strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
continue;
int i;
i = 0;
while(i < tab)
{
printf(" ");
i = i + 1;
}
printf("%s ", ent->d_name);
FILE *file = fopen(ent->d_name, "r");
int filesize;
if(file==NULL)
{
printf("[ Could not open! ]\n");
continue;
}
struct stat st;
stat(ent->d_name, &st);
filesize = st.st_size;
if (st.st_mode & S_IFDIR)
{
printf ("(subdirectory) [");
}
else
{
printf("(%d bytes) [", filesize);
}
printf( (S_ISDIR(st.st_mode)) ? "d" : "-");
printf( (st.st_mode & S_IRUSR) ? "r" : "-");
printf( (st.st_mode & S_IWUSR) ? "w" : "-");
printf( (st.st_mode & S_IXUSR) ? "x" : "-");
printf( (st.st_mode & S_IRGRP) ? "r" : "-");
printf( (st.st_mode & S_IWGRP) ? "w" : "-");
printf( (st.st_mode & S_IXGRP) ? "x" : "-");
printf( (st.st_mode & S_IROTH) ? "r" : "-");
printf( (st.st_mode & S_IWOTH) ? "w" : "-");
printf( (st.st_mode & S_IXOTH) ? "x" : "-");
printf("]\n");
fclose(file);
if (st.st_mode & S_IFDIR)
{
char tempwd[1024];
strcpy(tempwd, cwd);
strcat(tempwd, "/");
strcat(tempwd, ent->d_name);
DIR* tempdir;
if ((tempdir = opendir (tempwd)) != NULL)
{
printf("%s", tempwd);
exploreDIR(tempdir, tempwd, tab + 1);
}
}
}
closedir(dir);
}
However the fopen function always returns null when the function recurses on subdirectories. I cannot figure this out for the life of me. For reference, this is the main:
int main(int argc, char** argv)
{
printf("\n");
DIR* dir;
char cwd[1024];
if (getcwd(cwd, sizeof(cwd)) != NULL)
{
if ((dir = opendir (cwd)) != NULL)
{
exploreDIR(dir, cwd, 0);
}
}
printf("\n");
return (EXIT_SUCCESS);
}
I am also somewhat concerned with my methodology. Is strcat() really the best way to explore subdirectories?
Thanks
When you open a sub-directory ./snails, you read file names from the directory with readdir() such as chewy-snails, but to stat() the files, you need to prefix the name with the sub-directory name: ./snails/chewy-snails.
The alternative, not to be undertaken lightly, is to consider using chdir() or (better) fchdir() to change directory to the relevant sub-directory. You can then stat() the names from readdir() without messing with the strings. However, getting back to where you start is a problem — especially if you follow a symlink to get there. This is where fchdir() scores.
If you're on a system with the necessary support, the *at() functions may help (fstatat() etc).
But the simplest solution is to not change directories and to prefix file names with the sub-directory name before trying to use stat() or
lstat() — that's 3 links to the same content.
You don't seem to be putting your cwd variable to use. You should be putting that at the start of each filename.
Also I like using snprintf instead of strcat for building names. It will limit itself to the buffer size that you pass it, so there is no risk of overflow.

How can I correct this printing output issue?

For a homework assignment, I wrote some code in C to print out the permissions and file name of the files that are stored in an achive file. My code compiles, but for some reason, the name of the second file is returned in a new line.
Here is how my output looks like in terminal:
rw-r--r-- 501/20 1-s.txt
rw-r--r-- 501/20
2-s.txt
(empty blank line here)
This is how I want the output to look:
rw-r--r-- 501/20 1-s.txt
rw-r--r-- 501/20 2-s.txt
(no empty blank line here)
Can someone take a look at my code and give me some tips on how to fix my code? I suspect it's related to the way I read and select the file name (using my_ar.ar_name), but I can't figure out how to fix it. Thank you for your time.
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/utsname.h>
#include <ctype.h>
#include <string.h>
#include <ar.h>
int main (int argc, char **argv)
{
FILE *fp;
size_t readNum;
long long tot_file_size, cur_file_size;
struct stat fileStat;
struct ar_hdr my_ar;
//open the archive file (e.g., hw.a)
fp = fopen(argv[1], "r");
if (fp == NULL)
{
perror("Error opening the file\n");
exit(-1);
}
//size of the archive file
fseek(fp, 0, SEEK_END);
tot_file_size =ftell(fp);
rewind(fp);
//read data into struct
fseek(fp, strlen(ARMAG), SEEK_SET);
file_size_cnt = 0;
while (ftell(fp) < tot_file_size - 1)
{
readNum = fread(&my_ar, sizeof(my_ar), 1, fp);
if (stat(argv[1], &fileStat) == -1) {
perror("stat");
exit(EXIT_FAILURE);
}
if ((fileStat.st_mode & S_IFMT) == S_IFREG)
{
printf( (fileStat.st_mode & S_IRUSR) ? "r" : "-");
printf( (fileStat.st_mode & S_IWUSR) ? "w" : "-");
printf( (fileStat.st_mode & S_IXUSR) ? "x" : "-");
printf( (fileStat.st_mode & S_IRGRP) ? "r" : "-");
printf( (fileStat.st_mode & S_IWGRP) ? "w" : "-");
printf( (fileStat.st_mode & S_IXGRP) ? "x" : "-");
printf( (fileStat.st_mode & S_IROTH) ? "r" : "-");
printf( (fileStat.st_mode & S_IWOTH) ? "w" : "-");
printf( (fileStat.st_mode & S_IXOTH) ? "x" : "-");
printf("%.*s", 15, my_ar.ar_name);
printf("\n");
}
cur_file_size = atoll(my_ar.ar_size);
if (fseek(fp, cur_file_size, SEEK_CUR) != 0)
{
perror("You have an error.\n");
exit(-1);
}
}
//printf("\n");
fclose(fp);
return 0;
}
You don't want a new line to be printed? So don't print it!
Remove this:
printf("\n");
It is placed at the end of your code.
EDIT
I gauss you don't want to remove it completely, but you want to print it anytime except the last time.
if (ftell(fp) != tot_file_size - 1) {
printf("\n");
}
EDIT V1.1
I ran your code under my linux mint 13 after my improvment. This is my output:
rw-r--r--a.txt/
rw-r--r--b.txt/
This is the format you want, isn't it?
There are a number of issues.
OP has if (stat(argv[1], &fileStat) == -1) ... which is curious to repeatedly query the file status of the "file name of the files" rather than the file name in my_ar.ar_name. Thus the same file stats will appear.
The first use of printf("%.*s", 15, my_ar.ar_name) gave "501/20 1-s.txt". This looks like an unusual file name. The ar_name field is "If the file member name fits, the ar_name field contains the name directly, and is terminated by a slash (/) and padded with blanks on the right. If the member's name does not fit, ar_name contains a slash (/) followed by a decimal representation of the name's offset in the archive string table described below." So the presence of / implies you have more to do to extract the file name. It also may be that the fields are not NUL byte terminated. OP needs to read up on struct ar_hdr. Try: http://www.lehman.cuny.edu/cgi-bin/man-cgi?ar.h+3
The extracted filename, done errantly in this code, may or may not contain surprising bytes. I am certain this is why you saw an unexpected end-of-line in the 2nd line of output. Testing the filename for printable ASCII char is prudent. isprint()

Writing simple du clone. Getting random values for filesizes in subdirectories.

I am trying to write a basic program that will sum up the filesizes of all files in the current directory and all subdirectories. I thought it would be a nice exercise. I am trying to use basic recursion for this. Here is what I have so far:
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <string.h>
long totalbytes = 0;
long dirsize(const char* directory, int verbose)
{
struct dirent *de;
struct stat s;
DIR * dir;
//long total_items = 0;
long filesize = 0;
dir = opendir(directory);
if (dir == NULL)
{
printf("Failed to open %s.\n", directory);
return -1;
}
while ((de = readdir (dir)) != NULL)
{
stat(de->d_name, &s);
if (S_ISLNK(s.st_mode))
{
printf("links are ignored.\n");
}
if (de->d_type == DT_REG)
{
filesize = 0; //be sure to reset this each time to avoid inaccuracy
stat(de->d_name, &s); // get file info into our s structure
if (verbose)
{
printf("%s/%s : %ld bytes (%f MB)\n", directory, de->d_name, s.st_size, (float) s.st_size / 1024 / 1024);
}
filesize = s.st_size; //put file size into filesize variable
totalbytes += filesize; //increment totalbytes
}
if (de->d_type == DT_DIR && strcmp(de->d_name, ".") != 0 && strcmp(de->d_name, "..") != 0)
{
char pathname[PATH_MAX];
sprintf(pathname, "%s/%s", directory, de->d_name);
dirsize(pathname, verbose); //recursion: keep looping until no more subdirs remain
}
}
closedir(dir);
return totalbytes;
}
long compute_size(const char* directory, int verbose)
{
long space = dirsize(directory, verbose);
return space;
}
int main(int argc, char* argv[])
{
if (argc != 2)
{
printf("Usage: dirsize DIRECTORY\n");
return -1;
}
int verbose = 1; //show or hide individual computations
long space = compute_size(argv[1], verbose);
if (space != -1)
{
float space_mb = (float) space / 1024 / 1024;
printf("space occupied: %ld bytes\n", space);
printf("(%f MB)\n", space_mb);
}
return 0;
}
Here is my program output (I am also including an ls of the subdirectory)
08:35 PM#~/tmp$ ./dirsize .
./dirsize : 8369 bytes (0.007981 MB)
./diskstat.c : 1430 bytes (0.001364 MB)
./diskstat : 7993 bytes (0.007623 MB)
./ftw.c : 491 bytes (0.000468 MB)
./a.out : 8044 bytes (0.007671 MB)
./arrays.sh : 212 bytes (0.000202 MB)
./fileread/timestamp : 0 bytes (0.000000 MB)
./fileread/timestamp.c : 0 bytes (0.000000 MB)
./fileread/a.out : 8044 bytes (0.007671 MB)
./fileread/build.prop : 8044 bytes (0.007671 MB)
./fileread/read.c : 4096 bytes (0.003906 MB)
./fileread/read : 454656 bytes (0.433594 MB)
./local.fstab : 76 bytes (0.000072 MB)
./dirsize.c : 1857 bytes (0.001771 MB)
./echo.sh : 223 bytes (0.000213 MB)
./TEAMS.sh : 605 bytes (0.000577 MB)
space occupied: 504140 bytes
(0.480785 MB)
08:35 PM#~/tmp$ ls -l fileread/
total 40
-rwxr-xr-x 1 raidzero raidzero 8132 Dec 28 10:39 a.out
-rw-r--r-- 1 raidzero raidzero 2346 Dec 28 10:09 build.prop
-rwxr-xr-x 1 raidzero raidzero 8384 Dec 29 13:57 read
-rw-r--r-- 1 raidzero raidzero 1150 Dec 28 10:16 read.c
-rwxr-xr-x 1 raidzero raidzero 8132 Dec 29 13:57 timestamp
-rw-r--r-- 1 raidzero raidzero 659 Dec 28 10:39 timestamp.c
08:35 PM#~/tmp$
In my limited experience, getting random data is sign of improper memory allocation, but st_size in the stat struct is a long int..?
de->d_name only has the filename - it does not contain the path leading up to it. So you're statting ./timestamp rather than ./fileread/timestamp, for example. You can either construct the full path to the file, use chdir() to enter directories as you go (not safe if you're in a multi-threaded environment, and can be fragile if dirs are moved when you're in them - fchdir() can be very helpful to get back to higher directories), or (on recent unixen) use the openat()/fstat() functions to traverse directories.
Note that, had you checked for error returns from stat, you would have noticed this. Always check those error returns.

Resources