예제 #1
0
int
_er90b_write(struct fdinfo *fio, bitptr bufptr, int nbytes, 
	struct ffsw *retstat, int fulp, int *ubc)
{
int ret;
int nbt = 0;	/* number of bytes transferred so far */
int nbreq;	/* number of bytes requested this request */
char *buf;
ER90BYT *f;
int zero = 0;
struct ffsw dumstat;

	buf = BPTR2CP(bufptr);
	if ((BPBITOFF(bufptr) & 7) != 0 || *ubc != 0)
		ERETURN(retstat, FDC_ERR_UBC, 0);

	nbreq = nbytes;
	if (fio->rwflag == POSITIN) {
		f = (ER90BYT *)fio->lyr_info;
		if (f->tpos) {
			ret = _tape_tpwait(f->fd, &(f->tpos));
			if (ret < 0)
				ERETURN(retstat, errno, 0);
		}		
	}
	else if (fio->rwflag == READIN) {
		/* write after read requires position to zero */
		ret = _er90b_pos(fio, FP_RSEEK, &zero, 1,
			&dumstat);
		if (ret < 0) {
			*retstat = dumstat;
			return(ERR);
		}
	}
	if (nbreq > 0) {
again:
		/* It is not safe to reissue the write if it fails */
		/* with EINTR. Some data may have been transferred */
		ret= write(fio->realfd, buf, nbreq);
		if (ret < 0)
			ERETURN(retstat, errno, nbt);
		nbt += ret;
/*
 *		The assumption is made here that the system will never return
 *		zero bytes on a non-zero request without an error!
 */
		if (nbt < nbytes) {
			buf += ret;
			nbreq -= ret;
			goto again;
		}
	}
	else if (nbytes < 0)
		ERETURN(retstat, FDC_ERR_REQ, 0);

	SETSTAT(retstat, FFCNT, nbt);
	fio->rwflag = WRITIN;
	return (nbt);
}
예제 #2
0
ssize_t
_sys_read(
struct fdinfo *fio, 
bitptr bufptr, 
size_t nbytes, 
struct ffsw *retstat,
int fulp, 
int *ubc)
	{
	ssize_t ret = 0;
	char *buf;

	buf = BPTR2CP(bufptr);
	if ((BPBITOFF(bufptr) & 7) != 0 || *ubc != 0)
		ERETURN(retstat, FDC_ERR_UBC, 0);
#ifdef __mips
        /*
         * If our last i/o was asynchronous, then our file position
         * won't be what we expect. Seek to the right position. We
         * could use a pread instead of seeking, but that would also
         * not update the file position. I'm doing this because it seems
         * to me most 'expected' for the system call layer.
         */
        if (((struct sys_f *)fio->lyr_info)->needpos) {
                if (lseek( fio->realfd, ((struct sys_f *)fio->lyr_info)->curpos,
                        0)  < 0)
                        ERETURN(retstat, errno, 0);
                ((struct sys_f *)fio->lyr_info)->needpos = 0;
        }
#endif

	if (nbytes > 0)
		{
		if (((struct sys_f *)fio->lyr_info)->nointrio)
			ret = read(fio->realfd, buf, nbytes);
		else {
			LOOP_SYSCALL(ret, read(fio->realfd, buf, nbytes));
		}
		if (ret < 0)
			ERETURN(retstat, errno, 0);
		}

	if (ret == 0 && nbytes > 0) {
		SETSTAT(retstat, FFEOD, ret);
	}
	else {
		SETSTAT(retstat, FFCNT, ret);
#ifdef __mips
		((struct sys_f *)(fio->lyr_info))->curpos += ret;
#endif
	}
	return (ret);
	}
예제 #3
0
int
_er90b_writea(struct fdinfo *fio, bitptr bufptr, int nbytes, 
	struct ffsw *retstat, int fulp, int *ubc)
{
int ret = 0;
char *buf;
ER90BYT *f;
int zero = 0;
struct ffsw dumstat;

	buf = BPTR2CP(bufptr);
	if ((BPBITOFF(bufptr) & 7) != 0 || *ubc != 0)
		ERETURN(retstat, FDC_ERR_UBC, 0);

	if (fio->rwflag == POSITIN) {
		f = (ER90BYT *)fio->lyr_info;
		if (f->tpos) {
			ret = _tape_tpwait(f->fd, &(f->tpos));
			if (ret < 0)
				ERETURN(retstat, errno, 0);
		}		
	}
	else if (fio->rwflag == READIN) {
		/* write after read requires position to zero */
		ret = _er90b_pos(fio, FP_RSEEK, &zero, 1,
			&dumstat);
		if (ret < 0) {
			*retstat = dumstat;
			return(ERR);
		}
	}

