1/*
2  Copyright (c) 1990-1999 Info-ZIP.  All rights reserved.
3
4  See the accompanying file LICENSE, version 1999-Oct-05 or later
5  (the contents of which are also included in zip.h) for terms of use.
6  If, for some reason, both of these files are missing, the Info-ZIP license
7  also may be found at:  ftp://ftp.cdrom.com/pub/infozip/license.html
8*/
9/*
10 * MVS specific things
11 */
12#include "zip.h"
13#include "mvs.h"
14#include <errno.h>
15
16static int gen_node( DIR *dirp, RECORD *recptr )
17{
18   char *ptr, *name, ttr[TTRLEN];
19   int skip, count = 2;
20   unsigned int info_byte, alias, ttrn;
21   struct dirent *new;
22
23   ptr = recptr->rest;
24   while (count < recptr->count) {
25      if (!memcmp( ptr, endmark, NAMELEN ))
26         return 1;
27      name = ptr;                    /* member name */
28      ptr += NAMELEN;
29      memcpy( ttr, ptr, TTRLEN );    /* ttr name    */
30      ptr += TTRLEN;
31      info_byte = (unsigned int) (*ptr);   /* info byte */
32      if ( !(info_byte & ALIAS_MASK) ) {   /* no alias  */
33         new = malloc( sizeof(struct dirent) );
34         if (dirp->D_list == NULL)
35            dirp->D_list = dirp->D_curpos = new;
36         else
37            dirp->D_curpos = (dirp->D_curpos->d_next = new);
38         new->d_next = NULL;
39         memcpy( new->d_name, name, NAMELEN );
40         new->d_name[NAMELEN] = '\0';
41         if ((name = strchr( new->d_name, ' ' )) != NULL)
42            *name = '\0';      /* skip trailing blanks */
43      }
44      skip = (info_byte & SKIP_MASK) * 2 + 1;
45      ptr += skip;
46      count += (TTRLEN + NAMELEN + skip);
47   }
48   return 0;
49}
50
51DIR *opendir(const char *dirname)
52{
53   int bytes, list_end = 0;
54   DIR *dirp;
55   FILE *fp;
56   RECORD rec;
57
58   fp = fopen( dirname, "rb" );
59   if (fp != NULL) {
60      dirp = malloc( sizeof(DIR) );
61      if (dirp != NULL) {
62         dirp->D_list = dirp->D_curpos = NULL;
63         strcpy( dirp->D_path, dirname );
64         do {
65            bytes = fread( &rec, 1, sizeof(rec), fp );
66            if (bytes == sizeof(rec))
67               list_end = gen_node( dirp, &rec );
68         } while (!feof(fp) && !list_end);
69         fclose( fp );
70         dirp->D_curpos = dirp->D_list;
71         return dirp;
72      }
73      fclose( fp );
74   }
75   return NULL;
76}
77
78struct dirent *readdir(DIR *dirp)
79{
80   struct dirent *cur;
81
82   cur = dirp->D_curpos;
83   dirp->D_curpos = dirp->D_curpos->d_next;
84   return cur;
85}
86
87void rewinddir(DIR *dirp)
88{
89   dirp->D_curpos = dirp->D_list;
90}
91
92int closedir(DIR *dirp)
93{
94   struct dirent *node;
95
96   while (dirp->D_list != NULL) {
97      node = dirp->D_list;
98      dirp->D_list = dirp->D_list->d_next;
99      free( node );
100   }
101   free( dirp );
102   return 0;
103}
104
105local char *readd(d)
106DIR *d;                 /* directory stream to read from */
107/* Return a pointer to the next name in the directory stream d, or NULL if
108   no more entries or an error occurs. */
109{
110  struct dirent *e;
111
112  e = readdir(d);
113  return e == NULL ? (char *) NULL : e->d_name;
114}
115
116int procname(n, caseflag)
117char *n;                /* name to process */
118int caseflag;           /* true to force case-sensitive match */
119/* Process a name or sh expression to operate on (or exclude).  Return
120   an error code in the ZE_ class. */
121{
122  char *a;              /* path and name for recursion */
123  DIR *d;               /* directory stream from opendir() */
124  char *e;              /* pointer to name from readd() */
125  int m;                /* matched flag */
126  char *p;              /* path for recursion */
127  struct stat s;        /* result of stat() */
128  struct zlist far *z;  /* steps through zfiles list */
129  int exists;           /* 1 if file exists */
130
131  if (strcmp(n, "-") == 0)   /* if compressing stdin */
132    return newname(n, 0, caseflag);
133  else if (!(exists = (LSSTAT(n, &s) == 0)))
134  {
135#ifdef MVS
136    /* special case for MVS.  stat does not work on non-HFS files so if
137     * stat fails with ENOENT, try to open the file for reading anyway.
138     * If the user has no OMVS segment, stat gets an initialization error,
139     * even on external files.
140     */
141    if (errno == ENOENT || errno == EMVSINITIAL) {
142      FILE *f = fopen(n, "r");
143      if (f) {
144        /* stat got ENOENT but fopen worked, external file */
145        fclose(f);
146        exists = 1;
147        memset(&s, '\0', sizeof(s));   /* stat data is unreliable for externals */
148        s.st_mode = S_IFREG;           /* fudge it */
149      }
150    }
151#endif /* MVS */
152  }
153  if (! exists) {
154    /* Not a file or directory--search for shell expression in zip file */
155    p = ex2in(n, 0, (int *)NULL);       /* shouldn't affect matching chars */
156    m = 1;
157    for (z = zfiles; z != NULL; z = z->nxt) {
158      if (MATCH(p, z->iname, caseflag))
159      {
160        z->mark = pcount ? filter(z->zname, caseflag) : 1;
161        if (verbose)
162            fprintf(mesg, "zip diagnostic: %scluding %s\n",
163               z->mark ? "in" : "ex", z->name);
164        m = 0;
165      }
166    }
167    free((zvoid *)p);
168    return m ? ZE_MISS : ZE_OK;
169  }
170
171  /* Live name--use if file, recurse if directory */
172  if (!S_ISDIR(s.st_mode))
173  {
174    /* add or remove name of file */
175    if ((m = newname(n, 0, caseflag)) != ZE_OK)
176      return m;
177  } else {
178    /* Add trailing / to the directory name */
179    if ((p = malloc(strlen(n)+2)) == NULL)
180      return ZE_MEM;
181    if (strcmp(n, ".") == 0) {
182      *p = '\0';  /* avoid "./" prefix and do not create zip entry */
183    } else {
184      strcpy(p, n);
185      a = p + strlen(p);
186      if (a[-1] != '/')
187        strcpy(a, "/");
188      if (dirnames && (m = newname(p, 1, caseflag)) != ZE_OK) {
189        free((zvoid *)p);
190        return m;
191      }
192    }
193    /* recurse into directory */
194    if (recurse && (d = opendir(n)) != NULL)
195    {
196      while ((e = readd(d)) != NULL) {
197        if (strcmp(e, ".") && strcmp(e, ".."))
198        {
199          if ((a = malloc(strlen(p) + strlen(e) + 1)) == NULL)
200          {
201            closedir(d);
202            free((zvoid *)p);
203            return ZE_MEM;
204          }
205          strcat(strcpy(a, p), e);
206          if ((m = procname(a, caseflag)) != ZE_OK)   /* recurse on name */
207          {
208            if (m == ZE_MISS)
209              zipwarn("name not matched: ", a);
210            else
211              ziperr(m, a);
212          }
213          free((zvoid *)a);
214        }
215      }
216      closedir(d);
217    }
218    free((zvoid *)p);
219  } /* (s.st_mode & S_IFDIR) == 0) */
220  return ZE_OK;
221}
222