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