xref: /openbsd-src/gnu/usr.bin/cvs/src/commit.c (revision 62a742911104f98b9185b2c6b6007d9b1c36396c)
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     "\t-n\tDo not run the module program (if any).\n",
89     "\t-R\tProcess directories recursively.\n",
90     "\t-l\tLocal directory only (not recursive).\n",
91     "\t-f\tForce the file to be committed; disables recursion.\n",
92     "\t-F file\tRead the log message from file.\n",
93     "\t-m msg\tLog message.\n",
94     "\t-r rev\tCommit 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 	return 1;
267     }
268     else if (vers->ts_user != NULL
269 	     && vers->vn_user != NULL
270 	     && vers->vn_user[0] == '0')
271 	/* FIXME: If vn_user is "0" but ts_user is NULL, what classify_file
272 	   does is print "new-born %s has disappeared" and removes the entry.
273 	   We probably should do the same.  */
274 	status = T_ADDED;
275     else if (vers->ts_user != NULL
276 	     && vers->ts_rcs != NULL
277 	     && (args->force || strcmp (vers->ts_user, vers->ts_rcs) != 0))
278 	/* If we are forcing commits, pretend that the file is
279            modified.  */
280 	status = T_MODIFIED;
281     else
282     {
283 	/* This covers unmodified files, as well as a variety of other
284 	   cases.  FIXME: we probably should be printing a message and
285 	   returning 1 for many of those cases (but I'm not sure
286 	   exactly which ones).  */
287 	return 0;
288     }
289 
290     node = getnode ();
291     node->key = xstrdup (finfo->fullname);
292 
293     data = (struct logfile_info *) xmalloc (sizeof (struct logfile_info));
294     data->type = status;
295     data->tag = xstrdup (vers->tag);
296     data->rev_old = data->rev_new = NULL;
297 
298     node->type = UPDATE;
299     node->delproc = update_delproc;
300     node->data = (char *) data;
301     (void)addnode (args->ulist, node);
302 
303     ++args->argc;
304 
305     freevers_ts (&vers);
306     return 0;
307 }
308 
309 static int copy_ulist PROTO ((Node *, void *));
310 
311 static int
312 copy_ulist (node, data)
313     Node *node;
314     void *data;
315 {
316     struct find_data *args = (struct find_data *)data;
317     args->argv[args->argc++] = node->key;
318     return 0;
319 }
320 #endif /* CLIENT_SUPPORT */
321 
322 int
323 commit (argc, argv)
324     int argc;
325     char **argv;
326 {
327     int c;
328     int err = 0;
329     int local = 0;
330 
331     if (argc == -1)
332 	usage (commit_usage);
333 
334 #ifdef CVS_BADROOT
335     /*
336      * For log purposes, do not allow "root" to commit files.  If you look
337      * like root, but are really logged in as a non-root user, it's OK.
338      */
339     /* FIXME: Shouldn't this check be much more closely related to the
340        readonly user stuff (CVSROOT/readers, &c).  That is, why should
341        root be able to "cvs init", "cvs import", &c, but not "cvs ci"?  */
342     if (geteuid () == (uid_t) 0
343 #  ifdef CLIENT_SUPPORT
344 	/* Who we are on the client side doesn't affect logging.  */
345 	&& !client_active
346 #  endif
347 	)
348     {
349 	struct passwd *pw;
350 
351 	if ((pw = (struct passwd *) getpwnam (getcaller ())) == NULL)
352 	    error (1, 0, "you are unknown to this system");
353 	if (pw->pw_uid == (uid_t) 0)
354 	    error (1, 0, "cannot commit files as 'root'");
355     }
356 #endif /* CVS_BADROOT */
357 
358     optind = 0;
359     while ((c = getopt (argc, argv, "+nlRm:fF:r:")) != -1)
360     {
361 	switch (c)
362 	{
363 	    case 'n':
364 		run_module_prog = 0;
365 		break;
366 	    case 'm':
367 #ifdef FORCE_USE_EDITOR
368 		use_editor = 1;
369 #else
370 		use_editor = 0;
371 #endif
372 		if (saved_message)
373 		{
374 		    free (saved_message);
375 		    saved_message = NULL;
376 		}
377 
378 		saved_message = xstrdup(optarg);
379 		break;
380 	    case 'r':
381 		if (saved_tag)
382 		    free (saved_tag);
383 		saved_tag = xstrdup (optarg);
384 		break;
385 	    case 'l':
386 		local = 1;
387 		break;
388 	    case 'R':
389 		local = 0;
390 		break;
391 	    case 'f':
392 		force_ci = 1;
393 		local = 1;		/* also disable recursion */
394 		break;
395 	    case 'F':
396 #ifdef FORCE_USE_EDITOR
397 		use_editor = 1;
398 #else
399 		use_editor = 0;
400 #endif
401 		logfile = optarg;
402 		break;
403 	    case '?':
404 	    default:
405 		usage (commit_usage);
406 		break;
407 	}
408     }
409     argc -= optind;
410     argv += optind;
411 
412     /* numeric specified revision means we ignore sticky tags... */
413     if (saved_tag && isdigit ((unsigned char) *saved_tag))
414     {
415 	aflag = 1;
416 	/* strip trailing dots */
417 	while (saved_tag[strlen (saved_tag) - 1] == '.')
418 	    saved_tag[strlen (saved_tag) - 1] = '\0';
419     }
420 
421     /* some checks related to the "-F logfile" option */
422     if (logfile)
423     {
424 	int n, logfd;
425 	struct stat statbuf;
426 
427 	if (saved_message)
428 	    error (1, 0, "cannot specify both a message and a log file");
429 
430 	/* FIXME: Why is this binary?  Needs more investigation.  */
431 	if ((logfd = CVS_OPEN (logfile, O_RDONLY | OPEN_BINARY)) < 0)
432 	    error (1, errno, "cannot open log file %s", logfile);
433 
434 	if (fstat(logfd, &statbuf) < 0)
435 	    error (1, errno, "cannot find size of log file %s", logfile);
436 
437 	saved_message = xmalloc (statbuf.st_size + 1);
438 
439 	/* FIXME: Should keep reading until EOF, rather than assuming the
440 	   first read gets the whole thing.  */
441 	if ((n = read (logfd, saved_message, statbuf.st_size + 1)) < 0)
442 	    error (1, errno, "cannot read log message from %s", logfile);
443 
444 	(void) close (logfd);
445 	saved_message[n] = '\0';
446     }
447 
448 #ifdef CLIENT_SUPPORT
449     if (client_active)
450     {
451 	struct find_data find_args;
452 
453 	ign_setup ();
454 
455 	find_args.ulist = getlist ();
456 	find_args.argc = 0;
457 	find_args.questionables = NULL;
458 	find_args.ignlist = NULL;
459 	find_args.repository = NULL;
460 
461 	/* It is possible that only a numeric tag should set this.
462 	   I haven't really thought about it much.
463 	   Anyway, I suspect that setting it unnecessarily only causes
464 	   a little unneeded network traffic.  */
465 	find_args.force = force_ci || saved_tag != NULL;
466 
467 	err = start_recursion (find_fileproc, find_filesdoneproc,
468 			       find_dirent_proc, (DIRLEAVEPROC) NULL,
469 			       (void *)&find_args,
470 			       argc, argv, local, W_LOCAL, 0, 0,
471 			       (char *)NULL, 0);
472 	if (err)
473 	    error (1, 0, "correct above errors first!");
474 
475 	if (find_args.argc == 0)
476 	    /* Nothing to commit.  Exit now without contacting the
477 	       server (note that this means that we won't print "?
478 	       foo" for files which merit it, because we don't know
479 	       what is in the CVSROOT/cvsignore file).  */
480 	    return 0;
481 
482 	/* Now we keep track of which files we actually are going to
483 	   operate on, and only work with those files in the future.
484 	   This saves time--we don't want to search the file system
485 	   of the working directory twice.  */
486 	find_args.argv = (char **) xmalloc (find_args.argc * sizeof (char **));
487 	find_args.argc = 0;
488 	walklist (find_args.ulist, copy_ulist, &find_args);
489 
490 	/* Do this before calling do_editor; don't ask for a log
491 	   message if we can't talk to the server.  But do it after we
492 	   have made the checks that we can locally (to more quickly
493 	   catch syntax errors, the case where no files are modified,
494 	   added or removed, etc.).
495 
496 	   On the other hand, calling start_server before do_editor
497 	   means that we chew up server resources the whole time that
498 	   the user has the editor open (hours or days if the user
499 	   forgets about it), which seems dubious.  */
500 	start_server ();
501 
502 	/*
503 	 * We do this once, not once for each directory as in normal CVS.
504 	 * The protocol is designed this way.  This is a feature.
505 	 */
506 	if (use_editor)
507 	    do_editor (".", &saved_message, (char *)NULL, find_args.ulist);
508 
509 	/* Run the user-defined script to verify/check information in
510 	 *the log message
511 	 */
512 	do_verify (saved_message, (char *)NULL);
513 
514 	/* We always send some sort of message, even if empty.  */
515 	/* FIXME: is that true?  There seems to be some code in do_editor
516 	   which can leave the message NULL.  */
517 	option_with_arg ("-m", saved_message);
518 
519 	/* OK, now process all the questionable files we have been saving
520 	   up.  */
521 	{
522 	    struct question *p;
523 	    struct question *q;
524 
525 	    p = find_args.questionables;
526 	    while (p != NULL)
527 	    {
528 		if (ign_inhibit_server || !supported_request ("Questionable"))
529 		{
530 		    cvs_output ("? ", 2);
531 		    if (p->dir[0] != '\0')
532 		    {
533 			cvs_output (p->dir, 0);
534 			cvs_output ("/", 1);
535 		    }
536 		    cvs_output (p->file, 0);
537 		    cvs_output ("\n", 1);
538 		}
539 		else
540 		{
541 		    send_to_server ("Directory ", 0);
542 		    send_to_server (p->dir[0] == '\0' ? "." : p->dir, 0);
543 		    send_to_server ("\012", 1);
544 		    send_to_server (p->repos, 0);
545 		    send_to_server ("\012", 1);
546 
547 		    send_to_server ("Questionable ", 0);
548 		    send_to_server (p->file, 0);
549 		    send_to_server ("\012", 1);
550 		}
551 		free (p->dir);
552 		free (p->repos);
553 		free (p->file);
554 		q = p->next;
555 		free (p);
556 		p = q;
557 	    }
558 	}
559 
560 	if (local)
561 	    send_arg("-l");
562 	if (force_ci)
563 	    send_arg("-f");
564 	if (!run_module_prog)
565 	    send_arg("-n");
566 	option_with_arg ("-r", saved_tag);
567 
568 	/* FIXME: This whole find_args.force/SEND_FORCE business is a
569 	   kludge.  It would seem to be a server bug that we have to
570 	   say that files are modified when they are not.  This makes
571 	   "cvs commit -r 2" across a whole bunch of files a very slow
572 	   operation (and it isn't documented in cvsclient.texi).  I
573 	   haven't looked at the server code carefully enough to be
574 	   _sure_ why this is needed, but if it is because the "ci"
575 	   program, which we used to call, wanted the file to exist,
576 	   then it would be relatively simple to fix in the server.  */
577 	send_files (find_args.argc, find_args.argv, local, 0,
578 		    find_args.force ? SEND_FORCE : 0);
579 
580 	/* Sending only the names of the files which were modified, added,
581 	   or removed means that the server will only do an up-to-date
582 	   check on those files.  This is different from local CVS and
583 	   previous versions of client/server CVS, but it probably is a Good
584 	   Thing, or at least Not Such A Bad Thing.  */
585 	send_file_names (find_args.argc, find_args.argv, 0);
586 
587 	send_to_server ("ci\012", 0);
588 	err = get_responses_and_close ();
589 	if (err != 0 && use_editor && saved_message != NULL)
590 	{
591 	    /* If there was an error, don't nuke the user's carefully
592 	       constructed prose.  This is something of a kludge; a better
593 	       solution is probably more along the lines of #150 in TODO
594 	       (doing a second up-to-date check before accepting the
595 	       log message has also been suggested, but that seems kind of
596 	       iffy because the real up-to-date check could still fail,
597 	       another error could occur, &c.  Also, a second check would
598 	       slow things down).  */
599 
600 	    char *fname;
601 	    FILE *fp;
602 
603 	    fname = cvs_temp_name ();
604 	    fp = CVS_FOPEN (fname, "w+");
605 	    if (fp == NULL)
606 		error (1, 0, "cannot create temporary file %s", fname);
607 	    if (fwrite (saved_message, 1, strlen (saved_message), fp)
608 		!= strlen (saved_message))
609 		error (1, errno, "cannot write temporary file %s", fname);
610 	    if (fclose (fp) < 0)
611 		error (0, errno, "cannot close temporary file %s", fname);
612 	    error (0, 0, "saving log message in %s", fname);
613 	}
614 	return err;
615     }
616 #endif
617 
618     if (saved_tag != NULL)
619 	tag_check_valid (saved_tag, argc, argv, local, aflag, "");
620 
621     /* XXX - this is not the perfect check for this */
622     if (argc <= 0)
623 	write_dirtag = saved_tag;
624 
625     wrap_setup ();
626 
627     lock_tree_for_write (argc, argv, local, aflag);
628 
629     /*
630      * Set up the master update list and hard link list
631      */
632     mulist = getlist ();
633 
634 #ifdef PRESERVE_PERMISSIONS_SUPPORT
635     if (preserve_perms)
636     {
637 	hardlist = getlist ();
638 
639 	/*
640 	 * We need to save the working directory so that
641 	 * check_fileproc can construct a full pathname for each file.
642 	 */
643 	working_dir = xgetwd();
644     }
645 #endif
646 
647     /*
648      * Run the recursion processor to verify the files are all up-to-date
649      */
650     err = start_recursion (check_fileproc, check_filesdoneproc,
651 			   check_direntproc, (DIRLEAVEPROC) NULL, NULL, argc,
652 			   argv, local, W_LOCAL, aflag, 0, (char *) NULL, 1);
653     if (err)
654     {
655 	Lock_Cleanup ();
656 	error (1, 0, "correct above errors first!");
657     }
658 
659     /*
660      * Run the recursion processor to commit the files
661      */
662     write_dirnonbranch = 0;
663     if (noexec == 0)
664 	err = start_recursion (commit_fileproc, commit_filesdoneproc,
665 			       commit_direntproc, commit_dirleaveproc, NULL,
666 			       argc, argv, local, W_LOCAL, aflag, 0,
667 			       (char *) NULL, 1);
668 
669     /*
670      * Unlock all the dirs and clean up
671      */
672     Lock_Cleanup ();
673     dellist (&mulist);
674 
675     if (last_register_time)
676     {
677 	time_t now;
678 
679 	(void) time (&now);
680 	if (now == last_register_time)
681 	{
682 	    sleep (1);			/* to avoid time-stamp races */
683 	}
684     }
685 
686     return (err);
687 }
688 
689 /* This routine determines the status of a given file and retrieves
690    the version information that is associated with that file. */
691 
692 static
693 Ctype
694 classify_file_internal (finfo, vers)
695     struct file_info *finfo;
696     Vers_TS **vers;
697 {
698     int save_noexec, save_quiet, save_really_quiet;
699     Ctype status;
700 
701     /* FIXME: Do we need to save quiet as well as really_quiet?  Last
702        time I glanced at Classify_File I only saw it looking at really_quiet
703        not quiet.  */
704     save_noexec = noexec;
705     save_quiet = quiet;
706     save_really_quiet = really_quiet;
707     noexec = quiet = really_quiet = 1;
708 
709     /* handle specified numeric revision specially */
710     if (saved_tag && isdigit ((unsigned char) *saved_tag))
711     {
712 	/* If the tag is for the trunk, make sure we're at the head */
713 	if (numdots (saved_tag) < 2)
714 	{
715 	    status = Classify_File (finfo, (char *) NULL, (char *) NULL,
716 				    (char *) NULL, 1, aflag, vers, 0);
717 	    if (status == T_UPTODATE || status == T_MODIFIED ||
718 		status == T_ADDED)
719 	    {
720 		Ctype xstatus;
721 
722 		freevers_ts (vers);
723 		xstatus = Classify_File (finfo, saved_tag, (char *) NULL,
724 					 (char *) NULL, 1, aflag, vers, 0);
725 		if (xstatus == T_REMOVE_ENTRY)
726 		    status = T_MODIFIED;
727 		else if (status == T_MODIFIED && xstatus == T_CONFLICT)
728 		    status = T_MODIFIED;
729 		else
730 		    status = xstatus;
731 	    }
732 	}
733 	else
734 	{
735 	    char *xtag, *cp;
736 
737 	    /*
738 	     * The revision is off the main trunk; make sure we're
739 	     * up-to-date with the head of the specified branch.
740 	     */
741 	    xtag = xstrdup (saved_tag);
742 	    if ((numdots (xtag) & 1) != 0)
743 	    {
744 		cp = strrchr (xtag, '.');
745 		*cp = '\0';
746 	    }
747 	    status = Classify_File (finfo, xtag, (char *) NULL,
748 				    (char *) NULL, 1, aflag, vers, 0);
749 	    if ((status == T_REMOVE_ENTRY || status == T_CONFLICT)
750 		&& (cp = strrchr (xtag, '.')) != NULL)
751 	    {
752 		/* pluck one more dot off the revision */
753 		*cp = '\0';
754 		freevers_ts (vers);
755 		status = Classify_File (finfo, xtag, (char *) NULL,
756 					(char *) NULL, 1, aflag, vers, 0);
757 		if (status == T_UPTODATE || status == T_REMOVE_ENTRY)
758 		    status = T_MODIFIED;
759 	    }
760 	    /* now, muck with vers to make the tag correct */
761 	    free ((*vers)->tag);
762 	    (*vers)->tag = xstrdup (saved_tag);
763 	    free (xtag);
764 	}
765     }
766     else
767 	status = Classify_File (finfo, saved_tag, (char *) NULL, (char *) NULL,
768 				1, 0, vers, 0);
769     noexec = save_noexec;
770     quiet = save_quiet;
771     really_quiet = save_really_quiet;
772 
773     return status;
774 }
775 
776 /*
777  * Check to see if a file is ok to commit and make sure all files are
778  * up-to-date
779  */
780 /* ARGSUSED */
781 static int
782 check_fileproc (callerdat, finfo)
783     void *callerdat;
784     struct file_info *finfo;
785 {
786     Ctype status;
787     char *xdir;
788     Node *p;
789     List *ulist, *cilist;
790     Vers_TS *vers;
791     struct commit_info *ci;
792     struct logfile_info *li;
793 
794     size_t cvsroot_len = strlen (CVSroot_directory);
795 
796     if (strncmp (finfo->repository, CVSroot_directory, cvsroot_len) == 0
797 	&& ISDIRSEP (finfo->repository[cvsroot_len])
798 	&& strncmp (finfo->repository + cvsroot_len + 1,
799 		    CVSROOTADM,
800 		    sizeof (CVSROOTADM) - 1) == 0
801 	&& ISDIRSEP (finfo->repository[cvsroot_len + sizeof (CVSROOTADM)])
802 	&& strcmp (finfo->repository + cvsroot_len + sizeof (CVSROOTADM) + 1,
803 		   CVSNULLREPOS) == 0
804 	)
805 	error (1, 0, "cannot check in to %s", finfo->repository);
806 
807     status = classify_file_internal (finfo, &vers);
808 
809     /*
810      * If the force-commit option is enabled, and the file in question
811      * appears to be up-to-date, just make it look modified so that
812      * it will be committed.
813      */
814     if (force_ci && status == T_UPTODATE)
815 	status = T_MODIFIED;
816 
817     switch (status)
818     {
819 	case T_CHECKOUT:
820 #ifdef SERVER_SUPPORT
821 	case T_PATCH:
822 #endif
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
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 		    char *rcs;
937 
938 		    rcs = xmalloc (strlen (finfo->repository)
939 				   + strlen (finfo->file)
940 				   + sizeof RCSEXT
941 				   + 5);
942 
943 		    /* Don't look in the attic; if it exists there we
944 		       will move it back out in checkaddfile.  */
945 		    sprintf(rcs, "%s/%s%s", finfo->repository, finfo->file,
946 			    RCSEXT);
947 		    if (isreadable (rcs))
948 		    {
949 			error (0, 0,
950 		    "cannot add file `%s' when RCS file `%s' already exists",
951 			       finfo->fullname, rcs);
952 			freevers_ts (&vers);
953 			free (rcs);
954 			return (1);
955 		    }
956 		    free (rcs);
957 		}
958 		if (vers->tag && isdigit ((unsigned char) *vers->tag) &&
959 		    numdots (vers->tag) > 1)
960 		{
961 		    error (0, 0,
962 		"cannot add file `%s' with revision `%s'; must be on trunk",
963 			       finfo->fullname, vers->tag);
964 		    freevers_ts (&vers);
965 		    return (1);
966 		}
967 	    }
968 
969 	    /* done with consistency checks; now, to get on with the commit */
970 	    if (finfo->update_dir[0] == '\0')
971 		xdir = ".";
972 	    else
973 		xdir = finfo->update_dir;
974 	    if ((p = findnode (mulist, xdir)) != NULL)
975 	    {
976 		ulist = ((struct master_lists *) p->data)->ulist;
977 		cilist = ((struct master_lists *) p->data)->cilist;
978 	    }
979 	    else
980 	    {
981 		struct master_lists *ml;
982 
983 		ulist = getlist ();
984 		cilist = getlist ();
985 		p = getnode ();
986 		p->key = xstrdup (xdir);
987 		p->type = UPDATE;
988 		ml = (struct master_lists *)
989 		    xmalloc (sizeof (struct master_lists));
990 		ml->ulist = ulist;
991 		ml->cilist = cilist;
992 		p->data = (char *) ml;
993 		p->delproc = masterlist_delproc;
994 		(void) addnode (mulist, p);
995 	    }
996 
997 	    /* first do ulist, then cilist */
998 	    p = getnode ();
999 	    p->key = xstrdup (finfo->file);
1000 	    p->type = UPDATE;
1001 	    p->delproc = update_delproc;
1002 	    li = ((struct logfile_info *)
1003 		  xmalloc (sizeof (struct logfile_info)));
1004 	    li->type = status;
1005 	    li->tag = xstrdup (vers->tag);
1006 	    li->rev_old = xstrdup (vers->vn_rcs);
1007 	    li->rev_new = NULL;
1008 	    p->data = (char *) li;
1009 	    (void) addnode (ulist, p);
1010 
1011 	    p = getnode ();
1012 	    p->key = xstrdup (finfo->file);
1013 	    p->type = UPDATE;
1014 	    p->delproc = ci_delproc;
1015 	    ci = (struct commit_info *) xmalloc (sizeof (struct commit_info));
1016 	    ci->status = status;
1017 	    if (vers->tag)
1018 		if (isdigit ((unsigned char) *vers->tag))
1019 		    ci->rev = xstrdup (vers->tag);
1020 		else
1021 		    ci->rev = RCS_whatbranch (finfo->rcs, vers->tag);
1022 	    else
1023 		ci->rev = (char *) NULL;
1024 	    ci->tag = xstrdup (vers->tag);
1025 	    ci->options = xstrdup(vers->options);
1026 	    p->data = (char *) ci;
1027 	    (void) addnode (cilist, p);
1028 
1029 #ifdef PRESERVE_PERMISSIONS_SUPPORT
1030 	    if (preserve_perms)
1031 	    {
1032 		/* Add this file to hardlist, indexed on its inode.  When
1033 		   we are done, we can find out what files are hardlinked
1034 		   to a given file by looking up its inode in hardlist. */
1035 		char *fullpath;
1036 		Node *linkp;
1037 		struct hardlink_info *hlinfo;
1038 
1039 		/* Get the full pathname of the current file. */
1040 		fullpath = xmalloc (strlen(working_dir) +
1041 				    strlen(finfo->fullname) + 2);
1042 		sprintf (fullpath, "%s/%s", working_dir, finfo->fullname);
1043 
1044 		/* To permit following links in subdirectories, files
1045                    are keyed on finfo->fullname, not on finfo->name. */
1046 		linkp = lookup_file_by_inode (fullpath);
1047 
1048 		/* If linkp is NULL, the file doesn't exist... maybe
1049 		   we're doing a remove operation? */
1050 		if (linkp != NULL)
1051 		{
1052 		    /* Create a new hardlink_info node, which will record
1053 		       the current file's status and the links listed in its
1054 		       `hardlinks' delta field.  We will append this
1055 		       hardlink_info node to the appropriate hardlist entry. */
1056 		    hlinfo = (struct hardlink_info *)
1057 			xmalloc (sizeof (struct hardlink_info));
1058 		    hlinfo->status = status;
1059 		    linkp->data = (char *) hlinfo;
1060 		}
1061 	    }
1062 #endif
1063 
1064 	    break;
1065 	case T_UNKNOWN:
1066 	    error (0, 0, "nothing known about `%s'", finfo->fullname);
1067 	    freevers_ts (&vers);
1068 	    return (1);
1069 	case T_UPTODATE:
1070 	    break;
1071 	default:
1072 	    error (0, 0, "CVS internal error: unknown status %d", status);
1073 	    break;
1074     }
1075 
1076     freevers_ts (&vers);
1077     return (0);
1078 }
1079 
1080 /*
1081  * By default, return the code that tells do_recursion to examine all
1082  * directories
1083  */
1084 /* ARGSUSED */
1085 static Dtype
1086 check_direntproc (callerdat, dir, repos, update_dir, entries)
1087     void *callerdat;
1088     char *dir;
1089     char *repos;
1090     char *update_dir;
1091     List *entries;
1092 {
1093     if (!isdir (dir))
1094 	return (R_SKIP_ALL);
1095 
1096     if (!quiet)
1097 	error (0, 0, "Examining %s", update_dir);
1098 
1099     return (R_PROCESS);
1100 }
1101 
1102 /*
1103  * Walklist proc to run pre-commit checks
1104  */
1105 static int
1106 precommit_list_proc (p, closure)
1107     Node *p;
1108     void *closure;
1109 {
1110     struct logfile_info *li;
1111 
1112     li = (struct logfile_info *) p->data;
1113     if (li->type == T_ADDED
1114 	|| li->type == T_MODIFIED
1115 	|| li->type == T_REMOVED)
1116     {
1117 	run_arg (p->key);
1118     }
1119     return (0);
1120 }
1121 
1122 /*
1123  * Callback proc for pre-commit checking
1124  */
1125 static int
1126 precommit_proc (repository, filter)
1127     char *repository;
1128     char *filter;
1129 {
1130     /* see if the filter is there, only if it's a full path */
1131     if (isabsolute (filter))
1132     {
1133     	char *s, *cp;
1134 
1135 	s = xstrdup (filter);
1136 	for (cp = s; *cp; cp++)
1137 	    if (isspace ((unsigned char) *cp))
1138 	    {
1139 		*cp = '\0';
1140 		break;
1141 	    }
1142 	if (!isfile (s))
1143 	{
1144 	    error (0, errno, "cannot find pre-commit filter `%s'", s);
1145 	    free (s);
1146 	    return (1);			/* so it fails! */
1147 	}
1148 	free (s);
1149     }
1150 
1151     run_setup (filter);
1152     run_arg (repository);
1153     (void) walklist (saved_ulist, precommit_list_proc, NULL);
1154     return (run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL|RUN_REALLY));
1155 }
1156 
1157 /*
1158  * Run the pre-commit checks for the dir
1159  */
1160 /* ARGSUSED */
1161 static int
1162 check_filesdoneproc (callerdat, err, repos, update_dir, entries)
1163     void *callerdat;
1164     int err;
1165     char *repos;
1166     char *update_dir;
1167     List *entries;
1168 {
1169     int n;
1170     Node *p;
1171 
1172     /* find the update list for this dir */
1173     p = findnode (mulist, update_dir);
1174     if (p != NULL)
1175 	saved_ulist = ((struct master_lists *) p->data)->ulist;
1176     else
1177 	saved_ulist = (List *) NULL;
1178 
1179     /* skip the checks if there's nothing to do */
1180     if (saved_ulist == NULL || saved_ulist->list->next == saved_ulist->list)
1181 	return (err);
1182 
1183     /* run any pre-commit checks */
1184     if ((n = Parse_Info (CVSROOTADM_COMMITINFO, repos, precommit_proc, 1)) > 0)
1185     {
1186 	error (0, 0, "Pre-commit check failed");
1187 	err += n;
1188     }
1189 
1190     return (err);
1191 }
1192 
1193 /*
1194  * Do the work of committing a file
1195  */
1196 static int maxrev;
1197 static char *sbranch;
1198 
1199 /* ARGSUSED */
1200 static int
1201 commit_fileproc (callerdat, finfo)
1202     void *callerdat;
1203     struct file_info *finfo;
1204 {
1205     Node *p;
1206     int err = 0;
1207     List *ulist, *cilist;
1208     struct commit_info *ci;
1209 
1210     /* Keep track of whether write_dirtag is a branch tag.
1211        Note that if it is a branch tag in some files and a nonbranch tag
1212        in others, treat it as a nonbranch tag.  It is possible that case
1213        should elicit a warning or an error.  */
1214     if (write_dirtag != NULL
1215 	&& finfo->rcs != NULL)
1216     {
1217 	char *rev = RCS_getversion (finfo->rcs, write_dirtag, NULL, 1, NULL);
1218 	if (rev != NULL
1219 	    && !RCS_nodeisbranch (finfo->rcs, write_dirtag))
1220 	    write_dirnonbranch = 1;
1221 	if (rev != NULL)
1222 	    free (rev);
1223     }
1224 
1225     if (finfo->update_dir[0] == '\0')
1226 	p = findnode (mulist, ".");
1227     else
1228 	p = findnode (mulist, finfo->update_dir);
1229 
1230     /*
1231      * if p is null, there were file type command line args which were
1232      * all up-to-date so nothing really needs to be done
1233      */
1234     if (p == NULL)
1235 	return (0);
1236     ulist = ((struct master_lists *) p->data)->ulist;
1237     cilist = ((struct master_lists *) p->data)->cilist;
1238 
1239     /*
1240      * At this point, we should have the commit message unless we were called
1241      * with files as args from the command line.  In that latter case, we
1242      * need to get the commit message ourselves
1243      */
1244     if (!(got_message))
1245     {
1246 	got_message = 1;
1247 	if (use_editor)
1248 	    do_editor (finfo->update_dir, &saved_message,
1249 		       finfo->repository, ulist);
1250 	do_verify (saved_message, finfo->repository);
1251     }
1252 
1253     p = findnode (cilist, finfo->file);
1254     if (p == NULL)
1255 	return (0);
1256 
1257     ci = (struct commit_info *) p->data;
1258     if (ci->status == T_MODIFIED)
1259     {
1260 	if (finfo->rcs == NULL)
1261 	    error (1, 0, "internal error: no parsed RCS file");
1262 	if (lock_RCS (finfo->file, finfo->rcs, ci->rev,
1263 		      finfo->repository) != 0)
1264 	{
1265 	    unlockrcs (finfo->rcs);
1266 	    err = 1;
1267 	    goto out;
1268 	}
1269     }
1270     else if (ci->status == T_ADDED)
1271     {
1272 	if (checkaddfile (finfo->file, finfo->repository, ci->tag, ci->options,
1273 			  &finfo->rcs) != 0)
1274 	{
1275 	    fixaddfile (finfo->file, finfo->repository);
1276 	    err = 1;
1277 	    goto out;
1278 	}
1279 
1280 	/* adding files with a tag, now means adding them on a branch.
1281 	   Since the branch test was done in check_fileproc for
1282 	   modified files, we need to stub it in again here. */
1283 
1284 	if (ci->tag
1285 
1286 	    /* If numeric, it is on the trunk; check_fileproc enforced
1287 	       this.  */
1288 	    && !isdigit ((unsigned char) ci->tag[0]))
1289 	{
1290 	    if (finfo->rcs == NULL)
1291 		error (1, 0, "internal error: no parsed RCS file");
1292 	    ci->rev = RCS_whatbranch (finfo->rcs, ci->tag);
1293 	    err = Checkin ('A', finfo, finfo->rcs->path, ci->rev,
1294 			   ci->tag, ci->options, saved_message);
1295 	    if (err != 0)
1296 	    {
1297 		unlockrcs (finfo->rcs);
1298 		fixbranch (finfo->rcs, sbranch);
1299 	    }
1300 
1301 	    (void) time (&last_register_time);
1302 
1303 	    ci->status = T_UPTODATE;
1304 	}
1305     }
1306 
1307     /*
1308      * Add the file for real
1309      */
1310     if (ci->status == T_ADDED)
1311     {
1312 	char *xrev = (char *) NULL;
1313 
1314 	if (ci->rev == NULL)
1315 	{
1316 	    /* find the max major rev number in this directory */
1317 	    maxrev = 0;
1318 	    (void) walklist (finfo->entries, findmaxrev, NULL);
1319 	    if (maxrev == 0)
1320 		maxrev = 1;
1321 	    xrev = xmalloc (20);
1322 	    (void) sprintf (xrev, "%d", maxrev);
1323 	}
1324 
1325 	/* XXX - an added file with symbolic -r should add tag as well */
1326 	err = finaladd (finfo, ci->rev ? ci->rev : xrev, ci->tag, ci->options);
1327 	if (xrev)
1328 	    free (xrev);
1329     }
1330     else if (ci->status == T_MODIFIED)
1331     {
1332 	err = Checkin ('M', finfo,
1333 		       finfo->rcs->path, ci->rev, ci->tag,
1334 		       ci->options, saved_message);
1335 
1336 	(void) time (&last_register_time);
1337 
1338 	if (err != 0)
1339 	{
1340 	    unlockrcs (finfo->rcs);
1341 	    fixbranch (finfo->rcs, sbranch);
1342 	}
1343     }
1344     else if (ci->status == T_REMOVED)
1345     {
1346 	err = remove_file (finfo, ci->tag, saved_message);
1347 #ifdef SERVER_SUPPORT
1348 	if (server_active) {
1349 	    server_scratch_entry_only ();
1350 	    server_updated (finfo,
1351 			    NULL,
1352 
1353 			    /* Doesn't matter, it won't get checked.  */
1354 			    SERVER_UPDATED,
1355 
1356 			    (mode_t) -1,
1357 			    (unsigned char *) NULL,
1358 			    (struct buffer *) NULL);
1359 	}
1360 #endif
1361     }
1362 
1363     /* Clearly this is right for T_MODIFIED.  I haven't thought so much
1364        about T_ADDED or T_REMOVED.  */
1365     notify_do ('C', finfo->file, getcaller (), NULL, NULL, finfo->repository);
1366 
1367 out:
1368     if (err != 0)
1369     {
1370 	/* on failure, remove the file from ulist */
1371 	p = findnode (ulist, finfo->file);
1372 	if (p)
1373 	    delnode (p);
1374     }
1375     else
1376     {
1377 	/* On success, retrieve the new version number of the file and
1378            copy it into the log information (see logmsg.c
1379            (logfile_write) for more details).  We should only update
1380            the version number for files that have been added or
1381            modified but not removed.  Why?  classify_file_internal
1382            will return the version number of a file even after it has
1383            been removed from the archive, which is not the behavior we
1384            want for our commitlog messages; we want the old version
1385            number and then "NONE." */
1386 
1387 	if (ci->status != T_REMOVED)
1388 	{
1389 	    p = findnode (ulist, finfo->file);
1390 	    if (p)
1391 	    {
1392 		Vers_TS *vers;
1393 		struct logfile_info *li;
1394 
1395 		(void) classify_file_internal (finfo, &vers);
1396 		li = (struct logfile_info *) p->data;
1397 		li->rev_new = xstrdup (vers->vn_rcs);
1398 		freevers_ts (&vers);
1399 	    }
1400 	}
1401     }
1402 
1403     return (err);
1404 }
1405 
1406 /*
1407  * Log the commit and clean up the update list
1408  */
1409 /* ARGSUSED */
1410 static int
1411 commit_filesdoneproc (callerdat, err, repository, update_dir, entries)
1412     void *callerdat;
1413     int err;
1414     char *repository;
1415     char *update_dir;
1416     List *entries;
1417 {
1418     Node *p;
1419     List *ulist;
1420 
1421     p = findnode (mulist, update_dir);
1422     if (p == NULL)
1423 	return (err);
1424 
1425     ulist = ((struct master_lists *) p->data)->ulist;
1426 
1427     got_message = 0;
1428 
1429 
1430     Update_Logfile (repository, saved_message, (FILE *) 0, ulist);
1431 
1432     /* Build the administrative files if necessary.  */
1433     {
1434 	char *p;
1435 
1436 	if (strncmp (CVSroot_directory, repository,
1437 		     strlen (CVSroot_directory)) != 0)
1438 	    error (0, 0,
1439 		 "internal error: repository (%s) doesn't begin with root (%s)",
1440 		   repository, CVSroot_directory);
1441 	p = repository + strlen (CVSroot_directory);
1442 	if (*p == '/')
1443 	    ++p;
1444 	if (strcmp ("CVSROOT", p) == 0
1445 	    /* Check for subdirectories because people may want to create
1446 	       subdirectories and list files therein in checkoutlist.  */
1447 	    || strncmp ("CVSROOT/", p, strlen ("CVSROOT/")) == 0
1448 	    )
1449 	{
1450 	    /* "Database" might a little bit grandiose and/or vague,
1451 	       but "checked-out copies of administrative files, unless
1452 	       in the case of modules and you are using ndbm in which
1453 	       case modules.{pag,dir,db}" is verbose and excessively
1454 	       focused on how the database is implemented.  */
1455 
1456 	    /* mkmodules requires the absolute name of the CVSROOT directory.
1457 	       Remove anything after the `CVSROOT' component -- this is
1458 	       necessary when committing in a subdirectory of CVSROOT.  */
1459 	    char *admin_dir = xstrdup (repository);
1460 	    int cvsrootlen = strlen ("CVSROOT");
1461 	    assert (admin_dir[p - repository + cvsrootlen] == '\0'
1462 		    || admin_dir[p - repository + cvsrootlen] == '/');
1463 	    admin_dir[p - repository + cvsrootlen] = '\0';
1464 
1465 	    cvs_output (program_name, 0);
1466 	    cvs_output (" ", 1);
1467 	    cvs_output (command_name, 0);
1468 	    cvs_output (": Rebuilding administrative file database\n", 0);
1469 	    mkmodules (admin_dir);
1470 	    free (admin_dir);
1471 	}
1472     }
1473 
1474     if (err == 0 && run_module_prog)
1475     {
1476 	FILE *fp;
1477 
1478 	if ((fp = CVS_FOPEN (CVSADM_CIPROG, "r")) != NULL)
1479 	{
1480 	    char *line;
1481 	    int line_length;
1482 	    size_t line_chars_allocated;
1483 	    char *repos;
1484 
1485 	    line = NULL;
1486 	    line_chars_allocated = 0;
1487 	    line_length = getline (&line, &line_chars_allocated, fp);
1488 	    if (line_length > 0)
1489 	    {
1490 		/* Remove any trailing newline.  */
1491 		if (line[line_length - 1] == '\n')
1492 		    line[--line_length] = '\0';
1493 		repos = Name_Repository ((char *) NULL, update_dir);
1494 		run_setup (line);
1495 		run_arg (repos);
1496 		cvs_output (program_name, 0);
1497 		cvs_output (" ", 1);
1498 		cvs_output (command_name, 0);
1499 		cvs_output (": Executing '", 0);
1500 		run_print (stdout);
1501 		cvs_output ("'\n", 0);
1502 		(void) run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL);
1503 		free (repos);
1504 	    }
1505 	    else
1506 	    {
1507 		if (ferror (fp))
1508 		    error (0, errno, "warning: error reading %s",
1509 			   CVSADM_CIPROG);
1510 	    }
1511 	    if (line != NULL)
1512 		free (line);
1513 	    if (fclose (fp) < 0)
1514 		error (0, errno, "warning: cannot close %s", CVSADM_CIPROG);
1515 	}
1516 	else
1517 	{
1518 	    if (! existence_error (errno))
1519 		error (0, errno, "warning: cannot open %s", CVSADM_CIPROG);
1520 	}
1521     }
1522 
1523     return (err);
1524 }
1525 
1526 /*
1527  * Get the log message for a dir
1528  */
1529 /* ARGSUSED */
1530 static Dtype
1531 commit_direntproc (callerdat, dir, repos, update_dir, entries)
1532     void *callerdat;
1533     char *dir;
1534     char *repos;
1535     char *update_dir;
1536     List *entries;
1537 {
1538     Node *p;
1539     List *ulist;
1540     char *real_repos;
1541 
1542     if (!isdir (dir))
1543 	return (R_SKIP_ALL);
1544 
1545     /* find the update list for this dir */
1546     p = findnode (mulist, update_dir);
1547     if (p != NULL)
1548 	ulist = ((struct master_lists *) p->data)->ulist;
1549     else
1550 	ulist = (List *) NULL;
1551 
1552     /* skip the files as an optimization */
1553     if (ulist == NULL || ulist->list->next == ulist->list)
1554 	return (R_SKIP_FILES);
1555 
1556     /* get commit message */
1557     real_repos = Name_Repository (dir, update_dir);
1558     got_message = 1;
1559     if (use_editor)
1560 	do_editor (update_dir, &saved_message, real_repos, ulist);
1561     do_verify (saved_message, real_repos);
1562     free (real_repos);
1563     return (R_PROCESS);
1564 }
1565 
1566 /*
1567  * Process the post-commit proc if necessary
1568  */
1569 /* ARGSUSED */
1570 static int
1571 commit_dirleaveproc (callerdat, dir, err, update_dir, entries)
1572     void *callerdat;
1573     char *dir;
1574     int err;
1575     char *update_dir;
1576     List *entries;
1577 {
1578     /* update the per-directory tag info */
1579     /* FIXME?  Why?  The "commit examples" node of cvs.texinfo briefly
1580        mentions commit -r being sticky, but apparently in the context of
1581        this being a confusing feature!  */
1582     if (err == 0 && write_dirtag != NULL)
1583     {
1584 	WriteTag (NULL, write_dirtag, NULL, write_dirnonbranch,
1585 		  update_dir, Name_Repository (dir, update_dir));
1586     }
1587 
1588     return (err);
1589 }
1590 
1591 /*
1592  * find the maximum major rev number in an entries file
1593  */
1594 static int
1595 findmaxrev (p, closure)
1596     Node *p;
1597     void *closure;
1598 {
1599     char *cp;
1600     int thisrev;
1601     Entnode *entdata;
1602 
1603     entdata = (Entnode *) p->data;
1604     if (entdata->type != ENT_FILE)
1605 	return (0);
1606     cp = strchr (entdata->version, '.');
1607     if (cp != NULL)
1608 	*cp = '\0';
1609     thisrev = atoi (entdata->version);
1610     if (cp != NULL)
1611 	*cp = '.';
1612     if (thisrev > maxrev)
1613 	maxrev = thisrev;
1614     return (0);
1615 }
1616 
1617 /*
1618  * Actually remove a file by moving it to the attic
1619  * XXX - if removing a ,v file that is a relative symbolic link to
1620  * another ,v file, we probably should add a ".." component to the
1621  * link to keep it relative after we move it into the attic.
1622 
1623    Return value is 0 on success, or >0 on error (in which case we have
1624    printed an error message).  */
1625 static int
1626 remove_file (finfo, tag, message)
1627     struct file_info *finfo;
1628     char *tag;
1629     char *message;
1630 {
1631     int retcode;
1632 
1633     int branch;
1634     int lockflag;
1635     char *corev;
1636     char *rev;
1637     char *prev_rev;
1638     char *old_path;
1639 
1640     corev = NULL;
1641     rev = NULL;
1642     prev_rev = NULL;
1643 
1644     retcode = 0;
1645 
1646     if (finfo->rcs == NULL)
1647 	error (1, 0, "internal error: no parsed RCS file");
1648 
1649     branch = 0;
1650     if (tag && !(branch = RCS_nodeisbranch (finfo->rcs, tag)))
1651     {
1652 	/* a symbolic tag is specified; just remove the tag from the file */
1653 	if ((retcode = RCS_deltag (finfo->rcs, tag)) != 0)
1654 	{
1655 	    if (!quiet)
1656 		error (0, retcode == -1 ? errno : 0,
1657 		       "failed to remove tag `%s' from `%s'", tag,
1658 		       finfo->fullname);
1659 	    return (1);
1660 	}
1661 	RCS_rewrite (finfo->rcs, NULL, NULL);
1662 	Scratch_Entry (finfo->entries, finfo->file);
1663 	return (0);
1664     }
1665 
1666     /* we are removing the file from either the head or a branch */
1667     /* commit a new, dead revision. */
1668 
1669     /* Print message indicating that file is going to be removed. */
1670     cvs_output ("Removing ", 0);
1671     cvs_output (finfo->fullname, 0);
1672     cvs_output (";\n", 0);
1673 
1674     rev = NULL;
1675     lockflag = 1;
1676     if (branch)
1677     {
1678 	char *branchname;
1679 
1680 	rev = RCS_whatbranch (finfo->rcs, tag);
1681 	if (rev == NULL)
1682 	{
1683 	    error (0, 0, "cannot find branch \"%s\".", tag);
1684 	    return (1);
1685 	}
1686 
1687 	branchname = RCS_getbranch (finfo->rcs, rev, 1);
1688 	if (branchname == NULL)
1689 	{
1690 	    /* no revision exists on this branch.  use the previous
1691 	       revision but do not lock. */
1692 	    corev = RCS_gettag (finfo->rcs, tag, 1, (int *) NULL);
1693 	    prev_rev = xstrdup(rev);
1694 	    lockflag = 0;
1695 	} else
1696 	{
1697 	    corev = xstrdup (rev);
1698 	    prev_rev = xstrdup(branchname);
1699 	    free (branchname);
1700 	}
1701 
1702     } else  /* Not a branch */
1703     {
1704         /* Get current head revision of file. */
1705 	prev_rev = RCS_head (finfo->rcs);
1706     }
1707 
1708     /* if removing without a tag or a branch, then make sure the default
1709        branch is the trunk. */
1710     if (!tag && !branch)
1711     {
1712         if (RCS_setbranch (finfo->rcs, NULL) != 0)
1713 	{
1714 	    error (0, 0, "cannot change branch to default for %s",
1715 		   finfo->fullname);
1716 	    return (1);
1717 	}
1718 	RCS_rewrite (finfo->rcs, NULL, NULL);
1719     }
1720 
1721     /* check something out.  Generally this is the head.  If we have a
1722        particular rev, then name it.  */
1723     retcode = RCS_checkout (finfo->rcs, finfo->file, rev ? corev : NULL,
1724 			    (char *) NULL, (char *) NULL, RUN_TTY,
1725 			    (RCSCHECKOUTPROC) NULL, (void *) NULL);
1726     if (retcode != 0)
1727     {
1728 	error (0, 0,
1729 	       "failed to check out `%s'", finfo->fullname);
1730 	return (1);
1731     }
1732 
1733     /* Except when we are creating a branch, lock the revision so that
1734        we can check in the new revision.  */
1735     if (lockflag)
1736     {
1737 	if (RCS_lock (finfo->rcs, rev ? corev : NULL, 1) == 0)
1738 	    RCS_rewrite (finfo->rcs, NULL, NULL);
1739     }
1740 
1741     if (corev != NULL)
1742 	free (corev);
1743 
1744     retcode = RCS_checkin (finfo->rcs, finfo->file, message, rev,
1745 			   RCS_FLAGS_DEAD | RCS_FLAGS_QUIET);
1746     if (retcode	!= 0)
1747     {
1748 	if (!quiet)
1749 	    error (0, retcode == -1 ? errno : 0,
1750 		   "failed to commit dead revision for `%s'", finfo->fullname);
1751 	return (1);
1752     }
1753 
1754     if (rev != NULL)
1755 	free (rev);
1756 
1757     old_path = xstrdup (finfo->rcs->path);
1758     if (!branch)
1759 	RCS_setattic (finfo->rcs, 1);
1760 
1761     /* Print message that file was removed. */
1762     cvs_output (old_path, 0);
1763     cvs_output ("  <--  ", 0);
1764     cvs_output (finfo->file, 0);
1765     cvs_output ("\nnew revision: delete; previous revision: ", 0);
1766     cvs_output (prev_rev, 0);
1767     cvs_output ("\ndone\n", 0);
1768     free(prev_rev);
1769 
1770     free (old_path);
1771 
1772     Scratch_Entry (finfo->entries, finfo->file);
1773     return (0);
1774 }
1775 
1776 /*
1777  * Do the actual checkin for added files
1778  */
1779 static int
1780 finaladd (finfo, rev, tag, options)
1781     struct file_info *finfo;
1782     char *rev;
1783     char *tag;
1784     char *options;
1785 {
1786     int ret;
1787     char *rcs;
1788 
1789     rcs = locate_rcs (finfo->file, finfo->repository);
1790     ret = Checkin ('A', finfo, rcs, rev, tag, options, saved_message);
1791     if (ret == 0)
1792     {
1793 	char *tmp = xmalloc (strlen (finfo->file) + sizeof (CVSADM)
1794 			     + sizeof (CVSEXT_LOG) + 10);
1795 	(void) sprintf (tmp, "%s/%s%s", CVSADM, finfo->file, CVSEXT_LOG);
1796 	if (unlink_file (tmp) < 0
1797 	    && !existence_error (errno))
1798 	    error (0, errno, "cannot remove %s", tmp);
1799 	free (tmp);
1800     }
1801     else
1802 	fixaddfile (finfo->file, finfo->repository);
1803 
1804     (void) time (&last_register_time);
1805     free (rcs);
1806 
1807     return (ret);
1808 }
1809 
1810 /*
1811  * Unlock an rcs file
1812  */
1813 static void
1814 unlockrcs (rcs)
1815     RCSNode *rcs;
1816 {
1817     int retcode;
1818 
1819     if ((retcode = RCS_unlock (rcs, NULL, 0)) != 0)
1820 	error (retcode == -1 ? 1 : 0, retcode == -1 ? errno : 0,
1821 	       "could not unlock %s", rcs->path);
1822     else
1823 	RCS_rewrite (rcs, NULL, NULL);
1824 }
1825 
1826 /*
1827  * remove a partially added file.  if we can parse it, leave it alone.
1828  */
1829 static void
1830 fixaddfile (file, repository)
1831     char *file;
1832     char *repository;
1833 {
1834     RCSNode *rcsfile;
1835     char *rcs;
1836     int save_really_quiet;
1837 
1838     rcs = locate_rcs (file, repository);
1839     save_really_quiet = really_quiet;
1840     really_quiet = 1;
1841     if ((rcsfile = RCS_parsercsfile (rcs)) == NULL)
1842     {
1843 	if (unlink_file (rcs) < 0)
1844 	    error (0, errno, "cannot remove %s", rcs);
1845     }
1846     else
1847 	freercsnode (&rcsfile);
1848     really_quiet = save_really_quiet;
1849     free (rcs);
1850 }
1851 
1852 /*
1853  * put the branch back on an rcs file
1854  */
1855 static void
1856 fixbranch (rcs, branch)
1857     RCSNode *rcs;
1858     char *branch;
1859 {
1860     int retcode;
1861 
1862     if (branch != NULL)
1863     {
1864 	if ((retcode = RCS_setbranch (rcs, branch)) != 0)
1865 	    error (retcode == -1 ? 1 : 0, retcode == -1 ? errno : 0,
1866 		   "cannot restore branch to %s for %s", branch, rcs->path);
1867 	RCS_rewrite (rcs, NULL, NULL);
1868     }
1869 }
1870 
1871 /*
1872  * do the initial part of a file add for the named file.  if adding
1873  * with a tag, put the file in the Attic and point the symbolic tag
1874  * at the committed revision.
1875  */
1876 
1877 static int
1878 checkaddfile (file, repository, tag, options, rcsnode)
1879     char *file;
1880     char *repository;
1881     char *tag;
1882     char *options;
1883     RCSNode **rcsnode;
1884 {
1885     char *rcs;
1886     char *fname;
1887     mode_t omask;
1888     int retcode = 0;
1889     int newfile = 0;
1890     RCSNode *rcsfile = NULL;
1891     int retval;
1892     int adding_on_branch;
1893 
1894     /* Callers expect to be able to use either "" or NULL to mean the
1895        default keyword expansion.  */
1896     if (options != NULL && options[0] == '\0')
1897 	options = NULL;
1898     if (options != NULL)
1899 	assert (options[0] == '-' && options[1] == 'k');
1900 
1901     /* If numeric, it is on the trunk; check_fileproc enforced
1902        this.  */
1903     adding_on_branch = tag != NULL && !isdigit ((unsigned char) tag[0]);
1904 
1905     if (adding_on_branch)
1906     {
1907 	rcs = xmalloc (strlen (repository) + strlen (file)
1908 		       + sizeof (RCSEXT) + sizeof (CVSATTIC) + 10);
1909         (void) sprintf (rcs, "%s/%s%s", repository, file, RCSEXT);
1910 	if (! isreadable (rcs))
1911 	{
1912 	    (void) sprintf(rcs, "%s/%s", repository, CVSATTIC);
1913 	    omask = umask (cvsumask);
1914 	    if (CVS_MKDIR (rcs, 0777) != 0 && errno != EEXIST)
1915 		error (1, errno, "cannot make directory `%s'", rcs);;
1916 	    (void) umask (omask);
1917 	    (void) sprintf (rcs, "%s/%s/%s%s", repository, CVSATTIC, file,
1918 			    RCSEXT);
1919 	}
1920     }
1921     else
1922 	rcs = locate_rcs (file, repository);
1923 
1924     if (isreadable (rcs))
1925     {
1926 	/* file has existed in the past.  Prepare to resurrect. */
1927 	char *rev;
1928 	char *oldexpand;
1929 
1930 	if ((rcsfile = *rcsnode) == NULL)
1931 	{
1932 	    error (0, 0, "could not find parsed rcsfile %s", file);
1933 	    retval = 1;
1934 	    goto out;
1935 	}
1936 
1937 	oldexpand = RCS_getexpand (rcsfile);
1938 	if ((oldexpand != NULL
1939 	     && options != NULL
1940 	     && strcmp (options + 2, oldexpand) != 0)
1941 	    || (oldexpand == NULL && options != NULL))
1942 	{
1943 	    /* We tell the user about this, because it means that the
1944 	       old revisions will no longer retrieve the way that they
1945 	       used to.  */
1946 	    error (0, 0, "changing keyword expansion mode to %s", options);
1947 	    RCS_setexpand (rcsfile, options + 2);
1948 	}
1949 
1950 	if (!adding_on_branch)
1951 	{
1952 	    /* We are adding on the trunk, so move the file out of the
1953 	       Attic.  */
1954 	    if (!(rcsfile->flags & INATTIC))
1955 	    {
1956 		error (0, 0, "internal error: confused about attic for %s",
1957 		       rcsfile->path);
1958 		retval = 1;
1959 		goto out;
1960 	    }
1961 
1962 	    sprintf (rcs, "%s/%s%s", repository, file, RCSEXT);
1963 
1964 	    if (RCS_setattic (rcsfile, 0))
1965 	    {
1966 		retval = 1;
1967 		goto out;
1968 	    }
1969 	}
1970 
1971 	rev = RCS_getversion (rcsfile, tag, NULL, 1, (int *) NULL);
1972 	/* and lock it */
1973 	if (lock_RCS (file, rcsfile, rev, repository))
1974 	{
1975 	    error (0, 0, "cannot lock `%s'.", rcs);
1976 	    if (rev != NULL)
1977 		free (rev);
1978 	    retval = 1;
1979 	    goto out;
1980 	}
1981 
1982 	if (rev != NULL)
1983 	    free (rev);
1984     }
1985     else
1986     {
1987 	/* this is the first time we have ever seen this file; create
1988 	   an rcs file.  */
1989 
1990 	char *desc;
1991 	size_t descalloc;
1992 	size_t desclen;
1993 
1994 	char *opt;
1995 
1996 	desc = NULL;
1997 	descalloc = 0;
1998 	desclen = 0;
1999 	fname = xmalloc (strlen (file) + sizeof (CVSADM)
2000 			 + sizeof (CVSEXT_LOG) + 10);
2001 	(void) sprintf (fname, "%s/%s%s", CVSADM, file, CVSEXT_LOG);
2002 	/* If the file does not exist, no big deal.  In particular, the
2003 	   server does not (yet at least) create CVSEXT_LOG files.  */
2004 	if (isfile (fname))
2005 	    /* FIXME: Should be including update_dir in the appropriate
2006 	       place here.  */
2007 	    get_file (fname, fname, "r", &desc, &descalloc, &desclen);
2008 	free (fname);
2009 
2010 	/* From reading the RCS 5.7 source, "rcs -i" adds a newline to the
2011 	   end of the log message if the message is nonempty.
2012 	   Do it.  RCS also deletes certain whitespace, in cleanlogmsg,
2013 	   which we don't try to do here.  */
2014 	if (desclen > 0)
2015 	{
2016 	    expand_string (&desc, &descalloc, desclen + 1);
2017 	    desc[desclen++] = '\012';
2018 	}
2019 
2020 	/* Set RCS keyword expansion options.  */
2021 	if (options != NULL)
2022 	    opt = options + 2;
2023 	else
2024 	    opt = NULL;
2025 
2026 	/* This message is an artifact of the time when this
2027 	   was implemented via "rcs -i".  It should be revised at
2028 	   some point (does the "initial revision" in the message from
2029 	   RCS_checkin indicate that this is a new file?  Or does the
2030 	   "RCS file" message serve some function?).  */
2031 	cvs_output ("RCS file: ", 0);
2032 	cvs_output (rcs, 0);
2033 	cvs_output ("\ndone\n", 0);
2034 
2035 	if (add_rcs_file (NULL, rcs, file, NULL, opt,
2036 			  NULL, NULL, 0, NULL,
2037 			  desc, desclen, NULL) != 0)
2038 	{
2039 	    retval = 1;
2040 	    goto out;
2041 	}
2042 	rcsfile = RCS_parsercsfile (rcs);
2043 	newfile = 1;
2044 	if (desc != NULL)
2045 	    free (desc);
2046     }
2047 
2048     /* when adding a file for the first time, and using a tag, we need
2049        to create a dead revision on the trunk.  */
2050     if (adding_on_branch && newfile)
2051     {
2052 	char *tmp;
2053 	FILE *fp;
2054 
2055 	/* move the new file out of the way. */
2056 	fname = xmalloc (strlen (file) + sizeof (CVSADM)
2057 			 + sizeof (CVSPREFIX) + 10);
2058 	(void) sprintf (fname, "%s/%s%s", CVSADM, CVSPREFIX, file);
2059 	rename_file (file, fname);
2060 
2061 	/* Create empty FILE.  Can't use copy_file with a DEVNULL
2062 	   argument -- copy_file now ignores device files. */
2063 	fp = fopen (file, "w");
2064 	if (fp == NULL)
2065 	    error (1, errno, "cannot open %s for writing", file);
2066 	if (fclose (fp) < 0)
2067 	    error (0, errno, "cannot close %s", file);
2068 
2069 	tmp = xmalloc (strlen (file) + strlen (tag) + 80);
2070 	/* commit a dead revision. */
2071 	(void) sprintf (tmp, "file %s was initially added on branch %s.",
2072 			file, tag);
2073 	retcode = RCS_checkin (rcsfile, NULL, tmp, NULL,
2074 			       RCS_FLAGS_DEAD | RCS_FLAGS_QUIET);
2075 	free (tmp);
2076 	if (retcode != 0)
2077 	{
2078 	    error (retcode == -1 ? 1 : 0, retcode == -1 ? errno : 0,
2079 		   "could not create initial dead revision %s", rcs);
2080 	    retval = 1;
2081 	    goto out;
2082 	}
2083 
2084 	/* put the new file back where it was */
2085 	rename_file (fname, file);
2086 	free (fname);
2087 
2088 	/* double-check that the file was written correctly */
2089 	freercsnode (&rcsfile);
2090 	rcsfile = RCS_parse (file, repository);
2091 	if (rcsfile == NULL)
2092 	{
2093 	    error (0, 0, "could not read %s", rcs);
2094 	    retval = 1;
2095 	    goto out;
2096 	}
2097 	if (rcsnode != NULL)
2098 	{
2099 	    assert (*rcsnode == NULL);
2100 	    *rcsnode = rcsfile;
2101 	}
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     if (adding_on_branch)
2113     {
2114 	/* when adding with a tag, we need to stub a branch, if it
2115 	   doesn't already exist.  */
2116 
2117 	if (rcsfile == NULL)
2118 	{
2119 	    if (rcsnode != NULL && *rcsnode != NULL)
2120 		rcsfile = *rcsnode;
2121 	    else
2122 	    {
2123 		rcsfile = RCS_parse (file, repository);
2124 		if (rcsfile == NULL)
2125 		{
2126 		    error (0, 0, "could not read %s", rcs);
2127 		    retval = 1;
2128 		    goto out;
2129 		}
2130 	    }
2131 	}
2132 
2133 	if (!RCS_nodeisbranch (rcsfile, tag))
2134 	{
2135 	    /* branch does not exist.  Stub it.  */
2136 	    char *head;
2137 	    char *magicrev;
2138 
2139 	    head = RCS_getversion (rcsfile, NULL, NULL, 0, (int *) NULL);
2140 	    magicrev = RCS_magicrev (rcsfile, head);
2141 
2142 	    retcode = RCS_settag (rcsfile, tag, magicrev);
2143 	    RCS_rewrite (rcsfile, NULL, NULL);
2144 
2145 	    free (head);
2146 	    free (magicrev);
2147 
2148 	    if (retcode != 0)
2149 	    {
2150 		error (retcode == -1 ? 1 : 0, retcode == -1 ? errno : 0,
2151 		       "could not stub branch %s for %s", tag, rcs);
2152 		retval = 1;
2153 		goto out;
2154 	    }
2155 	}
2156 	else
2157 	{
2158 	    /* lock the branch. (stubbed branches need not be locked.)  */
2159 	    if (lock_RCS (file, rcsfile, NULL, repository))
2160 	    {
2161 		error (0, 0, "cannot lock `%s'.", rcs);
2162 		retval = 1;
2163 		goto out;
2164 	    }
2165 	}
2166 
2167 	if (rcsnode && *rcsnode != rcsfile)
2168 	{
2169 	    freercsnode(rcsnode);
2170 	    *rcsnode = rcsfile;
2171 	}
2172     }
2173 
2174     fileattr_newfile (file);
2175 
2176     /* At this point, we used to set the file mode of the RCS file
2177        based on the mode of the file in the working directory.  If we
2178        are creating the RCS file for the first time, add_rcs_file does
2179        this already.  If we are re-adding the file, then perhaps it is
2180        consistent to preserve the old file mode, just as we preserve
2181        the old keyword expansion mode.
2182 
2183        If we decide that we should change the modes, then we can't do
2184        it here anyhow.  At this point, the RCS file may be owned by
2185        somebody else, so a chmod will fail.  We need to instead do the
2186        chmod after rewriting it.
2187 
2188        FIXME: In general, I think the file mode (and the keyword
2189        expansion mode) should be associated with a particular revision
2190        of the file, so that it is possible to have different revisions
2191        of a file have different modes.  */
2192 
2193     retval = 0;
2194 
2195  out:
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