1 /***********************************************************
3 ***********************************************************/
5 static char *version = "0.01";
8 "ar -- compression archiver -- written by Haruhiko Okumura\n"
9 " PC-VAN:SCIENCE CompuServe:74050,1022\n"
10 " NIFTY-Serve:PAF01022 INTERNET:74050.1022@compuserve.com\n"
11 "Usage: ar command archive [file ...]\n"
13 " a: Add files to archive (replace if present)\n"
14 " x: Extract files from archive\n"
15 " r: Replace files in archive\n"
16 " d: Delete files from archive\n"
17 " p: Print files on standard output\n"
18 " l: List contents of archive\n"
19 "If no files are named, all files in archive are processed,\n"
20 " except for commands 'a' and 'd'.\n"
21 "You may copy, distribute, and rewrite this program freely.\n";
23 /***********************************************************
25 Structure of archive block (low order byte first):
28 = 25 + strlen(filename) (= 0 if end of archive)
29 1 basic header algebraic sum (mod 256)
31 5 method ("-lh0-" = stored, "-lh5-" = compressed)
32 4 compressed size (including extended headers)
41 2 first extended header size (0 if none)
42 -----first extended header, etc.
45 ***********************************************************/
57 extern char *basename(const char *);
59 struct lha_method methods[] = {
60 /* id, dicbit, pbit, maxmatch */
61 /* note: dicbit == 0 means no compress */
62 {"-lh0-", 0, 0, 0}, /* 0: no compress */
63 {"-lh1-", 12, 0, 60}, /* 1: 2^12 = 4KB dynamic huffman (LHarc) */
64 {"-lh2-", 13, 0,256}, /* 2: 2^13 = 8KB dynamic huffman */
65 {"-lh3-", 13, 0,256}, /* 3: 2^13 = 8KB static huffman */
66 {"-lh4-", 12, 4,256}, /* 4: 2^12 = 4KB static huffman (pos and len)*/
67 {"-lh5-", 13, 4,256}, /* 5: 2^13 = 8KB static huffman (pos and len)*/
68 {"-lh6-", 15, 5,256}, /* 6: 2^15 = 32KB static huffman (pos and len)*/
69 {"-lh7-", 16, 5,256}, /* 7: 2^16 = 64KB static huffman (pos and len)*/
70 {"-lzs-", 11, 0, 17}, /* 8: 2^11 = 2KB (LArc) */
71 {"-lz5-", 12, 0, 17}, /* 9: 2^12 = 4KB (LArc) */
72 {"-lz4-", 0, 0, 0}, /* 1: no compress (LArc) */
73 {"-lhd-", 0, 0, 0}, /* 1: directory */
79 which_method(char *id)
83 for (i = 0; i < sizeof(methods)/sizeof(methods[0]); i++) {
84 if (strncmp(id, methods[i].id, sizeof(methods[0].id)) == 0) {
91 #define FNAME_MAX (255 - 25) /* max strlen(filename) */
93 int unpackable; /* global, set in io.c */
94 ulong compsize, origsize; /* global */
96 static char *temp_name;
108 printf("version %s\n", version);
113 ratio(ulong a, ulong b)
114 { /* [(1000a + [b/2]) / b] */
117 for (i = 0; i < 3; i++)
118 if (a <= ULONG_MAX / 10)
122 if ((ulong) (a + (b >> 1)) < a) {
128 return (uint) ((a + (b >> 1)) / b);
139 {'M', "MS-DOS"}, /* Microsoft */
140 {'U', "Unix"}, /* Unix or POSIX compliant OS */
141 {'J', "Java"}, /* Sun Microsystems */
143 {'w', "Win9x"}, /* reserved by UNLHA32.DLL */
144 {'W', "WinNT"}, /* reserved by UNLHA32.DLL */
145 {'2', "OS/2"}, /* IBM OS/2 */
146 {'9', "OS9"}, /* unknown */
147 {'K', "OS/68K"}, /* unknown */
148 {'3', "OS/386"}, /* unknown */
149 {'H', "Human"}, /* SHARP Human68K */
150 {'C', "CP/M"}, /* Digital Research */
151 {'F', "FLEX"}, /* unknown */
152 {'m', "Mac"}, /* Apple */
153 {'R', "Runser"}, /* unknown */
154 {'T', "TownsOS"}, /* Fujitsu FM-TOWNS */
155 {'X', "XOSK"}, /* unknown */
158 for (i = 0; i < sizeof(os_types)/sizeof(os_types[0]); i++) {
159 if (id == os_types[i].id)
160 return os_types[i].name;
167 put_header(char *buf, int *i, int n, uint32_t x)
170 buf[(*i)++] = (uchar) (x & 0xFF);
176 put_header_tmp(char *buf, int i, int n, uint32_t x)
178 put_header(buf, &i, n, x);
182 put_string(char *buf, int *n, size_t size, char *p)
184 memcpy(buf + *n, p, size);
189 get_header(char *buf, int *i, int size)
195 for (n = size-1; n >= 0; n--) {
196 s = (s << 8) + (unsigned char)buf[*i + n]; /* little endian */
203 get_string(char *buf, int *i, size_t size, char *p)
205 memcpy(p, buf + *i, size);
210 calc_headersum(char *buf, int size)
216 for (i = 0; i < size; i++)
225 return *(unsigned char*)buf;
231 return get_byte(buf) | (get_byte(buf+1) << 8);
237 return get_byte(buf) |
238 (get_byte(buf+1) << 8) |
239 (get_byte(buf+2) << 16) |
240 (get_byte(buf+3) << 24);
244 get_char(char *buf, char *p, size_t size)
246 memcpy(p, buf, size);
250 put_byte(char *buf, int c)
252 *buf = (unsigned char)(c & 0xff);
256 put_word(char *buf, uint16_t c)
259 put_byte(buf+1, c>>8);
263 put_dword(char *buf, uint32_t c)
266 put_byte(buf+1, c>>8);
267 put_byte(buf+2, c>>16);
268 put_byte(buf+3, c>>24);
272 put_char(char *buf, char *p, size_t size)
274 memcpy(buf, p, size);
279 ftime_to_time_t(uint32_t ftime)
282 /* ftime is time structure on MS-DOS
285 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
286 |-------------|-------|---------|---------|-----------|---------|
287 year(-1980) month day hour minute second/2
288 (1-127) (1-12) (1-31) (0-23) (0-59) (0-29)
291 memset(&tm, 0, sizeof(tm));
292 tm.tm_year = (ftime >> 25) + 1980 - 1900;
293 tm.tm_mon = ((ftime >> 21) & 0x0f) - 1;
294 tm.tm_mday = (ftime >> 16) & 0x1f;
295 tm.tm_hour = (ftime >> 11) & 0x1f;
296 tm.tm_min = (ftime >> 5) & 0x3f;
297 tm.tm_sec = (ftime & 0x1f) * 2;
303 time_t_to_ftime(time_t t)
306 /* ftime is time structure on MS-DOS
309 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
310 |-------------|-------|---------|---------|-----------|---------|
311 year(-1980) month day hour minute second/2
312 (1-127) (1-12) (1-31) (0-23) (0-59) (0-29)
316 localtime_r(&t, &tm);
321 return (uint32_t)(tm.tm_year + 1900 - 1980) << 25
322 | (uint32_t)(tm.tm_mon + 1) << 21
323 | (uint32_t)(tm.tm_mday) << 16
324 | (uint32_t)(tm.tm_hour) << 11
325 | (uint32_t)(tm.tm_min) << 5
326 | (uint32_t)(tm.tm_sec / 2);
334 * offset size field name
335 * ----------------------------------
336 * 0 1 header size [*1]
338 * ---------------------------------------
340 * 7 4 packed size [*2] |
341 * 11 4 original size |
344 * 19 1 attribute | [*1] header size (X+Y+22)
345 * 20 1 level (0x00 fixed) |
348 * X +22 2 file crc (CRC-16) |
349 * X +24 Y ext-header(old style) v
350 * -------------------------------------------------
352 * : | [*2] packed size
354 * -------------------------------------------------
356 * ext-header(old style)
370 * bit6 archive bit (need to backup)
374 read_header_lv0(FILE *fp, char *buf, struct lzh_header *h)
382 headersize = get_header(buf, &pos, 1);
383 headersum = get_header(buf, &pos, 1);
385 fread_crc(buf + 21, headersize - (21 - pos), fp); /* CRC not used */
387 if (calc_headersum(buf+pos, headersize) != headersum)
388 error("Header sum error");
390 get_string(buf, &pos, 5, h->method);
391 h->compsize = get_header(buf, &pos, 4);
392 h->origsize = get_header(buf, &pos, 4);
393 h->mtime = ftime_to_time_t(get_header(buf, &pos, 4));
394 /* attrib = */ get_header(buf, &pos, 1);
395 h->level = get_header(buf, &pos, 1); /* header level */
396 h->namelen = get_header(buf, &pos, 1);
397 if (pos + h->namelen > headersize+2) {
398 warn("path name is too long");
399 h->namelen = headersize+2-pos;
401 get_string(buf, &pos, h->namelen, h->filename);
402 h->filename[h->namelen] = 0;
403 h->file_crc = get_header(buf, &pos, 2);
404 h->os_id = 0; /* generic */
406 ext_size = headersize - pos;
410 h->os_id = get_header(buf, &pos, 1);
414 get_header(buf, &pos, 1); /* minor version */
418 h->mtime = get_header(buf, &pos, 4);
422 get_header(buf, &pos, 2); /* mode */
426 get_header(buf, &pos, 2); /* uid */
430 get_header(buf, &pos, 2); /* gid */
435 return 1; /* success */
442 * offset size field name
443 * -----------------------------------
444 * 0 1 header size [*1]
446 * -------------------------------------
448 * 7 4 skip size [*2] |
449 * 11 4 original size |
452 * 19 1 attribute (0x20 fixed) | [*1] header size (X+Y+25)
453 * 20 1 level (0x01 fixed) |
456 * X+ 22 2 file crc (CRC-16) |
459 * X+Y+25 2 next-header size v
460 * -------------------------------------------------
461 * X+Y+27 Z ext-header ^
463 * ----------------------------------- | [*2] skip size
466 * -------------------------------------------------
470 read_header_lv1(FILE *fp, char *buf, struct lzh_header *h)
475 char dirname[1024] = "";
479 headersize = get_header(buf, &pos, 1);
480 headersum = get_header(buf, &pos, 1);
482 fread_crc(buf + 21, headersize - (21 - 2), fp); /* CRC not used */
484 if (calc_headersum(&buf[pos], headersize) != headersum)
485 error("Header sum error");
487 get_string(buf, &pos, 5, h->method);
488 h->compsize = get_header(buf, &pos, 4);
489 h->origsize = get_header(buf, &pos, 4);
490 h->mtime = ftime_to_time_t(get_header(buf, &pos, 4));
491 get_header(buf, &pos, 1); /* attribute */
492 h->level = get_header(buf, &pos, 1); /* header level */
493 h->namelen = get_header(buf, &pos, 1);
494 get_string(buf, &pos, h->namelen, h->filename);
495 h->filename[h->namelen] = 0;
496 h->file_crc = get_header(buf, &pos, 2);
497 h->os_id = get_header(buf, &pos, 1);
499 ext_headersize = get_header(buf, &pos, 2);
501 while (ext_headersize != 0) {
506 h->compsize -= ext_headersize;
508 if (fread(extbuf, ext_headersize, 1, fp) != 1) {
509 error("can't read ext header");
512 ext_type = get_header(extbuf, &extpos, 1);
515 /* filename header */
516 h->namelen = ext_headersize - 3;
517 get_string(extbuf, &extpos, h->namelen, h->filename);
518 h->filename[h->namelen] = 0;
522 dirnamelen = ext_headersize - 3;
523 get_string(extbuf, &extpos, dirnamelen, dirname);
524 dirname[dirnamelen] = 0;
527 h->mtime = get_header(extbuf, &extpos, 4);
532 extpos = ext_headersize - 2;
533 ext_headersize = get_header(extbuf, &extpos, 2);
536 if (dirnamelen > 0 && dirname[dirnamelen-1] != '/') {
537 dirname[dirnamelen++] = '/';
540 strcat(dirname, h->filename);
541 h->namelen = strlen(dirname);
542 strcpy(h->filename, dirname);
544 return 1; /* success */
551 * offset size field name
552 * --------------------------------------------------
553 * 0 2 total header size [*1] ^
554 * ----------------------- |
556 * 7 4 packed size [*2] |
557 * 11 4 original size |
559 * 19 1 RESERVED (0x20 fixed) | [*1] total header size
560 * 20 1 level (0x02 fixed) | (X+26+(1))
561 * 21 2 file crc (CRC-16) |
563 * 24 2 next-header size |
564 * ----------------------------------- |
567 * ----------------------------------- |
568 * X +26 (1) padding v
569 * -------------------------------------------------
571 * : | [*2] packed size
573 * -------------------------------------------------
577 read_header_lv2(FILE *fp, char *buf, struct lzh_header *h)
583 char dirname[1024] = "";
587 headersize = get_header(buf, &pos, 2);
589 fread_crc(buf + 21, 26 - 21, fp); /* CRC not used */
591 get_string(buf, &pos, 5, h->method);
592 h->compsize = get_header(buf, &pos, 4);
593 h->origsize = get_header(buf, &pos, 4);
594 h->mtime = get_header(buf, &pos, 4);
595 get_header(buf, &pos, 1); /* attrib */
596 h->level = get_header(buf, &pos, 1); /* header level */
597 h->file_crc = get_header(buf, &pos, 2);
598 h->os_id = get_header(buf, &pos, 1);
600 ext_headersize = get_header(buf, &pos, 2);
602 remainder = headersize - pos;
604 while (ext_headersize != 0) {
609 remainder -= ext_headersize;
611 if (fread(extbuf, ext_headersize, 1, fp) != 1) {
612 error("can't read ext header");
614 ext_type = get_header(extbuf, &extpos, 1);
620 /* filename header */
621 h->namelen = ext_headersize - 3;
622 get_string(extbuf, &extpos, h->namelen, h->filename);
623 h->filename[h->namelen] = 0;
627 dirnamelen = ext_headersize - 3;
628 get_string(extbuf, &extpos, dirnamelen, dirname);
629 dirname[dirnamelen] = 0;
634 extpos = ext_headersize - 2;
635 ext_headersize = get_header(extbuf, &extpos, 2);
638 if (dirnamelen > 0 && dirname[dirnamelen-1] != '/') {
639 dirname[dirnamelen++] = '/';
642 strcat(dirname, h->filename);
643 h->namelen = strlen(dirname);
644 strcpy(h->filename, dirname);
646 while (remainder > 0) {
647 fgetc(fp); /* skip padding */
651 return 1; /* success */
655 read_header(FILE *fp, struct lzh_header *h)
662 if (buf[0] == 0 || ret == EOF)
663 return 0; /* end of archive */
664 fread_crc(buf + 1, 21 - 1, fp);
667 return read_header_lv0(fp, buf, h);
670 return read_header_lv1(fp, buf, h);
673 return read_header_lv2(fp, buf, h);
676 error("unknown level (%d)\n", buf[20]);
680 return 1; /* success */
685 write_header_lv0(FILE *fp, struct lzh_header *h)
694 headersize += 12; /* extended header size */
696 if (headersize + h->namelen > 255) {
697 warn("path name is too long");
698 h->namelen = 255 - headersize;
702 headersize += h->namelen;
705 put_header(buf, &pos, 1, headersize);
706 put_header(buf, &pos, 1, 0); /* dummy */
708 put_string(buf, &pos, 5, h->method);
709 put_header(buf, &pos, 4, h->compsize); /* packed size */
710 put_header(buf, &pos, 4, h->origsize); /* original size */
711 put_header(buf, &pos, 4, time_t_to_ftime(h->mtime)); /* ftime */
712 put_header(buf, &pos, 1, 0x20); /* attribute */
713 put_header(buf, &pos, 1, 0); /* level */
714 put_header(buf, &pos, 1, h->namelen); /* length of pathname */
715 put_string(buf, &pos, h->namelen, h->filename);
716 put_header(buf, &pos, 2, h->file_crc);
719 /* extended header for Unix */
720 put_header(buf, &pos, 1, 'U'); /* OS type */
721 put_header(buf, &pos, 1, '\0'); /* minor version */
722 put_header(buf, &pos, 4, h->mtime); /* time_t */
723 put_header(buf, &pos, 2, 0100000); /* mode */
724 put_header(buf, &pos, 2, 0); /* uid */
725 put_header(buf, &pos, 2, 0); /* gid */
728 sum = calc_headersum(buf+2, headersize);
729 put_header_tmp(buf, 1, 1, sum);
731 fwrite_crc(buf, headersize+2, fp);
735 write_header_lv1(FILE *fp, struct lzh_header *h)
743 char *dirname, *fname;
746 fname = xbasename(h->filename);
747 dirname = h->filename;
748 dirnamelen = fname - dirname;
749 h->namelen = strlen(fname);
753 put_header(buf, &pos, 1, 0); /* dummy */
754 put_header(buf, &pos, 1, 0); /* dummy */
755 put_string(buf, &pos, 5, h->method);
756 put_header(buf, &pos, 4, h->compsize); /* packed size */
757 put_header(buf, &pos, 4, h->origsize); /* original size */
758 put_header(buf, &pos, 4, time_t_to_ftime(h->mtime)); /* ftime */
759 put_header(buf, &pos, 1, 0x20); /* attribute */
760 put_header(buf, &pos, 1, 1); /* level */
761 if (headersize + h->namelen > 255)
762 put_header(buf, &pos, 1, 0); /* length of pathname */
764 put_header(buf, &pos, 1, h->namelen); /* length of pathname */
765 put_string(buf, &pos, h->namelen, fname);
766 headersize += h->namelen;
768 put_header_tmp(buf, 0, 1, headersize); /* header size */
769 put_header(buf, &pos, 2, h->file_crc);
771 put_header(buf, &pos, 1, '\0');
773 put_header(buf, &pos, 1, 'U');
776 put_header(buf, &pos, 2, 7); /* next header size */
777 put_header(buf, &pos, 1, 0x54); /* time stamp */
778 put_header(buf, &pos, 4, h->mtime); /* time_t */
780 if (h->namelen > 0) {
781 put_header(buf, &pos, 2, 3 + h->namelen);
782 put_header(buf, &pos, 1, 1); /* 0x01: filename header */
783 put_string(buf, &pos, h->namelen, fname); /* filename */
786 if (dirnamelen > 0) {
787 put_header(buf, &pos, 2, 3 + dirnamelen);
788 put_header(buf, &pos, 1, 2); /* 0x02: dirname header */
789 put_string(buf, &pos, dirnamelen, dirname); /* dirname */
792 extsize = pos - extpos;
793 put_header(buf, &pos, 2, 0); /* next header size (end of header) */
795 put_header_tmp(buf, 7, 4, h->compsize+extsize); /* packed size */
797 sum = calc_headersum(buf+2, headersize);
798 put_header_tmp(buf, 1, 1, sum);
800 fwrite_crc(buf, headersize+2+extsize, fp);
804 write_header_lv2(FILE *fp, struct lzh_header *h)
806 char buf[4096], *crcptr;
808 extern ushort crctable[];
809 char dirname[1024] = "", *fname;
813 put_header(buf, &pos, 2, 0); /* dummy */
814 put_string(buf, &pos, 5, h->method);
815 put_header(buf, &pos, 4, h->compsize); /* packed size */
816 put_header(buf, &pos, 4, h->origsize); /* original size */
817 put_header(buf, &pos, 4, h->mtime); /* time_t */
818 put_header(buf, &pos, 1, 0x20); /* DOS attribute (0x20 fixed) */
819 put_header(buf, &pos, 1, 2); /* level */
820 put_header(buf, &pos, 2, h->file_crc);
822 put_header(buf, &pos, 1, '\0');
824 put_header(buf, &pos, 1, 'U');
826 put_header(buf, &pos, 2, 5);
827 put_header(buf, &pos, 1, 0); /* 0x00: header crc */
829 put_header(buf, &pos, 2, 0); /* crc (dummy) */
831 fname = xbasename(h->filename);
834 put_header(buf, &pos, 2, 3 + len);
835 put_header(buf, &pos, 1, 1); /* 0x01: filename header */
836 put_string(buf, &pos, len, fname); /* filename */
841 ptr = strrchr(h->filename, '/');
843 dirnamelen = ptr - h->filename;
844 strncpy(dirname, h->filename, dirnamelen);
845 dirname[dirnamelen+ 1] = 0;
850 put_header(buf, &pos, 2, 3 + dirnamelen);
851 put_header(buf, &pos, 1, 2); /* 0x02: dirname header */
852 put_string(buf, &pos, dirnamelen, dirname); /* dirname */
855 put_header(buf, &pos, 2, 0); /* next header size (end of header) */
858 if (pos % 256 == 0) {
859 put_header(buf, &pos, 1, 0);
863 put_header_tmp(buf, 0, 2, headersize);
869 for (i = 0; i < headersize; i++)
871 put_header_tmp(crcptr, 0, 2, crc);
874 fwrite_crc(buf, headersize, fp);
878 write_header(FILE *fp, struct lzh_header *h)
882 write_header_lv0(fp, h);
885 write_header_lv1(fp, h);
888 write_header_lv2(fp, h);
891 error("unknown level (%d)", h->level);
897 skip(FILE *fp, struct lzh_header *h)
900 if (opts.archive_to_stdio)
901 for (i = 0; i < h->compsize; i++)
904 fseek(fp, h->compsize, SEEK_CUR);
908 copy(FILE *arcfile, FILE *outfile, struct lzh_header *h)
911 uchar buffer[MAXDICSIZ];
913 write_header(outfile, h);
914 while (h->compsize != 0) {
915 n = (uint) ((h->compsize > sizeof(buffer)) ? sizeof(buffer) : h->compsize);
916 if (fread((char *) buffer, 1, n, arcfile) != n)
918 if (fwrite((char *) buffer, 1, n, outfile) != n)
919 error("Can't write");
928 uchar buffer[MAXDICSIZ];
932 while ((n = fread((char *) buffer, 1, sizeof(buffer), infile)) != 0) {
933 fwrite_crc(buffer, n, outfile);
940 add_dir(int replace_flag, struct lzh_header *h)
942 long headerpos, arcpos;
945 h->origsize = h->compsize = 0;
946 h->file_crc = INIT_CRC;
948 headerpos = ftell(outfile);
949 write_header(outfile, h);
950 arcpos = ftell(outfile);
953 printf(" %d.%d%%\n", r / 10, r % 10);
954 return 1; /* success */
958 add_1(int replace_flag, struct lzh_header *h)
960 long headerpos, arcpos;
963 if ((infile = fopen(h->filename, "rb")) == NULL) {
964 fprintf(stderr, "Can't open %s\n", h->filename);
965 return 0; /* failure */
969 printf("Replacing %s ", h->filename);
973 printf("Adding %s ", h->filename);
976 headerpos = ftell(outfile);
977 write_header(outfile, h);
978 arcpos = ftell(outfile);
980 origsize = compsize = 0;
982 if (opts.nocompress) {
991 memcpy(h->method, "-lh0-", sizeof(h->method)); /* store */
993 fseek(outfile, arcpos, SEEK_SET);
996 h->file_crc = crc ^ INIT_CRC;
999 h->compsize = compsize;
1000 h->origsize = origsize;
1002 fseek(outfile, headerpos, SEEK_SET);
1003 write_header(outfile, h);
1004 fseek(outfile, 0L, SEEK_END);
1005 r = ratio(compsize, origsize);
1007 printf(" %d.%d%%\n", r / 10, r % 10);
1008 return 1; /* success */
1012 add(int replace_flag, char *filename, int namelen)
1014 struct lzh_header h;
1017 memset(&h, 0, sizeof(h));
1019 h.level = opts.header_level;
1021 strcpy(h.filename, filename);
1022 h.namelen = namelen;
1024 stat(h.filename, &st);
1026 h.mtime = st.st_mtime;
1027 if (S_ISDIR(st.st_mode)) {
1031 memcpy(h.method, "-lhd-", sizeof(h.method)); /* directory */
1032 add_dir(replace_flag, &h);
1034 dir = opendir(h.filename);
1036 error("cannot open directory: \"%s\"", h.filename);
1038 while ((ent = readdir(dir)) != 0) {
1039 char filename[1024];
1041 if (string_equal(ent->d_name, ".") ||
1042 string_equal(ent->d_name, ".."))
1045 h.namelen = path_addsep(h.filename, sizeof(h.filename));
1047 string_cat(filename, sizeof(filename),
1048 h.filename, ent->d_name, NULL);
1050 add(replace_flag, filename, strlen(filename));
1055 memcpy(h.method, opts.method->id, sizeof(h.method)); /* compress */
1056 add_1(replace_flag, &h);
1061 get_line(char *s, int n)
1066 while ((c = getchar()) != EOF && c != '\n')
1074 extract(int to_file, struct lzh_header *h)
1077 uchar buffer[MAXDICSIZ];
1082 if (memcmp(h->method, "-lhd-", sizeof(h->method)) == 0) {
1084 if (mkdir(h->filename, 0777) == -1) {
1085 if (errno != EEXIST)
1086 error("cannot make directory \"%s\"", opts.outdir);
1091 if (file_exists(h->filename)) {
1092 if (!opts.force_extract) {
1093 message("'%s' has been already exist. skip", h->filename);
1098 while ((outfile = fopen(h->filename, "wb")) == NULL) {
1099 fprintf(stderr, "Can't open %s\nNew filename: ", h->filename);
1100 if (get_line(h->filename, FNAME_MAX) == 0) {
1101 fprintf(stderr, "Not extracted\n");
1105 h->namelen = strlen(h->filename);
1109 printf("Extracting %s ", h->filename);
1114 printf("===== %s =====\n", h->filename);
1117 opts.method = which_method(h->method);
1118 if (opts.method == NULL) {
1119 fprintf(stderr, "Unknown method: %.5s\n", h->method);
1124 if (opts.method->dicbit != 0)
1126 while (h->origsize != 0) {
1127 n = (uint) ((h->origsize > MAXDICSIZ) ? MAXDICSIZ : h->origsize);
1128 if (opts.method->dicbit != 0)
1130 else if (fread((char *) buffer, 1, n, arcfile) != n)
1131 error("Can't read");
1132 fwrite_crc(buffer, n, outfile);
1133 if (outfile != stdout && opts.quiet < 1) {
1140 if ((crc ^ INIT_CRC) != h->file_crc)
1144 fprintf(stdout, "\n");
1150 ut.actime = ut.modtime = h->mtime;
1151 utime(h->filename, &ut);
1161 printf("%-14.14s %-7.7s %10.10s %10.10s %-5.5s %-4.4s %-5.5s %-4.4s\n",
1173 list(struct lzh_header *h)
1177 printf("%-14.*s", h->namelen, h->filename);
1178 if (h->namelen > 14)
1180 r = ratio(h->compsize, h->origsize);
1181 printf(" %-7s %10lu %10lu %u.%03u %04x %-6.6s [%d]\n",
1182 os_string(h->os_id),
1193 match(char *s1, char *s2)
1196 while (*s2 == '*' || *s2 == '?') {
1198 while (*s1 && *s1 != *s2)
1215 search(int argc, char *argv[], struct lzh_header *h)
1221 for (i = 0; i < argc; i++)
1222 if (argv[i] && match(h->filename, argv[i]))
1233 #include "getopt_long.h"
1236 parse_args(int argc, char **argv)
1241 /* int this_option_optind = optind ? optind : 1; */
1242 int option_index = 0;
1249 static struct option long_options[] = {
1250 /* name, has_arg, *flag, val */
1253 required_argument (1)
1254 optional_argument (2)
1256 NULL: getopt_long() return val
1257 non-NULL: getopt_long() return 0, and *flag set val.
1259 {"help", no_argument, NULL, LHA_OPT_HELP},
1260 {"version", no_argument, NULL, LHA_OPT_VERSION},
1264 c = getopt_long(argc, argv, "012fgo[567]q[012]vw:z",
1265 long_options, &option_index);
1267 if (c == -1) break; /* end of parsing options */
1274 /* set value by long option */
1276 case '0': case '1': case '2':
1278 opts.header_level = c - '0';
1281 opts.force_extract = 1;
1285 opts.header_level = 0;
1288 /* compress method */
1290 int idx = 1; /* -o means -lh1- method */
1293 idx = *optarg - '0'; /* -lh[567]- method */
1295 opts.method = &methods[idx];
1300 opts.quiet = 2; /* -q is equivalent to -q2 */
1302 opts.quiet = *optarg - '0';
1310 /* extract directory */
1312 error("extract directory does not specified for `-w'");
1316 opts.outdir = optarg;
1318 case 'z': /* no compress */
1319 opts.nocompress = 1;
1324 case LHA_OPT_VERSION:
1336 temp_name = tmpnam(NULL);
1337 outfile = fopen(temp_name, "wb");
1338 if (outfile == NULL)
1339 error("Can't open temporary file");
1346 main(int argc, char *argv[])
1348 int i, cmd, count, nfiles, found, done;
1350 struct lzh_header h;
1353 INITIALIZE_OPTS(opts);
1358 /*take a command character */
1370 /* -<cmd> -<opts> ... */
1375 /* -<cmd><opts> => -<opts> */
1380 parse_args(argc, argv);
1384 archive_file = argv[0];
1386 if (strcmp(archive_file, "-") == 0)
1387 opts.archive_to_stdio = 1;
1395 count = done = nfiles = 0;
1401 if (opts.archive_to_stdio)
1404 outfile = open_tempfile();
1406 error("archived files are not specified.");
1408 if (!opts.archive_to_stdio && (cmd == 'a' || cmd == 'u')) {
1409 if (file_exists(archive_file)) {
1410 arcfile = fopen(archive_file, "rb");
1411 if (arcfile == NULL)
1412 error("Can't open archive '%s'", archive_file);
1417 for (i = 0; i < argc; i++) {
1418 add(0, argv[i], strlen(argv[i]));
1421 fputc(0, outfile); /* end of archive */
1422 if (ferror(outfile))
1423 error("Can't write");
1425 if (opts.archive_to_stdio) {
1426 if (move_file_to_stream(temp_name, stdout) == -1)
1427 error("fail to move_file_to_stream(): %s -> %s",temp_name,"stdout");
1430 unlink(archive_file);
1431 if (xrename(temp_name, archive_file) == -1)
1432 error("fail to rename(): %s -> %s",temp_name,archive_file);
1439 message("No files given in argument, do nothing.");
1442 outfile = open_tempfile();
1448 if (opts.archive_to_stdio) {
1452 arcfile = fopen(archive_file, "rb");
1454 if (arcfile == NULL)
1455 error("Can't open archive '%s'", archive_file);
1463 /* change directory to extract dir */
1466 if (mkdir(opts.outdir, 0777) == -1) {
1467 if (errno != EEXIST)
1468 error("cannot make directory \"%s\"", opts.outdir);
1471 if (chdir(opts.outdir) == -1)
1472 error("cannot change directory \"%s\"", opts.outdir);
1478 while (!done && read_header(arcfile, &h)) {
1482 compsize = h.compsize;
1483 origsize = h.origsize;
1485 found = search(argc, argv, &h);
1492 if (cmd == 'u' && h.mtime > file_mtime(h.filename)) {
1493 copy(arcfile, outfile, &h);
1497 if (add(1, h.filename, h.namelen)) {
1502 copy(arcfile, outfile, &h);
1505 copy(arcfile, outfile, &h);
1510 message("'%s' deleted", h.filename);
1514 copy(arcfile, outfile, &h);
1519 extract(cmd == 'x', &h);
1520 if (++count == nfiles)
1532 if (++count == nfiles)
1540 if (cmd == 'a' || cmd == 'u') {
1541 for (i = 0; i < argc; i++) {
1544 add(0, argv[i], strlen(argv[i]));
1551 printf(" %d files\n", count);
1554 if (count > 0 && (cmd == 'd' || cmd == 'a' || cmd == 'u')) {
1555 fputc(0, outfile); /* end of archive */
1556 if (ferror(outfile))
1557 error("Can't write");
1558 if (!opts.archive_to_stdio)
1559 unlink(archive_file);
1563 if (arc_count > count) {
1564 if (xrename(temp_name, archive_file) == -1)
1565 error("fail to rename(): %s -> %s",temp_name,archive_file);
1568 message("The archive file \"%s\" was removed because it would be empty.", archive_file);
1572 if (xrename(temp_name, archive_file) == -1)
1573 error("fail to rename(): %s -> %s",temp_name,archive_file);
1577 return EXIT_SUCCESS;