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 * `cvs add' supports `-k <mode>' and `-m <description>' options.
22 * Some may wish to supply other standard "rcs" options here, but I've
23 * found that this causes more 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 (struct file_info
*finfo
);
38 static int build_entry (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",
53 add (int argc
, char **argv
)
65 /* Nonzero if we found a slash, and are thus adding files in a
70 if (argc
== 1 || argc
== -1)
77 while ((c
= getopt (argc
, argv
, "+k:m:")) != -1)
82 if (options
) free (options
);
83 options
= RCS_check_kflag (optarg
);
87 if (message
) free (message
);
88 message
= xstrdup (optarg
);
102 cvsroot_len
= strlen (current_parsed_root
->directory
);
104 /* First some sanity checks. I know that the CVS case is (sort of)
105 also handled by add_directory, but we need to check here so the
106 client won't get all confused in send_file_names. */
107 for (i
= 0; i
< argc
; i
++)
111 /* If it were up to me I'd probably make this a fatal error.
112 But some people are really fond of their "cvs add *", and
113 don't seem to object to the warnings.
115 strip_trailing_slashes (argv
[i
]);
116 if (strcmp (argv
[i
], ".") == 0
117 || strcmp (argv
[i
], "..") == 0
118 || fncmp (argv
[i
], CVSADM
) == 0)
121 error (0, 0, "cannot add special file `%s'; skipping", argv
[i
]);
143 /* FIXME: We don't do anything about free'ing argv[i]. But
144 the problem is that it is only sometimes allocated (see
147 for (j
= i
; j
< argc
- 1; ++j
)
148 argv
[j
] = argv
[j
+ 1];
150 /* Check the new argv[i] again. */
156 #ifdef CLIENT_SUPPORT
157 if (current_parsed_root
->isremote
)
162 /* We snipped out all the arguments in the above sanity
163 check. We can just forget the whole thing (and we
164 better, because if we fired up the server and passed it
165 nothing, it would spit back a usage message). */
175 option_with_arg ("-m", message
);
178 /* If !found_slash, refrain from sending "Directory", for
179 CVS 1.9 compatibility. If we only tried to deal with servers
180 which are at least CVS 1.9.26 or so, we wouldn't have to
181 special-case this. */
184 repository
= Name_Repository (NULL
, NULL
);
185 send_a_repository ("", repository
, "");
189 for (j
= 0; j
< argc
; ++j
)
191 /* FIXME: Does this erroneously call Create_Admin in error
192 conditions which are only detected once the server gets its
202 /* This is some mungeable storage into which we can point
203 with p and/or update_dir. */
207 error (1, errno
, "Failed to save current directory.");
209 filedir
= xstrdup (argv
[j
]);
210 /* Deliberately discard the const below since we know we just
211 * allocated filedir and can do what we like with it.
213 p
= (char *)last_component (filedir
);
221 update_dir
= filedir
;
222 if (CVS_CHDIR (update_dir
) < 0)
224 "could not chdir to `%s'", update_dir
);
227 /* find the repository associated with our current dir */
228 repository
= Name_Repository (NULL
, update_dir
);
230 /* don't add stuff to Emptydir */
231 if (strncmp (repository
, current_parsed_root
->directory
, cvsroot_len
) == 0
232 && ISSLASH (repository
[cvsroot_len
])
233 && strncmp (repository
+ cvsroot_len
+ 1,
235 sizeof CVSROOTADM
- 1) == 0
236 && ISSLASH (repository
[cvsroot_len
+ sizeof CVSROOTADM
])
237 && strcmp (repository
+ cvsroot_len
+ sizeof CVSROOTADM
+ 1,
239 error (1, 0, "cannot add to `%s'", repository
);
241 /* before we do anything else, see if we have any
242 per-directory tags */
243 ParseTag (&tag
, &date
, &nonbranch
);
245 rcsdir
= Xasprintf ("%s/%s", repository
, p
);
247 Create_Admin (p
, argv
[j
], rcsdir
, tag
, date
,
251 send_a_repository ("", repository
, update_dir
);
253 if (restore_cwd (&cwd
))
255 "Failed to restore current directory, `%s'.",
266 Subdir_Register (NULL
, NULL
, argv
[j
]);
269 Subdir_Register (NULL
, update_dir
, p
);
275 send_files (argc
, argv
, 0, 0, SEND_BUILD_DIRS
| SEND_NO_CONTENTS
);
276 send_file_names (argc
, argv
, SEND_EXPAND_WILD
);
277 send_to_server ("add\012", 0);
280 return err
+ get_responses_and_close ();
284 /* walk the arg list adding files/dirs */
285 for (i
= 0; i
< argc
; i
++)
288 #ifdef SERVER_SUPPORT
289 int begin_added_files
= added_files
;
291 struct file_info finfo
;
294 memset (&finfo
, 0, sizeof finfo
);
297 error (1, errno
, "Failed to save current directory.");
299 finfo
.fullname
= xstrdup (argv
[i
]);
300 filename
= xstrdup (argv
[i
]);
301 /* We know we can discard the const below since we just allocated
302 * filename and can do as we like with it.
304 p
= (char *)last_component (filename
);
307 finfo
.update_dir
= "";
313 finfo
.update_dir
= filename
;
315 if (CVS_CHDIR (finfo
.update_dir
) < 0)
316 error (1, errno
, "could not chdir to `%s'", finfo
.update_dir
);
319 /* Add wrappers for this directory. They exist only until
320 the next call to wrap_add_file. */
321 wrap_add_file (CVSDOTWRAPPER
, 1);
325 /* Find the repository associated with our current dir. */
326 repository
= Name_Repository (NULL
, finfo
.update_dir
);
328 /* don't add stuff to Emptydir */
329 if (strncmp (repository
, current_parsed_root
->directory
,
331 && ISSLASH (repository
[cvsroot_len
])
332 && strncmp (repository
+ cvsroot_len
+ 1,
334 sizeof CVSROOTADM
- 1) == 0
335 && ISSLASH (repository
[cvsroot_len
+ sizeof CVSROOTADM
])
336 && strcmp (repository
+ cvsroot_len
+ sizeof CVSROOTADM
+ 1,
338 error (1, 0, "cannot add to `%s'", repository
);
340 entries
= Entries_Open (0, NULL
);
342 finfo
.repository
= repository
;
343 finfo
.entries
= entries
;
345 /* We pass force_tag_match as 1. If the directory has a
346 sticky branch tag, and there is already an RCS file which
347 does not have that tag, then the head revision is
348 meaningless to us. */
349 vers
= Version_TS (&finfo
, options
, NULL
, NULL
, 1, 0);
350 if (vers
->vn_user
== NULL
)
352 /* No entry available, ts_rcs is invalid */
353 if (vers
->vn_rcs
== NULL
)
355 /* There is no RCS file either */
356 if (vers
->ts_user
== NULL
)
358 /* There is no user file either */
359 error (0, 0, "nothing known about `%s'", finfo
.fullname
);
362 else if (!isdir (finfo
.file
)
363 || wrap_name_has (finfo
.file
, WRAP_TOCVS
))
366 * See if a directory exists in the repository with
367 * the same name. If so, blow this request off.
369 char *dname
= Xasprintf ("%s/%s", repository
, finfo
.file
);
373 "cannot add file `%s' since the directory",
375 error (0, 0, "`%s' already exists in the repository",
377 error (1, 0, "invalid filename overlap");
381 if (vers
->options
== NULL
|| *vers
->options
== '\0')
383 /* No options specified on command line (or in
384 rcs file if it existed, e.g. the file exists
385 on another branch). Check for a value from
386 the wrapper stuff. */
387 if (wrap_name_has (finfo
.file
, WRAP_RCSOPTION
))
390 free (vers
->options
);
391 vers
->options
= wrap_rcsoption (finfo
.file
, 1);
398 "cannot add file on non-branch tag `%s'",
404 /* There is a user file, so build the entry for it */
405 if (build_entry (repository
, finfo
.file
, vers
->options
,
406 message
, entries
, vers
->tag
) != 0)
414 error (0, 0, "scheduling %s `%s' for"
415 " addition on branch `%s'",
416 (wrap_name_has (finfo
.file
,
420 finfo
.fullname
, vers
->tag
);
423 "scheduling %s `%s' for addition",
424 (wrap_name_has (finfo
.file
,
434 else if (RCS_isdead (vers
->srcfile
, vers
->vn_rcs
))
436 if (isdir (finfo
.file
)
437 && !wrap_name_has (finfo
.file
, WRAP_TOCVS
))
440 "the directory `%s' cannot be added because a file"
441 " of the", finfo
.fullname
);
442 error (1, 0, "same name already exists in the repository.");
449 "cannot add file on non-branch tag `%s'",
455 char *timestamp
= NULL
;
456 if (vers
->ts_user
== NULL
)
458 /* If this file does not exist locally, assume that
459 * the last version on the branch is being
462 * Compute previous revision. We assume that it
463 * exists and that it is not a revision on the
464 * trunk of the form X.1 (1.1, 2.1, 3.1, ...). We
465 * also assume that it is not dead, which seems
466 * fair since we know vers->vn_rcs is dead
467 * and we shouldn't see two dead revisions in a
470 char *prev
= previous_rev (vers
->srcfile
,
475 /* There is no previous revision. Either:
477 * * Revision 1.1 was dead, as when a file was
478 * inititially added on a branch,
482 * * All previous revisions have been deleted.
483 * For instance, via `admin -o'.
487 "File `%s' has no previous revision to resurrect.",
494 "Resurrecting file `%s' from revision %s.",
495 finfo
.fullname
, prev
);
496 status
= RCS_checkout (vers
->srcfile
, finfo
.file
,
498 vers
->options
, RUN_TTY
,
500 xchmod (finfo
.file
, 1);
503 error (0, 0, "Failed to resurrect revision %s",
509 /* I don't actually set vers->ts_user here
510 * because it would confuse server_update().
512 timestamp
= time_stamp (finfo
.file
);
514 write_letter (&finfo
, 'U');
523 bbuf
= Xasprintf (" on branch `%s'",
529 "Re-adding file `%s'%s after dead revision %s.",
530 finfo
.fullname
, bbuf
, vers
->vn_rcs
);
534 Register (entries
, finfo
.file
, "0",
535 timestamp
? timestamp
: vers
->ts_user
,
536 vers
->options
, vers
->tag
, vers
->date
, NULL
);
537 if (timestamp
) free (timestamp
);
538 #ifdef SERVER_SUPPORT
539 if (server_active
&& vers
->ts_user
== NULL
)
541 /* If we resurrected the file from the archive, we
542 * need to tell the client about it.
544 server_updated (&finfo
, vers
,
546 (mode_t
) -1, NULL
, NULL
);
547 /* This is kinda hacky or, at least, it renders the
548 * name "begin_added_files" obsolete, but we want
549 * the added_files to be counted without triggering
550 * the check that causes server_checked_in() to be
551 * called below since we have already called
552 * server_updated() to complete the resurrection.
564 * There is an RCS file already, so somebody else must've
567 error (0, 0, "`%s' added independently by second party",
572 else if (vers
->vn_user
[0] == '0' && vers
->vn_user
[1] == '\0')
576 * An entry for a new-born file, ts_rcs is dummy, but that is
580 error (0, 0, "`%s' has already been entered", finfo
.fullname
);
583 else if (vers
->vn_user
[0] == '-')
585 /* An entry for a removed file, ts_rcs is invalid */
586 if (vers
->ts_user
== NULL
)
588 /* There is no user file (as it should be) */
589 if (vers
->vn_rcs
== NULL
)
593 * There is no RCS file, so somebody else must've removed
597 "cannot resurrect `%s'; RCS file removed by"
598 " second party", finfo
.fullname
);
605 * There is an RCS file, so remove the "-" from the
606 * version number and restore the file
608 char *tmp
= xstrdup (vers
->vn_user
+ 1);
609 (void) strcpy (vers
->vn_user
, tmp
);
611 status
= RCS_checkout (vers
->srcfile
, finfo
.file
,
612 vers
->vn_user
, vers
->tag
,
613 vers
->options
, RUN_TTY
,
615 xchmod (finfo
.file
, cvswrite
);
618 error (0, 0, "Failed to resurrect revision %s.",
625 /* I don't actually set vers->ts_user here because it
626 * would confuse server_update().
628 tmp
= time_stamp (finfo
.file
);
629 write_letter (&finfo
, 'U');
631 error (0, 0, "`%s', version %s, resurrected",
632 finfo
.fullname
, vers
->vn_user
);
634 Register (entries
, finfo
.file
, vers
->vn_user
,
636 vers
->tag
, vers
->date
, NULL
);
638 #ifdef SERVER_SUPPORT
641 /* If we resurrected the file from the archive, we
642 * need to tell the client about it.
644 server_updated (&finfo
, vers
,
646 (mode_t
) -1, NULL
, NULL
);
648 /* We don't increment added_files here because this isn't
649 * a change that needs to be committed.
656 /* The user file shouldn't be there */
658 `%s' should be removed and is still there (or is back again)", finfo
.fullname
);
664 /* A normal entry, ts_rcs is valid, so it must already be there */
666 error (0, 0, "`%s' already exists, with version number %s",
673 /* passed all the checks. Go ahead and add it if its a directory */
675 && isdir (finfo
.file
)
676 && !wrap_name_has (finfo
.file
, WRAP_TOCVS
))
678 err
+= add_directory (&finfo
);
682 #ifdef SERVER_SUPPORT
683 if (server_active
&& begin_added_files
!= added_files
)
684 server_checked_in (finfo
.file
, finfo
.update_dir
, repository
);
690 Entries_Close (entries
);
692 if (restore_cwd (&cwd
))
693 error (1, errno
, "Failed to restore current directory, `%s'.",
697 /* It's okay to discard the const to free this - we allocated this
698 * above. The const is for everybody else.
700 free ((char *) finfo
.fullname
);
703 if (added_files
&& !really_quiet
)
704 error (0, 0, "use `%s commit' to add %s permanently",
706 (added_files
== 1) ? "this file" : "these files");
719 * The specified user file is really a directory. So, let's make sure that
720 * it is created in the RCS source repository, and that the user's directory
721 * is updated to include a CVS directory.
723 * Returns 1 on failure, 0 on success.
726 add_directory (struct file_info
*finfo
)
728 const char *repository
= finfo
->repository
;
729 List
*entries
= finfo
->entries
;
730 const char *dir
= finfo
->file
;
733 struct saved_cwd cwd
;
734 char *message
= NULL
;
739 if (strchr (dir
, '/') != NULL
)
741 /* "Can't happen". */
743 "directory %s not added; must be a direct sub-directory", dir
);
746 if (fncmp (dir
, CVSADM
) == 0)
748 error (0, 0, "cannot add a `%s' directory", CVSADM
);
752 /* before we do anything else, see if we have any per-directory tags */
753 ParseTag (&tag
, &date
, &nonbranch
);
755 /* Remember the default attributes from this directory, so we can apply
756 them to the new directory. */
757 fileattr_startdir (repository
);
758 attrs
= fileattr_getall (NULL
);
761 /* now, remember where we were, so we can get back */
764 error (0, errno
, "Failed to save current directory.");
767 if (CVS_CHDIR (dir
) < 0)
769 error (0, errno
, "cannot chdir to %s", finfo
->fullname
);
772 if (!server_active
&& isfile (CVSADM
))
774 error (0, 0, "%s/%s already exists", finfo
->fullname
, CVSADM
);
778 rcsdir
= Xasprintf ("%s/%s", repository
, dir
);
779 if (isfile (rcsdir
) && !isdir (rcsdir
))
781 error (0, 0, "%s is not a directory; %s not added", rcsdir
,
786 /* setup the log message */
787 message
= Xasprintf ("Directory %s added to the repository\n%s%s%s%s%s%s",
789 tag
? "--> Using per-directory sticky tag `" : "",
790 tag
? tag
: "", tag
? "'\n" : "",
791 date
? "--> Using per-directory sticky date `" : "",
792 date
? date
: "", date
? "'\n" : "");
799 struct logfile_info
*li
;
801 /* There used to be some code here which would prompt for
802 whether to add the directory. The details of that code had
803 bitrotted, but more to the point it can't work
804 client/server, doesn't ask in the right way for GUIs, etc.
805 A better way of making it harder to accidentally add
806 directories would be to have to add and commit directories
807 like for files. The code was #if 0'd at least since CVS 1.5. */
811 omask
= umask (cvsumask
);
812 if (CVS_MKDIR (rcsdir
, 0777) < 0)
814 error (0, errno
, "cannot mkdir %s", rcsdir
);
815 (void) umask (omask
);
818 (void) umask (omask
);
821 /* Now set the default file attributes to the ones we inherited
822 from the parent directory. */
823 fileattr_startdir (rcsdir
);
824 fileattr_setall (NULL
, attrs
);
831 * Set up an update list with a single title node for Update_Logfile
836 p
->delproc
= update_delproc
;
837 p
->key
= xstrdup ("- New directory");
838 li
= xmalloc (sizeof (struct logfile_info
));
840 li
->tag
= xstrdup (tag
);
841 li
->rev_old
= li
->rev_new
= NULL
;
843 (void) addnode (ulist
, p
);
844 Update_Logfile (rcsdir
, message
, NULL
, ulist
);
849 WriteTemplate (finfo
->fullname
, 1, rcsdir
);
851 Create_Admin (".", finfo
->fullname
, rcsdir
, tag
, date
, nonbranch
, 0, 1);
858 if (restore_cwd (&cwd
))
859 error (1, errno
, "Failed to restore current directory, `%s'.",
863 Subdir_Register (entries
, NULL
, dir
);
866 cvs_output (message
, 0);
874 if (restore_cwd (&cwd
))
875 error (1, errno
, "Failed to restore current directory, `%s'.",
878 if (message
) free (message
);
887 * Builds an entry for a new file and sets up "CVS/file",[pt] by
888 * interrogating the user. Returns non-zero on error.
891 build_entry (const char *repository
, const char *user
, const char *options
,
892 const char *message
, List
*entries
, const char *tag
)
902 * The requested log is read directly from the user and stored in the
903 * file user,t. If the "message" argument is set, use it as the
904 * initial creation log (which typically describes the file).
906 fname
= Xasprintf ("%s/%s%s", CVSADM
, user
, CVSEXT_LOG
);
907 fp
= xfopen (fname
, "w+");
908 if (message
&& fputs (message
, fp
) == EOF
)
909 error (1, errno
, "cannot write to %s", fname
);
910 if (fclose (fp
) == EOF
)
911 error (1, errno
, "cannot close %s", fname
);
915 * Create the entry now, since this allows the user to interrupt us above
916 * without needing to clean anything up (well, we could clean up the
917 * ,t file, but who cares).
919 line
= Xasprintf ("Initial %s", user
);
920 Register (entries
, user
, "0", line
, options
, tag
, NULL
, NULL
);