Discussion:
recursive dir delete
mehul radheshyam choube
2005-01-19 19:08:24 UTC
Permalink
hi friends,

i am trying to write a c program which when given a directory path will recursive delete the contents of the directory and then delete the directory.

which data structure should i use?(i think tree data structure).........
any ideas on data structures,some precautions,...

mehul.
Kevin Partridge
2005-01-19 19:08:24 UTC
Permalink
are you trying to not use 'exec' ?

kevin
Stewart Stremler
2005-01-19 19:08:24 UTC
Permalink
Post by mehul radheshyam choube
hi friends,
i am trying to write a c program which when given a directory path
will recursive delete the contents of the directory and then delete the
directory.
"rm -rf dirname"
Post by mehul radheshyam choube
which data structure should i use?(i think tree data structure).........
any ideas on data structures,some precautions,...
Is this for your own edification, or is it an assignment?

The data structure most appropriate would be a stack, if you wanted
a data structure. Personally, I'd just use recursion, and then revise
to an iterative solution if profiling indicated this was a bottleneck.

-Stewart "Recursion is Divine." Stremler
John H. Robinson, IV
2005-01-19 19:08:24 UTC
Permalink
Post by Stewart Stremler
Post by mehul radheshyam choube
i am trying to write a c program which when given a directory path
will recursive delete the contents of the directory and then delete the
directory.
The data structure most appropriate would be a stack, if you wanted
a data structure. Personally, I'd just use recursion, and then revise
to an iterative solution if profiling indicated this was a bottleneck.
i'd go the recursion route, also. because Recursion is Fun(TM).

