This is add.c in view mode; [Download] [Up]
/* * 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.3 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" /* rcvs: header */ #include "rcvs.h" #ifndef lint static char rcsid[] = "@(#)add.c 1.46 92/04/03"; #endif #if __STDC__ static int add_directory (char *repository, char *dir); static int build_entry (char *repository, char *user, char *options, char *message, List * entries); #else static int add_directory (); static int build_entry (); #endif /* __STDC__ */ static char *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[MAXMESGLEN]; 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); /* parse args */ message[0] = '\0'; optind = 1; while ((c = gnu_getopt (argc, argv, "k:m:")) != -1) { /* rcvs: quietly go through all options */ if (rcvs_parse_opt) continue; switch (c) { case 'k': if (options) free (options); options = RCS_check_kflag (optarg); break; case 'm': if (strlen (optarg) >= sizeof (message)) { error (0, 0, "warning: message too long; truncated!"); (void) strncpy (message, optarg, sizeof (message)); message[sizeof (message) - 1] = '\0'; } else (void) strcpy (message, optarg); break; case '?': default: usage (add_usage); break; } } argc -= optind; argv += optind; if (argc <= 0) usage (add_usage); /* rcvs: return to rcvs_main after parsing options */ if (rcvs_parse_opt) { rcvs_cmd_optind = optind; return (0); } /* find the repository associated with our current dir */ repository = Name_Repository ((char *) NULL, (char *) NULL); entries = ParseEntries (0); /* walk the arg list adding files/dirs */ for (i = 0; i < argc; i++) { int begin_err = err; user = argv[i]; if (index (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, (List *) 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)) { /* * 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) != 0) err++; else if (!quiet) { added_files++; error (0, 0, "scheduling file `%s' for addition", user); } } } 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); free (tmp); /* XXX - bugs here; this really resurrect the head */ 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)) { err += add_directory (repository, user); continue; } } if (added_files) error (0, 0, "use 'cvs commit' to add %s permanently", (added_files == 1) ? "this file" : "these files"); dellist (&entries); 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 cwd[PATH_MAX], rcsdir[PATH_MAX]; char message[PATH_MAX + 100]; char *tag, *date; if (index (dir, '/') != NULL) { error (0, 0, "directory %s not added; must be a direct sub-directory", dir); return (1); } if (strcmp (dir, CVSADM) == 0 || strcmp (dir, OCVSADM) == 0) { error (0, 0, "cannot add a `%s' or a `%s' directory", CVSADM, OCVSADM); 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 (getwd (cwd) == NULL) { error (0, 0, "cannot get working directory: %s", cwd); return (1); } if (chdir (dir) < 0) { error (0, errno, "cannot chdir to %s", dir); return (1); } if (isfile (CVSADM) || isfile (OCVSADM)) { error (0, 0, "%s/%s (or %s/%s) already exists", dir, CVSADM, dir, OCVSADM); 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; char line[MAXLINELEN]; Node *p; List *ulist; (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; } omask = umask (2); if (mkdir (rcsdir, 0777) < 0) { error (0, errno, "cannot mkdir %s", rcsdir); (void) umask ((int) omask); goto out; } (void) umask ((int) 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); } Create_Admin (".", rcsdir, tag, date); if (tag) free (tag); if (date) free (date); (void) printf ("%s", message); out: if (chdir (cwd) < 0) error (1, errno, "cannot chdir to %s", 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) char *repository; char *user; char *options; char *message; List *entries; { char fname[PATH_MAX]; char line[MAXLINELEN]; FILE *fp; /* * There may be an old file with the same name in the Attic! This is, * perhaps, an awkward place to check for this, but other places are * equally awkward. */ (void) sprintf (fname, "%s/%s/%s%s", repository, CVSATTIC, user, RCSEXT); if (isreadable (fname)) { error (0, 0, "there is an old file %s already in %s/%s", user, repository, CVSATTIC); return (1); } if (noexec) return (0); /* * The options for the "add" command are store in the file CVS/user,p */ (void) sprintf (fname, "%s/%s%s", CVSADM, user, CVSEXT_OPT); fp = open_file (fname, "w+"); if (fclose (fp) == EOF) error(1, errno, "cannot close %s", fname); /* * And 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 ,p * and ,t files, but who cares). */ (void) sprintf (line, "Initial %s", user); Register (entries, user, "0", line, options, (char *) 0, (char *) 0); return (0); }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.