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