OSDN Git Service

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