1 /* ------------------------------------------------------------------------ */
3 /* header.c -- header manipulate functions */
5 /* Modified Nobutaka Watazaki */
7 /* Original Y.Tagawa */
8 /* modified 1991.12.16 M.Oki */
9 /* Ver. 1.10 Symbolic Link added 1993.10.01 N.Watazaki */
10 /* Ver. 1.13b Symbolic Link Bug Fix 1994.08.22 N.Watazaki */
11 /* Ver. 1.14 Source All chagned 1995.01.14 N.Watazaki */
12 /* Ver. 1.14e bug fixed 1999.05.27 T.Okamoto */
13 /* ------------------------------------------------------------------------ */
16 /* ------------------------------------------------------------------------ */
18 /* ------------------------------------------------------------------------ */
26 for (sum = 0; len; len--)
32 /* ------------------------------------------------------------------------ */
40 return (b1 << 8) + b0;
43 /* ------------------------------------------------------------------------ */
52 /* ------------------------------------------------------------------------ */
62 return (b3 << 24) + (b2 << 16) + (b1 << 8) + b0;
65 /* ------------------------------------------------------------------------ */
76 /* ------------------------------------------------------------------------ */
78 msdos_to_unix_filename(name, len)
85 for (i = 0; i < len; i++) {
86 if (MULTIBYTE_FIRST_P(name[i]) &&
87 MULTIBYTE_SECOND_P(name[i + 1]))
89 else if (name[i] == '\\')
91 else if (isupper(name[i]))
92 name[i] = tolower(name[i]);
95 for (i = 0; i < len; i++) {
98 else if (isupper(name[i]))
99 name[i] = tolower(name[i]);
104 /* ------------------------------------------------------------------------ */
106 generic_to_unix_filename(name, len)
111 boolean lower_case_used = FALSE;
113 #ifdef MULTIBYTE_CHAR
114 for (i = 0; i < len; i++) {
115 if (MULTIBYTE_FIRST_P(name[i]) &&
116 MULTIBYTE_SECOND_P(name[i + 1]))
118 else if (islower(name[i])) {
119 lower_case_used = TRUE;
123 for (i = 0; i < len; i++) {
124 if (MULTIBYTE_FIRST_P(name[i]) &&
125 MULTIBYTE_SECOND_P(name[i + 1]))
127 else if (name[i] == '\\')
129 else if (!lower_case_used && isupper(name[i]))
130 name[i] = tolower(name[i]);
133 for (i = 0; i < len; i++)
134 if (islower(name[i])) {
135 lower_case_used = TRUE;
138 for (i = 0; i < len; i++) {
141 else if (!lower_case_used && isupper(name[i]))
142 name[i] = tolower(name[i]);
147 /* ------------------------------------------------------------------------ */
149 macos_to_unix_filename(name, len)
155 for (i = 0; i < len; i++) {
158 else if (name[i] == '/')
163 /* ------------------------------------------------------------------------ */
165 unix_to_generic_filename(name, len)
171 for (i = 0; i < len; i++) {
174 else if (islower(name[i]))
175 name[i] = toupper(name[i]);
179 /* ------------------------------------------------------------------------ */
181 /* Generic stamp format: */
183 /* 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 */
184 /* |<-------- year ------->|<- month ->|<-- day -->| */
186 /* 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 */
187 /* |<--- hour --->|<---- minute --->|<- second*2 ->| */
189 /* ------------------------------------------------------------------------ */
192 * NOTE : If you don't have `gettimeofday(2)', or your gettimeofday(2)
193 * returns bogus timezone information, try FTIME, MKTIME, TIMELOCAL or TZSET.
201 #endif /* defined(MKTIME) */
203 #if defined(MKTIME) || defined(TIMELOCAL)
207 #endif /* defined(MKTIME) || defined(TIMELOCAL) */
209 #if defined(MKTIME) || defined(TIMELOCAL) || defined(TZSET)
215 #if defined(MKTIME) || defined(TIMELOCAL) || defined(TZSET) || defined(FTIME)
221 #define GETTIMEOFDAY /* use gettimeofday() */
226 #include <sys/timeb.h>
230 * You may define as : #define TIMEZONE_HOOK \ extern long
231 * timezone ; \ extern void tzset();
235 /* Which do you like better, `TIMEZONE_HOOK' or `TIMEZONE_HOOK;' ? */
238 #if defined(TZSET) && defined(_MINIX)
239 extern long timezone; /* not defined in time.h */
242 /* ------------------------------------------------------------------------ */
243 #if defined(FTIME) || defined(GETTIMEOFDAY) || defined(TZSET)
253 /* ------------------------------------------------------------------------ */
254 #if !defined(TZSET) && defined(FTIME)
259 return buf.timezone * 60L;
263 /* ------------------------------------------------------------------------ */
264 #if !defined(TZSET) && !defined(FTIME) /* maybe defined(GETTIMEOFDAY) */
270 return -localtime(&tt)->tm_gmtoff;
271 #else /* HAVE_TM_ZONE */
274 gettimeofday(&tp, &tzp);/* specific to 4.3BSD */
276 * return (tzp.tz_minuteswest * 60L + (tzp.tz_dsttime != 0 ? 60L *
279 return (tzp.tz_minuteswest * 60L);
280 #endif /* HAVE_TM_ZONE */
283 #endif /* defined(FTIME) || defined(GETTIMEOFDAY) ||
286 /* ------------------------------------------------------------------------ */
289 msdos_to_unix_stamp_tm(a)
294 t.tm_sec = (a & 0x1f) * 2;
295 t.tm_min = (a >> 5) & 0x3f;
296 t.tm_hour = (a >> 11) & 0x1f;
297 t.tm_mday = (a >> 16) & 0x1f;
298 t.tm_mon = ((a >> 16 + 5) & 0x0f) - 1;
299 t.tm_year = ((a >> 16 + 9) & 0x7f) + 80;
304 /* ------------------------------------------------------------------------ */
306 generic_to_unix_stamp(t)
308 #if defined(MKTIME) || defined(TIMELOCAL)
313 * special case: if MSDOS format date and time were zero, then we
314 * set time to be zero here too.
319 dostm.tm_sec = (t & 0x1f) * 2;
320 dostm.tm_min = t >> 5 & 0x3f;
321 dostm.tm_hour = t >> 11 & 0x1f;
322 dostm.tm_mday = t >> 16 & 0x1f;
323 dostm.tm_mon = (t >> 16 + 5 & 0x0f) - 1; /* 0..11 */
324 dostm.tm_year = (t >> 16 + 9 & 0x7f) + 80;
326 dostm.tm_isdst = 0; /* correct? */
328 dostm.tm_isdst = -1; /* correct? */
330 return (time_t) mktime(&dostm);
331 #else /* maybe defined(TIMELOCAL) */
332 return (time_t) timelocal(&dostm);
336 #else /* defined(MKTIME) || defined(TIMELOCAL) */
338 int year, month, day, hour, min, sec;
340 static unsigned int dsboy[12] = {0, 31, 59, 90, 120, 151,
341 181, 212, 243, 273, 304, 334};
345 * special case: if MSDOS format date and time were zero, then we
346 * set time to be zero here too.
351 year = ((int) (t >> 16 + 9) & 0x7f) + 1980;
352 month = (int) (t >> 16 + 5) & 0x0f; /* 1..12 means Jan..Dec */
353 day = (int) (t >> 16) & 0x1f; /* 1..31 means 1st,...31st */
355 hour = ((int) t >> 11) & 0x1f;
356 min = ((int) t >> 5) & 0x3f;
357 sec = ((int) t & 0x1f) * 2;
359 /* Calculate days since 1970.01.01 */
360 days = (365 * (year - 1970) + /* days due to whole years */
361 (year - 1970 + 1) / 4 + /* days due to leap years */
362 dsboy[month - 1] + /* days since beginning of this year */
363 day - 1); /* days since beginning of month */
365 if ((year % 4 == 0) &&
366 (year % 100 != 0 || year % 400 == 0) && /* 1999.5.24 t.oka */
367 (month >= 3)) /* if this is a leap year and month */
368 days++; /* is March or later, add a day */
370 /* Knowing the days, we can find seconds */
371 longtime = (((days * 24) + hour) * 60 + min) * 60 + sec;
372 longtime += gettz(); /* adjust for timezone */
374 /* LONGTIME is now the time in seconds, since 1970/01/01 00:00:00. */
375 return (time_t) longtime;
377 #endif /* defined(MKTIME) || defined(TIMELOCAL) */
379 /* ------------------------------------------------------------------------ */
381 unix_to_generic_stamp(t)
384 struct tm *tm = localtime(&t);
386 return ((((long) (tm->tm_year - 80)) << 25) +
387 (((long) (tm->tm_mon + 1)) << 21) +
388 (((long) tm->tm_mday) << 16) +
389 (long) ((tm->tm_hour << 11) +
394 /* ------------------------------------------------------------------------ */
395 /* build header functions */
396 /* ------------------------------------------------------------------------ */
400 register LzHeader *hdr;
404 char data[LZHEADER_STRAGE];
405 char dirname[FILENAME_LENGTH];
413 bzero(hdr, sizeof(LzHeader));
415 if (((header_size = getc(fp)) == EOF) || (header_size == 0)) {
416 return FALSE; /* finish */
419 if (fread(data + I_HEADER_CHECKSUM,
420 sizeof(char), header_size - 1, fp) < header_size - 1) {
421 fatal_error("Invalid header (LHarc file ?)");
422 return FALSE; /* finish */
424 setup_get(data + I_HEADER_LEVEL);
425 hdr->header_level = get_byte();
426 if (hdr->header_level != 2 &&
427 fread(data + header_size, sizeof(char), 2, fp) < 2) {
428 fatal_error("Invalid header (LHarc file ?)");
429 return FALSE; /* finish */
432 if (hdr->header_level >= 3) {
433 fatal_error("Unknown level header");
437 setup_get(data + I_HEADER_CHECKSUM);
438 checksum = get_byte();
440 hdr->header_size = header_size;
441 bcopy(data + I_METHOD, hdr->method, METHOD_TYPE_STRAGE);
442 setup_get(data + I_PACKED_SIZE);
443 hdr->packed_size = get_longword();
444 hdr->original_size = get_longword();
445 hdr->last_modified_stamp = get_longword();
446 hdr->attribute = get_byte();
448 if ((hdr->header_level = get_byte()) != 2) {
449 if (calc_sum(data + I_METHOD, header_size) != checksum)
450 warning("Checksum error (LHarc file?)", "");
451 name_length = get_byte();
452 for (i = 0; i < name_length; i++)
453 hdr->name[i] = (char) get_byte();
454 hdr->name[name_length] = '\0';
457 hdr->unix_last_modified_stamp = hdr->last_modified_stamp;
461 /* defaults for other type */
462 hdr->unix_mode = UNIX_FILE_REGULAR | UNIX_RW_RW_RW;
467 if (hdr->header_level == 0) {
468 extend_size = header_size - name_length -22;
469 if (extend_size < 0) {
470 if (extend_size == -2) {
471 hdr->extend_type = EXTEND_GENERIC;
472 hdr->has_crc = FALSE;
474 fatal_error("Unkonwn header (lha file?)");
479 hdr->crc = get_word();
482 if (extend_size >= 1) {
483 hdr->extend_type = get_byte();
486 if (hdr->extend_type == EXTEND_UNIX) {
487 if (extend_size >= 11) {
488 hdr->minor_version = get_byte();
489 hdr->unix_last_modified_stamp = (time_t) get_longword();
490 hdr->unix_mode = get_word();
491 hdr->unix_uid = get_word();
492 hdr->unix_gid = get_word();
495 hdr->extend_type = EXTEND_GENERIC;
498 while (extend_size-- > 0)
500 if (hdr->extend_type == EXTEND_UNIX)
502 } else if (hdr->header_level == 1) {
504 extend_size = header_size - name_length-25;
505 hdr->crc = get_word();
506 hdr->extend_type = get_byte();
507 while (extend_size-- > 0)
509 } else { /* level 2 */
511 hdr->crc = get_word();
512 hdr->extend_type = get_byte();
515 if (hdr->header_level > 0) {
517 if (hdr->header_level != 2)
518 setup_get(data + hdr->header_size);
520 while ((header_size = get_word()) != 0) {
521 if (hdr->header_level != 2 &&
522 ((data + LZHEADER_STRAGE - get_ptr < header_size) ||
523 fread(get_ptr, sizeof(char), header_size, fp) < header_size)) {
524 fatal_error("Invalid header (LHa file ?)");
527 switch (get_byte()) {
532 setup_get(get_ptr + header_size - 3);
538 for (i = 0; i < header_size - 3; i++)
539 hdr->name[i] = (char) get_byte();
540 hdr->name[header_size - 3] = '\0';
546 for (i = 0; i < header_size - 3; i++)
547 dirname[i] = (char) get_byte();
548 dirname[header_size - 3] = '\0';
549 convdelim(dirname, DELIM);
550 dir_length = header_size - 3;
556 if (hdr->extend_type == EXTEND_MSDOS ||
557 hdr->extend_type == EXTEND_HUMAN ||
558 hdr->extend_type == EXTEND_GENERIC)
559 hdr->attribute = get_word();
565 if (hdr->extend_type == EXTEND_UNIX)
566 hdr->unix_mode = get_word();
572 if (hdr->extend_type == EXTEND_UNIX) {
573 hdr->unix_gid = get_word();
574 hdr->unix_uid = get_word();
581 setup_get(get_ptr + header_size - 3);
587 setup_get(get_ptr + header_size - 3);
591 * UNIX last modified time
593 if (hdr->extend_type == EXTEND_UNIX)
594 hdr->unix_last_modified_stamp = (time_t) get_longword();
600 setup_get(get_ptr + header_size - 3);
604 if (hdr->header_level != 2 && get_ptr - ptr != 2) {
605 hdr->packed_size -= get_ptr - ptr - 2;
606 hdr->header_size += get_ptr - ptr - 2;
610 strcat(dirname, hdr->name);
611 strcpy(hdr->name, dirname);
612 name_length += dir_length;
615 switch (hdr->extend_type) {
617 msdos_to_unix_filename(hdr->name, name_length);
619 if (hdr->header_level == 2)
620 hdr->unix_last_modified_stamp = hdr->last_modified_stamp;
622 hdr->unix_last_modified_stamp =
623 generic_to_unix_stamp(hdr->last_modified_stamp);
634 macos_to_unix_filename(hdr->name, name_length);
635 hdr->unix_last_modified_stamp =
636 generic_to_unix_stamp(hdr->last_modified_stamp);
640 generic_to_unix_filename(hdr->name, name_length);
641 if (hdr->header_level == 2)
642 hdr->unix_last_modified_stamp = hdr->last_modified_stamp;
644 hdr->unix_last_modified_stamp =
645 generic_to_unix_stamp(hdr->last_modified_stamp);
649 printf("header level=%d\n", hdr->header_level); fflush(stdout);
655 /* ------------------------------------------------------------------------ */
657 init_header(name, v_stat, hdr)
664 if (compress_method == LZHUFF5_METHOD_NUM) /* Changed N.Watazaki */
665 bcopy(LZHUFF5_METHOD, hdr->method, METHOD_TYPE_STRAGE);
666 else if (compress_method)
667 bcopy(LZHUFF1_METHOD, hdr->method, METHOD_TYPE_STRAGE);
669 bcopy(LZHUFF0_METHOD, hdr->method, METHOD_TYPE_STRAGE);
671 hdr->packed_size = 0;
672 hdr->original_size = v_stat->st_size;
673 hdr->last_modified_stamp = unix_to_generic_stamp(v_stat->st_mtime);
674 hdr->attribute = GENERIC_ATTRIBUTE;
675 hdr->header_level = header_level;
676 strcpy(hdr->name, name);
679 hdr->extend_type = EXTEND_UNIX;
680 hdr->unix_last_modified_stamp = v_stat->st_mtime;
681 /* since 00:00:00 JAN.1.1970 */
682 #ifdef NOT_COMPATIBLE_MODE
683 /* Please need your modification in this space. */
685 hdr->unix_mode = v_stat->st_mode;
688 hdr->unix_uid = v_stat->st_uid;
689 hdr->unix_gid = v_stat->st_gid;
691 if (is_directory(v_stat)) {
692 bcopy(LZHDIRS_METHOD, hdr->method, METHOD_TYPE_STRAGE);
693 hdr->attribute = GENERIC_DIRECTORY_ATTRIBUTE;
694 hdr->original_size = 0;
695 if (len > 0 && hdr->name[len - 1] != '/')
696 strcpy(&hdr->name[len++], "/");
700 if (is_symlink(v_stat)) {
703 bcopy(LZHDIRS_METHOD, hdr->method, METHOD_TYPE_STRAGE);
704 hdr->attribute = GENERIC_DIRECTORY_ATTRIBUTE;
705 hdr->original_size = 0;
706 len = readlink(name, lkname, 256);
707 lkname[len] = (char)'\0';
708 sprintf(hdr->name, "%s|%s", hdr->name, lkname);
712 unix_to_generic_filename(hdr->name, len);
715 /* ------------------------------------------------------------------------ */
716 /* Write unix extended header or generic header. */
718 write_header(nafp, hdr)
724 char data[LZHEADER_STRAGE];
728 bzero(data, LZHEADER_STRAGE);
729 bcopy(hdr->method, data + I_METHOD, METHOD_TYPE_STRAGE);
730 setup_put(data + I_PACKED_SIZE);
731 put_longword(hdr->packed_size);
732 put_longword(hdr->original_size);
734 if (hdr->header_level == HEADER_LEVEL2)
735 put_longword((long) hdr->unix_last_modified_stamp);
737 put_longword(hdr->last_modified_stamp);
739 switch (hdr->header_level) {
741 put_byte(hdr->attribute);
749 put_byte(hdr->header_level);
751 convdelim(hdr->name, DELIM2);
752 if (hdr->header_level != HEADER_LEVEL2) {
753 if (p = (char *) rindex(hdr->name, DELIM2))
754 name_length = strlen(++p);
756 name_length = strlen(hdr->name);
757 put_byte(name_length);
758 bcopy(p ? p : hdr->name, data + I_NAME, name_length);
759 setup_put(data + I_NAME + name_length);
763 if (header_level == HEADER_LEVEL0) {
764 if (generic_format) {
765 header_size = I_GENERIC_HEADER_BOTTOM - 2 + name_length;
766 data[I_HEADER_SIZE] = header_size;
767 data[I_HEADER_CHECKSUM] = calc_sum(data + I_METHOD, header_size);
769 /* write old-style extend header */
770 put_byte(EXTEND_UNIX);
771 put_byte(CURRENT_UNIX_MINOR_VERSION);
772 put_longword((long) hdr->unix_last_modified_stamp);
773 put_word(hdr->unix_mode);
774 put_word(hdr->unix_uid);
775 put_word(hdr->unix_gid);
776 header_size = I_UNIX_EXTEND_BOTTOM - 2 + name_length;
777 data[I_HEADER_SIZE] = header_size;
778 data[I_HEADER_CHECKSUM] = calc_sum(data + I_METHOD, header_size);
781 /* write extend header. */
787 put_byte(EXTEND_UNIX);
790 if (hdr->header_level == HEADER_LEVEL2) {
791 /* write common header */
794 headercrc_ptr = put_ptr;
798 if (generic_format) {
799 header_size = put_ptr - data; /* +2 for last 0x0000 */
802 if (hdr->header_level == HEADER_LEVEL1)
803 header_size = put_ptr - data - 2;
804 put_byte(0x50); /* permission */
805 put_word(hdr->unix_mode);
807 put_byte(0x51); /* gid and uid */
808 put_word(hdr->unix_gid);
809 put_word(hdr->unix_uid);
811 if (p = (char *) rindex(hdr->name, DELIM2)) {
814 name_length = p - hdr->name + 1;
815 put_word(name_length + 3);
816 put_byte(2); /* dirname */
817 for (i = 0; i < name_length; i++)
818 put_byte(hdr->name[i]);
820 } /* if generic .. */
822 if (header_level != HEADER_LEVEL2) {
823 if (!generic_format) {
825 put_byte(0x54); /* time stamp */
826 put_longword(hdr->unix_last_modified_stamp);
828 hdr->packed_size += put_ptr - ptr;
830 setup_put(data + I_PACKED_SIZE);
831 put_longword(hdr->packed_size);
833 data[I_HEADER_SIZE] = header_size;
834 data[I_HEADER_CHECKSUM] = calc_sum(data + I_METHOD, header_size);
835 } else { /* header level 2 */
837 if (p = (char *) rindex(hdr->name, DELIM2))
838 name_length = strlen(++p);
841 name_length = strlen(hdr->name);
843 put_word(name_length + 3);
844 put_byte(1); /* filename */
845 for (i = 0; i < name_length; i++)
847 } /* if he.. != HEAD_LV2 */
848 header_size = put_ptr - data;
851 if (header_level == HEADER_LEVEL2) {
853 setup_put(data + I_HEADER_SIZE);
854 put_word(header_size + 2);
856 hcrc = calc_header_crc(data, (unsigned int) header_size + 2);
857 setup_put(headercrc_ptr);
861 if (fwrite(data, sizeof(char), header_size + 2, nafp) == 0)
862 fatal_error("Cannot write to temporary file");
864 convdelim(hdr->name, DELIM);