home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 9 Archive / 09-Archive.zip / unzip540.zip / tandem / tandem.c < prev    next >
C/C++ Source or Header  |  1998-08-28  |  44KB  |  1,396 lines

  1. /*
  2.  * routines common to TANDEM
  3.  */
  4.  
  5. #define UNZIP_INTERNAL
  6. #include "unzip.h"
  7.  
  8. #include <tal.h>
  9. #include "$system.zsysdefs.zsysc" nolist
  10. #include <cextdecs(FILE_GETINFOLISTBYNAME_, \
  11.                    FILENAME_SCAN_,          \
  12.                    INTERPRETTIMESTAMP,      \
  13.                    CONVERTTIMESTAMP         \
  14.                   )>
  15. #include <cextdecs(FILENAME_FINDSTART_, \
  16.                    FILENAME_FINDNEXT_,  \
  17.                    FILENAME_FINDFINISH_ \
  18.                   )>
  19. #include <cextdecs(SETMODE)>
  20. #ifdef LICENSED
  21. #include <cextdecs(COMPUTETIMESTAMP,     \
  22.                    PROCESS_GETINFO_,     \
  23.                    PROCESS_GETINFOLIST_, \
  24.                    PROCESSHANDLE_NULLIT_ \
  25.                   )>
  26. #endif /* LICENSED */
  27.  
  28. char *in2ex OF((char *));
  29.  
  30.  
  31.  
  32. void zexit(status)
  33.   int status;
  34. {
  35.   terminate_program (0,0,status,,,);   /* Exit(>0) creates saveabend files */
  36. }
  37.  
  38.  
  39. #ifdef fopen
  40. #  undef fopen
  41. #endif
  42.  
  43. FILE *zipopen(fname, opt)
  44.   const char *fname;
  45.   const char *opt;
  46. {
  47.   int fdesc, fnum, err;
  48.  
  49.   if (strcmp(opt,FOPW) == 0)
  50.     if ((fdesc = creat(fname,,100,500)) != -1) {
  51.       fnum = fdtogfn(fdesc);
  52.       err = SETMODE(fnum, SET_FILE_BUFFERSIZE, TANDEM_BLOCKSIZE);
  53.       err = SETMODE(fnum, SET_FILE_BUFFERED, 0, 0);
  54.       err = SETMODE(fnum, SET_FILE_BUFFERED, 0, 1);
  55.       err = close(fdesc);
  56.     }
  57.  
  58.   return fopen(fname,opt);
  59. }
  60. #define fopen zipopen
  61.  
  62.  
  63. #ifdef putc
  64. #  undef putc
  65. #endif
  66.  
  67. int zputc(ch, fptr)
  68.   int ch;
  69.   FILE *fptr;
  70. {
  71.   int err;
  72.   err = putc(ch,fptr);
  73.   fflush(fptr);
  74.   return err;
  75. }
  76. #define putc zputc
  77.  
  78.  
  79. #ifdef LICENSED
  80. _tal _priv short FILE_CHANGELABEL_ (
  81.  short,          /* IN */
  82.  short,          /* IN */
  83.  short _far *    /* IN */
  84.  );
  85.  
  86. _c _callable int changelabel OF((short, const short *, const short *));
  87.  
  88. _c _callable int changelabel(fnum, modtime, actime)
  89.   short fnum;
  90.   const short *modtime;
  91.   const short *actime;
  92. {
  93.   int err;
  94.  
  95.   err = FILE_CHANGELABEL_(fnum, 16, modtime);
  96.   if (!err)
  97.     err = FILE_CHANGELABEL_(fnum, 17, actime);
  98.   return err;
  99. }
  100.  
  101. int islicensed OF((void));
  102.  
  103. int islicensed(void)
  104. {
  105.   #define plist_items 1
  106.   #define plist_size 10
  107.  
  108.   short myphandle[ZSYS_VAL_PHANDLE_WLEN];
  109.   short licensetag[plist_items] = {37};
  110.   short licensed[plist_size];
  111.   short maxlen = plist_size;
  112.   short items = plist_items;
  113.   short resultlen[1], err;
  114.  
  115.   err = PROCESSHANDLE_NULLIT_(myphandle);
  116.  
  117.   if (!err)
  118.     err = PROCESS_GETINFO_(myphandle);
  119.  
  120.   if (!err)
  121.     err = PROCESS_GETINFOLIST_(/*cpu*/,
  122.                                /*pin*/,
  123.                                /*nodename*/,
  124.                                /*nodenamelen*/,
  125.                                myphandle,
  126.                                licensetag,
  127.                                items,
  128.                                licensed,
  129.                                maxlen,
  130.                                resultlen
  131.                               );
  132.  
  133.   if (err != 0)
  134.     return 0;
  135.   else
  136.     return licensed[0];
  137. }
  138. #endif /* LICENSED */
  139.  
  140.  
  141. int utime OF((const char *, const ztimbuf *));
  142.  
  143. int utime(file, time)
  144.   const char *file;
  145.   const ztimbuf *time;
  146. {
  147. #ifdef LICENSED
  148.   int fdesc, result, err;
  149.   union timestamp_ov {
  150.     long long fulltime;
  151.     short wordtime[4];
  152.   };
  153.   union timestamp_ov lasttime, opentime;
  154.   struct tm *modt, *opent;
  155.   short datetime[8], errormask[1], fnum;
  156.  
  157.   if (islicensed() ) {
  158.     /* Attempt to update file label */
  159.     modt = gmtime( &time->modtime );
  160.  
  161.     datetime[0] = modt->tm_year + 1900;
  162.     datetime[1] = modt->tm_mon + 1;
  163.     datetime[2] = modt->tm_mday;
  164.     datetime[3] = modt->tm_hour;
  165.     datetime[4] = modt->tm_min;
  166.     datetime[5] = modt->tm_sec;
  167.     datetime[6] = datetime[7] = 0;
  168.     errormask[0] = 0;
  169.     lasttime.fulltime = COMPUTETIMESTAMP (datetime, errormask);
  170.  
  171.     opent = gmtime( &time->actime );
  172.  
  173.     datetime[0] = opent->tm_year + 1900;
  174.     datetime[1] = opent->tm_mon + 1;
  175.     datetime[2] = opent->tm_mday;
  176.     datetime[3] = opent->tm_hour;
  177.     datetime[4] = opent->tm_min;
  178.     datetime[5] = opent->tm_sec;
  179.     datetime[6] = datetime[7] = 0;
  180.     errormask[0] = 0;
  181.     opentime.fulltime = COMPUTETIMESTAMP (datetime, errormask);
  182.  
  183.     fdesc = open(file, O_WRONLY);
  184.     fnum = fdtogfn(fdesc);
  185.     result = changelabel(fnum,lasttime.wordtime,opentime.wordtime);
  186.     err = close(fdesc);
  187.     return result;
  188.   }
  189.   return -1;
  190. #else  /* !LICENSED */
  191.   return 0;             /* "no error", to suppress annoying failure messages */
  192. #endif  /* ?LICENSED */
  193. }
  194.  
  195.  
  196. /* TANDEM version of chmod() function */
  197.  
  198. int chmod(file, unix_sec)
  199.   const char *file;
  200.   mode_t unix_sec;
  201. {
  202.   FILE *stream;
  203.   struct nsk_sec_type {
  204.     unsigned progid : 1;
  205.     unsigned clear  : 1;
  206.     unsigned null   : 2;
  207.     unsigned read   : 3;
  208.     unsigned write  : 3;
  209.     unsigned execute: 3;
  210.     unsigned purge  : 3;
  211.   };
  212.   union nsk_sec_ov {
  213.     struct nsk_sec_type bit_ov;
  214.     short int_ov;
  215.   };
  216.   union nsk_sec_ov nsk_sec;
  217.   short fnum, fdes, err, nsk_sec_int;
  218.  
  219.  
  220.   nsk_sec.bit_ov.progid = 0;
  221.   nsk_sec.bit_ov.clear  = 0;
  222.   nsk_sec.bit_ov.null   = 0;
  223.  
  224.   /*  4="N", 5="C", 6="U", 7="-"   */
  225.  
  226.   if (unix_sec & S_IROTH) nsk_sec.bit_ov.read = 4;
  227.   else if (unix_sec & S_IRGRP) nsk_sec.bit_ov.read = 5;
  228.   else if (unix_sec & S_IRUSR) nsk_sec.bit_ov.read = 6;
  229.   else nsk_sec.bit_ov.read = 7;
  230.  
  231.   if (unix_sec & S_IWOTH) nsk_sec.bit_ov.write = 4;
  232.   else if (unix_sec & S_IWGRP) nsk_sec.bit_ov.write = 5;
  233.   else if (unix_sec & S_IWUSR) nsk_sec.bit_ov.write = 6;
  234.   else nsk_sec.bit_ov.write = 7;
  235.  
  236.   if (unix_sec & S_IXOTH) nsk_sec.bit_ov.execute = 4;
  237.   else if (unix_sec & S_IXGRP) nsk_sec.bit_ov.execute = 5;
  238.   else if (unix_sec & S_IXUSR) nsk_sec.bit_ov.execute = 6;
  239.   else nsk_sec.bit_ov.execute = 7;
  240.  
  241.   nsk_sec.bit_ov.purge = nsk_sec.bit_ov.write;
  242.  
  243.   nsk_sec_int = nsk_sec.int_ov;
  244.  
  245.   if ((fdes = open(file, (O_EXCLUSIVE | O_RDONLY))) == -1)
  246.     return -1;
  247.   fnum = fdtogfn(fdes);
  248.   err = SETMODE(fnum, SET_FILE_SECURITY, nsk_sec_int);
  249.   close(fdes);
  250.   return (err != 0 ? -1 : 0);
  251. }
  252.  
  253.  
  254. /* TANDEM version of chown() function */
  255.  
  256. int chown(file, uid, gid)
  257.   const char *file;
  258.   uid_t uid;
  259.   gid_t gid;
  260. {
  261.   FILE *stream;
  262.   struct nsk_own_type {
  263.     unsigned group  : 8;
  264.     unsigned user   : 8;
  265.   };
  266.   union nsk_own_ov {
  267.     struct nsk_own_type bit_ov;
  268.     short int_ov;
  269.   };
  270.   union nsk_own_ov nsk_own;
  271.   short fnum, fdes, err, nsk_own_int;
  272.  
  273.   nsk_own.bit_ov.group = gid;
  274.   nsk_own.bit_ov.user  = uid;
  275.  
  276.   nsk_own_int = nsk_own.int_ov;
  277.  
  278.   if ((fdes = open(file, (O_EXCLUSIVE | O_RDONLY))) == -1)
  279.     return -1;
  280.   fnum = fdtogfn(fdes);
  281.   err = SETMODE(fnum, SET_FILE_OWNER, nsk_own_int);
  282.   close(fdes);
  283.   return (err != 0 ? -1 : 0);
  284. }
  285.  
  286.  
  287. /* TANDEM version of stat() function */
  288.  
  289. time_t gmt_to_time_t (long long *);
  290.  
  291. time_t gmt_to_time_t (gmt)
  292.   long long *gmt;
  293. {
  294.   #define GMT_TO_LCT 0;
  295.   #define GMT_TO_LST 1;
  296.  
  297.   struct tm temp_tm;
  298.   short  date_time[8];
  299.   long   julian_dayno;
  300.   long long lct, lst, itime;
  301.   short  err[1], type;
  302.  
  303.   type = GMT_TO_LCT;
  304.   lct = CONVERTTIMESTAMP(*gmt, type,, err);
  305.  
  306.   if (!err[0]) {
  307.     type = GMT_TO_LST;
  308.     lst = CONVERTTIMESTAMP(*gmt, type,, err);
  309.   }
  310.  
  311.   itime = (err[0] ? *gmt : lct);
  312.   temp_tm.tm_isdst = (err[0] ? -1 : ((lct == lst) ? 0 : 1));
  313.  
  314.   julian_dayno = INTERPRETTIMESTAMP (itime, date_time);
  315.  
  316.   temp_tm.tm_sec   = date_time[5];
  317.   temp_tm.tm_min   = date_time[4];
  318.   temp_tm.tm_hour  = date_time[3];
  319.   temp_tm.tm_mday  = date_time[2];
  320.   temp_tm.tm_mon   = date_time[1] - 1;     /* C's so sad */
  321.   temp_tm.tm_year  = date_time[0] - 1900;  /* it's almost funny */
  322.  
  323.   return (mktime(&temp_tm));
  324. }
  325.  
  326. short parsename( const char *, char *, char * );
  327.  
  328. short parsename(srce, fname, ext)
  329.   const char *srce;
  330.   char *fname;
  331.   char *ext;
  332. {
  333.   /* As a way of supporting DOS extensions from Tandem we look for a space
  334.      separated extension string after the Guardian filename
  335.      e.g. ZIP ZIPFILE "$DATA4.TESTING.INVOICE TXT"
  336.   */
  337.  
  338.   char *fstart;
  339.   char *fptr;
  340.   short extension = 0;
  341.  
  342.   *fname = *ext = '\0';  /* set to null string */
  343.  
  344.   fstart = (char *) srce;
  345.  
  346.   if ((fptr = strrchr(fstart, TANDEM_EXTENSION)) != NULL) {
  347.     extension = 1;
  348.  
  349.     fptr++;
  350.     strncat(ext, fptr, _min(EXTENSION_MAX, strlen(fptr)));
  351.  
  352.     fptr = strchr(fstart, TANDEM_EXTENSION);  /* End of filename */
  353.     strncat(fname, fstart, _min(FILENAME_MAX, (fptr - fstart)));
  354.   }
  355.   else {
  356.     /* just copy string */
  357.     strncat(fname, srce, _min(FILENAME_MAX, strlen(srce)));
  358.   }
  359.  
  360.   return extension;
  361. }
  362.  
  363. int stat(n, s)
  364. const char *n;
  365. struct stat *s;
  366. {
  367.   #define flist_items 14
  368.   #define flist_size 200
  369.  
  370.   short err, i, extension;
  371.   char fname[FILENAME_MAX + 1];
  372.   short fnamelen;
  373.   char ext[EXTENSION_MAX + 1];
  374.                          /* #0  #1  #2  #3 #4 #5 #6 #7 #8 #9 #10 #11 #12 #13 */
  375. /*short ilist[flist_items]={62,117,145,142,58,41,42,30,31,75, 78, 79, 60,119}*/
  376.   short ilist[flist_items]={62, 56,144,142,58,41,42,30,31,75, 78, 79, 60, 54};
  377.   short ilen[flist_items] ={ 2,  4,  4,  2, 1, 1, 1, 1, 1, 1,  1,  1,  1,  4};
  378.   short ioff[flist_items];
  379.   short flist[flist_size];
  380.   short extra[2];
  381.   short *rlen=&extra[0];
  382.   short *err_item=&extra[1];
  383.   unsigned short *fowner;
  384.   unsigned short *fprogid;
  385.   char *fsec;
  386.  
  387.   short end, count, kind, level, options, searchid;
  388.   short info[5];
  389.  
  390.   /* Initialise stat structure */
  391.   s->st_dev = _S_GUARDIANOBJECT;
  392.   s->st_ino = 0;
  393.   s->st_nlink = 0;
  394.   s->st_rdev = 0;
  395.   s->st_uid = s->st_gid = 0;
  396.   s->st_size = 0;
  397.   s->st_atime = s->st_ctime = s->st_mtime = 0;
  398.   s->st_reserved[0] = 0;
  399.  
  400.   /* Check to see if name contains a (pseudo) file extension */
  401.   extension = parsename (n,fname,ext);
  402.  
  403.   fnamelen = strlen(fname);
  404.  
  405.   options = 3; /* Allow Subvols and Templates */
  406.   err = FILENAME_SCAN_( fname,
  407.                         fnamelen,
  408.                         &count,
  409.                         &kind,
  410.                         &level,
  411.                         options
  412.                       );
  413.  
  414.   /* allow kind == 2 (DEFINE names) */
  415.   if (err != 0) return -1;
  416.  
  417.   if (kind == 1 || (kind == 0 && level < 2)) {
  418.     /* Pattern, Subvol Name or One part Filename - lets see if it exists */
  419.     err = FILENAME_FINDSTART_ ( &searchid,
  420.                                 fname,
  421.                                 fnamelen,
  422.                                 ,
  423.                                 DISK_DEVICE
  424.                               );
  425.  
  426.     if (err != 0) {
  427.       end = FILENAME_FINDFINISH_ ( searchid );
  428.       return -1;
  429.     }
  430.  
  431.     err = FILENAME_FINDNEXT_ ( searchid,
  432.                                fname,
  433.                                FILENAME_MAX,
  434.                                &fnamelen,
  435.                                info
  436.                               );
  437.     end = FILENAME_FINDFINISH_ ( searchid );
  438.  
  439.     if (err != 0)
  440.       return -1;  /* Non existing template, subvol or file */
  441.  
  442.     if (kind == 1 || info[2] == -1) {
  443.       s->st_mode = S_IFDIR;    /* Its an existing template or directory */
  444.       return 0;
  445.     }
  446.  
  447.     /* Must be a real file so drop to code below to get info on it */
  448.   }
  449.  
  450.   err = FILE_GETINFOLISTBYNAME_( fname,
  451.                                  fnamelen,
  452.                                  ilist,
  453.                                  flist_items,
  454.                                  flist,
  455.                                  flist_size,
  456.                                  rlen,
  457.                                  err_item
  458.                                );
  459.  
  460.   if (err != 0) return -1;
  461.  
  462.   ioff[0] = 0;
  463.  
  464.   /*  Build up table of offets into result list */
  465.   for (i=1; i < flist_items; i++)
  466.     ioff[i] = ioff[i-1] + ilen[i-1];
  467.  
  468.  
  469.   /* Setup timestamps */
  470.   s->st_atime = gmt_to_time_t ((long long *)&flist[ioff[1]]);
  471.   s->st_mtime = s->st_ctime = gmt_to_time_t ((long long *)&flist[ioff[2]]);
  472.   s->st_reserved[0] = (int64_t) gmt_to_time_t ((long long *)&flist[ioff[13]]);
  473.  
  474.   s->st_size = *(off_t *)&flist[ioff[3]];
  475.  
  476.   fowner = (unsigned short *)&flist[ioff[4]];
  477.   s->st_uid = *fowner & 0x00ff;
  478.   s->st_gid = *fowner >> 8;
  479.  
  480.   /* Note that Purge security (fsec[3]) in NSK has no relevance to stat() */
  481.   fsec = (char *)&flist[ioff[0]];
  482.   fprogid = (unsigned short *)&flist[ioff[12]];
  483.  
  484.   s->st_mode = S_IFREG |  /* Regular File */
  485.   /*  Parse Read Flag */
  486.                ((fsec[0] & 0x03) == 0x00 ? S_IROTH : 0) |
  487.                ((fsec[0] & 0x02) == 0x00 ? S_IRGRP : 0) |
  488.                ((fsec[0] & 0x03) != 0x03 ? S_IRUSR : 0) |
  489.   /*  Parse Write Flag */
  490.                ((fsec[1] & 0x03) == 0x00 ? S_IWOTH : 0) |
  491.                ((fsec[1] & 0x02) == 0x00 ? S_IWGRP : 0) |
  492.                ((fsec[1] & 0x03) != 0x03 ? S_IWUSR : 0) |
  493.   /*  Parse Execute Flag */
  494.                ((fsec[2] & 0x03) == 0x00 ? S_IXOTH : 0) |
  495.                ((fsec[2] & 0x02) == 0x00 ? S_IXGRP : 0) |
  496.                ((fsec[2] & 0x03) != 0x03 ? S_IXUSR : 0) |
  497.   /*  Parse Progid */
  498.                (*fprogid == 1 ? (S_ISUID | S_ISGID) : 0) ;
  499.  
  500.   return 0;
  501. }
  502.  
  503.  
  504.  
  505. /* TANDEM Directory processing */
  506.  
  507. DIR *opendir(const char *dirname)
  508. {
  509.    short i, resolve;
  510.    char sname[FILENAME_MAX + 1];
  511.    short snamelen;
  512.    char fname[FILENAME_MAX + 1];
  513.    short fnamelen;
  514.    char *p;
  515.    short searchid, err, end;
  516.    struct dirent *entry;
  517.    DIR *dirp;
  518.    char ext[EXTENSION_MAX + 1];
  519.    short extension;
  520.  
  521.    extension = parsename(dirname, sname, ext);
  522.    snamelen = strlen(sname);
  523.  
  524.    /*  First we work out how detailed the template is...
  525.     *  e.g. If the template is DAVES*.* we want the search result
  526.     *       in the same format
  527.     */
  528.  
  529.    p = sname;
  530.    i = 0;
  531.    while ((p = strchr(p, TANDEM_DELIMITER)) != NULL){
  532.      i++;
  533.      p++;
  534.    };
  535.    resolve = 2 - i;
  536.  
  537.    /*  Attempt to start a filename template */
  538.    err = FILENAME_FINDSTART_ ( &searchid,
  539.                                sname,
  540.                                snamelen,
  541.                                resolve,
  542.                                DISK_DEVICE
  543.                              );
  544.    if (err != 0) {
  545.      end = FILENAME_FINDFINISH_(searchid);
  546.      return NULL;
  547.    }
  548.  
  549.    /* Create DIR structure */
  550.    if ((dirp = malloc(sizeof(DIR))) == NULL ) {
  551.      end = FILENAME_FINDFINISH_(searchid);
  552.      return NULL;
  553.    }
  554.    dirp->D_list = dirp->D_curpos = NULL;
  555.    strcpy(dirp->D_path, dirname);
  556.  
  557.    while ((err = FILENAME_FINDNEXT_(searchid,
  558.                                     fname,
  559.                                     FILENAME_MAX,
  560.                                     &fnamelen
  561.                                    )
  562.            ) == 0 ){
  563.      /*  Create space for entry */
  564.      if ((entry = malloc (sizeof(struct dirent))) == NULL) {
  565.        end = FILENAME_FINDFINISH_(searchid);
  566.        return NULL;
  567.      }
  568.  
  569.      /*  Link to last entry */
  570.      if (dirp->D_curpos == NULL)
  571.        dirp->D_list = dirp->D_curpos = entry;  /* First name */
  572.      else {
  573.        dirp->D_curpos->d_next = entry;         /* Link */
  574.        dirp->D_curpos = entry;
  575.      };
  576.      /* Add directory entry */
  577.      *dirp->D_curpos->d_name = '\0';
  578.      strncat(dirp->D_curpos->d_name,fname,fnamelen);
  579.      if (extension) {
  580.        strcat(dirp->D_curpos->d_name,TANDEM_EXTENSION_STR);
  581.        strcat(dirp->D_curpos->d_name,ext);
  582.      };
  583.      dirp->D_curpos->d_next = NULL;
  584.    };
  585.  
  586.    end = FILENAME_FINDFINISH_(searchid);
  587.  
  588.    if (err == 1) {  /*  Should return EOF at end of search */
  589.      dirp->D_curpos = dirp->D_list;        /* Set current pos to start */
  590.      return dirp;
  591.    } else
  592.      return NULL;
  593. }
  594.  
  595. struct dirent *readdir(DIR *dirp)
  596. {
  597.    struct dirent *cur;
  598.  
  599.    cur = dirp->D_curpos;
  600.    dirp->D_curpos = dirp->D_curpos->d_next;
  601.    return cur;
  602. }
  603.  
  604. void rewinddir(DIR *dirp)
  605. {
  606.    dirp->D_curpos = dirp->D_list;
  607. }
  608.  
  609. int closedir(DIR *dirp)
  610. {
  611.    struct dirent *node;
  612.  
  613.    while (dirp->D_list != NULL) {
  614.       node = dirp->D_list;
  615.       dirp->D_list = dirp->D_list->d_next;
  616.       free( node );
  617.    }
  618.    free( dirp );
  619.    return 0;
  620. }
  621.  
  622.  
  623. static int created_dir;        /* used in mapname(), checkdir() */
  624. static int renamed_fullpath;   /* ditto */
  625.  
  626. /**********************/
  627. /* Function do_wild() */  /* for porting:  dir separator; match(ignore_case) */
  628. /**********************/
  629.  
  630. char *do_wild(__G__ wildspec)
  631.     __GDEF
  632.     char *wildspec;         /* only used first time on a given dir */
  633. {
  634.     static DIR *dir = (DIR *)NULL;
  635.     static char *dirname, *wildname, matchname[FILNAMSIZ];
  636.     static int firstcall=TRUE, have_dirname, dirnamelen;
  637.     struct dirent *file;
  638.     static char *intname;
  639.     int isdir = 0;
  640.     int pdosflag = 0;
  641.  
  642.     /* Even when we're just returning wildspec, we *always* do so in
  643.      * matchname[]--calling routine is allowed to append four characters
  644.      * to the returned string, and wildspec may be a pointer to argv[].
  645.      */
  646.     if (firstcall) {        /* first call:  must initialize everything */
  647.         firstcall = FALSE;
  648.  
  649.         if (!iswild(wildspec)) {
  650.             strcpy(matchname, wildspec);
  651.             have_dirname = FALSE;
  652.             dir = NULL;
  653.             return matchname;
  654.         }
  655.  
  656.         dirnamelen = strlen(wildspec);
  657.  
  658.         if ((dirname = (char *)malloc(dirnamelen+1)) == (char *)NULL) {
  659.             Info(slide, 0x201, ((char *)slide,
  660.               "warning:  cannot allocate wildcard buffers\n"));
  661.              strcpy(matchname, wildspec);
  662.              return matchname;   /* but maybe filespec was not a wildcard */
  663.         }
  664.         strcpy(dirname, wildspec);
  665.         wildname = wildspec;
  666.         have_dirname = FALSE;
  667.  
  668.         if ((dir = opendir(dirname)) != (DIR *)NULL) {
  669.             while ((file = readdir(dir)) != (struct dirent *)NULL) {
  670.                 Trace((stderr, "do_wild:  readdir returns %s\n", file->d_name));
  671.                 if (file->d_name[0] == '.' && wildname[0] != '.')
  672.                     continue;  /* Unix:  '*' and '?' do not match leading dot */
  673.                 if (match(file->d_name, wildname, 0) &&  /* 0 == case sens. */
  674.                     /* skip "." and ".." directory entries */
  675.                     strcmp(file->d_name, ".") && strcmp(file->d_name, "..")) {
  676.                     Trace((stderr, "do_wild:  match() succeeds\n"));
  677.                     if (have_dirname) {
  678.                         strcpy(matchname, dirname);
  679.                         strcpy(matchname+dirnamelen, file->d_name);
  680.                     } else
  681.                         strcpy(matchname, file->d_name);
  682.                     return matchname;
  683.                 }
  684.             }
  685.             /* if we get to here directory is exhausted, so close it */
  686.             closedir(dir);
  687.             dir = (DIR *)NULL;
  688.         }
  689.  
  690.         /* return the raw wildspec in case that works (e.g., directory not
  691.          * searchable, but filespec was not wild and file is readable) */
  692.         strcpy(matchname, wildspec);
  693.         return matchname;
  694.     }
  695.  
  696.     /* last time through, might have failed opendir but returned raw wildspec */
  697.     if (dir == (DIR *)NULL) {
  698.         firstcall = TRUE;  /* nothing left to try--reset for new wildspec */
  699.         if (have_dirname)
  700.             free(dirname);
  701.         return (char *)NULL;
  702.     }
  703.  
  704.     /* If we've gotten this far, we've read and matched at least one entry
  705.      * successfully (in a previous call), so dirname has been copied into
  706.      * matchname already.
  707.      */
  708.     while ((file = readdir(dir)) != (struct dirent *)NULL) {
  709.         Trace((stderr, "do_wild:  readdir returns %s\n", file->d_name));
  710.         if (file->d_name[0] == '.' && wildname[0] != '.')
  711.             continue;   /* Unix:  '*' and '?' do not match leading dot */
  712.         if (match(file->d_name, wildname, 0)) {   /* 0 == don't ignore case */
  713.             if (have_dirname) {
  714.                 /* strcpy(matchname, dirname); */
  715.                 strcpy(matchname+dirnamelen, file->d_name);
  716.             } else
  717.                 strcpy(matchname, file->d_name);
  718.             return matchname;
  719.         }
  720.     }
  721.  
  722.     closedir(dir);     /* have read at least one dir entry; nothing left */
  723.     dir = (DIR *)NULL;
  724.     firstcall = TRUE;  /* reset for new wildspec */
  725.     if (have_dirname)
  726.         free(dirname);
  727.     return (char *)NULL;
  728.  
  729. } /* end function do_wild() */
  730.  
  731.  
  732. /**********************/
  733. /* Function mapattr() */
  734. /**********************/
  735.  
  736. int mapattr(__G)
  737.     __GDEF
  738. {
  739.     ulg tmp = G.crec.external_file_attributes;
  740.  
  741.     switch (G.pInfo->hostnum) {
  742.         case AMIGA_:
  743.             tmp = (unsigned)(tmp>>17 & 7);   /* Amiga RWE bits */
  744.             G.pInfo->file_attr = (unsigned)(tmp<<6 | tmp<<3 | tmp);
  745.             break;
  746.         case UNIX_:
  747.         case VMS_:
  748.         case ACORN_:
  749.         case ATARI_:
  750.         case BEOS_:
  751.         case QDOS_:
  752.         case TANDEM_:
  753.             G.pInfo->file_attr = (unsigned)(tmp >> 16);
  754.             if (G.pInfo->file_attr != 0 || !G.extra_field) {
  755.                 return 0;
  756.             } else {
  757.                 /* Some (non-Info-ZIP) implementations of Zip for Unix and
  758.                    VMS (and probably others ??) leave 0 in the upper 16-bit
  759.                    part of the external_file_attributes field. Instead, they
  760.                    store file permission attributes in some extra field.
  761.                    As a work-around, we search for the presence of one of
  762.                    these extra fields and fall back to the MSDOS compatible
  763.                    part of external_file_attributes if one of the known
  764.                    e.f. types has been detected.
  765.                    Later, we might implement extraction of the permission
  766.                    bits from the VMS extra field. But for now, the work-around
  767.                    should be sufficient to provide "readable" extracted files.
  768.                    (For ASI Unix e.f., an experimental remap of the e.f.
  769.                    mode value IS already provided!)
  770.                  */
  771.                 ush ebID;
  772.                 unsigned ebLen;
  773.                 uch *ef = G.extra_field;
  774.                 unsigned ef_len = G.crec.extra_field_length;
  775.                 int r = FALSE;
  776.  
  777.                 while (!r && ef_len >= EB_HEADSIZE) {
  778.                     ebID = makeword(ef);
  779.                     ebLen = (unsigned)makeword(ef+EB_LEN);
  780.                     if (ebLen > (ef_len - EB_HEADSIZE))
  781.                         /* discoverd some e.f. inconsistency! */
  782.                         break;
  783.                     switch (ebID) {
  784.                       case EF_ASIUNIX:
  785.                         if (ebLen >= (EB_ASI_MODE+2)) {
  786.                             G.pInfo->file_attr =
  787.                               (unsigned)makeword(ef+(EB_HEADSIZE+EB_ASI_MODE));
  788.                             /* force stop of loop: */
  789.                             ef_len = (ebLen + EB_HEADSIZE);
  790.                             break;
  791.                         }
  792.                         /* else: fall through! */
  793.                       case EF_PKVMS:
  794.                         /* "found nondecypherable e.f. with perm. attr" */
  795.                         r = TRUE;
  796.                       default:
  797.                         break;
  798.                     }
  799.                     ef_len -= (ebLen + EB_HEADSIZE);
  800.                     ef += (ebLen + EB_HEADSIZE);
  801.                 }
  802.                 if (!r)
  803.                     return 0;
  804.             }
  805.             /* fall through! */
  806.         /* all remaining cases:  expand MSDOS read-only bit into write perms */
  807.         case FS_FAT_:
  808.         case FS_HPFS_:
  809.         case FS_NTFS_:
  810.         case MAC_:
  811.         case TOPS20_:
  812.         default:
  813.             tmp = !(tmp & 1) << 1;   /* read-only bit --> write perms bits */
  814.             G.pInfo->file_attr = (unsigned)(0444 | tmp<<6 | tmp<<3 | tmp);
  815.             break;
  816.     } /* end switch (host-OS-created-by) */
  817.  
  818.     /* for originating systems with no concept of "group," "other," "system": */
  819.     umask( (int)(tmp=umask(0)) );    /* apply mask to expanded r/w(/x) perms */
  820.     G.pInfo->file_attr &= ~tmp;
  821.  
  822.     return 0;
  823.  
  824. } /* end function mapattr() */
  825.  
  826.  
  827.  
  828. /************************/
  829. /*  Function mapname()  */
  830. /************************/
  831.                              /* return 0 if no error, 1 if caution (filename */
  832. int mapname(__G__ renamed)   /*  truncated), 2 if warning (skip file because */
  833.     __GDEF                   /*  dir doesn't exist), 3 if error (skip file), */
  834.     int renamed;             /*  or 10 if out of memory (skip file) */
  835. {                            /*  [also IZ_VOL_LABEL, IZ_CREATED_DIR] */
  836.     char pathcomp[FILNAMSIZ];      /* path-component buffer */
  837.     char *pp, *cp;                 /* character pointers */
  838.     char *lastsemi=(char *)NULL;   /* pointer to last semi-colon in pathcomp */
  839.     int quote = FALSE;             /* flags */
  840.     int error = 0;
  841.     register unsigned workch;      /* hold the character being tested */
  842.  
  843.  
  844. /*---------------------------------------------------------------------------
  845.     Initialize various pointers and counters and stuff.
  846.   ---------------------------------------------------------------------------*/
  847.  
  848.     if (G.pInfo->vollabel)
  849.         return IZ_VOL_LABEL;    /* can't set disk volume labels on Tandem */
  850.  
  851.     /* can create path as long as not just freshening, or if user told us */
  852.     G.create_dirs = (!uO.fflag || renamed);
  853.  
  854.     created_dir = FALSE;        /* not yet */
  855.  
  856.     /* user gave full pathname:  don't prepend rootpath */
  857.     renamed_fullpath = (renamed && (*G.filename == '/'));
  858.  
  859.     if (checkdir(__G__ (char *)NULL, INIT) == 10)
  860.         return 10;              /* initialize path buffer, unless no memory */
  861.  
  862.     /* TANDEM - call in2ex */
  863.     pp = in2ex(G.filename);
  864.     if (pp == (char *)NULL)
  865.         return 10;
  866.     strcpy(G.filename, pp);
  867.     free(pp);
  868.  
  869.     *pathcomp = '\0';           /* initialize translation buffer */
  870.     pp = pathcomp;              /* point to translation buffer */
  871.     /* directories have already been junked in in2ex() */
  872.     cp = G.filename;            /* point to internal zipfile-member pathname */
  873.  
  874. /*---------------------------------------------------------------------------
  875.     Begin main loop through characters in filename.
  876.   ---------------------------------------------------------------------------*/
  877.  
  878.     while ((workch = (uch)*cp++) != 0) {
  879.  
  880.         if (quote) {                 /* if character quoted, */
  881.             *pp++ = (char)workch;    /*  include it literally */
  882.             quote = FALSE;
  883.         } else
  884.             switch (workch) {
  885.             case TANDEM_DELIMITER: /* can assume -j flag not given */
  886.                 *pp = '\0';
  887.                 if ((error = checkdir(__G__ pathcomp, APPEND_DIR)) > 1)
  888.                     return error;
  889.                 pp = pathcomp;    /* reset conversion buffer for next piece */
  890.                 lastsemi = (char *)NULL; /* leave directory semi-colons alone */
  891.                 break;
  892.  
  893.             case ';':             /* VMS version (or DEC-20 attrib?) */
  894.                 lastsemi = pp;
  895.                 *pp++ = ';';      /* keep for now; remove VMS ";##" */
  896.                 break;            /*  later, if requested */
  897.  
  898.             case '\026':          /* control-V quote for special chars */
  899.                 quote = TRUE;     /* set flag for next character */
  900.                 break;
  901.  
  902.             case ' ':             /* remove spaces for Tandem */
  903.                 break;
  904.  
  905.             default:
  906.                 /* allow European characters in filenames: */
  907.                 if (isprint(workch) || (128 <= workch && workch <= 254))
  908.                     *pp++ = (char)workch;
  909.             } /* end switch */
  910.  
  911.     } /* end while loop */
  912.  
  913.     *pp = '\0';                   /* done with pathcomp:  terminate it */
  914.  
  915.     /* if not saving them, remove VMS version numbers (appended ";###") */
  916.     if (!uO.V_flag && lastsemi) {
  917.         pp = lastsemi + 1;
  918.         while (isdigit((uch)(*pp)))
  919.             ++pp;
  920.         if (*pp == '\0')          /* only digits between ';' and end:  nuke */
  921.             *lastsemi = '\0';
  922.     }
  923.  
  924. /*---------------------------------------------------------------------------
  925.     Report if directory was created (and no file to create:  filename ended
  926.     in '/'), check name to be sure it exists, and combine path and name be-
  927.     fore exiting.
  928.   ---------------------------------------------------------------------------*/
  929.  
  930.     if (G.filename[strlen(G.filename) - 1] == TANDEM_DELIMITER) {
  931.         checkdir(__G__ G.filename, GETPATH);
  932.         if (created_dir) {
  933.             if (QCOND2) {
  934.                 Info(slide, 0, ((char *)slide, "   creating: %s\n",
  935.                   G.filename));
  936.             }
  937.             return IZ_CREATED_DIR;   /* set dir time (note trailing '/') */
  938.         }
  939.         return 2;   /* dir existed already; don't look for data to extract */
  940.     }
  941.  
  942.     if (*pathcomp == '\0') {
  943.         Info(slide, 1, ((char *)slide, "mapname:  conversion of %s failed\n",
  944.           G.filename));
  945.         return 3;
  946.     }
  947.  
  948.     checkdir(__G__ pathcomp, APPEND_NAME);  /* returns 1 if truncated: care? */
  949.     checkdir(__G__ G.filename, GETPATH);
  950.  
  951.     return error;
  952.  
  953. } /* end function mapname() */
  954.  
  955.  
  956.  
  957. /***********************/
  958. /* Function checkdir() */
  959. /***********************/
  960.  
  961. int checkdir(__G__ pathcomp, flag)
  962.     __GDEF
  963.     char *pathcomp;
  964.     int flag;
  965. /*
  966.  * returns:  1 - (on APPEND_NAME) truncated filename
  967.  *           2 - path doesn't exist, not allowed to create
  968.  *           3 - path doesn't exist, tried to create and failed; or
  969.  *               path exists and is not a directory, but is supposed to be
  970.  *           4 - path is too long
  971.  *          10 - can't allocate memory for filename buffers
  972.  */
  973. {
  974.     static int rootlen = 0;   /* length of rootpath */
  975.     static char *rootpath;    /* user's "extract-to" directory */
  976.     static char *buildpath;   /* full path (so far) to extracted file */
  977.     static char *end;         /* pointer to end of buildpath ('\0') */
  978.  
  979. #   define FN_MASK   7
  980. #   define FUNCTION  (flag & FN_MASK)
  981.  
  982.  
  983.  
  984. /*---------------------------------------------------------------------------
  985.     APPEND_DIR:  append the path component to the path being built and check
  986.     for its existence.  If doesn't exist and we are creating directories, do
  987.     so for this one; else signal success or error as appropriate.
  988.   ---------------------------------------------------------------------------*/
  989.  
  990.     if (FUNCTION == APPEND_DIR) {
  991.         int too_long = FALSE;
  992. #ifdef SHORT_NAMES
  993.         char *old_end = end;
  994. #endif
  995.  
  996.         Trace((stderr, "appending dir segment [%s]\n", pathcomp));
  997.         while ((*end = *pathcomp++) != '\0')
  998.             ++end;
  999. #ifdef SHORT_NAMES   /* path components restricted to 14 chars, typically */
  1000.         if ((end-old_end) > FILENAME_MAX)  /* GRR:  proper constant? */
  1001.             *(end = old_end + FILENAME_MAX) = '\0';
  1002. #endif
  1003.  
  1004.         /* GRR:  could do better check, see if overrunning buffer as we go:
  1005.          * check end-buildpath after each append, set warning variable if
  1006.          * within 20 of FILNAMSIZ; then if var set, do careful check when
  1007.          * appending.  Clear variable when begin new path. */
  1008.  
  1009.         if ((end-buildpath) > FILNAMSIZ-3)  /* need '/', one-char name, '\0' */
  1010.             too_long = TRUE;                /* check if extracting directory? */
  1011.         if (stat(buildpath, &G.statbuf)) {  /* path doesn't exist */
  1012.             if (!G.create_dirs) { /* told not to create (freshening) */
  1013.                 free(buildpath);
  1014.                 return 2;         /* path doesn't exist:  nothing to do */
  1015.             }
  1016.             if (too_long) {
  1017.                 Info(slide, 1, ((char *)slide,
  1018.                   "checkdir error:  path too long: %s\n", buildpath));
  1019.                 free(buildpath);
  1020.                 return 4;         /* no room for filenames:  fatal */
  1021.             }
  1022.             if (mkdir(buildpath, 0777) == -1) {   /* create the directory */
  1023.                 Info(slide, 1, ((char *)slide,
  1024.                   "checkdir error:  cannot create %s\n\
  1025.                  unable to process %s.\n", buildpath, G.filename));
  1026.                 free(buildpath);
  1027.                 return 3;      /* path didn't exist, tried to create, failed */
  1028.             }
  1029.             created_dir = TRUE;
  1030.         } else if (!S_ISDIR(G.statbuf.st_mode)) {
  1031.             Info(slide, 1, ((char *)slide,
  1032.               "checkdir error:  %s exists but is not directory\n\
  1033.                  unable to process %s.\n", buildpath, G.filename));
  1034.             free(buildpath);
  1035.             return 3;          /* path existed but wasn't dir */
  1036.         }
  1037.         if (too_long) {
  1038.             Info(slide, 1, ((char *)slide,
  1039.               "checkdir error:  path too long: %s\n", buildpath));
  1040.             free(buildpath);
  1041.             return 4;         /* no room for filenames:  fatal */
  1042.         }
  1043.         *end++ = TANDEM_DELIMITER;
  1044.         *end = '\0';
  1045.         Trace((stderr, "buildpath now = [%s]\n", buildpath));
  1046.         return 0;
  1047.  
  1048.     } /* end if (FUNCTION == APPEND_DIR) */
  1049.  
  1050. /*---------------------------------------------------------------------------
  1051.     GETPATH:  copy full path to the string pointed at by pathcomp, and free
  1052.     buildpath.
  1053.   ---------------------------------------------------------------------------*/
  1054.  
  1055.     if (FUNCTION == GETPATH) {
  1056.         strcpy(pathcomp, buildpath);
  1057.         Trace((stderr, "getting and freeing path [%s]\n", pathcomp));
  1058.         free(buildpath);
  1059.         buildpath = end = (char *)NULL;
  1060.         return 0;
  1061.     }
  1062.  
  1063. /*---------------------------------------------------------------------------
  1064.     APPEND_NAME:  assume the path component is the filename; append it and
  1065.     return without checking for existence.
  1066.   ---------------------------------------------------------------------------*/
  1067.  
  1068.     if (FUNCTION == APPEND_NAME) {
  1069. #ifdef SHORT_NAMES
  1070.         char *old_end = end;
  1071. #endif
  1072.  
  1073.         Trace((stderr, "appending filename [%s]\n", pathcomp));
  1074.         while ((*end = *pathcomp++) != '\0') {
  1075.             ++end;
  1076. #ifdef SHORT_NAMES  /* truncate name at 14 characters, typically */
  1077.             if ((end-old_end) > FILENAME_MAX)      /* GRR:  proper constant? */
  1078.                 *(end = old_end + FILENAME_MAX) = '\0';
  1079. #endif
  1080.             if ((end-buildpath) >= FILNAMSIZ) {
  1081.                 *--end = '\0';
  1082.                 Info(slide, 0x201, ((char *)slide,
  1083.                   "checkdir warning:  path too long; truncating\n\
  1084.                    %s\n                -> %s\n", G.filename, buildpath));
  1085.                 return 1;   /* filename truncated */
  1086.             }
  1087.         }
  1088.         Trace((stderr, "buildpath now = [%s]\n", buildpath));
  1089.         return 0;  /* could check for existence here, prompt for new name... */
  1090.     }
  1091.  
  1092. /*---------------------------------------------------------------------------
  1093.     INIT:  allocate and initialize buffer space for the file currently being
  1094.     extracted.  If file was renamed with an absolute path, don't prepend the
  1095.     extract-to path.
  1096.   ---------------------------------------------------------------------------*/
  1097.  
  1098. /* GRR:  for VMS and TOPS-20, add up to 13 to strlen */
  1099.  
  1100.     if (FUNCTION == INIT) {
  1101.         Trace((stderr, "initializing buildpath to "));
  1102.         if ((buildpath = (char *)malloc(strlen(G.filename)+rootlen+1)) ==
  1103.             (char *)NULL)
  1104.             return 10;
  1105.         if ((rootlen > 0) && !renamed_fullpath) {
  1106.             strcpy(buildpath, rootpath);
  1107.             end = buildpath + rootlen;
  1108.         } else {
  1109.             *buildpath = '\0';
  1110.             end = buildpath;
  1111.         }
  1112.         Trace((stderr, "[%s]\n", buildpath));
  1113.         return 0;
  1114.     }
  1115.  
  1116. /*---------------------------------------------------------------------------
  1117.     ROOT:  if appropriate, store the path in rootpath and create it if neces-
  1118.     sary; else assume it's a zipfile member and return.  This path segment
  1119.     gets used in extracting all members from every zipfile specified on the
  1120.     command line.
  1121.   ---------------------------------------------------------------------------*/
  1122.  
  1123. #if (!defined(SFX) || defined(SFX_EXDIR))
  1124.     if (FUNCTION == ROOT) {
  1125.         Trace((stderr, "initializing root path to [%s]\n", pathcomp));
  1126.         if (pathcomp == (char *)NULL) {
  1127.             rootlen = 0;
  1128.             return 0;
  1129.         }
  1130.         if ((rootlen = strlen(pathcomp)) > 0) {
  1131.             if (pathcomp[rootlen-1] == TANDEM_DELIMITER) {
  1132.                 pathcomp[--rootlen] = '\0';
  1133.             }
  1134.             if (rootlen > 0 && (stat(pathcomp, &G.statbuf) ||
  1135.                 !S_ISDIR(G.statbuf.st_mode)))        /* path does not exist */
  1136.             {
  1137.                 if (!G.create_dirs /* || iswild(pathcomp) */ ) {
  1138.                     rootlen = 0;
  1139.                     return 2;   /* skip (or treat as stored file) */
  1140.                 }
  1141.                 /* create the directory (could add loop here to scan pathcomp
  1142.                  * and create more than one level, but why really necessary?) */
  1143.                 if (mkdir(pathcomp, 0777) == -1) {
  1144.                     Info(slide, 1, ((char *)slide,
  1145.                       "checkdir:  cannot create extraction directory: %s\n",
  1146.                       pathcomp));
  1147.                     rootlen = 0;   /* path didn't exist, tried to create, and */
  1148.                     return 3;  /* failed:  file exists, or 2+ levels required */
  1149.                 }
  1150.             }
  1151.             if ((rootpath = (char *)malloc(rootlen+2)) == (char *)NULL) {
  1152.                 rootlen = 0;
  1153.                 return 10;
  1154.             }
  1155.             strcpy(rootpath, pathcomp);
  1156.             rootpath[rootlen++] = TANDEM_DELIMITER;
  1157.             rootpath[rootlen] = '\0';
  1158.             Trace((stderr, "rootpath now = [%s]\n", rootpath));
  1159.         }
  1160.         return 0;
  1161.     }
  1162. #endif /* !SFX || SFX_EXDIR */
  1163.  
  1164. /*---------------------------------------------------------------------------
  1165.     END:  free rootpath, immediately prior to program exit.
  1166.   ---------------------------------------------------------------------------*/
  1167.  
  1168.     if (FUNCTION == END) {
  1169.         Trace((stderr, "freeing rootpath\n"));
  1170.         if (rootlen > 0) {
  1171.             free(rootpath);
  1172.             rootlen = 0;
  1173.         }
  1174.         return 0;
  1175.     }
  1176.  
  1177.     return 99;  /* should never reach */
  1178.  
  1179. } /* end function checkdir() */
  1180.  
  1181.  
  1182.  
  1183. /********************/
  1184. /* Function mkdir() */
  1185. /********************/
  1186.  
  1187. int mkdir(path, mode)
  1188. const char *path;  /* both    */
  1189. mode_t mode;       /* ignored */
  1190. /*
  1191.  * returns:   0 - successful
  1192.  *           -1 - failed (errno not set, however)
  1193.  */
  1194. {
  1195.     return 0;
  1196. }
  1197.  
  1198.  
  1199. /************************/
  1200. /*  Function version()  */
  1201. /************************/
  1202.  
  1203. void version(__G)
  1204.     __GDEF
  1205. {
  1206.  
  1207.     /* Pyramid, NeXT have problems with huge macro expansion, too: no Info() */
  1208.     sprintf((char *)slide, LoadFarString(CompiledWith),
  1209.  
  1210. #ifdef __GNUC__
  1211.       "gcc ", __VERSION__,
  1212. #else
  1213. #  ifdef __VERSION__
  1214.       "cc ", __VERSION__,
  1215. #  else
  1216.       "cc", "",
  1217. #  endif
  1218. #endif
  1219.  
  1220.       "Unix",
  1221.  
  1222. #ifdef TANDEM
  1223.       " (Tandem/NSK)",
  1224. #else
  1225.       "",
  1226. #endif /* TANDEM */
  1227.  
  1228. #ifdef __DATE__
  1229.       " on ", __DATE__
  1230. #else
  1231.       "", ""
  1232. #endif
  1233.     );
  1234.  
  1235.     (*G.message)((zvoid *)&G, slide, (ulg)strlen((char *)slide), 0);
  1236.  
  1237. } /* end function version() */
  1238.  
  1239.  
  1240.  
  1241.  
  1242. /****************************/
  1243. /* Function close_outfile() */
  1244. /****************************/
  1245.  
  1246. void close_outfile(__G)    /* GRR: change to return PK-style warning level */
  1247.     __GDEF
  1248. {
  1249.     iztimes zt;
  1250.     ush z_uidgid[2];
  1251.     unsigned eb_izux_flg;
  1252.  
  1253.     fclose(G.outfile);
  1254.  
  1255. /*---------------------------------------------------------------------------
  1256.     Convert from MSDOS-format local time and date to Unix-format 32-bit GMT
  1257.     time:  adjust base year from 1980 to 1970, do usual conversions from
  1258.     yy/mm/dd hh:mm:ss to elapsed seconds, and account for timezone and day-
  1259.     light savings time differences.  If we have a Unix extra field, however,
  1260.     we're laughing:  both mtime and atime are ours.  On the other hand, we
  1261.     then have to check for restoration of UID/GID.
  1262.   ---------------------------------------------------------------------------*/
  1263.  
  1264.     eb_izux_flg = (G.extra_field ? ef_scan_for_izux(G.extra_field,
  1265.                    G.lrec.extra_field_length, 0, G.lrec.last_mod_dos_datetime,
  1266. #ifdef IZ_CHECK_TZ
  1267.                    (G.tz_is_valid ? &zt : NULL),
  1268. #else
  1269.                    &zt,
  1270. #endif
  1271.                    z_uidgid) : 0);
  1272.     if (eb_izux_flg & EB_UT_FL_MTIME) {
  1273.         TTrace((stderr, "\nclose_outfile:  Unix e.f. modif. time = %ld\n",
  1274.           zt.mtime));
  1275.     } else {
  1276.         zt.mtime = dos_to_unix_time(G.lrec.last_mod_dos_datetime);
  1277.     }
  1278.     if (eb_izux_flg & EB_UT_FL_ATIME) {
  1279.         TTrace((stderr, "close_outfile:  Unix e.f. access time = %ld\n",
  1280.           zt.atime));
  1281.     } else {
  1282.         zt.atime = zt.mtime;
  1283.         TTrace((stderr, "\nclose_outfile:  modification/access times = %ld\n",
  1284.           zt.mtime));
  1285.     }
  1286.  
  1287. /*---------------------------------------------------------------------------
  1288.     Change the file's last modified time to that stored in the zipfile.
  1289.     Not sure how (yet) or whether its a good idea to set the last open time
  1290.   ---------------------------------------------------------------------------*/
  1291.  
  1292.     if (utime(G.filename, (ztimbuf *)&zt))
  1293.         if (uO.qflag)
  1294.             Info(slide, 0x201, ((char *)slide,
  1295.               "warning:  cannot set times for %s\n", G.filename));
  1296.         else
  1297.             Info(slide, 0x201, ((char *)slide,
  1298.               " (warning) cannot set times"));
  1299.  
  1300. /*---------------------------------------------------------------------------
  1301.     Change the file permissions from default ones to those stored in the
  1302.     zipfile.
  1303.   ---------------------------------------------------------------------------*/
  1304.  
  1305. #ifndef NO_CHMOD
  1306.     if (chmod(G.filename, 0xffff & G.pInfo->file_attr))
  1307.         perror("chmod (file attributes) error");
  1308. #endif
  1309.  
  1310. /*---------------------------------------------------------------------------
  1311.        if -X option was specified and we have UID/GID info, restore it
  1312.        this must come after the file security and modtimes changes - since once
  1313.        we have secured the file to somebody else we cannot access it again.
  1314.   ---------------------------------------------------------------------------*/
  1315.  
  1316.     if (uO.X_flag && eb_izux_flg & EB_UX2_VALID) {
  1317.         TTrace((stderr, "close_outfile:  restoring Unix UID/GID info\n"));
  1318.         if (chown(G.filename, (uid_t)z_uidgid[0], (gid_t)z_uidgid[1]))
  1319.         {
  1320.             if (uO.qflag)
  1321.                 Info(slide, 0x201, ((char *)slide,
  1322.                   "warning:  cannot set UID %d and/or GID %d for %s\n",
  1323.                   z_uidgid[0], z_uidgid[1], G.filename));
  1324.             else
  1325.                 Info(slide, 0x201, ((char *)slide,
  1326.                   " (warning) cannot set UID %d and/or GID %d",
  1327.                   z_uidgid[0], z_uidgid[1]));
  1328.         }
  1329.     }
  1330.  
  1331. } /* end function close_outfile() */
  1332.  
  1333.  
  1334.  
  1335.  
  1336. /********************/    /* swiped from Zip:  convert the zip file name to */
  1337. /* Function in2ex() */    /*  an external file name, returning the malloc'd */
  1338. /********************/    /*  string or NULL if not enough memory. */
  1339.  
  1340. char *in2ex(n)
  1341.     char *n;              /* internal file name */
  1342. {
  1343.     char *x;              /* external file name */
  1344.     char *t;              /* pointer to internal */
  1345.     char *p;              /* pointer to internal */
  1346.     char *e;              /* pointer to internal */
  1347.  
  1348.     if ((x = malloc(strlen(n) + 4)) == NULL)   /* + 4 for safety */
  1349.         return NULL;
  1350.     *x= '\0';
  1351.  
  1352.     /* Junk pathname as requested */
  1353.     if (uO.jflag && (t = strrchr(n, INTERNAL_DELIMITER)) != NULL)
  1354.         ++t;
  1355.     else
  1356.         t = n;
  1357.  
  1358.     while (*t != '\0') {      /* File part could be sys, vol, subvol or file */
  1359.         if (*t == INTERNAL_DELIMITER) {     /* System, Volume or Subvol Name */
  1360.             t++;
  1361.             if (*t == INTERNAL_DELIMITER) { /* System */
  1362.                 strcat(x, TANDEM_NODE_STR);
  1363.                 t++;
  1364.             } else
  1365.                 strcat(x, TANDEM_DELIMITER_STR);
  1366.         }
  1367.         p = strchr(t, INTERNAL_DELIMITER);
  1368.         if (p == NULL)
  1369.             break;
  1370.         if ((e = strchr(t, DOS_EXTENSION)) == NULL)
  1371.             e = p;
  1372.         else
  1373.             e = (e < p ? e : p);
  1374. #ifdef CLIP_MAXFNLEN_NSK
  1375.         strncat(x, t, _min(MAXFILEPARTLEN, (e - t)));
  1376. #else
  1377.         strncat(x, t, (e - t));
  1378. #endif
  1379.         t = p;
  1380.     }
  1381.  
  1382.     if ((e = strchr(t, DOS_EXTENSION)) == NULL)
  1383.         strcat(x, t);
  1384.     else {
  1385. #ifdef CLIP_MAXFNLEN_NSK
  1386.         strncat(x, t, _min(MAXFILEPARTLEN, (e - t)));
  1387. #else
  1388.         strncat(x, t, (e - t));
  1389. #endif
  1390.         strcat(x, TANDEM_EXTENSION_STR);
  1391.         strcat(x, e+1);
  1392.     }
  1393.  
  1394.     return x;
  1395. }
  1396.