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