vms.c
来自「压缩算法的源代码」· C语言 代码 · 共 2,500 行 · 第 1/5 页
C
2,500 行
cp = (char *)strrchr(filename, '/');
if (cp == NULL) /* no '/' or not junking dirs */
cp = filename; /* point to internal zipfile-member pathname */
else
++cp; /* point to start of last component of path */
/*---------------------------------------------------------------------------
Begin main loop through characters in filename.
---------------------------------------------------------------------------*/
while ((workch = (uch)*cp++) != 0) {
if (quote) { /* if character quoted, */
*pp++ = (char)workch; /* include it literally */
quote = FALSE;
} else
switch (workch) {
case '/': /* can assume -j flag not given */
*pp = '\0';
if (last_dot) { /* one dot in directory name is legal */
*last_dot = '.';
last_dot = NULL;
}
if ((error = checkdir(pathcomp, APPEND_DIR)) > 1)
return error;
pp = pathcomp; /* reset conversion buffer for next piece */
lastsemi = NULL; /* leave directory semi-colons alone */
break;
case ':':
*pp++ = '_'; /* drive names not stored in zipfile, */
break; /* so no colons allowed */
case '.':
if (pp == pathcomp) { /* nothing appended yet... */
if (*cp == '/') { /* don't bother appending a "./" */
++cp; /* component to the path: skip */
break; /* to next char after the '/' */
} else if (*cp == '.' && cp[1] == '/') { /* "../" */
*pp++ = '.'; /* add first dot, unchanged... */
++cp; /* skip second dot, since it will */
} /* added next (as '_' for now) */
}
last_dot = pp; /* point at last dot so far... */
*pp++ = '_'; /* convert dot to underscore for now */
break;
case ';': /* start of VMS version? */
if (lastsemi)
*lastsemi = '_'; /* convert previous one to underscore */
lastsemi = pp;
*pp++ = ';'; /* keep for now; remove VMS vers. later */
break;
case ' ':
*pp++ = '_';
break;
default:
if( isalpha(workch) || isdigit(workch) ||
workch=='$' || workch=='-' )
*pp++ = (char)workch;
else
*pp++ = '_'; /* convert everything else to underscore */
break;
} /* end switch */
} /* end while loop */
*pp = '\0'; /* done with pathcomp: terminate it */
/* if not saving them, remove VMS version numbers (appended "###") */
if (lastsemi) {
pp = lastsemi + 1; /* expect all digits after semi-colon */
while (isdigit((uch)(*pp)))
++pp;
if (*pp) /* not version number: convert ';' to '_' */
*lastsemi = '_';
else if (!V_flag) /* only digits between ';' and end: nuke */
*lastsemi = '\0';
/* else only digits and we're saving version number: do nothing */
}
if (last_dot != NULL) /* one dot is OK: put it back in */
*last_dot = '.'; /* (already done for directories) */
/*---------------------------------------------------------------------------
Report if directory was created (and no file to create: filename ended
in '/'), check name to be sure it exists, and combine path and name be-
fore exiting.
---------------------------------------------------------------------------*/
if (filename[strlen(filename) - 1] == '/') {
checkdir("", APPEND_NAME); /* create directory, if not found */
checkdir(filename, GETPATH);
if (created_dir && QCOND2) {
fprintf(stdout, " creating: %s\n", filename);
return IZ_CREATED_DIR; /* set dir time (note trailing '/') */
}
return 2; /* dir existed already; don't look for data to extract */
}
if (*pathcomp == '\0') {
fprintf(stderr, "mapname: conversion of %s failed\n", filename);
return 3;
}
checkdir(pathcomp, APPEND_NAME); /* returns 1 if truncated: care? */
checkdir(filename, GETPATH);
return error;
} /* end function mapname() */
int checkdir(pathcomp,fcn)
/*
* returns: 1 - (on APPEND_NAME) truncated filename
* 2 - path doesn't exist, not allowed to create
* 3 - path doesn't exist, tried to create and failed; or
* path exists and is not a directory, but is supposed to be
* 4 - path is too long
* 10 - can't allocate memory for filename buffers
*/
char *pathcomp;
int fcn;
{
int function=fcn & FN_MASK;
static char pathbuf[FILNAMSIZ];
static char lastdir[FILNAMSIZ]="\t"; /* directory created last time */
/* initially - impossible dir. spec. */
static char *pathptr=pathbuf; /* For debugger */
static char *devptr, *dirptr, *namptr;
static int devlen, dirlen, namlen;
static int root_dirlen;
static char *end;
static int first_comp,root_has_dir;
static int rootlen=0;
static char *rootend;
static int mkdir_failed=0;
int status;
/************
*** ROOT ***
************/
#if (!defined(SFX) || defined(SFX_EXDIR))
if(function==ROOT)
{ /* Assume VMS root spec */
char *p = pathcomp;
char *q;
struct
{ short len;
short code;
char *addr;
} itl [4] =
{
{ 0, FSCN$_DEVICE, 0 },
{ 0, FSCN$_ROOT, 0 },
{ 0, FSCN$_DIRECTORY, 0 },
{ 0, 0, 0 } /* End of itemlist */
};
int fields = 0;
struct dsc$descriptor pthcmp;
/*
* Initialize everything
*/
end = devptr = dirptr = rootend = pathbuf;
devlen = dirlen = rootlen = 0;
pthcmp.dsc$a_pointer = pathcomp;
if( (pthcmp.dsc$w_length = strlen(pathcomp)) > 255 )
return 4;
status = sys$filescan(&pthcmp, itl, &fields);
if( !OK(status) )
return 3;
if( fields & FSCN$M_DEVICE )
{ strncpy(devptr = end, itl[0].addr, itl[0].len);
dirptr = (end += (devlen = itl[0].len));
}
root_has_dir = 0;
if( fields & FSCN$M_ROOT )
{ int len;
strncpy(dirptr = end, itl[1].addr,
len = itl[1].len - 1); /* Cut out trailing ']' */
end += len;
root_has_dir = 1;
}
if( fields & FSCN$M_DIRECTORY )
{ char *ptr;
int len;
len = itl[2].len-1;
ptr = itl[2].addr;
if( root_has_dir /* i.e. root specified */ )
{ --len; /* Cut out leading dot */
++ptr; /* ??? [a.b.c.][.d.e] */
}
strncpy(dirptr=end, ptr, len); /* Replace trailing ']' */
*(end+=len) = '.'; /* ... with dot */
++end;
root_has_dir = 1;
}
/* When user specified "[a.b.c.]" or "[qq...]", we have too many
* trailing dots. Let's cut them out. Now we surely have at least
* one trailing dot and "end" points just behind it. */
dirlen = end - dirptr;
while( dirlen > 1 && end[-2] == '.' )
--dirlen,--end;
first_comp = !root_has_dir;
root_dirlen = end - dirptr;
*(rootend = end) = 0;
rootlen = rootend - devptr;
return 0;
}
#endif /* !SFX || SFX_EXDIR */
/************
*** INIT ***
************/
if( function == INIT )
{
if( strlen(filename) + rootlen + 13 > 255 )
return 4;
if( rootlen == 0 ) /* No root given, reset everything. */
{ devptr = dirptr = rootend = pathbuf;
devlen = dirlen = 0;
}
end = rootend;
first_comp = !root_has_dir;
if( dirlen = root_dirlen )
end[-1] = '.';
*end = 0;
return 0;
}
/******************
*** APPEND_DIR ***
******************/
if( function == APPEND_DIR )
{ int cmplen;
cmplen = strlen(pathcomp);
if( first_comp )
{ *end++ = '[';
if( cmplen )
*end++ = '.'; /* "dir/..." --> "[.dir...]" */
/* else "/dir..." --> "[dir...]" */
first_comp = 0;
}
if( cmplen == 1 && *pathcomp == '.' )
; /* "..././..." -- ignore */
else if( cmplen == 2 && pathcomp[0] == '.' && pathcomp[1] == '.' )
{ /* ".../../..." -- convert to "...-..." */
*end++ = '-';
*end++ = '.';
}
else if( cmplen + (end-pathptr) > 255 )
return 4;
else
{ strcpy(end, pathcomp);
*(end+=cmplen) = '.';
++end;
}
dirlen = end - dirptr;
*end = 0;
return 0;
}
/*******************
*** APPEND_NAME ***
*******************/
if( function == APPEND_NAME )
{ if( fcn & USE_DEFAULT )
{ /* Expand renamed filename using collected path, return
* at pathcomp */
struct FAB fab;
struct NAM nam;
fab = cc$rms_fab;
fab.fab$l_fna = filename;
fab.fab$b_fns = strlen(filename);
fab.fab$l_dna = pathptr;
fab.fab$b_dns = end-pathptr;
fab.fab$l_nam = &nam;
nam = cc$rms_nam;
nam.nam$l_esa = pathcomp;
nam.nam$b_ess = 255; /* Assume large enaugh */
if(!OK(status = sys$parse(&fab)) && status == RMS$_DNF ) /* Directory not found: */
{ char save; /* ... try to create it */
char *dirend;
int mkdir_failed;
dirend = (char*)nam.nam$l_dir + nam.nam$b_dir;
save = *dirend;
*dirend = 0;
if( (mkdir_failed = mkdir(nam.nam$l_dev, 0)) && errno == EEXIST )
mkdir_failed = 0;
*dirend = save;
if( mkdir_failed )
return 3;
created_dir = TRUE;
} /* if (sys$parse... */
pathcomp[nam.nam$b_esl] = 0;
return 0;
} /* if (USE_DEFAULT) */
else
{
*end = 0;
if( dirlen )
{ dirptr[dirlen-1] = ']'; /* Close directory */
/*
* Try to create the target directory.
* Don't waste time creating directory that was created
* last time.
*/
if( STRICMP(lastdir,pathbuf) )
{
mkdir_failed = 0;
if( mkdir(pathbuf,0) )
{ if( errno != EEXIST )
mkdir_failed = 1; /* Mine for GETPATH */
}
else
created_dir = TRUE;
strcpy(lastdir,pathbuf);
}
}
else
{ /*
* Target directory unspecified.
* Try to create "sys$disk:[]"
*/
if( strcmp(lastdir,"sys$disk:[]") )
{ strcpy(lastdir,"sys$disk:[]");
mkdir_failed = 0;
if( mkdir(lastdir,0) && errno != EEXIST )
mkdir_failed = 1; /* Mine for GETPATH */
}
}
if( strlen(pathcomp) + (end-pathbuf) > 255 )
return 1;
strcpy(end, pathcomp);
end += strlen(pathcomp);
return 0;
}
}
/***************
*** GETPATH ***
***************/
if( function == GETPATH )
{
if( mkdir_failed )
return 3;
*end = 0; /* To be safe */
strcpy( pathcomp, pathbuf );
return 0;
}
}
int check_for_newer(filename) /* return 1 if existing file newer or equal; */
char *filename; /* 0 if older; -1 if doesn't exist yet */
{
unsigned short timbuf[7];
int dy, mo, yr, hh, mm, ss, dy2, mo2, yr2, hh2, mm2, ss2;
struct FAB fab;
struct XABDAT xdat;
if (stat(filename, &statbuf))
return DOES_NOT_EXIST;
fab = cc$rms_fab;
xdat = cc$rms_xabdat;
fab.fab$l_xab = (char *) &xdat;
fab.fab$l_fna = filename;
fab.fab$b_fns = strlen(filename);
fab.fab$l_fop = FAB$M_GET | FAB$M_UFO;
if ((sys$open(&fab) & 1) == 0) /* open failure: report exists and */
return EXISTS_AND_OLDER; /* older so new copy will be made */
sys$numtim(&timbuf,&xdat.xab$q_cdt);
fab.fab$l_xab = 0L;
sys$dassgn(fab.fab$l_stv);
sys$close(&fab); /* be sure file is closed and RMS knows about it */
yr = timbuf[0];
yr2 = ((lrec.last_mod_file_date >> 9) & 0x7f) + 1980;
if (yr > yr2)
return EXISTS_AND_NEWER;
else if (yr < yr2)
return EXISTS_AND_OLDER;
mo = timbuf[1];
mo2 = ((lrec.last_mod_file_date >> 5) & 0x0f);
if (mo > mo2)
return EXISTS_AND_NEWER;
else if (mo < mo2)
return EXISTS_AND_OLDER;
dy = timbuf[2];
dy2 = (lrec.last_mod_file_date & 0x1f);
if (dy > dy2)
return EXISTS_AND_NEWER;
else if (dy < dy2)
return EXISTS_AND_OLDER;
hh = timbuf[3];
hh2 = (lrec.last_mod_file_time >> 11) & 0x1f;
if (hh > hh2)
return EXISTS_AND_NEWER;
else if (hh < hh2)
return EXISTS_AND_OLDER;
mm = timbuf[4];
mm2 = (lrec.last_mod_file_time >> 5) & 0x3f;
if (mm > mm2)
return EXISTS_AND_NEWER;
else if (mm < mm2)
return EXISTS_AND_OLDER;
/* round to nearest 2 secs--may become 60, but doesn't matter for compare */
ss = (int)((float)timbuf[5] + (float)timbuf[6]*.01 + 1.) & -2;
ss2 = (lrec.last_mod_file_time & 0x1f) * 2;
if (ss >= ss2)
return EXISTS_AND_NEWER;
return EXISTS_AND_OLDER;
}
void return_VMS(ziperr)
int ziperr;
{
#ifdef RETURN_CODES
/*---------------------------------------------------------------------------
Do our own, explicit processing of error codes and print message, since
VMS misinterprets return codes as rather obnoxious system errors ("access
violation," for example).
---------------------------------------------------------------------------*/
switch (ziperr) {
case PK_COOL:
break; /* life is fine... */
case PK_WARN:
fprintf(stderr, "\n[return-code 1: warning error \
(e.g., failed CRC or unknown compression method)]\n");
break;
case PK_ERR:
case PK_BADERR:
fprintf(stderr, "\n[return-code %d: error in zipfile \
(e.g., can't find local file header sig)]\n", ziperr);
break;
case PK_MEM:
case PK_MEM2:
case PK_MEM3:
case PK_MEM4:
case PK_MEM5:
fprintf(stderr, "\n[return-code %d: insufficient memory]\n", ziperr);
break;
case PK_NOZIP:
fprintf(stderr, "\n[return-code 9: zipfile not found]\n");
break;
case PK_PARAM: /* the one that gives "access violation," I think */
fprintf(stderr, "\n[return-code 10:
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?