1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * Copyright (c) 1988 AT&T 29 * All Rights Reserved 30 * 31 */ 32 33 #pragma ident "%Z%%M% %I% %E% SMI" 34 35 /* 36 * Incompatible Archive Header 37 * 38 * The archive file member header used in SunOS 4.1 archive files and 39 * Solaris archive files are incompatible. The header file is: 40 * /usr/include/ar.h, struct ar_hdr. 41 * The member ar_name[] in Solaris comforms with Standard and the 42 * member name terminates with '/'. The SunOS's member does not terminate 43 * with '/' character. A bug 4046054 was filed: 44 * The ar command in Solaris 2.5.1 is incompatible with archives 45 * created on 4.x. 46 * 47 * To handle archive files created in SunOS 4.1 system on Solaris, the 48 * following changes were made: 49 * 50 * 1. file.c/writefile() 51 * Before writing each member files into the output 52 * archive file, ar_name[] is checked. If it is NULL, 53 * it means that the original archive header for this 54 * member was incompatible with Solaris format. 55 * 56 * The original Solaris ar command ended up having 57 * NULL name for the header. The change here uses the 58 * ar_rawname, which is much closer to the original 59 * name. 60 * 61 * 2. cmd.c 62 * For the p command, the code used to use only ar_longname 63 * to seach the matching name. The member is set to NULL 64 * if the archive member header was incompatible. 65 * The ar_rawname is also used to find the matching member name. 66 * 67 * For commands to update the archive file, we do not 68 * use ar_rawname, and just use the ar_longname. The commands are 69 * r (replace), m (modify the position) and d (delete). 70 */ 71 72 #include "inc.h" 73 #include "extern.h" 74 75 /* 76 * Function prototypes 77 */ 78 static char *match(char *, Cmd_info *); 79 80 static void cleanup(Cmd_info *); 81 static void movefil(ARFILE *, struct stat *); 82 static void mesg(int, char *, Cmd_info *); 83 static void ar_select(int *, unsigned long); 84 85 static FILE *stats(char *, struct stat *); 86 87 static int create_extract(ARFILE *, int, int, Cmd_info *); 88 89 /* 90 * Commands 91 */ 92 int 93 rcmd(Cmd_info *cmd_info) 94 { 95 FILE *f; 96 ARFILE *fileptr; 97 ARFILE *abifile = NULL; 98 ARFILE *backptr = NULL; 99 ARFILE *endptr; 100 ARFILE *moved_files; 101 ARFILE *prev_entry, *new_listhead, *new_listend; 102 int deleted; 103 struct stat stbuf; 104 char *gfile; 105 106 new_listhead = NULL; 107 new_listend = NULL; 108 prev_entry = NULL; 109 110 for (fileptr = getfile(cmd_info); 111 fileptr; fileptr = getfile(cmd_info)) { 112 deleted = 0; 113 if (!abifile && cmd_info-> ponam && 114 strcmp(fileptr->ar_longname, cmd_info->ponam) == 0) 115 abifile = fileptr; 116 else if (!abifile) 117 backptr = fileptr; 118 119 if (cmd_info->namc == 0 || 120 (gfile = match(fileptr->ar_longname, cmd_info)) != NULL) { 121 /* 122 * NOTE: 123 * Refer to "Incompatible Archive Header" 124 * blocked comment at the beginning of this file. 125 */ 126 f = stats(gfile, &stbuf); /* gfile is set by match */ 127 if (f == NULL) { 128 if (cmd_info->namc) 129 error_message(SYS_OPEN_ERROR, 130 SYSTEM_ERROR, strerror(errno), 131 gfile); 132 /* 133 * Created 134 */ 135 mesg('c', gfile, cmd_info); 136 } else { 137 if (opt_FLAG(cmd_info, u_FLAG) && 138 stbuf.st_mtime <= fileptr->ar_date) { 139 (void) fclose(f); 140 continue; 141 } 142 /* 143 * Replaced 144 */ 145 mesg('r', fileptr->ar_longname, cmd_info); 146 movefil(fileptr, &stbuf); 147 /* 148 * Clear the previous contents. 149 */ 150 if (fileptr->ar_flag & F_MALLOCED) 151 free(fileptr->ar_contents); 152 else if (fileptr->ar_flag & F_ELFRAW) { 153 /* 154 * clear ar_elf 155 */ 156 (void) elf_end(fileptr->ar_elf); 157 fileptr->ar_elf = 0; 158 } 159 /* clear 'ar_flag' */ 160 fileptr->ar_flag &= 161 ~(F_ELFRAW | F_MMAPED | F_MALLOCED); 162 if ((cmd_info->OPT_flgs & M_FLAG) == 0) { 163 if ((cmd_info->bytes_in_mem + 164 stbuf.st_size) 165 < AR_MAX_BYTES_IN_MEM) { 166 if ((fileptr->ar_contents = 167 malloc(ROUNDUP( 168 stbuf.st_size))) == NULL) { 169 error_message( 170 MALLOC_ERROR, 171 PLAIN_ERROR, 172 (char *)0); 173 exit(1); 174 } 175 fileptr->ar_flag &= 176 ~(F_ELFRAW | F_MMAPED); 177 fileptr->ar_flag |= F_MALLOCED; 178 if (fread(fileptr->ar_contents, 179 sizeof (char), 180 stbuf.st_size, f) != 181 stbuf.st_size) { 182 error_message( 183 SYS_READ_ERROR, 184 SYSTEM_ERROR, 185 strerror(errno), 186 fileptr-> 187 ar_longname); 188 exit(1); 189 } 190 cmd_info->bytes_in_mem += 191 stbuf.st_size; 192 } 193 } else { 194 if ((fileptr->ar_contents = (char *) 195 mmap(0, stbuf.st_size, 196 PROT_READ, 197 MAP_SHARED, 198 fileno(f), 0)) == (char *)-1) { 199 error_message(MALLOC_ERROR, 200 PLAIN_ERROR, (char *)0); 201 exit(1); 202 } 203 fileptr->ar_flag &= 204 ~(F_ELFRAW | F_MALLOCED); 205 fileptr->ar_flag |= F_MMAPED; 206 } 207 if (fileptr->ar_pathname != NULL) 208 free(fileptr->ar_pathname); 209 if ((fileptr->ar_pathname = 210 malloc(strlen(gfile) + 1)) == NULL) { 211 error_message(MALLOC_ERROR, 212 PLAIN_ERROR, (char *)0); 213 exit(1); 214 } 215 216 (void) strcpy(fileptr->ar_pathname, gfile); 217 (void) fclose(f); 218 219 if (cmd_info->ponam && (abifile != fileptr)) { 220 deleted = 1; 221 /* remove from archive list */ 222 if (prev_entry != NULL) 223 prev_entry->ar_next = NULL; 224 else 225 listhead = NULL; 226 listend = prev_entry; 227 228 /* add to moved list */ 229 if (new_listhead == NULL) 230 new_listhead = fileptr; 231 else 232 new_listend->ar_next = fileptr; 233 new_listend = fileptr; 234 } 235 cmd_info->modified++; 236 } 237 } 238 else 239 /* 240 * Unchaged 241 */ 242 mesg('u', fileptr->ar_longname, cmd_info); 243 244 if (deleted) 245 deleted = 0; 246 else 247 prev_entry = fileptr; 248 } 249 250 endptr = listend; 251 cleanup(cmd_info); 252 if (cmd_info->ponam && endptr && 253 (((moved_files = endptr->ar_next) != NULL) || new_listhead)) { 254 if (!abifile) { 255 error_message(NOT_FOUND_02_ERROR, 256 PLAIN_ERROR, (char *)0, cmd_info->ponam); 257 exit(2); 258 } 259 endptr->ar_next = NULL; 260 261 /* 262 * link new/moved files into archive entry list... 263 * 1: prepend newlist to moved/appended list 264 */ 265 if (new_listhead) { 266 if (!moved_files) 267 listend = new_listend; 268 new_listend->ar_next = moved_files; 269 moved_files = new_listhead; 270 } 271 /* 2: insert at appropriate position... */ 272 if (opt_FLAG(cmd_info, b_FLAG)) 273 abifile = backptr; 274 if (abifile) { 275 listend->ar_next = abifile->ar_next; 276 abifile->ar_next = moved_files; 277 } else { 278 listend->ar_next = listhead; 279 listhead = moved_files; 280 } 281 listend = endptr; 282 } else if (cmd_info->ponam && !abifile) 283 error_message(NOT_FOUND_02_ERROR, 284 PLAIN_ERROR, (char *)0, cmd_info->ponam); 285 return (0); 286 } 287 288 int 289 dcmd(Cmd_info *cmd_info) 290 { 291 ARFILE *fptr; 292 ARFILE *backptr = NULL; 293 294 for (fptr = getfile(cmd_info); fptr; fptr = getfile(cmd_info)) { 295 if (match(fptr->ar_longname, cmd_info) != NULL) { 296 /* 297 * NOTE: 298 * Refer to "Incompatible Archive Header" 299 * blocked comment at the beginning of this file. 300 */ 301 302 /* 303 * Deleted 304 */ 305 mesg('d', fptr->ar_longname, cmd_info); 306 if (backptr == NULL) { 307 listhead = NULL; 308 listend = NULL; 309 } else { 310 backptr->ar_next = NULL; 311 listend = backptr; 312 } 313 cmd_info->modified = 1; 314 } else { 315 /* 316 * Unchaged 317 */ 318 mesg('u', fptr->ar_longname, cmd_info); 319 backptr = fptr; 320 } 321 } 322 return (0); 323 } 324 325 int 326 xcmd(Cmd_info *cmd_info) 327 { 328 int f; 329 ARFILE *next; 330 int rawname = 0; 331 int f_len = 0; 332 333 /* 334 * If -T is specified, get the maximum file name length. 335 */ 336 if (cmd_info->OPT_flgs & T_FLAG) { 337 f_len = pathconf(".", _PC_NAME_MAX); 338 if (f_len == -1) { 339 error_message(PATHCONF_ERROR, 340 SYSTEM_ERROR, strerror(errno)); 341 exit(1); 342 } 343 } 344 for (next = getfile(cmd_info); next; next = getfile(cmd_info)) { 345 if ((next->ar_longname[0] == 0) && (next->ar_rawname[0] != 0)) 346 rawname = 1; 347 if (cmd_info->namc == 0 || 348 match(next->ar_longname, cmd_info) != NULL || 349 match(next->ar_rawname, cmd_info) != NULL) { 350 /* 351 * NOTE: 352 * Refer to "Incompatible Archive Header" 353 * blocked comment at the beginning of this file. 354 */ 355 f = create_extract(next, rawname, f_len, cmd_info); 356 if (f >= 0) { 357 if (rawname) { 358 /* 359 * eXtracted 360 */ 361 mesg('x', next->ar_rawname, cmd_info); 362 if (write(f, next->ar_contents, 363 (unsigned)next->ar_size) != 364 next->ar_size) { 365 error_message(SYS_WRITE_ERROR, 366 SYSTEM_ERROR, 367 strerror(errno), 368 next->ar_rawname); 369 exit(1); 370 } 371 } else { 372 /* 373 * eXtracted 374 */ 375 mesg('x', next->ar_longname, cmd_info); 376 if (write(f, next->ar_contents, 377 (unsigned)next->ar_size) != 378 next->ar_size) { 379 error_message(SYS_WRITE_ERROR, 380 SYSTEM_ERROR, 381 strerror(errno), 382 next->ar_longname); 383 exit(1); 384 } 385 } 386 (void) close(f); 387 } else 388 exit(1); 389 } 390 rawname = 0; 391 } /* for */ 392 return (0); 393 } 394 395 int 396 pcmd(Cmd_info *cmd_info) 397 { 398 ARFILE *next; 399 400 for (next = getfile(cmd_info); next; next = getfile(cmd_info)) { 401 if (cmd_info->namc == 0 || 402 match(next->ar_longname, cmd_info) != NULL || 403 match(next->ar_rawname, cmd_info) != NULL) { 404 /* 405 * NOTE: 406 * Refer to "Incompatible Archive Header" 407 * blocked comment at the beginning of this file. 408 */ 409 if (opt_FLAG(cmd_info, v_FLAG)) { 410 (void) fprintf(stdout, 411 "\n<%s>\n\n", next->ar_longname); 412 (void) fflush(stdout); 413 } 414 (void) fwrite(next->ar_contents, sizeof (char), 415 next->ar_size, stdout); 416 } 417 } 418 return (0); 419 } 420 421 int 422 mcmd(Cmd_info *cmd_info) 423 { 424 ARFILE *fileptr; 425 ARFILE *abifile = NULL; 426 ARFILE *tmphead = NULL; 427 ARFILE *tmpend = NULL; 428 ARFILE *backptr1 = NULL; 429 ARFILE *backptr2 = NULL; 430 431 for (fileptr = getfile(cmd_info); 432 fileptr; fileptr = getfile(cmd_info)) { 433 if (match(fileptr->ar_longname, cmd_info) != NULL) { 434 /* 435 * position Modified 436 */ 437 mesg('m', fileptr->ar_longname, cmd_info); 438 if (tmphead) 439 tmpend->ar_next = fileptr; 440 else 441 tmphead = fileptr; 442 tmpend = fileptr; 443 if (backptr1) { 444 listend = backptr1; 445 listend->ar_next = NULL; 446 } 447 else 448 listhead = NULL; 449 continue; 450 } 451 /* 452 * position Unchaged 453 */ 454 mesg('u', fileptr->ar_longname, cmd_info); 455 backptr1 = fileptr; 456 if (cmd_info->ponam && !abifile) { 457 if (strcmp(fileptr->ar_longname, cmd_info->ponam) == 0) 458 abifile = fileptr; 459 else 460 backptr2 = fileptr; 461 } 462 } 463 464 if (!tmphead) 465 return (1); 466 467 if (!cmd_info->ponam) 468 listend->ar_next = tmphead; 469 else { 470 if (!abifile) { 471 error_message(NOT_FOUND_02_ERROR, 472 PLAIN_ERROR, (char *)0, cmd_info->ponam); 473 exit(2); 474 } 475 if (opt_FLAG(cmd_info, b_FLAG)) 476 abifile = backptr2; 477 if (abifile) { 478 tmpend->ar_next = abifile->ar_next; 479 abifile->ar_next = tmphead; 480 } else { 481 tmphead->ar_next = listhead; 482 listhead = tmphead; 483 } 484 } 485 (cmd_info->modified)++; 486 return (0); 487 } 488 489 int 490 tcmd(Cmd_info *cmd_info) 491 { 492 ARFILE *next; 493 int **mp; 494 char buf[DATESIZE]; 495 int m1[] = {1, ROWN, 'r', '-'}; 496 int m2[] = {1, WOWN, 'w', '-'}; 497 int m3[] = {2, SUID, 's', XOWN, 'x', '-'}; 498 int m4[] = {1, RGRP, 'r', '-'}; 499 int m5[] = {1, WGRP, 'w', '-'}; 500 int m6[] = {2, SGID, 's', XGRP, 'x', '-'}; 501 int m7[] = {1, ROTH, 'r', '-'}; 502 int m8[] = {1, WOTH, 'w', '-'}; 503 int m9[] = {2, STXT, 't', XOTH, 'x', '-'}; 504 int *m[10]; 505 506 m[0] = m1; 507 m[1] = m2; 508 m[2] = m3; 509 m[3] = m4; 510 m[4] = m5; 511 m[5] = m6; 512 m[6] = m7; 513 m[7] = m8; 514 m[8] = m9; 515 m[9] = 0; 516 517 for (next = getfile(cmd_info); next; next = getfile(cmd_info)) { 518 if (cmd_info->namc == 0 || 519 match(next->ar_longname, cmd_info) != NULL || 520 match(next->ar_rawname, cmd_info) != NULL) { 521 /* 522 * NOTE: 523 * Refer to "Incompatible Archive Header" 524 * blocked comment at the beginning of this file. 525 */ 526 if (opt_FLAG(cmd_info, v_FLAG)) { 527 for (mp = &m[0]; mp < &m[9]; ) 528 ar_select(*mp++, next->ar_mode); 529 530 (void) fprintf(stdout, "%6d/%6d", next->ar_uid, 531 next->ar_gid); 532 (void) fprintf(stdout, "%7ld", next->ar_size); 533 if ((strftime(buf, 534 DATESIZE, 535 "%b %e %H:%M %Y", 536 localtime(&(next->ar_date)))) == 0) { 537 error_message(LOCALTIME_ERROR, 538 PLAIN_ERROR, (char *)0); 539 exit(1); 540 } 541 (void) fprintf(stdout, " %s ", buf); 542 } 543 if ((next->ar_longname[0] == 0) && 544 (next->ar_rawname[0] != 0)) 545 (void) fprintf(stdout, 546 "%s\n", trim(next->ar_rawname)); 547 else 548 (void) fprintf(stdout, 549 "%s\n", trim(next->ar_longname)); 550 } 551 } /* for */ 552 return (0); 553 } 554 555 int 556 qcmd(Cmd_info *cmd_info) 557 { 558 ARFILE *fptr; 559 560 if (opt_FLAG(cmd_info, a_FLAG) || opt_FLAG(cmd_info, b_FLAG)) { 561 error_message(USAGE_05_ERROR, 562 PLAIN_ERROR, (char *)0); 563 exit(1); 564 } 565 for (fptr = getfile(cmd_info); fptr; fptr = getfile(cmd_info)) 566 ; 567 cleanup(cmd_info); 568 return (0); 569 } 570 571 /* 572 * Supplementary functions 573 */ 574 static char * 575 match(char *file, Cmd_info *cmd_info) 576 { 577 int i; 578 579 for (i = 0; i < cmd_info->namc; i++) { 580 if (cmd_info->namv[i] == 0) 581 continue; 582 if (strcmp(trim(cmd_info->namv[i]), file) == 0) { 583 file = cmd_info->namv[i]; 584 cmd_info->namv[i] = 0; 585 return (file); 586 } 587 } 588 return (NULL); 589 } 590 591 /* 592 * puts the file which was in the list in the linked list 593 */ 594 static void 595 cleanup(Cmd_info *cmd_info) 596 { 597 int i; 598 FILE *f; 599 ARFILE *fileptr; 600 struct stat stbuf; 601 602 for (i = 0; i < cmd_info->namc; i++) { 603 if (cmd_info->namv[i] == 0) 604 continue; 605 /* 606 * Appended 607 */ 608 mesg('a', cmd_info->namv[i], cmd_info); 609 f = stats(cmd_info->namv[i], &stbuf); 610 if (f == NULL) 611 error_message(SYS_OPEN_ERROR, 612 SYSTEM_ERROR, strerror(errno), cmd_info->namv[i]); 613 else { 614 fileptr = newfile(); 615 /* if short name */ 616 (void) strncpy(fileptr->ar_name, 617 trim(cmd_info->namv[i]), SNAME); 618 619 if ((fileptr->ar_longname = 620 malloc(strlen(trim(cmd_info->namv[i])) + 1)) == 621 NULL) { 622 error_message(MALLOC_ERROR, 623 PLAIN_ERROR, (char *)0); 624 exit(1); 625 } 626 627 (void) strcpy(fileptr->ar_longname, 628 trim(cmd_info->namv[i])); 629 630 if ((fileptr->ar_pathname = 631 malloc(strlen(cmd_info->namv[i]) + 1)) == NULL) { 632 error_message(MALLOC_ERROR, 633 PLAIN_ERROR, (char *)0); 634 exit(1); 635 } 636 637 (void) strcpy(fileptr->ar_pathname, cmd_info->namv[i]); 638 639 movefil(fileptr, &stbuf); 640 641 /* clear 'ar_flag' */ 642 fileptr->ar_flag &= ~(F_ELFRAW | F_MMAPED | F_MALLOCED); 643 644 if ((cmd_info->OPT_flgs & M_FLAG) == 0) { 645 if ((cmd_info->bytes_in_mem + stbuf.st_size) < 646 AR_MAX_BYTES_IN_MEM) { 647 fileptr->ar_flag &= 648 ~(F_ELFRAW | F_MMAPED); 649 fileptr->ar_flag |= F_MALLOCED; 650 if ((fileptr->ar_contents = 651 malloc(ROUNDUP(stbuf.st_size))) == 652 NULL) { 653 error_message(MALLOC_ERROR, 654 PLAIN_ERROR, (char *)0); 655 exit(1); 656 } 657 if (fread(fileptr->ar_contents, 658 sizeof (char), stbuf.st_size, 659 f) != stbuf.st_size) { 660 error_message(SYS_READ_ERROR, 661 SYSTEM_ERROR, 662 strerror(errno), 663 fileptr->ar_longname); 664 exit(1); 665 } 666 cmd_info->bytes_in_mem += stbuf.st_size; 667 } 668 } else { 669 fileptr->ar_flag &= ~(F_ELFRAW | F_MALLOCED); 670 fileptr->ar_flag |= F_MMAPED; 671 if ((fileptr->ar_contents = 672 (char *)mmap(0, stbuf.st_size, PROT_READ, 673 MAP_SHARED, fileno(f), 0)) == (char *)-1) { 674 error_message(MALLOC_ERROR, 675 PLAIN_ERROR, (char *)0); 676 exit(1); 677 } 678 } 679 (void) fclose(f); 680 (cmd_info->modified)++; 681 cmd_info->namv[i] = 0; 682 } 683 } 684 } 685 686 /* 687 * insert the file 'file' into the temporary file 688 */ 689 static void 690 movefil(ARFILE *fileptr, struct stat *stbuf) 691 { 692 fileptr->ar_size = stbuf->st_size; 693 fileptr->ar_date = stbuf->st_mtime; 694 fileptr->ar_mode = stbuf->st_mode; 695 696 /* 697 * The format of an 'ar' file includes a 6 character 698 * decimal string to contain the uid. 699 * 700 * If the uid or gid is too big to fit, then set it to 701 * nobody (for want of a better value). Clear the 702 * setuid/setgid bits in the mode to avoid setuid nobody 703 * or setgid nobody files unexpectedly coming into existence. 704 */ 705 if ((fileptr->ar_uid = stbuf->st_uid) > 999999) { 706 fileptr->ar_uid = UID_NOBODY; 707 if (S_ISREG(fileptr->ar_mode)) 708 fileptr->ar_mode &= ~S_ISUID; 709 } 710 if ((fileptr->ar_gid = stbuf->st_gid) > 999999) { 711 fileptr->ar_gid = GID_NOBODY; 712 if (S_ISREG(fileptr->ar_mode)) 713 fileptr->ar_mode &= ~S_ISGID; 714 } 715 } 716 717 static FILE * 718 stats(char *file, struct stat *stbuf) 719 { 720 FILE *f; 721 722 f = fopen(file, "r"); 723 if (f == NULL) 724 return (f); 725 if (stat(file, stbuf) < 0) { 726 (void) fclose(f); 727 return (NULL); 728 } 729 return (f); 730 } 731 732 /* 733 * Used by xcmd() 734 */ 735 int 736 create_extract(ARFILE *a, int rawname, int f_len, Cmd_info *cmd_info) 737 { 738 739 int f; 740 char *f_name; 741 char *dup = NULL; 742 if (rawname) 743 f_name = a->ar_rawname; 744 else 745 f_name = a->ar_longname; 746 747 /* 748 * If -T is specified, check the file length. 749 */ 750 if (cmd_info->OPT_flgs & T_FLAG) { 751 int len; 752 len = strlen(f_name); 753 if (f_len <= len) { 754 dup = malloc(f_len+1); 755 if (dup == NULL) { 756 error_message(MALLOC_ERROR, 757 PLAIN_ERROR, (char *)0); 758 exit(1); 759 } 760 (void) strncpy(dup, f_name, f_len); 761 } 762 f_name = dup; 763 } 764 765 /* 766 * Bug 4052067 - If a file to be extracted has the same 767 * filename as the archive, the archive gets overwritten 768 * which can lead to a corrupted archive or worse, a ufs 769 * deadlock because libelf has mmap'ed the archive! We 770 * can't rely on strcmp() to test for this case because 771 * the archive could be prefixed with a partial or full 772 * path (and we could be using the rawname from the archive) 773 * This means we have to do the same thing we did for mv, 774 * which is to explicitly check if the file we would extract 775 * to is identical to the archive. Because part of this 776 * test is essentially what the -C flag does, I've merged 777 * the code together. 778 */ 779 if (access(f_name, F_OK) != -1) { 780 struct stat s1, s2; 781 782 /* 783 * If -C is specified, this is an error anyway 784 */ 785 if (cmd_info->OPT_flgs & C_FLAG) { 786 if (dup != NULL) 787 free(dup); 788 error_message(OVERRIDE_WARN_ERROR, 789 PLAIN_ERROR, (char *)0, f_name); 790 return (-1); 791 } 792 793 /* 794 * Okay, -C wasn't specified. However, now we do 795 * the check to see if the archive would be overwritten 796 * by extracting this file. stat() both objects and 797 * test to see if their identical. 798 */ 799 if ((stat(f_name, &s1) == 0) && 800 (stat(cmd_info->arnam, &s2) == 0)) { 801 802 if ((s1.st_dev == s2.st_dev) && 803 (s1.st_ino == s2.st_ino)) { 804 805 if (dup != NULL) 806 free(dup); 807 error_message(OVERRIDE_WARN_ERROR, 808 PLAIN_ERROR, (char *)0, f_name); 809 return (-1); 810 } 811 } 812 } 813 814 /* 815 * Okay to create extraction file... 816 */ 817 f = creat(f_name, (mode_t)a->ar_mode & 0777); 818 if (f < 0) { 819 error_message(SYS_CREATE_01_ERROR, 820 SYSTEM_ERROR, strerror(errno), f_name); 821 /* 822 * Created 823 */ 824 mesg('c', f_name, cmd_info); 825 } 826 if (dup) 827 free(dup); 828 return (f); 829 } 830 831 static void 832 mesg(int c, char *file, Cmd_info *cmd_info) 833 { 834 #ifdef XPG4 835 /* 836 * XPG4 does not have any message defined for 837 * 'c' operation. 838 * In fact, XPG only defines messages for 839 * d, r, a and x at the present. (03/05/'96) 840 */ 841 if (c == 'c' || c == 'u' || c == 'm') 842 return; 843 #endif 844 /* 845 * If 'u' is passed, convert it to 'c'. 846 * 'u' makes more sense since the operation did not 847 * do anything, Unchanged, but 'c' has been used so 848 * I do no want to break the compatibility at this moment. 849 * (03/05/'96). 850 */ 851 if (c == 'u') 852 c = 'c'; 853 if (opt_FLAG(cmd_info, v_FLAG)) 854 if (c != 'c') 855 (void) fprintf(stdout, "%c - %s\n", c, file); 856 } 857 858 static void 859 ar_select(int *pairp, unsigned long mode) 860 { 861 int n, *ap; 862 863 ap = pairp; 864 n = *ap++; 865 while (--n >= 0 && (mode & *ap++) == 0) 866 ap++; 867 (void) putchar(*ap); 868 } 869