|
|
1.1 root 1: /*
2:
3: Copyright (C) 1990-1992 Mark Adler, Richard B. Wales, Jean-loup Gailly,
4: Kai Uwe Rommel 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: unmodified, that it is not sold for profit, and that this copyright notice
8: is retained.
9:
10: */
11:
12: /*
13: * fileio.c by Mark Adler.
14: */
15:
16: #include "zip.h"
17:
18: #include <time.h>
19:
20: #ifdef WIN32
21: # include <sys/utime.h>
22: # include <windows.h> /* for findfirst/findnext */
23: #endif
24:
25: #ifdef MACOS
26: # define EXDEV 1
27: #endif
28:
29: #ifdef OSF
30: # define EXDEV 18 /* avoid a bug in the DEC OSF/1 header files. */
31: #else
32: # include <errno.h>
33: #endif
34:
35: #ifdef MINIX
36: # ifdef S_IWRITE
37: # undef S_IWRITE
38: # endif /* S_IWRITE */
39: # define S_IWRITE S_IWUSR
40: #endif /* S_IWUSR */
41:
42: #ifdef ATARI_ST
43: # undef MSDOS
44: #endif
45:
46: #ifdef MSDOS
47: # include <io.h>
48: # if (defined(__TURBOC__) || defined(__GO32__))
49: # include <dir.h>
50: # else /* !__TURBOC__ */
51: # if !defined(__EMX__) && !defined(__WATCOMC__)
52: # include <direct.h>
53: # endif
54: # endif /* ?__TURBOC__ */
55: # define link rename
56: # ifdef OS2
57: # define MATCH shmatch
58: # else /* !OS2 */
59: # define MATCH dosmatch
60: # endif /* ?OS2 */
61: #else /* !MSDOS */
62: extern int errno; /* error number from system functions */
63: # ifdef VMS
64: # define RMDIR
65: # define link rename
66: # include "VMSmunch.h"
67: # endif /* VMS */
68: # ifdef MACOS
69: # define link rename
70: # define mktemp tmpnam
71: # endif
72: # define MATCH shmatch
73: #endif /* ?MSDOS */
74:
75: #ifdef ATARI_ST
76: # define MSDOS 1
77: #endif
78:
79: #ifdef UTS
80: # define RMDIR
81: #endif /* UTS */
82:
83:
84: /* Extra malloc() space in names for cutpath() */
85: #ifdef VMS
86: # define PAD 3 /* may have to change .FOO] to ]FOO.DIR */
87: #else /* !VMS */
88: # define PAD 0
89: #endif /* ?VMS */
90:
91:
92: /* For now, assume DIRENT implies System V implies TERMIO */
93: #if defined(DIRENT) && !defined(MINIX) && !defined(TERMIO)
94: # define TERMIO
95: #endif
96:
97:
98: #ifdef CRYPT
99: # ifdef MSVMS
100: # ifdef MSDOS
101: # ifdef __EMX__
102: # define getch() _read_kbd(0, 1, 0)
103: # else
104: # ifdef __GO32__
105: # include <pc.h>
106: # define getch() getkey()
107: # else
108: # include <conio.h>
109: # endif
110: # endif
111: # else /* !MSDOS */
112: # define getch() getc(stderr)
113: # define echoff(f) echo(0) /* for echo control */
114: # define echon() echo(1)
115: # include <iodef.h>
116: # include <ttdef.h>
117: # if !defined(SS$_NORMAL)
118: # define SS$_NORMAL 1 /* only thing we need from <ssdef.h> */
119: # endif
120: # endif /* ?MSDOS */
121: # else /* !MSVMS */
122: # ifdef TERMIO /* Amdahl, Cray, all SysV? */
123: # ifdef CONVEX
124: # include <sys/termios.h>
125: # include <sgtty.h>
126: # define O_BINARY 0
127: # else /* !CONVEX */
128: # ifdef LINUX
129: # include <termios.h>
130: # else /* !LINUX */
131: # include <termio.h>
132: # endif /* ?LINUX */
133: # define sgttyb termio
134: # define sg_flags c_lflag
135: int ioctl OF((int, int, voidp *));
136: # endif /* ?CONVEX */
137: # define GTTY(f,s) ioctl(f,TCGETA,s)
138: # define STTY(f,s) ioctl(f,TCSETAW,s)
139: # else /* !TERMIO */
140: # ifndef MINIX
141: # include <sys/ioctl.h>
142: # endif /* !MINIX */
143: # include <sgtty.h>
144: int gtty OF((int, struct sgttyb *));
145: int stty OF((int, struct sgttyb *));
146: # define GTTY gtty
147: # define STTY stty
148: # endif /* ?TERMIO */
149: int isatty OF((int));
150: char *ttyname OF((int));
151: int open OF((char *, int, ...));
152: int close OF((int));
153: int read OF((int, voidp *, int));
154: # endif /* ?MSVMS */
155: #endif /* ?CRYPT */
156:
157: #ifdef VMS
158: # include <descrip.h>
159: # include <rms.h>
160: #endif
161:
162: /* For directory access. (This is getting rather messy. Cleanup
163: * scheduled for version 17.9.)
164: */
165: #ifndef UTIL
166:
167: #ifdef SYSV /* use readdir() */
168: # include <dirent.h>
169: # define dstrm DIR
170: # define direct dirent
171: #else
172:
173: #ifdef DIRENT /* use getdents() */
174: # if defined(MINIX) || defined(OSF)
175: # include <dirent.h>
176: # else /* !MINIX */
177: # include <sys/dirent.h>
178: # endif /* ?MINIX */
179: # define direct dirent
180: # ifdef MINIX
181: int getdents OF((int, char *, unsigned));
182: # else /* !MINIX */
183: int getdents OF((int, char *, int));
184: # endif /* ?MINIX */
185: # define DBSZ 4096 /* This has to be bigger than a directory block */
186: typedef struct { /* directory stream buffer */
187: int f; /* file descriptor for the directory "file" */
188: char *p; /* pointer to next entry in buffer */
189: char *q; /* pointer after end of buffer contents */
190: char b[DBSZ]; /* buffer */
191: } dstrm;
192:
193: #else /* !DIRENT */ /* use opendir(), etc. */
194: # if defined(CONVEX) || defined(ultrix)
195: # include <dirent.h>
196: # ifdef direct
197: # undef direct /* ultrix 4.2, at least if !__POSIX */
198: # endif
199: # define direct dirent
200: # endif /* CONVEX || ultrix */
201: # ifdef NDIR
202: # include "ndir.h" /* for HPUX */
203: # else /* !NDIR */
204: # ifdef MSDOS
205: # ifdef OS2
206: # include "os2zip.h"
207: # else /* !OS2 */
208: # ifndef ATARI_ST
209: # include <dos.h>
210: # endif
211: # if (defined(__TURBOC__) || defined(__GO32__))
212: # define FATTR FA_HIDDEN+FA_SYSTEM+FA_DIREC
213: # define FFIRST(n,d) findfirst(n,(struct ffblk *)d,FATTR)
214: # define FNEXT(d) findnext((struct ffblk *)d)
215: # else /* !__TURBOC__ */
216: # define FATTR _A_HIDDEN+_A_SYSTEM+_A_SUBDIR
217: # define FFIRST(n,d) _dos_findfirst(n,FATTR,(struct find_t *)d)
218: # define FNEXT(d) _dos_findnext((struct find_t *)d)
219: # endif /* ?__TURBOC__ */
220: typedef struct direct {
221: char d_reserved[30];
222: char d_name[13];
223: int d_first;
224: #ifdef WIN32
225: HANDLE d_hFindFile;
226: #endif
227: } DIR;
228: # endif /* ?OS2 */
229: # else /* !MSDOS */
230: # ifdef VMS
231: # include <ssdef.h>
232: typedef struct direct {
233: int d_wild; /* flag for wildcard vs. non-wild */
234: struct FAB fab;
235: struct NAM nam;
236: char d_qualwildname[NAM$C_MAXRSS + 1];
237: char d_name[NAM$C_MAXRSS + 1];
238: } DIR;
239: # else /* !VMS */
240: # ifdef MACOS
241: typedef struct direct {
242: int d_wild; /* flag for wildcard vs. non-wild */
243: char *d_name;
244: } DIR;
245: # endif
246: # ifdef M_XENIX
247: # include <sys/ndir.h>
248: # else /* !M_XENIX */
249: # include <sys/dir.h>
250: # endif /* ?M_XENIX */
251: # ifdef NODIR /* for AT&T 3B1 */
252: # define dirent direct
253: typedef FILE DIR;
254: # define dstrm DIR
255: # endif /* NODIR */
256: # endif /* ?VMS */
257: # endif /* ?MSDOS */
258: # endif /* ?NDIR */
259: # define dstrm DIR
260: # ifndef NODIR
261: DIR *opendir OF((char *));
262: # endif /* !NODIR */
263: # ifndef CONVEX
264: struct direct *readdir OF((DIR *));
265: # endif /* !CONVEX */
266: #endif /* ?DIRENT */
267: #endif /* ?SYSV */
268: #endif /* !UTIL */
269:
270:
271: /* Library functions not in (most) header files */
272:
273: #if defined(__IBMC__) || defined(__WATCOMC__)
274: # define NO_MKTEMP
275: #endif
276: char *mktemp OF((char *));
277:
278: #ifdef __GO32__
279: char *strlwr OF((char *));
280: #else
281: int link OF((char *, char *));
282: int unlink OF((char *));
283: # if defined(MSDOS)
284: int chmod OF((char *, int));
285: /* For many targets, chmod is already defined by sys/stat.h, and second
286: * parameter is an unsigned long.
287: */
288: # endif
289: #endif
290:
291:
292: #ifndef UTIL /* the companion #endif is a bit of ways down ... */
293:
294: #ifndef __TURBOC__
295: int utime OF((char *, time_t *));
296: #endif /* !__TURBOC__ */
297: #ifndef MSDOS
298: int open OF((char *, int, ...));
299: int close OF((int));
300: # ifndef RMDIR
301: int rmdir OF((char *));
302: # endif /* !RMDIR */
303: #endif /* !MSDOS */
304:
305:
306: /* Local globals (kinda like "military intelligence" or "broadcast quality") */
307: local int exflag = 0; /* Exclude flag */
308:
309: #ifdef VMS
310: typedef int statime;
311: #else /* !VMS */
312: typedef time_t statime;
313: #endif /* ?VMS */
314:
315: /* Local functions */
316: #ifdef PROTO
317: # ifdef VMS
318: local void vms_wild(char *, dstrm *);
319: # endif /* VMS */
320: # ifdef DIRENT
321: local dstrm *opend(char *);
322: local void closed(dstrm *);
323: # endif /* DIRENT */
324: local char *readd(dstrm *);
325: local int fqcmp(voidp *, voidp *);
326: local int fqcmpz(voidp *, voidp *);
327: local char *last(char *);
328: local char *msname(char *);
329: # ifdef VMS
330: local char *strlower(char *);
331: local char *strupper(char *);
332: # endif /* VMS */
333: local char *ex2in(char *, int *);
334: local int newname(char *);
335: local void inctime(struct tm *);
336: local ulg unix2dostime(statime *);
337: # if !defined(__TURBOC__) && !defined(OS2) && !defined(__GO32__)
338: local int cmptime(struct tm *, struct tm *);
339: local time_t invlocal(struct tm *);
340: # endif /* !__TURBOC__ */
341: #endif /* PROTO */
342:
343:
344: #if defined(MSDOS) && !defined(OS2)
345: dstrm *opendir(n)
346: char *n; /* directory to open */
347: /* Start searching for files in the MSDOS directory n */
348: {
349: dstrm *d; /* malloc'd return value */
350: char *p; /* malloc'd temporary string */
351:
352: if ((d = (dstrm *)malloc(sizeof(dstrm))) == NULL ||
353: (p = malloc(strlen(n) + 5)) == NULL)
354: return NULL;
355: strcat(strcpy(p, n), "/*.*");
356: #ifdef WIN32
357: {
358: WIN32_FIND_DATA fd;
359: DWORD dwAttr;
360: BOOL bAttr;
361:
362: if ((HANDLE)0xFFFFFFFF == (d->d_hFindFile = FindFirstFile(p, &fd)))
363: {
364: free((voidp *)p);
365: return NULL;
366: }
367: else
368: strcpy(d->d_name, fd.cFileName);
369: if (-1 != (dwAttr = GetFileAttributes(fd.cFileName)))
370: {
371: bAttr = FALSE;
372: if (FILE_ATTRIBUTE_SYSTEM == (dwAttr & FILE_ATTRIBUTE_SYSTEM))
373: bAttr = TRUE;
374: if (FILE_ATTRIBUTE_HIDDEN == (dwAttr & FILE_ATTRIBUTE_HIDDEN))
375: bAttr = TRUE;
376: if (FILE_ATTRIBUTE_DIRECTORY == (dwAttr & FILE_ATTRIBUTE_DIRECTORY))
377: bAttr = TRUE;
378: if (!bAttr)
379: {
380: free ((voidp *)p);
381: free ((void *) d);
382: return NULL;
383: }
384: }
385:
386: }
387: #else
388: if (FFIRST(p, d))
389: {
390: free((voidp *)p);
391: return NULL;
392: }
393: free((voidp *)p);
394: #endif
395: d->d_first = 1;
396: return d;
397: }
398:
399: struct direct *readdir(d)
400: dstrm *d; /* directory stream to read from */
401: /* Return pointer to first or next directory entry, or NULL if end. */
402: {
403: if (d->d_first)
404: d->d_first = 0;
405: else
406: #ifdef WIN32
407: {
408: WIN32_FIND_DATA fd;
409:
410: if (!FindNextFile(d->d_hFindFile, &fd))
411: return NULL;
412: else
413: strcpy(d->d_name, fd.cFileName);
414: }
415: #else /* !WIN32 */
416: if (FNEXT(d))
417: return NULL;
418: #endif
419: return (struct direct *)d;
420: }
421: # define closedir free
422:
423: #endif /* MSDOS && !OS2 */
424:
425:
426: #ifdef VMS
427:
428: /*---------------------------------------------------------------------------
429:
430: _vms_findfirst() and _vms_findnext(), based on public-domain DECUS C
431: fwild() and fnext() routines (originally written by Martin Minow, poss-
432: ibly modified by Jerry Leichter for bintnxvms.c), were written by Greg
433: Roelofs and are still in the public domain. Routines approximate the
434: behavior of MS-DOS (MSC and Turbo C) findfirst and findnext functions.
435:
436: ---------------------------------------------------------------------------*/
437: local void vms_wild(p, d)
438: char *p;
439: dstrm *d;
440: {
441: /*
442: * Do wildcard setup
443: */
444: /* set up the FAB and NAM blocks. */
445: d->fab = cc$rms_fab; /* initialize fab */
446: d->nam = cc$rms_nam; /* initialize nam */
447:
448: d->fab.fab$l_nam = &d->nam; /* fab -> nam */
449: d->fab.fab$l_fna = p; /* argument wild name */
450: d->fab.fab$b_fns = strlen(p); /* length */
451:
452: d->nam.nam$l_esa = d->d_qualwildname; /* qualified wild name */
453: d->nam.nam$b_ess = NAM$C_MAXRSS; /* max length */
454: d->nam.nam$l_rsa = d->d_name; /* matching file name */
455: d->nam.nam$b_rss = NAM$C_MAXRSS; /* max length */
456:
457: /* parse the file name */
458: if (sys$parse(&d->fab) != RMS$_NORMAL)
459: return;
460: /* Does this replace d->fab.fab$l_fna with a new string in its own space?
461: I sure hope so, since p is free'ed before this routine returns. */
462:
463: /* have qualified wild name (i.e., disk:[dir.subdir]*.*); null-terminate
464: * and set wild-flag */
465: d->d_qualwildname[d->nam.nam$b_esl] = '\0';
466: d->d_wild = (d->nam.nam$l_fnb & NAM$M_WILDCARD)? 1 : 0; /* not used... */
467: #ifdef DEBUG
468: printf(" incoming wildname: %s\n", p);
469: printf(" qualified wildname: %s\n", d->d_qualwildname);
470: #endif /* DEBUG */
471: }
472:
473: dstrm *opendir(n)
474: char *n; /* directory to open */
475: /* Start searching for files in the VMS directory n */
476: {
477: char *c; /* scans VMS path */
478: dstrm *d; /* malloc'd return value */
479: int m; /* length of name */
480: char *p; /* malloc'd temporary string */
481:
482: if ((d = (dstrm *)malloc(sizeof(dstrm))) == NULL ||
483: (p = malloc((m = strlen(n)) + 4)) == NULL)
484: return NULL;
485: /* Directory may be in form "[DIR.SUB1.SUB2]" or "[DIR.SUB1]SUB2.DIR;1".
486: If latter, convert to former. */
487: if (m > 0 && *(c = strcpy(p,n)+m-1) != ']')
488: {
489: while (--c > p && *c != ';')
490: ;
491: if (c-p < 5 || strncmp(c-4, ".DIR", 4))
492: {
493: free((voidp *)d); free((voidp *)p);
494: return NULL;
495: }
496: c -= 3;
497: *c-- = '\0'; /* terminate at "DIR;#" */
498: *c = ']'; /* "." --> "]" */
499: while (c > p && *--c != ']')
500: ;
501: *c = '.'; /* "]" --> "." */
502: }
503: strcat(p, "*.*");
504: vms_wild(p, d); /* set up wildcard */
505: free((voidp *)p);
506: return d;
507: }
508:
509: struct direct *readdir(d)
510: dstrm *d; /* directory stream to read from */
511: /* Return pointer to first or next directory entry, or NULL if end. */
512: {
513: int r; /* return code */
514:
515: do {
516: d->fab.fab$w_ifi = 0; /* internal file index: what does this do? */
517:
518: /* get next match to possible wildcard */
519: if ((r = sys$search(&d->fab)) == RMS$_NORMAL)
520: {
521: d->d_name[d->nam.nam$b_rsl] = '\0'; /* null terminate */
522: return (struct direct *)d; /* OK */
523: }
524: } while (r == RMS$_PRV);
525: return NULL;
526: }
527: # define closedir free
528: #endif /* VMS */
529:
530:
531: #ifdef NODIR /* for AT&T 3B1 */
532: /*
533: ** Apparently originally by Rich Salz.
534: ** Cleaned up and modified by James W. Birdsall.
535: */
536:
537: # define opendir(path) fopen(path, "r")
538:
539: struct direct *readdir(dirp)
540: DIR *dirp;
541: {
542: static struct direct entry;
543:
544: if (dirp == NULL)
545: return NULL;
546: for (;;)
547: if (fread (&entry, sizeof (struct direct), 1, dirp) == 0)
548: return NULL;
549: else if (entry.d_ino)
550: return (&entry);
551: } /* end of readdir() */
552:
553: # define closedir(dirp) fclose(dirp)
554: #endif /* NODIR */
555:
556:
557: #ifdef DIRENT
558: local dstrm *opend(n)
559: char *n; /* directory name to open */
560: /* Open the directory *n, returning a pointer to an allocated dstrm, or
561: NULL if error. */
562: {
563: dstrm *d; /* pointer to malloc'ed directory stream */
564:
565: if ((d = (dstrm *)malloc(sizeof(dstrm))) == NULL)
566: return NULL;
567: if ((d->f = open(n, 0, 0)) < 0) /* open directory */
568: return NULL;
569: d->p = d->q = d->b; /* buffer is empty */
570: return d;
571: }
572: #else /* !DIRENT */
573: # define opend opendir /* just use opendir() */
574: #endif /* ?DIRENT */
575:
576:
577: local char *readd(d)
578: dstrm *d; /* directory stream to read from */
579: /* Return a pointer to the next name in the directory stream d, or NULL if
580: no more entries or an error occurs. */
581: {
582: struct direct *e; /* directory entry read */
583:
584: #ifdef DIRENT
585: int n; /* number of entries read by getdents */
586:
587: if (d->p >= d->q) /* if empty, fill buffer */
588: if ((n = getdents(d->f, d->b, DBSZ)) <= 0)
589: return NULL;
590: else
591: d->q = n + (d->p = d->b);
592: e = (struct direct *)(d->p); /* point to entry */
593: d->p += ((struct direct *)(d->p))->d_reclen; /* advance */
594: return e->d_name; /* return name */
595: #else /* !DIRENT */
596: return (e = readdir(d)) == NULL ? (char *)NULL : e->d_name;
597: #endif /* ?DIRENT */
598: }
599:
600:
601: #ifdef DIRENT
602: local void closed(d)
603: dstrm *d; /* directory stream to close */
604: /* Close the directory stream */
605: {
606: close(d->f);
607: free((voidp *)d);
608: }
609: #else /* !DIRENT */
610: # define closed closedir
611: #endif /* ?DIRENT */
612:
613:
614: #ifdef MSDOS
615:
616: int wild(w)
617: char *w; /* path/pattern to match */
618: /* If not in exclude mode, expand the pattern based on the contents of the
619: file system. Return an error code in the ZE_ class. */
620: {
621: char *a; /* alloc'ed space for name */
622: dstrm *d; /* stream for reading directory */
623: char *e; /* name found in directory */
624: int f; /* true if there was a match */
625: char *n; /* constructed name from directory */
626: char *p; /* path */
627: char *q; /* name */
628: int r; /* temporary variable */
629: char v[5]; /* space for device current directory */
630:
631: /* Allocate and copy pattern */
632: if ((p = a = malloc(strlen(w) + 1)) == NULL)
633: return ZE_MEM;
634: strcpy(p, w);
635:
636: /* Normalize pattern to upper case, path delimiter as '/'. */
637: #if defined(FORCE_UPPER)
638: #ifndef OS2
639: strupr(p); /* convert to upper case */
640: #else /* OS2 */
641: if (IsFileSystemFAT(p)) strupr(p);
642: #endif /* !OS2 */
643: #endif
644: for (q = p; *q; q++) /* use / consistently */
645: if (*q == '\\')
646: *q = '/';
647:
648: /* If excluding, don't bother with file system */
649: if (exflag)
650: {
651: r = procname(p);
652: free((voidp *)a);
653: return r;
654: }
655:
656: /* Only name can have special matching characters */
657: if ((q = isshexp(p)) != NULL &&
658: (strrchr(q, '/') != NULL || strrchr(q, ':') != NULL))
659: {
660: free((voidp *)a);
661: return ZE_PARMS;
662: }
663:
664: /* Separate path and name into p and q */
665: if ((q = strrchr(p, '/')) != NULL && (q == p || q[-1] != ':'))
666: {
667: *q++ = 0; /* path/name -> path, name */
668: if (*p == 0) /* path is just / */
669: p = strcpy(v, "/.");
670: }
671: else if ((q = strrchr(p, ':')) != NULL)
672: { /* has device and no or root path */
673: *q++ = 0;
674: p = strcat(strcpy(v, p), ":"); /* copy device as path */
675: if (*q == '/') /* -> device:/., name */
676: {
677: strcat(p, "/");
678: q++;
679: }
680: strcat(p, ".");
681: }
682: else /* no path or device */
683: {
684: q = p;
685: p = strcpy(v, ".");
686: }
687:
688: /* Search that level for matching names */
689: if ((d = opend(p)) == NULL)
690: {
691: free((voidp *)a);
692: return ZE_MISS;
693: }
694: if ((r = strlen(p)) > 1 &&
695: (strcmp(p + r - 2, ":.") == 0 || strcmp(p + r - 2, "/.") == 0))
696: *(p + r - 1) = 0;
697: f = 0;
698: while ((e = readd(d)) != NULL)
699: if (strcmp(e, ".") && strcmp(e, "..") && MATCH(q, e))
700: {
701: f = 1;
702: if (strcmp(p, ".") == 0) /* path is . */
703: procname(e); /* name is name */
704: else
705: {
706: if ((n = malloc(strlen(p) + strlen(e) + 2)) == NULL)
707: {
708: free((voidp *)a);
709: return ZE_MEM;
710: }
711: n = strcpy(n, p);
712: if (n[r = strlen(n) - 1] != '/' && n[r] != ':')
713: strcat(n, "/");
714: r = procname(strcat(n, e)); /* name is path/name */
715: free((voidp *)n);
716: if (r)
717: {
718: free((voidp *)a);
719: return r;
720: }
721: }
722: }
723: closed(d);
724:
725: /* Done */
726: free((voidp *)a);
727: return f ? ZE_OK : ZE_MISS;
728: }
729:
730: #endif /* MSDOS */
731:
732:
733: #ifdef VMS
734: int wild(p)
735: char *p; /* path/pattern to match */
736: /* Expand the pattern based on the contents of the file system. Return an
737: error code in the ZE_ class. */
738: {
739: dstrm *d; /* stream for reading directory */
740: char *e; /* name found in directory */
741: int f; /* true if there was a match */
742:
743: /* Search given pattern for matching names */
744: if ((d = (dstrm *)malloc(sizeof(dstrm))) == NULL)
745: return ZE_MEM;
746: vms_wild(p, d); /* pattern may be more than just directory name */
747: f = 0;
748: while ((e = readd(d)) != NULL) /* "dosmatch" is already built in */
749: if (procname(e) == ZE_OK)
750: f = 1;
751: closed(d);
752:
753: /* Done */
754: return f ? ZE_OK : ZE_MISS;
755: }
756: #endif /* VMS */
757:
758:
759: char *getnam(n)
760: char *n; /* where to put name (must have >=FNMAX+1 bytes) */
761: /* Read a space, \n, \r, or \t delimited name from stdin into n, and return
762: n. If EOF, then return NULL. Also, if the name read is too big, return
763: NULL. */
764: {
765: int c; /* last character read */
766: char *p; /* pointer into name area */
767:
768: p = n;
769: while ((c = getchar()) == ' ' || c == '\n' || c == '\r' || c == '\t')
770: ;
771: if (c == EOF)
772: return NULL;
773: do {
774: if (p - n >= FNMAX)
775: return NULL;
776: *p++ = (char)c;
777: c = getchar();
778: } while (c != EOF && c != ' ' && c != '\n' && c != '\r' && c != '\t');
779: *p = 0;
780: return n;
781: }
782:
783:
784: struct flist far *fexpel(f)
785: struct flist far *f; /* entry to delete */
786: /* Delete the entry *f in the doubly-linked found list. Return pointer to
787: next entry to allow stepping through list. */
788: {
789: struct flist far *t; /* temporary variable */
790:
791: t = f->nxt;
792: *(f->lst) = t; /* point last to next, */
793: if (t != NULL)
794: t->lst = f->lst; /* and next to last */
795: if (f->name != NULL) /* free memory used */
796: free((voidp *)(f->name));
797: if (f->zname != NULL)
798: free((voidp *)(f->zname));
799: farfree((voidp far *)f);
800: fcount--; /* decrement count */
801: return t; /* return pointer to next */
802: }
803:
804:
805: local int fqcmp(a, b)
806: voidp *a, *b; /* pointers to pointers to found entries */
807: /* Used by qsort() to compare entries in the found list by name. */
808: {
809: return strcmp((*(struct flist far **)a)->name,
810: (*(struct flist far **)b)->name);
811: }
812:
813:
814: local int fqcmpz(a, b)
815: voidp *a, *b; /* pointers to pointers to found entries */
816: /* Used by qsort() to compare entries in the found list by zname. */
817: {
818: return strcmp((*(struct flist far **)a)->zname,
819: (*(struct flist far **)b)->zname);
820: }
821:
822:
823: local char *last(p)
824: char *p; /* sequence of / delimited path components */
825: /* Return a pointer to the start of the last path component. */
826: {
827: char *t; /* temporary variable */
828:
829: #ifdef VMS
830: if ((t = strrchr(p, ']')) != NULL)
831: #else /* !VMS */
832: if ((t = strrchr(p, '/')) != NULL)
833: #endif /* ?VMS */
834: return t + 1;
835: else
836: return p;
837: }
838:
839:
840: local char *msname(n)
841: char *n;
842: /* Reduce all path components to MSDOS upper case 8.3 style names. Probably
843: should also check for invalid characters, but I don't know which ones
844: those are. */
845: {
846: int c; /* current character */
847: int f; /* characters in current component */
848: char *p; /* source pointer */
849: char *q; /* destination pointer */
850:
851: p = q = n;
852: f = 0;
853: while ((c = *p++) != 0)
854: if (c == '/')
855: {
856: *q++ = (char)c;
857: f = 0; /* new component */
858: }
859: else if (c == '.')
860: if (f < 9)
861: {
862: *q++ = (char)c;
863: f = 9; /* now in file type */
864: }
865: else
866: f = 12; /* now just excess characters */
867: else
868: if (f < 12 && f != 8)
869: {
870: *q++ = (char)(to_up(c));
871: f++; /* do until end of name or type */
872: }
873: *q = 0;
874: return n;
875: }
876:
877:
878: #ifdef VMS
879: local char *strlower(s)
880: char *s; /* string to convert */
881: /* Convert all uppercase letters to lowercase in string s */
882: {
883: char *p; /* scans string */
884:
885: for (p = s; *p; p++)
886: if (*p >= 'A' && *p <= 'Z')
887: *p += 'a' - 'A';
888: return s;
889: }
890:
891: local char *strupper(s)
892: char *s; /* string to convert */
893: /* Convert all lowercase letters to uppercase in string s */
894: {
895: char *p; /* scans string */
896:
897: for (p = s; *p; p++)
898: if (*p >= 'a' && *p <= 'z')
899: *p -= 'a' - 'A';
900: return s;
901: }
902: #endif /* VMS */
903:
904: local char *ex2in(x, pdosflag)
905: char *x; /* external file name */
906: int *pdosflag; /* output: force MSDOS file attributes? */
907: /* Convert the external file name to a zip file name, returning the malloc'ed
908: string or NULL if not enough memory. */
909: {
910: char *n; /* internal file name (malloc'ed) */
911: char *t; /* shortened name */
912: int dosflag;
913:
914: #ifdef OS2
915: dosflag = dosify || IsFileSystemFAT(x);
916: if ( !dosify && use_longname_ea && (t = GetLongPathEA(x)) != NULL )
917: {
918: x = t;
919: dosflag = 0;
920: }
921: #else
922: # ifdef MSDOS
923: dosflag = 1;
924: # else /* !MSDOS */
925: dosflag = dosify; /* default for non-DOS and non-OS/2 */
926: # endif /* MSDOS */
927: #endif /* OS2 */
928:
929: /* Find starting point in name before doing malloc */
930: #ifdef MSDOS /* msdos */
931: t = *x && *(x + 1) == ':' ? x + 2 : x;
932: while (*t == '/' || *t == '\\')
933: t++;
934: #else /* !MSDOS */
935: # ifdef VMS /* vms */
936: t = x;
937: if ((n = strrchr(t, ':')) != NULL)
938: t = n + 1;
939: if (*t == '[' && (n = strrchr(t, ']')) != NULL)
940: if ((x = strchr(t, '.')) != NULL && x < n)
941: t = x + 1;
942: else
943: t = n + 1;
944: # else /* !VMS */ /* unix */
945: for (t = x; *t == '/'; t++)
946: ;
947: # endif /* ?VMS */
948: #endif /* ?MSDOS */
949:
950: /* Make changes, if any, to the copied name (leave original intact) */
951: #ifdef MSDOS
952: for (n = t; *n; n++)
953: if (*n == '\\')
954: *n = '/';
955: #endif /* MSDOS */
956:
957: if (!pathput)
958: t = last(t);
959:
960: /* Malloc space for internal name and copy it */
961: if ((n = malloc(strlen(t) + 1)) == NULL)
962: return NULL;
963: strcpy(n, t);
964:
965: #ifdef VMS
966: if ((t = strrchr(n, ']')) != NULL)
967: {
968: *t = '/';
969: while (--t > n)
970: if (*t == '.')
971: *t = '/';
972: }
973:
974: /* Fix from Greg Roelofs: */
975: /* Get current working directory and strip from n (t now = n) */
976: {
977: char cwd[256], *p, *q;
978: int c;
979:
980: if (getcwd(cwd, 256) && ((p = strchr(cwd, '.')) != NULL))
981: {
982: ++p;
983: if ((q = strrchr(p, ']')) != NULL)
984: {
985: *q = '/';
986: while (--q > p)
987: if (*q == '.')
988: *q = '/';
989: /* strip bogus path parts from n */
990: if (strncmp(n, p, (c=strlen(p))) == 0)
991: {
992: q = n + c;
993: while (*t++ = *q++)
994: ;
995: }
996: }
997: }
998: }
999: strlower(n);
1000: if (!vmsver)
1001: if ((t = strrchr(n, ';')) != NULL)
1002: *t = 0;
1003:
1004: if( (t = strrchr(n, '.')) != NULL )
1005: {
1006: if( t[1] == 0 ) /* "filename." -> "filename" */
1007: *t = 0;
1008: else if( t[1] == ';' ) /* "filename.;vvv" -> "filename;vvv" */
1009: {
1010: char *f;
1011: for( f=t+1; *t++ = *f++; )
1012: ;
1013: }
1014: }
1015: #endif /* VMS */
1016: if (dosify)
1017: msname(n);
1018: #if defined(MSDOS) && !defined(OS2) && !defined(FORCE_UPPER)
1019: else
1020: strlwr(n);
1021: #endif
1022: /* Returned malloc'ed name */
1023: if (pdosflag)
1024: *pdosflag = dosflag;
1025: return n;
1026: }
1027:
1028:
1029: char *in2ex(n)
1030: char *n; /* internal file name */
1031: /* Convert the zip file name to an external file name, returning the malloc'ed
1032: string or NULL if not enough memory. */
1033: {
1034: char *x; /* external file name */
1035: #ifdef VMS
1036: char *t; /* scans name */
1037:
1038: if ((t = strrchr(n, '/')) == NULL)
1039: #endif /* VMS */
1040: {
1041: if ((x = malloc(strlen(n) + 1 + PAD)) == NULL)
1042: return NULL;
1043: strcpy(x, n);
1044: }
1045: #ifdef VMS
1046: else
1047: {
1048: if ((x = malloc(strlen(n) + 3 + PAD)) == NULL)
1049: return NULL;
1050: strcpy(x, "[.");
1051: strcpy(x + 2, n);
1052: *(t = x + 2 + (t - n)) = ']';
1053: while (--t > x)
1054: if (*t == '/')
1055: *t = '.';
1056: }
1057: strupper(x);
1058: #endif /* VMS */
1059: #ifdef OS2
1060: if ( !IsFileNameValid(x) )
1061: ChangeNameForFAT(x);
1062: #endif /* !OS2 */
1063: #if defined(FORCE_UPPER) && defined(MSDOS)
1064: /* Don't convert to upper case, causes wrong warnings. Keep the
1065: * name as it was before in the old zip file.
1066: */
1067: strupr(x);
1068: #endif
1069: return x;
1070: }
1071:
1072:
1073: int exclude()
1074: /* Change from including to excluding names when procname() called. Return
1075: an error code in the ZE_ class. */
1076: {
1077: struct flist far *f; /* steps through found linked list */
1078: extent j; /* index for s */
1079: struct flist far **s; /* sorted table */
1080:
1081: /* sort found list, remove duplicates */
1082: if (fcount)
1083: {
1084: if ((s = (struct flist far **)malloc(
1085: fcount * sizeof(struct flist far *))) == NULL)
1086: return ZE_MEM;
1087: for (j = 0, f = found; f != NULL; f = f->nxt)
1088: s[j++] = f;
1089: qsort((char *)s, fcount, sizeof(struct flist far *), fqcmp);
1090: for (j = fcount - 1; j > 0; j--)
1091: if (strcmp(s[j - 1]->name, s[j]->name) == 0)
1092: fexpel(s[j]); /* fexpel() changes fcount */
1093: qsort((char *)s, fcount, sizeof(struct flist far *), fqcmpz);
1094: for (j = 1; j < fcount; j++)
1095: if (strcmp(s[j - 1]->zname, s[j]->zname) == 0)
1096: {
1097: warn("name in zip file repeated: ", s[j]->zname);
1098: warn(" first full name: ", s[j - 1]->name);
1099: warn(" second full name: ", s[j]->name);
1100: return ZE_PARMS;
1101: }
1102: free((voidp *)s);
1103: }
1104: exflag = 1;
1105: return ZE_OK;
1106: }
1107:
1108:
1109: local int newname(n)
1110: char *n; /* name to add (or exclude) */
1111: /* Add (or exclude) a name that is not in the zip file. Return an error
1112: code in the ZE_ class. */
1113: {
1114: char *m;
1115: struct flist far *f; /* where in found, or new found entry */
1116: struct zlist far *z; /* where in zfiles (if found) */
1117: int dosflag;
1118:
1119: /* Search for name in zip file. If there, mark it, else add to
1120: list of new names to do (or remove from that list). */
1121: if ((m = ex2in(n, &dosflag)) == NULL)
1122: return ZE_MEM;
1123: if ((z = zsearch(m)) != NULL)
1124: if (exflag)
1125: {
1126: z->mark = 0;
1127: free((voidp *)m);
1128: if (verbose)
1129: printf("zip diagnostic: excluding %s\n", z->name);
1130: }
1131: else
1132: {
1133: free((voidp *)(z->name));
1134: free((voidp *)(z->zname));
1135: if ((z->name = malloc(strlen(n) + 1 + PAD)) == NULL)
1136: return ZE_MEM;
1137: strcpy(z->name, n);
1138: z->zname = m;
1139: z->mark = 1;
1140: z->dosflag = dosflag;
1141: if (verbose)
1142: printf("zip diagnostic: including %s\n", z->name);
1143: }
1144: else
1145: if (exflag)
1146: {
1147: /* search list for name--if there, remove it */
1148: for (f = found; f != NULL; f = f->nxt)
1149: if (namecmp(n, f->name) == 0)
1150: {
1151: fexpel(f);
1152: break;
1153: }
1154: free((voidp *)m);
1155: }
1156: else
1157: {
1158: /* allocate space and add to list */
1159: if ((f = (struct flist far *)farmalloc(sizeof(struct flist))) == NULL ||
1160: (f->name = malloc(strlen(n) + 1 + PAD)) == NULL)
1161: {
1162: if (f != NULL)
1163: farfree((voidp far *)f);
1164: return ZE_MEM;
1165: }
1166: strcpy(f->name, n);
1167: f->zname = m;
1168: f->dosflag = dosflag;
1169: *fnxt = f;
1170: f->lst = fnxt;
1171: f->nxt = NULL;
1172: fnxt = &f->nxt;
1173: fcount++;
1174: }
1175: return ZE_OK;
1176: }
1177:
1178:
1179: int procname(n)
1180: char *n; /* name to process */
1181: /* Process a name or sh expression to operate on (or exclude). Return
1182: an error code in the ZE_ class. */
1183: {
1184: char *a; /* path and name for recursion */
1185: dstrm *d; /* directory stream from opend() */
1186: char *e; /* pointer to name from readd() */
1187: struct flist far *f; /* steps through found list */
1188: int m; /* matched flag */
1189: char *p; /* path for recursion */
1190: struct stat s; /* result of stat() */
1191: struct zlist far *z; /* steps through zfiles list */
1192:
1193: if (strcmp(n, "-") == 0) /* if compressing stdin */
1194: return newname(n);
1195: else if (
1196: #ifdef S_IFLNK /* if symbolic links exist ... */
1197: linkput ? lstat(n, &s) :
1198: #endif /* S_IFLNK */
1199: SSTAT(n, &s)
1200: #if defined(__TURBOC__) || defined(VMS)
1201: /* Borland and VMS C bug: stat() succeeds on wild card names! */
1202: || isshexp(n)
1203: #endif
1204: )
1205: {
1206: /* Not a file or directory--search for shell expression in zip file */
1207: p = ex2in(n, NULL); /* shouldn't affect matching chars */
1208: m = 1;
1209: for (z = zfiles; z != NULL; z = z->nxt)
1210: if (MATCH(p, z->zname))
1211: {
1212: z->mark = !exflag;
1213: if (verbose)
1214: printf("zip diagnostic: %scluding %s\n",
1215: exflag ? "ex" : "in", z->name);
1216: m = 0;
1217: }
1218: /* If excluding, also search for expression in found list */
1219: if (exflag)
1220: {
1221: for (f = found; f != NULL;)
1222: if (MATCH(p, f->zname))
1223: {
1224: f = fexpel(f);
1225: m = 0;
1226: }
1227: else
1228: f = f->nxt;
1229: }
1230: free((voidp *)p);
1231: if (m)
1232: return ZE_MISS; /* no match */
1233: }
1234: else
1235: {
1236: /* Live name--use if file, recurse if directory */
1237: #if defined(FORCE_UPPER) && defined(MSDOS)
1238: # ifndef OS2
1239: strupr(n); /* convert to upper case */
1240: # else /* OS2 */
1241: if (IsFileSystemFAT(n)) strupr(n);
1242: # endif /* !OS2 */
1243: #endif
1244:
1245: #ifdef MSDOS
1246: for (p = n; *p; p++) /* use / consistently */
1247: if (*p == '\\')
1248: *p = '/';
1249: #endif /* MSDOS */
1250: if ((s.st_mode & S_IFDIR) == 0)
1251: {
1252: /* add or remove name of file */
1253: if ((m = newname(n)) != ZE_OK)
1254: return m;
1255: } else {
1256: /* recurse into directory */
1257: if (recurse && (d = opend(n)) != NULL)
1258: {
1259: #ifdef VMS
1260: while ((e = readd(d)) != NULL)
1261: if ((m = procname(e)) != ZE_OK) /* recurse on name */
1262: {
1263: /* want to just set warning error and continue */
1264: closed(d);
1265: return m;
1266: }
1267: #else /* !VMS */
1268: if ((p = malloc(strlen(n)+2)) == NULL)
1269: return ZE_MEM;
1270: if (strcmp(n, ".") == 0)
1271: *p = 0; /* avoid "./" prefix and do not create zip entry */
1272: else
1273: {
1274: strcpy(p, n);
1275: a = p + strlen(p);
1276: if (a[-1] != '/')
1277: strcpy(a, "/");
1278: if ((m = newname(p)) != ZE_OK)
1279: return m;
1280: }
1281: while ((e = readd(d)) != NULL)
1282: if (strcmp(e, ".") && strcmp(e, ".."))
1283: {
1284: if ((a = malloc(strlen(p) + strlen(e) + 1)) == NULL)
1285: {
1286: free((voidp *)p);
1287: closed(d);
1288: return ZE_MEM;
1289: }
1290: strcat(strcpy(a, p), e);
1291: if ((m = procname(a)) != ZE_OK) /* recurse on name */
1292: {
1293: free((voidp *)a); free((voidp *)p);
1294: closed(d);
1295: return m;
1296: }
1297: free((voidp *)a);
1298: }
1299: free((voidp *)p);
1300: #endif /* ?VMS */
1301: closed(d);
1302: }
1303: }
1304: }
1305: return ZE_OK;
1306: }
1307:
1308:
1309: #if !defined(CRAY) && !defined(__TURBOC__) && !defined(OS2) /* and ... */
1310: #if !defined( __GO32__)
1311:
1312: local int cmptime(p, q)
1313: struct tm *p, *q; /* times to compare */
1314: /* Return negative if time p is before time q, positive if after, and
1315: zero if the same */
1316: {
1317: int r; /* temporary variable */
1318:
1319: if (p == NULL)
1320: return -1;
1321: else if ((r = p->tm_year - q->tm_year) != 0)
1322: return r;
1323: else if ((r = p->tm_mon - q->tm_mon) != 0)
1324: return r;
1325: else if ((r = p->tm_mday - q->tm_mday) != 0)
1326: return r;
1327: else if ((r = p->tm_hour - q->tm_hour) != 0)
1328: return r;
1329: else if ((r = p->tm_min - q->tm_min) != 0)
1330: return r;
1331: else
1332: return p->tm_sec - q->tm_sec;
1333: }
1334:
1335:
1336: local time_t invlocal(t)
1337: struct tm *t; /* time to convert */
1338: /* Find inverse of localtime() using bisection. This routine assumes that
1339: time_t is an integer type, either signed or unsigned. The expectation
1340: is that sometime before the year 2038, time_t will be made a 64-bit
1341: integer, and this routine will still work. */
1342: {
1343: time_t i; /* midpoint of current root range */
1344: time_t l; /* lower end of root range */
1345: time_t u; /* upper end of root range */
1346:
1347: /* Bracket the root [0,largest time_t]. Note: if time_t is a 32-bit signed
1348: integer, then the upper bound is GMT 1/19/2038 03:14:07, after which all
1349: the Unix systems in the world come to a grinding halt. Either that, or
1350: all those systems will suddenly find themselves transported to December
1351: of 1901 ... */
1352: l = 0;
1353: u = 1;
1354: while (u < (u << 1))
1355: u = (u << 1) + 1;
1356:
1357: /* Find the root */
1358: while (u - l > 1)
1359: {
1360: i = l + ((u - l) >> 1);
1361: if (cmptime(localtime(&i), t) <= 0)
1362: l = i;
1363: else
1364: u = i;
1365: }
1366: return l;
1367: }
1368: #endif
1369: #endif
1370:
1371:
1372: void stamp(f, d)
1373: char *f; /* name of file to change */
1374: ulg d; /* dos-style time to change it to */
1375: /* Set last updated and accessed time of file f to the DOS time d. */
1376: {
1377: #if defined(MACOS)
1378: warn("timestamp not implemented yet", "");
1379: #else
1380: #ifdef __TURBOC__
1381: int h; /* file handle */
1382:
1383: if ((h = open(f, 0)) != -1)
1384: {
1385: #ifdef ATARI_ST
1386: d = ( d >> 16 ) | ( d << 16 );
1387: #endif
1388: setftime(h, (struct ftime *)&d);
1389: close(h);
1390: }
1391: #else /* !__TURBOC__ */
1392: #ifdef VMS
1393: int tm_sec, tm_min, tm_hour, tm_mday, tm_mon, tm_year;
1394: char timbuf[24];
1395: static char *month[] = {"JAN", "FEB", "MAR", "APR", "MAY", "JUN",
1396: "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"};
1397: struct VMStimbuf {
1398: char *actime; /* VMS revision date, ASCII format */
1399: char *modtime; /* VMS creation date, ASCII format */
1400: } ascii_times = {timbuf, timbuf};
1401:
1402: /* Convert DOS time to ASCII format for VMSmunch */
1403: tm_sec = (int)(d << 1) & 0x3e;
1404: tm_min = (int)(d >> 5) & 0x3f;
1405: tm_hour = (int)(d >> 11) & 0x1f;
1406: tm_mday = (int)(d >> 16) & 0x1f;
1407: tm_mon = ((int)(d >> 21) & 0xf) - 1;
1408: tm_year = ((int)(d >> 25) & 0x7f) + 1980;
1409: sprintf(timbuf, "%02d-%3s-%04d %02d:%02d:%02d.00", tm_mday, month[tm_mon],
1410: tm_year, tm_hour, tm_min, tm_sec);
1411:
1412: /* Set updated and accessed times of f */
1413: if (VMSmunch(f, SET_TIMES, &ascii_times) != RMS$_NMF)
1414: warn("can't set zipfile time: ", f);
1415:
1416: #else /* !VMS */
1417: #ifdef OS2
1418: SetFileTime(f, d);
1419: #else /* !OS2 */
1420: struct tm t; /* argument for mktime() or invlocal() */
1421: time_t u[2]; /* argument for utime() */
1422: #ifndef __GO32__
1423: extern time_t mktime OF((struct tm *));
1424: #endif
1425:
1426: /* Convert DOS time to time_t format in u[0] and u[1] */
1427: t.tm_sec = (int)(d << 1) & 0x3e;
1428: t.tm_min = (int)(d >> 5) & 0x3f;
1429: t.tm_hour = (int)(d >> 11) & 0x1f;
1430: t.tm_mday = (int)(d >> 16) & 0x1f;
1431: t.tm_mon = ((int)(d >> 21) & 0xf) - 1;
1432: t.tm_year = ((int)(d >> 25) & 0x7f) + 80;
1433: #if defined(MSDOS) || defined(OS2) || defined(CRAY)
1434: /* mktime() is more reliable than invlocal() because the time range is
1435: * wider on MSDOS than on Unix; required for Cray because invlocal assumes
1436: * 32-bit ints
1437: */
1438: u[0] = u[1] = mktime(&t);
1439: #else
1440: u[0] = u[1] = invlocal(&t);
1441: #endif
1442:
1443: /* Set updated and accessed times of f */
1444: utime(f, u);
1445: #endif /* ?OS2 */
1446: #endif /* ?VMS */
1447: #endif /* ?__TURBOC__ */
1448: #endif /* ?MACOS */
1449: }
1450:
1451:
1452: local void inctime(s)
1453: struct tm *s; /* time to increment in place */
1454: /* Increment the time structure *s by one second, return the result in
1455: place. */
1456: {
1457: int y; /* temporary variable */
1458:
1459: /* days in each month, except for February */
1460: static int days[] = {31,0,31,30,31,30,31,31,30,31,30,31};
1461:
1462: /* Set days in February from year (1900 is a leap year, 2000 is not) */
1463: y = s->tm_year + 1900;
1464: days[1] = y % 4 == 0 && (y % 100 != 0 || y % 400 == 0) ? 29 : 28;
1465:
1466: /* Increment time with carry */
1467: if (s->tm_sec != 59)
1468: s->tm_sec++;
1469: else if (s->tm_sec = 0, s->tm_min != 59)
1470: s->tm_min++;
1471: else if (s->tm_min = 0, s->tm_hour != 23)
1472: s->tm_hour++;
1473: else if (s->tm_hour = 0, s->tm_mday != days[s->tm_mon])
1474: s->tm_mday++;
1475: else if (s->tm_mday = 1, s->tm_mon != 11)
1476: s->tm_mon++;
1477: else
1478: {
1479: s->tm_mon = 0;
1480: s->tm_year++;
1481: }
1482: }
1483:
1484:
1485: ulg dostime(y, n, d, h, m, s)
1486: int y; /* year */
1487: int n; /* month */
1488: int d; /* day */
1489: int h; /* hour */
1490: int m; /* minute */
1491: int s; /* second */
1492: /* Convert the date y/n/d and time h:m:s to a four byte DOS date and
1493: time (date in high two bytes, time in low two bytes allowing magnitude
1494: comparison). */
1495: {
1496: return y < 1980 ? dostime(1980, 1, 1, 0, 0, 0) :
1497: (((ulg)y - 1980) << 25) | ((ulg)n << 21) | ((ulg)d << 16) |
1498: ((ulg)h << 11) | ((ulg)m << 5) | ((ulg)s >> 1);
1499: }
1500:
1501:
1502: local ulg unix2dostime(t)
1503: statime *t; /* unix time to convert */
1504: /* Return the Unix time t in DOS format, rounded up to the next two
1505: second boundary. */
1506: {
1507: struct tm *s; /* result of localtime() */
1508:
1509: s = localtime(t); /* Use local time since MSDOS does */
1510: inctime(s); /* Add one second to round up */
1511: return dostime(s->tm_year + 1900, s->tm_mon + 1, s->tm_mday,
1512: s->tm_hour, s->tm_min, s->tm_sec);
1513: }
1514:
1515:
1516: ulg filetime(f, a, n)
1517: char *f; /* name of file to get info on */
1518: ulg *a; /* return value: file attributes */
1519: long *n; /* return value: file size */
1520: /* If file *f does not exist, return 0. Else, return the file's last
1521: modified date and time as an MSDOS date and time. The date and
1522: time is returned in a long with the date most significant to allow
1523: unsigned integer comparison of absolute times. Also, if a is not
1524: a NULL pointer, store the file attributes there, with the high two
1525: bytes being the Unix attributes, and the low byte being a mapping
1526: of that to DOS attributes. If n is not NULL, store the file size
1527: there.
1528: If f is "-", use standard input as the file. If f is a device, return
1529: a file size of -1 */
1530: {
1531: struct stat s; /* results of stat() */
1532: char name[FNMAX];
1533: int len = strlen(f);
1534:
1535: strcpy(name, f);
1536: if (name[len - 1] == '/')
1537: name[len - 1] = 0;
1538: /* not all systems allow stat'ing a file with / appended */
1539:
1540: if (strcmp(f, "-") == 0) {
1541: if (fstat(fileno(stdin), &s) != 0)
1542: error("fstat(stdin)");
1543: } else if ((
1544: #ifdef S_IFLNK
1545: linkput ? lstat(name, &s) :
1546: #endif
1547: SSTAT(name, &s)) != 0)
1548: /* Accept about any file kind including directories
1549: * (stored with trailing / with -r option)
1550: */
1551: return 0;
1552:
1553: if (a != NULL)
1554: #ifdef OS2
1555: *a = (s.st_mode << 16) | GetFileMode(name);
1556: #else
1557: *a = (s.st_mode << 16) | !(s.st_mode & S_IWRITE);
1558: #endif
1559: if (n != NULL)
1560: *n = (s.st_mode & S_IFREG) == 0 ? -1L : s.st_size;
1561:
1562: #ifdef OS2
1563: return GetFileTime(name);
1564: #else /* !OS2 */
1565: # ifdef VMS
1566: return unix2dostime(&s.st_ctime); /* Use creation time in VMS */
1567: # else /* !VMS */
1568: # ifdef ATARI_ST
1569: return s.st_mtime; /* Turbo C doesn't use UNIX times */
1570: # else
1571: return unix2dostime(&s.st_mtime);
1572: # endif
1573: # endif /* ?VMS */
1574: #endif /* ?OS2 */
1575: }
1576:
1577:
1578: int issymlnk(a)
1579: ulg a; /* Attributes returned by filetime() */
1580: /* Return true if the attributes are those of a symbolic link */
1581: {
1582: #ifdef S_IFLNK
1583: return ((a >> 16) & S_IFMT) == S_IFLNK;
1584: #else /* !S_IFLNK */
1585: return (int)a & 0; /* avoid warning on unused parameter */
1586: #endif /* ?S_IFLNK */
1587: }
1588:
1589:
1590: int deletedir(d)
1591: char *d; /* directory to delete */
1592: /* Delete the directory *d if it is empty, do nothing otherwise.
1593: Return the result of rmdir(), delete(), or system().
1594: */
1595: {
1596: #ifdef MACOS
1597: warn("deletedir not implemented yet", "");
1598: return 127;
1599: #else
1600: #ifdef RMDIR
1601: /* code from Greg Roelofs, who horked it from Mark Edwards (unzip) */
1602: int r, len;
1603: char *s; /* malloc'd string for system command */
1604:
1605: len = strlen(d);
1606: if ((s = malloc(len + 34)) == NULL)
1607: return 127;
1608:
1609: #ifdef VMS
1610: {
1611: char *c; /* pointer into VMS path */
1612: /* convert "DEV:[DIR.SUB1.SUB2]" form to "DEV:[DIR.SUB1]SUB2.DIR;0" */
1613: strcat(strcpy(s, "set prot=(o:rwed) "), d); /* d starts at s+18 */
1614: if (*(c = s+17+len) != ']')
1615: {
1616: free(s);
1617: return 127;
1618: }
1619: strcpy(c, ".DIR;0"); /* 0 translates to highest version */
1620: while (--c > s+18 && *c != '.' && *c != '[') ;
1621: if (c == s+18)
1622: {
1623: free(s);
1624: return 127;
1625: }
1626: if (*c == '.')
1627: *c = ']';
1628: else if (*--c == ']') /* presumably of form "DEV:[DIR.SUB1.][SUB2]" */
1629: { /* (possible to have "DEV:[DIR.SUB1.][][SUB2]"?) */
1630: char *b = c + 2;
1631: c[-1] = ']';
1632: while (*c++ = *b++) ;
1633: }
1634: else /* must have reached device name: can't delete top level */
1635: {
1636: free(s);
1637: return 127;
1638: }
1639: }
1640: /* unprotect directory and delete it as a file. May fail if exists
1641: normal file "foo.dir" on top of directory "foo.dir" */
1642: system(s);
1643: r = delete(s+18);
1644: #else /* !VMS */
1645: sprintf(s, "IFS=\" \t\n\" /bin/rmdir %s 2>/dev/null", d);
1646: r = system(s);
1647: #endif /* ?VMS */
1648: free(s);
1649: return r;
1650: #else /* !RMDIR */
1651: return rmdir(d);
1652: #endif /* ?RMDIR */
1653: #endif /* ?MACOS */
1654: }
1655:
1656:
1657: #endif /* !UTIL */
1658:
1659: int destroy(f)
1660: char *f; /* file to delete */
1661: /* Delete the file *f, returning non-zero on failure. */
1662: {
1663: return unlink(f);
1664: }
1665:
1666:
1667: int replace(d, s)
1668: char *d, *s; /* destination and source file names */
1669: /* Replace file *d by file *s, removing the old *s. Return an error code
1670: in the ZE_ class. */
1671: {
1672: struct stat t; /* results of stat() */
1673:
1674: if (SSTAT(d, &t) == 0 && unlink(d))
1675: return ZE_CREAT; /* Can't erase zip file--give up */
1676: if (link(s, d)) /* Just move s on top of d */
1677: #if !defined(VMS) && !defined(ATARI_ST)
1678: /* For VMS & ATARI assume failure is EXDEV */
1679: if (errno != EXDEV
1680: # ifdef ENOTSAM
1681: && errno != ENOTSAM /* Used at least on Turbo C */
1682: # endif
1683: ) return ZE_CREAT;
1684: else
1685: #endif
1686: {
1687: FILE *f, *g; /* source and destination files */
1688: int r; /* temporary variable */
1689:
1690: if ((f = fopen(s, FOPR)) == NULL) {
1691: fprintf(stderr," replace: can't open %s\n", s);
1692: return ZE_TEMP;
1693: }
1694: if ((g = fopen(d, FOPW)) == NULL)
1695: {
1696: fclose(f);
1697: return ZE_CREAT;
1698: }
1699: r = fcopy(f, g, (ulg)-1L);
1700: fclose(f);
1701: if (fclose(g) || r != ZE_OK)
1702: {
1703: unlink(d);
1704: return r ? (r == ZE_TEMP ? ZE_WRITE : r) : ZE_WRITE;
1705: }
1706: #ifdef VMS /* only delete if rename failed: previous version may exist */
1707: unlink(s);
1708: }
1709: #else /* !VMS */
1710: }
1711: unlink(s);
1712: #endif /* !VMS */
1713: return ZE_OK;
1714: }
1715:
1716:
1717: int getfileattr(f)
1718: char *f; /* file path */
1719: /* Return the file attributes for file f or 0 if failure */
1720: {
1721: struct stat s;
1722:
1723: return SSTAT(f, &s) == 0 ? s.st_mode : 0;
1724: }
1725:
1726:
1727: int setfileattr(f, a)
1728: char *f; /* file path */
1729: int a; /* attributes returned by getfileattr() */
1730: /* Give the file f the attributes a, return non-zero on failure */
1731: {
1732: #if defined (VMS) || defined(MACOS)
1733: return 0;
1734: #else /* !VMS */
1735: return chmod(f, a);
1736: #endif /* ?VMS */
1737: }
1738:
1739:
1740: #ifdef NO_MKTEMP
1741:
1742: char *tempname(zip)
1743: char *zip; /* path name of zip file to generate temp name for */
1744:
1745: /* Return a temporary file name in its own malloc'ed space.
1746: * This function might accidentally destroy an existing file
1747: * with extension .$z$ . Use mktemp below if you have it on your system.
1748: */
1749: {
1750: char *p; /* temporary pointer */
1751: char *t; /* malloc'ed space for name */
1752:
1753: if ((t = malloc(strlen(zip)+5)) == NULL)
1754: return NULL;
1755: strcpy(t, zip);
1756: if ((p = strrchr(t, '.')) != NULL &&
1757: (!strncmp(p, ".zip", 4) || !strncmp(p, ".ZIP", 4)))
1758: /* strncmp to avoid problems with VMS ';' */
1759: strcpy(p, ".$z$");
1760: else
1761: strcat(t, ".$z$");
1762:
1763: return t;
1764: }
1765: #else /* !NO_MKTEMP */
1766:
1767: char *tempname(zip)
1768: char *zip; /* path name of zip file to generate temp name for */
1769:
1770: /* Return a temporary file name in its own malloc'ed space, using tempath. */
1771: {
1772: char *t = zip; /* malloc'ed space for name (use zip to avoid warning) */
1773:
1774: if (tempath != NULL)
1775: {
1776: if ((t = malloc(strlen(tempath)+10)) == NULL)
1777: return NULL;
1778: strcpy(t, tempath);
1779: #ifndef VMS
1780: if (t[strlen(t)-1] != '/')
1781: strcat(t, "/");
1782: #endif
1783: }
1784: else
1785: {
1786: if ((t = malloc(9)) == NULL)
1787: return NULL;
1788: *t = 0;
1789: }
1790: strcat(t, "_ZXXXXXX");
1791: return mktemp(t);
1792: }
1793:
1794: #endif /* NO_MKTEMP */
1795:
1796:
1797: int fcopy(f, g, n)
1798: FILE *f, *g; /* source and destination files */
1799: ulg n; /* number of bytes to copy or -1 for all */
1800: /* Copy n bytes from file *f to file *g, or until EOF if n == -1. Return
1801: an error code in the ZE_ class. */
1802: {
1803: char *b; /* malloc'ed buffer for copying */
1804: extent k; /* result of fread() */
1805: ulg m; /* bytes copied so far */
1806:
1807: if ((b = malloc(CBSZ)) == NULL)
1808: return ZE_MEM;
1809: m = 0;
1810: while (n == -1L || m < n)
1811: {
1812: if ((k = fread(b, 1, n == -1 ?
1813: CBSZ : (n - m < CBSZ ? (extent)(n - m) : CBSZ), f)) == 0)
1814: if (ferror(f))
1815: {
1816: free((voidp *)b);
1817: return ZE_READ;
1818: }
1819: else
1820: break;
1821: if (fwrite(b, 1, k, g) != k)
1822: {
1823: free((voidp *)b);
1824: fprintf(stderr," fcopy: write error\n");
1825: return ZE_TEMP;
1826: }
1827: m += k;
1828: }
1829: free((voidp *)b);
1830: return ZE_OK;
1831: }
1832:
1833:
1834: #ifdef CRYPT
1835:
1836: #ifndef MSDOS
1837:
1838: #ifdef VMS
1839:
1840: int echo(opt)
1841: int opt;
1842: {
1843: /*---------------------------------------------------------------------------
1844: Based on VMSmunch.c, which in turn was based on Joe Meadows' file.c code.
1845: ---------------------------------------------------------------------------
1846: * For VMS v5.x:
1847: * IO$_SENSEMODE/SETMODE info: Programming, Vol. 7A, System Programming,
1848: * I/O User's: Part I, sec. 8.4.1.1, 8.4.3, 8.4.5, 8.6
1849: * sys$assign(), sys$qio() info: Programming, Vol. 4B, System Services,
1850: * System Services Reference Manual, pp. sys-23, sys-379
1851: * fixed-length descriptor info: Programming, Vol. 3, System Services,
1852: * Intro to System Routines, sec. 2.9.2
1853: * GRR, 15 Aug 91
1854: ---------------------------------------------------------------------------*/
1855: static struct dsc$descriptor_s DevDesc =
1856: {9, DSC$K_DTYPE_T, DSC$K_CLASS_S, "SYS$INPUT"};
1857: /* {dsc$w_length, dsc$b_dtype, dsc$b_class, dsc$a_pointer}; */
1858: static short DevChan, iosb[4];
1859: static long i, status;
1860: static unsigned long oldmode[2], newmode[2]; /* each = 8 bytes */
1861:
1862:
1863: /*---------------------------------------------------------------------------
1864: Assign a channel to standard input.
1865: ---------------------------------------------------------------------------*/
1866:
1867: status = sys$assign(&DevDesc, &DevChan, 0, 0);
1868: if (!(status & 1))
1869: return status;
1870:
1871: /*---------------------------------------------------------------------------
1872: Use sys$qio and the IO$_SENSEMODE function to determine the current tty
1873: status (for password reading, could use IO$_READVBLK function instead,
1874: but echo on/off will be more general).
1875: ---------------------------------------------------------------------------*/
1876:
1877: status = sys$qio(0, DevChan, IO$_SENSEMODE, &iosb, 0, 0,
1878: oldmode, 8, 0, 0, 0, 0);
1879: if (!(status & 1))
1880: return status;
1881: status = iosb[0];
1882: if (!(status & 1))
1883: return status;
1884:
1885: /*---------------------------------------------------------------------------
1886: Copy old mode into new-mode buffer, then modify to be either NOECHO or
1887: ECHO (depending on function argument opt).
1888: ---------------------------------------------------------------------------*/
1889:
1890: newmode[0] = oldmode[0];
1891: newmode[1] = oldmode[1];
1892: if (opt == 0)
1893: newmode[1] |= TT$M_NOECHO; /* set NOECHO bit */
1894: else
1895: newmode[1] &= ~((unsigned long) TT$M_NOECHO); /* clear NOECHO bit */
1896:
1897: /*---------------------------------------------------------------------------
1898: Use the IO$_SETMODE function to change the tty status.
1899: ---------------------------------------------------------------------------*/
1900:
1901: status = sys$qio(0, DevChan, IO$_SETMODE, &iosb, 0, 0,
1902: newmode, 8, 0, 0, 0, 0);
1903: if (!(status & 1))
1904: return status;
1905: status = iosb[0];
1906: if (!(status & 1))
1907: return status;
1908:
1909: /*---------------------------------------------------------------------------
1910: Deassign the sys$input channel by way of clean-up, then exit happily.
1911: ---------------------------------------------------------------------------*/
1912:
1913: status = sys$dassgn(DevChan);
1914: if (!(status & 1))
1915: return status;
1916:
1917: return SS$_NORMAL; /* we be happy */
1918:
1919: } /* end function echo() */
1920:
1921:
1922: #else /* !VMS */
1923:
1924: local int echofd = -1; /* file descriptor whose echo is off */
1925:
1926: void echoff(f)
1927: int f; /* file descriptor to turn echo off on */
1928: /* Turn echo off for file descriptor f. Assumes that f is a tty device. */
1929: {
1930: struct sgttyb sg; /* tty device structure */
1931:
1932: echofd = f;
1933: GTTY(f, &sg); /* get settings */
1934: sg.sg_flags &= ~ECHO; /* turn echo off */
1935: STTY(f, &sg);
1936: }
1937:
1938: void echon()
1939: /* Turn echo back on for file descriptor echofd. */
1940: {
1941: struct sgttyb sg; /* tty device structure */
1942:
1943: if (echofd != -1)
1944: {
1945: GTTY(echofd, &sg); /* get settings */
1946: sg.sg_flags |= ECHO; /* turn echo on */
1947: STTY(echofd, &sg);
1948: echofd = -1;
1949: }
1950: }
1951:
1952: #endif /* ?VMS */
1953:
1954: #endif /* !MSDOS */
1955:
1956:
1957: char *getp(m, p, n)
1958: char *m; /* prompt for password */
1959: char *p; /* return value: line input */
1960: int n; /* bytes available in p[] */
1961: /* Get a password of length n-1 or less into *p using the prompt *m.
1962: The entered password is not echoed. Return p on success, NULL on
1963: failure (can't get controlling tty). */
1964: {
1965: char c; /* one-byte buffer for read() to use */
1966: int i; /* number of characters input */
1967: char *w; /* warning on retry */
1968:
1969: #ifndef MSDOS
1970: #ifndef VMS
1971: int f; /* file decsriptor for tty device */
1972:
1973: /* Turn off echo on tty */
1974: if (!isatty(2))
1975: return NULL; /* error if not tty */
1976: if ((f = open(ttyname(2), 0, 0)) == -1)
1977: return NULL;
1978: #endif /* !VMS */
1979: echoff(f); /* turn echo off */
1980: #endif /* !MSDOS */
1981:
1982: /* Get password */
1983: w = "";
1984: do {
1985: #ifdef VMS /* bug: VMS adds '\n' to NULL fputs (apparently) */
1986: if (*w)
1987: #endif /* VMS */
1988: fputs(w, stderr); /* warning if back again */
1989: fputs(m, stderr); /* prompt */
1990: fflush(stderr);
1991: i = 0;
1992: do { /* read line, keeping n */
1993: #ifdef MSVMS
1994: if ((c = (char)getch()) == '\r')
1995: c = '\n';
1996: #else /* !MSVMS */
1997: read(f, &c, 1);
1998: #endif /* ?MSVMS */
1999: if (i < n)
2000: p[i++] = c;
2001: } while (c != '\n');
2002: putc('\n', stderr); fflush(stderr);
2003: w = "(line too long--try again)\n";
2004: } while (p[i-1] != '\n');
2005: p[i-1] = 0; /* terminate at newline */
2006:
2007: #ifndef MSDOS
2008: echon(); /* turn echo back on */
2009: #ifndef VMS
2010: close(f);
2011: #endif /* !VMS */
2012: #endif /* !MSDOS */
2013:
2014: /* Return pointer to password */
2015: return p;
2016: }
2017:
2018: #endif /* ?CRYPT */
2019:
2020:
2021: #ifdef ZMEM
2022:
2023: /************************/
2024: /* Function memset() */
2025: /************************/
2026:
2027: /*
2028: * memset - for systems without it
2029: * bill davidsen - March 1990
2030: */
2031:
2032: char *
2033: memset(buf, init, len)
2034: register char *buf; /* buffer loc */
2035: register int init; /* initializer */
2036: register unsigned int len; /* length of the buffer */
2037: {
2038: char *start;
2039:
2040: start = buf;
2041: while (len--) *(buf++) = init;
2042: return(start);
2043: }
2044:
2045:
2046: /************************/
2047: /* Function memcpy() */
2048: /************************/
2049:
2050: char *
2051: memcpy(dst,src,len) /* v2.0f */
2052: register char *dst, *src;
2053: register unsigned int len;
2054: {
2055: char *start;
2056:
2057: start = dst;
2058: while (len--)
2059: *dst++ = *src++;
2060: return(start);
2061: }
2062:
2063:
2064: /************************/
2065: /* Function memcmp() */
2066: /************************/
2067:
2068: int
2069: memcmp(b1,b2,len) /* [email protected] -- 11/16/90 */
2070: register char *b1, *b2;
2071: register unsigned int len;
2072: {
2073:
2074: if (len) do { /* examine each byte (if any) */
2075: if (*b1++ != *b2++)
2076: return (*((uch *)b1-1) - *((uch *)b2-1)); /* exit when miscompare */
2077: } while (--len);
2078:
2079: return(0); /* no miscompares, yield 0 result */
2080: }
2081:
2082: #endif /* ZMEM */
2083:
2084: #ifdef __TURBOC__
2085:
2086: /************************/
2087: /* Function fcalloc() */
2088: /************************/
2089:
2090: /* Turbo C malloc() does not allow dynamic allocation of 64K bytes
2091: * and farmalloc(64K) returns a pointer with an offset of 8, so we
2092: * must fix the pointer. Warning: the pointer must be put back to its
2093: * original form in order to free it.
2094: * For MSC, use halloc instead of this function (see tailor.h).
2095: */
2096: void far * fcalloc(items, size)
2097: unsigned items; /* number of items */
2098: unsigned size; /* item size */
2099: {
2100: void far * buf = farmalloc((ulg)items*size + 16L);
2101: /* Normalize the pointer to seg:0 */
2102: *((int*)&buf+1) += ((unsigned)((uch*)buf-0) + 15) >> 4;
2103: *(int*)&buf = 0;
2104: return buf; /* buf stays NULL if alloc failed */
2105: }
2106:
2107: #endif /* __TURBOC__ */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.