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 * "commit" commits the present version to the RCS repository, AFTER
16 * having done a test on conflicts.
18 * The call is: cvs commit [options] files...
28 static Dtype check_direntproc (void *callerdat, const char *dir,
29 const char *repos, const char *update_dir,
31 static int check_fileproc (void *callerdat, struct file_info *finfo);
32 static int check_filesdoneproc (void *callerdat, int err, const char *repos,
33 const char *update_dir, List *entries);
34 static int checkaddfile (const char *file, const char *repository,
35 const char *tag, const char *options,
37 static Dtype commit_direntproc (void *callerdat, const char *dir,
38 const char *repos, const char *update_dir,
40 static int commit_dirleaveproc (void *callerdat, const char *dir, int err,
41 const char *update_dir, List *entries);
42 static int commit_fileproc (void *callerdat, struct file_info *finfo);
43 static int commit_filesdoneproc (void *callerdat, int err,
44 const char *repository,
45 const char *update_dir, List *entries);
46 static int finaladd (struct file_info *finfo, char *revision, char *tag,
48 static int findmaxrev (Node * p, void *closure);
49 static int lock_RCS (const char *user, RCSNode *rcs, const char *rev,
50 const char *repository);
51 static int precommit_list_to_args_proc (Node * p, void *closure);
52 static int precommit_proc (const char *repository, const char *filter,
54 static int remove_file (struct file_info *finfo, char *tag,
56 static void fixaddfile (const char *rcs);
57 static void fixbranch (RCSNode *, char *branch);
58 static void unlockrcs (RCSNode *rcs);
59 static void ci_delproc (Node *p);
60 static void masterlist_delproc (Node *p);
64 Ctype status; /* as returned from Classify_File() */
65 char *rev; /* a numeric rev, if we know it */
66 char *tag; /* any sticky tag, or -r option */
67 char *options; /* Any sticky -k option */
71 List *ulist; /* list for Update_Logfile */
72 List *cilist; /* list with commit_info structs */
75 static int check_valid_edit = 0;
76 static int force_ci = 0;
77 static int got_message;
79 static char *saved_tag;
80 static char *write_dirtag;
81 static int write_dirnonbranch;
84 static char *saved_message;
85 static time_t last_register_time;
87 static const char *const commit_usage[] =
89 "Usage: %s %s [-cRlf] [-m msg | -F logfile] [-r rev] files...\n",
90 " -c Check for valid edits before committing.\n",
91 " -R Process directories recursively.\n",
92 " -l Local directory only (not recursive).\n",
93 " -f Force the file to be committed; disables recursion.\n",
94 " -F logfile Read the log message from file.\n",
95 " -m msg Log message.\n",
96 " -r rev Commit to this branch or trunk revision.\n",
97 "(Specify the --help global option for a list of other help options)\n",
101 #ifdef CLIENT_SUPPORT
102 /* Identify a file which needs "? foo" or a Questionable request. */
105 /* The two fields for the Directory request. */
112 struct question *next;
121 /* This is used from dirent to filesdone time, for each directory,
122 to make a list of files we have already seen. */
125 /* Linked list of files which need "? foo" or a Questionable request. */
126 struct question *questionables;
128 /* Only good within functions called from the filesdoneproc. Stores
129 the repository (pointer into storage managed by the recursion
131 const char *repository;
133 /* Non-zero if we should force the commit. This is enabled by
134 either -f or -r options, unlike force_ci which is just -f. */
141 find_dirent_proc (void *callerdat, const char *dir, const char *repository,
142 const char *update_dir, List *entries)
144 struct find_data *find_data = callerdat;
146 /* This check seems to slowly be creeping throughout CVS (update
147 and send_dirent_proc by CVS 1.5, diff in 31 Oct 1995. My guess
148 is that it (or some variant thereof) should go in all the
149 dirent procs. Unless someone has some better idea... */
153 /* initialize the ignore list for this directory */
154 find_data->ignlist = getlist ();
156 /* Print the same warm fuzzy as in check_direntproc, since that
157 code will never be run during client/server operation and we
158 want the messages to match. */
160 error (0, 0, "Examining %s", update_dir);
167 /* Here as a static until we get around to fixing ignore_files to pass
168 it along as an argument. */
169 static struct find_data *find_data_static;
174 find_ignproc (const char *file, const char *dir)
178 p = xmalloc (sizeof (struct question));
179 p->dir = xstrdup (dir);
180 p->repos = xstrdup (find_data_static->repository);
181 p->file = xstrdup (file);
182 p->next = find_data_static->questionables;
183 find_data_static->questionables = p;
189 find_filesdoneproc (void *callerdat, int err, const char *repository,
190 const char *update_dir, List *entries)
192 struct find_data *find_data = callerdat;
193 find_data->repository = repository;
195 /* if this directory has an ignore list, process it then free it */
196 if (find_data->ignlist)
198 find_data_static = find_data;
199 ignore_files (find_data->ignlist, entries, update_dir, find_ignproc);
200 dellist (&find_data->ignlist);
203 find_data->repository = NULL;
210 /* Machinery to find out what is modified, added, and removed. It is
211 possible this should be broken out into a new client_classify function;
212 merging it with classify_file is almost sure to be a mess, though,
213 because classify_file has all kinds of repository processing. */
215 find_fileproc (void *callerdat, struct file_info *finfo)
218 enum classify_type status;
220 struct find_data *args = callerdat;
221 struct logfile_info *data;
222 struct file_info xfinfo;
224 /* if this directory has an ignore list, add this file to it */
231 p->key = xstrdup (finfo->file);
232 if (addnode (args->ignlist, p) != 0)
237 xfinfo.repository = NULL;
240 vers = Version_TS (&xfinfo, NULL, saved_tag, NULL, 0, 0);
241 if (vers->vn_user == NULL)
243 if (vers->ts_user == NULL)
244 error (0, 0, "nothing known about `%s'", finfo->fullname);
246 error (0, 0, "use `%s add' to create an entry for `%s'",
247 program_name, finfo->fullname);
251 if (vers->vn_user[0] == '-')
253 if (vers->ts_user != NULL)
256 "`%s' should be removed and is still there (or is back"
257 " again)", finfo->fullname);
264 else if (strcmp (vers->vn_user, "0") == 0)
266 if (vers->ts_user == NULL)
268 /* This happens when one has `cvs add'ed a file, but it no
269 longer exists in the working directory at commit time.
270 FIXME: What classify_file does in this case is print
271 "new-born %s has disappeared" and removes the entry.
272 We probably should do the same. */
274 error (0, 0, "warning: new-born %s has disappeared",
276 status = T_REMOVE_ENTRY;
281 else if (vers->ts_user == NULL)
283 /* FIXME: What classify_file does in this case is print
284 "%s was lost". We probably should do the same. */
288 else if (vers->ts_rcs != NULL
289 && (args->force || strcmp (vers->ts_user, vers->ts_rcs) != 0))
290 /* If we are forcing commits, pretend that the file is
295 /* This covers unmodified files, as well as a variety of other
296 cases. FIXME: we probably should be printing a message and
297 returning 1 for many of those cases (but I'm not sure
298 exactly which ones). */
304 node->key = xstrdup (finfo->fullname);
306 data = xmalloc (sizeof (struct logfile_info));
308 data->tag = xstrdup (vers->tag);
309 data->rev_old = data->rev_new = NULL;
312 node->delproc = update_delproc;
314 (void)addnode (args->ulist, node);
325 copy_ulist (Node *node, void *data)
327 struct find_data *args = data;
328 args->argv[args->argc++] = node->key;
331 #endif /* CLIENT_SUPPORT */
335 #ifdef SERVER_SUPPORT
336 # define COMMIT_OPTIONS "+cnlRm:fF:r:"
337 #else /* !SERVER_SUPPORT */
338 # define COMMIT_OPTIONS "+clRm:fF:r:"
339 #endif /* SERVER_SUPPORT */
341 commit (int argc, char **argv)
348 usage (commit_usage);
352 * For log purposes, do not allow "root" to commit files. If you look
353 * like root, but are really logged in as a non-root user, it's OK.
355 /* FIXME: Shouldn't this check be much more closely related to the
356 readonly user stuff (CVSROOT/readers, &c). That is, why should
357 root be able to "cvs init", "cvs import", &c, but not "cvs ci"? */
358 if (geteuid () == (uid_t) 0
359 # ifdef CLIENT_SUPPORT
360 /* Who we are on the client side doesn't affect logging. */
361 && !current_parsed_root->isremote
367 if ((pw = getpwnam (getcaller ())) == NULL)
369 "your apparent username (%s) is unknown to this system",
371 if (pw->pw_uid == (uid_t) 0)
372 error (1, 0, "'root' is not allowed to commit files");
374 #endif /* CVS_BADROOT */
377 while ((c = getopt (argc, argv, COMMIT_OPTIONS)) != -1)
382 check_valid_edit = 1;
384 #ifdef SERVER_SUPPORT
386 /* Silently ignore -n for compatibility with old
390 #endif /* SERVER_SUPPORT */
392 #ifdef FORCE_USE_EDITOR
399 free (saved_message);
400 saved_message = NULL;
403 saved_message = xstrdup (optarg);
408 saved_tag = xstrdup (optarg);
418 check_valid_edit = 0;
419 local = 1; /* also disable recursion */
422 #ifdef FORCE_USE_EDITOR
431 usage (commit_usage);
438 /* numeric specified revision means we ignore sticky tags... */
439 if (saved_tag && isdigit ((unsigned char) *saved_tag))
441 char *p = saved_tag + strlen (saved_tag);
443 /* strip trailing dots and leading zeros */
444 while (*--p == '.') ;
446 while (saved_tag[0] == '0' && isdigit ((unsigned char) saved_tag[1]))
450 /* some checks related to the "-F logfile" option */
453 size_t size = 0, len;
456 error (1, 0, "cannot specify both a message and a log file");
458 get_file (logfile, logfile, "r", &saved_message, &size, &len);
461 #ifdef CLIENT_SUPPORT
462 if (current_parsed_root->isremote)
464 struct find_data find_args;
468 find_args.ulist = getlist ();
470 find_args.questionables = NULL;
471 find_args.ignlist = NULL;
472 find_args.repository = NULL;
474 /* It is possible that only a numeric tag should set this.
475 I haven't really thought about it much.
476 Anyway, I suspect that setting it unnecessarily only causes
477 a little unneeded network traffic. */
478 find_args.force = force_ci || saved_tag != NULL;
480 err = start_recursion
481 (find_fileproc, find_filesdoneproc, find_dirent_proc, NULL,
482 &find_args, argc, argv, local, W_LOCAL, 0, CVS_LOCK_NONE,
485 error (1, 0, "correct above errors first!");
487 if (find_args.argc == 0)
489 /* Nothing to commit. Exit now without contacting the
490 server (note that this means that we won't print "?
491 foo" for files which merit it, because we don't know
492 what is in the CVSROOT/cvsignore file). */
493 dellist (&find_args.ulist);
497 /* Now we keep track of which files we actually are going to
498 operate on, and only work with those files in the future.
499 This saves time--we don't want to search the file system
500 of the working directory twice. */
501 if (size_overflow_p (xtimes (find_args.argc, sizeof (char **))))
506 find_args.argv = xnmalloc (find_args.argc, sizeof (char **));
508 walklist (find_args.ulist, copy_ulist, &find_args);
510 /* Do this before calling do_editor; don't ask for a log
511 message if we can't talk to the server. But do it after we
512 have made the checks that we can locally (to more quickly
513 catch syntax errors, the case where no files are modified,
514 added or removed, etc.).
516 On the other hand, calling start_server before do_editor
517 means that we chew up server resources the whole time that
518 the user has the editor open (hours or days if the user
519 forgets about it), which seems dubious. */
523 * We do this once, not once for each directory as in normal CVS.
524 * The protocol is designed this way. This is a feature.
527 do_editor (".", &saved_message, NULL, find_args.ulist);
529 /* We always send some sort of message, even if empty. */
530 option_with_arg ("-m", saved_message ? saved_message : "");
532 /* OK, now process all the questionable files we have been saving
538 p = find_args.questionables;
541 if (ign_inhibit_server || !supported_request ("Questionable"))
543 cvs_output ("? ", 2);
544 if (p->dir[0] != '\0')
546 cvs_output (p->dir, 0);
549 cvs_output (p->file, 0);
550 cvs_output ("\n", 1);
554 /* This used to send the Directory line of its own accord,
555 * but skipped some of the other processing like checking
556 * for whether the server would accept "Relative-directory"
557 * requests. Relying on send_a_repository() to do this
558 * picks up these checks but also:
560 * 1. Causes the "Directory" request to be sent only once
562 * 2. Causes the global TOPLEVEL_REPOS to be set.
563 * 3. Causes "Static-directory" and "Sticky" requests
564 * to sometimes be sent.
566 * (1) is almost certainly a plus. (2) & (3) may or may
567 * not be useful sometimes, and will ocassionally cause a
568 * little extra network traffic. The additional network
569 * traffic is probably already saved several times over and
570 * certainly cancelled out via the multiple "Directory"
571 * request suppression of (1).
573 send_a_repository (p->dir, p->repos, p->dir);
575 send_to_server ("Questionable ", 0);
576 send_to_server (p->file, 0);
577 send_to_server ("\012", 1);
590 if (check_valid_edit)
594 option_with_arg ("-r", saved_tag);
597 /* FIXME: This whole find_args.force/SEND_FORCE business is a
598 kludge. It would seem to be a server bug that we have to
599 say that files are modified when they are not. This makes
600 "cvs commit -r 2" across a whole bunch of files a very slow
601 operation (and it isn't documented in cvsclient.texi). I
602 haven't looked at the server code carefully enough to be
603 _sure_ why this is needed, but if it is because the "ci"
604 program, which we used to call, wanted the file to exist,
605 then it would be relatively simple to fix in the server. */
606 send_files (find_args.argc, find_args.argv, local, 0,
607 find_args.force ? SEND_FORCE : 0);
609 /* Sending only the names of the files which were modified, added,
610 or removed means that the server will only do an up-to-date
611 check on those files. This is different from local CVS and
612 previous versions of client/server CVS, but it probably is a Good
613 Thing, or at least Not Such A Bad Thing. */
614 send_file_names (find_args.argc, find_args.argv, 0);
615 free (find_args.argv);
616 dellist (&find_args.ulist);
618 send_to_server ("ci\012", 0);
619 err = get_responses_and_close ();
620 if (err != 0 && use_editor && saved_message != NULL)
622 /* If there was an error, don't nuke the user's carefully
623 constructed prose. This is something of a kludge; a better
624 solution is probably more along the lines of #150 in TODO
625 (doing a second up-to-date check before accepting the
626 log message has also been suggested, but that seems kind of
627 iffy because the real up-to-date check could still fail,
628 another error could occur, &c. Also, a second check would
629 slow things down). */
634 fp = cvs_temp_file (&fname);
636 error (1, 0, "cannot create temporary file %s", fname);
637 if (fwrite (saved_message, 1, strlen (saved_message), fp)
638 != strlen (saved_message))
639 error (1, errno, "cannot write temporary file %s", fname);
641 error (0, errno, "cannot close temporary file %s", fname);
642 error (0, 0, "saving log message in %s", fname);
649 if (saved_tag != NULL)
650 tag_check_valid (saved_tag, argc, argv, local, aflag, "", false);
652 /* XXX - this is not the perfect check for this */
654 write_dirtag = saved_tag;
658 lock_tree_promotably (argc, argv, local, W_LOCAL, aflag);
661 * Set up the master update list and hard link list
665 #ifdef PRESERVE_PERMISSIONS_SUPPORT
668 hardlist = getlist ();
671 * We need to save the working directory so that
672 * check_fileproc can construct a full pathname for each file.
674 working_dir = xgetcwd ();
679 * Run the recursion processor to verify the files are all up-to-date
681 err = start_recursion (check_fileproc, check_filesdoneproc,
682 check_direntproc, NULL, NULL, argc, argv, local,
683 W_LOCAL, aflag, CVS_LOCK_NONE, NULL, 1, NULL);
685 error (1, 0, "correct above errors first!");
688 * Run the recursion processor to commit the files
690 write_dirnonbranch = 0;
692 err = start_recursion (commit_fileproc, commit_filesdoneproc,
693 commit_direntproc, commit_dirleaveproc, NULL,
694 argc, argv, local, W_LOCAL, aflag,
695 CVS_LOCK_WRITE, NULL, 1, NULL);
698 * Unlock all the dirs and clean up
703 /* see if we need to sleep before returning to avoid time-stamp races */
705 #ifdef SERVER_SUPPORT
706 /* But only sleep on the client. */
711 sleep_past (last_register_time);
718 /* This routine determines the status of a given file and retrieves
719 the version information that is associated with that file. */
723 classify_file_internal (struct file_info *finfo, Vers_TS **vers)
725 int save_noexec, save_quiet, save_really_quiet;
728 /* FIXME: Do we need to save quiet as well as really_quiet? Last
729 time I glanced at Classify_File I only saw it looking at really_quiet
731 save_noexec = noexec;
733 save_really_quiet = really_quiet;
734 noexec = quiet = really_quiet = 1;
736 /* handle specified numeric revision specially */
737 if (saved_tag && isdigit ((unsigned char) *saved_tag))
739 /* If the tag is for the trunk, make sure we're at the head */
740 if (numdots (saved_tag) < 2)
742 status = Classify_File (finfo, NULL, NULL,
743 NULL, 1, aflag, vers, 0);
744 if (status == T_UPTODATE || status == T_MODIFIED ||
750 xstatus = Classify_File (finfo, saved_tag, NULL,
751 NULL, 1, aflag, vers, 0);
752 if (xstatus == T_REMOVE_ENTRY)
754 else if (status == T_MODIFIED && xstatus == T_CONFLICT)
765 * The revision is off the main trunk; make sure we're
766 * up-to-date with the head of the specified branch.
768 xtag = xstrdup (saved_tag);
769 if ((numdots (xtag) & 1) != 0)
771 cp = strrchr (xtag, '.');
774 status = Classify_File (finfo, xtag, NULL,
775 NULL, 1, aflag, vers, 0);
776 if ((status == T_REMOVE_ENTRY || status == T_CONFLICT)
777 && (cp = strrchr (xtag, '.')) != NULL)
779 /* pluck one more dot off the revision */
782 status = Classify_File (finfo, xtag, NULL,
783 NULL, 1, aflag, vers, 0);
784 if (status == T_UPTODATE || status == T_REMOVE_ENTRY)
787 /* now, muck with vers to make the tag correct */
789 (*vers)->tag = xstrdup (saved_tag);
794 status = Classify_File (finfo, saved_tag, NULL, NULL, 1, 0, vers, 0);
795 noexec = save_noexec;
797 really_quiet = save_really_quiet;
805 * Check to see if a file is ok to commit and make sure all files are
810 check_fileproc (void *callerdat, struct file_info *finfo)
815 List *ulist, *cilist;
817 struct commit_info *ci;
818 struct logfile_info *li;
821 size_t cvsroot_len = strlen (current_parsed_root->directory);
823 if (!finfo->repository)
825 error (0, 0, "nothing known about `%s'", finfo->fullname);
829 if (strncmp (finfo->repository, current_parsed_root->directory,
831 && ISSLASH (finfo->repository[cvsroot_len])
832 && strncmp (finfo->repository + cvsroot_len + 1,
834 sizeof (CVSROOTADM) - 1) == 0
835 && ISSLASH (finfo->repository[cvsroot_len + sizeof (CVSROOTADM)])
836 && strcmp (finfo->repository + cvsroot_len + sizeof (CVSROOTADM) + 1,
839 error (1, 0, "cannot check in to %s", finfo->repository);
841 status = classify_file_internal (finfo, &vers);
844 * If the force-commit option is enabled, and the file in question
845 * appears to be up-to-date, just make it look modified so that
846 * it will be committed.
848 if (force_ci && status == T_UPTODATE)
858 error (0, 0, "Up-to-date check failed for `%s'", finfo->fullname);
867 * some quick sanity checks; if no numeric -r option specified:
868 * - can't have a sticky date
869 * - can't have a sticky tag that is not a branch
871 * - if status is T_REMOVED, file must not exist and its entry
872 * can't have a numeric sticky tag.
873 * - if status is T_ADDED, rcs file must not exist unless on
874 * a branch or head is dead
875 * - if status is T_ADDED, can't have a non-trunk numeric rev
876 * - if status is T_MODIFIED and a Conflict marker exists, don't
877 * allow the commit if timestamp is identical or if we find
878 * an RCS_MERGE_PAT in the file.
880 if (!saved_tag || !isdigit ((unsigned char) *saved_tag))
885 "cannot commit with sticky date for file `%s'",
889 if (status == T_MODIFIED && vers->tag &&
890 !RCS_isbranch (finfo->rcs, vers->tag))
893 "sticky tag `%s' for file `%s' is not a branch",
894 vers->tag, finfo->fullname);
898 if (status == T_MODIFIED && !force_ci && vers->ts_conflict)
901 * We found a "conflict" marker.
903 * If the timestamp on the file is the same as the
904 * timestamp stored in the Entries file, we block the commit.
906 if (file_has_conflict (finfo, vers->ts_conflict))
909 "file `%s' had a conflict and has not been modified",
914 if (file_has_markers (finfo))
916 /* Make this a warning, not an error, because we have
917 no way of knowing whether the "conflict indicators"
918 are really from a conflict or whether they are part
919 of the document itself (cvs.texinfo and sanity.sh in
920 CVS itself, for example, tend to want to have strings
921 like ">>>>>>>" at the start of a line). Making people
922 kludge this the way they need to kludge keyword
923 expansion seems undesirable. And it is worse than
924 keyword expansion, because there is no -ko
928 warning: file `%s' seems to still contain conflict indicators",
933 if (status == T_REMOVED)
935 if (vers->ts_user != NULL)
938 "`%s' should be removed and is still there (or is"
939 " back again)", finfo->fullname);
943 if (vers->tag && isdigit ((unsigned char) *vers->tag))
945 /* Remove also tries to forbid this, but we should check
946 here. I'm only _sure_ about somewhat obscure cases
947 (hacking the Entries file, using an old version of
948 CVS for the remove and a new one for the commit), but
949 there might be other cases. */
951 "cannot remove file `%s' which has a numeric sticky"
952 " tag of `%s'", finfo->fullname, vers->tag);
957 if (status == T_ADDED)
959 if (vers->tag == NULL)
961 if (finfo->rcs != NULL &&
962 !RCS_isdead (finfo->rcs, finfo->rcs->head))
965 "cannot add file `%s' when RCS file `%s' already exists",
966 finfo->fullname, finfo->rcs->path);
970 else if (isdigit ((unsigned char) *vers->tag) &&
971 numdots (vers->tag) > 1)
974 "cannot add file `%s' with revision `%s'; must be on trunk",
975 finfo->fullname, vers->tag);
980 /* done with consistency checks; now, to get on with the commit */
981 if (finfo->update_dir[0] == '\0')
984 xdir = finfo->update_dir;
985 if ((p = findnode (mulist, xdir)) != NULL)
987 ulist = ((struct master_lists *) p->data)->ulist;
988 cilist = ((struct master_lists *) p->data)->cilist;
992 struct master_lists *ml;
994 ml = xmalloc (sizeof (struct master_lists));
995 ulist = ml->ulist = getlist ();
996 cilist = ml->cilist = getlist ();
999 p->key = xstrdup (xdir);
1002 p->delproc = masterlist_delproc;
1003 (void) addnode (mulist, p);
1006 /* first do ulist, then cilist */
1008 p->key = xstrdup (finfo->file);
1010 p->delproc = update_delproc;
1011 li = xmalloc (sizeof (struct logfile_info));
1014 if (check_valid_edit)
1016 char *editors = NULL;
1019 editors = fileattr_get0 (finfo->file, "_editors");
1020 if (editors != NULL)
1022 char *caller = getcaller ();
1030 p = strchr (p, '>');
1036 if (strcmp (caller, p0) == 0)
1040 p = strchr (p + 1, ',');
1049 if (strcmp (caller, p0) == 0)
1058 if (check_valid_edit && editor == NULL)
1060 error (0, 0, "Valid edit does not exist for %s",
1062 freevers_ts (&vers);
1066 li->tag = xstrdup (vers->tag);
1067 li->rev_old = xstrdup (vers->vn_rcs);
1070 (void) addnode (ulist, p);
1073 p->key = xstrdup (finfo->file);
1075 p->delproc = ci_delproc;
1076 ci = xmalloc (sizeof (struct commit_info));
1077 ci->status = status;
1079 if (isdigit ((unsigned char) *vers->tag))
1080 ci->rev = xstrdup (vers->tag);
1082 ci->rev = RCS_whatbranch (finfo->rcs, vers->tag);
1085 ci->tag = xstrdup (vers->tag);
1086 ci->options = xstrdup (vers->options);
1088 (void) addnode (cilist, p);
1090 #ifdef PRESERVE_PERMISSIONS_SUPPORT
1093 /* Add this file to hardlist, indexed on its inode. When
1094 we are done, we can find out what files are hardlinked
1095 to a given file by looking up its inode in hardlist. */
1098 struct hardlink_info *hlinfo;
1100 /* Get the full pathname of the current file. */
1101 fullpath = Xasprintf ("%s/%s", working_dir, finfo->fullname);
1103 /* To permit following links in subdirectories, files
1104 are keyed on finfo->fullname, not on finfo->name. */
1105 linkp = lookup_file_by_inode (fullpath);
1107 /* If linkp is NULL, the file doesn't exist... maybe
1108 we're doing a remove operation? */
1111 /* Create a new hardlink_info node, which will record
1112 the current file's status and the links listed in its
1113 `hardlinks' delta field. We will append this
1114 hardlink_info node to the appropriate hardlist entry. */
1115 hlinfo = xmalloc (sizeof (struct hardlink_info));
1116 hlinfo->status = status;
1117 linkp->data = hlinfo;
1126 error (0, 0, "nothing known about `%s'", finfo->fullname);
1131 error (0, 0, "CVS internal error: unknown status %d", status);
1139 freevers_ts (&vers);
1146 * By default, return the code that tells do_recursion to examine all
1151 check_direntproc (void *callerdat, const char *dir, const char *repos,
1152 const char *update_dir, List *entries)
1158 error (0, 0, "Examining %s", update_dir);
1166 * Walklist proc to generate an arg list from the line in commitinfo
1169 precommit_list_to_args_proc (p, closure)
1173 struct format_cmdline_walklist_closure *c = closure;
1174 struct logfile_info *li;
1180 if (p->data == NULL) return 1;
1184 /* foreach requested attribute */
1191 if (li->type == T_ADDED
1192 || li->type == T_MODIFIED
1193 || li->type == T_REMOVED)
1200 "Unknown format character or not a list attribute: %c",
1205 /* copy the attribute into an argument */
1208 arg = cmdlineescape (c->quotes, arg);
1212 arg = cmdlinequote ('"', arg);
1215 expand_string (c->buf, c->length, doff + strlen (arg));
1217 strncpy (d, arg, strlen (arg));
1221 /* and always put the extra space on. we'll have to back up a char
1222 * when we're done, but that seems most efficient
1225 expand_string (c->buf, c->length, doff + 1);
1229 /* correct our original pointer into the buff */
1237 * Callback proc for pre-commit checking
1240 precommit_proc (const char *repository, const char *filter, void *closure)
1242 char *newfilter = NULL;
1244 const char *srepos = Short_Repository (repository);
1245 List *ulist = closure;
1247 #ifdef SUPPORT_OLD_INFO_FMT_STRINGS
1248 if (!strchr (filter, '%'))
1251 "warning: commitinfo line contains no format strings:\n"
1253 "Appending defaults (\" %%r/%%p %%s\"), but please be aware that this usage is\n"
1254 "deprecated.", filter);
1255 newfilter = Xasprintf ("%s %%r/%%p %%s", filter);
1258 #endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
1261 * Cast any NULL arguments as appropriate pointers as this is an
1262 * stdarg function and we need to be certain the caller gets what
1265 cmdline = format_cmdline (
1266 #ifdef SUPPORT_OLD_INFO_FMT_STRINGS
1268 #endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
1270 "c", "s", cvs_cmd_name,
1271 #ifdef SERVER_SUPPORT
1272 "R", "s", referrer ? referrer->original : "NONE",
1273 #endif /* SERVER_SUPPORT */
1275 "r", "s", current_parsed_root->directory,
1276 "s", ",", ulist, precommit_list_to_args_proc,
1280 if (newfilter) free (newfilter);
1282 if (!cmdline || !strlen (cmdline))
1284 if (cmdline) free (cmdline);
1285 error (0, 0, "precommit proc resolved to the empty string!");
1289 run_setup (cmdline);
1292 return run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL | RUN_REALLY);
1298 * Run the pre-commit checks for the dir
1302 check_filesdoneproc (void *callerdat, int err, const char *repos,
1303 const char *update_dir, List *entries)
1309 /* find the update list for this dir */
1310 p = findnode (mulist, update_dir);
1312 saved_ulist = ((struct master_lists *) p->data)->ulist;
1316 /* skip the checks if there's nothing to do */
1317 if (saved_ulist == NULL || saved_ulist->list->next == saved_ulist->list)
1320 /* run any pre-commit checks */
1321 n = Parse_Info (CVSROOTADM_COMMITINFO, repos, precommit_proc, PIOPT_ALL,
1325 error (0, 0, "Pre-commit check failed");
1335 * Do the work of committing a file
1338 static char *sbranch;
1342 commit_fileproc (void *callerdat, struct file_info *finfo)
1346 List *ulist, *cilist;
1347 struct commit_info *ci;
1349 /* Keep track of whether write_dirtag is a branch tag.
1350 Note that if it is a branch tag in some files and a nonbranch tag
1351 in others, treat it as a nonbranch tag. It is possible that case
1352 should elicit a warning or an error. */
1353 if (write_dirtag != NULL
1354 && finfo->rcs != NULL)
1356 char *rev = RCS_getversion (finfo->rcs, write_dirtag, NULL, 1, NULL);
1358 && !RCS_nodeisbranch (finfo->rcs, write_dirtag))
1359 write_dirnonbranch = 1;
1364 if (finfo->update_dir[0] == '\0')
1365 p = findnode (mulist, ".");
1367 p = findnode (mulist, finfo->update_dir);
1370 * if p is null, there were file type command line args which were
1371 * all up-to-date so nothing really needs to be done
1375 ulist = ((struct master_lists *) p->data)->ulist;
1376 cilist = ((struct master_lists *) p->data)->cilist;
1379 * At this point, we should have the commit message unless we were called
1380 * with files as args from the command line. In that latter case, we
1381 * need to get the commit message ourselves
1387 #ifdef SERVER_SUPPORT
1391 do_editor (finfo->update_dir, &saved_message,
1392 finfo->repository, ulist);
1393 do_verify (&saved_message, finfo->repository);
1396 p = findnode (cilist, finfo->file);
1401 if (ci->status == T_MODIFIED)
1403 if (finfo->rcs == NULL)
1404 error (1, 0, "internal error: no parsed RCS file");
1405 if (lock_RCS (finfo->file, finfo->rcs, ci->rev,
1406 finfo->repository) != 0)
1408 unlockrcs (finfo->rcs);
1413 else if (ci->status == T_ADDED)
1415 if (checkaddfile (finfo->file, finfo->repository, ci->tag, ci->options,
1418 if (finfo->rcs != NULL)
1419 fixaddfile (finfo->rcs->path);
1424 /* adding files with a tag, now means adding them on a branch.
1425 Since the branch test was done in check_fileproc for
1426 modified files, we need to stub it in again here. */
1430 /* If numeric, it is on the trunk; check_fileproc enforced
1432 && !isdigit ((unsigned char) ci->tag[0]))
1434 if (finfo->rcs == NULL)
1435 error (1, 0, "internal error: no parsed RCS file");
1438 ci->rev = RCS_whatbranch (finfo->rcs, ci->tag);
1439 err = Checkin ('A', finfo, ci->rev,
1440 ci->tag, ci->options, saved_message);
1443 unlockrcs (finfo->rcs);
1444 fixbranch (finfo->rcs, sbranch);
1447 (void) time (&last_register_time);
1449 ci->status = T_UPTODATE;
1454 * Add the file for real
1456 if (ci->status == T_ADDED)
1460 if (ci->rev == NULL)
1462 /* find the max major rev number in this directory */
1464 (void) walklist (finfo->entries, findmaxrev, NULL);
1465 if (finfo->rcs->head)
1467 /* resurrecting: include dead revision */
1468 int thisrev = atoi (finfo->rcs->head);
1469 if (thisrev > maxrev)
1474 xrev = Xasprintf ("%d", maxrev);
1477 /* XXX - an added file with symbolic -r should add tag as well */
1478 err = finaladd (finfo, ci->rev ? ci->rev : xrev, ci->tag, ci->options);
1482 else if (ci->status == T_MODIFIED)
1484 err = Checkin ('M', finfo, ci->rev, ci->tag,
1485 ci->options, saved_message);
1487 (void) time (&last_register_time);
1491 unlockrcs (finfo->rcs);
1492 fixbranch (finfo->rcs, sbranch);
1495 else if (ci->status == T_REMOVED)
1497 err = remove_file (finfo, ci->tag, saved_message);
1498 #ifdef SERVER_SUPPORT
1501 server_scratch_entry_only ();
1502 server_updated (finfo,
1505 /* Doesn't matter, it won't get checked. */
1515 /* Clearly this is right for T_MODIFIED. I haven't thought so much
1516 about T_ADDED or T_REMOVED. */
1517 notify_do ('C', finfo->file, finfo->update_dir, getcaller (), NULL, NULL,
1523 /* on failure, remove the file from ulist */
1524 p = findnode (ulist, finfo->file);
1530 /* On success, retrieve the new version number of the file and
1531 copy it into the log information (see logmsg.c
1532 (logfile_write) for more details). We should only update
1533 the version number for files that have been added or
1534 modified but not removed since classify_file_internal
1535 will return the version number of a file even after it has
1536 been removed from the archive, which is not the behavior we
1537 want for our commitlog messages; we want the old version
1538 number and then "NONE." */
1540 if (ci->status != T_REMOVED)
1542 p = findnode (ulist, finfo->file);
1546 struct logfile_info *li;
1548 (void) classify_file_internal (finfo, &vers);
1550 li->rev_new = xstrdup (vers->vn_rcs);
1551 freevers_ts (&vers);
1555 if (SIG_inCrSect ())
1564 * Log the commit and clean up the update list
1568 commit_filesdoneproc (void *callerdat, int err, const char *repository,
1569 const char *update_dir, List *entries)
1574 assert (repository);
1576 p = findnode (mulist, update_dir);
1580 ulist = ((struct master_lists *) p->data)->ulist;
1584 /* Build the administrative files if necessary. */
1588 if (strncmp (current_parsed_root->directory, repository,
1589 strlen (current_parsed_root->directory)) != 0)
1591 "internal error: repository (%s) doesn't begin with root (%s)",
1592 repository, current_parsed_root->directory);
1593 p = repository + strlen (current_parsed_root->directory);
1596 if (strcmp ("CVSROOT", p) == 0
1597 /* Check for subdirectories because people may want to create
1598 subdirectories and list files therein in checkoutlist. */
1599 || strncmp ("CVSROOT/", p, strlen ("CVSROOT/")) == 0
1602 /* "Database" might a little bit grandiose and/or vague,
1603 but "checked-out copies of administrative files, unless
1604 in the case of modules and you are using ndbm in which
1605 case modules.{pag,dir,db}" is verbose and excessively
1606 focused on how the database is implemented. */
1608 /* mkmodules requires the absolute name of the CVSROOT directory.
1609 Remove anything after the `CVSROOT' component -- this is
1610 necessary when committing in a subdirectory of CVSROOT. */
1611 char *admin_dir = xstrdup (repository);
1612 int cvsrootlen = strlen ("CVSROOT");
1613 assert (admin_dir[p - repository + cvsrootlen] == '\0'
1614 || admin_dir[p - repository + cvsrootlen] == '/');
1615 admin_dir[p - repository + cvsrootlen] = '\0';
1619 cvs_output (program_name, 0);
1620 cvs_output (" ", 1);
1621 cvs_output (cvs_cmd_name, 0);
1622 cvs_output (": Rebuilding administrative file database\n", 0);
1624 mkmodules (admin_dir);
1626 WriteTemplate (".", 1, repository);
1630 /* FIXME: This used to be above the block above. The advantage of being
1631 * here is that it is not called until after all possible writes from this
1632 * process are complete. The disadvantage is that a fatal error during
1633 * update of CVSROOT can prevent the loginfo script from being called.
1635 * A more general solution I have been considering is calling a generic
1636 * "postwrite" hook from the remove write lock routine.
1638 Update_Logfile (repository, saved_message, NULL, ulist);
1646 * Get the log message for a dir
1650 commit_direntproc (void *callerdat, const char *dir, const char *repos,
1651 const char *update_dir, List *entries)
1660 /* find the update list for this dir */
1661 p = findnode (mulist, update_dir);
1663 ulist = ((struct master_lists *) p->data)->ulist;
1667 /* skip the files as an optimization */
1668 if (ulist == NULL || ulist->list->next == ulist->list)
1669 return R_SKIP_FILES;
1671 /* get commit message */
1673 real_repos = Name_Repository (dir, update_dir);
1675 #ifdef SERVER_SUPPORT
1679 do_editor (update_dir, &saved_message, real_repos, ulist);
1680 do_verify (&saved_message, real_repos);
1688 * Process the post-commit proc if necessary
1692 commit_dirleaveproc (void *callerdat, const char *dir, int err,
1693 const char *update_dir, List *entries)
1695 /* update the per-directory tag info */
1696 /* FIXME? Why? The "commit examples" node of cvs.texinfo briefly
1697 mentions commit -r being sticky, but apparently in the context of
1698 this being a confusing feature! */
1699 if (err == 0 && write_dirtag != NULL)
1701 char *repos = Name_Repository (NULL, update_dir);
1702 WriteTag (NULL, write_dirtag, NULL, write_dirnonbranch,
1713 * find the maximum major rev number in an entries file
1716 findmaxrev (Node *p, void *closure)
1719 Entnode *entdata = p->data;
1721 if (entdata->type != ENT_FILE)
1723 thisrev = atoi (entdata->version);
1724 if (thisrev > maxrev)
1730 * Actually remove a file by moving it to the attic
1731 * XXX - if removing a ,v file that is a relative symbolic link to
1732 * another ,v file, we probably should add a ".." component to the
1733 * link to keep it relative after we move it into the attic.
1735 Return value is 0 on success, or >0 on error (in which case we have
1736 printed an error message). */
1738 remove_file (struct file_info *finfo, char *tag, char *message)
1755 if (finfo->rcs == NULL)
1756 error (1, 0, "internal error: no parsed RCS file");
1759 if (tag && !(branch = RCS_nodeisbranch (finfo->rcs, tag)))
1761 /* a symbolic tag is specified; just remove the tag from the file */
1762 if ((retcode = RCS_deltag (finfo->rcs, tag)) != 0)
1765 error (0, retcode == -1 ? errno : 0,
1766 "failed to remove tag `%s' from `%s'", tag,
1770 RCS_rewrite (finfo->rcs, NULL, NULL);
1771 Scratch_Entry (finfo->entries, finfo->file);
1775 /* we are removing the file from either the head or a branch */
1776 /* commit a new, dead revision. */
1784 rev = RCS_whatbranch (finfo->rcs, tag);
1787 error (0, 0, "cannot find branch \"%s\".", tag);
1791 branchname = RCS_getbranch (finfo->rcs, rev, 1);
1792 if (branchname == NULL)
1794 /* no revision exists on this branch. use the previous
1795 revision but do not lock. */
1796 corev = RCS_gettag (finfo->rcs, tag, 1, NULL);
1797 prev_rev = xstrdup (corev);
1801 corev = xstrdup (rev);
1802 prev_rev = xstrdup (branchname);
1806 } else /* Not a branch */
1808 /* Get current head revision of file. */
1809 prev_rev = RCS_head (finfo->rcs);
1812 /* if removing without a tag or a branch, then make sure the default
1813 branch is the trunk. */
1814 if (!tag && !branch)
1816 if (RCS_setbranch (finfo->rcs, NULL) != 0)
1818 error (0, 0, "cannot change branch to default for %s",
1822 RCS_rewrite (finfo->rcs, NULL, NULL);
1825 /* check something out. Generally this is the head. If we have a
1826 particular rev, then name it. */
1827 retcode = RCS_checkout (finfo->rcs, finfo->file, rev ? corev : NULL,
1828 NULL, NULL, RUN_TTY, NULL, NULL);
1832 "failed to check out `%s'", finfo->fullname);
1836 /* Except when we are creating a branch, lock the revision so that
1837 we can check in the new revision. */
1840 if (RCS_lock (finfo->rcs, rev ? corev : NULL, 1) == 0)
1841 RCS_rewrite (finfo->rcs, NULL, NULL);
1847 retcode = RCS_checkin (finfo->rcs, NULL, finfo->file, message,
1848 rev, 0, RCS_FLAGS_DEAD | RCS_FLAGS_QUIET);
1852 error (0, retcode == -1 ? errno : 0,
1853 "failed to commit dead revision for `%s'", finfo->fullname);
1856 /* At this point, the file has been committed as removed. We should
1857 probably tell the history file about it */
1858 history_write ('R', NULL, finfo->rcs->head, finfo->file, finfo->repository);
1863 old_path = xstrdup (finfo->rcs->path);
1865 RCS_setattic (finfo->rcs, 1);
1867 /* Print message that file was removed. */
1870 cvs_output (old_path, 0);
1871 cvs_output (" <-- ", 0);
1872 if (finfo->update_dir && strlen (finfo->update_dir))
1874 cvs_output (finfo->update_dir, 0);
1875 cvs_output ("/", 1);
1877 cvs_output (finfo->file, 0);
1878 cvs_output ("\nnew revision: delete; previous revision: ", 0);
1879 cvs_output (prev_rev, 0);
1880 cvs_output ("\n", 0);
1887 Scratch_Entry (finfo->entries, finfo->file);
1894 * Do the actual checkin for added files
1897 finaladd (struct file_info *finfo, char *rev, char *tag, char *options)
1901 ret = Checkin ('A', finfo, rev, tag, options, saved_message);
1904 char *tmp = Xasprintf ("%s/%s%s", CVSADM, finfo->file, CVSEXT_LOG);
1905 if (unlink_file (tmp) < 0
1906 && !existence_error (errno))
1907 error (0, errno, "cannot remove %s", tmp);
1910 else if (finfo->rcs != NULL)
1911 fixaddfile (finfo->rcs->path);
1913 (void) time (&last_register_time);
1921 * Unlock an rcs file
1924 unlockrcs (RCSNode *rcs)
1928 if ((retcode = RCS_unlock (rcs, NULL, 1)) != 0)
1929 error (retcode == -1 ? 1 : 0, retcode == -1 ? errno : 0,
1930 "could not unlock %s", rcs->path);
1932 RCS_rewrite (rcs, NULL, NULL);
1938 * remove a partially added file. if we can parse it, leave it alone.
1940 * FIXME: Every caller that calls this function can access finfo->rcs (the
1941 * parsed RCSNode data), so we should be able to detect that the file needs
1942 * to be removed without reparsing the file as we do below.
1945 fixaddfile (const char *rcs)
1948 int save_really_quiet;
1950 save_really_quiet = really_quiet;
1952 if ((rcsfile = RCS_parsercsfile (rcs)) == NULL)
1954 if (unlink_file (rcs) < 0)
1955 error (0, errno, "cannot remove %s", rcs);
1958 freercsnode (&rcsfile);
1959 really_quiet = save_really_quiet;
1965 * put the branch back on an rcs file
1968 fixbranch (RCSNode *rcs, char *branch)
1974 if ((retcode = RCS_setbranch (rcs, branch)) != 0)
1975 error (retcode == -1 ? 1 : 0, retcode == -1 ? errno : 0,
1976 "cannot restore branch to %s for %s", branch, rcs->path);
1977 RCS_rewrite (rcs, NULL, NULL);
1984 * do the initial part of a file add for the named file. if adding
1985 * with a tag, put the file in the Attic and point the symbolic tag
1986 * at the committed revision.
1989 * file The name of the file in the workspace.
1990 * repository The repository directory to expect to find FILE,v in.
1991 * tag The name or rev num of the branch being added to, if any.
1992 * options Any RCS keyword expansion options specified by the user.
1993 * rcsnode A pointer to the pre-parsed RCSNode for this file, if the file
1994 * exists in the repository. If this is NULL, assume the file
1995 * does not yet exist.
1999 * 1 on errors, after printing any appropriate error messages.
2002 * This function will return an error when any of the following functions do:
2007 * RCS_parse (called to verify the newly created archive file)
2012 checkaddfile (const char *file, const char *repository, const char *tag,
2013 const char *options, RCSNode **rcsnode)
2017 int newfile = 0; /* Set to 1 if we created a new RCS archive. */
2019 int adding_on_branch;
2021 assert (rcsnode != NULL);
2023 /* Callers expect to be able to use either "" or NULL to mean the
2024 default keyword expansion. */
2025 if (options != NULL && options[0] == '\0')
2027 if (options != NULL)
2028 assert (options[0] == '-' && options[1] == 'k');
2030 /* If numeric, it is on the trunk; check_fileproc enforced
2032 adding_on_branch = tag != NULL && !isdigit ((unsigned char) tag[0]);
2034 if (*rcsnode == NULL)
2038 size_t descalloc = 0;
2042 if (adding_on_branch)
2045 rcsname = xmalloc (strlen (repository)
2050 (void) sprintf (rcsname, "%s/%s", repository, CVSATTIC);
2051 omask = umask (cvsumask);
2052 if (CVS_MKDIR (rcsname, 0777) != 0 && errno != EEXIST)
2053 error (1, errno, "cannot make directory `%s'", rcsname);
2054 (void) umask (omask);
2055 (void) sprintf (rcsname,
2063 rcsname = Xasprintf ("%s/%s%s", repository, file, RCSEXT);
2065 /* this is the first time we have ever seen this file; create
2067 fname = Xasprintf ("%s/%s%s", CVSADM, file, CVSEXT_LOG);
2068 /* If the file does not exist, no big deal. In particular, the
2069 server does not (yet at least) create CVSEXT_LOG files. */
2071 /* FIXME: Should be including update_dir in the appropriate
2073 get_file (fname, fname, "r", &desc, &descalloc, &desclen);
2076 /* From reading the RCS 5.7 source, "rcs -i" adds a newline to the
2077 end of the log message if the message is nonempty.
2078 Do it. RCS also deletes certain whitespace, in cleanlogmsg,
2079 which we don't try to do here. */
2082 expand_string (&desc, &descalloc, desclen + 1);
2083 desc[desclen++] = '\012';
2086 /* Set RCS keyword expansion options. */
2087 if (options != NULL)
2092 if (add_rcs_file (NULL, rcsname, file, NULL, opt,
2093 NULL, NULL, 0, NULL,
2094 desc, desclen, NULL, 0) != 0)
2096 if (rcsname != NULL)
2100 rcs = RCS_parsercsfile (rcsname);
2102 if (rcsname != NULL)
2110 /* file has existed in the past. Prepare to resurrect. */
2116 oldexpand = RCS_getexpand (rcs);
2117 if ((oldexpand != NULL
2119 && strcmp (options + 2, oldexpand) != 0)
2120 || (oldexpand == NULL && options != NULL))
2122 /* We tell the user about this, because it means that the
2123 old revisions will no longer retrieve the way that they
2125 error (0, 0, "changing keyword expansion mode to %s", options);
2126 RCS_setexpand (rcs, options + 2);
2129 if (!adding_on_branch)
2131 /* We are adding on the trunk, so move the file out of the
2133 if (!(rcs->flags & INATTIC))
2135 error (0, 0, "warning: expected %s to be in Attic",
2139 /* Begin a critical section around the code that spans the
2140 first commit on the trunk of a file that's already been
2141 committed on a branch. */
2144 if (RCS_setattic (rcs, 0))
2150 rev = RCS_getversion (rcs, tag, NULL, 1, NULL);
2152 if (lock_RCS (file, rcs, rev, repository))
2154 error (0, 0, "cannot lock `%s'.", rcs->path);
2164 /* when adding a file for the first time, and using a tag, we need
2165 to create a dead revision on the trunk. */
2166 if (adding_on_branch)
2174 /* move the new file out of the way. */
2175 fname = Xasprintf ("%s/%s%s", CVSADM, CVSPREFIX, file);
2176 rename_file (file, fname);
2178 /* Create empty FILE. Can't use copy_file with a DEVNULL
2179 argument -- copy_file now ignores device files. */
2180 fp = fopen (file, "w");
2182 error (1, errno, "cannot open %s for writing", file);
2183 if (fclose (fp) < 0)
2184 error (0, errno, "cannot close %s", file);
2186 tmp = Xasprintf ("file %s was initially added on branch %s.",
2188 /* commit a dead revision. */
2189 retcode = RCS_checkin (rcs, NULL, NULL, tmp, NULL, 0,
2190 RCS_FLAGS_DEAD | RCS_FLAGS_QUIET);
2194 error (retcode == -1 ? 1 : 0, retcode == -1 ? errno : 0,
2195 "could not create initial dead revision %s", rcs->path);
2200 /* put the new file back where it was */
2201 rename_file (fname, file);
2204 /* double-check that the file was written correctly */
2206 rcs = RCS_parse (file, repository);
2209 error (0, 0, "could not read %s", rcs->path);
2214 /* and lock it once again. */
2215 if (lock_RCS (file, rcs, NULL, repository))
2217 error (0, 0, "cannot lock `%s'.", rcs->path);
2222 /* when adding with a tag, we need to stub a branch, if it
2223 doesn't already exist. */
2224 if (!RCS_nodeisbranch (rcs, tag))
2226 /* branch does not exist. Stub it. */
2230 time_t headtime = -1;
2236 fixbranch (rcs, sbranch);
2238 head = RCS_getversion (rcs, NULL, NULL, 0, NULL);
2240 error (1, 0, "No head revision in archive file `%s'.",
2242 magicrev = RCS_magicrev (rcs, head);
2244 /* If this is not a new branch, then we will want a dead
2245 version created before this one. */
2247 headtime = RCS_getrevtime (rcs, head, 0, 0);
2249 retcode = RCS_settag (rcs, tag, magicrev);
2250 RCS_rewrite (rcs, NULL, NULL);
2257 error (retcode == -1 ? 1 : 0, retcode == -1 ? errno : 0,
2258 "could not stub branch %s for %s", tag, rcs->path);
2261 /* We need to add a dead version here to avoid -rtag -Dtime
2262 checkout problems between when the head version was
2264 if (!newfile && headtime != -1)
2266 /* move the new file out of the way. */
2267 fname = Xasprintf ("%s/%s%s", CVSADM, CVSPREFIX, file);
2268 rename_file (file, fname);
2270 /* Create empty FILE. Can't use copy_file with a DEVNULL
2271 argument -- copy_file now ignores device files. */
2272 fp = fopen (file, "w");
2274 error (1, errno, "cannot open %s for writing", file);
2275 if (fclose (fp) < 0)
2276 error (0, errno, "cannot close %s", file);
2278 /* As we will be hacking the delta date, put the time
2279 this was added into the log message. */
2282 tmp = Xasprintf ("file %s was added on branch %s on %d-%02d-%02d %02d:%02d:%02d +0000",
2284 ct->tm_year + (ct->tm_year < 100 ? 0 : 1900),
2285 ct->tm_mon + 1, ct->tm_mday,
2286 ct->tm_hour, ct->tm_min, ct->tm_sec);
2288 /* commit a dead revision. */
2289 revnum = RCS_whatbranch (rcs, tag);
2290 retcode = RCS_checkin (rcs, NULL, NULL, tmp, revnum, headtime,
2299 error (retcode == -1 ? 1 : 0, retcode == -1 ? errno : 0,
2300 "could not created dead stub %s for %s", tag,
2305 /* put the new file back where it was */
2306 rename_file (fname, file);
2309 /* double-check that the file was written correctly */
2311 rcs = RCS_parse (file, repository);
2314 error (0, 0, "could not read %s", rcs->path);
2322 /* lock the branch. (stubbed branches need not be locked.) */
2323 if (lock_RCS (file, rcs, NULL, repository))
2325 error (0, 0, "cannot lock `%s'.", rcs->path);
2330 if (*rcsnode != rcs)
2332 freercsnode (rcsnode);
2337 fileattr_newfile (file);
2339 /* At this point, we used to set the file mode of the RCS file
2340 based on the mode of the file in the working directory. If we
2341 are creating the RCS file for the first time, add_rcs_file does
2342 this already. If we are re-adding the file, then perhaps it is
2343 consistent to preserve the old file mode, just as we preserve
2344 the old keyword expansion mode.
2346 If we decide that we should change the modes, then we can't do
2347 it here anyhow. At this point, the RCS file may be owned by
2348 somebody else, so a chmod will fail. We need to instead do the
2349 chmod after rewriting it.
2351 FIXME: In general, I think the file mode (and the keyword
2352 expansion mode) should be associated with a particular revision
2353 of the file, so that it is possible to have different revisions
2354 of a file have different modes. */
2359 if (retval != 0 && SIG_inCrSect ())
2367 * Attempt to place a lock on the RCS file; returns 0 if it could and 1 if it
2368 * couldn't. If the RCS file currently has a branch as the head, we must
2369 * move the head back to the trunk before locking the file, and be sure to
2370 * put the branch back as the head if there are any errors.
2373 lock_RCS (const char *user, RCSNode *rcs, const char *rev,
2374 const char *repository)
2376 char *branch = NULL;
2380 * For a specified, numeric revision of the form "1" or "1.1", (or when
2381 * no revision is specified ""), definitely move the branch to the trunk
2382 * before locking the RCS file.
2384 * The assumption is that if there is more than one revision on the trunk,
2385 * the head points to the trunk, not a branch... and as such, it's not
2386 * necessary to move the head in this case.
2389 || (rev && isdigit ((unsigned char) *rev) && numdots (rev) < 2))
2391 branch = xstrdup (rcs->branch);
2394 if (RCS_setbranch (rcs, NULL) != 0)
2396 error (0, 0, "cannot change branch to default for %s",
2403 err = RCS_lock (rcs, NULL, 1);
2407 RCS_lock (rcs, rev, 1);
2410 /* We used to call RCS_rewrite here, and that might seem
2411 appropriate in order to write out the locked revision
2412 information. However, such a call would actually serve no
2413 purpose. CVS locks will prevent any interference from other
2414 CVS processes. The comment above rcs_internal_lockfile
2415 explains that it is already unsafe to use RCS and CVS
2416 simultaneously. It follows that writing out the locked
2417 revision information here would add no additional security.
2419 If we ever do care about it, the proper fix is to create the
2420 RCS lock file before calling this function, and maintain it
2421 until the checkin is complete.
2423 The call to RCS_lock is still required at present, since in
2424 some cases RCS_checkin will determine which revision to check
2425 in by looking for a lock. FIXME: This is rather roundabout,
2426 and a more straightforward approach would probably be easier to
2431 if (sbranch != NULL)
2437 /* try to restore the branch if we can on error */
2439 fixbranch (rcs, branch);
2449 * free an UPDATE node's data
2452 update_delproc (Node *p)
2454 struct logfile_info *li = p->data;
2466 * Free the commit_info structure in p.
2469 ci_delproc (Node *p)
2471 struct commit_info *ci = p->data;
2483 * Free the commit_info structure in p.
2486 masterlist_delproc (Node *p)
2488 struct master_lists *ml = p->data;
2490 dellist (&ml->ulist);
2491 dellist (&ml->cilist);