#include "cvs.h"
#include <glob.h>
#include <assert.h>
static int find_dirs (char *dir, List * list, int checkadm,
List *entries);
static int find_rcs (const char *dir, List * list);
static int add_subdir_proc (Node *, void *);
static int register_subdir_proc (Node *, void *);
static int add_entries_proc (Node *, void *);
static int
add_entries_proc (Node *node, void *closure)
{
Node *fnode;
List *filelist = closure;
Entnode *entnode = node->data;
if (entnode->type != ENT_FILE)
return (0);
fnode = getnode ();
fnode->type = FILES;
fnode->key = xstrdup (node->key);
if (addnode (filelist, fnode) != 0)
freenode (fnode);
return (0);
}
List *
Find_Names (char *repository, int which, int aflag, List **optentries)
{
List *entries;
List *files;
files = getlist ();
if (which & W_LOCAL)
{
entries = Entries_Open (aflag, NULL);
if (entries != NULL)
{
(void) walklist (entries, add_entries_proc, files);
if (optentries != NULL)
*optentries = entries;
else
Entries_Close (entries);
}
}
if ((which & W_REPOS) && repository && !isreadable (CVSADM_ENTSTAT))
{
if (find_rcs (repository, files) != 0)
{
error (0, errno, "cannot open directory %s",
primary_root_inverse_translate (repository));
goto error_exit;
}
if (which & W_ATTIC)
{
char *dir = Xasprintf ("%s/%s", repository, CVSATTIC);
if (find_rcs (dir, files) != 0
&& !existence_error (errno))
error (1, errno, "cannot open directory %s",
primary_root_inverse_translate (dir));
free (dir);
}
}
sortlist (files, fsortcmp);
return files;
error_exit:
dellist (&files);
return NULL;
}
static int
add_subdir_proc (Node *p, void *closure)
{
List *dirlist = closure;
Entnode *entnode = p->data;
Node *dnode;
if (entnode->type != ENT_SUBDIR)
return 0;
dnode = getnode ();
dnode->type = DIRS;
dnode->key = xstrdup (entnode->user);
if (addnode (dirlist, dnode) != 0)
freenode (dnode);
return 0;
}
static int
register_subdir_proc (Node *p, void *closure)
{
List *entries = (List *) closure;
Subdir_Register (entries, NULL, p->key);
return 0;
}
List *
Find_Directories (char *repository, int which, List *entries)
{
List *dirlist;
dirlist = getlist ();
if (which & W_LOCAL)
{
List *tmpentries;
struct stickydirtag *sdtp;
if (entries != NULL)
tmpentries = entries;
else if (isfile (CVSADM_ENT))
tmpentries = Entries_Open (0, NULL);
else
tmpentries = NULL;
if (tmpentries != NULL)
sdtp = tmpentries->list->data;
if (tmpentries != NULL && (sdtp == NULL || sdtp->subdirs))
walklist (tmpentries, add_subdir_proc, (void *) dirlist);
else
{
if (find_dirs (".", dirlist, 1, tmpentries) != 0)
error (1, errno, "cannot open current directory");
if (tmpentries != NULL)
{
if (! list_isempty (dirlist))
walklist (dirlist, register_subdir_proc,
(void *) tmpentries);
else
Subdirs_Known (tmpentries);
}
}
if (entries == NULL && tmpentries != NULL)
Entries_Close (tmpentries);
}
if ((which & W_REPOS) && repository)
{
if (find_dirs (repository, dirlist, 0, entries) != 0)
error (1, errno, "cannot open directory %s", repository);
}
sortlist (dirlist, fsortcmp);
return (dirlist);
}
List *
find_files (const char *dir, const char *pat)
{
List *retval;
glob_t glist;
int err, i;
char *catpat = NULL;
bool dirslash = false;
if (dir && *dir)
{
size_t catpatlen = 0;
const char *p;
if (glob_pattern_p (dir, false))
{
size_t len = 0;
p = dir;
while (*p)
{
switch (*p)
{
case '\\':
case '*':
case '[':
case ']':
case '?':
expand_string (&catpat, &catpatlen, len + 1);
catpat[len++] = '\\';
default:
expand_string (&catpat, &catpatlen, len + 1);
catpat[len++] = *p++;
break;
}
}
catpat[len] = '\0';
}
else
{
xrealloc_and_strcat (&catpat, &catpatlen, dir);
p = dir + strlen (dir);
}
dirslash = *p - 1 == '/';
if (!dirslash)
xrealloc_and_strcat (&catpat, &catpatlen, "/");
xrealloc_and_strcat (&catpat, &catpatlen, pat);
pat = catpat;
}
err = glob (pat, GLOB_PERIOD | (dir ? GLOB_ERR : 0), NULL, &glist);
if (err && err != GLOB_NOMATCH)
{
if (err == GLOB_ABORTED)
return NULL;
if (err == GLOB_NOSPACE) errno = ENOMEM;
if (!really_quiet)
error (0, errno, "glob failed");
if (catpat) free (catpat);
return NULL;
}
retval = getlist ();
for (i = 0; i < glist.gl_pathc; i++)
{
Node *p;
const char *tmp;
tmp = last_component (glist.gl_pathv[i]);
if (!strcmp (tmp, ".") || !strcmp (tmp, ".."))
continue;
p = getnode ();
p->type = FILES;
p->key = xstrdup (glist.gl_pathv[i]
+ (dir ? strlen (dir) + !dirslash : 0));
if (addnode (retval, p)) freenode (p);
}
if (catpat) free (catpat);
globfree (&glist);
return retval;
}
static int
strip_rcsext (Node *p, void *closure)
{
char *s = p->key + strlen (p->key) - strlen (RCSEXT);
assert (!strcmp (s, RCSEXT));
*s = '\0';
return 0;
}
static int
find_rcs (dir, list)
const char *dir;
List *list;
{
List *newlist;
if (!(newlist = find_files (dir, RCSPAT)))
return 1;
walklist (newlist, strip_rcsext, NULL);
mergelists (list, &newlist);
return 0;
}
static int
find_dirs (char *dir, List *list, int checkadm, List *entries)
{
Node *p;
char *tmp = NULL;
size_t tmp_size = 0;
struct dirent *dp;
DIR *dirp;
int skip_emptydir = 0;
if (ISABSOLUTE (dir)
&& strncmp (dir, current_parsed_root->directory, strlen (current_parsed_root->directory)) == 0
&& ISSLASH (dir[strlen (current_parsed_root->directory)])
&& strcmp (dir + strlen (current_parsed_root->directory) + 1, CVSROOTADM) == 0)
skip_emptydir = 1;
if ((dirp = CVS_OPENDIR (dir)) == NULL)
return (1);
errno = 0;
while ((dp = CVS_READDIR (dirp)) != NULL)
{
if (strcmp (dp->d_name, ".") == 0 ||
strcmp (dp->d_name, "..") == 0 ||
strcmp (dp->d_name, CVSATTIC) == 0 ||
strcmp (dp->d_name, CVSLCK) == 0 ||
strcmp (dp->d_name, CVSREP) == 0)
goto do_it_again;
if (entries != NULL && findnode (entries, dp->d_name) != NULL)
goto do_it_again;
if (skip_emptydir
&& strcmp (dp->d_name, CVSNULLREPOS) == 0)
goto do_it_again;
#ifdef DT_DIR
if (dp->d_type != DT_DIR)
{
if (dp->d_type != DT_UNKNOWN && dp->d_type != DT_LNK)
goto do_it_again;
#endif
if (CVS_FNMATCH (RCSPAT, dp->d_name, 0) == 0)
goto do_it_again;
expand_string (&tmp,
&tmp_size,
strlen (dir) + strlen (dp->d_name) + 10);
sprintf (tmp, "%s/%s", dir, dp->d_name);
if (!isdir (tmp))
goto do_it_again;
#ifdef DT_DIR
}
#endif
if (checkadm)
{
#ifdef DT_DIR
if (dp->d_type != DT_DIR)
{
if (dp->d_type == DT_LNK)
goto do_it_again;
#endif
if (islink (tmp))
goto do_it_again;
#ifdef DT_DIR
}
#endif
expand_string (&tmp,
&tmp_size,
(strlen (dir) + strlen (dp->d_name)
+ sizeof (CVSADM) + 10));
(void) sprintf (tmp, "%s/%s/%s", dir, dp->d_name, CVSADM);
if (!isdir (tmp))
goto do_it_again;
}
p = getnode ();
p->type = DIRS;
p->key = xstrdup (dp->d_name);
if (addnode (list, p) != 0)
freenode (p);
do_it_again:
errno = 0;
}
if (errno != 0)
{
int save_errno = errno;
(void) CVS_CLOSEDIR (dirp);
errno = save_errno;
return 1;
}
(void) CVS_CLOSEDIR (dirp);
if (tmp != NULL)
free (tmp);
return (0);
}