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 * "commit" commits the present version to the RCS repository, AFTER
11 * having done a test on conflicts.
13 * The call is: cvs commit [options] files...
25 static Dtype check_direntproc PROTO ((void *callerdat, const char *dir,
27 const char *update_dir,
29 static int check_fileproc PROTO ((void *callerdat, struct file_info *finfo));
30 static int check_filesdoneproc PROTO ((void *callerdat, int err,
32 const char *update_dir,
34 static int checkaddfile PROTO((const char *file, const char *repository,
35 const char *tag, const char *options,
37 static Dtype commit_direntproc PROTO ((void *callerdat, const char *dir,
39 const char *update_dir,
41 static int commit_dirleaveproc PROTO ((void *callerdat, const char *dir,
42 int err, const char *update_dir,
44 static int commit_fileproc PROTO ((void *callerdat, struct file_info *finfo));
45 static int commit_filesdoneproc PROTO ((void *callerdat, int err,
46 const char *repository,
47 const char *update_dir,
49 static int finaladd PROTO((struct file_info *finfo, char *revision, char *tag,
51 static int findmaxrev PROTO((Node * p, void *closure));
52 static int lock_RCS PROTO((const char *user, RCSNode *rcs, const char *rev,
53 const char *repository));
54 static int precommit_list_proc PROTO((Node * p, void *closure));
55 static int precommit_proc PROTO((const char *repository, const char *filter));
56 static int remove_file PROTO ((struct file_info *finfo, char *tag,
58 static void fixaddfile PROTO((const char *rcs));
59 static void fixbranch PROTO((RCSNode *, char *branch));
60 static void unlockrcs PROTO((RCSNode *rcs));
61 static void ci_delproc PROTO((Node *p));
62 static void masterlist_delproc PROTO((Node *p));
66 Ctype status; /* as returned from Classify_File() */
67 char *rev; /* a numeric rev, if we know it */
68 char *tag; /* any sticky tag, or -r option */
69 char *options; /* Any sticky -k option */
73 List *ulist; /* list for Update_Logfile */
74 List *cilist; /* list with commit_info structs */
77 static int force_ci = 0;
78 static int got_message;
80 static char *saved_tag;
81 static char *write_dirtag;
82 static int write_dirnonbranch;
85 static List *saved_ulist;
86 static char *saved_message;
87 static time_t last_register_time;
89 static const char *const commit_usage[] =
91 "Usage: %s %s [-Rlf] [-m msg | -F logfile] [-r rev] files...\n",
92 " -R Process directories recursively.\n",
93 " -l Local directory only (not recursive).\n",
94 " -f Force the file to be committed; disables recursion.\n",
95 " -F logfile Read the log message from file.\n",
96 " -m msg Log message.\n",
97 " -r rev Commit to this branch or trunk revision.\n",
98 "(Specify the --help global option for a list of other help options)\n",
102 #ifdef CLIENT_SUPPORT
103 /* Identify a file which needs "? foo" or a Questionable request. */
105 /* The two fields for the Directory request. */
112 struct question *next;
120 /* This is used from dirent to filesdone time, for each directory,
121 to make a list of files we have already seen. */
124 /* Linked list of files which need "? foo" or a Questionable request. */
125 struct question *questionables;
127 /* Only good within functions called from the filesdoneproc. Stores
128 the repository (pointer into storage managed by the recursion
130 const char *repository;
132 /* Non-zero if we should force the commit. This is enabled by
133 either -f or -r options, unlike force_ci which is just -f. */
139 static Dtype find_dirent_proc PROTO ((void *callerdat, const char *dir,
140 const char *repository,
141 const char *update_dir,
145 find_dirent_proc (callerdat, dir, repository, update_dir, entries)
148 const char *repository;
149 const char *update_dir;
152 struct find_data *find_data = (struct find_data *)callerdat;
154 /* This check seems to slowly be creeping throughout CVS (update
155 and send_dirent_proc by CVS 1.5, diff in 31 Oct 1995. My guess
156 is that it (or some variant thereof) should go in all the
157 dirent procs. Unless someone has some better idea... */
161 /* initialize the ignore list for this directory */
162 find_data->ignlist = getlist ();
164 /* Print the same warm fuzzy as in check_direntproc, since that
165 code will never be run during client/server operation and we
166 want the messages to match. */
168 error (0, 0, "Examining %s", update_dir);
175 /* Here as a static until we get around to fixing ignore_files to pass
176 it along as an argument. */
177 static struct find_data *find_data_static;
181 static void find_ignproc PROTO ((const char *, const char *));
184 find_ignproc (file, dir)
190 p = (struct question *) xmalloc (sizeof (struct question));
191 p->dir = xstrdup (dir);
192 p->repos = xstrdup (find_data_static->repository);
193 p->file = xstrdup (file);
194 p->next = find_data_static->questionables;
195 find_data_static->questionables = p;
200 static int find_filesdoneproc PROTO ((void *callerdat, int err,
201 const char *repository,
202 const char *update_dir,
206 find_filesdoneproc (callerdat, err, repository, update_dir, entries)
209 const char *repository;
210 const char *update_dir;
213 struct find_data *find_data = (struct find_data *)callerdat;
214 find_data->repository = repository;
216 /* if this directory has an ignore list, process it then free it */
217 if (find_data->ignlist)
219 find_data_static = find_data;
220 ignore_files (find_data->ignlist, entries, update_dir, find_ignproc);
221 dellist (&find_data->ignlist);
224 find_data->repository = NULL;
231 static int find_fileproc PROTO ((void *callerdat, struct file_info *finfo));
233 /* Machinery to find out what is modified, added, and removed. It is
234 possible this should be broken out into a new client_classify function;
235 merging it with classify_file is almost sure to be a mess, though,
236 because classify_file has all kinds of repository processing. */
238 find_fileproc (callerdat, finfo)
240 struct file_info *finfo;
243 enum classify_type status;
245 struct find_data *args = (struct find_data *)callerdat;
246 struct logfile_info *data;
247 struct file_info xfinfo;
249 /* if this directory has an ignore list, add this file to it */
256 p->key = xstrdup (finfo->file);
257 if (addnode (args->ignlist, p) != 0)
262 xfinfo.repository = NULL;
265 vers = Version_TS (&xfinfo, NULL, saved_tag, NULL, 0, 0);
266 if (vers->vn_user == NULL)
268 if (vers->ts_user == NULL)
269 error (0, 0, "nothing known about `%s'", finfo->fullname);
271 error (0, 0, "use `%s add' to create an entry for %s",
272 program_name, finfo->fullname);
276 if (vers->vn_user[0] == '-')
278 if (vers->ts_user != NULL)
281 "`%s' should be removed and is still there (or is back"
282 " again)", finfo->fullname);
289 else if (strcmp (vers->vn_user, "0") == 0)
291 if (vers->ts_user == NULL)
293 /* This happens when one has `cvs add'ed a file, but it no
294 longer exists in the working directory at commit time.
295 FIXME: What classify_file does in this case is print
296 "new-born %s has disappeared" and removes the entry.
297 We probably should do the same. */
299 error (0, 0, "warning: new-born %s has disappeared",
301 status = T_REMOVE_ENTRY;
306 else if (vers->ts_user == NULL)
308 /* FIXME: What classify_file does in this case is print
309 "%s was lost". We probably should do the same. */
313 else if (vers->ts_rcs != NULL
314 && (args->force || strcmp (vers->ts_user, vers->ts_rcs) != 0))
315 /* If we are forcing commits, pretend that the file is
320 /* This covers unmodified files, as well as a variety of other
321 cases. FIXME: we probably should be printing a message and
322 returning 1 for many of those cases (but I'm not sure
323 exactly which ones). */
329 node->key = xstrdup (finfo->fullname);
331 data = (struct logfile_info *) xmalloc (sizeof (struct logfile_info));
333 data->tag = xstrdup (vers->tag);
334 data->rev_old = data->rev_new = NULL;
337 node->delproc = update_delproc;
339 (void)addnode (args->ulist, node);
349 static int copy_ulist PROTO ((Node *, void *));
352 copy_ulist (node, data)
356 struct find_data *args = (struct find_data *)data;
357 args->argv[args->argc++] = node->key;
360 #endif /* CLIENT_SUPPORT */
362 #ifdef SERVER_SUPPORT
363 # define COMMIT_OPTIONS "+nlRm:fF:r:"
364 #else /* !SERVER_SUPPORT */
365 # define COMMIT_OPTIONS "+lRm:fF:r:"
366 #endif /* SERVER_SUPPORT */
377 usage (commit_usage);
381 * For log purposes, do not allow "root" to commit files. If you look
382 * like root, but are really logged in as a non-root user, it's OK.
384 /* FIXME: Shouldn't this check be much more closely related to the
385 readonly user stuff (CVSROOT/readers, &c). That is, why should
386 root be able to "cvs init", "cvs import", &c, but not "cvs ci"? */
387 if (geteuid () == (uid_t) 0
388 # ifdef CLIENT_SUPPORT
389 /* Who we are on the client side doesn't affect logging. */
390 && !current_parsed_root->isremote
396 if ((pw = (struct passwd *) getpwnam (getcaller ())) == NULL)
398 "your apparent username (%s) is unknown to this system",
400 if (pw->pw_uid == (uid_t) 0)
401 error (1, 0, "'root' is not allowed to commit files");
403 #endif /* CVS_BADROOT */
406 while ((c = getopt (argc, argv, COMMIT_OPTIONS)) != -1)
410 #ifdef SERVER_SUPPORT
412 /* Silently ignore -n for compatibility with old
416 #endif /* SERVER_SUPPORT */
418 #ifdef FORCE_USE_EDITOR
425 free (saved_message);
426 saved_message = NULL;
429 saved_message = xstrdup(optarg);
434 saved_tag = xstrdup (optarg);
444 local = 1; /* also disable recursion */
447 #ifdef FORCE_USE_EDITOR
456 usage (commit_usage);
463 /* numeric specified revision means we ignore sticky tags... */
464 if (saved_tag && isdigit ((unsigned char) *saved_tag))
466 char *p = saved_tag + strlen (saved_tag);
468 /* strip trailing dots and leading zeros */
469 while (*--p == '.') ;
471 while (saved_tag[0] == '0' && isdigit ((unsigned char) saved_tag[1]))
475 /* some checks related to the "-F logfile" option */
478 size_t size = 0, len;
481 error (1, 0, "cannot specify both a message and a log file");
483 get_file (logfile, logfile, "r", &saved_message, &size, &len);
486 #ifdef CLIENT_SUPPORT
487 if (current_parsed_root->isremote)
489 struct find_data find_args;
493 find_args.ulist = getlist ();
495 find_args.questionables = NULL;
496 find_args.ignlist = NULL;
497 find_args.repository = NULL;
499 /* It is possible that only a numeric tag should set this.
500 I haven't really thought about it much.
501 Anyway, I suspect that setting it unnecessarily only causes
502 a little unneeded network traffic. */
503 find_args.force = force_ci || saved_tag != NULL;
505 err = start_recursion (find_fileproc, find_filesdoneproc,
506 find_dirent_proc, (DIRLEAVEPROC) NULL,
508 argc, argv, local, W_LOCAL, 0, CVS_LOCK_NONE,
509 (char *) NULL, 0, (char *) NULL);
511 error (1, 0, "correct above errors first!");
513 if (find_args.argc == 0)
515 /* Nothing to commit. Exit now without contacting the
516 server (note that this means that we won't print "?
517 foo" for files which merit it, because we don't know
518 what is in the CVSROOT/cvsignore file). */
519 dellist (&find_args.ulist);
523 /* Now we keep track of which files we actually are going to
524 operate on, and only work with those files in the future.
525 This saves time--we don't want to search the file system
526 of the working directory twice. */
527 if (size_overflow_p (xtimes (find_args.argc, sizeof (char **))))
532 find_args.argv = xmalloc (xtimes (find_args.argc, sizeof (char **)));
534 walklist (find_args.ulist, copy_ulist, &find_args);
536 /* Do this before calling do_editor; don't ask for a log
537 message if we can't talk to the server. But do it after we
538 have made the checks that we can locally (to more quickly
539 catch syntax errors, the case where no files are modified,
540 added or removed, etc.).
542 On the other hand, calling start_server before do_editor
543 means that we chew up server resources the whole time that
544 the user has the editor open (hours or days if the user
545 forgets about it), which seems dubious. */
549 * We do this once, not once for each directory as in normal CVS.
550 * The protocol is designed this way. This is a feature.
553 do_editor (".", &saved_message, (char *)NULL, find_args.ulist);
555 /* We always send some sort of message, even if empty. */
556 option_with_arg ("-m", saved_message ? saved_message : "");
558 /* OK, now process all the questionable files we have been saving
564 p = find_args.questionables;
567 if (ign_inhibit_server || !supported_request ("Questionable"))
569 cvs_output ("? ", 2);
570 if (p->dir[0] != '\0')
572 cvs_output (p->dir, 0);
575 cvs_output (p->file, 0);
576 cvs_output ("\n", 1);
580 send_to_server ("Directory ", 0);
581 send_to_server (p->dir[0] == '\0' ? "." : p->dir, 0);
582 send_to_server ("\012", 1);
583 send_to_server (p->repos, 0);
584 send_to_server ("\012", 1);
586 send_to_server ("Questionable ", 0);
587 send_to_server (p->file, 0);
588 send_to_server ("\012", 1);
603 option_with_arg ("-r", saved_tag);
606 /* FIXME: This whole find_args.force/SEND_FORCE business is a
607 kludge. It would seem to be a server bug that we have to
608 say that files are modified when they are not. This makes
609 "cvs commit -r 2" across a whole bunch of files a very slow
610 operation (and it isn't documented in cvsclient.texi). I
611 haven't looked at the server code carefully enough to be
612 _sure_ why this is needed, but if it is because the "ci"
613 program, which we used to call, wanted the file to exist,
614 then it would be relatively simple to fix in the server. */
615 send_files (find_args.argc, find_args.argv, local, 0,
616 find_args.force ? SEND_FORCE : 0);
618 /* Sending only the names of the files which were modified, added,
619 or removed means that the server will only do an up-to-date
620 check on those files. This is different from local CVS and
621 previous versions of client/server CVS, but it probably is a Good
622 Thing, or at least Not Such A Bad Thing. */
623 send_file_names (find_args.argc, find_args.argv, 0);
624 free (find_args.argv);
625 dellist (&find_args.ulist);
627 send_to_server ("ci\012", 0);
628 err = get_responses_and_close ();
629 if (err != 0 && use_editor && saved_message != NULL)
631 /* If there was an error, don't nuke the user's carefully
632 constructed prose. This is something of a kludge; a better
633 solution is probably more along the lines of #150 in TODO
634 (doing a second up-to-date check before accepting the
635 log message has also been suggested, but that seems kind of
636 iffy because the real up-to-date check could still fail,
637 another error could occur, &c. Also, a second check would
638 slow things down). */
643 fp = cvs_temp_file (&fname);
645 error (1, 0, "cannot create temporary file %s", fname);
646 if (fwrite (saved_message, 1, strlen (saved_message), fp)
647 != strlen (saved_message))
648 error (1, errno, "cannot write temporary file %s", fname);
650 error (0, errno, "cannot close temporary file %s", fname);
651 error (0, 0, "saving log message in %s", fname);
658 if (saved_tag != NULL)
659 tag_check_valid (saved_tag, argc, argv, local, aflag, "");
661 /* XXX - this is not the perfect check for this */
663 write_dirtag = saved_tag;
667 lock_tree_for_write (argc, argv, local, W_LOCAL, aflag);
670 * Set up the master update list and hard link list
674 #ifdef PRESERVE_PERMISSIONS_SUPPORT
677 hardlist = getlist ();
680 * We need to save the working directory so that
681 * check_fileproc can construct a full pathname for each file.
683 working_dir = xgetwd();
688 * Run the recursion processor to verify the files are all up-to-date
690 err = start_recursion (check_fileproc, check_filesdoneproc,
691 check_direntproc, (DIRLEAVEPROC) NULL, NULL, argc,
692 argv, local, W_LOCAL, aflag, CVS_LOCK_NONE,
693 (char *) NULL, 1, (char *) NULL);
697 error (1, 0, "correct above errors first!");
701 * Run the recursion processor to commit the files
703 write_dirnonbranch = 0;
705 err = start_recursion (commit_fileproc, commit_filesdoneproc,
706 commit_direntproc, commit_dirleaveproc, NULL,
707 argc, argv, local, W_LOCAL, aflag, CVS_LOCK_NONE,
708 (char *) NULL, 1, (char *) NULL);
711 * Unlock all the dirs and clean up
716 #ifdef SERVER_SUPPORT
721 /* see if we need to sleep before returning to avoid time-stamp races */
722 if (last_register_time)
724 sleep_past (last_register_time);
732 /* This routine determines the status of a given file and retrieves
733 the version information that is associated with that file. */
737 classify_file_internal (finfo, vers)
738 struct file_info *finfo;
741 int save_noexec, save_quiet, save_really_quiet;
744 /* FIXME: Do we need to save quiet as well as really_quiet? Last
745 time I glanced at Classify_File I only saw it looking at really_quiet
747 save_noexec = noexec;
749 save_really_quiet = really_quiet;
750 noexec = quiet = really_quiet = 1;
752 /* handle specified numeric revision specially */
753 if (saved_tag && isdigit ((unsigned char) *saved_tag))
755 /* If the tag is for the trunk, make sure we're at the head */
756 if (numdots (saved_tag) < 2)
758 status = Classify_File (finfo, (char *) NULL, (char *) NULL,
759 (char *) NULL, 1, aflag, vers, 0);
760 if (status == T_UPTODATE || status == T_MODIFIED ||
766 xstatus = Classify_File (finfo, saved_tag, (char *) NULL,
767 (char *) NULL, 1, aflag, vers, 0);
768 if (xstatus == T_REMOVE_ENTRY)
770 else if (status == T_MODIFIED && xstatus == T_CONFLICT)
781 * The revision is off the main trunk; make sure we're
782 * up-to-date with the head of the specified branch.
784 xtag = xstrdup (saved_tag);
785 if ((numdots (xtag) & 1) != 0)
787 cp = strrchr (xtag, '.');
790 status = Classify_File (finfo, xtag, (char *) NULL,
791 (char *) NULL, 1, aflag, vers, 0);
792 if ((status == T_REMOVE_ENTRY || status == T_CONFLICT)
793 && (cp = strrchr (xtag, '.')) != NULL)
795 /* pluck one more dot off the revision */
798 status = Classify_File (finfo, xtag, (char *) NULL,
799 (char *) NULL, 1, aflag, vers, 0);
800 if (status == T_UPTODATE || status == T_REMOVE_ENTRY)
803 /* now, muck with vers to make the tag correct */
805 (*vers)->tag = xstrdup (saved_tag);
810 status = Classify_File (finfo, saved_tag, (char *) NULL, (char *) NULL,
812 noexec = save_noexec;
814 really_quiet = save_really_quiet;
822 * Check to see if a file is ok to commit and make sure all files are
827 check_fileproc (callerdat, finfo)
829 struct file_info *finfo;
834 List *ulist, *cilist;
836 struct commit_info *ci;
837 struct logfile_info *li;
839 size_t cvsroot_len = strlen (current_parsed_root->directory);
841 if (!finfo->repository)
843 error (0, 0, "nothing known about `%s'", finfo->fullname);
847 if (strncmp (finfo->repository, current_parsed_root->directory,
849 && ISDIRSEP (finfo->repository[cvsroot_len])
850 && strncmp (finfo->repository + cvsroot_len + 1,
852 sizeof (CVSROOTADM) - 1) == 0
853 && ISDIRSEP (finfo->repository[cvsroot_len + sizeof (CVSROOTADM)])
854 && strcmp (finfo->repository + cvsroot_len + sizeof (CVSROOTADM) + 1,
857 error (1, 0, "cannot check in to %s", finfo->repository);
859 status = classify_file_internal (finfo, &vers);
862 * If the force-commit option is enabled, and the file in question
863 * appears to be up-to-date, just make it look modified so that
864 * it will be committed.
866 if (force_ci && status == T_UPTODATE)
876 error (0, 0, "Up-to-date check failed for `%s'", finfo->fullname);
883 * some quick sanity checks; if no numeric -r option specified:
884 * - can't have a sticky date
885 * - can't have a sticky tag that is not a branch
887 * - if status is T_REMOVED, file must not exist and its entry
888 * can't have a numeric sticky tag.
889 * - if status is T_ADDED, rcs file must not exist unless on
890 * a branch or head is dead
891 * - if status is T_ADDED, can't have a non-trunk numeric rev
892 * - if status is T_MODIFIED and a Conflict marker exists, don't
893 * allow the commit if timestamp is identical or if we find
894 * an RCS_MERGE_PAT in the file.
896 if (!saved_tag || !isdigit ((unsigned char) *saved_tag))
901 "cannot commit with sticky date for file `%s'",
906 if (status == T_MODIFIED && vers->tag &&
907 !RCS_isbranch (finfo->rcs, vers->tag))
910 "sticky tag `%s' for file `%s' is not a branch",
911 vers->tag, finfo->fullname);
916 if (status == T_MODIFIED && !force_ci && vers->ts_conflict)
919 * We found a "conflict" marker.
921 * If the timestamp on the file is the same as the
922 * timestamp stored in the Entries file, we block the commit.
924 if ( file_has_conflict ( finfo, vers->ts_conflict ) )
927 "file `%s' had a conflict and has not been modified",
933 if (file_has_markers (finfo))
935 /* Make this a warning, not an error, because we have
936 no way of knowing whether the "conflict indicators"
937 are really from a conflict or whether they are part
938 of the document itself (cvs.texinfo and sanity.sh in
939 CVS itself, for example, tend to want to have strings
940 like ">>>>>>>" at the start of a line). Making people
941 kludge this the way they need to kludge keyword
942 expansion seems undesirable. And it is worse than
943 keyword expansion, because there is no -ko
947 warning: file `%s' seems to still contain conflict indicators",
952 if (status == T_REMOVED)
954 if (vers->ts_user != NULL)
957 "`%s' should be removed and is still there (or is"
958 " back again)", finfo->fullname);
963 if (vers->tag && isdigit ((unsigned char) *vers->tag))
965 /* Remove also tries to forbid this, but we should check
966 here. I'm only _sure_ about somewhat obscure cases
967 (hacking the Entries file, using an old version of
968 CVS for the remove and a new one for the commit), but
969 there might be other cases. */
971 "cannot remove file `%s' which has a numeric sticky"
972 " tag of `%s'", finfo->fullname, vers->tag);
977 if (status == T_ADDED)
979 if (vers->tag == NULL)
981 if (finfo->rcs != NULL &&
982 !RCS_isdead (finfo->rcs, finfo->rcs->head))
985 "cannot add file `%s' when RCS file `%s' already exists",
986 finfo->fullname, finfo->rcs->path);
991 else if (isdigit ((unsigned char) *vers->tag) &&
992 numdots (vers->tag) > 1)
995 "cannot add file `%s' with revision `%s'; must be on trunk",
996 finfo->fullname, vers->tag);
1002 /* done with consistency checks; now, to get on with the commit */
1003 if (finfo->update_dir[0] == '\0')
1006 xdir = finfo->update_dir;
1007 if ((p = findnode (mulist, xdir)) != NULL)
1009 ulist = ((struct master_lists *) p->data)->ulist;
1010 cilist = ((struct master_lists *) p->data)->cilist;
1014 struct master_lists *ml;
1017 cilist = getlist ();
1019 p->key = xstrdup (xdir);
1021 ml = (struct master_lists *)
1022 xmalloc (sizeof (struct master_lists));
1024 ml->cilist = cilist;
1026 p->delproc = masterlist_delproc;
1027 (void) addnode (mulist, p);
1030 /* first do ulist, then cilist */
1032 p->key = xstrdup (finfo->file);
1034 p->delproc = update_delproc;
1035 li = ((struct logfile_info *)
1036 xmalloc (sizeof (struct logfile_info)));
1038 li->tag = xstrdup (vers->tag);
1039 li->rev_old = xstrdup (vers->vn_rcs);
1042 (void) addnode (ulist, p);
1045 p->key = xstrdup (finfo->file);
1047 p->delproc = ci_delproc;
1048 ci = (struct commit_info *) xmalloc (sizeof (struct commit_info));
1049 ci->status = status;
1051 if (isdigit ((unsigned char) *vers->tag))
1052 ci->rev = xstrdup (vers->tag);
1054 ci->rev = RCS_whatbranch (finfo->rcs, vers->tag);
1056 ci->rev = (char *) NULL;
1057 ci->tag = xstrdup (vers->tag);
1058 ci->options = xstrdup(vers->options);
1060 (void) addnode (cilist, p);
1062 #ifdef PRESERVE_PERMISSIONS_SUPPORT
1065 /* Add this file to hardlist, indexed on its inode. When
1066 we are done, we can find out what files are hardlinked
1067 to a given file by looking up its inode in hardlist. */
1070 struct hardlink_info *hlinfo;
1072 /* Get the full pathname of the current file. */
1073 fullpath = xmalloc (strlen(working_dir) +
1074 strlen(finfo->fullname) + 2);
1075 sprintf (fullpath, "%s/%s", working_dir, finfo->fullname);
1077 /* To permit following links in subdirectories, files
1078 are keyed on finfo->fullname, not on finfo->name. */
1079 linkp = lookup_file_by_inode (fullpath);
1081 /* If linkp is NULL, the file doesn't exist... maybe
1082 we're doing a remove operation? */
1085 /* Create a new hardlink_info node, which will record
1086 the current file's status and the links listed in its
1087 `hardlinks' delta field. We will append this
1088 hardlink_info node to the appropriate hardlist entry. */
1089 hlinfo = (struct hardlink_info *)
1090 xmalloc (sizeof (struct hardlink_info));
1091 hlinfo->status = status;
1092 linkp->data = hlinfo;
1099 error (0, 0, "nothing known about `%s'", finfo->fullname);
1100 freevers_ts (&vers);
1105 error (0, 0, "CVS internal error: unknown status %d", status);
1109 freevers_ts (&vers);
1116 * By default, return the code that tells do_recursion to examine all
1121 check_direntproc (callerdat, dir, repos, update_dir, entries)
1125 const char *update_dir;
1132 error (0, 0, "Examining %s", update_dir);
1140 * Walklist proc to run pre-commit checks
1143 precommit_list_proc (p, closure)
1147 struct logfile_info *li = p->data;
1148 if (li->type == T_ADDED
1149 || li->type == T_MODIFIED
1150 || li->type == T_REMOVED)
1160 * Callback proc for pre-commit checking
1163 precommit_proc (repository, filter)
1164 const char *repository;
1167 /* see if the filter is there, only if it's a full path */
1168 if (isabsolute (filter))
1172 s = xstrdup (filter);
1173 for (cp = s; *cp; cp++)
1174 if (isspace ((unsigned char) *cp))
1181 error (0, errno, "cannot find pre-commit filter `%s'", s);
1183 return 1; /* so it fails! */
1189 run_arg (repository);
1190 (void) walklist (saved_ulist, precommit_list_proc, NULL);
1191 return run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL|RUN_REALLY);
1197 * Run the pre-commit checks for the dir
1201 check_filesdoneproc (callerdat, err, repos, update_dir, entries)
1205 const char *update_dir;
1211 /* find the update list for this dir */
1212 p = findnode (mulist, update_dir);
1214 saved_ulist = ((struct master_lists *) p->data)->ulist;
1216 saved_ulist = (List *) NULL;
1218 /* skip the checks if there's nothing to do */
1219 if (saved_ulist == NULL || saved_ulist->list->next == saved_ulist->list)
1222 /* run any pre-commit checks */
1223 if ((n = Parse_Info (CVSROOTADM_COMMITINFO, repos, precommit_proc, 1)) > 0)
1225 error (0, 0, "Pre-commit check failed");
1235 * Do the work of committing a file
1238 static char *sbranch;
1242 commit_fileproc (callerdat, finfo)
1244 struct file_info *finfo;
1248 List *ulist, *cilist;
1249 struct commit_info *ci;
1251 /* Keep track of whether write_dirtag is a branch tag.
1252 Note that if it is a branch tag in some files and a nonbranch tag
1253 in others, treat it as a nonbranch tag. It is possible that case
1254 should elicit a warning or an error. */
1255 if (write_dirtag != NULL
1256 && finfo->rcs != NULL)
1258 char *rev = RCS_getversion (finfo->rcs, write_dirtag, NULL, 1, NULL);
1260 && !RCS_nodeisbranch (finfo->rcs, write_dirtag))
1261 write_dirnonbranch = 1;
1266 if (finfo->update_dir[0] == '\0')
1267 p = findnode (mulist, ".");
1269 p = findnode (mulist, finfo->update_dir);
1272 * if p is null, there were file type command line args which were
1273 * all up-to-date so nothing really needs to be done
1277 ulist = ((struct master_lists *) p->data)->ulist;
1278 cilist = ((struct master_lists *) p->data)->cilist;
1281 * At this point, we should have the commit message unless we were called
1282 * with files as args from the command line. In that latter case, we
1283 * need to get the commit message ourselves
1289 #ifdef SERVER_SUPPORT
1293 do_editor (finfo->update_dir, &saved_message,
1294 finfo->repository, ulist);
1295 do_verify (&saved_message, finfo->repository);
1298 p = findnode (cilist, finfo->file);
1303 if (ci->status == T_MODIFIED)
1305 if (finfo->rcs == NULL)
1306 error (1, 0, "internal error: no parsed RCS file");
1307 if (lock_RCS (finfo->file, finfo->rcs, ci->rev,
1308 finfo->repository) != 0)
1310 unlockrcs (finfo->rcs);
1315 else if (ci->status == T_ADDED)
1317 if (checkaddfile (finfo->file, finfo->repository, ci->tag, ci->options,
1320 if (finfo->rcs != NULL)
1321 fixaddfile (finfo->rcs->path);
1326 /* adding files with a tag, now means adding them on a branch.
1327 Since the branch test was done in check_fileproc for
1328 modified files, we need to stub it in again here. */
1332 /* If numeric, it is on the trunk; check_fileproc enforced
1334 && !isdigit ((unsigned char) ci->tag[0]))
1336 if (finfo->rcs == NULL)
1337 error (1, 0, "internal error: no parsed RCS file");
1340 ci->rev = RCS_whatbranch (finfo->rcs, ci->tag);
1341 err = Checkin ('A', finfo, ci->rev,
1342 ci->tag, ci->options, saved_message);
1345 unlockrcs (finfo->rcs);
1346 fixbranch (finfo->rcs, sbranch);
1349 (void) time (&last_register_time);
1351 ci->status = T_UPTODATE;
1356 * Add the file for real
1358 if (ci->status == T_ADDED)
1360 char *xrev = (char *) NULL;
1362 if (ci->rev == NULL)
1364 /* find the max major rev number in this directory */
1366 (void) walklist (finfo->entries, findmaxrev, NULL);
1367 if (finfo->rcs->head) {
1368 /* resurrecting: include dead revision */
1369 int thisrev = atoi (finfo->rcs->head);
1370 if (thisrev > maxrev)
1375 xrev = xmalloc (20);
1376 (void) sprintf (xrev, "%d", maxrev);
1379 /* XXX - an added file with symbolic -r should add tag as well */
1380 err = finaladd (finfo, ci->rev ? ci->rev : xrev, ci->tag, ci->options);
1384 else if (ci->status == T_MODIFIED)
1386 err = Checkin ('M', finfo, ci->rev, ci->tag,
1387 ci->options, saved_message);
1389 (void) time (&last_register_time);
1393 unlockrcs (finfo->rcs);
1394 fixbranch (finfo->rcs, sbranch);
1397 else if (ci->status == T_REMOVED)
1399 err = remove_file (finfo, ci->tag, saved_message);
1400 #ifdef SERVER_SUPPORT
1401 if (server_active) {
1402 server_scratch_entry_only ();
1403 server_updated (finfo,
1406 /* Doesn't matter, it won't get checked. */
1410 (unsigned char *) NULL,
1411 (struct buffer *) NULL);
1416 /* Clearly this is right for T_MODIFIED. I haven't thought so much
1417 about T_ADDED or T_REMOVED. */
1418 notify_do ('C', finfo->file, getcaller (), NULL, NULL, finfo->repository);
1423 /* on failure, remove the file from ulist */
1424 p = findnode (ulist, finfo->file);
1430 /* On success, retrieve the new version number of the file and
1431 copy it into the log information (see logmsg.c
1432 (logfile_write) for more details). We should only update
1433 the version number for files that have been added or
1434 modified but not removed since classify_file_internal
1435 will return the version number of a file even after it has
1436 been removed from the archive, which is not the behavior we
1437 want for our commitlog messages; we want the old version
1438 number and then "NONE." */
1440 if (ci->status != T_REMOVED)
1442 p = findnode (ulist, finfo->file);
1446 struct logfile_info *li;
1448 (void) classify_file_internal (finfo, &vers);
1450 li->rev_new = xstrdup (vers->vn_rcs);
1451 freevers_ts (&vers);
1455 if (SIG_inCrSect ())
1464 * Log the commit and clean up the update list
1468 commit_filesdoneproc (callerdat, err, repository, update_dir, entries)
1471 const char *repository;
1472 const char *update_dir;
1478 p = findnode (mulist, update_dir);
1482 ulist = ((struct master_lists *) p->data)->ulist;
1486 Update_Logfile (repository, saved_message, (FILE *) 0, ulist);
1488 /* Build the administrative files if necessary. */
1492 if (strncmp (current_parsed_root->directory, repository,
1493 strlen (current_parsed_root->directory)) != 0)
1495 "internal error: repository (%s) doesn't begin with root (%s)",
1496 repository, current_parsed_root->directory);
1497 p = repository + strlen (current_parsed_root->directory);
1500 if (strcmp ("CVSROOT", p) == 0
1501 /* Check for subdirectories because people may want to create
1502 subdirectories and list files therein in checkoutlist. */
1503 || strncmp ("CVSROOT/", p, strlen ("CVSROOT/")) == 0
1506 /* "Database" might a little bit grandiose and/or vague,
1507 but "checked-out copies of administrative files, unless
1508 in the case of modules and you are using ndbm in which
1509 case modules.{pag,dir,db}" is verbose and excessively
1510 focused on how the database is implemented. */
1512 /* mkmodules requires the absolute name of the CVSROOT directory.
1513 Remove anything after the `CVSROOT' component -- this is
1514 necessary when committing in a subdirectory of CVSROOT. */
1515 char *admin_dir = xstrdup (repository);
1516 int cvsrootlen = strlen ("CVSROOT");
1517 assert (admin_dir[p - repository + cvsrootlen] == '\0'
1518 || admin_dir[p - repository + cvsrootlen] == '/');
1519 admin_dir[p - repository + cvsrootlen] = '\0';
1521 cvs_output (program_name, 0);
1522 cvs_output (" ", 1);
1523 cvs_output (cvs_cmd_name, 0);
1524 cvs_output (": Rebuilding administrative file database\n", 0);
1525 mkmodules (admin_dir);
1536 * Get the log message for a dir
1540 commit_direntproc (callerdat, dir, repos, update_dir, entries)
1544 const char *update_dir;
1554 /* find the update list for this dir */
1555 p = findnode (mulist, update_dir);
1557 ulist = ((struct master_lists *) p->data)->ulist;
1559 ulist = (List *) NULL;
1561 /* skip the files as an optimization */
1562 if (ulist == NULL || ulist->list->next == ulist->list)
1563 return R_SKIP_FILES;
1565 /* get commit message */
1566 real_repos = Name_Repository (dir, update_dir);
1569 #ifdef SERVER_SUPPORT
1573 do_editor (update_dir, &saved_message, real_repos, ulist);
1574 do_verify (&saved_message, real_repos);
1582 * Process the post-commit proc if necessary
1586 commit_dirleaveproc (callerdat, dir, err, update_dir, entries)
1590 const char *update_dir;
1593 /* update the per-directory tag info */
1594 /* FIXME? Why? The "commit examples" node of cvs.texinfo briefly
1595 mentions commit -r being sticky, but apparently in the context of
1596 this being a confusing feature! */
1597 if (err == 0 && write_dirtag != NULL)
1599 char *repos = Name_Repository (NULL, update_dir);
1600 WriteTag (NULL, write_dirtag, NULL, write_dirnonbranch,
1611 * find the maximum major rev number in an entries file
1614 findmaxrev (p, closure)
1619 Entnode *entdata = p->data;
1621 if (entdata->type != ENT_FILE)
1623 thisrev = atoi (entdata->version);
1624 if (thisrev > maxrev)
1630 * Actually remove a file by moving it to the attic
1631 * XXX - if removing a ,v file that is a relative symbolic link to
1632 * another ,v file, we probably should add a ".." component to the
1633 * link to keep it relative after we move it into the attic.
1635 Return value is 0 on success, or >0 on error (in which case we have
1636 printed an error message). */
1638 remove_file (finfo, tag, message)
1639 struct file_info *finfo;
1658 if (finfo->rcs == NULL)
1659 error (1, 0, "internal error: no parsed RCS file");
1662 if (tag && !(branch = RCS_nodeisbranch (finfo->rcs, tag)))
1664 /* a symbolic tag is specified; just remove the tag from the file */
1665 if ((retcode = RCS_deltag (finfo->rcs, tag)) != 0)
1668 error (0, retcode == -1 ? errno : 0,
1669 "failed to remove tag `%s' from `%s'", tag,
1673 RCS_rewrite (finfo->rcs, NULL, NULL);
1674 Scratch_Entry (finfo->entries, finfo->file);
1678 /* we are removing the file from either the head or a branch */
1679 /* commit a new, dead revision. */
1681 /* Print message indicating that file is going to be removed. */
1682 cvs_output ("Removing ", 0);
1683 cvs_output (finfo->fullname, 0);
1684 cvs_output (";\n", 0);
1692 rev = RCS_whatbranch (finfo->rcs, tag);
1695 error (0, 0, "cannot find branch \"%s\".", tag);
1699 branchname = RCS_getbranch (finfo->rcs, rev, 1);
1700 if (branchname == NULL)
1702 /* no revision exists on this branch. use the previous
1703 revision but do not lock. */
1704 corev = RCS_gettag (finfo->rcs, tag, 1, (int *) NULL);
1705 prev_rev = xstrdup (corev);
1709 corev = xstrdup (rev);
1710 prev_rev = xstrdup (branchname);
1714 } else /* Not a branch */
1716 /* Get current head revision of file. */
1717 prev_rev = RCS_head (finfo->rcs);
1720 /* if removing without a tag or a branch, then make sure the default
1721 branch is the trunk. */
1722 if (!tag && !branch)
1724 if (RCS_setbranch (finfo->rcs, NULL) != 0)
1726 error (0, 0, "cannot change branch to default for %s",
1730 RCS_rewrite (finfo->rcs, NULL, NULL);
1733 /* check something out. Generally this is the head. If we have a
1734 particular rev, then name it. */
1735 retcode = RCS_checkout (finfo->rcs, finfo->file, rev ? corev : NULL,
1736 (char *) NULL, (char *) NULL, RUN_TTY,
1737 (RCSCHECKOUTPROC) NULL, (void *) NULL);
1741 "failed to check out `%s'", finfo->fullname);
1745 /* Except when we are creating a branch, lock the revision so that
1746 we can check in the new revision. */
1749 if (RCS_lock (finfo->rcs, rev ? corev : NULL, 1) == 0)
1750 RCS_rewrite (finfo->rcs, NULL, NULL);
1756 retcode = RCS_checkin (finfo->rcs, finfo->file, message, rev,
1757 RCS_FLAGS_DEAD | RCS_FLAGS_QUIET);
1761 error (0, retcode == -1 ? errno : 0,
1762 "failed to commit dead revision for `%s'", finfo->fullname);
1765 /* At this point, the file has been committed as removed. We should
1766 probably tell the history file about it */
1767 history_write ('R', NULL, finfo->rcs->head, finfo->file, finfo->repository);
1772 old_path = xstrdup (finfo->rcs->path);
1774 RCS_setattic (finfo->rcs, 1);
1776 /* Print message that file was removed. */
1777 cvs_output (old_path, 0);
1778 cvs_output (" <-- ", 0);
1779 cvs_output (finfo->file, 0);
1780 cvs_output ("\nnew revision: delete; previous revision: ", 0);
1781 cvs_output (prev_rev, 0);
1782 cvs_output ("\ndone\n", 0);
1787 Scratch_Entry (finfo->entries, finfo->file);
1794 * Do the actual checkin for added files
1797 finaladd (finfo, rev, tag, options)
1798 struct file_info *finfo;
1805 ret = Checkin ('A', finfo, rev, tag, options, saved_message);
1808 char *tmp = xmalloc (strlen (finfo->file) + sizeof (CVSADM)
1809 + sizeof (CVSEXT_LOG) + 10);
1810 (void) sprintf (tmp, "%s/%s%s", CVSADM, finfo->file, CVSEXT_LOG);
1811 if (unlink_file (tmp) < 0
1812 && !existence_error (errno))
1813 error (0, errno, "cannot remove %s", tmp);
1816 else if (finfo->rcs != NULL)
1817 fixaddfile (finfo->rcs->path);
1819 (void) time (&last_register_time);
1827 * Unlock an rcs file
1835 if ((retcode = RCS_unlock (rcs, NULL, 1)) != 0)
1836 error (retcode == -1 ? 1 : 0, retcode == -1 ? errno : 0,
1837 "could not unlock %s", rcs->path);
1839 RCS_rewrite (rcs, NULL, NULL);
1845 * remove a partially added file. if we can parse it, leave it alone.
1847 * FIXME: Every caller that calls this function can access finfo->rcs (the
1848 * parsed RCSNode data), so we should be able to detect that the file needs
1849 * to be removed without reparsing the file as we do below.
1856 int save_really_quiet;
1858 save_really_quiet = really_quiet;
1860 if ((rcsfile = RCS_parsercsfile (rcs)) == NULL)
1862 if (unlink_file (rcs) < 0)
1863 error (0, errno, "cannot remove %s", rcs);
1866 freercsnode (&rcsfile);
1867 really_quiet = save_really_quiet;
1873 * put the branch back on an rcs file
1876 fixbranch (rcs, branch)
1884 if ((retcode = RCS_setbranch (rcs, branch)) != 0)
1885 error (retcode == -1 ? 1 : 0, retcode == -1 ? errno : 0,
1886 "cannot restore branch to %s for %s", branch, rcs->path);
1887 RCS_rewrite (rcs, NULL, NULL);
1894 * do the initial part of a file add for the named file. if adding
1895 * with a tag, put the file in the Attic and point the symbolic tag
1896 * at the committed revision.
1899 * file The name of the file in the workspace.
1900 * repository The repository directory to expect to find FILE,v in.
1901 * tag The name or rev num of the branch being added to, if any.
1902 * options Any RCS keyword expansion options specified by the user.
1903 * rcsnode A pointer to the pre-parsed RCSNode for this file, if the file
1904 * exists in the repository. If this is NULL, assume the file
1905 * does not yet exist.
1909 * 1 on errors, after printing any appropriate error messages.
1912 * This function will return an error when any of the following functions do:
1917 * RCS_parse (called to verify the newly created archive file)
1922 checkaddfile (file, repository, tag, options, rcsnode)
1924 const char *repository;
1926 const char *options;
1931 int newfile = 0; /* Set to 1 if we created a new RCS archive. */
1933 int adding_on_branch;
1935 assert (rcsnode != NULL);
1937 /* Callers expect to be able to use either "" or NULL to mean the
1938 default keyword expansion. */
1939 if (options != NULL && options[0] == '\0')
1941 if (options != NULL)
1942 assert (options[0] == '-' && options[1] == 'k');
1944 /* If numeric, it is on the trunk; check_fileproc enforced
1946 adding_on_branch = tag != NULL && !isdigit ((unsigned char) tag[0]);
1948 if (*rcsnode == NULL)
1952 size_t descalloc = 0;
1956 if ( adding_on_branch )
1959 rcsname = xmalloc (strlen (repository)
1964 (void) sprintf (rcsname, "%s/%s", repository, CVSATTIC);
1965 omask = umask ( cvsumask );
1966 if (CVS_MKDIR (rcsname, 0777 ) != 0 && errno != EEXIST)
1967 error (1, errno, "cannot make directory `%s'", rcsname);
1968 (void) umask ( omask );
1969 (void) sprintf (rcsname,
1978 rcsname = xmalloc (strlen (repository)
1982 (void) sprintf (rcsname,
1989 /* this is the first time we have ever seen this file; create
1991 fname = xmalloc (strlen (file) + sizeof (CVSADM)
1992 + sizeof (CVSEXT_LOG) + 10);
1993 (void) sprintf (fname, "%s/%s%s", CVSADM, file, CVSEXT_LOG);
1994 /* If the file does not exist, no big deal. In particular, the
1995 server does not (yet at least) create CVSEXT_LOG files. */
1997 /* FIXME: Should be including update_dir in the appropriate
1999 get_file (fname, fname, "r", &desc, &descalloc, &desclen);
2002 /* From reading the RCS 5.7 source, "rcs -i" adds a newline to the
2003 end of the log message if the message is nonempty.
2004 Do it. RCS also deletes certain whitespace, in cleanlogmsg,
2005 which we don't try to do here. */
2008 expand_string (&desc, &descalloc, desclen + 1);
2009 desc[desclen++] = '\012';
2012 /* Set RCS keyword expansion options. */
2013 if (options != NULL)
2018 /* This message is an artifact of the time when this
2019 was implemented via "rcs -i". It should be revised at
2020 some point (does the "initial revision" in the message from
2021 RCS_checkin indicate that this is a new file? Or does the
2022 "RCS file" message serve some function?). */
2023 cvs_output ("RCS file: ", 0);
2024 cvs_output (rcsname, 0);
2025 cvs_output ("\ndone\n", 0);
2027 if (add_rcs_file (NULL, rcsname, file, NULL, opt,
2028 NULL, NULL, 0, NULL,
2029 desc, desclen, NULL) != 0)
2031 if (rcsname != NULL)
2035 rcs = RCS_parsercsfile (rcsname);
2037 if (rcsname != NULL)
2045 /* file has existed in the past. Prepare to resurrect. */
2051 oldexpand = RCS_getexpand (rcs);
2052 if ((oldexpand != NULL
2054 && strcmp (options + 2, oldexpand) != 0)
2055 || (oldexpand == NULL && options != NULL))
2057 /* We tell the user about this, because it means that the
2058 old revisions will no longer retrieve the way that they
2060 error (0, 0, "changing keyword expansion mode to %s", options);
2061 RCS_setexpand (rcs, options + 2);
2064 if (!adding_on_branch)
2066 /* We are adding on the trunk, so move the file out of the
2068 if (!(rcs->flags & INATTIC))
2070 error (0, 0, "warning: expected %s to be in Attic",
2074 /* Begin a critical section around the code that spans the
2075 first commit on the trunk of a file that's already been
2076 committed on a branch. */
2079 if (RCS_setattic (rcs, 0))
2085 rev = RCS_getversion (rcs, tag, NULL, 1, (int *) NULL);
2087 if (lock_RCS (file, rcs, rev, repository))
2089 error (0, 0, "cannot lock `%s'.", rcs->path);
2099 /* when adding a file for the first time, and using a tag, we need
2100 to create a dead revision on the trunk. */
2101 if (adding_on_branch)
2109 /* move the new file out of the way. */
2110 fname = xmalloc (strlen (file) + sizeof (CVSADM)
2111 + sizeof (CVSPREFIX) + 10);
2112 (void) sprintf (fname, "%s/%s%s", CVSADM, CVSPREFIX, file);
2113 rename_file (file, fname);
2115 /* Create empty FILE. Can't use copy_file with a DEVNULL
2116 argument -- copy_file now ignores device files. */
2117 fp = fopen (file, "w");
2119 error (1, errno, "cannot open %s for writing", file);
2120 if (fclose (fp) < 0)
2121 error (0, errno, "cannot close %s", file);
2123 tmp = xmalloc (strlen (file) + strlen (tag) + 80);
2124 /* commit a dead revision. */
2125 (void) sprintf (tmp, "file %s was initially added on branch %s.",
2127 retcode = RCS_checkin (rcs, NULL, tmp, NULL,
2128 RCS_FLAGS_DEAD | RCS_FLAGS_QUIET);
2132 error (retcode == -1 ? 1 : 0, retcode == -1 ? errno : 0,
2133 "could not create initial dead revision %s", rcs->path);
2137 /* put the new file back where it was */
2138 rename_file (fname, file);
2141 /* double-check that the file was written correctly */
2143 rcs = RCS_parse (file, repository);
2146 error (0, 0, "could not read %s", rcs->path);
2151 /* and lock it once again. */
2152 if (lock_RCS (file, rcs, NULL, repository))
2154 error (0, 0, "cannot lock `%s'.", rcs->path);
2159 /* when adding with a tag, we need to stub a branch, if it
2160 doesn't already exist. */
2161 if (!RCS_nodeisbranch (rcs, tag))
2163 /* branch does not exist. Stub it. */
2168 fixbranch (rcs, sbranch);
2170 head = RCS_getversion (rcs, NULL, NULL, 0, (int *) NULL);
2171 magicrev = RCS_magicrev (rcs, head);
2173 retcode = RCS_settag (rcs, tag, magicrev);
2174 RCS_rewrite (rcs, NULL, NULL);
2181 error (retcode == -1 ? 1 : 0, retcode == -1 ? errno : 0,
2182 "could not stub branch %s for %s", tag, rcs->path);
2188 /* lock the branch. (stubbed branches need not be locked.) */
2189 if (lock_RCS (file, rcs, NULL, repository))
2191 error (0, 0, "cannot lock `%s'.", rcs->path);
2196 if (*rcsnode != rcs)
2198 freercsnode(rcsnode);
2203 fileattr_newfile (file);
2205 /* At this point, we used to set the file mode of the RCS file
2206 based on the mode of the file in the working directory. If we
2207 are creating the RCS file for the first time, add_rcs_file does
2208 this already. If we are re-adding the file, then perhaps it is
2209 consistent to preserve the old file mode, just as we preserve
2210 the old keyword expansion mode.
2212 If we decide that we should change the modes, then we can't do
2213 it here anyhow. At this point, the RCS file may be owned by
2214 somebody else, so a chmod will fail. We need to instead do the
2215 chmod after rewriting it.
2217 FIXME: In general, I think the file mode (and the keyword
2218 expansion mode) should be associated with a particular revision
2219 of the file, so that it is possible to have different revisions
2220 of a file have different modes. */
2225 if (retval != 0 && SIG_inCrSect ())
2233 * Attempt to place a lock on the RCS file; returns 0 if it could and 1 if it
2234 * couldn't. If the RCS file currently has a branch as the head, we must
2235 * move the head back to the trunk before locking the file, and be sure to
2236 * put the branch back as the head if there are any errors.
2239 lock_RCS (user, rcs, rev, repository)
2243 const char *repository;
2245 char *branch = NULL;
2249 * For a specified, numeric revision of the form "1" or "1.1", (or when
2250 * no revision is specified ""), definitely move the branch to the trunk
2251 * before locking the RCS file.
2253 * The assumption is that if there is more than one revision on the trunk,
2254 * the head points to the trunk, not a branch... and as such, it's not
2255 * necessary to move the head in this case.
2258 || (rev && isdigit ((unsigned char) *rev) && numdots (rev) < 2))
2260 branch = xstrdup (rcs->branch);
2263 if (RCS_setbranch (rcs, NULL) != 0)
2265 error (0, 0, "cannot change branch to default for %s",
2272 err = RCS_lock (rcs, NULL, 1);
2276 RCS_lock (rcs, rev, 1);
2279 /* We used to call RCS_rewrite here, and that might seem
2280 appropriate in order to write out the locked revision
2281 information. However, such a call would actually serve no
2282 purpose. CVS locks will prevent any interference from other
2283 CVS processes. The comment above rcs_internal_lockfile
2284 explains that it is already unsafe to use RCS and CVS
2285 simultaneously. It follows that writing out the locked
2286 revision information here would add no additional security.
2288 If we ever do care about it, the proper fix is to create the
2289 RCS lock file before calling this function, and maintain it
2290 until the checkin is complete.
2292 The call to RCS_lock is still required at present, since in
2293 some cases RCS_checkin will determine which revision to check
2294 in by looking for a lock. FIXME: This is rather roundabout,
2295 and a more straightforward approach would probably be easier to
2300 if (sbranch != NULL)
2306 /* try to restore the branch if we can on error */
2308 fixbranch (rcs, branch);
2318 * free an UPDATE node's data
2324 struct logfile_info *li = p->data;
2336 * Free the commit_info structure in p.
2342 struct commit_info *ci = p->data;
2354 * Free the commit_info structure in p.
2357 masterlist_delproc (p)
2360 struct master_lists *ml = p->data;
2362 dellist (&ml->ulist);
2363 dellist (&ml->cilist);