2 * Copyright (c) 1992, Brian Berliner and Jeff Polk
3 * Copyright (c) 1989-1992, Brian Berliner
5 * You may distribute under the terms of the GNU General Public License as
6 * specified in the README file that comes with the CVS source distribution.
10 * Adds a file or directory to the RCS source repository. For a file,
11 * the entry is marked as "needing to be added" in the user's own CVS
12 * directory, and really added to the repository when it is committed.
13 * For a directory, it is added at the appropriate place in the source
14 * repository and a CVS directory is generated within the directory.
16 * The -m option is currently the only supported option. Some may wish to
17 * supply standard "rcs" options here, but I've found that this causes more
18 * trouble than anything else.
20 * The user files or directories must already exist. For a directory, it must
21 * not already have a CVS file in it.
23 * An "add" on a file that has been "remove"d but not committed will cause the
24 * file to be resurrected.
32 static int add_directory PROTO ((struct file_info *finfo));
33 static int build_entry PROTO((const char *repository, const char *user,
34 const char *options, const char *message,
35 List * entries, const char *tag));
37 static const char *const add_usage[] =
39 "Usage: %s %s [-k rcs-kflag] [-m message] files...\n",
40 "\t-k\tUse \"rcs-kflag\" to add the file with the specified kflag.\n",
41 "\t-m\tUse \"message\" for the creation log.\n",
42 "(Specify the --help global option for a list of other help options)\n",
61 /* Nonzero if we found a slash, and are thus adding files in a
66 if (argc == 1 || argc == -1)
73 while ((c = getopt (argc, argv, "+k:m:")) != -1)
80 options = RCS_check_kflag (optarg);
84 message = xstrdup (optarg);
98 cvsroot_len = strlen (current_parsed_root->directory);
100 /* First some sanity checks. I know that the CVS case is (sort of)
101 also handled by add_directory, but we need to check here so the
102 client won't get all confused in send_file_names. */
103 for (i = 0; i < argc; i++)
107 /* If it were up to me I'd probably make this a fatal error.
108 But some people are really fond of their "cvs add *", and
109 don't seem to object to the warnings.
111 strip_trailing_slashes (argv[i]);
112 if (strcmp (argv[i], ".") == 0
113 || strcmp (argv[i], "..") == 0
114 || fncmp (argv[i], CVSADM) == 0)
117 error (0, 0, "cannot add special file `%s'; skipping", argv[i]);
139 /* FIXME: We don't do anything about free'ing argv[i]. But
140 the problem is that it is only sometimes allocated (see
143 for (j = i; j < argc - 1; ++j)
144 argv[j] = argv[j + 1];
146 /* Check the new argv[i] again. */
152 #ifdef CLIENT_SUPPORT
153 if (current_parsed_root->isremote)
158 /* We snipped out all the arguments in the above sanity
159 check. We can just forget the whole thing (and we
160 better, because if we fired up the server and passed it
161 nothing, it would spit back a usage message). */
171 option_with_arg ("-m", message);
174 /* If !found_slash, refrain from sending "Directory", for
175 CVS 1.9 compatibility. If we only tried to deal with servers
176 which are at least CVS 1.9.26 or so, we wouldn't have to
177 special-case this. */
180 repository = Name_Repository (NULL, NULL);
181 send_a_repository ("", repository, "");
185 for (j = 0; j < argc; ++j)
187 /* FIXME: Does this erroneously call Create_Admin in error
188 conditions which are only detected once the server gets its
198 /* This is some mungeable storage into which we can point
199 with p and/or update_dir. */
205 filedir = xstrdup (argv[j]);
206 /* Deliberately discard the const below since we know we just
207 * allocated filedir and can do what we like with it.
209 p = (char *)last_component (filedir);
217 update_dir = filedir;
218 if (CVS_CHDIR (update_dir) < 0)
220 "could not chdir to %s", update_dir);
223 /* find the repository associated with our current dir */
224 repository = Name_Repository (NULL, update_dir);
226 /* don't add stuff to Emptydir */
227 if (strncmp (repository, current_parsed_root->directory, cvsroot_len) == 0
228 && ISDIRSEP (repository[cvsroot_len])
229 && strncmp (repository + cvsroot_len + 1,
231 sizeof CVSROOTADM - 1) == 0
232 && ISDIRSEP (repository[cvsroot_len + sizeof CVSROOTADM])
233 && strcmp (repository + cvsroot_len + sizeof CVSROOTADM + 1,
235 error (1, 0, "cannot add to %s", repository);
237 /* before we do anything else, see if we have any
238 per-directory tags */
239 ParseTag (&tag, &date, &nonbranch);
241 rcsdir = xmalloc (strlen (repository) + strlen (p) + 5);
242 sprintf (rcsdir, "%s/%s", repository, p);
244 Create_Admin (p, argv[j], rcsdir, tag, date,
248 send_a_repository ("", repository, update_dir);
250 if (restore_cwd (&cwd, NULL))
261 Subdir_Register ((List *) NULL, (char *) NULL, argv[j]);
264 Subdir_Register ((List *) NULL, update_dir, p);
270 send_files (argc, argv, 0, 0, SEND_BUILD_DIRS | SEND_NO_CONTENTS);
271 send_file_names (argc, argv, SEND_EXPAND_WILD);
272 send_to_server ("add\012", 0);
275 return err + get_responses_and_close ();
279 /* walk the arg list adding files/dirs */
280 for (i = 0; i < argc; i++)
283 #ifdef SERVER_SUPPORT
284 int begin_added_files = added_files;
286 struct file_info finfo;
289 memset (&finfo, 0, sizeof finfo);
294 finfo.fullname = xstrdup (argv[i]);
295 filename = xstrdup (argv[i]);
296 /* We know we can discard the const below since we just allocated
297 * filename and can do as we like with it.
299 p = (char *)last_component (filename);
302 finfo.update_dir = "";
308 finfo.update_dir = filename;
310 if (CVS_CHDIR (finfo.update_dir) < 0)
311 error (1, errno, "could not chdir to %s", finfo.update_dir);
314 /* Add wrappers for this directory. They exist only until
315 the next call to wrap_add_file. */
316 wrap_add_file (CVSDOTWRAPPER, 1);
320 /* Find the repository associated with our current dir. */
321 repository = Name_Repository (NULL, finfo.update_dir);
323 /* don't add stuff to Emptydir */
324 if (strncmp (repository, current_parsed_root->directory,
326 && ISDIRSEP (repository[cvsroot_len])
327 && strncmp (repository + cvsroot_len + 1,
329 sizeof CVSROOTADM - 1) == 0
330 && ISDIRSEP (repository[cvsroot_len + sizeof CVSROOTADM])
331 && strcmp (repository + cvsroot_len + sizeof CVSROOTADM + 1,
333 error (1, 0, "cannot add to %s", repository);
335 entries = Entries_Open (0, NULL);
337 finfo.repository = repository;
338 finfo.entries = entries;
340 /* We pass force_tag_match as 1. If the directory has a
341 sticky branch tag, and there is already an RCS file which
342 does not have that tag, then the head revision is
343 meaningless to us. */
344 vers = Version_TS (&finfo, options, NULL, NULL, 1, 0);
346 if (vers->vn_user == NULL)
348 /* No entry available, ts_rcs is invalid */
349 if (vers->vn_rcs == NULL)
351 /* There is no RCS file either */
352 if (vers->ts_user == NULL)
354 /* There is no user file either */
355 error (0, 0, "nothing known about %s", finfo.fullname);
358 else if (!isdir (finfo.file)
359 || wrap_name_has (finfo.file, WRAP_TOCVS))
362 * See if a directory exists in the repository with
363 * the same name. If so, blow this request off.
365 char *dname = xmalloc (strlen (repository)
366 + strlen (finfo.file)
368 (void) sprintf (dname, "%s/%s", repository, finfo.file);
372 "cannot add file `%s' since the directory",
374 error (0, 0, "`%s' already exists in the repository",
376 error (1, 0, "illegal filename overlap");
380 if (vers->options == NULL || *vers->options == '\0')
382 /* No options specified on command line (or in
383 rcs file if it existed, e.g. the file exists
384 on another branch). Check for a value from
385 the wrapper stuff. */
386 if (wrap_name_has (finfo.file, WRAP_RCSOPTION))
389 free (vers->options);
390 vers->options = wrap_rcsoption (finfo.file, 1);
397 "cannot add file on non-branch tag %s",
403 /* There is a user file, so build the entry for it */
404 if (build_entry (repository, finfo.file, vers->options,
405 message, entries, vers->tag) != 0)
414 scheduling %s `%s' for addition on branch `%s'",
415 (wrap_name_has (finfo.file,
419 finfo.fullname, vers->tag);
422 "scheduling %s `%s' for addition",
423 (wrap_name_has (finfo.file,
433 else if (RCS_isdead (vers->srcfile, vers->vn_rcs))
435 if (isdir (finfo.file)
436 && !wrap_name_has (finfo.file, WRAP_TOCVS))
439 the directory `%s' cannot be added because a file of the", finfo.fullname);
441 same name already exists in the repository.");
448 "cannot add file on non-branch tag %s",
454 char *timestamp = NULL;
455 if (vers->ts_user == NULL)
457 /* If this file does not exist locally, assume that
458 * the last version on the branch is being
461 * Compute previous revision. We assume that it
462 * exists and that it is not a revision on the
463 * trunk of the form X.1 (1.1, 2.1, 3.1, ...). We
464 * also assume that it is not dead, which seems
465 * fair since we know vers->vn_rcs is dead
466 * and we shouldn't see two dead revisions in a
469 char *prev = previous_rev (vers->srcfile,
472 assert (prev != NULL);
475 "Resurrecting file `%s' from revision %s.",
476 finfo.fullname, prev);
477 status = RCS_checkout (vers->srcfile, finfo.file,
479 vers->options, RUN_TTY,
481 xchmod (finfo.file, 1);
484 error (0, 0, "Failed to resurrect revision %s",
490 /* I don't actually set vers->ts_user here
491 * because it would confuse server_update().
493 timestamp = time_stamp (finfo.file);
495 write_letter (&finfo, 'U');
503 "file `%s' will be added on branch `%s' from version %s",
504 finfo.fullname, vers->tag,
507 /* I'm not sure that mentioning
508 vers->vn_rcs makes any sense here; I
509 can't think of a way to word the
510 message which is not confusing. */
512 "Re-adding file `%s' (in place of dead revision %s).",
513 finfo.fullname, vers->vn_rcs);
515 Register (entries, finfo.file, "0",
516 timestamp ? timestamp : vers->ts_user,
517 vers->options, vers->tag, vers->date, NULL);
518 if (timestamp) free (timestamp);
519 #ifdef SERVER_SUPPORT
520 if (server_active && vers->ts_user == NULL)
522 /* If we resurrected the file from the archive, we
523 * need to tell the client about it.
525 server_updated (&finfo, vers,
527 (mode_t) -1, NULL, NULL);
528 /* This is kinda hacky or, at least, it renders the
529 * name "begin_added_files" obsolete, but we want
530 * the added_files to be counted without triggering
531 * the check that causes server_checked_in() to be
532 * called below since we have already called
533 * server_updated() to complete the resurrection.
545 * There is an RCS file already, so somebody else must've
548 error (0, 0, "%s added independently by second party",
553 else if (vers->vn_user[0] == '0' && vers->vn_user[1] == '\0')
557 * An entry for a new-born file, ts_rcs is dummy, but that is
561 error (0, 0, "%s has already been entered", finfo.fullname);
564 else if (vers->vn_user[0] == '-')
566 /* An entry for a removed file, ts_rcs is invalid */
567 if (vers->ts_user == NULL)
569 /* There is no user file (as it should be) */
570 if (vers->vn_rcs == NULL)
574 * There is no RCS file, so somebody else must've removed
578 cannot resurrect %s; RCS file removed by second party", finfo.fullname);
585 * There is an RCS file, so remove the "-" from the
586 * version number and restore the file
588 char *tmp = xmalloc (strlen (vers->vn_user));
589 (void) strcpy (tmp, vers->vn_user + 1);
590 (void) strcpy (vers->vn_user, tmp);
592 status = RCS_checkout (vers->srcfile, finfo.file,
593 vers->vn_user, vers->tag,
594 vers->options, RUN_TTY,
596 xchmod (finfo.file, 1);
599 error (0, 0, "Failed to resurrect revision %s",
606 /* I don't actually set vers->ts_user here because it
607 * would confuse server_update().
609 tmp = time_stamp (finfo.file);
610 write_letter (&finfo, 'U');
612 error (0, 0, "%s, version %s, resurrected",
613 finfo.fullname, vers->vn_user);
615 Register (entries, finfo.file, vers->vn_user,
617 vers->tag, vers->date, NULL);
619 #ifdef SERVER_SUPPORT
622 /* If we resurrected the file from the archive, we
623 * need to tell the client about it.
625 server_updated (&finfo, vers,
627 (mode_t) -1, NULL, NULL);
629 /* We don't increment added_files here because this isn't
630 * a change that needs to be committed.
637 /* The user file shouldn't be there */
639 %s should be removed and is still there (or is back again)", finfo.fullname);
645 /* A normal entry, ts_rcs is valid, so it must already be there */
647 error (0, 0, "%s already exists, with version number %s",
654 /* passed all the checks. Go ahead and add it if its a directory */
656 && isdir (finfo.file)
657 && !wrap_name_has (finfo.file, WRAP_TOCVS))
659 err += add_directory (&finfo);
663 #ifdef SERVER_SUPPORT
664 if (server_active && begin_added_files != added_files)
665 server_checked_in (finfo.file, finfo.update_dir, repository);
669 Entries_Close (entries);
671 if (restore_cwd (&cwd, NULL))
675 /* It's okay to discard the const to free this - we allocated this
676 * above. The const is for everybody else.
678 free ((char *) finfo.fullname);
679 free ((char *) filename);
681 if (added_files && !really_quiet)
682 error (0, 0, "use '%s commit' to add %s permanently",
684 (added_files == 1) ? "this file" : "these files");
697 * The specified user file is really a directory. So, let's make sure that
698 * it is created in the RCS source repository, and that the user's directory
699 * is updated to include a CVS directory.
701 * Returns 1 on failure, 0 on success.
704 add_directory (finfo)
705 struct file_info *finfo;
707 const char *repository = finfo->repository;
708 List *entries = finfo->entries;
709 const char *dir = finfo->file;
712 struct saved_cwd cwd;
713 char *message = NULL;
718 if (strchr (dir, '/') != NULL)
720 /* "Can't happen". */
722 "directory %s not added; must be a direct sub-directory", dir);
725 if (fncmp (dir, CVSADM) == 0)
727 error (0, 0, "cannot add a `%s' directory", CVSADM);
731 /* before we do anything else, see if we have any per-directory tags */
732 ParseTag (&tag, &date, &nonbranch);
734 /* Remember the default attributes from this directory, so we can apply
735 them to the new directory. */
736 fileattr_startdir (repository);
737 attrs = fileattr_getall (NULL);
740 /* now, remember where we were, so we can get back */
743 if (CVS_CHDIR (dir) < 0)
745 error (0, errno, "cannot chdir to %s", finfo->fullname);
748 #ifdef SERVER_SUPPORT
749 if (!server_active && isfile (CVSADM))
754 error (0, 0, "%s/%s already exists", finfo->fullname, CVSADM);
758 rcsdir = xmalloc (strlen (repository) + strlen (dir) + 5);
759 sprintf (rcsdir, "%s/%s", repository, dir);
760 if (isfile (rcsdir) && !isdir (rcsdir))
762 error (0, 0, "%s is not a directory; %s not added", rcsdir,
767 /* setup the log message */
768 message = xmalloc (strlen (rcsdir)
770 + (tag == NULL ? 0 : strlen (tag) + 80)
771 + (date == NULL ? 0 : strlen (date) + 80));
772 (void) sprintf (message, "Directory %s added to the repository\n",
776 (void) strcat (message, "--> Using per-directory sticky tag `");
777 (void) strcat (message, tag);
778 (void) strcat (message, "'\n");
782 (void) strcat (message, "--> Using per-directory sticky date `");
783 (void) strcat (message, date);
784 (void) strcat (message, "'\n");
792 struct logfile_info *li;
794 /* There used to be some code here which would prompt for
795 whether to add the directory. The details of that code had
796 bitrotted, but more to the point it can't work
797 client/server, doesn't ask in the right way for GUIs, etc.
798 A better way of making it harder to accidentally add
799 directories would be to have to add and commit directories
800 like for files. The code was #if 0'd at least since CVS 1.5. */
804 omask = umask (cvsumask);
805 if (CVS_MKDIR (rcsdir, 0777) < 0)
807 error (0, errno, "cannot mkdir %s", rcsdir);
808 (void) umask (omask);
811 (void) umask (omask);
814 /* Now set the default file attributes to the ones we inherited
815 from the parent directory. */
816 fileattr_startdir (rcsdir);
817 fileattr_setall (NULL, attrs);
824 * Set up an update list with a single title node for Update_Logfile
829 p->delproc = update_delproc;
830 p->key = xstrdup ("- New directory");
831 li = (struct logfile_info *) xmalloc (sizeof (struct logfile_info));
833 li->tag = xstrdup (tag);
834 li->rev_old = li->rev_new = NULL;
836 (void) addnode (ulist, p);
837 Update_Logfile (rcsdir, message, (FILE *) NULL, ulist);
841 #ifdef SERVER_SUPPORT
844 Create_Admin (".", finfo->fullname, rcsdir, tag, date, nonbranch, 0, 1);
850 if (restore_cwd (&cwd, NULL))
854 Subdir_Register (entries, (char *) NULL, dir);
857 cvs_output (message, 0);
865 if (restore_cwd (&cwd, NULL))
876 * Builds an entry for a new file and sets up "CVS/file",[pt] by
877 * interrogating the user. Returns non-zero on error.
880 build_entry (repository, user, options, message, entries, tag)
881 const char *repository;
896 * The requested log is read directly from the user and stored in the
897 * file user,t. If the "message" argument is set, use it as the
898 * initial creation log (which typically describes the file).
900 fname = xmalloc (strlen (user) + 80);
901 (void) sprintf (fname, "%s/%s%s", CVSADM, user, CVSEXT_LOG);
902 fp = open_file (fname, "w+");
903 if (message && fputs (message, fp) == EOF)
904 error (1, errno, "cannot write to %s", fname);
905 if (fclose(fp) == EOF)
906 error(1, errno, "cannot close %s", fname);
910 * Create the entry now, since this allows the user to interrupt us above
911 * without needing to clean anything up (well, we could clean up the
912 * ,t file, but who cares).
914 line = xmalloc (strlen (user) + 20);
915 (void) sprintf (line, "Initial %s", user);
916 Register (entries, user, "0", line, options, tag, (char *) 0, (char *) 0);