Question

Is there a way to get the total size of subdirectories with recursivity?

For example:

Dir1
-- FileA.txt (90)
-- SubDir2 (4096)
---- FileB.txt (100)
---- FileC.txt (400)

When I try to get the size of SubDir2, it gives me 4186. The expected answer I wish to get is 4596.

My program counts the size of FileA instead of FileB and FileC. How to make it count FileB and FileC?

To start, I have to use these headers:

#include <errno.h>
#include <stdio.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>

Then, I made this function to call it recursively:

static DIR *dir;

void goDir(char* argv[])
{
    struct dirent *dit;
    struct stat st;

    int size = 0;
    static int total_size = 0;

    char filePath[NAME_MAX];

    while ((dit = readdir(dir)) != NULL)
    {
        sprintf(filePath, "%s/%s", argv[1], dit->d_name); // To show correctly the size and name of files
        lstat(filePath, &st);
        // To skip . and ..
        if ( (strcmp(dit->d_name, ".") == 0) || (strcmp(dit->d_name, "..") == 0) ) continue;

        size = st.st_size;

        if(S_ISDIR(st.st_mode))
        {   
            goDir(argv); // For Recursivity 

            total_size += size;

            printf("DIR\t");            
            printf("MODE: %lo\t", (unsigned long) st.st_mode);
            printf("SIZE: %d\t", total_size);
            printf("%s\n", dit->d_name);
        }
        else
        {
            total_size += size;

            printf("FILES\t");
            printf("MODE: %lo\t", (unsigned long) st.st_mode);
            printf("SIZE: %d\t", size);
            printf("%s\n", dit->d_name);
        }

    }

}

And then, my main program:

int main (int argc, char *argv[])
{
    if ( argc != 2 ) {
        printf("Usage: Program <Directory>\n");
        return 1;
    }

    if ((dir = opendir(argv[1])) == NULL) return 1;

    goDir(argv);
    closedir(dir);

    return 0;
}
Was it helpful?

Solution

Your goDir() function never opens a new directory, or closes the directory once it has finished. That is going to lead to problems — basically, you are not traversing down your directory hierarchy.

You'll need to make dir a local (non-static) variable in the goDir() function; you'll open and close directories; and instead of passing argv, you'll pass a directory name, etc.

While you're at it, you should change goDir() to return the size it finds, and lose the static variable total_size.

This code looks semi-plausible:

#include <stdio.h>
#include <dirent.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>

#ifndef NAME_MAX
#define NAME_MAX 1024
#endif

static long goDir(char *dirname)
{
    DIR *dir = opendir(dirname);
    if (dir == 0)
        return 0;

    struct dirent *dit;
    struct stat st;
    long size = 0;
    long total_size = 0;
    char filePath[NAME_MAX];

    while ((dit = readdir(dir)) != NULL)
    {
        if ( (strcmp(dit->d_name, ".") == 0) || (strcmp(dit->d_name, "..") == 0) )
            continue;

        sprintf(filePath, "%s/%s", dirname, dit->d_name);
        if (lstat(filePath, &st) != 0)
            continue;
        size = st.st_size;

        if (S_ISDIR(st.st_mode))
        {
            long dir_size = goDir(filePath) + size;
            printf("DIR\t");
            printf("MODE: %lo\t", (unsigned long) st.st_mode);
            printf("SIZE: %ld\t", dir_size);
            printf("%s\n", filePath);
            total_size += dir_size;
        }
        else
        {
            total_size += size;
            printf("FILES\t");
            printf("MODE: %lo\t", (unsigned long) st.st_mode);
            printf("SIZE: %ld\t", size);
            printf("%s\n", filePath);
        }
    }
    return total_size;
}

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        fprintf(stderr, "Usage: %s <Directory>\n", argv[0]);
        return 1;
    }

    long size = goDir(argv[1]);
    printf("Total size: %ld\n", size);

    return 0;
}

It compiles and runs. It does not give the same answer as du -k, mainly because it does not round up the size of files to an integral number of disk blocks. You'd need to look at st_blksize and/or st_blocks in the struct stat to get that information.

OTHER TIPS

You'll have to use a hash table to keep track of the occurrences of inodes. So that they are not counted twice.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top