	if (nbytes > 0) {
		CLRFFSTAT(*retstat);	/* flag async in progress */
		ret=   writea(fio->realfd, buf, nbytes,
			(struct iosw *)retstat, 0);
		if (ret < 0)
			ERETURN(retstat, errno, 0);
	}
	else if (nbytes < 0) {
		ERETURN(retstat, FDC_ERR_REQ, 0);
	}
	else {	/* nbytes == 0 */
		retstat->sw_flag = 1;
		FFSTAT(*retstat) = FFCNT; /* I/O is done, and other stat */
					/* fields are already set. */
	}
	fio->rwflag = WRITIN;
	return (ret);
}
예제 #4
0
/*
 * The f77 layer makes no particular effort to be aligned in any way
 * within the file, other than trying to write/read full buffers.
 * As long as we are writing/reading sequentially, we should always
 * be aligned on a buffer boundary.  Any positioning will destroy that.
 * Even with no positioning, we may have to seek back and write a control
 * word.  This routine just attempts to make sure that the user's buffer
 * is memory aligned.
 * Returns:
 *		1 if address 'p' is aligned
 *		0 other wise
 */
static int _f77_aligned(char *p)
{
#ifdef	_CRAYMPP
	long	pl;
	/* Want it to be aligned on an 8-word boundary */
#define CACHE_MASK 0x3f
	pl = (long)p;
	if ((pl & CACHE_MASK) == 0)
		return(1);
	return(0);
#elif	_CRAY1
	/* want it be aligned on a word boundary */
	if (BPBITOFF(CPTR2BP(p)) == 0)
		return (1);
	return (0);
#elif	defined(__mips) || defined(_LITTLE_ENDIAN)
	return (1);	/* We know of no particular alignment requirements */
			/* except when O_DIRECT is specified. This layer */
			/* is not set up for O_DIRECT now. */
#else
	return (1);
#endif
}
예제 #5
0
/*
 * Read a tape file.
 * With this format, one tape block == one record.
 * Parameters:
 *	fio	Pointer to fdinfo block
 *	bufptr	bit pointer to where data is to go.
 *	nbytes	Number of bytes to be read
 *	stat	pointer to status return word
 *	fulp	full or partial read mode flag
 *	ubc	pointer to unused bit count (not used this class of file)
 *
 */
