OSDN Git Service

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