home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 9 Archive / 09-Archive.zip / unzip532.zip / tandem / tandem.c < prev    next >
C/C++ Source or Header  |  1997-10-21  |  35KB  |  1,136 lines

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