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 Symblic Link 1993.06.25 N.Watazaki */
32 /* Ver. 1.11 for Symblic 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 /* ------------------------------------------------------------------------ */
47 /* ------------------------------------------------------------------------ */
49 /* ------------------------------------------------------------------------ */
50 static int cmd = CMD_UNKNOWN;
52 /* 1996.8.13 t.okamoto */
58 char expanded_archive_name[FILENAME_LENGTH];
59 char temporary_name[FILENAME_LENGTH];
60 char backup_archive_name[FILENAME_LENGTH];
63 /* static functions */
64 static void sort_files();
65 static void print_version();
67 char *extract_directory = NULL;
71 /* 1996.8.13 t.okamoto */
73 char *writting_filename;
74 char *reading_filename;
76 int archive_file_mode;
79 /* ------------------------------------------------------------------------ */
81 init_variable() /* Added N.Watazaki */
87 noexec = FALSE; /* debugging option */
91 compress_method = LZHUFF5_METHOD_NUM;
94 compress_method = LZHUFF7_METHOD_NUM;
97 header_level = HEADER_LEVEL1;
104 /* view command flags */
105 verbose_listing = FALSE;
107 /* extract command flags */
108 output_to_stdout = FALSE;
110 /* append command flags */
112 update_if_newer = FALSE;
113 delete_after_append = FALSE;
114 generic_format = FALSE;
116 remove_temporary_at_error = FALSE;
117 recover_archive_when_interrupt = FALSE;
118 remove_extracting_file_when_interrupt = FALSE;
119 get_filename_from_stdin = FALSE;
120 ignore_directory = FALSE;
123 noconvertcase = FALSE;
125 extract_directory = NULL;
129 /* ------------------------------------------------------------------------ */
130 /* NOTES : Text File Format */
131 /* GENERATOR NewLine */
132 /* [generic] 0D 0A */
134 /* [OS9][MacOS] 0D */
136 /* ------------------------------------------------------------------------ */
138 print_tiny_usage_and_exit()
141 LHarc for UNIX V 1.02 Copyright(C) 1989 Y.Tagawa\n\
142 LHx for MSDOS V C2.01 Copyright(C) 1990 H.Yoshizaki\n\
143 LHx(arc) for OSK V 2.01 Modified 1990 Momozou\n\
144 LHa for UNIX V 1.00 Copyright(C) 1992 Masaru Oki\n\
145 LHa for UNIX V 1.14 Modified 1995 Nobutaka Watazaki\n\
146 LHa for UNIX V 1.14i Modified 2000 Tsugio Okamoto\n\
149 usage: lha [-]{axelvudmcp[q[num]][vnfodizg012]}[w=<dir>] archive_file [file...]\n\
150 commands: options:\n\
151 a Add(or replace) to archive q{num} quiet (num:quiet mode)\n\
152 x,e EXtract from archive v verbose\n\
153 l,v List / Verbose List n not execute\n\
154 u Update newer files to archive f force (over write at extract)\n\
155 d Delete from archive t FILES are TEXT file\n");
158 m Move to archive (means 'ad') o[567] compression method (a/u)\n\
163 m Move to archive (means 'ad') o use LHarc compatible method (a/u)\n\
167 c re-Construct new archive w=<dir> specify extract directory (a/u/m/x/e)\n\
168 p Print to STDOUT from archive d delete FILES after (a/u/c)\n\
169 t Test file CRC in archive i ignore directory path (x/e)\n\
170 z files not compress (a/u)\n\
171 g Generic format (for compatibility)\n\
172 or not convert case when extracting\n\
173 0/1/2 header level (a/u)\n\
177 e TEXT code convert from/to EUC\n\
183 /* ------------------------------------------------------------------------ */
189 char *p, inpbuf[256];
195 init_variable(); /* Added N.Watazaki */
198 av = (char **)malloc( sizeof(char*)*argc );
199 if (av == NULL) fatal_error("not enough memory\n");
200 for (i=0; i<argc; i++) {
201 if ((av[i] = strdup( argv[i] )) == NULL)
202 fatal_error("not enough memory\n");
206 print_tiny_usage_and_exit();
208 if (strcmp(av[1], "--version") == 0) {
215 av--; /* argv--; */ /* 1999.7.18 */
232 output_to_stdout = TRUE;
250 update_if_newer = TRUE;
255 delete_after_append = TRUE;
260 verbose_listing = TRUE;
274 print_tiny_usage_and_exit();
279 /* p = &argv[1][1]; */
287 quiet_mode = *p - '0';
317 generic_format = TRUE;
318 noconvertcase = TRUE;
322 delete_after_append = TRUE;
327 compress_method = LZHUFF1_METHOD_NUM;
331 compress_method = LZHUFF5_METHOD_NUM;
336 compress_method = LZHUFF6_METHOD_NUM;
340 compress_method = LZHUFF7_METHOD_NUM;
345 fprintf(stderr, "LHa: error option o%c\n", p[-1]);
350 compress_method = LZHUFF0_METHOD_NUM; /* Changed N.Watazaki */
353 ignore_directory = TRUE;
358 extract_directory = p;
363 header_level = HEADER_LEVEL0;
366 header_level = HEADER_LEVEL1;
369 header_level = HEADER_LEVEL2;
372 fprintf(stderr, "LHa: Unknown option '%c'.\n", p[-1]);
378 /* archive file name */
379 archive_name = av[2];
381 if (!strcmp(archive_name, "-")) {
382 if (!isatty(1) && cmd == CMD_ADD)
386 if (ac == 3 && !isatty(0)) { /* 1999.7.18 */
387 get_filename_from_stdin = TRUE;
391 /* target file name */
392 if (get_filename_from_stdin) {
394 if ((xfilev = (char **) malloc(sizeof(char *) * xfilec)) == NULL)
395 fatal_error("Virtual memory exhausted\n");
396 while (fgets(inpbuf, sizeof(inpbuf), stdin)) {
397 /* delete \n if it exist */
399 while (i < sizeof(inpbuf) && p != 0) {
407 if (cmd_filec >= xfilec) {
409 cmd_filev = (char **) realloc(xfilev,
410 sizeof(char *) * xfilec);
411 if (cmd_filev == NULL)
412 fatal_error("Virtual memory exhausted\n");
415 if (strlen(inpbuf) < 1)
417 if ((xfilev[cmd_filec++] = (char *) strdup(inpbuf)) == NULL)
418 fatal_error("Virtual memory exhausted\n");
420 xfilev[cmd_filec] = NULL;
455 /* ------------------------------------------------------------------------ */
457 /* ------------------------------------------------------------------------ */
459 /* ------------------------------------------------------------------------ */
463 fprintf(stderr, "%s\n", LHA_VERSION);
466 /* ------------------------------------------------------------------------ */
468 message_1(title, subject, name)
469 char *title, *subject, *name;
471 fprintf(stderr, "LHa: %s%s ", title, subject);
475 fprintf(stderr, "%s\n", name);
480 /* ------------------------------------------------------------------------ */
482 message(subject, name)
483 char *subject, *name;
485 message_1("", subject, name);
488 /* ------------------------------------------------------------------------ */
490 warning(subject, name)
491 char *subject, *name;
493 message_1("Warning: ", subject, name);
496 /* ------------------------------------------------------------------------ */
501 message_1("Error: ", subject, msg);
504 /* ------------------------------------------------------------------------ */
509 message_1("Fatal error:", "", msg);
511 if (remove_temporary_at_error)
512 unlink(temporary_name);
517 /* ------------------------------------------------------------------------ */
521 fatal_error(writting_filename);
524 /* ------------------------------------------------------------------------ */
528 fatal_error(reading_filename);
531 /* ------------------------------------------------------------------------ */
537 message("Interrupted\n", "");
540 fclose(temporary_fp);
541 unlink(temporary_name);
542 if (recover_archive_when_interrupt)
543 rename(backup_archive_name, archive_name);
544 if (remove_extracting_file_when_interrupt) {
546 message("Removing", writting_filename);
547 unlink(writting_filename);
549 signal(SIGINT, SIG_DFL);
550 signal(SIGHUP, SIG_DFL);
551 kill(getpid(), signo);
554 /* ------------------------------------------------------------------------ */
556 /* ------------------------------------------------------------------------ */
561 register char *p, *q;
565 if (generic_format) {
567 c1 = *(unsigned char *) p++;
568 c2 = *(unsigned char *) q++;
580 while (*p == *q && *p != '\0')
582 return *(unsigned char *) p - *(unsigned char *) q;
586 /* ------------------------------------------------------------------------ */
591 qsort(cmd_filev, cmd_filec, sizeof(char *), sort_by_ascii);
594 /* ------------------------------------------------------------------------ */
599 char *p = (char *) malloc(size);
601 fatal_error("Not enough memory");
605 /* ------------------------------------------------------------------------ */
611 char *p = (char *) realloc(old, size);
613 fatal_error("Not enough memory");
617 /* ------------------------------------------------------------------------ */
619 /* ------------------------------------------------------------------------ */
622 +-------------+-------------+------+-------------+----------+
623 | N A M E 1 \0| N A M E 2 \0| .... | N A M E n \0| |
624 +-------------+-------------+------+-------------+----------+
625 ^ ^ ^ buffer+0 buffer+used buffer+size
628 +---------------+---------------+------------- -----------------+
629 | pointer to | pointer to | pointer to ... pointer to |
630 | stringpool | N A M E 1 | N A M E 2 ... N A M E n |
631 +---------------+---------------+------------- -------------+
632 ^ malloc base returned
635 /* ------------------------------------------------------------------------ */
638 struct string_pool *sp;
640 sp->size = 1024 - 8; /* any ( >=0 ) */
643 sp->buffer = (char *) xmalloc(sp->size * sizeof(char));
646 /* ------------------------------------------------------------------------ */
648 add_sp(sp, name, len)
649 struct string_pool *sp;
650 char *name; /* stored '\0' at tail */
651 int len; /* include '\0' */
653 while (sp->used + len > sp->size) {
655 sp->buffer = (char *) xrealloc(sp->buffer, sp->size * sizeof(char));
657 bcopy(name, sp->buffer + sp->used, len);
662 /* ------------------------------------------------------------------------ */
664 finish_sp(sp, v_count, v_vector)
665 register struct string_pool *sp;
673 v = (char **) xmalloc((sp->n + 1) * sizeof(char *));
678 for (i = sp->n; i; i--) {
685 /* ------------------------------------------------------------------------ */
691 free(*vector); /* free string pool */
696 /* ------------------------------------------------------------------------ */
697 /* READ DIRECTORY FILES */
698 /* ------------------------------------------------------------------------ */
700 include_path_p(path, name)
706 return (path[-1] == '/' && *n == '\0');
707 return (*n == '/' || (n != name && path[-1] == '/' && n[-1] == '/'));
710 /* ------------------------------------------------------------------------ */
712 cleaning_files(v_filec, v_filev)
719 register char **filev = *v_filev;
720 register int filec = *v_filec;
727 flags = xmalloc(filec * sizeof(char));
729 /* flags & 0x01 : 1: ignore */
730 /* flags & 0x02 : 1: directory, 0 : regular file */
731 /* flags & 0x04 : 1: need delete */
734 for (i = 0; i < filec; i++)
735 if (GETSTAT(filev[i], &stbuf) < 0) {
738 "LHa: Cannot access \"%s\", ignored.\n", filev[i]);
741 if (is_regularfile(&stbuf))
743 else if (is_directory(&stbuf))
746 else if (is_symlink(&stbuf)) /* t.okamoto */
752 "LHa: Cannot archive \"%s\", ignored.\n", filev[i]);
757 for (i = 0; i < filec; i++) {
759 if ((flags[i] & 0x07) == 0x00) { /* regular file, not
761 for (j = i + 1; j < filec; j++) {
762 if ((flags[j] & 0x07) == 0x00) { /* regular file, not
764 if (STREQU(p, filev[j]))
765 flags[j] = 0x04; /* delete */
769 else if ((flags[i] & 0x07) == 0x02) { /* directory, not
771 for (j = i + 1; j < filec; j++) {
772 if ((flags[j] & 0x07) == 0x00) { /* regular file, not
774 if (include_path_p(p, filev[j]))
775 flags[j] = 0x04; /* delete */
777 else if ((flags[j] & 0x07) == 0x02) { /* directory, not
779 if (include_path_p(p, filev[j]))
780 flags[j] = 0x04; /* delete */
786 for (i = j = 0; i < filec; i++) {
787 if ((flags[i] & 0x04) == 0) {
798 /* ------------------------------------------------------------------------ */
800 /* please need your imprementation */
802 find_files(name, v_filec, v_filev)
807 return FALSE; /* DUMMY */
810 /* ------------------------------------------------------------------------ */
812 free_files(filec, filev)
818 /* ------------------------------------------------------------------------ */
821 find_files(name, v_filec, v_filev)
826 struct string_pool sp;
827 char newname[FILENAME_LENGTH];
831 struct stat tmp_stbuf, arc_stbuf, fil_stbuf;
833 strcpy(newname, name);
835 if (len > 0 && newname[len - 1] != '/')
836 newname[len++] = '/';
838 dirp = opendir(name);
844 GETSTAT(temporary_name, &tmp_stbuf);
845 GETSTAT(archive_name, &arc_stbuf);
847 for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
849 strncpy(newname + len, dp->d_name, n);
850 newname[len + n] = '\0';
851 if (GETSTAT(newname, &fil_stbuf) < 0)
854 if ( dp->d_name[0] != '.' ||
856 (dp->d_name[1] != '.' ||
858 add_sp(&sp, newname, len+n+1);
861 if ((dp->d_ino != 0) &&
862 /* exclude '.' and '..' */
863 ((dp->d_name[0] != '.') ||
865 ((dp->d_name[1] != '.') ||
867 ((tmp_stbuf.st_dev != fil_stbuf.st_dev ||
868 tmp_stbuf.st_ino != fil_stbuf.st_ino) &&
869 (arc_stbuf.st_dev != fil_stbuf.st_dev ||
870 arc_stbuf.st_ino != fil_stbuf.st_ino))) {
871 add_sp(&sp, newname, len + n + 1);
876 finish_sp(&sp, v_filec, v_filev);
878 qsort(*v_filev, *v_filec, sizeof(char *), sort_by_ascii);
879 cleaning_files(v_filec, v_filev);
884 /* ------------------------------------------------------------------------ */
886 free_files(filec, filev)
893 /* ------------------------------------------------------------------------ */
895 /* ------------------------------------------------------------------------ */
896 /* Build temporary file name and store to TEMPORARY_NAME */
898 build_temporary_name()
900 #ifdef TMP_FILENAME_TEMPLATE
901 /* "/tmp/lhXXXXXX" etc. */
902 if (extract_directory == NULL) {
903 strcpy(temporary_name, TMP_FILENAME_TEMPLATE);
906 sprintf(temporary_name, "%s/lhXXXXXX", extract_directory);
909 mkstemp(temporary_name);
911 mktemp(temporary_name);
916 strcpy(temporary_name, archive_name);
917 for (p = temporary_name, s = (char *) 0; *p; p++)
920 strcpy((s ? s + 1 : temporary_name), "lhXXXXXX");
922 mkstemp(temporary_name);
924 mktemp(temporary_name);
929 /* ------------------------------------------------------------------------ */
931 modify_filename_extention(buffer, ext)
935 register char *p, *dot;
937 for (p = buffer, dot = (char *) 0; *p; p++) {
950 /* ------------------------------------------------------------------------ */
951 /* build backup file name */
953 build_backup_name(buffer, original)
957 strcpy(buffer, original);
958 modify_filename_extention(buffer, BACKUPNAME_EXTENTION); /* ".bak" */
961 /* ------------------------------------------------------------------------ */
963 build_standard_archive_name(buffer, orginal)
967 strcpy(buffer, orginal);
968 modify_filename_extention(buffer, ARCHIVENAME_EXTENTION); /* ".lzh" */
971 /* ------------------------------------------------------------------------ */
973 /* ------------------------------------------------------------------------ */
983 for (i = 0; i < cmd_filec; i++) {
984 if (patmatch(cmd_filev[i], name, 0))
997 if ((fp = fopen(name, mode)) == NULL)
1003 /* ------------------------------------------------------------------------ */
1005 /* ------------------------------------------------------------------------ */
1007 open_old_archive_1(name, v_fp)
1014 if (stat(name, &stbuf) >= 0 &&
1015 is_regularfile(&stbuf) &&
1016 (fp = fopen(name, READ_BINARY)) != NULL) {
1018 archive_file_gid = stbuf.st_gid;
1019 archive_file_mode = stbuf.st_mode;
1024 archive_file_gid = -1;
1028 /* ------------------------------------------------------------------------ */
1035 if (!strcmp(archive_name, "-")) {
1036 if (cmd == CMD_EXTRACT || cmd == CMD_LIST)
1041 if (p = (char *) strrchr(archive_name, '.')) {
1042 if (strucmp(".LZH", p) == 0
1043 || strucmp(".LZS", p) == 0
1044 || strucmp(".COM", p) == 0 /* DOS SFX */
1045 || strucmp(".EXE", p) == 0
1046 || strucmp(".X", p) == 0 /* HUMAN SFX */
1047 || strucmp(".BAK", p) == 0) { /* for BackUp */
1048 open_old_archive_1(archive_name, &fp);
1053 if (open_old_archive_1(archive_name, &fp))
1055 sprintf(expanded_archive_name, "%s.lzh", archive_name);
1056 if (open_old_archive_1(expanded_archive_name, &fp)) {
1057 archive_name = expanded_archive_name;
1061 * if ( (errno&0xffff)!=E_PNNF ) { archive_name =
1062 * expanded_archive_name; return NULL; }
1064 sprintf(expanded_archive_name, "%s.lzs", archive_name);
1065 if (open_old_archive_1(expanded_archive_name, &fp)) {
1066 archive_name = expanded_archive_name;
1070 * if ( (errno&0xffff)!=E_PNNF ) { archive_name =
1071 * expanded_archive_name; return NULL; }
1074 * sprintf( expanded_archive_name , "%s.lzh",archive_name);
1075 * archive_name = expanded_archive_name;
1080 /* ------------------------------------------------------------------------ */
1082 inquire(msg, name, selective)
1083 char *msg, *name, *selective;
1089 fprintf(stderr, "%s %s ", name, msg);
1092 fgets(buffer, 1024, stdin);
1094 for (p = selective; *p; p++)
1095 if (buffer[0] == *p)
1096 return p - selective;
1101 /* ------------------------------------------------------------------------ */
1103 write_archive_tail(nafp)
1109 /* ------------------------------------------------------------------------ */
1111 copy_old_one(oafp, nafp, hdr)
1116 fseek(oafp, (long) (hdr->header_size + 2) + hdr->packed_size, SEEK_CUR);
1119 reading_filename = archive_name;
1120 writting_filename = temporary_name;
1121 if (hdr->header_level != 2) {
1122 copyfile(oafp, nafp,
1123 (long) (hdr->header_size + 2) + hdr->packed_size, 0);
1125 copyfile(oafp, nafp,
1126 (long) (hdr->header_size) + hdr->packed_size, 0);
1131 /* Local Variables: */
1134 /* compile-command:"gcc -c lharc.c" */