1 /* 2 * Copyright (c) 1992, Brian Berliner and Jeff Polk 3 * Copyright (c) 1989-1992, Brian Berliner 4 * 5 * You may distribute under the terms of the GNU General Public License as 6 * specified in the README file that comes with the CVS source distribution. 7 * 8 * "import" checks in the vendor release located in the current directory into 9 * the CVS source repository. The CVS vendor branch support is utilized. 10 * 11 * At least three arguments are expected to follow the options: 12 * repository Where the source belongs relative to the CVSROOT 13 * VendorTag Vendor's major tag 14 * VendorReleTag Tag for this particular release 15 * 16 * Additional arguments specify more Vendor Release Tags. 17 */ 18 19 #include "cvs.h" 20 #include "savecwd.h" 21 #include <assert.h> 22 23 static char *get_comment PROTO((char *user)); 24 static int add_rev PROTO((char *message, RCSNode *rcs, char *vfile, 25 char *vers)); 26 static int add_tags PROTO((RCSNode *rcs, char *vfile, char *vtag, int targc, 27 char *targv[])); 28 static int import_descend PROTO((char *message, char *vtag, int targc, char *targv[])); 29 static int import_descend_dir PROTO((char *message, char *dir, char *vtag, 30 int targc, char *targv[])); 31 static int process_import_file PROTO((char *message, char *vfile, char *vtag, 32 int targc, char *targv[])); 33 static int update_rcs_file PROTO((char *message, char *vfile, char *vtag, int targc, 34 char *targv[], int inattic)); 35 static void add_log PROTO((int ch, char *fname)); 36 37 static int repos_len; 38 static char *vhead; 39 static char *vbranch; 40 static FILE *logfp; 41 static char *repository; 42 static int conflicts; 43 static int use_file_modtime; 44 static char *keyword_opt = NULL; 45 46 static const char *const import_usage[] = 47 { 48 "Usage: %s %s [-d] [-k subst] [-I ign] [-m msg] [-b branch]\n", 49 " [-W spec] repository vendor-tag release-tags...\n", 50 "\t-d\tUse the file's modification time as the time of import.\n", 51 "\t-k sub\tSet default RCS keyword substitution mode.\n", 52 "\t-I ign\tMore files to ignore (! to reset).\n", 53 "\t-b bra\tVendor branch id.\n", 54 "\t-m msg\tLog message.\n", 55 "\t-W spec\tWrappers specification line.\n", 56 "(Specify the --help global option for a list of other help options)\n", 57 NULL 58 }; 59 60 int 61 import (argc, argv) 62 int argc; 63 char **argv; 64 { 65 char *message = NULL; 66 char *tmpfile; 67 char *cp; 68 int i, c, msglen, err; 69 List *ulist; 70 Node *p; 71 struct logfile_info *li; 72 73 if (argc == -1) 74 usage (import_usage); 75 76 ign_setup (); 77 wrap_setup (); 78 79 vbranch = xstrdup (CVSBRANCH); 80 optind = 0; 81 while ((c = getopt (argc, argv, "+Qqdb:m:I:k:W:")) != -1) 82 { 83 switch (c) 84 { 85 case 'Q': 86 case 'q': 87 #ifdef SERVER_SUPPORT 88 /* The CVS 1.5 client sends these options (in addition to 89 Global_option requests), so we must ignore them. */ 90 if (!server_active) 91 #endif 92 error (1, 0, 93 "-q or -Q must be specified before \"%s\"", 94 command_name); 95 break; 96 case 'd': 97 #ifdef SERVER_SUPPORT 98 if (server_active) 99 { 100 /* CVS 1.10 and older clients will send this, but it 101 doesn't do any good. So tell the user we can't 102 cope, rather than silently losing. */ 103 error (0, 0, 104 "warning: not setting the time of import from the file"); 105 error (0, 0, "due to client limitations"); 106 } 107 #endif 108 use_file_modtime = 1; 109 break; 110 case 'b': 111 free (vbranch); 112 vbranch = xstrdup (optarg); 113 break; 114 case 'm': 115 #ifdef FORCE_USE_EDITOR 116 use_editor = 1; 117 #else 118 use_editor = 0; 119 #endif 120 message = xstrdup(optarg); 121 break; 122 case 'I': 123 ign_add (optarg, 0); 124 break; 125 case 'k': 126 /* RCS_check_kflag returns strings of the form -kxx. We 127 only use it for validation, so we can free the value 128 as soon as it is returned. */ 129 free (RCS_check_kflag (optarg)); 130 keyword_opt = optarg; 131 break; 132 case 'W': 133 wrap_add (optarg, 0); 134 break; 135 case '?': 136 default: 137 usage (import_usage); 138 break; 139 } 140 } 141 argc -= optind; 142 argv += optind; 143 if (argc < 3) 144 usage (import_usage); 145 146 #ifdef SERVER_SUPPORT 147 /* This is for handling the Checkin-time request. It might seem a 148 bit odd to enable the use_file_modtime code even in the case 149 where Checkin-time was not sent for a particular file. The 150 effect is that we use the time of upload, rather than the time 151 when we call RCS_checkin. Since those times are both during 152 CVS's run, that seems OK, and it is easier to implement than 153 putting the "was Checkin-time sent" flag in CVS/Entries or some 154 such place. */ 155 156 if (server_active) 157 use_file_modtime = 1; 158 #endif 159 160 for (i = 1; i < argc; i++) /* check the tags for validity */ 161 { 162 int j; 163 164 RCS_check_tag (argv[i]); 165 for (j = 1; j < i; j++) 166 if (strcmp (argv[j], argv[i]) == 0) 167 error (1, 0, "tag `%s' was specified more than once", argv[i]); 168 } 169 170 /* XXX - this should be a module, not just a pathname */ 171 if (! isabsolute (argv[0]) 172 && pathname_levels (argv[0]) == 0) 173 { 174 if (current_parsed_root == NULL) 175 { 176 error (0, 0, "missing CVSROOT environment variable\n"); 177 error (1, 0, "Set it or specify the '-d' option to %s.", 178 program_name); 179 } 180 repository = xmalloc (strlen (current_parsed_root->directory) 181 + strlen (argv[0]) 182 + 2); 183 (void) sprintf (repository, "%s/%s", current_parsed_root->directory, argv[0]); 184 repos_len = strlen (current_parsed_root->directory); 185 } 186 else 187 { 188 /* It is somewhere between a security hole and "unexpected" to 189 let the client start mucking around outside the cvsroot 190 (wouldn't get the right CVSROOT configuration, &c). */ 191 error (1, 0, "directory %s not relative within the repository", 192 argv[0]); 193 } 194 195 /* 196 * Consistency checks on the specified vendor branch. It must be 197 * composed of only numbers and dots ('.'). Also, for now we only 198 * support branching to a single level, so the specified vendor branch 199 * must only have two dots in it (like "1.1.1"). 200 */ 201 for (cp = vbranch; *cp != '\0'; cp++) 202 if (!isdigit ((unsigned char) *cp) && *cp != '.') 203 error (1, 0, "%s is not a numeric branch", vbranch); 204 if (numdots (vbranch) != 2) 205 error (1, 0, "Only branches with two dots are supported: %s", vbranch); 206 vhead = xstrdup (vbranch); 207 cp = strrchr (vhead, '.'); 208 *cp = '\0'; 209 210 #ifdef CLIENT_SUPPORT 211 if (current_parsed_root->isremote) 212 { 213 /* For rationale behind calling start_server before do_editor, see 214 commit.c */ 215 start_server (); 216 } 217 #endif 218 219 if (use_editor) 220 { 221 do_editor ((char *) NULL, &message, repository, 222 (List *) NULL); 223 } 224 do_verify (message, repository); 225 msglen = message == NULL ? 0 : strlen (message); 226 if (msglen == 0 || message[msglen - 1] != '\n') 227 { 228 char *nm = xmalloc (msglen + 2); 229 *nm = '\0'; 230 if (message != NULL) 231 { 232 (void) strcpy (nm, message); 233 free (message); 234 } 235 (void) strcat (nm + msglen, "\n"); 236 message = nm; 237 } 238 239 #ifdef CLIENT_SUPPORT 240 if (current_parsed_root->isremote) 241 { 242 int err; 243 244 if (vbranch[0] != '\0') 245 option_with_arg ("-b", vbranch); 246 if (message) 247 option_with_arg ("-m", message); 248 if (keyword_opt != NULL) 249 option_with_arg ("-k", keyword_opt); 250 /* The only ignore processing which takes place on the server side 251 is the CVSROOT/cvsignore file. But if the user specified -I !, 252 the documented behavior is to not process said file. */ 253 if (ign_inhibit_server) 254 { 255 send_arg ("-I"); 256 send_arg ("!"); 257 } 258 wrap_send (); 259 260 { 261 int i; 262 for (i = 0; i < argc; ++i) 263 send_arg (argv[i]); 264 } 265 266 logfp = stdin; 267 client_import_setup (repository); 268 err = import_descend (message, argv[1], argc - 2, argv + 2); 269 client_import_done (); 270 if (message) 271 free (message); 272 free (repository); 273 free (vbranch); 274 free (vhead); 275 send_to_server ("import\012", 0); 276 err += get_responses_and_close (); 277 return err; 278 } 279 #endif 280 281 if (!safe_location ()) 282 { 283 error (1, 0, "attempt to import the repository"); 284 } 285 286 /* 287 * Make all newly created directories writable. Should really use a more 288 * sophisticated security mechanism here. 289 */ 290 (void) umask (cvsumask); 291 make_directories (repository); 292 293 /* Create the logfile that will be logged upon completion */ 294 if ((logfp = cvs_temp_file (&tmpfile)) == NULL) 295 error (1, errno, "cannot create temporary file `%s'", tmpfile); 296 /* On systems where we can unlink an open file, do so, so it will go 297 away no matter how we exit. FIXME-maybe: Should be checking for 298 errors but I'm not sure which error(s) we get if we are on a system 299 where one can't unlink open files. */ 300 (void) CVS_UNLINK (tmpfile); 301 (void) fprintf (logfp, "\nVendor Tag:\t%s\n", argv[1]); 302 (void) fprintf (logfp, "Release Tags:\t"); 303 for (i = 2; i < argc; i++) 304 (void) fprintf (logfp, "%s\n\t\t", argv[i]); 305 (void) fprintf (logfp, "\n"); 306 307 /* Just Do It. */ 308 err = import_descend (message, argv[1], argc - 2, argv + 2); 309 if (conflicts) 310 { 311 if (!really_quiet) 312 { 313 char buf[20]; 314 char *buf2; 315 316 cvs_output_tagged ("+importmergecmd", NULL); 317 cvs_output_tagged ("newline", NULL); 318 sprintf (buf, "%d", conflicts); 319 cvs_output_tagged ("conflicts", buf); 320 cvs_output_tagged ("text", " conflicts created by this import."); 321 cvs_output_tagged ("newline", NULL); 322 cvs_output_tagged ("text", 323 "Use the following command to help the merge:"); 324 cvs_output_tagged ("newline", NULL); 325 cvs_output_tagged ("newline", NULL); 326 cvs_output_tagged ("text", "\t"); 327 cvs_output_tagged ("text", program_name); 328 if (CVSroot_cmdline != NULL) 329 { 330 cvs_output_tagged ("text", " -d "); 331 cvs_output_tagged ("text", CVSroot_cmdline); 332 } 333 cvs_output_tagged ("text", " checkout -j"); 334 buf2 = xmalloc (strlen (argv[1]) + 20); 335 sprintf (buf2, "%s:yesterday", argv[1]); 336 cvs_output_tagged ("mergetag1", buf2); 337 free (buf2); 338 cvs_output_tagged ("text", " -j"); 339 cvs_output_tagged ("mergetag2", argv[1]); 340 cvs_output_tagged ("text", " "); 341 cvs_output_tagged ("repository", argv[0]); 342 cvs_output_tagged ("newline", NULL); 343 cvs_output_tagged ("newline", NULL); 344 cvs_output_tagged ("-importmergecmd", NULL); 345 } 346 347 /* FIXME: I'm not sure whether we need to put this information 348 into the loginfo. If we do, then note that it does not 349 report any required -d option. There is no particularly 350 clean way to tell the server about the -d option used by 351 the client. */ 352 (void) fprintf (logfp, "\n%d conflicts created by this import.\n", 353 conflicts); 354 (void) fprintf (logfp, 355 "Use the following command to help the merge:\n\n"); 356 (void) fprintf (logfp, "\t%s checkout ", program_name); 357 (void) fprintf (logfp, "-j%s:yesterday -j%s %s\n\n", 358 argv[1], argv[1], argv[0]); 359 } 360 else 361 { 362 if (!really_quiet) 363 cvs_output ("\nNo conflicts created by this import\n\n", 0); 364 (void) fprintf (logfp, "\nNo conflicts created by this import\n\n"); 365 } 366 367 /* 368 * Write out the logfile and clean up. 369 */ 370 ulist = getlist (); 371 p = getnode (); 372 p->type = UPDATE; 373 p->delproc = update_delproc; 374 p->key = xstrdup ("- Imported sources"); 375 li = (struct logfile_info *) xmalloc (sizeof (struct logfile_info)); 376 li->type = T_TITLE; 377 li->tag = xstrdup (vbranch); 378 li->rev_old = li->rev_new = NULL; 379 p->data = (char *) li; 380 (void) addnode (ulist, p); 381 Update_Logfile (repository, message, logfp, ulist); 382 dellist (&ulist); 383 if (fclose (logfp) < 0) 384 error (0, errno, "error closing %s", tmpfile); 385 386 /* Make sure the temporary file goes away, even on systems that don't let 387 you delete a file that's in use. */ 388 if (CVS_UNLINK (tmpfile) < 0 && !existence_error (errno)) 389 error (0, errno, "cannot remove %s", tmpfile); 390 free (tmpfile); 391 392 if (message) 393 free (message); 394 free (repository); 395 free (vbranch); 396 free (vhead); 397 398 return (err); 399 } 400 401 /* Process all the files in ".", then descend into other directories. 402 Returns 0 for success, or >0 on error (in which case a message 403 will have been printed). */ 404 static int 405 import_descend (message, vtag, targc, targv) 406 char *message; 407 char *vtag; 408 int targc; 409 char *targv[]; 410 { 411 DIR *dirp; 412 struct dirent *dp; 413 int err = 0; 414 List *dirlist = NULL; 415 416 /* first, load up any per-directory ignore lists */ 417 ign_add_file (CVSDOTIGNORE, 1); 418 wrap_add_file (CVSDOTWRAPPER, 1); 419 420 if ((dirp = CVS_OPENDIR (".")) == NULL) 421 { 422 error (0, errno, "cannot open directory"); 423 err++; 424 } 425 else 426 { 427 errno = 0; 428 while ((dp = CVS_READDIR (dirp)) != NULL) 429 { 430 if (strcmp (dp->d_name, ".") == 0 || strcmp (dp->d_name, "..") == 0) 431 goto one_more_time_boys; 432 #ifdef SERVER_SUPPORT 433 /* CVS directories are created in the temp directory by 434 server.c because it doesn't special-case import. So 435 don't print a message about them, regardless of -I!. */ 436 if (server_active && strcmp (dp->d_name, CVSADM) == 0) 437 goto one_more_time_boys; 438 #endif 439 if (ign_name (dp->d_name)) 440 { 441 add_log ('I', dp->d_name); 442 goto one_more_time_boys; 443 } 444 445 if ( 446 #ifdef DT_DIR 447 (dp->d_type == DT_DIR 448 || (dp->d_type == DT_UNKNOWN && isdir (dp->d_name))) 449 #else 450 isdir (dp->d_name) 451 #endif 452 && !wrap_name_has (dp->d_name, WRAP_TOCVS) 453 ) 454 { 455 Node *n; 456 457 if (dirlist == NULL) 458 dirlist = getlist(); 459 460 n = getnode(); 461 n->key = xstrdup (dp->d_name); 462 addnode(dirlist, n); 463 } 464 else if ( 465 #ifdef DT_DIR 466 dp->d_type == DT_LNK 467 || (dp->d_type == DT_UNKNOWN && islink (dp->d_name)) 468 #else 469 islink (dp->d_name) 470 #endif 471 ) 472 { 473 add_log ('L', dp->d_name); 474 err++; 475 } 476 else 477 { 478 #ifdef CLIENT_SUPPORT 479 if (current_parsed_root->isremote) 480 err += client_process_import_file (message, dp->d_name, 481 vtag, targc, targv, 482 repository, 483 keyword_opt != NULL && 484 keyword_opt[0] == 'b', 485 use_file_modtime); 486 else 487 #endif 488 err += process_import_file (message, dp->d_name, 489 vtag, targc, targv); 490 } 491 one_more_time_boys: 492 errno = 0; 493 } 494 if (errno != 0) 495 { 496 error (0, errno, "cannot read directory"); 497 ++err; 498 } 499 (void) CVS_CLOSEDIR (dirp); 500 } 501 502 if (dirlist != NULL) 503 { 504 Node *head, *p; 505 506 head = dirlist->list; 507 for (p = head->next; p != head; p = p->next) 508 { 509 err += import_descend_dir (message, p->key, vtag, targc, targv); 510 } 511 512 dellist(&dirlist); 513 } 514 515 return (err); 516 } 517 518 /* 519 * Process the argument import file. 520 */ 521 static int 522 process_import_file (message, vfile, vtag, targc, targv) 523 char *message; 524 char *vfile; 525 char *vtag; 526 int targc; 527 char *targv[]; 528 { 529 char *rcs; 530 int inattic = 0; 531 532 rcs = xmalloc (strlen (repository) + strlen (vfile) + sizeof (RCSEXT) 533 + 5); 534 (void) sprintf (rcs, "%s/%s%s", repository, vfile, RCSEXT); 535 if (!isfile (rcs)) 536 { 537 char *attic_name; 538 539 attic_name = xmalloc (strlen (repository) + strlen (vfile) + 540 sizeof (CVSATTIC) + sizeof (RCSEXT) + 10); 541 (void) sprintf (attic_name, "%s/%s/%s%s", repository, CVSATTIC, 542 vfile, RCSEXT); 543 if (!isfile (attic_name)) 544 { 545 int retval; 546 char *free_opt = NULL; 547 char *our_opt = keyword_opt; 548 549 free (attic_name); 550 /* 551 * A new import source file; it doesn't exist as a ,v within the 552 * repository nor in the Attic -- create it anew. 553 */ 554 add_log ('N', vfile); 555 556 #ifdef SERVER_SUPPORT 557 /* The most reliable information on whether the file is binary 558 is what the client told us. That is because if the client had 559 the wrong idea about binaryness, it corrupted the file, so 560 we might as well believe the client. */ 561 if (server_active) 562 { 563 Node *node; 564 List *entries; 565 566 /* Reading all the entries for each file is fairly silly, and 567 probably slow. But I am too lazy at the moment to do 568 anything else. */ 569 entries = Entries_Open (0, NULL); 570 node = findnode_fn (entries, vfile); 571 if (node != NULL) 572 { 573 Entnode *entdata = (Entnode *) node->data; 574 if (entdata->type == ENT_FILE) 575 { 576 assert (entdata->options[0] == '-' 577 && entdata->options[1] == 'k'); 578 our_opt = xstrdup (entdata->options + 2); 579 free_opt = our_opt; 580 } 581 } 582 Entries_Close (entries); 583 } 584 #endif 585 586 retval = add_rcs_file (message, rcs, vfile, vhead, our_opt, 587 vbranch, vtag, targc, targv, 588 NULL, 0, logfp); 589 if (free_opt != NULL) 590 free (free_opt); 591 free (rcs); 592 return retval; 593 } 594 free (attic_name); 595 inattic = 1; 596 } 597 598 free (rcs); 599 /* 600 * an rcs file exists. have to do things the official, slow, way. 601 */ 602 return (update_rcs_file (message, vfile, vtag, targc, targv, inattic)); 603 } 604 605 /* 606 * The RCS file exists; update it by adding the new import file to the 607 * (possibly already existing) vendor branch. 608 */ 609 static int 610 update_rcs_file (message, vfile, vtag, targc, targv, inattic) 611 char *message; 612 char *vfile; 613 char *vtag; 614 int targc; 615 char *targv[]; 616 int inattic; 617 { 618 Vers_TS *vers; 619 int letter; 620 char *tocvsPath; 621 struct file_info finfo; 622 623 memset (&finfo, 0, sizeof finfo); 624 finfo.file = vfile; 625 /* Not used, so don't worry about it. */ 626 finfo.update_dir = NULL; 627 finfo.fullname = finfo.file; 628 finfo.repository = repository; 629 finfo.entries = NULL; 630 finfo.rcs = NULL; 631 vers = Version_TS (&finfo, (char *) NULL, vbranch, (char *) NULL, 632 1, 0); 633 if (vers->vn_rcs != NULL 634 && !RCS_isdead(vers->srcfile, vers->vn_rcs)) 635 { 636 int different; 637 638 /* 639 * The rcs file does have a revision on the vendor branch. Compare 640 * this revision with the import file; if they match exactly, there 641 * is no need to install the new import file as a new revision to the 642 * branch. Just tag the revision with the new import tags. 643 * 644 * This is to try to cut down the number of "C" conflict messages for 645 * locally modified import source files. 646 */ 647 tocvsPath = wrap_tocvs_process_file (vfile); 648 /* FIXME: Why don't we pass tocvsPath to RCS_cmp_file if it is 649 not NULL? */ 650 different = RCS_cmp_file (vers->srcfile, vers->vn_rcs, "-ko", vfile); 651 if (tocvsPath) 652 if (unlink_file_dir (tocvsPath) < 0) 653 error (0, errno, "cannot remove %s", tocvsPath); 654 655 if (!different) 656 { 657 int retval = 0; 658 659 /* 660 * The two files are identical. Just update the tags, print the 661 * "U", signifying that the file has changed, but needs no 662 * attention, and we're done. 663 */ 664 if (add_tags (vers->srcfile, vfile, vtag, targc, targv)) 665 retval = 1; 666 add_log ('U', vfile); 667 freevers_ts (&vers); 668 return (retval); 669 } 670 } 671 672 /* We may have failed to parse the RCS file; check just in case */ 673 if (vers->srcfile == NULL || 674 add_rev (message, vers->srcfile, vfile, vers->vn_rcs) || 675 add_tags (vers->srcfile, vfile, vtag, targc, targv)) 676 { 677 freevers_ts (&vers); 678 return (1); 679 } 680 681 if (vers->srcfile->branch == NULL || inattic || 682 strcmp (vers->srcfile->branch, vbranch) != 0) 683 { 684 conflicts++; 685 letter = 'C'; 686 } 687 else 688 letter = 'U'; 689 add_log (letter, vfile); 690 691 freevers_ts (&vers); 692 return (0); 693 } 694 695 /* 696 * Add the revision to the vendor branch 697 */ 698 static int 699 add_rev (message, rcs, vfile, vers) 700 char *message; 701 RCSNode *rcs; 702 char *vfile; 703 char *vers; 704 { 705 int locked, status, ierrno; 706 char *tocvsPath; 707 708 if (noexec) 709 return (0); 710 711 locked = 0; 712 if (vers != NULL) 713 { 714 /* Before RCS_lock existed, we were directing stdout, as well as 715 stderr, from the RCS command, to DEVNULL. I wouldn't guess that 716 was necessary, but I don't know for sure. */ 717 /* Earlier versions of this function printed a `fork failed' error 718 when RCS_lock returned an error code. That's not appropriate 719 now that RCS_lock is librarified, but should the error text be 720 preserved? */ 721 if (RCS_lock (rcs, vbranch, 1) != 0) 722 return 1; 723 locked = 1; 724 RCS_rewrite (rcs, NULL, NULL); 725 } 726 tocvsPath = wrap_tocvs_process_file (vfile); 727 728 status = RCS_checkin (rcs, tocvsPath == NULL ? vfile : tocvsPath, 729 message, vbranch, 730 (RCS_FLAGS_QUIET | RCS_FLAGS_KEEPFILE 731 | (use_file_modtime ? RCS_FLAGS_MODTIME : 0))); 732 ierrno = errno; 733 734 if ((tocvsPath != NULL) && (unlink_file_dir (tocvsPath) < 0)) 735 error (0, errno, "cannot remove %s", tocvsPath); 736 737 if (status) 738 { 739 if (!noexec) 740 { 741 fperrmsg (logfp, 0, status == -1 ? ierrno : 0, 742 "ERROR: Check-in of %s failed", rcs->path); 743 error (0, status == -1 ? ierrno : 0, 744 "ERROR: Check-in of %s failed", rcs->path); 745 } 746 if (locked) 747 { 748 (void) RCS_unlock(rcs, vbranch, 0); 749 RCS_rewrite (rcs, NULL, NULL); 750 } 751 return (1); 752 } 753 return (0); 754 } 755 756 /* 757 * Add the vendor branch tag and all the specified import release tags to the 758 * RCS file. The vendor branch tag goes on the branch root (1.1.1) while the 759 * vendor release tags go on the newly added leaf of the branch (1.1.1.1, 760 * 1.1.1.2, ...). 761 */ 762 static int 763 add_tags (rcs, vfile, vtag, targc, targv) 764 RCSNode *rcs; 765 char *vfile; 766 char *vtag; 767 int targc; 768 char *targv[]; 769 { 770 int i, ierrno; 771 Vers_TS *vers; 772 int retcode = 0; 773 struct file_info finfo; 774 775 if (noexec) 776 return (0); 777 778 if ((retcode = RCS_settag(rcs, vtag, vbranch)) != 0) 779 { 780 ierrno = errno; 781 fperrmsg (logfp, 0, retcode == -1 ? ierrno : 0, 782 "ERROR: Failed to set tag %s in %s", vtag, rcs->path); 783 error (0, retcode == -1 ? ierrno : 0, 784 "ERROR: Failed to set tag %s in %s", vtag, rcs->path); 785 return (1); 786 } 787 RCS_rewrite (rcs, NULL, NULL); 788 789 memset (&finfo, 0, sizeof finfo); 790 finfo.file = vfile; 791 /* Not used, so don't worry about it. */ 792 finfo.update_dir = NULL; 793 finfo.fullname = finfo.file; 794 finfo.repository = repository; 795 finfo.entries = NULL; 796 finfo.rcs = NULL; 797 vers = Version_TS (&finfo, NULL, vtag, NULL, 1, 0); 798 for (i = 0; i < targc; i++) 799 { 800 if ((retcode = RCS_settag (rcs, targv[i], vers->vn_rcs)) == 0) 801 RCS_rewrite (rcs, NULL, NULL); 802 else 803 { 804 ierrno = errno; 805 fperrmsg (logfp, 0, retcode == -1 ? ierrno : 0, 806 "WARNING: Couldn't add tag %s to %s", targv[i], 807 rcs->path); 808 error (0, retcode == -1 ? ierrno : 0, 809 "WARNING: Couldn't add tag %s to %s", targv[i], 810 rcs->path); 811 } 812 } 813 freevers_ts (&vers); 814 return (0); 815 } 816 817 /* 818 * Stolen from rcs/src/rcsfnms.c, and adapted/extended. 819 */ 820 struct compair 821 { 822 char *suffix, *comlead; 823 }; 824 825 static const struct compair comtable[] = 826 { 827 828 /* 829 * comtable pairs each filename suffix with a comment leader. The comment 830 * leader is placed before each line generated by the $Log keyword. This 831 * table is used to guess the proper comment leader from the working file's 832 * suffix during initial ci (see InitAdmin()). Comment leaders are needed for 833 * languages without multiline comments; for others they are optional. 834 * 835 * I believe that the comment leader is unused if you are using RCS 5.7, which 836 * decides what leader to use based on the text surrounding the $Log keyword 837 * rather than a specified comment leader. 838 */ 839 {"a", "-- "}, /* Ada */ 840 {"ada", "-- "}, 841 {"adb", "-- "}, 842 {"asm", ";; "}, /* assembler (MS-DOS) */ 843 {"ads", "-- "}, /* Ada */ 844 {"bas", "' "}, /* Visual Basic code */ 845 {"bat", ":: "}, /* batch (MS-DOS) */ 846 {"body", "-- "}, /* Ada */ 847 {"c", " * "}, /* C */ 848 {"c++", "// "}, /* C++ in all its infinite guises */ 849 {"cc", "// "}, 850 {"cpp", "// "}, 851 {"cxx", "// "}, 852 {"m", "// "}, /* Objective-C */ 853 {"cl", ";;; "}, /* Common Lisp */ 854 {"cmd", ":: "}, /* command (OS/2) */ 855 {"cmf", "c "}, /* CM Fortran */ 856 {"cs", " * "}, /* C* */ 857 {"csh", "# "}, /* shell */ 858 {"dlg", " * "}, /* MS Windows dialog file */ 859 {"e", "# "}, /* efl */ 860 {"epsf", "% "}, /* encapsulated postscript */ 861 {"epsi", "% "}, /* encapsulated postscript */ 862 {"el", "; "}, /* Emacs Lisp */ 863 {"f", "c "}, /* Fortran */ 864 {"for", "c "}, 865 {"frm", "' "}, /* Visual Basic form */ 866 {"h", " * "}, /* C-header */ 867 {"hh", "// "}, /* C++ header */ 868 {"hpp", "// "}, 869 {"hxx", "// "}, 870 {"in", "# "}, /* for Makefile.in */ 871 {"l", " * "}, /* lex (conflict between lex and 872 * franzlisp) */ 873 {"mac", ";; "}, /* macro (DEC-10, MS-DOS, PDP-11, 874 * VMS, etc) */ 875 {"mak", "# "}, /* makefile, e.g. Visual C++ */ 876 {"me", ".\\\" "}, /* me-macros t/nroff */ 877 {"ml", "; "}, /* mocklisp */ 878 {"mm", ".\\\" "}, /* mm-macros t/nroff */ 879 {"ms", ".\\\" "}, /* ms-macros t/nroff */ 880 {"man", ".\\\" "}, /* man-macros t/nroff */ 881 {"1", ".\\\" "}, /* feeble attempt at man pages... */ 882 {"2", ".\\\" "}, 883 {"3", ".\\\" "}, 884 {"4", ".\\\" "}, 885 {"5", ".\\\" "}, 886 {"6", ".\\\" "}, 887 {"7", ".\\\" "}, 888 {"8", ".\\\" "}, 889 {"9", ".\\\" "}, 890 {"p", " * "}, /* pascal */ 891 {"pas", " * "}, 892 {"pl", "# "}, /* perl (conflict with Prolog) */ 893 {"ps", "% "}, /* postscript */ 894 {"psw", "% "}, /* postscript wrap */ 895 {"pswm", "% "}, /* postscript wrap */ 896 {"r", "# "}, /* ratfor */ 897 {"rc", " * "}, /* Microsoft Windows resource file */ 898 {"red", "% "}, /* psl/rlisp */ 899 #ifdef __sparc__ 900 {"s", "! "}, /* assembler */ 901 #endif 902 #ifdef __sparc64__ 903 {"s", "! "}, /* assembler */ 904 #endif 905 #ifdef __mc68000__ 906 {"s", "| "}, /* assembler */ 907 #endif 908 #ifdef __pdp11__ 909 {"s", "/ "}, /* assembler */ 910 #endif 911 #ifdef __vax__ 912 {"s", "# "}, /* assembler */ 913 #endif 914 #ifdef __ksr__ 915 {"s", "# "}, /* assembler */ 916 {"S", "# "}, /* Macro assembler */ 917 #endif 918 {"sh", "# "}, /* shell */ 919 {"sl", "% "}, /* psl */ 920 {"spec", "-- "}, /* Ada */ 921 {"tex", "% "}, /* tex */ 922 {"y", " * "}, /* yacc */ 923 {"ye", " * "}, /* yacc-efl */ 924 {"yr", " * "}, /* yacc-ratfor */ 925 {"", "# "}, /* default for empty suffix */ 926 {NULL, "# "} /* default for unknown suffix; */ 927 /* must always be last */ 928 }; 929 930 static char * 931 get_comment (user) 932 char *user; 933 { 934 char *cp, *suffix; 935 char *suffix_path; 936 int i; 937 char *retval; 938 939 suffix_path = xmalloc (strlen (user) + 5); 940 cp = strrchr (user, '.'); 941 if (cp != NULL) 942 { 943 cp++; 944 945 /* 946 * Convert to lower-case, since we are not concerned about the 947 * case-ness of the suffix. 948 */ 949 (void) strcpy (suffix_path, cp); 950 for (cp = suffix_path; *cp; cp++) 951 if (isupper ((unsigned char) *cp)) 952 *cp = tolower (*cp); 953 suffix = suffix_path; 954 } 955 else 956 suffix = ""; /* will use the default */ 957 for (i = 0;; i++) 958 { 959 if (comtable[i].suffix == NULL) 960 { 961 /* Default. Note we'll always hit this case before we 962 ever return NULL. */ 963 retval = comtable[i].comlead; 964 break; 965 } 966 if (strcmp (suffix, comtable[i].suffix) == 0) 967 { 968 retval = comtable[i].comlead; 969 break; 970 } 971 } 972 free (suffix_path); 973 return retval; 974 } 975 976 /* Create a new RCS file from scratch. 977 978 This probably should be moved to rcs.c now that it is called from 979 places outside import.c. 980 981 Return value is 0 for success, or nonzero for failure (in which 982 case an error message will have already been printed). */ 983 int 984 add_rcs_file (message, rcs, user, add_vhead, key_opt, 985 add_vbranch, vtag, targc, targv, 986 desctext, desclen, add_logfp) 987 /* Log message for the addition. Not used if add_vhead == NULL. */ 988 char *message; 989 /* Filename of the RCS file to create. */ 990 char *rcs; 991 /* Filename of the file to serve as the contents of the initial 992 revision. Even if add_vhead is NULL, we use this to determine 993 the modes to give the new RCS file. */ 994 char *user; 995 996 /* Revision number of head that we are adding. Normally 1.1 but 997 could be another revision as long as ADD_VBRANCH is a branch 998 from it. If NULL, then just add an empty file without any 999 revisions (similar to the one created by "rcs -i"). */ 1000 char *add_vhead; 1001 1002 /* Keyword expansion mode, e.g., "b" for binary. NULL means the 1003 default behavior. */ 1004 char *key_opt; 1005 1006 /* Vendor branch to import to, or NULL if none. If non-NULL, then 1007 vtag should also be non-NULL. */ 1008 char *add_vbranch; 1009 char *vtag; 1010 int targc; 1011 char *targv[]; 1012 1013 /* If non-NULL, description for the file. If NULL, the description 1014 will be empty. */ 1015 char *desctext; 1016 size_t desclen; 1017 1018 /* Write errors to here as well as via error (), or NULL if we should 1019 use only error (). */ 1020 FILE *add_logfp; 1021 { 1022 FILE *fprcs, *fpuser; 1023 struct stat sb; 1024 struct tm *ftm; 1025 time_t now; 1026 char altdate1[MAXDATELEN]; 1027 char *author; 1028 int i, ierrno, err = 0; 1029 mode_t mode; 1030 char *tocvsPath; 1031 char *userfile; 1032 char *local_opt = key_opt; 1033 char *free_opt = NULL; 1034 mode_t file_type; 1035 1036 if (noexec) 1037 return (0); 1038 1039 /* Note that as the code stands now, the -k option overrides any 1040 settings in wrappers (whether CVSROOT/cvswrappers, -W, or 1041 whatever). Some have suggested this should be the other way 1042 around. As far as I know the documentation doesn't say one way 1043 or the other. Before making a change of this sort, should think 1044 about what is best, document it (in cvs.texinfo and NEWS), &c. */ 1045 1046 if (local_opt == NULL) 1047 { 1048 if (wrap_name_has (user, WRAP_RCSOPTION)) 1049 { 1050 local_opt = free_opt = wrap_rcsoption (user, 0); 1051 } 1052 } 1053 1054 tocvsPath = wrap_tocvs_process_file (user); 1055 userfile = (tocvsPath == NULL ? user : tocvsPath); 1056 1057 /* Opening in text mode is probably never the right thing for the 1058 server (because the protocol encodes text files in a fashion 1059 which does not depend on what the client or server OS is, as 1060 documented in cvsclient.texi), but as long as the server just 1061 runs on unix it is a moot point. */ 1062 1063 /* If PreservePermissions is set, then make sure that the file 1064 is a plain file before trying to open it. Longstanding (although 1065 often unpopular) CVS behavior has been to follow symlinks, so we 1066 maintain that behavior if PreservePermissions is not on. 1067 1068 NOTE: this error message used to be `cannot fstat', but is now 1069 `cannot lstat'. I don't see a way around this, since we must 1070 stat the file before opening it. -twp */ 1071 1072 if (CVS_LSTAT (userfile, &sb) < 0) 1073 { 1074 /* not fatal, continue import */ 1075 if (add_logfp != NULL) 1076 fperrmsg (add_logfp, 0, errno, 1077 "ERROR: cannot lstat file %s", userfile); 1078 error (0, errno, "cannot lstat file %s", userfile); 1079 goto read_error; 1080 } 1081 file_type = sb.st_mode & S_IFMT; 1082 1083 fpuser = NULL; 1084 if (!preserve_perms || file_type == S_IFREG) 1085 { 1086 fpuser = CVS_FOPEN (userfile, 1087 ((local_opt != NULL && strcmp (local_opt, "b") == 0) 1088 ? "rb" 1089 : "r") 1090 ); 1091 if (fpuser == NULL) 1092 { 1093 /* not fatal, continue import */ 1094 if (add_logfp != NULL) 1095 fperrmsg (add_logfp, 0, errno, 1096 "ERROR: cannot read file %s", userfile); 1097 error (0, errno, "ERROR: cannot read file %s", userfile); 1098 goto read_error; 1099 } 1100 } 1101 1102 fprcs = CVS_FOPEN (rcs, "w+b"); 1103 if (fprcs == NULL) 1104 { 1105 ierrno = errno; 1106 goto write_error_noclose; 1107 } 1108 1109 /* 1110 * putadmin() 1111 */ 1112 if (add_vhead != NULL) 1113 { 1114 if (fprintf (fprcs, "head %s;\012", add_vhead) < 0) 1115 goto write_error; 1116 } 1117 else 1118 { 1119 if (fprintf (fprcs, "head ;\012") < 0) 1120 goto write_error; 1121 } 1122 1123 if (add_vbranch != NULL) 1124 { 1125 if (fprintf (fprcs, "branch %s;\012", add_vbranch) < 0) 1126 goto write_error; 1127 } 1128 if (fprintf (fprcs, "access ;\012") < 0 || 1129 fprintf (fprcs, "symbols ") < 0) 1130 { 1131 goto write_error; 1132 } 1133 1134 for (i = targc - 1; i >= 0; i--) 1135 { 1136 /* RCS writes the symbols backwards */ 1137 assert (add_vbranch != NULL); 1138 if (fprintf (fprcs, "%s:%s.1 ", targv[i], add_vbranch) < 0) 1139 goto write_error; 1140 } 1141 1142 if (add_vbranch != NULL) 1143 { 1144 if (fprintf (fprcs, "%s:%s", vtag, add_vbranch) < 0) 1145 goto write_error; 1146 } 1147 if (fprintf (fprcs, ";\012") < 0) 1148 goto write_error; 1149 1150 if (fprintf (fprcs, "locks ; strict;\012") < 0 || 1151 /* XXX - make sure @@ processing works in the RCS file */ 1152 fprintf (fprcs, "comment @%s@;\012", get_comment (user)) < 0) 1153 { 1154 goto write_error; 1155 } 1156 1157 if (local_opt != NULL) 1158 { 1159 if (fprintf (fprcs, "expand @%s@;\012", local_opt) < 0) 1160 { 1161 goto write_error; 1162 } 1163 } 1164 1165 if (fprintf (fprcs, "\012") < 0) 1166 goto write_error; 1167 1168 /* Write the revision(s), with the date and author and so on 1169 (that is "delta" rather than "deltatext" from rcsfile(5)). */ 1170 if (add_vhead != NULL) 1171 { 1172 if (use_file_modtime) 1173 now = sb.st_mtime; 1174 else 1175 (void) time (&now); 1176 ftm = gmtime (&now); 1177 (void) sprintf (altdate1, DATEFORM, 1178 ftm->tm_year + (ftm->tm_year < 100 ? 0 : 1900), 1179 ftm->tm_mon + 1, ftm->tm_mday, ftm->tm_hour, 1180 ftm->tm_min, ftm->tm_sec); 1181 author = getcaller (); 1182 1183 if (fprintf (fprcs, "\012%s\012", add_vhead) < 0 || 1184 fprintf (fprcs, "date %s; author %s; state Exp;\012", 1185 altdate1, author) < 0) 1186 goto write_error; 1187 1188 if (fprintf (fprcs, "branches") < 0) 1189 goto write_error; 1190 if (add_vbranch != NULL) 1191 { 1192 if (fprintf (fprcs, " %s.1", add_vbranch) < 0) 1193 goto write_error; 1194 } 1195 if (fprintf (fprcs, ";\012") < 0) 1196 goto write_error; 1197 1198 if (fprintf (fprcs, "next ;\012") < 0) 1199 goto write_error; 1200 1201 #ifdef PRESERVE_PERMISSIONS_SUPPORT 1202 /* Store initial permissions if necessary. */ 1203 if (preserve_perms) 1204 { 1205 if (file_type == S_IFLNK) 1206 { 1207 char *link = xreadlink (userfile); 1208 if (fprintf (fprcs, "symlink\t@") < 0 || 1209 expand_at_signs (link, strlen (link), fprcs) < 0 || 1210 fprintf (fprcs, "@;\012") < 0) 1211 goto write_error; 1212 free (link); 1213 } 1214 else 1215 { 1216 if (fprintf (fprcs, "owner\t%u;\012", sb.st_uid) < 0) 1217 goto write_error; 1218 if (fprintf (fprcs, "group\t%u;\012", sb.st_gid) < 0) 1219 goto write_error; 1220 if (fprintf (fprcs, "permissions\t%o;\012", 1221 sb.st_mode & 07777) < 0) 1222 goto write_error; 1223 switch (file_type) 1224 { 1225 case S_IFREG: break; 1226 case S_IFCHR: 1227 case S_IFBLK: 1228 #ifdef HAVE_ST_RDEV 1229 if (fprintf (fprcs, "special\t%s %lu;\012", 1230 (file_type == S_IFCHR 1231 ? "character" 1232 : "block"), 1233 (unsigned long) sb.st_rdev) < 0) 1234 goto write_error; 1235 #else 1236 error (0, 0, 1237 "can't import %s: unable to import device files on this system", 1238 userfile); 1239 #endif 1240 break; 1241 default: 1242 error (0, 0, 1243 "can't import %s: unknown kind of special file", 1244 userfile); 1245 } 1246 } 1247 } 1248 #endif 1249 1250 if (add_vbranch != NULL) 1251 { 1252 if (fprintf (fprcs, "\012%s.1\012", add_vbranch) < 0 || 1253 fprintf (fprcs, "date %s; author %s; state Exp;\012", 1254 altdate1, author) < 0 || 1255 fprintf (fprcs, "branches ;\012") < 0 || 1256 fprintf (fprcs, "next ;\012") < 0) 1257 goto write_error; 1258 1259 #ifdef PRESERVE_PERMISSIONS_SUPPORT 1260 /* Store initial permissions if necessary. */ 1261 if (preserve_perms) 1262 { 1263 if (file_type == S_IFLNK) 1264 { 1265 char *link = xreadlink (userfile); 1266 if (fprintf (fprcs, "symlink\t@") < 0 || 1267 expand_at_signs (link, strlen (link), fprcs) < 0 || 1268 fprintf (fprcs, "@;\012") < 0) 1269 goto write_error; 1270 free (link); 1271 } 1272 else 1273 { 1274 if (fprintf (fprcs, "owner\t%u;\012", sb.st_uid) < 0 || 1275 fprintf (fprcs, "group\t%u;\012", sb.st_gid) < 0 || 1276 fprintf (fprcs, "permissions\t%o;\012", 1277 sb.st_mode & 07777) < 0) 1278 goto write_error; 1279 1280 switch (file_type) 1281 { 1282 case S_IFREG: break; 1283 case S_IFCHR: 1284 case S_IFBLK: 1285 #ifdef HAVE_ST_RDEV 1286 if (fprintf (fprcs, "special\t%s %lu;\012", 1287 (file_type == S_IFCHR 1288 ? "character" 1289 : "block"), 1290 (unsigned long) sb.st_rdev) < 0) 1291 goto write_error; 1292 #else 1293 error (0, 0, 1294 "can't import %s: unable to import device files on this system", 1295 userfile); 1296 #endif 1297 break; 1298 default: 1299 error (0, 0, 1300 "cannot import %s: special file of unknown type", 1301 userfile); 1302 } 1303 } 1304 } 1305 #endif 1306 1307 if (fprintf (fprcs, "\012") < 0) 1308 goto write_error; 1309 } 1310 } 1311 1312 /* Now write the description (possibly empty). */ 1313 if (fprintf (fprcs, "\012desc\012") < 0 || 1314 fprintf (fprcs, "@") < 0) 1315 goto write_error; 1316 if (desctext != NULL) 1317 { 1318 /* The use of off_t not size_t for the second argument is very 1319 strange, since we are dealing with something which definitely 1320 fits in memory. */ 1321 if (expand_at_signs (desctext, (off_t) desclen, fprcs) < 0) 1322 goto write_error; 1323 } 1324 if (fprintf (fprcs, "@\012\012\012") < 0) 1325 goto write_error; 1326 1327 /* Now write the log messages and contents for the revision(s) (that 1328 is, "deltatext" rather than "delta" from rcsfile(5)). */ 1329 if (add_vhead != NULL) 1330 { 1331 if (fprintf (fprcs, "\012%s\012", add_vhead) < 0 || 1332 fprintf (fprcs, "log\012@") < 0) 1333 goto write_error; 1334 if (add_vbranch != NULL) 1335 { 1336 /* We are going to put the log message in the revision on the 1337 branch. So putting it here too seems kind of redundant, I 1338 guess (and that is what CVS has always done, anyway). */ 1339 if (fprintf (fprcs, "Initial revision\012") < 0) 1340 goto write_error; 1341 } 1342 else 1343 { 1344 if (expand_at_signs (message, (off_t) strlen (message), fprcs) < 0) 1345 goto write_error; 1346 } 1347 if (fprintf (fprcs, "@\012") < 0 || 1348 fprintf (fprcs, "text\012@") < 0) 1349 { 1350 goto write_error; 1351 } 1352 1353 /* Now copy over the contents of the file, expanding at signs. 1354 If preserve_perms is set, do this only for regular files. */ 1355 if (!preserve_perms || file_type == S_IFREG) 1356 { 1357 char buf[8192]; 1358 unsigned int len; 1359 1360 while (1) 1361 { 1362 len = fread (buf, 1, sizeof buf, fpuser); 1363 if (len == 0) 1364 { 1365 if (ferror (fpuser)) 1366 error (1, errno, "cannot read file %s for copying", 1367 user); 1368 break; 1369 } 1370 if (expand_at_signs (buf, len, fprcs) < 0) 1371 goto write_error; 1372 } 1373 } 1374 if (fprintf (fprcs, "@\012\012") < 0) 1375 goto write_error; 1376 if (add_vbranch != NULL) 1377 { 1378 if (fprintf (fprcs, "\012%s.1\012", add_vbranch) < 0 || 1379 fprintf (fprcs, "log\012@") < 0 || 1380 expand_at_signs (message, 1381 (off_t) strlen (message), fprcs) < 0 || 1382 fprintf (fprcs, "@\012text\012") < 0 || 1383 fprintf (fprcs, "@@\012") < 0) 1384 goto write_error; 1385 } 1386 } 1387 1388 if (fclose (fprcs) == EOF) 1389 { 1390 ierrno = errno; 1391 goto write_error_noclose; 1392 } 1393 /* Close fpuser only if we opened it to begin with. */ 1394 if (fpuser != NULL) 1395 { 1396 if (fclose (fpuser) < 0) 1397 error (0, errno, "cannot close %s", user); 1398 } 1399 1400 /* 1401 * Fix the modes on the RCS files. The user modes of the original 1402 * user file are propagated to the group and other modes as allowed 1403 * by the repository umask, except that all write permissions are 1404 * turned off. 1405 */ 1406 mode = (sb.st_mode | 1407 (sb.st_mode & S_IRWXU) >> 3 | 1408 (sb.st_mode & S_IRWXU) >> 6) & 1409 ~cvsumask & 1410 ~(S_IWRITE | S_IWGRP | S_IWOTH); 1411 if (chmod (rcs, mode) < 0) 1412 { 1413 ierrno = errno; 1414 if (add_logfp != NULL) 1415 fperrmsg (add_logfp, 0, ierrno, 1416 "WARNING: cannot change mode of file %s", rcs); 1417 error (0, ierrno, "WARNING: cannot change mode of file %s", rcs); 1418 err++; 1419 } 1420 if (tocvsPath) 1421 if (unlink_file_dir (tocvsPath) < 0) 1422 error (0, errno, "cannot remove %s", tocvsPath); 1423 if (free_opt != NULL) 1424 free (free_opt); 1425 return (err); 1426 1427 write_error: 1428 ierrno = errno; 1429 if (fclose (fprcs) < 0) 1430 error (0, errno, "cannot close %s", rcs); 1431 write_error_noclose: 1432 if (fclose (fpuser) < 0) 1433 error (0, errno, "cannot close %s", user); 1434 if (add_logfp != NULL) 1435 fperrmsg (add_logfp, 0, ierrno, "ERROR: cannot write file %s", rcs); 1436 error (0, ierrno, "ERROR: cannot write file %s", rcs); 1437 if (ierrno == ENOSPC) 1438 { 1439 if (CVS_UNLINK (rcs) < 0) 1440 error (0, errno, "cannot remove %s", rcs); 1441 if (add_logfp != NULL) 1442 fperrmsg (add_logfp, 0, 0, "ERROR: out of space - aborting"); 1443 error (1, 0, "ERROR: out of space - aborting"); 1444 } 1445 read_error: 1446 if (tocvsPath) 1447 if (unlink_file_dir (tocvsPath) < 0) 1448 error (0, errno, "cannot remove %s", tocvsPath); 1449 1450 if (free_opt != NULL) 1451 free (free_opt); 1452 1453 return (err + 1); 1454 } 1455 1456 /* 1457 * Write SIZE bytes at BUF to FP, expanding @ signs into double @ 1458 * signs. If an error occurs, return a negative value and set errno 1459 * to indicate the error. If not, return a nonnegative value. 1460 */ 1461 int 1462 expand_at_signs (buf, size, fp) 1463 char *buf; 1464 off_t size; 1465 FILE *fp; 1466 { 1467 register char *cp, *next; 1468 1469 cp = buf; 1470 while ((next = memchr (cp, '@', size)) != NULL) 1471 { 1472 int len; 1473 1474 ++next; 1475 len = next - cp; 1476 if (fwrite (cp, 1, len, fp) != len) 1477 return EOF; 1478 if (putc ('@', fp) == EOF) 1479 return EOF; 1480 cp = next; 1481 size -= len; 1482 } 1483 1484 if (fwrite (cp, 1, size, fp) != size) 1485 return EOF; 1486 1487 return 1; 1488 } 1489 1490 /* 1491 * Write an update message to (potentially) the screen and the log file. 1492 */ 1493 static void 1494 add_log (ch, fname) 1495 int ch; 1496 char *fname; 1497 { 1498 if (!really_quiet) /* write to terminal */ 1499 { 1500 char buf[2]; 1501 buf[0] = ch; 1502 buf[1] = ' '; 1503 cvs_output (buf, 2); 1504 if (repos_len) 1505 { 1506 cvs_output (repository + repos_len + 1, 0); 1507 cvs_output ("/", 1); 1508 } 1509 else if (repository[0] != '\0') 1510 { 1511 cvs_output (repository, 0); 1512 cvs_output ("/", 1); 1513 } 1514 cvs_output (fname, 0); 1515 cvs_output ("\n", 1); 1516 } 1517 1518 if (repos_len) /* write to logfile */ 1519 (void) fprintf (logfp, "%c %s/%s\n", ch, 1520 repository + repos_len + 1, fname); 1521 else if (repository[0]) 1522 (void) fprintf (logfp, "%c %s/%s\n", ch, repository, fname); 1523 else 1524 (void) fprintf (logfp, "%c %s\n", ch, fname); 1525 } 1526 1527 /* 1528 * This is the recursive function that walks the argument directory looking 1529 * for sub-directories that have CVS administration files in them and updates 1530 * them recursively. 1531 * 1532 * Note that we do not follow symbolic links here, which is a feature! 1533 */ 1534 static int 1535 import_descend_dir (message, dir, vtag, targc, targv) 1536 char *message; 1537 char *dir; 1538 char *vtag; 1539 int targc; 1540 char *targv[]; 1541 { 1542 struct saved_cwd cwd; 1543 char *cp; 1544 int ierrno, err; 1545 char *rcs = NULL; 1546 1547 if (islink (dir)) 1548 return (0); 1549 if (save_cwd (&cwd)) 1550 { 1551 fperrmsg (logfp, 0, 0, "ERROR: cannot get working directory"); 1552 return (1); 1553 } 1554 1555 /* Concatenate DIR to the end of REPOSITORY. */ 1556 if (repository[0] == '\0') 1557 { 1558 char *new = xstrdup (dir); 1559 free (repository); 1560 repository = new; 1561 } 1562 else 1563 { 1564 char *new = xmalloc (strlen (repository) + strlen (dir) + 10); 1565 strcpy (new, repository); 1566 (void) strcat (new, "/"); 1567 (void) strcat (new, dir); 1568 free (repository); 1569 repository = new; 1570 } 1571 1572 #ifdef CLIENT_SUPPORT 1573 if (!quiet && !current_parsed_root->isremote) 1574 #else 1575 if (!quiet) 1576 #endif 1577 error (0, 0, "Importing %s", repository); 1578 1579 if ( CVS_CHDIR (dir) < 0) 1580 { 1581 ierrno = errno; 1582 fperrmsg (logfp, 0, ierrno, "ERROR: cannot chdir to %s", repository); 1583 error (0, ierrno, "ERROR: cannot chdir to %s", repository); 1584 err = 1; 1585 goto out; 1586 } 1587 #ifdef CLIENT_SUPPORT 1588 if (!current_parsed_root->isremote && !isdir (repository)) 1589 #else 1590 if (!isdir (repository)) 1591 #endif 1592 { 1593 rcs = xmalloc (strlen (repository) + sizeof (RCSEXT) + 5); 1594 (void) sprintf (rcs, "%s%s", repository, RCSEXT); 1595 if (isfile (repository) || isfile(rcs)) 1596 { 1597 fperrmsg (logfp, 0, 0, 1598 "ERROR: %s is a file, should be a directory!", 1599 repository); 1600 error (0, 0, "ERROR: %s is a file, should be a directory!", 1601 repository); 1602 err = 1; 1603 goto out; 1604 } 1605 if (noexec == 0 && CVS_MKDIR (repository, 0777) < 0) 1606 { 1607 ierrno = errno; 1608 fperrmsg (logfp, 0, ierrno, 1609 "ERROR: cannot mkdir %s -- not added", repository); 1610 error (0, ierrno, 1611 "ERROR: cannot mkdir %s -- not added", repository); 1612 err = 1; 1613 goto out; 1614 } 1615 } 1616 err = import_descend (message, vtag, targc, targv); 1617 out: 1618 if (rcs != NULL) 1619 free (rcs); 1620 if ((cp = strrchr (repository, '/')) != NULL) 1621 *cp = '\0'; 1622 else 1623 repository[0] = '\0'; 1624 if (restore_cwd (&cwd, NULL)) 1625 error_exit (); 1626 free_cwd (&cwd); 1627 return (err); 1628 } 1629