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