OSDN Git Service

use the autoconf/automake
[lha/lha.git] / src / lhext.c
1 /* ------------------------------------------------------------------------ */
2 /* LHa for UNIX                                                                                                                         */
3 /*                              lhext.c -- LHarc extract                                                                        */
4 /*                                                                                                                                                      */
5 /*              Copyright (C) MCMLXXXIX Yooichi.Tagawa                                                          */
6 /*              Modified                        Nobutaka Watazaki                                                       */
7 /*                                                                                                                                                      */
8 /*  Ver. 0.00  Original                                                         1988.05.23  Y.Tagawa    */
9 /*  Ver. 1.00  Fixed                                                            1989.09.22  Y.Tagawa    */
10 /*  Ver. 0.03  LHa for UNIX                                                     1991.12.17  M.Oki               */
11 /*  Ver. 1.12  LHa for UNIX                                                     1993.10.01      N.Watazaki      */
12 /*  Ver. 1.13b Symbolic Link Update Bug Fix                     1994.06.21      N.Watazaki      */
13 /*      Ver. 1.14  Source All chagned                                   1995.01.14      N.Watazaki      */
14 /*  Ver. 1.14e bugfix                               1999.04.30  T.Okamoto   */
15 /* ------------------------------------------------------------------------ */
16 #include "lha.h"
17 /* ------------------------------------------------------------------------ */
18 static int      skip_flg = FALSE;       /* FALSE..No Skip , TRUE..Skip */
19 static char        *methods[] =
20 {
21         LZHUFF0_METHOD, LZHUFF1_METHOD, LZHUFF2_METHOD, LZHUFF3_METHOD,
22         LZHUFF4_METHOD, LZHUFF5_METHOD, LZHUFF6_METHOD,
23         LARC_METHOD, LARC5_METHOD, LARC4_METHOD,
24         LZHDIRS_METHOD,
25         NULL
26 };
27
28 /* ------------------------------------------------------------------------ */
29 static          boolean
30 inquire_extract(name)
31         char           *name;
32 {
33         struct stat     stbuf;
34
35         skip_flg = FALSE;
36         if (stat(name, &stbuf) >= 0) {
37                 if (!is_regularfile(&stbuf)) {
38                         error("Already exist (not a file)", name);
39                         return FALSE;
40                 }
41
42                 if (noexec) {
43                         printf("EXTRACT %s but file is exist.\n", name);
44                         return FALSE;
45                 }
46                 else if (!force) {
47                         if (!isatty(0))
48                                 return FALSE;
49
50                         switch (inquire("OverWrite ?(Yes/[No]/All/Skip)", name, "YyNnAaSs\n")) {
51                         case 0:
52                         case 1:/* Y/y */
53                                 break;
54                         case 2:
55                         case 3:/* N/n */
56                         case 8:/* Return */
57                                 return FALSE;
58                         case 4:
59                         case 5:/* A/a */
60                                 force = TRUE;
61                                 break;
62                         case 6:
63                         case 7:/* S/s */
64                                 skip_flg = TRUE;
65                                 break;
66                         }
67                 }
68         }
69         if (noexec)
70                 printf("EXTRACT %s\n", name);
71
72         return TRUE;
73 }
74
75 /* ------------------------------------------------------------------------ */
76 static          boolean
77 make_parent_path(name)
78         char           *name;
79 {
80         char            path[FILENAME_LENGTH];
81         struct stat     stbuf;
82         register char  *p;
83
84         /* make parent directory name into PATH for recursive call */
85         strcpy(path, name);
86         for (p = path + strlen(path); p > path; p--)
87                 if (p[-1] == '/') {
88                         *--p = '\0';
89                         break;
90                 }
91
92         if (p == path) {
93                 message("Why?", "ROOT");
94                 return FALSE;   /* no more parent. */
95         }
96
97         if (GETSTAT(path, &stbuf) >= 0) {
98                 if (is_directory(&stbuf))
99                         return TRUE;
100                 error("Not a directory", path);
101                 return FALSE;
102         }
103         errno = 0;
104
105         if (verbose)
106                 printf("Making directory \"%s\".\n", path);
107
108         if (mkdir(path, 0777) >= 0)     /* try */
109                 return TRUE;    /* successful done. */
110         errno = 0;
111
112         if (!make_parent_path(path))
113                 return FALSE;
114
115         if (mkdir(path, 0777) < 0) {    /* try again */
116                 message("Cannot make directory", path);
117                 return FALSE;
118         }
119
120         return TRUE;
121 }
122
123 /* ------------------------------------------------------------------------ */
124 static FILE    *
125 open_with_make_path(name)
126         char           *name;
127 {
128         FILE           *fp;
129
130         if ((fp = fopen(name, WRITE_BINARY)) == NULL) {
131                 errno = 0;
132                 if (!make_parent_path(name) ||
133                     (fp = fopen(name, WRITE_BINARY)) == NULL)
134                         error("Cannot extract", name);
135                 errno = 0;
136         }
137         return fp;
138 }
139
140 /* ------------------------------------------------------------------------ */
141 static void
142 adjust_info(name, hdr)
143         char           *name;
144         LzHeader       *hdr;
145 {
146         time_t          utimebuf[2];
147
148         /* adjust file stamp */
149         utimebuf[0] = utimebuf[1] = hdr->unix_last_modified_stamp;
150
151         if ((hdr->unix_mode & UNIX_FILE_TYPEMASK) != UNIX_FILE_SYMLINK)
152                 utime(name, utimebuf);
153
154         if (hdr->extend_type == EXTEND_UNIX
155             || hdr->extend_type == EXTEND_OS68K
156             || hdr->extend_type == EXTEND_XOSK) {
157 #ifdef NOT_COMPATIBLE_MODE
158                 Please need your modification in this space.
159 #else
160                 if ((hdr->unix_mode & UNIX_FILE_TYPEMASK) != UNIX_FILE_SYMLINK)
161                         chmod(name, hdr->unix_mode);
162 #endif
163                 if (!getuid()){
164 #if HAVE_LCHOWN
165                         if ((hdr->unix_mode & UNIX_FILE_TYPEMASK) == UNIX_FILE_SYMLINK)
166                                 lchown(name, hdr->unix_uid, hdr->unix_gid);
167                         else 
168 #endif
169                                 chown(name, hdr->unix_uid, hdr->unix_gid);
170                 }
171                 errno = 0;
172         }
173 }
174
175 /* ------------------------------------------------------------------------ */
176 static void
177 extract_one(afp, hdr)
178         FILE           *afp;    /* archive file */
179         LzHeader       *hdr;
180 {
181         FILE           *fp;     /* output file */
182         struct stat     stbuf;
183         char            name[257];
184         int             crc;
185         int             method;
186         boolean         save_quiet, save_verbose, up_flag;
187         char           *q = hdr->name, c;
188
189         if (ignore_directory && strrchr(hdr->name, '/')) {
190                 q = (char *) strrchr(hdr->name, '/') + 1;
191         }
192         else {
193                 if (*q == '/') {
194                         q++;
195                         /*
196                          * if OSK then strip device name
197                          */
198                         if (hdr->extend_type == EXTEND_OS68K
199                             || hdr->extend_type == EXTEND_XOSK) {
200                                 do
201                                         c = (*q++);
202                                 while (c && c != '/');
203                                 if (!c || !*q)
204                                         q = ".";        /* if device name only */
205                         }
206                 }
207         }
208
209         if (extract_directory)
210                 sprintf(name, "%s/%s", extract_directory, q);
211         else
212                 strcpy(name, q);
213
214
215         /* LZHDIRS_METHOD¤ò»ý¤Ä¥Ø¥Ã¥À¤ò¥Á¥§¥Ã¥¯¤¹¤ë */
216         /* 1999.4.30 t.okamoto */
217         for (method = 0;; method++) {
218                 if (methods[method] == NULL) {
219                         error("Unknown method skiped ...", name);
220                         return;
221                 }
222                 if (bcmp(hdr->method, methods[method], 5) == 0)
223                         break;
224         }
225
226         if ((hdr->unix_mode & UNIX_FILE_TYPEMASK) == UNIX_FILE_REGULAR
227                 && method != LZHDIRS_METHOD_NUM) {
228 #if 0
229                 for (method = 0;; method++) {
230                         if (methods[method] == NULL) {
231                                 error("Unknown method skiped ...", name);
232                                 return;
233                         }
234                         if (bcmp(hdr->method, methods[method], 5) == 0)
235                                 break;
236                 }
237 #endif
238
239                 reading_filename = archive_name;
240                 writting_filename = name;
241                 if (output_to_stdout || verify_mode) {
242                         if (noexec) {
243                                 printf("%s %s\n", verify_mode ? "VERIFY" : "EXTRACT", name);
244                                 if (afp == stdin) {
245                                         int             i = hdr->packed_size;
246                                         while (i--)
247                                                 fgetc(afp);
248                                 }
249                                 return;
250                         }
251
252                         save_quiet = quiet;
253                         save_verbose = verbose;
254                         if (!quiet && output_to_stdout) {
255                                 printf("::::::::\n%s\n::::::::\n", name);
256                                 quiet = TRUE;
257                                 verbose = FALSE;
258                         }
259                         else if (verify_mode) {
260                                 quiet = FALSE;
261                                 verbose = TRUE;
262                         }
263
264                         crc = decode_lzhuf
265                                 (afp, stdout, hdr->original_size, hdr->packed_size, name, method);
266                         quiet = save_quiet;
267                         verbose = save_verbose;
268                 }
269                 else {
270                         if (skip_flg == FALSE)  {
271                                 up_flag = inquire_extract(name);
272                                 if (up_flag == FALSE && force == FALSE) {
273                                         return;
274                                 }
275                         }
276
277                         if (skip_flg == TRUE) { /* if skip_flg */
278                                 if (stat(name, &stbuf) == 0 && force != TRUE) {
279                                         if (stbuf.st_mtime >= hdr->unix_last_modified_stamp) {
280                                                 if (quiet != TRUE)
281                                                         printf("%s : Skipped...\n", name);
282                                                 return;
283                                         }
284                                 }
285                         }
286                         if (noexec) {
287                                 if (afp == stdin) {
288                                         int i = hdr->packed_size;
289                                         while (i--)
290                                                 fgetc(afp);
291                                 }
292                                 return;
293                         }
294
295                         signal(SIGINT, interrupt);
296                         signal(SIGHUP, interrupt);
297
298                         unlink(name);
299                         errno = 0;
300                         remove_extracting_file_when_interrupt = TRUE;
301
302                         if ((fp = open_with_make_path(name)) != NULL) {
303                                 crc = decode_lzhuf
304                                         (afp, fp, hdr->original_size, hdr->packed_size, name, method);
305                                 fclose(fp);
306                         }
307                         remove_extracting_file_when_interrupt = FALSE;
308                         signal(SIGINT, SIG_DFL);
309                         signal(SIGHUP, SIG_DFL);
310
311                         if (!fp)
312                                 return;
313                 }
314
315                 errno = 0;
316                 if (hdr->has_crc && crc != hdr->crc)
317                         error("CRC error", name);
318         }
319         else if ((hdr->unix_mode & UNIX_FILE_TYPEMASK) == UNIX_FILE_DIRECTORY
320                          || (hdr->unix_mode & UNIX_FILE_TYPEMASK) == UNIX_FILE_SYMLINK
321                          || method == LZHDIRS_METHOD_NUM) {
322                 /* ¢¬¤³¤ì¤Ç¡¢Symblic Link ¤Ï¡¢Âç¾æÉפ«¡© */
323                 if (!ignore_directory && !verify_mode) {
324                         if (noexec) {
325                                 if (quiet != TRUE)
326                                         printf("EXTRACT %s (directory)\n", name);
327                                 return;
328                         }
329                         /* NAME has trailing SLASH '/', (^_^) */
330                         if ((hdr->unix_mode & UNIX_FILE_TYPEMASK) == UNIX_FILE_SYMLINK) {
331                                 char            buf[256], *bb1, *bb2;
332                                 int             l_code;
333                                 strcpy(buf, name);
334                                 bb1 = strtok(buf, "|");
335                                 bb2 = strtok(NULL, "|");
336
337 #ifdef S_IFLNK
338                                 if (skip_flg == FALSE)  {
339                                         up_flag = inquire_extract(name);
340                                         if (up_flag == FALSE && force == FALSE) {
341                                                 return;
342                                         }
343                                 } else {
344                                         if (GETSTAT(bb1, &stbuf) == 0 && force != TRUE) {
345                                                 if (stbuf.st_mtime >= hdr->unix_last_modified_stamp) {
346                                                         if (quiet != TRUE)
347                                                                 printf("%s : Skipped...\n", bb1);
348                                                         return;
349                                                 }
350                                         }
351                                 }
352
353                                 unlink(bb1);
354                                 l_code = symlink(bb2, bb1);
355                                 if (l_code < 0) {
356                                         if (quiet != TRUE)
357                                                 warning("Can't make Symbolic Link : ");
358                                 }
359                                 if (quiet != TRUE) {
360                                         printf("Symbolic Link %s -> %s\n", bb1, bb2);
361                                 }
362                                 strcpy(name, bb1);      /* Symbolic's name set */
363 #else
364                                 sprintf(buf, "%s -> %s", bb1, bb2);
365                                 warning("Can't make Symbolic Link", buf);
366                                 return;
367 #endif
368                         } else { /* make directory */
369                                 if (!output_to_stdout && !make_parent_path(name))
370                                         return;
371                         }
372                 }
373         }
374         else {
375                 error("Unknown information", name);
376         }
377
378         if (!output_to_stdout)
379                 adjust_info(name, hdr);
380 }
381
382 /* ------------------------------------------------------------------------ */
383 /* EXTRACT COMMAND MAIN                                                                                                         */
384 /* ------------------------------------------------------------------------ */
385 void
386 cmd_extract()
387 {
388         LzHeader        hdr;
389         long            pos;
390         FILE           *afp;
391
392         /* open archive file */
393         if ((afp = open_old_archive()) == NULL)
394                 fatal_error(archive_name);
395
396         if (archive_is_msdos_sfx1(archive_name))
397                 skip_msdos_sfx1_code(afp);
398
399         /* extract each files */
400         while (get_header(afp, &hdr)) {
401                 if (need_file(hdr.name)) {
402                         pos = ftell(afp);
403                         extract_one(afp, &hdr);
404                         fseek(afp, pos + hdr.packed_size, SEEK_SET);
405                 }
406                 else {
407                         if (afp != stdin)
408                                 fseek(afp, hdr.packed_size, SEEK_CUR);
409                         else {
410                                 int             i = hdr.packed_size;
411                                 while (i--)
412                                         fgetc(afp);
413                         }
414                 }
415         }
416
417         /* close archive file */
418         fclose(afp);
419
420         return;
421 }
422 /* Local Variables: */
423 /* tab-width : 4 */
424 /* End: */