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