ssize_t
_tmf_read(
	struct fdinfo	*fio,
	bitptr		bufptr,
	size_t		nbytes,
	struct ffsw	*stat,
	int		fulp,
	int		*ubc)
{
	register int	errn;	/* Error code */
	size_t		bytes;	/* Number of bytes actually read */
	ssize_t		ret;	/* Return status */
	struct tmfio	*xf_info;

	xf_info	= (struct tmfio *)fio->lyr_info;

	if (*ubc != 0) {
		errn	= FDC_ERR_UBC;
		goto eret;
	}

	if ((BPBITOFF(bufptr) & 07) != 0) {
		errn	= FDC_ERR_REQ;
		goto eret;
	}
	if (xf_info->rwflag == WRITIN && !xf_info->tmf_speov) {
		/* Read after write is OK in special processing */
		/* otherwise, it is an error. */
		errn	= FDC_ERR_RAWR;
		goto eret;
	}
	if (xf_info->tmf_tpos) {
		if (_tmf_tpwait(xf_info) < 0) {
			errn	= errno;
			goto eret;
		}
	}

	xf_info->rwflag	= READIN;

	if (xf_info->tmf_speov) {
		/* If we ever do async i/o, then we want to read */
		/* synchronously while in special processing. */
		if (xf_info->spblocks == 0) {
			/* We're not reading from the tape. */
			/* We're reading from buffer memory */
			goto spprocread;
		}
	}
/*
 *	If the number of bytes to read is zero and reading in full
 *	record mode, skip to the end of record. If in partial
 *	record mode, the position remains as is.
 *	Are we at the beginning of the record?
 */
	if (xf_info->tmf_cnt == 0) {
/*
 *		We are at the beginning of the record. Must read
 *		from tape. Even if the user has requested a FULL
 *		record, we need to read it in to the buffer, unless
 *		the request is for bufsiz bytes.
 *		That is because, if the user requests less than
 *		is actually in the tape block, the read would
 *		give an error.
 */
		if (nbytes == xf_info->tmf_bufsiz) {
			LOOP_SYSCALL(ret,read(xf_info->tmf_fd, BPTR2CP(bufptr),
			xf_info->tmf_bufsiz));
			bytes	= ret;
		}
		else {
			LOOP_SYSCALL(ret,read(xf_info->tmf_fd, 
				xf_info->tmf_bufptr,
				xf_info->tmf_bufsiz));
			if (ret > 0) {
				bytes	= MIN(ret, nbytes);
				(void) memcpy(BPTR2CP(bufptr),
					xf_info->tmf_bufptr, bytes);
			}
		}

		if (ret > 0) {
			if (ret == nbytes) {
				SETSTAT(stat, FFEOR, bytes);
				if (xf_info->spblocks > 0)
					xf_info->spblocks--;
				return(bytes);
			}
			else if (fulp == FULL) {
				SETSTAT(stat, FFCNT, bytes);
				if (xf_info->spblocks > 0)
					xf_info->spblocks--;
				return(bytes);
			}
			else {
				SETSTAT(stat, FFCNT, bytes);
				xf_info->tmf_bufptr    += bytes;
				xf_info->tmf_cnt	= ret - bytes;
			}
		}
		else if (ret == 0) {
			if (ioctl(xf_info->tmf_fd,TMFC_EOD,0)) {
				SETSTAT(stat, FFEOF, 0);
				return(0);
			}
			SETSTAT(stat, FFEOD, 0);
			return(0);
		}
		else {
			/* Could be EOV, or an error */
			if (errno == ENOSPC) {

				/* If we hit physical eov, */
				/* return an error */
				/* and set eovhit so that */
				/* checktp will tell us we */
				/* hit eov */
/* JAS - should document that ffread will return ENOSPC at eov */
/* also Fortran read will return an error */
				if (xf_info->tmf_eovon)
					xf_info->tmf_eovhit	= 1;
				ERETURN(stat, errno, 0);
			}
			else {
				ERETURN(stat, errno, 0);
			}
		}
	}	
	else {
		/* 
		 * We are in the middle of a record. The entire record,
		 * and nothing more, is already in our buffer. 
 		 */
		bytes	= MIN(nbytes, xf_info->tmf_cnt);
		(void) memcpy(BPTR2CP(bufptr), xf_info->tmf_bufptr, bytes);
		xf_info->tmf_cnt    -= bytes;
		xf_info->tmf_bufptr += bytes;

		if (xf_info->tmf_cnt == 0) {
			xf_info->tmf_bufptr = xf_info->tmf_base;
			if (xf_info->spblocks > 0)
				xf_info->spblocks--;
			SETSTAT(stat, FFEOR, bytes);
		}
		else {
			SETSTAT(stat, FFCNT, bytes);
			if (fulp == FULL) {
				if (xf_info->spblocks > 0)
					xf_info->spblocks--;
				xf_info->tmf_bufptr	= xf_info->tmf_base;
				xf_info->tmf_cnt	= 0;
			}
		}
	}
	return (bytes);
eret:
	ERETURN(stat, errn, 0);

spprocread:
	/* We're reading from buffer memory. */
	/* Right now, we've got only 1 block in buffer memory. */
	if (xf_info->tmf_tpmk) {
		xf_info->tmf_tpmk	= 0;
		SETSTAT(stat, FFEOF, 0);
		return(0);
	}
	else {
		if (xf_info->eovbytes == 0) {
			SETSTAT(stat, FFEOD, 0);
			return(0);
		}
		bytes	= MIN(xf_info->eovbytes, nbytes);
		(void) memcpy(BPTR2CP(bufptr), xf_info->eovbuf, bytes);
		if (fulp == FULL || (nbytes >= xf_info->eovbytes)) {
			xf_info->eovbytes	= 0;
			SETSTAT(stat, FFEOR, bytes);
		}
		else {
			xf_info->eovbytes -= nbytes;
			xf_info->eovbuf += nbytes;
			SETSTAT(stat, FFCNT, bytes);
		}

		return(bytes);
	}
}
예제 #6
0
/*
 * This is the tape layer for Irix systems.
 * When the tape is in variable block mode, each user's record 
 * corresponds to a block on tape.
 * This is accomplished by writing the record with 1 write statement.
 * The tape layer's buffer is big enough to hold 1 record.
 * If we get a full write, and nothing else is in the buffer for
 * this record, we can skip copying to the library buffer, and write it
 * directly from the user's space.
 * If we get a partial write, we need to copy to the library buffer.
 * Parameters:
 *      fio     - Pointer to fdinfo block
 *	bufptr	- bit pointer to where data is to go.
 *	nbytes	- Number of bytes to be written
 *	stat	- pointer to status return word
 *	fulp	- full or partial write mode flag
 *	ubc	- pointer to unused bit count (not used for IBM)
 */
