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