OSDN Git Service

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