ssize_t
_tmf_write(
	struct fdinfo	*fio,
	bitptr		bufptr,
	size_t		nbytes,
	struct ffsw	*stat,
	int		fulp,
	int		*ubc)
{
	register int	errn;
	ssize_t		ret;
	struct tmfio	*xfinfo;	

	if ((BPBITOFF(bufptr) & 07) != 0) {
		errn	= FDC_ERR_REQ;
		goto eret;
	}
	if (*ubc != 0) {
		errn	= FDC_ERR_UBC;
		goto eret;
	}
        xfinfo	= (struct tmfio *)fio->lyr_info;
/*
 *	If we've been reading, then try to switch the buffer into write mode.
 */
	if (xfinfo->rwflag == READIN) {
		/*
		 * Issue an error if we are not positioned at a record
		 * boundary.   ffweof would terminate the current record, but
 		 * _cos_write overwrites the current record.   We need to
		 * decide which is the proper approach before permitting this
		 * here.
		 */
		if (xfinfo->tmf_base != xfinfo->tmf_bufptr) {
			errn	= FDC_ERR_NOTREC;
			goto eret;
		}
		ret	= _tmf_wrard(fio, stat);
		if (ret < 0) return(ERR);
	}

	if (xfinfo->tmf_tpos) {
		if (_tmf_tpwait(xfinfo) < 0) {
			ERETURN(stat, errno, 0);
		}
	}
	xfinfo->rwflag	= WRITIN;

	if (xfinfo->tmf_speov) {
		/* We're in special processing. */
		/* Reset counter of blocks on tape */
		xfinfo->spblocks	= 0;

		/* If we've read anything from buffer memory, then mark it */
		/* all gone. - for now we don't need to worry about */
		/* this, because we can only have 1 block in buffer memory. */
		/* But if we every do async i/o, this could be a problem. */
	}
	if ((xfinfo->tmf_bufptr == xfinfo->tmf_base) && fulp == FULL) {
/*
 *		This is the entire record, so just write it out
 */
		LOOP_SYSCALL(ret, write(xfinfo->tmf_fd, BPTR2CP(bufptr), nbytes));
		if (ret != nbytes) {
			if (xfinfo->tmf_eovon && !xfinfo->tmf_speov) {
				/* The user has enabled eov processing. */
				/* Determine whether we hit EOV. */
				int err;
				if (_tmf_ateov(fio,xfinfo, nbytes,
					BPTR2CP(bufptr), ret, stat, &err)) {
					/* This is eov */
					/* We need to save away the */
					/* unwritten part of the data, */
					/* and set a flag so we can */
					/* tell the user eov was reached. */
					/* This user's write will return */
					/* a good status. */
					return(_tmf_eovseen(xfinfo, 
						nbytes, BPTR2CP(bufptr), 
						ret, stat));
				}
				if (err != 0) {
					ERETURN(stat, err, ret);
				}
				/* We were able to rewrite the block. */
				/* Carry on. */
			}
			else {
				if (ret < 0) {
					ERETURN(stat, errno, 0);
				}
				else{
					ERETURN(stat, FDC_ERR_WRTERR, ret);
				}
			}
		}
		SETSTAT(stat, FFEOR, ret);
		return(ret);
	}
/*
 *	This must not be the entire record. So, we need to copy it
 *	to our library buffer. 
 */
	if (nbytes + xfinfo->tmf_cnt > xfinfo->tmf_bufsiz) {
		ERETURN(stat, FDC_ERR_MXBLK, 0);
	}
	memcpy(xfinfo->tmf_bufptr, BPTR2CP(bufptr), nbytes);
	xfinfo->tmf_cnt += nbytes;
	xfinfo->tmf_bufptr += nbytes;
	if (fulp == FULL) {
		LOOP_SYSCALL(ret, write(xfinfo->tmf_fd, xfinfo->tmf_base, xfinfo->tmf_cnt));
		xfinfo->tmf_bufptr	= xfinfo->tmf_base;
		if (ret != xfinfo->tmf_cnt) {
			if (xfinfo->tmf_eovon && !xfinfo->tmf_speov) {
				int err;
				if (_tmf_ateov(fio,xfinfo, xfinfo->tmf_cnt,
					xfinfo->tmf_base, ret, stat, &err)) {
					/* This is eov */
					/* We need to save away the */
					/* unwritten part of the data, */
					/* and set a flag so we can */
					/* tell the user eov was reached. */
					/* This write will return OK */
					return(_tmf_eovseen(xfinfo, 
						xfinfo->tmf_cnt,
						xfinfo->tmf_base,
						ret, stat));
				}
				if (err != 0) {
					ERETURN(stat, err, ret);
				}
				/* We were able to rewrite the block. */
				/* Carry on. */
			}
			else {
				xfinfo->tmf_cnt	= 0;
				if (ret < 0) {
					ERETURN(stat, errno, 0);
				}
				else{
					ERETURN(stat, FDC_ERR_WRTERR, ret);
				}
			}
		}
		xfinfo->tmf_cnt	= 0;
		SETSTAT(stat, FFEOR, nbytes);
		return(nbytes);	
	}
	else {

		SETSTAT(stat, FFCNT, nbytes );
		return(nbytes);
	}
			
eret:
	ERETURN(stat, errn, 0);
}
예제 #7
0
/*
 * Write a f77 class file
 * Parameters:
 *      fio     - Pointer to fdinfo block
 *	bufptr	- bit pointer to where data is to go.
 *	nbytes	- Number of bytes to be written
 *	stat	- pointer to status return word
 *	fulp	- full or partial write mode flag
 *	ubc	- pointer to unused bit count (not used for IBM)
 */
