1 /* ------------------------------------------------------------------------ */
3 /* lhext.c -- LHarc extract */
5 /* Copyright (C) MCMLXXXIX Yooichi.Tagawa */
6 /* Modified Nobutaka Watazaki */
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 /* ------------------------------------------------------------------------ */
17 /* ------------------------------------------------------------------------ */
18 static int skip_flg = FALSE; /* FALSE..No Skip , TRUE..Skip */
19 static char *methods[] =
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,
28 static void add_dirinfo(char* name, LzHeader* hdr);
29 static void adjust_dirinfo();
31 /* ------------------------------------------------------------------------ */
39 if (stat(name, &stbuf) >= 0) {
40 if (!is_regularfile(&stbuf)) {
41 error("\"%s\" already exists (not a file)", name);
46 printf("EXTRACT %s but file is exist.\n", name);
51 warning("skip to extract %s.", name);
55 switch (inquire("OverWrite ?(Yes/[No]/All/Skip)", name, "YyNnAaSs\n")) {
76 printf("EXTRACT %s\n", name);
81 /* ------------------------------------------------------------------------ */
83 make_parent_path(name)
86 char path[FILENAME_LENGTH];
90 /* make parent directory name into PATH for recursive call */
92 for (p = path + strlen(path); p > path; p--)
99 message("invalid path name \"%s\"", name);
100 return FALSE; /* no more parent. */
103 if (GETSTAT(path, &stbuf) >= 0) {
104 if (is_directory(&stbuf))
109 message("Making directory \"%s\".", path);
111 #if defined __MINGW32__
112 if (mkdir(path) >= 0)
115 if (mkdir(path, 0777) >= 0) /* try */
116 return TRUE; /* successful done. */
119 if (!make_parent_path(path))
122 #if defined __MINGW32__
123 if (mkdir(path) < 0) { /* try again */
124 error("Cannot make directory \"%s\"", path);
128 if (mkdir(path, 0777) < 0) { /* try again */
129 error("Cannot make directory \"%s\"", path);
137 /* ------------------------------------------------------------------------ */
139 open_with_make_path(name)
144 if ((fp = fopen(name, WRITE_BINARY)) == NULL) {
145 if (!make_parent_path(name) ||
146 (fp = fopen(name, WRITE_BINARY)) == NULL)
147 error("Cannot extract a file \"%s\"", name);
152 /* ------------------------------------------------------------------------ */
154 adjust_info(name, hdr)
158 struct utimbuf utimebuf;
160 /* adjust file stamp */
161 utimebuf.actime = utimebuf.modtime = hdr->unix_last_modified_stamp;
163 if ((hdr->unix_mode & UNIX_FILE_TYPEMASK) != UNIX_FILE_SYMLINK)
164 utime(name, &utimebuf);
166 if (hdr->extend_type == EXTEND_UNIX
167 || hdr->extend_type == EXTEND_OS68K
168 || hdr->extend_type == EXTEND_XOSK) {
169 #ifdef NOT_COMPATIBLE_MODE
170 Please need your modification in this space.
172 if ((hdr->unix_mode & UNIX_FILE_TYPEMASK) != UNIX_FILE_SYMLINK)
173 chmod(name, hdr->unix_mode);
176 uid_t uid = hdr->unix_uid;
177 gid_t gid = hdr->unix_gid;
179 #if HAVE_GETPWNAM && HAVE_GETGRNAM
181 struct passwd *ent = getpwnam(hdr->user);
182 if (ent) uid = ent->pw_uid;
185 struct group *ent = getgrnam(hdr->group);
186 if (ent) gid = ent->gr_gid;
191 if ((hdr->unix_mode & UNIX_FILE_TYPEMASK) == UNIX_FILE_SYMLINK)
192 lchown(name, uid, gid);
194 #endif /* HAVE_LCHWON */
195 chown(name, uid, gid);
200 /* On Cygwin, execute permission should be set for .exe or .dll. */
203 umask(m = umask(0)); /* get current umask */
204 chmod(name, 0777 & ~m);
209 /* ------------------------------------------------------------------------ */
211 extract_one(afp, hdr)
212 FILE *afp; /* archive file */
215 FILE *fp; /* output file */
217 char name[FILENAME_LENGTH];
220 boolean save_quiet, save_verbose, up_flag;
221 char *q = hdr->name, c;
222 size_t read_size = 0;
224 if (ignore_directory && strrchr(hdr->name, '/')) {
225 q = (char *) strrchr(hdr->name, '/') + 1;
228 if (is_directory_traversal(q)) {
229 fprintf(stderr, "Possible directory traversal hack attempt in %s\n", q);
234 while (*q == '/') { q++; }
237 * if OSK then strip device name
239 if (hdr->extend_type == EXTEND_OS68K
240 || hdr->extend_type == EXTEND_XOSK) {
243 while (c && c != '/');
245 q = "."; /* if device name only */
250 if (extract_directory)
251 xsnprintf(name, sizeof(name), "%s/%s", extract_directory, q);
256 /* LZHDIRS_METHOD¤ò»ý¤Ä¥Ø¥Ã¥À¤ò¥Á¥§¥Ã¥¯¤¹¤ë */
257 /* 1999.4.30 t.okamoto */
258 for (method = 0;; method++) {
259 if (methods[method] == NULL) {
260 error("Unknown method \"%.*s\"; \"%s\" will be skiped ...",
261 5, hdr->method, name);
264 if (memcmp(hdr->method, methods[method], 5) == 0)
268 if ((hdr->unix_mode & UNIX_FILE_TYPEMASK) == UNIX_FILE_REGULAR
269 && method != LZHDIRS_METHOD_NUM) {
272 for (method = 0;; method++) {
273 if (methods[method] == NULL) {
274 error("Unknown method \"%.*s\"; \"%s\" will be skiped ...",
275 5, hdr->method, name);
278 if (memcmp(hdr->method, methods[method], 5) == 0)
283 reading_filename = archive_name;
284 writing_filename = name;
285 if (output_to_stdout || verify_mode) {
287 printf("%s %s\n", verify_mode ? "VERIFY" : "EXTRACT", name);
292 save_verbose = verbose;
293 if (!quiet && output_to_stdout) {
294 printf("::::::::\n%s\n::::::::\n", name);
298 else if (verify_mode) {
307 old_mode = setmode(fileno(stdout), O_BINARY);
310 crc = decode_lzhuf(afp, stdout,
311 hdr->original_size, hdr->packed_size,
312 name, method, &read_size);
315 setmode(fileno(stdout), old_mode);
319 verbose = save_verbose;
322 if (skip_flg == FALSE) {
323 up_flag = inquire_extract(name);
324 if (up_flag == FALSE && force == FALSE) {
329 if (skip_flg == TRUE) { /* if skip_flg */
330 if (stat(name, &stbuf) == 0 && force != TRUE) {
331 if (stbuf.st_mtime >= hdr->unix_last_modified_stamp) {
333 printf("%s : Skipped...\n", name);
342 signal(SIGINT, interrupt);
344 signal(SIGHUP, interrupt);
348 remove_extracting_file_when_interrupt = TRUE;
350 if ((fp = open_with_make_path(name)) != NULL) {
351 crc = decode_lzhuf(afp, fp,
352 hdr->original_size, hdr->packed_size,
353 name, method, &read_size);
356 remove_extracting_file_when_interrupt = FALSE;
357 signal(SIGINT, SIG_DFL);
359 signal(SIGHUP, SIG_DFL);
365 if (hdr->has_crc && crc != hdr->crc)
366 error("CRC error: \"%s\"", name);
368 else if ((hdr->unix_mode & UNIX_FILE_TYPEMASK) == UNIX_FILE_DIRECTORY
369 || (hdr->unix_mode & UNIX_FILE_TYPEMASK) == UNIX_FILE_SYMLINK
370 || method == LZHDIRS_METHOD_NUM) {
371 /* ¢¬¤³¤ì¤Ç¡¢Symbolic Link ¤Ï¡¢Âç¾æÉפ«¡© */
372 if (!ignore_directory && !verify_mode) {
375 printf("EXTRACT %s (directory)\n", name);
378 /* NAME has trailing SLASH '/', (^_^) */
379 if ((hdr->unix_mode & UNIX_FILE_TYPEMASK) == UNIX_FILE_SYMLINK) {
383 if (skip_flg == FALSE) {
384 up_flag = inquire_extract(name);
385 if (up_flag == FALSE && force == FALSE) {
389 if (GETSTAT(name, &stbuf) == 0 && force != TRUE) {
390 if (stbuf.st_mtime >= hdr->unix_last_modified_stamp) {
392 printf("%s : Skipped...\n", name);
399 make_parent_path(name);
400 l_code = symlink(hdr->realname, name);
403 warning("Can't make Symbolic Link \"%s\" -> \"%s\"",
404 hdr->realname, name);
407 message("Symbolic Link %s -> %s",
408 hdr->realname, name);
411 warning("Can't make Symbolic Link %s -> %s",
412 hdr->realname, name);
415 } else { /* make directory */
416 if (!output_to_stdout && !make_parent_path(name))
418 /* save directory information */
419 add_dirinfo(name, hdr);
424 if (force) /* force extract */
425 goto extract_regular;
427 error("Unknown file type: \"%s\". use `f' option to force extract.", name);
430 if (!output_to_stdout)
431 adjust_info(name, hdr);
436 /* ------------------------------------------------------------------------ */
437 /* EXTRACT COMMAND MAIN */
438 /* ------------------------------------------------------------------------ */
447 /* open archive file */
448 if ((afp = open_old_archive()) == NULL)
449 fatal_error("Cannot open archive file \"%s\"", archive_name);
451 if (archive_is_msdos_sfx1(archive_name))
452 seek_lha_header(afp);
454 /* extract each files */
455 while (get_header(afp, &hdr)) {
456 if (need_file(hdr.name)) {
458 read_size = extract_one(afp, &hdr);
459 if (read_size != hdr.packed_size) {
460 /* when error occurred in extract_one(), should adjust
461 point of file stream */
462 if (pos != -1 && afp != stdin)
463 fseeko(afp, pos + hdr.packed_size - read_size, SEEK_SET);
465 size_t i = hdr.packed_size - read_size;
466 while (i--) fgetc(afp);
471 fseeko(afp, hdr.packed_size, SEEK_CUR);
473 size_t i = hdr.packed_size;
474 while (i--) fgetc(afp);
479 /* close archive file */
482 /* adjust directory information */
489 is_directory_traversal(char *string)
491 unsigned int type = 0; /* 0 = new, 1 = only dots, 2 = other chars than dots */
497 if (temp[0] == '/') {
498 if (type == 1) { return 1; }
504 if ((temp[0] == '.') && (type < 2))
516 * restore directory information (time stamp).
517 * added by A.Iriyama 2003.12.12
520 typedef struct lhdDirectoryInfo_t {
521 struct lhdDirectoryInfo_t *next;
525 static LzHeaderList *dirinfo;
527 static void add_dirinfo(char *name, LzHeader *hdr)
531 if (memcmp(hdr->method, LZHDIRS_METHOD, 5) != 0)
534 p = xmalloc(sizeof(LzHeaderList));
536 memcpy(&p->hdr, hdr, sizeof(LzHeader));
537 strncpy(p->hdr.name, name, sizeof(p->hdr.name));
538 p->hdr.name[sizeof(p->hdr.name)-1] = 0;
541 LzHeaderList *tmp = dirinfo;
547 static void adjust_dirinfo()
550 adjust_info(dirinfo->hdr.name, &dirinfo->hdr);
553 LzHeaderList *tmp = dirinfo;
554 dirinfo = dirinfo->next;