home *** CD-ROM | disk | FTP | other *** search
/ Garbo / Garbo.cdr / pc / source / lhaxenix.zoo / lharc.xenix / lharc.c < prev    next >
C/C++ Source or Header  |  1990-04-02  |  50KB  |  2,197 lines

  1. /*----------------------------------------------------------------------*/
  2. /*        LHarc Archiver Driver for UNIX                */
  3. /*                                    */
  4. /*        Copyright(C) MCMLXXXIX  Yooichi.Tagawa            */
  5. /*        Thanks to H.Yoshizaki. (MS-DOS LHarc)            */
  6. /*                                    */
  7. /*  V0.00  Original                1988.05.23  Y.Tagawa    */
  8. /*  V0.01  Alpha Version (for 4.2BSD)        1989.05.28  Y.Tagawa    */
  9. /*  V0.02  Alpha Version Rel.2            1989.05.29  Y.Tagawa    */
  10. /*  V0.03  Release #3  Beta Version        1989.07.02  Y.Tagawa    */
  11. /*  V0.03a Fix few bug                          1989.07.03  Y.Tagawa    */
  12. /*  V0.04  A lot of bugs fixed, strict mode     1990.01.13  Kai Uwe Rommel */
  13. /*  V1.00  f and t commands, v option added     1990.01.27  Kai Uwe Rommel */
  14. /*----------------------------------------------------------------------*/
  15.  
  16.  
  17. #include <stdio.h>
  18. #include <ctype.h>
  19. #include <signal.h>
  20. #include <sys/types.h>
  21. #include <sys/stat.h>
  22. #include <prototypes.h>
  23.  
  24. #ifdef PROF
  25. #include <profile.h>
  26. #endif
  27.  
  28. #define STRICT
  29. #define FASTCOPY
  30.  
  31. #ifdef MSDOS
  32. #include <fcntl.h>
  33. extern unsigned char _osmode;
  34. extern FILE *popen();
  35. extern pclose();
  36. #define ftruncate chsize
  37. #define mktemp Mktemp
  38. #define SYSTIME_HAS_NO_TM
  39. #define NOBSTRING
  40. #define SYSNAME (_osmode ? "OS/2" : "MS-DOS")
  41. #define OUR_EXTEND (_osmode ? EXTEND_OS2 : EXTEND_MSDOS)
  42. #define FILENAME_LENGTH 128
  43. #define NULLFILE "nul"
  44. #define TMP_FILENAME_TEMPLATE "lhXXXXXX"
  45. #define NOT_COMPATIBLE_MODE
  46. #define RMODE "rb"
  47. #define WMODE "wb"
  48. #else
  49. #include <sys/file.h>
  50. #include <time.h>
  51. #define SYSNAME "UNIX"
  52. #define ftruncate chsize
  53. #define OUR_EXTEND EXTEND_UNIX
  54. #define FILENAME_LENGTH    1024
  55. #define NULLFILE "/dev/null"
  56. #define RMODE "r"
  57. #define WMODE "w"
  58. #endif
  59.  
  60. #ifdef SYSTIME_HAS_NO_TM
  61. /* most of System V,  define SYSTIME_HAS_NO_TM */
  62. #include <time.h>
  63. #endif
  64.  
  65. /* #include <strings.h> */
  66. #include <string.h>
  67. #include <sys/select.h>
  68. #include <sys/fcntl.h>
  69. /*----------------------------------------------------------------------*/
  70. /*            DIRECTORY ACCESS STUFF                */
  71. /*----------------------------------------------------------------------*/
  72. #ifndef NODIRECTORY
  73. #ifdef SYSV_SYSTEM_DIR
  74.  
  75. #include <dirent.h>
  76. #define DIRENTRY    struct dirent
  77. #define NAMLEN(p)    strlen (p->d_name)
  78.  
  79. #else    /* not SYSV_SYSTEM_DIR */
  80.  
  81. #ifdef NONSYSTEM_DIR_LIBRARY
  82. #include "lhdir.h"
  83. #else    /* not NONSYSTEM_DIR_LIBRARY */
  84. #include <sys/dir.h>
  85. #endif    /* not NONSYSTEM_DIR_LIBRARY */
  86.  
  87. #define DIRENTRY    struct direct
  88. #define NAMLEN(p)    p->d_namlen
  89.  
  90. extern DIR *opendir ();
  91. extern struct direct *readdir ();
  92.  
  93. #endif    /* not SYSV_SYSTEM_DIR */
  94. #endif
  95.  
  96. /*----------------------------------------------------------------------*/
  97. /*            FILE ATTRIBUTES                    */
  98. /*----------------------------------------------------------------------*/
  99.  
  100. /* If file mode is not compatible between your Machine/OS and
  101.    LHarc standard UNIX file mode.
  102.    (See UNIX Manual stat(1), <sys/stat.h>,
  103.    and/or below UNIX_* difinitions. ) */
  104. /* #define NOT_COMPATIBLE_MODE */
  105.  
  106.  
  107. /*----------------------------------------------------------------------*/
  108. /*            MEMORY FUNCTIONS                 */
  109. /*----------------------------------------------------------------------*/
  110.  
  111. #ifdef NOBSTRING
  112. #ifdef __ANSI__
  113. #include "mem.h"
  114. #define bcmp(a,b,n) memcmp ((a),(b),(n))
  115. #define bcopy(s,d,n) memmove((d),(s),(n))
  116. #define bzero(d,n) memset((d),0,(n))
  117. #else    /* not __ANSI__ */
  118. #include "memory.h"
  119. #define bcmp(a,b,n) memcmp ((a),(b),(n))
  120. #define bcopy(s,d,n) memcpy ((d),(s),(n))    /* movmem((s),(d),(n)) */
  121. #define bzero(d,n) memset((d),0,(n))
  122. #endif    /* not __ANSI__ */
  123. #endif    /* NOBSTRING */
  124.  
  125.  
  126. /*----------------------------------------------------------------------*/
  127. /*            YOUR CUSTOMIZIES                */
  128. /*----------------------------------------------------------------------*/
  129. /* These difinitions are changable to you like. */
  130.  #define ARCHIVENAME_EXTENTION    ".lzh"
  131. /* #define TMP_FILENAME_TEMPLATE    "/tmp/lhXXXXXX" */
  132. /* #define BACKUPNAME_EXTENTION        ".BAK"        */
  133. /* #define MULTIBYTE_CHAR                */
  134.  
  135.  
  136.  
  137. #define SJC_FIRST_P(c)            \
  138.   (((unsigned char)(c) >= 0x80) &&    \
  139.    (((unsigned char)(c) < 0xa0) ||    \
  140.     ((unsigned char)(c) >= 0xe0) &&    \
  141.     ((unsigned char)(c) < 0xfd)))
  142. #define SJC_SECOND_P(c)            \
  143.   (((unsigned char)(c) >= 0x40) &&    \
  144.    ((unsigned char)(c) < 0xfd) &&    \
  145.    ((ungigned char)(c) != 0x7f))
  146.  
  147. #ifdef MULTIBYTE_CHAR
  148. #define MULTIBYTE_FIRST_P    SJC_FIRST_P
  149. #define MULTIBYTE_SECOND_P    SJC_SECOND_P
  150. #endif
  151.  
  152. /*----------------------------------------------------------------------*/
  153. /*            OTHER DIFINITIONS                */
  154. /*----------------------------------------------------------------------*/
  155.  
  156. #ifndef SEEK_SET
  157. #define SEEK_SET    0
  158. #define SEEK_CUR    1
  159. #define SEEK_END    2
  160. #endif
  161.  
  162.  
  163. /* non-integral functions */
  164. extern struct tm *localtime ();
  165. extern char *getenv ();
  166. extern char *malloc ();
  167. extern char *realloc ();
  168.  
  169. extern int rson[];
  170.  
  171. /* external variables */
  172. extern int errno;
  173.  
  174.  
  175. #define    FALSE    0
  176. #define TRUE    1
  177. typedef int boolean;
  178.  
  179.  
  180. /*----------------------------------------------------------------------*/
  181. /*        LHarc FILE DIFINITIONS                    */
  182. /*----------------------------------------------------------------------*/
  183. #define METHOD_TYPE_STRAGE    5
  184. #define LZHUFF0_METHOD        "-lh0-"
  185. #define LZHUFF1_METHOD        "-lh1-"
  186. #define LARC4_METHOD        "-lz4-"
  187. #define LARC5_METHOD        "-lz5-"
  188.  
  189. #define I_HEADER_SIZE            0
  190. #define I_HEADER_CHECKSUM        1
  191. #define I_METHOD            2
  192. #define I_PACKED_SIZE            7
  193. #define I_ORIGINAL_SIZE            11
  194. #define I_LAST_MODIFIED_STAMP        15
  195. #define I_ATTRIBUTE            19
  196. #define I_NAME_LENGTH            21
  197. #define I_NAME                22
  198.  
  199. #define I_CRC                22 /* + name_length */
  200. #define I_EXTEND_TYPE            24 /* + name_length */
  201. #define I_MINOR_VERSION            25 /* + name_length */
  202. #define I_UNIX_LAST_MODIFIED_STAMP    26 /* + name_length */
  203. #define I_UNIX_MODE            30 /* + name_length */
  204. #define I_UNIX_UID            32 /* + name_length */
  205. #define I_UNIX_GID            34 /* + name_length */
  206. #define I_UNIX_EXTEND_BOTTOM        36 /* + name_length */
  207.  
  208.  
  209.  
  210. #define EXTEND_GENERIC  0
  211. #define EXTEND_UNIX    'U'
  212. #define EXTEND_MSDOS    'M'
  213. #define EXTEND_MACOS    'm'
  214. #define EXTEND_OS9    '9'
  215. #define EXTEND_OS2    '2'
  216. #define EXTEND_OS68K    'K'
  217. #define EXTEND_OS386    '3'
  218. #define EXTEND_HUMAN    'H'
  219. #define EXTEND_CPM    'C'
  220. #define EXTEND_FLEX    'F'
  221.  
  222. #define GENERIC_ATTRIBUTE        0x20
  223. #define GENERIC_DIRECTORY_ATTRIBUTE    0x10
  224.  
  225. #define CURRENT_UNIX_MINOR_VERSION    0x00
  226.  
  227.  
  228.  
  229. typedef struct LzHeader {
  230.   unsigned char        header_size;
  231.   char            method[METHOD_TYPE_STRAGE];
  232.   long            packed_size;
  233.   long            original_size;
  234.   long            last_modified_stamp;
  235.   unsigned short    attribute;
  236.   char            name[256];
  237.   unsigned short    crc;
  238.   boolean        has_crc;
  239.   unsigned char        extend_type;
  240.   unsigned char        minor_version;
  241.   /*  extend_type == EXTEND_UNIX  and convert from other type. */
  242.   time_t        unix_last_modified_stamp;
  243.   unsigned short    unix_mode;
  244.   unsigned short    unix_uid;
  245.   unsigned short    unix_gid;
  246. } LzHeader;
  247.  
  248. #define UNIX_FILE_TYPEMASK    0170000
  249. #define UNIX_FILE_REGULAR    0100000
  250. #define UNIX_FILE_DIRECTORY    0040000
  251. #define UNIX_SETUID        0004000
  252. #define UNIX_SETGID        0002000
  253. #define UNIX_STYCKYBIT        0001000
  254. #define UNIX_OWNER_READ_PERM    0000400
  255. #define UNIX_OWNER_WRITE_PERM    0000200
  256. #define UNIX_OWNER_EXEC_PERM    0000100
  257. #define UNIX_GROUP_READ_PERM    0000040
  258. #define UNIX_GROUP_WRITE_PERM    0000020
  259. #define UNIX_GROUP_EXEC_PERM    0000010
  260. #define UNIX_OTHER_READ_PERM    0000004
  261. #define UNIX_OTHER_WRITE_PERM    0000002
  262. #define UNIX_OTHER_EXEC_PERM    0000001
  263. #define UNIX_RW_RW_RW        0000666
  264.  
  265. #define LZHEADER_STRAGE        256
  266.  
  267. /*----------------------------------------------------------------------*/
  268. /*        PROGRAM                         */
  269. /*----------------------------------------------------------------------*/
  270.  
  271.  
  272. #define CMD_UNKNOWN    0
  273. #define CMD_EXTRACT    1
  274. #define CMD_APPEND    2
  275. #define CMD_VIEW    3
  276.  
  277. int      cmd = CMD_UNKNOWN;
  278. char     **cmd_filev;
  279. int      cmd_filec;
  280. char     *archive_name;
  281.  
  282. char     expanded_archive_name[FILENAME_LENGTH];
  283. char     temporary_name[FILENAME_LENGTH];
  284. char     pager[FILENAME_LENGTH];
  285.  
  286.  
  287. /* options */
  288. boolean    quiet = FALSE;
  289. boolean    text_mode = FALSE;
  290. /*boolean  verbose = FALSE; */
  291. boolean  noexec = FALSE; /* debugging option */
  292. boolean  force = FALSE;
  293. boolean  prof = FALSE;
  294.  
  295.  
  296. /* view flags */
  297. boolean  long_format_listing = FALSE;
  298.  
  299. /* extract flags */
  300. boolean  output_to_test = FALSE;
  301. boolean  output_to_stdout = FALSE;
  302.  
  303. /* append flags */
  304. boolean  new_archive = FALSE;
  305. boolean  update_if_newer = FALSE;
  306. boolean  update_freshen = FALSE;
  307. boolean  delete_after_append = FALSE;
  308. boolean  delete_from_archive = FALSE;
  309.  
  310. boolean  remove_temporary_at_error = FALSE;
  311.  
  312.  
  313. /*----------------------------------------------------------------------*/
  314. /* NOTES :    Text File Format                    */
  315. /*    GENERATOR        NewLine                    */
  316. /*    [generic]        0D 0A                    */
  317. /*    [MS-DOS]        0D 0A                    */
  318. /*    [MacOS]            0D                    */
  319. /*    [UNIX]            0A                    */
  320. /*----------------------------------------------------------------------*/
  321.  
  322. char *myname;
  323.  
  324.  
  325. void userbreak()
  326. {
  327.     error("Interrupt.");
  328. }
  329.  
  330.  
  331. main (argc, argv)
  332.      int argc;
  333.      char *argv[];
  334. {
  335.   char *p;
  336.  
  337.   myname = argv[0];
  338.   signal(SIGINT, userbreak);
  339.  
  340. #ifdef PROF
  341.   PROFINIT(PT_USER|PT_USEKP, NULL);
  342.   PROFCLEAR(PT_USER);
  343.   PROFON(PT_USER);
  344. #endif
  345.  
  346.   if (argc < 3)
  347.     print_tiny_usage_and_exit ();
  348.  
  349.   /* commands */
  350. #ifdef MSDOS
  351.   switch (tolower(argv[1][0]))
  352. #else
  353.   switch (argv[1][0])
  354. #endif
  355.     {
  356.     case 'x':
  357.     case 'e':
  358.       cmd = CMD_EXTRACT;
  359.       break;
  360.  
  361.     case 't':
  362.       output_to_test = TRUE;
  363.       cmd = CMD_EXTRACT;
  364.       break;
  365.  
  366.     case 'p':
  367.       output_to_stdout = TRUE;
  368.       cmd = CMD_EXTRACT;
  369.       break;
  370.  
  371.     case 'c':
  372.       new_archive = TRUE;
  373.       cmd = CMD_APPEND;
  374.       break;
  375.  
  376.     case 'a':
  377.       cmd = CMD_APPEND;
  378.       break;
  379.  
  380.     case 'd':
  381.       delete_from_archive = TRUE;
  382.       cmd = CMD_APPEND;
  383.       break;
  384.  
  385.     case 'u':
  386.       update_if_newer = TRUE;
  387.       cmd = CMD_APPEND;
  388.       break;
  389.  
  390.     case 'f':
  391.       update_if_newer = update_freshen = TRUE;
  392.       cmd = CMD_APPEND;
  393.       break;
  394.  
  395.     case 'm':
  396.       delete_after_append = TRUE;
  397.       cmd = CMD_APPEND;
  398.       break;
  399.  
  400.     case 'v':
  401.       cmd = CMD_VIEW;
  402.       break;
  403.  
  404.     case 'l':
  405.       long_format_listing = TRUE;
  406.       cmd = CMD_VIEW;
  407.       break;
  408.  
  409.     case 'h':
  410.     default:
  411.       print_tiny_usage_and_exit ();
  412.     }
  413.  
  414.   /* options */
  415.   p = &argv[1][1];
  416.   for (p = &argv[1][1]; *p; p++)
  417.     {
  418. #ifdef MSDOS
  419.       switch (tolower(*p))
  420. #else
  421.       switch (*p)
  422. #endif
  423.     {
  424.     case 'q':    quiet = TRUE; break;
  425.     case 'f':    force = TRUE; break;
  426. /*      case 'p':       prof = TRUE; break; */
  427. /*      case 'v':       verbose = TRUE; break; */
  428.         case 'v':       strcpy(pager, p + 1); *(p + 1) = 0; break;
  429.     case 't':    text_mode = TRUE; break;
  430.     case 'n':    noexec = TRUE; break;
  431.  
  432.     default:
  433.           fprintf (stderr, "unknown option '%c'.\n", *p);
  434.       exit (1);
  435.         }
  436.     }
  437.  
  438.   /* archive file name */
  439.   archive_name = argv[2];
  440.  
  441.   /* target file name */
  442.   cmd_filec = argc - 3;
  443.   cmd_filev = argv + 3;
  444.   sort_files ();
  445.  
  446.   switch (cmd)
  447.     {
  448.     case CMD_EXTRACT:    cmd_extract ();    break;
  449.     case CMD_APPEND:    cmd_append ();    break;
  450.     case CMD_VIEW:    cmd_view ();    break;
  451.     }
  452.  
  453. #ifdef PROF
  454.   PROFOFF(PT_USER);
  455.   PROFDUMP(PT_USER, "profile.out");
  456.   PROFFREE(PT_USER);
  457. #endif
  458.  
  459.   exit (0);
  460. }
  461.  
  462. print_tiny_usage_and_exit ()
  463. {
  464.   printf("\nC-LHarc for %s Version 1.00   (C) 1989-1990 Y.Tagawa, Kai Uwe Rommel\n"
  465.          "\nUsage: %s {axevlufdmctp}[qnftv] archive_file [files or directories...]\n",
  466.          SYSNAME, myname);
  467.   printf("\nCommands:                    Options:\n"
  468.          "  a   Append                   q   quiet\n"
  469.          "  x,e EXtract                  n   no execute\n"
  470.          "  v,l View/List                f   force (over write at extract)\n"
  471.          "  u   Update                   t   files are TEXT files\n"
  472.          "  f   Freshen                  v<pager>  use file pager for p command\n"
  473.          "  d   Delete\n"
  474.          "  m   Move\n"
  475.          "  c   re-Construct new archive\n"
  476.          "  t   Test archive\n"
  477.          "  p   Print to STDOUT\n");
  478.   exit (1);
  479. }
  480.  
  481. message (title, msg)
  482.      char *title, *msg;
  483. {
  484.   fprintf (stderr, "%s ", myname);
  485.   if (errno == 0)
  486.     fprintf (stderr, "%s %s\n", title, msg);
  487.   else
  488.     perror (msg);
  489. }
  490.  
  491. warning (msg)
  492.      char *msg;
  493. {
  494.   message ("Warning:", msg);
  495. }
  496.  
  497. error (msg)
  498.      char *msg;
  499. {
  500.   message ("Error:", msg);
  501.  
  502.   if (remove_temporary_at_error)
  503.   {
  504. #ifdef MSDOS
  505.     fcloseall();
  506. #endif
  507.     unlink (temporary_name);
  508.   }
  509.  
  510.   exit (1);
  511. }
  512.  
  513. char *writting_filename;
  514. char *reading_filename;
  515.  
  516. write_error ()
  517. {
  518.   error (writting_filename);
  519. }
  520.  
  521. read_error ()
  522. {
  523.   error (reading_filename);
  524. }
  525.  
  526.  
  527.  
  528. /*----------------------------------------------------------------------*/
  529. /*                                    */
  530. /*----------------------------------------------------------------------*/
  531.  
  532. boolean expand_archive_name (dst, src)
  533.      char *dst, *src;
  534. {
  535.   register char *p, *dot;
  536.  
  537.   strcpy (dst, src);
  538.  
  539.   for (p = dst, dot = (char*)0; *p; p++)
  540.     if (*p == '.')
  541.       dot = p;
  542.     else if (*p == '/' || *p == '\\')
  543.       dot = (char*)0;
  544.  
  545.   if (dot)
  546.     p = dot;
  547.  
  548. #ifdef ARCHIVENAME_EXTENTION
  549.   strcpy (p, ARCHIVENAME_EXTENTION);
  550. #else
  551.   strcpy (p, ".lzh");
  552. #endif
  553.   return (strcmp (dst, src) != 0);
  554. }
  555.  
  556. #ifdef MSDOS
  557. #define STRING_COMPARE(a,b) stricmp((a),(b))
  558. #else
  559. #define STRING_COMPARE(a,b) strcmp((a),(b))
  560. #endif
  561.  
  562. int sort_by_ascii (a, b)
  563.      char **a, **b;
  564. {
  565.   return STRING_COMPARE (*a, *b);
  566. }
  567.  
  568. sort_files ()
  569. {
  570.   qsort (cmd_filev, cmd_filec, sizeof (char*), sort_by_ascii);
  571. }
  572.  
  573. #ifndef MSDOS
  574. char *strdup (string)
  575.      char *string;
  576. {
  577.   int    len = strlen (string) + 1;
  578.   char    *p = malloc (len);
  579.   bcopy (string, p, len);
  580.   return p;
  581. }
  582. #endif
  583.  
  584. #ifdef NODIRECTORY
  585. /* please need your imprementation */
  586. boolean find_files (name, v_filec, v_filev)
  587.      char    *name;
  588.      int    *v_filec;
  589.      char    ***v_filev;
  590. {
  591.   return FALSE;            /* DUMMY */
  592. }
  593. #else
  594. boolean find_files (name, v_filec, v_filev)
  595.      char    *name;
  596.      int    *v_filec;
  597.      char    ***v_filev;
  598. {
  599.   char        newname[FILENAME_LENGTH];
  600.   int         len, n;
  601.   DIR        *dirp;
  602.   DIRENTRY    *dp;
  603.   int           alloc_size = 64; /* any (^_^) */
  604.   char        **filev;
  605.   int        filec = 0;
  606.  
  607.   if ( strcmp(name, ".") == 0 )
  608.     newname[0] = 0;
  609.   else
  610.     strcpy (newname, name);
  611.  
  612.   len = strlen (newname);
  613.   dirp = opendir (name);
  614.  
  615.   if (dirp)
  616.     {
  617.       filev = (char**)malloc (alloc_size * sizeof(char *));
  618.       if (!filev)
  619.     error ("not enough memory");
  620.  
  621.       for (dp = readdir (dirp); dp != NULL; dp = readdir (dirp))
  622.     {
  623.       n = NAMLEN (dp);
  624.           if (
  625. #ifndef MSDOS
  626.               (dp->d_ino != 0) &&
  627. #endif
  628.               ((dp->d_name[0] != '.') ||
  629.                  ((n != 1) &&
  630.                  ((dp->d_name[1] != '.') ||
  631.          (n != 2)))) &&            /* exclude '.' and '..' */
  632.           (strcmp (dp->d_name, temporary_name) != 0) &&
  633.           (strcmp (dp->d_name, archive_name) != 0))
  634.         {
  635.               if ((len != 0) && (newname[len-1] != '/') && (newname[len-1] != '\\'))
  636.                 {
  637. #ifdef MSDOS
  638.                   newname[len] = '\\';
  639. #else
  640.                   newname[len] = '/';
  641. #endif
  642.           strncpy (newname+len+1, dp->d_name, n);
  643.           newname[len+n+1] = '\0';
  644.         }
  645.           else
  646.         {
  647.           strncpy (newname+len, dp->d_name, n);
  648.           newname[len+n] = '\0';
  649.         }
  650.  
  651.           filev[filec++] = strdup (newname);
  652.           if (filec == alloc_size)
  653.         {
  654.                   alloc_size += 64;
  655.                   filev = (char**)realloc (filev, alloc_size * sizeof(char *));
  656.         }
  657.         }
  658.     }
  659.       closedir (dirp);
  660.     }
  661.  
  662.   *v_filev = filev;
  663.   *v_filec = filec;
  664.   if (dirp)
  665.     {
  666.       qsort (filev, filec, sizeof (char*), sort_by_ascii);
  667.       return TRUE;
  668.     }
  669.   else
  670.     return FALSE;
  671. }
  672. #endif
  673.  
  674. free_files (filec, filev)
  675.      int    filec;
  676.      char    **filev;
  677. {
  678.   int        i;
  679.  
  680.   for (i = 0; i < filec; i ++)
  681.     free (filev[i]);
  682.  
  683.   free (filev);
  684. }
  685.  
  686.  
  687. /*----------------------------------------------------------------------*/
  688. /*                                    */
  689. /*----------------------------------------------------------------------*/
  690.  
  691. int calc_sum (p, len)
  692.      register char *p;
  693.      register int len;
  694. {
  695.   register int sum;
  696.  
  697.   for (sum = 0; len; len--)
  698.     sum += *p++;
  699.  
  700.   return sum & 0xff;
  701. }
  702.  
  703. unsigned char *get_ptr;
  704. #define setup_get(PTR) get_ptr = (unsigned char*)(PTR)
  705. #define get_byte() (*get_ptr++)
  706. #define put_ptr    get_ptr
  707. #define setup_put(PTR) put_ptr = (unsigned char*)(PTR)
  708. #define put_byte(c) *put_ptr++ = (unsigned char)(c)
  709.  
  710. unsigned short get_word ()
  711. {
  712.   int b0, b1;
  713.  
  714.   b0 = get_byte ();
  715.   b1 = get_byte ();
  716.   return (b1 << 8) + b0;
  717. }
  718.  
  719. put_word (v)
  720.      unsigned int    v;
  721. {
  722.   put_byte (v);
  723.   put_byte (v >> 8);
  724. }
  725.  
  726. long get_longword ()
  727. {
  728.   long b0, b1, b2, b3;
  729.  
  730.   b0 = get_byte ();
  731.   b1 = get_byte ();
  732.   b2 = get_byte ();
  733.   b3 = get_byte ();
  734.   return (b3 << 24) + (b2 << 16) + (b1 << 8) + b0;
  735. }
  736.  
  737. put_longword (v)
  738.      long v;
  739. {
  740.   put_byte (v);
  741.   put_byte (v >> 8);
  742.   put_byte (v >> 16);
  743.   put_byte (v >> 24);
  744. }
  745.  
  746.  
  747. msdos_to_unix_filename (name, len)
  748.      register char *name;
  749.      register int len;
  750. {
  751.   register int i;
  752.  
  753. #ifdef MULTIBYTE_CHAR
  754.   for (i = 0; i < len; i ++)
  755.     {
  756.       if (MULTIBYTE_FIRST_P (name[i]) &&
  757.       MULTIBYTE_SECOND_P (name[i+1]))
  758.         i ++;
  759. #ifndef MSDOS
  760.       else if (name[i] == '\\')
  761.         name[i] = '/';
  762. #endif
  763.       else if (isupper (name[i]))
  764.     name[i] = tolower (name[i]);
  765.     }
  766. #else
  767.   for (i = 0; i < len; i ++)
  768.     {
  769. #ifndef MSDOS
  770.       if (name[i] == '\\')
  771.     name[i] = '/';
  772.       else
  773. #endif
  774.         if (isupper (name[i]))
  775.           name[i] = tolower (name[i]);
  776.     }
  777. #endif
  778. }
  779.  
  780. generic_to_unix_filename (name, len)
  781.      register char *name;
  782.      register int len;
  783. {
  784.   register int i;
  785.   boolean    lower_case_used = FALSE;
  786.  
  787. #ifdef MULTIBYTE_CHAR
  788.   for (i = 0; i < len; i ++)
  789.     {
  790.       if (MULTIBYTE_FIRST_P (name[i]) &&
  791.       MULTIBYTE_SECOND_P (name[i+1]))
  792.     i ++;
  793.       else if (islower (name[i]))
  794.     {
  795.       lower_case_used = TRUE;
  796.       break;
  797.     }
  798.     }
  799.   for (i = 0; i < len; i ++)
  800.     {
  801.       if (MULTIBYTE_FIRST_P (name[i]) &&
  802.       MULTIBYTE_SECOND_P (name[i+1]))
  803.         i ++;
  804. #ifndef MSDOS
  805.       else if (name[i] == '\\')
  806.         name[i] = '/';
  807. #endif
  808.       else if (!lower_case_used && isupper (name[i]))
  809.     name[i] = tolower (name[i]);
  810.     }
  811. #else
  812.   for (i = 0; i < len; i ++)
  813.     if (islower (name[i]))
  814.       {
  815.     lower_case_used = TRUE;
  816.     break;
  817.       }
  818.   for (i = 0; i < len; i ++)
  819.     {
  820. #ifndef MSDOS
  821.       if (name[i] == '\\')
  822.     name[i] = '/';
  823.       else
  824. #endif
  825.         if (!lower_case_used && isupper (name[i]))
  826.           name[i] = tolower (name[i]);
  827.     }
  828. #endif
  829. }
  830.  
  831. macos_to_unix_filename (name, len)
  832.      register char *name;
  833.      register int len;
  834. {
  835.   register int i;
  836.  
  837.   for (i = 0; i < len; i ++)
  838.     {
  839.       if (name[i] == ':')
  840.     name[i] = '/';
  841.       else if (name[i] == '/')
  842.     name[i] = ':';
  843.     }
  844. }
  845.  
  846. /*----------------------------------------------------------------------*/
  847. /*                                    */
  848. /*    Generic stamp format:                        */
  849. /*                                    */
  850. /*     31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16        */
  851. /*    |<-------- year ------->|<- month ->|<-- day -->|        */
  852. /*                                    */
  853. /*     15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0        */
  854. /*    |<--- hour --->|<---- minute --->|<- second*2 ->|        */
  855. /*                                    */
  856. /*----------------------------------------------------------------------*/
  857.  
  858.  
  859. long gettz ()
  860. {
  861. #ifdef MSDOS
  862.    return timezone;
  863. #else
  864.    struct timeval    tp;
  865. /*   struct timezone    tzp;*/
  866. /*   gettimeofday (&tp, &tzp);*/    /* specific to 4.3BSD */
  867. /* return (tzp.tz_minuteswest * 60 + (tzp.tz_dsttime != 0 ? 60L * 60L : 0));*/
  868.    return (60);
  869. #endif
  870. }
  871.  
  872. #ifdef NOT_USED
  873. struct tm *msdos_to_unix_stamp_tm (a)
  874.      long a;
  875. {
  876.   static struct tm t;
  877.   t.tm_sec    = ( a          & 0x1f) * 2;
  878.   t.tm_min    =  (a >>    5) & 0x3f;
  879.   t.tm_hour    =  (a >>   11) & 0x1f;
  880.   t.tm_mday    =  (a >>   16) & 0x1f;
  881.   t.tm_mon    =  (a >> 16+5) & 0x0f - 1;
  882.   t.tm_year    = ((a >> 16+9) & 0x7f) + 80;
  883.   return &t;
  884. }
  885. #endif
  886.  
  887. time_t generic_to_unix_stamp (t)
  888.      long t;
  889. {
  890.   struct tm tm;
  891.   long longtime;
  892.   static unsigned int dsboy[12] =
  893.     { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
  894.   unsigned long days;
  895.  
  896.   tm.tm_year =  ((int)(t >> 25) & 0x7f) + 80;
  897.   tm.tm_mon  =  ((int)(t >> 21) & 0x0f) - 1;     /* 0..11 means Jan..Dec */
  898.   tm.tm_mday =  (int)(t >> 16) & 0x1f;         /* 1..31 means 1st,...31st */
  899.  
  900.   tm.tm_hour =  ((int)t >> 11) & 0x1f;
  901.   tm.tm_min  =  ((int)t >> 5)  & 0x3f;
  902.   tm.tm_sec  =  ((int)t        & 0x1f) * 2;
  903.  
  904. #ifdef MSDOS
  905.   longtime = mktime(&tm);
  906. #else
  907.                                       /* Calculate days since 1970.01.01 */
  908.   days = (365 * (tm.tm_year - 70) +   /* days due to whole years */
  909.           (tm.tm_year - 70 + 1) / 4 + /* days due to leap years */
  910.           dsboy[tm.tm_mon] +          /* days since beginning of this year */
  911.           tm.tm_mday-1);              /* days since beginning of month */
  912.  
  913.   if ((tm.tm_year % 4 == 0) &&
  914.       (tm.tm_year % 400 != 0) &&
  915.       (tm.tm_mon >= 2))         /* if this is a leap year and month */
  916.     days++;            /* is March or later, add a day */
  917.  
  918.   /* Knowing the days, we can find seconds */
  919.   longtime = (((days * 24) + tm.tm_hour) * 60 + tm.tm_min) * 60 + tm.tm_sec;
  920.   longtime += gettz ();      /* adjust for timezone */
  921. #endif
  922.  
  923.   /* special case:  if MSDOS format date and time were zero, then we set
  924.      time to be zero here too. */
  925.   if (t == 0)
  926.     longtime = 0;
  927.  
  928.   /* LONGTIME is now the time in seconds, since 1970/01/01 00:00:00.  */
  929.   return (time_t)longtime;
  930. }
  931.  
  932. long unix_to_generic_stamp (t)
  933.      time_t t;
  934. {
  935.   struct tm *tm = localtime (&t);
  936.   unsigned long stamp;
  937.  
  938.   stamp =  ( ((long)(tm->tm_year - 80)) << 25 );
  939.   stamp += ( ((long)(tm->tm_mon + 1))   << 21 );
  940.   stamp += ( ((long)(tm->tm_mday))      << 16 );
  941.   stamp += ( ((long)(tm->tm_hour))      << 11 );
  942.   stamp += ( ((long)(tm->tm_min))       << 5 );
  943.   stamp += ( ((long)(tm->tm_sec))       >> 1 );
  944.  
  945.   return stamp;
  946. }
  947.  
  948. /*----------------------------------------------------------------------*/
  949. /*                                    */
  950. /*----------------------------------------------------------------------*/
  951.  
  952. boolean get_header (fp, hdr)
  953.      FILE *fp;
  954.      register LzHeader *hdr;
  955. {
  956.   int        header_size;
  957.   int        name_length;
  958.   char        data[LZHEADER_STRAGE];
  959.   int        checksum;
  960.   int        i;
  961.  
  962.   bzero (hdr, sizeof (LzHeader));
  963.  
  964.   if (((header_size = getc (fp)) == EOF) || (header_size == 0))
  965.     {
  966.       return FALSE;        /* finish */
  967.     }
  968.  
  969.   if (fread (data + I_HEADER_CHECKSUM,
  970.           sizeof (char), header_size + 1, fp) < header_size + 1)
  971.     {
  972.       error ("Invalid header (LHarc file ?)\a");
  973.       return FALSE;        /* finish */
  974.     }
  975.  
  976.   setup_get (data + I_HEADER_CHECKSUM);
  977.   checksum = calc_sum (data + I_METHOD, header_size);
  978.   if (get_byte () != checksum)
  979.     warning ("Checksum error (LHarc file?)\a");
  980.  
  981.   hdr->header_size = header_size;
  982.   bcopy (data + I_METHOD, hdr->method, METHOD_TYPE_STRAGE);
  983. #ifdef OLD
  984.   if ((bcmp (hdr->method, LZHUFF1_METHOD, METHOD_TYPE_STRAGE) != 0) &&
  985.       (bcmp (hdr->method, LZHUFF0_METHOD, METHOD_TYPE_STRAGE) != 0) &&
  986.       (bcmp (hdr->method, LARC5_METHOD, METHOD_TYPE_STRAGE) != 0) &&
  987.       (bcmp (hdr->method, LARC4_METHOD, METHOD_TYPE_STRAGE) != 0))
  988.     {
  989.       warning ("Unknown method (LHarc file ?)");
  990.       return FALSE;        /* invalid method */
  991.     }
  992. #endif
  993.   setup_get (data + I_PACKED_SIZE);
  994.   hdr->packed_size    = get_longword ();
  995.   hdr->original_size    = get_longword ();
  996.   hdr->last_modified_stamp = get_longword ();
  997.   hdr->attribute    = get_word ();
  998.   name_length        = get_byte ();
  999.   for (i = 0; i < name_length; i ++)
  1000.     hdr->name[i] =(char)get_byte ();
  1001.   hdr->name[name_length] = '\0';
  1002.  
  1003.   /* defaults for other type */
  1004.   hdr->unix_mode    = UNIX_FILE_REGULAR | UNIX_RW_RW_RW;
  1005.   hdr->unix_gid     = 0;
  1006.   hdr->unix_uid        = 0;
  1007.  
  1008.   if (header_size - name_length >= 24)
  1009.     {                /* EXTEND FORMAT */
  1010.       hdr->crc                = get_word ();
  1011.       hdr->extend_type            = get_byte ();
  1012.       hdr->minor_version        = get_byte ();
  1013.       hdr->has_crc = TRUE;
  1014.     }
  1015.   else if (header_size - name_length == 22)
  1016.     {                /* Generic with CRC */
  1017.       hdr->crc                = get_word ();
  1018.       hdr->extend_type            = EXTEND_GENERIC;
  1019.       hdr->has_crc = TRUE;
  1020.     }
  1021.   else if (header_size - name_length == 20)
  1022.     {                /* Generic no CRC */
  1023.       hdr->extend_type            = EXTEND_GENERIC;
  1024.       hdr->has_crc = FALSE;
  1025.     }
  1026.   else
  1027.     {
  1028.       warning ("Unknown header (LHarc file ?)");
  1029.       return FALSE;
  1030.     }
  1031.  
  1032.   switch (hdr->extend_type)
  1033.     {
  1034.     case EXTEND_MSDOS:
  1035.       msdos_to_unix_filename (hdr->name, name_length);
  1036.       hdr->unix_last_modified_stamp    =
  1037.     generic_to_unix_stamp (hdr->last_modified_stamp);
  1038.       break;
  1039.  
  1040.     case EXTEND_UNIX:
  1041.       hdr->unix_last_modified_stamp    = (time_t)get_longword ();
  1042.       hdr->unix_mode            = get_word ();
  1043.       hdr->unix_uid            = get_word ();
  1044.       hdr->unix_gid            = get_word ();
  1045.       break;
  1046.  
  1047.     case EXTEND_MACOS:
  1048.       macos_to_unix_filename (hdr->name, name_length);
  1049.       hdr->unix_last_modified_stamp    =
  1050.     generic_to_unix_stamp (hdr->last_modified_stamp);
  1051.       break;
  1052.  
  1053.     default:
  1054.       generic_to_unix_filename (hdr->name, name_length);
  1055.       hdr->unix_last_modified_stamp    =
  1056.     generic_to_unix_stamp (hdr->last_modified_stamp);
  1057.     }
  1058.  
  1059.   return TRUE;
  1060. }
  1061.  
  1062. init_header (name, v_stat, hdr)
  1063.      char *name;
  1064.      struct stat *v_stat;
  1065.      LzHeader *hdr;
  1066. {
  1067.   bcopy (LZHUFF1_METHOD, hdr->method, METHOD_TYPE_STRAGE);
  1068.   hdr->packed_size        = 0;
  1069.   hdr->original_size        = v_stat->st_size;
  1070.   hdr->last_modified_stamp      = unix_to_generic_stamp (v_stat->st_mtime);
  1071. #ifdef MSDOS
  1072.   getfilemode(name, &(hdr->attribute));
  1073. #else
  1074.   hdr->attribute                = GENERIC_ATTRIBUTE;
  1075. #endif
  1076.   strcpy (hdr->name, name);
  1077.   hdr->crc            = 0x0000;
  1078.   hdr->extend_type              = OUR_EXTEND;
  1079.   hdr->unix_last_modified_stamp    = v_stat->st_mtime;
  1080.                 /* 00:00:00 since JAN.1.1970 */
  1081. #ifdef NOT_COMPATIBLE_MODE
  1082.   hdr->unix_mode        = v_stat->st_mode;
  1083. #else
  1084.   hdr->unix_mode        = v_stat->st_mode;
  1085. #endif
  1086.  
  1087.   hdr->unix_uid            = v_stat->st_uid;
  1088.   hdr->unix_gid            = v_stat->st_gid;
  1089.  
  1090.   if ((v_stat->st_mode & S_IFMT) == S_IFDIR)
  1091.     {
  1092.       bcopy (LZHUFF0_METHOD, hdr->method, METHOD_TYPE_STRAGE);
  1093.       hdr->attribute = GENERIC_DIRECTORY_ATTRIBUTE;
  1094.       hdr->original_size = 0;
  1095.       strcat (hdr->name, "/");
  1096.     }
  1097. }
  1098.  
  1099. /* Write only unix extended header. */
  1100. write_header (nafp, hdr)
  1101.      FILE *nafp;
  1102.      LzHeader *hdr;
  1103. {
  1104.   int        header_size;
  1105.   int        name_length;
  1106.   char          data[LZHEADER_STRAGE], *ptr;
  1107.   int           cnt;
  1108.  
  1109.   bzero (data, LZHEADER_STRAGE);
  1110.   bcopy (hdr->method, data + I_METHOD, METHOD_TYPE_STRAGE);
  1111.   setup_put (data + I_PACKED_SIZE);
  1112.   put_longword (hdr->packed_size);
  1113.   put_longword (hdr->original_size);
  1114.   put_longword (hdr->last_modified_stamp);
  1115.   put_word (hdr->attribute);
  1116.   
  1117. #ifdef STRICT
  1118.  
  1119.   if ( hdr->name[1] == ':' )
  1120.   {
  1121.     name_length = strlen(hdr->name + 2);
  1122.     put_byte (name_length);
  1123.     bcopy (hdr->name + 2, data + I_NAME, name_length);
  1124.   }
  1125.   else
  1126.   {
  1127.     name_length = strlen(hdr->name);
  1128.     put_byte (name_length);
  1129.     bcopy (hdr->name, data + I_NAME, name_length);
  1130.   }
  1131.   
  1132.   for ( ptr = data + I_NAME, cnt = 0; cnt < name_length; ptr++, cnt++ )
  1133.   {
  1134.     *ptr = toupper(*ptr);
  1135.  
  1136.     if ( *ptr == '/' )
  1137.       *ptr = '\\';
  1138.   }
  1139. #else
  1140.   name_length = strlen (hdr->name);
  1141.   put_byte (name_length);
  1142.   bcopy (hdr->name, data + I_NAME, name_length);
  1143. #endif
  1144.   
  1145.   setup_put (data + I_NAME + name_length);
  1146.   put_word (hdr->crc);
  1147. #ifdef STRICT
  1148.   header_size = I_EXTEND_TYPE - 2 + name_length;
  1149. #else
  1150.   put_byte (OUR_EXTEND);
  1151.   put_byte (CURRENT_UNIX_MINOR_VERSION);
  1152.   put_longword ((long)hdr->unix_last_modified_stamp);
  1153.   put_word (hdr->unix_mode);
  1154.   put_word (hdr->unix_uid);
  1155.   put_word (hdr->unix_gid);
  1156.   header_size = I_UNIX_EXTEND_BOTTOM - 2 + name_length;
  1157. #endif
  1158.   data[I_HEADER_SIZE] = header_size;
  1159.   data[I_HEADER_CHECKSUM] = calc_sum (data + I_METHOD, header_size);
  1160.  
  1161.   if (fwrite (data, sizeof (char), header_size + 2, nafp) == NULL)
  1162.     error ("cannot write to temporary file");
  1163. }
  1164.  
  1165. boolean archive_is_msdos_sfx1 (name)
  1166.      char *name;
  1167. {
  1168.   int    len = strlen (name);
  1169.   return ((len >= 4) &&
  1170.       (strcmp (name + len - 4, ".com") == 0 ||
  1171.        strcmp (name + len - 4, ".exe") == 0));
  1172. }
  1173.  
  1174. boolean skip_msdos_sfx1_code (fp)
  1175.      FILE *fp;
  1176. {
  1177.   unsigned char buffer[2048];
  1178.   unsigned char *p, *q;
  1179.   int    n;
  1180.  
  1181.   n = fread (buffer, sizeof (char), 2048, fp);
  1182.  
  1183.   for (p = buffer + 2, q = buffer + n - 5; p < q; p ++)
  1184.     {
  1185.       /* found "-l??-" keyword (as METHOD type string) */
  1186.       if (p[0] == '-' && p[1] == 'l' && p[4] == '-')
  1187.     {
  1188.       /* size and checksum validate check */
  1189.       if (p[-2] > 20 && p[-1] == calc_sum (p, p[-2]))
  1190.         {
  1191.               fseek (fp, (long) ((p - 2) - buffer) - n, SEEK_CUR);
  1192.           return TRUE;
  1193.         }
  1194.     }
  1195.     }
  1196.  
  1197.   fseek (fp, (long) -n, SEEK_CUR);
  1198.   return FALSE;
  1199. }
  1200.  
  1201.  
  1202. /*----------------------------------------------------------------------*/
  1203. /*                                    */
  1204. /*----------------------------------------------------------------------*/
  1205.  
  1206. make_tmp_name (original, name)
  1207.      char *original;
  1208.      char *name;
  1209. {
  1210. #ifdef TMP_FILENAME_TEMPLATE
  1211.   /* "/tmp/lhXXXXXX" etc. */
  1212.   strcpy (name, TMP_FILENAME_TEMPLATE);
  1213. #else
  1214.   char *p, *s;
  1215.  
  1216.   strcpy (name, original);
  1217.   for (p = name, s = (char*)0; *p; p++)
  1218.     if (*p == '/' || *p == '\\')
  1219.       s = p;
  1220.  
  1221.   strcpy ((s ? s+1 : name), "lhXXXXXX");
  1222. #endif
  1223.  
  1224.   mktemp (name);
  1225. }
  1226.  
  1227. make_backup_name (name, orginal)
  1228.      char *name;
  1229.      char *orginal;
  1230. {
  1231.   register char *p, *dot;
  1232.  
  1233.   strcpy (name, orginal);
  1234.   for (p = name, dot = (char*)0; *p; p ++)
  1235.     {
  1236.       if (*p == '.')
  1237.     dot = p;
  1238.       else if (*p == '/' || *p == '\\')
  1239.     dot = (char*)0;
  1240.     }
  1241.  
  1242.   if (dot)
  1243.     p = dot;
  1244.  
  1245. #ifdef BACKUPNAME_EXTENTION
  1246.   strcpy (p, BACKUPNAME_EXTENTION)
  1247. #else
  1248.   strcpy (p, ".bak");
  1249. #endif
  1250. }
  1251.  
  1252. make_standard_archive_name (name, orginal)
  1253.      char *name;
  1254.      char *orginal;
  1255. {
  1256.   register char *p, *dot;
  1257.  
  1258.   strcpy (name, orginal);
  1259.   for (p = name, dot = (char*)0; *p; p ++)
  1260.     {
  1261.       if (*p == '.')
  1262.     dot = p;
  1263.       else if (*p == '/' || *p == '\\')
  1264.     dot = (char*)0;
  1265.     }
  1266.  
  1267.   if (dot)
  1268.     p = dot;
  1269.  
  1270. #ifdef ARCHIVENAME_EXTENTION
  1271.   strcpy (p, ARCHIVENAME_EXTENTION);
  1272. #else
  1273.   strcpy (p, ".lzh");
  1274. #endif
  1275. }
  1276.  
  1277. /*----------------------------------------------------------------------*/
  1278. /*                                    */
  1279. /*----------------------------------------------------------------------*/
  1280.  
  1281.  
  1282. boolean need_file (name)
  1283.      char *name;
  1284. {
  1285.   int    i;
  1286.  
  1287.   if (cmd_filec == 0)
  1288.     return TRUE;
  1289.  
  1290.   for (i = 0; i < cmd_filec; i ++)
  1291.     {
  1292.       if (STRING_COMPARE (cmd_filev[i], name) == 0)
  1293.     return TRUE;
  1294.     }
  1295.  
  1296.   return FALSE;
  1297. }
  1298.  
  1299. FILE *xfopen (name, mode)
  1300.      char *name, *mode;
  1301. {
  1302.   FILE *fp;
  1303.  
  1304.   if ((fp = fopen (name, mode)) == NULL)
  1305.     error (name);
  1306.  
  1307.   return fp;
  1308. }
  1309.  
  1310.  
  1311. /*----------------------------------------------------------------------*/
  1312. /*        Listing Stuff                        */
  1313. /*----------------------------------------------------------------------*/
  1314.  
  1315. /* need 14 or 22 (when long_format_listing is TRUE) column spaces */
  1316. print_size (packed_size, original_size)
  1317.      long packed_size, original_size;
  1318. {
  1319.   if (long_format_listing)
  1320.     printf ("%7ld ", packed_size);
  1321.  
  1322.   printf ("%7ld ", original_size);
  1323.  
  1324.   if (original_size == 0L)
  1325.     printf ("******");
  1326.   else
  1327.     printf ("%3d.%1d%%",
  1328.         (int)((packed_size * 100L) / original_size),
  1329.         (int)((packed_size * 1000L) / original_size) % 10);
  1330. }
  1331.  
  1332. /* need 12 or 17 (when long_format_listing is TRUE) column spaces */
  1333. print_stamp (t)
  1334.      time_t t;
  1335. {
  1336.   static boolean    got_now = FALSE;
  1337.   static time_t        now;
  1338.   static unsigned int    threshold;
  1339.   static char   t_month[12*3+1] = "JanFebMarAprMayJunJulAugSepOctNovDec";
  1340.   struct tm        *p;
  1341.  
  1342.   if (t == 0)
  1343.     {
  1344.       if (long_format_listing)
  1345.     printf ("                 "); /* 17 spaces */
  1346.       else
  1347.     printf ("            ");    /* 12 spaces */
  1348.  
  1349.       return;
  1350.     }
  1351.  
  1352.   if (!got_now)
  1353.     {
  1354.       time (&now);
  1355.       p = localtime (&now);
  1356.       threshold = p->tm_year * 12 + p->tm_mon - 6;
  1357.       got_now = TRUE;
  1358.     }
  1359.  
  1360.   p = localtime (&t);
  1361.  
  1362.   if (long_format_listing)
  1363.     printf ("%.3s %2d %02d:%02d %04d",
  1364.         &t_month[p->tm_mon * 3], p->tm_mday,
  1365.         p->tm_hour, p->tm_min, p->tm_year + 1900);
  1366.   else
  1367.     if (p->tm_year * 12 + p->tm_mon > threshold)
  1368.       printf ("%.3s %2d %02d:%02d",
  1369.           &t_month[p->tm_mon * 3], p->tm_mday, p->tm_hour, p->tm_min);
  1370.     else
  1371.       printf ("%.3s %2d  %04d",
  1372.           &t_month[p->tm_mon * 3], p->tm_mday, p->tm_year + 1900);
  1373. }
  1374.  
  1375. print_bar ()
  1376. {
  1377.   /* 17+1+(0 or 7+1)+7+1+6+1+(0 or 1+4)+(12 or 17)+1+20 */
  1378.   /*       12345678901234567_  1234567_123456  _123456789012   1234      */
  1379.   if (long_format_listing)
  1380. #ifdef STRICT
  1381.     printf ("------- ------- ------ ---- ----------------- -------------\n");
  1382. #else
  1383.     printf ("----------------- ------- ------- ------ ---- ----------------- -------------\n");
  1384. #endif
  1385.   else
  1386. #ifdef STRICT
  1387.     printf ("------- ------ ------------ --------------------\n");
  1388. #else
  1389.     printf ("----------------- ------- ------ ------------ --------------------\n");
  1390. #endif
  1391. }
  1392.  
  1393.  
  1394. /*
  1395.   view
  1396.  */
  1397. cmd_view ()
  1398. {
  1399.   FILE        *fp;
  1400.   LzHeader    hdr;
  1401.   register char    *p;
  1402.   long        a_packed_size = 0L;
  1403.   long        a_original_size = 0L;
  1404.   int        n_files = 0;
  1405.   struct stat    v_stat;
  1406.  
  1407.   if ((fp = fopen (archive_name, RMODE)) == NULL)
  1408.     if (!expand_archive_name (expanded_archive_name, archive_name))
  1409.       error (archive_name);
  1410.     else
  1411.       {
  1412.     errno = 0;
  1413.         fp = xfopen (expanded_archive_name, RMODE);
  1414.     archive_name = expanded_archive_name;
  1415.       }
  1416.  
  1417.   if (archive_is_msdos_sfx1 (archive_name))
  1418.     {
  1419.       skip_msdos_sfx1_code (fp);
  1420.     }
  1421.  
  1422.   if (!quiet)
  1423.     {
  1424.       /*       12345678901234567_  1234567_123456  _  123456789012  1234 */
  1425. #ifdef STRICT
  1426.       printf ("%s   SIZE  RATIO%s %s    STAMP   %s NAME\n",
  1427. #else
  1428.       printf (" PERMSSN  UID GID %s   SIZE  RATIO%s %s    STAMP   %s NAME\n",
  1429. #endif
  1430.           long_format_listing ? " PACKED " : "", /* 8,0 */
  1431.           long_format_listing ? "  CRC" : "", /* 5,0 */
  1432.           long_format_listing ? "  " : "", /* 2,0 */
  1433.           long_format_listing ? "   " : ""); /* 3,0 */
  1434.       print_bar ();
  1435.     }
  1436.  
  1437.   while (get_header (fp, &hdr))
  1438.     {
  1439.       if (need_file (hdr.name))
  1440.     {
  1441.       if (hdr.extend_type == EXTEND_UNIX)
  1442.             {
  1443. #ifndef STRICT
  1444.               printf ("%c%c%c%c%c%c%c%c%c%4d/%-4d",
  1445.           ((hdr.unix_mode & UNIX_OWNER_READ_PERM)  ? 'r' : '-'),
  1446.           ((hdr.unix_mode & UNIX_OWNER_WRITE_PERM) ? 'w' : '-'),
  1447.           ((hdr.unix_mode & UNIX_OWNER_EXEC_PERM)  ? 'x' : '-'),
  1448.           ((hdr.unix_mode & UNIX_GROUP_READ_PERM)  ? 'r' : '-'),
  1449.           ((hdr.unix_mode & UNIX_GROUP_WRITE_PERM) ? 'w' : '-'),
  1450.           ((hdr.unix_mode & UNIX_GROUP_EXEC_PERM)  ? 'x' : '-'),
  1451.           ((hdr.unix_mode & UNIX_OTHER_READ_PERM)  ? 'r' : '-'),
  1452.           ((hdr.unix_mode & UNIX_OTHER_WRITE_PERM) ? 'w' : '-'),
  1453.           ((hdr.unix_mode & UNIX_OTHER_EXEC_PERM)  ? 'x' : '-'),
  1454.           hdr.unix_uid, hdr.unix_gid);
  1455. #endif
  1456.         }
  1457.       else
  1458.         {
  1459.           switch (hdr.extend_type)
  1460.         {            /* max 18 characters */
  1461.                 case EXTEND_GENERIC:    p = "[Generic]"; break;
  1462.  
  1463.         case EXTEND_CPM:    p = "[CP/M]"; break;
  1464.  
  1465.           /* OS-9 and FLEX's CPU is MC-6809. I like it. :-)  */
  1466.         case EXTEND_FLEX:    p = "[FLEX]"; break;
  1467.  
  1468.         case EXTEND_OS9:    p = "[OS-9]"; break;
  1469.  
  1470.           /* I guessed from this ID.  Is this right? */
  1471.         case EXTEND_OS68K:    p = "[OS-9/68K]"; break;
  1472.  
  1473.         case EXTEND_MSDOS:    p = "[MS-DOS]"; break;
  1474.  
  1475.           /* I have Macintosh. :-)  */
  1476.         case EXTEND_MACOS:    p = "[Mac OS]"; break;
  1477.  
  1478.         case EXTEND_OS2:    p = "[OS/2]"; break;
  1479.  
  1480.         case EXTEND_HUMAN:    p = "[Human68K]"; break;
  1481.  
  1482.         case EXTEND_OS386:    p = "[OS-386]"; break;
  1483.  
  1484. #ifdef EXTEND_TOWNSOS
  1485.           /* This ID isn't fixed */
  1486.         case EXTEND_TOWNSOS:    p = "[TownsOS]"; break;
  1487. #endif
  1488.  
  1489.           /* Ouch!  Please customize it's ID.  */
  1490.                 default:                p = "[Unknown]"; break;
  1491.                 }
  1492. #ifndef STRICT
  1493.               printf ("%-18.18s", p);
  1494. #endif
  1495.         }
  1496.  
  1497.       print_size (hdr.packed_size, hdr.original_size);
  1498.  
  1499.       if (long_format_listing)
  1500.         if (hdr.has_crc)
  1501.           printf (" %04x", hdr.crc);
  1502.         else
  1503.           printf (" ****");
  1504.  
  1505.       printf (" ");
  1506.       print_stamp (hdr.unix_last_modified_stamp);
  1507.       printf (" %s\n", hdr.name);
  1508.       n_files ++;
  1509.       a_packed_size += hdr.packed_size;
  1510.       a_original_size += hdr.original_size;
  1511.     }
  1512.       fseek (fp, hdr.packed_size, SEEK_CUR);
  1513.     }
  1514.  
  1515.   fclose (fp);
  1516.   if (!quiet)
  1517.     {
  1518.       print_bar ();
  1519.  
  1520. #ifndef STRICT
  1521.       printf (" Total %4d file%c ",
  1522.           n_files, (n_files == 1) ? ' ' : 's');
  1523. #endif
  1524.       print_size (a_packed_size, a_original_size);
  1525.       printf (" ");
  1526.  
  1527.       if (long_format_listing)
  1528.     printf ("     ");
  1529.  
  1530.       if (stat (archive_name, &v_stat) < 0)
  1531.     print_stamp ((time_t)0);
  1532.       else
  1533.     print_stamp (v_stat.st_mtime);
  1534.  
  1535. #ifdef STRICT
  1536.       printf (" %4d file%c ",
  1537.           n_files, (n_files == 1) ? ' ' : 's');
  1538. #endif
  1539.       printf ("\n");
  1540.     }
  1541.  
  1542.   return;
  1543. }
  1544.  
  1545.  
  1546. boolean make_parent_path (name)
  1547.      char *name;
  1548. {
  1549.   char        path[FILENAME_LENGTH];
  1550.   struct stat    v_stat;
  1551.   register char    *p;
  1552.  
  1553.  /* make parent directory name into PATH for recursive call */
  1554.   strcpy (path, name);
  1555.   for (p = path + strlen (path); p > path; p --)
  1556.     if (p[-1] == '/' || p[-1] == '\\')
  1557.       {
  1558.     p[-1] = '\0';
  1559.     break;
  1560.       }
  1561.  
  1562.   if (p == path)
  1563.     return FALSE;        /* no more parent. */
  1564.  
  1565.   if (stat (path, &v_stat) >= 0)
  1566.     {
  1567.       if ((v_stat.st_mode & S_IFMT) != S_IFDIR)
  1568.     return FALSE;        /* already exist. but it isn't directory. */
  1569.       return TRUE;        /* already exist its directory. */
  1570.     }
  1571.  
  1572.   errno = 0;
  1573.  
  1574.   if (!quiet)
  1575.     message ("Making Directory", path);
  1576.  
  1577.   if (mkdir (path, 0777) >= 0)    /* try */
  1578.     return TRUE;        /* successful done. */
  1579.  
  1580.   errno = 0;
  1581.  
  1582.   if (!make_parent_path (path))
  1583.     return FALSE;
  1584.  
  1585.   if (mkdir (path, 0777) < 0)        /* try again */
  1586.     return FALSE;
  1587.  
  1588.   return TRUE;
  1589. }
  1590.  
  1591. FILE *open_with_make_path (name)
  1592.      char *name;
  1593. {
  1594.   FILE        *fp;
  1595.   struct stat    v_stat;
  1596.   char        buffer[1024];
  1597.  
  1598.   if (stat (name, &v_stat) >= 0)
  1599.     {
  1600.       if ((v_stat.st_mode & S_IFMT) != S_IFREG)
  1601.     return NULL;
  1602.  
  1603.       if (!force)
  1604.     {
  1605.       for (;;)
  1606.         {
  1607.           fprintf (stderr, "%s OverWrite ?(Yes/No/All) ", name);
  1608.           fflush (stderr);
  1609.           gets (buffer);
  1610.           if (buffer[0] == 'N' || buffer[0] == 'n')
  1611.         return NULL;
  1612.           if (buffer[0] == 'Y' || buffer[0] == 'y')
  1613.         break;
  1614.           if (buffer[0] == 'A' || buffer[0] == 'a')
  1615.         {
  1616.           force = TRUE;
  1617.           break;
  1618.         }
  1619.         }
  1620.     }
  1621.     }
  1622.  
  1623.   fp = fopen (name, WMODE);
  1624.   if (!fp)
  1625.     {
  1626.       errno = 0;
  1627.       if (!make_parent_path (name))
  1628.     return NULL;
  1629.  
  1630.       fp = fopen (name, WMODE);
  1631.       if (!fp)
  1632.         message ("Error:", name);
  1633.     }
  1634.   return fp;
  1635. }
  1636.  
  1637. #ifdef MSDOS
  1638. void dosname(char *name)
  1639. {
  1640.   char *ptr, *first = NULL, *last = NULL;
  1641.   char temp[8];
  1642.  
  1643.   for ( ptr = strchr(name, 0); ptr >= name; ptr-- )
  1644.     if ( *ptr == '.' )
  1645.     {
  1646.       if ( last == NULL )
  1647.         last = ptr;
  1648.     }
  1649.     else if ( (*ptr == '/') || (*ptr == '\\') )
  1650.     {
  1651.       first = ptr + 1;
  1652.       break;
  1653.     }
  1654.  
  1655.   if ( first == NULL )
  1656.     first = name;
  1657.   if ( last == NULL )
  1658.     last = strchr(name, 0);
  1659.  
  1660.   for ( ptr = first; ptr < last; ptr++ )
  1661.     if ( *ptr == '.' )
  1662.       *ptr = '_';
  1663.  
  1664.   if ( strlen(last) > 4 )
  1665.     last[4] = 0;
  1666.  
  1667.   if ( last - first > 8 )
  1668.   {
  1669.     strcpy(temp, last);
  1670.     strcpy(first + 8, last);
  1671.   }
  1672. }
  1673. #endif
  1674.  
  1675. extern int decode_lzhuf (), decode_larc ();
  1676. extern int decode_stored_crc (), decode_stored_nocrc ();
  1677.  
  1678. extract_one (fp, hdr)
  1679.      FILE *fp;
  1680.      LzHeader *hdr;
  1681. {
  1682.   FILE        *ofp;        /* output file */
  1683.   char        name[1024];
  1684.   time_t    utimebuf[2];
  1685.   int        crc;
  1686.   int        (*decode_proc)(); /* (ifp,ofp,original_size,name) */
  1687.   int        save_quiet;
  1688.  
  1689.   strcpy (name, hdr->name);
  1690.   if ((hdr->unix_mode & UNIX_FILE_TYPEMASK) == UNIX_FILE_REGULAR)
  1691.     {
  1692.       if (bcmp (hdr->method, LZHUFF1_METHOD, METHOD_TYPE_STRAGE) == 0)
  1693.     decode_proc = decode_lzhuf;
  1694.       else if ((bcmp (hdr->method, LZHUFF0_METHOD, METHOD_TYPE_STRAGE) == 0) ||
  1695.            (bcmp (hdr->method, LARC4_METHOD, METHOD_TYPE_STRAGE) == 0))
  1696.     decode_proc = (hdr->has_crc) ? decode_stored_crc : decode_stored_nocrc;
  1697.       else if (bcmp (hdr->method, LARC5_METHOD, METHOD_TYPE_STRAGE) == 0)
  1698.     decode_proc = decode_larc;
  1699.       else
  1700.         message ("Error:", "Sorry, Cannot Extract this method.");
  1701.  
  1702.       reading_filename = archive_name;
  1703.       writting_filename = name;
  1704.       if (output_to_stdout)
  1705.     {
  1706.           if (!quiet)
  1707.             printf ("::::::::\r\n%s\r\n::::::::\r\n", name);
  1708.  
  1709.           if ( strlen(pager) != 0 )
  1710.             ofp = popen(pager, WMODE);
  1711.           else
  1712.             ofp = stdout;
  1713.  
  1714.       save_quiet = quiet;
  1715.           quiet = TRUE;
  1716.           crc = (*decode_proc) (fp, ofp, hdr->original_size, name);
  1717.           quiet = save_quiet;
  1718.  
  1719.           if ( strlen(pager) != 0 )
  1720.             pclose(ofp);
  1721.     }
  1722.       else if (output_to_test)
  1723.         {
  1724.           ofp = fopen(NULLFILE, WMODE);
  1725.           crc = (*decode_proc) (fp, ofp, hdr->original_size, name);
  1726.           fclose(ofp);
  1727.         }
  1728.       else
  1729.         {
  1730. #ifdef MSDOS
  1731.           dosname(name);
  1732. #endif
  1733.       if ((ofp = open_with_make_path (name)) == NULL)
  1734.         return;
  1735.       else
  1736.         {
  1737.           crc = (*decode_proc) (fp, ofp, hdr->original_size, name);
  1738.           fclose (ofp);
  1739.         }
  1740.     }
  1741.  
  1742.       if (hdr->has_crc && (crc != hdr->crc))
  1743.         if (output_to_test)
  1744.           message ("Error:", "CRC failed\a");
  1745.         else
  1746.           error ("CRC failed\a");
  1747.     }
  1748.   else
  1749.     {
  1750.       /* NAME has trailing SLASH '/', (^_^) */
  1751.       if (!output_to_stdout &&
  1752.       !make_parent_path (name))
  1753.     error (name);
  1754.     }
  1755.  
  1756.   if (!output_to_stdout && !output_to_test)
  1757.     {
  1758.       utimebuf[0] = utimebuf[1] = hdr->unix_last_modified_stamp;
  1759.       utime (name, utimebuf);
  1760.  
  1761. #ifdef NOT_COMPATIBLE_MODE
  1762.       setfilemode(name, hdr->attribute);
  1763. #else
  1764.       chmod (name, hdr->unix_mode);
  1765. #endif
  1766.  
  1767. #ifndef MSDOS
  1768.       chown (name, hdr->unix_uid, hdr->unix_gid);
  1769. #endif
  1770.       errno = 0;
  1771.     }
  1772. }
  1773.  
  1774.  
  1775. /*
  1776.   extract
  1777.  */
  1778. cmd_extract ()
  1779. {
  1780.   LzHeader    hdr;
  1781.   long        pos;
  1782.   FILE        *fp;
  1783.  
  1784.   if ((fp = fopen (archive_name, RMODE)) == NULL)
  1785.     if (!expand_archive_name (expanded_archive_name, archive_name))
  1786.       error (archive_name);
  1787.     else
  1788.       {
  1789.     errno = 0;
  1790.         fp = xfopen (expanded_archive_name, RMODE);
  1791.     archive_name = expanded_archive_name;
  1792.       }
  1793.  
  1794.   if (archive_is_msdos_sfx1 (archive_name))
  1795.     {
  1796.       skip_msdos_sfx1_code (fp);
  1797.     }
  1798.  
  1799.   while (get_header (fp, &hdr))
  1800.     {
  1801.       if (need_file (hdr.name))
  1802.     {
  1803.       pos = ftell (fp);
  1804.       extract_one (fp, &hdr);
  1805.       fseek (fp, pos + hdr.packed_size, SEEK_SET);
  1806.     } else {
  1807.       fseek (fp, hdr.packed_size, SEEK_CUR);
  1808.     }
  1809.     }
  1810.  
  1811.   fclose (fp);
  1812.  
  1813.   return;
  1814. }
  1815.  
  1816. /*----------------------------------------------------------------------*/
  1817. /*                                    */
  1818. /*----------------------------------------------------------------------*/
  1819.  
  1820. extern int encode_lzhuf ();
  1821. extern int encode_storerd_crc ();
  1822.  
  1823. append_one (fp, nafp, hdr)
  1824.      FILE *fp, *nafp;
  1825.      LzHeader *hdr;
  1826. {
  1827.   long    header_pos, next_pos, org_pos, data_pos;
  1828.   long    v_original_size, v_packed_size;
  1829.  
  1830.   reading_filename = hdr->name;
  1831.   writting_filename = temporary_name;
  1832.  
  1833.   org_pos = ftell (fp);
  1834.   header_pos = ftell (nafp);
  1835.   write_header (nafp, hdr);    /* DUMMY */
  1836.  
  1837.   if (hdr->original_size == 0)
  1838.     return;            /* previous write_header is not DUMMY. (^_^) */
  1839.  
  1840.   data_pos = ftell (nafp);
  1841.   hdr->crc = encode_lzhuf (fp, nafp, hdr->original_size,
  1842.                &v_original_size, &v_packed_size, hdr->name);
  1843.   if (v_packed_size < v_original_size)
  1844.     {
  1845.       next_pos = ftell (nafp);
  1846.     }
  1847.   else
  1848.     {                /* retry by stored method */
  1849.       fseek (fp, org_pos, SEEK_SET);
  1850.       fseek (nafp, data_pos, SEEK_SET);
  1851.       hdr->crc = encode_stored_crc (fp, nafp, hdr->original_size,
  1852.                     &v_original_size, &v_packed_size);
  1853.       fflush (nafp);
  1854.       next_pos = ftell (nafp);
  1855.       ftruncate (fileno (nafp), next_pos);
  1856.       bcopy (LZHUFF0_METHOD, hdr->method, METHOD_TYPE_STRAGE);
  1857.     }
  1858.   hdr->original_size = v_original_size;
  1859.   hdr->packed_size = v_packed_size;
  1860.   fseek (nafp, header_pos, SEEK_SET);
  1861.   write_header (nafp, hdr);
  1862.   fseek (nafp, next_pos, SEEK_SET);
  1863. }
  1864.  
  1865. write_tail (nafp)
  1866.      FILE *nafp;
  1867. {
  1868.   putc (0x00, nafp);
  1869. }
  1870.  
  1871. copy_old_one (oafp, nafp, hdr)
  1872.      FILE *oafp, *nafp;
  1873.      LzHeader *hdr;
  1874. {
  1875.   if (noexec)
  1876.     {
  1877.       fseek (oafp, (long)(hdr->header_size + 2) + hdr->packed_size, SEEK_CUR);
  1878.     }
  1879.   else
  1880.     {
  1881.       reading_filename = archive_name;
  1882.       writting_filename = temporary_name;
  1883.       copy_file (oafp, nafp, (long)(hdr->header_size + 2) + hdr->packed_size);
  1884.     }
  1885. }
  1886.  
  1887.  
  1888. FILE *append_it (name, oafp, nafp)
  1889.      char *name;
  1890.      FILE *oafp, *nafp;
  1891. {
  1892.   LzHeader    ahdr, hdr;
  1893.   FILE        *fp;
  1894.   long        old_header;
  1895.   int        cmp;
  1896.   int        filec;
  1897.   char        **filev;
  1898.   int        i;
  1899.  
  1900.   struct stat    v_stat;
  1901.   boolean    directory;
  1902.  
  1903.   if (!delete_from_archive)
  1904.     if (stat (name, &v_stat) < 0)
  1905.       {
  1906.         message ("Error:", name);
  1907.         return oafp;
  1908.       }
  1909.  
  1910.   directory = ((v_stat.st_mode & S_IFMT) == S_IFDIR);
  1911.  
  1912.   init_header (name, &v_stat, &hdr);
  1913.  
  1914.   if (!delete_from_archive && !directory && !noexec)
  1915.     fp = xfopen (name, RMODE);
  1916.  
  1917.   while (oafp)
  1918.     {
  1919.       old_header = ftell (oafp);
  1920.       if (!get_header (oafp, &ahdr))
  1921.     {
  1922.       fclose (oafp);
  1923.       oafp = NULL;
  1924.       break;
  1925.     }
  1926.       else
  1927.     {
  1928.       cmp = STRING_COMPARE (ahdr.name, hdr.name);
  1929.       if (cmp < 0)
  1930.         {        /* SKIP */
  1931.           fseek (oafp, old_header, SEEK_SET);
  1932.           copy_old_one (oafp, nafp, &ahdr);
  1933.         }
  1934.       else if (cmp == 0)
  1935.         {        /* REPLACE */
  1936.           fseek (oafp, ahdr.packed_size, SEEK_CUR);
  1937.           break;
  1938.         }
  1939.       else        /* cmp > 0, INSERT */
  1940.         {
  1941.           fseek (oafp, old_header, SEEK_SET);
  1942.           break;
  1943.         }
  1944.     }
  1945.     }
  1946.  
  1947.   if (delete_from_archive)
  1948.     {
  1949.       if (noexec)
  1950.         fprintf (stderr, "DELETE %s\n", name);
  1951.       else
  1952.         printf ("%s - Deleted\n", name);
  1953.     }
  1954.   else
  1955.     {
  1956.       if ( !oafp || (cmp > 0) || !update_if_newer
  1957.            || (ahdr.unix_last_modified_stamp < hdr.unix_last_modified_stamp) )
  1958.     {
  1959.       if (noexec)
  1960.         fprintf (stderr, "APPEND %s\n", name);
  1961.           else
  1962. #ifdef STRICT
  1963.             if ( !directory )
  1964. #endif
  1965.               if ( !update_freshen || (cmp == 0) )
  1966.                 append_one (fp, nafp, &hdr);
  1967.     }
  1968.       else
  1969.     {                    /* archive has old one */
  1970.       fseek (oafp, old_header, SEEK_SET);
  1971.       copy_old_one (oafp, nafp, &ahdr);
  1972.     }
  1973.  
  1974.       if (!directory)
  1975.     {
  1976.       if (!noexec)
  1977.         fclose (fp);
  1978.     }
  1979.       else
  1980.     {            /* recurcive call */
  1981.       if (find_files (name, &filec, &filev))
  1982.         {
  1983.           for (i = 0; i < filec; i ++)
  1984.         oafp = append_it (filev[i], oafp, nafp);
  1985.           free_files (filec, filev);
  1986.         }
  1987.       return oafp;
  1988.     }
  1989.     }
  1990.  
  1991.   return oafp;
  1992. }
  1993.  
  1994.  
  1995. remove_it (name)
  1996.      char *name;
  1997. {
  1998.   struct stat    v_stat;
  1999.   int        i;
  2000.   char        **filev;
  2001.   int        filec;
  2002.  
  2003.   if (stat (name, &v_stat) < 0)
  2004.     {
  2005.       fprintf (stderr, "Cannot access \"%s\".\n", name);
  2006.       return;
  2007.     }
  2008.  
  2009.   if ((v_stat.st_mode & S_IFMT) == S_IFDIR)
  2010.     {
  2011.       if (!find_files (name, &filec, &filev))
  2012.     {
  2013.           fprintf (stderr, "Cannot open directory \"%s\".\n", name);
  2014.       return;
  2015.     }
  2016.  
  2017.       for (i = 0; i < filec; i ++)
  2018.     remove_it (filev[i]);
  2019.  
  2020.       free_files (filec, filev);
  2021.  
  2022.       if (noexec)
  2023.         printf ("REMOVE DIR %s\n", name);
  2024.       else if (rmdir (name) < 0)
  2025.         fprintf (stderr, "Cannot remove directory \"%s\".\n", name);
  2026.       else if (!quiet)
  2027.         printf ("%s - Removed\n", name);
  2028.     }
  2029.   else
  2030.     {
  2031.       if (noexec)
  2032.         printf ("REMOVE %s\n", name);
  2033.       else if (unlink (name) < 0)
  2034.         fprintf (stderr, "Cannot delete \"%s\".\n", name);
  2035.       else if (!quiet)
  2036.         printf ("%s - Removed\n", name);
  2037.     }
  2038. }
  2039.  
  2040. #ifdef FASTCOPY
  2041. #define BUFFER_SIZE 16384
  2042.  
  2043. #ifndef O_BINARY
  2044. #define O_BINARY 0
  2045. #endif
  2046.  
  2047. copy_archive(src,dst )
  2048. char *src;
  2049. char *dst;
  2050. {
  2051.   int ih, oh;
  2052.   unsigned chunk;
  2053.   char *buffer = (char *) rson;
  2054.  
  2055.   printf ("Copying temp to archive ... ");
  2056.  
  2057.   ih = open (src, O_RDONLY | O_BINARY);
  2058.   if ( ih == -1 )
  2059.     error(src);
  2060.   oh = open (dst, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC, S_IREAD | S_IWRITE);
  2061.   if ( oh == -1 )
  2062.     error(dst);
  2063.  
  2064.   while ( (chunk = read(ih, buffer, BUFFER_SIZE)) > 0 )
  2065.     if ( write(oh, buffer, chunk) != chunk )
  2066.       error(dst);
  2067.  
  2068.   close (ih);
  2069.   close (oh);
  2070.  
  2071.   printf("\b\b\b\b   \b\b\b\b.\n");
  2072. }
  2073. #endif
  2074.  
  2075. cmd_append ()
  2076. {
  2077.   LzHeader    ahdr;
  2078.   FILE        *oafp, *nafp;
  2079.   char        backup_archive_name [ FILENAME_LENGTH ];
  2080.   char        new_archive_name_buffer [ FILENAME_LENGTH ];
  2081.   char        *new_archive_name;
  2082.   int        i;
  2083.   long        old_header;
  2084.   struct stat    v_stat;
  2085.   boolean    old_archive_exist;
  2086.   extern    rename();
  2087.  
  2088.   if (cmd_filec == 0)
  2089.     return;
  2090.  
  2091.   make_tmp_name (archive_name, temporary_name);
  2092.  
  2093.   if ((oafp = fopen (archive_name, RMODE)) == NULL)
  2094.     if (expand_archive_name (expanded_archive_name, archive_name))
  2095.       {
  2096.     errno = 0;
  2097.         oafp = fopen (expanded_archive_name, RMODE);
  2098.     archive_name = expanded_archive_name;
  2099.       }
  2100.  
  2101.   old_archive_exist = (oafp) ? TRUE : FALSE;
  2102.   if (new_archive && oafp)
  2103.     {
  2104.       fclose (oafp);
  2105.       oafp = NULL;
  2106.     }
  2107.  
  2108.   if (oafp && archive_is_msdos_sfx1 (archive_name))
  2109.     {
  2110.       skip_msdos_sfx1_code (oafp);
  2111.       make_standard_archive_name (new_archive_name_buffer, archive_name);
  2112.       new_archive_name = new_archive_name_buffer;
  2113.     }
  2114.   else
  2115.     {
  2116.       new_archive_name = archive_name;
  2117.     }
  2118.  
  2119.   errno = 0;
  2120.   if (!noexec)
  2121.     {
  2122.       nafp = xfopen (temporary_name, WMODE);
  2123.       remove_temporary_at_error = TRUE;
  2124.     }
  2125.  
  2126.   for (i = 0; i < cmd_filec; i ++)
  2127.     oafp = append_it (cmd_filev[i], oafp, nafp);
  2128.  
  2129.   if (oafp)
  2130.     {
  2131.       old_header = ftell (oafp);
  2132.       while (get_header (oafp, &ahdr))
  2133.     {
  2134.       fseek (oafp, old_header, SEEK_SET);
  2135.       copy_old_one (oafp, nafp, &ahdr);
  2136.       old_header = ftell (oafp);
  2137.     }
  2138.       fclose (oafp);
  2139.     }
  2140.  
  2141.   if (!noexec)
  2142.     {
  2143.       write_tail (nafp);
  2144.       fclose (nafp);
  2145.     }
  2146.  
  2147.   make_backup_name (backup_archive_name, archive_name);
  2148.  
  2149.   if (!noexec && old_archive_exist)
  2150.   {
  2151. #ifdef ORIGINAL
  2152.     if (rename(archive_name, backup_archive_name) < 0)
  2153.       error (archive_name);
  2154.     unlink(backup_archive_name);
  2155. #endif
  2156.   }
  2157.  
  2158.   if (!quiet && new_archive_name == new_archive_name_buffer)
  2159.     {                /* warning at old archive is SFX */
  2160.       printf ("New Archive File is \"%s\"\n", new_archive_name);
  2161.     }
  2162.  
  2163. #ifdef ORIGINAL
  2164.   if (!noexec && rename(temporary_name, new_archive_name) < 0)
  2165. #endif
  2166.  
  2167.     {
  2168.  
  2169.       if (stat (temporary_name, &v_stat) < 0)
  2170.     error (temporary_name);
  2171. #ifdef FASTCOPY
  2172.       copy_archive(temporary_name, archive_name);
  2173. #else
  2174.       oafp = xfopen (temporary_name, RMODE);
  2175.       nafp = xfopen (archive_name, WMODE);
  2176.       reading_filename = temporary_name;
  2177.       writting_filename = archive_name;
  2178.       copy_file (oafp, nafp, (long)v_stat.st_size);
  2179.       fclose (nafp);
  2180.       fclose (oafp);
  2181. #endif
  2182.  
  2183.       unlink (temporary_name);
  2184.     }
  2185.   remove_temporary_at_error = FALSE;
  2186.  
  2187.   if (delete_after_append)
  2188.     {
  2189.       if (!quiet && !noexec)
  2190.     printf ("Erasing...\n");
  2191.       for (i = 0; i < cmd_filec; i ++)
  2192.     remove_it (cmd_filev[i]);
  2193.     }
  2194.  
  2195.   return;
  2196. }
  2197.