Archive-Unzip-Burst
view release on metacpan or search on metacpan
unzip-6.0/vms/vms.c view on Meta::CPAN
#define REPL_TASKMASK 255
/* 2008-09-13 CS.
* Note: In extract.c, there are similar strings "InvalidResponse" and
* "AssumeNone" defined. However, as the UI functionality of the VMS
* "version-aware" query is slightly different from the generic variant,
* these strings are kept separate for now to allow independent
* "fine tuning" without affecting the other variant of the
* "overwrite or ..." user query.
*/
ZCONST char Far InvalidResponse[] =
"error: invalid response [%.1s]\n";
ZCONST char Far AssumeNo[] =
"\n(EOF or read error, treating as \"[N]o extract (all)\" ...)\n";
#ifdef SET_DIR_ATTRIB
/* Structure for holding directory attribute data for final processing
* after all files are in place.
*/
typedef struct vmsdirattr {
struct vmsdirattr *next; /* link to next in (linked) list */
char *fn; /* file (directory) name */
/* Non-VMS attributes data */
ulg mod_dos_datetime; /* G.lrec.last_mod_dos_datetime */
unsigned perms; /* same as min_info.file_attr */
unsigned xlen; /* G.lrec.extra_field_length */
char buf[1]; /* data buffer (extra_field, fn) */
} vmsdirattr;
#define VmsAtt(d) ((vmsdirattr *)d) /* typecast shortcut */
#endif /* SET_DIR_ATTRIB */
/*
* Local static storage
*/
static struct FAB fileblk; /* File Access Block */
static struct XABDAT dattim; /* date-time XAB */
static struct XABRDT rdt; /* revision date-time XAB */
static struct RAB rab; /* Record Access Block */
static struct NAM_STRUCT nam; /* name block */
static struct FAB *outfab = NULL;
static struct RAB *outrab = NULL;
static struct XABFHC *xabfhc = NULL; /* file header characteristics */
static struct XABDAT *xabdat = NULL; /* date-time */
static struct XABRDT *xabrdt = NULL; /* revision date-time */
static struct XABPRO *xabpro = NULL; /* protection */
static struct XABKEY *xabkey = NULL; /* key (indexed) */
static struct XABALL *xaball = NULL; /* allocation */
static struct XAB *first_xab = NULL, *last_xab = NULL;
static int replace_code_all = -1; /* All-file response for replace(). */
static uch rfm;
static uch locbuf[BUFSALLOC]; /* Space for 2 buffers of BUFS512 */
static unsigned loccnt = 0;
static uch *locptr;
static char got_eol = 0;
struct bufdsc
{
struct bufdsc *next;
uch *buf;
unsigned bufcnt;
};
static struct bufdsc b1, b2, *curbuf; /* buffer ring for asynchronous I/O */
static int _flush_blocks(__GPRO__ uch *rawbuf, unsigned size, int final_flag);
static int _flush_stream(__GPRO__ uch *rawbuf, unsigned size, int final_flag);
static int _flush_varlen(__GPRO__ uch *rawbuf, unsigned size, int final_flag);
static int _flush_qio(__GPRO__ uch *rawbuf, unsigned size, int final_flag);
static int _close_rms(__GPRO);
static int _close_qio(__GPRO);
#ifdef ASYNCH_QIO
static int WriteQIO(__GPRO__ uch *buf, unsigned len);
#endif
static int WriteBuffer(__GPRO__ uch *buf, unsigned len);
static int WriteRecord(__GPRO__ uch *rec, unsigned len);
static int (*_flush_routine)(__GPRO__ uch *rawbuf, unsigned size,
int final_flag);
static int (*_close_routine)(__GPRO);
#ifdef SYMLINKS
static int _read_link_rms(__GPRO__ int byte_count, char *link_text_buf);
#endif /* SYMLINKS */
static void init_buf_ring(void);
static void set_default_datetime_XABs(__GPRO);
static int create_default_output(__GPRO);
static int create_rms_output(__GPRO);
static int create_qio_output(__GPRO);
static int replace(__GPRO);
static int replace_rms_newversion(__GPRO);
static int replace_rms_overwrite(__GPRO);
static int find_vms_attrs(__GPRO__ int set_date_time);
static void free_up(void);
#ifdef CHECK_VERSIONS
static int get_vms_version(char *verbuf, int len);
#endif /* CHECK_VERSIONS */
static unsigned find_eol(ZCONST uch *p, unsigned n, unsigned *l);
#ifdef SET_DIR_ATTRIB
static char *vms_path_fixdown(ZCONST char *dir_spec, char *dir_file);
#endif
#ifdef TIMESTAMP
static time_t mkgmtime(struct tm *tm);
static void uxtime2vmstime(time_t utimeval, long int binval[2]);
#endif /* TIMESTAMP */
static int vms_msg_fetch(int status);
static void vms_msg(__GPRO__ ZCONST char *string, int status);
/*
2005-02-14 SMS.
Added some ODS5 support:
Use longer name structures in NAML, where available.
Locate special characters mindful of "^" escapes.
*/
/* Hex digit table. */
char hex_digit[16] = {
'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
};
/* Character property table for converting Zip file names to
(simpler) ODS2 or (escaped) ODS5 extended file names.
ODS2 valid characters: 0-9 A-Z a-z $ - _
ODS5 Invalid characters:
C0 control codes (0x00 to 0x1F inclusive)
Asterisk (*)
Question mark (?)
ODS5 Invalid characters only in VMS V7.2 (which no one runs, right?):
Double quotation marks (")
Backslash (\)
Colon (:)
Left angle bracket (<)
Right angle bracket (>)
Slash (/)
Vertical bar (|)
Characters escaped by "^":
SP ! " # % & ' ( ) + , . : ; =
@ [ \ ] ^ ` { | } ~
Either "^_" or "^ " is accepted as a space. Period (.) is a special
case. Note that un-escaped < and > can also confuse a directory
spec.
Characters put out as ^xx:
7F (DEL)
80-9F (C1 control characters)
A0 (nonbreaking space)
FF (Latin small letter y diaeresis)
Other cases:
unzip-6.0/vms/vms.c view on Meta::CPAN
{
/* File exists.
* Consider command-line options, or ask the user what to do.
*/
ierr = replace(__G);
switch (ierr & REPL_TASKMASK)
{
case REPL_NO_EXTRACT: /* No extract. */
free_up();
return ((ierr & REPL_ERRLV_WARN)
? OPENOUT_SKIPWARN : OPENOUT_SKIPOK);
case REPL_NEW_VERSION: /* Create a new version. */
ierr = replace_rms_newversion(__G);
break;
case REPL_OVERWRITE: /* Overwrite the existing file. */
ierr = replace_rms_overwrite(__G);
break;
}
}
if (ERR(ierr))
{
char buf[NAM_MAXRSS + 128]; /* Name length + message length. */
sprintf(buf, "[ Cannot create ($create) output file %s ]\n",
G.filename);
vms_msg(__G__ buf, ierr);
if (fileblk.fab$l_stv != 0)
{
vms_msg(__G__ "", fileblk.fab$l_stv);
}
free_up();
return OPENOUT_FAILED;
}
if (!text_output)
{
rab.rab$l_rop |= (RAB$M_BIO | RAB$M_ASY);
}
rab.rab$b_rac = RAB$C_SEQ;
if ((ierr = sys$connect(&rab)) != RMS$_NORMAL)
{
#ifdef DEBUG
vms_msg(__G__ "create_default_output: sys$connect failed.\n", ierr);
if (fileblk.fab$l_stv != 0)
{
vms_msg(__G__ "", fileblk.fab$l_stv);
}
#endif
Info(slide, 1, ((char *)slide,
"Cannot create ($connect) output file: %s\n",
FnFilter1(G.filename)));
free_up();
return OPENOUT_FAILED;
}
} /* end if (!uO.cflag) */
init_buf_ring();
_flush_routine = text_output ? got_eol=0,_flush_stream : _flush_blocks;
_close_routine = _close_rms;
return OPENOUT_OK;
}
/* The following return codes are supported:
* OPENOUT_OK a file has been opened normally
* OPENOUT_FAILED the file open process failed
* OPENOUT_SKIPOK file open skipped at user request, err level OK
* OPENOUT_SKIPWARN file open skipped at user request, err level WARN
*/
static int create_rms_output(__GPRO)
{
int ierr;
int text_output;
/* extract the file in text (variable-length) format, when
* piping to SYS$OUTPUT, unless "binary" piping was requested
* by the user (through the -b option); the "-a" option is
* ignored when extracting zip entries with VMS attributes saved
*/
text_output = uO.cflag &&
(!uO.bflag || (!(uO.bflag - 1) && G.pInfo->textfile));
rfm = outfab->fab$b_rfm; /* Use record format from VMS extra field */
if (uO.cflag) /* SYS$OUTPUT */
{
if (text_output && !PRINTABLE_FORMAT(rfm))
{
Info(slide, 1, ((char *)slide,
"[ File %s has illegal record format to put to screen ]\n",
FnFilter1(G.filename)));
free_up();
return OPENOUT_FAILED;
}
}
else /* File output */
{
rab = cc$rms_rab; /* Initialize RAB. */
/* The output FAB has already been initialized with the values
* found in the Zip file's "VMS attributes" extra field.
*/
#ifdef NAML$C_MAXRSS
nam = CC_RMS_NAM; /* Initialize NAML. */
outfab->FAB_NAM = &nam; /* Point FAB to NAML. */
outfab->fab$l_dna = (char *) -1; /* Using NAML for default name. */
outfab->fab$l_fna = (char *) -1; /* Using NAML for file name. */
#endif /* NAML$C_MAXRSS */
FAB_OR_NAML(*outfab, nam).FAB_OR_NAML_FNA = G.filename;
FAB_OR_NAML(*outfab, nam).FAB_OR_NAML_FNS = strlen(G.filename);
/* Prepare date-time XABs, unless user requests not to. */
unzip-6.0/vms/vms.c view on Meta::CPAN
vms_msg(__G__ "", outfab->fab$l_stv);
}
free_up();
return OPENOUT_FAILED;
}
if (outfab->fab$b_org & (FAB$C_REL | FAB$C_IDX)) {
/* relative and indexed files require explicit allocation */
ierr = sys$extend(outfab);
if (ERR(ierr))
{
char buf[NAM_MAXRSS + 128]; /* Name length + msg length. */
sprintf(buf, "[ Cannot allocate space for %s ]\n", G.filename);
vms_msg(__G__ buf, ierr);
if (outfab->fab$l_stv != 0)
{
vms_msg(__G__ "", outfab->fab$l_stv);
}
free_up();
return OPENOUT_FAILED;
}
}
outrab = &rab;
rab.rab$l_fab = outfab;
{
rab.rab$l_rop |= (RAB$M_BIO | RAB$M_ASY);
}
rab.rab$b_rac = RAB$C_SEQ;
if ((ierr = sys$connect(outrab)) != RMS$_NORMAL)
{
#ifdef DEBUG
vms_msg(__G__ "create_rms_output: sys$connect failed.\n", ierr);
if (outfab->fab$l_stv != 0)
{
vms_msg(__G__ "", outfab->fab$l_stv);
}
#endif
Info(slide, 1, ((char *)slide,
"Cannot create ($connect) output file: %s\n",
FnFilter1(G.filename)));
free_up();
return OPENOUT_FAILED;
}
} /* end if (!uO.cflag) */
init_buf_ring();
if ( text_output )
switch (rfm)
{
case FAB$C_VAR:
_flush_routine = _flush_varlen;
break;
case FAB$C_STM:
case FAB$C_STMCR:
case FAB$C_STMLF:
_flush_routine = _flush_stream;
got_eol = 0;
break;
default:
_flush_routine = _flush_blocks;
break;
}
else
_flush_routine = _flush_blocks;
_close_routine = _close_rms;
return OPENOUT_OK;
}
static int pka_devchn;
static int pka_io_pending;
static unsigned pka_vbn;
/* IOSB for QIO[W] read and write operations. */
#if defined(__DECC) || defined(__DECCXX)
#pragma __member_alignment __save
#pragma __nomember_alignment
#endif /* __DECC || __DECCXX */
static struct
{
unsigned short status;
unsigned int count; /* Unaligned ! */
unsigned short dummy;
} pka_io_iosb;
#if defined(__DECC) || defined(__DECCXX)
#pragma __member_alignment __restore
#endif /* __DECC || __DECCXX */
/* IOSB for QIO[W] miscellaneous ACP operations. */
static struct
{
unsigned short status;
unsigned short dummy;
unsigned int count;
} pka_acp_iosb;
static struct fibdef pka_fib;
static struct atrdef pka_atr[VMS_MAX_ATRCNT];
static int pka_idx;
static ulg pka_uchar;
static struct fatdef pka_rattr;
/* Directory attribute storage, descriptor (list). */
static struct atrdef pka_recattr[2] =
{ { sizeof(pka_rattr), ATR$C_RECATTR, GVTC &pka_rattr}, /* RECATTR. */
{ 0, 0, 0 } /* List terminator. */
};
static struct dsc$descriptor pka_fibdsc =
{ sizeof(pka_fib), DSC$K_DTYPE_Z, DSC$K_CLASS_S, (void *) &pka_fib };
static struct dsc$descriptor_s pka_devdsc =
{ 0, DSC$K_DTYPE_T, DSC$K_CLASS_S, &nam.NAM_DVI[1] };
static struct dsc$descriptor_s pka_fnam =
{ 0, DSC$K_DTYPE_T, DSC$K_CLASS_S, NULL };
unzip-6.0/vms/vms.c view on Meta::CPAN
#ifdef NAML$C_MAXRSS
static char sys_nam[NAML$C_MAXRSS]; /* Probably need less here. */
#endif /* NAML$C_MAXRSS */
#define PK_PRINTABLE_RECTYP(x) ( (x) == FAT$C_VARIABLE \
|| (x) == FAT$C_STREAMLF \
|| (x) == FAT$C_STREAMCR \
|| (x) == FAT$C_STREAM )
/* The following return codes are supported:
* OPENOUT_OK a file has been opened normally
* OPENOUT_FAILED the file open process failed
* OPENOUT_SKIPOK file open skipped at user request, err level OK
* OPENOUT_SKIPWARN file open skipped at user request, err level WARN
*/
static int create_qio_output(__GPRO)
{
int status;
int i;
int text_output;
/* extract the file in text (variable-length) format, when
* piping to SYS$OUTPUT, unless "binary" piping was requested
* by the user (through the -b option); the "-a" option is
* ignored when extracting zip entries with VMS attributes saved
*/
text_output = uO.cflag &&
(!uO.bflag || (!(uO.bflag - 1) && G.pInfo->textfile));
if ( uO.cflag )
{
int rtype;
if (text_output)
{
rtype = pka_rattr.fat$v_rtype;
if (!PK_PRINTABLE_RECTYP(rtype))
{
Info(slide, 1, ((char *)slide,
"[ File %s has illegal record format to put to screen ]\n",
FnFilter1(G.filename)));
return OPENOUT_FAILED;
}
}
else
/* force "block I/O" for binary piping mode */
rtype = FAT$C_UNDEFINED;
init_buf_ring();
switch (rtype)
{
case FAT$C_VARIABLE:
_flush_routine = _flush_varlen;
break;
case FAT$C_STREAM:
case FAT$C_STREAMCR:
case FAT$C_STREAMLF:
_flush_routine = _flush_stream;
got_eol = 0;
break;
default:
_flush_routine = _flush_blocks;
break;
}
_close_routine = _close_rms;
}
else /* !(uO.cflag) : redirect output */
{
fileblk = cc$rms_fab; /* Initialize FAB. */
nam = CC_RMS_NAM; /* Initialize NAM[L]. */
fileblk.FAB_NAM = &nam; /* Point FAB to NAM[L]. */
#ifdef NAML$C_MAXRSS
fileblk.fab$l_dna = (char *) -1; /* Using NAML for default name. */
fileblk.fab$l_fna = (char *) -1; /* Using NAML for file name. */
/* Special ODS5-QIO-compatible name storage. */
nam.naml$l_filesys_name = sys_nam;
nam.naml$l_filesys_name_alloc = sizeof(sys_nam);
#endif /* NAML$C_MAXRSS */
/* VMS-format file name, derived from archive. */
FAB_OR_NAML(fileblk, nam).FAB_OR_NAML_FNA = G.filename;
FAB_OR_NAML(fileblk, nam).FAB_OR_NAML_FNS = strlen(G.filename);
/* Expanded and resultant name storage. */
nam.NAM_ESA = exp_nam;
nam.NAM_ESS = sizeof(exp_nam);
nam.NAM_RSA = res_nam;
nam.NAM_RSS = sizeof(res_nam);
if ( ERR(status = sys$parse(&fileblk)) )
{
vms_msg(__G__ "create_qio_output: sys$parse failed.\n", status);
return OPENOUT_FAILED;
}
pka_devdsc.dsc$w_length = (unsigned short)nam.NAM_DVI[0];
if ( ERR(status = sys$assign(&pka_devdsc, &pka_devchn, 0, 0)) )
{
vms_msg(__G__ "create_qio_output: sys$assign failed.\n", status);
return OPENOUT_FAILED;
}
#ifdef NAML$C_MAXRSS
/* Enable fancy name characters. Note that "fancy" here does
not include Unicode, for which there's no support elsewhere.
*/
pka_fib.fib$v_names_8bit = 1;
pka_fib.fib$b_name_format_in = FIB$C_ISL1;
/* ODS5 Extended names used as input to QIO have peculiar
encoding (perhaps to minimize storage?), so the special
filesys_name result (typically containing fewer carets) must
be used here.
unzip-6.0/vms/vms.c view on Meta::CPAN
memcpy(locbuf, inptr, size);
loccnt = size;
size = 0;
}
}
/*
* Final flush rest of local buffer
*/
if ( final_flag && loccnt > 0 )
{
char buf[80];
Info(buf, 1, (buf,
"[ Warning, incomplete record of length %u ]\n",
(unsigned)*(ush*)locbuf));
if ( WriteRecord(__G__ locbuf+2, loccnt-2) )
return PK_DISK;
}
return PK_COOL;
}
/*
* Routine _flush_stream breaks decompressed stream into records
* depending on format of the stream (fab->rfm, G.pInfo->textmode, etc.)
* and puts out these records. It also handles CR LF sequences.
* Should be used when extracting *text* files.
*/
#define VT 0x0B
#define FF 0x0C
/* The file is from MSDOS/OS2/NT -> handle CRLF as record end, throw out ^Z */
/* GRR NOTES: cannot depend on hostnum! May have "flip'd" file or re-zipped
* a Unix file, etc. */
#ifdef USE_ORIG_DOS
# define ORG_DOS \
(G.pInfo->hostnum==FS_FAT_ \
|| G.pInfo->hostnum==FS_HPFS_ \
|| G.pInfo->hostnum==FS_NTFS_)
#else
# define ORG_DOS 1
#endif
/* Record delimiters */
#ifdef undef
#define RECORD_END(c, f) \
( ( ORG_DOS || G.pInfo->textmode ) && c==CTRLZ \
|| ( f == FAB$C_STMLF && c==LF ) \
|| ( f == FAB$C_STMCR || ORG_DOS || G.pInfo->textmode ) && c==CR \
|| ( f == FAB$C_STM && (c==CR || c==LF || c==FF || c==VT) ) \
)
#else
# define RECORD_END(c, f) ((c) == LF || (c) == (CR))
#endif
static unsigned find_eol(p, n, l)
/*
* Find first CR, LF, CR/LF or LF/CR in string 'p' of length 'n'.
* Return offset of the sequence found or 'n' if not found.
* If found, return in '*l' length of the sequence (1 or 2) or
* zero if sequence end not seen, i.e. CR or LF is last char
* in the buffer.
*/
ZCONST uch *p;
unsigned n;
unsigned *l;
{
unsigned off = n;
ZCONST uch *q;
*l = 0;
for (q=p ; n > 0 ; --n, ++q)
if ( RECORD_END(*q, rfm) )
{
off = q-p;
break;
}
if ( n > 1 )
{
*l = 1;
if ( ( q[0] == CR && q[1] == LF ) || ( q[0] == LF && q[1] == CR ) )
*l = 2;
}
return off;
}
/* Record delimiters that must be put out */
#define PRINT_SPEC(c) ( (c)==FF || (c)==VT )
static int _flush_stream(__G__ rawbuf, size, final_flag)
__GDEF
uch *rawbuf;
unsigned size;
int final_flag; /* 1 if this is the final flushout */
{
int rest;
unsigned end = 0, start = 0;
if (size == 0 && loccnt == 0)
return PK_COOL; /* Nothing to do ... */
if ( final_flag )
{
unsigned recsize;
/*
* This is flush only call. size must be zero now.
* Just eject everything we have in locbuf.
*/
recsize = loccnt - (got_eol ? 1 : 0);
/*
* If the last char of file was ^Z ( end-of-file in MSDOS ),
* we will see it now.
*/
if ( recsize==1 && locbuf[0] == CTRLZ )
return PK_COOL;
return WriteRecord(__G__ locbuf, recsize);
}
if ( loccnt > 0 )
{
/* Find end of record partially saved in locbuf */
unsigned recsize;
int complete=0;
if ( got_eol )
{
recsize = loccnt - 1;
complete = 1;
if ( (got_eol == CR && rawbuf[0] == LF) ||
(got_eol == LF && rawbuf[0] == CR) )
end = 1;
got_eol = 0;
}
else
{
unsigned eol_len;
unsigned eol_off;
eol_off = find_eol(rawbuf, size, &eol_len);
if ( loccnt+eol_off > BUFSMAXREC )
{
/*
* No room in locbuf. Dump it and clear
*/
char buf[80]; /* CANNOT use slide for Info() */
recsize = loccnt;
start = 0;
Info(buf, 1, (buf,
"[ Warning: Record too long (%u) ]\n", loccnt+eol_off));
complete = 1;
end = 0;
}
else
{
if ( eol_off >= size )
{
end = size;
complete = 0;
}
else if ( eol_len == 0 )
{
got_eol = rawbuf[eol_off];
end = size;
complete = 0;
}
else
{
memcpy(locptr, rawbuf, eol_off);
recsize = loccnt + eol_off;
locptr += eol_off;
loccnt += eol_off;
end = eol_off + eol_len;
complete = 1;
}
}
}
if ( complete )
{
if (WriteRecord(__G__ locbuf, recsize))
return PK_DISK;
loccnt = 0;
locptr = locbuf;
}
} /* end if ( loccnt ) */
for (start = end; start < size && end < size; )
{
unsigned eol_off, eol_len;
got_eol = 0;
#ifdef undef
if (uO.cflag)
/* skip CR's at the beginning of record */
while (start < size && rawbuf[start] == CR)
++start;
#endif
if ( start >= size )
continue;
/* Find record end */
end = start+(eol_off = find_eol(rawbuf+start, size-start, &eol_len));
if ( end >= size )
continue;
if ( eol_len > 0 )
{
if ( WriteRecord(__G__ rawbuf+start, end-start) )
return PK_DISK;
start = end + eol_len;
}
else
{
got_eol = rawbuf[end];
end = size;
continue;
}
}
rest = size - start;
if (rest > 0)
{
if ( rest > BUFSMAXREC )
{
unsigned recsize;
char buf[80]; /* CANNOT use slide for Info() */
recsize = rest - (got_eol ? 1 : 0 );
Info(buf, 1, (buf,
"[ Warning: Record too long (%u) ]\n", recsize));
got_eol = 0;
return WriteRecord(__G__ rawbuf+start, recsize);
}
else
{
memcpy(locptr, rawbuf + start, rest);
locptr += rest;
loccnt += rest;
}
}
return PK_COOL;
}
static int WriteBuffer(__G__ buf, len)
__GDEF
uch *buf;
unsigned len;
{
int status;
if (uO.cflag)
{
(void)(*G.message)((zvoid *)&G, buf, len, 0);
}
else
{
status = sys$wait(outrab);
if (ERR(status))
{
vms_msg(__G__ "[ WriteBuffer: sys$wait failed ]\n", status);
if (outrab->rab$l_stv != 0)
{
vms_msg(__G__ "", outrab->rab$l_stv);
}
}
/* If odd byte count, then this must be the final record.
Clear the extra byte past EOF to help keep the file clean.
*/
if (len & 1)
buf[len] = '\0';
outrab->rab$w_rsz = len;
outrab->rab$l_rbf = (char *) buf;
if (ERR(status = sys$write(outrab)))
{
vms_msg(__G__ "[ WriteBuffer: sys$write failed ]\n", status);
if (outrab->rab$l_stv != 0)
{
vms_msg(__G__ "", outrab->rab$l_stv);
}
return PK_DISK;
}
}
return PK_COOL;
}
( run in 1.634 second using v1.01-cache-2.11-cpan-5b529ec07f3 )