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); }
/* * 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); } }
/* * Flush the buffer and clean up * This routine should return 0, or -1 on error. */ ssize_t _tmf_flush(struct fdinfo *fio, struct ffsw *stat) { struct tmfio *xfinfo; ssize_t ret; size_t request; xfinfo = (struct tmfio *)fio->lyr_info; if (xfinfo->tmf_tpos) { if (_tmf_tpwait (xfinfo) < 0) { ERETURN(stat, errno, 0); } } /* * if reading, clear out any unread data in the buffer. */ if (xfinfo->rwflag == READIN) { xfinfo->tmf_bufptr = xfinfo->tmf_base; xfinfo->tmf_cnt = 0; return(0); } /* * In write mode. Write out any uncompleted record. */ request = xfinfo->tmf_cnt; if (xfinfo->rwflag == WRITIN && request != 0) { LOOP_SYSCALL(ret, write(xfinfo->tmf_fd, xfinfo->tmf_base, request)); if (ret != request) { 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, xfinfo->tmf_cnt, xfinfo->tmf_base, ret, stat, &err)) { 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 { if (ret < 0) { ERETURN(stat, errno, 0); } else{ ERETURN(stat, FDC_ERR_WRTERR, ret); } } } xfinfo->tmf_bufptr = xfinfo->tmf_base; xfinfo->tmf_cnt = 0; if (ret == ERR) { ERETURN(stat, errno, 0); } else if (ret < request) { ERETURN(stat, FDC_ERR_WRTERR, 0); } } return(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); }
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); }