2 * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
4 * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
7 * Portions Copyright (c) 1992, Brian Berliner and Jeff Polk
8 * Portions Copyright (c) 1989-1992, Brian Berliner
10 * You may distribute under the terms of the GNU General Public License as
11 * specified in the README file that comes with the CVS source distribution.
15 * Adds a file or directory to the RCS source repository. For a file,
16 * the entry is marked as "needing to be added" in the user's own CVS
17 * directory, and really added to the repository when it is committed.
18 * For a directory, it is added at the appropriate place in the source
19 * repository and a CVS directory is generated within the directory.
21 * The -m option is currently the only supported option. Some may wish to
22 * supply standard "rcs" options here, but I've found that this causes more
23 * trouble than anything else.
25 * The user files or directories must already exist. For a directory, it must
26 * not already have a CVS file in it.
28 * An "add" on a file that has been "remove"d but not committed will cause the
29 * file to be resurrected.
37 static int add_directory PROTO ((struct file_info *finfo));
38 static int build_entry PROTO((const char *repository, const char *user,
39 const char *options, const char *message,
40 List * entries, const char *tag));
42 static const char *const add_usage[] =
44 "Usage: %s %s [-k rcs-kflag] [-m message] files...\n",
45 "\t-k rcs-kflag\tUse \"rcs-kflag\" to add the file with the specified\n",
47 "\t-m message\tUse \"message\" for the creation log.\n",
48 "(Specify the --help global option for a list of other help options)\n",
67 /* Nonzero if we found a slash, and are thus adding files in a
72 if (argc == 1 || argc == -1)
79 while ((c = getopt (argc, argv, "+k:m:")) != -1)
84 if (options) free (options);
85 options = RCS_check_kflag (optarg);
89 if (message) free (message);
90 message = xstrdup (optarg);
104 cvsroot_len = strlen (current_parsed_root->directory);
106 /* First some sanity checks. I know that the CVS case is (sort of)
107 also handled by add_directory, but we need to check here so the
108 client won't get all confused in send_file_names. */
109 for (i = 0; i < argc; i++)
113 /* If it were up to me I'd probably make this a fatal error.
114 But some people are really fond of their "cvs add *", and
115 don't seem to object to the warnings.
117 strip_trailing_slashes (argv[i]);
118 if (strcmp (argv[i], ".") == 0
119 || strcmp (argv[i], "..") == 0
120 || fncmp (argv[i], CVSADM) == 0)
123 error (0, 0, "cannot add special file `%s'; skipping", argv[i]);
145 /* FIXME: We don't do anything about free'ing argv[i]. But
146 the problem is that it is only sometimes allocated (see
149 for (j = i; j < argc - 1; ++j)
150 argv[j] = argv[j + 1];
152 /* Check the new argv[i] again. */
158 #ifdef CLIENT_SUPPORT
159 if (current_parsed_root->isremote)
165 /* We snipped out all the arguments in the above sanity
166 check. We can just forget the whole thing (and we
167 better, because if we fired up the server and passed it
168 nothing, it would spit back a usage message). */
183 option_with_arg ("-m", message);
186 /* If !found_slash, refrain from sending "Directory", for
187 CVS 1.9 compatibility. If we only tried to deal with servers
188 which are at least CVS 1.9.26 or so, we wouldn't have to
189 special-case this. */
192 repository = Name_Repository (NULL, NULL);
193 send_a_repository ("", repository, "");
197 for (j = 0; j < argc; ++j)
199 /* FIXME: Does this erroneously call Create_Admin in error
200 conditions which are only detected once the server gets its
210 /* This is some mungeable storage into which we can point
211 with p and/or update_dir. */
217 filedir = xstrdup (argv[j]);
218 /* Deliberately discard the const below since we know we just
219 * allocated filedir and can do what we like with it.
221 p = (char *)last_component (filedir);
229 update_dir = filedir;
230 if (CVS_CHDIR (update_dir) < 0)
232 "could not chdir to %s", update_dir);
235 /* find the repository associated with our current dir */
236 repository = Name_Repository (NULL, update_dir);
238 /* don't add stuff to Emptydir */
239 if (strncmp (repository, current_parsed_root->directory, cvsroot_len) == 0
240 && ISDIRSEP (repository[cvsroot_len])
241 && strncmp (repository + cvsroot_len + 1,
243 sizeof CVSROOTADM - 1) == 0
244 && ISDIRSEP (repository[cvsroot_len + sizeof CVSROOTADM])
245 && strcmp (repository + cvsroot_len + sizeof CVSROOTADM + 1,
247 error (1, 0, "cannot add to %s", repository);
249 /* before we do anything else, see if we have any
250 per-directory tags */
251 ParseTag (&tag, &date, &nonbranch);
253 rcsdir = xmalloc (strlen (repository) + strlen (p) + 5);
254 sprintf (rcsdir, "%s/%s", repository, p);
256 Create_Admin (p, argv[j], rcsdir, tag, date,
260 send_a_repository ("", repository, update_dir);
262 if (restore_cwd (&cwd, NULL))
273 Subdir_Register ((List *) NULL, (char *) NULL, argv[j]);
276 Subdir_Register ((List *) NULL, update_dir, p);
282 send_files (argc, argv, 0, 0, SEND_BUILD_DIRS | SEND_NO_CONTENTS);
283 send_file_names (argc, argv, SEND_EXPAND_WILD);
284 send_to_server ("add\012", 0);
287 return err + get_responses_and_close ();
291 /* walk the arg list adding files/dirs */
292 for (i = 0; i < argc; i++)
295 #ifdef SERVER_SUPPORT
296 int begin_added_files = added_files;
298 struct file_info finfo;
301 memset (&finfo, 0, sizeof finfo);
306 finfo.fullname = xstrdup (argv[i]);
307 filename = xstrdup (argv[i]);
308 /* We know we can discard the const below since we just allocated
309 * filename and can do as we like with it.
311 p = (char *)last_component (filename);
314 finfo.update_dir = "";
320 finfo.update_dir = filename;
322 if (CVS_CHDIR (finfo.update_dir) < 0)
323 error (1, errno, "could not chdir to %s", finfo.update_dir);
326 /* Add wrappers for this directory. They exist only until
327 the next call to wrap_add_file. */
328 wrap_add_file (CVSDOTWRAPPER, 1);
332 /* Find the repository associated with our current dir. */
333 repository = Name_Repository (NULL, finfo.update_dir);
335 /* don't add stuff to Emptydir */
336 if (strncmp (repository, current_parsed_root->directory,
338 && ISDIRSEP (repository[cvsroot_len])
339 && strncmp (repository + cvsroot_len + 1,
341 sizeof CVSROOTADM - 1) == 0
342 && ISDIRSEP (repository[cvsroot_len + sizeof CVSROOTADM])
343 && strcmp (repository + cvsroot_len + sizeof CVSROOTADM + 1,
345 error (1, 0, "cannot add to %s", repository);
347 entries = Entries_Open (0, NULL);
349 finfo.repository = repository;
350 finfo.entries = entries;
352 /* We pass force_tag_match as 1. If the directory has a
353 sticky branch tag, and there is already an RCS file which
354 does not have that tag, then the head revision is
355 meaningless to us. */
356 vers = Version_TS (&finfo, options, NULL, NULL, 1, 0);
358 if (vers->vn_user == NULL)
360 /* No entry available, ts_rcs is invalid */
361 if (vers->vn_rcs == NULL)
363 /* There is no RCS file either */
364 if (vers->ts_user == NULL)
366 /* There is no user file either */
367 error (0, 0, "nothing known about %s", finfo.fullname);
370 else if (!isdir (finfo.file)
371 || wrap_name_has (finfo.file, WRAP_TOCVS))
374 * See if a directory exists in the repository with
375 * the same name. If so, blow this request off.
377 char *dname = xmalloc (strlen (repository)
378 + strlen (finfo.file)
380 (void) sprintf (dname, "%s/%s", repository, finfo.file);
384 "cannot add file `%s' since the directory",
386 error (0, 0, "`%s' already exists in the repository",
388 error (1, 0, "illegal filename overlap");
392 if (vers->options == NULL || *vers->options == '\0')
394 /* No options specified on command line (or in
395 rcs file if it existed, e.g. the file exists
396 on another branch). Check for a value from
397 the wrapper stuff. */
398 if (wrap_name_has (finfo.file, WRAP_RCSOPTION))
401 free (vers->options);
402 vers->options = wrap_rcsoption (finfo.file, 1);
409 "cannot add file on non-branch tag %s",
415 /* There is a user file, so build the entry for it */
416 if (build_entry (repository, finfo.file, vers->options,
417 message, entries, vers->tag) != 0)
426 scheduling %s `%s' for addition on branch `%s'",
427 (wrap_name_has (finfo.file,
431 finfo.fullname, vers->tag);
434 "scheduling %s `%s' for addition",
435 (wrap_name_has (finfo.file,
445 else if (RCS_isdead (vers->srcfile, vers->vn_rcs))
447 if (isdir (finfo.file)
448 && !wrap_name_has (finfo.file, WRAP_TOCVS))
451 the directory `%s' cannot be added because a file of the", finfo.fullname);
453 same name already exists in the repository.");
460 "cannot add file on non-branch tag %s",
466 char *timestamp = NULL;
467 if (vers->ts_user == NULL)
469 /* If this file does not exist locally, assume that
470 * the last version on the branch is being
473 * Compute previous revision. We assume that it
474 * exists and that it is not a revision on the
475 * trunk of the form X.1 (1.1, 2.1, 3.1, ...). We
476 * also assume that it is not dead, which seems
477 * fair since we know vers->vn_rcs is dead
478 * and we shouldn't see two dead revisions in a
481 char *prev = previous_rev (vers->srcfile,
486 /* There is no previous revision. Either:
488 * * Revision 1.1 was dead, as when a file was
489 * inititially added on a branch,
493 * * All previous revisions have been deleted.
494 * For instance, via `admin -o'.
498 "File `%s' has no previous revision to resurrect.",
505 "Resurrecting file `%s' from revision %s.",
506 finfo.fullname, prev);
507 status = RCS_checkout (vers->srcfile, finfo.file,
509 vers->options, RUN_TTY,
511 xchmod (finfo.file, 1);
514 error (0, 0, "Failed to resurrect revision %s",
520 /* I don't actually set vers->ts_user here
521 * because it would confuse server_update().
523 timestamp = time_stamp (finfo.file);
525 write_letter (&finfo, 'U');
533 "file `%s' will be added on branch `%s' from version %s",
534 finfo.fullname, vers->tag,
537 /* I'm not sure that mentioning
538 vers->vn_rcs makes any sense here; I
539 can't think of a way to word the
540 message which is not confusing. */
542 "Re-adding file `%s' (in place of dead revision %s).",
543 finfo.fullname, vers->vn_rcs);
545 Register (entries, finfo.file, "0",
546 timestamp ? timestamp : vers->ts_user,
547 vers->options, vers->tag, vers->date, NULL);
548 if (timestamp) free (timestamp);
549 #ifdef SERVER_SUPPORT
550 if (server_active && vers->ts_user == NULL)
552 /* If we resurrected the file from the archive, we
553 * need to tell the client about it.
555 server_updated (&finfo, vers,
557 (mode_t) -1, NULL, NULL);
558 /* This is kinda hacky or, at least, it renders the
559 * name "begin_added_files" obsolete, but we want
560 * the added_files to be counted without triggering
561 * the check that causes server_checked_in() to be
562 * called below since we have already called
563 * server_updated() to complete the resurrection.
575 * There is an RCS file already, so somebody else must've
578 error (0, 0, "%s added independently by second party",
583 else if (vers->vn_user[0] == '0' && vers->vn_user[1] == '\0')
587 * An entry for a new-born file, ts_rcs is dummy, but that is
591 error (0, 0, "%s has already been entered", finfo.fullname);
594 else if (vers->vn_user[0] == '-')
596 /* An entry for a removed file, ts_rcs is invalid */
597 if (vers->ts_user == NULL)
599 /* There is no user file (as it should be) */
600 if (vers->vn_rcs == NULL)
604 * There is no RCS file, so somebody else must've removed
608 cannot resurrect %s; RCS file removed by second party", finfo.fullname);
615 * There is an RCS file, so remove the "-" from the
616 * version number and restore the file
618 char *tmp = xmalloc (strlen (vers->vn_user));
619 (void) strcpy (tmp, vers->vn_user + 1);
620 (void) strcpy (vers->vn_user, tmp);
622 status = RCS_checkout (vers->srcfile, finfo.file,
623 vers->vn_user, vers->tag,
624 vers->options, RUN_TTY,
626 xchmod (finfo.file, 1);
629 error (0, 0, "Failed to resurrect revision %s",
636 /* I don't actually set vers->ts_user here because it
637 * would confuse server_update().
639 tmp = time_stamp (finfo.file);
640 write_letter (&finfo, 'U');
642 error (0, 0, "%s, version %s, resurrected",
643 finfo.fullname, vers->vn_user);
645 Register (entries, finfo.file, vers->vn_user,
647 vers->tag, vers->date, NULL);
649 #ifdef SERVER_SUPPORT
652 /* If we resurrected the file from the archive, we
653 * need to tell the client about it.
655 server_updated (&finfo, vers,
657 (mode_t) -1, NULL, NULL);
659 /* We don't increment added_files here because this isn't
660 * a change that needs to be committed.
667 /* The user file shouldn't be there */
669 %s should be removed and is still there (or is back again)", finfo.fullname);
675 /* A normal entry, ts_rcs is valid, so it must already be there */
677 error (0, 0, "%s already exists, with version number %s",
684 /* passed all the checks. Go ahead and add it if its a directory */
686 && isdir (finfo.file)
687 && !wrap_name_has (finfo.file, WRAP_TOCVS))
689 err += add_directory (&finfo);
693 #ifdef SERVER_SUPPORT
694 if (server_active && begin_added_files != added_files)
695 server_checked_in (finfo.file, finfo.update_dir, repository);
701 Entries_Close (entries);
703 if (restore_cwd (&cwd, NULL))
707 /* It's okay to discard the const to free this - we allocated this
708 * above. The const is for everybody else.
710 free ((char *) finfo.fullname);
711 free ((char *) filename);
713 if (added_files && !really_quiet)
714 error (0, 0, "use '%s commit' to add %s permanently",
716 (added_files == 1) ? "this file" : "these files");
729 * The specified user file is really a directory. So, let's make sure that
730 * it is created in the RCS source repository, and that the user's directory
731 * is updated to include a CVS directory.
733 * Returns 1 on failure, 0 on success.
736 add_directory (finfo)
737 struct file_info *finfo;
739 const char *repository = finfo->repository;
740 List *entries = finfo->entries;
741 const char *dir = finfo->file;
744 struct saved_cwd cwd;
745 char *message = NULL;
750 if (strchr (dir, '/') != NULL)
752 /* "Can't happen". */
754 "directory %s not added; must be a direct sub-directory", dir);
757 if (fncmp (dir, CVSADM) == 0)
759 error (0, 0, "cannot add a `%s' directory", CVSADM);
763 /* before we do anything else, see if we have any per-directory tags */
764 ParseTag (&tag, &date, &nonbranch);
766 /* Remember the default attributes from this directory, so we can apply
767 them to the new directory. */
768 fileattr_startdir (repository);
769 attrs = fileattr_getall (NULL);
772 /* now, remember where we were, so we can get back */
775 if (CVS_CHDIR (dir) < 0)
777 error (0, errno, "cannot chdir to %s", finfo->fullname);
780 if (!server_active && isfile (CVSADM))
782 error (0, 0, "%s/%s already exists", finfo->fullname, CVSADM);
786 rcsdir = xmalloc (strlen (repository) + strlen (dir) + 5);
787 sprintf (rcsdir, "%s/%s", repository, dir);
788 if (isfile (rcsdir) && !isdir (rcsdir))
790 error (0, 0, "%s is not a directory; %s not added", rcsdir,
795 /* setup the log message */
796 message = xmalloc (strlen (rcsdir)
798 + (tag == NULL ? 0 : strlen (tag) + 80)
799 + (date == NULL ? 0 : strlen (date) + 80));
800 (void) sprintf (message, "Directory %s added to the repository\n",
804 (void) strcat (message, "--> Using per-directory sticky tag `");
805 (void) strcat (message, tag);
806 (void) strcat (message, "'\n");
810 (void) strcat (message, "--> Using per-directory sticky date `");
811 (void) strcat (message, date);
812 (void) strcat (message, "'\n");
820 struct logfile_info *li;
822 /* There used to be some code here which would prompt for
823 whether to add the directory. The details of that code had
824 bitrotted, but more to the point it can't work
825 client/server, doesn't ask in the right way for GUIs, etc.
826 A better way of making it harder to accidentally add
827 directories would be to have to add and commit directories
828 like for files. The code was #if 0'd at least since CVS 1.5. */
832 omask = umask (cvsumask);
833 if (CVS_MKDIR (rcsdir, 0777) < 0)
835 error (0, errno, "cannot mkdir %s", rcsdir);
836 (void) umask (omask);
839 (void) umask (omask);
842 /* Now set the default file attributes to the ones we inherited
843 from the parent directory. */
844 fileattr_startdir (rcsdir);
845 fileattr_setall (NULL, attrs);
855 * Set up an update list with a single title node for Update_Logfile
860 p->delproc = update_delproc;
861 p->key = xstrdup ("- New directory");
862 li = (struct logfile_info *) xmalloc (sizeof (struct logfile_info));
864 li->tag = xstrdup (tag);
865 li->rev_old = li->rev_new = NULL;
867 (void) addnode (ulist, p);
868 Update_Logfile (rcsdir, message, (FILE *) NULL, ulist);
873 Create_Admin (".", finfo->fullname, rcsdir, tag, date, nonbranch, 0, 1);
879 if (restore_cwd (&cwd, NULL))
883 Subdir_Register (entries, (char *) NULL, dir);
886 cvs_output (message, 0);
896 if (restore_cwd (&cwd, NULL))
899 if (message) free (message);
908 * Builds an entry for a new file and sets up "CVS/file",[pt] by
909 * interrogating the user. Returns non-zero on error.
912 build_entry (repository, user, options, message, entries, tag)
913 const char *repository;
928 * The requested log is read directly from the user and stored in the
929 * file user,t. If the "message" argument is set, use it as the
930 * initial creation log (which typically describes the file).
932 fname = xmalloc (strlen (user) + 80);
933 (void) sprintf (fname, "%s/%s%s", CVSADM, user, CVSEXT_LOG);
934 fp = open_file (fname, "w+");
935 if (message && fputs (message, fp) == EOF)
936 error (1, errno, "cannot write to %s", fname);
937 if (fclose(fp) == EOF)
938 error(1, errno, "cannot close %s", fname);
942 * Create the entry now, since this allows the user to interrupt us above
943 * without needing to clean anything up (well, we could clean up the
944 * ,t file, but who cares).
946 line = xmalloc (strlen (user) + 20);
947 (void) sprintf (line, "Initial %s", user);
948 Register (entries, user, "0", line, options, tag, (char *) 0, (char *) 0);