/*----------------------------------------------------------------------*/ /* LHarc Extract Command */ /* This is part of LHarc UNIX Archiver Driver */ /* */ /* Copyright(C) MCMLXXXIX Yooichi.Tagawa */ /* */ /* V0.00 Original 1988.05.23 Y.Tagawa */ /* V1.00 Fixed 1989.09.22 Y.Tagawa */ /* V0.03 LHa for UNIX 1991.12.17 M.Oki */ /*----------------------------------------------------------------------*/ #include "lharc.h" extern int decode_lzhuf (); static boolean inquire_extract (name) char *name; { struct stat stbuf; if (stat (name, &stbuf) >= 0) { if (!is_regularfile (&stbuf)) { error ("Already exist (not a file)", name); return FALSE; } if (noexec) { printf ("EXTRACT %s but file is exist.\n", name); return FALSE; } else if (!force) { if (!isatty(0)) return FALSE; switch (inquire ("OverWrite ?(Yes/No/All)", name, "YyNnAa")) { case 0: case 1: /* Y/y */ break; case 2: case 3: /* N/n */ return FALSE; case 4: case 5: /* A/a */ force = TRUE; break; } } } if (noexec) printf ("EXTRACT %s\n", name); return TRUE; } static boolean make_parent_path (name) char *name; { char path[FILENAME_LENGTH]; struct stat stbuf; register char *p; /* make parent directory name into PATH for recursive call */ strcpy (path, name); for (p = path + strlen (path); p > path; p--) if (p[-1] == '/') { *--p = '\0'; break; } if (p == path) { message ("Why?", "ROOT"); return FALSE; /* no more parent. */ } if (stat (path, &stbuf) >= 0) { if (is_directory (&stbuf)) return TRUE; error ("Not a directory", path); return FALSE; } errno = 0; if (verbose) printf ("Making directory \"%s\".", path); if (mkdir (path, 0777) >= 0)/* try */ return TRUE; /* successful done. */ errno = 0; if (!make_parent_path (path)) return FALSE; if (mkdir (path, 0777) < 0) /* try again */ { message ("Cannot make directory", path); return FALSE; } return TRUE; } static FILE * open_with_make_path (name) char *name; { FILE *fp; if ((fp = fopen (name, WRITE_BINARY)) == NULL) { errno = 0; if (!make_parent_path (name) || (fp = fopen (name, WRITE_BINARY)) == NULL) error ("Cannot extract", name); errno = 0; } return fp; } static void adjust_info (name,hdr) char *name; LzHeader *hdr; { time_t utimebuf[2]; unsigned myuid; /* adjust file stamp */ utimebuf[0] = utimebuf[1] = hdr->unix_last_modified_stamp; utime (name, utimebuf); if (hdr->extend_type == EXTEND_UNIX || hdr->extend_type == EXTEND_OS68K || hdr->extend_type == EXTEND_XOSK) { #if 0 /* GRR: chown(,-1,) is not valid argument */ if (!myuid) chown (name, hdr->unix_uid, hdr->unix_gid); else if (myuid == hdr->unix_uid) chown (name, -1 , hdr->unix_gid); #endif if ((myuid = getuid()) == hdr->unix_uid || myuid == 0) chown (name, hdr->unix_uid, hdr->unix_gid); #ifdef NOT_COMPATIBLE_MODE Please need your modification in this space. #else chmod (name, hdr->unix_mode); /* Do this after chown so suid stays */ #endif errno = 0; } } static char *methods[10] = { "-lh0-", "-lh1-", "-lh2-", "-lh3-", "-lh4-", "-lh5-", "-lzs-", "-lz5-", "-lz4-", NULL }; static void extract_one (afp, hdr) FILE *afp; /* archive file */ LzHeader *hdr; { FILE *fp; /* output file */ char name[257]; int crc; int method; boolean save_quiet, save_verbose; char *q = hdr->name , c; if ( ignore_directory && rindex(hdr->name,'/') ) { q = (char *)rindex(hdr->name,'/') + 1; } else { if ( *q=='/' ) { q++; /* * if OSK then strip device name */ if (hdr->extend_type == EXTEND_OS68K || hdr->extend_type == EXTEND_XOSK ) { do c=(*q++); while ( c && c!='/' ); if ( !c || !*q ) q = "."; /* if device name only */ } } } if (extract_directory) sprintf (name, "%s/%s", extract_directory, q); else strcpy (name, q); if ((hdr->unix_mode & UNIX_FILE_TYPEMASK) == UNIX_FILE_REGULAR) { for (method = 0; ; method++) { if (methods[method] == NULL) { error ("Unknown method skiped ...", name); return; } if (bcmp (hdr->method, methods[method], 5) == 0) break; } reading_filename = archive_name; writting_filename = name; if (output_to_stdout || verify_mode) { if (noexec) { printf ("%s %s\n", verify_mode ? "VERIFY" : "EXTRACT",name); if (afp == stdin) { int i = hdr->packed_size; while(i--) fgetc(afp); } return; } save_quiet = quiet; save_verbose = verbose; if (!quiet && output_to_stdout) { printf ("::::::::\n%s\n::::::::\n", name); quiet = TRUE; verbose = FALSE; } else if (verify_mode) { quiet = FALSE; verbose = TRUE; } crc = decode_lzhuf (afp, stdout, hdr->original_size, hdr->packed_size, name, method); quiet = save_quiet; verbose = save_verbose; } else { if (!inquire_extract (name)) return; if (noexec) { if (afp == stdin) { int i = hdr->packed_size; while(i--) fgetc(afp); } return; } signal (SIGINT, interrupt); signal (SIGHUP, interrupt); unlink (name); errno = 0; remove_extracting_file_when_interrupt = TRUE; if ((fp = open_with_make_path (name)) != NULL) { crc = decode_lzhuf (afp, fp, hdr->original_size, hdr->packed_size, name, method); fclose (fp); } remove_extracting_file_when_interrupt = FALSE; signal (SIGINT, SIG_DFL); signal (SIGHUP, SIG_DFL); if (!fp) return; } errno = 0; if (hdr->has_crc && crc != hdr->crc) error ("CRC error", name); } else if ((hdr->unix_mode & UNIX_FILE_TYPEMASK) == UNIX_FILE_DIRECTORY) { if (!ignore_directory && !verify_mode) { if (noexec) { printf ("EXTRACT %s (directory)\n", name); return; } /* NAME has trailing SLASH '/', (^_^) */ if (!output_to_stdout && !make_parent_path (name)) return; } } else { error ("Unknown information", name); } if (!output_to_stdout) adjust_info (name,hdr); } /*----------------------------------------------------------------------*/ /* EXTRACT COMMAND MAIN */ /*----------------------------------------------------------------------*/ void cmd_extract () { LzHeader hdr; long pos; FILE *afp; /* open archive file */ if ((afp = open_old_archive ()) == NULL) fatal_error (archive_name); if (archive_is_msdos_sfx1 (archive_name)) skip_msdos_sfx1_code (afp); /* extract each files */ while (get_header (afp, &hdr)) { if (need_file (hdr.name)) { pos = ftell (afp); extract_one (afp, &hdr); fseek (afp, pos + hdr.packed_size, SEEK_SET); } else { if (afp != stdin) fseek (afp, hdr.packed_size, SEEK_CUR); else { int i = hdr.packed_size; while(i--) fgetc(afp); } } } /* close archive file */ fclose (afp); return; }