4

I'm new to C but trying some system calls.

I'm writing program that iterates through all files in a directory and prints the current file name and size. I can get the program to print the file name but it errors when I preform the stat system call.

Here is some of the code:

while (dptr = readdir(dirp)) { if (stat(dptr->d_name, &buf) != 0) { //Always does this and it does print the file name printf("Error on when getting size of %s \n", dptr->d_name); } else { //Never gets here printf("%u", buf.st_size); } } 

I have the structs described like this:

struct stat buf; struct dirent *dptr; DIR *dirp; 

If I change:

if (stat(dptr->d_name, &buf) != 0) 

to

if (stat(dptr->d_name, &buf) != [EACCES]) 

It still goes into the loop which makes me think it can't read the file name but it's printing it in the error statement without a problem.

Can someone point me in the right direction? Thanks!

Аркадий

3
  • 2
    Are the names you're providing the full paths to the files and folders? Commented Dec 15, 2011 at 18:45
  • 3
    stat will never return EACCES. It will return -1 and then set errno to EACCES. Commented Dec 15, 2011 at 18:51
  • Does it work when it is in the current directory? (As per @codaddict's answer) Commented Dec 15, 2011 at 19:00

4 Answers 4

4

First, stat() returns -1 if an error is encountered, not the actual error code. The error code will be set in errno. An easy way to print the error is to use perror().

Second, dptr->d_name only provides a relative filename of the file and not the full filename. To obtain the full filename, you must generate it from the relative filename and the directory name.

Here is an example:

int cwdloop(void) { DIR * dirp; struct stat buff; struct dirent * dptr; char filename[1024]; char dirname[1024]; if (!(getcwd(dirname, 1024))) { perror("getcwd"); return(1); }; dirp = opendir(dirname); if (!(dirp)) { perror("opendir()"); return(1); }; while ((dptr = readdir(dirp))) { snprintf(filename, 1024, "%s/%s", dirname, dptr->d_name); if (stat(filename, &buff) != 0) { perror("stat()"); return(1); } else { printf("size: %u\n", (unsigned)buff.st_size); }; }; closedir(dirp); return(0); } 
Sign up to request clarification or add additional context in comments.

2 Comments

I think this is it, as others mentioned. Could this: snprintf(filename, 1024, "%s/%s", dirname, dptr->d_name); be changed so that dirname is a variable to the current working directory? Thanks for your help. Really appreciate it!
I update the example to use the data from getcwd() to loop through the files in the current directory.
4

These things are a lot easier to deal with if you know the exact error. Try

printf("error = %d: %s", errno, strerror(errno)); 

3 Comments

(with one more parenthesis near the end)
Thanks for that. I'm getting... error = 2: No such file or directory for every file in the directory.
Also..Permissions are not the problem. I have checked them earlier.
3

One common problem with this kind of code is using just the filename as path name. The d_name entry of dirent structure does not provide you full pathname but provides pathname relative to your directory.

To resolve this you can either

  1. construct the full path name and then pass it to stat or

  2. chdir to the directory before calling stat.

1 Comment

Thanks for your help. I believe this is the problem. I will not be sure of the current directory. What is the best approach of getting the full path? Thank you
0

The direct answer to the question is covered by other answers. I'm providing this as a complimentary answer. While you're debugging stat() system call, you may find the following function helpful for nicely formatting the stat buffer that's returned.

How to format, and print or log stat() system call:

static void logstat(struct stat *sp) { int mode = sp->st_mode; if (sp->st_size > 1000000000) printf(" File Size: %lluGB\n", sp->st_size / 1000000000); else if(sp->st_size > 1000000) printf(" File Size: %lluMB\n", sp->st_size / 1000000); else printf(" File Size: %llu bytes\n", sp->st_size); printf(" Number of Links: %d\n", sp->st_nlink); printf(" File inode: %d\n", sp->st_ino); printf(" File type: "); switch (mode & S_IFMT) { case S_IFBLK: printf("BLK\n"); break; case S_IFCHR: printf("CHR\n"); break; case S_IFDIR: printf("DIR\n"); break; case S_IFIFO: printf("FIFO\n"); break; case S_IFLNK: printf("LINK\n"); break; case S_IFREG: printf("REG\n"); break; case S_IFSOCK: printf("SOCK\n"); break; } printf(" File Permissions: "); printf( (S_ISDIR(sp->st_mode) ? "d" : "-"); printf( (sp->st_mode & S_IRUSR) ? "r" : "-"); printf( (sp->st_mode & S_IWUSR) ? "w" : "-"); printf( (sp->st_mode & S_IXUSR) ? "x" : "-"); printf( (sp->st_mode & S_IRGRP) ? "r" : "-"); printf( (sp->st_mode & S_IWGRP) ? "w" : "-"); printf( (sp->st_mode & S_IXGRP) ? "x" : "-"); printf( (sp->st_mode & S_IROTH) ? "r" : "-"); printf( (sp->st_mode & S_IWOTH) ? "w" : "-"); printf( (sp->st_mode & S_IXOTH) ? "x" : "-"); printf("\n\n"); } 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.