speaking of that, in a perl script i wrote to do the exact same thing,
(since i'm allergic to exec()) i did use recursion.

-john
mehul radheshyam choube
2005-01-19 19:08:24 UTC
Permalink
Post by Stewart Stremler
Is this for your own edification, or is it an
assignment?
we are writing a ftp client program and for this i am given the module which will recursively delete the directory.
Post by Stewart Stremler
The data structure most appropriate would be a stack,
if you wanted
a data structure. Personally, I'd just use recursion,
and then revise
to an iterative solution if profiling indicated this
was a bottleneck.
i have decided to use tree data structure and have written a recursive function
rfCreateDirTree(struct node *dirTree,char *dirName)
this create a tree of all the dirctories in the directory dirName.i have dine upto this.
now i think i will calculate the depth of the tree and start deleting from the node with highest depth.is this ok???
please i need some guidence as i want to create a effective recursive dir delete function.

mehul.
Stewart Stremler
2005-01-19 19:08:24 UTC
Permalink
begin repeating what mehul radheshyam choube wrote on Sat, Feb 16, 2002 at 09:03:53AM -0000 :
[snip]
Post by mehul radheshyam choube
i have decided to use tree data structure and have written a
recursive function rfCreateDirTree(struct node *dirTree,char *dirName)
"rf"? Radio Frequency?
Post by mehul radheshyam choube
this create a tree of all the dirctories in the directory dirName.i have dine upto this.
That seems the hard way to do it. Is there some reason why you need to
data in a tree? Does the user validate the directories to be deleted
first?
Post by mehul radheshyam choube
now i think i will calculate the depth of the tree and start
deleting from the node with highest depth.is this ok???
Too much work.
Post by mehul radheshyam choube
please i need some guidence as i want to create a effective recursive dir delete function.
If you're using recursion, all you need is a list and a loop.

Some pascalish psuedo-code:

procedure recursiveDelete( FILE fp )
begin
if isDirectory( fp ) then
begin
list[] := getDirectoryContents( fp )
for i := list.start to list.end
begin
recursiveDelete( list[ i ] )
system_call_delete_dir( fp )
end
endfor
end
else
begin
system_call_delete_file( fp );
end
endif
end

NOTE that this psuedocode makes a ton of assumptions. It assumes
that everything not a directory is a file. It assumes that there
are no loops in the file system. It assumes that all calls return
without error. And it assumes that the faked up syntax is obvious.

In short, this is academic "algorithm" code, suitable for students,
and to demonstrate the algorithm, but with all the typical checking
required in production code simply stripped out and thrown away.

-Stewart "Assuming" Stremler
mehul radheshyam choube
2005-01-19 19:08:24 UTC
Permalink
now this is the code i have written for recursively deleting the contents of a folder.

i am going to change it so that given a dirname it will not delete dirname but will delete other than dirname.

there are reasons why i used tree data structure.
for example :-

there is a folder fdt, say it contents subfolders sd1,sd2,sd3. say sd1 has subfolder ssd1.
now if i use gftp to delete contents od fdt it deletes in following seq.

remove /fdt/sd1/ssd1
remove /fdt/sd3
remove /fdt/sd2
remove /fdt/sd1

now i want to delete in same manner but yet to acheive it. i think tree data structure will help me in this like if i calculate depth of the tree and then start deleting from highest depth. or like this ...

please go through it and give suggestions.

mehul.

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

#define Error(Str) FatalError(Str)
#define FatalError(Str) fprintf(stderr, "%s\n", Str), exit(1)

struct treenode
{
struct treenode *father; ----> not using now
char data[257];
struct treenode *son;
struct treenode *next;
};
typedef struct treenode *NODEPTR;

NODEPTR rfCreateTreeNode(NODEPTR,char *,int);

NODEPTR rfCreateDirTree(NODEPTR,char *,int);

void rfPrintDirTree(NODEPTR);

int rfDeleteDirTree(NODEPTR);

int main(void)
{

NODEPTR tree = NULL;
int retStatus;

tree = rfCreateTreeNode(tree,"/usr/kalinga/ftp_delete_test1",-1);

tree = rfCreateDirTree(tree,"/usr/kalinga/ftp_delete_test1",-1);

rfPrintDirTree(tree);

retStatus = rfDeleteDirTree(tree);

return 0;

}//end of main()

NODEPTR rfCreateTreeNode(NODEPTR tree,char *value,int status)
{

if(tree == NULL)
{
//printf("1\n");
tree = (NODEPTR)malloc(sizeof(struct treenode));
if(tree == NULL)
FatalError("Out of space!!!");
else
tree->son = tree->next = tree->father = NULL;
strcpy(tree->data,value);
}//end of if(tree == NULL)

if(status == 1)
{
tree->son = rfCreateTreeNode(tree->son,value,-1);
tree->son->father = tree;
tree = tree->son;
}//end of if(status == 1)
if(status == 0)
{
while(tree->next != NULL)
tree = tree->next;
tree->next = rfCreateTreeNode(tree->next,value,-1);
tree->next->father = tree->father;
tree = tree->next;
}//end of if(status == 0)

return tree;

}//end of rfCreateTree()

NODEPTR rfCreateDirTree(NODEPTR dirTree,char *dirName,int iStatus)
{

DIR *dp;
struct dirent *d;
struct stat st;
static int fiCnt1 = 0;
int fiCnt2 = 0;
char filename[257];

if((dp=opendir(dirName)) == NULL)
{
printf ("ERROR unable to open %s directory, at line %d of file %s.\n",
dirName,__LINE__, __FILE__);
return NULL;
}//end of if((dp=opendir(dirName)) == NULL)

if(fiCnt1)
dirTree = rfCreateTreeNode(dirTree,dirName,iStatus);

while((d=readdir(dp))!= NULL)
{
if(!(strcmp(d->d_name,".")) || !(strcmp(d->d_name,"..")))
continue;

sprintf(filename,"%s/%s",dirName,d->d_name);

if(lstat(filename,&st) < 0)
return NULL;

if((st.st_mode & S_IFMT) == S_IFDIR)
{
fiCnt1++;
if(fiCnt2)
{
if(dirTree->son != NULL)
dirTree = rfCreateDirTree(dirTree->son,filename,0);
}//end of if(fiCnt2)
else
dirTree = rfCreateDirTree(dirTree,filename,1);

fiCnt2++;
}//end of if((st.st_mode & S_IFMT) == S_IFDIR)

}//end of while((d=readdir(dp))!= NULL)

if(dirTree->father != NULL)
dirTree = dirTree->father;

return dirTree;

}//end of rfCreateDirTree()

void rfPrintDirTree(NODEPTR tree)
{

if(tree != NULL)
{
rfPrintDirTree(tree->son);
printf("%s\n",tree->data);
rfPrintDirTree(tree->next);
}//end of if(tree != NULL)

}//end of fPrintTree()

int rfDeleteDirTree(NODEPTR tree)
{

DIR *dp;
struct dirent *d;
struct stat st;
char filename[257];
char cmd[263];

if(tree != NULL)
{
rfDeleteDirTree(tree->son);

if((dp=opendir(tree->data)) == NULL)
{
printf ("ERROR unable to open %s directory, at line %d of file %s.\n",
tree->data,__LINE__, __FILE__);
return -1;
}//end of if((dp=opendir(tree->data)) == NULL)

while((d=readdir(dp))!= NULL)
{
if(!(strcmp(d->d_name,".")) || !(strcmp(d->d_name,"..")))
continue;

sprintf(filename,"%s/%s",tree->data,d->d_name);

if(lstat(filename,&st) < 0)
return -1;

if((st.st_mode & S_IFMT) == S_IFDIR)
sprintf(cmd,"rmdir %s",filename);
else
sprintf(cmd,"rm %s",filename);

printf("Deleting %s...\n",filename);

if(system(cmd) != 0)
{
printf ("ERROR when called system, at line %d of file %s.\n",
__LINE__, __FILE__);
return -1;
}//end of if(system(cmd) != 0)

}//end of while((d=readdir(dp))!= NULL)

rfDeleteDirTree(tree->next);

}//end of if(tree != NULL)

return 0;

}//end of fPrintTree()*/
Kevin Partridge
2005-01-19 19:08:24 UTC
Permalink
ok...
i'm not a development programmer but i asked this earlier and it didn't get
a response.

is there some reason you don't want to use 'exec' and simply execute the
systems rm -rf command?
is there a super portability issue? do you simply want the exercise in
programming?

this is just as much for my education as it is for you.

if anyone else has any input please go ahead.

kevin
Stewart Stremler
2005-01-19 19:08:24 UTC
Permalink
Post by Kevin Partridge
ok...
i'm not a development programmer but i asked this earlier and it didn't get
a response.
is there some reason you don't want to use 'exec' and simply execute the
systems rm -rf command?
I dunno about the actual reason, but there are a number of issues
that might arise...
Post by Kevin Partridge
is there a super portability issue? do you simply want the exercise in
programming?
"All the world is Unix" is just as offensive (well, _almost_ as offensive)
as "All the world runs Windows" or "All the world's a VAX". Not all systems
may have an "rm" command, or the "rm" command it does take might not
support the -r or -f flags (or require them to be seperate: rm -r -f).

There might be peformance issues. An exec() is relatively slow. Witness
the frequent discussion about find and xargs.

There might be reliability issues. Perhaps the PATH for this process
one day fails to include /bin... or no 'rm' is to be found anywhere
in the program's accessible filesystem (e.g. it's running in a chrooted
environment and someone decided that _only_ this program should remove
files, and thus removed any instance of 'rm' in the chrooted bin dir.)
Post by Kevin Partridge
this is just as much for my education as it is for you.
In general, you do not want to hard-code commands to exec *anyway*.
Post by Kevin Partridge
if anyone else has any input please go ahead.
Heh.

