Linux Directory Size Issue with C - c

Here is what I need to do:
Write a C program to calculate the total size of the files in a
directory and the sub-directories of the directory. Note that the
total size should include the sizes of sub-directories (directories
are also files) and size of the top-level directory. If a file is a
symbolic link, the symbolic link should not be dereferenced. So the
size of the symbolic link is added to the total size, not the size of
the file pointed by the link. To facilitate testing, your program
should print out ONLY the total size in bytes, i.e., ONE number,
nothing else.
Here is what I have:
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <string.h>
#include <stdio.h>
int main(int argc, char *argv[]){
char* folder = argv[1];
long length;
DIR* dir_p;
struct dirent* dir_element;
struct stat file_info;
dir_p = opendir(folder);
while(dir_element = readdir(dir_p)){
lstat(dir_element->d_name, &file_info);
length+=file_info.st_size;
printf("%s\n" , dir_element->d_name);
}
return 0;
}
The problem here is that I do not get the right number for some reason. I check the output of my program with du -abc "directory_pathname" call in Ubuntu(Linux).

You never initialize length. Also, you need to actually recurse into directories. Put the while into a function, then call that function for each directory you find (check man stat to figure out how to tell if the file is a directory; I forget the exact test off the top of my head but it's a member of struct stat).

Related

GCC fatal error: quit.h no such file or directory

I am learning C for an operating systems course and have just finished writing this program as per the textbook instructions:
#include <dirent.h>
#include <stdio.h>
#include "quit.h"
int main(int argc, char **argv) {
DIR *dir;
struct dirent *direntry;
arg_check(2, argc, "Specify a directory\n", 1);
if ( (dir = opendir(argv[1])) == NULL)
quit("opendir", 1);
while ((direntry = readdir(dir)) != NULL)
printf("%10d %s\n", direntry->d_ino, direntry->d_name);
closedir(dir);
exit(0);
}
This code is exactly copied from the textbook, but quit.h appears to be causing the compile to file. I have tried switching "quit.h" to , and "quit", but none of these have worked, and I cannot find other questions about this specific issue.
include "quit.h"
The word #include (with its hash # prefix) means that a file has to be read in; the content of that file (quit.h in this case) is processed exactly as if it was typed inside the program. Suppose you have a file name "test.h" which contains the single line
// this is a test
if you a have a program like this:
#include "test.h"
int main(int argc, char **argv)
...
the compiler processes (sees) exactly these lines:
// this is a test
int main(int argc, char **argv)
...
The file name specified after #include can be enclosed with angles or quotes. Conventionally, if angles are used, like
#include <stdio.h>
this means that the file (stdio.h in this case) is some system or standard file or so - in other simple words, someone else has written that file for you. If quotes are used, instead, the file specified is considered somehow part of the program you are compiling. Your quit.h seems like this. So you must have a file named quit.h. If you change that "quit.h" to "quit", a file named quit must be present in the same directory of the file you are compiling. (Actually things are more complicated, but don't mind it for now). Read your book, somewhere it should explain what is that file "quit.h".

lstat returning <0

Basically, this should be a simple piece of code that opens a directory stream and looks for symbolic links. Whenever a symbolic link is found, it should print ("Symbolic link found");
However, the lstat(dirp->d_name,&bufcall always returns a value < 0, and I don't know why.
I created the two symbolic link opening the file folder, opening a terminal window inside the folder and running
ln -s ciao.txt link1 and
ln -s ciao2.txt link2
I know I should call closedir() later in my code, please don't care about this.
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <unistd.h>
void main (int argc, char* argv[])
{
char buffer[100],dir[100];
struct stat buf;
int x;
DIR *dp;
struct dirent *dirp;
if((dp=opendir(argv[1]))==NULL)
{
printf("\nError opening directory stream, now exiting...\n");
exit(-1);
}
while((dirp=readdir(dp))!=NULL)
{
lstat(dirp->d_name,&buf);
if(S_ISLNK(buf.st_mode))
printf("\n%s Is a symbolic link\n",dirp->d_name);
else
printf("\n%s Is not a symbolic link\n",dirp->d_name);
}
}
Some help would be appreciated. Thanks.
d_name is the file name in the directory, not a full path name. You must eather chdir into the directory you are looking at, or construct full path names for the files.
The simplest solution is to add this line just before your while loop:
chdir(argv[1]);

Why is the file size repeating itself?

I'm trying to list files and their sizes in "first" folder but I am getting weird repetition of every two files.
#include <stdlib.h>
#include <stdio.h>
#include <dirent.h>
#include <sys/stat.h>
struct dirent *dirPtr;
struct stat st;
void main()
{
DIR * dirp;
if((dirp=opendir("first"))==NULL)
{
printf("There has been an error");
}
while(dirPtr=readdir(dirp))
{
printf("%s - ", dirPtr->d_name);
stat(dirPtr->d_name, &st);
printf(" file size: %lu\n", st.st_size);
}
closedir(dirp);
}
This is my output:
Does anyone know why this is happening?
For starters, you should probably check the return result from "stat()", and print an error # (instead of file size) if stat() fails.
Also: "opendir()" is reading files from some arbitrary directory.
Q: Does "dirPtr->d_name" contain a full filepath ... or just a filename? In other words, are you trying to "stat()" from the wrong directory?
You are basically calling stat("test.c", &st). How is stat supposed to know what directory test.c is in? I don't think it can.
I think you should try doing stat("./first/test.c", &st) or stat("/full/path/to/first/test.c", &st). Better yet, you should find some function like stat that takes a struct dirent as the argument, so you don't have to worry about concatenating strings.
I'll see if there is a such a function and edit my answer if I find one.
Every directory has at least two entries, the current directory - a single dot . - and the parent directory - two dots ..

program to validate directory name

I just want to write a program which takes a directory name as argument
Validate that it is in fact a directory
Get a listing of all files in the directory and print it
The word directory doesn't even appear in the C standard. This is an OS concept.
Look at stat. It will provide you with the information you want; all you have to do is interpret it.
Edit: A brief example.
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#define TRUE 1
#define FALSE 0
int is_dir(char *path)
{
struct stat dir_stats;
stat(path, &dir_stats);
if (S_ISDIR(dir_stats.st_mode))
return TRUE;
return FALSE;
}
For the list of files in the directory, use readdir.

How do I get the size of a directory in C?

Is there a POSIX function that will give me the size of a directory (including all sub-folders), roughly equivalent to "du -s somepath"?
$ man nftw
NAME
ftw, nftw - file tree walk
DESCRIPTION
ftw() walks through the directory tree
that is located under the directory
dirpath, and calls fn() once for each
entry in the tree. By default,
directories are handled before the
files and subdirectories they contain
(pre-order traversal).
CONFORMING TO
POSIX.1-2001, SVr4, SUSv1.
Simple example
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
static unsigned int total = 0;
int sum(const char *fpath, const struct stat *sb, int typeflag) {
total += sb->st_size;
return 0;
}
int main(int argc, char **argv) {
if (!argv[1] || access(argv[1], R_OK)) {
return 1;
}
if (ftw(argv[1], &sum, 1)) {
perror("ftw");
return 2;
}
printf("%s: %u\n", argv[1], total);
return 0;
}
There is no ready-made function, so you will have to make your own. You may look at the source code of the GNU implemenation of du as an example (see http://www.gnu.org/prep/ftp.html for a list of places to download from). It is in the coreutils package.
The crucial Posix calls are probably opendir, readdir, closedir, and stat.
Result in bytes:
du -sb | grep -oE '^\s*[0-9]+'

Resources