xref: /openbsd/gnu/usr.bin/cvs/src/commit.c (revision 3cab2bb3)
1 /*
2  * Copyright (c) 1992, Brian Berliner and Jeff Polk
3  * Copyright (c) 1989-1992, Brian Berliner
4  *
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.
7  *
8  * Commit Files
9  *
10  * "commit" commits the present version to the RCS repository, AFTER
11  * having done a test on conflicts.
12  *
13  * The call is: cvs commit [options] files...
14  *
15  */
16 
17 #include <assert.h>
18 #include "cvs.h"
19 #include "getline.h"
20 #include "edit.h"
21 #include "fileattr.h"
22 #include "hardlink.h"
23 
24 static Dtype check_direntproc PROTO ((void *callerdat, char *dir,
25 				      char *repos, char *update_dir,
26 				      List *entries));
27 static int check_fileproc PROTO ((void *callerdat, struct file_info *finfo));
28 static int check_filesdoneproc PROTO ((void *callerdat, int err,
29 				       char *repos, char *update_dir,
30 				       List *entries));
31 static int checkaddfile PROTO((char *file, char *repository, char *tag,
32 			       char *options, RCSNode **rcsnode));
33 static Dtype commit_direntproc PROTO ((void *callerdat, char *dir,
34 				       char *repos, char *update_dir,
35 				       List *entries));
36 static int commit_dirleaveproc PROTO ((void *callerdat, char *dir,
37 				       int err, char *update_dir,
38 				       List *entries));
39 static int commit_fileproc PROTO ((void *callerdat, struct file_info *finfo));
40 static int commit_filesdoneproc PROTO ((void *callerdat, int err,
41 					char *repository, char *update_dir,
42 					List *entries));
43 static int finaladd PROTO((struct file_info *finfo, char *revision, char *tag,
44 			   char *options));
45 static int findmaxrev PROTO((Node * p, void *closure));
46 static int lock_RCS PROTO((char *user, RCSNode *rcs, char *rev,
47 			   char *repository));
48 static int precommit_list_proc PROTO((Node * p, void *closure));
49 static int precommit_proc PROTO((char *repository, char *filter));
50 static int remove_file PROTO ((struct file_info *finfo, char *tag,
51 			       char *message));
52 static void fixaddfile PROTO((char *file, char *repository));
53 static void fixbranch PROTO((RCSNode *, char *branch));
54 static void unlockrcs PROTO((RCSNode *rcs));
55 static void ci_delproc PROTO((Node *p));
56 static void masterlist_delproc PROTO((Node *p));
57 static char *locate_rcs PROTO((char *file, char *repository));
58 
59 struct commit_info
60 {
61     Ctype status;			/* as returned from Classify_File() */
62     char *rev;				/* a numeric rev, if we know it */
63     char *tag;				/* any sticky tag, or -r option */
64     char *options;			/* Any sticky -k option */
65 };
66 struct master_lists
67 {
68     List *ulist;			/* list for Update_Logfile */
69     List *cilist;			/* list with commit_info structs */
70 };
71 
72 static int force_ci = 0;
73 static int got_message;
74 static int run_module_prog = 1;
75 static int aflag;
76 static char *saved_tag;
77 static char *write_dirtag;
78 static int write_dirnonbranch;
79 static char *logfile;
80 static List *mulist;
81 static List *saved_ulist;
82 static char *saved_message;
83 static time_t last_register_time;
84 
85 static const char *const commit_usage[] =
86 {
87     "Usage: %s %s [-nRlf] [-m msg | -F logfile] [-r rev] files...\n",
88     "    -n          Do not run the module program (if any).\n",
89     "    -R          Process directories recursively.\n",
90     "    -l          Local directory only (not recursive).\n",
91     "    -f          Force the file to be committed; disables recursion.\n",
92     "    -F logfile  Read the log message from file.\n",
93     "    -m msg      Log message.\n",
94     "    -r rev      Commit to this branch or trunk revision.\n",
95     "(Specify the --help global option for a list of other help options)\n",
96     NULL
97 };
98 
99 #ifdef CLIENT_SUPPORT
100 /* Identify a file which needs "? foo" or a Questionable request.  */
101 struct question {
102     /* The two fields for the Directory request.  */
103     char *dir;
104     char *repos;
105 
106     /* The file name.  */
107     char *file;
108 
109     struct question *next;
110 };
111 
112 struct find_data {
113     List *ulist;
114     int argc;
115     char **argv;
116 
117     /* This is used from dirent to filesdone time, for each directory,
118        to make a list of files we have already seen.  */
119     List *ignlist;
120 
121     /* Linked list of files which need "? foo" or a Questionable request.  */
122     struct question *questionables;
123 
124     /* Only good within functions called from the filesdoneproc.  Stores
125        the repository (pointer into storage managed by the recursion
126        processor.  */
127     char *repository;
128 
129     /* Non-zero if we should force the commit.  This is enabled by
130        either -f or -r options, unlike force_ci which is just -f.  */
131     int force;
132 };
133 
134 static Dtype find_dirent_proc PROTO ((void *callerdat, char *dir,
135 				      char *repository, char *update_dir,
136 				      List *entries));
137 
138 static Dtype
139 find_dirent_proc (callerdat, dir, repository, update_dir, entries)
140     void *callerdat;
141     char *dir;
142     char *repository;
143     char *update_dir;
144     List *entries;
145 {
146     struct find_data *find_data = (struct find_data *)callerdat;
147 
148     /* This check seems to slowly be creeping throughout CVS (update
149        and send_dirent_proc by CVS 1.5, diff in 31 Oct 1995.  My guess
150        is that it (or some variant thereof) should go in all the
151        dirent procs.  Unless someone has some better idea...  */
152     if (!isdir (dir))
153 	return (R_SKIP_ALL);
154 
155     /* initialize the ignore list for this directory */
156     find_data->ignlist = getlist ();
157 
158     /* Print the same warm fuzzy as in check_direntproc, since that
159        code will never be run during client/server operation and we
160        want the messages to match. */
161     if (!quiet)
162 	error (0, 0, "Examining %s", update_dir);
163 
164     return R_PROCESS;
165 }
166 
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;
170 
171 static void find_ignproc PROTO ((char *, char *));
172 
173 static void
174 find_ignproc (file, dir)
175     char *file;
176     char *dir;
177 {
178     struct question *p;
179 
180     p = (struct question *) xmalloc (sizeof (struct question));
181     p->dir = xstrdup (dir);
182     p->repos = xstrdup (find_data_static->repository);
183     p->file = xstrdup (file);
184     p->next = find_data_static->questionables;
185     find_data_static->questionables = p;
186 }
187 
188 static int find_filesdoneproc PROTO ((void *callerdat, int err,
189 				      char *repository, char *update_dir,
190 				      List *entries));
191 
192 static int
193 find_filesdoneproc (callerdat, err, repository, update_dir, entries)
194     void *callerdat;
195     int err;
196     char *repository;
197     char *update_dir;
198     List *entries;
199 {
200     struct find_data *find_data = (struct find_data *)callerdat;
201     find_data->repository = repository;
202 
203     /* if this directory has an ignore list, process it then free it */
204     if (find_data->ignlist)
205     {
206 	find_data_static = find_data;
207 	ignore_files (find_data->ignlist, entries, update_dir, find_ignproc);
208 	dellist (&find_data->ignlist);
209     }
210 
211     find_data->repository = NULL;
212 
213     return err;
214 }
215 
216 static int find_fileproc PROTO ((void *callerdat, struct file_info *finfo));
217 
218 /* Machinery to find out what is modified, added, and removed.  It is
219    possible this should be broken out into a new client_classify function;
220    merging it with classify_file is almost sure to be a mess, though,
221    because classify_file has all kinds of repository processing.  */
222 static int
223 find_fileproc (callerdat, finfo)
224     void *callerdat;
225     struct file_info *finfo;
226 {
227     Vers_TS *vers;
228     enum classify_type status;
229     Node *node;
230     struct find_data *args = (struct find_data *)callerdat;
231     struct logfile_info *data;
232     struct file_info xfinfo;
233 
234     /* if this directory has an ignore list, add this file to it */
235     if (args->ignlist)
236     {
237 	Node *p;
238 
239 	p = getnode ();
240 	p->type = FILES;
241 	p->key = xstrdup (finfo->file);
242 	if (addnode (args->ignlist, p) != 0)
243 	    freenode (p);
244     }
245 
246     xfinfo = *finfo;
247     xfinfo.repository = NULL;
248     xfinfo.rcs = NULL;
249 
250     vers = Version_TS (&xfinfo, NULL, saved_tag, NULL, 0, 0);
251     if (vers->ts_user == NULL
252 	&& vers->vn_user != NULL
253 	&& vers->vn_user[0] == '-')
254 	/* FIXME: If vn_user is starts with "-" but ts_user is
255 	   non-NULL, what classify_file does is print "%s should be
256 	   removed and is still there".  I'm not sure what it does
257 	   then.  We probably should do the same.  */
258 	status = T_REMOVED;
259     else if (vers->vn_user == NULL)
260     {
261 	if (vers->ts_user == NULL)
262 	    error (0, 0, "nothing known about `%s'", finfo->fullname);
263 	else
264 	    error (0, 0, "use `%s add' to create an entry for %s",
265 		   program_name, finfo->fullname);
266 	freevers_ts (&vers);
267 	return 1;
268     }
269     else if (vers->ts_user != NULL
270 	     && vers->vn_user != NULL
271 	     && vers->vn_user[0] == '0')
272 	/* FIXME: If vn_user is "0" but ts_user is NULL, what classify_file
273 	   does is print "new-born %s has disappeared" and removes the entry.
274 	   We probably should do the same.  */
275 	status = T_ADDED;
276     else if (vers->ts_user != NULL
277 	     && vers->ts_rcs != NULL
278 	     && (args->force || strcmp (vers->ts_user, vers->ts_rcs) != 0))
279 	/* If we are forcing commits, pretend that the file is
280            modified.  */
281 	status = T_MODIFIED;
282     else
283     {
284 	/* This covers unmodified files, as well as a variety of other
285 	   cases.  FIXME: we probably should be printing a message and
286 	   returning 1 for many of those cases (but I'm not sure
287 	   exactly which ones).  */
288 	freevers_ts (&vers);
289 	return 0;
290     }
291 
292     node = getnode ();
293     node->key = xstrdup (finfo->fullname);
294 
295     data = (struct logfile_info *) xmalloc (sizeof (struct logfile_info));
296     data->type = status;
297     data->tag = xstrdup (vers->tag);
298     data->rev_old = data->rev_new = NULL;
299 
300     node->type = UPDATE;
301     node->delproc = update_delproc;
302     node->data = (char *) data;
303     (void)addnode (args->ulist, node);
304 
305     ++args->argc;
306 
307     freevers_ts (&vers);
308     return 0;
309 }
310 
311 static int copy_ulist PROTO ((Node *, void *));
312 
313 static int
314 copy_ulist (node, data)
315     Node *node;
316     void *data;
317 {
318     struct find_data *args = (struct find_data *)data;
319     args->argv[args->argc++] = node->key;
320     return 0;
321 }
322 #endif /* CLIENT_SUPPORT */
323 
324 int
325 commit (argc, argv)
326     int argc;
327     char **argv;
328 {
329     int c;
330     int err = 0;
331     int local = 0;
332 
333     if (argc == -1)
334 	usage (commit_usage);
335 
336 #ifdef CVS_BADROOT
337     /*
338      * For log purposes, do not allow "root" to commit files.  If you look
339      * like root, but are really logged in as a non-root user, it's OK.
340      */
341     /* FIXME: Shouldn't this check be much more closely related to the
342        readonly user stuff (CVSROOT/readers, &c).  That is, why should
343        root be able to "cvs init", "cvs import", &c, but not "cvs ci"?  */
344     if (geteuid () == (uid_t) 0
345 #  ifdef CLIENT_SUPPORT
346 	/* Who we are on the client side doesn't affect logging.  */
347 	&& !current_parsed_root->isremote
348 #  endif
349 	)
350     {
351 	struct passwd *pw;
352 
353 	if ((pw = (struct passwd *) getpwnam (getcaller ())) == NULL)
354 	    error (1, 0, "you are unknown to this system");
355 	if (pw->pw_uid == (uid_t) 0)
356 	    error (1, 0, "cannot commit files as 'root'");
357     }
358 #endif /* CVS_BADROOT */
359 
360     optind = 0;
361     while ((c = getopt (argc, argv, "+nlRm:fF:r:")) != -1)
362     {
363 	switch (c)
364 	{
365 	    case 'n':
366 		run_module_prog = 0;
367 		break;
368 	    case 'm':
369 #ifdef FORCE_USE_EDITOR
370 		use_editor = 1;
371 #else
372 		use_editor = 0;
373 #endif
374 		if (saved_message)
375 		{
376 		    free (saved_message);
377 		    saved_message = NULL;
378 		}
379 
380 		saved_message = xstrdup(optarg);
381 		break;
382 	    case 'r':
383 		if (saved_tag)
384 		    free (saved_tag);
385 		saved_tag = xstrdup (optarg);
386 		break;
387 	    case 'l':
388 		local = 1;
389 		break;
390 	    case 'R':
391 		local = 0;
392 		break;
393 	    case 'f':
394 		force_ci = 1;
395 		local = 1;		/* also disable recursion */
396 		break;
397 	    case 'F':
398 #ifdef FORCE_USE_EDITOR
399 		use_editor = 1;
400 #else
401 		use_editor = 0;
402 #endif
403 		logfile = optarg;
404 		break;
405 	    case '?':
406 	    default:
407 		usage (commit_usage);
408 		break;
409 	}
410     }
411     argc -= optind;
412     argv += optind;
413 
414     /* numeric specified revision means we ignore sticky tags... */
415     if (saved_tag && isdigit ((unsigned char) *saved_tag))
416     {
417 	aflag = 1;
418 	/* strip trailing dots */
419 	while (saved_tag[strlen (saved_tag) - 1] == '.')
420 	    saved_tag[strlen (saved_tag) - 1] = '\0';
421     }
422 
423     /* some checks related to the "-F logfile" option */
424     if (logfile)
425     {
426 	size_t size = 0, len;
427 
428 	if (saved_message)
429 	    error (1, 0, "cannot specify both a message and a log file");
430 
431 	get_file (logfile, logfile, "r", &saved_message, &size, &len);
432     }
433 
434 #ifdef CLIENT_SUPPORT
435     if (current_parsed_root->isremote)
436     {
437 	struct find_data find_args;
438 
439 	ign_setup ();
440 
441 	find_args.ulist = getlist ();
442 	find_args.argc = 0;
443 	find_args.questionables = NULL;
444 	find_args.ignlist = NULL;
445 	find_args.repository = NULL;
446 
447 	/* It is possible that only a numeric tag should set this.
448 	   I haven't really thought about it much.
449 	   Anyway, I suspect that setting it unnecessarily only causes
450 	   a little unneeded network traffic.  */
451 	find_args.force = force_ci || saved_tag != NULL;
452 
453 	err = start_recursion (find_fileproc, find_filesdoneproc,
454 			       find_dirent_proc, (DIRLEAVEPROC) NULL,
455 			       (void *)&find_args,
456 			       argc, argv, local, W_LOCAL, 0, 0,
457 			       (char *)NULL, 0);
458 	if (err)
459 	    error (1, 0, "correct above errors first!");
460 
461 	if (find_args.argc == 0)
462 	{
463 	    /* Nothing to commit.  Exit now without contacting the
464 	       server (note that this means that we won't print "?
465 	       foo" for files which merit it, because we don't know
466 	       what is in the CVSROOT/cvsignore file).  */
467 	    dellist (&find_args.ulist);
468 	    return 0;
469 	}
470 
471 	/* Now we keep track of which files we actually are going to
472 	   operate on, and only work with those files in the future.
473 	   This saves time--we don't want to search the file system
474 	   of the working directory twice.  */
475 	if (size_overflow_p (xtimes (find_args.argc, sizeof (char **))))
476 	{
477 	    find_args.argc = 0;
478 	    return 0;
479 	}
480 	find_args.argv = xmalloc (xtimes (find_args.argc, sizeof (char **)));
481 	find_args.argc = 0;
482 	walklist (find_args.ulist, copy_ulist, &find_args);
483 
484 	/* Do this before calling do_editor; don't ask for a log
485 	   message if we can't talk to the server.  But do it after we
486 	   have made the checks that we can locally (to more quickly
487 	   catch syntax errors, the case where no files are modified,
488 	   added or removed, etc.).
489 
490 	   On the other hand, calling start_server before do_editor
491 	   means that we chew up server resources the whole time that
492 	   the user has the editor open (hours or days if the user
493 	   forgets about it), which seems dubious.  */
494 	start_server ();
495 
496 	/*
497 	 * We do this once, not once for each directory as in normal CVS.
498 	 * The protocol is designed this way.  This is a feature.
499 	 */
500 	if (use_editor)
501 	    do_editor (".", &saved_message, (char *)NULL, find_args.ulist);
502 
503 	/* Run the user-defined script to verify/check information in
504 	 *the log message
505 	 */
506 	do_verify (saved_message, (char *)NULL);
507 
508 	/* We always send some sort of message, even if empty.  */
509 	/* FIXME: is that true?  There seems to be some code in do_editor
510 	   which can leave the message NULL.  */
511 	option_with_arg ("-m", saved_message);
512 
513 	/* OK, now process all the questionable files we have been saving
514 	   up.  */
515 	{
516 	    struct question *p;
517 	    struct question *q;
518 
519 	    p = find_args.questionables;
520 	    while (p != NULL)
521 	    {
522 		if (ign_inhibit_server || !supported_request ("Questionable"))
523 		{
524 		    cvs_output ("? ", 2);
525 		    if (p->dir[0] != '\0')
526 		    {
527 			cvs_output (p->dir, 0);
528 			cvs_output ("/", 1);
529 		    }
530 		    cvs_output (p->file, 0);
531 		    cvs_output ("\n", 1);
532 		}
533 		else
534 		{
535 		    send_to_server ("Directory ", 0);
536 		    send_to_server (p->dir[0] == '\0' ? "." : p->dir, 0);
537 		    send_to_server ("\012", 1);
538 		    send_to_server (p->repos, 0);
539 		    send_to_server ("\012", 1);
540 
541 		    send_to_server ("Questionable ", 0);
542 		    send_to_server (p->file, 0);
543 		    send_to_server ("\012", 1);
544 		}
545 		free (p->dir);
546 		free (p->repos);
547 		free (p->file);
548 		q = p->next;
549 		free (p);
550 		p = q;
551 	    }
552 	}
553 
554 	if (local)
555 	    send_arg("-l");
556 	if (force_ci)
557 	    send_arg("-f");
558 	if (!run_module_prog)
559 	    send_arg("-n");
560 	option_with_arg ("-r", saved_tag);
561 
562 	/* FIXME: This whole find_args.force/SEND_FORCE business is a
563 	   kludge.  It would seem to be a server bug that we have to
564 	   say that files are modified when they are not.  This makes
565 	   "cvs commit -r 2" across a whole bunch of files a very slow
566 	   operation (and it isn't documented in cvsclient.texi).  I
567 	   haven't looked at the server code carefully enough to be
568 	   _sure_ why this is needed, but if it is because the "ci"
569 	   program, which we used to call, wanted the file to exist,
570 	   then it would be relatively simple to fix in the server.  */
571 	send_files (find_args.argc, find_args.argv, local, 0,
572 		    find_args.force ? SEND_FORCE : 0);
573 
574 	/* Sending only the names of the files which were modified, added,
575 	   or removed means that the server will only do an up-to-date
576 	   check on those files.  This is different from local CVS and
577 	   previous versions of client/server CVS, but it probably is a Good
578 	   Thing, or at least Not Such A Bad Thing.  */
579 	send_file_names (find_args.argc, find_args.argv, 0);
580 	free (find_args.argv);
581 	dellist (&find_args.ulist);
582 
583 	send_to_server ("ci\012", 0);
584 	err = get_responses_and_close ();
585 	if (err != 0 && use_editor && saved_message != NULL)
586 	{
587 	    /* If there was an error, don't nuke the user's carefully
588 	       constructed prose.  This is something of a kludge; a better
589 	       solution is probably more along the lines of #150 in TODO
590 	       (doing a second up-to-date check before accepting the
591 	       log message has also been suggested, but that seems kind of
592 	       iffy because the real up-to-date check could still fail,
593 	       another error could occur, &c.  Also, a second check would
594 	       slow things down).  */
595 
596 	    char *fname;
597 	    FILE *fp;
598 
599 	    fp = cvs_temp_file (&fname);
600 	    if (fp == NULL)
601 		error (1, 0, "cannot create temporary file %s", fname);
602 	    if (fwrite (saved_message, 1, strlen (saved_message), fp)
603 		!= strlen (saved_message))
604 		error (1, errno, "cannot write temporary file %s", fname);
605 	    if (fclose (fp) < 0)
606 		error (0, errno, "cannot close temporary file %s", fname);
607 	    error (0, 0, "saving log message in %s", fname);
608 	    free (fname);
609 	}
610 	return err;
611     }
612 #endif
613 
614     if (saved_tag != NULL)
615 	tag_check_valid (saved_tag, argc, argv, local, aflag, "");
616 
617     /* XXX - this is not the perfect check for this */
618     if (argc <= 0)
619 	write_dirtag = saved_tag;
620 
621     wrap_setup ();
622 
623     lock_tree_for_write (argc, argv, local, W_LOCAL, aflag);
624 
625     /*
626      * Set up the master update list and hard link list
627      */
628     mulist = getlist ();
629 
630 #ifdef PRESERVE_PERMISSIONS_SUPPORT
631     if (preserve_perms)
632     {
633 	hardlist = getlist ();
634 
635 	/*
636 	 * We need to save the working directory so that
637 	 * check_fileproc can construct a full pathname for each file.
638 	 */
639 	working_dir = xgetwd();
640     }
641 #endif
642 
643     /*
644      * Run the recursion processor to verify the files are all up-to-date
645      */
646     err = start_recursion (check_fileproc, check_filesdoneproc,
647 			   check_direntproc, (DIRLEAVEPROC) NULL, NULL, argc,
648 			   argv, local, W_LOCAL, aflag, 0, (char *) NULL, 1);
649     if (err)
650     {
651 	Lock_Cleanup ();
652 	error (1, 0, "correct above errors first!");
653     }
654 
655     /*
656      * Run the recursion processor to commit the files
657      */
658     write_dirnonbranch = 0;
659     if (noexec == 0)
660 	err = start_recursion (commit_fileproc, commit_filesdoneproc,
661 			       commit_direntproc, commit_dirleaveproc, NULL,
662 			       argc, argv, local, W_LOCAL, aflag, 0,
663 			       (char *) NULL, 1);
664 
665     /*
666      * Unlock all the dirs and clean up
667      */
668     Lock_Cleanup ();
669     dellist (&mulist);
670 
671 #ifdef SERVER_SUPPORT
672     if (server_active)
673 	return err;
674 #endif
675 
676     /* see if we need to sleep before returning to avoid time-stamp races */
677     if (last_register_time)
678     {
679 	sleep_past (last_register_time);
680     }
681 
682     return (err);
683 }
684 
685 /* This routine determines the status of a given file and retrieves
686    the version information that is associated with that file. */
687 
688 static
689 Ctype
690 classify_file_internal (finfo, vers)
691     struct file_info *finfo;
692     Vers_TS **vers;
693 {
694     int save_noexec, save_quiet, save_really_quiet;
695     Ctype status;
696 
697     /* FIXME: Do we need to save quiet as well as really_quiet?  Last
698        time I glanced at Classify_File I only saw it looking at really_quiet
699        not quiet.  */
700     save_noexec = noexec;
701     save_quiet = quiet;
702     save_really_quiet = really_quiet;
703     noexec = quiet = really_quiet = 1;
704 
705     /* handle specified numeric revision specially */
706     if (saved_tag && isdigit ((unsigned char) *saved_tag))
707     {
708 	/* If the tag is for the trunk, make sure we're at the head */
709 	if (numdots (saved_tag) < 2)
710 	{
711 	    status = Classify_File (finfo, (char *) NULL, (char *) NULL,
712 				    (char *) NULL, 1, aflag, vers, 0);
713 	    if (status == T_UPTODATE || status == T_MODIFIED ||
714 		status == T_ADDED)
715 	    {
716 		Ctype xstatus;
717 
718 		freevers_ts (vers);
719 		xstatus = Classify_File (finfo, saved_tag, (char *) NULL,
720 					 (char *) NULL, 1, aflag, vers, 0);
721 		if (xstatus == T_REMOVE_ENTRY)
722 		    status = T_MODIFIED;
723 		else if (status == T_MODIFIED && xstatus == T_CONFLICT)
724 		    status = T_MODIFIED;
725 		else
726 		    status = xstatus;
727 	    }
728 	}
729 	else
730 	{
731 	    char *xtag, *cp;
732 
733 	    /*
734 	     * The revision is off the main trunk; make sure we're
735 	     * up-to-date with the head of the specified branch.
736 	     */
737 	    xtag = xstrdup (saved_tag);
738 	    if ((numdots (xtag) & 1) != 0)
739 	    {
740 		cp = strrchr (xtag, '.');
741 		*cp = '\0';
742 	    }
743 	    status = Classify_File (finfo, xtag, (char *) NULL,
744 				    (char *) NULL, 1, aflag, vers, 0);
745 	    if ((status == T_REMOVE_ENTRY || status == T_CONFLICT)
746 		&& (cp = strrchr (xtag, '.')) != NULL)
747 	    {
748 		/* pluck one more dot off the revision */
749 		*cp = '\0';
750 		freevers_ts (vers);
751 		status = Classify_File (finfo, xtag, (char *) NULL,
752 					(char *) NULL, 1, aflag, vers, 0);
753 		if (status == T_UPTODATE || status == T_REMOVE_ENTRY)
754 		    status = T_MODIFIED;
755 	    }
756 	    /* now, muck with vers to make the tag correct */
757 	    free ((*vers)->tag);
758 	    (*vers)->tag = xstrdup (saved_tag);
759 	    free (xtag);
760 	}
761     }
762     else
763 	status = Classify_File (finfo, saved_tag, (char *) NULL, (char *) NULL,
764 				1, 0, vers, 0);
765     noexec = save_noexec;
766     quiet = save_quiet;
767     really_quiet = save_really_quiet;
768 
769     return status;
770 }
771 
772 /*
773  * Check to see if a file is ok to commit and make sure all files are
774  * up-to-date
775  */
776 /* ARGSUSED */
777 static int
778 check_fileproc (callerdat, finfo)
779     void *callerdat;
780     struct file_info *finfo;
781 {
782     Ctype status;
783     char *xdir;
784     Node *p;
785     List *ulist, *cilist;
786     Vers_TS *vers;
787     struct commit_info *ci;
788     struct logfile_info *li;
789 
790     size_t cvsroot_len = strlen (current_parsed_root->directory);
791 
792     if (!finfo->repository)
793     {
794 	error (0, 0, "nothing known about `%s'", finfo->fullname);
795 	return (1);
796     }
797 
798     if (strncmp (finfo->repository, current_parsed_root->directory, cvsroot_len) == 0
799 	&& ISDIRSEP (finfo->repository[cvsroot_len])
800 	&& strncmp (finfo->repository + cvsroot_len + 1,
801 		    CVSROOTADM,
802 		    sizeof (CVSROOTADM) - 1) == 0
803 	&& ISDIRSEP (finfo->repository[cvsroot_len + sizeof (CVSROOTADM)])
804 	&& strcmp (finfo->repository + cvsroot_len + sizeof (CVSROOTADM) + 1,
805 		   CVSNULLREPOS) == 0
806 	)
807 	error (1, 0, "cannot check in to %s", finfo->repository);
808 
809     status = classify_file_internal (finfo, &vers);
810 
811     /*
812      * If the force-commit option is enabled, and the file in question
813      * appears to be up-to-date, just make it look modified so that
814      * it will be committed.
815      */
816     if (force_ci && status == T_UPTODATE)
817 	status = T_MODIFIED;
818 
819     switch (status)
820     {
821 	case T_CHECKOUT:
822 	case T_PATCH:
823 	case T_NEEDS_MERGE:
824 	case T_CONFLICT:
825 	case T_REMOVE_ENTRY:
826 	    error (0, 0, "Up-to-date check failed for `%s'", finfo->fullname);
827 	    freevers_ts (&vers);
828 	    return (1);
829 	case T_MODIFIED:
830 	case T_ADDED:
831 	case T_REMOVED:
832 	    /*
833 	     * some quick sanity checks; if no numeric -r option specified:
834 	     *	- can't have a sticky date
835 	     *	- can't have a sticky tag that is not a branch
836 	     * Also,
837 	     *	- if status is T_REMOVED, can't have a numeric tag
838 	     *	- if status is T_ADDED, rcs file must not exist unless on
839 	     *    a branch or head is dead
840 	     *	- if status is T_ADDED, can't have a non-trunk numeric rev
841 	     *	- if status is T_MODIFIED and a Conflict marker exists, don't
842 	     *    allow the commit if timestamp is identical or if we find
843 	     *    an RCS_MERGE_PAT in the file.
844 	     */
845 	    if (!saved_tag || !isdigit ((unsigned char) *saved_tag))
846 	    {
847 		if (vers->date)
848 		{
849 		    error (0, 0,
850 			   "cannot commit with sticky date for file `%s'",
851 			   finfo->fullname);
852 		    freevers_ts (&vers);
853 		    return (1);
854 		}
855 		if (status == T_MODIFIED && vers->tag &&
856 		    !RCS_isbranch (finfo->rcs, vers->tag))
857 		{
858 		    error (0, 0,
859 			   "sticky tag `%s' for file `%s' is not a branch",
860 			   vers->tag, finfo->fullname);
861 		    freevers_ts (&vers);
862 		    return (1);
863 		}
864 	    }
865 	    if (status == T_MODIFIED && !force_ci && vers->ts_conflict)
866 	    {
867 		char *filestamp;
868 		int retcode;
869 
870 		/*
871 		 * We found a "conflict" marker.
872 		 *
873 		 * If the timestamp on the file is the same as the
874 		 * timestamp stored in the Entries file, we block the commit.
875 		 */
876 #ifdef SERVER_SUPPORT
877 		if (server_active)
878 		    retcode = vers->ts_conflict[0] != '=';
879 		else {
880 		    filestamp = time_stamp (finfo->file);
881 		    retcode = strcmp (vers->ts_conflict, filestamp);
882 		    free (filestamp);
883 		}
884 #else
885 		filestamp = time_stamp (finfo->file);
886 		retcode = strcmp (vers->ts_conflict, filestamp);
887 		free (filestamp);
888 #endif
889 		if (retcode == 0)
890 		{
891 		    error (0, 0,
892 			  "file `%s' had a conflict and has not been modified",
893 			   finfo->fullname);
894 		    freevers_ts (&vers);
895 		    return (1);
896 		}
897 
898 		if (file_has_markers (finfo))
899 		{
900 		    /* Make this a warning, not an error, because we have
901 		       no way of knowing whether the "conflict indicators"
902 		       are really from a conflict or whether they are part
903 		       of the document itself (cvs.texinfo and sanity.sh in
904 		       CVS itself, for example, tend to want to have strings
905 		       like ">>>>>>>" at the start of a line).  Making people
906 		       kludge this the way they need to kludge keyword
907 		       expansion seems undesirable.  And it is worse than
908 		       keyword expansion, because there is no -ko
909 		       analogue.  */
910 		    error (0, 0,
911 			   "\
912 warning: file `%s' seems to still contain conflict indicators",
913 			   finfo->fullname);
914 		}
915 	    }
916 
917 	    if (status == T_REMOVED
918 		&& vers->tag
919 		&& isdigit ((unsigned char) *vers->tag))
920 	    {
921 		/* Remove also tries to forbid this, but we should check
922 		   here.  I'm only _sure_ about somewhat obscure cases
923 		   (hacking the Entries file, using an old version of
924 		   CVS for the remove and a new one for the commit), but
925 		   there might be other cases.  */
926 		error (0, 0,
927 	"cannot remove file `%s' which has a numeric sticky tag of `%s'",
928 			   finfo->fullname, vers->tag);
929 		freevers_ts (&vers);
930 		return (1);
931 	    }
932 	    if (status == T_ADDED)
933 	    {
934 	        if (vers->tag == NULL)
935 		{
936 		    if (finfo->rcs != NULL &&
937 			!RCS_isdead (finfo->rcs, finfo->rcs->head))
938 		    {
939 			error (0, 0,
940 		    "cannot add file `%s' when RCS file `%s' already exists",
941 			       finfo->fullname, finfo->rcs->path);
942 			freevers_ts (&vers);
943 			return (1);
944 		    }
945 		}
946 		else if (isdigit ((unsigned char) *vers->tag) &&
947 		    numdots (vers->tag) > 1)
948 		{
949 		    error (0, 0,
950 		"cannot add file `%s' with revision `%s'; must be on trunk",
951 			       finfo->fullname, vers->tag);
952 		    freevers_ts (&vers);
953 		    return (1);
954 		}
955 	    }
956 
957 	    /* done with consistency checks; now, to get on with the commit */
958 	    if (finfo->update_dir[0] == '\0')
959 		xdir = ".";
960 	    else
961 		xdir = finfo->update_dir;
962 	    if ((p = findnode (mulist, xdir)) != NULL)
963 	    {
964 		ulist = ((struct master_lists *) p->data)->ulist;
965 		cilist = ((struct master_lists *) p->data)->cilist;
966 	    }
967 	    else
968 	    {
969 		struct master_lists *ml;
970 
971 		ulist = getlist ();
972 		cilist = getlist ();
973 		p = getnode ();
974 		p->key = xstrdup (xdir);
975 		p->type = UPDATE;
976 		ml = (struct master_lists *)
977 		    xmalloc (sizeof (struct master_lists));
978 		ml->ulist = ulist;
979 		ml->cilist = cilist;
980 		p->data = (char *) ml;
981 		p->delproc = masterlist_delproc;
982 		(void) addnode (mulist, p);
983 	    }
984 
985 	    /* first do ulist, then cilist */
986 	    p = getnode ();
987 	    p->key = xstrdup (finfo->file);
988 	    p->type = UPDATE;
989 	    p->delproc = update_delproc;
990 	    li = ((struct logfile_info *)
991 		  xmalloc (sizeof (struct logfile_info)));
992 	    li->type = status;
993 	    li->tag = xstrdup (vers->tag);
994 	    li->rev_old = xstrdup (vers->vn_rcs);
995 	    li->rev_new = NULL;
996 	    p->data = (char *) li;
997 	    (void) addnode (ulist, p);
998 
999 	    p = getnode ();
1000 	    p->key = xstrdup (finfo->file);
1001 	    p->type = UPDATE;
1002 	    p->delproc = ci_delproc;
1003 	    ci = (struct commit_info *) xmalloc (sizeof (struct commit_info));
1004 	    ci->status = status;
1005 	    if (vers->tag)
1006 		if (isdigit ((unsigned char) *vers->tag))
1007 		    ci->rev = xstrdup (vers->tag);
1008 		else
1009 		    ci->rev = RCS_whatbranch (finfo->rcs, vers->tag);
1010 	    else
1011 		ci->rev = (char *) NULL;
1012 	    ci->tag = xstrdup (vers->tag);
1013 	    ci->options = xstrdup(vers->options);
1014 	    p->data = (char *) ci;
1015 	    (void) addnode (cilist, p);
1016 
1017 #ifdef PRESERVE_PERMISSIONS_SUPPORT
1018 	    if (preserve_perms)
1019 	    {
1020 		/* Add this file to hardlist, indexed on its inode.  When
1021 		   we are done, we can find out what files are hardlinked
1022 		   to a given file by looking up its inode in hardlist. */
1023 		char *fullpath;
1024 		Node *linkp;
1025 		struct hardlink_info *hlinfo;
1026 
1027 		/* Get the full pathname of the current file. */
1028 		fullpath = xmalloc (strlen(working_dir) +
1029 				    strlen(finfo->fullname) + 2);
1030 		sprintf (fullpath, "%s/%s", working_dir, finfo->fullname);
1031 
1032 		/* To permit following links in subdirectories, files
1033                    are keyed on finfo->fullname, not on finfo->name. */
1034 		linkp = lookup_file_by_inode (fullpath);
1035 
1036 		/* If linkp is NULL, the file doesn't exist... maybe
1037 		   we're doing a remove operation? */
1038 		if (linkp != NULL)
1039 		{
1040 		    /* Create a new hardlink_info node, which will record
1041 		       the current file's status and the links listed in its
1042 		       `hardlinks' delta field.  We will append this
1043 		       hardlink_info node to the appropriate hardlist entry. */
1044 		    hlinfo = (struct hardlink_info *)
1045 			xmalloc (sizeof (struct hardlink_info));
1046 		    hlinfo->status = status;
1047 		    linkp->data = (char *) hlinfo;
1048 		}
1049 	    }
1050 #endif
1051 
1052 	    break;
1053 	case T_UNKNOWN:
1054 	    error (0, 0, "nothing known about `%s'", finfo->fullname);
1055 	    freevers_ts (&vers);
1056 	    return (1);
1057 	case T_UPTODATE:
1058 	    break;
1059 	default:
1060 	    error (0, 0, "CVS internal error: unknown status %d", status);
1061 	    break;
1062     }
1063 
1064     freevers_ts (&vers);
1065     return (0);
1066 }
1067 
1068 /*
1069  * By default, return the code that tells do_recursion to examine all
1070  * directories
1071  */
1072 /* ARGSUSED */
1073 static Dtype
1074 check_direntproc (callerdat, dir, repos, update_dir, entries)
1075     void *callerdat;
1076     char *dir;
1077     char *repos;
1078     char *update_dir;
1079     List *entries;
1080 {
1081     if (!isdir (dir))
1082 	return (R_SKIP_ALL);
1083 
1084     if (!quiet)
1085 	error (0, 0, "Examining %s", update_dir);
1086 
1087     return (R_PROCESS);
1088 }
1089 
1090 /*
1091  * Walklist proc to run pre-commit checks
1092  */
1093 static int
1094 precommit_list_proc (p, closure)
1095     Node *p;
1096     void *closure;
1097 {
1098     struct logfile_info *li;
1099 
1100     li = (struct logfile_info *) p->data;
1101     if (li->type == T_ADDED
1102 	|| li->type == T_MODIFIED
1103 	|| li->type == T_REMOVED)
1104     {
1105 	run_arg (p->key);
1106     }
1107     return (0);
1108 }
1109 
1110 /*
1111  * Callback proc for pre-commit checking
1112  */
1113 static int
1114 precommit_proc (repository, filter)
1115     char *repository;
1116     char *filter;
1117 {
1118     /* see if the filter is there, only if it's a full path */
1119     if (isabsolute (filter))
1120     {
1121     	char *s, *cp;
1122 
1123 	s = xstrdup (filter);
1124 	for (cp = s; *cp; cp++)
1125 	    if (isspace ((unsigned char) *cp))
1126 	    {
1127 		*cp = '\0';
1128 		break;
1129 	    }
1130 	if (!isfile (s))
1131 	{
1132 	    error (0, errno, "cannot find pre-commit filter `%s'", s);
1133 	    free (s);
1134 	    return (1);			/* so it fails! */
1135 	}
1136 	free (s);
1137     }
1138 
1139     run_setup (filter);
1140     run_arg (repository);
1141     (void) walklist (saved_ulist, precommit_list_proc, NULL);
1142     return (run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL|RUN_REALLY));
1143 }
1144 
1145 /*
1146  * Run the pre-commit checks for the dir
1147  */
1148 /* ARGSUSED */
1149 static int
1150 check_filesdoneproc (callerdat, err, repos, update_dir, entries)
1151     void *callerdat;
1152     int err;
1153     char *repos;
1154     char *update_dir;
1155     List *entries;
1156 {
1157     int n;
1158     Node *p;
1159 
1160     /* find the update list for this dir */
1161     p = findnode (mulist, update_dir);
1162     if (p != NULL)
1163 	saved_ulist = ((struct master_lists *) p->data)->ulist;
1164     else
1165 	saved_ulist = (List *) NULL;
1166 
1167     /* skip the checks if there's nothing to do */
1168     if (saved_ulist == NULL || saved_ulist->list->next == saved_ulist->list)
1169 	return (err);
1170 
1171     /* run any pre-commit checks */
1172     if ((n = Parse_Info (CVSROOTADM_COMMITINFO, repos, precommit_proc, 1)) > 0)
1173     {
1174 	error (0, 0, "Pre-commit check failed");
1175 	err += n;
1176     }
1177 
1178     return (err);
1179 }
1180 
1181 /*
1182  * Do the work of committing a file
1183  */
1184 static int maxrev;
1185 static char *sbranch;
1186 
1187 /* ARGSUSED */
1188 static int
1189 commit_fileproc (callerdat, finfo)
1190     void *callerdat;
1191     struct file_info *finfo;
1192 {
1193     Node *p;
1194     int err = 0;
1195     List *ulist, *cilist;
1196     struct commit_info *ci;
1197 
1198     /* Keep track of whether write_dirtag is a branch tag.
1199        Note that if it is a branch tag in some files and a nonbranch tag
1200        in others, treat it as a nonbranch tag.  It is possible that case
1201        should elicit a warning or an error.  */
1202     if (write_dirtag != NULL
1203 	&& finfo->rcs != NULL)
1204     {
1205 	char *rev = RCS_getversion (finfo->rcs, write_dirtag, NULL, 1, NULL);
1206 	if (rev != NULL
1207 	    && !RCS_nodeisbranch (finfo->rcs, write_dirtag))
1208 	    write_dirnonbranch = 1;
1209 	if (rev != NULL)
1210 	    free (rev);
1211     }
1212 
1213     if (finfo->update_dir[0] == '\0')
1214 	p = findnode (mulist, ".");
1215     else
1216 	p = findnode (mulist, finfo->update_dir);
1217 
1218     /*
1219      * if p is null, there were file type command line args which were
1220      * all up-to-date so nothing really needs to be done
1221      */
1222     if (p == NULL)
1223 	return (0);
1224     ulist = ((struct master_lists *) p->data)->ulist;
1225     cilist = ((struct master_lists *) p->data)->cilist;
1226 
1227     /*
1228      * At this point, we should have the commit message unless we were called
1229      * with files as args from the command line.  In that latter case, we
1230      * need to get the commit message ourselves
1231      */
1232     if (!(got_message))
1233     {
1234 	got_message = 1;
1235 	if (use_editor)
1236 	    do_editor (finfo->update_dir, &saved_message,
1237 		       finfo->repository, ulist);
1238 	do_verify (saved_message, finfo->repository);
1239     }
1240 
1241     p = findnode (cilist, finfo->file);
1242     if (p == NULL)
1243 	return (0);
1244 
1245     ci = (struct commit_info *) p->data;
1246     if (ci->status == T_MODIFIED)
1247     {
1248 	if (finfo->rcs == NULL)
1249 	    error (1, 0, "internal error: no parsed RCS file");
1250 	if (lock_RCS (finfo->file, finfo->rcs, ci->rev,
1251 		      finfo->repository) != 0)
1252 	{
1253 	    unlockrcs (finfo->rcs);
1254 	    err = 1;
1255 	    goto out;
1256 	}
1257     }
1258     else if (ci->status == T_ADDED)
1259     {
1260 	if (checkaddfile (finfo->file, finfo->repository, ci->tag, ci->options,
1261 			  &finfo->rcs) != 0)
1262 	{
1263 	    fixaddfile (finfo->file, finfo->repository);
1264 	    err = 1;
1265 	    goto out;
1266 	}
1267 
1268 	/* adding files with a tag, now means adding them on a branch.
1269 	   Since the branch test was done in check_fileproc for
1270 	   modified files, we need to stub it in again here. */
1271 
1272 	if (ci->tag
1273 
1274 	    /* If numeric, it is on the trunk; check_fileproc enforced
1275 	       this.  */
1276 	    && !isdigit ((unsigned char) ci->tag[0]))
1277 	{
1278 	    if (finfo->rcs == NULL)
1279 		error (1, 0, "internal error: no parsed RCS file");
1280 	    if (ci->rev)
1281 		free (ci->rev);
1282 	    ci->rev = RCS_whatbranch (finfo->rcs, ci->tag);
1283 	    err = Checkin ('A', finfo, finfo->rcs->path, ci->rev,
1284 			   ci->tag, ci->options, saved_message);
1285 	    if (err != 0)
1286 	    {
1287 		unlockrcs (finfo->rcs);
1288 		fixbranch (finfo->rcs, sbranch);
1289 	    }
1290 
1291 	    (void) time (&last_register_time);
1292 
1293 	    ci->status = T_UPTODATE;
1294 	}
1295     }
1296 
1297     /*
1298      * Add the file for real
1299      */
1300     if (ci->status == T_ADDED)
1301     {
1302 	char *xrev = (char *) NULL;
1303 
1304 	if (ci->rev == NULL)
1305 	{
1306 	    /* find the max major rev number in this directory */
1307 	    maxrev = 0;
1308 	    (void) walklist (finfo->entries, findmaxrev, NULL);
1309 	    if (finfo->rcs->head) {
1310 		/* resurrecting: include dead revision */
1311 		int thisrev = atoi (finfo->rcs->head);
1312 		if (thisrev > maxrev)
1313 		    maxrev = thisrev;
1314 	    }
1315 	    if (maxrev == 0)
1316 		maxrev = 1;
1317 	    xrev = xmalloc (20);
1318 	    (void) sprintf (xrev, "%d", maxrev);
1319 	}
1320 
1321 	/* XXX - an added file with symbolic -r should add tag as well */
1322 	err = finaladd (finfo, ci->rev ? ci->rev : xrev, ci->tag, ci->options);
1323 	if (xrev)
1324 	    free (xrev);
1325     }
1326     else if (ci->status == T_MODIFIED)
1327     {
1328 	err = Checkin ('M', finfo,
1329 		       finfo->rcs->path, ci->rev, ci->tag,
1330 		       ci->options, saved_message);
1331 
1332 	(void) time (&last_register_time);
1333 
1334 	if (err != 0)
1335 	{
1336 	    unlockrcs (finfo->rcs);
1337 	    fixbranch (finfo->rcs, sbranch);
1338 	}
1339     }
1340     else if (ci->status == T_REMOVED)
1341     {
1342 	err = remove_file (finfo, ci->tag, saved_message);
1343 #ifdef SERVER_SUPPORT
1344 	if (server_active) {
1345 	    server_scratch_entry_only ();
1346 	    server_updated (finfo,
1347 			    NULL,
1348 
1349 			    /* Doesn't matter, it won't get checked.  */
1350 			    SERVER_UPDATED,
1351 
1352 			    (mode_t) -1,
1353 			    (unsigned char *) NULL,
1354 			    (struct buffer *) NULL);
1355 	}
1356 #endif
1357     }
1358 
1359     /* Clearly this is right for T_MODIFIED.  I haven't thought so much
1360        about T_ADDED or T_REMOVED.  */
1361     notify_do ('C', finfo->file, getcaller (), NULL, NULL, finfo->repository);
1362 
1363 out:
1364     if (err != 0)
1365     {
1366 	/* on failure, remove the file from ulist */
1367 	p = findnode (ulist, finfo->file);
1368 	if (p)
1369 	    delnode (p);
1370     }
1371     else
1372     {
1373 	/* On success, retrieve the new version number of the file and
1374            copy it into the log information (see logmsg.c
1375            (logfile_write) for more details).  We should only update
1376            the version number for files that have been added or
1377            modified but not removed.  Why?  classify_file_internal
1378            will return the version number of a file even after it has
1379            been removed from the archive, which is not the behavior we
1380            want for our commitlog messages; we want the old version
1381            number and then "NONE." */
1382 
1383 	if (ci->status != T_REMOVED)
1384 	{
1385 	    p = findnode (ulist, finfo->file);
1386 	    if (p)
1387 	    {
1388 		Vers_TS *vers;
1389 		struct logfile_info *li;
1390 
1391 		(void) classify_file_internal (finfo, &vers);
1392 		li = (struct logfile_info *) p->data;
1393 		li->rev_new = xstrdup (vers->vn_rcs);
1394 		freevers_ts (&vers);
1395 	    }
1396 	}
1397     }
1398     if (SIG_inCrSect ())
1399 	SIG_endCrSect ();
1400 
1401     return (err);
1402 }
1403 
1404 /*
1405  * Log the commit and clean up the update list
1406  */
1407 /* ARGSUSED */
1408 static int
1409 commit_filesdoneproc (callerdat, err, repository, update_dir, entries)
1410     void *callerdat;
1411     int err;
1412     char *repository;
1413     char *update_dir;
1414     List *entries;
1415 {
1416     Node *p;
1417     List *ulist;
1418 
1419     p = findnode (mulist, update_dir);
1420     if (p == NULL)
1421 	return (err);
1422 
1423     ulist = ((struct master_lists *) p->data)->ulist;
1424 
1425     got_message = 0;
1426 
1427 
1428     Update_Logfile (repository, saved_message, (FILE *) 0, ulist);
1429 
1430     /* Build the administrative files if necessary.  */
1431     {
1432 	char *p;
1433 
1434 	if (strncmp (current_parsed_root->directory, repository,
1435 		     strlen (current_parsed_root->directory)) != 0)
1436 	    error (0, 0,
1437 		 "internal error: repository (%s) doesn't begin with root (%s)",
1438 		   repository, current_parsed_root->directory);
1439 	p = repository + strlen (current_parsed_root->directory);
1440 	if (*p == '/')
1441 	    ++p;
1442 	if (strcmp ("CVSROOT", p) == 0
1443 	    /* Check for subdirectories because people may want to create
1444 	       subdirectories and list files therein in checkoutlist.  */
1445 	    || strncmp ("CVSROOT/", p, strlen ("CVSROOT/")) == 0
1446 	    )
1447 	{
1448 	    /* "Database" might a little bit grandiose and/or vague,
1449 	       but "checked-out copies of administrative files, unless
1450 	       in the case of modules and you are using ndbm in which
1451 	       case modules.{pag,dir,db}" is verbose and excessively
1452 	       focused on how the database is implemented.  */
1453 
1454 	    /* mkmodules requires the absolute name of the CVSROOT directory.
1455 	       Remove anything after the `CVSROOT' component -- this is
1456 	       necessary when committing in a subdirectory of CVSROOT.  */
1457 	    char *admin_dir = xstrdup (repository);
1458 	    int cvsrootlen = strlen ("CVSROOT");
1459 	    assert (admin_dir[p - repository + cvsrootlen] == '\0'
1460 		    || admin_dir[p - repository + cvsrootlen] == '/');
1461 	    admin_dir[p - repository + cvsrootlen] = '\0';
1462 
1463 	    cvs_output (program_name, 0);
1464 	    cvs_output (" ", 1);
1465 	    cvs_output (command_name, 0);
1466 	    cvs_output (": Rebuilding administrative file database\n", 0);
1467 	    mkmodules (admin_dir);
1468 	    free (admin_dir);
1469 	}
1470     }
1471 
1472     if (err == 0 && run_module_prog)
1473     {
1474 	FILE *fp;
1475 
1476 	if ((fp = CVS_FOPEN (CVSADM_CIPROG, "r")) != NULL)
1477 	{
1478 	    char *line;
1479 	    int line_length;
1480 	    size_t line_chars_allocated;
1481 	    char *repos;
1482 
1483 	    line = NULL;
1484 	    line_chars_allocated = 0;
1485 	    line_length = get_line (&line, &line_chars_allocated, fp);
1486 	    if (line_length > 0)
1487 	    {
1488 		/* Remove any trailing newline.  */
1489 		if (line[line_length - 1] == '\n')
1490 		    line[--line_length] = '\0';
1491 		repos = Name_Repository ((char *) NULL, update_dir);
1492 		run_setup (line);
1493 		run_arg (repos);
1494 		cvs_output (program_name, 0);
1495 		cvs_output (" ", 1);
1496 		cvs_output (command_name, 0);
1497 		cvs_output (": Executing '", 0);
1498 		run_print (stdout);
1499 		cvs_output ("'\n", 0);
1500 		cvs_flushout ();
1501 		(void) run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL);
1502 		free (repos);
1503 	    }
1504 	    else
1505 	    {
1506 		if (ferror (fp))
1507 		    error (0, errno, "warning: error reading %s",
1508 			   CVSADM_CIPROG);
1509 	    }
1510 	    if (line != NULL)
1511 		free (line);
1512 	    if (fclose (fp) < 0)
1513 		error (0, errno, "warning: cannot close %s", CVSADM_CIPROG);
1514 	}
1515 	else
1516 	{
1517 	    if (! existence_error (errno))
1518 		error (0, errno, "warning: cannot open %s", CVSADM_CIPROG);
1519 	}
1520     }
1521 
1522     return (err);
1523 }
1524 
1525 /*
1526  * Get the log message for a dir
1527  */
1528 /* ARGSUSED */
1529 static Dtype
1530 commit_direntproc (callerdat, dir, repos, update_dir, entries)
1531     void *callerdat;
1532     char *dir;
1533     char *repos;
1534     char *update_dir;
1535     List *entries;
1536 {
1537     Node *p;
1538     List *ulist;
1539     char *real_repos;
1540 
1541     if (!isdir (dir))
1542 	return (R_SKIP_ALL);
1543 
1544     /* find the update list for this dir */
1545     p = findnode (mulist, update_dir);
1546     if (p != NULL)
1547 	ulist = ((struct master_lists *) p->data)->ulist;
1548     else
1549 	ulist = (List *) NULL;
1550 
1551     /* skip the files as an optimization */
1552     if (ulist == NULL || ulist->list->next == ulist->list)
1553 	return (R_SKIP_FILES);
1554 
1555     /* get commit message */
1556     real_repos = Name_Repository (dir, update_dir);
1557     got_message = 1;
1558     if (use_editor)
1559 	do_editor (update_dir, &saved_message, real_repos, ulist);
1560     do_verify (saved_message, real_repos);
1561     free (real_repos);
1562     return (R_PROCESS);
1563 }
1564 
1565 /*
1566  * Process the post-commit proc if necessary
1567  */
1568 /* ARGSUSED */
1569 static int
1570 commit_dirleaveproc (callerdat, dir, err, update_dir, entries)
1571     void *callerdat;
1572     char *dir;
1573     int err;
1574     char *update_dir;
1575     List *entries;
1576 {
1577     /* update the per-directory tag info */
1578     /* FIXME?  Why?  The "commit examples" node of cvs.texinfo briefly
1579        mentions commit -r being sticky, but apparently in the context of
1580        this being a confusing feature!  */
1581     if (err == 0 && write_dirtag != NULL)
1582     {
1583 	char *repos = Name_Repository (dir, update_dir);
1584 	WriteTag (NULL, write_dirtag, NULL, write_dirnonbranch,
1585 		  update_dir, repos);
1586 	free (repos);
1587     }
1588 
1589     return (err);
1590 }
1591 
1592 /*
1593  * find the maximum major rev number in an entries file
1594  */
1595 static int
1596 findmaxrev (p, closure)
1597     Node *p;
1598     void *closure;
1599 {
1600     int thisrev;
1601     Entnode *entdata;
1602 
1603     entdata = (Entnode *) p->data;
1604     if (entdata->type != ENT_FILE)
1605 	return (0);
1606     thisrev = atoi (entdata->version);
1607     if (thisrev > maxrev)
1608 	maxrev = thisrev;
1609     return (0);
1610 }
1611 
1612 /*
1613  * Actually remove a file by moving it to the attic
1614  * XXX - if removing a ,v file that is a relative symbolic link to
1615  * another ,v file, we probably should add a ".." component to the
1616  * link to keep it relative after we move it into the attic.
1617 
1618    Return value is 0 on success, or >0 on error (in which case we have
1619    printed an error message).  */
1620 static int
1621 remove_file (finfo, tag, message)
1622     struct file_info *finfo;
1623     char *tag;
1624     char *message;
1625 {
1626     int retcode;
1627 
1628     int branch;
1629     int lockflag;
1630     char *corev;
1631     char *rev;
1632     char *prev_rev;
1633     char *old_path;
1634 
1635     corev = NULL;
1636     rev = NULL;
1637     prev_rev = NULL;
1638 
1639     retcode = 0;
1640 
1641     if (finfo->rcs == NULL)
1642 	error (1, 0, "internal error: no parsed RCS file");
1643 
1644     branch = 0;
1645     if (tag && !(branch = RCS_nodeisbranch (finfo->rcs, tag)))
1646     {
1647 	/* a symbolic tag is specified; just remove the tag from the file */
1648 	if ((retcode = RCS_deltag (finfo->rcs, tag)) != 0)
1649 	{
1650 	    if (!quiet)
1651 		error (0, retcode == -1 ? errno : 0,
1652 		       "failed to remove tag `%s' from `%s'", tag,
1653 		       finfo->fullname);
1654 	    return (1);
1655 	}
1656 	RCS_rewrite (finfo->rcs, NULL, NULL);
1657 	Scratch_Entry (finfo->entries, finfo->file);
1658 	return (0);
1659     }
1660 
1661     /* we are removing the file from either the head or a branch */
1662     /* commit a new, dead revision. */
1663 
1664     /* Print message indicating that file is going to be removed. */
1665     cvs_output ("Removing ", 0);
1666     cvs_output (finfo->fullname, 0);
1667     cvs_output (";\n", 0);
1668 
1669     rev = NULL;
1670     lockflag = 1;
1671     if (branch)
1672     {
1673 	char *branchname;
1674 
1675 	rev = RCS_whatbranch (finfo->rcs, tag);
1676 	if (rev == NULL)
1677 	{
1678 	    error (0, 0, "cannot find branch \"%s\".", tag);
1679 	    return (1);
1680 	}
1681 
1682 	branchname = RCS_getbranch (finfo->rcs, rev, 1);
1683 	if (branchname == NULL)
1684 	{
1685 	    /* no revision exists on this branch.  use the previous
1686 	       revision but do not lock. */
1687 	    corev = RCS_gettag (finfo->rcs, tag, 1, (int *) NULL);
1688 	    prev_rev = xstrdup(rev);
1689 	    lockflag = 0;
1690 	} else
1691 	{
1692 	    corev = xstrdup (rev);
1693 	    prev_rev = xstrdup(branchname);
1694 	    free (branchname);
1695 	}
1696 
1697     } else  /* Not a branch */
1698     {
1699         /* Get current head revision of file. */
1700 	prev_rev = RCS_head (finfo->rcs);
1701     }
1702 
1703     /* if removing without a tag or a branch, then make sure the default
1704        branch is the trunk. */
1705     if (!tag && !branch)
1706     {
1707         if (RCS_setbranch (finfo->rcs, NULL) != 0)
1708 	{
1709 	    error (0, 0, "cannot change branch to default for %s",
1710 		   finfo->fullname);
1711 	    return (1);
1712 	}
1713 	RCS_rewrite (finfo->rcs, NULL, NULL);
1714     }
1715 
1716     /* check something out.  Generally this is the head.  If we have a
1717        particular rev, then name it.  */
1718     retcode = RCS_checkout (finfo->rcs, finfo->file, rev ? corev : NULL,
1719 			    (char *) NULL, (char *) NULL, RUN_TTY,
1720 			    (RCSCHECKOUTPROC) NULL, (void *) NULL);
1721     if (retcode != 0)
1722     {
1723 	error (0, 0,
1724 	       "failed to check out `%s'", finfo->fullname);
1725 	return (1);
1726     }
1727 
1728     /* Except when we are creating a branch, lock the revision so that
1729        we can check in the new revision.  */
1730     if (lockflag)
1731     {
1732 	if (RCS_lock (finfo->rcs, rev ? corev : NULL, 1) == 0)
1733 	    RCS_rewrite (finfo->rcs, NULL, NULL);
1734     }
1735 
1736     if (corev != NULL)
1737 	free (corev);
1738 
1739     retcode = RCS_checkin (finfo->rcs, finfo->file, message, rev,
1740 			   RCS_FLAGS_DEAD | RCS_FLAGS_QUIET);
1741     if (retcode	!= 0)
1742     {
1743 	if (!quiet)
1744 	    error (0, retcode == -1 ? errno : 0,
1745 		   "failed to commit dead revision for `%s'", finfo->fullname);
1746 	return (1);
1747     }
1748     /* At this point, the file has been committed as removed.  We should
1749        probably tell the history file about it  */
1750     history_write ('R', NULL, finfo->rcs->head, finfo->file, finfo->repository);
1751 
1752     if (rev != NULL)
1753 	free (rev);
1754 
1755     old_path = xstrdup (finfo->rcs->path);
1756     if (!branch)
1757 	RCS_setattic (finfo->rcs, 1);
1758 
1759     /* Print message that file was removed. */
1760     cvs_output (old_path, 0);
1761     cvs_output ("  <--  ", 0);
1762     cvs_output (finfo->file, 0);
1763     cvs_output ("\nnew revision: delete; previous revision: ", 0);
1764     cvs_output (prev_rev, 0);
1765     cvs_output ("\ndone\n", 0);
1766     free(prev_rev);
1767 
1768     free (old_path);
1769 
1770     Scratch_Entry (finfo->entries, finfo->file);
1771     return (0);
1772 }
1773 
1774 /*
1775  * Do the actual checkin for added files
1776  */
1777 static int
1778 finaladd (finfo, rev, tag, options)
1779     struct file_info *finfo;
1780     char *rev;
1781     char *tag;
1782     char *options;
1783 {
1784     int ret;
1785     char *rcs;
1786 
1787     rcs = locate_rcs (finfo->file, finfo->repository);
1788     ret = Checkin ('A', finfo, rcs, rev, tag, options, saved_message);
1789     if (ret == 0)
1790     {
1791 	char *tmp = xmalloc (strlen (finfo->file) + sizeof (CVSADM)
1792 			     + sizeof (CVSEXT_LOG) + 10);
1793 	(void) sprintf (tmp, "%s/%s%s", CVSADM, finfo->file, CVSEXT_LOG);
1794 	if (unlink_file (tmp) < 0
1795 	    && !existence_error (errno))
1796 	    error (0, errno, "cannot remove %s", tmp);
1797 	free (tmp);
1798     }
1799     else
1800 	fixaddfile (finfo->file, finfo->repository);
1801 
1802     (void) time (&last_register_time);
1803     free (rcs);
1804 
1805     return (ret);
1806 }
1807 
1808 /*
1809  * Unlock an rcs file
1810  */
1811 static void
1812 unlockrcs (rcs)
1813     RCSNode *rcs;
1814 {
1815     int retcode;
1816 
1817     if ((retcode = RCS_unlock (rcs, NULL, 0)) != 0)
1818 	error (retcode == -1 ? 1 : 0, retcode == -1 ? errno : 0,
1819 	       "could not unlock %s", rcs->path);
1820     else
1821 	RCS_rewrite (rcs, NULL, NULL);
1822 }
1823 
1824 /*
1825  * remove a partially added file.  if we can parse it, leave it alone.
1826  */
1827 static void
1828 fixaddfile (file, repository)
1829     char *file;
1830     char *repository;
1831 {
1832     RCSNode *rcsfile;
1833     char *rcs;
1834     int save_really_quiet;
1835 
1836     rcs = locate_rcs (file, repository);
1837     save_really_quiet = really_quiet;
1838     really_quiet = 1;
1839     if ((rcsfile = RCS_parsercsfile (rcs)) == NULL)
1840     {
1841 	if (unlink_file (rcs) < 0)
1842 	    error (0, errno, "cannot remove %s", rcs);
1843     }
1844     else
1845 	freercsnode (&rcsfile);
1846     really_quiet = save_really_quiet;
1847     free (rcs);
1848 }
1849 
1850 /*
1851  * put the branch back on an rcs file
1852  */
1853 static void
1854 fixbranch (rcs, branch)
1855     RCSNode *rcs;
1856     char *branch;
1857 {
1858     int retcode;
1859 
1860     if (branch != NULL)
1861     {
1862 	if ((retcode = RCS_setbranch (rcs, branch)) != 0)
1863 	    error (retcode == -1 ? 1 : 0, retcode == -1 ? errno : 0,
1864 		   "cannot restore branch to %s for %s", branch, rcs->path);
1865 	RCS_rewrite (rcs, NULL, NULL);
1866     }
1867 }
1868 
1869 /*
1870  * do the initial part of a file add for the named file.  if adding
1871  * with a tag, put the file in the Attic and point the symbolic tag
1872  * at the committed revision.
1873  */
1874 
1875 static int
1876 checkaddfile (file, repository, tag, options, rcsnode)
1877     char *file;
1878     char *repository;
1879     char *tag;
1880     char *options;
1881     RCSNode **rcsnode;
1882 {
1883     char *rcs;
1884     char *fname;
1885     mode_t omask;
1886     int retcode = 0;
1887     int newfile = 0;
1888     RCSNode *rcsfile = NULL;
1889     int retval;
1890     int adding_on_branch;
1891 
1892     /* Callers expect to be able to use either "" or NULL to mean the
1893        default keyword expansion.  */
1894     if (options != NULL && options[0] == '\0')
1895 	options = NULL;
1896     if (options != NULL)
1897 	assert (options[0] == '-' && options[1] == 'k');
1898 
1899     /* If numeric, it is on the trunk; check_fileproc enforced
1900        this.  */
1901     adding_on_branch = tag != NULL && !isdigit ((unsigned char) tag[0]);
1902 
1903     if (adding_on_branch)
1904     {
1905 	rcs = xmalloc (strlen (repository) + strlen (file)
1906 		       + sizeof (RCSEXT) + sizeof (CVSATTIC) + 10);
1907         (void) sprintf (rcs, "%s/%s%s", repository, file, RCSEXT);
1908 	if (! isreadable (rcs))
1909 	{
1910 	    (void) sprintf(rcs, "%s/%s", repository, CVSATTIC);
1911 	    omask = umask (cvsumask);
1912 	    if (CVS_MKDIR (rcs, 0777) != 0 && errno != EEXIST)
1913 		error (1, errno, "cannot make directory `%s'", rcs);;
1914 	    (void) umask (omask);
1915 	    (void) sprintf (rcs, "%s/%s/%s%s", repository, CVSATTIC, file,
1916 			    RCSEXT);
1917 	}
1918     }
1919     else
1920 	rcs = locate_rcs (file, repository);
1921 
1922     if (isreadable (rcs))
1923     {
1924 	/* file has existed in the past.  Prepare to resurrect. */
1925 	char *rev;
1926 	char *oldexpand;
1927 
1928 	if ((rcsfile = *rcsnode) == NULL)
1929 	{
1930 	    error (0, 0, "could not find parsed rcsfile %s", file);
1931 	    retval = 1;
1932 	    goto out;
1933 	}
1934 
1935 	oldexpand = RCS_getexpand (rcsfile);
1936 	if ((oldexpand != NULL
1937 	     && options != NULL
1938 	     && strcmp (options + 2, oldexpand) != 0)
1939 	    || (oldexpand == NULL && options != NULL))
1940 	{
1941 	    /* We tell the user about this, because it means that the
1942 	       old revisions will no longer retrieve the way that they
1943 	       used to.  */
1944 	    error (0, 0, "changing keyword expansion mode to %s", options);
1945 	    RCS_setexpand (rcsfile, options + 2);
1946 	}
1947 
1948 	if (!adding_on_branch)
1949 	{
1950 	    /* We are adding on the trunk, so move the file out of the
1951 	       Attic.  */
1952 	    if (!(rcsfile->flags & INATTIC))
1953 	    {
1954 		error (0, 0, "warning: expected %s to be in Attic",
1955 		       rcsfile->path);
1956 	    }
1957 
1958 	    sprintf (rcs, "%s/%s%s", repository, file, RCSEXT);
1959 
1960 	    /* Begin a critical section around the code that spans the
1961 	       first commit on the trunk of a file that's already been
1962 	       committed on a branch.  */
1963 	    SIG_beginCrSect ();
1964 
1965 	    if (RCS_setattic (rcsfile, 0))
1966 	    {
1967 		retval = 1;
1968 		goto out;
1969 	    }
1970 	}
1971 
1972 	rev = RCS_getversion (rcsfile, tag, NULL, 1, (int *) NULL);
1973 	/* and lock it */
1974 	if (lock_RCS (file, rcsfile, rev, repository))
1975 	{
1976 	    error (0, 0, "cannot lock `%s'.", rcs);
1977 	    if (rev != NULL)
1978 		free (rev);
1979 	    retval = 1;
1980 	    goto out;
1981 	}
1982 
1983 	if (rev != NULL)
1984 	    free (rev);
1985     }
1986     else
1987     {
1988 	/* this is the first time we have ever seen this file; create
1989 	   an rcs file.  */
1990 
1991 	char *desc;
1992 	size_t descalloc;
1993 	size_t desclen;
1994 
1995 	char *opt;
1996 
1997 	desc = NULL;
1998 	descalloc = 0;
1999 	desclen = 0;
2000 	fname = xmalloc (strlen (file) + sizeof (CVSADM)
2001 			 + sizeof (CVSEXT_LOG) + 10);
2002 	(void) sprintf (fname, "%s/%s%s", CVSADM, file, CVSEXT_LOG);
2003 	/* If the file does not exist, no big deal.  In particular, the
2004 	   server does not (yet at least) create CVSEXT_LOG files.  */
2005 	if (isfile (fname))
2006 	    /* FIXME: Should be including update_dir in the appropriate
2007 	       place here.  */
2008 	    get_file (fname, fname, "r", &desc, &descalloc, &desclen);
2009 	free (fname);
2010 
2011 	/* From reading the RCS 5.7 source, "rcs -i" adds a newline to the
2012 	   end of the log message if the message is nonempty.
2013 	   Do it.  RCS also deletes certain whitespace, in cleanlogmsg,
2014 	   which we don't try to do here.  */
2015 	if (desclen > 0)
2016 	{
2017 	    expand_string (&desc, &descalloc, desclen + 1);
2018 	    desc[desclen++] = '\012';
2019 	}
2020 
2021 	/* Set RCS keyword expansion options.  */
2022 	if (options != NULL)
2023 	    opt = options + 2;
2024 	else
2025 	    opt = NULL;
2026 
2027 	/* This message is an artifact of the time when this
2028 	   was implemented via "rcs -i".  It should be revised at
2029 	   some point (does the "initial revision" in the message from
2030 	   RCS_checkin indicate that this is a new file?  Or does the
2031 	   "RCS file" message serve some function?).  */
2032 	cvs_output ("RCS file: ", 0);
2033 	cvs_output (rcs, 0);
2034 	cvs_output ("\ndone\n", 0);
2035 
2036 	if (add_rcs_file (NULL, rcs, file, NULL, opt,
2037 			  NULL, NULL, 0, NULL,
2038 			  desc, desclen, NULL) != 0)
2039 	{
2040 	    retval = 1;
2041 	    goto out;
2042 	}
2043 	rcsfile = RCS_parsercsfile (rcs);
2044 	newfile = 1;
2045 	if (desc != NULL)
2046 	    free (desc);
2047 	if (rcsnode != NULL)
2048 	{
2049 	    assert (*rcsnode == NULL);
2050 	    *rcsnode = rcsfile;
2051 	}
2052     }
2053 
2054     /* when adding a file for the first time, and using a tag, we need
2055        to create a dead revision on the trunk.  */
2056     if (adding_on_branch)
2057     {
2058 	if (newfile)
2059 	{
2060 	    char *tmp;
2061 	    FILE *fp;
2062 
2063 	    /* move the new file out of the way. */
2064 	    fname = xmalloc (strlen (file) + sizeof (CVSADM)
2065 			     + sizeof (CVSPREFIX) + 10);
2066 	    (void) sprintf (fname, "%s/%s%s", CVSADM, CVSPREFIX, file);
2067 	    rename_file (file, fname);
2068 
2069 	    /* Create empty FILE.  Can't use copy_file with a DEVNULL
2070 	       argument -- copy_file now ignores device files. */
2071 	    fp = fopen (file, "w");
2072 	    if (fp == NULL)
2073 		error (1, errno, "cannot open %s for writing", file);
2074 	    if (fclose (fp) < 0)
2075 		error (0, errno, "cannot close %s", file);
2076 
2077 	    tmp = xmalloc (strlen (file) + strlen (tag) + 80);
2078 	    /* commit a dead revision. */
2079 	    (void) sprintf (tmp, "file %s was initially added on branch %s.",
2080 			    file, tag);
2081 	    retcode = RCS_checkin (rcsfile, NULL, tmp, NULL,
2082 				   RCS_FLAGS_DEAD | RCS_FLAGS_QUIET);
2083 	    free (tmp);
2084 	    if (retcode != 0)
2085 	    {
2086 		error (retcode == -1 ? 1 : 0, retcode == -1 ? errno : 0,
2087 		       "could not create initial dead revision %s", rcs);
2088 		retval = 1;
2089 		goto out;
2090 	    }
2091 
2092 	    /* put the new file back where it was */
2093 	    rename_file (fname, file);
2094 	    free (fname);
2095 
2096 	    /* double-check that the file was written correctly */
2097 	    freercsnode (&rcsfile);
2098 	    rcsfile = RCS_parse (file, repository);
2099 	    if (rcsfile == NULL)
2100 	    {
2101 		error (0, 0, "could not read %s", rcs);
2102 		retval = 1;
2103 		goto out;
2104 	    }
2105 	    if (rcsnode != NULL)
2106 		*rcsnode = rcsfile;
2107 
2108 	    /* and lock it once again. */
2109 	    if (lock_RCS (file, rcsfile, NULL, repository))
2110 	    {
2111 		error (0, 0, "cannot lock `%s'.", rcs);
2112 		retval = 1;
2113 		goto out;
2114 	    }
2115 	}
2116 
2117 	/* when adding with a tag, we need to stub a branch, if it
2118 	   doesn't already exist.  */
2119 
2120 	if (rcsfile == NULL)
2121 	{
2122 	    if (rcsnode != NULL && *rcsnode != NULL)
2123 		rcsfile = *rcsnode;
2124 	    else
2125 	    {
2126 		rcsfile = RCS_parse (file, repository);
2127 		if (rcsfile == NULL)
2128 		{
2129 		    error (0, 0, "could not read %s", rcs);
2130 		    retval = 1;
2131 		    goto out;
2132 		}
2133 	    }
2134 	}
2135 
2136 	if (!RCS_nodeisbranch (rcsfile, tag))
2137 	{
2138 	    /* branch does not exist.  Stub it.  */
2139 	    char *head;
2140 	    char *magicrev;
2141 
2142 	    head = RCS_getversion (rcsfile, NULL, NULL, 0, (int *) NULL);
2143 	    magicrev = RCS_magicrev (rcsfile, head);
2144 
2145 	    retcode = RCS_settag (rcsfile, tag, magicrev);
2146 	    RCS_rewrite (rcsfile, NULL, NULL);
2147 
2148 	    free (head);
2149 	    free (magicrev);
2150 
2151 	    if (retcode != 0)
2152 	    {
2153 		error (retcode == -1 ? 1 : 0, retcode == -1 ? errno : 0,
2154 		       "could not stub branch %s for %s", tag, rcs);
2155 		retval = 1;
2156 		goto out;
2157 	    }
2158 	}
2159 	else
2160 	{
2161 	    /* lock the branch. (stubbed branches need not be locked.)  */
2162 	    if (lock_RCS (file, rcsfile, NULL, repository))
2163 	    {
2164 		error (0, 0, "cannot lock `%s'.", rcs);
2165 		retval = 1;
2166 		goto out;
2167 	    }
2168 	}
2169 
2170 	if (rcsnode && *rcsnode != rcsfile)
2171 	{
2172 	    freercsnode(rcsnode);
2173 	    *rcsnode = rcsfile;
2174 	}
2175     }
2176 
2177     fileattr_newfile (file);
2178 
2179     /* At this point, we used to set the file mode of the RCS file
2180        based on the mode of the file in the working directory.  If we
2181        are creating the RCS file for the first time, add_rcs_file does
2182        this already.  If we are re-adding the file, then perhaps it is
2183        consistent to preserve the old file mode, just as we preserve
2184        the old keyword expansion mode.
2185 
2186        If we decide that we should change the modes, then we can't do
2187        it here anyhow.  At this point, the RCS file may be owned by
2188        somebody else, so a chmod will fail.  We need to instead do the
2189        chmod after rewriting it.
2190 
2191        FIXME: In general, I think the file mode (and the keyword
2192        expansion mode) should be associated with a particular revision
2193        of the file, so that it is possible to have different revisions
2194        of a file have different modes.  */
2195 
2196     retval = 0;
2197 
2198  out:
2199     if (retval != 0 && SIG_inCrSect ())
2200 	SIG_endCrSect ();
2201     free (rcs);
2202     return retval;
2203 }
2204 
2205 /*
2206  * Attempt to place a lock on the RCS file; returns 0 if it could and 1 if it
2207  * couldn't.  If the RCS file currently has a branch as the head, we must
2208  * move the head back to the trunk before locking the file, and be sure to
2209  * put the branch back as the head if there are any errors.
2210  */
2211 static int
2212 lock_RCS (user, rcs, rev, repository)
2213     char *user;
2214     RCSNode *rcs;
2215     char *rev;
2216     char *repository;
2217 {
2218     char *branch = NULL;
2219     int err = 0;
2220 
2221     /*
2222      * For a specified, numeric revision of the form "1" or "1.1", (or when
2223      * no revision is specified ""), definitely move the branch to the trunk
2224      * before locking the RCS file.
2225      *
2226      * The assumption is that if there is more than one revision on the trunk,
2227      * the head points to the trunk, not a branch... and as such, it's not
2228      * necessary to move the head in this case.
2229      */
2230     if (rev == NULL
2231 	|| (rev && isdigit ((unsigned char) *rev) && numdots (rev) < 2))
2232     {
2233 	branch = xstrdup (rcs->branch);
2234 	if (branch != NULL)
2235 	{
2236 	    if (RCS_setbranch (rcs, NULL) != 0)
2237 	    {
2238 		error (0, 0, "cannot change branch to default for %s",
2239 		       rcs->path);
2240 		if (branch)
2241 		    free (branch);
2242 		return (1);
2243 	    }
2244 	}
2245 	err = RCS_lock(rcs, NULL, 1);
2246     }
2247     else
2248     {
2249 	(void) RCS_lock(rcs, rev, 1);
2250     }
2251 
2252     /* We used to call RCS_rewrite here, and that might seem
2253        appropriate in order to write out the locked revision
2254        information.  However, such a call would actually serve no
2255        purpose.  CVS locks will prevent any interference from other
2256        CVS processes.  The comment above rcs_internal_lockfile
2257        explains that it is already unsafe to use RCS and CVS
2258        simultaneously.  It follows that writing out the locked
2259        revision information here would add no additional security.
2260 
2261        If we ever do care about it, the proper fix is to create the
2262        RCS lock file before calling this function, and maintain it
2263        until the checkin is complete.
2264 
2265        The call to RCS_lock is still required at present, since in
2266        some cases RCS_checkin will determine which revision to check
2267        in by looking for a lock.  FIXME: This is rather roundabout,
2268        and a more straightforward approach would probably be easier to
2269        understand.  */
2270 
2271     if (err == 0)
2272     {
2273 	if (sbranch != NULL)
2274 	    free (sbranch);
2275 	sbranch = branch;
2276 	return (0);
2277     }
2278 
2279     /* try to restore the branch if we can on error */
2280     if (branch != NULL)
2281 	fixbranch (rcs, branch);
2282 
2283     if (branch)
2284 	free (branch);
2285     return (1);
2286 }
2287 
2288 /*
2289  * free an UPDATE node's data
2290  */
2291 void
2292 update_delproc (p)
2293     Node *p;
2294 {
2295     struct logfile_info *li;
2296 
2297     li = (struct logfile_info *) p->data;
2298     if (li->tag)
2299 	free (li->tag);
2300     if (li->rev_old)
2301 	free (li->rev_old);
2302     if (li->rev_new)
2303 	free (li->rev_new);
2304     free (li);
2305 }
2306 
2307 /*
2308  * Free the commit_info structure in p.
2309  */
2310 static void
2311 ci_delproc (p)
2312     Node *p;
2313 {
2314     struct commit_info *ci;
2315 
2316     ci = (struct commit_info *) p->data;
2317     if (ci->rev)
2318 	free (ci->rev);
2319     if (ci->tag)
2320 	free (ci->tag);
2321     if (ci->options)
2322 	free (ci->options);
2323     free (ci);
2324 }
2325 
2326 /*
2327  * Free the commit_info structure in p.
2328  */
2329 static void
2330 masterlist_delproc (p)
2331     Node *p;
2332 {
2333     struct master_lists *ml;
2334 
2335     ml = (struct master_lists *) p->data;
2336     dellist (&ml->ulist);
2337     dellist (&ml->cilist);
2338     free (ml);
2339 }
2340 
2341 /* Find an RCS file in the repository.  Most parts of CVS will want to
2342    rely instead on RCS_parse which performs a similar operation and is
2343    called by recurse.c which then puts the result in useful places
2344    like the rcs field of struct file_info.
2345 
2346    REPOSITORY is the repository (including the directory) and FILE is
2347    the filename within that directory (without RCSEXT).  Returns a
2348    newly-malloc'd array containing the absolute pathname of the RCS
2349    file that was found.  */
2350 static char *
2351 locate_rcs (file, repository)
2352     char *file;
2353     char *repository;
2354 {
2355     char *rcs;
2356 
2357     rcs = xmalloc (strlen (repository) + strlen (file) + sizeof (RCSEXT) + 10);
2358     (void) sprintf (rcs, "%s/%s%s", repository, file, RCSEXT);
2359     if (!isreadable (rcs))
2360     {
2361 	(void) sprintf (rcs, "%s/%s/%s%s", repository, CVSATTIC, file, RCSEXT);
2362 	if (!isreadable (rcs))
2363 	    (void) sprintf (rcs, "%s/%s%s", repository, file, RCSEXT);
2364     }
2365     return rcs;
2366 }
2367