-Stewart "Why, yes, I've replaced /bin/rm with a shell script before." Stremler
Kevin Partridge
2005-01-19 19:08:25 UTC
Permalink
Post by Stewart Stremler
"All the world is Unix" is just as offensive (well, _almost_ as offensive)
as "All the world runs Windows" or "All the world's a VAX". Not all systems
may have an "rm" command, or the "rm" command it does take might not
support the -r or -f flags (or require them to be seperate: rm -r -f).
because of the list this is on i kind of defaulted to a *NIX environment
thought process.
point taken.
Post by Stewart Stremler
There might be peformance issues. An exec() is relatively slow. Witness
the frequent discussion about find and xargs.
i thought about that but i thought it would be fairly negligible for an ftp
application.
Post by Stewart Stremler
There might be reliability issues. Perhaps the PATH for this process
one day fails to include /bin... or no 'rm' is to be found anywhere
in the program's accessible filesystem (e.g. it's running in a chrooted
environment and someone decided that _only_ this program should remove
files, and thus removed any instance of 'rm' in the chrooted bin dir.)
that (and the above problem with rm command arguments) could be solved with
appropriate make files and variable initialization / macros.
Post by Stewart Stremler
Post by Kevin Partridge
this is just as much for my education as it is for you.
In general, you do not want to hard-code commands to exec *anyway*.
i could see how it could be a problem in certain instances for security
reasons but that would depend on the robustness of the programming whether
you used exec or not... unless there is an issue i'm not aware of.

thanks, big Stew.
kevin
Stewart Stremler
2005-01-19 19:08:25 UTC
Permalink
Post by Kevin Partridge
Post by Stewart Stremler
There might be peformance issues. An exec() is relatively slow. Witness
the frequent discussion about find and xargs.
i thought about that but i thought it would be fairly negligible for an ftp
application.
True. And optimizing before testing and profiling is not a good thing. :)
Post by Kevin Partridge
Post by Stewart Stremler
There might be reliability issues. Perhaps the PATH for this process
one day fails to include /bin... or no 'rm' is to be found anywhere
in the program's accessible filesystem (e.g. it's running in a chrooted
environment and someone decided that _only_ this program should remove
files, and thus removed any instance of 'rm' in the chrooted bin dir.)
that (and the above problem with rm command arguments) could be solved with
appropriate make files and variable initialization / macros.
And install scripts, error-checking, user documentation.... and the code
gets pretty complex. Some people don't mind having code that requires a
lot of environmental support ("hey, that's what the install script is for!")
and others prefer to make an application as self-contained as possible.

e.g.

% cat README
1) untar the tarball.
2) edit the makefile to make sure you have the correct compiler set
3) type make
4) copy the resulting executable to wherever you need it
%

And, as usual, the "correct" way depends... :)

Personally, I *like* packages that don't go outside their domains, and
I would love it if the "official" way to distribute code was into distinct
directories, and only symbolic links were made to the actual executables,
libraries, etc.

"Uninstall" would then just be a matter of removing the directory, and
then searching for the broken symbolic links. Easy.
Post by Kevin Partridge
Post by Stewart Stremler
In general, you do not want to hard-code commands to exec *anyway*.
i could see how it could be a problem in certain instances for security
reasons but that would depend on the robustness of the programming whether
you used exec or not... unless there is an issue i'm not aware of.
There is a lot of discussion out there about this. The XP (eXtreme Proramming,
not M$) people say that the source should remain available and that you can
always go in and recompile, no problem.

