OSDN Git Service

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