home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 9 Archive / 09-Archive.zip / zip22.zip / vms / vmszip.c < prev    next >
C/C++ Source or Header  |  1997-08-19  |  17KB  |  567 lines

  1. /*
  2.  
  3.  Copyright (C) 1990-1997 Mark Adler, Richard B. Wales, Jean-loup Gailly,
  4.  Kai Uwe Rommel, Onno van der Linden, Christian Spieler and Igor Mandrichenko.
  5.  Permission is granted to any individual or institution to use, copy, or
  6.  redistribute this software so long as all of the original files are included,
  7.  that it is not sold for profit, and that this copyright notice is retained.
  8.  
  9. */
  10.  
  11. #include "zip.h"
  12.  
  13. #include <time.h>
  14. #include <unixlib.h>
  15.  
  16. #include <descrip.h>
  17. #include <rms.h>
  18. #include <ssdef.h>
  19. #include <starlet.h>
  20.  
  21. #define PATH_START '['
  22. #define PATH_END ']'
  23. #define PATH_START2 '<'
  24. #define PATH_END2 '>'
  25. #define MATCH shmatch
  26. #include "vms/vmsmunch.h"
  27.  
  28. /* Extra malloc() space in names for cutpath() */
  29. #define PAD 5         /* may have to change .FOO] to ]FOO.DIR;1 */
  30.  
  31.  
  32. typedef struct dirent {
  33.   int d_wild;                /* flag for wildcard vs. non-wild */
  34.   struct FAB fab;
  35.   struct NAM nam;
  36.   char d_qualwildname[NAM$C_MAXRSS + 1];
  37.   char d_name[NAM$C_MAXRSS + 1];
  38. } DIR;
  39.  
  40. /* Library functions not in (most) header files */
  41.  
  42. #ifndef UTIL    /* the companion #endif is a bit of ways down ... */
  43.  
  44. extern char *label;
  45. local ulg label_time = 0;
  46. local ulg label_mode = 0;
  47. local time_t label_utim = 0;
  48.  
  49. /* Local functions */
  50. local void vms_wild OF((char *, DIR *));
  51. DIR *opendir OF((ZCONST char *));
  52. struct dirent *readdir OF((DIR *));
  53. local char *readd OF((DIR *));
  54. local char *strlower OF((char *));
  55. local char *strupper OF((char *));
  56.  
  57.  
  58. /*---------------------------------------------------------------------------
  59.  
  60.     _vms_findfirst() and _vms_findnext(), based on public-domain DECUS C
  61.     fwild() and fnext() routines (originally written by Martin Minow, poss-
  62.     ibly modified by Jerry Leichter for bintnxvms.c), were written by Greg
  63.     Roelofs and are still in the public domain.  Routines approximate the
  64.     behavior of MS-DOS (MSC and Turbo C) findfirst and findnext functions.
  65.  
  66.   ---------------------------------------------------------------------------*/
  67.  
  68. static char wild_version_part[10]="\0";
  69.  
  70. local void vms_wild(p, d)
  71. char *p;
  72. DIR *d;
  73. {
  74.   /*
  75.    * Do wildcard setup
  76.    */
  77.   /* set up the FAB and NAM blocks. */
  78.   d->fab = cc$rms_fab;             /* initialize fab */
  79.   d->nam = cc$rms_nam;             /* initialize nam */
  80.  
  81.   d->fab.fab$l_nam = &d->nam;           /* fab -> nam */
  82.   d->fab.fab$l_fna = p;                 /* argument wild name */
  83.   d->fab.fab$b_fns = strlen(p);         /* length */
  84.  
  85.   d->fab.fab$l_dna = "sys$disk:[]";     /* Default fspec */
  86.   d->fab.fab$b_dns = sizeof("sys$disk:[]")-1;
  87.  
  88.   d->nam.nam$l_esa = d->d_qualwildname; /* qualified wild name */
  89.   d->nam.nam$b_ess = NAM$C_MAXRSS;      /* max length */
  90.   d->nam.nam$l_rsa = d->d_name;         /* matching file name */
  91.   d->nam.nam$b_rss = NAM$C_MAXRSS;      /* max length */
  92.  
  93.   /* parse the file name */
  94.   if (sys$parse(&d->fab) != RMS$_NORMAL)
  95.     return;
  96.   /* Does this replace d->fab.fab$l_fna with a new string in its own space?
  97.      I sure hope so, since p is free'ed before this routine returns. */
  98.  
  99.   /* have qualified wild name (i.e., disk:[dir.subdir]*.*); null-terminate
  100.    * and set wild-flag */
  101.   d->d_qualwildname[d->nam.nam$b_esl] = '\0';
  102.   d->d_wild = (d->nam.nam$l_fnb & NAM$M_WILDCARD)? 1 : 0;   /* not used... */
  103. #ifdef DEBUG
  104.   fprintf(mesg, "  incoming wildname:  %s\n", p);
  105.   fprintf(mesg, "  qualified wildname:  %s\n", d->d_qualwildname);
  106. #endif /* DEBUG */
  107. }
  108.  
  109. DIR *opendir(n)
  110. ZCONST char *n;          /* directory to open */
  111. /* Start searching for files in the VMS directory n */
  112. {
  113.   char *c;              /* scans VMS path */
  114.   DIR *d;               /* malloc'd return value */
  115.   int m;                /* length of name */
  116.   char *p;              /* malloc'd temporary string */
  117.  
  118.   if ((d = (DIR *)malloc(sizeof(DIR))) == NULL ||
  119.       (p = malloc((m = strlen(n)) + 4)) == NULL) {
  120.     if (d != NULL) free((zvoid *)d);
  121.     return NULL;
  122.   }
  123.   /* Directory may be in form "[DIR.SUB1.SUB2]" or "[DIR.SUB1]SUB2.DIR;1".
  124.      If latter, convert to former. */
  125.   if (m > 0  &&  *(c = strcpy(p,n)+m-1) != ']')
  126.   {
  127.     while (--c > p  &&  *c != ';')
  128.       ;
  129.     if (c-p < 5  ||  strncmp(c-4, ".DIR", 4))
  130.     {
  131.       free((zvoid *)d);  free((zvoid *)p);
  132.       return NULL;
  133.     }
  134.     c -= 3;
  135.     *c-- = '\0';        /* terminate at "DIR;#" */
  136.     *c = ']';           /* "." --> "]" */
  137.     while (c > p  &&  *--c != ']')
  138.       ;
  139.     *c = '.';           /* "]" --> "." */
  140.   }
  141.   strcat(p, "*.*");
  142.   strcat(p, wild_version_part);
  143.   vms_wild(p, d);       /* set up wildcard */
  144.   free((zvoid *)p);
  145.   return d;
  146. }
  147.  
  148. struct dirent *readdir(d)
  149. DIR *d;                 /* directory stream to read from */
  150. /* Return pointer to first or next directory entry, or NULL if end. */
  151. {
  152.   int r;                /* return code */
  153.  
  154.   do {
  155.     d->fab.fab$w_ifi = 0;       /* internal file index:  what does this do? */
  156.  
  157.     /* get next match to possible wildcard */
  158.     if ((r = sys$search(&d->fab)) == RMS$_NORMAL)
  159.     {
  160.         d->d_name[d->nam.nam$b_rsl] = '\0';   /* null terminate */
  161.         return (struct dirent *)d;   /* OK */
  162.     }
  163.   } while (r == RMS$_PRV);
  164.   return NULL;
  165. }
  166.  
  167. #define closedir free
  168.  
  169. local char *readd(d)
  170. DIR *d;                 /* directory stream to read from */
  171. /* Return a pointer to the next name in the directory stream d, or NULL if
  172.    no more entries or an error occurs. */
  173. {
  174.   struct dirent *e;     /* directory entry read */
  175.  
  176.   e = readdir(d);
  177.   return e == NULL ? (char *)NULL : e->d_name;
  178. }
  179.  
  180. int wild(p)
  181. char *p;                /* path/pattern to match */
  182. /* Expand the pattern based on the contents of the file system.  Return an
  183.    error code in the ZE_ class. */
  184. {
  185.   DIR *d;               /* stream for reading directory */
  186.   char *e;              /* name found in directory */
  187.   int f;                /* true if there was a match */
  188.  
  189.   /* special handling of stdin request */
  190.   if (strcmp(p, "-") == 0)   /* if compressing stdin */
  191.     return newname(p, 0);
  192.  
  193.   /* Search given pattern for matching names */
  194.   if ((d = (DIR *)malloc(sizeof(DIR))) == NULL)
  195.     return ZE_MEM;
  196.   vms_wild(p, d);       /* pattern may be more than just directory name */
  197.  
  198.   /*
  199.    * Save version specified by user to use in recursive drops into
  200.    * subdirectories.
  201.    */
  202.   strncpy(wild_version_part,d->nam.nam$l_ver,d->nam.nam$b_ver);
  203.   wild_version_part[d->nam.nam$b_ver] = '\0';
  204.  
  205.   f = 0;
  206.   while ((e = readd(d)) != NULL)        /* "dosmatch" is already built in */
  207.     if (procname(e) == ZE_OK)
  208.       f = 1;
  209.   closedir(d);
  210.  
  211.   /* Done */
  212.   return f ? ZE_OK : ZE_MISS;
  213. }
  214.  
  215. int procname(n)
  216. char *n;                /* name to process */
  217. /* Process a name or sh expression to operate on (or exclude).  Return
  218.    an error code in the ZE_ class. */
  219. {
  220.   DIR *d;               /* directory stream from opendir() */
  221.   char *e;              /* pointer to name from readd() */
  222.   int m;                /* matched flag */
  223.   char *p;              /* path for recursion */
  224.   struct stat s;        /* result of stat() */
  225.   struct zlist far *z;  /* steps through zfiles list */
  226.  
  227.   if (strcmp(n, "-") == 0)   /* if compressing stdin */
  228.     return newname(n, 0);
  229.   else if (LSSTAT(n, &s)
  230. #if defined(__TURBOC__) || defined(VMS) || defined(__WATCOMC__)
  231.            /* For these 3 compilers, stat() succeeds on wild card names! */
  232.            || isshexp(n)
  233. #endif
  234.           )
  235.   {
  236.     /* Not a file or directory--search for shell expression in zip file */
  237.     p = ex2in(n, 0, (int *)NULL);       /* shouldn't affect matching chars */
  238.     m = 1;
  239.     for (z = zfiles; z != NULL; z = z->nxt) {
  240.       if (MATCH(p, z->iname))
  241.       {
  242.         z->mark = pcount ? filter(z->zname) : 1;
  243.         if (verbose)
  244.             fprintf(mesg, "zip diagnostic: %scluding %s\n",
  245.                z->mark ? "in" : "ex", z->name);
  246.         m = 0;
  247.       }
  248.     }
  249.     free((zvoid *)p);
  250.     return m ? ZE_MISS : ZE_OK;
  251.   }
  252.  
  253.   /* Live name--use if file, recurse if directory */
  254.   if ((s.st_mode & S_IFDIR) == 0)
  255.   {
  256.     /* add or remove name of file */
  257.     if ((m = newname(n, 0)) != ZE_OK)
  258.       return m;
  259.   } else {
  260.     if (dirnames && (m = newname(n, 1)) != ZE_OK) {
  261.       return m;
  262.     }
  263.     /* recurse into directory */
  264.     if (recurse && (d = opendir(n)) != NULL)
  265.     {
  266.       while ((e = readd(d)) != NULL) {
  267.         if ((m = procname(e)) != ZE_OK)     /* recurse on name */
  268.         {
  269.           closedir(d);
  270.           return m;
  271.         }
  272.       }
  273.       closedir(d);
  274.     }
  275.   } /* (s.st_mode & S_IFDIR) == 0) */
  276.   return ZE_OK;
  277. }
  278.  
  279. local char *strlower(s)
  280. char *s;                /* string to convert */
  281. /* Convert all uppercase letters to lowercase in string s */
  282. {
  283.   char *p;              /* scans string */
  284.  
  285.   for (p = s; *p; p++)
  286.     if (*p >= 'A' && *p <= 'Z')
  287.       *p += 'a' - 'A';
  288.   return s;
  289. }
  290.  
  291. local char *strupper(s)
  292. char *s;                /* string to convert */
  293. /* Convert all lowercase letters to uppercase in string s */
  294. {
  295.   char *p;              /* scans string */
  296.  
  297.   for (p = s; *p; p++)
  298.     if (*p >= 'a' && *p <= 'z')
  299.       *p -= 'a' - 'A';
  300.   return s;
  301. }
  302.  
  303. char *ex2in(x, isdir, pdosflag)
  304. char *x;                /* external file name */
  305. int isdir;              /* input: x is a directory */
  306. int *pdosflag;          /* output: force MSDOS file attributes? */
  307. /* Convert the external file name to a zip file name, returning the malloc'ed
  308.    string or NULL if not enough memory. */
  309. {
  310.   char *n;              /* internal file name (malloc'ed) */
  311.   char *t;              /* shortened name */
  312.   int dosflag;
  313.  
  314.   dosflag = dosify; /* default for non-DOS and non-OS/2 */
  315.  
  316.   /* Find starting point in name before doing malloc */
  317.   t = x;
  318.   if ((n = strrchr(t, ':')) != NULL)
  319.     t = n + 1;
  320.   if ( (*t == PATH_START && (n = strrchr(t, PATH_END)) != NULL)
  321.       || (*t == PATH_START2 && (n = strrchr(t, PATH_END2)) != NULL) )
  322.     /* external name contains valid VMS path specification */
  323.     if (*(++t) == '.')
  324.       /* path is relative to current directory, skip leading '.' */
  325.       t++;
  326.  
  327.   if (!pathput)
  328.     t = last(last(t, PATH_END), PATH_END2);
  329.  
  330.   /* Malloc space for internal name and copy it */
  331.   if ((n = malloc(strlen(t) + 1)) == NULL)
  332.     return NULL;
  333.   strcpy(n, t);
  334.  
  335.   if (((t = strrchr(n, PATH_END)) != NULL) ||
  336.        (t = strrchr(n, PATH_END2)) != NULL)
  337.   {
  338.     *t = '/';
  339.     while (--t > n)
  340.       if (*t == '.')
  341.         *t = '/';
  342.   }
  343.  
  344.   /* Fix from Greg Roelofs: */
  345.   /* Get current working directory and strip from n (t now = n) */
  346.   {
  347.     char cwd[256], *p, *q;
  348.     int c;
  349.  
  350. #if 0 /* fix by Igor */
  351.     if (getcwd(cwd, 256) && ((p = strchr(cwd, '.')) != NULL))
  352. #else
  353.     if (getcwd(cwd, 256) && ((p = strchr(cwd, PATH_START)) != NULL ||
  354.                              (p = strchr(cwd, PATH_START2)) != NULL))
  355. #endif
  356.     {
  357.       if (*(++p) == '.')
  358.         p++;
  359.       if ((q = strrchr(p, PATH_END)) != NULL ||
  360.           (q = strrchr(p, PATH_END2)) != NULL)
  361.       {
  362.         *q = '/';
  363.         while (--q > p)
  364.           if (*q == '.')
  365.             *q = '/';
  366.  
  367.         /* strip bogus path parts from n */
  368.         if (strncmp(n, p, (c=strlen(p))) == 0)
  369.         {
  370.           q = n + c;
  371.           while (*t++ = *q++)
  372.             ;
  373.         }
  374.       }
  375.     }
  376.   }
  377.   strlower(n);
  378.  
  379.   if (isdir)
  380.   {
  381.     if (strcmp((t=n+strlen(n)-6), ".dir;1"))
  382.       error("directory not version 1");
  383.     else
  384.       if (pathput)
  385.         strcpy(t, "/");
  386.       else
  387.         *n = '\0';              /* directories are discarded with zip -rj */
  388.   }
  389.   else if (!vmsver)
  390.     if ((t = strrchr(n, ';')) != NULL)
  391.       *t = '\0';
  392.  
  393.   if ((t = strrchr(n, '.')) != NULL)
  394.   {
  395.     if ( t[1] == '\0')             /* "filename." -> "filename" */
  396.       *t = '\0';
  397.     else if (t[1] == ';')         /* "filename.;vvv" -> "filename;vvv" */
  398.     {
  399.       char *f = t+1;
  400.       while (*t++ = *f++) ;
  401.     }
  402.   }
  403.  
  404.   if (dosify)
  405.     msname(n);
  406.  
  407.   /* Returned malloc'ed name */
  408.   if (pdosflag)
  409.     *pdosflag = dosflag;
  410.   return n;
  411. }
  412.  
  413.  
  414. char *in2ex(n)
  415. char *n;                /* internal file name */
  416. /* Convert the zip file name to an external file name, returning the malloc'ed
  417.    string or NULL if not enough memory. */
  418. {
  419.   char *x;              /* external file name */
  420.   char *t;              /* scans name */
  421.  
  422.   if ((t = strrchr(n, '/')) == NULL)
  423.   {
  424.     if ((x = malloc(strlen(n) + 1 + PAD)) == NULL)
  425.       return NULL;
  426.     strcpy(x, n);
  427.   }
  428.   else
  429.   {
  430.     if ((x = malloc(strlen(n) + 3 + PAD)) == NULL)
  431.       return NULL;
  432.     x[0] = PATH_START;
  433.     x[1] = '.';
  434.     strcpy(x + 2, n);
  435.     *(t = x + 2 + (t - n)) = PATH_END;
  436.     while (--t > x)
  437.       if (*t == '/')
  438.         *t = '.';
  439.   }
  440.   strupper(x);
  441.  
  442.   return x;
  443. }
  444.  
  445. void stamp(f, d)
  446. char *f;                /* name of file to change */
  447. ulg d;                  /* dos-style time to change it to */
  448. /* Set last updated and accessed time of file f to the DOS time d. */
  449. {
  450.   int tm_sec, tm_min, tm_hour, tm_mday, tm_mon, tm_year;
  451.   char timbuf[24];
  452.   static ZCONST char *month[] = {"JAN", "FEB", "MAR", "APR", "MAY", "JUN",
  453.                                  "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"};
  454.   struct VMStimbuf {
  455.       char *actime;           /* VMS revision date, ASCII format */
  456.       char *modtime;          /* VMS creation date, ASCII format */
  457.   } ascii_times;
  458.  
  459.   ascii_times.actime = ascii_times.modtime = timbuf;
  460.  
  461.   /* Convert DOS time to ASCII format for VMSmunch */
  462.   tm_sec = (int)(d << 1) & 0x3e;
  463.   tm_min = (int)(d >> 5) & 0x3f;
  464.   tm_hour = (int)(d >> 11) & 0x1f;
  465.   tm_mday = (int)(d >> 16) & 0x1f;
  466.   tm_mon = ((int)(d >> 21) & 0xf) - 1;
  467.   tm_year = ((int)(d >> 25) & 0x7f) + 1980;
  468.   sprintf(timbuf, "%02d-%3s-%04d %02d:%02d:%02d.00", tm_mday, month[tm_mon],
  469.     tm_year, tm_hour, tm_min, tm_sec);
  470.  
  471.   /* Set updated and accessed times of f */
  472.   if (VMSmunch(f, SET_TIMES, (char *)&ascii_times) != RMS$_NMF)
  473.     zipwarn("can't set zipfile time: ", f);
  474. }
  475.  
  476. ulg filetime(f, a, n, t)
  477. char *f;                /* name of file to get info on */
  478. ulg *a;                 /* return value: file attributes */
  479. long *n;                /* return value: file size */
  480. iztimes *t;             /* return value: access, modific. and creation times */
  481. /* If file *f does not exist, return 0.  Else, return the file's last
  482.    modified date and time as an MSDOS date and time.  The date and
  483.    time is returned in a long with the date most significant to allow
  484.    unsigned integer comparison of absolute times.  Also, if a is not
  485.    a NULL pointer, store the file attributes there, with the high two
  486.    bytes being the Unix attributes, and the low byte being a mapping
  487.    of that to DOS attributes.  If n is not NULL, store the file size
  488.    there.  If t is not NULL, the file's access, modification and creation
  489.    times are stored there as UNIX time_t values.
  490.    If f is "-", use standard input as the file. If f is a device, return
  491.    a file size of -1 */
  492. {
  493.   struct stat s;        /* results of stat() */
  494.   char name[FNMAX];
  495.   int len = strlen(f);
  496.  
  497.   if (f == label) {
  498.     if (a != NULL)
  499.       *a = label_mode;
  500.     if (n != NULL)
  501.       *n = -2L; /* convention for a label name */
  502.     if (t != NULL)
  503.       t->atime = t->mtime = t->ctime = label_utim;
  504.     return label_time;
  505.   }
  506.   strcpy(name, f);
  507.   if (name[len - 1] == '/')
  508.     name[len - 1] = '\0';
  509.   /* not all systems allow stat'ing a file with / appended */
  510.  
  511.   if (strcmp(f, "-") == 0) {
  512.     if (fstat(fileno(stdin), &s) != 0)
  513.       error("fstat(stdin)");
  514.   } else if (LSSTAT(name, &s) != 0)
  515.              /* Accept about any file kind including directories
  516.               * (stored with trailing / with -r option)
  517.               */
  518.     return 0;
  519.  
  520.   if (a != NULL) {
  521.     *a = ((ulg)s.st_mode << 16) | !(s.st_mode & S_IWRITE);
  522.     if ((s.st_mode & S_IFDIR) != 0) {
  523.       *a |= MSDOS_DIR_ATTR;
  524.     }
  525.   }
  526.   if (n != NULL)
  527.     *n = (s.st_mode & S_IFMT) == S_IFREG ? s.st_size : -1L;
  528.   if (t != NULL) {
  529.     t->atime = s.st_mtime;
  530. #ifdef USE_MTIME
  531.     t->mtime = s.st_mtime;            /* Use modification time in VMS */
  532. #else
  533.     t->mtime = s.st_ctime;            /* Use creation time in VMS */
  534. #endif
  535.     t->ctime = s.st_ctime;
  536.   }
  537.  
  538. #ifdef USE_MTIME
  539.   return unix2dostime((time_t *)&s.st_mtime); /* Use modification time in VMS */
  540. #else
  541.   return unix2dostime((time_t *)&s.st_ctime); /* Use creation time in VMS */
  542. #endif
  543. }
  544.  
  545. int deletedir(d)
  546. char *d;                /* directory to delete */
  547. /* Delete the directory *d if it is empty, do nothing otherwise.
  548.    Return the result of rmdir(), delete(), or system().
  549.    For VMS, d must be in format [x.y]z.dir;1  (not [x.y.z]).
  550.  */
  551. {
  552.     /* code from Greg Roelofs, who horked it from Mark Edwards (unzip) */
  553.     int r, len;
  554.     char *s;              /* malloc'd string for system command */
  555.  
  556.     len = strlen(d);
  557.     if ((s = malloc(len + 34)) == NULL)
  558.       return 127;
  559.  
  560.     system(strcat(strcpy(s, "set prot=(o:rwed) "), d));
  561.     r = delete(d);
  562.     free(s);
  563.     return r;
  564. }
  565.  
  566. #endif /* !UTIL */
  567.