(In my experience, it's very easy to lose code, or to lose track between
the current revision of code and the version actually executing out there
in the field. At work, I'm a bit of a CVS nut, chewing people out for
not checking intermediate-but-compiles code into the development tree.)

As far as the security aspect... well, it works both ways. On the one
hand, if the user can some how fool the system into exec'ing a different
program, undefined behavior results. If this program ends up being setgid
or setuid, then very BAD behavior is possible.

On the other hand, if the system administrator makes a change, and
cannot change the program to reflect the new changes in the system,
then you get a potential for chaotic behavior. But, like all things,
there is a time and a place....

(And command-oriented programming is just 'scripting'. :) )

-Stewart "Not A Guru" Stremler
Kevin Partridge
2005-01-19 19:08:25 UTC
Permalink
Post by Stewart Stremler
(And command-oriented programming is just 'scripting'. :) )
-Stewart "Not A Guru" Stremler
'not a guru' but thanks. that answered a lot from my non-developer
viewpoint.

kevin
Gregory Ade
2005-01-19 19:08:25 UTC
Permalink
Post by Stewart Stremler
Personally, I *like* packages that don't go outside their domains, and
I would love it if the "official" way to distribute code was into distinct
directories, and only symbolic links were made to the actual executables,
libraries, etc.
Trust me, if you've ever had to manage an SCO OpenServer system, you DO
NOT WANT THIS. Granted, they took this idea to the extreme. EVERYTHING
was symlinked, and all the packages installed from the OS distribution
media was actually installed into directories such as
/opt/K/SCO/Unix/5.0.5Eb or similar. Sure, it's a great idea, because
then in theory, all you have to do to upgrade the system is replace the
directories that the system lives in. Of course, then you have to
repoint all the symlinks. In the end, you end up with a big mess, but
that's because I believe SCO didn't quite get it right.
Post by Stewart Stremler
"Uninstall" would then just be a matter of removing the directory, and
then searching for the broken symbolic links. Easy.
Or, learning how to create an RPM or .deb, and using the appropriate
install/uninstall commands. =) Thousand ways to skin a cat, and stuff.
--
Gregory K. Ade <***@bigbrother.net>
http://unnerving.org/~gkade
OpenPGP Key ID: EAF4844B keyserver: pgpkeys.mit.edu
Stewart Stremler
2005-01-19 19:08:25 UTC
Permalink
Post by Gregory Ade
Post by Stewart Stremler
Personally, I *like* packages that don't go outside their domains, and
I would love it if the "official" way to distribute code was into distinct
directories, and only symbolic links were made to the actual executables,
libraries, etc.
Trust me, if you've ever had to manage an SCO OpenServer system, you DO
NOT WANT THIS. Granted, they took this idea to the extreme. EVERYTHING
was symlinked, and all the packages installed from the OS distribution
media was actually installed into directories such as
/opt/K/SCO/Unix/5.0.5Eb or similar.
Actually, the os distribution for a minimally bootable system should be
exempt. Stuff in /sbin should not be symlinked, for example. :)

'sides, if it's in /opt/, it's optional, and can be blown away at a
moment's notice, right? That doesn't seem a wise place to but essential
OS files. :)
Post by Gregory Ade
Sure, it's a great idea, because
then in theory, all you have to do to upgrade the system is replace the
directories that the system lives in. Of course, then you have to
repoint all the symlinks. In the end, you end up with a big mess, but
that's because I believe SCO didn't quite get it right.
I was thinking more along the lines of /opt/gcc-3.0.1, and in that
directory, you'd have a bin/, and a lib/, and so forth. Recreating the
symlinks would be a short shell-script or even a single command-line.
Post by Gregory Ade
Post by Stewart Stremler
"Uninstall" would then just be a matter of removing the directory, and
then searching for the broken symbolic links. Easy.
Or, learning how to create an RPM or .deb, and using the appropriate
install/uninstall commands. =) Thousand ways to skin a cat, and stuff.
I no longer trust RPM. It's hosed up my systems more times than Sun's
oft-considered-broken pkg system. I've never run Debian, so I don't know
how good or bad .deb is.

Personally, I do not trust the RPM creators to know what my system is
like. My /var may be large, as is my /opt, and I have a symlink from
/usr/local to /local, which is plenty of space, but no! they're going
to remove my symlink from /usr/local to /local, make a directory in
/usr/local/ fill my /usr disk, and then abort when the disk fills up.

