]> gcc.gnu.org Git - gcc.git/blame - fastjar/jartool.c
cse.c (record_jump_cond_subreg): New.
[gcc.git] / fastjar / jartool.c
CommitLineData
bd8757b3
APB
1/*
2 jartool.c - main functions for fastjar utility
97b62d47 3 Copyright (C) 2002, 2004 Free Software Foundation
0ee6e0a9 4 Copyright (C) 1999, 2000, 2001 Bryan Burns
bd8757b3
APB
5
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License
8 as published by the Free Software Foundation; either version 2
9 of the License, or (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19*/
20
7a93476d
TT
21/*
22 Revision 1.10 2002/01/03 04:57:56 rodrigc
23 2001-01-02 Craig Rodrigues <rodrigc@gcc.gnu.org>
24
25 PR bootstrap/5117
26 * configure.in (AC_CHECK_HEADERS): Check for stdlib.h.
27 * Makefile.am: Move grepjar to bin_PROGRAMS.
28 * config.h.in: Regenerated.
29 * Makefile.in: Regenerated.
30 * aclocal.m4: Regenerated.
31 * jargrep.c: Eliminate some signed/unsigned and default
32 uninitialized warnings. Use HAVE_STDLIB_H instead of
33 STDC_HEADERS macro.
34 * jartool.c: Likewise.
35 * compress.c: Likewise.
bd8757b3 36
79801091
CR
37 Revision 1.9 2001/10/12 00:49:42 bryce
38 * jatool.c (extract_jar): Account for null termination when
39 determining whether to expand "filename".
40
ac43be73
BM
41 Revision 1.8 2001/08/29 01:35:31 apbianco
42 2001-08-28 Alexandre Petit-Bianco <apbianco@redhat.com>
43
44 * jartool.c (add_to_jar): Return 1 if `stat' initialy failed.
45 Fixes PR java/3949.
46
47 (http://gcc.gnu.org/ml/gcc-patches/2001-08/msg01641.html)
48
51a25585
APB
49 Revision 1.7 2001/08/27 23:09:37 tromey
50 * jartool.c (jarfile): Remove length limitation.
51 (main): Use jt_strdup when initializing jarfile.
52
c5bb59c1
TT
53 Revision 1.6 2001/07/04 18:33:53 tromey
54 Modified from patch by Julian Hall <jules@acris.co.uk>:
55 * jartool.c (errno): Conditionally declare.
56 (O_BINARY): Conditionally define.
57 (main): Use open, not creat. Use O_BINARY everywhere.
58 (make_manifest): Use O_BINARY.
59 (add_to_jar): Likewise.
60
72ea889a
TT
61 Revision 1.5 2001/05/03 21:40:47 danglin
62 * jartool.c (jt_strdup): New function.
63 (get_next_arg): Use jt_strdup instead of strdup.
64
0ee6e0a9
JDA
65 Revision 1.4 2000/12/28 21:47:37 robertl
66 2000-12-28 Robert Lipe <robertl@sco.com>
67
68 * jartool.c (MAXPATHLEN): Provide if not defined.
69
347d73aa
RL
70 Revision 1.3 2000/12/14 18:45:35 ghazi
71 Warning fixes:
72
73 * compress.c: Include stdlib.h and compress.h.
74 (rcsid): Delete.
75 (report_str_error): Make static.
76 (ez_inflate_str): Delete unused variable. Add parens in if-stmt.
77 (hrd_inflate_str): Likewise.
78
79 * compress.h (init_compression, end_compression, init_inflation,
80 end_inflation): Prototype void arguments.
81
82 * dostime.c (rcsid): Delete.
83
84 * jargrep.c: Include ctype.h, stdlib.h, zlib.h and compress.h.
85 Make functions static. Cast ctype function argument to `unsigned
86 char'. Add parens in if-stmts. Constify.
87 (Usage): Change into a macro.
88 (jargrep): Remove unused parameter.
89
90 * jartool.c: Constify. Add parens in if-stmts. Align
91 signed/unsigned char pointers in functions calls using casts.
92 (rcsid): Delete.
93 (list_jar): Fix printf format specifier.
94 (usage): Chop long string into bits. Reformat.
95
96 * pushback.c (rcsid): Delete.
97
990bee10
KG
98 Revision 1.2 2000/12/13 18:11:57 tromey
99 * jartool.c (extract_jar): Use strchr, not index.
100
b114d8ed
TT
101 Revision 1.1 2000/12/09 03:08:23 apbianco
102 2000-12-08 Alexandre Petit-Bianco <apbianco@cygnus.com>
103
104 * fastjar: Imported.
105
bd8757b3
APB
106 Revision 1.5 2000/08/24 15:01:27 cory
107 Made certain that fastjar opened the jar file before trying to update it
108 with the -u option.
109
110 Revision 1.4 2000/08/24 13:39:21 cory
111 Changed +'s to |'s in jartool.c to insure there was no confusion with sign
112 when byte swapping. Better safe than sorry.
113
114 Revision 1.3 2000/08/23 19:42:17 cory
115 Added support for more Unix platforms. The following code has been hacked
116 to work on AIX, Solaris, True 64, and HP-UX.
117 Added bigendian check. Probably works on most big and little endian platforms
118 now.
119
120 Revision 1.2 1999/12/06 07:38:28 toast
121 fixed recursive archiving bug
122
123 Revision 1.1.1.1 1999/12/06 03:09:34 toast
124 initial checkin..
125
126
127
128 Revision 1.22 1999/10/12 19:45:13 burnsbr
129 adding patch to fix compat problem
130
131 Revision 1.21 1999/05/10 09:15:49 burnsbr
132 fixed manifest file version info
133
134 Revision 1.20 1999/05/10 08:53:16 burnsbr
135 *** empty log message ***
136
137 Revision 1.19 1999/05/10 08:30:39 burnsbr
138 added extract / listing code
139
140 Revision 1.18 1999/04/28 04:24:29 burnsbr
141 updated version
142
143 Revision 1.17 1999/04/28 04:21:23 burnsbr
144 added support for -C dir-changing flag.. Updated total compression display
145
146 Revision 1.16 1999/04/27 10:28:22 burnsbr
147 updated version string
148
149 Revision 1.15 1999/04/27 10:04:06 burnsbr
150 configure support
151
152 Revision 1.14 1999/04/27 08:56:14 burnsbr
153 added -V flag, better error messages
154
155 Revision 1.13 1999/04/26 02:35:21 burnsbr
156 changed all sorts of stuff.. compression now works 100%
157
158 Revision 1.12 1999/04/23 12:00:45 burnsbr
159 90% done with compression code
160
161 Revision 1.11 1999/04/22 04:12:57 burnsbr
162 finished first round of Manifest file support..
163 might need to do more, digest etc..
164
165 Revision 1.10 1999/04/22 02:35:23 burnsbr
166 added more manifest support, about 75% done now. Replaced all the
167 redundant shifts and bit-logic with a macro or two, making the code
168 easier to read.
169
170 Revision 1.9 1999/04/21 09:55:16 burnsbr
171 pulled out printfs
172
173 Revision 1.8 1999/04/21 02:58:01 burnsbr
174 started manifest code
175
176 Revision 1.7 1999/04/20 23:15:28 burnsbr
177 added patch sent by John Bley <jbb6@acpub.duke.edu>
178
179 Revision 1.6 1999/04/20 08:56:02 burnsbr
180 added GPL comment
181
182 Revision 1.5 1999/04/20 08:16:09 burnsbr
183 fixed verbose flag, did some optimization
184
185 Revision 1.4 1999/04/20 05:09:59 burnsbr
186 added rcsid variable
187
188 Revision 1.3 1999/04/20 05:08:54 burnsbr
189 fixed Log statement
190
191*/
192
193#include "config.h"
194
195#include <zlib.h>
196
79801091 197#ifdef HAVE_STDLIB_H
bd8757b3
APB
198#include <stdlib.h>
199#endif
200
201#ifdef HAVE_UNISTD_H
202#include <unistd.h>
203#endif
204
205#include <stdio.h>
206#include <sys/stat.h>
207#include <sys/types.h>
208
209#ifdef HAVE_SYS_PARAM_H
210#include <sys/param.h>
347d73aa
RL
211#endif
212
213#ifndef MAXPATHLEN
bd8757b3
APB
214#define MAXPATHLEN 1024
215#endif
216
217#ifdef HAVE_DIRENT_H
218#include <dirent.h>
219#endif
220
221#ifdef HAVE_FCNTL_H
222#include <fcntl.h>
223#endif
224
225#include <string.h>
226#include <errno.h>
227
228#ifdef TM_IN_SYS_TIME
229#include <sys/time.h>
230#else
231#include <time.h>
232#endif
233
7a93476d
TT
234#include <getopt.h>
235
bd8757b3
APB
236#include "jartool.h"
237#include "zipfile.h"
238#include "dostime.h"
239#include "pushback.h"
240#include "compress.h"
97b62d47 241#include "shift.h"
bd8757b3 242
9251acb4
TT
243/* Some systems have mkdir that takes a single argument. */
244#ifdef MKDIR_TAKES_ONE_ARG
245# define mkdir(a,b) mkdir(a)
246#endif
247
248
bd8757b3
APB
249#ifdef WORDS_BIGENDIAN
250
251#define L2BI(l) ((l & 0xff000000) >> 24) | \
252 ((l & 0x00ff0000) >> 8) | \
253 ((l & 0x0000ff00) << 8) | \
254 ((l & 0x000000ff) << 24);
255
256#define L2BS(l) ((l & 0xff00) >> 8) | ((l & 0x00ff) << 8);
257
258#endif
259
72ea889a 260#ifndef errno
bd8757b3 261extern int errno;
72ea889a
TT
262#endif
263
264#ifndef O_BINARY
265#define O_BINARY 0
266#endif
bd8757b3 267
990bee10 268void usage(const char*);
7a93476d
TT
269void help(const char *);
270void version(void);
bd8757b3 271void add_entry(struct zipentry *);
990bee10 272void init_headers(void);
bd8757b3
APB
273
274int consume(pb_file *, int);
275int list_jar(int, char**, int);
276int extract_jar(int, char**, int);
97b62d47
MK
277int add_file_to_jar(int, int, const char*, struct stat*, int);
278int add_to_jar(int, const char*, int);
279int add_to_jar_with_dir(int, const char*, const char*, int);
bd8757b3 280int create_central_header(int);
97b62d47
MK
281int make_manifest(int, const char*, int);
282int read_entries (int);
bd8757b3 283static void init_args(char **, int);
990bee10 284static char *get_next_arg (void);
0ee6e0a9 285static char *jt_strdup (char*);
7a93476d 286static void expand_options (int *argcp, char ***argvp);
90428457
RS
287static struct zipentry *find_entry (const char *);
288static int looks_like_dir (const char *);
bd8757b3
APB
289
290/* global variables */
291ub1 file_header[30];
292ub1 data_descriptor[16];
293int do_compress;
294int seekable;
295int verbose;
c5bb59c1 296char *jarfile;
bd8757b3
APB
297
298/* If non zero, then don't recurse in directory. Instead, add the
299 directory entry and relie on an explicit list of files to populate
300 the archive. This option isn't supported by the original jar tool. */
301int use_explicit_list_only;
302
303/* If non zero, then read the entry names from stdin. This option
304 isn't supported by the original jar tool. */
305int read_names_from_stdin;
306
307zipentry *ziplist; /* linked list of entries */
308zipentry *ziptail; /* tail of the linked list */
309
310int number_of_entries; /* number of entries in the linked list */
311
97b62d47
MK
312/* What we go by. */
313const char *progname;
314
315/* The offset of the end of the last zip entry. */
316ub4 end_of_entries;
317
7a93476d
TT
318/* This is used to mark options with no short value. */
319#define LONG_OPT(Num) ((Num) + 128)
320
321#define OPT_HELP LONG_OPT (0)
322
b9f8d427
AG
323/* This holds all options. */
324#define OPTION_STRING "-ctxuvVf:m:C:0ME@"
7a93476d 325
6838645e
AT
326/* Define the MANIFEST content here to have it easier with calculations
327 below. This is for the case we create an empty MANIFEST.MF. */
328#define MANIFEST_STR "Manifest-Version: 1.0\nCreated-By: "
329#define MANIFEST_END "\n\n"
330
7a93476d
TT
331static const struct option options[] =
332{
333 { "help", no_argument, NULL, OPT_HELP },
334 { "version", no_argument, NULL, 'V' },
335 { NULL, no_argument, NULL, 0 }
336};
337
bd8757b3
APB
338int main(int argc, char **argv){
339
7a93476d 340 char *mfile = NULL;
bd8757b3
APB
341
342 int action = ACTION_NONE;
343 int manifest = TRUE;
7a93476d 344 int opt;
bd8757b3 345
bd8757b3
APB
346 int jarfd = -1;
347
7a93476d
TT
348 /* These are used to collect file names and `-C' options for the
349 second pass through the command line. */
350 int new_argc;
351 char **new_argv;
352
97b62d47
MK
353 progname = argv[0];
354
bd8757b3
APB
355 do_compress = TRUE;
356 verbose = FALSE;
357
358 ziplist = NULL;
359
360 number_of_entries = 0;
361
362 if(argc < 2)
363 usage(argv[0]);
364
7a93476d
TT
365 new_argc = 0;
366 new_argv = (char **) malloc (argc * sizeof (char *));
367
368 expand_options (&argc, &argv);
369 while ((opt = getopt_long (argc, argv, OPTION_STRING,
370 options, NULL)) != -1) {
371 switch(opt){
b9f8d427
AG
372 case 'C':
373 new_argv[new_argc++] = (char *) "-C";
374 /* ... fall through ... */
7a93476d 375 case 1:
b9f8d427 376 /* File name or unparsed option, due to RETURN_IN_ORDER. */
7a93476d
TT
377 new_argv[new_argc++] = optarg;
378 break;
bd8757b3
APB
379 case 'c':
380 action = ACTION_CREATE;
381 break;
382 case 't':
383 action = ACTION_LIST;
384 break;
385 case 'x':
386 action = ACTION_EXTRACT;
387 break;
388 case 'u':
389 action = ACTION_UPDATE;
390 break;
391 case 'v':
392 verbose = TRUE;
393 break;
394 case 'V':
7a93476d 395 version();
bd8757b3
APB
396 exit(0);
397 case 'f':
7a93476d 398 jarfile = optarg;
bd8757b3
APB
399 break;
400 case 'm':
7a93476d 401 mfile = optarg;
bd8757b3
APB
402 break;
403 case '0':
404 do_compress = FALSE;
405 break;
406 case 'M':
407 manifest = FALSE;
408 break;
7a93476d
TT
409
410 case OPT_HELP:
411 help(argv[0]);
bd8757b3 412 break;
7a93476d 413
bd8757b3
APB
414 /* The following options aren't supported by the original jar tool. */
415 case 'E':
416 use_explicit_list_only = TRUE;
417 break;
418 case '@':
419 read_names_from_stdin = TRUE;
420 break;
421 default:
bd8757b3
APB
422 usage(argv[0]);
423 }
424 }
425
7a93476d
TT
426 /* We might have seen `--'. In this case we want to make sure that
427 all following options are handled as file names. */
428 while (optind < argc)
429 new_argv[new_argc++] = argv[optind++];
250fce1d 430 new_argv[new_argc] = NULL;
7a93476d 431
bd8757b3 432 if(action == ACTION_NONE){
97b62d47
MK
433 fprintf(stderr, "%s: one of options -{ctxu} must be specified.\n",
434 progname);
bd8757b3
APB
435 usage(argv[0]);
436 }
437
438 /* Verify unsupported combinations and warn of the use of non
439 standard features */
440 if(verbose && use_explicit_list_only)
441 fprintf (stderr, "Warning: using non standard '-E' option\n");
442 if(verbose && read_names_from_stdin)
443 fprintf (stderr, "Warning: using non standard '-@' option\n");
444 if(read_names_from_stdin
445 && (action != ACTION_CREATE && action != ACTION_UPDATE)){
97b62d47
MK
446 fprintf(stderr, "%s: option '-@' is supported only with '-c' or '-u'.\n",
447 progname);
bd8757b3
APB
448 usage(argv[0]);
449 }
450
bd8757b3
APB
451 /* create the jarfile */
452 if(action == ACTION_CREATE){
7a93476d 453 if(jarfile){
248cfd1c 454 jarfd = open(jarfile, O_CREAT | O_BINARY | O_WRONLY | O_TRUNC, 0666);
72ea889a 455
bd8757b3 456 if(jarfd < 0){
97b62d47
MK
457 fprintf(stderr, "%s: error opening %s for writing: %s\n", progname,
458 jarfile, strerror (errno));
bd8757b3
APB
459 exit(1);
460 }
461
462 /* We assume that the file is seekable */
463 seekable = TRUE;
464
465 } else {
466
467 jarfd = STDOUT_FILENO; /* jarfd is stdout otherwise */
468
469 /* standard out is not seekable */
470 seekable = FALSE;
471
472 /* don't want our output to be part of the jar file.. figured this one
473 out the hard way.. =P */
474 verbose = FALSE;
475 }
476 } else if(action == ACTION_LIST || action == ACTION_EXTRACT){
477
7a93476d 478 if(jarfile){
72ea889a 479 jarfd = open(jarfile, O_RDONLY | O_BINARY);
bd8757b3
APB
480
481 if(jarfd < 0){
97b62d47
MK
482 fprintf(stderr, "%s: error opening %s for reading: %s\n", progname,
483 jarfile, strerror (errno));
bd8757b3
APB
484 exit(1);
485 }
486
487 seekable = TRUE;
488 } else {
489 jarfd = STDIN_FILENO; /* jarfd is standard in */
490
491 /* we assume that the stream isn't seekable for safety */
492 seekable = FALSE;
493 }
494 }
495
97b62d47
MK
496 if (action == ACTION_UPDATE)
497 {
498 if (!jarfile)
499 {
500 fprintf (stderr, "%s: `-u' mode requires a file name\n",
501 argv[0]);
502 exit (1);
503 }
504
505 if ((jarfd = open (jarfile, O_RDWR | O_BINARY)) < 0)
506 {
507 fprintf (stderr, "Error opening %s for reading!\n", jarfile);
508 perror (jarfile);
509 exit (1);
510 }
511
512 /* Assert that jarfd is seekable. */
513 if (lseek (jarfd, 0, SEEK_CUR) == -1)
514 {
515 fprintf (stderr, "%s: %s is not seekable\n", argv[0], jarfile);
516 exit (1);
517 }
518
519 seekable = TRUE;
520 }
521
bd8757b3 522 if(action == ACTION_CREATE || action == ACTION_UPDATE){
990bee10 523 const char *arg;
bd8757b3
APB
524 init_headers();
525
bd8757b3
APB
526 if(do_compress)
527 init_compression();
97b62d47
MK
528
529 if (action == ACTION_UPDATE)
530 {
531 if (read_entries (jarfd))
532 exit (1);
533 }
bd8757b3
APB
534
535 /* Add the META-INF/ directory and the manifest */
7a93476d 536 if(manifest && mfile)
97b62d47
MK
537 make_manifest(jarfd, mfile, action == ACTION_UPDATE);
538 else if(manifest && action == ACTION_CREATE)
539 make_manifest(jarfd, NULL, FALSE);
540
250fce1d 541 init_args (new_argv, 0);
bd8757b3
APB
542 /* now we add the files to the archive */
543 while ((arg = get_next_arg ())){
544
545 if(!strcmp(arg, "-C")){
990bee10
KG
546 const char *dir_to_change = get_next_arg ();
547 const char *file_to_add = get_next_arg ();
a55a78d1 548 if (!dir_to_change || !file_to_add) {
97b62d47 549 fprintf(stderr, "%s: error: missing argument for -C.\n", progname);
bd8757b3
APB
550 exit(1);
551 }
97b62d47
MK
552 if (add_to_jar_with_dir(jarfd, dir_to_change, file_to_add,
553 action == ACTION_UPDATE))
554 {
555 fprintf(stderr,
556 "Error adding %s (in directory %s) to jar archive!\n",
557 file_to_add, dir_to_change);
558 exit(1);
559 }
bd8757b3 560 } else {
97b62d47 561 if(add_to_jar(jarfd, arg, action == ACTION_UPDATE)){
a55a78d1 562 fprintf(stderr, "Error adding %s to jar archive!\n", arg);
bd8757b3
APB
563 exit(1);
564 }
565 }
566 }
567 /* de-initialize the compression DS */
568 if(do_compress)
569 end_compression();
97b62d47
MK
570
571 if (action == ACTION_UPDATE)
572 lseek (jarfd, end_of_entries, SEEK_SET);
bd8757b3
APB
573
574 create_central_header(jarfd);
97b62d47 575
fab62285
BM
576#if ! (HAVE_FTRUNCATE || HAVE__CHSIZE)
577 #error neither ftruncate() or _chsize() available
578#endif
97b62d47
MK
579 /* Check if the file shrunk when we updated it. */
580 if (action == ACTION_UPDATE)
fab62285 581#if HAVE_FTRUNCATE
97b62d47 582 ftruncate (jarfd, lseek (jarfd, 0, SEEK_CUR));
932c738d 583#else
fab62285
BM
584 _chsize (jarfd, lseek (jarfd, 0, SEEK_CUR));
585#endif
97b62d47
MK
586
587 if (jarfd != STDIN_FILENO && close(jarfd) != 0) {
588 fprintf(stderr, "%s: error closing jar archive: %s\n",
589 progname, strerror (errno));
590 exit (1);
bd8757b3
APB
591 }
592 } else if(action == ACTION_LIST){
7a93476d 593 list_jar(jarfd, &new_argv[0], new_argc);
bd8757b3 594 } else if(action == ACTION_EXTRACT){
7a93476d 595 extract_jar(jarfd, &new_argv[0], new_argc);
bd8757b3
APB
596 }
597
598 exit(0);
599}
600
601static int args_current_g;
602static char **args_g;
603
604static void
605init_args(args, current)
606 char **args;
607 int current;
608{
609 if(!read_names_from_stdin)
610 {
611 args_g = args;
612 args_current_g = current;
613 }
614}
615
616static char *
617get_next_arg ()
618{
619 static int reached_end = 0;
620
621 if (reached_end)
622 return NULL;
623
624 if (args_g)
625 {
626 if (!args_g [args_current_g])
627 {
628 reached_end = 1;
629 return NULL;
630 }
631 return args_g [args_current_g++];
632 }
633 else
634 {
635 /* Read the name from stdin. Delimiters are '\n' and
636 '\r'. Reading EOF indicates that we don't have anymore file
637 names characters to read. */
638
639 char s [MAXPATHLEN];
640 int pos = 0;
641
642 /* Get rid of '\n' and '\r' first. */
643 while (1)
644 {
645 int c = getc (stdin);
646 if (c == '\n' || c == '\r')
647 continue;
648 else
649 {
650 if (c == EOF)
651 return NULL;
652 ungetc (c, stdin);
653 break;
654 }
655 }
656
657 while (1)
658 {
659 int c = getc (stdin);
660 /* Exit when we get a delimiter or don't have any characters
661 to read */
662 if (c == '\n'|| c == '\r'|| c == EOF)
663 break;
664 s [pos++] = (char) c;
665 }
666
667 if (pos)
668 {
669 s [pos] = '\0';
0ee6e0a9 670 return jt_strdup (s);
bd8757b3
APB
671 }
672 else
673 return NULL;
674 }
675}
676
677void init_headers(){
678 /* packing file header */
679 /* magic number */
680 file_header[0] = 0x50;
681 file_header[1] = 0x4b;
682 file_header[2] = 0x03;
683 file_header[3] = 0x04;
684 /* version number (Unix 1.0)*/
685 file_header[4] = 10;
686 file_header[5] = 0;
687 /* bit flag (normal deflation)*/
688 file_header[6] = 0x00;
689
690 file_header[7] = 0x00;
691 /* do_compression method (deflation) */
692 file_header[8] = 0;
693 file_header[9] = 0;
694
695 /* last mod file time (MS-DOS format) */
696 file_header[10] = 0;
697 file_header[11] = 0;
698 /* last mod file date (MS-DOS format) */
699 file_header[12] = 0;
700 file_header[13] = 0;
701 /* CRC 32 */
702 file_header[14] = 0;
703 file_header[15] = 0;
704 file_header[16] = 0;
705 file_header[17] = 0;
706 /* compressed size */
707 file_header[18] = 0;
708 file_header[19] = 0;
709 file_header[20] = 0;
710 file_header[21] = 0;
711 /* uncompressed size */
712 file_header[22] = 0;
713 file_header[23] = 0;
714 file_header[24] = 0;
715 file_header[25] = 0;
716 /* filename length */
717 file_header[26] = 0;
718 file_header[27] = 0;
719 /* extra field length */
720 file_header[28] = 0;
721 file_header[29] = 0;
722
723 /* Initialize the compression DS */
724 PACK_UB4(data_descriptor, 0, 0x08074b50);
725
726}
727
728void add_entry(struct zipentry *ze){
729
730 if(ziplist == NULL){
731 ziplist = ze;
732 ziptail = ziplist;
733 } else {
734 ziplist->next_entry = ze;
735 ziplist = ze;
736 }
737
738 number_of_entries++;
739}
740
90428457 741static struct zipentry *
97b62d47
MK
742find_entry (const char *fname)
743{
744 struct zipentry *ze;
745
746 for (ze = ziptail; ze; ze = ze->next_entry)
747 {
748 if (!strcmp (ze->filename, fname))
749 return ze;
750 }
751 return NULL;
752}
753
754
90428457 755static int
97b62d47
MK
756looks_like_dir (const char *fname)
757{
758 struct zipentry *ze;
759 size_t len = strlen (fname);
760
761 for (ze = ziptail; ze; ze = ze->next_entry)
762 {
763 if (strlen (ze->filename) > len
764 && !strncmp (fname, ze->filename, len)
765 && ze->filename[len] == '/')
766 return 1;
767 }
768 return 0;
769}
770
771
772/*
773 * Read the zip entries of an existing file, building `ziplist' as we go.
774 */
775int read_entries (int fd)
776{
777 struct zipentry *ze;
778 ub1 intbuf[4];
779 ub1 header[46];
780 ub2 len;
781 ub2 count, i;
782 off_t offset;
783
784 if (lseek (fd, -22, SEEK_END) == -1)
785 {
786 fprintf (stderr, "%s: %s: can't seek file\n", progname, jarfile);
787 return 1;
788 }
789
790 if (read (fd, intbuf, 4) < 4)
791 {
792 perror (progname);
793 return 1;
794 }
795 /* Is there a zipfile comment? */
796 while (UNPACK_UB4(intbuf, 0) != 0x06054b50)
797 {
798 if (lseek (fd, -5, SEEK_CUR) == -1 ||
799 read (fd, intbuf, 4) != 4)
800 {
801 fprintf (stderr, "%s: can't find end of central directory: %s\n",
802 progname, strerror (errno));
803 return 1;
804 }
805 }
806
807 /* Skip disk numbers. */
808 if (lseek (fd, 6, SEEK_CUR) == -1)
809 {
810 perror (progname);
811 return 1;
812 }
813
814 /* Number of entries in the central directory. */
815 if (read (fd, intbuf, 2) != 2)
816 {
817 perror (progname);
818 return 1;
819 }
820 count = UNPACK_UB2(intbuf, 0);
821
822 if (lseek (fd, 4, SEEK_CUR) == -1)
823 {
824 perror (progname);
825 return 1;
826 }
827
828 /* Offset where the central directory begins. */
829 if (read (fd, intbuf, 4) != 4)
830 {
831 perror (progname);
832 return 1;
833 }
834 offset = UNPACK_UB4(intbuf, 0);
835 end_of_entries = offset;
836
837 if (lseek (fd, offset, SEEK_SET) != offset)
838 {
839 perror (progname);
840 return 1;
841 }
842
843 if (read (fd, header, 46) != 46)
844 {
845 fprintf (stderr, "%s: %s: unexpected end of file\n",
846 progname, jarfile);
847 return 1;
848 }
849
850 for (i = 0; i < count; i++)
851 {
852 if (UNPACK_UB4(header, 0) != 0x02014b50)
853 {
854 fprintf (stderr, "%s: can't find central directory header\n",
855 progname);
856 return 1;
857 }
858 ze = (struct zipentry *) malloc (sizeof (struct zipentry));
859 if (!ze)
860 {
861 perror (progname);
862 return 1;
863 }
864 memset (ze, 0, sizeof (struct zipentry));
865 ze->flags = UNPACK_UB2(header, CEN_FLAGS);
866 ze->mod_time = UNPACK_UB2(header, CEN_MODTIME);
867 ze->mod_date = UNPACK_UB2(header, CEN_MODDATE);
868 ze->crc = UNPACK_UB4(header, CEN_CRC);
869 ze->usize = UNPACK_UB4(header, CEN_USIZE);
870 ze->csize = UNPACK_UB4(header, CEN_CSIZE);
871 ze->offset = UNPACK_UB4(header, CEN_OFFSET);
872 ze->compressed = (header[CEN_COMP] || header[CEN_COMP+1]);
873 len = UNPACK_UB2(header, CEN_FNLEN);
874 ze->filename = (char *) malloc ((len+1) * sizeof (char));
875 if (!ze->filename)
876 {
877 perror (progname);
878 return 1;
879 }
880 if (read (fd, ze->filename, len) != len)
881 {
882 fprintf (stderr, "%s: %s: unexpected end of file\n",
883 progname, jarfile);
884 return 1;
885 }
886 len = UNPACK_UB4(header, CEN_EFLEN);
887 len += UNPACK_UB4(header, CEN_COMLEN);
888 if (lseek (fd, len, SEEK_CUR) == -1)
889 {
890 perror (progname);
891 return 1;
892 }
893 add_entry (ze);
894 if (i < count - 1)
895 {
896 if (read (fd, header, 46) != 46)
897 {
898 fprintf (stderr, "%s: %s: unexpected end of file\n",
899 progname, jarfile);
900 return 1;
901 }
902 }
903 }
904
905 lseek (fd, 0, SEEK_SET);
906 return 0;
907}
908
909int make_manifest(int jfd, const char *mf_name, int updating){
bd8757b3
APB
910 time_t current_time;
911 int nlen; /* length of file name */
912 int mod_time; /* file modification time */
913 struct zipentry *ze;
914
915 nlen = 9; /* trust me on this one */
916
917 memset((file_header + 12), '\0', 16); /*clear mod time, crc, size fields*/
918
919 current_time = time(NULL);
920 if(current_time == (time_t)-1){
921 perror("time");
922 exit(1);
923 }
924
925 mod_time = unix2dostime(&current_time);
926
927 PACK_UB2(file_header, LOC_EXTRA, 0);
928 PACK_UB2(file_header, LOC_COMP, 0);
929 PACK_UB2(file_header, LOC_FNLEN, nlen);
930 PACK_UB4(file_header, LOC_MODTIME, mod_time);
931
932 if(verbose)
933 printf("adding: META-INF/ (in=0) (out=0) (stored 0%%)\n");
934
935 ze = (zipentry*)malloc(sizeof(zipentry));
936 if(ze == NULL){
937 perror("malloc");
938 exit(1);
939 }
940
941 memset(ze, 0, sizeof(zipentry)); /* clear all the fields*/
942 ze->filename = (char*)malloc((nlen + 1) * sizeof(char) + 1);
943 strcpy(ze->filename, "META-INF/");
944 ze->filename[nlen] = '\0';
945
946 ze->offset = lseek(jfd, 0, SEEK_CUR);
947 ze->mod_time = (ub2)(mod_time & 0x0000ffff);
948 ze->mod_date = (ub2)((mod_time & 0xffff0000) >> 16);
949 ze->compressed = FALSE;
950
951 add_entry(ze);
952
953 write(jfd, file_header, 30);
954 write(jfd, "META-INF/", nlen);
955
956 /* if the user didn't specify an external manifest file... */
957 if(mf_name == NULL){
6838645e
AT
958
959 int mf_len = strlen(MANIFEST_STR) + strlen(VERSION) + strlen(MANIFEST_END);
bd8757b3
APB
960 char *mf;
961
990bee10 962 if((mf = (char *) malloc(mf_len + 1))) {
bd8757b3
APB
963 uLong crc;
964
6838645e 965 sprintf(mf, "%s%s%s", MANIFEST_STR, VERSION, MANIFEST_END);
bd8757b3
APB
966
967 crc = crc32(0L, Z_NULL, 0);
968
990bee10 969 crc = crc32(crc, (const unsigned char *)mf, mf_len);
bd8757b3
APB
970
971 nlen = 20; /* once again, trust me */
972
973 PACK_UB2(file_header, LOC_EXTRA, 0);
974 PACK_UB2(file_header, LOC_COMP, 0);
975 PACK_UB2(file_header, LOC_FNLEN, nlen);
976 PACK_UB4(file_header, LOC_USIZE, mf_len);
977
978 memcpy((file_header + LOC_CSIZE), (file_header + LOC_USIZE), 4);
979
980 PACK_UB4(file_header, LOC_CRC, crc);
981
982 if(verbose)
983 printf("adding: META-INF/MANIFEST.MF (in=56) (out=56) (stored 0%%)\n");
984
985 ze = (zipentry*)malloc(sizeof(zipentry));
986 if(ze == NULL){
987 perror("malloc");
988 exit(1);
989 }
990
991 memset(ze, 0, sizeof(zipentry)); /* clear all the fields*/
992 ze->filename = (char*)malloc((nlen + 1) * sizeof(char) + 1);
993 strcpy(ze->filename, "META-INF/MANIFEST.MF");
994 ze->filename[nlen] = '\0';
995
996 ze->offset = lseek(jfd, 0, SEEK_CUR);
997 ze->mod_time = (ub2)(mod_time & 0x0000ffff);
998 ze->mod_date = (ub2)((mod_time & 0xffff0000) >> 16);
999 ze->crc = crc;
1000 ze->csize = mf_len;
1001 ze->usize = ze->csize;
1002 ze->compressed = FALSE;
1003
1004 add_entry(ze);
1005
1006 write(jfd, file_header, 30);
1007 write(jfd, "META-INF/MANIFEST.MF", nlen);
1008 write(jfd, mf, mf_len);
1009 free(mf);
1010 }
1011 else {
1012 printf("malloc errror\n");
1013 exit(-1);
1014 }
1015 } else {
1016 int mfd;
1017 struct stat statbuf;
1018
1019 stat(mf_name, &statbuf);
1020
1021 if(!S_ISREG(statbuf.st_mode)){
1022 fprintf(stderr, "Invalid manifest file specified.\n");
1023 exit(1);
1024 }
1025
72ea889a 1026 mfd = open(mf_name, O_RDONLY | O_BINARY);
bd8757b3
APB
1027
1028 if(mfd < 0){
1029 fprintf(stderr, "Error opening %s.\n", mf_name);
1030 exit(1);
1031 }
1032
97b62d47 1033 if(add_file_to_jar(jfd, mfd, "META-INF/MANIFEST.MF", &statbuf, updating)){
bd8757b3
APB
1034 perror("error writing to jar");
1035 exit(1);
1036 }
1037
1038 }
1039
1040 return 0;
1041}
1042
5208b50b 1043/* Implements -C by wrapping add_to_jar. new_dir is the directory
97b62d47
MK
1044 to switch to.
1045
1046 `updating', if nonzero, will indicate that we are updating an
1047 existing file, and will need to take special care. If set, we will
1048 also expect that the linked list of zip entries will be filled in
1049 with the jar file's current contents.
1050 */
5208b50b 1051int
97b62d47
MK
1052add_to_jar_with_dir (int fd, const char* new_dir, const char* file,
1053 const int updating)
5208b50b
NN
1054{
1055 int retval;
1056 char old_dir[MAXPATHLEN];
1057 if (getcwd(old_dir, MAXPATHLEN) == NULL) {
1058 perror("getcwd");
1059 return 1;
1060 }
1061 if (chdir(new_dir) == -1) {
1062 perror(new_dir);
1063 return 1;
1064 }
97b62d47 1065 retval=add_to_jar(fd, file, updating);
5208b50b
NN
1066 if (chdir(old_dir) == -1) {
1067 perror(old_dir);
1068 return 1;
1069 }
1070 return retval;
1071}
1072
1073int
97b62d47
MK
1074add_to_jar (int fd, const char *file, const int updating)
1075{
bd8757b3
APB
1076 struct stat statbuf;
1077 DIR *dir;
1078 struct dirent *de;
1079 zipentry *ze;
97b62d47 1080 zipentry *existing = NULL;
bd8757b3 1081 int stat_return;
a55a78d1 1082
bd8757b3
APB
1083 /* This is a quick compatibility fix -- Simon Weijgers <simon@weijgers.com>
1084 * It fixes this:
1085 * "normal" jar : org/apache/java/io/LogRecord.class
1086 * fastjar : ./org/apache/java/io/LogRecord.class
1087 * Fastjar's preservation of the ./'s makes the jarfile unusuable for use
1088 * with both kaffe-1.0b4 and JDK.
1089 */
1090 while (*file=='.' && *(file+1)=='/')
1091 file+=2;
1092
9d8f417b 1093 if(jarfile && !strcmp(file, jarfile)){
bd8757b3
APB
1094 if(verbose)
1095 printf("skipping: %s\n", file);
1096 return 0; /* we don't want to add ourselves.. */
1097 }
1098
1099 stat_return = stat(file, &statbuf);
1100
1101 if(stat_return == -1){
1102 perror(file);
51a25585 1103 return 1;
bd8757b3
APB
1104 } else if(S_ISDIR(statbuf.st_mode)){
1105 char *fullname;
1106 char *t_ptr;
1107 int nlen;
1108 unsigned long mod_time;
1109
1110 dir = opendir(file);
1111
1112 if(dir == NULL){
1113 perror("opendir");
1114 return 1;
1115 }
1116
1117 nlen = strlen(file) + 256;
1118 fullname = (char*)malloc(nlen * sizeof(char));
1119 memset(fullname, 0, (nlen * sizeof(char)));
1120
1121 if(fullname == NULL){
1122 fprintf(stderr, "Filename is NULL!\n");
1123 return 1;
1124 }
1125
1126 strcpy(fullname, file);
1127 nlen = strlen(file);
1128
1129 if(fullname[nlen - 1] != '/'){
1130 fullname[nlen] = '/';
1131 t_ptr = (fullname + nlen + 1);
1132 } else
1133 t_ptr = (fullname + nlen);
1134
1135
1136 memset((file_header + 12), '\0', 16); /*clear mod time, crc, size fields*/
1137
1138 nlen = (t_ptr - fullname);
1139
1140 mod_time = unix2dostime(&statbuf.st_mtime);
1141
1142 PACK_UB2(file_header, LOC_EXTRA, 0);
1143 PACK_UB2(file_header, LOC_COMP, 0);
1144 PACK_UB2(file_header, LOC_FNLEN, nlen);
1145 PACK_UB4(file_header, LOC_MODTIME, mod_time);
1146
bd8757b3
APB
1147 ze = (zipentry*)malloc(sizeof(zipentry));
1148 if(ze == NULL){
1149 perror("malloc");
1150 exit(1);
1151 }
1152
1153 memset(ze, 0, sizeof(zipentry)); /* clear all the fields*/
1154 ze->filename = (char*)malloc((nlen + 1) * sizeof(char) + 1);
1155 strcpy(ze->filename, fullname);
1156 ze->filename[nlen] = '\0';
1157
1158 ze->offset = lseek(fd, 0, SEEK_CUR);
1159 ze->mod_time = (ub2)(mod_time & 0x0000ffff);
1160 ze->mod_date = (ub2)((mod_time & 0xffff0000) >> 16);
1161 ze->compressed = FALSE;
1162
97b62d47
MK
1163 if (updating)
1164 {
1165 if ((existing = find_entry (ze->filename)) != NULL)
1166 {
1167 if (existing->usize != 0)
1168 {
1169 /* XXX overwriting non-directory with directory? */
1170 fprintf (stderr, "%s: %s: can't overwrite non-directory with directory\n",
1171 progname, fullname);
1172 return 1;
1173 }
1174 }
1175 if (lseek (fd, end_of_entries, SEEK_SET) == -1)
1176 {
1177 fprintf (stderr, "%s %d\n", __FILE__, __LINE__);
1178 perror ("lseek");
1179 return 1;
1180 }
1181 }
1182
1183 if (!existing)
1184 {
1185 add_entry (ze);
1186 write (fd, file_header, 30);
1187 write (fd, fullname, nlen);
1188 end_of_entries = lseek (fd, 0, SEEK_CUR);
bd8757b3 1189
97b62d47
MK
1190 if (verbose)
1191 printf ("adding: %s (in=%d) (out=%d) (stored 0%%)\n", fullname, 0, 0);
1192 }
bd8757b3
APB
1193
1194 while(!use_explicit_list_only && (de = readdir(dir)) != NULL){
1195 if(de->d_name[0] == '.')
1196 continue;
9d8f417b
JJ
1197 if(jarfile && !strcmp(de->d_name, jarfile)){
1198 /* we don't want to add ourselves. Believe me */
bd8757b3
APB
1199 if(verbose)
1200 printf("skipping: %s\n", de->d_name);
1201 continue;
1202 }
1203
1204 strcpy(t_ptr, de->d_name);
1205
97b62d47 1206 if (add_to_jar(fd, fullname, updating)) {
bd8757b3
APB
1207 fprintf(stderr, "Error adding file to jar!\n");
1208 return 1;
1209 }
1210 }
1211
1212 free(fullname);
1213 closedir(dir);
1214
1215 } else if(S_ISREG(statbuf.st_mode)){
1216 int add_fd;
1217
72ea889a 1218 add_fd = open(file, O_RDONLY | O_BINARY);
bd8757b3
APB
1219 if(add_fd < 0){
1220 fprintf(stderr, "Error opening %s.\n", file);
5208b50b 1221 return 1;
bd8757b3
APB
1222 }
1223
97b62d47 1224 if(add_file_to_jar(fd, add_fd, file, &statbuf, updating)){
bd8757b3
APB
1225 fprintf(stderr, "Error adding file to jar!\n");
1226 return 1;
1227 }
1228
1229 } else {
1230 fprintf(stderr, "Illegal file specified: %s\n", file);
1231 }
bd8757b3
APB
1232 return 0;
1233}
1234
97b62d47
MK
1235int add_file_to_jar(int jfd, int ffd, const char *fname, struct stat *statbuf,
1236 const int updating)
1237{
bd8757b3
APB
1238 unsigned short file_name_length;
1239 unsigned long mod_time;
1240 ub1 rd_buff[RDSZ];
1241 uLong crc = 0;
1242 off_t offset = 0;
1243 int rdamt;
1244 struct zipentry *ze;
97b62d47
MK
1245 struct zipentry *existing = NULL;
1246
1247 if (updating)
1248 {
1249 existing = find_entry (fname);
1250 if (existing && looks_like_dir (fname))
1251 {
1252 fprintf (stderr, "%s: %s is a directory in the archive\n",
1253 progname, fname);
1254 return 1;
1255 }
1256 }
bd8757b3
APB
1257
1258 mod_time = unix2dostime(&(statbuf->st_mtime));
1259 file_name_length = strlen(fname);
1260
1261 if(!seekable && !do_compress){
1262 crc = crc32(0L, Z_NULL, 0);
1263
1264 while((rdamt = read(ffd, rd_buff, RDSZ)) != 0)
1265 crc = crc32(crc, rd_buff, rdamt);
1266
1267 lseek(ffd, 0, SEEK_SET);
1268 }
1269
1270 /* data descriptor */
1271 if(!seekable && do_compress){
1272 PACK_UB2(file_header, LOC_EXTRA, 8);
1273 } else {
1274 PACK_UB2(file_header, LOC_EXTRA, 0);
1275 }
1276
1277 if(do_compress){
1278 PACK_UB2(file_header, LOC_COMP, 8);
1279 } else {
1280 PACK_UB2(file_header, LOC_COMP, 0);
1281 }
1282
1283 PACK_UB4(file_header, LOC_MODTIME, mod_time);
1284 PACK_UB2(file_header, LOC_FNLEN, file_name_length);
1285
1286 if(!seekable && !do_compress){
1287 PACK_UB4(file_header, LOC_CRC, crc);
1288 PACK_UB4(file_header, LOC_USIZE, statbuf->st_size);
1289 PACK_UB4(file_header, LOC_CSIZE, statbuf->st_size);
1290 } else
1291 memset((file_header + LOC_CRC), '\0', 12); /* clear crc/usize/csize */
1292
1293 ze = (zipentry*)malloc(sizeof(zipentry));
1294 if(ze == NULL){
1295 perror("malloc");
1296 exit(1);
1297 }
1298
1299 memset(ze, 0, sizeof(zipentry)); /* clear all the fields*/
1300 ze->filename = (char*)malloc((file_name_length + 1) * sizeof(char));
1301 strcpy(ze->filename, fname);
1302
1303 ze->mod_time = (ub2)(mod_time & 0x0000ffff);
1304 ze->mod_date = (ub2)((mod_time & 0xffff0000) >> 16);
1305
1306 if(!seekable && !do_compress)
1307 ze->crc = crc;
1308
1309 ze->csize = statbuf->st_size;
1310 ze->usize = ze->csize;
97b62d47
MK
1311
1312 if (existing)
1313 ze->offset = existing->offset;
1314 else if (updating)
1315 ze->offset = end_of_entries;
1316 else
1317 ze->offset = lseek(jfd, 0, SEEK_CUR);
1318
bd8757b3
APB
1319 if(do_compress)
1320 ze->compressed = TRUE;
1321 else
1322 ze->compressed = FALSE;
97b62d47
MK
1323
1324 if (!existing)
1325 add_entry(ze);
1326 if (updating && lseek (jfd, ze->offset, SEEK_SET) < 0)
1327 {
1328 perror ("lseek");
1329 return 1;
1330 }
1331
1332 /* We can safely write the header here, since it will be the same size
1333 as before */
bd8757b3
APB
1334
1335 /* Write the local header */
1336 write(jfd, file_header, 30);
1337
1338 /* write the file name to the zip file */
1339 write(jfd, fname, file_name_length);
1340
1341
1342 if(verbose){
97b62d47
MK
1343 if (existing)
1344 printf ("updating: %s ", fname);
1345 else
1346 printf("adding: %s ", fname);
bd8757b3
APB
1347 fflush(stdout);
1348 }
1349
1350 if(do_compress){
1351 /* compress the file */
97b62d47 1352 compress_file(ffd, jfd, ze, existing);
bd8757b3 1353 } else {
97b62d47
MK
1354 /* If we are not writing the last entry, make space for it. */
1355 if (existing && existing->next_entry)
1356 {
1357 if (ze->usize > existing->usize)
1358 {
1359 if (shift_down (jfd, existing->next_entry->offset,
1360 ze->usize - existing->usize, existing->next_entry))
1361 {
1362 fprintf (stderr, "%s: %s\n", progname, strerror (errno));
1363 return 1;
1364 }
1365 }
1366 }
1367
bd8757b3
APB
1368 /* Write the contents of the file (uncompressed) to the zip file */
1369 /* calculate the CRC as we go along */
1370 ze->crc = crc32(0L, Z_NULL, 0);
1371
1372 while((rdamt = read(ffd, rd_buff, RDSZ)) != 0){
1373 ze->crc = crc32(ze->crc, rd_buff, rdamt);
1374 if(write(jfd, rd_buff, rdamt) != rdamt){
1375 perror("write");
1376 return 0;
1377 }
1378 }
1379 }
1380 close(ffd);
1381
1382 /* write out data descriptor */
1383 PACK_UB4(data_descriptor, 4, ze->crc);
1384 PACK_UB4(data_descriptor, 8, ze->csize);
1385 PACK_UB4(data_descriptor, 12, ze->usize);
1386
1387 /* we need to seek back and fill the header */
1388 if(seekable){
1389 offset = (ze->csize + strlen(ze->filename) + 16);
1390
1391 if(lseek(jfd, -offset, SEEK_CUR) == (off_t)-1){
1392 perror("lseek");
1393 exit(1);
1394 }
1395
1396 if(write(jfd, (data_descriptor + 4), 12) != 12){
1397 perror("write");
1398 return 0;
1399 }
1400
1401 offset -= 12;
1402
1403 if(lseek(jfd, offset, SEEK_CUR) == (off_t)-1){
1404 perror("lseek");
1405 exit(1);
1406 }
1407 } else if(do_compress){
1408 /* Sun's jar tool will only allow a data descriptor if the entry is
1409 compressed, but we'll save 16 bytes/entry if we only use it when
1410 we can't seek back on the file */
97b62d47
MK
1411 /* Technically, you CAN'T have a data descriptor unless the data
1412 part has an obvious end, which DEFLATED does. Otherwise, there
1413 would not be any way to determine where the data descriptor is.
1414 Store an uncompressed file that ends with 0x504b0708, and see.
1415 -- csm */
bd8757b3
APB
1416
1417 if(write(jfd, data_descriptor, 16) != 16){
1418 perror("write");
1419 return 0;
1420 }
1421 }
97b62d47
MK
1422
1423 if (existing)
1424 {
1425 int dd = (existing->flags & (1 << 3)) ? 12 : 0;
1426 if (existing->next_entry && ze->csize < existing->csize + dd)
1427 {
1428 if (shift_up (jfd, existing->next_entry->offset,
1429 existing->csize + dd - ze->csize,
1430 existing->next_entry))
1431 {
1432 perror (progname);
1433 return 1;
1434 }
1435 }
1436 /* Replace the existing entry data with this entry's. */
1437 existing->csize = ze->csize;
1438 existing->usize = ze->usize;
1439 existing->crc = ze->crc;
1440 existing->mod_time = ze->mod_time;
1441 existing->mod_date = ze->mod_date;
1442 free (ze->filename);
1443 free (ze);
1444 }
1445 else if (updating)
1446 end_of_entries = lseek (jfd, 0, SEEK_CUR);
bd8757b3
APB
1447
1448 if(verbose)
1449 printf("(in=%d) (out=%d) (%s %d%%)\n",
1450 (int)ze->usize, (int)ze->csize,
1451 (do_compress ? "deflated" : "stored"),
1452 (do_compress ? ((int)((1 - ze->csize/(float)ze->usize) * 100)) : 0));
1453
1454 return 0;
1455}
1456
1457int create_central_header(int fd){
1458 ub1 header[46];
1459 ub1 end_header[22];
1460 int start_offset;
1461 int dir_size;
bd8757b3
APB
1462 int total_in = 0, total_out = 22;
1463
1464 zipentry *ze;
1465
bd8757b3
APB
1466 /* magic number */
1467 header[0] = 'P';
1468 header[1] = 'K';
1469 header[2] = 1;
1470 header[3] = 2;
1471 /* version made by */
1472 header[4] = 10;
1473 header[5] = 0;
1474 /* version needed to extract */
1475 header[6] = 10;
1476 header[7] = 0;
1477 /* bit flag */
1478 header[8] = 0;
1479 header[9] = 0;
1480 /* compression method */
1481 header[10] = 0;
1482 header[11] = 0;
1483 /* file mod time */
1484 header[12] = 0;
1485 header[13] = 0;
1486 /* file mod date */
1487 header[14] = 0;
1488 header[15] = 0;
1489 /* crc 32 */
1490 header[16] = 0;
1491 header[17] = 0;
1492 header[18] = 0;
1493 header[19] = 0;
1494 /* compressed size */
1495 header[20] = 0;
1496 header[21] = 0;
1497 header[22] = 0;
1498 header[23] = 0;
1499 /* uncompressed size */
1500 header[24] = 0;
1501 header[25] = 0;
1502 header[26] = 0;
1503 header[27] = 0;
1504 /* filename length */
1505 header[28] = 0;
1506 header[29] = 0;
1507 /* extra field length */
1508 header[30] = 0;
1509 header[31] = 0;
1510 /* file comment length */
1511 header[32] = 0;
1512 header[33] = 0;
1513 /* disk number start */
1514 header[34] = 0;
1515 header[35] = 0;
1516 /* internal file attribs */
1517 header[36] = 0;
1518 header[37] = 0;
1519 /* external file attribs */
1520 header[38] = 0;
1521 header[39] = 0;
1522 header[40] = 0;
1523 header[41] = 0;
1524 /* relative offset of local header */
1525 header[42] = 0;
1526 header[43] = 0;
1527 header[44] = 0;
1528 header[45] = 0;
1529
1530 start_offset = lseek(fd, 0, SEEK_CUR);
1531
1532 for(ze = ziptail; ze != NULL; ze = ze->next_entry){
1533
1534 total_in += ze->usize;
1535 total_out += ze->csize + 76 + strlen(ze->filename) * 2;
1536
1537 if(ze->compressed){
1538 PACK_UB2(header, CEN_COMP, 8);
1539 } else {
1540 PACK_UB2(header, CEN_COMP, 0);
1541 }
1542
1543 PACK_UB2(header, CEN_MODTIME, ze->mod_time);
1544 PACK_UB2(header, CEN_MODDATE, ze->mod_date);
1545 PACK_UB4(header, CEN_CRC, ze->crc);
1546 PACK_UB4(header, CEN_CSIZE, ze->csize);
1547 PACK_UB4(header, CEN_USIZE, ze->usize);
1548 PACK_UB2(header, CEN_FNLEN, strlen(ze->filename));
1549 PACK_UB4(header, CEN_OFFSET, ze->offset);
1550
1551 write(fd, header, 46);
1552
1553 write(fd, ze->filename, strlen(ze->filename));
1554 }
1555
1556 dir_size = lseek(fd, 0, SEEK_CUR) - start_offset;
1557
1558 /* magic number */
1559 end_header[0] = 0x50;
1560 end_header[1] = 0x4b;
1561 end_header[2] = 0x05;
1562 end_header[3] = 0x06;
1563 /* number of this disk */
1564 end_header[4] = 0;
1565 end_header[5] = 0;
1566 /* number of disk w/ start of central header */
1567 end_header[6] = 0;
1568 end_header[7] = 0;
1569 /* total number of entries in central dir on this disk*/
1570 PACK_UB2(end_header, 8, number_of_entries);
1571 /* total number of entries in central dir*/
1572 PACK_UB2(end_header, 10, number_of_entries);
1573 /* size of central dir. */
1574 PACK_UB4(end_header, 12, dir_size);
1575 /* offset of start of central dir */
1576 PACK_UB4(end_header, 16, start_offset);
1577 /* zipfile comment length */
1578 end_header[20] = 0;
1579 end_header[21] = 0;
1580
1581 write(fd, end_header, 22);
1582
1583 if(verbose)
1584 printf("Total:\n------\n(in = %d) (out = %d) (%s %d%%)\n",
1585 total_in,
1586 total_out,
1587 (do_compress ? "deflated" : "stored"),
1588 (int)((1 - (total_out / (float)total_in)) * 100)
1589 );
1590
1591 return 0;
1592}
1593
1594int extract_jar(int fd, char **files, int file_num){
1595 int rdamt;
1596 int out_a, in_a;
1597 ub4 signature;
1598 ub4 csize;
1599 ub4 crc;
1600 ub2 fnlen;
1601 ub2 eflen;
1602 ub2 flags;
1603 ub2 method;
1604 ub1 *filename = NULL;
1605 int filename_len = 0;
1606 ub4 rd_buff[RDSZ];
1607 pb_file pbf;
1608 ub1 scratch[16];
1609 zipentry ze;
1610 int f_fd;
1611 int dir;
1612 int handle;
1613 int j;
1614
1615 init_inflation();
1616
1617 pb_init(&pbf, fd);
1618
1619 for(;;){
1620 f_fd = 0;
1621 crc = 0;
1622 ze.crc = 0;
1623
1624 dir = FALSE; /* by default, the file isn't a dir */
1625 handle = TRUE; /* by default we'll extract/create the file */
1626
1627 if((rdamt = pb_read(&pbf, scratch, 4)) != 4){
1628 perror("read");
1629 break;
1630 }
1631
1632 signature = UNPACK_UB4(scratch, 0);
1633
1634#ifdef DEBUG
1635 printf("signature is %x\n", signature);
1636#endif
1637 if(signature == 0x08074b50){
1638#ifdef DEBUG
1639 printf("skipping data descriptor\n");
1640#endif
1641 pb_read(&pbf, scratch, 12);
1642 continue;
1643 } else if(signature == 0x02014b50){
1644#ifdef DEBUG
1645 printf("Central header reached.. we're all done!\n");
1646#endif
1647 break;
1648 }else if(signature != 0x04034b50){
1649 printf("Ick! %#x\n", signature);
1650 break;
1651 }
1652
1653 if((rdamt = pb_read(&pbf, (file_header + 4), 26)) != 26){
1654 perror("read");
1655 break;
1656 }
1657
1658 csize = UNPACK_UB4(file_header, LOC_CSIZE);
1659#ifdef DEBUG
1660 printf("Compressed size is %u\n", csize);
1661#endif
1662
1663 fnlen = UNPACK_UB2(file_header, LOC_FNLEN);
1664#ifdef DEBUG
1665 printf("Filename length is %hu\n", fnlen);
1666#endif
1667
1668 eflen = UNPACK_UB2(file_header, LOC_EFLEN);
1669#ifdef DEBUG
1670 printf("Extra field length is %hu\n", eflen);
1671#endif
1672
1673 flags = UNPACK_UB2(file_header, LOC_EXTRA);
1674#ifdef DEBUG
1675 printf("Flags are %#hx\n", flags);
1676#endif
1677
1678 method = UNPACK_UB2(file_header, LOC_COMP);
1679#ifdef DEBUG
1680 printf("Compression method is %#hx\n", method);
1681#endif
1682
1683 /* if there isn't a data descriptor */
1684 if(!(flags & 0x0008)){
1685 crc = UNPACK_UB4(file_header, LOC_CRC);
1686#ifdef DEBUG
1687 printf("CRC is %x\n", crc);
1688#endif
1689 }
1690
ac43be73 1691 if(filename_len < fnlen + 1){
bd8757b3
APB
1692 if(filename != NULL)
1693 free(filename);
1694
1695 filename = malloc(sizeof(ub1) * (fnlen + 1));
1696 filename_len = fnlen + 1;
1697 }
1698
1699 pb_read(&pbf, filename, fnlen);
1700 filename[fnlen] = '\0';
1701
1702#ifdef DEBUG
1703 printf("filename is %s\n", filename);
1704#endif
1705
1706 if(file_num > 0){
1707 handle = FALSE;
1708
1709 for(j = 0; j < file_num; j++)
990bee10 1710 if(strcmp(files[j], (const char *)filename) == 0){
bd8757b3
APB
1711 handle = TRUE;
1712 break;
1713 }
1714 }
1715
1716 if(!handle)
1717 f_fd = -1;
1718
1719 /* OK, there is some directory information in the file. Nothing to do
1720 but ensure the directory(s) exist, and create them if they don't.
1721 What a pain! */
990bee10 1722 if(strchr((const char *)filename, '/') != NULL && handle){
bd8757b3 1723 /* Loop through all the directories in the path, (everything w/ a '/') */
990bee10 1724 const ub1 *start = filename;
bd8757b3
APB
1725 char *tmp_buff;
1726 struct stat sbuf;
1727
990bee10 1728 tmp_buff = malloc(sizeof(char) * strlen((const char *)filename));
bd8757b3
APB
1729
1730 for(;;){
990bee10 1731 const ub1 *idx = (const unsigned char *)strchr((const char *)start, '/');
bd8757b3
APB
1732
1733 if(idx == NULL)
1734 break;
1735 else if(idx == start){
1736 start++;
1737 continue;
1738 }
1739 start = idx + 1;
1740
990bee10 1741 strncpy(tmp_buff, (const char *)filename, (idx - filename));
bd8757b3
APB
1742 tmp_buff[(idx - filename)] = '\0';
1743
1744#ifdef DEBUG
1745 printf("checking the existance of %s\n", tmp_buff);
1746#endif
1747
1748 if(stat(tmp_buff, &sbuf) < 0){
1749 if(errno != ENOENT){
1750 perror("stat");
1751 exit(1);
1752 }
1753
1754 } else if(S_ISDIR(sbuf.st_mode)){
1755#ifdef DEBUG
1756 printf("Directory exists\n");
1757#endif
1758 continue;
1759 }else {
1760 fprintf(stderr, "Hmmm.. %s exists but isn't a directory!\n",
1761 tmp_buff);
1762 exit(1);
1763 }
1764
1765#ifdef DEBUG
1766 printf("Making directory..\n");
1767#endif
1768 if(mkdir(tmp_buff, 0755) < 0){
1769 perror("mkdir");
1770 exit(1);
1771 }
1772 if(verbose && handle)
1773 printf("%10s: %s/\n", "created", tmp_buff);
1774
1775 }
1776
1777 /* only a directory */
990bee10 1778 if(strlen((const char *)start) == 0)
bd8757b3
APB
1779 dir = TRUE;
1780
1781#ifdef DEBUG
990bee10 1782 printf("Leftovers are \"%s\" (%d)\n", start, strlen((const char *)start));
bd8757b3
APB
1783#endif
1784
1785 /* If the entry was just a directory, don't write to file, etc */
990bee10 1786 if(strlen((const char *)start) == 0)
bd8757b3
APB
1787 f_fd = -1;
1788
1789 free(tmp_buff);
1790 }
1791
1792 if(f_fd != -1 && handle){
7fe75c03
RM
1793 f_fd = open((const char *)filename,
1794 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
bd8757b3
APB
1795
1796 if(f_fd < 0){
1797 fprintf(stderr, "Error extracting JAR archive!\n");
990bee10 1798 perror((const char *)filename);
bd8757b3
APB
1799 exit(1);
1800 }
1801 }
1802
1803 if(method != 8 && flags & 0x0008){
1804 fprintf(stderr, "Error in JAR file! (not compressed but data desc.)\n");
1805 exit(1);
1806 }
1807
847450b4
TT
1808 if (eflen > 0)
1809 consume(&pbf, eflen);
1810
bd8757b3 1811 if(method == 8 || flags & 0x0008){
bd8757b3
APB
1812
1813 inflate_file(&pbf, f_fd, &ze);
1814 } else {
1815
1816#ifdef DEBUG
1817 printf("writing stored data.. (%d bytes)\n", csize);
1818#endif
1819
1820 out_a = 0;
1821 in_a = csize;
1822
1823 ze.crc = crc32(ze.crc, NULL, 0); /* initialize the crc */
1824
79801091 1825 while(out_a < (int)csize){
bd8757b3
APB
1826 rdamt = (in_a > RDSZ ? RDSZ : in_a);
1827 if(pb_read(&pbf, rd_buff, rdamt) != rdamt){
1828 perror("read");
1829 exit(1);
1830 }
1831
1832 ze.crc = crc32(ze.crc, (Bytef*)rd_buff, rdamt);
1833
1834 if(f_fd >= 0)
1835 write(f_fd, rd_buff, rdamt);
1836
1837 out_a += rdamt;
1838 in_a -= rdamt;
1839
1840#ifdef DEBUG
1841 printf("%d bytes written\n", out_a);
1842#endif
1843 }
bd8757b3
APB
1844 }
1845
1846 /* if there is a data descriptor left, compare the CRC */
1847 if(flags & 0x0008){
1848
1849 if(pb_read(&pbf, scratch, 16) != 16){
1850 perror("read");
1851 exit(1);
1852 }
1853
1854 signature = UNPACK_UB4(scratch, 0);
1855
1856 if(signature != 0x08074b50){
1857 fprintf(stderr, "Error! Missing data descriptor!\n");
1858 exit(1);
1859 }
1860
1861 crc = UNPACK_UB4(scratch, 4);
1862
1863 }
1864
1865 if(crc != ze.crc){
1866 fprintf(stderr, "Error! CRCs do not match! Got %x, expected %x\n",
1867 ze.crc, crc);
1868 exit(1);
1869 }
1870
1871 close(f_fd);
1872
1873 if(verbose && dir == FALSE && handle)
1874 printf("%10s: %s\n",
1875 (method == 8 ? "inflated" : "extracted"),
1876 filename);
1877 }
1878
1879 return 0;
1880}
1881
1882int list_jar(int fd, char **files, int file_num){
bd8757b3
APB
1883 ub4 signature;
1884 ub4 csize;
1885 ub4 usize;
1886 ub4 mdate;
1887 ub4 tmp;
1888 ub2 fnlen;
1889 ub2 eflen;
1890 ub2 clen;
1891 ub2 flags;
1892 ub2 method;
1893 ub2 cen_size;
1894 ub1 *filename = NULL;
1895 ub1 scratch[16];
1896 ub1 cen_header[46];
1897 int filename_len = 0;
1898 off_t size;
1899 int i, j;
1900 time_t tdate;
1901 struct tm *s_tm;
b39864a9 1902 char ascii_date[31];
bd8757b3
APB
1903 zipentry ze;
1904
1905#ifdef DEBUG
1906 printf("Listing jar file, looking for %d files\n", file_num);
1907#endif
1908
1909 /* This should be the start of the central-header-end section */
1910 if(seekable){
1911 if(lseek(fd, -22, SEEK_END) == (off_t)-1){
1912 perror("lseek");
1913 exit(1);
1914 }
1915
1916 if(read(fd, &tmp, sizeof(ub4)) != 4){
1917 perror("read");
1918 exit(1);
1919 }
1920
1921#ifdef WORDS_BIGENDIAN
1922 tmp = L2BI(tmp);
1923#endif
1924
1925 if(tmp != 0x06054b50){
1926 fprintf(stderr, "Error in JAR file format. zip-style comment?\n");
1927 exit(1);
1928 }
1929
1930 if(lseek(fd, 6, SEEK_CUR) == (off_t)-1){
1931 perror("lseek");
1932 exit(1);
1933 }
1934
1935 if(read(fd, &cen_size, 2) != 2){
1936 perror("read");
1937 exit(1);
1938 }
1939
1940#ifdef WORDS_BIGENDIAN
1941 cen_size = L2BS(cen_size);
1942#endif
1943
1944 /* printf("%hu entries in central header\n", cen_size); */
1945
1946 if(lseek(fd, 4, SEEK_CUR) == (off_t)-1){
1947 perror("lseek");
1948 exit(1);
1949 }
1950
1951 if(read(fd, &tmp, 4) != 4){
1952 perror("read");
1953 exit(1);
1954 }
1955
1956#ifdef WORDS_BIGENDIAN
1957 tmp = L2BI(tmp);
1958#endif
1959
1960 /* printf("Central header offset = %d\n", tmp); */
1961
79801091 1962 if(lseek(fd, tmp, SEEK_SET) != (int)tmp){
bd8757b3
APB
1963 perror("lseek");
1964 exit(1);
1965 }
1966
1967 /* Loop through the entries in the central header */
1968 for(i = 0; i < cen_size; i++){
1969
1970 if(read(fd, &cen_header, 46) != 46){
1971 perror("read");
1972 exit(1);
1973 }
1974
1975 signature = UNPACK_UB4(cen_header, 0);
1976 if(signature != 0x02014b50){
1977 fprintf(stderr, "Error in JAR file! Cannot locate central header!\n");
1978 exit(1);
1979 }
1980
1981 usize = UNPACK_UB4(cen_header, CEN_USIZE);
1982 fnlen = UNPACK_UB2(cen_header, CEN_FNLEN);
1983 eflen = UNPACK_UB2(cen_header, CEN_EFLEN);
1984 clen = UNPACK_UB2(cen_header, CEN_COMLEN);
1985
1986 /* If we're providing verbose output, we need to make an ASCII
1987 * formatted version of the date. */
1988 if(verbose){
1989 mdate = UNPACK_UB4(cen_header, CEN_MODTIME);
1990 tdate = dos2unixtime(mdate);
1991 s_tm = localtime(&tdate);
1992 strftime(ascii_date, 30, "%a %b %d %H:%M:%S %Z %Y", s_tm);
b39864a9 1993 ascii_date[30] = '\0';
bd8757b3
APB
1994 }
1995
a038cc83 1996 if(filename_len < fnlen + 1){
bd8757b3
APB
1997 if(filename != NULL)
1998 free(filename);
1999
2000 filename = malloc(sizeof(ub1) * (fnlen + 1));
2001 filename_len = fnlen + 1;
2002 }
2003
2004 if(read(fd, filename, fnlen) != fnlen){
2005 perror("read");
2006 exit(1);
2007 }
2008 filename[fnlen] = '\0';
2009
2010 /* if the user specified a list of files on the command line,
2011 we'll only display those, otherwise we'll display everything */
2012 if(file_num > 0){
2013 for(j = 0; j < file_num; j++)
990bee10 2014 if(strcmp(files[j], (const char *)filename) == 0){
bd8757b3
APB
2015 if(verbose)
2016 printf("%6d %s %s\n", usize, ascii_date, filename);
2017 else
2018 printf("%s\n", filename);
2019 break;
2020 }
2021 } else {
2022 if(verbose)
2023 printf("%6d %s %s\n", usize, ascii_date, filename);
2024 else
2025 printf("%s\n", filename);
2026 }
2027
2028 size = eflen + clen;
2029 if(size > 0){
2030 if(lseek(fd, size, SEEK_CUR) == (off_t)-1){
2031 perror("lseek");
2032 exit(1);
2033 }
2034 }
2035 }
2036 } else {
2037 /* the file isn't seekable.. evil! */
2038 pb_file pbf;
2039
2040 pb_init(&pbf, fd);
2041
2042 init_inflation();
2043
2044 for(;;){
4977bab6 2045 if(pb_read(&pbf, scratch, 4) != 4){
bd8757b3
APB
2046 perror("read");
2047 break;
2048 }
2049
2050 signature = UNPACK_UB4(scratch, 0);
2051
2052#ifdef DEBUG
2053 printf("signature is %x\n", signature);
2054#endif
2055
2056 if(signature == 0x08074b50){
2057#ifdef DEBUG
2058 printf("skipping data descriptor\n");
2059#endif
2060 pb_read(&pbf, scratch, 12);
2061 continue;
2062 } else if(signature == 0x02014b50){
2063#ifdef DEBUG
2064 printf("Central header reached.. we're all done!\n");
2065#endif
2066 break;
2067 }else if(signature != 0x04034b50){
2068#ifdef DEBUG
2069 printf("Ick! %#x\n", signature);
2070#endif
2071 break;
2072 }
2073
4977bab6 2074 if(pb_read(&pbf, (file_header + 4), 26) != 26){
bd8757b3
APB
2075 perror("read");
2076 break;
2077 }
2078
2079 csize = UNPACK_UB4(file_header, LOC_CSIZE);
2080#ifdef DEBUG
2081 printf("Compressed size is %u\n", csize);
2082#endif
2083
2084 fnlen = UNPACK_UB2(file_header, LOC_FNLEN);
2085#ifdef DEBUG
2086 printf("Filename length is %hu\n", fnlen);
2087#endif
2088
2089 eflen = UNPACK_UB2(file_header, LOC_EFLEN);
2090#ifdef DEBUG
2091 printf("Extra field length is %hu\n", eflen);
2092#endif
2093
2094 method = UNPACK_UB2(file_header, LOC_COMP);
2095#ifdef DEBUG
2096 printf("Compression method is %#hx\n", method);
2097#endif
2098
2099 flags = UNPACK_UB2(file_header, LOC_EXTRA);
2100#ifdef DEBUG
2101 printf("Flags are %#hx\n", flags);
2102#endif
2103
2104 usize = UNPACK_UB4(file_header, LOC_USIZE);
2105
2106 /* If we're providing verbose output, we need to make an ASCII
2107 * formatted version of the date. */
2108 if(verbose){
2109 mdate = UNPACK_UB4(file_header, LOC_MODTIME);
2110 tdate = dos2unixtime(mdate);
2111 s_tm = localtime(&tdate);
2112 strftime(ascii_date, 30, "%a %b %d %H:%M:%S %Z %Y", s_tm);
2113 }
2114
a038cc83 2115 if(filename_len < fnlen + 1){
bd8757b3
APB
2116 if(filename != NULL)
2117 free(filename);
2118
2119 filename = malloc(sizeof(ub1) * (fnlen + 1));
b39864a9 2120 ascii_date[30] = '\0';
bd8757b3
APB
2121 filename_len = fnlen + 1;
2122 }
2123
2124 pb_read(&pbf, filename, fnlen);
2125 filename[fnlen] = '\0';
2126
2127 /* the header is at the end. In a JAR file, this means that the data
2128 happens to be compressed. We have no choice but to inflate the
2129 data */
2130 if(flags & 0x0008){
2131
2132 size = eflen;
2133
2134 if(size > 0)
2135 consume(&pbf, size);
2136
2137 if(method == 8){
2138#ifdef DEBUG
2139 printf("inflating %s\n", filename);
2140#endif
2141 inflate_file(&pbf, -1, &ze);
2142
2143 usize = ze.usize;
2144 } else
2145 printf("We're shit outta luck!\n");
2146
2147 } else {
2148 size = csize + (eflen > 0 ? eflen : 0);
2149
2150
2151#ifdef DEBUG
990bee10 2152 printf("Skipping %ld bytes\n", (long)size);
bd8757b3
APB
2153#endif
2154
2155 consume(&pbf, size);
2156 }
2157 /* print out the listing */
2158 if(file_num > 0){
2159 for(j = 0; j < file_num; j++)
990bee10 2160 if(strcmp(files[j], (const char *)filename) == 0){
bd8757b3
APB
2161 if(verbose)
2162 printf("%6d %s %s\n", usize, ascii_date, filename);
2163 else
2164 printf("%s\n", filename);
2165 break;
2166 }
2167 } else {
2168 if(verbose)
2169 printf("%6d %s %s\n", usize, ascii_date, filename);
2170 else
2171 printf("%s\n", filename);
2172 }
2173 }
2174 }
2175 return 0;
2176}
2177
2178int consume(pb_file *pbf, int amt){
2179 int tc = 0; /* total amount consumed */
2180 ub1 buff[RDSZ];
2181 int rdamt;
2182
2183#ifdef DEBUG
2184 printf("Consuming %d bytes\n", amt);
2185#endif
2186
0120f3d4
DU
2187 if (seekable){
2188 if (amt <= (int)pbf->buff_amt)
2189 pb_read(pbf, buff, amt);
2190 else {
2191 lseek(pbf->fd, amt - pbf->buff_amt, SEEK_CUR);
2192 pb_read(pbf, buff, pbf->buff_amt); /* clear pbf */
2193 }
2194 } else
bd8757b3
APB
2195 while(tc < amt){
2196 rdamt = pb_read(pbf, buff, ((amt - tc) < RDSZ ? (amt - tc) : RDSZ));
2197#ifdef DEBUG
2198 printf("got %d bytes\n", rdamt);
2199#endif
2200 tc += rdamt;
2201 }
2202
2203#ifdef DEBUG
0120f3d4 2204 printf("%d bytes consumed\n", amt);
bd8757b3
APB
2205#endif
2206
2207 return 0;
2208}
2209
990bee10 2210void usage(const char *filename){
7a93476d
TT
2211 fprintf(stderr, "Try `%s --help' for more information.\n", filename);
2212 exit (1);
2213}
2214
2215void version ()
2216{
2217 printf("jar (%s) %s\n\n", PACKAGE, VERSION);
2218 printf("Copyright 1999, 2000, 2001 Bryan Burns\n");
97b62d47 2219 printf("Copyright 2002, 2004 Free Software Foundation\n");
7a93476d
TT
2220 printf("\
2221This is free software; see the source for copying conditions. There is NO\n\
2222warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n");
2223 exit (0);
2224}
2225
2226void help(const char *filename)
2227{
2228 printf("\
990bee10 2229Usage: %s {ctxuV}[vfm0ME@] [jar-file] [manifest-file] [-C dir] files ...\n\
7a93476d
TT
2230\n\
2231Store many files together in a single `jar' file.\n\
2232\n\
2233 -c create new archive\n\
2234 -t list table of contents for archive\n\
2235 -x extract named (or all) files from archive\n\
2236 -u update existing archive\n\
990bee10 2237", filename);
7a93476d
TT
2238 printf("\n\
2239 -@ read names from stdin\n\
2240 -0 store only; use no ZIP compression\n\
2241 -C DIR FILE change to the specified directory and include\n\
2242 the following file\n\
2243 -E don't include the files found in a directory\n\
2244 -f FILE specify archive file name\n\
2245 --help print this help, then exit\n\
2246 -m FILE include manifest information from specified manifest file\n\
2247 -M Do not create a manifest file for the entries\n\
2248 -v generate verbose output on standard output\n\
2249 -V, --version display version information\n\
990bee10 2250");
7a93476d 2251 printf("\n\
990bee10
KG
2252If any file is a directory then it is processed recursively.\n\
2253The manifest file name and the archive file name needs to be specified\n\
2254in the same order the 'm' and 'f' flags are specified.\n\
2255\n\
2256Example 1: to archive two class files into an archive called classes.jar: \n\
2257 jar cvf classes.jar Foo.class Bar.class \n\
2258Example 2: use an existing manifest file 'mymanifest' and archive all the\n\
2259 files in the foo/ directory into 'classes.jar': \n\
2260 jar cvfm classes.jar mymanifest -C foo/ .\n\
2261");
bd8757b3 2262
7a93476d 2263 exit(0);
bd8757b3 2264}
0ee6e0a9
JDA
2265
2266static char *
2267jt_strdup(s)
2268 char *s;
2269{
2270 char *result = (char*)malloc(strlen(s) + 1);
2271 if (result == (char*)0)
2272 return (char*)0;
2273 strcpy(result, s);
2274 return result;
2275}
7a93476d
TT
2276
2277/* Convert "tar-style" first argument to a form expected by getopt.
2278 This idea and the code comes from GNU tar. This can allocate a new
2279 argument vector. This might leak some memory, but we don't care. */
2280static void
2281expand_options (int *argcp, char ***argvp)
2282{
2283 int argc = *argcp;
2284 char **argv = *argvp;
2285
38cb4e84
BM
2286 /* Accept arguments with a leading "-" (eg "-cvf"), but don't do expansion
2287 if a long argument (like "--help") is detected. */
2288 if (argc > 1 && argv[1][1] != '-')
7a93476d
TT
2289 {
2290 char buf[3];
2291 char **new_argv;
2292 int new_argc;
38cb4e84 2293 int args_to_expand;
7a93476d
TT
2294 char *p;
2295 char **in, **out;
2296
2297 buf[0] = '-';
2298 buf[2] = '\0';
2299
38cb4e84
BM
2300 args_to_expand = strlen (argv[1]);
2301 if (argv[1][0] == '-')
2302 --args_to_expand;
2303
2304 new_argc = argc - 1 + args_to_expand;
7a93476d
TT
2305 new_argv = (char **) malloc (new_argc * sizeof (char *));
2306 in = argv;
2307 out = new_argv;
2308
2309 *out++ = *in++;
38cb4e84
BM
2310 p = *in++;
2311 if (*p == '-')
2312 p++;
2313 while (*p != '\0')
7a93476d
TT
2314 {
2315 char *opt;
2316 buf[1] = *p;
2317 *out++ = jt_strdup (buf);
2318 /* If the option takes an argument, move the next argument
2319 to just after this option. */
2320 opt = strchr (OPTION_STRING, *p);
2321 if (opt && opt[1] == ':')
2322 {
2323 if (in < argv + argc)
2324 *out++ = *in++;
2325 else
2326 {
2327 fprintf(stderr, "%s: option `%s' requires an argument.\n",
2328 argv[0], buf);
2329 usage(argv[0]);
2330 }
2331 }
38cb4e84 2332 ++p;
7a93476d
TT
2333 }
2334
2335 /* Copy remaining options. */
2336 while (in < argv + argc)
2337 *out++ = *in++;
2338
2339 *argcp = new_argc;
2340 *argvp = new_argv;
2341 }
2342}
This page took 0.510039 seconds and 5 git commands to generate.