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#include "zip.h"
10
11#include <time.h>
12#include <stdio.h>
13#include <dirent.h>
14#ifndef UTIL
15#include <sys/dos.h>
16#endif
17
18#define MATCH shmatch
19
20#define PAD 0
21
22
23#ifndef UTIL
24
25/* Library functions not in (most) header files */
26
27int utime OF((char *, ztimbuf *));
28
29/* Local functions */
30local char *readd OF((DIR *));
31
32local char *readd(DIR* d)
33{
34   struct dirent* e = readdir(d);
35
36   return e == NULL ? NULL : e->d_name;
37}
38
39int wild(char* w)
40{
41  struct _filbuf inf;
42  /* convert FNAMX to malloc - 11/08/04 EG */
43  char *name;
44  char *p;
45
46  if (strcmp(w, "-") == 0)   /* if compressing stdin */
47    return newname(w, 0, 0);
48  if ((name = malloc(strlen(w) + 1)) == NULL) {
49    ZIPERR(ZE_MEM, "wild");
50  }
51  strcpy(name, w);
52  _toslash(name);
53
54  if ((p = strrchr(name, '/')) == NULL && (p = strrchr(name, ':')) == NULL)
55    p = name;
56  else
57    p++;
58  if (_dos_lfiles (&inf, w, 0xff) < 0) {
59    free(name);
60    return ZE_MISS;
61  }
62  do {
63    int r;
64
65    strcpy(p, inf.name);
66    r = procname(name, 0);
67    if (r != ZE_OK) {
68      free(name);
69      return r;
70    }
71  } while (_dos_nfiles(&inf) >= 0);
72  free(name);
73
74  return ZE_OK;
75}
76
77int procname(n, caseflag)
78char *n;                /* name to process */
79int caseflag;           /* true to force case-sensitive match */
80/* Process a name or sh expression to operate on (or exclude).  Return
81   an error code in the ZE_ class. */
82{
83  char *a;              /* path and name for recursion */
84  DIR *d;               /* directory stream from opendir() */
85  char *e;              /* pointer to name from readd() */
86  int m;                /* matched flag */
87  char *p;              /* path for recursion */
88  struct stat s;        /* result of stat() */
89  struct zlist far *z;  /* steps through zfiles list */
90
91  if (strcmp(n, "-") == 0)   /* if compressing stdin */
92    return newname(n, 0, caseflag);
93  else if (LSSTAT(n, &s))
94  {
95    /* Not a file or directory--search for shell expression in zip file */
96    p = ex2in(n, 0, (int *)NULL);       /* shouldn't affect matching chars */
97    m = 1;
98    for (z = zfiles; z != NULL; z = z->nxt) {
99      if (MATCH(p, z->iname, caseflag))
100      {
101        z->mark = pcount ? filter(z->zname, caseflag) : 1;
102        if (verbose)
103            fprintf(mesg, "zip diagnostic: %scluding %s\n",
104               z->mark ? "in" : "ex", z->name);
105        m = 0;
106      }
107    }
108    free((zvoid *)p);
109    return m ? ZE_MISS : ZE_OK;
110  }
111
112  /* Live name--use if file, recurse if directory */
113  _toslash(n);
114  if ((s.st_mode & S_IFDIR) == 0)
115  {
116    /* add or remove name of file */
117    if ((m = newname(n, 0, caseflag)) != ZE_OK)
118      return m;
119  } else {
120    /* Add trailing / to the directory name */
121    if ((p = malloc(strlen(n)+2)) == NULL)
122      return ZE_MEM;
123    if (strcmp(n, ".") == 0) {
124      *p = '\0';  /* avoid "./" prefix and do not create zip entry */
125    } else {
126      strcpy(p, n);
127      a = p + strlen(p);
128      if (a[-1] != '/')
129        strcpy(a, "/");
130      if (dirnames && (m = newname(p, 1, caseflag)) != ZE_OK) {
131        free((zvoid *)p);
132        return m;
133      }
134    }
135    /* recurse into directory */
136    if (recurse && (d = opendir(n)) != NULL)
137    {
138      while ((e = readd(d)) != NULL) {
139        if (strcmp(e, ".") && strcmp(e, ".."))
140        {
141          if ((a = malloc(strlen(p) + strlen(e) + 1)) == NULL)
142          {
143            closedir(d);
144            free((zvoid *)p);
145            return ZE_MEM;
146          }
147          strcat(strcpy(a, p), e);
148          if ((m = procname(a, caseflag)) != ZE_OK)   /* recurse on name */
149          {
150            if (m == ZE_MISS)
151              zipwarn("name not matched: ", a);
152            else
153              ziperr(m, a);
154          }
155          free((zvoid *)a);
156        }
157      }
158      closedir(d);
159    }
160    free((zvoid *)p);
161  } /* (s.st_mode & S_IFDIR) == 0) */
162  return ZE_OK;
163}
164
165char *ex2in(x, isdir, pdosflag)
166char *x;                /* external file name */
167int isdir;              /* input: x is a directory */
168int *pdosflag;          /* output: force MSDOS file attributes? */
169/* Convert the external file name to a zip file name, returning the malloc'ed
170   string or NULL if not enough memory. */
171{
172  char *n;              /* internal file name (malloc'ed) */
173  char *t;              /* shortened name */
174
175  /* Find starting point in name before doing malloc */
176  t = (x[0] && x[1] == (char)':') ? x + 2 : x;
177  while (*t == (char)'/')
178    t++;
179
180  /* Make changes, if any, to the copied name (leave original intact) */
181  _toslash(t);
182
183  if (!pathput)
184    t = last(t, '/');
185
186  /* Malloc space for internal name and copy it */
187  if ((n = malloc(strlen(t) + 1)) == NULL)
188    return NULL;
189  strcpy(n, t);
190
191  if (dosify)
192    msname(n);
193  /* Returned malloc'ed name */
194  if (pdosflag)
195    *pdosflag = dosify;
196  return n;
197}
198
199
200char *in2ex(n)
201char *n;                /* internal file name */
202/* Convert the zip file name to an external file name, returning the malloc'ed
203   string or NULL if not enough memory. */
204{
205  char *x;              /* external file name */
206  if ((x = malloc(strlen(n) + 1 + PAD)) == NULL)
207      return NULL;
208  return strcpy(x, n);
209}
210
211void stamp(f, d)
212char *f;                /* name of file to change */
213ulg d;                  /* dos-style time to change it to */
214/* Set last updated and accessed time of file f to the DOS time d. */
215{
216  ztimbuf u;            /* argument for utime() */
217
218  /* Convert DOS time to time_t format in u */
219  u.actime = u.modtime = dos2unixtime(d);
220
221  /* Set updated and accessed times of f */
222  utime(f, &u);
223}
224
225ulg filetime(f, a, n, t)
226char *f;                /* name of file to get info on */
227ulg *a;                 /* return value: file attributes */
228long *n;                /* return value: file size */
229iztimes *t;             /* return value: access, modific. and creation times */
230/* If file *f does not exist, return 0.  Else, return the file's last
231   modified date and time as an MSDOS date and time.  The date and
232   time is returned in a long with the date most significant to allow
233   unsigned integer comparison of absolute times.  Also, if a is not
234   a NULL pointer, store the file attributes there, with the high two
235   bytes being the Unix attributes, and the low byte being a mapping
236   of that to DOS attributes.  If n is not NULL, store the file size
237   there.  If t is not NULL, the file's access, modification and creation
238   times are stored there as UNIX time_t values.
239   If f is "-", use standard input as the file. If f is a device, return
240   a file size of -1 */
241{
242  struct stat s;        /* results of stat() */
243  /* convert FNMAX to malloc - 11/8/04 EG */
244  char *name;
245  int len = strlen(f);
246  isstdin = !strcmp(f, "-");
247
248  if ((name = malloc(len + 1)) == NULL) {
249    ZIPERR(ZE_MEM, "filetime");
250  }
251  strcpy(name, f);
252  if (name[len - 1] == '/')
253    name[len - 1] = '\0';
254  /* not all systems allow stat'ing a file with / appended */
255
256  if (isstdin) {
257    if (fstat(fileno(stdin), &s) != 0) {
258      free(name);
259      error("fstat(stdin)");
260    }
261  } else if (LSSTAT(name, &s) != 0) {
262             /* Accept about any file kind including directories
263              * (stored with trailing / with -r option)
264              */
265    free(name);
266    return 0;
267  }
268
269  if (a != NULL) {
270    int atr = _dos_chmod(name, -1);
271
272    if (atr < 0)
273      atr = 0x20;
274    *a = ((ulg)s.st_mode << 16) | (isstdin ? 0L : (ulg)atr);
275  }
276  free(name);
277  if (n != NULL)
278    *n = S_ISVOL(s.st_mode) ? -2L : S_ISREG(s.st_mode) ? s.st_size : -1L;
279  if (t != NULL) {
280    t->atime = s.st_atime;
281    t->mtime = s.st_mtime;
282    t->ctime = s.st_ctime;
283  }
284
285  return unix2dostime(&s.st_mtime);
286}
287
288int set_extra_field(z, z_utim)
289  struct zlist far *z;
290  iztimes *z_utim;
291  /* create extra field and change z->att if desired */
292{
293#ifdef USE_EF_UT_TIME
294  if ((z->extra = (char *)malloc(EB_HEADSIZE+EB_UT_LEN(1))) == NULL)
295    return ZE_MEM;
296
297  z->extra[0]  = 'U';
298  z->extra[1]  = 'T';
299  z->extra[2]  = EB_UT_LEN(1);          /* length of data part of e.f. */
300  z->extra[3]  = 0;
301  z->extra[4]  = EB_UT_FL_MTIME;
302  z->extra[5]  = (char)(z_utim->mtime);
303  z->extra[6]  = (char)(z_utim->mtime >> 8);
304  z->extra[7]  = (char)(z_utim->mtime >> 16);
305  z->extra[8]  = (char)(z_utim->mtime >> 24);
306
307  z->cext = z->ext = (EB_HEADSIZE+EB_UT_LEN(1));
308  z->cextra = z->extra;
309
310  return ZE_OK;
311#else /* !USE_EF_UT_TIME */
312  return (int)(z-z);
313#endif /* ?USE_EF_UT_TIME */
314}
315
316int deletedir(d)
317char *d;                /* directory to delete */
318/* Delete the directory *d if it is empty, do nothing otherwise.
319   Return the result of rmdir(), delete(), or system().
320   For VMS, d must be in format [x.y]z.dir;1  (not [x.y.z]).
321 */
322{
323    return rmdir(d);
324}
325
326void print_period(void)
327{
328  fputc('.', stderr);
329}
330
331#endif /* !UTIL */
332
333
334/******************************/
335/*  Function version_local()  */
336/******************************/
337
338void version_local()
339{
340    static ZCONST char CompiledWith[] = "Compiled with %s%s for %s%s%s%s.\n\n";
341#if 0
342    char buf[40];
343#endif
344
345    printf(CompiledWith,
346
347#ifdef __GNUC__
348      "gcc ", __VERSION__,
349#else
350#  if 0
351      "cc ", (sprintf(buf, " version %d", _RELEASE), buf),
352#  else
353      "unknown compiler", "",
354#  endif
355#endif
356
357      "Human68k",
358#ifdef __MC68020__
359      " (X68030)",
360#else
361      " (X680x0)",
362#endif
363
364#ifdef __DATE__
365      " on ", __DATE__
366#else
367      "", ""
368#endif
369      );
370
371} /* end function version_local() */
372