(It's been so long I forget what it was I was trying to install. Something
trivial and optional, I'm sure...)

Besides, if you're using a package manager to install and uninstall, IT
can keep track of the symlinks too; the package manager neatly avoids the
difficulty you point out with SCO. You only run into a big mess if the
package management system is broken -- which, if it's broke, then using
it isn't an improvement -- or if you don't use a package management system
at all -- which kind of excludes .rpm and .deb and .pkg and all their ilk.

There's no reason why in install-script shouldn't be a directory creation,
fifo-creation from the install-file, a cd, a chroot, and a simple unpack.
The installer can make the appropriate symbolic links after it's installed,
or not, depending on the user's preferences.

After all, the sysadmin can always just do:

# echo "New compiler: Add /opt/gcc-4.11.3p6/bin to your PATH." >> /etc/motd

See? Easy!

(One of the gripes I've heard about about Sun's pkg system is that if the
package database in /var gets trashed, the whole system is hosed. It's
time to restore /var, or resinstall the OS, or stop patching and adding
packages. This scheme would allow for rebuilding the database, in a time
consuming but robust manner. I see that RPM has --rebuilddb -- how
does this actually work? Just where are the installed-package-headers?)

-Stewart "Maybe it's time to go back to Slackware." Stremler
Stewart Stremler
2005-01-19 19:08:24 UTC
Permalink
Post by mehul radheshyam choube
now this is the code i have written for recursively deleting the contents of a folder.
What's wrong with 80 columns. HIT RETURN. Turn on word-wrap. PLEASE.
Post by mehul radheshyam choube
i am going to change it so that given a dirname it will not delete
dirname but will delete other than dirname.
Huh?

Try again, please.
Post by mehul radheshyam choube
there are reasons why i used tree data structure.
for example :-
there is a folder fdt, say it contents subfolders sd1,sd2,sd3. say sd1 has subfolder ssd1.
Okay.
Post by mehul radheshyam choube
now if i use gftp to delete contents od fdt it deletes in following seq.
remove /fdt/sd1/ssd1
remove /fdt/sd3
remove /fdt/sd2
remove /fdt/sd1
Is this sorting order important?
Post by mehul radheshyam choube
now i want to delete in same manner but yet to acheive it.
You can't delete a directory until it is empty. This forces you
to delete the directory tree from the bottom-up anyways.
Post by mehul radheshyam choube
i think tree data structure will help me in this like if i calculate
depth of the tree and then start deleting from highest depth. or like this ...
Let's try a few more examples, first...

/root/a
/root/a/b
/root/a/b/c
/root/a/b/d
/root/a/e
/root/a/f
/root/a/f/g
/root/a/f/g/h
/root/a/f/g/i
/root/a/f/g/i/j
/root/a/f/k
/root/a/l
/root/m
/root/n

To delete this directory system, would this order be sufficient:

/root/a/b/c
/root/a/b/d
/root/a/b
/root/a/e
/root/a/f/g/h
/root/a/f/g/i/j
/root/a/f/g/i
/root/a/f/g
/root/a/f/k
/root/a/f
/root/a/l
/root/a
/root/m
/root/n

?
Post by mehul radheshyam choube
please go through it and give suggestions.
mehul.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#define Error(Str) FatalError(Str)
#define FatalError(Str) fprintf(stderr, "%s\n", Str), exit(1)
Try to practice define-before-use.

Try to avoid putting needless code into defines. Why not just

void die( char *message, int code ) {
fprintf( stderr, "\n%s\n", message );
exit( code );
}
Post by mehul radheshyam choube
struct treenode
{
struct treenode *father; ----> not using now
char data[257];
struct treenode *son;
struct treenode *next;
Isn't "parent", "child", and "sibling" the common way to structure trees?
Post by mehul radheshyam choube
};
typedef struct treenode *NODEPTR;
Personally, I am in the habit of typdef'ing the struct, and leaving the
dereferencing explicit.
Post by mehul radheshyam choube
NODEPTR rfCreateTreeNode(NODEPTR,char *,int);
NODEPTR rfCreateDirTree(NODEPTR,char *,int);
void rfPrintDirTree(NODEPTR);
int rfDeleteDirTree(NODEPTR);
Those should probably be in a .h file. :)
Post by mehul radheshyam choube
int main(void)
This isn't C.

int main( int argc, char **argv )

is legal C.
Post by mehul radheshyam choube
{
Ugh. I hate this brace convention. Objective-C forces it on you, but
to use it voluntarily? It's not wrong. Just ugly. :)
Post by mehul radheshyam choube
NODEPTR tree = NULL;
int retStatus;
tree = rfCreateTreeNode(tree,"/usr/kalinga/ftp_delete_test1",-1);
tree = rfCreateDirTree(tree,"/usr/kalinga/ftp_delete_test1",-1);
Hard-coding paths is bad. AT LEAST use a #define with some suitable
name:

#define TESTING_PATH_DIRECTORY_TO_BE_DELETED "/usr/kalinga/ftp_delete_test1"

...then there's less chance of you forgetting to yank this from the
production code; it's always annoying when someone leaves in a hard-coded
test...
Post by mehul radheshyam choube
rfPrintDirTree(tree);
retStatus = rfDeleteDirTree(tree);
return 0;
}//end of main()
When I do this, I am in the habit of just saying

}//main()

