Sync usage with man page.
[netbsd-mini2440.git] / external / gpl2 / xcvs / dist / src / commit.c
blob3aec74f417014b960f35ad281b1a03d299e133ea
1 /*
2 * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
4 * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
5 * and others.
7 * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk
8 * Portions Copyright (C) 1989-1992, Brian Berliner
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.
13 * Commit Files
15 * "commit" commits the present version to the RCS repository, AFTER
16 * having done a test on conflicts.
18 * The call is: cvs commit [options] files...
22 #include "cvs.h"
23 #include "getline.h"
24 #include "edit.h"
25 #include "fileattr.h"
26 #include "hardlink.h"
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);
62 struct commit_info
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 */
69 struct master_lists
71 List *ulist; /* list for Update_Logfile */
72 List *cilist; /* list with commit_info structs */
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;
87 static const char *const commit_usage[] =
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
101 #ifdef CLIENT_SUPPORT
102 /* Identify a file which needs "? foo" or a Questionable request. */
103 struct question
105 /* The two fields for the Directory request. */
106 char *dir;
107 char *repos;
109 /* The file name. */
110 char *file;
112 struct question *next;
115 struct find_data
117 List *ulist;
118 int argc;
119 char **argv;
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;
125 /* Linked list of files which need "? foo" or a Questionable request. */
126 struct question *questionables;
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;
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;
140 static Dtype
141 find_dirent_proc (void *callerdat, const char *dir, const char *repository,
142 const char *update_dir, List *entries)
144 struct find_data *find_data = callerdat;
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;
153 /* initialize the ignore list for this directory */
154 find_data->ignlist = getlist ();
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);
162 return R_PROCESS;
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;
173 static void
174 find_ignproc (const char *file, const char *dir)
176 struct question *p;
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;
188 static int
189 find_filesdoneproc (void *callerdat, int err, const char *repository,
190 const char *update_dir, List *entries)
192 struct find_data *find_data = callerdat;
193 find_data->repository = repository;
195 /* if this directory has an ignore list, process it then free it */
196 if (find_data->ignlist)
198 find_data_static = find_data;
199 ignore_files (find_data->ignlist, entries, update_dir, find_ignproc);
200 dellist (&find_data->ignlist);
203 find_data->repository = NULL;
205 return err;
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)
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;
224 /* if this directory has an ignore list, add this file to it */
225 if (args->ignlist)
227 Node *p;
229 p = getnode ();
230 p->type = FILES;
231 p->key = xstrdup (finfo->file);
232 if (addnode (args->ignlist, p) != 0)
233 freenode (p);
236 xfinfo = *finfo;
237 xfinfo.repository = NULL;
238 xfinfo.rcs = NULL;
240 vers = Version_TS (&xfinfo, NULL, saved_tag, NULL, 0, 0);
241 if (vers->vn_user == NULL)
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;
251 if (vers->vn_user[0] == '-')
253 if (vers->ts_user != NULL)
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;
261 /* else */
262 status = T_REMOVED;
264 else if (strcmp (vers->vn_user, "0") == 0)
266 if (vers->ts_user == NULL)
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;
278 else
279 status = T_ADDED;
281 else if (vers->ts_user == NULL)
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;
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
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;
303 node = getnode ();
304 node->key = xstrdup (finfo->fullname);
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;
311 node->type = UPDATE;
312 node->delproc = update_delproc;
313 node->data = data;
314 (void)addnode (args->ulist, node);
316 ++args->argc;
318 freevers_ts (&vers);
319 return 0;
324 static int
325 copy_ulist (Node *node, void *data)
327 struct find_data *args = data;
328 args->argv[args->argc++] = node->key;
329 return 0;
331 #endif /* CLIENT_SUPPORT */
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 */
341 commit (int argc, char **argv)
343 int c;
344 int err = 0;
345 int local = 0;
347 if (argc == -1)
348 usage (commit_usage);
350 #ifdef CVS_BADROOT
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.
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)
361 struct passwd *pw;
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");
370 #endif /* CVS_BADROOT */
372 getoptreset ();
373 while ((c = getopt (argc, argv, COMMIT_OPTIONS)) != -1)
375 switch (c)
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.
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)
395 free (saved_message);
396 saved_message = NULL;
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;
431 argc -= optind;
432 argv += optind;
434 /* numeric specified revision means we ignore sticky tags... */
435 if (saved_tag && isdigit ((unsigned char) *saved_tag))
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;
446 /* some checks related to the "-F logfile" option */
447 if (logfile)
449 size_t size = 0, len;
451 if (saved_message)
452 error (1, 0, "cannot specify both a message and a log file");
454 get_file (logfile, logfile, "r", &saved_message, &size, &len);
457 #ifdef CLIENT_SUPPORT
458 if (current_parsed_root->isremote)
460 struct find_data find_args;
462 ign_setup ();
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;
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;
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!");
483 if (find_args.argc == 0)
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;
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 **))))
499 find_args.argc = 0;
500 return 0;
502 find_args.argv = xnmalloc (find_args.argc, sizeof (char **));
503 find_args.argc = 0;
504 walklist (find_args.ulist, copy_ulist, &find_args);
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.).
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 ();
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.
522 if (use_editor)
523 do_editor (".", &saved_message, NULL, find_args.ulist);
525 /* We always send some sort of message, even if empty. */
526 option_with_arg ("-m", saved_message ? saved_message : "");
528 /* OK, now process all the questionable files we have been saving
529 up. */
531 struct question *p;
532 struct question *q;
534 p = find_args.questionables;
535 while (p != NULL)
537 if (ign_inhibit_server || !supported_request ("Questionable"))
539 cvs_output ("? ", 2);
540 if (p->dir[0] != '\0')
542 cvs_output (p->dir, 0);
543 cvs_output ("/", 1);
545 cvs_output (p->file, 0);
546 cvs_output ("\n", 1);
548 else
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:
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.
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).
569 send_a_repository (p->dir, p->repos, p->dir);
571 send_to_server ("Questionable ", 0);
572 send_to_server (p->file, 0);
573 send_to_server ("\012", 1);
575 free (p->dir);
576 free (p->repos);
577 free (p->file);
578 q = p->next;
579 free (p);
580 p = q;
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 ("--");
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);
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);
614 send_to_server ("ci\012", 0);
615 err = get_responses_and_close ();
616 if (err != 0 && use_editor && saved_message != NULL)
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). */
627 char *fname;
628 FILE *fp;
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);
641 return err;
643 #endif
645 if (saved_tag != NULL)
646 tag_check_valid (saved_tag, argc, argv, local, aflag, "", false);
648 /* XXX - this is not the perfect check for this */
649 if (argc <= 0)
650 write_dirtag = saved_tag;
652 wrap_setup ();
654 lock_tree_promotably (argc, argv, local, W_LOCAL, aflag);
657 * Set up the master update list and hard link list
659 mulist = getlist ();
661 #ifdef PRESERVE_PERMISSIONS_SUPPORT
662 if (preserve_perms)
664 hardlist = getlist ();
667 * We need to save the working directory so that
668 * check_fileproc can construct a full pathname for each file.
670 working_dir = xgetcwd ();
672 #endif
675 * Run the recursion processor to verify the files are all up-to-date
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!");
684 * Run the recursion processor to commit the files
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);
694 * Unlock all the dirs and clean up
696 Lock_Cleanup ();
697 dellist (&mulist);
699 /* see if we need to sleep before returning to avoid time-stamp races */
700 if (!server_active && last_register_time)
702 sleep_past (last_register_time);
705 return err;
710 /* This routine determines the status of a given file and retrieves
711 the version information that is associated with that file. */
713 static
714 Ctype
715 classify_file_internal (struct file_info *finfo, Vers_TS **vers)
717 int save_noexec, save_quiet, save_really_quiet;
718 Ctype status;
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;
728 /* handle specified numeric revision specially */
729 if (saved_tag && isdigit ((unsigned char) *saved_tag))
731 /* If the tag is for the trunk, make sure we're at the head */
732 if (numdots (saved_tag) < 2)
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)
739 Ctype xstatus;
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;
752 else
754 char *xtag, *cp;
757 * The revision is off the main trunk; make sure we're
758 * up-to-date with the head of the specified branch.
760 xtag = xstrdup (saved_tag);
761 if ((numdots (xtag) & 1) != 0)
763 cp = strrchr (xtag, '.');
764 *cp = '\0';
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)
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;
779 /* now, muck with vers to make the tag correct */
780 free ((*vers)->tag);
781 (*vers)->tag = xstrdup (saved_tag);
782 free (xtag);
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;
791 return status;
797 * Check to see if a file is ok to commit and make sure all files are
798 * up-to-date
800 /* ARGSUSED */
801 static int
802 check_fileproc (void *callerdat, struct file_info *finfo)
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;
813 size_t cvsroot_len = strlen (current_parsed_root->directory);
815 if (!finfo->repository)
817 error (0, 0, "nothing known about `%s'", finfo->fullname);
818 return 1;
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
831 error (1, 0, "cannot check in to %s", finfo->repository);
833 status = classify_file_internal (finfo, &vers);
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.
840 if (force_ci && status == T_UPTODATE)
841 status = T_MODIFIED;
843 switch (status)
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:
856 char *editor;
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.
872 if (!saved_tag || !isdigit ((unsigned char) *saved_tag))
874 if (vers->date)
876 error (0, 0,
877 "cannot commit with sticky date for file `%s'",
878 finfo->fullname);
879 goto out;
881 if (status == T_MODIFIED && vers->tag &&
882 !RCS_isbranch (finfo->rcs, vers->tag))
884 error (0, 0,
885 "sticky tag `%s' for file `%s' is not a branch",
886 vers->tag, finfo->fullname);
887 goto out;
890 if (status == T_CONFLICT && !force_ci)
892 error (0, 0,
893 "file `%s' had a conflict and has not been modified",
894 finfo->fullname);
895 goto out;
897 if (status == T_MODIFIED && !force_ci && file_has_markers (finfo))
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,
911 warning: file `%s' seems to still contain conflict indicators",
912 finfo->fullname);
915 if (status == T_REMOVED)
917 if (vers->ts_user != NULL)
919 error (0, 0,
920 "`%s' should be removed and is still there (or is"
921 " back again)", finfo->fullname);
922 goto out;
925 if (vers->tag && isdigit ((unsigned char) *vers->tag))
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;
939 if (status == T_ADDED)
941 if (vers->tag == NULL)
943 if (finfo->rcs != NULL &&
944 !RCS_isdead (finfo->rcs, finfo->rcs->head))
946 error (0, 0,
947 "cannot add file `%s' when RCS file `%s' already exists",
948 finfo->fullname, finfo->rcs->path);
949 goto out;
952 else if (isdigit ((unsigned char) *vers->tag) &&
953 numdots (vers->tag) > 1)
955 error (0, 0,
956 "cannot add file `%s' with revision `%s'; must be on trunk",
957 finfo->fullname, vers->tag);
958 goto out;
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)
969 ulist = ((struct master_lists *) p->data)->ulist;
970 cilist = ((struct master_lists *) p->data)->cilist;
972 else
974 struct master_lists *ml;
976 ml = xmalloc (sizeof (struct master_lists));
977 ulist = ml->ulist = getlist ();
978 cilist = ml->cilist = getlist ();
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);
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;
996 if (check_valid_edit)
998 char *editors = NULL;
1000 editor = NULL;
1001 editors = fileattr_get0 (finfo->file, "_editors");
1002 if (editors != NULL)
1004 char *caller = getcaller ();
1005 char *p = NULL;
1006 char *p0 = NULL;
1008 p = editors;
1009 p0 = p;
1010 while (*p != '\0')
1012 p = strchr (p, '>');
1013 if (p == NULL)
1015 break;
1017 *p = '\0';
1018 if (strcmp (caller, p0) == 0)
1020 break;
1022 p = strchr (p + 1, ',');
1023 if (p == NULL)
1025 break;
1027 ++p;
1028 p0 = p;
1031 if (strcmp (caller, p0) == 0)
1033 editor = caller;
1036 free (editors);
1040 if (check_valid_edit && editor == NULL)
1042 error (0, 0, "Valid edit does not exist for %s",
1043 finfo->fullname);
1044 freevers_ts (&vers);
1045 return 1;
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);
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);
1074 #ifdef PRESERVE_PERMISSIONS_SUPPORT
1075 if (preserve_perms)
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;
1084 /* Get the full pathname of the current file. */
1085 fullpath = Xasprintf ("%s/%s", working_dir, finfo->fullname);
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);
1091 /* If linkp is NULL, the file doesn't exist... maybe
1092 we're doing a remove operation? */
1093 if (linkp != NULL)
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;
1104 #endif
1106 break;
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;
1119 retval = 0;
1121 out:
1123 freevers_ts (&vers);
1124 return retval;
1130 * By default, return the code that tells do_recursion to examine all
1131 * directories
1133 /* ARGSUSED */
1134 static Dtype
1135 check_direntproc (void *callerdat, const char *dir, const char *repos,
1136 const char *update_dir, List *entries)
1138 if (!isdir (dir))
1139 return R_SKIP_ALL;
1141 if (!quiet)
1142 error (0, 0, "Examining %s", update_dir);
1144 return R_PROCESS;
1150 * Walklist proc to generate an arg list from the line in commitinfo
1152 static int
1153 precommit_list_to_args_proc (p, closure)
1154 Node *p;
1155 void *closure;
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;
1164 if (p->data == NULL) return 1;
1166 f = c->format;
1167 d = *c->d;
1168 /* foreach requested attribute */
1169 while (*f)
1171 switch (*f++)
1173 case 's':
1174 li = p->data;
1175 if (li->type == T_ADDED
1176 || li->type == T_MODIFIED
1177 || li->type == T_REMOVED)
1179 arg = p->key;
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;
1189 /* copy the attribute into an argument */
1190 if (c->quotes)
1192 arg = cmdlineescape (c->quotes, arg);
1194 else
1196 arg = cmdlinequote ('"', arg);
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);
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
1208 doff = d - *c->buf;
1209 expand_string (c->buf, c->length, doff + 1);
1210 d = *c->buf + doff;
1211 *d++ = ' ';
1213 /* correct our original pointer into the buff */
1214 *c->d = d;
1215 return 0;
1221 * Callback proc for pre-commit checking
1223 static int
1224 precommit_proc (const char *repository, const char *filter, void *closure)
1226 char *newfilter = NULL;
1227 char *cmdline;
1228 const char *srepos = Short_Repository (repository);
1229 List *ulist = closure;
1231 #ifdef SUPPORT_OLD_INFO_FMT_STRINGS
1232 if (!strchr (filter, '%'))
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;
1242 #endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
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.
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);
1264 if (newfilter) free (newfilter);
1266 if (!cmdline || !strlen (cmdline))
1268 if (cmdline) free (cmdline);
1269 error (0, 0, "precommit proc resolved to the empty string!");
1270 return 1;
1273 run_setup (cmdline);
1274 free (cmdline);
1276 return run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL|RUN_REALLY|
1277 (server_active ? 0 : RUN_UNSETXID));
1283 * Run the pre-commit checks for the dir
1285 /* ARGSUSED */
1286 static int
1287 check_filesdoneproc (void *callerdat, int err, const char *repos,
1288 const char *update_dir, List *entries)
1290 int n;
1291 Node *p;
1292 List *saved_ulist;
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;
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;
1305 /* run any pre-commit checks */
1306 n = Parse_Info (CVSROOTADM_COMMITINFO, repos, precommit_proc, PIOPT_ALL,
1307 saved_ulist);
1308 if (n > 0)
1310 error (0, 0, "Pre-commit check failed");
1311 err += n;
1314 return err;
1320 * Do the work of committing a file
1322 static int maxrev;
1323 static char *sbranch;
1325 /* ARGSUSED */
1326 static int
1327 commit_fileproc (void *callerdat, struct file_info *finfo)
1329 Node *p;
1330 int err = 0;
1331 List *ulist, *cilist;
1332 struct commit_info *ci;
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)
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);
1349 if (finfo->update_dir[0] == '\0')
1350 p = findnode (mulist, ".");
1351 else
1352 p = findnode (mulist, finfo->update_dir);
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
1358 if (p == NULL)
1359 return 0;
1360 ulist = ((struct master_lists *) p->data)->ulist;
1361 cilist = ((struct master_lists *) p->data)->cilist;
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
1368 if (!got_message)
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);
1377 p = findnode (cilist, finfo->file);
1378 if (p == NULL)
1379 return 0;
1381 ci = p->data;
1382 if (ci->status == T_MODIFIED)
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)
1389 unlockrcs (finfo->rcs);
1390 err = 1;
1391 goto out;
1394 else if (ci->status == T_ADDED)
1396 if (checkaddfile (finfo->file, finfo->repository, ci->tag, ci->options,
1397 &finfo->rcs) != 0)
1399 if (finfo->rcs != NULL)
1400 fixaddfile (finfo->rcs->path);
1401 err = 1;
1402 goto out;
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. */
1409 if (ci->tag
1411 /* If numeric, it is on the trunk; check_fileproc enforced
1412 this. */
1413 && !isdigit ((unsigned char) ci->tag[0]))
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)
1424 unlockrcs (finfo->rcs);
1425 fixbranch (finfo->rcs, sbranch);
1428 (void) time (&last_register_time);
1430 ci->status = T_UPTODATE;
1435 * Add the file for real
1437 if (ci->status == T_ADDED)
1439 char *xrev = NULL;
1441 if (ci->rev == NULL)
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)
1448 /* resurrecting: include dead revision */
1449 int thisrev = atoi (finfo->rcs->head);
1450 if (thisrev > maxrev)
1451 maxrev = thisrev;
1453 if (maxrev == 0)
1454 maxrev = 1;
1455 xrev = Xasprintf ("%d", maxrev);
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);
1463 else if (ci->status == T_MODIFIED)
1465 err = Checkin ('M', finfo, ci->rev, ci->tag,
1466 ci->options, saved_message);
1468 (void) time (&last_register_time);
1470 if (err != 0)
1472 unlockrcs (finfo->rcs);
1473 fixbranch (finfo->rcs, sbranch);
1476 else if (ci->status == T_REMOVED)
1478 err = remove_file (finfo, ci->tag, saved_message);
1479 #ifdef SERVER_SUPPORT
1480 if (server_active)
1482 server_scratch_entry_only ();
1483 server_updated (finfo,
1484 NULL,
1486 /* Doesn't matter, it won't get checked. */
1487 SERVER_UPDATED,
1489 (mode_t) -1,
1490 NULL,
1491 NULL);
1493 #endif
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);
1501 out:
1502 if (err != 0)
1504 /* on failure, remove the file from ulist */
1505 p = findnode (ulist, finfo->file);
1506 if (p)
1507 delnode (p);
1509 else
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." */
1521 if (ci->status != T_REMOVED)
1523 p = findnode (ulist, finfo->file);
1524 if (p)
1526 Vers_TS *vers;
1527 struct logfile_info *li;
1529 (void) classify_file_internal (finfo, &vers);
1530 li = p->data;
1531 li->rev_new = xstrdup (vers->vn_rcs);
1532 freevers_ts (&vers);
1536 if (SIG_inCrSect ())
1537 SIG_endCrSect ();
1539 return err;
1545 * Log the commit and clean up the update list
1547 /* ARGSUSED */
1548 static int
1549 commit_filesdoneproc (void *callerdat, int err, const char *repository,
1550 const char *update_dir, List *entries)
1552 Node *p;
1553 List *ulist;
1555 assert (repository);
1557 p = findnode (mulist, update_dir);
1558 if (p == NULL)
1559 return err;
1561 ulist = ((struct master_lists *) p->data)->ulist;
1563 got_message = 0;
1565 /* Build the administrative files if necessary. */
1567 const char *p;
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
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. */
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';
1598 if (!really_quiet)
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);
1605 mkmodules (admin_dir);
1606 free (admin_dir);
1607 WriteTemplate (".", 1, repository);
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.
1616 * A more general solution I have been considering is calling a generic
1617 * "postwrite" hook from the remove write lock routine.
1619 Update_Logfile (repository, saved_message, NULL, ulist);
1621 return err;
1627 * Get the log message for a dir
1629 /* ARGSUSED */
1630 static Dtype
1631 commit_direntproc (void *callerdat, const char *dir, const char *repos,
1632 const char *update_dir, List *entries)
1634 Node *p;
1635 List *ulist;
1636 char *real_repos;
1638 if (!isdir (dir))
1639 return R_SKIP_ALL;
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;
1648 /* skip the files as an optimization */
1649 if (ulist == NULL || ulist->list->next == ulist->list)
1650 return R_SKIP_FILES;
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;
1665 * Process the post-commit proc if necessary
1667 /* ARGSUSED */
1668 static int
1669 commit_dirleaveproc (void *callerdat, const char *dir, int err,
1670 const char *update_dir, List *entries)
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)
1678 char *repos = Name_Repository (NULL, update_dir);
1679 WriteTag (NULL, write_dirtag, NULL, write_dirnonbranch,
1680 update_dir, repos);
1681 free (repos);
1684 return err;
1690 * find the maximum major rev number in an entries file
1692 static int
1693 findmaxrev (Node *p, void *closure)
1695 int thisrev;
1696 Entnode *entdata = p->data;
1698 if (entdata->type != ENT_FILE)
1699 return 0;
1700 thisrev = atoi (entdata->version);
1701 if (thisrev > maxrev)
1702 maxrev = thisrev;
1703 return 0;
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.
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)
1717 int retcode;
1719 int branch;
1720 int lockflag;
1721 char *corev;
1722 char *rev;
1723 char *prev_rev;
1724 char *old_path;
1726 corev = NULL;
1727 rev = NULL;
1728 prev_rev = NULL;
1730 retcode = 0;
1732 if (finfo->rcs == NULL)
1733 error (1, 0, "internal error: no parsed RCS file");
1735 branch = 0;
1736 if (tag && !(branch = RCS_nodeisbranch (finfo->rcs, tag)))
1738 /* a symbolic tag is specified; just remove the tag from the file */
1739 if ((retcode = RCS_deltag (finfo->rcs, tag)) != 0)
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;
1747 RCS_rewrite (finfo->rcs, NULL, NULL);
1748 Scratch_Entry (finfo->entries, finfo->file);
1749 return 0;
1752 /* we are removing the file from either the head or a branch */
1753 /* commit a new, dead revision. */
1755 rev = NULL;
1756 lockflag = 1;
1757 if (branch)
1759 char *branchname;
1761 rev = RCS_whatbranch (finfo->rcs, tag);
1762 if (rev == NULL)
1764 error (0, 0, "cannot find branch \"%s\".", tag);
1765 return 1;
1768 branchname = RCS_getbranch (finfo->rcs, rev, 1);
1769 if (branchname == NULL)
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
1778 corev = xstrdup (rev);
1779 prev_rev = xstrdup (branchname);
1780 free (branchname);
1783 } else /* Not a branch */
1785 /* Get current head revision of file. */
1786 prev_rev = RCS_head (finfo->rcs);
1789 /* if removing without a tag or a branch, then make sure the default
1790 branch is the trunk. */
1791 if (!tag && !branch)
1793 if (RCS_setbranch (finfo->rcs, NULL) != 0)
1795 error (0, 0, "cannot change branch to default for %s",
1796 finfo->fullname);
1797 return 1;
1799 RCS_rewrite (finfo->rcs, NULL, NULL);
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)
1808 error (0, 0,
1809 "failed to check out `%s'", finfo->fullname);
1810 return 1;
1813 /* Except when we are creating a branch, lock the revision so that
1814 we can check in the new revision. */
1815 if (lockflag)
1817 if (RCS_lock (finfo->rcs, rev ? corev : NULL, 1) == 0)
1818 RCS_rewrite (finfo->rcs, NULL, NULL);
1821 if (corev != NULL)
1822 free (corev);
1824 retcode = RCS_checkin (finfo->rcs, NULL, finfo->file, message,
1825 rev, 0, RCS_FLAGS_DEAD | RCS_FLAGS_QUIET);
1826 if (retcode != 0)
1828 if (!quiet)
1829 error (0, retcode == -1 ? errno : 0,
1830 "failed to commit dead revision for `%s'", finfo->fullname);
1831 return 1;
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);
1837 if (rev != NULL)
1838 free (rev);
1840 old_path = xstrdup (finfo->rcs->path);
1841 if (!branch)
1842 RCS_setattic (finfo->rcs, 1);
1844 /* Print message that file was removed. */
1845 if (!really_quiet)
1847 cvs_output (old_path, 0);
1848 cvs_output (" <-- ", 0);
1849 if (finfo->update_dir && strlen (finfo->update_dir))
1851 cvs_output (finfo->update_dir, 0);
1852 cvs_output ("/", 1);
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);
1860 free (prev_rev);
1862 free (old_path);
1864 Scratch_Entry (finfo->entries, finfo->file);
1865 return 0;
1871 * Do the actual checkin for added files
1873 static int
1874 finaladd (struct file_info *finfo, char *rev, char *tag, char *options)
1876 int ret;
1878 ret = Checkin ('A', finfo, rev, tag, options, saved_message);
1879 if (ret == 0)
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);
1887 else if (finfo->rcs != NULL)
1888 fixaddfile (finfo->rcs->path);
1890 (void) time (&last_register_time);
1892 return ret;
1898 * Unlock an rcs file
1900 static void
1901 unlockrcs (RCSNode *rcs)
1903 int retcode;
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);
1915 * remove a partially added file. if we can parse it, leave it alone.
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.
1921 static void
1922 fixaddfile (const char *rcs)
1924 RCSNode *rcsfile;
1925 int save_really_quiet;
1927 save_really_quiet = really_quiet;
1928 really_quiet = 1;
1929 if ((rcsfile = RCS_parsercsfile (rcs)) == NULL)
1931 if (unlink_file (rcs) < 0)
1932 error (0, errno, "cannot remove %s", rcs);
1934 else
1935 freercsnode (&rcsfile);
1936 really_quiet = save_really_quiet;
1942 * put the branch back on an rcs file
1944 static void
1945 fixbranch (RCSNode *rcs, char *branch)
1947 int retcode;
1949 if (branch != NULL)
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);
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.
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.
1974 * RETURNS
1975 * 0 on success.
1976 * 1 on errors, after printing any appropriate error messages.
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
1988 static int
1989 checkaddfile (const char *file, const char *repository, const char *tag,
1990 const char *options, RCSNode **rcsnode)
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;
1998 assert (rcsnode != NULL);
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');
2007 /* If numeric, it is on the trunk; check_fileproc enforced
2008 this. */
2009 adding_on_branch = tag != NULL && !isdigit ((unsigned char) tag[0]);
2011 if (*rcsnode == NULL)
2013 char *rcsname;
2014 char *desc = NULL;
2015 size_t descalloc = 0;
2016 size_t desclen = 0;
2017 const char *opt;
2019 if (adding_on_branch)
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);
2039 else
2040 rcsname = Xasprintf ("%s/%s%s", repository, file, RCSEXT);
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);
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)
2059 expand_string (&desc, &descalloc, desclen + 1);
2060 desc[desclen++] = '\012';
2063 /* Set RCS keyword expansion options. */
2064 if (options != NULL)
2065 opt = options + 2;
2066 else
2067 opt = NULL;
2069 if (add_rcs_file (NULL, rcsname, file, NULL, opt,
2070 NULL, NULL, 0, NULL,
2071 desc, desclen, NULL, 0) != 0)
2073 if (rcsname != NULL)
2074 free (rcsname);
2075 goto out;
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;
2085 else
2087 /* file has existed in the past. Prepare to resurrect. */
2088 char *rev;
2089 char *oldexpand;
2091 rcs = *rcsnode;
2093 oldexpand = RCS_getexpand (rcs);
2094 if ((oldexpand != NULL
2095 && options != NULL
2096 && strcmp (options + 2, oldexpand) != 0)
2097 || (oldexpand == NULL && options != NULL))
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);
2106 if (!adding_on_branch)
2108 /* We are adding on the trunk, so move the file out of the
2109 Attic. */
2110 if (!(rcs->flags & INATTIC))
2112 error (0, 0, "warning: expected %s to be in Attic",
2113 rcs->path);
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 ();
2121 if (RCS_setattic (rcs, 0))
2123 goto out;
2127 rev = RCS_getversion (rcs, tag, NULL, 1, NULL);
2128 /* and lock it */
2129 if (lock_RCS (file, rcs, rev, repository))
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;
2138 if (rev != NULL)
2139 free (rev);
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)
2146 if (newfile)
2148 char *tmp;
2149 FILE *fp;
2150 int retcode;
2152 /* move the new file out of the way. */
2153 fname = Xasprintf ("%s/%s%s", CVSADM, CVSPREFIX, file);
2154 rename_file (file, fname);
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);
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)
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;
2178 /* put the new file back where it was */
2179 rename_file (fname, file);
2180 free (fname);
2182 /* double-check that the file was written correctly */
2183 freercsnode (&rcs);
2184 rcs = RCS_parse (file, repository);
2185 if (rcs == NULL)
2187 error (0, 0, "could not read %s", rcs->path);
2188 goto out;
2190 *rcsnode = rcs;
2192 /* and lock it once again. */
2193 if (lock_RCS (file, rcs, NULL, repository))
2195 error (0, 0, "cannot lock initial revision in `%s'.",
2196 rcs->path);
2197 goto out;
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))
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;
2215 fixbranch (rcs, sbranch);
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);
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);
2228 retcode = RCS_settag (rcs, tag, magicrev);
2229 RCS_rewrite (rcs, NULL, NULL);
2231 free (head);
2232 free (magicrev);
2234 if (retcode != 0)
2236 error (retcode == -1 ? 1 : 0, retcode == -1 ? errno : 0,
2237 "could not stub branch %s for %s", tag, rcs->path);
2238 goto out;
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)
2245 /* move the new file out of the way. */
2246 fname = Xasprintf ("%s/%s%s", CVSADM, CVSPREFIX, file);
2247 rename_file (file, fname);
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);
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);
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);
2276 if (retcode != 0)
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;
2284 /* put the new file back where it was */
2285 rename_file (fname, file);
2286 free (fname);
2288 /* double-check that the file was written correctly */
2289 freercsnode (&rcs);
2290 rcs = RCS_parse (file, repository);
2291 if (rcs == NULL)
2293 error (0, 0, "could not read %s", rcs->path);
2294 goto out;
2296 *rcsnode = rcs;
2299 else
2301 /* lock the branch. (stubbed branches need not be locked.) */
2302 if (lock_RCS (file, rcs, NULL, repository))
2304 error (0, 0, "cannot lock head revision in `%s'.", rcs->path);
2305 goto out;
2309 if (*rcsnode != rcs)
2311 freercsnode (rcsnode);
2312 *rcsnode = rcs;
2316 fileattr_newfile (file);
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.
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.
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. */
2335 retval = 0;
2337 out:
2338 if (retval != 0 && SIG_inCrSect ())
2339 SIG_endCrSect ();
2340 return retval;
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.
2351 static int
2352 lock_RCS (const char *user, RCSNode *rcs, const char *rev,
2353 const char *repository)
2355 char *branch = NULL;
2356 int err = 0;
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.
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.
2367 if (rev == NULL
2368 || (rev && isdigit ((unsigned char) *rev) && numdots (rev) < 2))
2370 branch = xstrdup (rcs->branch);
2371 if (branch != NULL)
2373 if (RCS_setbranch (rcs, NULL) != 0)
2375 error (0, 0, "cannot change branch to default for %s",
2376 rcs->path);
2377 if (branch)
2378 free (branch);
2379 return 1;
2382 err = RCS_lock (rcs, NULL, 1);
2384 else
2386 RCS_lock (rcs, rev, 1);
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.
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.
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. */
2408 if (err == 0)
2410 if (sbranch != NULL)
2411 free (sbranch);
2412 sbranch = branch;
2413 return 0;
2416 /* try to restore the branch if we can on error */
2417 if (branch != NULL)
2418 fixbranch (rcs, branch);
2420 if (branch)
2421 free (branch);
2422 return 1;
2428 * free an UPDATE node's data
2430 void
2431 update_delproc (Node *p)
2433 struct logfile_info *li = p->data;
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);
2445 * Free the commit_info structure in p.
2447 static void
2448 ci_delproc (Node *p)
2450 struct commit_info *ci = p->data;
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);
2462 * Free the commit_info structure in p.
2464 static void
2465 masterlist_delproc (Node *p)
2467 struct master_lists *ml = p->data;
2469 dellist (&ml->ulist);
2470 dellist (&ml->cilist);
2471 free (ml);