1 /* 2 * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 #ifdef _ALLBSD_SOURCE 26 #include <stdint.h> 27 #define THRTYPE intptr_t 28 #else 29 #define THRTYPE int 30 #endif 31 32 #include <sys/types.h> 33 34 #include <stdio.h> 35 #include <string.h> 36 #include <stdlib.h> 37 #include <stdarg.h> 38 #include <errno.h> 39 40 #include <limits.h> 41 #include <time.h> 42 43 #if defined(unix) && !defined(PRODUCT) 44 #include "pthread.h" 45 #define THREAD_SELF ((THRTYPE)pthread_self()) 46 #endif 47 48 #include "defines.h" 49 #include "bytes.h" 50 #include "utils.h" 51 #include "coding.h" 52 #include "bands.h" 53 54 #include "constants.h" 55 56 #include "zip.h" 57 58 #include "unpack.h" 59 60 61 int main(int argc, char **argv) { 62 return unpacker::run(argc, argv); 63 } 64 65 // Single-threaded, implementation, not reentrant. 66 // Includes a weak error check against MT access. 67 #ifndef THREAD_SELF 68 #define THREAD_SELF ((THRTYPE) 0) 69 #endif 70 NOT_PRODUCT(static THRTYPE uThread = -1;) 71 72 unpacker* unpacker::non_mt_current = null; 73 unpacker* unpacker::current() { 74 //assert(uThread == THREAD_SELF); 75 return non_mt_current; 76 } 77 static void set_current_unpacker(unpacker* u) { 78 unpacker::non_mt_current = u; 79 assert(((uThread = (u == null) ? (THRTYPE) -1 : THREAD_SELF), 80 true)); 81 } 82 83 // Callback for fetching data, Unix style. 84 static jlong read_input_via_stdio(unpacker* u, 85 void* buf, jlong minlen, jlong maxlen) { 86 assert(minlen <= maxlen); // don't talk nonsense 87 jlong numread = 0; 88 char* bufptr = (char*) buf; 89 while (numread < minlen) { 90 // read available input, up to buf.length or maxlen 91 int readlen = (1<<16); 92 if (readlen > (maxlen - numread)) 93 readlen = (int)(maxlen - numread); 94 int nr = 0; 95 if (u->infileptr != null) { 96 nr = (int)fread(bufptr, 1, readlen, u->infileptr); 97 } else { 98 #ifndef WIN32 99 // we prefer unbuffered inputs 100 nr = (int)read(u->infileno, bufptr, readlen); 101 #else 102 nr = (int)fread(bufptr, 1, readlen, stdin); 103 #endif 104 } 105 if (nr <= 0) { 106 if (errno != EINTR) 107 break; 108 nr = 0; 109 } 110 numread += nr; 111 bufptr += nr; 112 assert(numread <= maxlen); 113 } 114 //fprintf(u->errstrm, "readInputFn(%d,%d) => %d\n", 115 // (int)minlen, (int)maxlen, (int)numread); 116 return numread; 117 } 118 119 enum { EOF_MAGIC = 0, BAD_MAGIC = -1 }; 120 static int read_magic(unpacker* u, char peek[], int peeklen) { 121 assert(peeklen == 4); // magic numbers are always 4 bytes 122 jlong nr = (u->read_input_fn)(u, peek, peeklen, peeklen); 123 if (nr != peeklen) { 124 return (nr == 0) ? EOF_MAGIC : BAD_MAGIC; 125 } 126 int magic = 0; 127 for (int i = 0; i < peeklen; i++) { 128 magic <<= 8; 129 magic += peek[i] & 0xFF; 130 } 131 return magic; 132 } 133 134 static void setup_gzin(unpacker* u) { 135 gunzip* gzin = NEW(gunzip, 1); 136 gzin->init(u); 137 } 138 139 static const char* nbasename(const char* progname) { 140 const char* slash = strrchr(progname, '/'); 141 if (slash != null) progname = ++slash; 142 return progname; 143 } 144 145 #define USAGE_HEADER "Usage: %s [-opt... | --option=value]... x.pack[.gz] y.jar\n" 146 #define USAGE_OPTIONS \ 147 "\n" \ 148 "Unpacking Options\n" \ 149 " -H{h}, --deflate-hint={h} override transmitted deflate hint:\n" \ 150 " true, false, or keep (default)\n" \ 151 " -r, --remove-pack-file remove input file after unpacking\n" \ 152 " -v, --verbose increase program verbosity\n" \ 153 " -q, --quiet set verbosity to lowest level\n" \ 154 " -l{F}, --log-file={F} output to the given log file,\n" \ 155 " or '-' for standard output (default)\n" \ 156 " -?, -h, --help print this message\n" \ 157 " -V, --version print program version\n" \ 158 "\n" \ 159 "Exit Status:\n" \ 160 " 0 if successful, >0 if an error occurred\n" 161 162 static void usage(unpacker* u, const char* progname, bool full = false) { 163 // WinMain does not set argv[0] to the progrname 164 progname = (progname != null) ? nbasename(progname) : "unpack200"; 165 166 fprintf(u->errstrm, USAGE_HEADER, progname); 167 if (full) { 168 fprintf(u->errstrm, USAGE_OPTIONS); 169 } else { 170 fprintf(u->errstrm, "(For more information, run %s --help .)\n", progname); 171 } 172 } 173 174 // argument parsing 175 static char** init_args(int argc, char** argv, int &envargc) { 176 const char* env = getenv("UNPACK200_FLAGS"); 177 ptrlist envargs; 178 envargs.init(); 179 if (env != null) { 180 char* buf = (char*) strdup(env); 181 const char* delim = "\n\t "; 182 for (char* p = strtok(buf, delim); p != null; p = strtok(null, delim)) { 183 envargs.add(p); 184 } 185 } 186 // allocate extra margin at both head and tail 187 char** argp = NEW(char*, envargs.length()+argc+1); 188 char** argp0 = argp; 189 int i; 190 for (i = 0; i < envargs.length(); i++) { 191 *argp++ = (char*) envargs.get(i); 192 } 193 for (i = 1; i < argc; i++) { 194 // note: skip argv[0] (program name) 195 *argp++ = (char*) strdup(argv[i]); // make a scratch copy 196 } 197 *argp = null; // sentinel 198 envargc = envargs.length(); // report this count to next_arg 199 envargs.free(); 200 return argp0; 201 } 202 203 static int strpcmp(const char* str, const char* pfx) { 204 return strncmp(str, pfx, strlen(pfx)); 205 } 206 207 static const char flag_opts[] = "vqrVh?"; 208 static const char string_opts[] = "HlJ"; 209 210 static int next_arg(char** &argp) { 211 char* arg = *argp; 212 if (arg == null || arg[0] != '-') { // end of option list 213 return 0; 214 } 215 //printf("opt: %s\n", arg); 216 char ach = arg[1]; 217 if (ach == '\0') { 218 // ++argp; // do not pop this arg 219 return 0; // bare "-" is stdin/stdout 220 } else if (arg[1] == '-') { // --foo option 221 static const char* keys[] = { 222 "Hdeflate-hint=", 223 "vverbose", 224 "qquiet", 225 "rremove-pack-file", 226 "llog-file=", 227 "Vversion", 228 "hhelp", 229 null }; 230 if (arg[2] == '\0') { // end of option list 231 ++argp; // pop the "--" 232 return 0; 233 } 234 for (int i = 0; keys[i] != null; i++) { 235 const char* key = keys[i]; 236 char kch = *key++; 237 if (strchr(key, '=') == null) { 238 if (!strcmp(arg+2, key)) { 239 ++argp; // pop option arg 240 return kch; 241 } 242 } else { 243 if (!strpcmp(arg+2, key)) { 244 *argp += 2 + strlen(key); // remove "--"+key from arg 245 return kch; 246 } 247 } 248 } 249 } else if (strchr(flag_opts, ach) != null) { // plain option 250 if (arg[2] == '\0') { 251 ++argp; 252 } else { 253 // in-place edit of "-vxyz" to "-xyz" 254 arg += 1; // skip original '-' 255 arg[0] = '-'; 256 *argp = arg; 257 } 258 //printf(" key => %c\n", ach); 259 return ach; 260 } else if (strchr(string_opts, ach) != null) { // argument-bearing option 261 if (arg[2] == '\0') { 262 if (argp[1] == null) return -1; // no next arg 263 ++argp; // leave the argument in place 264 } else { 265 // in-place edit of "-Hxyz" to "xyz" 266 arg += 2; // skip original '-H' 267 *argp = arg; 268 } 269 //printf(" key => %c\n", ach); 270 return ach; 271 } 272 return -1; // bad argument 273 } 274 275 static const char sccsver[] = "1.30, 07/05/05"; 276 277 // Usage: unpackage input.pack output.jar 278 int unpacker::run(int argc, char **argv) { 279 unpacker u; 280 u.init(read_input_via_stdio); 281 set_current_unpacker(&u); 282 283 jar jarout; 284 jarout.init(&u); 285 286 int envargc = 0; 287 char** argbuf = init_args(argc, argv, envargc); 288 char** arg0 = argbuf+envargc; 289 char** argp = argbuf; 290 291 int verbose = 0; 292 char* logfile = null; 293 294 for (;;) { 295 const char* arg = (*argp == null)? "": u.saveStr(*argp); 296 bool isenvarg = (argp < arg0); 297 int ach = next_arg(argp); 298 bool hasoptarg = (ach != 0 && strchr(string_opts, ach) != null); 299 if (ach == 0 && argp >= arg0) break; 300 if (isenvarg && argp == arg0 && hasoptarg) ach = 0; // don't pull from cmdline 301 switch (ach) { 302 case 'H': u.set_option(UNPACK_DEFLATE_HINT,*argp++); break; 303 case 'v': ++verbose; break; 304 case 'q': verbose = 0; break; 305 case 'r': u.set_option(UNPACK_REMOVE_PACKFILE,"1"); break; 306 case 'l': logfile = *argp++; break; 307 case 'J': argp += 1; break; // skip ignored -Jxxx parameter 308 309 case 'V': 310 fprintf(u.errstrm, VERSION_STRING, nbasename(argv[0]), sccsver); 311 exit(0); 312 313 case 'h': 314 case '?': 315 usage(&u, argv[0], true); 316 exit(1); 317 318 default: 319 const char* inenv = isenvarg? " in ${UNPACK200_FLAGS}": ""; 320 if (hasoptarg) 321 fprintf(u.errstrm, "Missing option string%s: %s\n", inenv, arg); 322 else 323 fprintf(u.errstrm, "Unrecognized argument%s: %s\n", inenv, arg); 324 usage(&u, argv[0]); 325 exit(2); 326 } 327 } 328 329 if (verbose != 0) { 330 u.set_option(DEBUG_VERBOSE, u.saveIntStr(verbose)); 331 } 332 if (logfile != null) { 333 u.set_option(UNPACK_LOG_FILE, logfile); 334 } 335 336 u.redirect_stdio(); 337 338 const char* source_file = *argp++; 339 const char* destination_file = *argp++; 340 341 if (source_file == null || destination_file == null || *argp != null) { 342 usage(&u, argv[0]); 343 exit(2); 344 } 345 346 if (verbose != 0) { 347 fprintf(u.errstrm, 348 "Unpacking from %s to %s\n", source_file, destination_file); 349 } 350 bool& remove_source = u.remove_packfile; 351 352 if (strcmp(source_file, "-") == 0) { 353 remove_source = false; 354 u.infileno = fileno(stdin); 355 } else { 356 u.infileptr = fopen(source_file, "rb"); 357 if (u.infileptr == null) { 358 fprintf(u.errstrm, 359 "Error: Could not open input file: %s\n", source_file); 360 exit(3); // Called only from the native standalone unpacker 361 } 362 } 363 364 if (strcmp(destination_file, "-") == 0) { 365 jarout.jarfp = stdout; 366 jarout.jarname = null; 367 if (u.errstrm == stdout) // do not mix output 368 u.set_option(UNPACK_LOG_FILE, LOGFILE_STDERR); 369 } else { 370 jarout.openJarFile(destination_file); 371 assert(jarout.jarfp != null); 372 } 373 374 if (verbose != 0) 375 u.dump_options(); 376 377 char peek[4]; 378 int magic; 379 380 // check for GZIP input 381 magic = read_magic(&u, peek, (int)sizeof(peek)); 382 if ((magic & GZIP_MAGIC_MASK) == GZIP_MAGIC) { 383 // Oops; must slap an input filter on this data. 384 setup_gzin(&u); 385 u.gzin->start(magic); 386 u.gzin->gzcrc = 0; 387 u.gzin->gzlen = 0; 388 if (!u.aborting()) { 389 u.start(); 390 } 391 } else { 392 u.start(peek, sizeof(peek)); 393 } 394 395 // Note: The checks to u.aborting() are necessary to gracefully 396 // terminate processing when the first segment throws an error. 397 398 for (;;) { 399 if (u.aborting()) break; 400 401 // Each trip through this loop unpacks one segment 402 // and then resets the unpacker. 403 for (unpacker::file* filep; (filep = u.get_next_file()) != null; ) { 404 if (u.aborting()) break; 405 u.write_file_to_jar(filep); 406 } 407 if (u.aborting()) break; 408 409 // Peek ahead for more data. 410 magic = read_magic(&u, peek, (int)sizeof(peek)); 411 if (magic != (int)JAVA_PACKAGE_MAGIC) { 412 if (magic != EOF_MAGIC) 413 u.abort("garbage after end of pack archive"); 414 break; // all done 415 } 416 417 // Release all storage from parsing the old segment. 418 u.reset(); 419 420 // Restart, beginning with the peek-ahead. 421 u.start(peek, sizeof(peek)); 422 } 423 424 int status = 0; 425 if (u.aborting()) { 426 fprintf(u.errstrm, "Error: %s\n", u.get_abort_message()); 427 status = 1; 428 } 429 430 if (u.infileptr != null) { 431 fclose(u.infileptr); 432 u.infileptr = null; 433 } 434 435 if (!u.aborting() && remove_source) 436 remove(source_file); 437 438 if (verbose != 0) { 439 fprintf(u.errstrm, "unpacker completed with status=%d\n", status); 440 } 441 442 u.finish(); 443 444 u.free(); // tidy up malloc blocks 445 set_current_unpacker(null); // clean up global pointer 446 447 return status; 448 }