diff options
author | peter <peter@FreeBSD.org> | 1996-08-20 23:46:10 +0000 |
---|---|---|
committer | peter <peter@FreeBSD.org> | 1996-08-20 23:46:10 +0000 |
commit | 8982e501c77217c860f79bba431f46a62b607a21 (patch) | |
tree | 70187fdf5be4cbefd0baf46bddac7e5e32c13c24 /contrib/cvs/src/add.c | |
parent | 01ee40fd6a76f6ff7ef247fc1b2cf6e337f216c5 (diff) | |
download | FreeBSD-src-8982e501c77217c860f79bba431f46a62b607a21.zip FreeBSD-src-8982e501c77217c860f79bba431f46a62b607a21.tar.gz |
Import of slightly trimmed cvs-1.8 distribution. Generated files
and non-unix code has been left out.
Diffstat (limited to 'contrib/cvs/src/add.c')
-rw-r--r-- | contrib/cvs/src/add.c | 514 |
1 files changed, 514 insertions, 0 deletions
diff --git a/contrib/cvs/src/add.c b/contrib/cvs/src/add.c new file mode 100644 index 0000000..82efefe --- /dev/null +++ b/contrib/cvs/src/add.c @@ -0,0 +1,514 @@ +/* + * Copyright (c) 1992, Brian Berliner and Jeff Polk + * Copyright (c) 1989-1992, Brian Berliner + * + * You may distribute under the terms of the GNU General Public License as + * specified in the README file that comes with the CVS 1.4 kit. + * + * Add + * + * Adds a file or directory to the RCS source repository. For a file, + * the entry is marked as "needing to be added" in the user's own CVS + * directory, and really added to the repository when it is committed. + * For a directory, it is added at the appropriate place in the source + * repository and a CVS directory is generated within the directory. + * + * The -m option is currently the only supported option. Some may wish to + * supply standard "rcs" options here, but I've found that this causes more + * trouble than anything else. + * + * The user files or directories must already exist. For a directory, it must + * not already have a CVS file in it. + * + * An "add" on a file that has been "remove"d but not committed will cause the + * file to be resurrected. + */ + +#include "cvs.h" +#include "savecwd.h" + +static int add_directory PROTO((char *repository, char *dir)); +static int build_entry PROTO((char *repository, char *user, char *options, + char *message, List * entries, char *tag)); + +static const char *const add_usage[] = +{ + "Usage: %s %s [-k rcs-kflag] [-m message] files...\n", + "\t-k\tUse \"rcs-kflag\" to add the file with the specified kflag.\n", + "\t-m\tUse \"message\" for the creation log.\n", + NULL +}; + +int +add (argc, argv) + int argc; + char **argv; +{ + char *message = NULL; + char *user; + int i; + char *repository; + int c; + int err = 0; + int added_files = 0; + char *options = NULL; + List *entries; + Vers_TS *vers; + + if (argc == 1 || argc == -1) + usage (add_usage); + + wrap_setup (); + + /* parse args */ + optind = 1; + while ((c = getopt (argc, argv, "k:m:")) != -1) + { + switch (c) + { + case 'k': + if (options) + free (options); + options = RCS_check_kflag (optarg); + break; + + case 'm': + message = xstrdup (optarg); + break; + case '?': + default: + usage (add_usage); + break; + } + } + argc -= optind; + argv += optind; + + if (argc <= 0) + usage (add_usage); + + /* find the repository associated with our current dir */ + repository = Name_Repository ((char *) NULL, (char *) NULL); + +#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])) + { + char *tag; + char *date; + char *rcsdir = xmalloc (strlen (repository) + + strlen (argv[i]) + 10); + + /* before we do anything else, see if we have any + per-directory tags */ + ParseTag (&tag, &date); + + sprintf (rcsdir, "%s/%s", repository, argv[i]); + + Create_Admin (argv[i], argv[i], rcsdir, tag, date); + + if (tag) + free (tag); + if (date) + free (date); + free (rcsdir); + } + send_file_names (argc, argv, SEND_EXPAND_WILD); + send_files (argc, argv, 0, 0); + send_to_server ("add\012", 0); + return get_responses_and_close (); + } +#endif + + entries = Entries_Open (0); + + /* walk the arg list adding files/dirs */ + for (i = 0; i < argc; i++) + { + int begin_err = err; + int begin_added_files = added_files; + + user = argv[i]; + strip_trailing_slashes (user); + if (strchr (user, '/') != NULL) + { + error (0, 0, + "cannot add files with '/' in their name; %s not added", user); + err++; + continue; + } + + vers = Version_TS (repository, options, (char *) NULL, (char *) NULL, + user, 0, 0, entries, (RCSNode *) NULL); + if (vers->vn_user == NULL) + { + /* No entry available, ts_rcs is invalid */ + if (vers->vn_rcs == NULL) + { + /* There is no RCS file either */ + if (vers->ts_user == NULL) + { + /* There is no user file either */ + error (0, 0, "nothing known about %s", user); + err++; + } + else if (!isdir (user) || wrap_name_has (user, WRAP_TOCVS)) + { + /* + * See if a directory exists in the repository with + * the same name. If so, blow this request off. + */ + char dname[PATH_MAX]; + (void) sprintf (dname, "%s/%s", repository, user); + if (isdir (dname)) + { + error (0, 0, + "cannot add file `%s' since the directory", + user); + error (0, 0, "`%s' already exists in the repository", + dname); + error (1, 0, "illegal filename overlap"); + } + + /* 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); + } + } + } + } + else if (RCS_isdead (vers->srcfile, vers->vn_rcs)) + { + 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."); + } + else + { + if (vers->tag) + error (0, 0, "file `%s' will be added on branch `%s' from version %s", + user, vers->tag, vers->vn_rcs); + 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; + } + } + else + { + /* + * There is an RCS file already, so somebody else must've + * added it + */ + error (0, 0, "%s added independently by second party", user); + err++; + } + } + else if (vers->vn_user[0] == '0' && vers->vn_user[1] == '\0') + { + + /* + * An entry for a new-born file, ts_rcs is dummy, but that is + * inappropriate here + */ + error (0, 0, "%s has already been entered", user); + err++; + } + else if (vers->vn_user[0] == '-') + { + /* An entry for a removed file, ts_rcs is invalid */ + if (vers->ts_user == NULL) + { + /* There is no user file (as it should be) */ + if (vers->vn_rcs == NULL) + { + + /* + * 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); + err++; + } + else + { + + /* + * There is an RCS file, so remove the "-" from the + * version number and restore the file + */ + char *tmp = xmalloc (strlen (user) + 50); + + (void) strcpy (tmp, vers->vn_user + 1); + (void) strcpy (vers->vn_user, tmp); + (void) sprintf (tmp, "Resurrected %s", user); + Register (entries, user, vers->vn_user, tmp, vers->options, + vers->tag, vers->date, vers->ts_conflict); + free (tmp); + + /* XXX - bugs here; this really resurrect the head */ + /* Note that this depends on the Register above actually + having written Entries, or else it won't really + check the file out. */ + if (update (2, argv + i - 1) == 0) + { + error (0, 0, "%s, version %s, resurrected", user, + vers->vn_user); + } + else + { + error (0, 0, "could not resurrect %s", user); + err++; + } + } + } + else + { + /* The user file shouldn't be there */ + error (0, 0, "%s should be removed and is still there (or is back again)", user); + err++; + } + } + else + { + /* A normal entry, ts_rcs is valid, so it must already be there */ + error (0, 0, "%s already exists, with version number %s", user, + vers->vn_user); + err++; + } + freevers_ts (&vers); + + /* passed all the checks. Go ahead and add it if its a directory */ + if (begin_err == err + && isdir (user) + && !wrap_name_has (user, WRAP_TOCVS)) + { + err += add_directory (repository, user); + continue; + } +#ifdef SERVER_SUPPORT + if (server_active && begin_added_files != added_files) + server_checked_in (user, ".", repository); +#endif + } + if (added_files) + error (0, 0, "use 'cvs commit' to add %s permanently", + (added_files == 1) ? "this file" : "these files"); + + Entries_Close (entries); + + if (message) + free (message); + + return (err); +} + +/* + * The specified user file is really a directory. So, let's make sure that + * it is created in the RCS source repository, and that the user's directory + * is updated to include a CVS directory. + * + * Returns 1 on failure, 0 on success. + */ +static int +add_directory (repository, dir) + char *repository; + char *dir; +{ + char rcsdir[PATH_MAX]; + struct saved_cwd cwd; + char message[PATH_MAX + 100]; + char *tag, *date; + + if (strchr (dir, '/') != NULL) + { + error (0, 0, + "directory %s not added; must be a direct sub-directory", dir); + return (1); + } + if (strcmp (dir, CVSADM) == 0) + { + error (0, 0, "cannot add a `%s' directory", CVSADM); + return (1); + } + + /* before we do anything else, see if we have any per-directory tags */ + ParseTag (&tag, &date); + + /* now, remember where we were, so we can get back */ + if (save_cwd (&cwd)) + return (1); + if (chdir (dir) < 0) + { + error (0, errno, "cannot chdir to %s", dir); + return (1); + } +#ifdef SERVER_SUPPORT + if (!server_active && isfile (CVSADM)) +#else + if (isfile (CVSADM)) +#endif + { + error (0, 0, "%s/%s already exists", dir, CVSADM); + goto out; + } + + (void) sprintf (rcsdir, "%s/%s", repository, dir); + if (isfile (rcsdir) && !isdir (rcsdir)) + { + error (0, 0, "%s is not a directory; %s not added", rcsdir, dir); + goto out; + } + + /* setup the log message */ + (void) sprintf (message, "Directory %s added to the repository\n", rcsdir); + if (tag) + { + (void) strcat (message, "--> Using per-directory sticky tag `"); + (void) strcat (message, tag); + (void) strcat (message, "'\n"); + } + if (date) + { + (void) strcat (message, "--> Using per-directory sticky date `"); + (void) strcat (message, date); + (void) strcat (message, "'\n"); + } + + if (!isdir (rcsdir)) + { + mode_t omask; + Node *p; + List *ulist; + +#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 + + omask = umask (cvsumask); + if (CVS_MKDIR (rcsdir, 0777) < 0) + { + error (0, errno, "cannot mkdir %s", rcsdir); + (void) umask (omask); + goto out; + } + (void) umask (omask); + + /* + * Set up an update list with a single title node for Update_Logfile + */ + ulist = getlist (); + p = getnode (); + p->type = UPDATE; + p->delproc = update_delproc; + p->key = xstrdup ("- New directory"); + p->data = (char *) T_TITLE; + (void) addnode (ulist, p); + Update_Logfile (rcsdir, message, (char *) NULL, (FILE *) NULL, ulist); + dellist (&ulist); + } + +#ifdef SERVER_SUPPORT + if (!server_active) + Create_Admin (".", dir, rcsdir, tag, date); +#else + Create_Admin (".", dir, rcsdir, tag, date); +#endif + if (tag) + free (tag); + if (date) + free (date); + + (void) printf ("%s", message); +out: + if (restore_cwd (&cwd, NULL)) + exit (EXIT_FAILURE); + free_cwd (&cwd); + return (0); +} + +/* + * Builds an entry for a new file and sets up "CVS/file",[pt] by + * interrogating the user. Returns non-zero on error. + */ +static int +build_entry (repository, user, options, message, entries, tag) + char *repository; + char *user; + char *options; + char *message; + List *entries; + char *tag; +{ + char fname[PATH_MAX]; + char line[MAXLINELEN]; + FILE *fp; + + if (noexec) + return (0); + + /* + * The requested log is read directly from the user and stored in the + * file user,t. If the "message" argument is set, use it as the + * initial creation log (which typically describes the file). + */ + (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); + + /* + * 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). + */ + (void) sprintf (line, "Initial %s", user); + Register (entries, user, "0", line, options, tag, (char *) 0, (char *) 0); + return (0); +} |