OSDN Git Service

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