1 /* ------------------------------------------------------------------------ */
2 /* LHa for UNIX */
3 /* lharc.c -- append to archive */
4 /* */
5 /* Copyright (C) MCMLXXXIX Yooichi.Tagawa */
6 /* Modified Nobutaka Watazaki */
7 /* Thanks to H.Yoshizaki. (MS-DOS LHarc) */
8 /* */
9 /* Ver. 0.00 Original 1988.05.23 Y.Tagawa */
10 /* Ver. 0.01 Alpha Version (for 4.2BSD) 1989.05.28 Y.Tagawa */
11 /* Ver. 0.02 Alpha Version Rel.2 1989.05.29 Y.Tagawa */
12 /* Ver. 0.03 Release #3 Beta Version 1989.07.02 Y.Tagawa */
13 /* Ver. 0.03a Debug 1989.07.03 Y.Tagawa */
14 /* Ver. 0.03b Modified 1989.07.13 Y.Tagawa */
15 /* Ver. 0.03c Debug (Thanks to void@rena.dit.junet) */
16 /* 1989.08.09 Y.Tagawa */
17 /* Ver. 0.03d Modified (quiet and verbose) 1989.09.14 Y.Tagawa */
18 /* V1.00 Fixed 1989.09.22 Y.Tagawa */
19 /* V1.01 Bug Fixed 1989.12.25 Y.Tagawa */
20 /* */
21 /* DOS-Version Original LHx V C2.01 (C) H.Yohizaki */
22 /* */
23 /* V2.00 UNIX Lharc + DOS LHx -> OSK LHx 1990.11.01 Momozou */
24 /* V2.01 Minor Modified 1990.11.24 Momozou */
25 /* */
26 /* Ver. 0.02 LHx for UNIX 1991.11.18 M.Oki */
27 /* Ver. 0.03 LHa for UNIX 1991.12.17 M.Oki */
28 /* Ver. 0.04 LHa for UNIX beta version 1992.01.20 M.Oki */
29 /* Ver. 1.00 LHa for UNIX Fixed 1992.03.19 M.Oki */
30 /* */
31 /* Ver. 1.10 for Symbolic Link 1993.06.25 N.Watazaki */
32 /* Ver. 1.11 for Symbolic Link Bug Fixed 1993.08.18 N.Watazaki */
33 /* Ver. 1.12 for File Date Check 1993.10.28 N.Watazaki */
34 /* Ver. 1.13 Bug Fixed (Idicator calcurate) 1994.02.21 N.Watazaki */
35 /* Ver. 1.13a Bug Fixed (Sym. Link delete) 1994.03.11 N.Watazaki */
36 /* Ver. 1.13b Bug Fixed (Sym. Link delete) 1994.07.29 N.Watazaki */
37 /* Ver. 1.14 Source All chagned 1995.01.14 N.Watazaki */
38 /* Ver. 1.14b,c Bug Fixed 1996.03.07 t.okamoto */
39 /* Ver. 1.14d Version up 1997.01.12 t.okamoto */
40 /* Ver. 1.14g Bug Fixed 2000.05.06 t.okamoto */
41 /* Ver. 1.14i Modified 2000.10.06 t.okamoto */
42 /* ------------------------------------------------------------------------ */
43 #define LHA_MAIN_SRC
44
45 #include "lha.h"
46
47 static int cmd = CMD_UNKNOWN;
48 static int error_occurred;
49
50 /* static functions */
51 static void sort_files();
52 static void print_version();
53
54 extern int optional_archive_kanji_code;
55 extern int optional_system_kanji_code;
56
57 /* ------------------------------------------------------------------------ */
58 static void
init_variable()59 init_variable() /* Added N.Watazaki */
60 {
61 /* options */
62 quiet = FALSE;
63 text_mode = FALSE;
64 verbose = 0;
65 noexec = FALSE; /* debugging option */
66 force = FALSE;
67
68 compress_method = DEFAULT_LZHUFF_METHOD; /* defined in config.h */
69
70 header_level = 2; /* level 2 */
71 quiet_mode = 0;
72
73 #ifdef EUC
74 euc_mode = FALSE;
75 #endif
76
77 /* view command flags */
78 verbose_listing = FALSE;
79
80 /* extract command flags */
81 output_to_stdout = FALSE;
82
83 /* append command flags */
84 new_archive = FALSE;
85 update_if_newer = FALSE;
86 delete_after_append = FALSE;
87 generic_format = FALSE;
88
89 recover_archive_when_interrupt = FALSE;
90 remove_extracting_file_when_interrupt = FALSE;
91 get_filename_from_stdin = FALSE;
92 ignore_directory = FALSE;
93 exclude_files = NULL;
94 verify_mode = FALSE;
95
96 noconvertcase = FALSE;
97
98 extract_directory = NULL;
99 temporary_fd = -1;
100
101 #if BACKUP_OLD_ARCHIVE
102 backup_old_archive = TRUE;
103 #else
104 backup_old_archive = FALSE;
105 #endif
106
107 extract_broken_archive = FALSE;
108 }
109
110 /* ------------------------------------------------------------------------ */
111 /* NOTES : Text File Format */
112 /* GENERATOR NewLine */
113 /* [generic] 0D 0A */
114 /* [MS-DOS] 0D 0A */
115 /* [OS9][MacOS] 0D */
116 /* [UNIX] 0A */
117 /* ------------------------------------------------------------------------ */
118 static void
print_tiny_usage()119 print_tiny_usage()
120 {
121 fprintf(stderr, "\
122 usage: lha [-]<commands>[<options>] [-<options> ...] archive_file [file...]\n\
123 commands: [axelvudmcpt]\n\
124 options: [q[012]vnfto[567]dizg012e[w=<dir>|x=<pattern>]]\n\
125 long options: --system-kanji-code={euc,sjis,utf8,cap}\n\
126 --archive-kanji-code={euc,sjis,utf8,cap}\n\
127 --extract-broken-archive\n\
128 --help\n\
129 --version\n");
130 }
131
132 static void
print_usage()133 print_usage()
134 {
135 fprintf(stderr, "\
136 LHarc for UNIX V 1.02 Copyright(C) 1989 Y.Tagawa\n\
137 LHx for MSDOS V C2.01 Copyright(C) 1990 H.Yoshizaki\n\
138 LHx(arc) for OSK V 2.01 Modified 1990 Momozou\n\
139 LHa for UNIX V 1.00 Copyright(C) 1992 Masaru Oki\n\
140 LHa for UNIX V 1.14 Modified 1995 Nobutaka Watazaki\n\
141 LHa for UNIX V 1.14i Modified 2000 Tsugio Okamoto\n\
142 Autoconfiscated 2001-2005 Koji Arai\n\
143 ");
144
145 print_tiny_usage();
146
147 fprintf(stderr, "\
148 commands: options:\n\
149 a Add(or replace) to archive q{num} quiet (num:quiet mode)\n\
150 x,e EXtract from archive v verbose\n\
151 l,v List / Verbose List n not execute\n\
152 u Update newer files to archive f force (over write at extract)\n\
153 d Delete from archive t FILES are TEXT file\n");
154 #ifdef SUPPORT_LH7
155 fprintf(stderr, "\
156 m Move to archive (means 'ad') o[567] compression method (a/u/c)\n\
157 ");
158 #endif
159 #ifndef SUPPORT_LH7
160 fprintf(stderr, "\
161 m Move to archive (means 'ad') o use LHarc compatible method (a/u/c)\n\
162 ");
163 #endif
164 fprintf(stderr, "\
165 c re-Construct new archive d delete FILES after (a/u/c)\n\
166 p Print to STDOUT from archive i ignore directory path (x/e)\n\
167 t Test file CRC in archive z files not compress (a/u/c)\n\
168 g Generic format (for compatibility)\n\
169 or not convert case when extracting\n\
170 0/1/2 header level (a/u/c)\n\
171 ");
172 #ifdef EUC
173 fprintf(stderr, "\
174 e TEXT code convert from/to EUC\n\
175 ");
176 #endif
177 fprintf(stderr, "\
178 w=<dir> specify extract directory (x/e)\n\
179 x=<pattern> eXclude files (a/u/c)\n\
180 ");
181 #if IGNORE_DOT_FILES /* experimental feature */
182 fprintf(stderr, "\
183 X ignore dot files (a/u/c)\n\
184 ");
185 #endif
186 }
187
188 #include "getopt_long.h"
189
190 /*
191 Parse LHA options
192 */
193 static int
parse_suboption(int argc,char ** argv)194 parse_suboption(int argc, char **argv)
195 {
196 char *short_options = "q[012]vnfto[567]dizg012ew:x:";
197 /* "[...]" means optional 1 byte argument (original extention) */
198 enum {
199 HELP_OPTION = 256,
200 VERSION_OPTION,
201 SYSTEM_KANJI_CODE_OPTION,
202 ARCHIVE_KANJI_CODE_OPTION,
203 };
204
205 struct option long_options[] = {
206 /* These options set a flag. */
207 {"help", no_argument, 0, HELP_OPTION},
208 {"version", no_argument, 0, VERSION_OPTION},
209
210 {"system-kanji-code", required_argument, 0, SYSTEM_KANJI_CODE_OPTION},
211 {"archive-kanji-code", required_argument, 0, ARCHIVE_KANJI_CODE_OPTION},
212 {"extract-broken-archive", no_argument, &extract_broken_archive, 1},
213 {0, 0, 0, 0}
214 };
215 int i;
216
217 /* parse option */
218 while (1) {
219 int option_index = 0;
220 int c = getopt_long(argc, argv,
221 short_options, long_options,
222 &option_index);
223
224 if (c == -1) break; /* end of options */
225
226 switch (c) {
227 case 0:
228 /* Already set a flag variable by the definition of the
229 long_options. */
230 break;
231 case '?':
232 /* Invalid option */
233 print_tiny_usage();
234 exit(2);
235 case HELP_OPTION:
236 print_usage();
237 exit(0);
238 case VERSION_OPTION:
239 print_version();
240 exit(0);
241 case 'q':
242 if (!optarg) {
243 /* In quiet mode, no confirm to overwrite */
244 force = TRUE;
245 quiet = TRUE;
246 break;
247 }
248
249 switch (*optarg) {
250 case '0': /* no quiet */
251 case '1': /* no use the incremental indicator */
252 quiet_mode = *optarg - '0';
253 break;
254 case '2': /* no output */
255 /* fall through */
256 default:
257 force = TRUE;
258 quiet = TRUE;
259 break;
260 }
261 break;
262 case 'f':
263 force = TRUE;
264 break;
265 case 'v':
266 verbose++;
267 break;
268 case 't':
269 text_mode = TRUE;
270 break;
271 #ifdef EUC
272 case 'e':
273 text_mode = TRUE;
274 euc_mode = TRUE;
275 break;
276 #endif
277 case 'n':
278 noexec = TRUE;
279 break;
280 case 'g':
281 generic_format = TRUE;
282 noconvertcase = TRUE;
283 header_level = 0;
284 break;
285 case 'd':
286 delete_after_append = TRUE;
287 break;
288 case 'o':
289 if (!optarg) {
290 compress_method = LZHUFF1_METHOD_NUM;
291 header_level = 0;
292 break;
293 }
294 switch (*optarg) {
295 case '5':
296 compress_method = LZHUFF5_METHOD_NUM;
297 break;
298 #ifdef SUPPORT_LH7
299 case '6':
300 compress_method = LZHUFF6_METHOD_NUM;
301 break;
302 case '7':
303 compress_method = LZHUFF7_METHOD_NUM;
304 break;
305 #endif
306 default:
307 error("invalid compression method 'o%c'", *optarg);
308 return -1;
309 }
310 break;
311 case 'z':
312 compress_method = LZHUFF0_METHOD_NUM; /* Changed N.Watazaki */
313 break;
314 case 'i':
315 ignore_directory = TRUE;
316 break;
317 case 'x':
318 if (!optarg) {
319 error("exclude files does not specified for `-x'");
320 exit(2);
321 }
322
323 for (i = 0; exclude_files && exclude_files[i]; i++)
324 ;
325 exclude_files = (char**)xrealloc(exclude_files,
326 sizeof(char*) * (i+2));
327
328 if (*optarg == '=')
329 optarg++;
330 exclude_files[i] = optarg;
331 exclude_files[i+1] = 0;
332
333 break;
334 #if IGNORE_DOT_FILES /* experimental feature */
335 case 'X':
336 for (i = 0; exclude_files && exclude_files[i]; i++)
337 ;
338 exclude_files = (char**)xrealloc(exclude_files,
339 sizeof(char*) * (i+2));
340
341 exclude_files[i] = xstrdup(".*");
342 exclude_files[i+1] = 0;
343 break;
344 #endif
345 case 'w':
346 if (!optarg) {
347 error("working directory does not specified for `-w'");
348 exit(2);
349 }
350 if (*optarg == '=')
351 optarg++;
352
353 extract_directory = optarg;
354 break;
355 case '0':
356 header_level = 0;
357 break;
358 case '1':
359 header_level = 1;
360 break;
361 case '2':
362 header_level = 2;
363 break;
364 case SYSTEM_KANJI_CODE_OPTION:
365 if (!optarg) {
366 error("kanji code not specified for --%s",
367 long_options[option_index].name);
368 return -1;
369 }
370 if (strcmp(optarg, "euc") == 0) {
371 optional_system_kanji_code = CODE_EUC;
372 }
373 else if (strcmp(optarg, "sjis") == 0) {
374 optional_system_kanji_code = CODE_SJIS;
375 }
376 else if (strcmp(optarg, "utf8") == 0) {
377 optional_system_kanji_code = CODE_UTF8;
378 }
379 else if (strcmp(optarg, "cap") == 0) {
380 optional_system_kanji_code = CODE_CAP;
381 }
382 else {
383 error("unknown kanji code \"%s\"", optarg);
384 return -1;
385 }
386 break;
387
388 case ARCHIVE_KANJI_CODE_OPTION:
389 if (!optarg) {
390 error("kanji code not specified for --%s",
391 long_options[option_index].name);
392 return -1;
393 }
394 if (strcmp(optarg, "euc") == 0) {
395 optional_archive_kanji_code = CODE_EUC;
396 }
397 else if (strcmp(optarg, "sjis") == 0) {
398 optional_archive_kanji_code = CODE_SJIS;
399 }
400 else if (strcmp(optarg, "utf8") == 0) {
401 optional_archive_kanji_code = CODE_UTF8;
402 }
403 else if (strcmp(optarg, "cap") == 0) {
404 optional_archive_kanji_code = CODE_CAP;
405 }
406 else {
407 error("unknown kanji code \"%s\"", optarg);
408 return -1;
409 }
410 break;
411
412 default:
413 error("unknown option `-%c'.", c);
414 return -1;
415 }
416 }
417
418 argc -= optind;
419 argv += optind;
420
421 if (!archive_name) {
422 archive_name = *argv++;
423 argc--;
424 }
425
426 cmd_filec = argc;
427 cmd_filev = argv;
428
429 return 0;
430 }
431
432 /*
433 Parse LHA command and options.
434 */
435 static int
parse_option(int argc,char ** argv)436 parse_option(int argc, char **argv)
437 {
438 char *cmd_char;
439
440 if (argv[1] == NULL || strcmp(argv[1], "--help") == 0) {
441 print_usage();
442 exit(0);
443 }
444
445 if (strcmp(argv[1], "--version") == 0) {
446 print_version();
447 exit(0);
448 }
449
450 if (argc == 2 && *argv[1] != '-') {
451 archive_name = argv[1];
452 cmd = CMD_LIST;
453 cmd_filec = 0;
454 cmd_filev = 0;
455 return 0;
456 }
457
458 cmd_char = argv[1];
459
460 if (cmd_char[0] == '-')
461 cmd_char++;
462
463 /* parse commands */
464 switch (*cmd_char) {
465 case 'x':
466 case 'e':
467 cmd = CMD_EXTRACT;
468 break;
469
470 case 'p':
471 output_to_stdout = TRUE;
472 cmd = CMD_EXTRACT;
473 break;
474
475 case 'c':
476 new_archive = TRUE;
477 cmd = CMD_ADD;
478 break;
479
480 case 'a':
481 cmd = CMD_ADD;
482 break;
483
484 case 'd':
485 cmd = CMD_DELETE;
486 break;
487
488 case 'u':
489 update_if_newer = TRUE;
490 cmd = CMD_ADD;
491 break;
492
493 case 'm':
494 delete_after_append = TRUE;
495 cmd = CMD_ADD;
496 break;
497
498 case 'v':
499 verbose_listing = TRUE;
500 cmd = CMD_LIST;
501 break;
502
503 case 'l':
504 cmd = CMD_LIST;
505 break;
506
507 case 't':
508 cmd = CMD_EXTRACT;
509 verify_mode = TRUE;
510 break;
511
512 default:
513 error("unknown command `-%c'", *cmd_char);
514 return -1;
515 }
516
517 if (cmd_char[1] == '\0') {
518 /* argv[1] is command name */
519 argv[1] = argv[0];
520 argv++;
521 argc--;
522 }
523 else {
524 /* Eliminate command character
525 e.g.) lha cv foo.lzh -> lha -v foo.lzh
526 lha -cv foo.lzh -> lha -v foo.lzh
527 */
528 cmd_char[0] = '-';
529 argv[1] = cmd_char;
530 }
531
532 return parse_suboption(argc, argv);
533 }
534
535 /* ------------------------------------------------------------------------ */
536 int
main(argc,argv)537 main(argc, argv)
538 int argc;
539 char *argv[];
540 {
541 char *p;
542
543 int i;
544
545 init_variable(); /* Added N.Watazaki */
546
547 if (parse_option(argc, argv) == -1) {
548 fputs("\n", stderr);
549 print_tiny_usage();
550 exit(2);
551 }
552
553 if (!archive_name) {
554 error("archive file does not specified");
555 fputs("\n", stderr);
556 print_tiny_usage();
557 exit(2);
558 }
559
560 if (!strcmp(archive_name, "-")) {
561 if (!isatty(1) && cmd == CMD_ADD)
562 quiet = TRUE;
563 }
564 #if 0 /* Comment out; IMHO, this feature is useless. by Koji Arai */
565 else {
566 if (argc == 3 && !isatty(0)) { /* 1999.7.18 */
567 /* Bug(?) on MinGW, isatty() return 0 on Cygwin console.
568 mingw-runtime-1.3-2 and Cygwin 1.3.10(0.51/3/2) on Win2000 */
569 get_filename_from_stdin = TRUE;
570 }
571 }
572 #endif
573
574 /* target file name */
575 if (get_filename_from_stdin) {
576 char inpbuf[4096];
577 char **xfilev;
578 int xfilec = 257;
579
580 cmd_filec = 0;
581 xfilev = (char **)xmalloc(sizeof(char *) * xfilec);
582 while (fgets(inpbuf, sizeof(inpbuf), stdin)) {
583 /* delete \n if it exist */
584 i=0; p=inpbuf;
585 while (i < sizeof(inpbuf) && p != 0) {
586 if (*p == '\n') {
587 *p = 0;
588 break;
589 }
590 p++; i++;
591 }
592
593 if (cmd_filec >= xfilec) {
594 xfilec += 256;
595 xfilev = (char **) xrealloc(xfilev,
596 sizeof(char *) * xfilec);
597 }
598 if (strlen(inpbuf) < 1)
599 continue;
600 xfilev[cmd_filec++] = xstrdup(inpbuf);
601 }
602 xfilev[cmd_filec] = NULL;
603 cmd_filev = xfilev;
604 }
605
606 sort_files();
607
608 /* make crc table */
609 make_crctable();
610
611 switch (cmd) {
612 case CMD_EXTRACT:
613 cmd_extract();
614 break;
615 case CMD_ADD:
616 cmd_add();
617 break;
618 case CMD_LIST:
619 cmd_list();
620 break;
621 case CMD_DELETE:
622 cmd_delete();
623 break;
624 }
625
626 if (error_occurred)
627 return 1;
628 return 0;
629 }
630
631
632 /* ------------------------------------------------------------------------ */
633 static void
print_version()634 print_version()
635 {
636 /* macro PACKAGE_NAME, PACKAGE_VERSION and PLATFORM are
637 defined in config.h by configure script */
638 fprintf(stderr, "%s version %s (%s)\n",
639 PACKAGE_NAME, PACKAGE_VERSION, PLATFORM);
640 }
641
642 void
643 #if STDC_HEADERS
message(char * fmt,...)644 message(char *fmt, ...)
645 #else
646 message(fmt, va_alist)
647 char *fmt;
648 va_dcl
649 #endif
650 {
651 int errno_sv = errno;
652 va_list v;
653
654 fprintf(stderr, "LHa: ");
655
656 va_init(v, fmt);
657 vfprintf(stderr, fmt, v);
658 va_end(v);
659
660 fputs("\n", stderr);
661
662 errno = errno_sv;
663 }
664
665 /* ------------------------------------------------------------------------ */
666 void
667 #if STDC_HEADERS
warning(char * fmt,...)668 warning(char *fmt, ...)
669 #else
670 warning(fmt, va_alist)
671 char *fmt;
672 va_dcl
673 #endif
674 {
675 int errno_sv = errno;
676 va_list v;
677
678 fprintf(stderr, "LHa: Warning: ");
679
680 va_init(v, fmt);
681 vfprintf(stderr, fmt, v);
682 va_end(v);
683
684 fputs("\n", stderr);
685
686 errno = errno_sv;
687 }
688
689 /* ------------------------------------------------------------------------ */
690 void
691 #if STDC_HEADERS
error(char * fmt,...)692 error(char *fmt, ...)
693 #else
694 error(fmt, va_alist)
695 char *fmt;
696 va_dcl
697 #endif
698 {
699 int errno_sv = errno;
700 va_list v;
701
702 fprintf(stderr, "LHa: Error: ");
703
704 va_init(v, fmt);
705 vfprintf(stderr, fmt, v);
706 va_end(v);
707
708 fputs("\n", stderr);
709
710 error_occurred = 1;
711
712 errno = errno_sv;
713 }
714
715 void
716 #if STDC_HEADERS
fatal_error(char * fmt,...)717 fatal_error(char *fmt, ...)
718 #else
719 fatal_error(fmt, va_alist)
720 char *fmt;
721 va_dcl
722 #endif
723 {
724 int errno_sv = errno;
725 va_list v;
726
727 fprintf(stderr, "LHa: Fatal error: ");
728
729 va_init(v, fmt);
730 vfprintf(stderr, fmt, v);
731 va_end(v);
732
733 if (errno)
734 fprintf(stderr, ": %s\n", strerror(errno_sv));
735 else
736 fputs("\n", stderr);
737
738 exit(1);
739 }
740
741 void
cleanup()742 cleanup()
743 {
744 if (temporary_fd != -1) {
745 close(temporary_fd);
746 temporary_fd = -1;
747 unlink(temporary_name);
748 }
749
750 if (recover_archive_when_interrupt) {
751 rename(backup_archive_name, archive_name);
752 recover_archive_when_interrupt = FALSE;
753 }
754 if (remove_extracting_file_when_interrupt) {
755 message("Removing: %s", writing_filename);
756 unlink(writing_filename);
757 remove_extracting_file_when_interrupt = FALSE;
758 }
759 }
760
761 RETSIGTYPE
interrupt(signo)762 interrupt(signo)
763 int signo;
764 {
765 message("Interrupted");
766
767 cleanup();
768
769 signal(SIGINT, SIG_DFL);
770 #ifdef SIGHUP
771 signal(SIGHUP, SIG_DFL);
772 #endif
773 kill(getpid(), signo);
774 }
775
776 /* ------------------------------------------------------------------------ */
777 /* */
778 /* ------------------------------------------------------------------------ */
779 static int
sort_by_ascii(a,b)780 sort_by_ascii(a, b)
781 char **a, **b;
782 {
783 register char *p, *q;
784 register int c1, c2;
785
786 p = *a, q = *b;
787 if (generic_format) {
788 do {
789 c1 = *(unsigned char *) p++;
790 c2 = *(unsigned char *) q++;
791 if (!c1 || !c2)
792 break;
793 if (islower(c1))
794 c1 = toupper(c1);
795 if (islower(c2))
796 c2 = toupper(c2);
797 }
798 while (c1 == c2);
799 return c1 - c2;
800 }
801 else {
802 while (*p == *q && *p != '\0')
803 p++, q++;
804 return *(unsigned char *) p - *(unsigned char *) q;
805 }
806 }
807
808 /* ------------------------------------------------------------------------ */
809 static void
sort_files()810 sort_files()
811 {
812 if (cmd_filec > 1)
813 qsort(cmd_filev, cmd_filec, sizeof(char *), sort_by_ascii);
814 }
815
816 /* ------------------------------------------------------------------------ */
817 void *
xmalloc(size)818 xmalloc(size)
819 size_t size;
820 {
821 void *p = malloc(size);
822 if (!p)
823 fatal_error("Not enough memory");
824 return p;
825 }
826
827 /* ------------------------------------------------------------------------ */
828 void *
xrealloc(old,size)829 xrealloc(old, size)
830 void *old;
831 size_t size;
832 {
833 void *p = (char *) realloc(old, size);
834 if (!p)
835 fatal_error("Not enough memory");
836 return p;
837 }
838
839 char *
xstrdup(str)840 xstrdup(str)
841 char *str;
842 {
843 int len = strlen(str);
844 char *p = (char *)xmalloc(len + 1);
845 strcpy(p, str); /* ok */
846 return p;
847 }
848
849 /* ------------------------------------------------------------------------ */
850 /* STRING POOL */
851 /* ------------------------------------------------------------------------ */
852 /*
853 string pool :
854 +-------------+-------------+------+-------------+----------+
855 | N A M E 1 \0| N A M E 2 \0| .... | N A M E n \0| |
856 +-------------+-------------+------+-------------+----------+
857 ^ ^ ^ buffer+0 buffer+used buffer+size
858
859 vector :
860 +---------------+---------------+------------- -----------------+
861 | pointer to | pointer to | pointer to ... pointer to |
862 | stringpool | N A M E 1 | N A M E 2 ... N A M E n |
863 +---------------+---------------+------------- -------------+
864 ^ malloc base returned
865 */
866
867 /* ------------------------------------------------------------------------ */
868 void
init_sp(sp)869 init_sp(sp)
870 struct string_pool *sp;
871 {
872 sp->size = 1024 - 8; /* any ( >=0 ) */
873 sp->used = 0;
874 sp->n = 0;
875 sp->buffer = (char *) xmalloc(sp->size * sizeof(char));
876 }
877
878 /* ------------------------------------------------------------------------ */
879 void
add_sp(sp,name,len)880 add_sp(sp, name, len)
881 struct string_pool *sp;
882 char *name; /* stored '\0' at tail */
883 int len; /* include '\0' */
884 {
885 while (sp->used + len > sp->size) {
886 sp->size *= 2;
887 sp->buffer = (char *) xrealloc(sp->buffer, sp->size * sizeof(char));
888 }
889 memmove(sp->buffer + sp->used, name, len);
890 sp->used += len;
891 sp->n++;
892 }
893
894 /* ------------------------------------------------------------------------ */
895 void
finish_sp(sp,v_count,v_vector)896 finish_sp(sp, v_count, v_vector)
897 register struct string_pool *sp;
898 int *v_count;
899 char ***v_vector;
900 {
901 int i;
902 register char *p;
903 char **v;
904
905 v = (char **) xmalloc((sp->n + 1) * sizeof(char *));
906 *v++ = sp->buffer;
907 *v_vector = v;
908 *v_count = sp->n;
909 p = sp->buffer;
910 for (i = sp->n; i; i--) {
911 *v++ = p;
912 if (i - 1)
913 p += strlen(p) + 1;
914 }
915 }
916
917 /* ------------------------------------------------------------------------ */
918 void
free_sp(vector)919 free_sp(vector)
920 char **vector;
921 {
922 vector--;
923 free(*vector); /* free string pool */
924 free(vector);
925 }
926
927
928 /* ------------------------------------------------------------------------ */
929 /* READ DIRECTORY FILES */
930 /* ------------------------------------------------------------------------ */
931 static boolean
include_path_p(path,name)932 include_path_p(path, name)
933 char *path, *name;
934 {
935 char *n = name;
936 while (*path)
937 if (*path++ != *n++)
938 return (path[-1] == '/' && *n == '\0');
939 return (*n == '/' || (n != name && path[-1] == '/' && n[-1] == '/'));
940 }
941
942 /* ------------------------------------------------------------------------ */
943 void
cleaning_files(v_filec,v_filev)944 cleaning_files(v_filec, v_filev)
945 int *v_filec;
946 char ***v_filev;
947 {
948 char *flags;
949 struct stat stbuf;
950
951 register char **filev = *v_filev;
952 register int filec = *v_filec;
953 register char *p;
954 register int i, j;
955
956 if (filec == 0)
957 return;
958
959 flags = xmalloc(filec * sizeof(char));
960
961 /* flags & 0x01 : 1: ignore */
962 /* flags & 0x02 : 1: directory, 0 : regular file */
963 /* flags & 0x04 : 1: need delete */
964
965 for (i = 0; i < filec; i++)
966 if (GETSTAT(filev[i], &stbuf) < 0) {
967 flags[i] = 0x04;
968 warning("Cannot access \"%s\" : %s; ignored.", filev[i],
969 strerror(errno));
970 }
971 else {
972 if (is_regularfile(&stbuf))
973 flags[i] = 0x00;
974 else if (is_directory(&stbuf))
975 flags[i] = 0x02;
976 #ifdef S_IFLNK
977 else if (is_symlink(&stbuf)) /* t.okamoto */
978 flags[i] = 0x00;
979 #endif
980 else {
981 flags[i] = 0x04;
982 warning("Cannot archive \"%s\", ignored.", filev[i]);
983 }
984 }
985
986 for (i = 0; i < filec; i++) {
987 p = filev[i];
988 if ((flags[i] & 0x07) == 0x00) { /* regular file, not
989 * deleted/ignored */
990 for (j = i + 1; j < filec; j++) {
991 if ((flags[j] & 0x07) == 0x00) { /* regular file, not
992 * deleted/ignored */
993 if (STREQU(p, filev[j]))
994 flags[j] = 0x04; /* delete */
995 }
996 }
997 }
998 else if ((flags[i] & 0x07) == 0x02) { /* directory, not
999 * deleted/ignored */
1000 for (j = i + 1; j < filec; j++) {
1001 if ((flags[j] & 0x07) == 0x00) { /* regular file, not
1002 * deleted/ignored */
1003 if (include_path_p(p, filev[j]))
1004 flags[j] = 0x04; /* delete */
1005 }
1006 else if ((flags[j] & 0x07) == 0x02) { /* directory, not
1007 * deleted/ignored */
1008 if (include_path_p(p, filev[j]))
1009 flags[j] = 0x04; /* delete */
1010 }
1011 }
1012 }
1013 }
1014
1015 for (i = j = 0; i < filec; i++) {
1016 if ((flags[i] & 0x04) == 0) {
1017 if (i != j)
1018 filev[j] = filev[i];
1019 j++;
1020 }
1021 }
1022 *v_filec = j;
1023
1024 free(flags);
1025 }
1026
1027 /* ------------------------------------------------------------------------ */
1028 boolean
find_files(name,v_filec,v_filev)1029 find_files(name, v_filec, v_filev)
1030 char *name;
1031 int *v_filec;
1032 char ***v_filev;
1033 {
1034 struct string_pool sp;
1035 char newname[FILENAME_LENGTH];
1036 int len, n, i;
1037 DIR *dirp;
1038 struct dirent *dp;
1039 struct stat tmp_stbuf, arc_stbuf, fil_stbuf;
1040 int exist_tmp = 1, exist_arc = 1;
1041
1042 len = str_safe_copy(newname, name, sizeof(newname));
1043 if (len > 0 && newname[len - 1] != '/') {
1044 if (len < sizeof(newname)-1)
1045 strcpy(&newname[len++], "/"); /* ok */
1046 else
1047 warning("the length of pathname \"%s\" is too long.", name);
1048 }
1049
1050 dirp = opendir(name);
1051 if (!dirp)
1052 return FALSE;
1053
1054 init_sp(&sp);
1055
1056 if (GETSTAT(temporary_name, &tmp_stbuf) == -1)
1057 exist_tmp = 0;
1058 if (GETSTAT(archive_name, &arc_stbuf) == -1)
1059 exist_arc = 0;
1060
1061 while ((dp = readdir(dirp)) != NULL) {
1062 n = NAMLEN(dp);
1063
1064 /* exclude '.' and '..' */
1065 if (strncmp(dp->d_name, ".", n) == 0
1066 || strncmp(dp->d_name, "..", n) == 0)
1067 continue;
1068
1069 /* exclude exclude_files supplied by user */
1070 for (i = 0; exclude_files && exclude_files[i]; i++) {
1071 if (fnmatch(exclude_files[i], dp->d_name,
1072 FNM_PATHNAME|FNM_NOESCAPE|FNM_PERIOD) == 0)
1073 goto next;
1074 }
1075
1076 if (len + n >= sizeof(newname)) {
1077 warning("filename is too long");
1078 continue;
1079 }
1080
1081 strncpy(newname + len, dp->d_name, n);
1082 newname[len + n] = '\0';
1083 if (GETSTAT(newname, &fil_stbuf) < 0)
1084 continue;
1085
1086 #if defined(HAVE_STRUCT_STAT_ST_INO) && !__MINGW32__
1087 /* MinGW has meaningless st_ino */
1088
1089 /* exclude temporary file, archive file and these links */
1090 if (exist_tmp &&
1091 tmp_stbuf.st_dev == fil_stbuf.st_dev &&
1092 tmp_stbuf.st_ino == fil_stbuf.st_ino)
1093 continue;
1094
1095 if (exist_arc &&
1096 arc_stbuf.st_dev == fil_stbuf.st_dev &&
1097 arc_stbuf.st_ino == fil_stbuf.st_ino)
1098 continue;
1099 #endif
1100 add_sp(&sp, newname, len+n+1);
1101 next:
1102 ;
1103 }
1104 closedir(dirp);
1105 finish_sp(&sp, v_filec, v_filev);
1106 if (*v_filec > 1)
1107 qsort(*v_filev, *v_filec, sizeof(char *), sort_by_ascii);
1108 cleaning_files(v_filec, v_filev);
1109
1110 return TRUE;
1111 }
1112
1113 /* ------------------------------------------------------------------------ */
1114 void
free_files(filec,filev)1115 free_files(filec, filev)
1116 int filec;
1117 char **filev;
1118 {
1119 free_sp(filev);
1120 }
1121
1122 /* ------------------------------------------------------------------------ */
1123 /* */
1124 /* ------------------------------------------------------------------------ */
1125 /* Build temporary file name and store to TEMPORARY_NAME */
1126 int
build_temporary_name()1127 build_temporary_name()
1128 {
1129 #ifdef TMP_FILENAME_TEMPLATE
1130 /* "/tmp/lhXXXXXX" etc. */
1131 if (extract_directory == NULL) {
1132 str_safe_copy(temporary_name, TMP_FILENAME_TEMPLATE,
1133 sizeof(temporary_name));
1134 }
1135 else {
1136 xsnprintf(temporary_name, sizeof(temporary_name),
1137 "%s/lhXXXXXX", extract_directory);
1138 }
1139 #else
1140 char *s;
1141
1142 str_safe_copy(temporary_name, archive_name, sizeof(temporary_name));
1143 s = strrchr(temporary_name, '/');
1144 if (s) {
1145 int len;
1146 len = s - temporary_name;
1147 if (len + strlen("lhXXXXXX") < sizeof(temporary_name))
1148 /* use directory at archive file */
1149 strcpy(s, "lhXXXXXX"); /* ok */
1150 else
1151 /* use current directory */
1152 str_safe_copy(temporary_name, "lhXXXXXX", sizeof(temporary_name));
1153 }
1154 else
1155 /* use current directory */
1156 str_safe_copy(temporary_name, "lhXXXXXX", sizeof(temporary_name));
1157 #endif
1158 #ifdef HAVE_MKSTEMP
1159 {
1160 int old_umask, fd;
1161
1162 old_umask = umask(077);
1163 fd = mkstemp(temporary_name);
1164 umask(old_umask);
1165 return fd;
1166 }
1167 #else
1168 {
1169 int flags;
1170
1171 mktemp(temporary_name);
1172 flags = O_CREAT|O_EXCL|O_RDWR;
1173 #ifdef O_BINARY
1174 flags |= O_BINARY;
1175 #endif
1176 return open(temporary_name, flags, 0600);
1177 }
1178 #endif
1179 }
1180
1181 /* ------------------------------------------------------------------------ */
1182 static void
modify_filename_extention(buffer,ext,size)1183 modify_filename_extention(buffer, ext, size)
1184 char *buffer;
1185 char *ext;
1186 size_t size;
1187 {
1188 register char *p, *dot;
1189
1190 for (p = buffer, dot = (char *) 0; *p; p++) {
1191 if (*p == '.')
1192 dot = p;
1193 else if (*p == '/')
1194 dot = (char *) 0;
1195 }
1196
1197 if (dot)
1198 p = dot;
1199
1200 str_safe_copy(p, ext, size - (p - buffer));
1201 }
1202
1203 /* ------------------------------------------------------------------------ */
1204 /* build backup file name */
1205 void
build_backup_name(buffer,original,size)1206 build_backup_name(buffer, original, size)
1207 char *buffer;
1208 char *original;
1209 size_t size;
1210 {
1211 str_safe_copy(buffer, original, size);
1212 modify_filename_extention(buffer, BACKUPNAME_EXTENTION, size); /* ".bak" */
1213 }
1214
1215 /* ------------------------------------------------------------------------ */
1216 void
build_standard_archive_name(buffer,original,size)1217 build_standard_archive_name(buffer, original, size)
1218 char *buffer;
1219 char *original;
1220 size_t size;
1221 {
1222 str_safe_copy(buffer, original, size);
1223 modify_filename_extention(buffer, ARCHIVENAME_EXTENTION, size); /* ".lzh" */
1224 }
1225
1226 /* ------------------------------------------------------------------------ */
1227 /* */
1228 /* ------------------------------------------------------------------------ */
1229 boolean
need_file(name)1230 need_file(name)
1231 char *name;
1232 {
1233 int i;
1234
1235 if (cmd_filec == 0)
1236 return TRUE;
1237
1238 for (i = 0; i < cmd_filec; i++) {
1239 if (patmatch(cmd_filev[i], name, 0))
1240 return TRUE;
1241 }
1242
1243 return FALSE;
1244 }
1245
1246 FILE *
xfopen(name,mode)1247 xfopen(name, mode)
1248 char *name, *mode;
1249 {
1250 FILE *fp;
1251
1252 if ((fp = fopen(name, mode)) == NULL)
1253 fatal_error("Cannot open file \"%s\"", name);
1254
1255 return fp;
1256 }
1257
1258 /* ------------------------------------------------------------------------ */
1259 /* */
1260 /* ------------------------------------------------------------------------ */
1261 static boolean
open_old_archive_1(name,v_fp)1262 open_old_archive_1(name, v_fp)
1263 char *name;
1264 FILE **v_fp;
1265 {
1266 FILE *fp;
1267 struct stat stbuf;
1268
1269 if (stat(name, &stbuf) >= 0 &&
1270 is_regularfile(&stbuf) &&
1271 (fp = fopen(name, READ_BINARY)) != NULL) {
1272 *v_fp = fp;
1273 archive_file_gid = stbuf.st_gid;
1274 archive_file_mode = stbuf.st_mode;
1275 return TRUE;
1276 }
1277
1278 *v_fp = NULL;
1279 archive_file_gid = -1;
1280 return FALSE;
1281 }
1282
1283 /* ------------------------------------------------------------------------ */
1284 FILE *
open_old_archive()1285 open_old_archive()
1286 {
1287 FILE *fp;
1288 char *p;
1289 static char expanded_archive_name[FILENAME_LENGTH];
1290
1291 if (!strcmp(archive_name, "-")) {
1292 if (cmd == CMD_EXTRACT || cmd == CMD_LIST) {
1293 #if __MINGW32__
1294 setmode(fileno(stdin), O_BINARY);
1295 #endif
1296 return stdin;
1297 }
1298 else
1299 return NULL;
1300 }
1301 p = strrchr(archive_name, '.');
1302 if (p) {
1303 if (strcasecmp(".LZH", p) == 0
1304 || strcasecmp(".LZS", p) == 0
1305 || strcasecmp(".COM", p) == 0 /* DOS SFX */
1306 || strcasecmp(".EXE", p) == 0
1307 || strcasecmp(".X", p) == 0 /* HUMAN SFX */
1308 || strcasecmp(".BAK", p) == 0) { /* for BackUp */
1309 open_old_archive_1(archive_name, &fp);
1310 return fp;
1311 }
1312 }
1313
1314 if (open_old_archive_1(archive_name, &fp))
1315 return fp;
1316 xsnprintf(expanded_archive_name, sizeof(expanded_archive_name),
1317 "%s.lzh", archive_name);
1318 if (open_old_archive_1(expanded_archive_name, &fp)) {
1319 archive_name = expanded_archive_name;
1320 return fp;
1321 }
1322 /*
1323 * if ( (errno&0xffff)!=E_PNNF ) { archive_name =
1324 * expanded_archive_name; return NULL; }
1325 */
1326 xsnprintf(expanded_archive_name, sizeof(expanded_archive_name),
1327 "%s.lzs", archive_name);
1328 if (open_old_archive_1(expanded_archive_name, &fp)) {
1329 archive_name = expanded_archive_name;
1330 return fp;
1331 }
1332 /*
1333 * if ( (errno&0xffff)!=E_PNNF ) { archive_name =
1334 * expanded_archive_name; return NULL; }
1335 */
1336 /*
1337 * sprintf( expanded_archive_name , "%s.lzh",archive_name);
1338 * archive_name = expanded_archive_name;
1339 */
1340 return NULL;
1341 }
1342
1343 /* ------------------------------------------------------------------------ */
1344 int
inquire(msg,name,selective)1345 inquire(msg, name, selective)
1346 char *msg, *name, *selective;
1347 {
1348 char buffer[1024];
1349 char *p;
1350
1351 for (;;) {
1352 fprintf(stderr, "%s %s ", name, msg);
1353 fflush(stderr);
1354
1355 fgets(buffer, 1024, stdin);
1356
1357 for (p = selective; *p; p++)
1358 if (buffer[0] == *p)
1359 return p - selective;
1360 }
1361 /* NOTREACHED */
1362 }
1363
1364 /* ------------------------------------------------------------------------ */
1365 void
write_archive_tail(nafp)1366 write_archive_tail(nafp)
1367 FILE *nafp;
1368 {
1369 putc(0x00, nafp);
1370 }
1371
1372 /* ------------------------------------------------------------------------ */
1373 void
copy_old_one(oafp,nafp,hdr)1374 copy_old_one(oafp, nafp, hdr)
1375 FILE *oafp, *nafp;
1376 LzHeader *hdr;
1377 {
1378 if (noexec) {
1379 fseeko(oafp, hdr->header_size + hdr->packed_size, SEEK_CUR);
1380 }
1381 else {
1382 reading_filename = archive_name;
1383 writing_filename = temporary_name;
1384 copyfile(oafp, nafp, hdr->header_size + hdr->packed_size, 0, 0);
1385 }
1386 }
1387
1388 #undef exit
1389
1390 void
lha_exit(status)1391 lha_exit(status)
1392 int status;
1393 {
1394 cleanup();
1395 exit(status);
1396 }
1397