OSDN Git Service

Initial revision
[lha/lha.git] / src / header.c
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.14e bug fixed                                                1999.05.27  T.Okamoto       */
13 /* ------------------------------------------------------------------------ */
14 #include "lha.h"
15
16 /* ------------------------------------------------------------------------ */
17 static char    *get_ptr;
18 /* ------------------------------------------------------------------------ */
19 int
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
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
45 put_word(v)
46         unsigned int    v;
47 {
48         put_byte(v);
49         put_byte(v >> 8);
50 }
51
52 /* ------------------------------------------------------------------------ */
53 static long
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
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
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 (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 (isupper(name[i]))
99                         name[i] = tolower(name[i]);
100         }
101 #endif
102 }
103
104 /* ------------------------------------------------------------------------ */
105 static void
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 (!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 (!lower_case_used && isupper(name[i]))
142                         name[i] = tolower(name[i]);
143         }
144 #endif
145 }
146
147 /* ------------------------------------------------------------------------ */
148 static void
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
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
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 *
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
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
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
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         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();
447
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';
455         }
456         else {
457                 hdr->unix_last_modified_stamp = hdr->last_modified_stamp;
458                 name_length = 0;
459         }
460
461         /* defaults for other type */
462         hdr->unix_mode = UNIX_FILE_REGULAR | UNIX_RW_RW_RW;
463         hdr->unix_gid = 0;
464         hdr->unix_uid = 0;
465
466
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;
473                         } else {
474                                 fatal_error("Unkonwn header (lha file?)");
475                                 return FALSE;
476                         }
477                 } else {
478                         hdr->has_crc = TRUE;
479                         hdr->crc = get_word();
480                 }
481
482                 if (extend_size >= 1) {
483                         hdr->extend_type = get_byte();
484                         extend_size--;
485                 }
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();
493                                 extend_size -= 11;
494                         } else {
495                                 hdr->extend_type = EXTEND_GENERIC;
496                         }
497                 }
498                 while (extend_size-- > 0)
499                         dmy = get_byte();
500                 if (hdr->extend_type == EXTEND_UNIX)
501                         return TRUE;
502         } else if (hdr->header_level == 1) {
503                 hdr->has_crc = TRUE;
504                 extend_size = header_size - name_length-25;
505                 hdr->crc = get_word();
506                 hdr->extend_type = get_byte();
507                 while (extend_size-- > 0)
508                         dmy = get_byte();
509         } else { /* level 2 */
510                 hdr->has_crc = TRUE;
511                 hdr->crc = get_word();
512                 hdr->extend_type = get_byte();
513         }               
514
515         if (hdr->header_level > 0) {
516                 /* Extend Header */
517                 if (hdr->header_level != 2)
518                         setup_get(data + hdr->header_size);
519                 ptr = get_ptr;
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 ?)");
525                                 return FALSE;
526                         }
527                         switch (get_byte()) {
528                         case 0:
529                                 /*
530                                  * header crc
531                                  */
532                                 setup_get(get_ptr + header_size - 3);
533                                 break;
534                         case 1:
535                                 /*
536                                  * filename
537                                  */
538                                 for (i = 0; i < header_size - 3; i++)
539                                         hdr->name[i] = (char) get_byte();
540                                 hdr->name[header_size - 3] = '\0';
541                                 break;
542                         case 2:
543                                 /*
544                                  * directory
545                                  */
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;
551                                 break;
552                         case 0x40:
553                                 /*
554                                  * MS-DOS attribute
555                                  */
556                                 if (hdr->extend_type == EXTEND_MSDOS ||
557                                     hdr->extend_type == EXTEND_HUMAN ||
558                                     hdr->extend_type == EXTEND_GENERIC)
559                                         hdr->attribute = get_word();
560                                 break;
561                         case 0x50:
562                                 /*
563                                  * UNIX permission
564                                  */
565                                 if (hdr->extend_type == EXTEND_UNIX)
566                                         hdr->unix_mode = get_word();
567                                 break;
568                         case 0x51:
569                                 /*
570                                  * UNIX gid and uid
571                                  */
572                                 if (hdr->extend_type == EXTEND_UNIX) {
573                                         hdr->unix_gid = get_word();
574                                         hdr->unix_uid = get_word();
575                                 }
576                                 break;
577                         case 0x52:
578                                 /*
579                                  * UNIX group name
580                                  */
581                                 setup_get(get_ptr + header_size - 3);
582                                 break;
583                         case 0x53:
584                                 /*
585                                  * UNIX user name
586                                  */
587                                 setup_get(get_ptr + header_size - 3);
588                                 break;
589                         case 0x54:
590                                 /*
591                                  * UNIX last modified time
592                                  */
593                                 if (hdr->extend_type == EXTEND_UNIX)
594                                         hdr->unix_last_modified_stamp = (time_t) get_longword();
595                                 break;
596                         default:
597                                 /*
598                                  * other headers
599                                  */
600                                 setup_get(get_ptr + header_size - 3);
601                                 break;
602                         }
603                 }
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;
607                 }
608         }
609         if (dir_length) {
610                 strcat(dirname, hdr->name);
611                 strcpy(hdr->name, dirname);
612                 name_length += dir_length;
613         }
614
615         switch (hdr->extend_type) {
616         case EXTEND_MSDOS:
617                 msdos_to_unix_filename(hdr->name, name_length);
618         case EXTEND_HUMAN:
619                 if (hdr->header_level == 2)
620                         hdr->unix_last_modified_stamp = hdr->last_modified_stamp;
621                 else
622                         hdr->unix_last_modified_stamp =
623                                 generic_to_unix_stamp(hdr->last_modified_stamp);
624                 break;
625
626 #ifdef OSK
627         case EXTEND_OS68K:
628         case EXTEND_XOSK:
629 #endif
630         case EXTEND_UNIX:
631                 break;
632
633         case EXTEND_MACOS:
634                 macos_to_unix_filename(hdr->name, name_length);
635                 hdr->unix_last_modified_stamp =
636                         generic_to_unix_stamp(hdr->last_modified_stamp);
637                 break;
638
639         default:
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;
643                 else
644                         hdr->unix_last_modified_stamp =
645                                 generic_to_unix_stamp(hdr->last_modified_stamp);
646         }
647
648 #if 0
649         printf("header level=%d\n", hdr->header_level); fflush(stdout);
650 #endif
651
652         return TRUE;
653 }
654
655 /* ------------------------------------------------------------------------ */
656 void
657 init_header(name, v_stat, hdr)
658         char           *name;
659         struct stat    *v_stat;
660         LzHeader       *hdr;
661 {
662         int             len;
663
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);
668         else
669                 bcopy(LZHUFF0_METHOD, hdr->method, METHOD_TYPE_STRAGE);
670
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);
677         len = strlen(name);
678         hdr->crc = 0x0000;
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. */
684 #else
685         hdr->unix_mode = v_stat->st_mode;
686 #endif
687
688         hdr->unix_uid = v_stat->st_uid;
689         hdr->unix_gid = v_stat->st_gid;
690
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++], "/");
697         }
698
699 #ifdef S_IFLNK  
700         if (is_symlink(v_stat)) {
701                 char    lkname[257];
702                 int             len;    
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);
709         }
710 #endif
711         if (generic_format)
712                 unix_to_generic_filename(hdr->name, len);
713 }
714
715 /* ------------------------------------------------------------------------ */
716 /* Write unix extended header or generic header. */
717 void
718 write_header(nafp, hdr)
719         FILE           *nafp;
720         LzHeader       *hdr;
721 {
722         int             header_size;
723         int             name_length;
724         char            data[LZHEADER_STRAGE];
725         char           *p;
726         char           *headercrc_ptr;
727
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);
733
734         if (hdr->header_level == HEADER_LEVEL2)
735                 put_longword((long) hdr->unix_last_modified_stamp);
736         else
737                 put_longword(hdr->last_modified_stamp);
738
739         switch (hdr->header_level) {
740         case HEADER_LEVEL0:
741                 put_byte(hdr->attribute);
742                 break;
743         case HEADER_LEVEL1:
744         case HEADER_LEVEL2:
745                 put_byte(0x20);
746                 break;
747         }
748
749         put_byte(hdr->header_level);
750
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);
755                 else
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);
760         }
761
762         put_word(hdr->crc);
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);
768                 } else {
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);
779                 }
780         } else {
781                 /* write extend header. */
782                 char           *ptr;
783
784                 if (generic_format)
785                         put_byte(0x00);
786                 else
787                         put_byte(EXTEND_UNIX);
788
789                 ptr = put_ptr;
790                 if (hdr->header_level == HEADER_LEVEL2) {
791                         /* write common header */
792                         put_word(5);
793                         put_byte(0x00);
794                         headercrc_ptr = put_ptr;
795                         put_word(0x0000);
796                 }
797
798                 if (generic_format) {
799                         header_size = put_ptr - data;   /* +2 for last 0x0000 */
800                 } else {
801                         put_word(5);
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);
806                         put_word(7);
807                         put_byte(0x51); /* gid and uid */
808                         put_word(hdr->unix_gid);
809                         put_word(hdr->unix_uid);
810
811                         if (p = (char *) rindex(hdr->name, DELIM2)) {
812                                 int             i;
813
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]);
819                         }
820                 }               /* if generic .. */
821
822                 if (header_level != HEADER_LEVEL2) {
823                         if (!generic_format) {
824                                 put_word(7);
825                                 put_byte(0x54); /* time stamp */
826                                 put_longword(hdr->unix_last_modified_stamp);
827                         }
828                         hdr->packed_size += put_ptr - ptr;
829                         ptr = put_ptr;
830                         setup_put(data + I_PACKED_SIZE);
831                         put_longword(hdr->packed_size);
832                         put_ptr = ptr;
833                         data[I_HEADER_SIZE] = header_size;
834                         data[I_HEADER_CHECKSUM] = calc_sum(data + I_METHOD, header_size);
835                 } else {                /* header level 2 */
836                         int             i;
837                         if (p = (char *) rindex(hdr->name, DELIM2))
838                                 name_length = strlen(++p);
839                         else {
840                                 p = hdr->name;
841                                 name_length = strlen(hdr->name);
842                         }
843                         put_word(name_length + 3);
844                         put_byte(1);    /* filename */
845                         for (i = 0; i < name_length; i++)
846                                 put_byte(*p++);
847                 }               /* if he.. != HEAD_LV2 */
848                 header_size = put_ptr - data;
849         }
850
851         if (header_level == HEADER_LEVEL2) {
852                 unsigned short  hcrc;
853                 setup_put(data + I_HEADER_SIZE);
854                 put_word(header_size + 2);
855                 /* common header */
856                 hcrc = calc_header_crc(data, (unsigned int) header_size + 2);
857                 setup_put(headercrc_ptr);
858                 put_word(hcrc);
859         }
860
861         if (fwrite(data, sizeof(char), header_size + 2, nafp) == 0)
862                 fatal_error("Cannot write to temporary file");
863
864         convdelim(hdr->name, DELIM);
865 }