cosmopolitan/third_party/infozip/zip/cmsmvs/mvs.c
2021-06-22 12:38:56 -07:00

221 lines
6.2 KiB
C

/*
Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
See the accompanying file LICENSE, version 1999-Oct-05 or later
(the contents of which are also included in zip.h) for terms of use.
If, for some reason, both of these files are missing, the Info-ZIP license
also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
*/
/*
* MVS specific things
*/
#include "zip.h"
#include "mvs.h"
#include <errno.h>
static int gen_node( DIR *dirp, RECORD *recptr )
{
char *ptr, *name, ttr[TTRLEN];
int skip, count = 2;
unsigned int info_byte, alias, ttrn;
struct dirent *new;
ptr = recptr->rest;
while (count < recptr->count) {
if (!memcmp( ptr, endmark, NAMELEN ))
return 1;
name = ptr; /* member name */
ptr += NAMELEN;
memcpy( ttr, ptr, TTRLEN ); /* ttr name */
ptr += TTRLEN;
info_byte = (unsigned int) (*ptr); /* info byte */
if ( !(info_byte & ALIAS_MASK) ) { /* no alias */
new = malloc( sizeof(struct dirent) );
if (dirp->D_list == NULL)
dirp->D_list = dirp->D_curpos = new;
else
dirp->D_curpos = (dirp->D_curpos->d_next = new);
new->d_next = NULL;
memcpy( new->d_name, name, NAMELEN );
new->d_name[NAMELEN] = '\0';
if ((name = strchr( new->d_name, ' ' )) != NULL)
*name = '\0'; /* skip trailing blanks */
}
skip = (info_byte & SKIP_MASK) * 2 + 1;
ptr += skip;
count += (TTRLEN + NAMELEN + skip);
}
return 0;
}
DIR *opendir(const char *dirname)
{
int bytes, list_end = 0;
DIR *dirp;
FILE *fp;
RECORD rec;
fp = fopen( dirname, "rb" );
if (fp != NULL) {
dirp = malloc( sizeof(DIR) );
if (dirp != NULL) {
dirp->D_list = dirp->D_curpos = NULL;
strcpy( dirp->D_path, dirname );
do {
bytes = fread( &rec, 1, sizeof(rec), fp );
if (bytes == sizeof(rec))
list_end = gen_node( dirp, &rec );
} while (!feof(fp) && !list_end);
fclose( fp );
dirp->D_curpos = dirp->D_list;
return dirp;
}
fclose( fp );
}
return NULL;
}
struct dirent *readdir(DIR *dirp)
{
struct dirent *cur;
cur = dirp->D_curpos;
dirp->D_curpos = dirp->D_curpos->d_next;
return cur;
}
void rewinddir(DIR *dirp)
{
dirp->D_curpos = dirp->D_list;
}
int closedir(DIR *dirp)
{
struct dirent *node;
while (dirp->D_list != NULL) {
node = dirp->D_list;
dirp->D_list = dirp->D_list->d_next;
free( node );
}
free( dirp );
return 0;
}
local char *readd(d)
DIR *d; /* directory stream to read from */
/* Return a pointer to the next name in the directory stream d, or NULL if
no more entries or an error occurs. */
{
struct dirent *e;
e = readdir(d);
return e == NULL ? (char *) NULL : e->d_name;
}
int procname(n, caseflag)
char *n; /* name to process */
int caseflag; /* true to force case-sensitive match */
/* Process a name or sh expression to operate on (or exclude). Return
an error code in the ZE_ class. */
{
char *a; /* path and name for recursion */
DIR *d; /* directory stream from opendir() */
char *e; /* pointer to name from readd() */
int m; /* matched flag */
char *p; /* path for recursion */
struct stat s; /* result of stat() */
struct zlist far *z; /* steps through zfiles list */
int exists; /* 1 if file exists */
if (strcmp(n, "-") == 0) /* if compressing stdin */
return newname(n, 0, caseflag);
else if (!(exists = (LSSTAT(n, &s) == 0)))
{
#ifdef MVS
/* special case for MVS. stat does not work on non-HFS files so if
* stat fails with ENOENT, try to open the file for reading anyway.
* If the user has no OMVS segment, stat gets an initialization error,
* even on external files.
*/
if (errno == ENOENT || errno == EMVSINITIAL) {
FILE *f = fopen(n, "r");
if (f) {
/* stat got ENOENT but fopen worked, external file */
fclose(f);
exists = 1;
memset(&s, '\0', sizeof(s)); /* stat data is unreliable for externals */
s.st_mode = S_IFREG; /* fudge it */
}
}
#endif /* MVS */
}
if (! exists) {
/* Not a file or directory--search for shell expression in zip file */
p = ex2in(n, 0, (int *)NULL); /* shouldn't affect matching chars */
m = 1;
for (z = zfiles; z != NULL; z = z->nxt) {
if (MATCH(p, z->iname, caseflag))
{
z->mark = pcount ? filter(z->zname, caseflag) : 1;
if (verbose)
fprintf(mesg, "zip diagnostic: %scluding %s\n",
z->mark ? "in" : "ex", z->name);
m = 0;
}
}
free((zvoid *)p);
return m ? ZE_MISS : ZE_OK;
}
/* Live name--use if file, recurse if directory */
if (!S_ISDIR(s.st_mode))
{
/* add or remove name of file */
if ((m = newname(n, 0, caseflag)) != ZE_OK)
return m;
} else {
/* Add trailing / to the directory name */
if ((p = malloc(strlen(n)+2)) == NULL)
return ZE_MEM;
if (strcmp(n, ".") == 0) {
*p = '\0'; /* avoid "./" prefix and do not create zip entry */
} else {
strcpy(p, n);
a = p + strlen(p);
if (a[-1] != '/')
strcpy(a, "/");
if (dirnames && (m = newname(p, 1, caseflag)) != ZE_OK) {
free((zvoid *)p);
return m;
}
}
/* recurse into directory */
if (recurse && (d = opendir(n)) != NULL)
{
while ((e = readd(d)) != NULL) {
if (strcmp(e, ".") && strcmp(e, ".."))
{
if ((a = malloc(strlen(p) + strlen(e) + 1)) == NULL)
{
closedir(d);
free((zvoid *)p);
return ZE_MEM;
}
strcat(strcpy(a, p), e);
if ((m = procname(a, caseflag)) != ZE_OK) /* recurse on name */
{
if (m == ZE_MISS)
zipwarn("name not matched: ", a);
else
ziperr(m, a);
}
free((zvoid *)a);
}
}
closedir(d);
}
free((zvoid *)p);
} /* (s.st_mode & S_IFDIR) == 0) */
return ZE_OK;
}