#include "cvs.h"
#include "savecwd.h"
#include "fileattr.h"
#include "edit.h"
#ifdef CLIENT_SUPPORT
static int do_argument_proc PROTO((Node * p, void *closure));
#endif
static int do_dir_proc PROTO((Node * p, void *closure));
static int do_file_proc PROTO((Node * p, void *closure));
static void addlist PROTO((List ** listp, char *key));
static int unroll_files_proc PROTO((Node *p, void *closure));
static void addfile PROTO((List **listp, char *dir, char *file));
static char *update_dir;
static char *repository = NULL;
static List *filelist = NULL;
static List *dirlist = NULL;
struct recursion_frame {
FILEPROC fileproc;
FILESDONEPROC filesdoneproc;
DIRENTPROC direntproc;
DIRLEAVEPROC dirleaveproc;
void *callerdat;
Dtype flags;
int which;
int aflag;
int readlock;
int dosrcs;
};
static int do_recursion PROTO ((struct recursion_frame *frame));
struct frame_and_file {
struct recursion_frame *frame;
struct file_info *finfo;
};
struct frame_and_entries {
struct recursion_frame *frame;
List *entries;
};
#ifdef CLIENT_SUPPORT
static int
do_argument_proc (p, closure)
Node *p;
void *closure;
{
char *dir = p->key;
send_to_server ("Argument ", 0);
send_to_server (dir, 0);
send_to_server ("\012", 1);
return 0;
}
#endif
int
start_recursion (fileproc, filesdoneproc, direntproc, dirleaveproc, callerdat,
argc, argv, local, which, aflag, readlock,
update_preload, dosrcs)
FILEPROC fileproc;
FILESDONEPROC filesdoneproc;
DIRENTPROC direntproc;
DIRLEAVEPROC dirleaveproc;
void *callerdat;
int argc;
char **argv;
int local;
int which;
int aflag;
int readlock;
char *update_preload;
int dosrcs;
{
int i, err = 0;
List *files_by_dir = NULL;
struct recursion_frame frame;
frame.fileproc = fileproc;
frame.filesdoneproc = filesdoneproc;
frame.direntproc = direntproc;
frame.dirleaveproc = dirleaveproc;
frame.callerdat = callerdat;
frame.flags = local ? R_SKIP_DIRS : R_PROCESS;
frame.which = which;
frame.aflag = aflag;
frame.readlock = readlock;
frame.dosrcs = dosrcs;
expand_wild (argc, argv, &argc, &argv);
if (update_preload == NULL)
update_dir = xstrdup ("");
else
update_dir = xstrdup (update_preload);
if (repository)
{
free (repository);
repository = (char *) NULL;
}
if (filelist)
dellist (&filelist);
if (dirlist)
dellist (&dirlist);
#ifdef SERVER_SUPPORT
if (server_active)
{
for (i = 0; i < argc; ++i)
server_pathname_check (argv[i]);
}
#endif
if (argc == 0)
{
if ((which & W_LOCAL) && !isdir (CVSADM))
{
dirlist = Find_Directories ((char *) NULL, W_LOCAL, (List *) NULL);
if (list_isempty (dirlist))
{
if (update_dir[0] == '\0')
error (0, 0, "in directory .:");
else
error (0, 0, "in directory %s:", update_dir);
error (1, 0,
"there is no version here; run '%s checkout' first",
program_name);
}
#ifdef CLIENT_SUPPORT
else if (client_active && server_started)
{
err += walklist (dirlist, do_argument_proc, NULL);
}
#endif
}
else
addlist (&dirlist, ".");
err += do_recursion (&frame);
goto out;
}
for (i = 0; i < argc; i++)
{
if (!wrap_name_has (argv[i], WRAP_TOCVS) && isdir (argv[i]))
addlist (&dirlist, argv[i]);
else
{
char *dir;
char *comp;
char *file_to_try;
dir = xstrdup (argv[i]);
comp = last_component (dir);
if (comp == dir)
{
dir = xstrdup(".");
}
else
{
char *p = comp;
p[-1] = '\0';
comp = xstrdup (p);
}
if (!(which & W_LOCAL))
{
file_to_try = xmalloc (strlen (argv[i]) + sizeof (RCSEXT) + 5);
sprintf (file_to_try, "%s%s", argv[i], RCSEXT);
}
else
file_to_try = xstrdup (argv[i]);
if (isfile (file_to_try))
addfile (&files_by_dir, dir, comp);
else if (isdir (dir))
{
if ((which & W_LOCAL) && isdir (CVSADM)
#ifdef CLIENT_SUPPORT
&& !client_active
#endif
)
{
char *tmp_update_dir;
char *repos;
char *reposfile;
tmp_update_dir = xmalloc (strlen (update_dir)
+ strlen (dir)
+ 5);
strcpy (tmp_update_dir, update_dir);
if (*tmp_update_dir != '\0')
(void) strcat (tmp_update_dir, "/");
(void) strcat (tmp_update_dir, dir);
repos = Name_Repository (dir, tmp_update_dir);
reposfile = xmalloc (strlen (repos)
+ strlen (comp)
+ 5);
(void) sprintf (reposfile, "%s/%s", repos, comp);
free (repos);
if (!wrap_name_has (comp, WRAP_TOCVS) && isdir (reposfile))
addlist (&dirlist, argv[i]);
else
addfile (&files_by_dir, dir, comp);
free (tmp_update_dir);
free (reposfile);
}
else
addfile (&files_by_dir, dir, comp);
}
else
error (1, 0, "no such directory `%s'", dir);
free (file_to_try);
free (dir);
free (comp);
}
}
err += walklist (files_by_dir, unroll_files_proc, (void *) &frame);
dellist(&files_by_dir);
if (dirlist != NULL)
err += do_recursion (&frame);
free_names (&argc, argv);
out:
free (update_dir);
update_dir = NULL;
return (err);
}
static int
do_recursion (frame)
struct recursion_frame *frame;
{
int err = 0;
int dodoneproc = 1;
char *srepository;
List *entries = NULL;
int should_readlock;
if (frame->flags == R_SKIP_ALL)
return (0);
should_readlock = noexec ? 0 : frame->readlock;
#if defined(SERVER_SUPPORT) && defined(SERVER_FLOWCONTROL)
if (server_active
&& (should_readlock || noexec))
server_pause_check();
#endif
if (frame->which & W_LOCAL)
{
if (isdir (CVSADM))
repository = Name_Repository ((char *) NULL, update_dir);
else
repository = NULL;
}
else
{
repository = xgetwd ();
if (repository == NULL)
error (1, errno, "could not get working directory");
}
srepository = repository;
fileattr_startdir (repository);
if (dirlist != NULL && filelist == NULL)
dodoneproc = 0;
if (filelist == NULL && dirlist == NULL)
{
if (frame->fileproc != NULL && frame->flags != R_SKIP_FILES)
{
int lwhich = frame->which;
if ((lwhich & W_ATTIC) == 0)
if (isreadable (CVSADM_TAG))
lwhich |= W_ATTIC;
if (repository == NULL)
repository = Name_Repository ((char *) NULL, update_dir);
filelist = Find_Names (repository, lwhich, frame->aflag, &entries);
}
if (frame->flags != R_SKIP_DIRS)
dirlist = Find_Directories (repository, frame->which, entries);
}
else
{
if (filelist != NULL && frame->fileproc != NULL)
{
if (frame->which & W_LOCAL)
entries = Entries_Open (frame->aflag, NULL);
}
}
if (filelist != NULL && frame->fileproc)
{
struct file_info finfo_struct;
struct frame_and_file frfile;
if (should_readlock && repository && Reader_Lock (repository) != 0)
error (1, 0, "read lock failed - giving up");
#ifdef CLIENT_SUPPORT
if (client_active)
notify_check (repository, update_dir);
#endif
finfo_struct.repository = repository;
finfo_struct.update_dir = update_dir;
finfo_struct.entries = entries;
frfile.finfo = &finfo_struct;
frfile.frame = frame;
err += walklist (filelist, do_file_proc, &frfile);
if (should_readlock)
Lock_Cleanup ();
dellist (&filelist);
}
if (dodoneproc && frame->filesdoneproc != NULL)
err = frame->filesdoneproc (frame->callerdat, err, repository,
update_dir[0] ? update_dir : ".",
entries);
fileattr_write ();
fileattr_free ();
if (dirlist != NULL)
{
struct frame_and_entries frent;
frent.frame = frame;
frent.entries = entries;
err += walklist (dirlist, do_dir_proc, (void *) &frent);
}
#if 0
else if (frame->dirleaveproc != NULL)
err += frame->dirleaveproc (frame->callerdat, ".", err, ".");
#endif
dellist (&dirlist);
if (entries)
{
Entries_Close (entries);
entries = NULL;
}
if (srepository)
{
free (srepository);
repository = (char *) NULL;
}
return (err);
}
static int
do_file_proc (p, closure)
Node *p;
void *closure;
{
struct frame_and_file *frfile = (struct frame_and_file *)closure;
struct file_info *finfo = frfile->finfo;
int ret;
finfo->file = p->key;
finfo->fullname = xmalloc (strlen (finfo->file)
+ strlen (finfo->update_dir)
+ 2);
finfo->fullname[0] = '\0';
if (finfo->update_dir[0] != '\0')
{
strcat (finfo->fullname, finfo->update_dir);
strcat (finfo->fullname, "/");
}
strcat (finfo->fullname, finfo->file);
if (frfile->frame->dosrcs && repository)
finfo->rcs = RCS_parse (finfo->file, repository);
else
finfo->rcs = (RCSNode *) NULL;
ret = frfile->frame->fileproc (frfile->frame->callerdat, finfo);
freercsnode(&finfo->rcs);
free (finfo->fullname);
cvs_flushout ();
return (ret);
}
static int
do_dir_proc (p, closure)
Node *p;
void *closure;
{
struct frame_and_entries *frent = (struct frame_and_entries *) closure;
struct recursion_frame *frame = frent->frame;
struct recursion_frame xframe;
char *dir = p->key;
char *newrepos;
List *sdirlist;
char *srepository;
Dtype dir_return = R_PROCESS;
int stripped_dot = 0;
int err = 0;
struct saved_cwd cwd;
char *saved_update_dir;
if (fncmp (dir, CVSADM) == 0)
{
static int printed_cvs_msg = 0;
if (!printed_cvs_msg)
{
error (0, 0, "warning: directory %s specified in argument",
dir);
error (0, 0, "\
but CVS uses %s for its own purposes; skipping %s directory",
CVSADM, dir);
printed_cvs_msg = 1;
}
return 0;
}
saved_update_dir = update_dir;
update_dir = xmalloc (strlen (saved_update_dir)
+ strlen (dir)
+ 5);
strcpy (update_dir, saved_update_dir);
if (strcmp (dir, ".") != 0)
{
if (update_dir[0] != '\0')
{
(void) strcat (update_dir, "/");
(void) strcat (update_dir, dir);
}
else
(void) strcpy (update_dir, dir);
if (repository == NULL)
newrepos = xstrdup ("");
else
{
newrepos = xmalloc (strlen (repository) + strlen (dir) + 5);
sprintf (newrepos, "%s/%s", repository, dir);
}
}
else
{
if (update_dir[0] == '\0')
(void) strcpy (update_dir, dir);
if (repository == NULL)
newrepos = xstrdup ("");
else
newrepos = xstrdup (repository);
}
if (frame->which & W_LOCAL)
{
char *cvsadmdir;
cvsadmdir = xmalloc (strlen (dir)
+ sizeof (CVSADM_REP)
+ sizeof (CVSADM_ENT)
+ 80);
strcpy (cvsadmdir, dir);
strcat (cvsadmdir, "/");
strcat (cvsadmdir, CVSADM);
if (isdir (cvsadmdir))
{
strcpy (cvsadmdir, dir);
strcat (cvsadmdir, "/");
strcat (cvsadmdir, CVSADM_REP);
if (!isfile (cvsadmdir))
{
error (0, 0, "ignoring %s (%s missing)", update_dir,
CVSADM_REP);
dir_return = R_SKIP_ALL;
}
if (dir_return != R_SKIP_ALL)
{
strcpy (cvsadmdir, dir);
strcat (cvsadmdir, "/");
strcat (cvsadmdir, CVSADM_ENT);
if (!isfile (cvsadmdir))
{
error (0, 0, "ignoring %s (%s missing)", update_dir,
CVSADM_ENT);
dir_return = R_SKIP_ALL;
}
}
}
free (cvsadmdir);
}
if (dir_return == R_SKIP_ALL)
;
else if (frame->direntproc != NULL)
dir_return = frame->direntproc (frame->callerdat, dir, newrepos,
update_dir, frent->entries);
else
{
if ((frame->which & W_LOCAL) && !isdir (dir))
dir_return = R_SKIP_ALL;
}
free (newrepos);
if (dir_return != R_SKIP_ALL)
{
if (save_cwd (&cwd))
error_exit ();
sdirlist = dirlist;
srepository = repository;
dirlist = NULL;
if ( CVS_CHDIR (dir) < 0)
error (1, errno, "could not chdir to %s", dir);
if (frame->flags == R_SKIP_DIRS)
dir_return = R_SKIP_DIRS;
if (strcmp (update_dir, ".") == 0)
{
update_dir[0] = '\0';
stripped_dot = 1;
}
xframe = *frame;
xframe.flags = dir_return;
err += do_recursion (&xframe);
if (stripped_dot)
(void) strcpy (update_dir, ".");
if (frame->dirleaveproc != NULL)
err = frame->dirleaveproc (frame->callerdat, dir, err, update_dir,
frent->entries);
if (restore_cwd (&cwd, NULL))
error_exit ();
free_cwd (&cwd);
dirlist = sdirlist;
repository = srepository;
}
free (update_dir);
update_dir = saved_update_dir;
return (err);
}
static void
addlist (listp, key)
List **listp;
char *key;
{
Node *p;
if (*listp == NULL)
*listp = getlist ();
p = getnode ();
p->type = FILES;
p->key = xstrdup (key);
if (addnode (*listp, p) != 0)
freenode (p);
}
static void
addfile (listp, dir, file)
List **listp;
char *dir;
char *file;
{
Node *n;
addlist (listp, dir);
n = findnode (*listp, dir);
if (n == NULL)
{
error (1, 0, "can't find recently added dir node `%s' in start_recursion.",
dir);
}
n->type = DIRS;
addlist ((List **) &n->data, file);
return;
}
static int
unroll_files_proc (p, closure)
Node *p;
void *closure;
{
Node *n;
struct recursion_frame *frame = (struct recursion_frame *) closure;
int err = 0;
List *save_dirlist;
char *save_update_dir = NULL;
struct saved_cwd cwd;
n = findnode (dirlist, p->key);
if (n != NULL)
return (0);
filelist = (List *) p->data;
p->data = NULL;
save_dirlist = dirlist;
dirlist = NULL;
if (strcmp(p->key, ".") != 0)
{
if (save_cwd (&cwd))
error_exit ();
if ( CVS_CHDIR (p->key) < 0)
error (1, errno, "could not chdir to %s", p->key);
save_update_dir = update_dir;
update_dir = xmalloc (strlen (save_update_dir)
+ strlen (p->key)
+ 5);
strcpy (update_dir, save_update_dir);
if (*update_dir != '\0')
(void) strcat (update_dir, "/");
(void) strcat (update_dir, p->key);
}
err += do_recursion (frame);
if (save_update_dir != NULL)
{
free (update_dir);
update_dir = save_update_dir;
if (restore_cwd (&cwd, NULL))
error_exit ();
free_cwd (&cwd);
}
dirlist = save_dirlist;
filelist = NULL;
return(err);
}