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!

Аркадий

user795954
  • 77
  • 2
  • 8

4 Answers4

4

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

printf("error = %d: %s", errno, strerror(errno));
Fred Foo
  • 355,277
  • 75
  • 744
  • 836
dbeer
  • 6,963
  • 3
  • 31
  • 47
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);
}
David M. Syzdek
  • 15,360
  • 6
  • 30
  • 40
  • 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! – user795954 Dec 15 '11 at 19:06
  • I update the example to use the data from `getcwd()` to loop through the files in the current directory. – David M. Syzdek Dec 15 '11 at 19:12
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.

codaddict
  • 445,704
  • 82
  • 492
  • 529
  • 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 – user795954 Dec 15 '11 at 19:08
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");
}
clearlight
  • 12,255
  • 11
  • 57
  • 75