OSDN Git Service

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