OSDN Git Service

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