So I'm working on a C program with UNIX as its terminal, and the program is supposed to call my directory recursively. The output should give me the directory themselves and the time period they were modified.
The code works, it compiles well, but it refuses to display its output.
And right now all I need is to display the output. But this is what it gives me...
I've tried ./compdir, ./compdir dir1 dir2, and also ./compdir dir2 dir1...the only possible solution in the UNIX terminal, but to no avail.
Can someone help me out? Here is the code down below. I appreciate your help.
#include <stdio.h>
#include <ctype.h>
#include <math.h>
#include <stdlib.h>
#include <dirent.h>
#include <errno.h>
#include <sys/stat.h>
#include <string.h>
#include <time.h>
#define E_INVALIDSWITCH 100
#define E_TOOMANYPARAMS 101
#define E_TOOFEWPARAMS 102
#define E_OPENDIRFAIL 103
void status();
void greetDirectory(char * baseDir, char * modDir);
int main(int argc, char ** argv)
{
int R_switch = 0;
char * modDir = NULL;
char * baseDir = NULL;
int i;
for (i = 1; i < argc; i++)
{
if (argv[i][0] == '-')
{
if (strcmp(argv[i], "-R") == 0)
{
R_switch = 1;
}
else
{
fprintf(stderr, "Error: Invalid switch %s\n", argv[i]);
status();
return E_INVALIDSWITCH;
}
}
else
{
if (baseDir == NULL)
{
baseDir = argv[i];
}
else if (modDir == NULL)
{
modDir = argv[i];
}
else
{
fprintf(stderr, "Error: Too many parameters\n");
status();
return E_TOOMANYPARAMS;
}
}
}
if (modDir == NULL)
{
fprintf(stderr, "Error: Too few parameters\n");
status();
return E_TOOFEWPARAMS;
}
if (R_switch)
{
greetDirectory(baseDir, modDir);
}
return 0;
}
void status()
{
printf("\t-R\tGreet all files in current directory\n");
printf("\t<modDir>\tName of person being greeted\n");
}
char *formatdate(char *buff, time_t val)
{
strftime(buff,200, "%d.%m.%Y %H:%M:%S", localtime(&val));
return buff;
}
void greetDirectory(char * baseDir, char * modDir)
{
DIR * directory;
struct dirent * dirInfo;
directory = opendir(baseDir);
if (directory == NULL)
{
fprintf(stderr,
"opendir() failed for '%s', errno=%d\n",
baseDir,
errno);
exit(E_OPENDIRFAIL);
}
while((dirInfo = readdir(directory)) != NULL)
{
if (strcmp(dirInfo->d_name, ".") != 0 &&
strcmp(dirInfo->d_name, "..") != 0)
{
/* BASE DIR*/
char basePathName[PATH_MAX];
strcpy(basePathName, baseDir);
strcat(basePathName, "/");
strcat(basePathName, dirInfo->d_name);
/* MOD DIR */
char modPathName[PATH_MAX];
strcpy(modPathName, modDir);
strcat(modPathName, "/");
strcat(modPathName, dirInfo->d_name);
struct stat statBuf;
struct stat otherStatBuf;
if (stat(basePathName, &statBuf) == -1)
{
/* error! */
fprintf(stderr, "stat() failed for '%s'", basePathName);
}
else
{
//display time
stat(modPathName, &otherStatBuf);
if (statBuf.st_mtime > otherStatBuf.st_mtime)
{
char date[36];
printf("Modify: %s\n", formatdate(date, otherStatBuf.st_mtime));
}
if (S_ISDIR(statBuf.st_mode))
{
/* if this is a directory, then recurse! */
greetDirectory(basePathName, modPathName);
}
else
{
/* else if it's a file, then greet it! */
printf("entry name = %s\n", modPathName);
}
}
}
}
closedir(directory);
}
Your code will give output only when you specify the -R switch.
If you do not want this behavior, you need to remove if block on line 72 and call greetDirectory function directly.
// Remove if block
if (R_switch)
{
greetDirectory(baseDir, modDir);
}
// Replace with
greetDirectory(baseDir, modDir);
Here is the full code:
#include <stdio.h>
#include <ctype.h>
#include <math.h>
#include <stdlib.h>
#include <dirent.h>
#include <errno.h>
#include <sys/stat.h>
#include <string.h>
#include <time.h>
#define E_INVALIDSWITCH 100
#define E_TOOMANYPARAMS 101
#define E_TOOFEWPARAMS 102
#define E_OPENDIRFAIL 103
#define MAX_DIR_NAME_SIZE 100
void status();
void greetDirectory(char * baseDir, char * modDir);
int main(int argc, char ** argv)
{
int R_switch = 0;
char modDir[MAX_DIR_NAME_SIZE] = {0};
char baseDir[MAX_DIR_NAME_SIZE] = {0};
int i;
for (i = 1; i < argc; i++)
{
if (argv[i][0] == '-')
{
if (strcmp(argv[i], "-R") == 0)
{
R_switch = 1;
continue;
}
else
{
fprintf(stderr, "Error: Invalid switch %s\n", argv[i]);
status();
return E_INVALIDSWITCH;
}
}
else
{
if (baseDir[0] == 0 && modDir[0] == 0)
{
strcpy(baseDir, argv[i]);
strcpy(modDir, argv[i]);
}
else
{
fprintf(stderr, "Error: Too many parameters\n");
status();
return E_TOOMANYPARAMS;
}
}
}
if (modDir[0] == 0)
{
fprintf(stderr, "Error: Too few parameters\n");
status();
return E_TOOFEWPARAMS;
}
if (R_switch)
{
greetDirectory(baseDir, modDir);
}
return 0;
}
void status()
{
printf("\t-R\tGreet all files in current directory\n");
printf("\t<modDir>\tName of person being greeted\n");
}
char *formatdate(char *buff, time_t val)
{
strftime(buff,200, "%d.%m.%Y %H:%M:%S", localtime(&val));
return buff;
}
void greetDirectory(char * baseDir, char * modDir)
{
DIR * directory;
struct dirent * dirInfo;
directory = opendir(baseDir);
if (directory == NULL)
{
fprintf(stderr,
"opendir() failed for '%s', errno=%d\n",
baseDir,
errno);
exit(E_OPENDIRFAIL);
}
while((dirInfo = readdir(directory)) != NULL)
{
if (strcmp(dirInfo->d_name, ".") != 0 &&
strcmp(dirInfo->d_name, "..") != 0)
{
/* BASE DIR*/
char basePathName[PATH_MAX];
strcpy(basePathName, baseDir);
strcat(basePathName, "/");
strcat(basePathName, dirInfo->d_name);
/* MOD DIR */
char modPathName[PATH_MAX];
strcpy(modPathName, modDir);
strcat(modPathName, "/");
strcat(modPathName, dirInfo->d_name);
struct stat statBuf;
struct stat otherStatBuf;
if (stat(basePathName, &statBuf) == -1)
{
/* error! */
fprintf(stderr, "stat() failed for '%s'", basePathName);
}
else
{
//display time
stat(modPathName, &otherStatBuf);
if (statBuf.st_mtime > otherStatBuf.st_mtime)
{
char date[36];
printf("Modify: %s\n", formatdate(date, otherStatBuf.st_mtime));
}
if (S_ISDIR(statBuf.st_mode))
{
/* if this is a directory, then recurse! */
greetDirectory(basePathName, modPathName);
}
else
{
/* else if it's a file, then greet it! */
printf("entry name = %s\n", modPathName);
}
}
}
}
closedir(directory);
}
The main problem was in your loop where you assign values to modDir and baseDir. Say, for example, you have the argument -R, so you want to print out the directory names. You assign R_switch a value of 1 since argv[1] is -R. The problem is, you go on in the loop to assign baseDir and modDir -R as well! This should have been done on the next iteration of the loop, when argv[2] is whatever directory you put in for input.
The very simple way to solve this problem is to add a continue; statement after you set R_switch a value of 1.
Also note that while playing around, I did create the limitation of having a MAX_DIR_NAME_SIZE, when it was not needed with the char * you were working with originally. It should be fairly easy to change this back. I also ended up changing the comparison of modDir and baseDir to something like if (baseDir[0] == 0 && modDir[0] == 0), which probably should have still been done by comparing your char * to NULL (like it was originally).
Related
I'm trying to sort a current working directory, sub-directories, and then display them. My program behavior begins the process and works for the first sub-directory but none after that. A few prints are to check behavior of the code. While there is a complete working version of this on stackoverflow, I just want to better understand where my code logic is failing. Any help is greatly appreciated. Here is the code:
#include <stdio.h>
#include <dirent.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/types.h>
void sortArr(char array[256][256], int amt) {
char temp[1000];
for(int i=0; i<amt; i++) {
for(int j=0; j<(amt-1-i); j++) {
if(strcmp(array[j], array[j+1]) > 0) {
strcpy(temp, array[j]);
strcpy(array[j], array[j+1]);
strcpy(array[j+1], temp);
}
}
}
printf("SortList: %s\n", array[0]);
}
void build(char *s_path, const int root) {
char path[1000];
strcat(path, s_path);
int amt=0,index;
struct dirent *dp;
DIR *dir =opendir(path);
char list[256][256];
struct stat statbuf;
if(!dir)
return;
while((dp =readdir(dir)) != NULL) {
if (strcmp(dp->d_name, ".") != 0 && strcmp(dp->d_name, "..") != 0) {
strcpy(list[amt], dp->d_name);
amt++;
}
}
sortArr(list, amt);
for(int i=0; i <amt;i++) {
for (index=0; index<root; index++) {
if (index%2 == 0 || index == 0)
printf("%c", ' ');
else
printf(" ");
}
printf("%c %s\n", '-', list[i]);
strcpy(path, s_path);
strcat(path, "/");
strcat(path, list[i]);
stat(path, &statbuf);
if((S_ISDIR(statbuf.st_mode)) != 0 && (S_ISREG(statbuf.st_mode)) ==0) {
printf("DIR: %s\n", path);
build(path,root +2);
}
}
closedir(dir);
}
int main() {
build(".", 0);
};
Based on my comments.
The key problem is that you've no idea what's in path when you call build(), so concatenating on the end does nothing reliable. Either add path[0] = '\0'; before the call to strcat(), or (simpler) use strcpy().
That fixes your problems as long as your directories do not have more than 256 entries (other than . and ..) in them.
If you do have bigger directories, you run into problems. Those would be resolved by using dynamic memory allocation — malloc() et al, and using strdup(), probably. That which you allocate you should free, too, of course.
You should check that the calls to stat() succeed, but they won't often fail. One time they could fail is if a file is removed between the when readdir() returns the name and the time when the code calls stat() for the file.
There are POSIX tools for scanning directories. These include:
scandir()
nftw()
Amended source code (including some uncommented upon changes):
#include <dirent.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
static
void sortArr(char array[356][256], int amt)
{
char temp[1000];
for (int i = 0; i < amt; i++)
{
for (int j = 0; j < (amt - 1 - i); j++)
{
if (strcmp(array[j], array[j + 1]) > 0)
{
strcpy(temp, array[j]);
strcpy(array[j], array[j + 1]);
strcpy(array[j + 1], temp);
}
}
}
printf("SortList: %s\n", array[0]);
}
static
void build(const char *s_path, int root)
{
char path[1000];
strcpy(path, s_path);
int amt = 0;
struct dirent *dp;
DIR *dir = opendir(path);
char list[356][256];
struct stat statbuf;
if (!dir)
return;
while ((dp = readdir(dir)) != NULL)
{
if (strcmp(dp->d_name, ".") != 0 && strcmp(dp->d_name, "..") != 0)
{
strcpy(list[amt], dp->d_name);
amt++;
}
}
sortArr(list, amt);
for (int i = 0; i < amt; i++)
{
printf("%*s", root, "");
/*for (int index = 0; index < root; index++)*/
/* putchar(' ');*/
printf("%c %s\n", '-', list[i]);
strcpy(path, s_path);
strcat(path, "/");
strcat(path, list[i]);
if (stat(path, &statbuf) != 0)
{
fprintf(stderr, "failed to stat name '%s' (%d: %s)\n", path, errno, strerror(errno));
continue;
}
if ((S_ISDIR(statbuf.st_mode)) != 0 && (S_ISREG(statbuf.st_mode)) == 0)
{
printf("DIR: %s\n", path);
build(path, root + 2);
}
}
closedir(dir);
}
int main(void)
{
build(".", 0);
}
EDIT : Note that It's not that I can't access the memory allocated by storeContents() in main() if you think so. Program crashes during the execution of storeContents()
The program fails here :
strcpy(contents[count], dir->d_name);
printf("Stored %s(out hiddenVisible)\n", dir->d_name); // for testing
It's strcpy() not the printf(), I added it just for the reference.
The debugger(gdb) says :
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7f3cd72 in __strcpy_ssse3 () from /usr/lib/libc.so.6
I am making a program that involves the following function "storeContents"(It stores contents' names of a directory in a dynamic array). There are two issues with this function : (1) It says "Stored file_name" twice for the first file and (2) says "Segmentation fault". I can't figure out either of them. Thanks for your efforts!
#include <stdio.h>
#include <string.h>
#include <dirent.h>
#include <stdlib.h>
#include <sys/types.h>
#include <limits.h>
static short hiddenVisible = 0;
/* Store directory's contents in **contents */
static char ** storeContents(struct dirent *dir, DIR *dirp, unsigned numOfContents);
/* Count files/directories in a directory */
static unsigned getNumOfContents(struct dirent *dir, DIR *dirp);
int main(int argc, char const *argv[])
{
char **contents;
DIR *dirp;
struct dirent *dir;
unsigned numOfContents;
dirp = opendir("/home/gaurav");
if((dir = readdir(dirp)) == NULL) {
perror("readdir");
exit(1);
}
/* Getting number of files/directories */
numOfContents = getNumOfContents(dir, dirp);
printf("There are %u files.\n", numOfContents);
/* To position again to the first entry */
rewinddir(dirp);
contents = storeContents(dir, dirp, numOfContents);
/* Print contents */
for(unsigned i = 0; i < numOfContents; ++i)
printf("%s\n", contents[i]);
closedir(dirp);
return 0;
}
char **
storeContents(struct dirent *dir, DIR *dirp, unsigned numOfContents) {
char **contents;
unsigned count = 0;
/* Allocating memory for entries */
contents = malloc(numOfContents * sizeof(*contents));
/* Allocating memory for each '*contents' */
for(unsigned i = 0; i < numOfContents; i++)
contents[i] = (char *)malloc(NAME_MAX); /* we know char is 1 byte, so no "sizeof" */
while(count < numOfContents) {
/* Ignore "." and ".." */
if(!(strcmp(dir->d_name, ".")) || !(strcmp(dir->d_name, ".."))) {
if((dir = readdir(dirp)) == NULL) {
perror("readdir");
exit(1);
}
continue;
}
if(hiddenVisible) {
strcpy(contents[count], dir->d_name);
if((dir = readdir(dirp)) == NULL) {
perror("readdir");
exit(1);
}
count++;
} else {
if(dir->d_name[0] == '.')
if((dir = readdir(dirp)) == NULL) {
perror("readdir");
exit(1);
}
else {
strcpy(contents[count], dir->d_name);
if((dir = readdir(dirp)) == NULL) {
perror("readdir");
exit(1);
}
count++;
}
}
}
return contents;
}
unsigned
getNumOfContents(struct dirent *dir, DIR *dirp) {
unsigned count = 0;
while(dir) {
if(hiddenVisible) {
/* Ignore "." and ".." */
if(!(strcmp(dir->d_name, ".")) || !(strcmp(dir->d_name, ".."))) {
if((dir = readdir(dirp)) == NULL) {
perror("readdir a");
exit(1);
}
continue;
}
count++;
if((dir = readdir(dirp)) == NULL) {
perror("readdir b");
exit(1);
}
} else {
if(dir->d_name[0] == '.') {
if((dir = readdir(dirp)) == NULL) {
perror("readdir c");
exit(1);
}
}
else {
count++;
if((dir = readdir(dirp)) == NULL) {
perror("readdir d");
exit(1);
}
}
}
}
return count;
}
contents in the function storeContents is a local copy of contents from main.
Changing it in the function does not change the variable in main.
You should return the array. Change
static void storeContents(struct dirent *dir, DIR *dirp, char **contents, unsigned numOfContents);
to
static char **storeContents(struct dirent *dir, DIR *dirp, unsigned numOfContents);
,return contents; in the function and call it like char **contents = storeContents(...);
Some bugs:
contents is a local parameter to the function, it will not get returned to main(). See Dynamic memory access only works inside function.
contents = (char **)malloc(numOfContents); is wrong, you need to allocate room for numOfContents pointers. Change this to contents = malloc(numOfContents * sizeof(*contents)).
You should check each call to readdir and make sure it doesn't return NULL.
The goal is to compare files by size and filter those of the same size.
For that you need to compare every file to every file.
However the first loop doesnt work so the search of the first directory is stuck at the first file.
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/stat.h>
int main(int argc, char *v[]) {
struct dirent *d_verzeichnis1;
struct dirent *d_verzeichnis2;
DIR *dir1;
DIR *dir2;
FILE *file = fopen(v[3], "W");
dir1 = opendir(v[1]);
dir2 = opendir(v[2]);
struct stat filesize1;
struct stat filesize2;
while ((d_verzeichnis1 = readdir(dir1)) != NULL) {
stat((d_verzeichnis1->d_name), &filesize1);
while ((d_verzeichnis2 = readdir(dir2)) != NULL) {
stat((d_verzeichnis2->d_name), &filesize2);
if (filesize1.st_size == filesize2.st_size);
{
printf("%s und %s sind gleich\n",
d_verzeichnis1->d_name, d_verzeichnis2->d_name);
}
}
d_verzeichnis1 = readdir(dir1);
}
}
There are multiple problems in your code:
you should verify the actual number of arguments provided on the command line to avoid undefined behavior if fewer than 3 were provided.
fopen(v[3], "W"); uses an invalid mode string, you should use "w". It is unclear what this stream pointer is used for anyway.
dir1 and dir2 are not tested: you have undefined behavior if opendir() fails.
stat is called with the directory entry name, which is not a relative pathname to the file if the directory is different from the current directory. You should construct the path name from the directory name and entry name.
if (filesize1.st_size == filesize2.st_size); has an extra ; at the end of the line, causing the following block to execute unconditionally. You should use K&R style with{` at the end of the line to avoid such silly mistakes.
the logic of parallel scan is incorrect: you should reopen or at least rewind the second directory for each entry in the first to allow a full scan for potential matches.
Here is a corrected version:
#include <dirent.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/stat.h>
char *buildpath(char *dest, size_t size, const char *dir, const char *name) {
size_t len = strlen(dir);
const char *sep = "";
if (len > 0 && dir[len - 1] != '/')
sep = "/";
if ((unsigned)snprintf(dest, size, "%s%s%s", dir, sep, name) < size)
return dest;
else
return NULL;
}
int main(int argc, char *argv[]) {
char path1[1024];
char path2[1024];
struct dirent *dp1;
struct dirent *dp2;
DIR *dir1;
DIR *dir2;
struct stat filesize1;
struct stat filesize2;
if (argc < 3) {
fprintf(stderr, "missing argument\n");
fprintf(stderr, "usage: cmpdir dir1 dir2\n");
return 1;
}
dir1 = opendir(argv[1]);
if (dir1 == NULL) {
fprintf(stderr, "cannt open directory %s: %s\n", argv[1], strerror(errno));
return 1;
}
dir2 = opendir(argv[2]);
if (dir2 == NULL) {
fprintf(stderr, "cannt open directory %s: %s\n", argv[2], strerror(errno));
return 1;
}
while ((dp1 = readdir(dir1)) != NULL) {
/* ignore . and .. entries */
if (!strcmp(dp1->d_name, ".")
|| !strcmp(dp1->d_name, ".."))
continue;
if (!buildpath(path1, sizeof path1, argv[1], dp1->d_name)) {
/* path too long */
continue;
}
if (stat(path1, &filesize1)) {
/* cannot stat entry */
continue;
}
if (!S_ISREG(filesize1.st_mode)) {
/* not a regular file */
continue;
}
rewinddir(dir2);
while ((dp2 = readdir(dir2)) != NULL) {
/* ignore . and .. entries */
if (!strcmp(dp2->d_name, ".")
|| !strcmp(dp2->d_name, ".."))
continue;
if (!buildpath(path2, sizeof path2, argv[2], dp2->d_name)) {
/* path too long */
continue;
}
if (stat(path2, &filesize2)) {
/* cannot stat entry */
continue;
}
if (!S_ISREG(filesize2.st_mode)) {
/* not a regular file */
continue;
}
if (filesize1.st_size == filesize2.st_size) {
printf("%s and %s have the same size %llu\n",
path1, path2, (unsigned long long)filesize1.st_size);
/* perform actual comparison... */
}
}
}
closedir(dir1);
closedir(dir2);
return 0;
}
I am trying to count only the directories from a path, but it doesn't work. So, i don't want to number both files and directories, i want only the directories. Could you help me, please?
The code:
int listdir(char *dir) {
struct dirent *dp;
struct stat s;
DIR *fd;
int count = 0;
if ((fd = opendir(dir)) == NULL) {
fprintf(stderr, "listdir: can't open %s\n", dir);
}
while ((dp = readdir(fd)) != NULL) {
if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
continue;
stat(dp->d_name, &s);
if (S_ISDIR(s.st_mode))
count++;
}
closedir(fd);
return count;
}
your stat() call will fail, since you are not in the correct directory. This you can solve by either changing the current directory, or generate full paths and give to stat as argument.
Some Unixes, you can optimize away the stat call by looking at struct dirent, the d_type field
int listdir(char *dir) {
struct dirent *dp;
struct stat s;
DIR *fd;
int count = 0;
if ((fd = opendir(dir)) == NULL) {
fprintf(stderr, "listdir: can't open %s\n", dir);
}
chdir (dir); /* needed for stat to work */
while ((dp = readdir(fd)) != NULL) {
if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
continue;
#ifdef _DIRENT_HAVE_D_TYPE
switch (dp->d_type)
{
case DT_UNKNOWN:
stat(dp->d_name, &s);
if (S_ISDIR(s.st_mode)) count++;
break;
case DT_DIR:
count++;
break;
}
#else
stat(dp->d_name, &s);
if (S_ISDIR(s.st_mode)) count++;
#endif
}
closedir(fd);
return count;
}
I think you want...
written in C
count the number of directoriesfrom a path.
the counting function will returns int value.
I have no idea about your environment, so it is just a example solution.
If you can use glob, it is so easy to count the number of directories. that is: main.c
#include <stdio.h>
#include <glob.h>
#include <string.h>
#define MAX_PATH 1023
int countDirectories(char* dir)
{
char path[MAX_PATH] = "";
strcat(path, dir);
strcat(path, "/*");
glob_t globbuf;
long i, count = 0;
if (glob(path, GLOB_NOSORT | GLOB_ONLYDIR, NULL, &globbuf) == 0)
{
count = globbuf.gl_pathc;
for (i = 0; i < globbuf.gl_pathc; i++)
{
count += countDirectories(globbuf.gl_pathv[i]);
}
}
globfree(&globbuf);
return count;
}
int main(int argc, char* argv[])
{
int count;
if (argc > 1)
{
count = countDirectories(argv[1]);
}
else
{
count = countDirectories(".");
}
printf("there are %d directories.\n", count);
return 0;
}
and you can try this like:
> gcc main.c -o testglob
> ./testglob /path/to/target/dir
then you'll receive output like this:
path = /path/to/target/dir/*, there are N directories
thanks.
I have a program that recursively prints the cwd size plus containing file sizes and repeats for each sub directory.
Recursive directory traversal function: (Note the reason for printf in this function and passing two strings is that the output needs to be in a special format so I can't just output the actual filepath. Also I am just learning about system calls to work with directories in ubuntu so if you have any comments on improvements on the code I would appreciate them (style or using something more simple to accomplish the same).
#include <sys/stat.h>
#include <limits.h>
#include <dirent.h>
#include <libgen.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define TRUE 1
#define FALSE 0
#define FIRST_ARG 1
#define SECOND_ARG 2
char* fileName;
FILE* fileToRead;
DIR* directoryToRead;
int printFileSize(char*);
int printWorkingSize(char*, char*);
int printSize(char*, char*);
int printDir(char*, char*);
int printCurrentDir(char*, char*);
int bytesToKbytes(long long, char*);
int main(int argc, char** argv) {
if(argc == FIRST_ARG) {
char currentDir[PATH_MAX + 1] = "";
char* currentDirectory;
directoryToRead = opendir (".");
if (directoryToRead == NULL){
exit (EXIT_FAILURE);
}
closedir(directoryToRead);
printCurrentDir(currentDirectory, ".");
}
return 0;
}
int printCurrentDir(char* name, char* path) {
struct dirent *dir;
struct stat statBuffer;
char fileName[PATH_MAX + 1];
char filePath[PATH_MAX + 1];
DIR* openDir;
if((openDir = opendir(path)) == NULL) {
printf("Could not open %s\n", path);
}
stat(path, &statBuffer);
if(strcmp(path, ".") == 0) {
printf("%lld .\n", (long long)statBuffer.st_size);
} else {
printf("%lld %s\n", (long long)statBuffer.st_size, name);
}
while (TRUE) { // go through contents of current directory
dir = readdir(openDir);
if(!dir) {
break;
}
if((strcmp(dir->d_name, "..") == 0) || (strcmp(dir->d_name,".") == 0)) {
continue;
}
if(name == NULL) {
strcpy(fileName, dir->d_name);
} else {
strcpy(fileName, name);
strcat(fileName, "/");
strcat(fileName, dir->d_name);
}
strcpy(filePath, path);
strcat(filePath, "/");
strcat(filePath, dir->d_name);
if(dir->d_type == DT_DIR) { // if the next file is a directory
if(!printCurrentDir(fileName, filePath)) {
return FALSE;
}
}
else if(!printWorkingSize(fileName, filePath)) {
return FALSE;
}
}
return TRUE;
}
//output file size in bytes followed by name-> (char* file)
int printWorkingSize(char* file, char* path) {
struct stat statBuffer;
stat(path, &statBuffer);
char result[PATH_MAX];
if(bytesToKbytes((long long)statBuffer.st_size, result) == FALSE) {
sprintf(result, "%lld", (long long)statBuffer.st_size);
}
printf("%5s %s\n", result, path);
return TRUE;
}
// convert bytes to kilobytes if more than 5 digits
int bytesToKbytes(long long bytes, char* result) {
if(!(bytes > 99999)) {
return FALSE;
}
char size[PATH_MAX];
sprintf(size, "%lld", bytes);
size[3] = 'K';
size[4] = '\0';
strcpy(result, size);
return TRUE;
}
It is operating system specific. On Linux and POSIX, you should simply use the nftw(3) library function, which is recursively reading the directories and already calling stat(2) for you.
The problem is effectively in the way you use bytesToKbytes. It returns a boolean to indicate if it wrote anything in result and :
you do not preload anything in result before calling bytesToKbytes
you do not test return value to write anything in resul if size was less than 99999
You could use :
int printWorkingSize(char* file, char* path) {
struct stat statBuffer;
stat(path, &statBuffer);
char result[PATH_MAX];
if (! bytesToKbytes((long long)statBuffer.st_size, result)) {
sprintf(result, "%lld", (long long)statBuffer.st_size);
}
printf("%5s %s\n", result, path);
return TRUE;
}
You could also change bytesToKbytes to put length in bytes into resul if size is less than 99999