1 /* ------------------------------------------------------------------------ */
3 /* lharc.c -- append to archive */
5 /* Copyright (C) MCMLXXXIX Yooichi.Tagawa */
6 /* Modified Nobutaka Watazaki */
7 /* Thanks to H.Yoshizaki. (MS-DOS LHarc) */
9 /* Ver. 0.00 Original 1988.05.23 Y.Tagawa */
10 /* Ver. 0.01 Alpha Version (for 4.2BSD) 1989.05.28 Y.Tagawa */
11 /* Ver. 0.02 Alpha Version Rel.2 1989.05.29 Y.Tagawa */
12 /* Ver. 0.03 Release #3 Beta Version 1989.07.02 Y.Tagawa */
13 /* Ver. 0.03a Debug 1989.07.03 Y.Tagawa */
14 /* Ver. 0.03b Modified 1989.07.13 Y.Tagawa */
15 /* Ver. 0.03c Debug (Thanks to void@rena.dit.junet) */
16 /* 1989.08.09 Y.Tagawa */
17 /* Ver. 0.03d Modified (quiet and verbose) 1989.09.14 Y.Tagawa */
18 /* V1.00 Fixed 1989.09.22 Y.Tagawa */
19 /* V1.01 Bug Fixed 1989.12.25 Y.Tagawa */
21 /* DOS-Version Original LHx V C2.01 (C) H.Yohizaki */
23 /* V2.00 UNIX Lharc + DOS LHx -> OSK LHx 1990.11.01 Momozou */
24 /* V2.01 Minor Modified 1990.11.24 Momozou */
26 /* Ver. 0.02 LHx for UNIX 1991.11.18 M.Oki */
27 /* Ver. 0.03 LHa for UNIX 1991.12.17 M.Oki */
28 /* Ver. 0.04 LHa for UNIX beta version 1992.01.20 M.Oki */
29 /* Ver. 1.00 LHa for UNIX Fixed 1992.03.19 M.Oki */
31 /* Ver. 1.10 for Symbolic Link 1993.06.25 N.Watazaki */
32 /* Ver. 1.11 for Symbolic Link Bug Fixed 1993.08.18 N.Watazaki */
33 /* Ver. 1.12 for File Date Check 1993.10.28 N.Watazaki */
34 /* Ver. 1.13 Bug Fixed (Idicator calcurate) 1994.02.21 N.Watazaki */
35 /* Ver. 1.13a Bug Fixed (Sym. Link delete) 1994.03.11 N.Watazaki */
36 /* Ver. 1.13b Bug Fixed (Sym. Link delete) 1994.07.29 N.Watazaki */
37 /* Ver. 1.14 Source All chagned 1995.01.14 N.Watazaki */
38 /* Ver. 1.14b,c Bug Fixed 1996.03.07 t.okamoto */
39 /* Ver. 1.14d Version up 1997.01.12 t.okamoto */
40 /* Ver. 1.14g Bug Fixed 2000.05.06 t.okamoto */
41 /* Ver. 1.14i Modified 2000.10.06 t.okamoto */
42 /* Modified for Mac OS X 2002.06.03 H.Sakai */
43 /* ------------------------------------------------------------------------ */
48 static int cmd = CMD_UNKNOWN;
50 /* static functions */
51 static void sort_files();
52 static void print_version();
54 /* ------------------------------------------------------------------------ */
56 init_variable() /* Added N.Watazaki */
62 noexec = FALSE; /* debugging option */
66 compress_method = DEFAULT_LZHUFF_METHOD; /* defined in config.h */
68 header_level = HEADER_LEVEL1;
75 /* view command flags */
76 verbose_listing = FALSE;
78 /* extract command flags */
79 output_to_stdout = FALSE;
81 /* append command flags */
83 update_if_newer = FALSE;
84 delete_after_append = FALSE;
85 generic_format = FALSE;
87 remove_temporary_at_error = FALSE;
88 recover_archive_when_interrupt = FALSE;
89 remove_extracting_file_when_interrupt = FALSE;
90 get_filename_from_stdin = FALSE;
91 ignore_directory = FALSE;
94 noconvertcase = FALSE;
96 extract_directory = NULL;
100 /* ------------------------------------------------------------------------ */
101 /* NOTES : Text File Format */
102 /* GENERATOR NewLine */
103 /* [generic] 0D 0A */
105 /* [OS9][MacOS] 0D */
107 /* ------------------------------------------------------------------------ */
112 LHarc for UNIX V 1.02 Copyright(C) 1989 Y.Tagawa\n\
113 LHx for MSDOS V C2.01 Copyright(C) 1990 H.Yoshizaki\n\
114 LHx(arc) for OSK V 2.01 Modified 1990 Momozou\n\
115 LHa for UNIX V 1.00 Copyright(C) 1992 Masaru Oki\n\
116 LHa for UNIX V 1.14 Modified 1995 Nobutaka Watazaki\n\
117 LHa for UNIX V 1.14i Modified 2000 Tsugio Okamoto\n\
118 Modified 2002 Hiroto Sakai\n\
119 Autoconfiscated 2001,2002 Koji Arai\n\
122 usage: lha [-]{axelvudmcp[q[num]][vnfodizg012]}[w=<dir>] archive_file [file...]\n\
123 commands: options:\n\
124 a Add(or replace) to archive q{num} quiet (num:quiet mode)\n\
125 x,e EXtract from archive v verbose\n\
126 l,v List / Verbose List n not execute\n\
127 u Update newer files to archive f force (over write at extract)\n\
128 d Delete from archive t FILES are TEXT file\n");
131 m Move to archive (means 'ad') o[567] compression method (a/u)\n\
136 m Move to archive (means 'ad') o use LHarc compatible method (a/u)\n\
140 c re-Construct new archive w=<dir> specify extract directory (a/u/m/x/e)\n\
141 p Print to STDOUT from archive d delete FILES after (a/u/c)\n\
142 t Test file CRC in archive i ignore directory path (x/e)\n\
143 z files not compress (a/u)\n\
144 g Generic format (for compatibility)\n\
145 or not convert case when extracting\n\
146 0/1/2 header level (a/u)\n\
150 e TEXT code convert from/to EUC\n\
156 /* ------------------------------------------------------------------------ */
162 char *p, inpbuf[256];
168 init_variable(); /* Added N.Watazaki */
171 av = (char **)xmalloc( sizeof(char*)*argc );
172 for (i=0; i<argc; i++) {
173 av[i] = xstrdup( argv[i] );
176 if (ac < 2 || strcmp(av[1], "--help") == 0) {
181 if (strcmp(av[1], "--version") == 0) {
188 av--; /* argv--; */ /* 1999.7.18 */
205 output_to_stdout = TRUE;
223 update_if_newer = TRUE;
228 delete_after_append = TRUE;
233 verbose_listing = TRUE;
247 print_tiny_usage_and_exit();
252 /* p = &argv[1][1]; */
258 case '0': /* no quiet */
259 case '1': /* no use the incremental indicator */
260 quiet_mode = *p - '0';
263 case '2': /* no output */
267 /* In quiet mode, no confirm to overwrite */
295 generic_format = TRUE;
296 noconvertcase = TRUE;
300 delete_after_append = TRUE;
305 compress_method = LZHUFF1_METHOD_NUM;
309 compress_method = LZHUFF5_METHOD_NUM;
314 compress_method = LZHUFF6_METHOD_NUM;
318 compress_method = LZHUFF7_METHOD_NUM;
323 error("invalid compression method 'o%c'", *p);
328 compress_method = LZHUFF0_METHOD_NUM; /* Changed N.Watazaki */
331 ignore_directory = TRUE;
336 extract_directory = p;
341 header_level = HEADER_LEVEL0;
344 header_level = HEADER_LEVEL1;
347 header_level = HEADER_LEVEL2;
350 error("Unknown option '%c'.", p[-1]);
356 /* archive file name */
357 archive_name = av[2];
359 if (!strcmp(archive_name, "-")) {
360 if (!isatty(1) && cmd == CMD_ADD)
363 #if 0 /* Comment out; IMHO, this feature is useless. by Koji Arai */
365 if (ac == 3 && !isatty(0)) { /* 1999.7.18 */
366 /* Bug(?) on MinGW, isatty() return 0 on Cygwin console.
367 mingw-runtime-1.3-2 and Cygwin 1.3.10(0.51/3/2) on
369 get_filename_from_stdin = TRUE;
374 /* target file name */
375 if (get_filename_from_stdin) {
380 xfilev = (char **)xmalloc(sizeof(char *) * xfilec);
381 while (fgets(inpbuf, sizeof(inpbuf), stdin)) {
382 /* delete \n if it exist */
384 while (i < sizeof(inpbuf) && p != 0) {
392 if (cmd_filec >= xfilec) {
394 xfilev = (char **) xrealloc(xfilev,
395 sizeof(char *) * xfilec);
397 if (strlen(inpbuf) < 1)
399 xfilev[cmd_filec++] = xstrdup(inpbuf);
401 xfilev[cmd_filec] = NULL;
436 /* ------------------------------------------------------------------------ */
438 /* ------------------------------------------------------------------------ */
440 /* ------------------------------------------------------------------------ */
444 fprintf(stderr, "%s\n", LHA_VERSION);
449 message(char *fmt, ...)
451 message(fmt, va_alist)
456 int errno_sv = errno;
459 fprintf(stderr, "LHa: ");
462 vfprintf(stderr, fmt, v);
470 /* ------------------------------------------------------------------------ */
473 warning(char *fmt, ...)
475 warning(fmt, va_alist)
480 int errno_sv = errno;
483 fprintf(stderr, "LHa: Warning: ");
486 vfprintf(stderr, fmt, v);
494 /* ------------------------------------------------------------------------ */
497 error(char *fmt, ...)
504 int errno_sv = errno;
507 fprintf(stderr, "LHa: Error: ");
510 vfprintf(stderr, fmt, v);
520 fatal_error(char *fmt, ...)
522 fatal_error(fmt, va_alist)
527 int errno_sv = errno;
530 fprintf(stderr, "LHa: Fatal error: ");
533 vfprintf(stderr, fmt, v);
537 fprintf(stderr, ": %s\n", strerror(errno_sv));
541 if (remove_temporary_at_error) {
542 if (temporary_fd != -1)
544 unlink(temporary_name);
550 /* ------------------------------------------------------------------------ */
555 message("Interrupted");
557 if (temporary_fd != -1)
559 unlink(temporary_name);
560 if (recover_archive_when_interrupt)
561 rename(backup_archive_name, archive_name);
562 if (remove_extracting_file_when_interrupt) {
563 message("Removing: %s", writting_filename);
564 unlink(writting_filename);
566 signal(SIGINT, SIG_DFL);
568 signal(SIGHUP, SIG_DFL);
570 kill(getpid(), signo);
573 /* ------------------------------------------------------------------------ */
575 /* ------------------------------------------------------------------------ */
580 register char *p, *q;
584 if (generic_format) {
586 c1 = *(unsigned char *) p++;
587 c2 = *(unsigned char *) q++;
599 while (*p == *q && *p != '\0')
601 return *(unsigned char *) p - *(unsigned char *) q;
605 /* ------------------------------------------------------------------------ */
610 qsort(cmd_filev, cmd_filec, sizeof(char *), sort_by_ascii);
613 /* ------------------------------------------------------------------------ */
618 void *p = malloc(size);
620 fatal_error("Not enough memory");
624 /* ------------------------------------------------------------------------ */
630 void *p = (char *) realloc(old, size);
632 fatal_error("Not enough memory");
640 int len = strlen(str);
641 char *p = (char *)xmalloc(len + 1);
646 /* ------------------------------------------------------------------------ */
648 /* ------------------------------------------------------------------------ */
651 +-------------+-------------+------+-------------+----------+
652 | N A M E 1 \0| N A M E 2 \0| .... | N A M E n \0| |
653 +-------------+-------------+------+-------------+----------+
654 ^ ^ ^ buffer+0 buffer+used buffer+size
657 +---------------+---------------+------------- -----------------+
658 | pointer to | pointer to | pointer to ... pointer to |
659 | stringpool | N A M E 1 | N A M E 2 ... N A M E n |
660 +---------------+---------------+------------- -------------+
661 ^ malloc base returned
664 /* ------------------------------------------------------------------------ */
667 struct string_pool *sp;
669 sp->size = 1024 - 8; /* any ( >=0 ) */
672 sp->buffer = (char *) xmalloc(sp->size * sizeof(char));
675 /* ------------------------------------------------------------------------ */
677 add_sp(sp, name, len)
678 struct string_pool *sp;
679 char *name; /* stored '\0' at tail */
680 int len; /* include '\0' */
682 while (sp->used + len > sp->size) {
684 sp->buffer = (char *) xrealloc(sp->buffer, sp->size * sizeof(char));
686 memmove(sp->buffer + sp->used, name, len);
691 /* ------------------------------------------------------------------------ */
693 finish_sp(sp, v_count, v_vector)
694 register struct string_pool *sp;
702 v = (char **) xmalloc((sp->n + 1) * sizeof(char *));
707 for (i = sp->n; i; i--) {
714 /* ------------------------------------------------------------------------ */
720 free(*vector); /* free string pool */
725 /* ------------------------------------------------------------------------ */
726 /* READ DIRECTORY FILES */
727 /* ------------------------------------------------------------------------ */
729 include_path_p(path, name)
735 return (path[-1] == '/' && *n == '\0');
736 return (*n == '/' || (n != name && path[-1] == '/' && n[-1] == '/'));
739 /* ------------------------------------------------------------------------ */
741 cleaning_files(v_filec, v_filev)
748 register char **filev = *v_filev;
749 register int filec = *v_filec;
756 flags = xmalloc(filec * sizeof(char));
758 /* flags & 0x01 : 1: ignore */
759 /* flags & 0x02 : 1: directory, 0 : regular file */
760 /* flags & 0x04 : 1: need delete */
763 for (i = 0; i < filec; i++)
764 if (GETSTAT(filev[i], &stbuf) < 0) {
766 warning("Cannot access \"%s\", ignored.", filev[i]);
769 if (is_regularfile(&stbuf))
771 else if (is_directory(&stbuf))
774 else if (is_symlink(&stbuf)) /* t.okamoto */
779 warning("Cannot archive \"%s\", ignored.", filev[i]);
783 for (i = 0; i < filec; i++) {
785 if ((flags[i] & 0x07) == 0x00) { /* regular file, not
787 for (j = i + 1; j < filec; j++) {
788 if ((flags[j] & 0x07) == 0x00) { /* regular file, not
790 if (STREQU(p, filev[j]))
791 flags[j] = 0x04; /* delete */
795 else if ((flags[i] & 0x07) == 0x02) { /* directory, not
797 for (j = i + 1; j < filec; j++) {
798 if ((flags[j] & 0x07) == 0x00) { /* regular file, not
800 if (include_path_p(p, filev[j]))
801 flags[j] = 0x04; /* delete */
803 else if ((flags[j] & 0x07) == 0x02) { /* directory, not
805 if (include_path_p(p, filev[j]))
806 flags[j] = 0x04; /* delete */
812 for (i = j = 0; i < filec; i++) {
813 if ((flags[i] & 0x04) == 0) {
824 /* ------------------------------------------------------------------------ */
826 /* please need your imprementation */
828 find_files(name, v_filec, v_filev)
833 return FALSE; /* DUMMY */
836 /* ------------------------------------------------------------------------ */
838 free_files(filec, filev)
844 /* ------------------------------------------------------------------------ */
847 find_files(name, v_filec, v_filev)
852 struct string_pool sp;
853 char newname[FILENAME_LENGTH];
857 struct stat tmp_stbuf, arc_stbuf, fil_stbuf;
859 strcpy(newname, name);
861 if (len > 0 && newname[len - 1] != '/')
862 newname[len++] = '/';
864 dirp = opendir(name);
870 GETSTAT(temporary_name, &tmp_stbuf);
871 GETSTAT(archive_name, &arc_stbuf);
873 for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
875 strncpy(newname + len, dp->d_name, n);
876 newname[len + n] = '\0';
877 if (GETSTAT(newname, &fil_stbuf) < 0)
879 #if !defined(HAVE_STRUCT_STAT_ST_INO) || __MINGW32__
880 if ( dp->d_name[0] != '.' ||
882 (dp->d_name[1] != '.' ||
884 add_sp(&sp, newname, len+n+1);
887 if ((dp->d_ino != 0) &&
888 /* exclude '.' and '..' */
889 ((dp->d_name[0] != '.') ||
891 ((dp->d_name[1] != '.') ||
893 ((tmp_stbuf.st_dev != fil_stbuf.st_dev ||
894 tmp_stbuf.st_ino != fil_stbuf.st_ino) &&
895 (arc_stbuf.st_dev != fil_stbuf.st_dev ||
896 arc_stbuf.st_ino != fil_stbuf.st_ino))) {
897 add_sp(&sp, newname, len + n + 1);
902 finish_sp(&sp, v_filec, v_filev);
904 qsort(*v_filev, *v_filec, sizeof(char *), sort_by_ascii);
905 cleaning_files(v_filec, v_filev);
910 /* ------------------------------------------------------------------------ */
912 free_files(filec, filev)
919 /* ------------------------------------------------------------------------ */
921 /* ------------------------------------------------------------------------ */
922 /* Build temporary file name and store to TEMPORARY_NAME */
924 build_temporary_name()
926 #ifdef TMP_FILENAME_TEMPLATE
927 /* "/tmp/lhXXXXXX" etc. */
928 if (extract_directory == NULL) {
929 strcpy(temporary_name, TMP_FILENAME_TEMPLATE);
932 xsnprintf(temporary_name, sizeof(temporary_name),
933 "%s/lhXXXXXX", extract_directory);
938 strcpy(temporary_name, archive_name);
939 for (p = temporary_name, s = (char *) 0; *p; p++)
942 strcpy((s ? s + 1 : temporary_name), "lhXXXXXX");
948 old_umask = umask(077);
949 fd = mkstemp(temporary_name);
957 mktemp(temporary_name);
958 flags = O_CREAT|O_EXCL|O_RDWR;
962 return open(temporary_name, flags, 0600);
967 /* ------------------------------------------------------------------------ */
969 modify_filename_extention(buffer, ext)
973 register char *p, *dot;
975 for (p = buffer, dot = (char *) 0; *p; p++) {
988 /* ------------------------------------------------------------------------ */
989 /* build backup file name */
991 build_backup_name(buffer, original)
995 strcpy(buffer, original);
996 modify_filename_extention(buffer, BACKUPNAME_EXTENTION); /* ".bak" */
999 /* ------------------------------------------------------------------------ */
1001 build_standard_archive_name(buffer, orginal)
1005 strcpy(buffer, orginal);
1006 modify_filename_extention(buffer, ARCHIVENAME_EXTENTION); /* ".lzh" */
1009 /* ------------------------------------------------------------------------ */
1011 /* ------------------------------------------------------------------------ */
1021 for (i = 0; i < cmd_filec; i++) {
1022 if (patmatch(cmd_filev[i], name, 0))
1035 if ((fp = fopen(name, mode)) == NULL)
1036 fatal_error("Cannot open file \"%s\"", name);
1041 /* ------------------------------------------------------------------------ */
1043 /* ------------------------------------------------------------------------ */
1045 open_old_archive_1(name, v_fp)
1052 if (stat(name, &stbuf) >= 0 &&
1053 is_regularfile(&stbuf) &&
1054 (fp = fopen(name, READ_BINARY)) != NULL) {
1056 archive_file_gid = stbuf.st_gid;
1057 archive_file_mode = stbuf.st_mode;
1062 archive_file_gid = -1;
1066 /* ------------------------------------------------------------------------ */
1072 static char expanded_archive_name[FILENAME_LENGTH];
1074 if (!strcmp(archive_name, "-")) {
1075 if (cmd == CMD_EXTRACT || cmd == CMD_LIST) {
1077 setmode(fileno(stdin), O_BINARY);
1084 if (p = strrchr(archive_name, '.')) {
1085 if (strucmp(".LZH", p) == 0
1086 || strucmp(".LZS", p) == 0
1087 || strucmp(".COM", p) == 0 /* DOS SFX */
1088 || strucmp(".EXE", p) == 0
1089 || strucmp(".X", p) == 0 /* HUMAN SFX */
1090 || strucmp(".BAK", p) == 0) { /* for BackUp */
1091 open_old_archive_1(archive_name, &fp);
1096 if (open_old_archive_1(archive_name, &fp))
1098 xsnprintf(expanded_archive_name, sizeof(expanded_archive_name),
1099 "%s.lzh", archive_name);
1100 if (open_old_archive_1(expanded_archive_name, &fp)) {
1101 archive_name = expanded_archive_name;
1105 * if ( (errno&0xffff)!=E_PNNF ) { archive_name =
1106 * expanded_archive_name; return NULL; }
1108 xsnprintf(expanded_archive_name, sizeof(expanded_archive_name),
1109 "%s.lzs", archive_name);
1110 if (open_old_archive_1(expanded_archive_name, &fp)) {
1111 archive_name = expanded_archive_name;
1115 * if ( (errno&0xffff)!=E_PNNF ) { archive_name =
1116 * expanded_archive_name; return NULL; }
1119 * sprintf( expanded_archive_name , "%s.lzh",archive_name);
1120 * archive_name = expanded_archive_name;
1125 /* ------------------------------------------------------------------------ */
1127 inquire(msg, name, selective)
1128 char *msg, *name, *selective;
1134 fprintf(stderr, "%s %s ", name, msg);
1137 fgets(buffer, 1024, stdin);
1139 for (p = selective; *p; p++)
1140 if (buffer[0] == *p)
1141 return p - selective;
1146 /* ------------------------------------------------------------------------ */
1148 write_archive_tail(nafp)
1154 /* ------------------------------------------------------------------------ */
1156 copy_old_one(oafp, nafp, hdr)
1161 fseek(oafp, (long) (hdr->header_size + 2) + hdr->packed_size, SEEK_CUR);
1164 reading_filename = archive_name;
1165 writting_filename = temporary_name;
1166 if (hdr->header_level != 2) {
1167 copyfile(oafp, nafp,
1168 (long) (hdr->header_size + 2) + hdr->packed_size, 0);
1170 copyfile(oafp, nafp,
1171 (long) (hdr->header_size) + hdr->packed_size, 0);
1176 /* Local Variables: */
1179 /* compile-command:"gcc -c lharc.c" */
1181 /* vi: set tabstop=4: */