diff options
Diffstat (limited to 'contrib/cvs/src/recurse.c')
-rw-r--r-- | contrib/cvs/src/recurse.c | 102 |
1 files changed, 77 insertions, 25 deletions
diff --git a/contrib/cvs/src/recurse.c b/contrib/cvs/src/recurse.c index d5eeabf705ed8..b807e2dc4dda5 100644 --- a/contrib/cvs/src/recurse.c +++ b/contrib/cvs/src/recurse.c @@ -12,6 +12,7 @@ #include "savecwd.h" #include "fileattr.h" #include "edit.h" +#include <assert.h> static int do_dir_proc PROTO((Node * p, void *closure)); static int do_file_proc PROTO((Node * p, void *closure)); @@ -35,6 +36,7 @@ struct recursion_frame { int aflag; int locktype; int dosrcs; + char *repository; /* Keep track of repository for rtag */ }; static int do_recursion PROTO ((struct recursion_frame *frame)); @@ -67,7 +69,7 @@ struct frame_and_entries { int start_recursion (fileproc, filesdoneproc, direntproc, dirleaveproc, callerdat, argc, argv, local, which, aflag, locktype, - update_preload, dosrcs) + update_preload, dosrcs, repository_in) FILEPROC fileproc; FILESDONEPROC filesdoneproc; DIRENTPROC direntproc; @@ -105,6 +107,15 @@ start_recursion (fileproc, filesdoneproc, direntproc, dirleaveproc, callerdat, int locktype; char *update_preload; int dosrcs; + /* Keep track of the repository string. This is only for the remote mode, + * specifically, r* commands (rtag, rdiff, co, ...) where xgetwd() was + * used to locate the repository. Things would break when xgetwd() was + * used with a symlinked repository because xgetwd() would return the true + * path and in some cases this would cause the path to be printed as other + * than the user specified in error messages and in other cases some of + * CVS's security assertions would fail. + */ + char *repository_in; { int i, err = 0; #ifdef CLIENT_SUPPORT @@ -123,6 +134,7 @@ start_recursion (fileproc, filesdoneproc, direntproc, dirleaveproc, callerdat, frame.aflag = aflag; frame.locktype = locktype; frame.dosrcs = dosrcs; + frame.repository = repository_in; expand_wild (argc, argv, &argc, &argv); @@ -261,7 +273,10 @@ start_recursion (fileproc, filesdoneproc, direntproc, dirleaveproc, callerdat, /* Now break out argv[i] into directory part (DIR) and file part (COMP). DIR and COMP will each point to a newly malloc'd string. */ dir = xstrdup (argv[i]); - comp = last_component (dir); + /* Its okay to discard the const below - we know we just allocated + * dir ourselves. + */ + comp = (char *)last_component (dir); if (comp == dir) { /* no dir component. What we have is an implied "./" */ @@ -502,7 +517,7 @@ do_recursion (frame) { int err = 0; int dodoneproc = 1; - char *srepository; + char *srepository = NULL; List *entries = NULL; int locktype; int process_this_directory = 1; @@ -613,17 +628,19 @@ do_recursion (frame) if (frame->which & W_LOCAL) { if (isdir (CVSADM)) + { repository = Name_Repository ((char *) NULL, update_dir); + srepository = repository; /* remember what to free */ + } else repository = NULL; } else { - repository = xgetwd (); - if (repository == NULL) - error (1, errno, "could not get working directory"); + repository = frame->repository; + assert (repository != NULL); + assert (strstr (repository, "/./") == NULL); } - srepository = repository; /* remember what to free */ fileattr_startdir (repository); @@ -662,7 +679,10 @@ do_recursion (frame) repository at this point. Name_Repository will give a reasonable error message. */ if (repository == NULL) - repository = Name_Repository ((char *) NULL, update_dir); + { + Name_Repository ((char *) NULL, update_dir); + assert (!"Not reached. Please report this problem to <bug-cvs@gnu.org>"); + } /* find the files and fill in entries if appropriate */ if (process_this_directory) @@ -736,7 +756,10 @@ do_recursion (frame) err += walklist (filelist, do_file_proc, &frfile); /* unlock it */ - if (locktype != CVS_LOCK_NONE) + if (/* We only lock the repository above when repository is set */ + repository + /* and when asked for a read or write lock. */ + && locktype != CVS_LOCK_NONE) Lock_Cleanup (); /* clean up */ @@ -778,12 +801,14 @@ do_recursion (frame) if (srepository) { free (srepository); - repository = (char *) NULL; } + repository = (char *) NULL; - return (err); + return err; } + + /* * Process each of the files in the list with the callback proc */ @@ -795,18 +820,19 @@ do_file_proc (p, closure) struct frame_and_file *frfile = (struct frame_and_file *)closure; struct file_info *finfo = frfile->finfo; int ret; + char *tmp; finfo->file = p->key; - finfo->fullname = xmalloc (strlen (finfo->file) + tmp = xmalloc (strlen (finfo->file) + strlen (finfo->update_dir) + 2); - finfo->fullname[0] = '\0'; + tmp[0] = '\0'; if (finfo->update_dir[0] != '\0') { - strcat (finfo->fullname, finfo->update_dir); - strcat (finfo->fullname, "/"); + strcat (tmp, finfo->update_dir); + strcat (tmp, "/"); } - strcat (finfo->fullname, finfo->file); + strcat (tmp, finfo->file); if (frfile->frame->dosrcs && repository) { @@ -821,27 +847,30 @@ do_file_proc (p, closure) if (finfo->rcs == NULL && !(frfile->frame->which & W_LOCAL)) { - error (0, 0, "could not read RCS file for %s", finfo->fullname); - free (finfo->fullname); + error (0, 0, "could not read RCS file for %s", tmp); + free (tmp); cvs_flushout (); return 0; } } else finfo->rcs = (RCSNode *) NULL; + finfo->fullname = tmp; ret = frfile->frame->fileproc (frfile->frame->callerdat, finfo); freercsnode(&finfo->rcs); - free (finfo->fullname); + free (tmp); /* 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); + return ret; } + + /* * Process each of the directories in the list (recursing as we go) */ @@ -1076,7 +1105,7 @@ but CVS uses %s for its own purposes; skipping %s directory", dirlist = NULL; /* cd to the sub-directory */ - if ( CVS_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) */ @@ -1093,7 +1122,30 @@ but CVS uses %s for its own purposes; skipping %s directory", /* make the recursive call */ xframe = *frame; xframe.flags = dir_return; + /* Keep track of repository, really just for r* commands (rtag, rdiff, + * co, ...) to tag_check_valid, since all the other commands use + * CVS/Repository to figure it out per directory. + */ + if (repository) + { + if (strcmp (dir, ".") == 0) + xframe.repository = xstrdup (repository); + else + { + xframe.repository = xmalloc (strlen (repository) + + strlen (dir) + + 2); + sprintf (xframe.repository, "%s/%s", repository, dir); + } + } + else + xframe.repository = NULL; err += do_recursion (&xframe); + if (xframe.repository) + { + free (xframe.repository); + xframe.repository = NULL; + } /* put the `.' back if necessary */ if (stripped_dot) @@ -1115,7 +1167,7 @@ but CVS uses %s for its own purposes; skipping %s directory", free (update_dir); update_dir = saved_update_dir; - return (err); + return err; } /* @@ -1157,9 +1209,9 @@ addfile (listp, dir, file) } n->type = DIRS; - fl = (List *) n->data; + fl = n->data; addlist (&fl, file); - n->data = (char *) fl; + n->data = fl; return; } @@ -1182,7 +1234,7 @@ unroll_files_proc (p, closure) return (0); /* otherwise, call dorecusion for this list of files. */ - filelist = (List *) p->data; + filelist = p->data; p->data = NULL; save_dirlist = dirlist; dirlist = NULL; |