📄 tapefslib.c
字号:
) { int status = 0; int blkSize = pTapeFd->tapefd_pTapeVol->tapevd_pSeqDev->sd_blkSize; TAPE_VOL_DESC * pTapeVol = pTapeFd->tapefd_pTapeVol; if (nBytes <= 0) /* This condition should never be true */ return (ERROR); /* If there is no data in the buffer, then read a block into the buffer */ /* Assumption: bufIndex will be 0 only if there is no data in the buffer */ if (pTapeFd->tapefd_bufIndex == 0) { if ((status = tapeFsDevRd (pTapeVol, 1, pTapeFd->tapefd_buffer, FIXED_BLK)) == ERROR) return (ERROR); nBytes *= status; } /* * If there are less bytes to be read than the remainder of the buffer * then simply read these bytes into the specified buffer (pBuf) */ if (nBytes <= (blkSize - pTapeFd->tapefd_bufIndex)) { bcopy (pTapeFd->tapefd_buffer+pTapeFd->tapefd_bufIndex, pBuf, nBytes); pTapeFd->tapefd_bufIndex += nBytes; if (blkSize == pTapeFd->tapefd_bufIndex) pTapeFd->tapefd_bufIndex = 0; /* reset bufIndex */ } /* * If there are more bytes to be read than in the buffer, read the * remainder of the bytes into the specified buffer (pBuf) */ else { nBytes = blkSize - pTapeFd->tapefd_bufIndex; bcopy (pTapeFd->tapefd_buffer+pTapeFd->tapefd_bufIndex, pBuf, nBytes); pTapeFd->tapefd_bufIndex = 0; } /* * Return the number of bytes actually read into the * specified buffer (pBuf) */ return (nBytes); }/********************************************************************************* tapeFsReadyChange - notify tapeFsLib of a change in ready status** This routine sets the volume descriptor state to TAPE_VD_READY_CHANGED.* It should be called whenever a driver senses that a device has come on-line* or gone off-line (for example, that a tape has been inserted or removed).** After this routine has been called, the next attempt to use the volume* results in an attempted remount.** RETURNS: OK if the read change status is set, or ERROR if the file descriptor* is in use.** ERRNO: S_tapeFsLib_FILE_DESCRIPTOR_BUSY*/STATUS tapeFsReadyChange ( TAPE_VOL_DESC *pTapeVol /* pointer to volume descriptor */ ) { FAST TAPE_FILE_DESC *pTapeFd = pTapeVol->tapevd_pTapeFd; semTake (pTapeVol->tapevd_semId, WAIT_FOREVER); /* take control of volume */ if (pTapeFd->tapefd_inUse) { errno = S_tapeFsLib_FILE_DESCRIPTOR_BUSY; semGive (pTapeVol->tapevd_semId); /* release volume */ return (ERROR); } pTapeVol->tapevd_state = TAPE_VD_READY_CHANGED; semGive (pTapeVol->tapevd_semId); /* release volume */ return (OK); }/********************************************************************************* tapeFsVolCheck - verify that volume descriptor is current** This routine is called at the beginning of most operations on* the device. The status field in the volume descriptor is examined,* and the appropriate action is taken. In particular, the tape is* mounted if it is currently unmounted or a ready-change has occurred.** If the tape is already mounted or is successfully mounted as a* result of this routine calling tapeFsVolMount, this routine returns* OK. If the tape cannot be mounted, ERROR is returned.** RETURNS: OK, or ERROR.*/LOCAL STATUS tapeFsVolCheck ( FAST TAPE_VOL_DESC *pTapeVol /* pointer to volume descriptor */ ) { FAST int status; /* return status value */ /* ptr to sequential device */ FAST SEQ_DEV * pSeqDev = pTapeVol->tapevd_pSeqDev; status = OK; /* init return value */ /* Check if device driver announced ready-change */ if (pSeqDev->sd_readyChanged) { pTapeVol->tapevd_state = TAPE_VD_READY_CHANGED; pSeqDev->sd_readyChanged = FALSE; } /* Check volume status */ switch (pTapeVol->tapevd_state) { case TAPE_VD_MOUNTED: /* Tape is already mounted. Do nothing */ break; case TAPE_VD_UNMOUNTED: /* * This case should cause an error because a volume has been * unmounted and a ready-change did not occur since then. */ case TAPE_VD_READY_CHANGED: /* Ready change occurred; try to mount volume */ if (tapeFsVolMount (pTapeVol) != OK) { TAPE_DEBUG_MSG ("tapeFsVolCheck: tapeFsVolMount failed\n", 0,0,0,0,0,0); status = ERROR; /* can't mount */ break; } pTapeVol->tapevd_state = TAPE_VD_MOUNTED; /* volume mounted */ break; /* ready to go as is */ } return (status); /* return status value */ }/********************************************************************************* tapeFsVolMount - prepare to use tape volume** This routine prepares the library to use the tape volume on the device* specified.** This routine should be called every time a tape is changed (i.e. a tape* is swapped, or whatever), or before every open and create, if the driver* can't tell when tape are changed.** RETURNS: OK or ERROR.*/LOCAL STATUS tapeFsVolMount ( FAST TAPE_VOL_DESC *pTapeVol /* pointer to volume descriptor */ ) { /* ptr to sequential device */ FAST SEQ_DEV * pSeqDev = pTapeVol->tapevd_pSeqDev; /* XXX */ pTapeVol->tapevd_status = OK; if (pSeqDev->sd_load != NULL) { if ((*pSeqDev->sd_load) (pSeqDev, TRUE, FALSE, FALSE) != OK) { TAPE_DEBUG_MSG ("tapeFsVolMount: pSeqDev->sd_load failed\n", 0,0,0,0,0,0); return (ERROR); } } else { return (ERROR); } return (OK); }/********************************************************************************* tapeFsVolUnmount - disable a tape device volume** This routine is called when I/O operations on a volume are to be* discontinued. This is commonly done before changing removable tape.* All buffered data for the volume is written to the device (if possible),* any open file descriptors are marked obsolete, and the volume is* marked not mounted.** Because this routine flushes data from memory to the physical* device, it should not be used in situations where the tape-change is* not recognized until after a new tape has been inserted. In these* circumstances, use the ready-change mechanism. (See the manual entry for * tapeFsReadyChange().)** This routine may also be called by issuing an ioctl() call using the* FIOUNMOUNT function code.** RETURNS: OK, or ERROR if the routine cannot access the volume.** ERRNO:* S_tapeFsLib_VOLUME_NOT_AVAILABLE,* S_tapeFsLib_FILE_DESCRIPTOR_BUSY,* S_tapeFsLib_SERVICE_NOT_AVAILABLE** SEE ALSO: tapeFsReadyChange()*/STATUS tapeFsVolUnmount ( FAST TAPE_VOL_DESC *pTapeVol /* pointer to volume descriptor */ ) { /* pointer to file descriptor */ FAST TAPE_FILE_DESC *pTapeFd = pTapeVol->tapevd_pTapeFd; /* pointer to seq device */ FAST SEQ_DEV * pSeqDev = pTapeVol->tapevd_pSeqDev; FAST BOOL failed = FALSE; /* Check that volume is available */ semTake (pTapeVol->tapevd_semId, WAIT_FOREVER);/* get ownership of volume */ if (pTapeVol->tapevd_state == TAPE_VD_UNMOUNTED) { errno = S_tapeFsLib_VOLUME_NOT_AVAILABLE; semGive (pTapeVol->tapevd_semId); /* release volume */ return (ERROR); /* cannot access volume */ } /* Check if the file descriptor is being used. It should be available */ if (pTapeFd->tapefd_inUse == TRUE) { errno = S_tapeFsLib_FILE_DESCRIPTOR_BUSY; semGive (pTapeVol->tapevd_semId); /* release volume */ return (ERROR); /* file descriptor busy */ } /* Unload the volume */ if (pSeqDev->sd_load != NULL) { if ((*pSeqDev->sd_load) (pSeqDev, FALSE, FALSE, FALSE) != OK) failed = TRUE; } else { errno = S_tapeFsLib_SERVICE_NOT_AVAILABLE; failed = TRUE; } semGive (pTapeVol->tapevd_semId); /* release volume */ if (failed) { return (ERROR); /* cannot access volume */ } return (OK); }/********************************************************************************* tapeFsWrite - write to a tape volume** This routine writes to the tape volume specified by the file descriptor* from the specified buffer. If the block containing the tape locations* to be written is already in the file descriptor's read/write buffer,* the buffer won't be flushed. If another in-memory block is needed,* any block already in memory will be flushed.** This routine calls the device driver block-writing routine directly* to write (possibly multiple) whole blocks.** RETURNS: Number of bytes written (error if != maxBytes), or* ERROR if maxBytes < 0, or no more space for the file,* or can't write block.*/LOCAL int tapeFsWrite ( FAST TAPE_FILE_DESC *pTapeFd, /* file descriptor pointer */ char *pBuf, /* data to be written */ int maxBytes /* number of bytes to write */ ) { FAST int nBytes; /* byte count for individual write */ FAST int numBlks; /* number of blocks to write */ /* pointer to vol descriptor */ FAST TAPE_VOL_DESC *pTapeVol = pTapeFd->tapefd_pTapeVol; /* pointer to sequential device info */ FAST SEQ_DEV *pSeqDev = pTapeFd->tapefd_pTapeVol->tapevd_pSeqDev; FAST int bytesLeft; /* remaining bytes to write */ semTake (pTapeVol->tapevd_semId, WAIT_FOREVER); /* take control of volume */ TAPE_DEBUG_MSG ("tapeFsWrite: Device block size is: %d\n", pSeqDev->sd_blkSize, 0,0,0,0,0); /* Check that device was opened for writing */ if (pTapeFd->tapefd_mode == O_RDONLY) { semGive (pTapeVol->tapevd_semId); errno = EROFS; /* posix errno */ TAPE_DEBUG_MSG ("tapeFsWrite: read only volume\n",0,0,0,0,0,0); return (ERROR); } /* Check for valid length of write */ if (maxBytes < 0) { semGive (pTapeVol->tapevd_semId); /* errnoSet (S_tapeFsLib_INVALID_NUMBER_OF_BYTES); */ TAPE_DEBUG_MSG ("tapeFsWrite: maxBytes < 0\n",0,0,0,0,0,0); return (ERROR); } /* Device blockSize and FD buffer size should be identical */ if (pSeqDev->sd_blkSize != pTapeFd->tapefd_bufSize) { semGive (pTapeVol->tapevd_semId); errno = S_tapeFsLib_INVALID_BLOCK_SIZE; TAPE_DEBUG_MSG ("tapeFsWrite: invalid blkSize\n",0,0,0,0,0,0); return (ERROR); } /* Write into successive blocks until all of caller's buffer written */ bytesLeft = maxBytes; /* Variable block write */ if (pSeqDev->sd_blkSize == VARIABLE_BLOCK_SIZE) { while (bytesLeft > 0) { /* Read a variable block upto a maximum size */ nBytes = (bytesLeft > pSeqDev->sd_maxVarBlockLimit) ? pSeqDev->sd_maxVarBlockLimit : bytesLeft; if (tapeFsBlkWrt (pTapeVol, nBytes, pBuf, VARIABLE_BLK) != OK) goto writeFailed; bytesLeft -= nBytes; pBuf += nBytes; } semGive (pTapeVol->tapevd_semId); /* release volume */ return (maxBytes - bytesLeft); } /* Fixed block write */ while (bytesLeft > 0) { nBytes = 0; /* init individual write count*/ /* Do direct whole-block write if possible */ if ((bytesLeft >= pSeqDev->sd_blkSize) && (pTapeFd->tapefd_bufIndex == 0)) { /* Calculate starting block and number to write */ numBlks = bytesLeft / pSeqDev->sd_blkSize; /* Write as many blocks as possible */ if (tapeFsBlkWrt (pTapeVol, numBlks, pBuf, FIXED_BLK) != OK) goto writeFailed; nBytes = numBlks * pSeqDev->sd_blkSize; } /* Handle partially written blocks with buffering */ else { if ((nBytes = tapeFsPartWrt (pTapeFd, pBuf, bytesLeft)) == ERROR) break; } pBuf += nBytes; bytesLeft -= nBytes; } semGive (pTapeVol->tapevd_semId); /* release volume */ return (maxBytes - bytesLeft); /* return actual copy count */writeFailed: semGive (pTapeVol->tapevd_semId); TAPE_DEBUG_MSG ("tapeFsWrite: write failed \n",0,0,0,0,0,0); return (ERROR); }/********************************************************************************* tapeFsPartWrt - write a partial tape block ** This routine writes to the tape volume specified by the file descriptor* from the specified buffer. The partial block data is written into a * buffer, until that buffer is full and at that point the full buffer is* written to tape.** This routine calls the device driver block-writing routine directly* to write (possibly) a whole block.** RETURNS: Number of bytes written (error if != maxBytes), or* ERROR if maxBytes < 0, or no more space for the file,* or can't write block.*/LOCAL int tapeFsPartWrt ( TAPE_FILE_DESC * pTapeFd, /* pointer to a tape file descriptor */ char * pBuf, /* pointer to data buffer */ int nBytes /* number of partial block bytes to write */ ) { int blkSize = pTapeFd->tapefd_pTapeVol->tapevd_pSeqDev->sd_blkSize; TAPE_VOL_DESC * pTapeVol = pTapeFd->tapefd_pTapeVol; /* * If there are less bytes to be written than the remainder of the * buffered block, write those bytes to the buffer. */ if (nBytes <= (blkSize - pTapeFd->tapefd_bufIndex)) { bcopy (pBuf, pTapeFd->tapefd_buffer + pTapeFd->tapefd_bufIndex, nBytes); pTapeFd->tapefd_bufIndex += nBytes; /* * If the entire block is filled, write out the block and reset the * bufIndex. */ if (pTapeFd->tapefd_bufIndex == blkSize) { if (tapeFsBlkWrt (pTapeVol, 1, pTapeFd->tapefd_buffer, FIXED_BLK) != OK) return (ERROR); pTapeFd->tapefd_bufIndex = 0; } } /* * If there are more bytes to be written than the remainder of the * buffered block, write until block is full and then write that full block * out to tape. */ else { nBytes = blkSize - pTapeFd->tapefd_bufIndex; bcopy (pBuf, pTapeFd->tapefd_buffer + pTapeFd->tapefd_bufIndex, nBytes); if (tapeFsBlkWrt (pTapeVol, 1, pTapeFd->tapefd_buffer, FIXED_BLK) != OK) return (ERROR); pTapeFd->tapefd_bufIndex = 0; } /* Return the number of bytes actually written to buffer or tape */ return (nBytes); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -