Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.   Copyright (c) 1990-2009 Info-ZIP.  All rights reserved.
  3.  
  4.   See the accompanying file LICENSE, version 2009-Jan-02 or later
  5.   (the contents of which are also included in unzip.h) for terms of use.
  6.   If, for some reason, all these files are missing, the Info-ZIP license
  7.   also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
  8. */
  9. /*---------------------------------------------------------------------------
  10.  
  11.   unix.c
  12.  
  13.   Unix-specific routines for use with Info-ZIP's UnZip 5.41 and later.
  14.  
  15.   Contains:  readdir()
  16.              do_wild()           <-- generic enough to put in fileio.c?
  17.              mapattr()
  18.              mapname()
  19.              checkdir()
  20.              mkdir()
  21.              close_outfile()
  22.              defer_dir_attribs()
  23.              set_direc_attribs()
  24.              stamp_file()
  25.              version()
  26.  
  27.   ---------------------------------------------------------------------------*/
  28.  
  29.  
  30. #define UNZIP_INTERNAL
  31. #include "unzip.h"
  32.  
  33. #ifdef SCO_XENIX
  34. #  define SYSNDIR
  35. #else  /* SCO Unix, AIX, DNIX, TI SysV, Coherent 4.x, ... */
  36. #  if defined(__convexc__) || defined(SYSV) || defined(CRAY) || defined(BSD4_4)
  37. #    define DIRENT
  38. #  endif
  39. #endif
  40. #if defined(_AIX) || defined(__mpexl)
  41. #  define DIRENT
  42. #endif
  43. #ifdef COHERENT
  44. #  if defined(_I386) || (defined(__COHERENT__) && (__COHERENT__ >= 0x420))
  45. #    define DIRENT
  46. #  endif
  47. #endif
  48.  
  49. #ifdef _POSIX_VERSION
  50. #  ifndef DIRENT
  51. #    define DIRENT
  52. #  endif
  53. #endif
  54.  
  55. #ifdef DIRENT
  56. #  include <dirent.h>
  57. #else
  58. #  ifdef SYSV
  59. #    ifdef SYSNDIR
  60. #      include <sys/ndir.h>
  61. #    else
  62. #      include <ndir.h>
  63. #    endif
  64. #  else /* !SYSV */
  65. #    ifndef NO_SYSDIR
  66. #      include <sys/dir.h>
  67. #    endif
  68. #  endif /* ?SYSV */
  69. #  ifndef dirent
  70. #    define dirent direct
  71. #  endif
  72. #endif /* ?DIRENT */
  73.  
  74. #ifdef SET_DIR_ATTRIB
  75. typedef struct uxdirattr {      /* struct for holding unix style directory */
  76.     struct uxdirattr *next;     /*  info until can be sorted and set at end */
  77.     char *fn;                   /* filename of directory */
  78.     union {
  79.         iztimes t3;             /* mtime, atime, ctime */
  80.         ztimbuf t2;             /* modtime, actime */
  81.     } u;
  82.     unsigned perms;             /* same as min_info.file_attr */
  83.     int have_uidgid;            /* flag */
  84.     ulg uidgid[2];
  85.     char fnbuf[1];              /* buffer stub for directory name */
  86. } uxdirattr;
  87. #define UxAtt(d)  ((uxdirattr *)d)    /* typecast shortcut */
  88. #endif /* SET_DIR_ATTRIB */
  89.  
  90. #ifdef ACORN_FTYPE_NFS
  91. /* Acorn bits for NFS filetyping */
  92. typedef struct {
  93.   uch ID[2];
  94.   uch size[2];
  95.   uch ID_2[4];
  96.   uch loadaddr[4];
  97.   uch execaddr[4];
  98.   uch attr[4];
  99. } RO_extra_block;
  100.  
  101. #endif /* ACORN_FTYPE_NFS */
  102.  
  103. /* static int created_dir;      */      /* used in mapname(), checkdir() */
  104. /* static int renamed_fullpath; */      /* ditto */
  105.  
  106. static unsigned filtattr OF((__GPRO__ unsigned perms));
  107.  
  108.  
  109. /*****************************/
  110. /* Strings used multiple     */
  111. /* times in unix.c           */
  112. /*****************************/
  113.  
  114. #ifndef MTS
  115. /* messages of code for setting file/directory attributes */
  116. static ZCONST char CannotSetItemUidGid[] =
  117.   "warning:  cannot set UID %lu and/or GID %lu for %s\n          %s\n";
  118. static ZCONST char CannotSetUidGid[] =
  119.   " (warning) cannot set UID %lu and/or GID %lu\n          %s";
  120. static ZCONST char CannotSetItemTimestamps[] =
  121.   "warning:  cannot set modif./access times for %s\n          %s\n";
  122. static ZCONST char CannotSetTimestamps[] =
  123.   " (warning) cannot set modif./access times\n          %s";
  124. #endif /* !MTS */
  125.  
  126.  
  127. #ifndef SFX
  128. #ifdef NO_DIR                  /* for AT&T 3B1 */
  129.  
  130. #define opendir(path) fopen(path,"r")
  131. #define closedir(dir) fclose(dir)
  132. typedef FILE DIR;
  133. typedef struct zdir {
  134.     FILE *dirhandle;
  135.     struct dirent *entry;
  136. } DIR
  137. DIR *opendir OF((ZCONST char *dirspec));
  138. void closedir OF((DIR *dirp));
  139. struct dirent *readdir OF((DIR *dirp));
  140.  
  141. DIR *opendir(dirspec)
  142.     ZCONST char *dirspec;
  143. {
  144.     DIR *dirp;
  145.  
  146.     if ((dirp = malloc(sizeof(DIR)) != NULL) {
  147.         if ((dirp->dirhandle = fopen(dirspec, "r")) == NULL) {
  148.             free(dirp);
  149.             dirp = NULL;
  150.         }
  151.     }
  152.     return dirp;
  153. }
  154.  
  155. void closedir(dirp)
  156.     DIR *dirp;
  157. {
  158.     fclose(dirp->dirhandle);
  159.     free(dirp);
  160. }
  161.  
  162. /*
  163.  *  Apparently originally by Rich Salz.
  164.  *  Cleaned up and modified by James W. Birdsall.
  165.  */
  166. struct dirent *readdir(dirp)
  167.     DIR *dirp;
  168. {
  169.  
  170.     if (dirp == NULL)
  171.         return NULL;
  172.  
  173.     for (;;)
  174.         if (fread(&(dirp->entry), sizeof (struct dirent), 1,
  175.                   dirp->dirhandle) == 0)
  176.             return (struct dirent *)NULL;
  177.         else if ((dirp->entry).d_ino)
  178.             return &(dirp->entry);
  179.  
  180. } /* end function readdir() */
  181.  
  182. #endif /* NO_DIR */
  183.  
  184.  
  185. /**********************/
  186. /* Function do_wild() */   /* for porting: dir separator; match(ignore_case) */
  187. /**********************/
  188.  
  189. char *do_wild(__G__ wildspec)
  190.     __GDEF
  191.     ZCONST char *wildspec;  /* only used first time on a given dir */
  192. {
  193. /* these statics are now declared in SYSTEM_SPECIFIC_GLOBALS in unxcfg.h:
  194.     static DIR *wild_dir = (DIR *)NULL;
  195.     static ZCONST char *wildname;
  196.     static char *dirname, matchname[FILNAMSIZ];
  197.     static int notfirstcall=FALSE, have_dirname, dirnamelen;
  198. */
  199.     struct dirent *file;
  200.  
  201.     /* Even when we're just returning wildspec, we *always* do so in
  202.      * matchname[]--calling routine is allowed to append four characters
  203.      * to the returned string, and wildspec may be a pointer to argv[].
  204.      */
  205.     if (!G.notfirstcall) {  /* first call:  must initialize everything */
  206.         G.notfirstcall = TRUE;
  207.  
  208.         if (!iswild(wildspec)) {
  209.             strncpy(G.matchname, wildspec, FILNAMSIZ);
  210.             G.matchname[FILNAMSIZ-1] = '\0';
  211.             G.have_dirname = FALSE;
  212.             G.wild_dir = NULL;
  213.             return G.matchname;
  214.         }
  215.  
  216.         /* break the wildspec into a directory part and a wildcard filename */
  217.         if ((G.wildname = (ZCONST char *)strrchr(wildspec, '/')) == NULL) {
  218.             G.dirname = ".";
  219.             G.dirnamelen = 1;
  220.             G.have_dirname = FALSE;
  221.             G.wildname = wildspec;
  222.         } else {
  223.             ++G.wildname;     /* point at character after '/' */
  224.             G.dirnamelen = G.wildname - wildspec;
  225.             if ((G.dirname = (char *)malloc(G.dirnamelen+1)) == (char *)NULL) {
  226.                 Info(slide, 0x201, ((char *)slide,
  227.                   "warning:  cannot allocate wildcard buffers\n"));
  228.                 strncpy(G.matchname, wildspec, FILNAMSIZ);
  229.                 G.matchname[FILNAMSIZ-1] = '\0';
  230.                 return G.matchname; /* but maybe filespec was not a wildcard */
  231.             }
  232.             strncpy(G.dirname, wildspec, G.dirnamelen);
  233.             G.dirname[G.dirnamelen] = '\0';   /* terminate for strcpy below */
  234.             G.have_dirname = TRUE;
  235.         }
  236.  
  237.         if ((G.wild_dir = (zvoid *)opendir(G.dirname)) != (zvoid *)NULL) {
  238.             while ((file = readdir((DIR *)G.wild_dir)) !=
  239.                    (struct dirent *)NULL) {
  240.                 Trace((stderr, "do_wild:  readdir returns %s\n",
  241.                   FnFilter1(file->d_name)));
  242.                 if (file->d_name[0] == '.' && G.wildname[0] != '.')
  243.                     continue; /* Unix:  '*' and '?' do not match leading dot */
  244.                 if (match(file->d_name, G.wildname, 0 WISEP) &&/*0=case sens.*/
  245.                     /* skip "." and ".." directory entries */
  246.                     strcmp(file->d_name, ".") && strcmp(file->d_name, "..")) {
  247.                     Trace((stderr, "do_wild:  match() succeeds\n"));
  248.                     if (G.have_dirname) {
  249.                         strcpy(G.matchname, G.dirname);
  250.                         strcpy(G.matchname+G.dirnamelen, file->d_name);
  251.                     } else
  252.                         strcpy(G.matchname, file->d_name);
  253.                     return G.matchname;
  254.                 }
  255.             }
  256.             /* if we get to here directory is exhausted, so close it */
  257.             closedir((DIR *)G.wild_dir);
  258.             G.wild_dir = (zvoid *)NULL;
  259.         }
  260.         Trace((stderr, "do_wild:  opendir(%s) returns NULL\n",
  261.           FnFilter1(G.dirname)));
  262.  
  263.         /* return the raw wildspec in case that works (e.g., directory not
  264.          * searchable, but filespec was not wild and file is readable) */
  265.         strncpy(G.matchname, wildspec, FILNAMSIZ);
  266.         G.matchname[FILNAMSIZ-1] = '\0';
  267.         return G.matchname;
  268.     }
  269.  
  270.     /* last time through, might have failed opendir but returned raw wildspec */
  271.     if ((DIR *)G.wild_dir == (DIR *)NULL) {
  272.         G.notfirstcall = FALSE; /* nothing left--reset for new wildspec */
  273.         if (G.have_dirname)
  274.             free(G.dirname);
  275.         return (char *)NULL;
  276.     }
  277.  
  278.     /* If we've gotten this far, we've read and matched at least one entry
  279.      * successfully (in a previous call), so dirname has been copied into
  280.      * matchname already.
  281.      */
  282.     while ((file = readdir((DIR *)G.wild_dir)) != (struct dirent *)NULL) {
  283.         Trace((stderr, "do_wild:  readdir returns %s\n",
  284.           FnFilter1(file->d_name)));
  285.         if (file->d_name[0] == '.' && G.wildname[0] != '.')
  286.             continue;   /* Unix:  '*' and '?' do not match leading dot */
  287.         if (match(file->d_name, G.wildname, 0 WISEP)) { /* 0 == case sens. */
  288.             Trace((stderr, "do_wild:  match() succeeds\n"));
  289.             if (G.have_dirname) {
  290.                 /* strcpy(G.matchname, G.dirname); */
  291.                 strcpy(G.matchname+G.dirnamelen, file->d_name);
  292.             } else
  293.                 strcpy(G.matchname, file->d_name);
  294.             return G.matchname;
  295.         }
  296.     }
  297.  
  298.     closedir((DIR *)G.wild_dir);  /* at least one entry read; nothing left */
  299.     G.wild_dir = (zvoid *)NULL;
  300.     G.notfirstcall = FALSE;       /* reset for new wildspec */
  301.     if (G.have_dirname)
  302.         free(G.dirname);
  303.     return (char *)NULL;
  304.  
  305. } /* end function do_wild() */
  306.  
  307. #endif /* !SFX */
  308.  
  309.  
  310.  
  311.  
  312. #ifndef S_ISUID
  313. # define S_ISUID        0004000 /* set user id on execution */
  314. #endif
  315. #ifndef S_ISGID
  316. # define S_ISGID        0002000 /* set group id on execution */
  317. #endif
  318. #ifndef S_ISVTX
  319. # define S_ISVTX        0001000 /* save swapped text even after use */
  320. #endif
  321.  
  322. /************************/
  323. /*  Function filtattr() */
  324. /************************/
  325. /* This is used to clear or keep the SUID and SGID bits on file permissions.
  326.  * It's possible that a file in an archive could have one of these bits set
  327.  * and, unknown to the person unzipping, could allow others to execute the
  328.  * file as the user or group.  The new option -K bypasses this check.
  329.  */
  330.  
  331. static unsigned filtattr(__G__ perms)
  332.     __GDEF
  333.     unsigned perms;
  334. {
  335.     /* keep setuid/setgid/tacky perms? */
  336.     if (!uO.K_flag)
  337.         perms &= ~(S_ISUID | S_ISGID | S_ISVTX);
  338.  
  339.     return (0xffff & perms);
  340. } /* end function filtattr() */
  341.  
  342.  
  343.  
  344.  
  345.  
  346. /**********************/
  347. /* Function mapattr() */
  348. /**********************/
  349.  
  350. int mapattr(__G)
  351.     __GDEF
  352. {
  353.     int r;
  354.     ulg tmp = G.crec.external_file_attributes;
  355.  
  356.     G.pInfo->file_attr = 0;
  357.     /* initialized to 0 for check in "default" branch below... */
  358.  
  359.     switch (G.pInfo->hostnum) {
  360.         case AMIGA_:
  361.             tmp = (unsigned)(tmp>>17 & 7);   /* Amiga RWE bits */
  362.             G.pInfo->file_attr = (unsigned)(tmp<<6 | tmp<<3 | tmp);
  363.             break;
  364.         case THEOS_:
  365.             tmp &= 0xF1FFFFFFL;
  366.             if ((tmp & 0xF0000000L) != 0x40000000L)
  367.                 tmp &= 0x01FFFFFFL;     /* not a dir, mask all ftype bits */
  368.             else
  369.                 tmp &= 0x41FFFFFFL;     /* leave directory bit as set */
  370.             /* fall through! */
  371.         case UNIX_:
  372.         case VMS_:
  373.         case ACORN_:
  374.         case ATARI_:
  375.         case ATHEOS_:
  376.         case BEOS_:
  377.         case QDOS_:
  378.         case TANDEM_:
  379.             r = FALSE;
  380.             G.pInfo->file_attr = (unsigned)(tmp >> 16);
  381.             if (G.pInfo->file_attr == 0 && G.extra_field) {
  382.                 /* Some (non-Info-ZIP) implementations of Zip for Unix and
  383.                  * VMS (and probably others ??) leave 0 in the upper 16-bit
  384.                  * part of the external_file_attributes field. Instead, they
  385.                  * store file permission attributes in some extra field.
  386.                  * As a work-around, we search for the presence of one of
  387.                  * these extra fields and fall back to the MSDOS compatible
  388.                  * part of external_file_attributes if one of the known
  389.                  * e.f. types has been detected.
  390.                  * Later, we might implement extraction of the permission
  391.                  * bits from the VMS extra field. But for now, the work-around
  392.                  * should be sufficient to provide "readable" extracted files.
  393.                  * (For ASI Unix e.f., an experimental remap of the e.f.
  394.                  * mode value IS already provided!)
  395.                  */
  396.                 ush ebID;
  397.                 unsigned ebLen;
  398.                 uch *ef = G.extra_field;
  399.                 unsigned ef_len = G.crec.extra_field_length;
  400.  
  401.                 while (!r && ef_len >= EB_HEADSIZE) {
  402.                     ebID = makeword(ef);
  403.                     ebLen = (unsigned)makeword(ef+EB_LEN);
  404.                     if (ebLen > (ef_len - EB_HEADSIZE))
  405.                         /* discoverd some e.f. inconsistency! */
  406.                         break;
  407.                     switch (ebID) {
  408.                       case EF_ASIUNIX:
  409.                         if (ebLen >= (EB_ASI_MODE+2)) {
  410.                             G.pInfo->file_attr =
  411.                               (unsigned)makeword(ef+(EB_HEADSIZE+EB_ASI_MODE));
  412.                             /* force stop of loop: */
  413.                             ef_len = (ebLen + EB_HEADSIZE);
  414.                             break;
  415.                         }
  416.                         /* else: fall through! */
  417.                       case EF_PKVMS:
  418.                         /* "found nondecypherable e.f. with perm. attr" */
  419.                         r = TRUE;
  420.                       default:
  421.                         break;
  422.                     }
  423.                     ef_len -= (ebLen + EB_HEADSIZE);
  424.                     ef += (ebLen + EB_HEADSIZE);
  425.                 }
  426.             }
  427.             if (!r) {
  428. #ifdef SYMLINKS
  429.                 /* Check if the file is a (POSIX-compatible) symbolic link.
  430.                  * We restrict symlink support to those "made-by" hosts that
  431.                  * are known to support symbolic links.
  432.                  */
  433.                 G.pInfo->symlink = S_ISLNK(G.pInfo->file_attr) &&
  434.                                    SYMLINK_HOST(G.pInfo->hostnum);
  435. #endif
  436.                 return 0;
  437.             }
  438.             /* fall through! */
  439.         /* all remaining cases:  expand MSDOS read-only bit into write perms */
  440.         case FS_FAT_:
  441.             /* PKWARE's PKZip for Unix marks entries as FS_FAT_, but stores the
  442.              * Unix attributes in the upper 16 bits of the external attributes
  443.              * field, just like Info-ZIP's Zip for Unix.  We try to use that
  444.              * value, after a check for consistency with the MSDOS attribute
  445.              * bits (see below).
  446.              */
  447.             G.pInfo->file_attr = (unsigned)(tmp >> 16);
  448.             /* fall through! */
  449.         case FS_HPFS_:
  450.         case FS_NTFS_:
  451.         case MAC_:
  452.         case TOPS20_:
  453.         default:
  454.             /* Ensure that DOS subdir bit is set when the entry's name ends
  455.              * in a '/'.  Some third-party Zip programs fail to set the subdir
  456.              * bit for directory entries.
  457.              */
  458.             if ((tmp & 0x10) == 0) {
  459.                 extent fnlen = strlen(G.filename);
  460.                 if (fnlen > 0 && G.filename[fnlen-1] == '/')
  461.                     tmp |= 0x10;
  462.             }
  463.             /* read-only bit --> write perms; subdir bit --> dir exec bit */
  464.             tmp = !(tmp & 1) << 1  |  (tmp & 0x10) >> 4;
  465.             if ((G.pInfo->file_attr & 0700) == (unsigned)(0400 | tmp<<6)) {
  466.                 /* keep previous G.pInfo->file_attr setting, when its "owner"
  467.                  * part appears to be consistent with DOS attribute flags!
  468.                  */
  469. #ifdef SYMLINKS
  470.                 /* Entries "made by FS_FAT_" could have been zipped on a
  471.                  * system that supports POSIX-style symbolic links.
  472.                  */
  473.                 G.pInfo->symlink = S_ISLNK(G.pInfo->file_attr) &&
  474.                                    (G.pInfo->hostnum == FS_FAT_);
  475. #endif
  476.                 return 0;
  477.             }
  478.             G.pInfo->file_attr = (unsigned)(0444 | tmp<<6 | tmp<<3 | tmp);
  479.             break;
  480.     } /* end switch (host-OS-created-by) */
  481.  
  482.     /* for originating systems with no concept of "group," "other," "system": */
  483.     umask( (int)(tmp=umask(0)) );    /* apply mask to expanded r/w(/x) perms */
  484.     G.pInfo->file_attr &= ~tmp;
  485.  
  486.     return 0;
  487.  
  488. } /* end function mapattr() */
  489.  
  490.  
  491.  
  492.  
  493.  
  494. /************************/
  495. /*  Function mapname()  */
  496. /************************/
  497.  
  498. int mapname(__G__ renamed)
  499.     __GDEF
  500.     int renamed;
  501. /*
  502.  * returns:
  503.  *  MPN_OK          - no problem detected
  504.  *  MPN_INF_TRUNC   - caution (truncated filename)
  505.  *  MPN_INF_SKIP    - info "skip entry" (dir doesn't exist)
  506.  *  MPN_ERR_SKIP    - error -> skip entry
  507.  *  MPN_ERR_TOOLONG - error -> path is too long
  508.  *  MPN_NOMEM       - error (memory allocation failed) -> skip entry
  509.  *  [also MPN_VOL_LABEL, MPN_CREATED_DIR]
  510.  */
  511. {
  512.     char pathcomp[FILNAMSIZ];      /* path-component buffer */
  513.     char *pp, *cp=(char *)NULL;    /* character pointers */
  514.     char *lastsemi=(char *)NULL;   /* pointer to last semi-colon in pathcomp */
  515. #ifdef ACORN_FTYPE_NFS
  516.     char *lastcomma=(char *)NULL;  /* pointer to last comma in pathcomp */
  517.     RO_extra_block *ef_spark;      /* pointer Acorn FTYPE ef block */
  518. #endif
  519.     int killed_ddot = FALSE;       /* is set when skipping "../" pathcomp */
  520.     int error = MPN_OK;
  521.     register unsigned workch;      /* hold the character being tested */
  522.  
  523.  
  524. /*---------------------------------------------------------------------------
  525.     Initialize various pointers and counters and stuff.
  526.   ---------------------------------------------------------------------------*/
  527.  
  528.     if (G.pInfo->vollabel)
  529.         return MPN_VOL_LABEL;   /* can't set disk volume labels in Unix */
  530.  
  531.     /* can create path as long as not just freshening, or if user told us */
  532.     G.create_dirs = (!uO.fflag || renamed);
  533.  
  534.     G.created_dir = FALSE;      /* not yet */
  535.  
  536.     /* user gave full pathname:  don't prepend rootpath */
  537.     G.renamed_fullpath = (renamed && (*G.filename == '/'));
  538.  
  539.     if (checkdir(__G__ (char *)NULL, INIT) == MPN_NOMEM)
  540.         return MPN_NOMEM;       /* initialize path buffer, unless no memory */
  541.  
  542.     *pathcomp = '\0';           /* initialize translation buffer */
  543.     pp = pathcomp;              /* point to translation buffer */
  544.     if (uO.jflag)               /* junking directories */
  545.         cp = (char *)strrchr(G.filename, '/');
  546.     if (cp == (char *)NULL)     /* no '/' or not junking dirs */
  547.         cp = G.filename;        /* point to internal zipfile-member pathname */
  548.     else
  549.         ++cp;                   /* point to start of last component of path */
  550.  
  551. /*---------------------------------------------------------------------------
  552.     Begin main loop through characters in filename.
  553.   ---------------------------------------------------------------------------*/
  554.  
  555.     while ((workch = (uch)*cp++) != 0) {
  556.  
  557.         switch (workch) {
  558.             case '/':             /* can assume -j flag not given */
  559.                 *pp = '\0';
  560.                 if (strcmp(pathcomp, ".") == 0) {
  561.                     /* don't bother appending "./" to the path */
  562.                     *pathcomp = '\0';
  563.                 } else if (!uO.ddotflag && strcmp(pathcomp, "..") == 0) {
  564.                     /* "../" dir traversal detected, skip over it */
  565.                     *pathcomp = '\0';
  566.                     killed_ddot = TRUE;     /* set "show message" flag */
  567.                 }
  568.                 /* when path component is not empty, append it now */
  569.                 if (*pathcomp != '\0' &&
  570.                     ((error = checkdir(__G__ pathcomp, APPEND_DIR))
  571.                      & MPN_MASK) > MPN_INF_TRUNC)
  572.                     return error;
  573.                 pp = pathcomp;    /* reset conversion buffer for next piece */
  574.                 lastsemi = (char *)NULL; /* leave direct. semi-colons alone */
  575.                 break;
  576.  
  577. #ifdef __CYGWIN__   /* Cygwin runs on Win32, apply FAT/NTFS filename rules */
  578.             case ':':         /* drive spec not stored, so no colon allowed */
  579.             case '\\':        /* '\\' may come as normal filename char (not */
  580.             case '<':         /*  dir sep char!) from unix-like file system */
  581.             case '>':         /* no redirection symbols allowed either */
  582.             case '|':         /* no pipe signs allowed */
  583.             case '"':         /* no double quotes allowed */
  584.             case '?':         /* no wildcards allowed */
  585.             case '*':
  586.                 *pp++ = '_';  /* these rules apply equally to FAT and NTFS */
  587.                 break;
  588. #endif
  589.  
  590.             case ';':             /* VMS version (or DEC-20 attrib?) */
  591.                 lastsemi = pp;
  592.                 *pp++ = ';';      /* keep for now; remove VMS ";##" */
  593.                 break;            /*  later, if requested */
  594.  
  595. #ifdef ACORN_FTYPE_NFS
  596.             case ',':             /* NFS filetype extension */
  597.                 lastcomma = pp;
  598.                 *pp++ = ',';      /* keep for now; may need to remove */
  599.                 break;            /*  later, if requested */
  600. #endif
  601.  
  602. #ifdef MTS
  603.             case ' ':             /* change spaces to underscore under */
  604.                 *pp++ = '_';      /*  MTS; leave as spaces under Unix */
  605.                 break;
  606. #endif
  607.  
  608.             default:
  609.                 /* disable control character filter when requested,
  610.                  * else allow 8-bit characters (e.g. UTF-8) in filenames:
  611.                  */
  612.                 if (uO.cflxflag ||
  613.                     (isprint(workch) || (128 <= workch && workch <= 254)))
  614.                     *pp++ = (char)workch;
  615.         } /* end switch */
  616.  
  617.     } /* end while loop */
  618.  
  619.     /* Show warning when stripping insecure "parent dir" path components */
  620.     if (killed_ddot && QCOND2) {
  621.         Info(slide, 0, ((char *)slide,
  622.           "warning:  skipped \"../\" path component(s) in %s\n",
  623.           FnFilter1(G.filename)));
  624.         if (!(error & ~MPN_MASK))
  625.             error = (error & MPN_MASK) | PK_WARN;
  626.     }
  627.  
  628. /*---------------------------------------------------------------------------
  629.     Report if directory was created (and no file to create:  filename ended
  630.     in '/'), check name to be sure it exists, and combine path and name be-
  631.     fore exiting.
  632.   ---------------------------------------------------------------------------*/
  633.  
  634.     if (G.filename[strlen(G.filename) - 1] == '/') {
  635.         checkdir(__G__ G.filename, GETPATH);
  636.         if (G.created_dir) {
  637.             if (QCOND2) {
  638.                 Info(slide, 0, ((char *)slide, "   creating: %s\n",
  639.                   FnFilter1(G.filename)));
  640.             }
  641. #ifndef NO_CHMOD
  642.             /* Filter out security-relevant attributes bits. */
  643.             G.pInfo->file_attr = filtattr(__G__ G.pInfo->file_attr);
  644.             /* When extracting non-UNIX directories or when extracting
  645.              * without UID/GID restoration or SGID preservation, any
  646.              * SGID flag inherited from the parent directory should be
  647.              * maintained to allow files extracted into this new folder
  648.              * to inherit the GID setting from the parent directory.
  649.              */
  650.             if (G.pInfo->hostnum != UNIX_ || !(uO.X_flag || uO.K_flag)) {
  651.                 /* preserve SGID bit when inherited from parent dir */
  652.                 if (!SSTAT(G.filename, &G.statbuf)) {
  653.                     G.pInfo->file_attr |= G.statbuf.st_mode & S_ISGID;
  654.                 } else {
  655.                     perror("Could not read directory attributes");
  656.                 }
  657.             }
  658.  
  659.             /* set approx. dir perms (make sure can still read/write in dir) */
  660.             if (chmod(G.filename, G.pInfo->file_attr | 0700))
  661.                 perror("chmod (directory attributes) error");
  662. #endif
  663.             /* set dir time (note trailing '/') */
  664.             return (error & ~MPN_MASK) | MPN_CREATED_DIR;
  665.         }
  666.         /* dir existed already; don't look for data to extract */
  667.         return (error & ~MPN_MASK) | MPN_INF_SKIP;
  668.     }
  669.  
  670.     *pp = '\0';                   /* done with pathcomp:  terminate it */
  671.  
  672.     /* if not saving them, remove VMS version numbers (appended ";###") */
  673.     if (!uO.V_flag && lastsemi) {
  674.         pp = lastsemi + 1;
  675.         while (isdigit((uch)(*pp)))
  676.             ++pp;
  677.         if (*pp == '\0')          /* only digits between ';' and end:  nuke */
  678.             *lastsemi = '\0';
  679.     }
  680.  
  681.     /* On UNIX (and compatible systems), "." and ".." are reserved for
  682.      * directory navigation and cannot be used as regular file names.
  683.      * These reserved one-dot and two-dot names are mapped to "_" and "__".
  684.      */
  685.     if (strcmp(pathcomp, ".") == 0)
  686.         *pathcomp = '_';
  687.     else if (strcmp(pathcomp, "..") == 0)
  688.         strcpy(pathcomp, "__");
  689.  
  690. #ifdef ACORN_FTYPE_NFS
  691.     /* translate Acorn filetype information if asked to do so */
  692.     if (uO.acorn_nfs_ext &&
  693.         (ef_spark = (RO_extra_block *)
  694.                     getRISCOSexfield(G.extra_field, G.lrec.extra_field_length))
  695.         != (RO_extra_block *)NULL)
  696.     {
  697.         /* file *must* have a RISC OS extra field */
  698.         long ft = (long)makelong(ef_spark->loadaddr);
  699.         /*32-bit*/
  700.         if (lastcomma) {
  701.             pp = lastcomma + 1;
  702.             while (isxdigit((uch)(*pp))) ++pp;
  703.             if (pp == lastcomma+4 && *pp == '\0') *lastcomma='\0'; /* nuke */
  704.         }
  705.         if ((ft & 1<<31)==0) ft=0x000FFD00;
  706.         sprintf(pathcomp+strlen(pathcomp), ",%03x", (int)(ft>>8) & 0xFFF);
  707.     }
  708. #endif /* ACORN_FTYPE_NFS */
  709.  
  710.     if (*pathcomp == '\0') {
  711.         Info(slide, 1, ((char *)slide, "mapname:  conversion of %s failed\n",
  712.           FnFilter1(G.filename)));
  713.         return (error & ~MPN_MASK) | MPN_ERR_SKIP;
  714.     }
  715.  
  716.     checkdir(__G__ pathcomp, APPEND_NAME);  /* returns 1 if truncated: care? */
  717.     checkdir(__G__ G.filename, GETPATH);
  718.  
  719.     return error;
  720.  
  721. } /* end function mapname() */
  722.  
  723.  
  724.  
  725.  
  726. #if 0  /*========== NOTES ==========*/
  727.  
  728.   extract-to dir:      a:path/
  729.   buildpath:           path1/path2/ ...   (NULL-terminated)
  730.   pathcomp:                filename
  731.  
  732.   mapname():
  733.     loop over chars in zipfile member name
  734.       checkdir(path component, COMPONENT | CREATEDIR) --> map as required?
  735.         (d:/tmp/unzip/)                    (disk:[tmp.unzip.)
  736.         (d:/tmp/unzip/jj/)                 (disk:[tmp.unzip.jj.)
  737.         (d:/tmp/unzip/jj/temp/)            (disk:[tmp.unzip.jj.temp.)
  738.     finally add filename itself and check for existence? (could use with rename)
  739.         (d:/tmp/unzip/jj/temp/msg.outdir)  (disk:[tmp.unzip.jj.temp]msg.outdir)
  740.     checkdir(name, GETPATH)     -->  copy path to name and free space
  741.  
  742. #endif /* 0 */
  743.  
  744.  
  745.  
  746.  
  747. /***********************/
  748. /* Function checkdir() */
  749. /***********************/
  750.  
  751. int checkdir(__G__ pathcomp, flag)
  752.     __GDEF
  753.     char *pathcomp;
  754.     int flag;
  755. /*
  756.  * returns:
  757.  *  MPN_OK          - no problem detected
  758.  *  MPN_INF_TRUNC   - (on APPEND_NAME) truncated filename
  759.  *  MPN_INF_SKIP    - path doesn't exist, not allowed to create
  760.  *  MPN_ERR_SKIP    - path doesn't exist, tried to create and failed; or path
  761.  *                    exists and is not a directory, but is supposed to be
  762.  *  MPN_ERR_TOOLONG - path is too long
  763.  *  MPN_NOMEM       - can't allocate memory for filename buffers
  764.  */
  765. {
  766.  /* static int rootlen = 0; */  /* length of rootpath */
  767.  /* static char *rootpath;  */  /* user's "extract-to" directory */
  768.  /* static char *buildpath; */  /* full path (so far) to extracted file */
  769.  /* static char *end;       */  /* pointer to end of buildpath ('\0') */
  770.  
  771. #   define FN_MASK   7
  772. #   define FUNCTION  (flag & FN_MASK)
  773.  
  774.  
  775.  
  776. /*---------------------------------------------------------------------------
  777.     APPEND_DIR:  append the path component to the path being built and check
  778.     for its existence.  If doesn't exist and we are creating directories, do
  779.     so for this one; else signal success or error as appropriate.
  780.   ---------------------------------------------------------------------------*/
  781.  
  782.     if (FUNCTION == APPEND_DIR) {
  783.         int too_long = FALSE;
  784. #ifdef SHORT_NAMES
  785.         char *old_end = end;
  786. #endif
  787.  
  788.         Trace((stderr, "appending dir segment [%s]\n", FnFilter1(pathcomp)));
  789.         while ((*G.end = *pathcomp++) != '\0')
  790.             ++G.end;
  791. #ifdef SHORT_NAMES   /* path components restricted to 14 chars, typically */
  792.         if ((G.end-old_end) > FILENAME_MAX)  /* GRR:  proper constant? */
  793.             *(G.end = old_end + FILENAME_MAX) = '\0';
  794. #endif
  795.  
  796.         /* GRR:  could do better check, see if overrunning buffer as we go:
  797.          * check end-buildpath after each append, set warning variable if
  798.          * within 20 of FILNAMSIZ; then if var set, do careful check when
  799.          * appending.  Clear variable when begin new path. */
  800.  
  801.         /* next check: need to append '/', at least one-char name, '\0' */
  802.         if ((G.end-G.buildpath) > FILNAMSIZ-3)
  803.             too_long = TRUE;                    /* check if extracting dir? */
  804.         if (SSTAT(G.buildpath, &G.statbuf)) {   /* path doesn't exist */
  805.             if (!G.create_dirs) { /* told not to create (freshening) */
  806.                 free(G.buildpath);
  807.                 return MPN_INF_SKIP;    /* path doesn't exist: nothing to do */
  808.             }
  809.             if (too_long) {
  810.                 Info(slide, 1, ((char *)slide,
  811.                   "checkdir error:  path too long: %s\n",
  812.                   FnFilter1(G.buildpath)));
  813.                 free(G.buildpath);
  814.                 /* no room for filenames:  fatal */
  815.                 return MPN_ERR_TOOLONG;
  816.             }
  817.             if (mkdir(G.buildpath, 0777) == -1) {   /* create the directory */
  818.                 Info(slide, 1, ((char *)slide,
  819.                   "checkdir error:  cannot create %s\n\
  820.                 %s\n\
  821.                 unable to process %s.\n",
  822.                   FnFilter2(G.buildpath),
  823.                   strerror(errno),
  824.                   FnFilter1(G.filename)));
  825.                 free(G.buildpath);
  826.                 /* path didn't exist, tried to create, failed */
  827.                 return MPN_ERR_SKIP;
  828.             }
  829.             G.created_dir = TRUE;
  830.         } else if (!S_ISDIR(G.statbuf.st_mode)) {
  831.             Info(slide, 1, ((char *)slide,
  832.               "checkdir error:  %s exists but is not directory\n\
  833.                 unable to process %s.\n",
  834.               FnFilter2(G.buildpath), FnFilter1(G.filename)));
  835.             free(G.buildpath);
  836.             /* path existed but wasn't dir */
  837.             return MPN_ERR_SKIP;
  838.         }
  839.         if (too_long) {
  840.             Info(slide, 1, ((char *)slide,
  841.               "checkdir error:  path too long: %s\n", FnFilter1(G.buildpath)));
  842.             free(G.buildpath);
  843.             /* no room for filenames:  fatal */
  844.             return MPN_ERR_TOOLONG;
  845.         }
  846.         *G.end++ = '/';
  847.         *G.end = '\0';
  848.         Trace((stderr, "buildpath now = [%s]\n", FnFilter1(G.buildpath)));
  849.         return MPN_OK;
  850.  
  851.     } /* end if (FUNCTION == APPEND_DIR) */
  852.  
  853. /*---------------------------------------------------------------------------
  854.     GETPATH:  copy full path to the string pointed at by pathcomp, and free
  855.     G.buildpath.
  856.   ---------------------------------------------------------------------------*/
  857.  
  858.     if (FUNCTION == GETPATH) {
  859.         strcpy(pathcomp, G.buildpath);
  860.         Trace((stderr, "getting and freeing path [%s]\n",
  861.           FnFilter1(pathcomp)));
  862.         free(G.buildpath);
  863.         G.buildpath = G.end = (char *)NULL;
  864.         return MPN_OK;
  865.     }
  866.  
  867. /*---------------------------------------------------------------------------
  868.     APPEND_NAME:  assume the path component is the filename; append it and
  869.     return without checking for existence.
  870.   ---------------------------------------------------------------------------*/
  871.  
  872.     if (FUNCTION == APPEND_NAME) {
  873. #ifdef SHORT_NAMES
  874.         char *old_end = end;
  875. #endif
  876.  
  877.         Trace((stderr, "appending filename [%s]\n", FnFilter1(pathcomp)));
  878.         while ((*G.end = *pathcomp++) != '\0') {
  879.             ++G.end;
  880. #ifdef SHORT_NAMES  /* truncate name at 14 characters, typically */
  881.             if ((G.end-old_end) > FILENAME_MAX)    /* GRR:  proper constant? */
  882.                 *(G.end = old_end + FILENAME_MAX) = '\0';
  883. #endif
  884.             if ((G.end-G.buildpath) >= FILNAMSIZ) {
  885.                 *--G.end = '\0';
  886.                 Info(slide, 0x201, ((char *)slide,
  887.                   "checkdir warning:  path too long; truncating\n\
  888.                   %s\n                -> %s\n",
  889.                   FnFilter1(G.filename), FnFilter2(G.buildpath)));
  890.                 return MPN_INF_TRUNC;   /* filename truncated */
  891.             }
  892.         }
  893.         Trace((stderr, "buildpath now = [%s]\n", FnFilter1(G.buildpath)));
  894.         /* could check for existence here, prompt for new name... */
  895.         return MPN_OK;
  896.     }
  897.  
  898. /*---------------------------------------------------------------------------
  899.     INIT:  allocate and initialize buffer space for the file currently being
  900.     extracted.  If file was renamed with an absolute path, don't prepend the
  901.     extract-to path.
  902.   ---------------------------------------------------------------------------*/
  903.  
  904. /* GRR:  for VMS and TOPS-20, add up to 13 to strlen */
  905.  
  906.     if (FUNCTION == INIT) {
  907.         Trace((stderr, "initializing buildpath to "));
  908. #ifdef ACORN_FTYPE_NFS
  909.         if ((G.buildpath = (char *)malloc(strlen(G.filename)+G.rootlen+
  910.                                           (uO.acorn_nfs_ext ? 5 : 1)))
  911. #else
  912.         if ((G.buildpath = (char *)malloc(strlen(G.filename)+G.rootlen+1))
  913. #endif
  914.             == (char *)NULL)
  915.             return MPN_NOMEM;
  916.         if ((G.rootlen > 0) && !G.renamed_fullpath) {
  917.             strcpy(G.buildpath, G.rootpath);
  918.             G.end = G.buildpath + G.rootlen;
  919.         } else {
  920.             *G.buildpath = '\0';
  921.             G.end = G.buildpath;
  922.         }
  923.         Trace((stderr, "[%s]\n", FnFilter1(G.buildpath)));
  924.         return MPN_OK;
  925.     }
  926.  
  927. /*---------------------------------------------------------------------------
  928.     ROOT:  if appropriate, store the path in rootpath and create it if
  929.     necessary; else assume it's a zipfile member and return.  This path
  930.     segment gets used in extracting all members from every zipfile specified
  931.     on the command line.
  932.   ---------------------------------------------------------------------------*/
  933.  
  934. #if (!defined(SFX) || defined(SFX_EXDIR))
  935.     if (FUNCTION == ROOT) {
  936.         Trace((stderr, "initializing root path to [%s]\n",
  937.           FnFilter1(pathcomp)));
  938.         if (pathcomp == (char *)NULL) {
  939.             G.rootlen = 0;
  940.             return MPN_OK;
  941.         }
  942.         if (G.rootlen > 0)      /* rootpath was already set, nothing to do */
  943.             return MPN_OK;
  944.         if ((G.rootlen = strlen(pathcomp)) > 0) {
  945.             char *tmproot;
  946.  
  947.             if ((tmproot = (char *)malloc(G.rootlen+2)) == (char *)NULL) {
  948.                 G.rootlen = 0;
  949.                 return MPN_NOMEM;
  950.             }
  951.             strcpy(tmproot, pathcomp);
  952.             if (tmproot[G.rootlen-1] == '/') {
  953.                 tmproot[--G.rootlen] = '\0';
  954.             }
  955.             if (G.rootlen > 0 && (SSTAT(tmproot, &G.statbuf) ||
  956.                                   !S_ISDIR(G.statbuf.st_mode)))
  957.             {   /* path does not exist */
  958.                 if (!G.create_dirs /* || iswild(tmproot) */ ) {
  959.                     free(tmproot);
  960.                     G.rootlen = 0;
  961.                     /* skip (or treat as stored file) */
  962.                     return MPN_INF_SKIP;
  963.                 }
  964.                 /* create the directory (could add loop here scanning tmproot
  965.                  * to create more than one level, but why really necessary?) */
  966.                 if (mkdir(tmproot, 0777) == -1) {
  967.                     Info(slide, 1, ((char *)slide,
  968.                       "checkdir:  cannot create extraction directory: %s\n\
  969.           %s\n",
  970.                       FnFilter1(tmproot), strerror(errno)));
  971.                     free(tmproot);
  972.                     G.rootlen = 0;
  973.                     /* path didn't exist, tried to create, and failed: */
  974.                     /* file exists, or 2+ subdir levels required */
  975.                     return MPN_ERR_SKIP;
  976.                 }
  977.             }
  978.             tmproot[G.rootlen++] = '/';
  979.             tmproot[G.rootlen] = '\0';
  980.             if ((G.rootpath = (char *)realloc(tmproot, G.rootlen+1)) == NULL) {
  981.                 free(tmproot);
  982.                 G.rootlen = 0;
  983.                 return MPN_NOMEM;
  984.             }
  985.             Trace((stderr, "rootpath now = [%s]\n", FnFilter1(G.rootpath)));
  986.         }
  987.         return MPN_OK;
  988.     }
  989. #endif /* !SFX || SFX_EXDIR */
  990.  
  991. /*---------------------------------------------------------------------------
  992.     END:  free rootpath, immediately prior to program exit.
  993.   ---------------------------------------------------------------------------*/
  994.  
  995.     if (FUNCTION == END) {
  996.         Trace((stderr, "freeing rootpath\n"));
  997.         if (G.rootlen > 0) {
  998.             free(G.rootpath);
  999.             G.rootlen = 0;
  1000.         }
  1001.         return MPN_OK;
  1002.     }
  1003.  
  1004.     return MPN_INVALID; /* should never reach */
  1005.  
  1006. } /* end function checkdir() */
  1007.  
  1008.  
  1009.  
  1010.  
  1011.  
  1012. #ifdef NO_MKDIR
  1013.  
  1014. /********************/
  1015. /* Function mkdir() */
  1016. /********************/
  1017.  
  1018. int mkdir(path, mode)
  1019.     ZCONST char *path;
  1020.     int mode;   /* ignored */
  1021. /*
  1022.  * returns:   0 - successful
  1023.  *           -1 - failed (errno not set, however)
  1024.  */
  1025. {
  1026.     char command[FILNAMSIZ+40]; /* buffer for system() call */
  1027.  
  1028.     /* GRR 930416:  added single quotes around path to avoid bug with
  1029.      * creating directories with ampersands in name; not yet tested */
  1030.     sprintf(command, "IFS=\" \t\n\" /bin/mkdir '%s' 2>/dev/null", path);
  1031.     if (system(command))
  1032.         return -1;
  1033.     return 0;
  1034. }
  1035.  
  1036. #endif /* NO_MKDIR */
  1037.  
  1038.  
  1039.  
  1040.  
  1041. #if (!defined(MTS) || defined(SET_DIR_ATTRIB))
  1042. static int get_extattribs OF((__GPRO__ iztimes *pzt, ulg z_uidgid[2]));
  1043.  
  1044. static int get_extattribs(__G__ pzt, z_uidgid)
  1045.     __GDEF
  1046.     iztimes *pzt;
  1047.     ulg z_uidgid[2];
  1048. {
  1049. /*---------------------------------------------------------------------------
  1050.     Convert from MSDOS-format local time and date to Unix-format 32-bit GMT
  1051.     time:  adjust base year from 1980 to 1970, do usual conversions from
  1052.     yy/mm/dd hh:mm:ss to elapsed seconds, and account for timezone and day-
  1053.     light savings time differences.  If we have a Unix extra field, however,
  1054.     we're laughing:  both mtime and atime are ours.  On the other hand, we
  1055.     then have to check for restoration of UID/GID.
  1056.   ---------------------------------------------------------------------------*/
  1057.     int have_uidgid_flg;
  1058.     unsigned eb_izux_flg;
  1059.  
  1060.     eb_izux_flg = (G.extra_field ? ef_scan_for_izux(G.extra_field,
  1061.                    G.lrec.extra_field_length, 0, G.lrec.last_mod_dos_datetime,
  1062. #ifdef IZ_CHECK_TZ
  1063.                    (G.tz_is_valid ? pzt : NULL),
  1064. #else
  1065.                    pzt,
  1066. #endif
  1067.                    z_uidgid) : 0);
  1068.     if (eb_izux_flg & EB_UT_FL_MTIME) {
  1069.         TTrace((stderr, "\nget_extattribs:  Unix e.f. modif. time = %ld\n",
  1070.           pzt->mtime));
  1071.     } else {
  1072.         pzt->mtime = dos_to_unix_time(G.lrec.last_mod_dos_datetime);
  1073.     }
  1074.     if (eb_izux_flg & EB_UT_FL_ATIME) {
  1075.         TTrace((stderr, "get_extattribs:  Unix e.f. access time = %ld\n",
  1076.           pzt->atime));
  1077.     } else {
  1078.         pzt->atime = pzt->mtime;
  1079.         TTrace((stderr, "\nget_extattribs:  modification/access times = %ld\n",
  1080.           pzt->mtime));
  1081.     }
  1082.  
  1083.     /* if -X option was specified and we have UID/GID info, restore it */
  1084.     have_uidgid_flg =
  1085. #ifdef RESTORE_UIDGID
  1086.             (uO.X_flag && (eb_izux_flg & EB_UX2_VALID));
  1087. #else
  1088.             0;
  1089. #endif
  1090.     return have_uidgid_flg;
  1091. }
  1092. #endif /* !MTS || SET_DIR_ATTRIB */
  1093.  
  1094.  
  1095.  
  1096. #ifndef MTS
  1097.  
  1098. /****************************/
  1099. /* Function close_outfile() */
  1100. /****************************/
  1101.  
  1102. void close_outfile(__G)    /* GRR: change to return PK-style warning level */
  1103.     __GDEF
  1104. {
  1105.     union {
  1106.         iztimes t3;             /* mtime, atime, ctime */
  1107.         ztimbuf t2;             /* modtime, actime */
  1108.     } zt;
  1109.     ulg z_uidgid[2];
  1110.     int have_uidgid_flg;
  1111.  
  1112.     have_uidgid_flg = get_extattribs(__G__ &(zt.t3), z_uidgid);
  1113.  
  1114. /*---------------------------------------------------------------------------
  1115.     If symbolic links are supported, allocate storage for a symlink control
  1116.     structure, put the uncompressed "data" and other required info in it, and
  1117.     add the structure to the "deferred symlinks" chain.  Since we know it's a
  1118.     symbolic link to start with, we shouldn't have to worry about overflowing
  1119.     unsigned ints with unsigned longs.
  1120.   ---------------------------------------------------------------------------*/
  1121.  
  1122. #ifdef SYMLINKS
  1123.     if (G.symlnk) {
  1124.         extent ucsize = (extent)G.lrec.ucsize;
  1125. # ifdef SET_SYMLINK_ATTRIBS
  1126.         extent attribsize = sizeof(unsigned) +
  1127.                             (have_uidgid_flg ? sizeof(z_uidgid) : 0);
  1128. # else
  1129.         extent attribsize = 0;
  1130. # endif
  1131.         /* size of the symlink entry is the sum of
  1132.          *  (struct size (includes 1st '\0') + 1 additional trailing '\0'),
  1133.          *  system specific attribute data size (might be 0),
  1134.          *  and the lengths of name and link target.
  1135.          */
  1136.         extent slnk_entrysize = (sizeof(slinkentry) + 1) + attribsize +
  1137.                                 ucsize + strlen(G.filename);
  1138.         slinkentry *slnk_entry;
  1139.  
  1140.         if (slnk_entrysize < ucsize) {
  1141.             Info(slide, 0x201, ((char *)slide,
  1142.               "warning:  symbolic link (%s) failed: mem alloc overflow\n",
  1143.               FnFilter1(G.filename)));
  1144.             fclose(G.outfile);
  1145.             return;
  1146.         }
  1147.  
  1148.         if ((slnk_entry = (slinkentry *)malloc(slnk_entrysize)) == NULL) {
  1149.             Info(slide, 0x201, ((char *)slide,
  1150.               "warning:  symbolic link (%s) failed: no mem\n",
  1151.               FnFilter1(G.filename)));
  1152.             fclose(G.outfile);
  1153.             return;
  1154.         }
  1155.         slnk_entry->next = NULL;
  1156.         slnk_entry->targetlen = ucsize;
  1157.         slnk_entry->attriblen = attribsize;
  1158. # ifdef SET_SYMLINK_ATTRIBS
  1159.         memcpy(slnk_entry->buf, &(G.pInfo->file_attr),
  1160.                sizeof(unsigned));
  1161.         if (have_uidgid_flg)
  1162.             memcpy(slnk_entry->buf + 4, z_uidgid, sizeof(z_uidgid));
  1163. # endif
  1164.         slnk_entry->target = slnk_entry->buf + slnk_entry->attriblen;
  1165.         slnk_entry->fname = slnk_entry->target + ucsize + 1;
  1166.         strcpy(slnk_entry->fname, G.filename);
  1167.  
  1168.         /* move back to the start of the file to re-read the "link data" */
  1169.         rewind(G.outfile);
  1170.  
  1171.         if (fread(slnk_entry->target, 1, ucsize, G.outfile) != ucsize)
  1172.         {
  1173.             Info(slide, 0x201, ((char *)slide,
  1174.               "warning:  symbolic link (%s) failed\n",
  1175.               FnFilter1(G.filename)));
  1176.             free(slnk_entry);
  1177.             fclose(G.outfile);
  1178.             return;
  1179.         }
  1180.         fclose(G.outfile);                  /* close "link" file for good... */
  1181.         slnk_entry->target[ucsize] = '\0';
  1182.         if (QCOND2)
  1183.             Info(slide, 0, ((char *)slide, "-> %s ",
  1184.               FnFilter1(slnk_entry->target)));
  1185.         /* add this symlink record to the list of deferred symlinks */
  1186.         if (G.slink_last != NULL)
  1187.             G.slink_last->next = slnk_entry;
  1188.         else
  1189.             G.slink_head = slnk_entry;
  1190.         G.slink_last = slnk_entry;
  1191.         return;
  1192.     }
  1193. #endif /* SYMLINKS */
  1194.  
  1195. #ifdef QLZIP
  1196.     if (G.extra_field) {
  1197.         static void qlfix OF((__GPRO__ uch *ef_ptr, unsigned ef_len));
  1198.  
  1199.         qlfix(__G__ G.extra_field, G.lrec.extra_field_length);
  1200.     }
  1201. #endif
  1202.  
  1203. #if (defined(NO_FCHOWN))
  1204.     fclose(G.outfile);
  1205. #endif
  1206.  
  1207.     /* if -X option was specified and we have UID/GID info, restore it */
  1208.     if (have_uidgid_flg
  1209.         /* check that both uid and gid values fit into their data sizes */
  1210.         && ((ulg)(uid_t)(z_uidgid[0]) == z_uidgid[0])
  1211.         && ((ulg)(gid_t)(z_uidgid[1]) == z_uidgid[1])) {
  1212.         TTrace((stderr, "close_outfile:  restoring Unix UID/GID info\n"));
  1213. #if (defined(NO_FCHOWN))
  1214.         if (chown(G.filename, (uid_t)z_uidgid[0], (gid_t)z_uidgid[1]))
  1215. #else
  1216.         if (fchown(fileno(G.outfile), (uid_t)z_uidgid[0], (gid_t)z_uidgid[1]))
  1217. #endif
  1218.         {
  1219.             if (uO.qflag)
  1220.                 Info(slide, 0x201, ((char *)slide, CannotSetItemUidGid,
  1221.                   z_uidgid[0], z_uidgid[1], FnFilter1(G.filename),
  1222.                   strerror(errno)));
  1223.             else
  1224.                 Info(slide, 0x201, ((char *)slide, CannotSetUidGid,
  1225.                   z_uidgid[0], z_uidgid[1], strerror(errno)));
  1226.         }
  1227.     }
  1228.  
  1229. #if (!defined(NO_FCHOWN) && defined(NO_FCHMOD))
  1230.     fclose(G.outfile);
  1231. #endif
  1232.  
  1233. #if (!defined(NO_FCHOWN) && !defined(NO_FCHMOD))
  1234. /*---------------------------------------------------------------------------
  1235.     Change the file permissions from default ones to those stored in the
  1236.     zipfile.
  1237.   ---------------------------------------------------------------------------*/
  1238.  
  1239.     if (fchmod(fileno(G.outfile), filtattr(__G__ G.pInfo->file_attr)))
  1240.         perror("fchmod (file attributes) error");
  1241.  
  1242.     fclose(G.outfile);
  1243. #endif /* !NO_FCHOWN && !NO_FCHMOD */
  1244.  
  1245.     /* skip restoring time stamps on user's request */
  1246.     if (uO.D_flag <= 1) {
  1247.         /* set the file's access and modification times */
  1248.         if (utime(G.filename, &(zt.t2))) {
  1249.             if (uO.qflag)
  1250.                 Info(slide, 0x201, ((char *)slide, CannotSetItemTimestamps,
  1251.                   FnFilter1(G.filename), strerror(errno)));
  1252.             else
  1253.                 Info(slide, 0x201, ((char *)slide, CannotSetTimestamps,
  1254.                   strerror(errno)));
  1255.         }
  1256.     }
  1257.  
  1258. #if (defined(NO_FCHOWN) || defined(NO_FCHMOD))
  1259. /*---------------------------------------------------------------------------
  1260.     Change the file permissions from default ones to those stored in the
  1261.     zipfile.
  1262.   ---------------------------------------------------------------------------*/
  1263.  
  1264. #ifndef NO_CHMOD
  1265.     if (chmod(G.filename, filtattr(__G__ G.pInfo->file_attr)))
  1266.         perror("chmod (file attributes) error");
  1267. #endif
  1268. #endif /* NO_FCHOWN || NO_FCHMOD */
  1269.  
  1270. } /* end function close_outfile() */
  1271.  
  1272. #endif /* !MTS */
  1273.  
  1274.  
  1275. #if (defined(SYMLINKS) && defined(SET_SYMLINK_ATTRIBS))
  1276. int set_symlnk_attribs(__G__ slnk_entry)
  1277.     __GDEF
  1278.     slinkentry *slnk_entry;
  1279. {
  1280.     if (slnk_entry->attriblen > 0) {
  1281. # if (!defined(NO_LCHOWN))
  1282.       if (slnk_entry->attriblen > sizeof(unsigned)) {
  1283.         ulg *z_uidgid_p = (zvoid *)(slnk_entry->buf + sizeof(unsigned));
  1284.         /* check that both uid and gid values fit into their data sizes */
  1285.         if (((ulg)(uid_t)(z_uidgid_p[0]) == z_uidgid_p[0]) &&
  1286.             ((ulg)(gid_t)(z_uidgid_p[1]) == z_uidgid_p[1])) {
  1287.           TTrace((stderr,
  1288.             "set_symlnk_attribs:  restoring Unix UID/GID info for\n\
  1289.        %s\n",
  1290.             FnFilter1(slnk_entry->fname)));
  1291.           if (lchown(slnk_entry->fname,
  1292.                      (uid_t)z_uidgid_p[0], (gid_t)z_uidgid_p[1]))
  1293.           {
  1294.             Info(slide, 0x201, ((char *)slide, CannotSetItemUidGid,
  1295.               z_uidgid_p[0], z_uidgid_p[1], FnFilter1(slnk_entry->fname),
  1296.               strerror(errno)));
  1297.           }
  1298.         }
  1299.       }
  1300. # endif /* !NO_LCHOWN */
  1301. # if (!defined(NO_LCHMOD))
  1302.       TTrace((stderr,
  1303.         "set_symlnk_attribs:  restoring Unix attributes for\n        %s\n",
  1304.         FnFilter1(slnk_entry->fname)));
  1305.       if (lchmod(slnk_entry->fname,
  1306.                  filtattr(__G__ *(unsigned *)(zvoid *)slnk_entry->buf)))
  1307.           perror("lchmod (file attributes) error");
  1308. # endif /* !NO_LCHMOD */
  1309.     }
  1310.     /* currently, no error propagation... */
  1311.     return PK_OK;
  1312. } /* end function set_symlnk_attribs() */
  1313. #endif /* SYMLINKS && SET_SYMLINK_ATTRIBS */
  1314.  
  1315.  
  1316. #ifdef SET_DIR_ATTRIB
  1317. /* messages of code for setting directory attributes */
  1318. #  ifndef NO_CHMOD
  1319.   static ZCONST char DirlistChmodFailed[] =
  1320.     "warning:  cannot set permissions for %s\n          %s\n";
  1321. #  endif
  1322.  
  1323.  
  1324. int defer_dir_attribs(__G__ pd)
  1325.     __GDEF
  1326.     direntry **pd;
  1327. {
  1328.     uxdirattr *d_entry;
  1329.  
  1330.     d_entry = (uxdirattr *)malloc(sizeof(uxdirattr) + strlen(G.filename));
  1331.     *pd = (direntry *)d_entry;
  1332.     if (d_entry == (uxdirattr *)NULL) {
  1333.         return PK_MEM;
  1334.     }
  1335.     d_entry->fn = d_entry->fnbuf;
  1336.     strcpy(d_entry->fn, G.filename);
  1337.  
  1338.     d_entry->perms = G.pInfo->file_attr;
  1339.  
  1340.     d_entry->have_uidgid = get_extattribs(__G__ &(d_entry->u.t3),
  1341.                                           d_entry->uidgid);
  1342.     return PK_OK;
  1343. } /* end function defer_dir_attribs() */
  1344.  
  1345.  
  1346. int set_direc_attribs(__G__ d)
  1347.     __GDEF
  1348.     direntry *d;
  1349. {
  1350.     int errval = PK_OK;
  1351.  
  1352.     if (UxAtt(d)->have_uidgid &&
  1353.         /* check that both uid and gid values fit into their data sizes */
  1354.         ((ulg)(uid_t)(UxAtt(d)->uidgid[0]) == UxAtt(d)->uidgid[0]) &&
  1355.         ((ulg)(gid_t)(UxAtt(d)->uidgid[1]) == UxAtt(d)->uidgid[1]) &&
  1356.         chown(UxAtt(d)->fn, (uid_t)UxAtt(d)->uidgid[0],
  1357.               (gid_t)UxAtt(d)->uidgid[1]))
  1358.     {
  1359.         Info(slide, 0x201, ((char *)slide, CannotSetItemUidGid,
  1360.           UxAtt(d)->uidgid[0], UxAtt(d)->uidgid[1], FnFilter1(d->fn),
  1361.           strerror(errno)));
  1362.         if (!errval)
  1363.             errval = PK_WARN;
  1364.     }
  1365.     /* Skip restoring directory time stamps on user' request. */
  1366.     if (uO.D_flag <= 0) {
  1367.         /* restore directory timestamps */
  1368.         if (utime(d->fn, &UxAtt(d)->u.t2)) {
  1369.             Info(slide, 0x201, ((char *)slide, CannotSetItemTimestamps,
  1370.               FnFilter1(d->fn), strerror(errno)));
  1371.             if (!errval)
  1372.                 errval = PK_WARN;
  1373.         }
  1374.     }
  1375. #ifndef NO_CHMOD
  1376.     if (chmod(d->fn, UxAtt(d)->perms)) {
  1377.         Info(slide, 0x201, ((char *)slide, DirlistChmodFailed,
  1378.           FnFilter1(d->fn), strerror(errno)));
  1379.         if (!errval)
  1380.             errval = PK_WARN;
  1381.     }
  1382. #endif /* !NO_CHMOD */
  1383.     return errval;
  1384. } /* end function set_direc_attribs() */
  1385.  
  1386. #endif /* SET_DIR_ATTRIB */
  1387.  
  1388.  
  1389.  
  1390.  
  1391. #ifdef TIMESTAMP
  1392.  
  1393. /***************************/
  1394. /*  Function stamp_file()  */
  1395. /***************************/
  1396.  
  1397. int stamp_file(fname, modtime)
  1398.     ZCONST char *fname;
  1399.     time_t modtime;
  1400. {
  1401.     ztimbuf tp;
  1402.  
  1403.     tp.modtime = tp.actime = modtime;
  1404.     return (utime(fname, &tp));
  1405.  
  1406. } /* end function stamp_file() */
  1407.  
  1408. #endif /* TIMESTAMP */
  1409.  
  1410.  
  1411.  
  1412.  
  1413. #ifndef SFX
  1414.  
  1415. /************************/
  1416. /*  Function version()  */
  1417. /************************/
  1418.  
  1419. void version(__G)
  1420.     __GDEF
  1421. {
  1422. #if (defined(__GNUC__) && defined(NX_CURRENT_COMPILER_RELEASE))
  1423.     char cc_namebuf[40];
  1424.     char cc_versbuf[40];
  1425. #else
  1426. #if (defined(__SUNPRO_C))
  1427.     char cc_versbuf[17];
  1428. #else
  1429. #if (defined(__HP_cc) || defined(__IBMC__))
  1430.     char cc_versbuf[25];
  1431. #else
  1432. #if (defined(__DECC_VER))
  1433.     char cc_versbuf[17];
  1434.     int cc_verstyp;
  1435. #else
  1436. #if (defined(CRAY) && defined(_RELEASE))
  1437.     char cc_versbuf[40];
  1438. #endif /* (CRAY && _RELEASE) */
  1439. #endif /* __DECC_VER */
  1440. #endif /* __HP_cc || __IBMC__ */
  1441. #endif /* __SUNPRO_C */
  1442. #endif /* (__GNUC__ && NX_CURRENT_COMPILER_RELEASE) */
  1443.  
  1444. #if ((defined(CRAY) || defined(cray)) && defined(_UNICOS))
  1445.     char os_namebuf[40];
  1446. #else
  1447. #if defined(__NetBSD__)
  1448.     char os_namebuf[40];
  1449. #endif
  1450. #endif
  1451.  
  1452.     /* Pyramid, NeXT have problems with huge macro expansion, too:  no Info() */
  1453.     sprintf((char *)slide, LoadFarString(CompiledWith),
  1454.  
  1455. #ifdef __GNUC__
  1456. #  ifdef NX_CURRENT_COMPILER_RELEASE
  1457.       (sprintf(cc_namebuf, "NeXT DevKit %d.%02d ",
  1458.         NX_CURRENT_COMPILER_RELEASE/100, NX_CURRENT_COMPILER_RELEASE%100),
  1459.        cc_namebuf),
  1460.       (strlen(__VERSION__) > 8)? "(gcc)" :
  1461.         (sprintf(cc_versbuf, "(gcc %s)", __VERSION__), cc_versbuf),
  1462. #  else
  1463.       "gcc ", __VERSION__,
  1464. #  endif
  1465. #else
  1466. #if defined(__SUNPRO_C)
  1467.       "Sun C ", (sprintf(cc_versbuf, "version %x", __SUNPRO_C), cc_versbuf),
  1468. #else
  1469. #if (defined(__HP_cc))
  1470.       "HP C ",
  1471.       (((__HP_cc% 100) == 0) ?
  1472.       (sprintf(cc_versbuf, "version A.%02d.%02d",
  1473.       (__HP_cc/ 10000), ((__HP_cc% 10000)/ 100))) :
  1474.       (sprintf(cc_versbuf, "version A.%02d.%02d.%02d",
  1475.       (__HP_cc/ 10000), ((__HP_cc% 10000)/ 100), (__HP_cc% 100))),
  1476.       cc_versbuf),
  1477. #else
  1478. #if (defined(__DECC_VER))
  1479.       "DEC C ",
  1480.       (sprintf(cc_versbuf, "%c%d.%d-%03d",
  1481.                ((cc_verstyp = (__DECC_VER / 10000) % 10) == 6 ? 'T' :
  1482.                 (cc_verstyp == 8 ? 'S' : 'V')),
  1483.                __DECC_VER / 10000000,
  1484.                (__DECC_VER % 10000000) / 100000, __DECC_VER % 1000),
  1485.                cc_versbuf),
  1486. #else
  1487. #if defined(CRAY) && defined(_RELEASE)
  1488.       "cc ", (sprintf(cc_versbuf, "version %d", _RELEASE), cc_versbuf),
  1489. #else
  1490. #ifdef __IBMC__
  1491.       "IBM C ",
  1492.       (sprintf(cc_versbuf, "version %d.%d.%d",
  1493.                (__IBMC__ / 100), ((__IBMC__ / 10) % 10), (__IBMC__ % 10)),
  1494.                cc_versbuf),
  1495. #else
  1496. #ifdef __VERSION__
  1497. #   ifndef IZ_CC_NAME
  1498. #    define IZ_CC_NAME "cc "
  1499. #   endif
  1500.       IZ_CC_NAME, __VERSION__
  1501. #else
  1502. #   ifndef IZ_CC_NAME
  1503. #    define IZ_CC_NAME "cc"
  1504. #   endif
  1505.       IZ_CC_NAME, "",
  1506. #endif /* ?__VERSION__ */
  1507. #endif /* ?__IBMC__ */
  1508. #endif /* ?(CRAY && _RELEASE) */
  1509. #endif /* ?__DECC_VER */
  1510. #endif /* ?__HP_cc */
  1511. #endif /* ?__SUNPRO_C */
  1512. #endif /* ?__GNUC__ */
  1513.  
  1514. #ifndef IZ_OS_NAME
  1515. #  define IZ_OS_NAME "Unix"
  1516. #endif
  1517.       IZ_OS_NAME,
  1518.  
  1519. #if defined(sgi) || defined(__sgi)
  1520.       " (Silicon Graphics IRIX)",
  1521. #else
  1522. #ifdef sun
  1523. #  ifdef sparc
  1524. #    ifdef __SVR4
  1525.       " (Sun SPARC/Solaris)",
  1526. #    else /* may or may not be SunOS */
  1527.       " (Sun SPARC)",
  1528. #    endif
  1529. #  else
  1530. #  if defined(sun386) || defined(i386)
  1531.       " (Sun 386i)",
  1532. #  else
  1533. #  if defined(mc68020) || defined(__mc68020__)
  1534.       " (Sun 3)",
  1535. #  else /* mc68010 or mc68000:  Sun 2 or earlier */
  1536.       " (Sun 2)",
  1537. #  endif
  1538. #  endif
  1539. #  endif
  1540. #else
  1541. #ifdef __hpux
  1542.       " (HP-UX)",
  1543. #else
  1544. #ifdef __osf__
  1545.       " (DEC OSF/1)",
  1546. #else
  1547. #ifdef _AIX
  1548.       " (IBM AIX)",
  1549. #else
  1550. #ifdef aiws
  1551.       " (IBM RT/AIX)",
  1552. #else
  1553. #if defined(CRAY) || defined(cray)
  1554. #  ifdef _UNICOS
  1555.       (sprintf(os_namebuf, " (Cray UNICOS release %d)", _UNICOS), os_namebuf),
  1556. #  else
  1557.       " (Cray UNICOS)",
  1558. #  endif
  1559. #else
  1560. #if defined(uts) || defined(UTS)
  1561.       " (Amdahl UTS)",
  1562. #else
  1563. #ifdef NeXT
  1564. #  ifdef mc68000
  1565.       " (NeXTStep/black)",
  1566. #  else
  1567.       " (NeXTStep for Intel)",
  1568. #  endif
  1569. #else              /* the next dozen or so are somewhat order-dependent */
  1570. #ifdef LINUX
  1571. #  ifdef __ELF__
  1572.       " (Linux ELF)",
  1573. #  else
  1574.       " (Linux a.out)",
  1575. #  endif
  1576. #else
  1577. #ifdef MINIX
  1578.       " (Minix)",
  1579. #else
  1580. #ifdef M_UNIX
  1581.       " (SCO Unix)",
  1582. #else
  1583. #ifdef M_XENIX
  1584.       " (SCO Xenix)",
  1585. #else
  1586. #ifdef __NetBSD__
  1587. #  ifdef NetBSD0_8
  1588.       (sprintf(os_namebuf, " (NetBSD 0.8%c)", (char)(NetBSD0_8 - 1 + 'A')),
  1589.        os_namebuf),
  1590. #  else
  1591. #  ifdef NetBSD0_9
  1592.       (sprintf(os_namebuf, " (NetBSD 0.9%c)", (char)(NetBSD0_9 - 1 + 'A')),
  1593.        os_namebuf),
  1594. #  else
  1595. #  ifdef NetBSD1_0
  1596.       (sprintf(os_namebuf, " (NetBSD 1.0%c)", (char)(NetBSD1_0 - 1 + 'A')),
  1597.        os_namebuf),
  1598. #  else
  1599.       (BSD4_4 == 0.5)? " (NetBSD before 0.9)" : " (NetBSD 1.1 or later)",
  1600. #  endif
  1601. #  endif
  1602. #  endif
  1603. #else
  1604. #ifdef __FreeBSD__
  1605.       (BSD4_4 == 0.5)? " (FreeBSD 1.x)" : " (FreeBSD 2.0 or later)",
  1606. #else
  1607. #ifdef __bsdi__
  1608.       (BSD4_4 == 0.5)? " (BSD/386 1.0)" : " (BSD/386 1.1 or later)",
  1609. #else
  1610. #ifdef __386BSD__
  1611.       (BSD4_4 == 1)? " (386BSD, post-4.4 release)" : " (386BSD)",
  1612. #else
  1613. #ifdef __CYGWIN__
  1614.       " (Cygwin)",
  1615. #else
  1616. #if defined(i686) || defined(__i686) || defined(__i686__)
  1617.       " (Intel 686)",
  1618. #else
  1619. #if defined(i586) || defined(__i586) || defined(__i586__)
  1620.       " (Intel 586)",
  1621. #else
  1622. #if defined(i486) || defined(__i486) || defined(__i486__)
  1623.       " (Intel 486)",
  1624. #else
  1625. #if defined(i386) || defined(__i386) || defined(__i386__)
  1626.       " (Intel 386)",
  1627. #else
  1628. #ifdef pyr
  1629.       " (Pyramid)",
  1630. #else
  1631. #ifdef ultrix
  1632. #  ifdef mips
  1633.       " (DEC/MIPS)",
  1634. #  else
  1635. #  ifdef vax
  1636.       " (DEC/VAX)",
  1637. #  else /* __alpha? */
  1638.       " (DEC/Alpha)",
  1639. #  endif
  1640. #  endif
  1641. #else
  1642. #ifdef gould
  1643.       " (Gould)",
  1644. #else
  1645. #ifdef MTS
  1646.       " (MTS)",
  1647. #else
  1648. #ifdef __convexc__
  1649.       " (Convex)",
  1650. #else
  1651. #ifdef __QNX__
  1652.       " (QNX 4)",
  1653. #else
  1654. #ifdef __QNXNTO__
  1655.       " (QNX Neutrino)",
  1656. #else
  1657. #ifdef Lynx
  1658.       " (LynxOS)",
  1659. #else
  1660. #ifdef __APPLE__
  1661. #  ifdef __i386__
  1662.       " Mac OS X Intel i32",
  1663. #  else
  1664. #  ifdef __ppc__
  1665.       " Mac OS X PowerPC",
  1666. #  else
  1667. #  ifdef __ppc64__
  1668.       " Mac OS X PowerPC64",
  1669. #  else
  1670.       " Mac OS X",
  1671. #  endif /* __ppc64__ */
  1672. #  endif /* __ppc__ */
  1673. #  endif /* __i386__ */
  1674. #else
  1675.       "",
  1676. #endif /* Apple */
  1677. #endif /* Lynx */
  1678. #endif /* QNX Neutrino */
  1679. #endif /* QNX 4 */
  1680. #endif /* Convex */
  1681. #endif /* MTS */
  1682. #endif /* Gould */
  1683. #endif /* DEC */
  1684. #endif /* Pyramid */
  1685. #endif /* 386 */
  1686. #endif /* 486 */
  1687. #endif /* 586 */
  1688. #endif /* 686 */
  1689. #endif /* Cygwin */
  1690. #endif /* 386BSD */
  1691. #endif /* BSDI BSD/386 */
  1692. #endif /* NetBSD */
  1693. #endif /* FreeBSD */
  1694. #endif /* SCO Xenix */
  1695. #endif /* SCO Unix */
  1696. #endif /* Minix */
  1697. #endif /* Linux */
  1698. #endif /* NeXT */
  1699. #endif /* Amdahl */
  1700. #endif /* Cray */
  1701. #endif /* RT/AIX */
  1702. #endif /* AIX */
  1703. #endif /* OSF/1 */
  1704. #endif /* HP-UX */
  1705. #endif /* Sun */
  1706. #endif /* SGI */
  1707.  
  1708. #ifdef __DATE__
  1709.       " on ", __DATE__
  1710. #else
  1711.       "", ""
  1712. #endif
  1713.     );
  1714.  
  1715.     (*G.message)((zvoid *)&G, slide, (ulg)strlen((char *)slide), 0);
  1716.  
  1717. } /* end function version() */
  1718.  
  1719. #endif /* !SFX */
  1720.  
  1721.  
  1722.  
  1723.  
  1724. #ifdef QLZIP
  1725.  
  1726. struct qdirect  {
  1727.     long            d_length __attribute__ ((packed));  /* file length */
  1728.     unsigned char   d_access __attribute__ ((packed));  /* file access type */
  1729.     unsigned char   d_type __attribute__ ((packed));    /* file type */
  1730.     long            d_datalen __attribute__ ((packed)); /* data length */
  1731.     long            d_reserved __attribute__ ((packed));/* Unused */
  1732.     short           d_szname __attribute__ ((packed));  /* size of name */
  1733.     char            d_name[36] __attribute__ ((packed));/* name area */
  1734.     long            d_update __attribute__ ((packed));  /* last update */
  1735.     long            d_refdate __attribute__ ((packed));
  1736.     long            d_backup __attribute__ ((packed));   /* EOD */
  1737. };
  1738.  
  1739. #define LONGID  "QDOS02"
  1740. #define EXTRALEN (sizeof(struct qdirect) + 8)
  1741. #define JBLONGID    "QZHD"
  1742. #define JBEXTRALEN  (sizeof(jbextra)  - 4 * sizeof(char))
  1743.  
  1744. typedef struct {
  1745.     char        eb_header[4] __attribute__ ((packed));  /* place_holder */
  1746.     char        longid[8] __attribute__ ((packed));
  1747.     struct      qdirect     header __attribute__ ((packed));
  1748. } qdosextra;
  1749.  
  1750. typedef struct {
  1751.     char        eb_header[4];                           /* place_holder */
  1752.     char        longid[4];
  1753.     struct      qdirect     header;
  1754. } jbextra;
  1755.  
  1756.  
  1757.  
  1758. /*  The following two functions SH() and LG() convert big-endian short
  1759.  *  and long numbers into native byte order.  They are some kind of
  1760.  *  counterpart to the generic UnZip's makeword() and makelong() functions.
  1761.  */
  1762. static ush SH(ush val)
  1763. {
  1764.     uch swapbuf[2];
  1765.  
  1766.     swapbuf[1] = (uch)(val & 0xff);
  1767.     swapbuf[0] = (uch)(val >> 8);
  1768.     return (*(ush *)swapbuf);
  1769. }
  1770.  
  1771.  
  1772.  
  1773. static ulg LG(ulg val)
  1774. {
  1775.     /*  convert the big-endian unsigned long number `val' to the machine
  1776.      *  dependent representation
  1777.      */
  1778.     ush swapbuf[2];
  1779.  
  1780.     swapbuf[1] = SH((ush)(val & 0xffff));
  1781.     swapbuf[0] = SH((ush)(val >> 16));
  1782.     return (*(ulg *)swapbuf);
  1783. }
  1784.  
  1785.  
  1786.  
  1787. static void qlfix(__G__ ef_ptr, ef_len)
  1788.     __GDEF
  1789.     uch *ef_ptr;
  1790.     unsigned ef_len;
  1791. {
  1792.     while (ef_len >= EB_HEADSIZE)
  1793.     {
  1794.         unsigned    eb_id  = makeword(EB_ID + ef_ptr);
  1795.         unsigned    eb_len = makeword(EB_LEN + ef_ptr);
  1796.  
  1797.         if (eb_len > (ef_len - EB_HEADSIZE)) {
  1798.             /* discovered some extra field inconsistency! */
  1799.             Trace((stderr,
  1800.               "qlfix: block length %u > rest ef_size %u\n", eb_len,
  1801.               ef_len - EB_HEADSIZE));
  1802.             break;
  1803.         }
  1804.  
  1805.         switch (eb_id) {
  1806.           case EF_QDOS:
  1807.           {
  1808.             struct _ntc_
  1809.             {
  1810.                 long id;
  1811.                 long dlen;
  1812.             } ntc;
  1813.             long dlen = 0;
  1814.  
  1815.             qdosextra   *extra = (qdosextra *)ef_ptr;
  1816.             jbextra     *jbp   = (jbextra   *)ef_ptr;
  1817.  
  1818.             if (!strncmp(extra->longid, LONGID, strlen(LONGID)))
  1819.             {
  1820.                 if (eb_len != EXTRALEN)
  1821.                     if (uO.qflag)
  1822.                         Info(slide, 0x201, ((char *)slide,
  1823.                           "warning:  invalid length in Qdos field for %s\n",
  1824.                           FnFilter1(G.filename)));
  1825.                     else
  1826.                         Info(slide, 0x201, ((char *)slide,
  1827.                           "warning:  invalid length in Qdos field"));
  1828.  
  1829.                 if (extra->header.d_type)
  1830.                 {
  1831.                     dlen = extra->header.d_datalen;
  1832.                 }
  1833.             }
  1834.  
  1835.             if (!strncmp(jbp->longid, JBLONGID, strlen(JBLONGID)))
  1836.             {
  1837.                 if (eb_len != JBEXTRALEN)
  1838.                     if (uO.qflag)
  1839.                         Info(slide, 0x201, ((char *)slide,
  1840.                           "warning:  invalid length in QZ field for %s\n",
  1841.                           FnFilter1(G.filename)));
  1842.                     else
  1843.                         Info(slide, 0x201, ((char *)slide,
  1844.                           "warning:  invalid length in QZ field"));
  1845.                 if (jbp->header.d_type)
  1846.                 {
  1847.                     dlen = jbp->header.d_datalen;
  1848.                 }
  1849.             }
  1850.  
  1851.             if ((long)LG(dlen) > 0)
  1852.             {
  1853.                 zfseeko(G.outfile, -8, SEEK_END);
  1854.                 fread(&ntc, 8, 1, G.outfile);
  1855.                 if (ntc.id != *(long *)"XTcc")
  1856.                 {
  1857.                     ntc.id = *(long *)"XTcc";
  1858.                     ntc.dlen = dlen;
  1859.                     fwrite (&ntc, 8, 1, G.outfile);
  1860.                 }
  1861.                 Info(slide, 0x201, ((char *)slide, "QData = %d", LG(dlen)));
  1862.             }
  1863.             return;     /* finished, cancel further extra field scanning */
  1864.           }
  1865.  
  1866.           default:
  1867.             Trace((stderr,"qlfix: unknown extra field block, ID=%d\n",
  1868.                eb_id));
  1869.         }
  1870.  
  1871.         /* Skip this extra field block */
  1872.         ef_ptr += (eb_len + EB_HEADSIZE);
  1873.         ef_len -= (eb_len + EB_HEADSIZE);
  1874.     }
  1875. }
  1876. #endif /* QLZIP */
  1877.