Reputation: 15
kimhyojong@kimhyojong-VirtualBox:~/newpro$ tree
.
├── main
├── main.c
├── main.c~
├── mkdirTest
│ ├── recursion
│ ├── test1
│ │ └── recursion1
│ └── test2
│ └── recursion2
├── re
├── recurs
│ └── what
├── recursion
├── recursion.c
└── test3
It looks so beatiful.
I can get this tree by ' apt-get install tree'.
So I want to print like that tree.
And this is my code
void recursion(const char *pwd){
char next[255];
struct dirent *filelist;
struct stat info;
int i;
int dirNum;
DIR* dp;
if((dp = opendir(pwd)) == NULL)
{
exit(1);
}
if(dp != NULL)
{
while((filelist = readdir(dp)))
{
if((strcmp(".", filelist->d_name) == 0) || (strcmp("..", filelist->d_name) == 0))
continue;
memset(next, 0, 255);
lstat(filelist->d_name, &info);
if(S_ISDIR(info.st_mode))
{
strcat(next, pwd);
strcat(next, "/");
strcat(next, filelist->d_name);
printf("%-15s", filelist->d_name);
printf("%s\n", next);
recursion(next);
}
else
printf("%-15s\n", filelist->d_name);
}
}
}
I think it works by recursion.
but, it is printing like this.
test3
recursion.c
main
mkdirTest recursion
test2
test1
recursion
main.c~
main.c
recurs what
re
Not recursing.... Just root lvl and next lvl. No more proceed.
What's the problem?
Upvotes: 0
Views: 76
Reputation: 1655
There are a number of problems in your code.
Your call to lstat
is silently failing if you are not in the current directory (the one you started the program from). This is because filelist->d_name
does not include the path.
When you find a directory (when lstat
works) you are printing its name twice. This is because filelist->d_name
and next
are the same except for a prefixed path on the latter.
You have no code to put multiple levels of spaces or tabs in to get the tree structure.
Even if you were calling lstat
correctly, it would break on directories you don't have access to (e.g. those owned by root
).
My suggestions are:
Right near the start of your recursion
function, change to the directory that is passed as an argument, using chdir
, then call opendir(".")
. Hopefully lstat
will work at that point. You can save the current working directory (getcwd
) and restore it at the end of the function, so as not to mess things up for further calls.
Only print the name of the file once.
Pass in a level
argument to your recursion argument which counts the number of levels you are down in the tree (0 when you first call it). Add 1 to this for future recursions. You can then use level
to print spaces or tabs to get the tree effect.
I don't have a solution for the permissions issue. Maybe check for the error code on lstat
and print a question mark for that entry?
Here is some code which implements some of the above suggestions and might work (not properly tested):
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/stat.h>
#include <unistd.h>
#define TABSIZE 4
void recursion(const char *pwd, int level) { // note number of levels added
char next[255];
struct dirent *filelist;
struct stat info;
int i;
int dirNum;
DIR* dp;
char * lastpwd;
lastpwd = getcwd(NULL, 0); // remember current directory
if (chdir(pwd) != 0) { // change directory to pwd
free(lastpwd);
exit(1);
};
if((dp = opendir(".")) == NULL) // opendir is called on cwd
{
chdir(lastpwd);
free(lastpwd);
exit(1);
}
if(dp != NULL)
{
while((filelist = readdir(dp)))
{
if((strcmp(".", filelist->d_name) == 0) ||
(strcmp("..", filelist->d_name) == 0))
continue;
memset(next, 0, 255);
lstat(filelist->d_name, &info);
for (i=0; i<level*TABSIZE; i++) { // spaces for tree effect
putchar(' ');
}
printf("%s\n", filelist->d_name); // print just once
if(S_ISDIR(info.st_mode)) // note info will be broken
// if lstat silently failed
{
strcat(next, filelist->d_name);
recursion(next, level+1); // recurse, next level down
}
}
}
chdir(lastpwd); // restore current directory
free(lastpwd);
}
int main(int argc, char ** argv)
{
recursion(argv[1], 0);
return 0;
}
Upvotes: 1