1 /* ------------------------------------------------------------------------ */
2 /* LHa for UNIX */
3 /* header.c -- header manipulate functions */
4 /* */
5 /* Modified Nobutaka Watazaki */
6 /* */
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.14i bug fixed 2000.10.06 t.okamoto */
13 /* ------------------------------------------------------------------------ */
14 #include "lha.h"
15
16 /* ------------------------------------------------------------------------ */
17 static char *get_ptr;
18 /* ------------------------------------------------------------------------ */
19 int
calc_sum(p,len)20 calc_sum(p, len)
21 register char *p;
22 register int len;
23 {
24 register int sum;
25
26 for (sum = 0; len; len--)
27 sum += *p++;
28
29 return sum & 0xff;
30 }
31
32 /* ------------------------------------------------------------------------ */
33 static unsigned short
get_word()34 get_word()
35 {
36 int b0, b1;
37
38 b0 = get_byte();
39 b1 = get_byte();
40 return (b1 << 8) + b0;
41 }
42
43 /* ------------------------------------------------------------------------ */
44 static void
put_word(v)45 put_word(v)
46 unsigned int v;
47 {
48 put_byte(v);
49 put_byte(v >> 8);
50 }
51
52 /* ------------------------------------------------------------------------ */
53 static long
get_longword()54 get_longword()
55 {
56 long b0, b1, b2, b3;
57
58 b0 = get_byte();
59 b1 = get_byte();
60 b2 = get_byte();
61 b3 = get_byte();
62 return (b3 << 24) + (b2 << 16) + (b1 << 8) + b0;
63 }
64
65 /* ------------------------------------------------------------------------ */
66 static void
put_longword(v)67 put_longword(v)
68 long v;
69 {
70 put_byte(v);
71 put_byte(v >> 8);
72 put_byte(v >> 16);
73 put_byte(v >> 24);
74 }
75
76 /* ------------------------------------------------------------------------ */
77 static void
msdos_to_unix_filename(name,len)78 msdos_to_unix_filename(name, len)
79 register char *name;
80 register int len;
81 {
82 register int i;
83
84 #ifdef MULTIBYTE_CHAR
85 for (i = 0; i < len; i++) {
86 if (MULTIBYTE_FIRST_P(name[i]) &&
87 MULTIBYTE_SECOND_P(name[i + 1]))
88 i++;
89 else if (name[i] == '\\')
90 name[i] = '/';
91 else if (!noconvertcase && isupper(name[i]))
92 name[i] = tolower(name[i]);
93 }
94 #else
95 for (i = 0; i < len; i++) {
96 if (name[i] == '\\')
97 name[i] = '/';
98 else if (!noconvertcase && isupper(name[i]))
99 name[i] = tolower(name[i]);
100 }
101 #endif
102 }
103
104 /* ------------------------------------------------------------------------ */
105 static void
generic_to_unix_filename(name,len)106 generic_to_unix_filename(name, len)
107 register char *name;
108 register int len;
109 {
110 register int i;
111 boolean lower_case_used = FALSE;
112
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]))
117 i++;
118 else if (islower(name[i])) {
119 lower_case_used = TRUE;
120 break;
121 }
122 }
123 for (i = 0; i < len; i++) {
124 if (MULTIBYTE_FIRST_P(name[i]) &&
125 MULTIBYTE_SECOND_P(name[i + 1]))
126 i++;
127 else if (name[i] == '\\')
128 name[i] = '/';
129 else if (!noconvertcase && !lower_case_used && isupper(name[i]))
130 name[i] = tolower(name[i]);
131 }
132 #else
133 for (i = 0; i < len; i++)
134 if (islower(name[i])) {
135 lower_case_used = TRUE;
136 break;
137 }
138 for (i = 0; i < len; i++) {
139 if (name[i] == '\\')
140 name[i] = '/';
141 else if (!noconvertcase && !lower_case_used && isupper(name[i]))
142 name[i] = tolower(name[i]);
143 }
144 #endif
145 }
146
147 /* ------------------------------------------------------------------------ */
148 static void
macos_to_unix_filename(name,len)149 macos_to_unix_filename(name, len)
150 register char *name;
151 register int len;
152 {
153 register int i;
154
155 for (i = 0; i < len; i++) {
156 if (name[i] == ':')
157 name[i] = '/';
158 else if (name[i] == '/')
159 name[i] = ':';
160 }
161 }
162
163 /* ------------------------------------------------------------------------ */
164 static void
unix_to_generic_filename(name,len)165 unix_to_generic_filename(name, len)
166 register char *name;
167 register int len;
168 {
169 register int i;
170
171 for (i = 0; i < len; i++) {
172 if (name[i] == '/')
173 name[i] = '\\';
174 else if (islower(name[i]))
175 name[i] = toupper(name[i]);
176 }
177 }
178
179 /* ------------------------------------------------------------------------ */
180 /* */
181 /* Generic stamp format: */
182 /* */
183 /* 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 */
184 /* |<-------- year ------->|<- month ->|<-- day -->| */
185 /* */
186 /* 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 */
187 /* |<--- hour --->|<---- minute --->|<- second*2 ->| */
188 /* */
189 /* ------------------------------------------------------------------------ */
190
191 /*
192 * NOTE : If you don't have `gettimeofday(2)', or your gettimeofday(2)
193 * returns bogus timezone information, try FTIME, MKTIME, TIMELOCAL or TZSET.
194 */
195
196 /* choose one */
197 #if defined(MKTIME)
198 #ifdef TIMELOCAL
199 #undef TIMELOCAL
200 #endif
201 #endif /* defined(MKTIME) */
202
203 #if defined(MKTIME) || defined(TIMELOCAL)
204 #ifdef TZSET
205 #undef TZSET
206 #endif
207 #endif /* defined(MKTIME) || defined(TIMELOCAL) */
208
209 #if defined(MKTIME) || defined(TIMELOCAL) || defined(TZSET)
210 #ifdef FTIME
211 #undef FTIME
212 #endif
213 #endif
214
215 #if defined(MKTIME) || defined(TIMELOCAL) || defined(TZSET) || defined(FTIME)
216 #ifdef GETTIMEOFDAY
217 #undef GETTIMEOFDAY
218 #endif
219 #else
220 #ifndef GETTIMEOFDAY
221 #define GETTIMEOFDAY /* use gettimeofday() */
222 #endif
223 #endif
224
225 #ifdef FTIME
226 #include <sys/timeb.h>
227 #endif
228
229 /*
230 * You may define as : #define TIMEZONE_HOOK \ extern long
231 * timezone ; \ extern void tzset();
232 */
233 #ifdef TIMEZONE_HOOK
234 TIMEZONE_HOOK
235 /* Which do you like better, `TIMEZONE_HOOK' or `TIMEZONE_HOOK;' ? */
236 #endif
237
238 #if defined(TZSET) && defined(_MINIX)
239 extern long timezone; /* not defined in time.h */
240 #endif
241
242 /* ------------------------------------------------------------------------ */
243 #if defined(FTIME) || defined(GETTIMEOFDAY) || defined(TZSET)
244 static long
gettz()245 gettz()
246 #ifdef TZSET
247 {
248 tzset();
249 return timezone;
250 }
251 #endif
252
253 /* ------------------------------------------------------------------------ */
254 #if !defined(TZSET) && defined(FTIME)
255 {
256 struct timeb buf;
257
258 ftime(&buf);
259 return buf.timezone * 60L;
260 }
261 #endif
262
263 /* ------------------------------------------------------------------------ */
264 #if !defined(TZSET) && !defined(FTIME) /* maybe defined(GETTIMEOFDAY) */
265 {
266 #ifdef HAVE_TM_ZONE
267 time_t tt;
268
269 time(&tt);
270 return -localtime(&tt)->tm_gmtoff;
271 #else /* HAVE_TM_ZONE */
272 struct timeval tp;
273 struct timezone tzp;
274 gettimeofday(&tp, &tzp);/* specific to 4.3BSD */
275 /*
276 * return (tzp.tz_minuteswest * 60L + (tzp.tz_dsttime != 0 ? 60L *
277 * 60L : 0));
278 */
279 return (tzp.tz_minuteswest * 60L);
280 #endif /* HAVE_TM_ZONE */
281 }
282 #endif
283 #endif /* defined(FTIME) || defined(GETTIMEOFDAY) ||
284 * defined(TZSET) */
285
286 /* ------------------------------------------------------------------------ */
287 #ifdef NOT_USED
288 static struct tm *
msdos_to_unix_stamp_tm(a)289 msdos_to_unix_stamp_tm(a)
290 long a;
291 {
292 static struct tm t;
293
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;
300 return &t;
301 }
302 #endif
303
304 /* ------------------------------------------------------------------------ */
305 static time_t
generic_to_unix_stamp(t)306 generic_to_unix_stamp(t)
307 long t;
308 #if defined(MKTIME) || defined(TIMELOCAL)
309 {
310 struct tm dostm;
311
312 /*
313 * special case: if MSDOS format date and time were zero, then we
314 * set time to be zero here too.
315 */
316 if (t == 0)
317 return (time_t) 0;
318
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;
325 #if 0
326 dostm.tm_isdst = 0; /* correct? */
327 #endif
328 dostm.tm_isdst = -1; /* correct? */
329 #ifdef MKTIME
330 return (time_t) mktime(&dostm);
331 #else /* maybe defined(TIMELOCAL) */
332 return (time_t) timelocal(&dostm);
333 #endif
334 }
335
336 #else /* defined(MKTIME) || defined(TIMELOCAL) */
337 {
338 int year, month, day, hour, min, sec;
339 long longtime;
340 static unsigned int dsboy[12] = {0, 31, 59, 90, 120, 151,
341 181, 212, 243, 273, 304, 334};
342 unsigned int days;
343
344 /*
345 * special case: if MSDOS format date and time were zero, then we
346 * set time to be zero here too.
347 */
348 if (t == 0)
349 return (time_t) 0;
350
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 */
354
355 hour = ((int) t >> 11) & 0x1f;
356 min = ((int) t >> 5) & 0x3f;
357 sec = ((int) t & 0x1f) * 2;
358
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 */
364
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 */
369
370 /* Knowing the days, we can find seconds */
371 longtime = (((days * 24) + hour) * 60 + min) * 60 + sec;
372 longtime += gettz(); /* adjust for timezone */
373
374 /* LONGTIME is now the time in seconds, since 1970/01/01 00:00:00. */
375 return (time_t) longtime;
376 }
377 #endif /* defined(MKTIME) || defined(TIMELOCAL) */
378
379 /* ------------------------------------------------------------------------ */
380 static long
unix_to_generic_stamp(t)381 unix_to_generic_stamp(t)
382 time_t t;
383 {
384 struct tm *tm = localtime(&t);
385
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) +
390 (tm->tm_min << 5) +
391 (tm->tm_sec / 2)));
392 }
393
394 /* ------------------------------------------------------------------------ */
395 /* build header functions */
396 /* ------------------------------------------------------------------------ */
397 boolean
get_header(fp,hdr)398 get_header(fp, hdr)
399 FILE *fp;
400 register LzHeader *hdr;
401 {
402 int header_size;
403 int name_length;
404 char data[LZHEADER_STRAGE];
405 char dirname[FILENAME_LENGTH];
406 int dir_length = 0;
407 int checksum;
408 int i;
409 char *ptr;
410 int extend_size;
411 int dmy;
412
413 bzero(hdr, sizeof(LzHeader));
414
415 if (((header_size = getc(fp)) == EOF) || (header_size == 0)) {
416 return FALSE; /* finish */
417 }
418
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 */
423 }
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 */
430 }
431
432 if (hdr->header_level >= 3) {
433 fatal_error("Unknown level header");
434 return FALSE;
435 }
436
437 setup_get(data + I_HEADER_CHECKSUM);
438 checksum = get_byte();
439
440 if (hdr->header_level == 2) {
441 hdr->header_size = header_size + checksum*256;
442 } else {
443 hdr->header_size = header_size;
444 }
445 bcopy(data + I_METHOD, hdr->method, METHOD_TYPE_STRAGE);
446 setup_get(data + I_PACKED_SIZE);
447 hdr->packed_size = get_longword();
448 hdr->original_size = get_longword();
449 hdr->last_modified_stamp = get_longword();
450 hdr->attribute = get_byte();
451
452 if ((hdr->header_level = get_byte()) != 2) {
453 if (calc_sum(data + I_METHOD, header_size) != checksum)
454 warning("Checksum error (LHarc file?)", "");
455 name_length = get_byte();
456 for (i = 0; i < name_length; i++)
457 hdr->name[i] = (char) get_byte();
458 hdr->name[name_length] = '\0';
459 }
460 else {
461 hdr->unix_last_modified_stamp = hdr->last_modified_stamp;
462 name_length = 0;
463 }
464
465 /* defaults for other type */
466 hdr->unix_mode = UNIX_FILE_REGULAR | UNIX_RW_RW_RW;
467 hdr->unix_gid = 0;
468 hdr->unix_uid = 0;
469
470 if (hdr->header_level == 0) {
471 extend_size = header_size - name_length -22;
472 if (extend_size < 0) {
473 if (extend_size == -2) {
474 hdr->extend_type = EXTEND_GENERIC;
475 hdr->has_crc = FALSE;
476 } else {
477 fatal_error("Unkonwn header (lha file?)");
478 return FALSE;
479 }
480 } else {
481 hdr->has_crc = TRUE;
482 hdr->crc = get_word();
483 }
484
485 if (extend_size >= 1) {
486 hdr->extend_type = get_byte();
487 extend_size--;
488 }
489 if (hdr->extend_type == EXTEND_UNIX) {
490 if (extend_size >= 11) {
491 hdr->minor_version = get_byte();
492 hdr->unix_last_modified_stamp = (time_t) get_longword();
493 hdr->unix_mode = get_word();
494 hdr->unix_uid = get_word();
495 hdr->unix_gid = get_word();
496 extend_size -= 11;
497 } else {
498 hdr->extend_type = EXTEND_GENERIC;
499 }
500 }
501 while (extend_size-- > 0)
502 dmy = get_byte();
503 if (hdr->extend_type == EXTEND_UNIX)
504 return TRUE;
505 } else if (hdr->header_level == 1) {
506 hdr->has_crc = TRUE;
507 extend_size = header_size - name_length-25;
508 hdr->crc = get_word();
509 hdr->extend_type = get_byte();
510 while (extend_size-- > 0)
511 dmy = get_byte();
512 } else { /* level 2 */
513 hdr->has_crc = TRUE;
514 hdr->crc = get_word();
515 hdr->extend_type = get_byte();
516 }
517
518 if (hdr->header_level > 0) {
519 /* Extend Header */
520 if (hdr->header_level != 2)
521 setup_get(data + hdr->header_size);
522 ptr = get_ptr;
523 while ((header_size = get_word()) != 0) {
524 if (hdr->header_level != 2 &&
525 ((data + LZHEADER_STRAGE - get_ptr < header_size) ||
526 fread(get_ptr, sizeof(char), header_size, fp) < header_size)) {
527 fatal_error("Invalid header (LHa file ?)");
528 return FALSE;
529 }
530 switch (get_byte()) {
531 case 0:
532 /*
533 * header crc
534 */
535 setup_get(get_ptr + header_size - 3);
536 break;
537 case 1:
538 /*
539 * filename
540 */
541 if (header_size >= 256) {
542 fprintf(stderr, "Possible buffer overflow hack attack, type #1\n");
543 exit(109);
544 }
545 for (i = 0; i < header_size - 3; i++)
546 hdr->name[i] = (char) get_byte();
547 hdr->name[header_size - 3] = '\0';
548 name_length = header_size - 3;
549 break;
550 case 2:
551 /*
552 * directory
553 */
554 if (header_size >= FILENAME_LENGTH) {
555 fprintf(stderr, "Possible buffer overflow hack attack, type #2\n");
556 exit(110);
557 }
558 for (i = 0; i < header_size - 3; i++)
559 dirname[i] = (char) get_byte();
560 dirname[header_size - 3] = '\0';
561 convdelim(dirname, DELIM);
562 dir_length = header_size - 3;
563 break;
564 case 0x40:
565 /*
566 * MS-DOS attribute
567 */
568 if (hdr->extend_type == EXTEND_MSDOS ||
569 hdr->extend_type == EXTEND_HUMAN ||
570 hdr->extend_type == EXTEND_GENERIC)
571 hdr->attribute = get_word();
572 break;
573 case 0x50:
574 /*
575 * UNIX permission
576 */
577 if (hdr->extend_type == EXTEND_UNIX)
578 hdr->unix_mode = get_word();
579 break;
580 case 0x51:
581 /*
582 * UNIX gid and uid
583 */
584 if (hdr->extend_type == EXTEND_UNIX) {
585 hdr->unix_gid = get_word();
586 hdr->unix_uid = get_word();
587 }
588 break;
589 case 0x52:
590 /*
591 * UNIX group name
592 */
593 setup_get(get_ptr + header_size - 3);
594 break;
595 case 0x53:
596 /*
597 * UNIX user name
598 */
599 setup_get(get_ptr + header_size - 3);
600 break;
601 case 0x54:
602 /*
603 * UNIX last modified time
604 */
605 if (hdr->extend_type == EXTEND_UNIX)
606 hdr->unix_last_modified_stamp = (time_t) get_longword();
607 break;
608 default:
609 /*
610 * other headers
611 */
612 setup_get(get_ptr + header_size - 3);
613 break;
614 }
615 }
616 if (hdr->header_level != 2 && get_ptr - ptr != 2) {
617 hdr->packed_size -= get_ptr - ptr - 2;
618 hdr->header_size += get_ptr - ptr - 2;
619 }
620 }
621
622 switch (hdr->extend_type) {
623 case EXTEND_MSDOS:
624 msdos_to_unix_filename(hdr->name, name_length);
625 msdos_to_unix_filename(dirname, dir_length);
626 case EXTEND_HUMAN:
627 if (hdr->header_level == 2)
628 hdr->unix_last_modified_stamp = hdr->last_modified_stamp;
629 else
630 hdr->unix_last_modified_stamp =
631 generic_to_unix_stamp(hdr->last_modified_stamp);
632 break;
633
634 #ifdef OSK
635 case EXTEND_OS68K:
636 case EXTEND_XOSK:
637 #endif
638 case EXTEND_UNIX:
639 break;
640
641 case EXTEND_MACOS:
642 macos_to_unix_filename(hdr->name, name_length);
643 /* macos_to_unix_filename(dirname, dir_length); */
644 hdr->unix_last_modified_stamp =
645 generic_to_unix_stamp(hdr->last_modified_stamp);
646 break;
647
648 default:
649 generic_to_unix_filename(hdr->name, name_length);
650 generic_to_unix_filename(dirname, dir_length);
651 if (hdr->header_level == 2)
652 hdr->unix_last_modified_stamp = hdr->last_modified_stamp;
653 else
654 hdr->unix_last_modified_stamp =
655 generic_to_unix_stamp(hdr->last_modified_stamp);
656 }
657
658 if (dir_length) {
659 if ((dir_length + name_length) >= sizeof(dirname)) {
660 fprintf(stderr, "Insufficient buffer size\n");
661 exit(112);
662 }
663 strcat(dirname, hdr->name);
664 if ((dir_length + name_length) >= sizeof(hdr->name)) {
665 fprintf(stderr, "Insufficient buffer size\n");
666 exit(112);
667 }
668 strncpy(hdr->name, dirname, sizeof(hdr->name));
669 name_length += dir_length;
670 }
671
672 return TRUE;
673 }
674
675 /* ------------------------------------------------------------------------ */
676 void
init_header(name,v_stat,hdr)677 init_header(name, v_stat, hdr)
678 char *name;
679 struct stat *v_stat;
680 LzHeader *hdr;
681 {
682 int len;
683
684 if (compress_method == LZHUFF5_METHOD_NUM) /* Changed N.Watazaki */
685 bcopy(LZHUFF5_METHOD, hdr->method, METHOD_TYPE_STRAGE);
686 else if (compress_method)
687 bcopy(LZHUFF1_METHOD, hdr->method, METHOD_TYPE_STRAGE);
688 else
689 bcopy(LZHUFF0_METHOD, hdr->method, METHOD_TYPE_STRAGE);
690
691 hdr->packed_size = 0;
692 hdr->original_size = v_stat->st_size;
693 hdr->last_modified_stamp = unix_to_generic_stamp(v_stat->st_mtime);
694 hdr->attribute = GENERIC_ATTRIBUTE;
695 hdr->header_level = header_level;
696 strcpy(hdr->name, name);
697 len = strlen(name);
698 hdr->crc = 0x0000;
699 hdr->extend_type = EXTEND_UNIX;
700 hdr->unix_last_modified_stamp = v_stat->st_mtime;
701 /* since 00:00:00 JAN.1.1970 */
702 #ifdef NOT_COMPATIBLE_MODE
703 /* Please need your modification in this space. */
704 #else
705 hdr->unix_mode = v_stat->st_mode;
706 #endif
707
708 hdr->unix_uid = v_stat->st_uid;
709 hdr->unix_gid = v_stat->st_gid;
710
711 if (is_directory(v_stat)) {
712 bcopy(LZHDIRS_METHOD, hdr->method, METHOD_TYPE_STRAGE);
713 hdr->attribute = GENERIC_DIRECTORY_ATTRIBUTE;
714 hdr->original_size = 0;
715 if (len > 0 && hdr->name[len - 1] != '/')
716 strcpy(&hdr->name[len++], "/");
717 }
718
719 #ifdef S_IFLNK
720 if (is_symlink(v_stat)) {
721 char lkname[257];
722 int len;
723 bcopy(LZHDIRS_METHOD, hdr->method, METHOD_TYPE_STRAGE);
724 hdr->attribute = GENERIC_DIRECTORY_ATTRIBUTE;
725 hdr->original_size = 0;
726 len = readlink(name, lkname, 256);
727 lkname[len] = (char)'\0';
728 sprintf(hdr->name, "%s|%s", hdr->name, lkname);
729 }
730 #endif
731 if (generic_format)
732 unix_to_generic_filename(hdr->name, len);
733 }
734
735 /* ------------------------------------------------------------------------ */
736 /* Write unix extended header or generic header. */
737 void
write_header(nafp,hdr)738 write_header(nafp, hdr)
739 FILE *nafp;
740 LzHeader *hdr;
741 {
742 int header_size;
743 int name_length;
744 char data[LZHEADER_STRAGE];
745 char *p;
746 char *headercrc_ptr;
747
748 bzero(data, LZHEADER_STRAGE);
749 bcopy(hdr->method, data + I_METHOD, METHOD_TYPE_STRAGE);
750 setup_put(data + I_PACKED_SIZE);
751 put_longword(hdr->packed_size);
752 put_longword(hdr->original_size);
753
754 if (hdr->header_level == HEADER_LEVEL2)
755 put_longword((long) hdr->unix_last_modified_stamp);
756 else
757 put_longword(hdr->last_modified_stamp);
758
759 switch (hdr->header_level) {
760 case HEADER_LEVEL0:
761 put_byte(hdr->attribute);
762 break;
763 case HEADER_LEVEL1:
764 case HEADER_LEVEL2:
765 put_byte(0x20);
766 break;
767 }
768
769 put_byte(hdr->header_level);
770
771 convdelim(hdr->name, DELIM2);
772 if (hdr->header_level != HEADER_LEVEL2) {
773 if ((p = (char *) rindex(hdr->name, DELIM2)))
774 name_length = strlen(++p);
775 else
776 name_length = strlen(hdr->name);
777 put_byte(name_length);
778 bcopy(p ? p : hdr->name, data + I_NAME, name_length);
779 setup_put(data + I_NAME + name_length);
780 }
781
782 put_word(hdr->crc);
783 if (header_level == HEADER_LEVEL0) {
784 if (generic_format) {
785 header_size = I_GENERIC_HEADER_BOTTOM - 2 + name_length;
786 data[I_HEADER_SIZE] = header_size;
787 data[I_HEADER_CHECKSUM] = calc_sum(data + I_METHOD, header_size);
788 } else {
789 /* write old-style extend header */
790 put_byte(EXTEND_UNIX);
791 put_byte(CURRENT_UNIX_MINOR_VERSION);
792 put_longword((long) hdr->unix_last_modified_stamp);
793 put_word(hdr->unix_mode);
794 put_word(hdr->unix_uid);
795 put_word(hdr->unix_gid);
796 header_size = I_UNIX_EXTEND_BOTTOM - 2 + name_length;
797 data[I_HEADER_SIZE] = header_size;
798 data[I_HEADER_CHECKSUM] = calc_sum(data + I_METHOD, header_size);
799 }
800 } else {
801 /* write extend header. */
802 char *ptr;
803
804 if (generic_format)
805 put_byte(0x00);
806 else
807 put_byte(EXTEND_UNIX);
808
809 ptr = put_ptr;
810 if (hdr->header_level == HEADER_LEVEL2) {
811 /* write common header */
812 put_word(5);
813 put_byte(0x00);
814 headercrc_ptr = put_ptr;
815 put_word(0x0000);
816 }
817
818 if (generic_format) {
819 header_size = put_ptr - data; /* +2 for last 0x0000 */
820 } else {
821 put_word(5);
822 if (hdr->header_level == HEADER_LEVEL1)
823 header_size = put_ptr - data - 2;
824 put_byte(0x50); /* permission */
825 put_word(hdr->unix_mode);
826 put_word(7);
827 put_byte(0x51); /* gid and uid */
828 put_word(hdr->unix_gid);
829 put_word(hdr->unix_uid);
830
831 if ((p = (char *) rindex(hdr->name, DELIM2))) {
832 int i;
833
834 name_length = p - hdr->name + 1;
835 put_word(name_length + 3);
836 put_byte(2); /* dirname */
837 for (i = 0; i < name_length; i++)
838 put_byte(hdr->name[i]);
839 }
840 } /* if generic .. */
841
842 if (header_level != HEADER_LEVEL2) {
843 if (!generic_format) {
844 put_word(7);
845 put_byte(0x54); /* time stamp */
846 put_longword(hdr->unix_last_modified_stamp);
847 }
848 hdr->packed_size += put_ptr - ptr;
849 ptr = put_ptr;
850 setup_put(data + I_PACKED_SIZE);
851 put_longword(hdr->packed_size);
852 put_ptr = ptr;
853 data[I_HEADER_SIZE] = header_size;
854 data[I_HEADER_CHECKSUM] = calc_sum(data + I_METHOD, header_size);
855 } else { /* header level 2 */
856 int i;
857 if ((p = (char *) rindex(hdr->name, DELIM2)))
858 name_length = strlen(++p);
859 else {
860 p = hdr->name;
861 name_length = strlen(hdr->name);
862 }
863 put_word(name_length + 3);
864 put_byte(1); /* filename */
865 for (i = 0; i < name_length; i++)
866 put_byte(*p++);
867 } /* if he.. != HEAD_LV2 */
868 header_size = put_ptr - data;
869 }
870
871 if (header_level == HEADER_LEVEL2) {
872 unsigned short hcrc;
873 setup_put(data + I_HEADER_SIZE);
874 put_word(header_size + 2);
875 /* common header */
876 hcrc = calc_header_crc(data, (unsigned int) header_size + 2);
877 setup_put(headercrc_ptr);
878 put_word(hcrc);
879 }
880
881 if (fwrite(data, sizeof(char), header_size + 2, nafp) == 0)
882 fatal_error("Cannot write to temporary file");
883
884 convdelim(hdr->name, DELIM);
885 }
886
887 /* Local Variables: */
888 /* mode:c */
889 /* tab-width:4 */
890 /* compile-command:"gcc -c header.c" */
891 /* End: */
892