OSDN Git Service

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