/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- rmtree
- armtree_delete_dirs
- armtree_ll_add
- armtree_ll_delete
- armtree_ll_debug
/* Directory tree removal API.
Rick Smereka, Copyright (C) 2005.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, get a copy via the Internet at
http://gnu.org/copyleft/gpl.html or write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston,
MA 02111-1307 USA
You can contact the author via email at rsmereka@future-lab.com
This API will delete all files and directories from a specific
directory. BE VERY CAREFULL. You can easly delete the entire
contents of the disk by starting from the root of the drive.
This API uses the 'dscan' API to navigate through the tree.
Two passes take place. The first pass deletes all the files
and stores all directory names in a link list (new entires
are added to the top of the list [LIFO]). The second pass
goes through the link list from the top and deletes all
the directories.
Original version for Linux. Jan/2005, Rick Smereka.
Ported to QNX, 32bit Windows and DOS. Jun/2005, Rick Smereka. */
#include "stdhead.h"
#include "dscan.h"
#include "armtree.h"
// global data
// directory name link list node structure
struct armtree_entry
{
char *dir_path;
struct armtree_entry *next;
};
#define ARMTREE_NULL ((struct armtree_entry *)NULL)
struct armtree_entry *armtree_head;
// private functions
static int armtree_delete_dirs(void);
static int armtree_ll_add(char *);
static void armtree_ll_delete(void);
static void armtree_ll_debug(void);
int rmtree(char *path)
{
/* Delete all files and directores from 'path' down.
Function returns 'TRUE' upon success, 'FALSE'
otherwise. */
char mname[] = "rmtree", fname[256];
int ret;
if (path == (char *)NULL || !strlen(path))
{
logman("%s:exit[0]:null or empty[path]", mname);
return(FALSE);
}
logman("%s:enter:path=%s", mname, path);
// scan for everything and include sub-directories
#ifdef OS_UNIX
if ((ret = dscan_findfirst(path, "*", "flds", fname)) == FALSE)
#else
if ((ret = dscan_findfirst(path, "*", "fds", fname)) == FALSE)
#endif
{
logman("%s:exit[0]:bad rc[FALSE] from dscan_findfirst", mname);
return(FALSE);
}
// loop to delete files and build dir link list
while(ret)
{
switch(ret)
{
case DSCAN_TYPE_FILE:
logman("%s:deleting found file %s", mname, fname);
unlink(fname);
break;
case DSCAN_TYPE_DIR:
logman("%s:adding found dir %s", mname, fname);
if (!armtree_ll_add(fname))
{
logman("%s:exit[0]:bad rc[FALSE] from armtree_ll_add", mname);
return(FALSE);
}
break;
#ifdef OS_UNIX
case DSCAN_TYPE_SYMLINK:
logman("%s:deleting found symlink %s", mname, fname);
unlink(fname);
break;
#endif
default:
logman("%s:unknown type:rc=%d", mname, ret);
};
ret = dscan_findnext(fname);
}
// armtree_ll_debug();
// delete all directories in the tree
if (!armtree_delete_dirs())
{
logman("%s:exit:deletion of all dirs failed", mname);
armtree_ll_delete();
return(FALSE);
}
logman("%s:delete of all sub-dirs successful", mname);
armtree_ll_delete();
// remove top level directory
if (rmdir(path))
{
logman("%s:exit:deletion of top level dir %s failed", mname, path);
return(FALSE);
}
logman("%s:delete of top level dir successful", mname);
return(TRUE);
}
static int armtree_delete_dirs(void)
{
/* Delete all directories in the link list. Function
returns 'TRUE' upon success, 'FALSE' otherwise. */
struct armtree_entry *rov = armtree_head;
char mname[] = "armtree_delete_dirs";
while(rov != ARMTREE_NULL)
{
if (rmdir(rov->dir_path))
{
logman("%s:exit[0]:delete of dir %s failed", mname, rov->dir_path);
return(FALSE);
}
rov = rov->next;
}
return(TRUE);
}
static int armtree_ll_add(char *dirname)
{
/* Add a directory to the link list. The new entry will be
placed at the top of the list. Function returns 'TRUE'
upon success, 'FALSE' otherwise. */
struct armtree_entry *rov;
struct armtree_entry *prev;
char mname[] = "armtree_ll_add";
int size, len;
if (dirname == (char *)NULL || !strlen(dirname))
{
logman("%s:exit[0]:null or empty[dirname]", mname);
return(FALSE);
}
if (armtree_head != ARMTREE_NULL)
prev = armtree_head;
else
prev = ARMTREE_NULL;
size = sizeof(struct armtree_entry);
len = strlen(dirname);
// if the last char of the path is '.', do not add
if (dirname[len - 1] == '.')
return(TRUE);
if ((rov = (struct armtree_entry *)malloc(size)) == ARMTREE_NULL)
{
logman("%s:exit[0]:alloc fail[rov]", mname);
return(FALSE);
}
if ((rov->dir_path = (char *)malloc(len + 1)) == (char *)NULL)
{
logman("%s:exit[0]:alloc fail[rov->dir_path]", mname);
free(rov);
return(FALSE);
}
strcpy(rov->dir_path, dirname);
armtree_head = rov;
rov->next = prev;
return(TRUE);
}
static void armtree_ll_delete(void)
{
struct armtree_entry *rov = armtree_head;
struct armtree_entry *tmp;
while(rov != ARMTREE_NULL)
{
free(rov->dir_path);
tmp = rov->next;
free(rov);
rov = tmp;
}
armtree_head = ARMTREE_NULL;
}
static void armtree_ll_debug(void)
{
struct armtree_entry *rov = armtree_head;
while(rov != ARMTREE_NULL)
{
logman("dir:%s", rov->dir_path);
rov = rov->next;
}
}