OSDN Git Service

* src/lhext.c (adjust_info): mismatched braces.
[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             uid_t uid = hdr->unix_uid;
176             gid_t gid = hdr->unix_gid;
177
178 #if HAVE_GETPWNAM && HAVE_GETGRNAM
179             if (hdr->user[0]) {
180                 struct passwd *ent = getpwnam(hdr->user);
181                 if (ent) uid = ent->pw_uid;
182             }
183             if (hdr->group[0]) {
184                 struct group *ent = getgrnam(hdr->group);
185                 if (ent) gid = ent->gr_gid;
186             }
187 #endif
188
189 #if HAVE_LCHOWN
190                         if ((hdr->unix_mode & UNIX_FILE_TYPEMASK) == UNIX_FILE_SYMLINK)
191                                 lchown(name, uid, gid);
192                         else
193 #endif /* HAVE_LCHWON */
194                                 chown(name, uid, gid);
195                 }
196                 errno = 0;
197         }
198 }
199
200 /* ------------------------------------------------------------------------ */
201 static void
202 extract_one(afp, hdr)
203         FILE           *afp;    /* archive file */
204         LzHeader       *hdr;
205 {
206         FILE           *fp;     /* output file */
207         struct stat     stbuf;
208         char            name[257];
209         int             crc;
210         int             method;
211         boolean         save_quiet, save_verbose, up_flag;
212         char           *q = hdr->name, c;
213
214         if (ignore_directory && strrchr(hdr->name, '/')) {
215                 q = (char *) strrchr(hdr->name, '/') + 1;
216         }
217         else {
218                 if (*q == '/') {
219                         q++;
220                         /*
221                          * if OSK then strip device name
222                          */
223                         if (hdr->extend_type == EXTEND_OS68K
224                             || hdr->extend_type == EXTEND_XOSK) {
225                                 do
226                                         c = (*q++);
227                                 while (c && c != '/');
228                                 if (!c || !*q)
229                                         q = ".";        /* if device name only */
230                         }
231                 }
232         }
233
234         if (extract_directory)
235                 sprintf(name, "%s/%s", extract_directory, q);
236         else
237                 strcpy(name, q);
238
239
240         /* LZHDIRS_METHOD¤ò»ý¤Ä¥Ø¥Ã¥À¤ò¥Á¥§¥Ã¥¯¤¹¤ë */
241         /* 1999.4.30 t.okamoto */
242         for (method = 0;; method++) {
243                 if (methods[method] == NULL) {
244                         error("Unknown method skiped ...", name);
245                         return;
246                 }
247                 if (bcmp(hdr->method, methods[method], 5) == 0)
248                         break;
249         }
250
251         if ((hdr->unix_mode & UNIX_FILE_TYPEMASK) == UNIX_FILE_REGULAR
252                 && method != LZHDIRS_METHOD_NUM) {
253 #if 0
254                 for (method = 0;; method++) {
255                         if (methods[method] == NULL) {
256                                 error("Unknown method skiped ...", name);
257                                 return;
258                         }
259                         if (bcmp(hdr->method, methods[method], 5) == 0)
260                                 break;
261                 }
262 #endif
263
264                 reading_filename = archive_name;
265                 writting_filename = name;
266                 if (output_to_stdout || verify_mode) {
267                         if (noexec) {
268                                 printf("%s %s\n", verify_mode ? "VERIFY" : "EXTRACT", name);
269                                 if (afp == stdin) {
270                                         int             i = hdr->packed_size;
271                                         while (i--)
272                                                 fgetc(afp);
273                                 }
274                                 return;
275                         }
276
277                         save_quiet = quiet;
278                         save_verbose = verbose;
279                         if (!quiet && output_to_stdout) {
280                                 printf("::::::::\n%s\n::::::::\n", name);
281                                 quiet = TRUE;
282                                 verbose = FALSE;
283                         }
284                         else if (verify_mode) {
285                                 quiet = FALSE;
286                                 verbose = TRUE;
287                         }
288
289 #if __MINGW32__
290             {
291                 int old_mode;
292                 fflush(stdout);
293                 old_mode = setmode(fileno(stdout), O_BINARY);
294 #endif
295
296                         crc = decode_lzhuf
297                                 (afp, stdout, hdr->original_size, hdr->packed_size, name, method);
298 #if __MINGW32__
299                 fflush(stdout);
300                 setmode(fileno(stdout), old_mode);
301             }
302 #endif
303                         quiet = save_quiet;
304                         verbose = save_verbose;
305                 }
306                 else {
307                         if (skip_flg == FALSE)  {
308                                 up_flag = inquire_extract(name);
309                                 if (up_flag == FALSE && force == FALSE) {
310                                         return;
311                                 }
312                         }
313
314                         if (skip_flg == TRUE) { /* if skip_flg */
315                                 if (stat(name, &stbuf) == 0 && force != TRUE) {
316                                         if (stbuf.st_mtime >= hdr->unix_last_modified_stamp) {
317                                                 if (quiet != TRUE)
318                                                         printf("%s : Skipped...\n", name);
319                                                 return;
320                                         }
321                                 }
322                         }
323                         if (noexec) {
324                                 if (afp == stdin) {
325                                         int i = hdr->packed_size;
326                                         while (i--)
327                                                 fgetc(afp);
328                                 }
329                                 return;
330                         }
331
332                         signal(SIGINT, interrupt);
333 #ifdef SIGHUP
334                         signal(SIGHUP, interrupt);
335 #endif
336
337                         unlink(name);
338                         errno = 0;
339                         remove_extracting_file_when_interrupt = TRUE;
340
341                         if ((fp = open_with_make_path(name)) != NULL) {
342                                 crc = decode_lzhuf
343                                         (afp, fp, hdr->original_size, hdr->packed_size, name, method);
344                                 fclose(fp);
345                         }
346                         remove_extracting_file_when_interrupt = FALSE;
347                         signal(SIGINT, SIG_DFL);
348 #ifdef SIGHUP
349                         signal(SIGHUP, SIG_DFL);
350 #endif
351                         if (!fp)
352                                 return;
353                 }
354
355                 errno = 0;
356                 if (hdr->has_crc && crc != hdr->crc)
357                         error("CRC error", name);
358         }
359         else if ((hdr->unix_mode & UNIX_FILE_TYPEMASK) == UNIX_FILE_DIRECTORY
360                          || (hdr->unix_mode & UNIX_FILE_TYPEMASK) == UNIX_FILE_SYMLINK
361                          || method == LZHDIRS_METHOD_NUM) {
362                 /* ¢¬¤³¤ì¤Ç¡¢Symblic Link ¤Ï¡¢Âç¾æÉפ«¡© */
363                 if (!ignore_directory && !verify_mode) {
364                         if (noexec) {
365                                 if (quiet != TRUE)
366                                         printf("EXTRACT %s (directory)\n", name);
367                                 return;
368                         }
369                         /* NAME has trailing SLASH '/', (^_^) */
370                         if ((hdr->unix_mode & UNIX_FILE_TYPEMASK) == UNIX_FILE_SYMLINK) {
371                                 char            buf[256], *bb1, *bb2;
372                                 int             l_code;
373                                 strcpy(buf, name);
374                                 bb1 = strtok(buf, "|");
375                                 bb2 = strtok(NULL, "|");
376
377 #ifdef S_IFLNK
378                                 if (skip_flg == FALSE)  {
379                                         up_flag = inquire_extract(name);
380                                         if (up_flag == FALSE && force == FALSE) {
381                                                 return;
382                                         }
383                                 } else {
384                                         if (GETSTAT(bb1, &stbuf) == 0 && force != TRUE) {
385                                                 if (stbuf.st_mtime >= hdr->unix_last_modified_stamp) {
386                                                         if (quiet != TRUE)
387                                                                 printf("%s : Skipped...\n", bb1);
388                                                         return;
389                                                 }
390                                         }
391                                 }
392
393                                 unlink(bb1);
394                                 l_code = symlink(bb2, bb1);
395                                 if (l_code < 0) {
396                                         if (quiet != TRUE)
397                                                 warning("Can't make Symbolic Link : ");
398                                 }
399                                 if (quiet != TRUE) {
400                                         printf("Symbolic Link %s -> %s\n", bb1, bb2);
401                                 }
402                                 strcpy(name, bb1);      /* Symbolic's name set */
403 #else
404                                 sprintf(buf, "%s -> %s", bb1, bb2);
405                                 warning("Can't make Symbolic Link", buf);
406                                 return;
407 #endif
408                         } else { /* make directory */
409                                 if (!output_to_stdout && !make_parent_path(name))
410                                         return;
411                         }
412                 }
413         }
414         else {
415                 error("Unknown information", name);
416         }
417
418         if (!output_to_stdout)
419                 adjust_info(name, hdr);
420 }
421
422 /* ------------------------------------------------------------------------ */
423 /* EXTRACT COMMAND MAIN                                                                                                         */
424 /* ------------------------------------------------------------------------ */
425 void
426 cmd_extract()
427 {
428         LzHeader        hdr;
429         long            pos;
430         FILE           *afp;
431
432         /* open archive file */
433         if ((afp = open_old_archive()) == NULL)
434                 fatal_error(archive_name);
435
436         if (archive_is_msdos_sfx1(archive_name))
437                 skip_msdos_sfx1_code(afp);
438
439         /* extract each files */
440         while (get_header(afp, &hdr)) {
441                 if (need_file(hdr.name)) {
442                         pos = ftell(afp);
443                         extract_one(afp, &hdr);
444 #if 0 /* On MinGW, if afp == stdin, fseek() will succeed.
445          but next getc(afp) return EOF */
446                         fseek(afp, pos + hdr.packed_size, SEEK_SET);
447 #endif
448                 } else {
449                         if (afp != stdin)
450                                 fseek(afp, hdr.packed_size, SEEK_CUR);
451                         else {
452                                 int             i = hdr.packed_size;
453                                 while (i--)
454                                         fgetc(afp);
455                         }
456                 }
457         }
458
459         /* close archive file */
460         fclose(afp);
461
462         return;
463 }
464
465 /* Local Variables: */
466 /* mode:c */
467 /* tab-width:4 */
468 /* End: */
469 /* vi: set tabstop=4: */