123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600 |
- /*
- Copyright (c) 1990-2007 Info-ZIP. All rights reserved.
- See the accompanying file LICENSE, version 2007-Mar-4 or later
- (the contents of which are also included in zip.h) for terms of use.
- If, for some reason, all these files are missing, the Info-ZIP license
- also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
- */
- /*
- * vms_pk.c by Igor Mandrichenko
- *
- * version 2.0 20-Mar-1993
- * Generates PKWARE version of VMS attributes
- * extra field according to appnote 2.0.
- * Uses low level QIO-ACP interface.
- * version 2.0-1 10-Apr-1993
- * Save ACLs
- * version 2.1 24-Aug-1993
- * By default produce 0x010C extra record ID instead of
- * PKWARE's 0x000C. The format is mostly compatible with
- * PKWARE.
- * Incompatibility (?): zip produces multiple ACE
- * fields.
- * version 2.1-1 Clean extra fields in vms_get_attributes().
- * Fixed bug with EOF.
- * version 2.1-2 15-Sep-1995, Chr. Spieler
- * Removed extra fields cleanup from vms_get_attributes().
- * This is now done in zipup.c
- * Modified (according to UnZip's vms.[ch]) the fib stuff
- * for DEC C (AXP,VAX) support.
- * version 2.2 28-Sep-1995, Chr. Spieler
- * Reorganized code for easier maintance of the two
- * incompatible flavours (IM style and PK style) VMS
- * attribute support. Generic functions (common to
- * both flavours) are now collected in a `wrapper'
- * source file that includes one of the VMS attribute
- * handlers.
- * Made extra block header conforming to PKware's
- * specification (extra block header has a length
- * of four bytes, two bytes for a signature, and two
- * bytes for the length of the block excluding this
- * header.
- * version 2.2-1 19-Oct-1995, Chr. Spieler
- * Fixed bug in CRC calculation.
- * Use official PK VMS extra field id.
- * version 2.2-2 21-Nov-1997, Chr. Spieler
- * Fixed bug in vms_get_attributes() for directory
- * entries (access to uninitialized ioctx record).
- * Removed unused second arg for vms_open().
- * version 2.2-3 04-Apr-1999, Chr. Spieler
- * Changed calling interface of vms_get_attributes()
- * to accept a void pointer as first argument.
- * version 2.2-4 26-Jan-2002, Chr. Spieler
- * Modified vms_read() to handle files larger than 2GByte
- * (up to size limit of "unsigned long", resp. 4GByte).
- * version 3.0 20-Oct-2004, Steven Schweda.
- * Changed vms_read() to read all the allocated
- * blocks in a file, for sure. Changed the default
- * chunk size from 16K to 32K. Changed to use the
- * new typedef for the ioctx structure. Moved the
- * VMS_PK_EXTRA test into here from VMS.C to allow
- * more general automatic dependency generation.
- * 08-Feb-2005, SMS.
- * Changed to accomodate ODS5 extended file names:
- * NAM structure -> NAM[L], and so on. (VMS.H.)
- * Added some should-never-appear error messages in
- * vms_open().
- */
- #ifdef VMS /* For VMS only ! */
- #ifdef VMS_PK_EXTRA
- #include <ssdef.h>
- #ifndef VMS_ZIP
- #define VMS_ZIP
- #endif
- #include "crc32.h"
- #include "vms.h"
- #include "vmsdefs.h"
- #ifndef ERR
- #define ERR(x) (((x)&1)==0)
- #endif
- #ifndef NULL
- #define NULL (void*)(0L)
- #endif
- #ifndef UTIL
- static PK_info_t PK_def_info =
- {
- ATR$C_RECATTR, ATR$S_RECATTR, {0},
- ATR$C_UCHAR, ATR$S_UCHAR, {0},
- ATR$C_CREDATE, ATR$S_CREDATE, {0},
- ATR$C_REVDATE, ATR$S_REVDATE, {0},
- ATR$C_EXPDATE, ATR$S_EXPDATE, {0},
- ATR$C_BAKDATE, ATR$S_BAKDATE, {0},
- ATR$C_ASCDATES, sizeof(ush), 0,
- ATR$C_UIC, ATR$S_UIC, {0},
- ATR$C_FPRO, ATR$S_FPRO, {0},
- ATR$C_RPRO, ATR$S_RPRO, {0},
- ATR$C_JOURNAL, ATR$S_JOURNAL, {0}
- };
- /* File description structure for Zip low level I/O */
- typedef struct
- {
- struct iosb iosb;
- long vbn;
- uzoff_t size;
- uzoff_t rest;
- int status;
- ush chan;
- ush chan_pad; /* alignment member */
- long acllen;
- uch aclbuf[ATR$S_READACL];
- PK_info_t PKi;
- } ioctx_t;
- /* Forward declarations of public functions: */
- ioctx_t *vms_open(char *file);
- unsigned int vms_read(register ioctx_t *ctx,
- register char *buf, register unsigned int size);
- int vms_error(ioctx_t *ctx);
- int vms_rewind(ioctx_t *ctx);
- int vms_get_attributes(ioctx_t *ctx, struct zlist far *z,
- iztimes *z_utim);
- int vms_close(ioctx_t *ctx);
- #define BLOCK_BYTES 512
- /*---------------*
- | vms_open() |
- *---------------*
- | This routine opens file for reading fetching its attributes.
- | Returns pointer to file description structure.
- */
- ioctx_t *vms_open(file)
- char *file;
- {
- static struct atrdef Atr[VMS_MAX_ATRCNT+1];
- static struct NAM_STRUCT Nam;
- static struct fibdef Fib;
- static struct dsc$descriptor FibDesc =
- {sizeof(Fib),DSC$K_DTYPE_Z,DSC$K_CLASS_S,(char *)&Fib};
- static struct dsc$descriptor_s DevDesc =
- {0,DSC$K_DTYPE_T,DSC$K_CLASS_S,&Nam.NAM_DVI[1]};
- static char EName[NAM_MAXRSS];
- static char RName[NAM_MAXRSS];
- struct FAB Fab;
- register ioctx_t *ctx;
- register struct fatdef *fat;
- int status;
- int i;
- ulg efblk;
- ulg hiblk;
- if ( (ctx=(ioctx_t *)malloc(sizeof(ioctx_t))) == NULL )
- return NULL;
- ctx -> PKi = PK_def_info;
- #define FILL_REQ(ix,id,b) { \
- Atr[ix].atr$l_addr = GVTC &(b); \
- Atr[ix].atr$w_type = (id); \
- Atr[ix].atr$w_size = sizeof(b); \
- }
- FILL_REQ(0, ATR$C_RECATTR, ctx->PKi.ra);
- FILL_REQ(1, ATR$C_UCHAR, ctx->PKi.uc);
- FILL_REQ(2, ATR$C_REVDATE, ctx->PKi.rd);
- FILL_REQ(3, ATR$C_EXPDATE, ctx->PKi.ed);
- FILL_REQ(4, ATR$C_CREDATE, ctx->PKi.cd);
- FILL_REQ(5, ATR$C_BAKDATE, ctx->PKi.bd);
- FILL_REQ(6, ATR$C_ASCDATES, ctx->PKi.rn);
- FILL_REQ(7, ATR$C_JOURNAL, ctx->PKi.jr);
- FILL_REQ(8, ATR$C_RPRO, ctx->PKi.rp);
- FILL_REQ(9, ATR$C_FPRO, ctx->PKi.fp);
- FILL_REQ(10,ATR$C_UIC, ctx->PKi.ui);
- FILL_REQ(11,ATR$C_ACLLENGTH,ctx->acllen);
- FILL_REQ(12,ATR$C_READACL, ctx->aclbuf);
- Atr[13].atr$w_type = 0; /* End of ATR list */
- Atr[13].atr$w_size = 0;
- Atr[13].atr$l_addr = GVTC NULL;
- /* Initialize RMS structures. We need a NAM[L] to retrieve the FID. */
- Fab = cc$rms_fab;
- Nam = CC_RMS_NAM;
- Fab.FAB_NAM = &Nam; /* FAB has an associated NAM[L]. */
- #ifdef NAML$C_MAXRSS
- Fab.fab$l_dna =(char *) -1; /* Using NAML for default name. */
- Fab.fab$l_fna = (char *) -1; /* Using NAML for file name. */
- #endif /* def NAML$C_MAXRSS */
- FAB_OR_NAML( Fab, Nam).FAB_OR_NAML_FNA = file ; /* File name. */
- FAB_OR_NAML( Fab, Nam).FAB_OR_NAML_FNS = strlen(file);
- Nam.NAM_ESA = EName; /* expanded filename */
- Nam.NAM_ESS = sizeof(EName);
- Nam.NAM_RSA = RName; /* resultant filename */
- Nam.NAM_RSS = sizeof(RName);
- /* Do $PARSE and $SEARCH here. */
- status = sys$parse(&Fab);
- if (!(status & 1))
- {
- fprintf( stderr,
- " vms_open(): $parse sts = %%x%08x.\n", status);
- return NULL;
- }
- #ifdef NAML$M_OPEN_SPECIAL
- /* 2007-02-28 SMS.
- * If processing symlinks as symlinks ("-y"), then $SEARCH for the
- * link, not the target file.
- */
- if (linkput)
- {
- Nam.naml$v_open_special = 1;
- }
- #endif /* def NAML$M_OPEN_SPECIAL */
- /* Search for the first file. If none, signal error. */
- status = sys$search(&Fab);
- if (!(status & 1))
- {
- fprintf( stderr,
- " vms_open(): $search sts = %%x%08x.\n", status);
- return NULL;
- }
- /* Initialize Device name length. Note that this points into the
- NAM[L] to get the device name filled in by the $PARSE, $SEARCH
- services.
- */
- DevDesc.dsc$w_length = Nam.NAM_DVI[0];
- status = sys$assign(&DevDesc,&ctx->chan,0,0);
- if (!(status & 1))
- {
- fprintf( stderr,
- " vms_open(): $assign sts = %%x%08x.\n", status);
- return NULL;
- }
- /* Move the FID (and not the DID) into the FIB.
- 2005=02-08 SMS.
- Note that only the FID is needed, not the DID, and not the file
- name. Setting these other items causes failures on ODS5.
- */
- Fib.FIB$L_ACCTL = FIB$M_NOWRITE;
- for (i = 0; i < 3; i++)
- {
- Fib.FIB$W_FID[ i] = Nam.NAM_FID[ i];
- Fib.FIB$W_DID[ i] = 0;
- }
- /* Use the IO$_ACCESS function to return info about the file. */
- status = sys$qiow( 0, ctx->chan,
- (IO$_ACCESS| IO$M_ACCESS), &ctx->iosb, 0, 0,
- &FibDesc, 0, 0, 0, Atr, 0);
- if (ERR(status) || ERR(status = ctx->iosb.status))
- {
- vms_close(ctx);
- fprintf( stderr,
- " vms_open(): $qiow (access) sts = %%x%08x, iosb sts = %%x%08x.\n",
- status, ctx->iosb.status);
- return NULL;
- }
- fat = (struct fatdef *)&(ctx -> PKi.ra);
- #define SWAPW(x) ( (((x)>>16)&0xFFFF) + ((x)<<16) )
- efblk = SWAPW(fat->fat$l_efblk);
- hiblk = SWAPW(fat->fat$l_hiblk);
- if (efblk == 0)
- {
- /* Only known size is all allocated blocks.
- (This occurs with a zero-length file, for example.)
- */
- ctx -> size =
- ctx -> rest = ((uzoff_t) hiblk)* BLOCK_BYTES;
- }
- else
- {
- /* Store normal (used) size in ->size.
- If only one -V, store normal (used) size in ->rest.
- If multiple -V, store allocated-blocks size in ->rest.
- */
- ctx -> size =
- (((uzoff_t) efblk)- 1)* BLOCK_BYTES+ fat -> fat$w_ffbyte;
- if (vms_native < 2)
- ctx -> rest = ctx -> size;
- else
- ctx -> rest = ((uzoff_t) hiblk)* BLOCK_BYTES;
- }
- ctx -> status = SS$_NORMAL;
- ctx -> vbn = 1;
- return ctx;
- }
- #define KByte (2* BLOCK_BYTES)
- #define MAX_READ_BYTES (32* KByte)
- /*----------------*
- | vms_read() |
- *----------------*
- | Reads file in (multi-)block-sized chunks into the buffer.
- | Stops on EOF. Returns number of bytes actually read.
- | Note: This function makes no sense (and will error) if the buffer
- | size ("size") is not a multiple of the disk block size (512).
- */
- size_t vms_read( ctx, buf, size)
- ioctx_t *ctx;
- char *buf;
- size_t size;
- {
- int act_cnt;
- uzoff_t rest_rndup;
- int status;
- size_t bytes_read = 0;
- /* If previous read hit EOF, fail early. */
- if (ctx -> status == SS$_ENDOFFILE)
- return 0; /* EOF. */
- /* If no more expected to be read, fail early. */
- if (ctx -> rest == 0)
- return 0; /* Effective EOF. */
- /* If request is smaller than a whole block, fail.
- This really should never happen. (assert()?)
- */
- if (size < BLOCK_BYTES)
- return 0;
- /* Note that on old VMS VAX versions (like V5.5-2), QIO[W] may fail
- with status %x0000034c (= %SYSTEM-F-IVBUFLEN, invalid buffer
- length) when size is not a multiple of 512. Thus the requested
- size is boosted as needed, but the IOSB byte count returned is
- reduced when it exceeds the actual bytes remaining (->rest).
- */
- /* Adjust request size as appropriate. */
- if (size > MAX_READ_BYTES)
- {
- /* Restrict request to MAX_READ_BYTES. */
- size = MAX_READ_BYTES;
- }
- else
- {
- /* Round odd-ball request up to the next whole block.
- This really should never happen. (assert()?)
- */
- size = (size+ BLOCK_BYTES- 1)& ~(BLOCK_BYTES- 1);
- }
- rest_rndup = (ctx -> rest+ BLOCK_BYTES- 1)& ~(BLOCK_BYTES- 1);
- /* Read (QIOW) until error or "size" bytes have been read. */
- do
- {
- /* Reduce "size" when next (last) read would overrun the EOF,
- but never below one block (so we'll always get a nice EOF).
- */
- if (size > rest_rndup)
- size = rest_rndup;
- status = sys$qiow( 0, ctx->chan, IO$_READVBLK,
- &ctx->iosb, 0, 0,
- buf, size, ctx->vbn, 0, 0, 0);
- /* If initial status was good, use final status. */
- if ( !ERR(status) )
- status = ctx->iosb.status;
- if ( !ERR(status) || status == SS$_ENDOFFILE )
- {
- act_cnt = ctx->iosb.count;
- /* Ignore whole-block boost when remainder is smaller. */
- if (act_cnt > ctx->rest)
- {
- act_cnt = ctx->rest;
- status = SS$_ENDOFFILE;
- }
- /* Adjust counters/pointers according to delivered bytes. */
- size -= act_cnt;
- buf += act_cnt;
- bytes_read += act_cnt;
- ctx->vbn += ctx->iosb.count/ BLOCK_BYTES;
- }
- } while ( !ERR(status) && (size > 0) );
- if (!ERR(status))
- {
- /* Record any successful status as SS$_NORMAL. */
- ctx -> status = SS$_NORMAL;
- }
- else if (status == SS$_ENDOFFILE)
- {
- /* Record EOF as SS$_ENDOFFILE. (Ignore error status codes?) */
- ctx -> status = SS$_ENDOFFILE;
- }
- /* Decrement bytes-to-read. Return the total bytes read. */
- ctx -> rest -= bytes_read;
- return bytes_read;
- }
- /*-----------------*
- | vms_error() |
- *-----------------*
- | Returns whether last operation on the file caused an error
- */
- int vms_error(ctx)
- ioctx_t *ctx;
- { /* EOF is not actual error */
- return ERR(ctx->status) && (ctx->status != SS$_ENDOFFILE);
- }
- /*------------------*
- | vms_rewind() |
- *------------------*
- | Rewinds file to the beginning for the next vms_read().
- */
- int vms_rewind(ctx)
- ioctx_t *ctx;
- {
- ctx -> vbn = 1;
- ctx -> rest = ctx -> size;
- return 0;
- }
- /*--------------------------*
- | vms_get_attributes() |
- *--------------------------*
- | Malloc a PKWARE extra field and fill with file attributes. Returns
- | error number of the ZE_??? class.
- | If the passed ioctx record "FILE *" pointer is NULL, vms_open() is
- | called to fetch the file attributes.
- | When `vms_native' is not set, a generic "UT" type timestamp extra
- | field is generated instead.
- |
- | 2004-11-11 SMS.
- | Changed to use separate storage for ->extra and ->cextra. Zip64
- | processing may move (reallocate) one and not the other.
- */
- int vms_get_attributes(ctx, z, z_utim)
- ioctx_t *ctx; /* Internal file control structure. */
- struct zlist far *z; /* Zip entry to compress. */
- iztimes *z_utim;
- {
- byte *p;
- byte *xtra;
- byte *cxtra;
- struct PK_header *h;
- extent l;
- int notopened;
- if ( !vms_native )
- {
- #ifdef USE_EF_UT_TIME
- /*
- * A `portable' zipfile entry is created. Create an "UT" extra block
- * containing UNIX style modification time stamp in UTC, which helps
- * maintaining the `real' "last modified" time when the archive is
- * transfered across time zone boundaries.
- */
- # ifdef IZ_CHECK_TZ
- if (!zp_tz_is_valid)
- return ZE_OK; /* skip silently if no valid TZ info */
- # endif
- if ((xtra = (uch *) malloc( EB_HEADSIZE+ EB_UT_LEN( 1))) == NULL)
- return ZE_MEM;
- if ((cxtra = (uch *) malloc( EB_HEADSIZE+ EB_UT_LEN( 1))) == NULL)
- return ZE_MEM;
- /* Fill xtra[] with data. */
- xtra[ 0] = 'U';
- xtra[ 1] = 'T';
- xtra[ 2] = EB_UT_LEN(1); /* length of data part of e.f. */
- xtra[ 3] = 0;
- xtra[ 4] = EB_UT_FL_MTIME;
- xtra[ 5] = (byte) (z_utim->mtime);
- xtra[ 6] = (byte) (z_utim->mtime >> 8);
- xtra[ 7] = (byte) (z_utim->mtime >> 16);
- xtra[ 8] = (byte) (z_utim->mtime >> 24);
- /* Copy xtra[] data into cxtra[]. */
- memcpy( cxtra, xtra, (EB_HEADSIZE+ EB_UT_LEN( 1)));
- /* Set sizes and pointers. */
- z->cext = z->ext = (EB_HEADSIZE+ EB_UT_LEN( 1));
- z->extra = (char*) xtra;
- z->cextra = (char*) cxtra;
- #endif /* USE_EF_UT_TIME */
- return ZE_OK;
- }
- notopened = (ctx == NULL);
- if ( notopened && ((ctx = vms_open(z->name)) == NULL) )
- return ZE_OPEN;
- l = PK_HEADER_SIZE + sizeof(ctx->PKi);
- if (ctx->acllen > 0)
- l += PK_FLDHDR_SIZE + ctx->acllen;
- if ((xtra = (uch *) malloc( l)) == NULL)
- return ZE_MEM;
- if ((cxtra = (uch *) malloc( l)) == NULL)
- return ZE_MEM;
- /* Fill xtra[] with data. */
- h = (struct PK_header *) xtra;
- h->tag = PK_SIGNATURE;
- h->size = l - EB_HEADSIZE;
- p = (h->data);
- /* Copy default set of attributes */
- memcpy(h->data, (char*)&(ctx->PKi), sizeof(ctx->PKi));
- p += sizeof(ctx->PKi);
- if ( ctx->acllen > 0 )
- {
- struct PK_field *f;
- if (dosify)
- zipwarn("file has ACL, may be incompatible with PKUNZIP","");
- f = (struct PK_field *)p;
- f->tag = ATR$C_ADDACLENT;
- f->size = ctx->acllen;
- memcpy((char *)&(f->value[0]), ctx->aclbuf, ctx->acllen);
- p += PK_FLDHDR_SIZE + ctx->acllen;
- }
- h->crc32 = CRCVAL_INITIAL; /* Init CRC register */
- h->crc32 = crc32(h->crc32, (uch *)(h->data), l - PK_HEADER_SIZE);
- /* Copy xtra[] data into cxtra[]. */
- memcpy( cxtra, xtra, l);
- /* Set sizes and pointers. */
- z->ext = z->cext = l;
- z->extra = (char *) xtra;
- z->cextra = (char *) cxtra;
- if (notopened) /* close "ctx", if we have opened it here */
- vms_close(ctx);
- return ZE_OK;
- }
- int vms_close(ctx)
- ioctx_t *ctx;
- {
- sys$dassgn(ctx->chan);
- free(ctx);
- return 0;
- }
- #endif /* !_UTIL */
- #endif /* def VMS_PK_EXTRA */
- #endif /* VMS */
|