OSDN Git Service

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