1 /* UNARJ.C, UNARJ, R JUNG, 06/05/02
2 * Main Extractor routine
3 * Copyright (c) 1991-2002 by ARJ Software, Inc. All rights reserved.
4 *
5 * This code may be freely used in programs that are NOT ARJ archivers
6 * (both compress and extract ARJ archives).
7 *
8 * If you wish to distribute a modified version of this program, you
9 * MUST indicate that it is a modified version both in the program and
10 * source code.
11 *
12 * We are holding the copyright on the source code, so please do not
13 * delete our name from the program files or from the documentation.
14 *
15 * We wish to give credit to Haruhiko Okumura for providing the
16 * basic ideas for ARJ and UNARJ in his program AR. Please note
17 * that UNARJ is significantly different from AR from an archive
18 * structural point of view.
19 *
20 * Modification history:
21 * Date Programmer Description of modification.
22 * 09/27/00 R. Jung Added additional header data checks.
23 * 04/04/98 R. Jung Added minor comments.
24 * 04/05/91 R. Jung Rewrote code.
25 * 04/23/91 M. Adler Portabilized.
26 * 04/29/91 R. Jung Added l command. Removed 16 bit dependency in
27 * fillbuf().
28 * 05/19/91 R. Jung Fixed extended header skipping code.
29 * 05/25/91 R. Jung Improved find_header().
30 * 06/03/91 R. Jung Changed arguments in get_mode_str() and
31 * set_ftime_mode().
32 * 06/19/81 R. Jung Added two more %c in printf() in list_arc().
33 * 07/07/91 R. Jung Added default_case_path() to extract().
34 * Added strlower().
35 * 07/20/91 R. Jung Changed uint ratio() to static uint ratio().
36 * 07/21/91 R. Jung Added #ifdef VMS.
37 * 08/28/91 R. Jung Changed M_DIFFHOST message.
38 * 08/31/91 R. Jung Added changes to support MAC THINK_C compiler
39 * per Eric Larson.
40 * 10/07/91 R. Jung Added missing ; to THINK_C additions.
41 * 11/11/91 R. Jung Added host_os test to fwrite_txt_crc().
42 * 11/24/91 R. Jung Added more error_count processing.
43 * 12/03/91 R. Jung Added backup file processing.
44 * 02/17/93 R. Jung Added archive modified date support.
45 * 01/22/94 R. Jung Changed copyright message.
46 * 07/29/96 R. Jung Added "/" to list of path separators.
47 * 06/05/02 R. Jung Changed version number.
48 *
49 */
50
51 #include "unarj.h"
52
53 #ifdef MODERN
54 #include <stdlib.h>
55 #include <string.h>
56 #include <ctype.h>
57 #include <sys/stat.h>
58 #include <sys/types.h>
59 #include <fcntl.h>
60 #include <unistd.h>
61 #else /* !MODERN */
62 extern void free();
63 extern void exit();
64 extern char *strcat();
65 extern char *strcpy();
66 extern char *strncpy();
67 extern char *strchr();
68 extern char *strrchr();
69 extern int strlen();
70 extern int strcmp();
71 #ifdef VMS
72 #include <ssdef.h>
73 #define EXIT_FAILURE SS$_ABORT
74 #define EXIT_SUCCESS SS$_NORMAL
75 #else
76 #define EXIT_FAILURE (1)
77 #define EXIT_SUCCESS (0)
78 #endif
79 #define toupper(c) ((c)>='a'&&(c)<='z'?(c)-('a'-'A'):(c))
80 #define tolower(c) ((c)>='A'&&(c)<='Z'?(c)+('a'-'A'):(c))
81 #endif /* ?MODERN */
82
83 #ifdef THINK_C
84 #include <console.h>
85 #endif
86
87 /* Global variables */
88
89 UCRC crc;
90 FILE *arcfile;
91 FILE *outfile;
92 ushort bitbuf;
93 long compsize;
94 long origsize;
95 uchar subbitbuf;
96 uchar header[HEADERSIZE_MAX];
97 char arc_name[FNAME_MAX];
98 int command;
99 int bitcount;
100 int file_type;
101 int no_output;
102 int error_count;
103
104 /* Messages */
105
106 static char *M_USAGE [] =
107 {
108 "Usage: UNARJ archive[.arj] (list archive)\n",
109 " UNARJ e archive (extract archive)\n",
110 " UNARJ l archive (list archive)\n",
111 " UNARJ t archive (test archive)\n",
112 " UNARJ x archive (extract with pathnames)\n",
113 "\n",
114 "This is an ARJ demonstration program and ** IS NOT OPTIMIZED ** for speed.\n",
115 "You may freely use, copy and distribute this program, provided that no fee\n",
116 "is charged for such use, copying or distribution, and it is distributed\n",
117 "ONLY in its original unmodified state. UNARJ is provided as is without\n",
118 "warranty of any kind, express or implied, including but not limited to\n",
119 "the implied warranties of merchantability and fitness for a particular\n",
120 "purpose. Refer to UNARJ.DOC for more warranty information.\n",
121 "\n",
122 "ARJ Software, Inc. Internet address: robjung@world.std.com\n",
123 "P.O. Box 249 Web site: www.arjsoftware.com\n",
124 "Norwood MA 02062\n",
125 "USA\n",
126 NULL
127 };
128
129 char M_VERSION [] = "UNARJ (Demo version) 2.65 Copyright (c) 1991-2002 ARJ Software, Inc.\n\n";
130
131 char M_ARCDATE [] = "Archive created: %s";
132 char M_ARCDATEM[] = ", modified: %s";
133 char M_BADCOMND[] = "Bad UNARJ command: %s";
134 char M_BADCOMNT[] = "Invalid comment header";
135 char M_BADHEADR[] = "Bad header";
136 char M_BADTABLE[] = "Bad file data";
137 char M_CANTOPEN[] = "Can't open %s";
138 char M_CANTREAD[] = "Can't read file or unexpected end of file";
139 char M_CANTWRIT[] = "Can't write file. Disk full?";
140 char M_CRCERROR[] = "CRC error!\n";
141 char M_CRCOK [] = "CRC OK\n";
142 char M_DIFFHOST[] = " Binary file!";
143 char M_ENCRYPT [] = "File is password encrypted, ";
144 char M_ERRORCNT[] = "%sFound %5d error(s)!";
145 char M_EXTRACT [] = "Extracting %-25s";
146 char M_FEXISTS [] = "%-25s exists, ";
147 char M_HEADRCRC[] = "Header CRC error!";
148 char M_NBRFILES[] = "%5d file(s)\n";
149 char M_NOMEMORY[] = "Out of memory";
150 char M_NOTARJ [] = "%s is not an ARJ archive";
151 char M_PROCARC [] = "Processing archive: %s\n";
152 char M_SKIPPED [] = "Skipped %s\n";
153 char M_SUFFIX [] = ARJ_SUFFIX;
154 char M_TESTING [] = "Testing %-25s";
155 char M_UNKNMETH[] = "Unsupported method: %d, ";
156 char M_UNKNTYPE[] = "Unsupported file type: %d, ";
157 char M_UNKNVERS[] = "Unsupported version: %d, ";
158
159 #define get_crc() get_longword()
160 #define fget_crc(f) fget_longword(f)
161
162 #define setup_get(PTR) (get_ptr = (PTR))
163 #define get_byte() ((uchar)(*get_ptr++ & 0xff))
164
165 #define BUFFERSIZE 4096
166
167 #define ASCII_MASK 0x7F
168
169 #define CRCPOLY 0xEDB88320L
170
171 #define UPDATE_CRC(r,c) r=crctable[((uchar)(r)^(uchar)(c))&0xff]^(r>>CHAR_BIT)
172
173 /* Local functions */
174
175 #ifdef MODERN
176 static void make_crctable(void);
177 static void crc_buf(char *str, int len);
178 static void strparity(uchar *p);
179 static FILE *fopen_msg(char *name, char *mode);
180 static int fget_byte(FILE *f);
181 static uint fget_word(FILE *f);
182 static ulong fget_longword(FILE *f);
183 static void fread_crc(uchar *p, int n, FILE *f);
184 static void decode_path(char *name);
185 static void get_date_str(char *str, ulong tstamp);
186 static int parse_path(char *pathname, char *path, char *entry);
187 static void strncopy(char *to, char *from, int len);
188 static uint get_word(void);
189 static ulong get_longword(void);
190 static long find_header(FILE *fd);
191 static int read_header(int first, FILE *fd, char *name);
192 static void skip(void);
193 static void unstore(void);
194 static int check_flags(void);
195 static int extract(void);
196 static int test(void);
197 static uint ratio(long a, long b);
198 static void list_start(void);
199 static void list_arc(int count);
200 static void execute_cmd(void);
201 static void help(void);
202 #endif /* MODERN */
203
204 /* Local variables */
205
206 static char filename[FNAME_MAX];
207 static char comment[COMMENT_MAX];
208 static char *hdr_filename;
209 static char *hdr_comment;
210
211 static ushort headersize;
212 static uchar first_hdr_size;
213 static uchar arj_nbr;
214 static uchar arj_x_nbr;
215 static uchar host_os;
216 static uchar arj_flags;
217 static short method;
218 static uint file_mode;
219 static ulong time_stamp;
220 static ushort entry_pos;
221 static ushort host_data;
222 static uchar *get_ptr;
223 static UCRC file_crc;
224 static UCRC header_crc;
225
226 static long first_hdr_pos;
227 static long torigsize;
228 static long tcompsize;
229
230 static int clock_inx;
231
232 static char *writemode[2] = { "wb", "w" };
233
234 static UCRC crctable[UCHAR_MAX + 1];
235
236 /* Functions */
237
238 void copy_path_relative(char *dest, char *src, size_t len);
239
240 static void
make_crctable()241 make_crctable()
242 {
243 uint i, j;
244 UCRC r;
245
246 for (i = 0; i <= UCHAR_MAX; i++)
247 {
248 r = i;
249 for (j = CHAR_BIT; j > 0; j--)
250 {
251 if (r & 1)
252 r = (r >> 1) ^ CRCPOLY;
253 else
254 r >>= 1;
255 }
256 crctable[i] = r;
257 }
258 }
259
260 static void
crc_buf(str,len)261 crc_buf(str, len)
262 char *str;
263 int len;
264 {
265 while (len--)
266 UPDATE_CRC(crc, *str++);
267 }
268
269 void
disp_clock()270 disp_clock()
271 {
272 static char clock_str[4] = { '|', '/', '-', '\\' };
273
274 printf("(%c)\b\b\b", clock_str[clock_inx]);
275 clock_inx = (clock_inx + 1) & 0x03;
276 }
277
278 void
error(fmt,arg)279 error(fmt, arg)
280 char *fmt;
281 char *arg;
282 {
283 putc('\n', stdout);
284 printf(fmt, arg, error_count);
285 putc('\n', stdout);
286 exit(EXIT_FAILURE);
287 }
288
289 static void
strparity(p)290 strparity(p)
291 uchar *p;
292 {
293 while (*p)
294 {
295 FIX_PARITY(*p);
296 p++;
297 }
298 }
299
300 static FILE *
fopen_msg(name,mode)301 fopen_msg(name, mode)
302 char *name;
303 char *mode;
304 {
305 FILE *fd;
306
307 fd = file_open(name, mode);
308 if (fd == NULL)
309 error(M_CANTOPEN, name);
310 return fd;
311 }
312
313 static int
fget_byte(f)314 fget_byte(f)
315 FILE *f;
316 {
317 int c;
318
319 if ((c = getc(f)) == EOF)
320 error(M_CANTREAD, "");
321 return c & 0xFF;
322 }
323
324 static uint
fget_word(f)325 fget_word(f)
326 FILE *f;
327 {
328 uint b0, b1;
329
330 b0 = fget_byte(f);
331 b1 = fget_byte(f);
332 return (b1 << 8) + b0;
333 }
334
335 static ulong
fget_longword(f)336 fget_longword(f)
337 FILE *f;
338 {
339 ulong b0, b1, b2, b3;
340
341 b0 = fget_byte(f);
342 b1 = fget_byte(f);
343 b2 = fget_byte(f);
344 b3 = fget_byte(f);
345 return (b3 << 24) + (b2 << 16) + (b1 << 8) + b0;
346 }
347
348 static void
fread_crc(p,n,f)349 fread_crc(p, n, f)
350 uchar *p;
351 int n;
352 FILE *f;
353 {
354 n = file_read((char *)p, 1, n, f);
355 origsize += n;
356 crc_buf((char *)p, n);
357 }
358
359 void
fwrite_txt_crc(p,n)360 fwrite_txt_crc(p, n)
361 uchar *p;
362 int n;
363 {
364 uchar c;
365
366 crc_buf((char *)p, n);
367 if (no_output)
368 return;
369
370 if (file_type == TEXT_TYPE)
371 {
372 while (n--)
373 {
374 c = *p++;
375 if (host_os != OS)
376 {
377 FIX_PARITY(c);
378 }
379 if (putc((int) c, outfile) == EOF)
380 error(M_CANTWRIT, "");
381 }
382 }
383 else
384 {
385 if (file_write((char *)p, 1, n, outfile) != n)
386 error(M_CANTWRIT, "");
387 }
388 }
389
390 void
init_getbits()391 init_getbits()
392 {
393 bitbuf = 0;
394 subbitbuf = 0;
395 bitcount = 0;
396 fillbuf(2 * CHAR_BIT);
397 }
398
399 void
fillbuf(n)400 fillbuf(n) /* Shift bitbuf n bits left, read n bits */
401 int n;
402 {
403 bitbuf = (bitbuf << n) & 0xFFFF; /* lose the first n bits */
404 while (n > bitcount)
405 {
406 bitbuf |= subbitbuf << (n -= bitcount);
407 if (compsize != 0)
408 {
409 compsize--;
410 subbitbuf = (uchar) getc(arcfile);
411 }
412 else
413 subbitbuf = 0;
414 bitcount = CHAR_BIT;
415 }
416 bitbuf |= subbitbuf >> (bitcount -= n);
417 }
418
419 ushort
getbits(n)420 getbits(n)
421 int n;
422 {
423 ushort x;
424
425 x = bitbuf >> (2 * CHAR_BIT - n);
426 fillbuf(n);
427 return x;
428 }
429
430 static void
decode_path(name)431 decode_path(name)
432 char *name;
433 {
434 for ( ; *name; name++)
435 {
436 if (*name == ARJ_PATH_CHAR)
437 *name = PATH_CHAR;
438 }
439 }
440
441 static void
get_date_str(str,tstamp)442 get_date_str(str, tstamp)
443 char *str;
444 ulong tstamp;
445 {
446 sprintf(str, "%04u-%02u-%02u %02u:%02u:%02u",
447 ts_year(tstamp), ts_month(tstamp), ts_day(tstamp),
448 ts_hour(tstamp), ts_min(tstamp), ts_sec(tstamp));
449 }
450
451 static int
parse_path(pathname,path,entry)452 parse_path(pathname, path, entry)
453 char *pathname;
454 char *path;
455 char *entry;
456 {
457 char *cptr, *ptr, *fptr;
458 short pos;
459
460 fptr = NULL;
461 for (cptr = PATH_SEPARATORS; *cptr; cptr++)
462 {
463 if ((ptr = strrchr(pathname, *cptr)) != NULL &&
464 (fptr == NULL || ptr > fptr))
465 fptr = ptr;
466 }
467 if (fptr == NULL)
468 pos = 0;
469 else
470 pos = fptr + 1 - pathname;
471 if (path != NULL)
472 {
473 strncpy(path, pathname, pos);
474 path[pos] = NULL_CHAR;
475 }
476 if (entry != NULL)
477 strcpy(entry, &pathname[pos]);
478 return pos;
479 }
480
481 static void
strncopy(to,from,len)482 strncopy(to, from, len)
483 char *to;
484 char *from;
485 int len;
486 {
487 int i;
488
489 for (i = 1; i < len && *from; i++)
490 *to++ = *from++;
491 *to = NULL_CHAR;
492 }
493
494 void
strlower(s)495 strlower(s)
496 char *s;
497 {
498 while (*s)
499 {
500 *s = (char) tolower(*s);
501 s++;
502 }
503 }
504
505 void
strupper(s)506 strupper(s)
507 char *s;
508 {
509 while (*s)
510 {
511 *s = (char) toupper(*s);
512 s++;
513 }
514 }
515
516 voidp *
malloc_msg(size)517 malloc_msg(size)
518 int size;
519 {
520 char *p;
521
522 if ((p = (char *)xmalloc(size)) == NULL)
523 error(M_NOMEMORY, "");
524 return (voidp *)p;
525 }
526
527 static uint
get_word()528 get_word()
529 {
530 uint b0, b1;
531
532 b0 = get_byte();
533 b1 = get_byte();
534 return (b1 << 8) + b0;
535 }
536
537 static ulong
get_longword()538 get_longword()
539 {
540 ulong b0, b1, b2, b3;
541
542 b0 = get_byte();
543 b1 = get_byte();
544 b2 = get_byte();
545 b3 = get_byte();
546 return (b3 << 24) + (b2 << 16) + (b1 << 8) + b0;
547 }
548
549 static long
find_header(fd)550 find_header(fd)
551 FILE *fd;
552 {
553 long arcpos, lastpos;
554 int c;
555
556 arcpos = file_tell(fd);
557 file_seek(fd, 0L, SEEK_END);
558 lastpos = file_tell(fd) - 2;
559 if (lastpos > MAXSFX)
560 lastpos = MAXSFX;
561 for ( ; arcpos < lastpos; arcpos++)
562 {
563 file_seek(fd, arcpos, SEEK_SET);
564 c = fget_byte(fd);
565 while (arcpos < lastpos)
566 {
567 if (c != HEADER_ID_LO) /* low order first */
568 c = fget_byte(fd);
569 else if ((c = fget_byte(fd)) == HEADER_ID_HI)
570 break;
571 arcpos++;
572 }
573 if (arcpos >= lastpos)
574 break;
575 if ((headersize = fget_word(fd)) <= HEADERSIZE_MAX)
576 {
577 crc = CRC_MASK;
578 fread_crc(header, (int) headersize, fd);
579 if ((crc ^ CRC_MASK) == fget_crc(fd))
580 {
581 file_seek(fd, arcpos, SEEK_SET);
582 return arcpos;
583 }
584 }
585 }
586 return -1; /* could not find a valid header */
587 }
588
589 static int
read_header(first,fd,name)590 read_header(first, fd, name)
591 int first;
592 FILE *fd;
593 char *name;
594 {
595 ushort extheadersize, header_id;
596
597 header_id = fget_word(fd);
598 if (header_id != HEADER_ID)
599 {
600 if (first)
601 error(M_NOTARJ, name);
602 else
603 error(M_BADHEADR, "");
604 }
605
606 headersize = fget_word(fd);
607 if (headersize == 0)
608 return 0; /* end of archive */
609 if (headersize > HEADERSIZE_MAX)
610 error(M_BADHEADR, "");
611
612 crc = CRC_MASK;
613 memset(header, 0, sizeof(header));
614 fread_crc(header, (int) headersize, fd);
615 header_crc = fget_crc(fd);
616 if ((crc ^ CRC_MASK) != header_crc)
617 error(M_HEADRCRC, "");
618
619 setup_get(header);
620 first_hdr_size = get_byte();
621 arj_nbr = get_byte();
622 arj_x_nbr = get_byte();
623 host_os = get_byte();
624 arj_flags = get_byte();
625 method = get_byte();
626 file_type = get_byte();
627 (void)get_byte();
628 time_stamp = get_longword();
629 compsize = get_longword();
630 origsize = get_longword();
631 file_crc = get_crc();
632 entry_pos = get_word();
633 file_mode = get_word();
634 host_data = get_word();
635
636 if (origsize < 0 || compsize < 0)
637 error(M_HEADRCRC, "");
638 if(first_hdr_size > headersize-2) /* need two \0 for file and comment */
639 error(M_BADHEADR, "");
640
641 hdr_filename = (char *)&header[first_hdr_size];
642 strncopy(filename, hdr_filename, sizeof(filename));
643 if(entry_pos >= strlen(filename))
644 error(M_BADHEADR, "");
645 if (host_os != OS)
646 strparity((uchar *)filename);
647 if ((arj_flags & PATHSYM_FLAG) != 0)
648 decode_path(filename);
649
650 hdr_comment = (char *)&header[first_hdr_size + strlen(hdr_filename) + 1];
651 strncopy(comment, hdr_comment, sizeof(comment));
652 if (host_os != OS)
653 strparity((uchar *)comment);
654
655 /* if extheadersize == 0 then no CRC */
656 /* otherwise read extheader data and read 4 bytes for CRC */
657
658 while ((extheadersize = fget_word(fd)) != 0)
659 file_seek(fd, (long) (extheadersize + 4), SEEK_CUR);
660
661 return 1; /* success */
662 }
663
664 static void
skip()665 skip()
666 {
667 file_seek(arcfile, compsize, SEEK_CUR);
668 }
669
670 static void
unstore()671 unstore()
672 {
673 int n;
674 long pos;
675 char *buffer;
676
677 buffer = (char *)malloc_msg(BUFFERSIZE);
678 pos = file_tell(arcfile);
679 disp_clock();
680 n = (int)(BUFFERSIZE - (pos % BUFFERSIZE));
681 n = compsize > (long)n ? n : (int)compsize;
682 while (compsize > 0)
683 {
684 if (file_read(buffer, 1, n, arcfile) != n)
685 error(M_CANTREAD, "");
686 disp_clock();
687 compsize -= n;
688 fwrite_txt_crc((uchar *)buffer, n);
689 n = compsize > BUFFERSIZE ? BUFFERSIZE : (int)compsize;
690 }
691 free(buffer);
692 }
693
694 static int
check_flags()695 check_flags()
696 {
697 if (arj_x_nbr > ARJ_X_VERSION)
698 {
699 printf(M_UNKNVERS, arj_x_nbr);
700 printf(M_SKIPPED, filename);
701 skip();
702 return -1;
703 }
704 if ((arj_flags & GARBLE_FLAG) != 0)
705 {
706 printf(M_ENCRYPT);
707 printf(M_SKIPPED, filename);
708 skip();
709 return -1;
710 }
711 if (method < 0 || method > MAXMETHOD || (method == 4 && arj_nbr == 1))
712 {
713 printf(M_UNKNMETH, method);
714 printf(M_SKIPPED, filename);
715 skip();
716 return -1;
717 }
718 if (file_type != BINARY_TYPE && file_type != TEXT_TYPE)
719 {
720 printf(M_UNKNTYPE, file_type);
721 printf(M_SKIPPED, filename);
722 skip();
723 return -1;
724 }
725 return 0;
726 }
727
728 static int
extract()729 extract()
730 {
731 char name[FNAME_MAX];
732 char dir[FNAME_MAX];
733 char *pos;
734
735 if (check_flags())
736 {
737 error_count++;
738 return 0;
739 }
740
741 no_output = 0;
742 if (command == 'E')
743 copy_path_relative(name, &filename[entry_pos], sizeof(name));
744 else
745 {
746 strcpy(name, DEFAULT_DIR);
747 copy_path_relative(name+strlen(name), filename, sizeof(name)-strlen(name));
748 }
749
750 if (host_os != OS)
751 default_case_path(name);
752
753
754 /*
755 8/8/2000 Phil Knirsch: Bugfix to create subdirectories. Unarj didn't
756 do this for a long time, so it's finally fixed.
757 */
758 pos = strchr(name, PATH_CHAR);
759
760 while (pos != NULL)
761 {
762 strncpy(dir, name, pos-name);
763 dir[pos-name] = '\0';
764 mkdir(dir, 0777);
765 pos = strchr(pos+1, PATH_CHAR);
766 }
767
768 if (file_exists(name))
769 {
770 printf(M_FEXISTS, name);
771 printf(M_SKIPPED, name);
772 skip();
773 error_count++;
774 return 0;
775 }
776 outfile = file_open(name, writemode[file_type & 1]);
777 if (outfile == NULL)
778 {
779 printf(M_CANTOPEN, name);
780 putchar('\n');
781 skip();
782 error_count++;
783 return 0;
784 }
785 printf(M_EXTRACT, name);
786 if (host_os != OS && file_type == BINARY_TYPE)
787 printf(M_DIFFHOST);
788 printf(" ");
789
790 crc = CRC_MASK;
791
792 if (method == 0)
793 unstore();
794 else if (method == 1 || method == 2 || method == 3)
795 decode();
796 else if (method == 4)
797 decode_f();
798 fclose(outfile);
799
800 set_ftime_mode(name, time_stamp, file_mode, (uint) host_os);
801
802 if ((crc ^ CRC_MASK) == file_crc)
803 printf(M_CRCOK);
804 else
805 {
806 printf(M_CRCERROR);
807 error_count++;
808 }
809 return 1;
810 }
811
812 static int
test()813 test()
814 {
815 if (check_flags())
816 return 0;
817
818 no_output = 1;
819 printf(M_TESTING, filename);
820 printf(" ");
821
822 crc = CRC_MASK;
823
824 if (method == 0)
825 unstore();
826 else if (method == 1 || method == 2 || method == 3)
827 decode();
828 else if (method == 4)
829 decode_f();
830
831 if ((crc ^ CRC_MASK) == file_crc)
832 printf(M_CRCOK);
833 else
834 {
835 printf(M_CRCERROR);
836 error_count++;
837 }
838 return 1;
839 }
840
841 static uint
ratio(a,b)842 ratio(a, b)
843 long a, b;
844 {
845 int i;
846
847 for (i = 0; i < 3; i++)
848 if (a <= LONG_MAX / 10)
849 a *= 10;
850 else
851 b /= 10;
852 if ((long) (a + (b >> 1)) < a)
853 {
854 a >>= 1;
855 b >>= 1;
856 }
857 if (b == 0)
858 return 0;
859 return (uint) ((a + (b >> 1)) / b);
860 }
861
862 static void
list_start()863 list_start()
864 {
865 printf("Filename Original Compressed Ratio DateTime modified CRC-32 AttrBTPMGVX\n");
866 printf("------------ ---------- ---------- ----- ----------------- -------- -----------\n");
867 }
868
869 static void
list_arc(count)870 list_arc(count)
871 int count;
872 {
873 uint r;
874 int garble_mode, path_mode, volume_mode, extfil_mode, ftype, bckf_mode;
875 char date_str[20], fmode_str[10];
876 static char mode[5] = { 'B', 'T', '?', 'D', 'V' };
877 static char pthf[2] = { ' ', '+' };
878 static char pwdf[2] = { ' ', 'G' }; /* plain, encrypted */
879 static char volf[2] = { ' ', 'V' };
880 static char extf[2] = { ' ', 'X' };
881 static char bckf[2] = { ' ', '*' };
882
883 if (count == 0)
884 list_start();
885
886 garble_mode = ((arj_flags & GARBLE_FLAG) != 0);
887 volume_mode = ((arj_flags & VOLUME_FLAG) != 0);
888 extfil_mode = ((arj_flags & EXTFILE_FLAG) != 0);
889 bckf_mode = ((arj_flags & BACKUP_FLAG) != 0);
890 path_mode = (entry_pos > 0);
891 r = ratio(compsize, origsize);
892 torigsize += origsize;
893 tcompsize += compsize;
894 ftype = file_type;
895 if (ftype != BINARY_TYPE && ftype != TEXT_TYPE && ftype != DIR_TYPE &&
896 ftype != LABEL_TYPE)
897 ftype = 3;
898 get_date_str(date_str, time_stamp);
899 strcpy(fmode_str, " ");
900 if (host_os == OS)
901 get_mode_str(fmode_str, (uint) file_mode);
902 if (strlen(&filename[entry_pos]) > 12)
903 printf("%-12s\n ", &filename[entry_pos]);
904 else
905 printf("%-12s ", &filename[entry_pos]);
906 printf("%10ld %10ld %u.%03u %s %08lX %4s%c%c%c%u%c%c%c\n",
907 origsize, compsize, r / 1000, r % 1000, &date_str[2], file_crc,
908 fmode_str, bckf[bckf_mode], mode[ftype], pthf[path_mode], method,
909 pwdf[garble_mode], volf[volume_mode], extf[extfil_mode]);
910 }
911
912 static void
execute_cmd()913 execute_cmd()
914 {
915 int file_count;
916 char date_str[22];
917 uint r;
918
919 first_hdr_pos = 0;
920 time_stamp = 0;
921 first_hdr_size = FIRST_HDR_SIZE;
922
923 arcfile = fopen_msg(arc_name, "rb");
924
925 printf(M_PROCARC, arc_name);
926
927 first_hdr_pos = find_header(arcfile);
928 if (first_hdr_pos < 0)
929 error(M_NOTARJ, arc_name);
930 file_seek(arcfile, first_hdr_pos, SEEK_SET);
931 if (!read_header(1, arcfile, arc_name))
932 error(M_BADCOMNT, "");
933 get_date_str(date_str, time_stamp);
934 printf(M_ARCDATE, date_str);
935 if (arj_nbr >= ARJ_M_VERSION)
936 {
937 get_date_str(date_str, (ulong) compsize);
938 printf(M_ARCDATEM, date_str);
939 }
940 printf("\n");
941
942 file_count = 0;
943 while (read_header(0, arcfile, arc_name))
944 {
945 switch (command)
946 {
947 case 'E':
948 case 'X':
949 if (extract())
950 file_count++;
951 break;
952 case 'L':
953 list_arc(file_count++);
954 skip();
955 break;
956 case 'T':
957 if (test())
958 file_count++;
959 break;
960 }
961 }
962
963 if (command == 'L')
964 {
965 printf("------------ ---------- ---------- ----- -----------------\n");
966 r = ratio(tcompsize, torigsize);
967 printf(" %5d files %10ld %10ld %u.%03u %s\n",
968 file_count, torigsize, tcompsize, r / 1000, r % 1000, &date_str[2]);
969 }
970 else
971 printf(M_NBRFILES, file_count);
972
973 fclose(arcfile);
974 }
975
976 static void
help()977 help()
978 {
979 int i;
980
981 for (i = 0; M_USAGE[i] != NULL; i++)
982 printf(M_USAGE[i]);
983 }
984
985 int
main(argc,argv)986 main(argc, argv)
987 int argc;
988 char *argv[];
989 {
990 int i, j, lastc;
991 char *arc_p;
992
993 #ifdef THINK_C
994 argc = ccommand(&argv);
995 #endif
996
997 printf(M_VERSION);
998
999 if (argc == 1)
1000 {
1001 help();
1002 return EXIT_SUCCESS;
1003 }
1004 else if (argc == 2)
1005 {
1006 command = 'L';
1007 arc_p = argv[1];
1008 }
1009 else if (argc == 3)
1010 {
1011 if (strlen(argv[1]) > 1)
1012 error(M_BADCOMND, argv[1]);
1013 command = toupper(*argv[1]);
1014 if (strchr("ELTX", command) == NULL)
1015 error(M_BADCOMND, argv[1]);
1016 arc_p = argv[2];
1017 }
1018 else
1019 {
1020 help();
1021 return EXIT_FAILURE;
1022 }
1023
1024 strncopy(arc_name, arc_p, FNAME_MAX);
1025 case_path(arc_name);
1026 i = strlen(arc_name);
1027 j = parse_path(arc_name, (char *)NULL, (char *)NULL);
1028 lastc = arc_name[i - 1];
1029 if (lastc == ARJ_DOT)
1030 arc_name[i - 1] = NULL_CHAR;
1031 else if (strchr(&arc_name[j], ARJ_DOT) == NULL)
1032 strcat(arc_name, M_SUFFIX);
1033
1034 make_crctable();
1035
1036 error_count = 0;
1037 clock_inx = 0;
1038 arcfile = NULL;
1039 outfile = NULL;
1040
1041 execute_cmd();
1042
1043 if (error_count > 0)
1044 error(M_ERRORCNT, "");
1045
1046 return EXIT_SUCCESS;
1047 }
1048
1049 /* end UNARJ.C */
1050