But that's just personal preference. "end of" doesn't help, as that is
what the } tells you.
Post by mehul radheshyam choube
NODEPTR rfCreateTreeNode(NODEPTR tree,char *value,int status)
{
if(tree == NULL)
You have a function called if()?
Post by mehul radheshyam choube
{
//printf("1\n");
tree = (NODEPTR)malloc(sizeof(struct treenode));
INDENT!
Post by mehul radheshyam choube
if(tree == NULL)
FatalError("Out of space!!!");
else
tree->son = tree->next = tree->father = NULL;
Fully-brace the code, especially code you're having someone else look at.

(And if you're debugging, de-chain the assignments.)
Post by mehul radheshyam choube
strcpy(tree->data,value);
}//end of if(tree == NULL)
if(status == 1)
Two blanks lines and no open-brace?

[Hopefully I didn't corrupt the message...]
Post by mehul radheshyam choube
tree->son = rfCreateTreeNode(tree->son,value,-1);
tree->son->father = tree;
tree = tree->son;
}//end of if(status == 1)
No blank lines? You didn't change status, so why not an "else if"?
Post by mehul radheshyam choube
if(status == 0)
{
while(tree->next != NULL)
tree = tree->next;
tree->next = rfCreateTreeNode(tree->next,value,-1);
tree->next->father = tree->father;
tree = tree->next;
}//end of if(status == 0)
return tree;
}//end of rfCreateTree()
I must admit that this is a very odd tree. Rather lispish, I think.
Post by mehul radheshyam choube
NODEPTR rfCreateDirTree(NODEPTR dirTree,char *dirName,int iStatus)
What does the 'rf' mean?
Post by mehul radheshyam choube
{
DIR *dp;
Where is DIR defined?
Post by mehul radheshyam choube
struct dirent *d;
struct stat st;
static int fiCnt1 = 0;
int fiCnt2 = 0;
char filename[257];
Isn't there a system constant you can use instead of 257?

What is a fiCnt anyway?

Avoid single-character and double-character variable names!

Use 'em for loops only.
Post by mehul radheshyam choube
if((dp=opendir(dirName)) == NULL)
{
printf ("ERROR unable to open %s directory, at line %d of file %s.\n",
dirName,__LINE__, __FILE__);
return NULL;
}//end of if((dp=opendir(dirName)) == NULL)
Okay, so at this point you have an open directory.
Post by mehul radheshyam choube
if(fiCnt1)
dirTree = rfCreateTreeNode(dirTree,dirName,iStatus);
This does nothing, as fiCnt1 is set to 0 when allocated, and never changed.
Post by mehul radheshyam choube
while((d=readdir(dp))!= NULL)
{
if(!(strcmp(d->d_name,".")) || !(strcmp(d->d_name,"..")))
continue;
sprintf(filename,"%s/%s",dirName,d->d_name);
if(lstat(filename,&st) < 0)
return NULL;
Don't you need to delete the filenames? Shouldn't you keep those around too?
Post by mehul radheshyam choube
if((st.st_mode & S_IFMT) == S_IFDIR)
{
fiCnt1++;
if(fiCnt2)
{
if(dirTree->son != NULL)
dirTree = rfCreateDirTree(dirTree->son,filename,0);
}//end of if(fiCnt2)
else
dirTree = rfCreateDirTree(dirTree,filename,1);
fiCnt2++;
}//end of if((st.st_mode & S_IFMT) == S_IFDIR)
Ah, recursion!
Post by mehul radheshyam choube
}//end of while((d=readdir(dp))!= NULL)
if(dirTree->father != NULL)
dirTree = dirTree->father;
return dirTree;
}//end of rfCreateDirTree()
So you have a hierarchial tree structure that mirrors your directory structure
that you want to get rid of. You've already traversed _one_ hierarchy to
build it, surely you can traverse it again.
Post by mehul radheshyam choube
void rfPrintDirTree(NODEPTR tree)
{
if(tree != NULL)
{
rfPrintDirTree(tree->son);
printf("%s\n",tree->data);
rfPrintDirTree(tree->next);
}//end of if(tree != NULL)
}//end of fPrintTree()
Now that's more like it. Recursive functions should be short!

[chop]

I think that's enough comments right now.

BTW, the way to find the height of a tree is to traverse the tree,
tracking the current depth and maximum depth. The height is the max
depth... For what you appear to be asking, you just need to traverse
the tree, storing the node and depth in a list, and then sorting the
list on the depth. THAT will get you deepest-first ordering....

Personally, I'd suggest deleting and printing the tree *as* you
recurse through the filesystem. Simpler, faster, cleaner...

-Stewart "My way is often not everyone else's way." Stremler
mehul radheshyam choube
2005-01-19 19:08:25 UTC
Permalink
now this seams to be simple no tree data structure.
(please read my earlier mail).

but i wanted to do deletion in an ordered way.
please go through the code and please give suggestions.

mehul.

(stew rf is for recursive function)

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

#define test "/usr/kalinga/ftp_delete_test1"

#define FILENAME_VAR_LEN 256

#define CMD_VAR_LEN 262

int isdir(char *ItemName)
{

struct stat st;

if(lstat(ItemName,&st) < 0)
exit(1);

return ((st.st_mode & S_IFMT) == S_IFDIR);

}//isdir()

int fGetDirContents(char ***DirContents,char *ItemName)
{

char **LocalDirContents = NULL;
struct dirent *d;
char filename[FILENAME_VAR_LEN + 1];
int iNoofItems=0;
int iPosition=0;
DIR *dp;

if((dp=opendir(ItemName)) == NULL)
{
printf ("ERROR unable to open %s directory, at line %d of file %s.\n",
ItemName,__LINE__, __FILE__);
return -1;
}//if((dp=opendir(dirName)) == NULL)

while((d=readdir(dp))!= NULL)
{
if(!(strcmp(d->d_name,".")) || !(strcmp(d->d_name,"..")))
continue;

sprintf(filename,"%s/%s",ItemName,d->d_name);

if((LocalDirContents = (char **)realloc(LocalDirContents,(iNoofItems + 1) * sizeof(char *))) == NULL)
{
printf("ERROR : realloc fail, at line %d of file %s.\n",
__LINE__, __FILE__);
return -1;
}

LocalDirContents[iPosition] = strdup(filename);

iPosition++;iNoofItems++;

}//while((d=readdir(dp))!= NULL)

*DirContents = LocalDirContents;

return iNoofItems;

}//fGetDirContents()

int rfDirDelete(char *ItemName)
{

int iNoofItems,iCnt;
int retStatus;
char cmd[CMD_VAR_LEN + 1];
char **DirContents = NULL;
int iCmpStatus;

if(isdir(ItemName))
{
iNoofItems = fGetDirContents(&DirContents,ItemName);

for(iCnt = (iNoofItems - 1); iCnt > -1 ; iCnt--)
{
retStatus = rfDirDelete(DirContents[iCnt]);

if(DirContents[iCnt])
free(DirContents[iCnt]);
DirContents[iCnt] = NULL;
}//for

sprintf(cmd,"rmdir %s",ItemName);

printf("Deleting %s...\n",ItemName);

if(system(cmd) != 0)
{
printf("ERROR when called system, at line %d of file %s.\n",
__LINE__, __FILE__);
return -1;
}//if(system(cmd) != 0)
}//if(isdir(ItemName))
else
{
sprintf(cmd,"rm %s",ItemName);

printf("Deleting %s...\n",ItemName);

if(system(cmd) != 0)
{
printf("ERROR when called system, at line %d of file %s.\n",
__LINE__, __FILE__);
return -1;
}//if(system(cmd) != 0)
}//else

iCmpStatus = strcasecmp(ItemName,test);
if(!iCmpStatus)
{
if(DirContents)
free(DirContents);
DirContents = NULL;
}//if(!iCmpStatus)

return 0;

}//rfDirDelete()

int main(void)
{

int retStatus;

retStatus = rfDirDelete(test);

return 0;
}//main()
Stewart Stremler
2005-01-19 19:08:25 UTC
Permalink
Post by mehul radheshyam choube
now this seams to be simple no tree data structure.
(please read my earlier mail).
but i wanted to do deletion in an ordered way.
Was the ordering I listed in my response before sufficient an ordering?
Post by mehul radheshyam choube
please go through the code and please give suggestions.
mehul.
(stew rf is for recursive function)
Oh, it's hungarian notation? Ugh. I *hate* hungarian notation.

[chop]
Post by mehul radheshyam choube
int isdir(char *ItemName)
{
Now is the time for comment blocks, too. :)
Post by mehul radheshyam choube
struct stat st;
if(lstat(ItemName,&st) < 0)
exit(1);
return ((st.st_mode & S_IFMT) == S_IFDIR);
}//isdir()
Is "//" legal C yet? Was that C99?
Post by mehul radheshyam choube
int fGetDirContents(char ***DirContents,char *ItemName)
{
I always wince when I see ***. Lessee, you're wanting to set
an output value that is an array of strings. Okay. What if there
is already something there?
Post by mehul radheshyam choube
char **LocalDirContents = NULL;
struct dirent *d;
char filename[FILENAME_VAR_LEN + 1];
int iNoofItems=0;
int iPosition=0;
DIR *dp;
if((dp=opendir(ItemName)) == NULL)
{
printf ("ERROR unable to open %s directory, at line %d of file %s.\n",
ItemName,__LINE__, __FILE__);
return -1;
}//if((dp=opendir(dirName)) == NULL)
while((d=readdir(dp))!= NULL)
{
if(!(strcmp(d->d_name,".")) || !(strcmp(d->d_name,"..")))
continue;
sprintf(filename,"%s/%s",ItemName,d->d_name);
Potential buffer overflow. Use snprintf, or check the size of d->d_name,
and ItemName.

Actually, *always* prefer snprintf in favor of sprintf. You could also use
strncat as well, I suppose.
Post by mehul radheshyam choube
if((LocalDirContents = (char **)realloc(LocalDirContents,(iNoofItems + 1) * sizeof(char *))) == NULL)
iNoofItems? What is a noof?

<ponders>

Ah. Integer-Number-Of-Items. Isn't "itemCount" or "item_count" easier? :)
Post by mehul radheshyam choube
{
printf("ERROR : realloc fail, at line %d of file %s.\n",
__LINE__, __FILE__);
return -1;
}
LocalDirContents[iPosition] = strdup(filename);
Note: strdup is a wrapper around malloc, and may therefore return null.
Post by mehul radheshyam choube
iPosition++;iNoofItems++;
This kind of thing is the first step to the path to obscurity. :)
Post by mehul radheshyam choube
}//while((d=readdir(dp))!= NULL)
*DirContents = LocalDirContents;
You just stomped on the argument without checking to see if there was data
there -- potentially, you have a memory leak.
Post by mehul radheshyam choube
return iNoofItems;
}//fGetDirContents()
int rfDirDelete(char *ItemName)
{
int iNoofItems,iCnt;
int retStatus;
char cmd[CMD_VAR_LEN + 1];
char **DirContents = NULL;
int iCmpStatus;
if(isdir(ItemName))
{
iNo
This is not a valid C statement.
Post by mehul radheshyam choube
for(iCnt = (iNoofItems - 1); iCnt > -1 ; iCnt--)
{
retStatus = rfDirDelete(DirContents[iCnt]);
DirContents has not been set yet in this function.
Post by mehul radheshyam choube
if(DirContents[iCnt])
free(DirContents[iCnt]);
DirContents[iCnt] = NULL;
If the 'if' fails, isn't the second statement redundant?
Post by mehul radheshyam choube
}//for
sprintf(cmd,"rmdir %s",ItemName);
WARNING! WARNING! DANGER WILL ROBINSON!

(And not just the sprintf vs. snprintf...)
Post by mehul radheshyam choube
printf("Deleting %s...\n",ItemName);
if(system(cmd) != 0)
You're using system(). That means you're passing the command to the shell.
But the command is a single string. Filenames may contain spaces. (And
they may contain ; as well, IIRC, with may be even worse.) Shells tokenize
on spaces. So what gets deleted may not be what you want.

If you're doing it this way -- bit by bit -- then go ahead an use unlink.

If you want to use system() or fork()-exec(), use "rm -rf" to do the
recursive walk _for_ you.
Post by mehul radheshyam choube
{
printf("ERROR when called system, at line %d of file %s.\n",
__LINE__, __FILE__);
return -1;
}//if(system(cmd) != 0)
}//if(isdir(ItemName))
else
{
sprintf(cmd,"rm %s",ItemName);
printf("Deleting %s...\n",ItemName);
if(system(cmd) != 0)
{
printf("ERROR when called system, at line %d of file %s.\n",
__LINE__, __FILE__);
return -1;
}//if(system(cmd) != 0)
}//else
Quite aside from everything else, this could have been collapsed, in that
the only difference was the command in the sprintf...
Post by mehul radheshyam choube
iCmpStatus = strcasecmp(ItemName,test);
if(!iCmpStatus)
{
if(DirContents)
free(DirContents);
DirContents = NULL;
}//if(!iCmpStatus)
return 0;
}//rfDirDelete()
int main(void)
{
int retStatus;
retStatus = rfDirDelete(test);
return 0;
}//main()
-Stewart "HTH" Stremler
mehul radheshyam choube
2005-01-19 19:08:25 UTC
Permalink
Post by mehul radheshyam choube
Post by mehul radheshyam choube
int fGetDirContents(char ***DirContents,char
*ItemName)
Post by mehul radheshyam choube
{
I always wince when I see ***. Lessee, you're wanting
to set
an output value that is an array of strings. Okay. What
if there
is already something there?
in DirContents? the actual parameter which is being assinged to formal parameter DirContents is initialised to NULL.
Post by mehul radheshyam choube
sprintf(filename,"%s/%s",ItemName,d->d_name);
Potential buffer overflow. Use snprintf, or check the
size of d->d_name,
and ItemName.
ok will look into this.
Post by mehul radheshyam choube
Post by mehul radheshyam choube
LocalDirContents[iPosition] =
strdup(filename);
Note: strdup is a wrapper around malloc, and may
therefore return null.
oh this is a major bug will correct this.
Post by mehul radheshyam choube
Post by mehul radheshyam choube
iPosition++;iNoofItems++;
This kind of thing is the first step to the path to
obscurity. :)
what do u mean i didnt get u.
Post by mehul radheshyam choube
Post by mehul radheshyam choube
if(DirContents[iCnt])
free(DirContents[iCnt]);
DirContents[iCnt] = NULL;
If the 'if' fails, isn't the second statement redundant?
oh oh oh.
Post by mehul radheshyam choube
Post by mehul radheshyam choube
if(system(cmd) != 0)
You're using system(). That means you're passing the
command to the shell.
But the command is a single string. Filenames may
contain spaces. (And
they may contain ; as well, IIRC, with may be even
worse.) Shells tokenize
on spaces. So what gets deleted may not be what you
want.
If you're doing it this way -- bit by bit -- then go
ahead an use unlink.
If you want to use system() or fork()-exec(), use "rm
-rf" to do the
recursive walk _for_ you.
i am already using unlink.

mehul.

Loading...