ssize_t
_f77_xwrite(
struct fdinfo	*fio,
bitptr		bufptr,
size_t		nbytes,
struct ffsw	*stat,
int		fulp,
int		*ubc)
{
	ssize_t ret;
	size_t  bytomove, moved, bytes;
	struct f77_xf *xfinfo;	
	struct fflistreq list_array[1];
	long left;
	char *cbufptr;
	long ii;
	char *cb;
	int ijk;
	int cwbytes;
	int ernum;
	int zero = 0;

	cbufptr = BPTR2CP(bufptr);
	if ((BPBITOFF(bufptr) & 07) != 0) {
		ernum = FDC_ERR_REQ;
		goto eret;
	}
	if (*ubc != 0){
		ernum = FDC_ERR_UBC;
		goto eret;
	}
        xfinfo = (struct f77_xf *)fio->lyr_info;
/*
 *	If we've been reading, then try to switch the buffer into write mode.
 */
	if (fio->rwflag == READIN) {
		/*
		 * Issue an error if we are not positioned at a record
		 * boundary.   ffweof would terminate the current record, but
 		 * _cos_write overwrites the current record.   We need to
		 * decide which is the proper approach before permitting this
		 * here.
		 */
		if (!(xfinfo->flag & ATEOR) && !(fio->ateod ) && !(fio->ateof)) {
		ernum = FDC_ERR_NOTREC;
		goto eret;
		}
		ret = f77_xwrard(fio, stat);
		if (ret < 0) return(ERR);
	}

	fio->rwflag = WRITIN;

/*
 *	initialize a new record, if needed.
 */
	bytomove = nbytes;
	moved = 0;
/*
 *	Check for record size exceeded.
 */
	if (bytomove > 0) {
		if ((xfinfo->maxrecsize > 0) &&
			(xfinfo->recbytes + bytomove) > xfinfo->maxrecsize){
			ernum = FDC_ERR_MXREC;
			goto eret;
		}
	}
	if (xfinfo->recbytes == 0) {
		/* This is the start of the record */
		ii = bytomove;
		if (fio->rtype == TR_UX_MIPS) {SWAPB(ii);}
		if ((bytomove > 0) || (fulp == FULL)) {
/*
 *			Put our guess at a control word in the buffer.
 *			This is the control word at the beginning of record.
 */
			cwbytes = RDWLEN;
			cb = (char *)&ii;
#if	!(defined(_LITTLE_ENDIAN) && defined(_LP64))
			cb += sizeof(ii) - RDWLEN;	/* The control word is only RDWLEN bytes long */
#endif
			if ((xfinfo->_cnt + RDWLEN) >= xfinfo->_ffbufsiz) {
				/* only part of the control word will fit */
				/* in this buffer.  Insert what will fit. */
				for (ijk = 0; ijk < xfinfo->_ffbufsiz - xfinfo->_cnt; ijk++){
					*(xfinfo->_ptr++) = *cb++;
					cwbytes--;
				}
				/* buffer is full. write it out. */
				if (_f77_put_block(fio, stat, (size_t)xfinfo->_ffbufsiz) != 0)
					return(ERR);
			}
			for (ijk = 0; ijk < cwbytes; ijk++){
				*(xfinfo->_ptr++) = *cb++;
			}
			xfinfo->_cnt += cwbytes;
			xfinfo->recbytes += RDWLEN;
			xfinfo->cwwritten = 1;
		}
	}

	else {
		/* This record has already been started. */
		ii = (xfinfo->recbytes + bytomove - RDWLEN) ;
		if (fio->rtype == TR_UX_MIPS) {SWAPB(ii);}
		if (bytomove != 0) {
/*
 *			If the control word at the start of the 
 *			record is in the buffer, update it.
 */
			if (xfinfo->recbytes <= xfinfo->_cnt){
				char *tbptr;
				/* the whole control word is in the buffer */
				cb = (char *)&ii;
#if	!(defined(_LITTLE_ENDIAN) && defined(_LP64))
				cb += sizeof(ii) - RDWLEN;	/* The control word is only RDWLEN bytes long */
#endif
				tbptr = xfinfo->_ptr - xfinfo->recbytes;
				for (ijk = 0; ijk < RDWLEN; ijk++)
					*(tbptr++) = *cb++;
				xfinfo->cwwritten = 1;
			}		
			else if ((xfinfo->recbytes - RDWLEN) <= xfinfo->_cnt){
				char *tbptr;
				int istart;
				/* part of the control word is in the buffer */
				/* Insert what will fit. */
				cb = (char *)&ii;
#if	!(defined(_LITTLE_ENDIAN) && defined(_LP64))
				cb += sizeof(ii) - RDWLEN;	/* The control word is only RDWLEN bytes long */
#endif
				istart = xfinfo->recbytes -xfinfo->_cnt;
				cb += istart;
				tbptr = xfinfo->_base;
				for (ijk = istart; ijk < RDWLEN; ijk++)
					*(tbptr++) = *cb++;
				xfinfo->cwwritten = 0; /* 0 because this is */
						/* not the whole thing*/
			}
			else 
				xfinfo->cwwritten = 0;
		}
	}
/*
 *	loop putting data in buffer 
 */
	while (bytomove > 0) {
/*
 *		bytes tells when data has been moved.  Set it to zero
 *		unless someone moves some data in the loop
 */
/*
 *		If enough room for bytes, put them in the buffer
 */
		left = xfinfo->_ffbufsiz - xfinfo->_cnt;
		if (left == 0) {
			if (_f77_put_block(fio, stat, (size_t)xfinfo->_cnt) != 0)
				return(ERR);
			left = xfinfo->_ffbufsiz;
#ifdef	__CRAY
#pragma _CRI inline _f77_aligned
#elif	defined(__mips) || defined(_LITTLE_ENDIAN)
#pragma inline _f77_aligned
#endif
			if ((bytomove >= left) && _f77_aligned(cbufptr)) {
				/* We write directly from the user's buffer */
				bytes = bytomove - bytomove%xfinfo->_ffbufsiz;
				ret = XRCALL(fio->fioptr, writertn) fio->fioptr,
					CPTR2BP(cbufptr), bytes, stat, PARTIAL,
					&zero);
				if (ret != bytes){
					return(ERR);
				}	
				bytomove -= bytes;
				cbufptr += bytes;
				moved += bytes;
			}
		}
		bytes = (bytomove < left)? bytomove : left;
		memcpy(xfinfo->_ptr, cbufptr, bytes);
		xfinfo->_cnt += bytes;
		xfinfo->_ptr += bytes;
		cbufptr += bytes;
		bytomove -= bytes;
		moved += bytes;
	}
