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 + -
显示快捷键?