OSDN Git Service

* configure.ac: added a command line switch `--enable-backup-archive'.
[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                 = FALSE;
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_LEVEL1;
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 = TRUE;
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         fprintf(stderr, "%s\n", LHA_VERSION);
454 }
455
456 void
457 #if STDC_HEADERS
458 message(char *fmt, ...)
459 #else
460 message(fmt, va_alist)
461     char *fmt;
462     va_dcl
463 #endif
464 {
465     int errno_sv = errno;
466     va_list v;
467
468         fprintf(stderr, "LHa: ");
469
470     va_init(v, fmt);
471     vfprintf(stderr, fmt, v);
472     va_end(v);
473
474     fputs("\n", stderr);
475
476     errno =  errno_sv;
477 }
478
479 /* ------------------------------------------------------------------------ */
480 void
481 #if STDC_HEADERS
482 warning(char *fmt, ...)
483 #else
484 warning(fmt, va_alist)
485     char *fmt;
486     va_dcl
487 #endif
488 {
489     int errno_sv = errno;
490     va_list v;
491
492         fprintf(stderr, "LHa: Warning: ");
493
494     va_init(v, fmt);
495     vfprintf(stderr, fmt, v);
496     va_end(v);
497
498     fputs("\n", stderr);
499
500     errno =  errno_sv;
501 }
502
503 /* ------------------------------------------------------------------------ */
504 void
505 #if STDC_HEADERS
506 error(char *fmt, ...)
507 #else
508 error(fmt, va_alist)
509     char *fmt;
510     va_dcl
511 #endif
512 {
513     int errno_sv = errno;
514     va_list v;
515
516         fprintf(stderr, "LHa: Error: ");
517
518     va_init(v, fmt);
519     vfprintf(stderr, fmt, v);
520     va_end(v);
521
522     fputs("\n", stderr);
523
524     error_occurred = 1;
525
526     errno =  errno_sv;
527 }
528
529 void
530 #if STDC_HEADERS
531 fatal_error(char *fmt, ...)
532 #else
533 fatal_error(fmt, va_alist)
534     char *fmt;
535     va_dcl
536 #endif
537 {
538     int errno_sv = errno;
539     va_list v;
540
541         fprintf(stderr, "LHa: Fatal error: ");
542
543     va_init(v, fmt);
544     vfprintf(stderr, fmt, v);
545     va_end(v);
546
547         if (errno)
548         fprintf(stderr, ": %s\n", strerror(errno_sv));
549     else
550         fputs("\n", stderr);
551
552     if (remove_temporary_at_error) {
553         if (temporary_fd != -1)
554             close(temporary_fd);
555         unlink(temporary_name);
556     }
557
558     exit(1);
559 }
560
561 /* ------------------------------------------------------------------------ */
562 RETSIGTYPE
563 interrupt(signo)
564         int             signo;
565 {
566         message("Interrupted");
567
568         if (temporary_fd != -1)
569                 close(temporary_fd);
570         unlink(temporary_name);
571         if (recover_archive_when_interrupt)
572                 rename(backup_archive_name, archive_name);
573         if (remove_extracting_file_when_interrupt) {
574                 message("Removing: %s", writing_filename);
575                 unlink(writing_filename);
576         }
577         signal(SIGINT, SIG_DFL);
578 #ifdef SIGHUP
579         signal(SIGHUP, SIG_DFL);
580 #endif
581         kill(getpid(), signo);
582 }
583
584 /* ------------------------------------------------------------------------ */
585 /*                                                                                                                                                      */
586 /* ------------------------------------------------------------------------ */
587 static int
588 sort_by_ascii(a, b)
589         char          **a, **b;
590 {
591         register char  *p, *q;
592         register int    c1, c2;
593
594         p = *a, q = *b;
595         if (generic_format) {
596                 do {
597                         c1 = *(unsigned char *) p++;
598                         c2 = *(unsigned char *) q++;
599                         if (!c1 || !c2)
600                                 break;
601                         if (islower(c1))
602                                 c1 = toupper(c1);
603                         if (islower(c2))
604                                 c2 = toupper(c2);
605                 }
606                 while (c1 == c2);
607                 return c1 - c2;
608         }
609         else {
610                 while (*p == *q && *p != '\0')
611                         p++, q++;
612                 return *(unsigned char *) p - *(unsigned char *) q;
613         }
614 }
615
616 /* ------------------------------------------------------------------------ */
617 static void
618 sort_files()
619 {
620         if (cmd_filec > 1)
621                 qsort(cmd_filev, cmd_filec, sizeof(char *), sort_by_ascii);
622 }
623
624 /* ------------------------------------------------------------------------ */
625 void *
626 xmalloc(size)
627         int             size;
628 {
629     void *p = malloc(size);
630         if (!p)
631                 fatal_error("Not enough memory");
632         return p;
633 }
634
635 /* ------------------------------------------------------------------------ */
636 void *
637 xrealloc(old, size)
638         void *old;
639         int size;
640 {
641         void *p = (char *) realloc(old, size);
642         if (!p)
643                 fatal_error("Not enough memory");
644         return p;
645 }
646
647 char *
648 xstrdup(str)
649         char *str;
650 {
651     int len = strlen(str);
652         char *p = (char *)xmalloc(len + 1);
653     strcpy(p, str);
654         return p;
655 }
656
657 /* ------------------------------------------------------------------------ */
658 /*                                                              STRING POOL                                                                     */
659 /* ------------------------------------------------------------------------ */
660 /*
661   string pool :
662         +-------------+-------------+------+-------------+----------+
663         | N A M E 1 \0| N A M E 2 \0| .... | N A M E n \0|                      |
664         +-------------+-------------+------+-------------+----------+
665           ^ ^            ^ buffer+0 buffer+used buffer+size
666
667   vector :
668         +---------------+---------------+------------- -----------------+
669         | pointer to    | pointer to    | pointer to   ...  pointer to  |
670         |  stringpool   |  N A M E 1    |  N A M E 2   ...   N A M E n  |
671         +---------------+---------------+-------------     -------------+
672         ^ malloc base      returned
673 */
674
675 /* ------------------------------------------------------------------------ */
676 void
677 init_sp(sp)
678         struct string_pool *sp;
679 {
680         sp->size = 1024 - 8;    /* any ( >=0 ) */
681         sp->used = 0;
682         sp->n = 0;
683         sp->buffer = (char *) xmalloc(sp->size * sizeof(char));
684 }
685
686 /* ------------------------------------------------------------------------ */
687 void
688 add_sp(sp, name, len)
689         struct string_pool *sp;
690         char           *name;   /* stored '\0' at tail */
691         int             len;    /* include '\0' */
692 {
693         while (sp->used + len > sp->size) {
694                 sp->size *= 2;
695                 sp->buffer = (char *) xrealloc(sp->buffer, sp->size * sizeof(char));
696         }
697         memmove(sp->buffer + sp->used, name, len);
698         sp->used += len;
699         sp->n++;
700 }
701
702 /* ------------------------------------------------------------------------ */
703 void
704 finish_sp(sp, v_count, v_vector)
705         register struct string_pool *sp;
706         int            *v_count;
707         char         ***v_vector;
708 {
709         int             i;
710         register char  *p;
711         char          **v;
712
713         v = (char **) xmalloc((sp->n + 1) * sizeof(char *));
714         *v++ = sp->buffer;
715         *v_vector = v;
716         *v_count = sp->n;
717         p = sp->buffer;
718         for (i = sp->n; i; i--) {
719                 *v++ = p;
720                 if (i - 1)
721                         p += strlen(p) + 1;
722         }
723 }
724
725 /* ------------------------------------------------------------------------ */
726 void
727 free_sp(vector)
728         char          **vector;
729 {
730         vector--;
731         free(*vector);          /* free string pool */
732         free(vector);
733 }
734
735
736 /* ------------------------------------------------------------------------ */
737 /*                                                      READ DIRECTORY FILES                                                    */
738 /* ------------------------------------------------------------------------ */
739 static          boolean
740 include_path_p(path, name)
741         char           *path, *name;
742 {
743         char           *n = name;
744         while (*path)
745                 if (*path++ != *n++)
746                         return (path[-1] == '/' && *n == '\0');
747         return (*n == '/' || (n != name && path[-1] == '/' && n[-1] == '/'));
748 }
749
750 /* ------------------------------------------------------------------------ */
751 void
752 cleaning_files(v_filec, v_filev)
753         int            *v_filec;
754         char         ***v_filev;
755 {
756         char           *flags;
757         struct stat     stbuf;
758
759         register char **filev = *v_filev;
760         register int    filec = *v_filec;
761         register char  *p;
762         register int    i, j;
763
764         if (filec == 0)
765                 return;
766
767         flags = xmalloc(filec * sizeof(char));
768
769         /* flags & 0x01 :       1: ignore */
770         /* flags & 0x02 :       1: directory, 0 : regular file */
771         /* flags & 0x04 :       1: need delete */
772
773         
774         for (i = 0; i < filec; i++)
775                 if (GETSTAT(filev[i], &stbuf) < 0) {
776                         flags[i] = 0x04;
777                         warning("Cannot access \"%s\", ignored.", filev[i]);
778                 }
779                 else {
780                         if (is_regularfile(&stbuf))
781                                 flags[i] = 0x00;
782                         else if (is_directory(&stbuf))
783                                 flags[i] = 0x02;
784 #ifdef S_IFLNK
785                         else if (is_symlink(&stbuf)) /* t.okamoto */
786                                 flags[i] = 0x00;
787 #endif                  
788                         else {
789                                 flags[i] = 0x04;
790                                 warning("Cannot archive \"%s\", ignored.", filev[i]);
791                         }
792                 }
793
794         for (i = 0; i < filec; i++) {
795                 p = filev[i];
796                 if ((flags[i] & 0x07) == 0x00) {        /* regular file, not
797                                                          * deleted/ignored */
798                         for (j = i + 1; j < filec; j++) {
799                                 if ((flags[j] & 0x07) == 0x00) {        /* regular file, not
800                                                                          * deleted/ignored */
801                                         if (STREQU(p, filev[j]))
802                                                 flags[j] = 0x04;        /* delete */
803                                 }
804                         }
805                 }
806                 else if ((flags[i] & 0x07) == 0x02) {   /* directory, not
807                                                          * deleted/ignored */
808                         for (j = i + 1; j < filec; j++) {
809                                 if ((flags[j] & 0x07) == 0x00) {        /* regular file, not
810                                                                          * deleted/ignored */
811                                         if (include_path_p(p, filev[j]))
812                                                 flags[j] = 0x04;        /* delete */
813                                 }
814                                 else if ((flags[j] & 0x07) == 0x02) {   /* directory, not
815                                                                          * deleted/ignored */
816                                         if (include_path_p(p, filev[j]))
817                                                 flags[j] = 0x04;        /* delete */
818                                 }
819                         }
820                 }
821         }
822
823         for (i = j = 0; i < filec; i++) {
824                 if ((flags[i] & 0x04) == 0) {
825                         if (i != j)
826                                 filev[j] = filev[i];
827                         j++;
828                 }
829         }
830         *v_filec = j;
831
832         free(flags);
833 }
834
835 /* ------------------------------------------------------------------------ */
836 boolean
837 find_files(name, v_filec, v_filev)
838         char           *name;
839         int            *v_filec;
840         char         ***v_filev;
841 {
842         struct string_pool sp;
843         char            newname[FILENAME_LENGTH];
844         int             len, n;
845         DIR            *dirp;
846     struct dirent  *dp;
847         struct stat     tmp_stbuf, arc_stbuf, fil_stbuf;
848
849         strcpy(newname, name);
850         len = strlen(name);
851         if (len > 0 && newname[len - 1] != '/')
852                 newname[len++] = '/';
853
854         dirp = opendir(name);
855         if (!dirp)
856                 return FALSE;
857
858         init_sp(&sp);
859
860         GETSTAT(temporary_name, &tmp_stbuf);
861         GETSTAT(archive_name, &arc_stbuf);
862
863         for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
864                 n = NAMLEN(dp);
865                 strncpy(newname + len, dp->d_name, n);
866                 newname[len + n] = '\0';
867                 if (GETSTAT(newname, &fil_stbuf) < 0)
868                         continue;
869 #if !defined(HAVE_STRUCT_STAT_ST_INO) || __MINGW32__
870                 if ( dp->d_name[0] != '.' ||
871                         (n != 1 &&
872                          (dp->d_name[1] != '.' ||
873                           n != 2))  ) {
874                         add_sp(&sp, newname, len+n+1);
875                 }
876 #else           
877                 if ((dp->d_ino != 0) &&
878                 /* exclude '.' and '..' */
879                     ((dp->d_name[0] != '.') ||
880                      ((n != 1) &&
881                       ((dp->d_name[1] != '.') ||
882                        (n != 2)))) &&
883                     ((tmp_stbuf.st_dev != fil_stbuf.st_dev ||
884                       tmp_stbuf.st_ino != fil_stbuf.st_ino) &&
885                      (arc_stbuf.st_dev != fil_stbuf.st_dev ||
886                       arc_stbuf.st_ino != fil_stbuf.st_ino))) {
887                         add_sp(&sp, newname, len + n + 1);
888                 }
889 #endif
890         }
891         closedir(dirp);
892         finish_sp(&sp, v_filec, v_filev);
893         if (*v_filec > 1)
894                 qsort(*v_filev, *v_filec, sizeof(char *), sort_by_ascii);
895         cleaning_files(v_filec, v_filev);
896
897         return TRUE;
898 }
899
900 /* ------------------------------------------------------------------------ */
901 void
902 free_files(filec, filev)
903         int             filec;
904         char          **filev;
905 {
906         free_sp(filev);
907 }
908
909 /* ------------------------------------------------------------------------ */
910 /*                                                                                                                                                      */
911 /* ------------------------------------------------------------------------ */
912 /* Build temporary file name and store to TEMPORARY_NAME */
913 int
914 build_temporary_name()
915 {
916 #ifdef TMP_FILENAME_TEMPLATE
917         /* "/tmp/lhXXXXXX" etc. */
918         if (extract_directory == NULL) {
919                 strcpy(temporary_name, TMP_FILENAME_TEMPLATE);
920         }
921         else {
922                 xsnprintf(temporary_name, sizeof(temporary_name),
923                   "%s/lhXXXXXX", extract_directory);
924         }
925 #else
926         char           *p, *s;
927
928         strcpy(temporary_name, archive_name);
929         for (p = temporary_name, s = (char *) 0; *p; p++)
930                 if (*p == '/')
931                         s = p;
932         strcpy((s ? s + 1 : temporary_name), "lhXXXXXX");
933 #endif
934 #ifdef HAVE_MKSTEMP
935     {
936         int old_umask, fd;
937
938         old_umask = umask(077);
939         fd = mkstemp(temporary_name);
940         umask(old_umask);
941         return fd;
942     }
943 #else
944     {
945         int flags;
946
947         mktemp(temporary_name);
948         flags = O_CREAT|O_EXCL|O_RDWR;
949 #ifdef O_BINARY
950         flags |= O_BINARY;
951 #endif
952         return open(temporary_name, flags, 0600);
953     }
954 #endif
955 }
956
957 /* ------------------------------------------------------------------------ */
958 static void
959 modify_filename_extention(buffer, ext)
960         char           *buffer;
961         char           *ext;
962 {
963         register char  *p, *dot;
964
965         for (p = buffer, dot = (char *) 0; *p; p++) {
966                 if (*p == '.')
967                         dot = p;
968                 else if (*p == '/')
969                         dot = (char *) 0;
970         }
971
972         if (dot)
973                 p = dot;
974
975         strcpy(p, ext);
976 }
977
978 /* ------------------------------------------------------------------------ */
979 /* build backup file name */
980 void
981 build_backup_name(buffer, original)
982         char           *buffer;
983         char           *original;
984 {
985         strcpy(buffer, original);
986         modify_filename_extention(buffer, BACKUPNAME_EXTENTION);        /* ".bak" */
987 }
988
989 /* ------------------------------------------------------------------------ */
990 void
991 build_standard_archive_name(buffer, orginal)
992         char           *buffer;
993         char           *orginal;
994 {
995         strcpy(buffer, orginal);
996         modify_filename_extention(buffer, ARCHIVENAME_EXTENTION);       /* ".lzh" */
997 }
998
999 /* ------------------------------------------------------------------------ */
1000 /*                                                                                                                                                      */
1001 /* ------------------------------------------------------------------------ */
1002 boolean
1003 need_file(name)
1004         char           *name;
1005 {
1006         int             i;
1007
1008         if (cmd_filec == 0)
1009                 return TRUE;
1010
1011         for (i = 0; i < cmd_filec; i++) {
1012                 if (patmatch(cmd_filev[i], name, 0))
1013                         return TRUE;
1014         }
1015
1016         return FALSE;
1017 }
1018
1019 FILE           *
1020 xfopen(name, mode)
1021         char           *name, *mode;
1022 {
1023         FILE           *fp;
1024
1025         if ((fp = fopen(name, mode)) == NULL)
1026                 fatal_error("Cannot open file \"%s\"", name);
1027
1028         return fp;
1029 }
1030
1031 /* ------------------------------------------------------------------------ */
1032 /*                                                                                                                                                      */
1033 /* ------------------------------------------------------------------------ */
1034 static          boolean
1035 open_old_archive_1(name, v_fp)
1036         char           *name;
1037         FILE          **v_fp;
1038 {
1039         FILE           *fp;
1040         struct stat     stbuf;
1041
1042         if (stat(name, &stbuf) >= 0 &&
1043             is_regularfile(&stbuf) &&
1044             (fp = fopen(name, READ_BINARY)) != NULL) {
1045                 *v_fp = fp;
1046                 archive_file_gid = stbuf.st_gid;
1047                 archive_file_mode = stbuf.st_mode;
1048                 return TRUE;
1049         }
1050
1051         *v_fp = NULL;
1052         archive_file_gid = -1;
1053         return FALSE;
1054 }
1055
1056 /* ------------------------------------------------------------------------ */
1057 FILE           *
1058 open_old_archive()
1059 {
1060         FILE           *fp;
1061         char           *p;
1062     static char expanded_archive_name[FILENAME_LENGTH];
1063
1064         if (!strcmp(archive_name, "-")) {
1065                 if (cmd == CMD_EXTRACT || cmd == CMD_LIST) {
1066 #if __MINGW32__
1067             setmode(fileno(stdin), O_BINARY);
1068 #endif
1069                         return stdin;
1070         }
1071                 else
1072                         return NULL;
1073         }
1074     p = strrchr(archive_name, '.');
1075         if (p) {
1076                 if (strucmp(".LZH", p) == 0
1077                     || strucmp(".LZS", p) == 0
1078                     || strucmp(".COM", p) == 0  /* DOS SFX */
1079                     || strucmp(".EXE", p) == 0
1080                     || strucmp(".X", p) == 0    /* HUMAN SFX */
1081                     || strucmp(".BAK", p) == 0) {       /* for BackUp */
1082                         open_old_archive_1(archive_name, &fp);
1083                         return fp;
1084                 }
1085         }
1086
1087         if (open_old_archive_1(archive_name, &fp))
1088                 return fp;
1089         xsnprintf(expanded_archive_name, sizeof(expanded_archive_name),
1090               "%s.lzh", archive_name);
1091         if (open_old_archive_1(expanded_archive_name, &fp)) {
1092                 archive_name = expanded_archive_name;
1093                 return fp;
1094         }
1095         /*
1096          * if ( (errno&0xffff)!=E_PNNF ) { archive_name =
1097          * expanded_archive_name; return NULL; }
1098          */
1099         xsnprintf(expanded_archive_name, sizeof(expanded_archive_name),
1100               "%s.lzs", archive_name);
1101         if (open_old_archive_1(expanded_archive_name, &fp)) {
1102                 archive_name = expanded_archive_name;
1103                 return fp;
1104         }
1105         /*
1106          * if ( (errno&0xffff)!=E_PNNF ) { archive_name =
1107          * expanded_archive_name; return NULL; }
1108          */
1109         /*
1110          * sprintf( expanded_archive_name , "%s.lzh",archive_name);
1111          * archive_name = expanded_archive_name;
1112          */
1113         return NULL;
1114 }
1115
1116 /* ------------------------------------------------------------------------ */
1117 int
1118 inquire(msg, name, selective)
1119         char           *msg, *name, *selective;
1120 {
1121         char            buffer[1024];
1122         char           *p;
1123
1124         for (;;) {
1125                 fprintf(stderr, "%s %s ", name, msg);
1126                 fflush(stderr);
1127
1128                 fgets(buffer, 1024, stdin);
1129
1130                 for (p = selective; *p; p++)
1131                         if (buffer[0] == *p)
1132                                 return p - selective;
1133         }
1134         /* NOTREACHED */
1135 }
1136
1137 /* ------------------------------------------------------------------------ */
1138 void
1139 write_archive_tail(nafp)
1140         FILE           *nafp;
1141 {
1142         putc(0x00, nafp);
1143 }
1144
1145 /* ------------------------------------------------------------------------ */
1146 void
1147 copy_old_one(oafp, nafp, hdr)
1148         FILE           *oafp, *nafp;
1149         LzHeader       *hdr;
1150 {
1151         if (noexec) {
1152                 fseek(oafp, (long) (hdr->header_size + 2) + hdr->packed_size, SEEK_CUR);
1153         }
1154         else {
1155                 reading_filename = archive_name;
1156                 writing_filename = temporary_name;
1157                 if (hdr->header_level != 2) {
1158                         copyfile(oafp, nafp,
1159                                          (long) (hdr->header_size + 2) + hdr->packed_size, 0);
1160                 } else {
1161                         copyfile(oafp, nafp,
1162                                          (long) (hdr->header_size) + hdr->packed_size, 0);
1163                 }
1164         }
1165 }
1166
1167 /* Local Variables: */
1168 /* mode:c */
1169 /* tab-width:4 */
1170 /* compile-command:"gcc -c lharc.c" */
1171 /* End: */
1172 /* vi: set tabstop=4: */