diff options
author | peter <peter@FreeBSD.org> | 1997-05-15 22:46:24 +0000 |
---|---|---|
committer | peter <peter@FreeBSD.org> | 1997-05-15 22:46:24 +0000 |
commit | 4f40fe8334ad5f056e1d9105f23fe7ac859c39ba (patch) | |
tree | 3b2f0092fa216d9f61059ba94b7f10b5bacf9496 /contrib/cvs/src/recurse.c | |
parent | 8982e501c77217c860f79bba431f46a62b607a21 (diff) | |
download | FreeBSD-src-4f40fe8334ad5f056e1d9105f23fe7ac859c39ba.zip FreeBSD-src-4f40fe8334ad5f056e1d9105f23fe7ac859c39ba.tar.gz |
Import of cvs-1.9.9-970515 onto vendor branch.
Obtained from: cyclic.com
Diffstat (limited to 'contrib/cvs/src/recurse.c')
-rw-r--r-- | contrib/cvs/src/recurse.c | 431 |
1 files changed, 270 insertions, 161 deletions
diff --git a/contrib/cvs/src/recurse.c b/contrib/cvs/src/recurse.c index ec51a98..e18d576 100644 --- a/contrib/cvs/src/recurse.c +++ b/contrib/cvs/src/recurse.c @@ -19,79 +19,113 @@ 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)); - -/* - * Local static versions eliminates the need for globals - */ -static FILEPROC fileproc; -static FILESDONEPROC filesdoneproc; -static DIRENTPROC direntproc; -static DIRLEAVEPROC dirleaveproc; -static int which; -static Dtype flags; -static int aflag; -static int readlock; -static int dosrcs; -static char update_dir[PATH_MAX]; +static char *update_dir; static char *repository = NULL; static List *filelist = NULL; /* holds list of files on which to operate */ static List *dirlist = NULL; /* holds list of directories on which to operate */ struct recursion_frame { - FILEPROC fileproc; - FILESDONEPROC filesdoneproc; - DIRENTPROC direntproc; - DIRLEAVEPROC dirleaveproc; - Dtype flags; - int which; - int aflag; - int readlock; - int dosrcs; + FILEPROC fileproc; + FILESDONEPROC filesdoneproc; + DIRENTPROC direntproc; + DIRLEAVEPROC dirleaveproc; + void *callerdat; + Dtype flags; + int which; + int aflag; + int readlock; + int dosrcs; }; -/* - * Called to start a recursive command. - * - * Command line arguments dictate the directories and files on which - * we operate. In the special case of no arguments, we default to - * ".". - * - * The general algorithm is as follows. - */ +static int do_recursion PROTO ((struct recursion_frame *frame)); + +/* I am half tempted to shove a struct file_info * into the struct + recursion_frame (but then we would need to modify or create a + recursion_frame for each file), or shove a struct recursion_frame * + into the struct file_info (more tempting, although it isn't completely + clear that the struct file_info should contain info about recursion + processor internals). So instead use this struct. */ + +struct frame_and_file { + struct recursion_frame *frame; + struct file_info *finfo; +}; + +/* Similarly, we need to pass the entries list to do_dir_proc. */ + +struct frame_and_entries { + struct recursion_frame *frame; + List *entries; +}; + +/* Start a recursive command. + + Command line arguments (ARGC, ARGV) dictate the directories and + files on which we operate. In the special case of no arguments, we + default to ".". */ int -start_recursion (fileproc, filesdoneproc, direntproc, dirleaveproc, +start_recursion (fileproc, filesdoneproc, direntproc, dirleaveproc, callerdat, argc, argv, local, which, aflag, readlock, - update_preload, dosrcs, wd_is_repos) + update_preload, dosrcs) FILEPROC fileproc; FILESDONEPROC filesdoneproc; DIRENTPROC direntproc; DIRLEAVEPROC dirleaveproc; + void *callerdat; + int argc; char **argv; int local; + + /* This specifies the kind of recursion. There are several cases: + + 1. W_LOCAL is not set but W_REPOS or W_ATTIC is. The current + directory when we are called must be the repository and + recursion proceeds according to what exists in the repository. + + 2a. W_LOCAL is set but W_REPOS and W_ATTIC are not. The + current directory when we are called must be the working + directory. Recursion proceeds according to what exists in the + working directory, never (I think) consulting any part of the + repository which does not correspond to the working directory + ("correspond" == Name_Repository). + + 2b. W_LOCAL is set and so is W_REPOS or W_ATTIC. This is the + weird one. The current directory when we are called must be + the working directory. We recurse through working directories, + but we recurse into a directory if it is exists in the working + directory *or* it exists in the repository. If a directory + does not exist in the working directory, the direntproc must + either tell us to skip it (R_SKIP_ALL), or must create it (I + think those are the only two cases). */ int which; + int aflag; int readlock; char *update_preload; int dosrcs; - int wd_is_repos; /* Set if caller has already cd'd to the repository */ { int i, err = 0; - Dtype flags; 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[0] = '\0'; - else - (void) strcpy (update_dir, update_preload); - - if (local) - flags = R_SKIP_DIRS; + update_dir = xstrdup (""); else - flags = R_PROCESS; + update_dir = xstrdup (update_preload); /* clean up from any previous calls to start_recursion */ if (repository) @@ -101,10 +135,17 @@ start_recursion (fileproc, filesdoneproc, direntproc, dirleaveproc, } if (filelist) dellist (&filelist); /* FIXME-krp: no longer correct. */ -/* FIXME-krp: clean up files_by_dir */ 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) { @@ -116,14 +157,12 @@ start_recursion (fileproc, filesdoneproc, direntproc, dirleaveproc, * called with the list of sub-dirs of the current dir as args */ if ((which & W_LOCAL) && !isdir (CVSADM)) - dirlist = Find_Directories ((char *) NULL, W_LOCAL); + dirlist = Find_Directories ((char *) NULL, W_LOCAL, (List *) NULL); else addlist (&dirlist, "."); - err += do_recursion (fileproc, filesdoneproc, direntproc, - dirleaveproc, flags, which, aflag, - readlock, dosrcs); - return(err); + err += do_recursion (&frame); + goto out; } @@ -151,7 +190,6 @@ start_recursion (fileproc, filesdoneproc, direntproc, dirleaveproc, /* otherwise, split argument into directory and component names. */ char *dir; char *comp; - char tmp[PATH_MAX]; char *file_to_try; /* Now break out argv[i] into directory part (DIR) and file part (COMP). @@ -174,45 +212,55 @@ start_recursion (fileproc, filesdoneproc, direntproc, dirleaveproc, /* if this argument exists as a file in the current working directory tree, then add it to the files list. */ - if (wd_is_repos) + if (!(which & W_LOCAL)) { /* If doing rtag, we've done a chdir to the repository. */ - sprintf (tmp, "%s%s", argv[i], RCSEXT); - file_to_try = tmp; + file_to_try = xmalloc (strlen (argv[i]) + sizeof (RCSEXT) + 5); + sprintf (file_to_try, "%s%s", argv[i], RCSEXT); } else - file_to_try = argv[i]; + file_to_try = xstrdup (argv[i]); - if(isfile(file_to_try)) + if (isfile (file_to_try)) addfile (&files_by_dir, dir, comp); else if (isdir (dir)) { - if (isdir (CVSADM)) + if ((which & W_LOCAL) && isdir (CVSADM) +#ifdef CLIENT_SUPPORT + && !client_active +#endif + ) { /* otherwise, look for it in the repository. */ - char *save_update_dir; + char *tmp_update_dir; char *repos; - - /* save & set (aka push) update_dir */ - save_update_dir = xstrdup (update_dir); + char *reposfile; + + tmp_update_dir = xmalloc (strlen (update_dir) + + strlen (dir) + + 5); + strcpy (tmp_update_dir, update_dir); - if (*update_dir != '\0') - (void) strcat (update_dir, "/"); + if (*tmp_update_dir != '\0') + (void) strcat (tmp_update_dir, "/"); + + (void) strcat (tmp_update_dir, dir); - (void) strcat (update_dir, dir); - /* look for it in the repository. */ - repos = Name_Repository (dir, update_dir); - (void) sprintf (tmp, "%s/%s", repos, comp); + 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(tmp)) + if (!wrap_name_has (comp, WRAP_TOCVS) && isdir (reposfile)) addlist (&dirlist, argv[i]); else addfile (&files_by_dir, dir, comp); - (void) sprintf (update_dir, "%s", save_update_dir); - free (save_update_dir); + free (tmp_update_dir); + free (reposfile); } else addfile (&files_by_dir, dir, comp); @@ -220,6 +268,7 @@ start_recursion (fileproc, filesdoneproc, direntproc, dirleaveproc, else error (1, 0, "no such directory `%s'", dir); + free (file_to_try); free (dir); free (comp); } @@ -229,29 +278,21 @@ start_recursion (fileproc, filesdoneproc, direntproc, dirleaveproc, a coupla lists. Now we unroll the lists, setting up and calling do_recursion. */ - frame.fileproc = fileproc; - frame.filesdoneproc = filesdoneproc; - frame.direntproc = direntproc; - frame.dirleaveproc = dirleaveproc; - frame.flags = flags; - frame.which = which; - frame.aflag = aflag; - frame.readlock = readlock; - frame.dosrcs = dosrcs; err += walklist (files_by_dir, unroll_files_proc, (void *) &frame); + dellist(&files_by_dir); /* then do_recursion on the dirlist. */ if (dirlist != NULL) - err += do_recursion (frame.fileproc, frame.filesdoneproc, - frame.direntproc, frame.dirleaveproc, - frame.flags, frame.which, frame.aflag, - frame.readlock, frame.dosrcs); + err += do_recursion (&frame); /* Free the data which expand_wild allocated. */ for (i = 0; i < argc; ++i) free (argv[i]); free (argv); + out: + free (update_dir); + update_dir = NULL; return (err); } @@ -259,38 +300,21 @@ start_recursion (fileproc, filesdoneproc, direntproc, dirleaveproc, * Implement the recursive policies on the local directory. This may be * called directly, or may be called by start_recursion */ -int -do_recursion (xfileproc, xfilesdoneproc, xdirentproc, xdirleaveproc, - xflags, xwhich, xaflag, xreadlock, xdosrcs) - FILEPROC xfileproc; - FILESDONEPROC xfilesdoneproc; - DIRENTPROC xdirentproc; - DIRLEAVEPROC xdirleaveproc; - Dtype xflags; - int xwhich; - int xaflag; - int xreadlock; - int xdosrcs; +static int +do_recursion (frame) + struct recursion_frame *frame; { int err = 0; int dodoneproc = 1; char *srepository; List *entries = NULL; + int should_readlock; /* do nothing if told */ - if (xflags == R_SKIP_ALL) + if (frame->flags == R_SKIP_ALL) return (0); - /* set up the static vars */ - fileproc = xfileproc; - filesdoneproc = xfilesdoneproc; - direntproc = xdirentproc; - dirleaveproc = xdirleaveproc; - flags = xflags; - which = xwhich; - aflag = xaflag; - readlock = noexec ? 0 : xreadlock; - dosrcs = xdosrcs; + should_readlock = noexec ? 0 : frame->readlock; /* The fact that locks are not active here is what makes us fail to have the @@ -332,14 +356,14 @@ do_recursion (xfileproc, xfilesdoneproc, xdirentproc, xdirleaveproc, */ if (server_active /* If there are writelocks around, we cannot pause here. */ - && (readlock || noexec)) + && (should_readlock || noexec)) server_pause_check(); #endif /* * Fill in repository with the current repository */ - if (which & W_LOCAL) + if (frame->which & W_LOCAL) { if (isdir (CVSADM)) repository = Name_Repository ((char *) NULL, update_dir); @@ -348,8 +372,9 @@ do_recursion (xfileproc, xfilesdoneproc, xdirentproc, xdirleaveproc, } else { - repository = xmalloc (PATH_MAX); - (void) getwd (repository); + repository = xgetwd (); + if (repository == NULL) + error (1, errno, "could not get working directory"); } srepository = repository; /* remember what to free */ @@ -373,41 +398,52 @@ do_recursion (xfileproc, xfilesdoneproc, xdirentproc, xdirleaveproc, if (filelist == NULL && dirlist == NULL) { /* both lists were NULL, so start from scratch */ - if (fileproc != NULL && flags != R_SKIP_FILES) + if (frame->fileproc != NULL && frame->flags != R_SKIP_FILES) { - int lwhich = which; + int lwhich = frame->which; /* be sure to look in the attic if we have sticky tags/date */ if ((lwhich & W_ATTIC) == 0) if (isreadable (CVSADM_TAG)) lwhich |= W_ATTIC; + /* In the !(which & W_LOCAL) case, we filled in repository + earlier in the function. In the (which & W_LOCAL) case, + the Find_Names function is going to look through the + Entries file. If we do not have a repository, that + does not make sense, so we insist upon having a + repository at this point. Name_Repository will give a + reasonable error message. */ + if (repository == NULL) + repository = Name_Repository ((char *) NULL, update_dir); + /* find the files and fill in entries if appropriate */ - filelist = Find_Names (repository, lwhich, aflag, &entries); + filelist = Find_Names (repository, lwhich, frame->aflag, &entries); } /* find sub-directories if we will recurse */ - if (flags != R_SKIP_DIRS) - dirlist = Find_Directories (repository, which); + if (frame->flags != R_SKIP_DIRS) + dirlist = Find_Directories (repository, frame->which, entries); } else { /* something was passed on the command line */ - if (filelist != NULL && fileproc != NULL) + if (filelist != NULL && frame->fileproc != NULL) { /* we will process files, so pre-parse entries */ - if (which & W_LOCAL) - entries = Entries_Open (aflag); + if (frame->which & W_LOCAL) + entries = Entries_Open (frame->aflag); } } /* process the files (if any) */ - if (filelist != NULL && fileproc) + if (filelist != NULL && frame->fileproc) { struct file_info finfo_struct; + struct frame_and_file frfile; /* read lock it if necessary */ - if (readlock && repository && Reader_Lock (repository) != 0) + if (should_readlock && repository && Reader_Lock (repository) != 0) error (1, 0, "read lock failed - giving up"); #ifdef CLIENT_SUPPORT @@ -424,39 +460,50 @@ do_recursion (xfileproc, xfilesdoneproc, xdirentproc, xdirleaveproc, finfo_struct.entries = entries; /* do_file_proc will fill in finfo_struct.file. */ + frfile.finfo = &finfo_struct; + frfile.frame = frame; + /* process the files */ - err += walklist (filelist, do_file_proc, &finfo_struct); + err += walklist (filelist, do_file_proc, &frfile); /* unlock it */ - if (readlock) + if (should_readlock) Lock_Cleanup (); /* clean up */ dellist (&filelist); } - if (entries) - { - Entries_Close (entries); - entries = NULL; - } - /* call-back files done proc (if any) */ - if (dodoneproc && filesdoneproc != NULL) - err = filesdoneproc (err, repository, update_dir[0] ? update_dir : "."); + if (dodoneproc && frame->filesdoneproc != NULL) + err = frame->filesdoneproc (frame->callerdat, err, repository, + update_dir[0] ? update_dir : ".", + entries); fileattr_write (); fileattr_free (); /* process the directories (if necessary) */ if (dirlist != NULL) - err += walklist (dirlist, do_dir_proc, NULL); -#ifdef notdef - else if (dirleaveproc != NULL) - err += dirleaveproc(".", err, "."); + { + 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; + } + /* free the saved copy of the pointer if necessary */ if (srepository) { @@ -475,7 +522,8 @@ do_file_proc (p, closure) Node *p; void *closure; { - struct file_info *finfo = (struct file_info *)closure; + struct frame_and_file *frfile = (struct frame_and_file *)closure; + struct file_info *finfo = frfile->finfo; int ret; finfo->file = p->key; @@ -490,15 +538,20 @@ do_file_proc (p, closure) } strcat (finfo->fullname, finfo->file); - if (dosrcs && repository) + if (frfile->frame->dosrcs && repository) finfo->rcs = RCS_parse (finfo->file, repository); else finfo->rcs = (RCSNode *) NULL; - ret = fileproc (finfo); + ret = frfile->frame->fileproc (frfile->frame->callerdat, finfo); freercsnode(&finfo->rcs); free (finfo->fullname); + /* Allow the user to monitor progress with tail -f. Doing this once + per file should be no big deal, but we don't want the performance + hit of flushing on every line like previous versions of CVS. */ + cvs_flushout (); + return (ret); } @@ -510,8 +563,11 @@ 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[PATH_MAX]; + char *newrepos; List *sdirlist; char *srepository; char *cp; @@ -519,6 +575,46 @@ do_dir_proc (p, closure) int stripped_dot = 0; int err = 0; struct saved_cwd cwd; + char *saved_update_dir; + + if (fncmp (dir, CVSADM) == 0) + { + /* This seems to most often happen when users (beginning users, + generally), try "cvs ci *" or something similar. On that + theory, it is possible that we should just silently skip the + CVSADM directories, but on the other hand, using a wildcard + like this isn't necessarily a practice to encourage (it operates + only on files which exist in the working directory, unlike + regular CVS recursion). */ + + /* FIXME-reentrancy: printed_cvs_msg should be in a "command + struct" or some such, so that it gets cleared for each new + command (this is possible using the remote protocol and a + custom-written client). The struct recursion_frame is not + far back enough though, some commands (commit at least) + will call start_recursion several times. An alternate solution + would be to take this whole check and move it to a new function + validate_arguments or some such that all the commands call + and which snips the offending directory from the argc,argv + vector. */ + 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); /* set up update_dir - skip dots if not at start */ if (strcmp (dir, ".") != 0) @@ -539,9 +635,12 @@ do_dir_proc (p, closure) * update -d and in that case the generated name will be correct. */ if (repository == NULL) - newrepos[0] = '\0'; + newrepos = xstrdup (""); else + { + newrepos = xmalloc (strlen (repository) + strlen (dir) + 5); (void) sprintf (newrepos, "%s/%s", repository, dir); + } } else { @@ -549,31 +648,33 @@ do_dir_proc (p, closure) (void) strcpy (update_dir, dir); if (repository == NULL) - newrepos[0] = '\0'; + newrepos = xstrdup (""); else - (void) strcpy (newrepos, repository); + newrepos = xstrdup (repository); } /* call-back dir entry proc (if any) */ - if (direntproc != NULL) - dir_return = direntproc (dir, newrepos, update_dir); + if (frame->direntproc != NULL) + dir_return = frame->direntproc (frame->callerdat, dir, newrepos, + update_dir, frent->entries); + free (newrepos); /* only process the dir if the return code was 0 */ if (dir_return != R_SKIP_ALL) { /* save our current directory and static vars */ if (save_cwd (&cwd)) - exit (EXIT_FAILURE); + error_exit (); sdirlist = dirlist; srepository = repository; dirlist = NULL; /* cd to the sub-directory */ - if (chdir (dir) < 0) + if ( CVS_CHDIR (dir) < 0) error (1, errno, "could not chdir to %s", dir); /* honor the global SKIP_DIRS (a.k.a. local) */ - if (flags == R_SKIP_DIRS) + if (frame->flags == R_SKIP_DIRS) dir_return = R_SKIP_DIRS; /* remember if the `.' will be stripped for subsequent dirs */ @@ -584,31 +685,37 @@ do_dir_proc (p, closure) } /* make the recursive call */ - err += do_recursion (fileproc, filesdoneproc, direntproc, dirleaveproc, - dir_return, which, aflag, readlock, dosrcs); + xframe = *frame; + xframe.flags = dir_return; + err += do_recursion (&xframe); /* put the `.' back if necessary */ if (stripped_dot) (void) strcpy (update_dir, "."); /* call-back dir leave proc (if any) */ - if (dirleaveproc != NULL) - err = dirleaveproc (dir, err, update_dir); + if (frame->dirleaveproc != NULL) + err = frame->dirleaveproc (frame->callerdat, dir, err, update_dir, + frent->entries); /* get back to where we started and restore state vars */ if (restore_cwd (&cwd, NULL)) - exit (EXIT_FAILURE); + error_exit (); free_cwd (&cwd); dirlist = sdirlist; repository = srepository; } - /* put back update_dir */ + /* Put back update_dir. I think this is the same as just setting + update_dir back to saved_update_dir, but there are a few cases I'm + not sure about (in particular, if DIR is "." and update_dir is + not ""), so for conservatism I'm leaving this here. */ cp = last_component (update_dir); if (cp > update_dir) cp[-1] = '\0'; else update_dir[0] = '\0'; + free (saved_update_dir); return (err); } @@ -675,17 +782,22 @@ unroll_files_proc (p, closure) /* otherwise, call dorecusion for this list of files. */ filelist = (List *) p->data; + p->data = NULL; save_dirlist = dirlist; dirlist = NULL; if (strcmp(p->key, ".") != 0) { if (save_cwd (&cwd)) - exit (EXIT_FAILURE); - if (chdir (p->key) < 0) + error_exit (); + if ( CVS_CHDIR (p->key) < 0) error (1, errno, "could not chdir to %s", p->key); - save_update_dir = xstrdup (update_dir); + 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, "/"); @@ -693,18 +805,15 @@ unroll_files_proc (p, closure) (void) strcat (update_dir, p->key); } - err += do_recursion (frame->fileproc, frame->filesdoneproc, - frame->direntproc, frame->dirleaveproc, - frame->flags, frame->which, frame->aflag, - frame->readlock, frame->dosrcs); + err += do_recursion (frame); if (save_update_dir != NULL) { - (void) strcpy (update_dir, save_update_dir); - free (save_update_dir); + free (update_dir); + update_dir = save_update_dir; if (restore_cwd (&cwd, NULL)) - exit (EXIT_FAILURE); + error_exit (); free_cwd (&cwd); } |