OSDN Git Service

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