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