예제 #8
0
ssize_t
_sys_write(
struct fdinfo *fio, 
bitptr bufptr, 
size_t nbytes,
struct ffsw  *retstat,
int fulp,
int *ubc)
{
	ssize_t ret;
	ssize_t nbt = 0;	/* number of bytes transferred so far */
	size_t nbreq;	/* number of bytes requested this request */
	char *buf;

	buf = BPTR2CP(bufptr);
	if ((BPBITOFF(bufptr) & 7) != 0 || *ubc != 0)
		ERETURN(retstat, FDC_ERR_UBC, 0);

	nbreq = nbytes;
#ifdef __mips
	/*
	 * If our last i/o was asynchronous, then our file position
	 * won't be what we expect. Seek to the right position. We
	 * could use a pwrite instead of seeking, but that would also
	 * not update the file position. I'm doing this because it seems
	 * to me most 'expected' for the system call layer.
	 */
	if (((struct sys_f *)fio->lyr_info)->needpos) {
		if (lseek( fio->realfd, ((struct sys_f *)fio->lyr_info)->curpos,
			0)  < 0)
			ERETURN(retstat, errno, nbt);
		((struct sys_f *)fio->lyr_info)->needpos = 0;
	}
#endif
	if (nbreq > 0) {
#ifdef __mips
		if (((struct sys_f *)fio->lyr_info)->oappend) {
			((struct sys_f *)fio->lyr_info)->curpos = 
				((struct sys_f *)fio->lyr_info)->endpos;
		}
#endif
again:
		if (((struct sys_f *)fio->lyr_info)->nointrio)
			ret = write(fio->realfd, buf, nbreq);
		else {
			LOOP_SYSCALL(ret, write(fio->realfd, buf, nbreq));
		}
		if (ret < 0)
			ERETURN(retstat, errno, nbt);
#ifdef __mips
		((struct sys_f *)fio->lyr_info)->curpos += ret;
		if (((struct sys_f *)fio->lyr_info)->curpos > 
			((struct sys_f *)fio->lyr_info)->endpos)
			((struct sys_f *)fio->lyr_info)->endpos = 
				((struct sys_f *)fio->lyr_info)->curpos;
#endif
		nbt += ret;
/*
 *		The assumption is made here that the system will never return
 *		zero bytes on a non-zero request without an error!
 */
		if (nbt < nbytes) {
			buf += ret;
			nbreq -= ret;
			goto again;
		}
	}

	SETSTAT(retstat, FFCNT, nbt);
	return (nbt);
}
예제 #9
0
/*
 * _cch_write
 *
 * Process write requests for the cache layer.
 *
 * Return value:
 *
 *	The number of bytes transferred is returned upon successful completion.
 *	If an error occurs, -1 is returned.
 *
 *	The stat->sw_stat field is set to FFCNT upon normal return.
 */
