926 lines
23 KiB
C
926 lines
23 KiB
C
/*
|
|
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_im.c (zip) by Igor Mandrichenko Version 2.2-2
|
|
*
|
|
* Revision history:
|
|
* ...
|
|
* 2.1-1 16-feb-1993 I.Mandrichenko
|
|
* Get file size from XABFHC and check bytes rest in file before
|
|
* reading.
|
|
* 2.1-2 2-mar-1993 I.Mandrichenko
|
|
* Make code more standard
|
|
* 2.2 21-jun-1993 I.Mandrichenko
|
|
* Free all allocated space, use more static storage.
|
|
* Use memcompress() from bits.c (deflation) for block compression.
|
|
* To revert to old compression method #define OLD_COMPRESS
|
|
* 2.2-2 28-sep-1995 C.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.
|
|
* 3.0 23-Oct-2004 Steven Schweda
|
|
* Changed to maintain compatibility with VMS_PK.C. Note that
|
|
* reading with sys$read() prevents getting any data past EOF,
|
|
* regardless of appearances. Moved the VMS_PK_EXTRA test into
|
|
* here from VMS.C to allow more general automatic dependency
|
|
* generation.
|
|
* 17-Feb-2005 Steven Schweda
|
|
* Added support for ODS5 extended names.
|
|
*/
|
|
|
|
#ifdef VMS /* For VMS only ! */
|
|
|
|
#ifndef VMS_PK_EXTRA
|
|
|
|
#define OLD_COMPRESS /*To use old compression method define it.*/
|
|
|
|
#ifdef VMS_ZIP
|
|
#undef VMS_ZIP /* do NOT include PK style Zip definitions */
|
|
#endif
|
|
|
|
#include "vms.h"
|
|
|
|
#ifndef __LIB$ROUTINES_LOADED
|
|
#include <lib$routines.h>
|
|
#endif
|
|
|
|
#ifndef UTIL
|
|
|
|
#define RET_ERROR 1
|
|
#define RET_SUCCESS 0
|
|
#define RET_EOF 0
|
|
|
|
#define Kbyte 1024
|
|
|
|
typedef struct XAB *xabptr;
|
|
|
|
/*
|
|
* Block sizes
|
|
*/
|
|
|
|
#define EXTL0 ((FABL + EXTHL)+ \
|
|
(XFHCL + EXTHL)+ \
|
|
(XPROL + EXTHL)+ \
|
|
(XDATL + EXTHL)+ \
|
|
(XRDTL + EXTHL))
|
|
|
|
#ifdef OLD_COMPRESS
|
|
#define PAD sizeof(uch)
|
|
#else
|
|
#define PAD 10*sizeof(ush) /* Two extra bytes for compr. header */
|
|
#endif
|
|
|
|
#define PAD0 (5*PAD) /* Reserve space for the case when
|
|
* compression fails */
|
|
static int _compress(uch *from, uch *to, int size);
|
|
#ifdef DEBUG
|
|
static void dump_rms_block(uch *p);
|
|
#endif /* DEBUG */
|
|
|
|
/********************************
|
|
* Function set_extra_field *
|
|
********************************/
|
|
/*
|
|
| 2004-11-11 SMS.
|
|
| Changed to use separate storage for ->extra and ->cextra. Zip64
|
|
| processing may move (reallocate) one and not the other.
|
|
*/
|
|
|
|
static uch *_compress_block(register struct IZ_block *to,
|
|
uch *from, int size, char *sig);
|
|
static int get_vms_version(char *verbuf, int len);
|
|
|
|
int set_extra_field(z, z_utim)
|
|
struct zlist far *z;
|
|
iztimes *z_utim;
|
|
/*
|
|
* Get file VMS file attributes and store them into extent fields.
|
|
* Store VMS version also.
|
|
* On error leave z intact.
|
|
*/
|
|
{
|
|
int status;
|
|
uch *xtra;
|
|
uch *cxtra;
|
|
uch *scan;
|
|
extent extra_l;
|
|
static struct FAB fab;
|
|
static struct NAM_STRUCT nam;
|
|
static struct XABSUM xabsum;
|
|
static struct XABFHC xabfhc;
|
|
static struct XABDAT xabdat;
|
|
static struct XABPRO xabpro;
|
|
static struct XABRDT xabrdt;
|
|
xabptr x = (xabptr)NULL, xab_chain = (xabptr)NULL, last_xab = (xabptr)NULL;
|
|
int nk, na;
|
|
int i;
|
|
int rc=RET_ERROR;
|
|
char verbuf[80];
|
|
int verlen = 0;
|
|
|
|
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] = (uch) (z_utim->mtime);
|
|
xtra[ 6] = (uch) (z_utim->mtime >> 8);
|
|
xtra[ 7] = (uch) (z_utim->mtime >> 16);
|
|
xtra[ 8] = (uch) (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 RET_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* Initialize RMS control blocks and link them
|
|
*/
|
|
|
|
fab = cc$rms_fab;
|
|
nam = CC_RMS_NAM;
|
|
xabsum = cc$rms_xabsum;
|
|
xabdat = cc$rms_xabdat;
|
|
xabfhc = cc$rms_xabfhc;
|
|
xabpro = cc$rms_xabpro;
|
|
xabrdt = cc$rms_xabrdt;
|
|
|
|
fab.FAB_NAM = &nam;
|
|
fab.fab$l_xab = (char*)&xabsum;
|
|
/*
|
|
* Open the file and read summary information.
|
|
*/
|
|
|
|
#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 = z->name;
|
|
FAB_OR_NAML( fab, nam).FAB_OR_NAML_FNS = strlen( z->name);
|
|
|
|
#ifdef NAML$M_OPEN_SPECIAL
|
|
/* 2007-02-28 SMS.
|
|
* If processing symlinks as symlinks ("-y"), then $OPEN the
|
|
* link, not the target file.
|
|
*
|
|
* (nam.naml$v_open_special gets us the symlink itself instead of
|
|
* its target. fab.fab$v_bio is necessary to allow sys$open() to
|
|
* work. Without it, you get status %x0001860c, "%RMS-F-ORG,
|
|
* invalid file organization value".)
|
|
*/
|
|
if (linkput)
|
|
{
|
|
nam.naml$v_open_special = 1;
|
|
fab.fab$v_bio = 1;
|
|
}
|
|
#endif /* def NAML$M_OPEN_SPECIAL */
|
|
|
|
status = sys$open(&fab);
|
|
if (ERR(status))
|
|
{
|
|
#ifdef DEBUG
|
|
printf("set_extra_field: sys$open for file %s:\n error status = %d\n",
|
|
z->name, status);
|
|
#endif
|
|
goto err_exit;
|
|
}
|
|
|
|
nk = xabsum.xab$b_nok;
|
|
na = xabsum.xab$b_noa;
|
|
#ifdef DEBUG
|
|
printf("%d keys, %d alls\n", nk, na);
|
|
#endif
|
|
|
|
/*
|
|
* Allocate XABKEY and XABALL blocks and link them
|
|
*/
|
|
|
|
xabfhc.xab$l_nxt = (char*)&xabdat;
|
|
xabdat.xab$l_nxt = (char*)&xabpro;
|
|
xabpro.xab$l_nxt = (char*)&xabrdt;
|
|
xabrdt.xab$l_nxt = NULL;
|
|
|
|
xab_chain = (xabptr)(&xabfhc);
|
|
last_xab = (xabptr)(&xabrdt);
|
|
|
|
#define INIT(ptr,size,type,init) \
|
|
if ( (ptr = (type *)malloc(size)) == NULL ) \
|
|
{ \
|
|
printf( "set_extra_field: Insufficient memory.\n" ); \
|
|
goto err_exit; \
|
|
} \
|
|
*(ptr) = (init);
|
|
/*
|
|
* Allocate and initialize all needed XABKEYs and XABALLs
|
|
*/
|
|
for (i = 0; i < nk; i++)
|
|
{
|
|
struct XABKEY *k;
|
|
INIT(k, XKEYL, struct XABKEY, cc$rms_xabkey);
|
|
k->xab$b_ref = i;
|
|
if (last_xab != NULL)
|
|
last_xab->xab$l_nxt = (char*)k;
|
|
last_xab = (xabptr)k;
|
|
}
|
|
for (i = 0; i < na; i++)
|
|
{
|
|
struct XABALL *a;
|
|
INIT(a, XALLL, struct XABALL, cc$rms_xaball);
|
|
a->xab$b_aid = i;
|
|
if (last_xab != NULL)
|
|
last_xab->xab$l_nxt = (char*)a;
|
|
last_xab = (xabptr)a;
|
|
}
|
|
|
|
fab.fab$l_xab = (char*)xab_chain;
|
|
#ifdef DEBUG
|
|
printf("Dump of XAB chain before $DISPLAY:\n");
|
|
for (x = xab_chain; x != NULL; x = x->xab$l_nxt)
|
|
dump_rms_block((uch *)x);
|
|
#endif
|
|
/*
|
|
* Get information on the file structure etc.
|
|
*/
|
|
status = sys$display(&fab, 0, 0);
|
|
if (ERR(status))
|
|
{
|
|
#ifdef DEBUG
|
|
printf("set_extra_field: sys$display for file %s:\n error status = %d\n",
|
|
z->name, status);
|
|
#endif
|
|
goto err_exit;
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
printf("\nDump of XAB chain after $DISPLAY:\n");
|
|
for (x = xab_chain; x != NULL; x = x->xab$l_nxt)
|
|
dump_rms_block((uch *)x);
|
|
#endif
|
|
|
|
fab.fab$l_xab = NULL; /* Keep XABs */
|
|
status = sys$close(&fab);
|
|
if (ERR(status))
|
|
{
|
|
#ifdef DEBUG
|
|
printf("set_extra_field: sys$close for file %s:\n error status = %d\n",
|
|
z->name, status);
|
|
#endif
|
|
goto err_exit;
|
|
}
|
|
|
|
extra_l = EXTL0 + nk * (XKEYL + EXTHL) + na * (XALLL + EXTHL);
|
|
#ifndef OLD_COMPRESS
|
|
extra_l += PAD0 + (nk+na) * PAD;
|
|
#endif
|
|
|
|
if ( (verlen = get_vms_version(verbuf, sizeof(verbuf))) > 0 )
|
|
{
|
|
extra_l += verlen + EXTHL;
|
|
#ifndef OLD_COMPRESS
|
|
extra_l += PAD;
|
|
#endif
|
|
}
|
|
|
|
if ((scan = xtra = (uch *) malloc( extra_l)) == (uch*)NULL)
|
|
{
|
|
#ifdef DEBUG
|
|
printf(
|
|
"set_extra_field: Insufficient memory to allocate extra L buffer\n");
|
|
#endif
|
|
goto err_exit;
|
|
}
|
|
|
|
if ((cxtra = (uch *) malloc( extra_l)) == (uch*)NULL)
|
|
{
|
|
#ifdef DEBUG
|
|
printf(
|
|
"set_extra_field: Insufficient memory to allocate extra C buffer\n");
|
|
#endif
|
|
goto err_exit;
|
|
}
|
|
|
|
if (verlen > 0)
|
|
scan = _compress_block((struct IZ_block *)scan, (uch *)verbuf,
|
|
verlen, VERSIG);
|
|
|
|
/*
|
|
* Zero all unusable fields to improve compression
|
|
*/
|
|
fab.fab$b_fns = fab.fab$b_shr = fab.fab$b_dns = fab.fab$b_fac = 0;
|
|
fab.fab$w_ifi = 0;
|
|
fab.fab$l_stv = fab.fab$l_sts = fab.fab$l_ctx = 0;
|
|
fab.fab$l_dna = NULL;
|
|
fab.fab$l_fna = NULL;
|
|
fab.fab$l_nam = NULL;
|
|
#ifdef NAML$C_MAXRSS
|
|
fab.fab$l_naml = NULL;
|
|
#endif /* def NAML$C_MAXRSS */
|
|
fab.fab$l_xab = NULL;
|
|
|
|
#ifdef DEBUG
|
|
dump_rms_block( (uch *)&fab );
|
|
#endif
|
|
scan = _compress_block((struct IZ_block *)scan, (uch *)&fab, FABL, FABSIG);
|
|
for (x = xab_chain; x != NULL;)
|
|
{
|
|
int bln;
|
|
char *sig;
|
|
xabptr next;
|
|
|
|
next = (xabptr)(x->xab$l_nxt);
|
|
x->xab$l_nxt = 0;
|
|
|
|
switch (x->xab$b_cod)
|
|
{
|
|
case XAB$C_ALL:
|
|
bln = XALLL;
|
|
sig = XALLSIG;
|
|
break;
|
|
case XAB$C_KEY:
|
|
bln = XKEYL;
|
|
sig = XKEYSIG;
|
|
break;
|
|
case XAB$C_PRO:
|
|
bln = XPROL;
|
|
sig = XPROSIG;
|
|
break;
|
|
case XAB$C_FHC:
|
|
bln = XFHCL;
|
|
sig = XFHCSIG;
|
|
break;
|
|
case XAB$C_DAT:
|
|
bln = XDATL;
|
|
sig = XDATSIG;
|
|
break;
|
|
case XAB$C_RDT:
|
|
bln = XRDTL;
|
|
sig = XRDTSIG;
|
|
break;
|
|
default:
|
|
bln = 0;
|
|
sig = 0L;
|
|
break;
|
|
}
|
|
if (bln > 0)
|
|
scan = _compress_block((struct IZ_block *)scan, (uch *)x,
|
|
bln, sig);
|
|
x = next;
|
|
}
|
|
|
|
/* Copy xtra[] data into cxtra[]. */
|
|
memcpy( cxtra, xtra, (scan- xtra));
|
|
|
|
/* Set sizes and pointers. */
|
|
z->cext = z->ext = scan- xtra;
|
|
z->extra = (char*) xtra;
|
|
z->cextra = (char*) cxtra;
|
|
|
|
rc = RET_SUCCESS;
|
|
|
|
err_exit:
|
|
/*
|
|
* Give up all allocated blocks
|
|
*/
|
|
for (x = (struct XAB *)xab_chain; x != NULL; )
|
|
{
|
|
struct XAB *next;
|
|
next = (xabptr)(x->xab$l_nxt);
|
|
if (x->xab$b_cod == XAB$C_ALL || x->xab$b_cod == XAB$C_KEY)
|
|
free(x);
|
|
x = next;
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
static int get_vms_version(verbuf, len)
|
|
char *verbuf;
|
|
int len;
|
|
{
|
|
int i = SYI$_VERSION;
|
|
int verlen = 0;
|
|
struct dsc$descriptor version;
|
|
char *m;
|
|
|
|
version.dsc$a_pointer = verbuf;
|
|
version.dsc$w_length = len - 1;
|
|
version.dsc$b_dtype = DSC$K_DTYPE_B;
|
|
version.dsc$b_class = DSC$K_CLASS_S;
|
|
|
|
if (ERR(lib$getsyi(&i, 0, &version, &verlen, 0, 0)) || verlen == 0)
|
|
return 0;
|
|
|
|
/* Cut out trailing spaces "V5.4-3 " -> "V5.4-3" */
|
|
for (m = verbuf + verlen, i = verlen - 1; i > 0 && verbuf[i] == ' '; --i)
|
|
--m;
|
|
*m = 0;
|
|
|
|
/* Cut out release number "V5.4-3" -> "V5.4" */
|
|
if ((m = strrchr(verbuf, '-')) != NULL)
|
|
*m = 0;
|
|
return strlen(verbuf) + 1; /* Transmit ending 0 too */
|
|
}
|
|
|
|
#define CTXSIG ((ulg)('CtXx'))
|
|
|
|
typedef struct user_context
|
|
{
|
|
ulg sig;
|
|
struct FAB *fab;
|
|
struct NAM_STRUCT *nam;
|
|
struct RAB *rab;
|
|
uzoff_t size;
|
|
uzoff_t rest;
|
|
int status;
|
|
} Ctx, *Ctxptr;
|
|
|
|
Ctx init_ctx =
|
|
{
|
|
CTXSIG,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
0L,
|
|
0L,
|
|
0
|
|
};
|
|
|
|
#define CTXL sizeof(Ctx)
|
|
#define CHECK_RAB(_r) ( (_r) != NULL && \
|
|
(_r) -> rab$b_bid == RAB$C_BID && \
|
|
(_r) -> rab$b_bln == RAB$C_BLN && \
|
|
(_r) -> rab$l_ctx != 0 && \
|
|
(_r) -> rab$l_fab != NULL )
|
|
|
|
|
|
#define BLOCK_BYTES 512
|
|
|
|
/**************************
|
|
* Function vms_open *
|
|
**************************/
|
|
struct RAB *vms_open(name)
|
|
char *name;
|
|
{
|
|
struct FAB *fab;
|
|
struct NAM_STRUCT *nam;
|
|
struct RAB *rab;
|
|
struct XABFHC *fhc;
|
|
Ctxptr ctx;
|
|
|
|
if ((fab = (struct FAB *) malloc(FABL)) == NULL)
|
|
return NULL;
|
|
|
|
if ((nam =
|
|
(struct NAM_STRUCT *) malloc( sizeof( struct NAM_STRUCT))) == NULL)
|
|
{
|
|
free(fab);
|
|
return NULL;
|
|
}
|
|
|
|
if ((rab = (struct RAB *) malloc(RABL)) == NULL)
|
|
{
|
|
free(fab);
|
|
free(nam);
|
|
return NULL;
|
|
}
|
|
|
|
if ((fhc = (struct XABFHC *) malloc(XFHCL)) == (struct XABFHC *)NULL)
|
|
{
|
|
free(fab);
|
|
free(nam);
|
|
free(rab);
|
|
return (struct RAB *)NULL;
|
|
}
|
|
if ((ctx = (Ctxptr) malloc(CTXL)) == (Ctxptr)NULL)
|
|
{
|
|
free(fab);
|
|
free(nam);
|
|
free(rab);
|
|
free(fhc);
|
|
return (struct RAB *)NULL;
|
|
}
|
|
*fab = cc$rms_fab;
|
|
*nam = CC_RMS_NAM;
|
|
*rab = cc$rms_rab;
|
|
*fhc = cc$rms_xabfhc;
|
|
|
|
fab->FAB_NAM = nam;
|
|
|
|
#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 = name;
|
|
FAB_OR_NAML( fab, nam)->FAB_OR_NAML_FNS = strlen( name);
|
|
|
|
fab->fab$b_fac = FAB$M_GET | FAB$M_BIO;
|
|
fab->fab$l_xab = (char*)fhc;
|
|
|
|
#ifdef NAML$M_OPEN_SPECIAL
|
|
/* 2007-02-28 SMS.
|
|
* If processing symlinks as symlinks ("-y"), then $OPEN the
|
|
* link, not the target file. (Note that here the required
|
|
* fab->fab$v_bio flag was set above.)
|
|
*/
|
|
if (linkput)
|
|
{
|
|
nam->naml$v_open_special = 1;
|
|
}
|
|
#endif /* def NAML$M_OPEN_SPECIAL */
|
|
|
|
if (ERR(sys$open(fab)))
|
|
{
|
|
sys$close(fab);
|
|
free(fab);
|
|
free(nam);
|
|
free(rab);
|
|
free(fhc);
|
|
free(ctx);
|
|
return (struct RAB *)NULL;
|
|
}
|
|
|
|
rab->rab$l_fab = fab;
|
|
rab->rab$l_rop = RAB$M_BIO;
|
|
|
|
if (ERR(sys$connect(rab)))
|
|
{
|
|
sys$close(fab);
|
|
free(fab);
|
|
free(nam);
|
|
free(rab);
|
|
free(ctx);
|
|
return (struct RAB *)NULL;
|
|
}
|
|
|
|
*ctx = init_ctx;
|
|
ctx->fab = fab;
|
|
ctx->nam = nam;
|
|
ctx->rab = rab;
|
|
|
|
if (fhc->xab$l_ebk == 0)
|
|
{
|
|
/* Only known size is all allocated blocks.
|
|
(This occurs with a zero-length file, for example.)
|
|
*/
|
|
ctx->size =
|
|
ctx->rest = ((uzoff_t) fhc->xab$l_hbk)* BLOCK_BYTES;
|
|
}
|
|
else
|
|
{
|
|
/* Store normal (used) size in ->size.
|
|
If only one -V, store normal (used) size in ->rest.
|
|
If -VV, store allocated-blocks size in ->rest.
|
|
*/
|
|
ctx->size =
|
|
(((uzoff_t) fhc->xab$l_ebk)- 1)* BLOCK_BYTES+ fhc->xab$w_ffb;
|
|
if (vms_native < 2)
|
|
ctx->rest = ctx->size;
|
|
else
|
|
ctx->rest = ((uzoff_t) fhc->xab$l_hbk)* BLOCK_BYTES;
|
|
}
|
|
|
|
free(fhc);
|
|
fab->fab$l_xab = NULL;
|
|
rab->rab$l_ctx = (unsigned) ctx;
|
|
return rab;
|
|
}
|
|
|
|
/**************************
|
|
* Function vms_close *
|
|
**************************/
|
|
int vms_close(rab)
|
|
struct RAB *rab;
|
|
{
|
|
struct FAB *fab;
|
|
struct NAM_STRUCT *nam;
|
|
Ctxptr ctx;
|
|
|
|
if (!CHECK_RAB(rab))
|
|
return RET_ERROR;
|
|
fab = (ctx = (Ctxptr)(rab->rab$l_ctx))->fab;
|
|
nam = (ctx = (Ctxptr)(rab->rab$l_ctx))->nam;
|
|
sys$close(fab);
|
|
|
|
free(fab);
|
|
free(nam);
|
|
free(rab);
|
|
free(ctx);
|
|
|
|
return RET_SUCCESS;
|
|
}
|
|
|
|
/**************************
|
|
* Function vms_rewind *
|
|
**************************/
|
|
int vms_rewind(rab)
|
|
struct RAB *rab;
|
|
{
|
|
Ctxptr ctx;
|
|
|
|
int status;
|
|
if (!CHECK_RAB(rab))
|
|
return RET_ERROR;
|
|
|
|
ctx = (Ctxptr) (rab->rab$l_ctx);
|
|
if (ERR(status = sys$rewind(rab)))
|
|
{
|
|
ctx->status = status;
|
|
return RET_ERROR;
|
|
}
|
|
|
|
ctx->status = 0;
|
|
ctx->rest = ctx->size;
|
|
|
|
return RET_SUCCESS;
|
|
}
|
|
|
|
|
|
#define KByte (2* BLOCK_BYTES)
|
|
#define MAX_READ_BYTES (32* KByte)
|
|
|
|
/**************************
|
|
* Function vms_read *
|
|
**************************/
|
|
size_t vms_read(rab, buf, size)
|
|
struct RAB *rab;
|
|
char *buf;
|
|
size_t size;
|
|
/*
|
|
* size must be greater or equal to 512 !
|
|
*/
|
|
{
|
|
int status;
|
|
Ctxptr ctx;
|
|
|
|
ctx = (Ctxptr)rab->rab$l_ctx;
|
|
|
|
if (!CHECK_RAB(rab))
|
|
return 0;
|
|
|
|
if (ctx -> rest == 0)
|
|
return 0; /* Eof */
|
|
|
|
/* If request is smaller than a whole block, fail.
|
|
This really should never happen. (assert()?)
|
|
*/
|
|
if (size < BLOCK_BYTES)
|
|
return 0;
|
|
|
|
/* 2004-09-27 SMS.
|
|
Code here now resembles low-level QIO code in VMS_PK.C, but I
|
|
doubt that sys$read() will actually get past the official EOF.
|
|
*/
|
|
|
|
/* 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);
|
|
}
|
|
|
|
/* Reduce "size" when next (last) read would overrun the EOF,
|
|
but never below one byte (so we'll always get a nice EOF).
|
|
*/
|
|
if (size > ctx->rest)
|
|
size = ctx->rest;
|
|
if (size == 0)
|
|
size = 1;
|
|
|
|
rab->rab$l_ubf = buf;
|
|
rab->rab$w_usz = size;
|
|
status = sys$read(rab);
|
|
|
|
if (!ERR(status) && rab->rab$w_rsz > 0)
|
|
{
|
|
ctx -> status = 0;
|
|
ctx -> rest -= rab->rab$w_rsz;
|
|
return rab->rab$w_rsz;
|
|
}
|
|
else
|
|
{
|
|
ctx->status = (status==RMS$_EOF ? 0:status);
|
|
if (status == RMS$_EOF)
|
|
ctx -> rest = 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/**************************
|
|
* Function vms_error *
|
|
**************************/
|
|
int vms_error(rab)
|
|
struct RAB *rab;
|
|
{
|
|
if (!CHECK_RAB(rab))
|
|
return RET_ERROR;
|
|
return ((Ctxptr) (rab->rab$l_ctx))->status;
|
|
}
|
|
|
|
|
|
#ifdef DEBUG
|
|
static void dump_rms_block(p)
|
|
uch *p;
|
|
{
|
|
uch bid, len;
|
|
int err;
|
|
char *type;
|
|
char buf[132];
|
|
int i;
|
|
|
|
err = 0;
|
|
bid = p[0];
|
|
len = p[1];
|
|
switch (bid)
|
|
{
|
|
case FAB$C_BID:
|
|
type = "FAB";
|
|
break;
|
|
case XAB$C_ALL:
|
|
type = "xabALL";
|
|
break;
|
|
case XAB$C_KEY:
|
|
type = "xabKEY";
|
|
break;
|
|
case XAB$C_DAT:
|
|
type = "xabDAT";
|
|
break;
|
|
case XAB$C_RDT:
|
|
type = "xabRDT";
|
|
break;
|
|
case XAB$C_FHC:
|
|
type = "xabFHC";
|
|
break;
|
|
case XAB$C_PRO:
|
|
type = "xabPRO";
|
|
break;
|
|
default:
|
|
type = "Unknown";
|
|
err = 1;
|
|
break;
|
|
}
|
|
printf("Block @%08X of type %s (%d).", p, type, bid);
|
|
if (err)
|
|
{
|
|
printf("\n");
|
|
return;
|
|
}
|
|
printf(" Size = %d\n", len);
|
|
printf(" Offset - Hex - Dec\n");
|
|
for (i = 0; i < len; i += 8)
|
|
{
|
|
int j;
|
|
|
|
printf("%3d - ", i);
|
|
for (j = 0; j < 8; j++)
|
|
if (i + j < len)
|
|
printf("%02X ", p[i + j]);
|
|
else
|
|
printf(" ");
|
|
printf(" - ");
|
|
for (j = 0; j < 8; j++)
|
|
if (i + j < len)
|
|
printf("%03d ", p[i + j]);
|
|
else
|
|
printf(" ");
|
|
printf("\n");
|
|
}
|
|
}
|
|
#endif /* DEBUG */
|
|
|
|
#ifdef OLD_COMPRESS
|
|
# define BC_METHOD EB_IZVMS_BC00
|
|
# define COMP_BLK(to,tos,from,froms) _compress( from,to,froms )
|
|
#else
|
|
# define BC_METHOD EB_IZVMS_BCDEFL
|
|
# define COMP_BLK(to,tos,from,froms) memcompress(to,tos,from,froms)
|
|
#endif
|
|
|
|
static uch *_compress_block(to,from,size,sig)
|
|
register struct IZ_block *to;
|
|
uch *from;
|
|
int size;
|
|
char *sig;
|
|
{
|
|
ulg cl;
|
|
to -> sig = *(ush*)IZ_SIGNATURE;
|
|
to -> bid = *(ulg*)(sig);
|
|
to -> flags = BC_METHOD;
|
|
to -> length = size;
|
|
#ifdef DEBUG
|
|
printf("\nmemcompr(%d,%d,%d,%d)\n",&(to->body[0]),size+PAD,from,size);
|
|
#endif
|
|
cl = COMP_BLK( &(to->body[0]), size+PAD, from, size );
|
|
#ifdef DEBUG
|
|
printf("Compressed to %d\n",cl);
|
|
#endif
|
|
if (cl >= size)
|
|
{
|
|
memcpy(&(to->body[0]), from, size);
|
|
to->flags = EB_IZVMS_BCSTOR;
|
|
cl = size;
|
|
#ifdef DEBUG
|
|
printf("Storing block...\n");
|
|
#endif
|
|
}
|
|
return (uch*)(to) + (to->size = cl + EXTBSL + RESL) + EB_HEADSIZE;
|
|
}
|
|
|
|
#define NBITS 32
|
|
|
|
static int _compress(from,to,size)
|
|
uch *from,*to;
|
|
int size;
|
|
{
|
|
int off=0;
|
|
ulg bitbuf=0;
|
|
int bitcnt=0;
|
|
int i;
|
|
|
|
#define _BIT(val,len) { \
|
|
if (bitcnt + (len) > NBITS) \
|
|
while(bitcnt >= 8) \
|
|
{ \
|
|
to[off++] = (uch)bitbuf; \
|
|
bitbuf >>= 8; \
|
|
bitcnt -= 8; \
|
|
} \
|
|
bitbuf |= ((ulg)(val))<<bitcnt; \
|
|
bitcnt += len; \
|
|
}
|
|
|
|
#define _FLUSH { \
|
|
while(bitcnt>0) \
|
|
{ \
|
|
to[off++] = (uch)bitbuf; \
|
|
bitbuf >>= 8; \
|
|
bitcnt -= 8; \
|
|
} \
|
|
}
|
|
|
|
for (i=0; i<size; i++)
|
|
{
|
|
if (from[i])
|
|
{
|
|
_BIT(1,1);
|
|
_BIT(from[i],8);
|
|
}
|
|
else
|
|
_BIT(0,1);
|
|
}
|
|
_FLUSH;
|
|
return off;
|
|
}
|
|
|
|
#endif /* !UTIL */
|
|
|
|
#endif /* ndef VMS_PK_EXTRA */
|
|
|
|
#endif /* VMS */
|