/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- dscan_findfirst
- dscan_findnext
- dscan_end
- dscan_ll_debug
- dscan_find
- dscan_sub
- dscan_add_sub
- dscan_chop_path
- dscan_match
- dscan_umatch
- dscan_set_flags
- dscan_set_current_path
- dscan_ll_delete
- dscan_ll_delete_all
- dscan_set_mvars
- dscan_delete_mvars
- dscan_ll_find
- dscan_ll_add
- dscan_header
/* Directory scanning API.
Rick Smereka, Copyright (C) 2001-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
This directory scanning module/API will traverse one or more directories
from a specific entry point matching file/directory names. This API is
multi-platform. It will compile and run in under any OS that supports
the POSIX 1003.1 directory system calls. This includes 16bit DOS, 32bit
Windows, QNX (both RtP and 4.x) and all versions of Linix/Unix. This API
does not use recursion to traverse the directory tree and is not subject to
stack limitations and excessive memory consumption typical with recursive
algorithms.
You can contact the author via email at rsmereka@future-lab.com
Original version for Unix, QNX, DOS and Windows. Feb/2001, Rick Smereka
Ported to Debian Linux. Nov/2002, Rick Smereka
Changed all logging calls from 'log_file_date' to 'logman'.
Mar/2004, Rick Smereka
Modified function 'dscan_find' to use the 'lstat' function
instead of 'stat'. Added detection of symbolic links
API now returns 'SCAN_TYPE_SYMLINK' when a symbolic link is found.
Added the global variable 'dscan_for_symlinks'. Added detection
of the option 'l' for symbolic links. Symbolic link detection
and return of this type is available only on the QNX/Linux/Unix
platforms. Jan/2005, Rick Smereka */
#include "stdhead.h"
#include "dscan.h"
#define DSCAN_SUB_DELIM '*'
struct dscan_entry
{
DIR *dir;
char *dir_path;
char *subs;
int sub_count;
int sub_index;
struct dscan_entry *next;
};
/* private function prototypes */
static int dscan_find(char *);
static int dscan_sub(void);
static void dscan_add_sub(struct dscan_entry *, char *);
static int dscan_chop_path(void);
static int dscan_match(char *, char *);
static int dscan_umatch(char *, char *);
static int dscan_set_flags(char *);
static int dscan_set_current_path(char *);
static void dscan_ll_delete(char *);
static void dscan_ll_delete_all(void);
static int dscan_set_mvars(char *, char *);
static void dscan_delete_mvars(void);
static struct dscan_entry *dscan_ll_find(char *);
static struct dscan_entry *dscan_ll_add(char *);
static void dscan_header(char *);
/* module globals */
struct dscan_entry *dscan_list_head = NULL;
char *dscan_base_path = NULL;
char *dscan_current_path = NULL;
char *dscan_fname = NULL;
int dscan_for_files;
int dscan_for_dirs;
#ifdef OS_UNIX
int dscan_for_symlinks;
#endif
int dscan_descend;
int dscan_findfirst(char *path, char *fname, char *flags, char *pfname)
{
/* Find the first occurance of the file 'fname' within the 'path'.
The 'flags' can have any combination of 'fdls' where 'f' is
scan for files, 'd' is scan for directories, 'l' is scan for
symbolic links (QNX/Linux/Unix only) and 's' is descend into
sub-directories. If an item is found, its full path
and name is loaded into 'pfname'. Function returns a type
code (file, directory or symlink) upon success. Function returns
'FALSE' otherwise. */
char mname[] = "dscan_findfirst";
int ret;
dscan_header(mname);
if (path == (char *)NULL || !strlen(path))
{
logman("%s:exit[0]null or empty[path]", mname);
return(FALSE);
}
if (fname == (char *)NULL || !strlen(fname))
{
logman("%s:exit[0]null or empty[fname]", mname);
return(FALSE);
}
if (flags == (char *)NULL || !strlen(flags))
{
logman("%s:exit[0]null or empty[flags]", mname);
return(FALSE);
}
if (pfname == (char *)NULL)
{
logman("%s:exit[0]null[pfname]", mname);
return(FALSE);
}
if (!isdirectory(path))
{
logman("%s:%s is not a directory", mname, path);
return(FALSE);
}
logman("%s:path=%s[%d],fname=%s[%d],flags=%s[%d]",
mname, path, strlen(path), fname, strlen(fname),
flags, strlen(flags));
dscan_delete_mvars();
if (!dscan_set_mvars(path, fname))
{
logman("%s:exit[0]bad rc[0] from dscan_set_mvars", mname);
return(FALSE);
}
if (!dscan_set_flags(flags))
{
logman("%s:exit[0]bad rc[0] from dscan_set_flags", mname);
return(FALSE);
}
if (dscan_list_head != NULL)
{
logman("%s:link list already exists, deleting", mname);
dscan_ll_delete_all();
}
if (!dscan_set_current_path(dscan_base_path))
{
logman("%s:exit[0]bad rc[0] from dscan_set_current_path", mname);
return(FALSE);
}
ret = dscan_findnext(pfname);
logman("%s:exit[%d]:pfname=%s[%d]", mname, ret, pfname,
strlen(pfname));
return(ret);
}
int dscan_findnext(char *pfname)
{
/* Find the next occurance of the desired file/directory.
'dscan_findfirst' must be called initially. Function
returns a type code with the full path and item name
in 'pfname' upon success. Function returns 'FALSE'
otherwise. */
char mname[] = "dscan_findnext";
int ret;
logman("%s:enter:cp=%s", mname, dscan_current_path);
if (pfname == NULL)
{
logman("%s:exit[0]null[pfname]", mname);
return(FALSE);
}
pfname[0] = EOS;
while(TRUE)
{
/* find next occurance in current directory */
if ((ret = dscan_find(pfname)) != FALSE)
{
logman("%s:exit[%d]:pfname=%s[%d]", mname,
ret, pfname, strlen(pfname));
return(ret);
}
if (!dscan_descend)
{
logman("%s:exit[0]:no subs processed", mname);
return(FALSE);
}
/* locate sub-directory or go up one level */
if (!dscan_sub())
{
logman("%s:exit[0]:no more subs", mname);
return(FALSE);
}
}
logman("%s:exit[0]", mname);
return(FALSE);
}
void dscan_end(void)
{
/* De-allocate all memory used by 'dscan'. */
char mname[] = "dscan_end";
dscan_header(mname);
dscan_ll_delete_all();
dscan_delete_mvars();
logman("%s:exit", mname);
}
void dscan_ll_debug(void)
{
/* Output the current contents of the link list
to the log file (if active). */
struct dscan_entry *rov;
char mname[] = "dscan_ll_debug";
int cnt;
logman("%s:enter", mname);
rov = dscan_list_head;
if (rov == NULL)
{
logman("%s:exit:link list empty", mname);
return;
}
cnt = 1;
while(rov != NULL)
{
logman("%s[%d]:path=%s[%d],sc=%d,si=%d",
mname, cnt, rov->dir_path, strlen(rov->dir_path),
rov->sub_count, rov->sub_index);
if (rov->subs != NULL)
logman("%s[%d]:subs=%s[%d]", mname, cnt, rov->subs,
strlen(rov->subs));
rov = rov->next;
cnt++;
}
logman("%s:normal exit", mname);
}
static int dscan_find(char *fname)
{
/* Find an item in the current path. Function returns
a type code with the item name in 'fname' upon
success, 'FALSE' otherwise. */
struct dscan_entry *rov;
struct dirent *direntry;
struct stat stat_buf;
char mname[] = "dscan_find";
char *full_name;
int len, type;
logman("%s:enter:cp=%s", mname, dscan_current_path);
// locate link list pointer to current path or add if not found
if ((rov = dscan_ll_find(dscan_current_path)) == NULL)
{
logman("%s:rc[NULL] from dscan_ll_find, will add", mname);
if ((rov = dscan_ll_add(dscan_current_path)) == NULL)
{
logman("%s:exit[0]bad rc[NULL] from dscan_ll_add[0]", mname);
return(FALSE);
}
}
// scan each item in directory
while((direntry = readdir(rov->dir)) != NULL)
{
len = strlen(dscan_current_path) + strlen(direntry->d_name) + 2;
if ((full_name = (char *)malloc(len)) == (char *)NULL)
{
logman("%s:exit[0]alloc fail[full_name]", mname);
return(FALSE);
}
// concatenate full name
len = strlen(dscan_current_path);
if (dscan_current_path[len - 1] == PATH_SEP)
sprintf(full_name, "%s%s", dscan_current_path, direntry->d_name);
else
sprintf(full_name, "%s%c%s", dscan_current_path, PATH_SEP,
direntry->d_name);
// under QNX/Linux/Unix use 'lstat' otherwise use 'stat'
#ifdef OS_UNIX
if (lstat(full_name, &stat_buf) != 0)
#else
if (stat(full_name, &stat_buf) != 0)
#endif
{
free(full_name);
logman("%s:exit[0]bad rc from stat,full_name=%s",
mname, full_name);
return(FALSE);
}
// get object type
type = stat_buf.st_mode & S_IFMT;
// process based on type
switch(type)
{
case S_IFREG:
// a regular file
if (dscan_for_files)
if (dscan_match(dscan_fname, direntry->d_name))
{
strcpy(fname, full_name);
free(full_name);
logman("%s:exit[%d]:found file=%s[%d]", mname,
DSCAN_TYPE_FILE, fname, strlen(fname));
return(DSCAN_TYPE_FILE);
}
break;
case S_IFDIR:
// a directory
// don't process '.' and '..'
if (!strcmp(direntry->d_name, "."))
{
logman("%s:found reference to current dir,ignoring", mname);
break;
}
if (!strcmp(direntry->d_name, ".."))
{
logman("%s:found reference to parent dir,ignoring", mname);
break;
}
if (dscan_descend)
dscan_add_sub(rov, direntry->d_name);
if (dscan_for_dirs)
if (dscan_match(dscan_fname, direntry->d_name))
{
strcpy(fname, full_name);
free(full_name);
logman("%s:exit[%d]:found dir=%s[%d]", mname,
DSCAN_TYPE_DIR, fname, strlen(fname));
return(DSCAN_TYPE_DIR);
}
break;
#ifdef OS_UNIX
case S_IFLNK:
// a symbolic link
if (dscan_for_symlinks)
if (dscan_match(dscan_fname, direntry->d_name))
{
strcpy(fname, full_name);
free(full_name);
logman("%s:exit[%d]:found symlink=%s[%d]", mname,
DSCAN_TYPE_SYMLINK, fname, strlen(fname));
return(DSCAN_TYPE_SYMLINK);
}
break;
#endif
default:
logman("%s:exit[FALSE]:%s[%d] is an unknown type",
mname, full_name, strlen(full_name));
free(full_name);
return(FALSE);
};
free(full_name);
}
logman("%s:exit[0]", mname);
return(FALSE);
}
static int dscan_sub(void)
{
/* Locate a sub-directory of the current or go back up one
level in the directory tree. Function returns 'TRUE'
if another directory was found, 'FALSE' otheriwse. */
struct dscan_entry *rov;
char mname[] = "dscan_sub";
char *p, *s;
int len;
dscan_header(mname);
logman("%s:cp=%s", mname, dscan_current_path);
if ((rov = dscan_ll_find(dscan_current_path)) == NULL)
{
logman("%s:exit[0]bad rc[NULL] from dscan_ll_find", mname);
return(FALSE);
}
if (rov->sub_count)
{
rov->sub_index++;
logman("%s:subs=%s,si=%d,sc=%d", mname, rov->subs, rov->sub_index,
rov->sub_count);
if (rov->sub_index <= rov->sub_count)
{
len = ll_wordlen(rov->subs, rov->sub_index, DSCAN_SUB_DELIM);
logman("%s:word[%d]len=%d", mname, rov->sub_index, len);
if ((s = (char *)malloc(len + 1)) == NULL)
{
logman("%s:exit[0]:alloc fail[s]", mname);
return(FALSE);
}
if (!ll_word(rov->subs, s, rov->sub_index, DSCAN_SUB_DELIM))
{
free(s);
logman("%s:exit[0]:bad rc from ll_word", mname);
return(FALSE);
}
len = len + strlen(dscan_current_path) + 2;
if ((p = (char *)malloc(len)) == NULL)
{
free(s);
logman("%s:exit[0]:alloc fail[p]", mname);
return(FALSE);
}
len = strlen(dscan_current_path);
if (dscan_current_path[len - 1] == PATH_SEP)
sprintf(p, "%s%s", dscan_current_path, s);
else
sprintf(p, "%s%c%s", dscan_current_path, PATH_SEP, s);
logman("%s:pick sub:new cp=%s[%d]", mname, p, strlen(p));
free(s);
if (!dscan_set_current_path(p))
{
free(p);
logman("%s:exit[0]:bad rc[0] from dscan_set_current_path",
mname);
return(FALSE);
}
free(p);
logman("%s:exit[TRUE]", mname);
return(TRUE);
}
}
dscan_ll_delete(dscan_current_path);
if (!strcmp(dscan_base_path, dscan_current_path))
{
dscan_end();
logman("%s:exit[0]:back at base path, assuming done", mname);
return(FALSE);
}
if (!dscan_chop_path())
{
logman("%s:exit[0]:bad rc[0] from dscan_chop_path", mname);
return(FALSE);
}
logman("%s:exit[TRUE]", mname);
return(TRUE);
}
static void dscan_add_sub(struct dscan_entry *rov, char *dname)
{
/* Add a directory name to the indicated entries sub-directory
list. */
char mname[] = "dscan_add_sub";
char *outstr;
int len;
dscan_header(mname);
if (rov == NULL || dname == NULL || !strlen(dname))
{
logman("%s:exit[0]parm error", mname);
return;
}
logman("%s:cp=%s,dname=%s,sc=%d,si=%d", mname,
dscan_current_path, dname, rov->sub_count, rov->sub_index);
/* if no subs present, add first one */
if (rov->sub_count == 0)
{
if ((rov->subs = (char *)malloc(strlen(dname) + 1)) == NULL)
return;
strcpy(rov->subs, dname);
rov->sub_count++;
logman("%s:exit:add first sub name", mname);
return;
}
/* add sub name to delimited list of sub names */
len = strlen(rov->subs) + strlen(dname) + 2;
if ((outstr = (char *)malloc(len)) == (char *)NULL)
{
logman("%s:exit:alloc fail[outstr]", mname);
return;
}
rov->sub_count++;
if (ll_wordput(rov->subs, outstr, dname, rov->sub_count, DSCAN_SUB_DELIM))
{
len = strlen(outstr);
free(rov->subs);
rov->subs = NULL;
if ((rov->subs = (char *)malloc(len + 1)) == (char *)NULL)
{
logman("%s:exit:alloc fail[rov->subs]", mname);
return;
}
strcpy(rov->subs, outstr);
}
else
logman("%s:bad rc[0] from ll_wordput[%s]", mname, dname);
free(outstr);
logman("%s:normal exit", mname);
}
static int dscan_chop_path(void)
{
/* Remove one level from the current path. Function returns
'TRUE' upon success, 'FALSE' otherwise. */
char mname[] = "dscan_chop_path";
char *p;
int nwords, len;
dscan_header(mname);
nwords = ll_words(dscan_current_path, PATH_SEP);
len = strlen(dscan_current_path);
if ((p = (char *)malloc(len + 1)) == NULL)
{
logman("%s:exit[0]alloc fail[p]", mname);
return(FALSE);
}
if (!ll_worddel(dscan_current_path, p, nwords, PATH_SEP))
{
free(p);
logman("%s:exit[0]bad rc from ll_worddel", mname);
return(FALSE);
}
len = strlen(p);
/* detect back at drive root */
#ifdef OS_WIN32
/* windoze where a drive ID is present */
if (len == 2 && p[1] == ':')
{
p[2] = PATH_SEP;
p[3] = EOS;
}
#endif
if (!len)
{
/* any platform where the path is reduced to an empty string */
p[0] = PATH_SEP;
p[1] = EOS;
}
logman("%s:reduce from current,new cp=%s[%d]", mname, p, strlen(p));
if (!dscan_set_current_path(p))
{
free(p);
logman("%s:exit[0]bad rc[0] from dscan_set_current_path", mname);
return(FALSE);
}
free(p);
logman("%s:exit[TRUE]:new cp=%s[%d]", mname, dscan_current_path,
strlen(dscan_current_path));
return(TRUE);
}
static int dscan_match(char *pat, char *fname)
{
/* Match a file name to a pattern. Function returns
'TRUE' if a match was found, 'FALSE' otherwise. */
char mname[] = "dscan_match";
int ret;
dscan_header(mname);
/* for Windoze and DOS, compare case insensitive */
#ifdef OS_WIN32
ret = dscan_umatch(pat, fname);
logman("%s:exit[%d]", mname, ret);
return(ret);
#endif
#ifdef OS_DOS
ret = dscan_umatch(pat, fname);
logman("%s:exit[%d]", mname, ret);
return(ret);
#endif
if (pat == NULL || !strlen(pat))
{
logman("%s:exit[0]:null or empty[pat]", mname);
return(FALSE);
}
if (fname == NULL || !strlen(fname))
{
logman("%s:exit[0]:null or empty[fname]", mname);
return(FALSE);
}
logman("%s:pat=%s[%d],fname=%s[%d]", mname, pat, strlen(pat),
fname, strlen(fname));
ret = pmatch(pat, fname);
logman("%s:exit[%d]", mname, ret);
return(ret);
}
static int dscan_umatch(char *pat, char *fname)
{
/* Match a file name to a pattern case insensitive.
Function returns 'TRUE' if a match is found,
'FALSE' otherwise. */
char mname[] = "dscan_umatch";
int ret;
char *upat, *ufname;
dscan_header(mname);
if (pat == NULL || !strlen(pat))
{
logman("%s:exit[0]:null or empty[pat]", mname);
return(FALSE);
}
if (fname == NULL || !strlen(fname))
{
logman("%s:exit[0]:null or empty[fname]", mname);
return(FALSE);
}
if ((upat = initstring(pat)) == NULL)
{
logman("%s:exit[0]:alloc fail[upat]", mname);
return(FALSE);
}
if ((ufname = initstring(fname)) == NULL)
{
free(upat);
logman("%s:exit[0]:alloc fail[ufname]", mname);
return(FALSE);
}
ucase(pat, upat);
ucase(fname, ufname);
ret = pmatch(upat, ufname);
free(upat);
free(ufname);
logman("%s:exit[%d]:case insensitive", mname, ret);
return(ret);
}
static int dscan_set_flags(char *flags)
{
/* Load scan flags into module globals. Function returns 'TRUE'
upon success, 'FALSE' otherwise. */
char mname[] = "dscan_set_flags";
char uflags[10];
int len, i;
dscan_header(mname);
if (flags == NULL || !strlen(flags))
{
logman("%s:exit[0]null or empty[flags]", mname);
return(FALSE);
}
ucase(flags, uflags);
len = strlen(uflags);
dscan_for_files = dscan_for_dirs = dscan_descend = FALSE;
#ifdef OS_UNIX
dscan_for_symlinks = FALSE;
#endif
for(i = 0; i < len; i++)
{
switch(uflags[i])
{
case 'F':
dscan_for_files = TRUE;
break;
case 'D':
dscan_for_dirs = TRUE;
break;
case 'S':
dscan_descend = TRUE;
break;
#ifdef OS_UNIX
case 'L':
dscan_for_symlinks = TRUE;
break;
#endif
default:
logman("%s:exit[0]:unknown flag[%c]", mname, uflags[i]);
return(FALSE);
};
}
#ifdef OS_UNIX
if (!dscan_for_files && !dscan_for_dirs && !dscan_for_symlinks)
{
logman("%s:exit[0]one of scan for files[f], scan for "
"dirs[d] or scan for symlinks[l] must be given", mname);
#else
if (!dscan_for_files && !dscan_for_dirs)
{
logman("%s:exit[0]one of scan for files[f] or scan for "
"dirs[d] must be given", mname);
#endif
return(FALSE);
}
#ifdef OS_UNIX
logman("%s:exit[TRUE]sff=%d,sfd=%d,sfl=%d,sd=%d", mname, dscan_for_files,
dscan_for_dirs, dscan_for_symlinks, dscan_descend);
#else
logman("%s:exit[TRUE]sff=%d,sfd=%d,sd=%d", mname,
dscan_for_files, dscan_for_dirs, dscan_descend);
#endif
return(TRUE);
}
static int dscan_set_current_path(char *p)
{
/* Save the current path. Function returns 'TRUE' upon success,
'FALSE' otherwise. */
char mname[] = "dscan_set_current_path";
dscan_header(mname);
if (p == NULL || !strlen(p))
{
logman("%s:exit[0]null or empty[p]", mname);
return(FALSE);
}
if (dscan_current_path != NULL)
free(dscan_current_path);
if ((dscan_current_path = (char *)malloc(strlen(p) + 1))
== (char *)NULL)
{
logman("%s:exit[0]alloc fail[dscan_current_path]", mname);
return(FALSE);
}
strcpy(dscan_current_path, p);
logman("%s:exit[TRUE]:cp=%s", mname, dscan_current_path);
return(TRUE);
}
static void dscan_ll_delete(char *p)
{
/* Delete a link list entry by it's path. */
struct dscan_entry *rov, *prev;
char mname[] = "dscan_ll_delete";
int found = FALSE;
dscan_header(mname);
logman("%s:ll before", mname);
dscan_ll_debug();
if (p == NULL || !strlen(p))
{
logman("%s:exit:null or empty[p]", mname);
return;
}
logman("%s:p=%s[%d]", mname, p, strlen(p));
rov = dscan_list_head;
prev = NULL;
while(rov != NULL && !found)
if (!strcmp(p, rov->dir_path))
{
found = TRUE;
break;
}
else
{
prev = rov;
rov = rov->next;
}
if (!found)
{
logman("%s:exit:entry not found", mname);
return;
}
closedir(rov->dir);
if (rov->subs != NULL)
free(rov->subs);
free(rov->dir_path);
if (prev != NULL)
prev->next = rov->next;
else
dscan_list_head = rov->next;
free(rov);
logman("%s:normal exit:ll after", mname);
dscan_ll_debug();
}
static void dscan_ll_delete_all(void)
{
/* Delete all members of the link list and set the
head of list pointer to 'NULL'. */
struct dscan_entry *rov, *tmp;
char mname[] = "dscan_ll_delete_all";
dscan_header(mname);
if (dscan_list_head == NULL)
{
logman("%s:exit:link list empty", mname);
return;
}
rov = dscan_list_head;
while(rov != NULL)
{
closedir(rov->dir);
free(rov->dir_path);
if (rov->subs != NULL)
free(rov->subs);
tmp = rov->next;
free(rov);
rov = tmp;
}
dscan_list_head = NULL;
logman("%s:normal exit", mname);
}
static int dscan_set_mvars(char *path, char *fname)
{
/* Allocate space for global path and file name. Function returns
'TRUE' upon success, 'FALSE' otherwise. */
char mname[] = "dscan_set_mvars";
dscan_header(mname);
if (path == NULL || !strlen(path) || fname == NULL || !strlen(fname))
{
logman("%s:exit[0]parm error", mname);
return(FALSE);
}
if (dscan_base_path != NULL)
{
logman("%s:exit[0]base path already assigned", mname);
return(FALSE);
}
if ((dscan_base_path = (char *)malloc(strlen(path) + 1)) == (char *)NULL)
{
logman("%s:exit[0]alloc fail[dscan_base_path]", mname);
return(FALSE);
}
strcpy(dscan_base_path, path);
if (dscan_fname != NULL)
{
logman("%s:exit[0]target file name already assigned", mname);
return(FALSE);
}
if ((dscan_fname = (char *)malloc(strlen(fname) + 1)) == (char *)NULL)
{
free(dscan_base_path);
dscan_base_path = NULL;
logman("%s:exit[0]alloc fail[dscan_fname]", mname);
return(FALSE);
}
strcpy(dscan_fname, fname);
logman("%s:exit[TRUE]", mname);
return(TRUE);
}
static void dscan_delete_mvars(void)
{
/* Delete the module global strings. */
char mname[] = "dscan_delete_mvars";
dscan_header(mname);
if (dscan_base_path != NULL)
{
free(dscan_base_path);
dscan_base_path = NULL;
}
if (dscan_current_path != NULL)
{
free(dscan_current_path);
dscan_current_path = NULL;
}
if (dscan_fname != NULL)
{
free(dscan_fname);
dscan_fname = NULL;
}
logman("%s:normal exit", mname);
}
static struct dscan_entry *dscan_ll_find(char *p)
{
/* Locate a link list entry by the path. Function returns
a pointer to the appropriate link list entry upon success,
a NULL pointer otherwise. */
struct dscan_entry *rov;
char mname[] = "dscan_ll_find";
dscan_header(mname);
if (p == NULL || !strlen(p))
{
logman("%s:exit[NULL]:null or empty[p]", mname);
return(NULL);
}
logman("%s:attempting to locate %s[%d]", mname, p, strlen(p));
rov = dscan_list_head;
if (rov == NULL)
{
logman("%s:exit[NULL]:link list empty", mname);
return(NULL);
}
while(rov != NULL)
{
if (!strcmp(rov->dir_path, p))
{
logman("%s:exit:found entry", mname);
return(rov);
}
rov = rov->next;
}
logman("%s:exit:entry not found", mname);
return(NULL);
}
static struct dscan_entry *dscan_ll_add(char *p)
{
/* Add a directory to the link list. Function returns a pointer
to the new entry upon success, a NULL pointer otherwise. */
struct dscan_entry *rov, *last;
char mname[] = "dscan_ll_add";
int len;
dscan_header(mname);
dscan_ll_debug();
if (p == NULL || !strlen(p))
{
logman("%s:exit[NULL]null or empty[p]", mname);
return(NULL);
}
logman("%s:adding %s", mname, p);
rov = dscan_list_head;
last = NULL;
while(rov != NULL)
{
if (rov->next == NULL)
{
last = rov;
break;
}
rov = rov->next;
}
len = sizeof(struct dscan_entry);
if ((rov = (struct dscan_entry *)malloc(len)) == NULL)
{
logman("%s:exit[NULL]alloc error[rov]", mname);
return(NULL);
}
if ((rov->dir_path = (char *)malloc(strlen(p) + 1)) == NULL)
{
free(rov);
logman("%s:exit[NULL]alloc fail[p]", mname);
return(NULL);
}
strcpy(rov->dir_path, p);
rov->subs = NULL;
rov->sub_count = rov->sub_index = 0;
rov->next = NULL;
if ((rov->dir = opendir(rov->dir_path)) == NULL)
{
free(rov->dir_path);
free(rov);
logman("%s:unable to access directory %s[%d], dumping",
mname, p, strlen(p));
(void)dscan_chop_path();
logman("%s:exit[NULL]", mname);
return(NULL);
}
if (last != NULL)
last->next = rov;
if (dscan_list_head == NULL)
dscan_list_head = rov;
dscan_ll_debug();
logman("%s:exit[ok]", mname);
return(rov);
}
static void dscan_header(char *mname)
{
// Log the entrance into a function.
logman("%s:enter", mname);
}