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