diff options
Diffstat (limited to 'contrib/cvs/src/add.c')
-rw-r--r-- | contrib/cvs/src/add.c | 324 |
1 files changed, 233 insertions, 91 deletions
diff --git a/contrib/cvs/src/add.c b/contrib/cvs/src/add.c index 82efefe..b7d5e5d 100644 --- a/contrib/cvs/src/add.c +++ b/contrib/cvs/src/add.c @@ -27,7 +27,7 @@ #include "cvs.h" #include "savecwd.h" -static int add_directory PROTO((char *repository, char *dir)); +static int add_directory PROTO((char *repository, List *, char *dir)); static int build_entry PROTO((char *repository, char *user, char *options, char *message, List * entries, char *tag)); @@ -39,6 +39,47 @@ static const char *const add_usage[] = NULL }; +static char *combine_dir PROTO ((char *, char *)); + +/* Given a directory DIR and a subdirectory within it, SUBDIR, combine + the two into a new directory name. Returns a newly malloc'd string. + For now this is a fairly simple affair, but perhaps it will want + to have grander ambitions in the context of VMS or others (or perhaps + not, perhaps that should all be hidden inside CVS_FOPEN and libc and so + on, and CVS should just see foo/bar/baz style pathnames). */ +static char * +combine_dir (dir, subdir) + char *dir; + char *subdir; +{ + char *retval; + size_t dir_len; + + dir_len = strlen (dir); + retval = xmalloc (dir_len + strlen (subdir) + 10); + if (dir_len >= 2 + && dir[dir_len - 1] == '.' + && ISDIRSEP (dir[dir_len - 2])) + { + /* The dir name has an extraneous "." at the end. + I'm not completely sure that this is the best place + to strip it off--it is possible that Name_Repository + should do so, or it shouldn't be in the CVS/Repository + file in the first place. Fixing it here seems like + a safe, small change, but I'm not sure it catches + all the cases. */ + strncpy (retval, dir, dir_len - 2); + retval[dir_len - 2] = '\0'; + } + else + { + strcpy (retval, dir); + } + strcat (retval, "/"); + strcat (retval, subdir); + return retval; +} + int add (argc, argv) int argc; @@ -62,7 +103,7 @@ add (argc, argv) /* parse args */ optind = 1; - while ((c = getopt (argc, argv, "k:m:")) != -1) + while ((c = getopt (argc, argv, "+k:m:")) != -1) { switch (c) { @@ -92,42 +133,61 @@ add (argc, argv) #ifdef CLIENT_SUPPORT if (client_active) - { + { int i; start_server (); ign_setup (); if (options) send_arg(options); option_with_arg ("-m", message); for (i = 0; i < argc; ++i) - /* FIXME: Does this erroneously call Create_Admin in error - conditions which are only detected once the server gets its - hands on things? */ - if (isdir (argv[i])) + /* FIXME: Does this erroneously call Create_Admin in error + conditions which are only detected once the server gets its + hands on things? */ + if (isdir (argv[i])) { - char *tag; - char *date; - char *rcsdir = xmalloc (strlen (repository) - + strlen (argv[i]) + 10); + char *tag; + char *date; + int nonbranch; + char *rcsdir; - /* before we do anything else, see if we have any - per-directory tags */ - ParseTag (&tag, &date); + /* before we do anything else, see if we have any + per-directory tags */ + ParseTag (&tag, &date, &nonbranch); - sprintf (rcsdir, "%s/%s", repository, argv[i]); + rcsdir = combine_dir (repository, argv[i]); - Create_Admin (argv[i], argv[i], rcsdir, tag, date); + strip_trailing_slashes (argv[i]); - if (tag) - free (tag); - if (date) - free (date); - free (rcsdir); + Create_Admin (argv[i], argv[i], rcsdir, tag, date, nonbranch); + + if (tag) + free (tag); + if (date) + free (date); + free (rcsdir); + + if (strchr (argv[i], '/') == NULL) + Subdir_Register ((List *) NULL, (char *) NULL, argv[i]); + else + { + char *cp, *b; + + cp = xstrdup (argv[i]); + b = strrchr (cp, '/'); + *b++ = '\0'; + Subdir_Register ((List *) NULL, cp, b); + free (cp); + } } send_file_names (argc, argv, SEND_EXPAND_WILD); - send_files (argc, argv, 0, 0); + /* FIXME: should be able to pass SEND_NO_CONTENTS, I think. */ + send_files (argc, argv, 0, 0, SEND_BUILD_DIRS); send_to_server ("add\012", 0); + if (message) + free (message); + free (repository); return get_responses_and_close (); - } + } #endif entries = Entries_Open (0); @@ -136,7 +196,10 @@ add (argc, argv) for (i = 0; i < argc; i++) { int begin_err = err; +#ifdef SERVER_SUPPORT int begin_added_files = added_files; +#endif + struct file_info finfo; user = argv[i]; strip_trailing_slashes (user); @@ -148,8 +211,19 @@ add (argc, argv) continue; } - vers = Version_TS (repository, options, (char *) NULL, (char *) NULL, - user, 0, 0, entries, (RCSNode *) NULL); + memset (&finfo, 0, sizeof finfo); + finfo.file = user; + finfo.update_dir = ""; + finfo.fullname = user; + finfo.repository = repository; + finfo.entries = entries; + finfo.rcs = NULL; + + /* We pass force_tag_match as 1. If the directory has a + sticky branch tag, and there is already an RCS file which + does not have that tag, then the head revision is + meaningless to us. */ + vers = Version_TS (&finfo, options, NULL, NULL, 1, 0); if (vers->vn_user == NULL) { /* No entry available, ts_rcs is invalid */ @@ -168,7 +242,8 @@ add (argc, argv) * See if a directory exists in the repository with * the same name. If so, blow this request off. */ - char dname[PATH_MAX]; + char *dname = xmalloc (strlen (repository) + strlen (user) + + 10); (void) sprintf (dname, "%s/%s", repository, user); if (isdir (dname)) { @@ -179,29 +254,55 @@ add (argc, argv) dname); error (1, 0, "illegal filename overlap"); } + free (dname); - /* There is a user file, so build the entry for it */ - if (build_entry (repository, user, vers->options, - message, entries, vers->tag) != 0) - err++; - else + if (vers->options == NULL || *vers->options == '\0') { - added_files++; - if (!quiet) + /* No options specified on command line (or in + rcs file if it existed, e.g. the file exists + on another branch). Check for a value from + the wrapper stuff. */ + if (wrap_name_has (user, WRAP_RCSOPTION)) { - if (vers->tag) - error (0, 0, "\ + if (vers->options) + free (vers->options); + vers->options = wrap_rcsoption (user, 1); + } + } + + if (vers->nonbranch) + { + error (0, 0, + "cannot add file on non-branch tag %s", + vers->tag); + ++err; + } + else + { + /* There is a user file, so build the entry for it */ + if (build_entry (repository, user, vers->options, + message, entries, vers->tag) != 0) + err++; + else + { + added_files++; + if (!quiet) + { + if (vers->tag) + error (0, 0, "\ scheduling %s `%s' for addition on branch `%s'", - (wrap_name_has (user, WRAP_TOCVS) - ? "wrapper" - : "file"), - user, vers->tag); - else - error (0, 0, "scheduling %s `%s' for addition", - (wrap_name_has (user, WRAP_TOCVS) - ? "wrapper" - : "file"), - user); + (wrap_name_has (user, WRAP_TOCVS) + ? "wrapper" + : "file"), + user, vers->tag); + else + error (0, 0, + "scheduling %s `%s' for addition", + (wrap_name_has (user, WRAP_TOCVS) + ? "wrapper" + : "file"), + user); + } } } } @@ -210,20 +311,38 @@ scheduling %s `%s' for addition on branch `%s'", { if (isdir (user) && !wrap_name_has (user, WRAP_TOCVS)) { - error (0, 0, "the directory `%s' cannot be added because a file of the", user); - error (1, 0, "same name already exists in the repository."); + error (0, 0, "\ +the directory `%s' cannot be added because a file of the", user); + error (1, 0, "\ +same name already exists in the repository."); } else { - if (vers->tag) - error (0, 0, "file `%s' will be added on branch `%s' from version %s", - user, vers->tag, vers->vn_rcs); + if (vers->nonbranch) + { + error (0, 0, + "cannot add file on non-branch tag %s", + vers->tag); + ++err; + } else - error (0, 0, "version %s of `%s' will be resurrected", - vers->vn_rcs, user); - Register (entries, user, "0", vers->ts_user, NULL, - vers->tag, NULL, NULL); - ++added_files; + { + if (vers->tag) + error (0, 0, "\ +file `%s' will be added on branch `%s' from version %s", + user, vers->tag, vers->vn_rcs); + else + /* I'm not sure that mentioning + vers->vn_rcs makes any sense here; I + can't think of a way to word the + message which is not confusing. */ + error (0, 0, "\ +re-adding file %s (in place of dead revision %s)", + user, vers->vn_rcs); + Register (entries, user, "0", vers->ts_user, NULL, + vers->tag, NULL, NULL); + ++added_files; + } } } else @@ -259,8 +378,8 @@ scheduling %s `%s' for addition on branch `%s'", * There is no RCS file, so somebody else must've removed * it from under us */ - error (0, 0, - "cannot resurrect %s; RCS file removed by second party", user); + error (0, 0, "\ +cannot resurrect %s; RCS file removed by second party", user); err++; } else @@ -298,7 +417,8 @@ scheduling %s `%s' for addition on branch `%s'", else { /* The user file shouldn't be there */ - error (0, 0, "%s should be removed and is still there (or is back again)", user); + error (0, 0, "\ +%s should be removed and is still there (or is back again)", user); err++; } } @@ -316,7 +436,7 @@ scheduling %s `%s' for addition on branch `%s'", && isdir (user) && !wrap_name_has (user, WRAP_TOCVS)) { - err += add_directory (repository, user); + err += add_directory (repository, entries, user); continue; } #ifdef SERVER_SUPPORT @@ -332,6 +452,7 @@ scheduling %s `%s' for addition on branch `%s'", if (message) free (message); + free (repository); return (err); } @@ -344,14 +465,16 @@ scheduling %s `%s' for addition on branch `%s'", * Returns 1 on failure, 0 on success. */ static int -add_directory (repository, dir) +add_directory (repository, entries, dir) char *repository; + List *entries; char *dir; { - char rcsdir[PATH_MAX]; + char *rcsdir = NULL; struct saved_cwd cwd; - char message[PATH_MAX + 100]; + char *message = NULL; char *tag, *date; + int nonbranch; if (strchr (dir, '/') != NULL) { @@ -366,12 +489,12 @@ add_directory (repository, dir) } /* before we do anything else, see if we have any per-directory tags */ - ParseTag (&tag, &date); + ParseTag (&tag, &date, &nonbranch); /* now, remember where we were, so we can get back */ if (save_cwd (&cwd)) return (1); - if (chdir (dir) < 0) + if ( CVS_CHDIR (dir) < 0) { error (0, errno, "cannot chdir to %s", dir); return (1); @@ -386,7 +509,7 @@ add_directory (repository, dir) goto out; } - (void) sprintf (rcsdir, "%s/%s", repository, dir); + rcsdir = combine_dir (repository, dir); if (isfile (rcsdir) && !isdir (rcsdir)) { error (0, 0, "%s is not a directory; %s not added", rcsdir, dir); @@ -394,6 +517,7 @@ add_directory (repository, dir) } /* setup the log message */ + message = xmalloc (strlen (rcsdir) + 80); (void) sprintf (message, "Directory %s added to the repository\n", rcsdir); if (tag) { @@ -413,30 +537,27 @@ add_directory (repository, dir) mode_t omask; Node *p; List *ulist; + struct logfile_info *li; -#if 0 - char line[MAXLINELEN]; - - (void) printf ("Add directory %s to the repository (y/n) [n] ? ", - rcsdir); - (void) fflush (stdout); - clearerr (stdin); - if (fgets (line, sizeof (line), stdin) == NULL || - (line[0] != 'y' && line[0] != 'Y')) - { - error (0, 0, "directory %s not added", rcsdir); - goto out; - } -#endif + /* There used to be some code here which would prompt for + whether to add the directory. The details of that code had + bitrotted, but more to the point it can't work + client/server, doesn't ask in the right way for GUIs, etc. + A better way of making it harder to accidentally add + directories would be to have to add and commit directories + like for files. The code was #if 0'd at least since CVS 1.5. */ - omask = umask (cvsumask); - if (CVS_MKDIR (rcsdir, 0777) < 0) + if (!noexec) { - error (0, errno, "cannot mkdir %s", rcsdir); + omask = umask (cvsumask); + if (CVS_MKDIR (rcsdir, 0777) < 0) + { + error (0, errno, "cannot mkdir %s", rcsdir); + (void) umask (omask); + goto out; + } (void) umask (omask); - goto out; } - (void) umask (omask); /* * Set up an update list with a single title node for Update_Logfile @@ -446,28 +567,45 @@ add_directory (repository, dir) p->type = UPDATE; p->delproc = update_delproc; p->key = xstrdup ("- New directory"); - p->data = (char *) T_TITLE; + li = (struct logfile_info *) xmalloc (sizeof (struct logfile_info)); + li->type = T_TITLE; + li->tag = xstrdup (tag); + li->rev_old = li->rev_new = NULL; + p->data = (char *) li; (void) addnode (ulist, p); - Update_Logfile (rcsdir, message, (char *) NULL, (FILE *) NULL, ulist); + Update_Logfile (rcsdir, message, (FILE *) NULL, ulist); dellist (&ulist); } #ifdef SERVER_SUPPORT if (!server_active) - Create_Admin (".", dir, rcsdir, tag, date); + Create_Admin (".", dir, rcsdir, tag, date, nonbranch); #else - Create_Admin (".", dir, rcsdir, tag, date); + Create_Admin (".", dir, rcsdir, tag, date, nonbranch); #endif if (tag) free (tag); if (date) free (date); + if (restore_cwd (&cwd, NULL)) + error_exit (); + free_cwd (&cwd); + + Subdir_Register (entries, (char *) NULL, dir); + (void) printf ("%s", message); + free (rcsdir); + free (message); + + return (0); + out: if (restore_cwd (&cwd, NULL)) - exit (EXIT_FAILURE); + error_exit (); free_cwd (&cwd); + if (rcsdir != NULL) + free (rcsdir); return (0); } @@ -484,8 +622,8 @@ build_entry (repository, user, options, message, entries, tag) List *entries; char *tag; { - char fname[PATH_MAX]; - char line[MAXLINELEN]; + char *fname; + char *line; FILE *fp; if (noexec) @@ -496,19 +634,23 @@ build_entry (repository, user, options, message, entries, tag) * file user,t. If the "message" argument is set, use it as the * initial creation log (which typically describes the file). */ + fname = xmalloc (strlen (user) + 80); (void) sprintf (fname, "%s/%s%s", CVSADM, user, CVSEXT_LOG); fp = open_file (fname, "w+"); if (message && fputs (message, fp) == EOF) error (1, errno, "cannot write to %s", fname); if (fclose(fp) == EOF) error(1, errno, "cannot close %s", fname); + free (fname); /* * Create the entry now, since this allows the user to interrupt us above * without needing to clean anything up (well, we could clean up the * ,t file, but who cares). */ + line = xmalloc (strlen (user) + 20); (void) sprintf (line, "Initial %s", user); Register (entries, user, "0", line, options, tag, (char *) 0, (char *) 0); + free (line); return (0); } |