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