home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 9 Archive / 09-Archive.zip / lha100bt.zip / lha-1.00 / src / header.c < prev    next >
C/C++ Source or Header  |  1992-04-04  |  19KB  |  795 lines

  1. /*----------------------------------------------------------------------*/
  2. /*    header.c (from lharc.c)    -- header manipulate functions        */
  3. /*    Original                    by Y.Tagawa    */
  4. /*    modified  Dec 16 1991                by M.Oki    */
  5. /*----------------------------------------------------------------------*/
  6.  
  7. #include "lharc.h"
  8. extern int header_level;
  9.  
  10. int
  11. calc_sum (p, len)
  12.      register char *p;
  13.      register int len;
  14. {
  15.   register int sum;
  16.  
  17.   for (sum = 0; len; len --)
  18.     sum += *p++;
  19.  
  20.   return sum & 0xff;
  21. }
  22.  
  23. static char *get_ptr;
  24. #define setup_get(PTR)        (get_ptr = (PTR))
  25. #define get_byte()        (*get_ptr++ & 0xff)
  26. #define put_ptr            get_ptr
  27. #define setup_put(PTR)        (put_ptr = (PTR))
  28. #define put_byte(c)        (*put_ptr++ = (char)(c))
  29.  
  30. static unsigned short
  31. get_word ()
  32. {
  33.   int b0, b1;
  34.  
  35.   b0 = get_byte ();
  36.   b1 = get_byte ();
  37.   return (b1 << 8) + b0;
  38. }
  39.  
  40. static void
  41. put_word (v)
  42.      unsigned int v;
  43. {
  44.   put_byte (v);
  45.   put_byte (v >> 8);
  46. }
  47.  
  48. static long
  49. get_longword ()
  50. {
  51.   long b0, b1, b2, b3;
  52.  
  53.   b0 = get_byte ();
  54.   b1 = get_byte ();
  55.   b2 = get_byte ();
  56.   b3 = get_byte ();
  57.   return (b3 << 24) + (b2 << 16) + (b1 << 8) + b0;
  58. }
  59.  
  60. static void
  61. put_longword (v)
  62.      long v;
  63. {
  64.   put_byte (v);
  65.   put_byte (v >> 8);
  66.   put_byte (v >> 16);
  67.   put_byte (v >> 24);
  68. }
  69.  
  70.  
  71. static void
  72. msdos_to_unix_filename (name, len)
  73.      register char *name;
  74.      register int len;
  75. {
  76.   register int i;
  77.  
  78. #ifdef MULTIBYTE_CHAR
  79.   for (i = 0; i < len; i ++)
  80.     {
  81.       if (MULTIBYTE_FIRST_P (name[i]) &&
  82.       MULTIBYTE_SECOND_P (name[i+1]))
  83.     i ++;
  84.       else if (name[i] == '\\')
  85.     name[i] = '/';
  86.       else if (isupper (name[i]))
  87.     name[i] = tolower (name[i]);
  88.     }
  89. #else
  90.   for (i = 0; i < len; i ++)
  91.     {
  92.       if (name[i] == '\\')
  93.     name[i] = '/';
  94.       else if (isupper (name[i]))
  95.     name[i] = tolower (name[i]);
  96.     }
  97. #endif
  98. }
  99.  
  100. static void
  101. generic_to_unix_filename (name, len)
  102.      register char *name;
  103.      register int len;
  104. {
  105.   register int i;
  106.   boolean lower_case_used = FALSE;
  107.  
  108. #ifdef MULTIBYTE_CHAR
  109.   for (i = 0; i < len; i ++)
  110.     {
  111.       if (MULTIBYTE_FIRST_P (name[i]) &&
  112.           MULTIBYTE_SECOND_P (name[i+1]))
  113.         i ++;
  114.       else if (islower (name[i]))
  115.         {
  116.           lower_case_used = TRUE;
  117.           break;
  118.         }
  119.     }
  120.   for (i = 0; i < len; i ++)
  121.     {
  122.       if (MULTIBYTE_FIRST_P (name[i]) &&
  123.           MULTIBYTE_SECOND_P (name[i+1]))
  124.         i ++;
  125.       else if (name[i] == '\\')
  126.         name[i] = '/';
  127.       else if (!lower_case_used && isupper (name[i]))
  128.         name[i] = tolower (name[i]);
  129.     }
  130. #else
  131.   for (i = 0; i < len; i ++)
  132.     if (islower (name[i]))
  133.       {
  134.         lower_case_used = TRUE;
  135.         break;
  136.       }
  137.   for (i = 0; i < len; i ++)
  138.     {
  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. static void
  148. macos_to_unix_filename (name, len)
  149.      register char *name;
  150.      register int len;
  151. {
  152.   register int i;
  153.  
  154.   for (i = 0; i < len; i ++)
  155.     {
  156.       if (name[i] == ':')
  157.     name[i] = '/';
  158.       else if (name[i] == '/')
  159.     name[i] = ':';
  160.     }
  161. }
  162.  
  163. static void
  164. unix_to_generic_filename (name, len)
  165.      register char *name;
  166.      register int len;
  167. {
  168.   register int i;
  169.  
  170.   for (i = 0; i < len; i ++)
  171.     {
  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. /* NOTE : If you don't have `gettimeofday(2)', or your gettimeofday(2)
  192.    returns bogus timezone information, try FTIME, MKTIME, TIMELOCAL or
  193.    TZSET. */
  194.  
  195. /* choose one */
  196. #if defined(MKTIME)
  197. #ifdef TIMELOCAL
  198. #undef TIMELOCAL
  199. #endif
  200. #endif /* defined(MKTIME) */
  201.  
  202. #if defined(MKTIME) || defined(TIMELOCAL)
  203. #ifdef TZSET
  204. #undef TZSET
  205. #endif
  206. #endif /* defined(MKTIME) || defined(TIMELOCAL) */
  207.  
  208. #if defined(MKTIME) || defined(TIMELOCAL) || defined(TZSET)
  209. #ifdef FTIME
  210. #undef FTIME
  211. #endif
  212. #endif
  213.  
  214. #if defined(MKTIME) || defined(TIMELOCAL) || defined(TZSET) || defined(FTIME)
  215. #ifdef GETTIMEOFDAY
  216. #undef GETTIMEOFDAY
  217. #endif
  218. #else
  219. #ifndef GETTIMEOFDAY
  220. #define GETTIMEOFDAY    /* use gettimeofday() */
  221. #endif
  222. #endif
  223.  
  224. #ifdef FTIME
  225. #include <sys/timeb.h>
  226. #endif
  227.  
  228. /* You may define as : 
  229.     #define TIMEZONE_HOOK        \
  230.         extern long timezone ;    \
  231.         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. #if defined(FTIME) || defined(GETTIMEOFDAY) || defined(TZSET)
  243. static long
  244. gettz ()
  245. #ifdef TZSET
  246. {
  247.    tzset();
  248.    return timezone;
  249. }
  250. #endif
  251. #if !defined(TZSET) && defined(FTIME)
  252. {
  253.    struct timeb buf;
  254.  
  255.    ftime(&buf);
  256.    return buf.timezone * 60L;
  257. }
  258. #endif
  259. #if !defined(TZSET) && !defined(FTIME) /* maybe defined(GETTIMEOFDAY) */
  260. {
  261.    struct timeval tp;
  262.    struct timezone tzp;
  263.    gettimeofday (&tp, &tzp);    /* specific to 4.3BSD */
  264. /* return (tzp.tz_minuteswest * 60L + (tzp.tz_dsttime != 0 ? 60L * 60L : 0));*/
  265.    return (tzp.tz_minuteswest * 60L);
  266. }
  267. #endif
  268. #endif /* defined(FTIME) || defined(GETTIMEOFDAY) || defined(TZSET) */
  269.  
  270. #ifdef NOT_USED
  271. static struct tm *
  272. msdos_to_unix_stamp_tm (a)
  273.      long a;
  274. {
  275.   static struct tm t;
  276.  
  277.   t.tm_sec    = ( a          & 0x1f) * 2;
  278.   t.tm_min    =  (a >>    5) & 0x3f;
  279.   t.tm_hour    =  (a >>   11) & 0x1f;
  280.   t.tm_mday    =  (a >>   16) & 0x1f;
  281.   t.tm_mon    = ((a >> 16+5) & 0x0f) - 1;
  282.   t.tm_year    = ((a >> 16+9) & 0x7f) + 80;
  283.   return &t;
  284. }
  285. #endif
  286.  
  287. static time_t
  288. generic_to_unix_stamp (t)
  289.      long t;
  290. #if defined(MKTIME) || defined(TIMELOCAL)
  291. {
  292.   struct tm dostm;
  293.  
  294.   /* special case:  if MSDOS format date and time were zero, then we set
  295.      time to be zero here too. */
  296.   if (t == 0)
  297.     return (time_t)0;
  298.  
  299.   dostm.tm_sec     = (t         & 0x1f) * 2;
  300.   dostm.tm_min     =  t >> 5    & 0x3f;
  301.   dostm.tm_hour     =  t >> 11   & 0x1f;
  302.   dostm.tm_mday     =  t >> 16   & 0x1f;
  303.   dostm.tm_mon     = (t >> 16+5 & 0x0f) - 1;    /* 0..11 */
  304.   dostm.tm_year     = (t >> 16+9 & 0x7f) + 80;
  305.   dostm.tm_isdst = 0;                /* correct? */
  306. #ifdef MKTIME
  307.   return (time_t)mktime(&dostm);
  308. #else /* maybe defined(TIMELOCAL) */
  309.   return (time_t)timelocal(&dostm);
  310. #endif
  311. }
  312. #else /* defined(MKTIME) || defined(TIMELOCAL) */
  313. {
  314.   int year, month, day, hour, min, sec;
  315.   long longtime;
  316.   static unsigned int dsboy[12] = { 0, 31, 59, 90, 120, 151,
  317.                       181, 212, 243, 273, 304, 334};
  318.   unsigned int days;
  319.  
  320.   /* special case:  if MSDOS format date and time were zero, then we set
  321.      time to be zero here too. */
  322.   if (t == 0)
  323.     return (time_t)0;
  324.  
  325.   year  = ((int)(t >> 16+9) & 0x7f) + 1980;
  326.   month =  (int)(t >> 16+5) & 0x0f;    /* 1..12 means Jan..Dec */
  327.   day   =  (int)(t >> 16)   & 0x1f;    /* 1..31 means 1st,...31st */
  328.  
  329.   hour  =  ((int)t >> 11) & 0x1f;
  330.   min   =  ((int)t >> 5)  & 0x3f;
  331.   sec   = ((int)t         & 0x1f) * 2;
  332.  
  333.                 /* Calculate days since 1970.01.01 */
  334.   days = (365 * (year - 1970) + /* days due to whole years */
  335.       (year - 1970 + 1) / 4 + /* days due to leap years */
  336.       dsboy[month-1] +    /* days since beginning of this year */
  337.       day-1);        /* days since beginning of month */
  338.  
  339.   if ((year % 4 == 0) &&
  340.       (year % 400 != 0) &&
  341.       (month >= 3))        /* if this is a leap year and month */
  342.     days ++;            /* is March or later, add a day */
  343.  
  344.   /* Knowing the days, we can find seconds */
  345.   longtime = (((days * 24) + hour) * 60 + min) * 60 + sec;
  346.   longtime += gettz ();      /* adjust for timezone */
  347.  
  348.   /* LONGTIME is now the time in seconds, since 1970/01/01 00:00:00.  */
  349.   return (time_t)longtime;
  350. }
  351. #endif /* defined(MKTIME) || defined(TIMELOCAL) */
  352.  
  353. static long
  354. unix_to_generic_stamp (t)
  355.      time_t t;
  356. {
  357.   struct tm *tm = localtime (&t);
  358.  
  359.   return ((((long)(tm->tm_year - 80)) << 25) +
  360.       (((long)(tm->tm_mon + 1)) << 21) +
  361.       (((long)tm->tm_mday) << 16) +
  362.       (long)((tm->tm_hour << 11) +
  363.          (tm->tm_min << 5) +
  364.          (tm->tm_sec / 2)));
  365. }
  366.  
  367. /*----------------------------------------------------------------------*/
  368. /*            build header functions                */
  369. /*----------------------------------------------------------------------*/
  370.  
  371. boolean
  372. get_header (fp, hdr)
  373.      FILE *fp;
  374.      register LzHeader *hdr;
  375. {
  376.   int header_size;
  377.   int name_length;
  378.   char data[LZHEADER_STRAGE];
  379.   char dirname[FILENAME_LENGTH];
  380.   int dir_length = 0;
  381.   int checksum;
  382.   int i;
  383.   char *ptr;
  384.  
  385.   bzero (hdr, sizeof (LzHeader));
  386.  
  387.   if (((header_size = getc (fp)) == EOF) || (header_size == 0))
  388.     {
  389.       return FALSE;        /* finish */
  390.     }
  391.  
  392.   if (fread (data + I_HEADER_CHECKSUM,
  393.           sizeof (char), header_size - 1, fp) < header_size - 1)
  394.     {
  395.       fatal_error ("Invalid header (LHarc file ?)");
  396.       return FALSE;        /* finish */
  397.     }
  398.   setup_get(data + I_HEADER_LEVEL);
  399.   hdr->header_level = get_byte();
  400.   if (hdr->header_level != 2 &&
  401.       fread (data + header_size, sizeof (char), 2, fp) < 2)
  402.     {
  403.       fatal_error ("Invalid header (LHarc file ?)");
  404.       return FALSE;        /* finish */
  405.     }
  406.  
  407.   setup_get (data + I_HEADER_CHECKSUM);
  408.   checksum = get_byte();
  409.  
  410.   hdr->header_size = header_size;
  411.   bcopy (data + I_METHOD, hdr->method, METHOD_TYPE_STRAGE);
  412. #ifdef OLD
  413.   if ((bcmp (hdr->method, LZHUFF1_METHOD, METHOD_TYPE_STRAGE) != 0) &&
  414.       (bcmp (hdr->method, LZHUFF0_METHOD, METHOD_TYPE_STRAGE) != 0) &&
  415.       (bcmp (hdr->method, LARC5_METHOD, METHOD_TYPE_STRAGE) != 0) &&
  416.       (bcmp (hdr->method, LARC4_METHOD, METHOD_TYPE_STRAGE) != 0))
  417.     {
  418.       warning ("Unknown method (LHarc file ?)", "");
  419.       return FALSE;        /* invalid method */
  420.     }
  421. #endif
  422.   setup_get (data + I_PACKED_SIZE);
  423.   hdr->packed_size    = get_longword ();
  424.   hdr->original_size    = get_longword ();
  425.   hdr->last_modified_stamp = get_longword ();
  426.   hdr->attribute    = get_byte ();
  427.  
  428.   if ((hdr->header_level = get_byte ()) != 2) {
  429.     if (calc_sum (data + I_METHOD, header_size) != checksum)
  430.       warning ("Checksum error (LHarc file?)", "");
  431.     name_length    = get_byte ();
  432.     for (i = 0; i < name_length; i ++)
  433.       hdr->name[i] =(char)get_byte ();
  434.     hdr->name[name_length] = '\0';
  435.   } else {
  436.     hdr->unix_last_modified_stamp = hdr->last_modified_stamp;
  437.     name_length = 0;
  438.   }
  439.  
  440.   /* defaults for other type */
  441.   hdr->unix_mode    = UNIX_FILE_REGULAR | UNIX_RW_RW_RW;
  442.   hdr->unix_gid     = 0;
  443.   hdr->unix_uid        = 0;
  444.  
  445.   if (header_size - name_length >= 24)
  446.     {                /* EXTEND FORMAT */
  447.       hdr->crc                = get_word ();
  448.       hdr->extend_type            = get_byte ();
  449.       hdr->has_crc = TRUE;
  450.     }
  451.   else if (header_size - name_length == 22)
  452.     {                /* Generic with CRC */
  453.       hdr->crc                = get_word ();
  454.       hdr->extend_type            = EXTEND_GENERIC;
  455.       hdr->has_crc = TRUE;
  456.     }
  457.   else if (header_size - name_length == 20)
  458.     {                /* Generic no CRC */
  459.       hdr->extend_type            = EXTEND_GENERIC;
  460.       hdr->has_crc = FALSE;
  461.     }
  462.   else
  463.     {
  464.       warning ("Unknown header (LHarc file ?)", "");
  465.       return FALSE;
  466.     }
  467.  
  468.   if (hdr->extend_type == EXTEND_UNIX && hdr->header_level == 0)
  469.     {
  470.       hdr->minor_version        = get_byte ();
  471.       hdr->unix_last_modified_stamp    = (time_t)get_longword ();
  472.       hdr->unix_mode            = get_word ();
  473.       hdr->unix_uid            = get_word ();
  474.       hdr->unix_gid            = get_word ();
  475.       return TRUE;
  476.     }
  477.  
  478.   if (hdr->header_level > 0) {
  479.     /* Extend Header */
  480.     if (hdr->header_level != 2) setup_get(data + hdr->header_size);
  481.     ptr = get_ptr;
  482.     while((header_size = get_word()) != 0)
  483.       {
  484.     if (hdr->header_level != 2 &&
  485.         ((data + LZHEADER_STRAGE - get_ptr < header_size) ||
  486.          fread(get_ptr, sizeof(char), header_size, fp) < header_size))
  487.       {
  488.         fatal_error ("Invalid header (LHa file ?)");
  489.         return FALSE;
  490.       }
  491.     switch (get_byte()) {
  492.     case 0:
  493.       /*
  494.        * header crc
  495.        */
  496.       setup_get(get_ptr + header_size - 3);
  497.       break;
  498.     case 1:
  499.       /*
  500.        * filename
  501.        */
  502.       for (i = 0; i < header_size - 3; i++)
  503.         hdr->name[i] =(char)get_byte ();
  504.       hdr->name[header_size - 3] = '\0';
  505.       break;
  506.     case 2:
  507.       /*
  508.        * directory
  509.        */
  510.       for (i = 0; i < header_size - 3; i++)
  511.         dirname[i] = (char)get_byte ();
  512.       dirname[header_size - 3] = '\0';
  513.       convdelim(dirname, DELIM);
  514.       dir_length = header_size-3;
  515.       break;
  516.     case 0x40:
  517.       /*
  518.        * MS-DOS attribute
  519.        */
  520.       if (hdr->extend_type == EXTEND_MSDOS ||
  521.           hdr->extend_type == EXTEND_HUMAN ||
  522.           hdr->extend_type == EXTEND_GENERIC)
  523.         hdr->attribute = get_word();
  524.       break;
  525.     case 0x50:
  526.       /*
  527.        * UNIX permission
  528.        */
  529.       if (hdr->extend_type == EXTEND_UNIX)
  530.         hdr->unix_mode = get_word();
  531.       break;
  532.     case 0x51:
  533.       /*
  534.        * UNIX gid and uid
  535.        */
  536.       if (hdr->extend_type == EXTEND_UNIX)
  537.         {
  538.           hdr->unix_gid = get_word();
  539.           hdr->unix_uid = get_word();
  540.         }
  541.       break;
  542.     case 0x52:
  543.       /*
  544.        * UNIX group name
  545.        */
  546.       setup_get(get_ptr + header_size - 3);
  547.       break;
  548.     case 0x53:
  549.       /*
  550.        * UNIX user name
  551.        */
  552.       setup_get(get_ptr + header_size - 3);
  553.       break;
  554.     case 0x54:
  555.       /*
  556.        * UNIX last modified time
  557.        */
  558.       if (hdr->extend_type == EXTEND_UNIX)
  559.         hdr->unix_last_modified_stamp = (time_t)get_longword();
  560.       break;
  561.     default:
  562.       /*
  563.        * other headers
  564.        */
  565.       setup_get(get_ptr + header_size - 3);
  566.       break;
  567.     }
  568.       }
  569.     if (hdr->header_level != 2 && get_ptr - ptr != 2) {
  570.       hdr->packed_size -= get_ptr - ptr - 2;
  571.       hdr->header_size += get_ptr - ptr - 2;
  572.     }
  573.   }
  574.   if (dir_length)
  575.     {
  576.       strcat(dirname, hdr->name);
  577.       strcpy(hdr->name, dirname);
  578.       name_length += dir_length;
  579.     }
  580.  
  581.   switch (hdr->extend_type)
  582.     {
  583.     case EXTEND_MSDOS:
  584.       msdos_to_unix_filename (hdr->name, name_length);
  585.     case EXTEND_HUMAN:
  586.       if (hdr->header_level == 2)
  587.     hdr->unix_last_modified_stamp = hdr->last_modified_stamp;
  588.       else
  589.     hdr->unix_last_modified_stamp    =
  590.       generic_to_unix_stamp (hdr->last_modified_stamp);
  591.       break;
  592.  
  593. #ifdef OSK
  594.     case EXTEND_OS68K:
  595.     case EXTEND_XOSK:
  596. #endif
  597.     case EXTEND_UNIX:
  598.       break;
  599.  
  600.     case EXTEND_MACOS:
  601.       macos_to_unix_filename (hdr->name, name_length);
  602.       hdr->unix_last_modified_stamp    =
  603.         generic_to_unix_stamp (hdr->last_modified_stamp);
  604.       break;
  605.  
  606.     default:
  607.       generic_to_unix_filename (hdr->name, name_length);
  608.       if (hdr->header_level == 2)
  609.     hdr->unix_last_modified_stamp = hdr->last_modified_stamp;
  610.       else
  611.     hdr->unix_last_modified_stamp    =
  612.       generic_to_unix_stamp (hdr->last_modified_stamp);
  613.     }
  614.  
  615.   return TRUE;
  616. }
  617.  
  618. void
  619. init_header (name, v_stat, hdr)
  620.      char *name;
  621.      struct stat *v_stat;
  622.      LzHeader *hdr;
  623. {
  624.   int len;
  625.  
  626.   if ( compress_method == 5 )
  627.           bcopy (LZHUFF5_METHOD, hdr->method, METHOD_TYPE_STRAGE);
  628.   else if ( compress_method )
  629.           bcopy (LZHUFF1_METHOD, hdr->method, METHOD_TYPE_STRAGE);
  630.   else
  631.         bcopy (LZHUFF0_METHOD, hdr->method, METHOD_TYPE_STRAGE);
  632.  
  633.   hdr->packed_size        = 0;
  634.   hdr->original_size        = v_stat->st_size;
  635.   hdr->last_modified_stamp    = unix_to_generic_stamp (v_stat->st_mtime);
  636.   hdr->attribute        = GENERIC_ATTRIBUTE;
  637.   hdr->header_level        = header_level;
  638.   strcpy (hdr->name, name);
  639.   len = strlen (name);
  640.   hdr->crc            = 0x0000;
  641.   hdr->extend_type        = EXTEND_UNIX;
  642.   hdr->unix_last_modified_stamp    = v_stat->st_mtime;
  643.                 /* since 00:00:00 JAN.1.1970 */
  644. #ifdef NOT_COMPATIBLE_MODE
  645. /*  Please need your modification in this space. */
  646. #else
  647.   hdr->unix_mode        = v_stat->st_mode;
  648. #endif
  649.  
  650.   hdr->unix_uid            = v_stat->st_uid;
  651.   hdr->unix_gid            = v_stat->st_gid;
  652.  
  653.   if (is_directory (v_stat))
  654.     {
  655.       bcopy (LZHDIRS_METHOD, hdr->method, METHOD_TYPE_STRAGE);
  656.       hdr->attribute = GENERIC_DIRECTORY_ATTRIBUTE;
  657.       hdr->original_size = 0;
  658.       if (len > 0 && hdr->name[len-1] != '/')
  659.         strcpy (&hdr->name[len++], "/");
  660.     }
  661.   if (generic_format)
  662.     unix_to_generic_filename (hdr->name, len);
  663. }
  664.  
  665. /* Write unix extended header or generic header. */
  666. void
  667. write_header (nafp, hdr)
  668.      FILE *nafp;
  669.      LzHeader *hdr;
  670. {
  671.   int header_size;
  672.   int name_length;
  673.   char data[LZHEADER_STRAGE];
  674.   char *p;
  675.  
  676.   bzero (data, LZHEADER_STRAGE);
  677.   bcopy (hdr->method, data + I_METHOD, METHOD_TYPE_STRAGE);
  678.   setup_put (data + I_PACKED_SIZE);
  679.   put_longword (hdr->packed_size);
  680.   put_longword (hdr->original_size);
  681.  
  682.   if (hdr->header_level == HEADER_LEVEL2)
  683.       put_longword ((long)hdr->unix_last_modified_stamp);
  684.   else
  685.       put_longword (hdr->last_modified_stamp);
  686.  
  687.   switch (hdr->header_level)
  688.     {
  689.     case HEADER_LEVEL0:
  690.       put_byte (hdr->attribute);
  691.       break;
  692.     case HEADER_LEVEL1:
  693.     case HEADER_LEVEL2:
  694.       put_byte (0x20);
  695.       break;
  696.     }
  697.  
  698.   put_byte (hdr->header_level);
  699.  
  700.   convdelim(hdr->name, DELIM2);
  701.   if (hdr->header_level != HEADER_LEVEL2)
  702.     {
  703.       if (p = (char *)rindex(hdr->name, DELIM2))
  704.     name_length = strlen(++p);
  705.       else
  706.     name_length = strlen(hdr->name);
  707.       put_byte (name_length);
  708.       bcopy (p ? p : hdr->name, data + I_NAME, name_length);
  709.       setup_put (data + I_NAME + name_length);
  710.     }
  711.  
  712.   put_word (hdr->crc);
  713.   if (generic_format)
  714.     {
  715.       header_size = I_GENERIC_HEADER_BOTTOM - 2 + name_length;
  716.       data[I_HEADER_SIZE] = header_size;
  717.       data[I_HEADER_CHECKSUM] = calc_sum (data + I_METHOD, header_size);
  718.     }
  719.   else if (header_level == HEADER_LEVEL0)
  720.     {
  721.       /* write old-style extend header */
  722.       put_byte (EXTEND_UNIX);
  723.       put_byte (CURRENT_UNIX_MINOR_VERSION);
  724.       put_longword ((long)hdr->unix_last_modified_stamp);
  725.       put_word (hdr->unix_mode);
  726.       put_word (hdr->unix_uid);
  727.       put_word (hdr->unix_gid);
  728.       header_size = I_UNIX_EXTEND_BOTTOM - 2 + name_length;
  729.       data[I_HEADER_SIZE] = header_size;
  730.       data[I_HEADER_CHECKSUM] = calc_sum (data + I_METHOD, header_size);
  731.     }
  732.   else
  733.     {
  734.       /* write extend header. */
  735.       char *ptr;
  736.       put_byte (EXTEND_UNIX);
  737.       ptr = put_ptr;
  738.       put_word(5);
  739.       if (hdr->header_level == HEADER_LEVEL1)
  740.     header_size = put_ptr - data - 2;
  741.       put_byte(0x50);        /* permission */
  742.       put_word(hdr->unix_mode);
  743.       put_word(7);
  744.       put_byte(0x51);        /* gid and uid */
  745.       put_word(hdr->unix_gid);
  746.       put_word(hdr->unix_uid);
  747.       if (p = (char *)rindex(hdr->name, DELIM2))
  748.     {
  749.       int i;
  750.       name_length = p - hdr->name + 1;
  751.       put_word(name_length + 3);
  752.       put_byte(2);        /* dirname */
  753.       for (i = 0; i < name_length; i++)
  754.         put_byte(hdr->name[i]);
  755.     }
  756.       if (header_level != HEADER_LEVEL2)
  757.     {
  758.       put_word(7);
  759.       put_byte(0x54);    /* time stamp */
  760.       put_longword(hdr->unix_last_modified_stamp);
  761.       hdr->packed_size += put_ptr - ptr;
  762.       ptr = put_ptr;
  763.       setup_put (data + I_PACKED_SIZE);
  764.       put_longword (hdr->packed_size);
  765.       put_ptr = ptr;
  766.       data[I_HEADER_SIZE] = header_size;
  767.       data[I_HEADER_CHECKSUM] = calc_sum (data + I_METHOD, header_size);
  768.     }
  769.       else
  770.     {
  771.       int i;
  772.       if (p = (char *)rindex(hdr->name, DELIM2))
  773.         name_length = strlen(++p);
  774.       else
  775.         {
  776.           p = hdr->name;
  777.           name_length = strlen(hdr->name);
  778.         }
  779.       put_word(name_length + 3);
  780.       put_byte(1);        /* filename */
  781.       for (i = 0; i < name_length; i++)
  782.         put_byte(*p++);
  783.     }
  784.       header_size = put_ptr - data;
  785.     }
  786.   if (header_level == HEADER_LEVEL2)
  787.     {
  788.       setup_put(data + I_HEADER_SIZE);
  789.       put_word(header_size + 2);
  790.     }
  791.   if (fwrite (data, sizeof (char), header_size + 2, nafp) == 0)
  792.     fatal_error ("Cannot write to temporary file");
  793.   convdelim(hdr->name, DELIM);
  794. }
  795.