ssize_t
_cch_write(
    struct fdinfo	*fio, 		/* ffio file descriptor. */
    bitptr		datptr,		/* bit pointer to the user's data. */
    size_t		nbytes,		/* Nuber of bytes to be written. */
    struct ffsw	*stat,		/* pointer to status return word */
    int		fulp,		/* full or partial write mode flag */
    int		*ubcp 		/* pointer to unused bit count.  On return, */
    /* *ubcp is updated to contain the unused bit */
    /* count in the data returned. */
)
{
    off_t		cpos;		/* bit position in file */
    int64		moved;		/* number of bits transfered */
    int64		bytes_moved;	/* number of bytes transfered */
    int64		morebits;	/* bits moved in current iteration */
    int64		numblocks;	/* num of pages to process this iter */
    int		pgoff;
    off_t		fileaddr;
    off_t		eofaddr;
    int		gb_rd;		/* nonzero if pages must be read */
    int		valid;		/* nonzero if CCH_VALIDBUFFER should */
    /* be set */
    int64		nbits;
    int64		i;
    int		bs, nbu;
    off_t		olpos, endpos, endoff;
    bitptr		toptr;
    struct ffsw	locstat;
    struct fdinfo	*llfio;
    struct cch_f	*cch_info;
    struct cch_buf	*cubuf;
    int		err;
    short		firsteof = 0;
    short		setfirst;

    CCH_DEBUG(("_cch_write EN: nbytes=%d fulp=%d ubc=%d\n",nbytes,fulp,
               *ubcp));
    CLRSTAT(locstat);
    cch_info = (struct cch_f *)fio->lyr_info;
    nbits = BYTES2BITS(nbytes) - *ubcp;

    fio->rwflag = WRITIN;
#if	defined(__mips) || defined(_LITTLE_ENDIAN)
    /* Although this layer is capable of handling non-zero ubc */
    /* and bitptrs that aren't on a byte boundary, we are not */
    /* supporting this right now on mips systems. */
    if (*ubcp != 0) {
        err = FDC_ERR_UBC;
        goto err1_ret;
    }
    if ((BPBITOFF(datptr) & 07) != 0) {
        err = FDC_ERR_REQ;
        goto err1_ret;
    }
#endif

    if (nbits == 0) {			/* quick return for nbits == 0*/
        SETSTAT(stat, FFCNT, 0);
        return(0);
    }

    /*
     *	Move data from user to buffer
     */
    llfio	 = fio->fioptr;
    bs	 = cch_info->bsize;	/* bit size of each buffer */
    cpos	 = cch_info->cpos;	/* current file position */
    olpos    = cpos;		/* save original position */
    fileaddr = CCHFLOOR(cpos,bs);	/* bit offset within the file of the
					 * start of the current page */

    if (cpos > cch_info->fsize) {

        firsteof = 1;

        /* Is the page with eof in memory? */
        /* If so, zero out the portion beyond eof. */
        eofaddr = CCHFLOOR(cch_info->fsize, bs);
        CCH_FINDBLK(cch_info, eofaddr, cubuf);
        if (cubuf != NULL && (cubuf->flags & CCH_ZEROED) == 0) {
#ifdef CCH_SDS_SUPPORTED
            if (cch_info->optflags & CCHOPT_SDS) {
                /* should never happen */
                ERETURN(stat, FDC_ERR_INTERR, 0);
            }
#endif
            pgoff = cch_info->fsize - eofaddr; /* offset of eof */
            /* within the page */
            SET_BPTR(toptr, INC_BPTR(cubuf->buf, pgoff));
            morebits = bs - pgoff;
            if (morebits != 0) {
                CCH_MEMCLEAR(toptr, morebits);
            }
            cubuf->flags |= CCH_ZEROED;
        }
    }
    while (nbits > 0) {
        /*
         * Find the cache buffer assigned to the current page.  If
         * no buffer is currently assigned, then _cch_getblk assigns
         * one.
         */
        pgoff	  = cpos - fileaddr;	/* offset within the page */
        numblocks = 1;			/* number of of pages to prcess
						 * in this iteration */

        CCH_FINDBLK(cch_info, fileaddr, cubuf);

        if (cubuf == NULL) {	/* if data not buffer-resident*/

            if (nbits > cch_info->bypasssize
#ifdef CCH_SDS_SUPPORTED
                    && !(cch_info->optflags & CCHOPT_SDS)
#endif
               ) {
                /* Maybe we can bypass buffering */
                if ((morebits= _cch_bypass(cch_info, nbits, cpos,
                                           datptr, fileaddr, 'w', llfio, &locstat))>0)
                    goto adjust;
                else if (morebits < 0) {
                    /* Is it right to return the count */
                    /* in locstat? Because we might */
                    /* have read some data... */
                    goto er1;
                }
                /* we weren't able to bypass buffering */
            }

            morebits = nbits;
            endpos = cpos + morebits; /*1 bit past the end*/
            endoff = endpos - CCHFLOOR(endpos,bs);

            if (endpos > fileaddr + bs) {
                numblocks = (endpos-fileaddr-1)/bs + 1;
                nbu	  = cch_info->nbufs;
                /*
                 * Handle at most a cache full at a time
                 */
                if (numblocks > nbu) {
                    numblocks = nbu;
                    endpos    = fileaddr + nbu * bs;
                    endoff    = 0;
                    morebits  = endpos - cpos;
                }
            }

            /*
             * It is possible that the first or last
             * page must be read because the transfer
             * fills only part of these pages.  In each
             * iteration, _cch_getblk requires that
             * consecutive buffer pages must all be read,
             * or else all be assigned without pre-reading.
             * The following code breaks off the current
             * portion of the transfer when necessary to
             * accomplish this.
             */

            if (numblocks > 1) {

                if (numblocks == 2) {
                    if ((pgoff == 0) != (endoff == 0)) {
                        /* process only first page */
                        numblocks  = 1;
                        endoff     = 0;
                        morebits   = bs - pgoff;
                    }
                }
                else {
                    if (pgoff) {
                        /* process only first page */
                        numblocks  = 1;
                        endoff     = 0;
                        morebits   = bs - pgoff;
                    }
                    else if (endoff) {
                        /* process all but last page */
                        numblocks -= 1;
                        endoff     = 0;
                        morebits  -= endoff;
                    }
                }
            }

            /*
             * Request that _cch_getblk read in the file
             * pages if partial pages of data will be
             * written.
             */

            gb_rd = (pgoff || endoff);
            /* The pages will be valid if we do not */
            /* have to read them. That's because */
            /* we will be writing to the entire page */
            /* The page will also be valid if we do read it */
            valid = 1;
            setfirst = 0;
            if (gb_rd &&
#ifdef CCH_SDS_SUPPORTED
                    !(cch_info->optflags & CCHOPT_SDS) &&
#endif
                    (numblocks == 1) &&
                    ((fileaddr+bs) < cch_info->feof) &&
                    (_CCH_ALIGN(pgoff) && _CCH_ALIGN(endoff))) {
                /* do we really need to read the page in? */
                /* if pgoff and endoff are properly aligned, */
                /* we do not */
                /* Note that if any part of the page is */
                /* beyond feof, we want to read it in. */
                /* That's because code in _cch_rdabuf */
                /* that handles having a partially dirty */
                /* page expects to be able to read the */
                /* data preceding the dirty data */
                gb_rd = 0;
                valid = 0;	/* the page will not be valid */
                setfirst = 1;
            }
            cubuf = _cch_getblk(cch_info, llfio, fileaddr,
                                &numblocks, gb_rd, valid, &locstat);
            if (cubuf == NULL) {
                goto er1;
            }
            if (setfirst) {
                cubuf->firstdata = pgoff;
                if (endoff == 0)
                    cubuf->lastdata = bs;
                else
                    cubuf->lastdata = endoff;
            }

            if (firsteof  && pgoff != 0) {
                /* There is a gap between the eof and */
                /* this data. Zero it if necessary. */
                if ((cubuf->flags & CCH_ZEROED) == 0) {
                    int zbits;
#ifdef CCH_SDS_SUPPORTED
                    if (cch_info->optflags & CCHOPT_SDS) {
                        /* should never happen */
                        ERETURN(stat, FDC_ERR_INTERR, 0);
                    }
#endif
                    if ((eofaddr == fileaddr)) {
                        /* the eof is on this page */

                        zbits = bs - (cch_info->fsize - eofaddr);
                        SET_BPTR(toptr, INC_BPTR(cubuf->buf,
                                                 (cch_info->fsize - eofaddr)));
                    }
                    else {
                        /* the eof is not on this page */
                        /* zero the entire page */
                        zbits = bs;
                        toptr = cubuf->buf;
                    }
                    CCH_MEMCLEAR(toptr, zbits);
                    cubuf->flags |= CCH_ZEROED;
                }
            }
            morebits  = MIN(nbits, bs * numblocks - pgoff);

            /* remember the last buffer page for next time */
            cch_info->cubuf = cubuf + numblocks - 1;
        }
        else {
            morebits	= MIN(nbits, bs - pgoff);

            if (!(cubuf->flags & CCH_VALIDBUFFER)) {
                /* The buffer is there, but it */
                /* is not entirely valid, because */
                /* we never read into it. */
                /* We can continue to just dirty it, */
                /* provided that the dirty part is */
                /* contiguous, and is properly aligned */

                endoff = pgoff + morebits;
                if ((pgoff == cubuf->lastdata &&
                        _CCH_ALIGN(endoff))|| (endoff ==
                                               cubuf->firstdata && _CCH_ALIGN(pgoff))
                        || (pgoff >= cubuf->firstdata &&
                            endoff <=  cubuf->lastdata)) {
                    cubuf->firstdata = MIN(pgoff,
                                           cubuf->firstdata);
                    cubuf->lastdata = MAX(endoff,
                                          cubuf->lastdata);
                    if (cubuf->firstdata == 0 &&
                            cubuf->lastdata == bs) {
                        cubuf->lastdata = 0;
                        cubuf->flags |=CCH_VALIDBUFFER;
                    }
                } else {

                    /* We can't just keep on putting */
                    /* stuff in the buffer without  */
                    /* prereading it. So, we will call */
                    /* _cch_rdabuf, which has the */
                    /* smarts to read only the non-dirty */
                    /* parts */
                    if (_cch_rdabuf(cch_info, llfio, cubuf,
                                    BITS2BYTES(cch_info->bsize),
                                    BITS2BYTES(cubuf->filead), 1, 's',
                                    &locstat)) {
                        goto er1;
                    }
                }
            }
        }

        for (i=0; i<numblocks; i++) {
            /* adjust last access time */
            CCH_CHRONOMETER(cubuf[i],cch_info);
            cubuf[i].flags |= CCH_DIRTY;
        }

        SET_BPTR(toptr, INC_BPTR(cubuf->buf, pgoff));

#ifdef CCH_SDS_SUPPORTED
        if (cch_info->optflags & CCHOPT_SDS) {
            if (_sds_fr_mem(toptr, datptr, morebits) == ERR)
                ERETURN(stat, errno, 0);
        }
        else
            _CCH_MOV_BITS(toptr, datptr, morebits); /* contiguous bufs */
#else
        _CCH_MOV_BITS(toptr, datptr, morebits); /* contiguous bufs */
#endif
adjust:

        SET_BPTR(datptr, INC_BPTR(datptr, morebits));

        cpos  += morebits;
        nbits -= morebits;
        fileaddr = CCHFLOOR(cpos,bs);
        /* bit offset within the file of the page */
        firsteof = 0;
        if (cpos > cch_info->fsize) {
            cch_info->fsize = cpos;
        }
    }
    cch_info->cpos   = cpos;
    moved		 = cpos - olpos;
    fio->recbits	+= moved;


    bytes_moved = BITS2BYTES(moved);
    SETSTAT(stat, FFCNT, bytes_moved);
    return(bytes_moved);
err1_ret:
    ERETURN(stat, err, 0);
er1:
    *stat = locstat;
    return(ERR);
}