1/* ------------------------------------------------------------------------ */ 2/* LHa for UNIX */ 3/* lhadd.c -- LHarc Add Command */ 4/* */ 5/* Copyright (C) MCMLXXXIX Yooichi.Tagawa */ 6/* Modified Nobutaka Watazaki */ 7/* */ 8/* Ver. 1.14 Source All chagned 1995.01.14 N.Watazaki */ 9/* ------------------------------------------------------------------------ */ 10#include "lha.h" 11/* ------------------------------------------------------------------------ */ 12static void remove_files(); 13 14static char new_archive_name_buffer[FILENAME_LENGTH]; 15static char *new_archive_name; 16/* ------------------------------------------------------------------------ */ 17static void 18add_one(fp, nafp, hdr) 19 FILE *fp, *nafp; 20 LzHeader *hdr; 21{ 22 long header_pos, next_pos, org_pos, data_pos; 23 long v_original_size, v_packed_size; 24 int mode; 25 26 reading_filename = hdr->name; 27 writting_filename = temporary_name; 28 29 if (!fp && generic_format) /* [generic] doesn't need directory 30 * info. */ 31 return; 32 header_pos = ftell(nafp); 33 write_header(nafp, hdr);/* DUMMY */ 34 35 if ((hdr->unix_mode & UNIX_FILE_SYMLINK) == UNIX_FILE_SYMLINK) { 36 char buf[256], *b1, *b2; 37 if (!quiet) { 38 strcpy(buf, hdr->name); 39 b1 = strtok(buf, "|"); 40 b2 = strtok(NULL, "|"); 41 printf("%s -> %s\t- Symbolic Link\n", b1, b2); 42 } /* if quiet .. */ 43 } 44 45 if (hdr->original_size == 0) /* empty file or directory */ 46 return; /* previous write_header is not DUMMY. (^_^) */ 47 48 org_pos = ftell(fp); 49 data_pos = ftell(nafp); 50 51 hdr->crc = encode_lzhuf(fp, nafp, hdr->original_size, 52 &v_original_size, &v_packed_size, hdr->name, hdr->method); 53 54 if (v_packed_size < v_original_size) { 55 next_pos = ftell(nafp); 56 } 57 else { /* retry by stored method */ 58 fseek(fp, org_pos, SEEK_SET); 59 fseek(nafp, data_pos, SEEK_SET); 60 hdr->crc = encode_stored_crc(fp, nafp, hdr->original_size, 61 &v_original_size, &v_packed_size); 62 fflush(nafp); 63 next_pos = ftell(nafp); 64#ifndef NOFTRUNCATE 65 ftruncate(fileno(nafp), next_pos); 66#endif 67 bcopy(LZHUFF0_METHOD, hdr->method, METHOD_TYPE_STRAGE); 68 } 69 hdr->original_size = v_original_size; 70 hdr->packed_size = v_packed_size; 71 fseek(nafp, header_pos, SEEK_SET); 72 write_header(nafp, hdr); 73 fseek(nafp, next_pos, SEEK_SET); 74} 75 76 77/* ------------------------------------------------------------------------ */ 78FILE * 79append_it(name, oafp, nafp) 80 char *name; 81 FILE *oafp, *nafp; 82{ 83 LzHeader ahdr, hdr; 84 FILE *fp; 85 long old_header; 86 int cmp; 87 int filec; 88 char **filev; 89 int i; 90 struct stat stbuf /*, lstbuf*/; 91 92 boolean directory, symlink; 93 94 if (GETSTAT(name, &stbuf) < 0) { 95 error("Cannot access", name); /* See cleaning_files, Why? */ 96 return oafp; 97 } 98 99 directory = is_directory(&stbuf); 100#ifdef S_IFLNK 101 symlink = is_symlink(&stbuf); 102#else 103 symlink = 0; 104#endif 105 init_header(name, &stbuf, &hdr); 106 107 if (!directory && !noexec) 108 if (symlink) 109 fp = NULL; 110 else 111 fp = xfopen(name, READ_BINARY); 112 else { 113 fp = NULL; 114 } 115 116 while (oafp) { 117 old_header = ftell(oafp); 118 if (!get_header(oafp, &ahdr)) { 119 fclose(oafp); 120 oafp = NULL; 121 break; 122 } else { 123#if 0 124 cmp = STRING_COMPARE(ahdr.name, hdr.name); 125#endif 126 /* for symbolic link. t.okamoto */ 127 cmp = strcmp_filename(ahdr.name, hdr.name); 128 if (cmp < 0) { /* SKIP */ 129 /* copy old to new */ 130 if (!noexec) { 131 fseek(oafp, old_header, SEEK_SET); 132 copy_old_one(oafp, nafp, &ahdr); 133 } 134 else 135 fseek(oafp, ahdr.packed_size, SEEK_CUR); 136 } else if (cmp == 0) { /* REPLACE */ 137 /* drop old archive's */ 138 fseek(oafp, ahdr.packed_size, SEEK_CUR); 139 break; 140 } else { /* cmp > 0, INSERT */ 141 fseek(oafp, old_header, SEEK_SET); 142 break; 143 } 144 } 145 } 146 147 if (update_if_newer) { 148 if (!oafp || /* not in archive */ 149 cmp > 0 || /* // */ 150 ahdr.unix_last_modified_stamp < /* newer than archive's */ 151 hdr.unix_last_modified_stamp) { 152 if (noexec) 153 printf("ADD %s\n", name); 154 else 155 add_one(fp, nafp, &hdr); 156 } else { /* cmp == 0 *//* copy old to new */ 157 if (!noexec) { 158 fseek(oafp, old_header, SEEK_SET); 159 copy_old_one(oafp, nafp, &ahdr); 160 } 161 } 162 } else { 163 if (!oafp || cmp > 0) { /* not in archive or dropped */ 164 if (noexec) 165 printf("ADD %s\n", name); 166 else 167 add_one(fp, nafp, &hdr); 168 } 169 else { /* cmp == 0 */ 170 /* replace */ 171 if (noexec) 172 printf("REPLACE\n"); 173 else 174 add_one(fp, nafp, &hdr); 175 } 176 } 177 178 if (!directory) { 179 if (!noexec) 180 if (!symlink) 181 fclose(fp); 182 } 183 else { /* recurcive call */ 184 if (find_files(name, &filec, &filev)) { 185 for (i = 0; i < filec; i++) 186 oafp = append_it(filev[i], oafp, nafp); 187 free_files(filec, filev); 188 } 189 } 190 return oafp; 191} 192 193/* ------------------------------------------------------------------------ */ 194static void 195find_update_files(oafp) 196 FILE *oafp; /* old archive */ 197{ 198 char name[FILENAME_LENGTH]; 199 struct string_pool sp; 200 LzHeader hdr; 201 long pos; 202 struct stat stbuf; 203 int len; 204 205 pos = ftell(oafp); 206 207 init_sp(&sp); 208 while (get_header(oafp, &hdr)) { 209 if ((hdr.unix_mode & UNIX_FILE_TYPEMASK) == UNIX_FILE_REGULAR) { 210 if (stat(hdr.name, &stbuf) >= 0) /* exist ? */ 211 add_sp(&sp, hdr.name, strlen(hdr.name) + 1); 212 } 213 else if ((hdr.unix_mode & UNIX_FILE_TYPEMASK) == UNIX_FILE_DIRECTORY) { 214 strcpy(name, hdr.name); 215 len = strlen(name); 216 if (len > 0 && name[len - 1] == '/') 217 name[--len] = '\0'; /* strip tail '/' */ 218 if (stat(name, &stbuf) >= 0) /* exist ? */ 219 add_sp(&sp, name, len + 1); 220 } 221 fseek(oafp, hdr.packed_size, SEEK_CUR); 222 } 223 224 fseek(oafp, pos, SEEK_SET); 225 226 finish_sp(&sp, &cmd_filec, &cmd_filev); 227} 228 229/* ------------------------------------------------------------------------ */ 230static void 231delete(oafp, nafp) 232 FILE *oafp, *nafp; 233{ 234 LzHeader ahdr; 235 long old_header_pos; 236 char lpath[256], *b1, *b2; 237 238 old_header_pos = ftell(oafp); 239 while (get_header(oafp, &ahdr)) { 240 strcpy(lpath, ahdr.name); 241 b1 = strtok(lpath, "|"); 242 b2 = strtok(NULL, "|"); 243 if (need_file(b1)) { /* skip */ 244 fseek(oafp, ahdr.packed_size, SEEK_CUR); 245 if (noexec || !quiet) 246 if (b2 != NULL) 247 printf("delete %s -> %s\n", b1, b2); 248 else 249 printf("delete %s\n", b1); 250 } 251 else { /* copy */ 252 if (noexec) { 253 fseek(oafp, ahdr.packed_size, SEEK_CUR); 254 } 255 else { 256 fseek(oafp, old_header_pos, SEEK_SET); 257 copy_old_one(oafp, nafp, &ahdr); 258 } 259 } 260 old_header_pos = ftell(oafp); 261 } 262 return; 263} 264 265/* ------------------------------------------------------------------------ */ 266/* */ 267/* ------------------------------------------------------------------------ */ 268static FILE * 269build_temporary_file() 270{ 271 int old_umask; 272 FILE *afp; 273 274 build_temporary_name(); 275 signal(SIGINT, interrupt); 276 signal(SIGHUP, interrupt); 277 278 old_umask = umask(077); 279 afp = xfopen(temporary_name, WRITE_BINARY); 280 remove_temporary_at_error = TRUE; 281 temporary_fp = afp; 282 umask(old_umask); 283 284 return afp; 285} 286 287/* ------------------------------------------------------------------------ */ 288static void 289build_backup_file() 290{ 291 292 build_backup_name(backup_archive_name, archive_name); 293 if (!noexec) { 294 signal(SIGINT, SIG_IGN); 295 signal(SIGHUP, SIG_IGN); 296 if (rename(archive_name, backup_archive_name) < 0) 297 fatal_error(archive_name); 298 recover_archive_when_interrupt = TRUE; 299 signal(SIGINT, interrupt); 300 signal(SIGHUP, interrupt); 301 } 302} 303 304/* ------------------------------------------------------------------------ */ 305static void 306report_archive_name_if_different() 307{ 308 if (!quiet && new_archive_name == new_archive_name_buffer) { 309 /* warning at old archive is SFX */ 310 printf("New archive file is \"%s\"\n", new_archive_name); 311 } 312} 313 314/* ------------------------------------------------------------------------ */ 315#ifdef TMP_FILENAME_TEMPLATE 316void 317temporary_to_new_archive_file(new_archive_size) 318 long new_archive_size; 319{ 320 FILE *oafp, *nafp; 321 322 oafp = xfopen(temporary_name, READ_BINARY); 323 if (!strcmp(new_archive_name, "-")) { 324 nafp = stdout; 325 writting_filename = "starndard output"; 326 } 327 else { 328 nafp = xfopen(new_archive_name, WRITE_BINARY); 329 writting_filename = archive_name; 330 } 331 reading_filename = temporary_name; 332 copyfile(oafp, nafp, new_archive_size, 0); 333 if (nafp != stdout) 334 fclose(nafp); 335 fclose(oafp); 336 337 recover_archive_when_interrupt = FALSE; 338 unlink(temporary_name); 339 340 remove_temporary_at_error = FALSE; 341} 342#else 343temporary_to_new_archive_file(new_archive_size) 344 long new_archive_size; 345{ 346 char *p; 347 p = (char *) rindex(new_archive_name, '/'); 348 p = p ? p + 1 : new_archive_name; 349 unlink(new_archive_name); 350 if (rename(temporary_name, p) < 0) { 351 fprintf(stderr, "Can't rename temporary_name '%s'\n", new_archive_name); 352 exit(1); 353 } 354} 355#endif 356 357/* ------------------------------------------------------------------------ */ 358static void 359set_archive_file_mode() 360{ 361 int umask_value; 362 struct stat stbuf; 363 364 if (archive_file_gid < 0) { 365 umask(umask_value = umask(0)); 366 archive_file_mode = (~umask_value) & 0666; /* rw-rw-rw- */ 367 if (stat(".", &stbuf) >= 0) 368 archive_file_gid = stbuf.st_gid; 369 } 370 if (archive_file_gid >= 0) 371 chown(new_archive_name, getuid(), archive_file_gid); 372 373 chmod(new_archive_name, archive_file_mode); 374} 375 376/* ------------------------------------------------------------------------ */ 377/* REMOVE FILE/DIRECTORY */ 378/* ------------------------------------------------------------------------ */ 379static void 380remove_one(name) 381 char *name; 382{ 383 struct stat stbuf; 384 int filec; 385 char **filev; 386 387 if (GETSTAT(name, &stbuf) < 0) { 388 warning("Cannot access", name); 389 } 390 else if (is_directory(&stbuf)) { 391 if (find_files(name, &filec, &filev)) { 392 remove_files(filec, filev); 393 free_files(filec, filev); 394 } 395 else 396 warning("Cannot open directory", name); 397 398 if (noexec) 399 printf("REMOVE DIRECTORY %s\n", name); 400 else if (rmdir(name) < 0) 401 warning("Cannot remove directory", name); 402 else if (verbose) 403 printf("Removed %s.\n", name); 404 } 405 else if (is_regularfile(&stbuf)) { 406 if (noexec) 407 printf("REMOVE FILE %s.\n", name); 408 else if (unlink(name) < 0) 409 warning("Cannot remove", name); 410 else if (verbose) 411 printf("Removed %s.\n", name); 412 } 413#ifdef S_IFLNK 414 else if (is_symlink(&stbuf)) { 415 if (noexec) 416 printf("REMOVE SYMBOLIC LINK %s.\n", name); 417 else if (unlink(name) < 0) 418 warning("Cannot remove", name); 419 else if (verbose) 420 printf("Removed %s.\n", name); 421 } 422#endif 423 else { 424 error("Cannot remove (not a file or directory)", name); 425 } 426} 427 428static void 429remove_files(filec, filev) 430 int filec; 431 char **filev; 432{ 433 int i; 434 435 for (i = 0; i < filec; i++) 436 remove_one(filev[i]); 437} 438 439/* ------------------------------------------------------------------------ */ 440/* */ 441/* ------------------------------------------------------------------------ */ 442void 443cmd_add() 444{ 445 LzHeader ahdr; 446 FILE *oafp, *nafp; 447 int i; 448 long old_header; 449 boolean old_archive_exist; 450 long new_archive_size; 451 452 /* exit if no operation */ 453 if (!update_if_newer && cmd_filec == 0) { 454 error("No files given in argument, do nothing.", ""); 455 return; 456 } 457 458 /* open old archive if exist */ 459 if ((oafp = open_old_archive()) == NULL) 460 old_archive_exist = FALSE; 461 else 462 old_archive_exist = TRUE; 463 464 if (update_if_newer && cmd_filec == 0 && !oafp) 465 fatal_error(archive_name); /* exit if cannot execute 466 * automatic update */ 467 errno = 0; 468 469 if (new_archive && old_archive_exist) { 470 fclose(oafp); 471 oafp = NULL; 472 } 473 474 if (oafp && archive_is_msdos_sfx1(archive_name)) { 475 skip_msdos_sfx1_code(oafp); 476 build_standard_archive_name(new_archive_name_buffer, archive_name); 477 new_archive_name = new_archive_name_buffer; 478 } 479 else { 480 new_archive_name = archive_name; 481 } 482 483 /* build temporary file */ 484 if (!noexec) 485 nafp = build_temporary_file(); 486 487 /* find needed files when automatic update */ 488 if (update_if_newer && cmd_filec == 0) 489 find_update_files(oafp); 490 491 /* build new archive file */ 492 /* cleaning arguments */ 493 cleaning_files(&cmd_filec, &cmd_filev); 494 if (cmd_filec == 0) { 495 if (oafp) 496 fclose(oafp); 497 if (!noexec) 498 fclose(nafp); 499 return; 500 } 501 502 for (i = 0; i < cmd_filec; i++) 503 oafp = append_it(cmd_filev[i], oafp, nafp); 504 if (oafp) { 505 old_header = ftell(oafp); 506 while (get_header(oafp, &ahdr)) { 507 if (noexec) 508 fseek(oafp, ahdr.packed_size, SEEK_CUR); 509 else { 510 fseek(oafp, old_header, SEEK_SET); 511 copy_old_one(oafp, nafp, &ahdr); 512 } 513 old_header = ftell(oafp); 514 } 515 fclose(oafp); 516 } 517 if (!noexec) { 518 write_archive_tail(nafp); 519 new_archive_size = ftell(nafp); 520 fclose(nafp); 521 } 522 523 /* build backup archive file */ 524 if (old_archive_exist) 525 build_backup_file(); 526 527 report_archive_name_if_different(); 528 529 /* copy temporary file to new archive file */ 530 if (!noexec && (!strcmp(new_archive_name, "-") || 531 rename(temporary_name, new_archive_name) < 0)) 532 temporary_to_new_archive_file(new_archive_size); 533 534 /* set new archive file mode/group */ 535 set_archive_file_mode(); 536 537 /* remove archived files */ 538 if (delete_after_append) 539 remove_files(cmd_filec, cmd_filev); 540 541 return; 542} 543 544/* ------------------------------------------------------------------------ */ 545void 546cmd_delete() 547{ 548 FILE *oafp, *nafp; 549 long new_archive_size; 550 551 /* open old archive if exist */ 552 if ((oafp = open_old_archive()) == NULL) 553 fatal_error(archive_name); 554 errno = 0; 555 556 /* exit if no operation */ 557 if (cmd_filec == 0) { 558 fclose(oafp); 559 warning("No files given in argument, do nothing.", ""); 560 return; 561 } 562 563 if (archive_is_msdos_sfx1(archive_name)) { 564 skip_msdos_sfx1_code(oafp); 565 build_standard_archive_name(new_archive_name_buffer, archive_name); 566 new_archive_name = new_archive_name_buffer; 567 } 568 else { 569 new_archive_name = archive_name; 570 } 571 572 /* build temporary file */ 573 if (!noexec) 574 nafp = build_temporary_file(); 575 576 /* build new archive file */ 577 delete(oafp, nafp); 578 fclose(oafp); 579 580 if (!noexec) { 581 write_archive_tail(nafp); 582 new_archive_size = ftell(nafp); 583 fclose(nafp); 584 } 585 586 /* build backup archive file */ 587 build_backup_file(); 588 589 /* 1999.5.24 t.oka */ 590 if(!noexec && new_archive_size <= 1){ 591 unlink(temporary_name); 592 printf("New archive file \"%s\" is not created because it would be empty.\n", new_archive_name); 593 return; 594 } 595 596 report_archive_name_if_different(); 597 598 /* copy temporary file to new archive file */ 599 if (!noexec && rename(temporary_name, new_archive_name) < 0) 600 temporary_to_new_archive_file(new_archive_size); 601 602 /* set new archive file mode/group */ 603 set_archive_file_mode(); 604 605 return; 606} 607 608/* for symbolic link name. t.okamoto 96/2/20 */ 609int strcmp_filename( str1, str2 ) 610char *str1; 611char *str2; 612{ 613 char *p, *q; 614 615 p = str1; q = str2; 616 while (*p != 0 && *q != 0) { 617 if (*p == '|') { 618 if (*q == 0) return 0; 619 else if (*q != '|') return -1; 620 } else if (*q == '|') { 621 if (*p == 0) return 0; 622 else if (*q != '|') return 1; 623 } else if (*p != *q) break; 624 p++; q++; 625 } 626 return (int)*p-(int)*q; 627} 628 629 630/* Local Variables: */ 631/* mode:c */ 632/* tab-width:4 */ 633/* compile-command:"gcc -c lhadd.c" */ 634/* End: */ 635