249 lines
8.7 KiB
C
249 lines
8.7 KiB
C
/****************************************************************
|
|
* *
|
|
* Copyright 2001, 2011 Fidelity Information Services, Inc *
|
|
* *
|
|
* This source code contains the intellectual property *
|
|
* of its copyright holder(s), and is made available *
|
|
* under a license. If you do not know the terms of *
|
|
* the license, please stop and do not read further. *
|
|
* *
|
|
****************************************************************/
|
|
|
|
#include "mdef.h"
|
|
|
|
#include "gtm_unistd.h"
|
|
#include "gtm_stat.h"
|
|
#include "gtm_stdio.h"
|
|
#include "gtm_string.h"
|
|
#include "gtm_limits.h"
|
|
#include "io.h"
|
|
#include "iormdef.h"
|
|
#include "io_params.h"
|
|
#include "eintr_wrappers.h"
|
|
#ifdef __MVS__
|
|
#include "gtm_zos_io.h"
|
|
#include "gtm_zos_chset.h"
|
|
#endif
|
|
|
|
GBLREF io_pair io_curr_device;
|
|
GBLREF boolean_t gtm_utf8_mode;
|
|
ZOS_ONLY(GBLREF boolean_t gtm_tag_utf8_as_ascii;)
|
|
#ifdef __MVS__
|
|
error_def(ERR_BADTAG);
|
|
#endif
|
|
error_def(ERR_DEVOPENFAIL);
|
|
error_def(ERR_TEXT);
|
|
|
|
|
|
|
|
LITREF mstr chset_names[];
|
|
LITREF unsigned char io_params_size[];
|
|
|
|
/* WARNING, this routine is called from ioff_open as well as from the dispatch table. */
|
|
/* WARNING, this routine is called from iopi_open as well as from the dispatch table. */
|
|
|
|
short iorm_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 timeout)
|
|
{
|
|
io_desc *iod;
|
|
d_rm_struct *d_rm;
|
|
off_t size;
|
|
unsigned char ch;
|
|
int fstat_res, width_bytes;
|
|
int4 recsize_before;
|
|
struct stat statbuf;
|
|
int p_offset;
|
|
boolean_t utf_active, def_recsize_before, text_tag, newversion = FALSE;
|
|
gtm_chset_t width_chset, dummy_chset;
|
|
long pipe_buff_size;
|
|
#ifdef __MVS__
|
|
int file_tag, obtained_tag, realfiletag;
|
|
char *errmsg;
|
|
#endif
|
|
|
|
iod = dev_name->iod;
|
|
size = 0;
|
|
p_offset = 0;
|
|
assert((params) *(pp->str.addr + p_offset) < (unsigned char)n_iops);
|
|
assert(NULL != iod);
|
|
assert(0 <= iod->state && n_io_dev_states > iod->state);
|
|
assert(rm == iod->type);
|
|
if (dev_never_opened == iod->state)
|
|
{
|
|
iod->dev_sp = (void *)malloc(SIZEOF(d_rm_struct));
|
|
memset(iod->dev_sp, 0, SIZEOF(d_rm_struct));
|
|
d_rm = (d_rm_struct *)iod->dev_sp;
|
|
iod->state = dev_closed;
|
|
d_rm->stream = FALSE;
|
|
iod->width = DEF_RM_WIDTH;
|
|
iod->length = DEF_RM_LENGTH;
|
|
d_rm->recordsize = DEF_RM_RECORDSIZE;
|
|
d_rm->def_width = d_rm->def_recsize = TRUE;
|
|
d_rm->fixed = FALSE;
|
|
d_rm->noread = FALSE;
|
|
d_rm->fifo = FALSE;
|
|
d_rm->pipe = FALSE;
|
|
d_rm->padchar = DEF_RM_PADCHAR;
|
|
d_rm->inbuf = NULL;
|
|
d_rm->outbuf = NULL;
|
|
} else
|
|
d_rm = (d_rm_struct *)iod->dev_sp;
|
|
if (dev_closed == iod->state)
|
|
{
|
|
d_rm->lastop = RM_NOOP;
|
|
d_rm->out_bytes = 0;
|
|
d_rm->crlast = FALSE;
|
|
d_rm->done_1st_read = FALSE;
|
|
d_rm->done_1st_write = FALSE;
|
|
assert(0 <= fd);
|
|
d_rm->fildes = fd;
|
|
FSTAT_FILE(fd, &statbuf, fstat_res);
|
|
if (-1 == fstat_res)
|
|
rts_error(VARLSTCNT(9) ERR_DEVOPENFAIL, 2, dev_name->len, dev_name->dollar_io, ERR_TEXT, 2,
|
|
LEN_AND_LIT("Error in fstat"), errno);
|
|
for (p_offset = 0; iop_eol != *(pp->str.addr + p_offset); )
|
|
{
|
|
if (iop_append == (ch = *(pp->str.addr + p_offset++)))
|
|
{
|
|
if (!d_rm->fifo && !d_rm->pipe && (off_t)-1 == (size = lseek(fd, (off_t)0, SEEK_END)))
|
|
rts_error(VARLSTCNT(9) ERR_DEVOPENFAIL, 2, dev_name->len, dev_name->dollar_io,
|
|
ERR_TEXT, 2, LEN_AND_LIT("Error setting file pointer to end of file"), errno);
|
|
if (0 < statbuf.st_size)
|
|
{ /* Only disable BOM writing if there is something in the file already (not empty) */
|
|
d_rm->done_1st_read = FALSE;
|
|
d_rm->done_1st_write = FALSE;
|
|
}
|
|
break;
|
|
} else if (iop_newversion == ch)
|
|
newversion = TRUE;
|
|
p_offset += ((IOP_VAR_SIZE == io_params_size[ch]) ? (unsigned char)*(pp->str.addr + p_offset) + 1 :
|
|
io_params_size[ch]);
|
|
}
|
|
if (!d_rm->fifo && !d_rm->pipe && fd != 0)
|
|
{
|
|
if ((off_t)-1 == (size = lseek(fd, (off_t)0, SEEK_CUR)))
|
|
rts_error(VARLSTCNT(9) ERR_DEVOPENFAIL, 2, dev_name->len, dev_name->dollar_io,
|
|
ERR_TEXT, 2, LEN_AND_LIT("Error setting file pointer to the current position"), errno);
|
|
if (size == statbuf.st_size)
|
|
iod->dollar.zeof = TRUE;
|
|
} else
|
|
{
|
|
pipe_buff_size = fpathconf(fd, _PC_PIPE_BUF);
|
|
d_rm->pipe_buff_size = (-1 == pipe_buff_size) ? _POSIX_PIPE_BUF : pipe_buff_size;
|
|
}
|
|
if (1 == fd)
|
|
d_rm->filstr = NULL;
|
|
else if (NULL == (d_rm->filstr = FDOPEN(fd, "r")) && NULL == (d_rm->filstr = FDOPEN(fd, "w")))
|
|
rts_error(VARLSTCNT(9) ERR_DEVOPENFAIL, 2, dev_name->len, dev_name->dollar_io,
|
|
ERR_TEXT, 2, LEN_AND_LIT("Error in stream open"), errno);
|
|
}
|
|
recsize_before = d_rm->recordsize;
|
|
def_recsize_before = d_rm->def_recsize;
|
|
iorm_use(iod, pp);
|
|
/* Now that recordsize and CHSET parms have been handled (if any), set WIDTH if necessary */
|
|
if (recsize_before != d_rm->recordsize || def_recsize_before != d_rm->def_recsize)
|
|
{ /* record size was specified even if the same value */
|
|
SET_WIDTH_BYTES
|
|
assert(width_bytes <= d_rm->recordsize); /* or else RECSIZENOTEVEN error would have been issued */
|
|
iod->width = d_rm->recordsize;/* we are guaranteed this width will hold at least one character due to above check */
|
|
}
|
|
/* Now that recordsize and CHSET parms have been handled (if any), allocate the record buffer if needed (utf8 fixed) */
|
|
if (dev_closed == iod->state)
|
|
{
|
|
#ifdef __MVS__
|
|
/* need to get file tag info before set policy which can change what is returned */
|
|
if (-1 == gtm_zos_check_tag(fd, &file_tag, &text_tag))
|
|
rts_error(VARLSTCNT(9) ERR_DEVOPENFAIL, 2, dev_name->len, dev_name->dollar_io, ERR_TEXT, 2,
|
|
LEN_AND_LIT("Error in check_tag fstat"), errno);
|
|
SET_CHSET_FROM_TAG(file_tag, iod->file_chset);
|
|
iod->text_flag = text_tag;
|
|
if (!d_rm->pipe && 2 < fd)
|
|
{ /* not for stdin, stdout, stderr or pipes */
|
|
if (iod->newly_created || newversion)
|
|
{ /* tag the file. The macros also modify text_tag and file_tag. */
|
|
if (d_rm->fifo && (iod->is_ochset_default || d_rm->noread))
|
|
{ /* If FIFO, set tag per ichset if no ochset or READONLY */
|
|
SET_TAG_FROM_CHSET(iod->ichset, iod->file_chset, TRUE);
|
|
} else
|
|
{
|
|
SET_TAG_FROM_CHSET(iod->ochset, iod->file_chset, TRUE);
|
|
}
|
|
iod->file_tag = (unsigned int)file_tag;
|
|
iod->text_flag = text_tag;
|
|
if (-1 == gtm_zos_set_tag(fd, file_tag, text_tag, TAG_FORCE, &realfiletag))
|
|
{
|
|
errmsg = STRERROR(errno);
|
|
rts_error(VARLSTCNT(10) ERR_BADTAG, 4, dev_name->len, dev_name->dollar_io, realfiletag,
|
|
file_tag, ERR_TEXT, 2, RTS_ERROR_STRING(errmsg));
|
|
}
|
|
if (gtm_utf8_mode && gtm_tag_utf8_as_ascii && (CHSET_UTF8 == iod->ochset))
|
|
iod->process_chset = iod->ochset;
|
|
else
|
|
iod->process_chset = iod->file_chset;
|
|
} else
|
|
{
|
|
iod->file_tag = (unsigned int)file_tag; /* save real tag for file */
|
|
if (iod->is_ochset_default || d_rm->noread)
|
|
{ /* set tag per ichset if no ochset or READONLY */
|
|
SET_TAG_FROM_CHSET(iod->ichset, dummy_chset, FALSE);
|
|
} else
|
|
{
|
|
SET_TAG_FROM_CHSET(iod->ochset, dummy_chset, FALSE);
|
|
}
|
|
if (-1 == (obtained_tag = gtm_zos_tag_to_policy(fd, file_tag, &realfiletag)))
|
|
{
|
|
errmsg = STRERROR(errno);
|
|
rts_error(VARLSTCNT(10) ERR_BADTAG, 4, dev_name->len, dev_name->dollar_io, realfiletag,
|
|
file_tag, ERR_TEXT, 2, RTS_ERROR_STRING(errmsg));
|
|
}
|
|
SET_CHSET_FROM_TAG(obtained_tag, iod->process_chset);
|
|
}
|
|
} else
|
|
iod->process_chset = iod->file_chset; /* stdin, stdout, stderr */
|
|
if (!gtm_utf8_mode || !IS_UTF_CHSET(iod->ochset))
|
|
iod->ochset = CHSET_M;
|
|
if (!gtm_utf8_mode || !IS_UTF_CHSET(iod->ichset))
|
|
iod->ichset = CHSET_M;
|
|
if (CHSET_BINARY == iod->process_chset)
|
|
{
|
|
d_rm->fixed = TRUE;
|
|
iod->wrap = TRUE;
|
|
}
|
|
#endif
|
|
if (IS_UTF_CHSET(iod->ichset))
|
|
{
|
|
assert(NULL == d_rm->inbuf); /* We shouldn't have an existing buffer at this point */
|
|
assert(gtm_utf8_mode);
|
|
d_rm->bufsize = d_rm->fixed ? (d_rm->recordsize + 4) : 20; /* +4 for one extra utf8 char */
|
|
d_rm->inbuf = malloc(d_rm->bufsize);
|
|
d_rm->inbuf_pos = d_rm->inbuf_top = d_rm->inbuf_off = d_rm->inbuf; /* Force read first time thru */
|
|
}
|
|
if (IS_UTF16_CHSET(iod->ochset))
|
|
{
|
|
assert(NULL == d_rm->outbuf); /* We shouldn't have an existing buffer at this point */
|
|
d_rm->outbufsize = d_rm->recordsize + 4;
|
|
d_rm->outbuf = malloc(d_rm->outbufsize);
|
|
d_rm->out_bytes = 0;
|
|
}
|
|
} else
|
|
{ /* check for changed recordsize */
|
|
if (IS_UTF_CHSET(iod->ichset) && (recsize_before != d_rm->recordsize))
|
|
{
|
|
if (NULL != d_rm->inbuf)
|
|
free(d_rm->inbuf);
|
|
d_rm->bufsize = d_rm->fixed ? (d_rm->recordsize + 4) : 20; /* +4 for one extra utf8 char */
|
|
d_rm->inbuf = malloc(d_rm->bufsize);
|
|
d_rm->inbuf_pos = d_rm->inbuf_top = d_rm->inbuf_off = d_rm->inbuf; /* Force read first time thru */
|
|
}
|
|
if (IS_UTF16_CHSET(iod->ochset) && (recsize_before != d_rm->recordsize))
|
|
{
|
|
if (NULL != d_rm->outbuf)
|
|
free(d_rm->outbuf);
|
|
d_rm->outbufsize = d_rm->recordsize + 4;
|
|
d_rm->outbuf = malloc(d_rm->outbufsize);
|
|
d_rm->out_bytes = 0;
|
|
}
|
|
}
|
|
iod->state = dev_open;
|
|
return TRUE;
|
|
}
|