OSDN Git Service

untabify all sources.
[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, LZHUFF7_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("\"%s\" already exists (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("invalid path name \"%s\"", name);
94         return FALSE;   /* no more parent. */
95     }
96
97     if (GETSTAT(path, &stbuf) >= 0) {
98         if (is_directory(&stbuf))
99             return TRUE;
100     }
101
102     if (verbose)
103         message("Making directory \"%s\".", path);
104
105 #if defined __MINGW32__
106     if (mkdir(path) >= 0)
107         return TRUE;
108 #else
109     if (mkdir(path, 0777) >= 0) /* try */
110         return TRUE;    /* successful done. */
111 #endif
112
113     if (!make_parent_path(path))
114         return FALSE;
115
116 #if defined __MINGW32__
117     if (mkdir(path) < 0) {      /* try again */
118         error("Cannot make directory \"%s\"", path);
119         return FALSE;
120     }
121 #else
122     if (mkdir(path, 0777) < 0) {    /* try again */
123         error("Cannot make directory \"%s\"", path);
124         return FALSE;
125     }
126 #endif
127
128     return TRUE;
129 }
130
131 /* ------------------------------------------------------------------------ */
132 static FILE    *
133 open_with_make_path(name)
134     char           *name;
135 {
136     FILE           *fp;
137
138     if ((fp = fopen(name, WRITE_BINARY)) == NULL) {
139         if (!make_parent_path(name) ||
140             (fp = fopen(name, WRITE_BINARY)) == NULL)
141             error("Cannot extract a file \"%s\"", name);
142     }
143     return fp;
144 }
145
146 /* ------------------------------------------------------------------------ */
147 static void
148 adjust_info(name, hdr)
149     char           *name;
150     LzHeader       *hdr;
151 {
152     struct utimbuf utimebuf;
153
154     /* adjust file stamp */
155     utimebuf.actime = utimebuf.modtime = hdr->unix_last_modified_stamp;
156
157     if ((hdr->unix_mode & UNIX_FILE_TYPEMASK) != UNIX_FILE_SYMLINK)
158         utime(name, &utimebuf);
159
160     if (hdr->extend_type == EXTEND_UNIX
161         || hdr->extend_type == EXTEND_OS68K
162         || hdr->extend_type == EXTEND_XOSK) {
163 #ifdef NOT_COMPATIBLE_MODE
164         Please need your modification in this space.
165 #else
166         if ((hdr->unix_mode & UNIX_FILE_TYPEMASK) != UNIX_FILE_SYMLINK)
167             chmod(name, hdr->unix_mode);
168 #endif
169         if (!getuid()){
170             uid_t uid = hdr->unix_uid;
171             gid_t gid = hdr->unix_gid;
172
173 #if HAVE_GETPWNAM && HAVE_GETGRNAM
174             if (hdr->user[0]) {
175                 struct passwd *ent = getpwnam(hdr->user);
176                 if (ent) uid = ent->pw_uid;
177             }
178             if (hdr->group[0]) {
179                 struct group *ent = getgrnam(hdr->group);
180                 if (ent) gid = ent->gr_gid;
181             }
182 #endif
183
184 #if HAVE_LCHOWN
185             if ((hdr->unix_mode & UNIX_FILE_TYPEMASK) == UNIX_FILE_SYMLINK)
186                 lchown(name, uid, gid);
187             else
188 #endif /* HAVE_LCHWON */
189                 chown(name, uid, gid);
190         }
191     }
192 }
193
194 /* ------------------------------------------------------------------------ */
195 static void
196 extract_one(afp, hdr)
197     FILE           *afp;    /* archive file */
198     LzHeader       *hdr;
199 {
200     FILE           *fp; /* output file */
201     struct stat     stbuf;
202     char            name[FILENAME_LENGTH];
203     unsigned int crc;
204     int             method;
205     boolean         save_quiet, save_verbose, up_flag;
206     char           *q = hdr->name, c;
207
208     if (ignore_directory && strrchr(hdr->name, '/')) {
209         q = (char *) strrchr(hdr->name, '/') + 1;
210     }
211     else {
212         if (*q == '/') {
213             q++;
214             /*
215              * if OSK then strip device name
216              */
217             if (hdr->extend_type == EXTEND_OS68K
218                 || hdr->extend_type == EXTEND_XOSK) {
219                 do
220                     c = (*q++);
221                 while (c && c != '/');
222                 if (!c || !*q)
223                     q = ".";    /* if device name only */
224             }
225         }
226     }
227
228     if (extract_directory)
229         xsnprintf(name, sizeof(name), "%s/%s", extract_directory, q);
230     else
231         strcpy(name, q);
232
233
234     /* LZHDIRS_METHOD¤ò»ý¤Ä¥Ø¥Ã¥À¤ò¥Á¥§¥Ã¥¯¤¹¤ë */
235     /* 1999.4.30 t.okamoto */
236     for (method = 0;; method++) {
237         if (methods[method] == NULL) {
238             error("Unknown method \"%.*s\"; \"%s\" will be skiped ...",
239                   5, hdr->method, name);
240             return;
241         }
242         if (memcmp(hdr->method, methods[method], 5) == 0)
243             break;
244     }
245
246     if ((hdr->unix_mode & UNIX_FILE_TYPEMASK) == UNIX_FILE_REGULAR
247         && method != LZHDIRS_METHOD_NUM) {
248     extract_regular:
249 #if 0
250         for (method = 0;; method++) {
251             if (methods[method] == NULL) {
252                 error("Unknown method \"%.*s\"; \"%s\" will be skiped ...",
253                       5, hdr->method, name);
254                 return;
255             }
256             if (memcmp(hdr->method, methods[method], 5) == 0)
257                 break;
258         }
259 #endif
260
261         reading_filename = archive_name;
262         writing_filename = name;
263         if (output_to_stdout || verify_mode) {
264             if (noexec) {
265                 printf("%s %s\n", verify_mode ? "VERIFY" : "EXTRACT", name);
266                 if (afp == stdin) {
267                     int             i = hdr->packed_size;
268                     while (i--)
269                         fgetc(afp);
270                 }
271                 return;
272             }
273
274             save_quiet = quiet;
275             save_verbose = verbose;
276             if (!quiet && output_to_stdout) {
277                 printf("::::::::\n%s\n::::::::\n", name);
278                 quiet = TRUE;
279                 verbose = FALSE;
280             }
281             else if (verify_mode) {
282                 quiet = FALSE;
283                 verbose = TRUE;
284             }
285
286 #if __MINGW32__
287             {
288                 int old_mode;
289                 fflush(stdout);
290                 old_mode = setmode(fileno(stdout), O_BINARY);
291 #endif
292
293             crc = decode_lzhuf
294                 (afp, stdout, hdr->original_size, hdr->packed_size, name, method);
295 #if __MINGW32__
296                 fflush(stdout);
297                 setmode(fileno(stdout), old_mode);
298             }
299 #endif
300             quiet = save_quiet;
301             verbose = save_verbose;
302         }
303         else {
304             if (skip_flg == FALSE)  {
305                 up_flag = inquire_extract(name);
306                 if (up_flag == FALSE && force == FALSE) {
307                     return;
308                 }
309             }
310
311             if (skip_flg == TRUE) { /* if skip_flg */
312                 if (stat(name, &stbuf) == 0 && force != TRUE) {
313                     if (stbuf.st_mtime >= hdr->unix_last_modified_stamp) {
314                         if (quiet != TRUE)
315                             printf("%s : Skipped...\n", name);
316                         return;
317                     }
318                 }
319             }
320             if (noexec) {
321                 if (afp == stdin) {
322                     int i = hdr->packed_size;
323                     while (i--)
324                         fgetc(afp);
325                 }
326                 return;
327             }
328
329             signal(SIGINT, interrupt);
330 #ifdef SIGHUP
331             signal(SIGHUP, interrupt);
332 #endif
333
334             unlink(name);
335             remove_extracting_file_when_interrupt = TRUE;
336
337             if ((fp = open_with_make_path(name)) != NULL) {
338                 crc = decode_lzhuf
339                     (afp, fp, hdr->original_size, hdr->packed_size, name, method);
340                 fclose(fp);
341             }
342             remove_extracting_file_when_interrupt = FALSE;
343             signal(SIGINT, SIG_DFL);
344 #ifdef SIGHUP
345             signal(SIGHUP, SIG_DFL);
346 #endif
347             if (!fp)
348                 return;
349         }
350
351         if (hdr->has_crc && crc != hdr->crc)
352             error("CRC error: \"%s\"", name);
353     }
354     else if ((hdr->unix_mode & UNIX_FILE_TYPEMASK) == UNIX_FILE_DIRECTORY
355              || (hdr->unix_mode & UNIX_FILE_TYPEMASK) == UNIX_FILE_SYMLINK
356              || method == LZHDIRS_METHOD_NUM) {
357         /* ¢¬¤³¤ì¤Ç¡¢Symbolic Link ¤Ï¡¢Âç¾æÉפ«¡© */
358         if (!ignore_directory && !verify_mode) {
359             if (noexec) {
360                 if (quiet != TRUE)
361                     printf("EXTRACT %s (directory)\n", name);
362                 return;
363             }
364             /* NAME has trailing SLASH '/', (^_^) */
365             if ((hdr->unix_mode & UNIX_FILE_TYPEMASK) == UNIX_FILE_SYMLINK) {
366                 int             l_code;
367
368 #ifdef S_IFLNK
369                 if (skip_flg == FALSE)  {
370                     up_flag = inquire_extract(name);
371                     if (up_flag == FALSE && force == FALSE) {
372                         return;
373                     }
374                 } else {
375                     if (GETSTAT(name, &stbuf) == 0 && force != TRUE) {
376                         if (stbuf.st_mtime >= hdr->unix_last_modified_stamp) {
377                             if (quiet != TRUE)
378                                 printf("%s : Skipped...\n", name);
379                             return;
380                         }
381                     }
382                 }
383
384                 unlink(name);
385                 make_parent_path(name);
386                 l_code = symlink(hdr->realname, name);
387                 if (l_code < 0) {
388                     if (quiet != TRUE)
389                         warning("Can't make Symbolic Link \"%s\" -> \"%s\"",
390                                 hdr->realname, name);
391                 }
392                 if (quiet != TRUE) {
393                     message("Symbolic Link %s -> %s",
394                             hdr->realname, name);
395                 }
396 #else
397                 warning("Can't make Symbolic Link %s -> %s",
398                         hdr->realname, name);
399                 return;
400 #endif
401             } else { /* make directory */
402                 if (!output_to_stdout && !make_parent_path(name))
403                     return;
404             }
405         }
406     }
407     else {
408         if (force)              /* force extract */
409             goto extract_regular;
410         else
411             error("Unknown file type: \"%s\". use `f' option to force extract.", name);
412     }
413
414     if (!output_to_stdout)
415         adjust_info(name, hdr);
416 }
417
418 /* ------------------------------------------------------------------------ */
419 /* EXTRACT COMMAND MAIN                                                     */
420 /* ------------------------------------------------------------------------ */
421 void
422 cmd_extract()
423 {
424     LzHeader        hdr;
425     long            pos;
426     FILE           *afp;
427
428     /* open archive file */
429     if ((afp = open_old_archive()) == NULL)
430         fatal_error("Cannot open archive file \"%s\"", archive_name);
431
432     if (archive_is_msdos_sfx1(archive_name))
433         skip_msdos_sfx1_code(afp);
434
435     /* extract each files */
436     while (get_header(afp, &hdr)) {
437         if (need_file(hdr.name)) {
438             pos = ftell(afp);
439             extract_one(afp, &hdr);
440             /* when error occurred in extract_one(), should adjust
441                point of file stream */
442             if (afp != stdin)
443                 fseek(afp, pos + hdr.packed_size, SEEK_SET);
444             else {
445                 /* FIXME: assume that the extract_one() has read
446                    packed_size bytes from stdin. */
447                 long i = 0;
448                 while (i--) fgetc(afp);
449             }
450         } else {
451             if (afp != stdin)
452                 fseek(afp, hdr.packed_size, SEEK_CUR);
453             else {
454                 int             i = hdr.packed_size;
455                 while (i--)
456                     fgetc(afp);
457             }
458         }
459     }
460
461     /* close archive file */
462     fclose(afp);
463
464     return;
465 }