tandem.c
上传用户:andy_li
上传日期:2007-01-06
资源大小:1019k
文件大小:43k
源码类别:

压缩解压

开发平台:

MultiPlatform

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