tapeFsLib.c
上传用户:nvosite88
上传日期:2007-01-17
资源大小:4983k
文件大小:59k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* tapeFsLib.c - tape sequential device file system library */
  2. /* Copyright 1984-1995 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 01f,21feb99,jdi  doc: listed errnos.
  8. 01e,06mar97,dds  SPR 8120: fixed tapeFsRead to return the actual number
  9.                  of bytes read, 0 if end of file, or ERROR.
  10. 01d,29oct96,dgp  doc: editing for newly published SCSI libraries
  11. 01c,08may96,jds  more doc changes
  12. 01b,01may96,jds  doc changes
  13. 01a,17jul95,jds  written
  14. */
  15. /*
  16. This library provides basic services for tape devices that do not
  17. use a standard file or directory structure on tape.  The tape volume is treated
  18. much like a large file. The tape may either be read or written. However, there
  19. is no high-level organization of the tape into files or directories, 
  20. which must be provided by a higher-level layer.
  21. USING THIS LIBRARY
  22. The various routines provided by the VxWorks tape file system, or tapeFs, can
  23. be categorized into three broad groupings: general initialization,
  24. device initialization, and file system operation.
  25. The tapeFsInit() routine is the principal general initialization function;
  26. it needs to be called only once, regardless of how many tapeFs devices
  27. are used.
  28. To initialize devices, tapeFsDevInit() must be called for each tapeFs device.
  29. Use of this library typically occurs through standard use of the I/O system
  30. routines open(), close(), read(), write() and ioctl().  Besides these 
  31. standard I/O system operations, several routines are provided to inform the 
  32. file system of changes in the system environment.  
  33. The tapeFsVolUnmount() routine informs the file system that a particular 
  34. device should be unmounted; any synchronization should be done prior to 
  35. invocation of this routine, in preparation for a tape volume change. 
  36. The tapeFsReadyChange() routine is used to inform the file system that a
  37. tape may have been swapped and that the next tape operation should first
  38. remount the tape. Information about a ready-change is also obtained from the 
  39. driver using the SEQ_DEV device structure. Note that tapeFsVolUnmount() and
  40. tapeFsReadyChange() should be called only after a file has been closed.
  41. INITIALIZATION OF THE FILE SYSTEM
  42. Before any other routines in tapeFsLib can be used, tapeFsInit() 
  43. must be called to initialize the library. This implementation
  44. of the tape file system assumes only one file descriptor per volume. However,
  45. this constraint can be changed in case a future implementation demands
  46. multiple file descriptors per volume.
  47. During the tapeFsInit() call, the tape device library is installed as a driver
  48. in the I/O system driver table.  The driver number associated with it is
  49. then placed in a global variable, `tapeFsDrvNum'.
  50. To enable this initialization, define INCLUDE_TAPEFS in the BSP, or simply 
  51. start using the tape file system with a call to tapeFsDevInit() and 
  52. tapeFsInit() will be called automatically if it has not been called before. 
  53. DEFINING A TAPE DEVICE
  54. To use this library for a particular device, the device structure
  55. used by the device driver must contain, as the very first item, a
  56. sequential device description structure (SEQ_DEV).  The SEQ_DEV must be 
  57. initialized before calling tapeFsDevInit(). The driver places in the SEQ_DEV 
  58. structure the addresses of routines that it must supply:  one that reads one
  59. or more blocks, one that writes one or more blocks, one that performs
  60. I/O control (ioctl()) on the device, one that writes file marks on a tape, 
  61. one that rewinds the tape volume, one that reserves a tape device for use,
  62. one that releases a tape device after use, one that mounts/unmounts a volume,
  63. one that spaces forward or backwards by blocks or file marks, one that erases
  64. the tape, one that resets the tape device, and one that checks 
  65. the status of the device.
  66. The SEQ_DEV structure also contains fields that describe the physical 
  67. configuration of the device.  For more information about defining sequential
  68. devices, see the 
  69. .I "VxWorks Programmer's Guide: I/O System."
  70. INITIALIZATION OF THE DEVICE 
  71. The tapeFsDevInit() routine is used to associate a device with the tapeFsLib
  72. functions.  The `volName' parameter expected by tapeFsDevInit() is a pointer to
  73. a name string which identifies the device.  This string serves as
  74. the pathname for I/O operations which operate on the device and  
  75. appears in the I/O system device table, which can be displayed
  76. using iosDevShow().
  77. The `pSeqDev' parameter expected by tapeFsDevInit() is a pointer
  78. to the SEQ_DEV structure describing the device and containing the
  79. addresses of the required driver functions.  
  80. The `pTapeConfig' parameter is a pointer to a TAPE_CONFIG structure that 
  81. contains information specifying how the tape device should be configured. The 
  82. configuration items are fixed/variable block size, rewind/no-rewind device,
  83. and number of file marks to be written. For more information about the 
  84. TAPE_CONFIG structure, look at the header file tapeFsLib.h. 
  85. The syntax of the tapeFsDevInit() routine is as follows:
  86. .CS
  87.     tapeFsDevInit
  88. (
  89. char *        volName,     /@ name to be used for volume   @/
  90. SEQ_DEV *     pSeqDev,     /@ pointer to device descriptor @/
  91. TAPE_CONFIG * pTapeConfig  /@ pointer to tape config info  @/
  92. )
  93. .CE
  94. When tapeFsLib receives a request from the I/O system, after tapeFsDevInit()
  95. has been called, it calls the device driver routines (whose addresses were
  96. passed in the SEQ_DEV structure) to access the device.
  97. OPENING AND CLOSING A FILE
  98. A tape volume is opened by calling the I/O system routine open(). A file can
  99. be opened only with the O_RDONLY or O_WRONLY flags. The O_RDWR mode is not 
  100. used by this library. A call to
  101. open() initializes the file descriptor buffer and state information, reserves
  102. the tape device, rewinds the tape device if it was configured as a rewind
  103. device, and mounts a volume. Once a tape volume has been opened, that tape
  104. device is reserved, disallowing any other system from accessing that device 
  105. until the tape volume is closed. Also, the single file descriptor is marked
  106. "in use" until the file is closed, making sure that a file descriptor is
  107. not opened multiple times.
  108. A tape device is closed by calling the I/O system routine close(). Upon a 
  109. close() request, any unwritten
  110. buffers are flushed, the device is rewound (if it is a rewind device), and, 
  111. finally, the device is released.
  112. UNMOUNTING VOLUMES (CHANGING TAPES)
  113. A tape volume should be unmounted before it is removed.  When unmounting a 
  114. volume, make sure that any open file is closed first.
  115. A tape may be unmounted by calling tapeFsVolUnmount() directly.
  116. If a file is open, it is not correct to change the medium and continue with 
  117. the same file descriptor still open.
  118. Since tapeFs assumes only one file descriptor per device, to reuse 
  119. that device, the file must be closed and opened later for the new tape volume.
  120. Before tapeFsVolUnmount() is called, the device should be synchronized by 
  121. invoking the ioctl() FIOSYNC or FIOFLUSH. It is the responsibility
  122. of the higher-level layer to synchronize the tape file system before 
  123. unmounting. Failure to synchronize the volume before unmounting may result
  124. in loss of data.
  125. IOCTL FUNCTIONS
  126. The VxWorks tape sequential device file system supports the following ioctl()
  127. functions.  The functions listed are defined in the header files ioLib.h and 
  128. tapeFsLib.h.
  129. .iP "FIOFLUSH" 16 3
  130. Writes all modified file descriptor buffers to the physical device.
  131. .CS
  132.     status = ioctl (fd, FIOFLUSH, 0);
  133. .CE
  134. .iP "FIOSYNC"
  135. Performs the same function as FIOFLUSH.
  136. .iP "FIOBLKSIZEGET"
  137. Returns the value of the block size set on the physical device. This value
  138. is compared against the 'sd_blkSize' value set in the SEQ_DEV device structure.
  139. .iP "FIOBLKSIZESET"
  140. Sets a specified block size value on the physical device and also updates the
  141. value in the SEQ_DEV and TAPE_VOL_DESC structures, unless the supplied value
  142. is zero, in which case the device structures are updated but the device 
  143. is not set to zero. This is because zero implies variable block operations,
  144. therefore the device block size is ignored.
  145. .iP "MTIOCTOP"
  146. Allows use of the standard UNIX MTIO `ioctl' operations
  147. by means of the MTOP structure. The MTOP structure appears as follows:
  148. .CS
  149. typedef struct mtop
  150.     {
  151.     short       mt_op;                  /@ operation @/
  152.     int         mt_count;               /@ number of operations @/
  153.     } MTOP;
  154. .CE
  155. Use these ioctl() operations as follows:
  156. .CS
  157.     MTOP mtop;
  158.     mtop.mt_op    = MTWEOF;
  159.     mtop.mt_count = 1;
  160.     status = ioctl (fd, MTIOCTOP, (int) &mtop);
  161. .CE
  162. .LP
  163. The permissable values for 'mt_op' are:
  164. .iP "MTWEOF"
  165. Writes an end-of-file record to tape. An end-of-file record is a file mark.
  166. .iP "MTFSF"
  167. Forward space over a file mark and position the tape head in the gap between
  168. the file mark just skipped and the next data block.
  169. Any buffered data is flushed out to the tape if the tape is in write
  170. mode.
  171. .iP "MTBSF"
  172. Backward space over a file mark and position the tape head in the gap 
  173. preceeding the file mark, that is, right before the file mark.
  174. Any buffered data is flushed out to the tape if the tape is in write
  175. mode.
  176. .iP "MTFSR"
  177. Forward space over a data block and position the tape head in the gap between
  178. the block just skipped and the next block.
  179. Any buffered data is flushed out to the tape if the tape is in write
  180. mode.
  181. .iP "MTBSR"
  182. Backward space over a data block and position the tape head right before the
  183. block just skipped.
  184. Any buffered data is flushed out to the tape if the tape is in write
  185. mode.
  186. .iP "MTREW"
  187. Rewind the tape to the beginning of the medium.
  188. Any buffered data is flushed out to the tape if the tape is in write
  189. mode.
  190. .iP "MTOFFL"
  191. Rewind and unload the tape.
  192. Any buffered data is flushed out to the tape if the tape is in write
  193. mode.
  194. .iP "MTNOP"
  195. No operation, but check the status of the device, thus setting the appropriate
  196. SEQ_DEV fields.
  197. .iP "MTRETEN"
  198. Retension the tape. This command usually sets tape tension and can be
  199. used in either read or write mode.
  200. Any buffered data is flushed out to tape if the tape is in write
  201. mode.
  202. .iP "MTERASE"
  203. Erase the entire tape and rewind it.
  204. .iP "MTEOM"
  205. Position the tape at the end of the medium and unload the tape.
  206. Any buffered data is flushed out to the tape if the tape is in write
  207. mode.
  208. INCLUDE FILES: tapeFsLib.h
  209. SEE ALSO: ioLib, iosLib,
  210. .pG "I/O System, Local File Systems"
  211. */
  212. #include "vxWorks.h"
  213. #include "ctype.h"
  214. #include "ioLib.h"
  215. #include "lstLib.h"
  216. #include "stdlib.h"
  217. #include "string.h"
  218. #include "semLib.h"
  219. #include "errnoLib.h"
  220. #include "logLib.h"
  221. #include "tapeFsLib.h"
  222. /* GLOBALS */
  223. int  tapeDebug = FALSE;
  224. #define TAPE_DEBUG_MSG if (tapeDebug) 
  225.             logMsg
  226. int  tapeFsDrvNum   = NONE;    /* I/O system driver number for tapeFsLib */
  227. /* default mutex options */
  228. int tapeFsVolMutexOptions    = (SEM_Q_PRIORITY | SEM_DELETE_SAFE);
  229. /* forward static functions */
  230. LOCAL int        tapeFsDevRd (TAPE_VOL_DESC * pTapeVol, UINT numBlks, 
  231. char * pBuf, BOOL fixed);
  232. LOCAL STATUS        tapeFsBlkWrt (TAPE_VOL_DESC * pTapeVol, int numBlks, 
  233. char * pBuf, BOOL fixed);
  234. LOCAL STATUS        tapeFsClose (TAPE_FILE_DESC * pTapeFd);
  235. LOCAL STATUS        tapeFsFdFlush (TAPE_FILE_DESC * pTapeFd);
  236. LOCAL STATUS        tapeFsIoctl (TAPE_FILE_DESC * pTapeFd, int function, 
  237. int arg);
  238. LOCAL int        tapeFsRead (TAPE_FILE_DESC * pTapeFd, char * pBuf, 
  239. UINT maxBytes);
  240. LOCAL int         tapeFsPartWrt (TAPE_FILE_DESC * pTapeFd, char * pBuf, 
  241. int nBytes);
  242. LOCAL STATUS        tapeFsVolCheck (TAPE_VOL_DESC * pTapeVol);
  243. LOCAL STATUS        tapeFsVolMount (TAPE_VOL_DESC * pTapeVol);
  244. LOCAL int        tapeFsWrite (TAPE_FILE_DESC * pTapeFd, char * pBuf,
  245. int maxBytes);
  246. LOCAL int         tapeFsPartRd (TAPE_FILE_DESC * pTapeFd, char * pBuf, 
  247. UINT nBytes);
  248. LOCAL STATUS         mtOpHandle (FAST TAPE_FILE_DESC * pTapeFd, int op, 
  249. int numOps);
  250. LOCAL TAPE_FILE_DESC * tapeFsOpen (TAPE_VOL_DESC * pTapeVol, char * name, 
  251. int flags, int mode);
  252. /*******************************************************************************
  253. *
  254. * tapeFsDevRd - read blocks or bytes from a tape volume
  255. *
  256. * This routine reads the specified block or bytes from the specified volume.
  257. *
  258. * RETURNS: Number of bytes or blocks read, 0 if EOF, or error
  259. */
  260. LOCAL int tapeFsDevRd
  261.     (
  262.     FAST TAPE_VOL_DESC * pTapeVol,      /* pointer to volume descriptor      */
  263.     UINT                 numDataUnits,  /* how many (blocks | bytes) to read */
  264.     FAST char *          pBuf,          /* buffer to receive block           */
  265.     BOOL  fixed         /* FIXED_BLK or VARIABLE_BLK read    */
  266.     )
  267.     {
  268.     /* Pointer to sequential device struct */
  269.     
  270.     SEQ_DEV *pSeqDev = pTapeVol->tapevd_pSeqDev;
  271.     
  272.     if (pSeqDev->sd_seqRd == NULL)
  273. {
  274. errno = S_tapeFsLib_SERVICE_NOT_AVAILABLE;
  275. return (ERROR);
  276. }
  277.     
  278.     /* Try to read the data once */
  279.     return ((* pSeqDev->sd_seqRd) (pSeqDev, numDataUnits, pBuf, fixed));
  280.     }
  281. /*******************************************************************************
  282. *
  283. * tapeFsBlkWrt - write block(s) to a tape volume
  284. *
  285. * This routine writes the specified blocks to the specified volume.
  286. *
  287. * RETURNS:
  288. * OK, or
  289. * ERROR, if write error. 
  290. */
  291. LOCAL STATUS tapeFsBlkWrt
  292.     (
  293.     FAST TAPE_VOL_DESC * pTapeVol,      /* pointer to volume descriptor       */
  294.     int                  numDataUnits,  /* how many (blocks | bytes) to write */
  295.     char *               pBuf,          /* pointer to buffer to write to tape */
  296.     BOOL          fixed /* FIXED_BLK or VARIABLE_BLK write    */
  297.     )
  298.     {
  299.     /* Pointer to sequential device struct */
  300.     FAST SEQ_DEV *pSeqDev = pTapeVol->tapevd_pSeqDev;
  301.     if (pSeqDev->sd_seqWrt == NULL)
  302. {
  303. errno = S_tapeFsLib_SERVICE_NOT_AVAILABLE;
  304. return (ERROR);
  305. }
  306.     /* Try to write the data once */
  307.     if (((* pSeqDev->sd_seqWrt) (pSeqDev, numDataUnits, pBuf, fixed)) != OK)
  308.         return (ERROR);
  309.     return (OK);
  310.     }
  311. /*******************************************************************************
  312. *
  313. * tapeFsClose - close tape volume
  314. *
  315. * This routine closes the specified tape volume file descriptor.  Any
  316. * buffered data for the descriptor is written to the physical device.
  317. *
  318. * If the file descriptor has been marked as obsolete (meaning the
  319. * volume was unmounted while the descriptor was open), the descriptor
  320. * is freed, but an error is returned.
  321. *
  322. * RETURNS: OK, or ERROR.
  323. */
  324. LOCAL STATUS tapeFsClose
  325.     (
  326.     FAST TAPE_FILE_DESC  *pTapeFd         /* file descriptor pointer */
  327.     )
  328.     {
  329.     FAST STATUS          status;
  330.     /* Pointer to volume descriptor */
  331.     FAST TAPE_VOL_DESC * pTapeVol = pTapeFd->tapefd_pTapeVol;
  332.     /* Pointer to sequential device */
  333.     FAST SEQ_DEV *       pSeqDev  = pTapeVol->tapevd_pSeqDev;
  334.     semTake (pTapeVol->tapevd_semId, WAIT_FOREVER); /* get ownership of vol */
  335.     /* Write out file descriptor buffer, if WRONLY mode and fixed block */
  336.     if ((pTapeFd->tapefd_mode == O_WRONLY) && (pTapeVol->tapevd_blkSize > 0))
  337. {
  338.         if (tapeFsFdFlush (pTapeFd) != OK)
  339.     goto closeFailed;
  340. }
  341.     /* Rewind if neccessary */
  342.     if (pTapeVol->tapevd_rewind)
  343. {
  344. if (pSeqDev->sd_rewind == NULL)
  345.     goto closeFailed;
  346. if ((*(pSeqDev->sd_rewind)) (pSeqDev) != OK)
  347.     goto closeFailed;
  348. }
  349.     /* Release the device */
  350.     if (pSeqDev->sd_release == NULL)
  351. goto closeFailed;
  352.     status = (*(pSeqDev->sd_release)) (pSeqDev);
  353.     
  354.     pTapeFd->tapefd_bufSize = 0; /* disable buffer        */
  355.     pTapeFd->tapefd_inUse   = FALSE; /* fd not in use anymore */
  356.     semGive (pTapeVol->tapevd_semId); /* release volume        */
  357.     free (pTapeFd->tapefd_buffer); /* free file I/O buffer  */
  358.     return (status);
  359. closeFailed:
  360.     semGive (pTapeVol->tapevd_semId); /* release volume */
  361.     return (ERROR);
  362.     }
  363. /*******************************************************************************
  364. *
  365. * tapeFsDevInit - associate a sequential device with tape volume functions
  366. *
  367. * This routine takes a sequential device created by a device driver and
  368. * defines it as a tape file system volume.  As a result, when high-level 
  369. * I/O operations, such as open() and write(), are performed on the
  370. * device, the calls will be routed through tapeFsLib.
  371. *
  372. * This routine associates `volName' with a device and installs it in
  373. * the VxWorks I/O system-device table.  The driver number used when
  374. * the device is added to the table is that which was assigned to the
  375. * tape library during tapeFsInit().  (The driver number is kept in
  376. * the global variable `tapeFsDrvNum'.)
  377. *
  378. * The SEQ_DEV structure specified by `pSeqDev' contains configuration
  379. * data describing the device and the addresses of the routines which
  380. * are called to read blocks, write blocks, write file marks, reset the 
  381. * device, check device status, perform other I/O control functions (ioctl()),
  382. * reserve and release devices, load and unload devices, and rewind devices.
  383. * These routines are not called until they are required by subsequent I/O
  384. * operations.  The TAPE_CONFIG structure is used to define configuration
  385. * parameters for the TAPE_VOL_DESC.  The configuration parameters are defined
  386. * and described in tapeFsLib.h.
  387. *
  388. * INTERNAL
  389. * The semaphore in the device is given, so the device is available for
  390. * use immediately.
  391. *
  392. * RETURNS: A pointer to the volume descriptor (TAPE_VOL_DESC),
  393. * or NULL if there is an error.
  394. *
  395. * ERRNO: S_tapeFsLib_NO_SEQ_DEV, S_tapeFsLib_ILLEGAL_TAPE_CONFIG_PARM
  396. */
  397. TAPE_VOL_DESC *tapeFsDevInit
  398.     (
  399.     char *             volName,     /* volume name                       */
  400.     FAST SEQ_DEV *     pSeqDev,     /* pointer to sequential device info */
  401.     FAST TAPE_CONFIG * pTapeConfig /* pointer to tape config info       */
  402.     )
  403.     {
  404.     FAST TAPE_VOL_DESC * pTapeVol; /* pointer to new volume descriptor */
  405.     /* Initialise the tape file system if it has not been initialised before */
  406.     if (tapeFsDrvNum == NONE)
  407.  tapeFsInit ();
  408.     /* Return error if no SEQ_DEV */
  409.     if (pSeqDev == NULL)
  410. {
  411. errno = S_tapeFsLib_NO_SEQ_DEV;
  412. TAPE_DEBUG_MSG ("tapeFsDevInit: pSeqDev nulln",0,0,0,0,0,0);
  413. return (NULL);
  414. }
  415.     /* Check configuration parameters */
  416.     if ((pTapeConfig->blkSize < 0) /* XXX || blkSize > some MAX*/)
  417. {
  418. errno = S_tapeFsLib_ILLEGAL_TAPE_CONFIG_PARM;
  419. TAPE_DEBUG_MSG ("tapeFsDevInit: blkSize < 0n",0,0,0,0,0,0);
  420. return (NULL);
  421. }
  422.     if (pTapeConfig->numFileMarks < 0)
  423. {
  424. errno = S_tapeFsLib_ILLEGAL_TAPE_CONFIG_PARM; 
  425. TAPE_DEBUG_MSG ("tapeFsDevInit: numFileMarks < 0n",0,0,0,0,0,0);
  426. return (NULL);
  427. }
  428.     if ((pTapeConfig->rewind != TRUE) && (pTapeConfig->rewind != FALSE))
  429. {
  430. errno = S_tapeFsLib_ILLEGAL_TAPE_CONFIG_PARM;
  431. TAPE_DEBUG_MSG ("tapeFsDevInit: rewind flag wrongn",0,0,0,0,0,0);
  432. return (NULL);
  433. }
  434.     /* Allocate a tape volume descriptor for device */
  435.     if ((pTapeVol = (TAPE_VOL_DESC *) calloc 
  436. (sizeof (TAPE_VOL_DESC), 1)) == NULL)
  437. return (NULL); /* no memory */
  438.     TAPE_DEBUG_MSG ("tapeFsDevInit: pTapeVol is %xn",(int)pTapeVol,0,0,0,0,0);
  439.     /* Create volume locking semaphore (initially available) */
  440.     pTapeVol->tapevd_semId = semMCreate (tapeFsVolMutexOptions);
  441.     if (pTapeVol->tapevd_semId == NULL)
  442. {
  443. free ((char *) pTapeVol);
  444. return (NULL); /* could not create semaphore */
  445. }
  446.     /* Allocate a File Descriptor (FD) for this volume */
  447.     pTapeVol->tapevd_pTapeFd = (TAPE_FILE_DESC *) calloc 
  448.   (sizeof (TAPE_FILE_DESC), 1);
  449.     if (pTapeVol->tapevd_pTapeFd == NULL) 
  450. {
  451. free ((char *) pTapeVol);
  452. return (NULL); /* could not allocate FD */
  453. }
  454.     /* Add device to system device table */
  455.     if (iosDevAdd ((DEV_HDR *) pTapeVol, volName, tapeFsDrvNum) != OK)
  456. {
  457. TAPE_DEBUG_MSG ("tapeFsDevInit: iosDevAdd errorn",0,0,0,0,0,0);
  458. free ((char *) pTapeVol->tapevd_pTapeFd);
  459. free ((char *) pTapeVol);
  460. return (NULL); /* can't add device */
  461. }
  462.     /* Initialize volume descriptor */
  463.     pTapeVol->tapevd_pSeqDev      = pSeqDev;
  464.     pTapeVol->tapevd_status   = OK;
  465.     pTapeVol->tapevd_state   = TAPE_VD_READY_CHANGED;
  466.     pTapeVol->tapevd_rewind   = pTapeConfig->rewind;
  467.     pTapeVol->tapevd_blkSize   = pTapeConfig->blkSize;
  468.     pTapeVol->tapevd_numFileMarks = pTapeConfig->numFileMarks;
  469.     pTapeVol->tapevd_density      = pTapeConfig->density;
  470.     pSeqDev->sd_blkSize           = pTapeConfig->blkSize;
  471.     /* File descriptor initialization */
  472.     pTapeVol->tapevd_pTapeFd->tapefd_inUse = FALSE;
  473.     return (pTapeVol);
  474.     }
  475. /*******************************************************************************
  476. *
  477. * tapeFsFdFlush - flush tape volume file descriptor I/O buffer to tape
  478. *
  479. * This routine causes the I/O buffer of a tape volume file descriptor
  480. * to be written out to the physical device. It is assumed that the volume
  481. * is of fixed block type.
  482. *
  483. * Note: This function should only be called for file descriptors opened with
  484. *       the O_WRONLY mode
  485. *
  486. * RETURNS: OK, or ERROR if something could not be written out.
  487. */
  488. LOCAL STATUS tapeFsFdFlush
  489.     (
  490.     FAST TAPE_FILE_DESC  *pTapeFd         /* pointer to file descriptor */
  491.     )
  492.     {
  493.     FAST int     index   = pTapeFd->tapefd_bufIndex;  /* buffer index */
  494.     /* ptr to sequential device */
  495.     FAST SEQ_DEV * pSeqDev = pTapeFd->tapefd_pTapeVol->tapevd_pSeqDev;
  496.     /* seq device block Size */
  497.     FAST int    blkSize = pSeqDev->sd_blkSize;
  498.     if (pTapeFd->tapefd_bufIndex != 0)
  499. {
  500. /* Pad partial blocks with zeros */
  501. bzero (pTapeFd->tapefd_buffer + index, blkSize - index); 
  502. /* Write out the current (dirty) block */
  503. if (tapeFsBlkWrt (pTapeFd->tapefd_pTapeVol, 1,
  504.        pTapeFd->tapefd_buffer, TRUE) != OK)
  505.     return (ERROR); /* write error */
  506. /* Reset the buffer index so as to invalidate the buffer */
  507. pTapeFd->tapefd_bufIndex = 0;
  508. }
  509.     return (OK);
  510.     }
  511. /*******************************************************************************
  512. *
  513. * tapeFsInit - initialize the tape volume library
  514. *
  515. * This routine initializes the tape volume library.  It must be called exactly
  516. * once, before any other routine in the library. Only one file descriptor
  517. * per volume is assumed. 
  518. *
  519. * This routine also installs tape volume library routines in the VxWorks I/O
  520. * system driver table.  The driver number assigned to tapeFsLib is placed in
  521. * the global variable `tapeFsDrvNum'.  This number is later associated
  522. * with system file descriptors opened to tapeFs devices.
  523. *
  524. * To enable this initialization, simply call the routine tapeFsDevInit(), which
  525. * automatically calls tapeFsInit() in order to initialize the tape file system.
  526. *
  527. * RETURNS: OK or ERROR.
  528. */
  529. STATUS tapeFsInit ()
  530.     {
  531.     /*
  532.      * Install tapeFsLib routines in I/O system driver table
  533.      * Note: there is no delete routine, and that the
  534.      *       tapeFsOpen routine is also used as the create function.
  535.      */
  536.     tapeFsDrvNum = iosDrvInstall ((FUNCPTR) tapeFsOpen, (FUNCPTR) NULL,
  537.          (FUNCPTR) tapeFsOpen, tapeFsClose,
  538.          tapeFsRead, tapeFsWrite, tapeFsIoctl);
  539.     if (tapeFsDrvNum == ERROR)
  540. return (ERROR); /* can't install as driver */
  541.     return (OK);
  542.     }
  543. /*******************************************************************************
  544. *
  545. * tapeFsIoctl - perform a device-specific control function
  546. *
  547. * This routine performs the following ioctl() functions:
  548. *
  549. * .CS
  550. *    MTIOCTOP       - Perform all UNIX MTIO operations. Use the MTIO structure
  551. *        to pass the correct operation and operation count.
  552. *    FIOSYNC       - Write all modified file descriptor buffers to device.
  553. *    FIOFLUSH        - Same as FIOSYNC.
  554. *    FIOBLKSIZESET   - Set the device block size (0 implies variable blocks)
  555. *    FIOBLKSIZEGET   - Get the device block size and compare with tapeFs value
  556. * .CE
  557. *
  558. * If the ioctl (`function') is not one of the above, the device driver
  559. * ioctl() routine is called to perform the function.
  560. *
  561. * If an ioctl() call fails, the task status (see errnoGet()) indicates
  562. * the nature of the error.
  563. *
  564. * RETURNS: OK, or ERROR if function failed or unknown function, or
  565. * current byte pointer for FIOWHERE.
  566. */
  567. LOCAL STATUS tapeFsIoctl
  568.     (
  569.     FAST TAPE_FILE_DESC * pTapeFd,      /* file descriptor of file to control */
  570.     int                   function,     /* function code                      */
  571.     int                   arg           /* some argument                      */
  572.     )
  573.     {
  574.     FAST STATUS status; /* return status value        */
  575.     FAST TAPE_VOL_DESC *pTapeVol = pTapeFd->tapefd_pTapeVol;
  576.     FAST SEQ_DEV *     pSeqDev  = pTapeVol->tapevd_pSeqDev;
  577.     FAST MTOP * pMtOp    = (MTOP *) arg;   /* ptr to operation struct */
  578.     switch (function)
  579. {
  580. case MTIOCTOP:
  581.     /* Handle MTIO MTIOCTOP operations */
  582.     status = mtOpHandle (pTapeFd, pMtOp->mt_op, pMtOp->mt_count);
  583.             break;
  584.         
  585.         case FIOFLUSH:
  586.         case FIOSYNC:
  587.             /* Check if the file mode is correct */
  588.             if (pTapeFd->tapefd_mode == O_RDONLY)
  589.                 {
  590.                 errno = EROFS; /* posix errno */
  591.                 status = ERROR;
  592.                 break;
  593.                 }
  594.             /* Flush any buffered data */
  595.             status = tapeFsFdFlush (pTapeFd);  /* errno set by lower layer */
  596.             break;
  597.         case FIOBLKSIZESET:
  598.             
  599.     if (pSeqDev->sd_ioctl == NULL)
  600.                 {
  601.                 errno = S_tapeFsLib_SERVICE_NOT_AVAILABLE;
  602. status = ERROR;
  603.                 break;
  604. }
  605.     
  606.     if (arg != 0) /* Variable block size */
  607. {
  608.         /* Call driver's ioctl routine with function and arg */
  609.         status = (*pSeqDev->sd_ioctl) (pSeqDev, function, arg);
  610. }
  611.             else
  612. status = OK;
  613.     if (status == ERROR)
  614. break; /* do not modify any device structs */
  615.     /* Set the block Size in the tapeFs device structures */
  616.             pTapeVol->tapevd_blkSize = arg;
  617.     pSeqDev->sd_blkSize      = arg;
  618.             break;
  619.         case FIOBLKSIZEGET:
  620.             if (pSeqDev->sd_ioctl == NULL)
  621.                 {
  622.                 errno = S_tapeFsLib_SERVICE_NOT_AVAILABLE;
  623.                 status = ERROR;
  624.                 break;
  625.                 }
  626.    
  627.             /* Perform an FIOBLKSIZEGET ioctl on the driver */
  628.             status = (*pSeqDev->sd_ioctl) (pSeqDev, function, arg);
  629.             /*
  630.              * If an ERROR was not returned, then the value returned is a 
  631.              * valid block size, and this value should be compared with
  632.              * that set in the device and volume structures.
  633.              */
  634.             if ((status != ERROR) && (pSeqDev->sd_blkSize != 0))
  635.                 {
  636.                 if  ( (pSeqDev->sd_blkSize != status) || 
  637.                       (pTapeVol->tapevd_blkSize != status)
  638.                     )
  639.                     {
  640.                     errno = S_tapeFsLib_BLOCK_SIZE_MISMATCH;
  641.                     status = ERROR;
  642.                     break;
  643.                     }
  644.                 }
  645.             break;
  646. default:
  647.     if (pSeqDev->sd_ioctl == NULL)
  648.                 {
  649.                 errno = S_tapeFsLib_SERVICE_NOT_AVAILABLE;
  650. status = ERROR;
  651.                 break;
  652. }
  653.     
  654.     /* Call driver's ioctl routine with function and arg */
  655.     status = (*pSeqDev->sd_ioctl) (pSeqDev, function, arg);
  656.             break;
  657. } /* switch */
  658.         return (status);
  659.     }
  660. /*******************************************************************************
  661. *
  662. * mtOpHandle - Handles MTIOCTOP type ioctl operations
  663. *
  664. * This routine performs the following ioctl() functions:
  665. *
  666. * MTWEOF - write an end-of-file record 
  667. * MTFSF - forward space over file mark 
  668. * MTBSF - backward space over file mark 
  669. * MTFSR - forward space to inter-record gap 
  670. * MTBSR - backward space to inter-record gap 
  671. * MTREW - rewind 
  672. * MTOFFL - rewind and put the drive offline
  673. * MTNOP - no operation, sets status only
  674. * MTRETEN - retension the tape (use for cartridge tape only)
  675. * MTERASE - erase the entire tape
  676. * MTEOM - position to end of media
  677. * MTNBSF - backward space file to BOF
  678. *
  679. * If the ioctl (`function') is not one of the above, the device driver
  680. * ioctl() routine is called to perform the function.
  681. *
  682. * If an ioctl() call fails, the task status (see errnoGet()) indicates
  683. * the nature of the error.
  684. *
  685. * RETURNS: OK, or ERROR if function failed or unknown function, or
  686. * current byte pointer for FIOWHERE.
  687. */
  688. LOCAL STATUS mtOpHandle
  689.     (
  690.     FAST TAPE_FILE_DESC * pTapeFd,    /* file descriptor of file to control */
  691.     int                   op,         /* function code                      */
  692.     int                   numOps      /* some argument                      */
  693.     )
  694.     {
  695.     FAST TAPE_VOL_DESC *pTapeVol = pTapeFd->tapefd_pTapeVol;
  696.     FAST SEQ_DEV *     pSeqDev  = pTapeVol->tapevd_pSeqDev;
  697.     /* Perform requested function */
  698.     switch (op)
  699. {
  700. /* Write an end-of-file record, which means: write a file mark */
  701. case MTWEOF:
  702.     /* Check if the file mode is correct */
  703.     if (pTapeFd->tapefd_mode == O_RDONLY)
  704. {
  705.                 errno = EROFS; /* posix errno */
  706. return (ERROR);
  707. }
  708.     /* Flush any buffered data */
  709.     if (tapeFsFdFlush (pTapeFd) == ERROR)
  710. {
  711. return (ERROR);
  712. }
  713.     if (pSeqDev->sd_seqWrtFileMarks == NULL)
  714. {
  715.                 errno = S_tapeFsLib_SERVICE_NOT_AVAILABLE;
  716. return (ERROR);
  717. }
  718.             /* Write "numOps" number of short file marks */
  719.             if ((*pSeqDev->sd_seqWrtFileMarks) (pSeqDev, numOps, TRUE)
  720.       == ERROR)
  721.                 {
  722. return (ERROR);
  723. }
  724.     
  725.     pTapeFd->tapefd_bufIndex = 0;
  726.     return (OK);
  727.         /* Forward space over a file mark */
  728. case MTFSF:     
  729.     if (pTapeFd->tapefd_mode != O_RDONLY)
  730. {
  731.         /* Flush any buffered data */
  732.         if (tapeFsFdFlush (pTapeFd) == ERROR)
  733.          {
  734.     return (ERROR);
  735.     }
  736. }
  737.     if (pSeqDev->sd_space == NULL)
  738. {
  739.                 errno = S_tapeFsLib_SERVICE_NOT_AVAILABLE;
  740. return (ERROR);
  741. }
  742.             /* Space forward "numOps" file marks */
  743.     if ((*pSeqDev->sd_space) (pSeqDev, numOps, SPACE_CODE_FILEMARK)
  744.       == ERROR)
  745.                 {
  746. return (ERROR);
  747. }
  748.     pTapeFd->tapefd_bufIndex = 0;
  749.     return (OK);
  750.     
  751.         /* Backward space over a file mark */
  752. case MTBSF:
  753.     if (pTapeFd->tapefd_mode != O_RDONLY)
  754. {
  755.         /* Flush any buffered data */
  756.         if (tapeFsFdFlush (pTapeFd) == ERROR)
  757.          {
  758.     return (ERROR);
  759.     }
  760. }
  761.     if (pSeqDev->sd_space == NULL)
  762. {
  763.         errno = S_tapeFsLib_SERVICE_NOT_AVAILABLE;
  764. return (ERROR);
  765. }
  766.             /* Space backward "numOps" file marks */
  767.     if ((*pSeqDev->sd_space) (pSeqDev, -numOps, SPACE_CODE_FILEMARK)
  768.       == ERROR)
  769.                 {
  770. return (ERROR);
  771. }
  772.     pTapeFd->tapefd_bufIndex = 0;     
  773.     return (OK);
  774.     
  775. /* Forward space to inter-record gap (data blocks) */
  776. case MTFSR:
  777.     if (pTapeFd->tapefd_mode != O_RDONLY)
  778. {
  779.         /* Flush any buffered data */
  780.         if (tapeFsFdFlush (pTapeFd) == ERROR)
  781.          {
  782.     return (ERROR);
  783.     }
  784. }
  785.     if (pSeqDev->sd_space == NULL)
  786. {
  787. errno = S_tapeFsLib_SERVICE_NOT_AVAILABLE;
  788. return (ERROR);
  789. }
  790.             /* Space forward "numOps" data blocks */
  791.     if ((*pSeqDev->sd_space) (pSeqDev, numOps, SPACE_CODE_DATABLK)
  792.       == ERROR)
  793.                 {
  794. return (ERROR);
  795. }
  796.     
  797.     pTapeFd->tapefd_bufIndex = 0;
  798.     return (OK);
  799.     
  800. /* Backward space to inter-record gap (data blocks) */
  801.         case MTBSR:
  802.     if (pTapeFd->tapefd_mode != O_RDONLY)
  803. {
  804.         /* Flush any buffered data */
  805.         if (tapeFsFdFlush (pTapeFd) == ERROR)
  806.          {
  807.     return (ERROR);
  808.     }
  809. }
  810.     if (pSeqDev->sd_space == NULL)
  811. {
  812. errno = S_tapeFsLib_SERVICE_NOT_AVAILABLE;
  813. return (ERROR);
  814. }
  815.             /* Space backward "numOps" data blocks */
  816.     if ((*pSeqDev->sd_space) (pSeqDev, -numOps, SPACE_CODE_DATABLK)
  817.       == ERROR)
  818.                 {
  819. return (ERROR);
  820. }
  821.     pTapeFd->tapefd_bufIndex = 0;     
  822.     return (OK);
  823.     
  824. /* Rewind the tape device */
  825. case MTREW:
  826.     if (pTapeFd->tapefd_mode != O_RDONLY)
  827. {
  828.         /* Flush any buffered data */
  829.         if (tapeFsFdFlush (pTapeFd) == ERROR)
  830.          {
  831.     return (ERROR);
  832.     }
  833. }
  834.     if (pSeqDev->sd_rewind == NULL)
  835. {
  836. errno = S_tapeFsLib_SERVICE_NOT_AVAILABLE;
  837. return (ERROR);
  838. }
  839.             /* Rewind the tape device */
  840.     if ((*pSeqDev->sd_rewind) (pSeqDev) == ERROR)
  841.                 {
  842. return (ERROR);
  843. }
  844.     pTapeFd->tapefd_bufIndex = 0;     
  845.     return (OK);
  846.     
  847.         /* Rewind and take the device offline */
  848. case MTOFFL:
  849.     if (pTapeFd->tapefd_mode != O_RDONLY)
  850. {
  851.         /* Flush any buffered data */
  852.         if (tapeFsFdFlush (pTapeFd) == ERROR)
  853.          {
  854.     return (ERROR);
  855.     }
  856. }
  857.     if ((pSeqDev->sd_rewind == NULL) || (pSeqDev->sd_load == NULL))
  858. {
  859. errno = S_tapeFsLib_SERVICE_NOT_AVAILABLE;
  860. return (ERROR);
  861. }
  862.             /* Rewind the tape device */
  863.     if ((*pSeqDev->sd_rewind) (pSeqDev) == ERROR)
  864.                 {
  865. return (ERROR);
  866. }
  867.     pTapeFd->tapefd_bufIndex = 0;     
  868.     /* Take it offline by unloading the device */
  869.     if ((*pSeqDev->sd_load) (pSeqDev, UNLOAD, FALSE, FALSE) == ERROR)
  870.                 {
  871. return (ERROR);
  872. }
  873.     
  874.     return (OK);
  875.         /* No operation on device, simply sets the status */
  876. case MTNOP:
  877.     if (pSeqDev->sd_statusChk == NULL)
  878. {
  879. errno = S_tapeFsLib_SERVICE_NOT_AVAILABLE;
  880. return (ERROR);
  881. }
  882.             /* Check device status (driver sets the status in SEQ_DEV) */
  883.     if ((*pSeqDev->sd_statusChk) (pSeqDev) == ERROR)
  884.                 {
  885. return (ERROR);
  886. }
  887.     
  888.     return (OK);
  889.     
  890. /* Retension the tape */
  891. case MTRETEN:
  892.     if (pTapeFd->tapefd_mode != O_RDONLY)
  893. {
  894.         /* Flush any buffered data */
  895.         if (tapeFsFdFlush (pTapeFd) == ERROR)
  896.          {
  897.     return (ERROR);
  898.     }
  899. }
  900.     if (pSeqDev->sd_load == NULL)
  901.                 {
  902. errno = S_tapeFsLib_SERVICE_NOT_AVAILABLE;
  903. return (ERROR);
  904. }
  905.     
  906.     /* Take it offline by unloading the device */
  907.     if ((*pSeqDev->sd_load) (pSeqDev, UNLOAD, RETEN, FALSE) == ERROR)
  908.                 {
  909. return (ERROR);
  910. }
  911.     
  912.     pTapeFd->tapefd_bufIndex = 0;
  913.     return (OK);
  914.         /* Erase the entire tape and rewind */
  915. case MTERASE:
  916.     if (pSeqDev->sd_erase == NULL)
  917.                 {
  918. errno = S_tapeFsLib_SERVICE_NOT_AVAILABLE;
  919. return (ERROR);
  920. }
  921.     
  922.     /* Take it offline by unloading the device */
  923.     if ((*pSeqDev->sd_erase) (pSeqDev, LONG) == ERROR)
  924.                 {
  925. return (ERROR);
  926. }
  927.     pTapeFd->tapefd_bufIndex = 0;     
  928.     return (OK);
  929.         /* Position the tape at the end-of-medium before unloading */
  930. case MTEOM:
  931.     if (pTapeFd->tapefd_mode != O_RDONLY)
  932. {
  933.         /* Flush any buffered data */
  934.         if (tapeFsFdFlush (pTapeFd) == ERROR)
  935.          {
  936.     return (ERROR);
  937.     }
  938. }
  939.     if (pSeqDev->sd_load == NULL)
  940.                 {
  941. errno = S_tapeFsLib_SERVICE_NOT_AVAILABLE;
  942. return (ERROR);
  943. }
  944.     
  945.     /* Take it offline by unloading the device */
  946.     if ((*pSeqDev->sd_load) (pSeqDev, UNLOAD, FALSE, EOT) == ERROR)
  947.                 {
  948. return (ERROR);
  949. }
  950.     pTapeFd->tapefd_bufIndex = 0;     
  951.     return (OK);
  952.         /* Backward space file to beginning of file */
  953.         /* XXX Not sure how this is different that MTBSF 1 */
  954.         case MTNBSF:
  955.     return (ERROR);
  956.         /* Any other operation is an error */
  957.         default:
  958.     return (ERROR);
  959.         } /* switch */
  960.     }
  961. /*******************************************************************************
  962. *
  963. * tapeFsOpen - open a tape volume
  964. *
  965. * This routine opens the volume with the specified mode
  966. * (O_RDONLY or O_WRONLY).
  967. *
  968. * The specified `name' must be a null string, indicating that the
  969. * caller specified only the device name during open(). This is because
  970. * there is no file structure on the tape device.
  971. *
  972. * If the device driver supplies a status-check routine, it will be
  973. * called before the volume state is examined.
  974. *
  975. * RETURNS: Pointer to tape volume file descriptor, or ERROR.
  976. */
  977. LOCAL TAPE_FILE_DESC *tapeFsOpen
  978.     (
  979.     FAST TAPE_VOL_DESC * pTapeVol,      /* pointer to volume descriptor      */
  980.     FAST char *          name,      /* "file" name - should be empty str */
  981.     FAST int             flags,         /* open flags                        */
  982.     FAST int  mode /* not used                          */
  983.     )
  984.     {
  985.                                         /* file descriptor pointer */
  986.     FAST TAPE_FILE_DESC *pTapeFd = pTapeVol->tapevd_pTapeFd;
  987. /* pointer to block device info */
  988.     FAST SEQ_DEV *pSeqDev = pTapeVol->tapevd_pSeqDev;
  989.     UINT16          unused;
  990.     /* Check for open of other than tape volume (non-null filename) */
  991.     if (name [0] != EOS)
  992. {
  993. errno = S_tapeFsLib_ILLEGAL_FILE_SYSTEM_NAME; 
  994. return ((TAPE_FILE_DESC *) ERROR); /* cannot specify filename */
  995. }
  996.     /* check the open flags for read only or write only */
  997.     if ((flags != O_RDONLY) && (flags != O_WRONLY))
  998. {
  999. errno = S_tapeFsLib_ILLEGAL_FLAGS; 
  1000. TAPE_DEBUG_MSG ("tapeFsOpen: Wrong Tape Moden", 0,0,0,0,0,0);
  1001. return ((TAPE_FILE_DESC *) ERROR); /* cannot specify filename */
  1002. }
  1003.     /* Get ownership of volume. If taken, return ERROR */
  1004.     if (semTake (pTapeVol->tapevd_semId, NO_WAIT) == ERROR)
  1005. {
  1006. errno = EBUSY;   /* posix errno */
  1007. TAPE_DEBUG_MSG ("tapeFsOpen: Could not get Semaphoren", 0,0,0,0,0,0);
  1008.         return ((TAPE_FILE_DESC *) ERROR);
  1009. }
  1010.     /* Check if file descriptor is in use */
  1011.     if (pTapeFd->tapefd_inUse == TRUE)
  1012. {
  1013.         errno = S_tapeFsLib_FILE_DESCRIPTOR_BUSY;
  1014. semGive (pTapeVol->tapevd_semId); /* release volume         */
  1015. return ((TAPE_FILE_DESC *) ERROR); /* file descriptor in use */
  1016. }
  1017.     /* Call driver check-status routine, if any */
  1018.     if (pSeqDev->sd_statusChk != NULL)
  1019. {
  1020. if ((* pSeqDev->sd_statusChk) (pSeqDev) != OK)
  1021.     {
  1022.     semGive (pTapeVol->tapevd_semId);
  1023.     TAPE_DEBUG_MSG ("tapeFsOpen: statusChk failedn", 0,0,0,0,0, 0);
  1024.     return ((TAPE_FILE_DESC *) ERROR); /* driver returned error */
  1025.     }
  1026. }
  1027.     /* Check for read-only volume opened for write/update */
  1028.     if ((pSeqDev->sd_mode == O_RDONLY)  && (flags == O_WRONLY ))
  1029. {
  1030. errno = S_ioLib_WRITE_PROTECTED;
  1031. semGive (pTapeVol->tapevd_semId);
  1032. TAPE_DEBUG_MSG ("tapeFsOpen: write protected. sd_mode is %xn", 
  1033.     pSeqDev->sd_mode,0,0,0,0, 0);
  1034. return ((TAPE_FILE_DESC *) ERROR); /* volume not writable */
  1035. }
  1036.     /* fill in the rest of the tape volume fields */
  1037.     pTapeFd->tapefd_mode    = flags;
  1038.     pTapeFd->tapefd_pTapeVol    = pTapeVol;
  1039.     /* Check that volume is available */
  1040.     if (tapeFsVolCheck (pTapeVol) != OK)
  1041. {
  1042. semGive (pTapeVol->tapevd_semId);
  1043. errno = S_tapeFsLib_VOLUME_NOT_AVAILABLE;
  1044. TAPE_DEBUG_MSG ("tapeFsOpen: volume not availablen", 0,0,0,0,0, 0);
  1045. return ((TAPE_FILE_DESC *) ERROR); /* cannot access volume */
  1046. }
  1047.     /* 
  1048.      * Reserve the tape device for exclusive use unitl the file is closed.
  1049.      * When the file is closed, the device should be released. Reserving the
  1050.      * device disallows any other host from accessing the tape device.
  1051.      */
  1052.     if ((*pSeqDev->sd_reserve) (pSeqDev) != OK)
  1053. {
  1054. semGive (pTapeVol->tapevd_semId);
  1055. TAPE_DEBUG_MSG ("tapeFsOpen: reserve unit failedn", 0,0,0,0,0, 0);
  1056. return ((TAPE_FILE_DESC *) ERROR);  /* driver returned error */
  1057. }
  1058.     /* mount a tape device if not already mounted */
  1059.     
  1060.     if (pTapeVol->tapevd_state != TAPE_VD_MOUNTED)
  1061. {
  1062. if ((*pSeqDev->sd_load) (pSeqDev, LOAD, FALSE, FALSE) != OK)
  1063.     {
  1064.     semGive (pTapeVol->tapevd_semId);
  1065.     TAPE_DEBUG_MSG ("tapeFsOpen: mount failedn", 0,0,0,0,0, 0);
  1066.     return ((TAPE_FILE_DESC *) ERROR);  /* driver returned error */
  1067.     }
  1068.         }
  1069.     /* rewind if it is a rewind device */
  1070.     if (pTapeVol->tapevd_rewind)
  1071. {
  1072. if ((*pSeqDev->sd_rewind) (pSeqDev) != OK)
  1073.     {
  1074.     semGive (pTapeVol->tapevd_semId);
  1075.     TAPE_DEBUG_MSG ("tapeFsOpen: rewind failedn", 0,0,0,0,0, 0);
  1076.     return ((TAPE_FILE_DESC *) ERROR);  /* driver returned error */
  1077.     }
  1078. }
  1079.     /* Read block limits */
  1080.     if (pSeqDev->sd_readBlkLim != NULL)
  1081. {
  1082. if ((*pSeqDev->sd_readBlkLim) (pSeqDev, &pSeqDev->sd_maxVarBlockLimit,
  1083.        &unused) != OK)
  1084.     {
  1085.     semGive (pTapeVol->tapevd_semId);
  1086.     TAPE_DEBUG_MSG ("tapeFsOpen: readBlkLim failedn", 0,0,0,0,0, 0);
  1087.     return ((TAPE_FILE_DESC *) ERROR);  /* driver returned error */
  1088.     }
  1089. }
  1090.     /* Allocate a 1 block buffer for short reads/writes if fixed block */
  1091.     if (pSeqDev->sd_blkSize != 0)
  1092. {
  1093.         pTapeFd->tapefd_buffer = (char *) calloc 
  1094. ((unsigned) pSeqDev->sd_blkSize, 1);
  1095.         if (pTapeFd->tapefd_buffer == NULL)
  1096.          {
  1097.             semGive (pTapeVol->tapevd_semId); /* release volume */
  1098.     TAPE_DEBUG_MSG ("tapeFsOpen: calloc failedn", 0,0,0,0,0, 0);
  1099.     return ((TAPE_FILE_DESC *) ERROR); /* mem alloc error */
  1100.     }
  1101.         pTapeFd->tapefd_bufSize = pSeqDev->sd_blkSize;
  1102.         }
  1103.     pTapeFd->tapefd_inUse = TRUE; /* fd in use      */
  1104.     semGive (pTapeVol->tapevd_semId); /* release volume */
  1105.     return (pTapeFd);
  1106.     }
  1107. /*******************************************************************************
  1108. *
  1109. * tapeFsRead - read from a tape volume
  1110. *
  1111. * This routine reads from the volume specified by the file descriptor
  1112. * (returned by tapeFsOpen()) into the specified buffer.
  1113. * `maxbytes' bytes will be read, if there is that much data in the file.
  1114. *
  1115. * RETURNS: Number of bytes actually read, 0 if end of file, or ERROR.
  1116. */
  1117. LOCAL int tapeFsRead
  1118.     (
  1119.     FAST TAPE_FILE_DESC * pTapeFd,      /* file descriptor pointer          */
  1120.     char                * pBuf,         /* addr of input buffer             */
  1121.     UINT                  maxBytes      /* count of data units to read      */
  1122.     )
  1123.     {
  1124.     int bytesLeft; /* count of remaining bytes to read */
  1125.     int dataCount; /* count of remaining bytes to read */
  1126.     int bytesRead; /* count of bytes read              */
  1127.     int blocksRead; /* count of bytes read              */
  1128.     int nBytes; /* byte count from individual read  */
  1129.     int numBytes; /* byte count from individual read  */
  1130.     int numBlks; /* number of blocks to read         */
  1131.     
  1132.     /* pointer to vol descriptor        */
  1133.     TAPE_VOL_DESC *pTapeVol = pTapeFd->tapefd_pTapeVol;
  1134.     
  1135.     /* pointer to sequential device     */
  1136.     SEQ_DEV *pSeqDev = pTapeFd->tapefd_pTapeVol->tapevd_pSeqDev;
  1137.     
  1138.     /* take control of volume */
  1139.     semTake (pTapeVol->tapevd_semId, WAIT_FOREVER); 
  1140.     
  1141.     TAPE_DEBUG_MSG ("tapeFsRead: Device block size is: %dn",
  1142.     pSeqDev->sd_blkSize, 0,0,0,0,0);
  1143.     
  1144.     /* Check for valid length of read */
  1145.     
  1146.     if (maxBytes <= 0)
  1147. {
  1148. semGive (pTapeVol->tapevd_semId);
  1149. errno =  S_tapeFsLib_INVALID_NUMBER_OF_BYTES;
  1150. return (ERROR);
  1151. }
  1152.     
  1153.     /* Check that device was opened for reading */
  1154.     
  1155.     if (pTapeFd->tapefd_mode == O_WRONLY)
  1156.         {
  1157.      semGive (pTapeVol->tapevd_semId);
  1158.     /* errnoSet (S_tapeFsLib_READ_ONLY); */
  1159.      return (ERROR);
  1160.      }
  1161.     
  1162.     /* Do successive reads until requested byte count or EOF */
  1163.     
  1164.     bytesLeft  = maxBytes; /* init number bytes remaining     */
  1165.     dataCount  = maxBytes;
  1166.     
  1167.     /* Variable block read */
  1168.     
  1169.     if (pSeqDev->sd_blkSize == VARIABLE_BLOCK_SIZE)
  1170. {
  1171. while (dataCount > 0)
  1172.     {
  1173.     /* Read a variable block upto a maximum size */
  1174.     
  1175.     nBytes = (bytesLeft > pSeqDev->sd_maxVarBlockLimit) ?
  1176.      pSeqDev->sd_maxVarBlockLimit  : bytesLeft;
  1177.     
  1178.             if ((bytesRead = tapeFsDevRd (pTapeVol, nBytes, pBuf, 
  1179.   VARIABLE_BLK)) == ERROR)
  1180. break;  /* do nothing, may not be an error */
  1181.     
  1182.             dataCount -= nBytes;
  1183.             bytesLeft -= bytesRead;
  1184.     pBuf      += bytesRead;
  1185.     }
  1186.         semGive (pTapeVol->tapevd_semId);           /* release volume */
  1187.         return (maxBytes - bytesLeft);              /* number of bytes read */
  1188.      }
  1189.     
  1190.     /* Fixed block read */
  1191.     
  1192.     while (dataCount > 0)
  1193. {
  1194. nBytes = 0; /* init individual read count */
  1195.      /* 
  1196.  * Do direct whole-block read, if the data is more than a blocks worth
  1197.  * and the FD buffer is empty.
  1198.  */
  1199.      if ((dataCount >= pSeqDev->sd_blkSize) &&
  1200.     (pTapeFd->tapefd_bufIndex == 0))
  1201.     {
  1202.             /* calculate number of blocks to read */
  1203.     
  1204.     numBlks = dataCount / pSeqDev->sd_blkSize;
  1205.     
  1206.     /* Read as many blocks as possible */
  1207.     
  1208.     if ((blocksRead = tapeFsDevRd (pTapeVol, numBlks, pBuf, FIXED_BLK))
  1209. == ERROR)
  1210.           break;
  1211.     
  1212.     numBytes = numBlks * pSeqDev->sd_blkSize;
  1213.     
  1214.     /* calculate the number of bytes read */
  1215.     
  1216.     nBytes = blocksRead * pSeqDev->sd_blkSize;
  1217.     }
  1218.         /* Handle partially read blocks (buffered) */
  1219.      else /* if not whole-block transfer */
  1220.     {
  1221.     if (pTapeFd->tapefd_bufIndex != 0)
  1222.         numBytes =  pSeqDev->sd_blkSize - pTapeFd->tapefd_bufIndex;
  1223.     else 
  1224.         numBytes = dataCount;
  1225.     
  1226.     if ((nBytes = tapeFsPartRd (pTapeFd, pBuf, dataCount)) == ERROR)
  1227. break;
  1228.     }
  1229. /* Adjust count remaining, buffer pointer, and file pointer */
  1230. dataCount -= numBytes;
  1231. bytesLeft -= nBytes;
  1232. pBuf      += nBytes;
  1233. }
  1234.     
  1235.     semGive (pTapeVol->tapevd_semId); /* release volume */
  1236.     return (maxBytes - bytesLeft);   /* number of bytes read */
  1237.     }
  1238. /*******************************************************************************
  1239. *
  1240. * tapeFsPartRd - read a partial tape block
  1241. *
  1242. * This routine reads from a tape volume specified by the file descriptor,
  1243. * to the specified buffer. When a partial block needs to be read, the entire
  1244. * block is first read into the file descriptor buffer and then the desired
  1245. * portion is copied into the specified buffer. If the number of bytes to be
  1246. * read is more than that in the buffer then only the number of bytes left
  1247. * in the buffer are read.
  1248. *
  1249. * This routine calls the device driver block-reading routine directly
  1250. * to read (possibly) a whole block.
  1251. *
  1252. * RETURNS: Number of bytes read (error if != maxBytes), or
  1253. * ERROR if maxBytes < 0, or can't read block.
  1254. */
  1255. LOCAL int tapeFsPartRd
  1256.     (
  1257.     TAPE_FILE_DESC * pTapeFd,   /* pointer to a tape file descriptor      */
  1258.     char *           pBuf,      /* pointer to data buffer                 */
  1259.     UINT             nBytes     /* number of partial bytes to read        */
  1260.     )
  1261.     {
  1262.     int         status = 0;
  1263.     int  blkSize = pTapeFd->tapefd_pTapeVol->tapevd_pSeqDev->sd_blkSize;
  1264.     TAPE_VOL_DESC * pTapeVol = pTapeFd->tapefd_pTapeVol;
  1265.     
  1266.     
  1267.     if (nBytes <= 0)  /* This condition should never be true */
  1268. return (ERROR);
  1269.     
  1270.     /* If there is no data in the buffer, then read a block into the buffer */
  1271.     /* Assumption: bufIndex will be 0 only if there is no data in the buffer */
  1272.     
  1273.     if (pTapeFd->tapefd_bufIndex == 0)
  1274. {
  1275. if ((status = tapeFsDevRd (pTapeVol, 1, pTapeFd->tapefd_buffer, 
  1276.    FIXED_BLK)) == ERROR)
  1277.     return (ERROR);
  1278. nBytes *= status;
  1279.         }
  1280.     
  1281.     /*
  1282.      * If there are less bytes to be read than the remainder of the buffer
  1283.      * then simply read these bytes into the specified buffer (pBuf)
  1284.      */
  1285.     if (nBytes <= (blkSize - pTapeFd->tapefd_bufIndex))
  1286.         {
  1287.         bcopy (pTapeFd->tapefd_buffer+pTapeFd->tapefd_bufIndex, pBuf, nBytes);
  1288. pTapeFd->tapefd_bufIndex += nBytes;
  1289. if (blkSize == pTapeFd->tapefd_bufIndex)
  1290.     pTapeFd->tapefd_bufIndex = 0; /* reset bufIndex */
  1291. }
  1292.     
  1293.     /*
  1294.      * If there are more bytes to be read than in the buffer, read the 
  1295.      * remainder of the bytes into the specified buffer (pBuf)
  1296.      */
  1297.     
  1298.     else
  1299. {
  1300.         nBytes = blkSize - pTapeFd->tapefd_bufIndex;
  1301. bcopy (pTapeFd->tapefd_buffer+pTapeFd->tapefd_bufIndex, pBuf, nBytes);
  1302. pTapeFd->tapefd_bufIndex = 0;
  1303. }
  1304.     /*
  1305.      * Return the number of bytes actually read into the 
  1306.      * specified buffer (pBuf)
  1307.      */
  1308.     
  1309.     return (nBytes);
  1310.     }
  1311. /*******************************************************************************
  1312. *
  1313. * tapeFsReadyChange - notify tapeFsLib of a change in ready status
  1314. *
  1315. * This routine sets the volume descriptor state to TAPE_VD_READY_CHANGED.
  1316. * It should be called whenever a driver senses that a device has come on-line
  1317. * or gone off-line (for example, that a tape has been inserted or removed).
  1318. *
  1319. * After this routine has been called, the next attempt to use the volume
  1320. * results in an attempted remount.
  1321. *
  1322. * RETURNS: OK if the read change status is set, or ERROR if the file descriptor
  1323. * is in use.
  1324. *
  1325. * ERRNO: S_tapeFsLib_FILE_DESCRIPTOR_BUSY
  1326. */
  1327. STATUS tapeFsReadyChange
  1328.     (
  1329.     TAPE_VOL_DESC *pTapeVol         /* pointer to volume descriptor */
  1330.     )
  1331.     {
  1332.     FAST TAPE_FILE_DESC *pTapeFd = pTapeVol->tapevd_pTapeFd;
  1333.     semTake (pTapeVol->tapevd_semId, WAIT_FOREVER); /* take control of volume */
  1334.     if (pTapeFd->tapefd_inUse)
  1335. {
  1336.         errno = S_tapeFsLib_FILE_DESCRIPTOR_BUSY;
  1337.         semGive (pTapeVol->tapevd_semId); /* release volume */
  1338. return (ERROR);
  1339. }
  1340.     pTapeVol->tapevd_state = TAPE_VD_READY_CHANGED;
  1341.     semGive (pTapeVol->tapevd_semId); /* release volume */
  1342.     return (OK);
  1343.     }
  1344. /*******************************************************************************
  1345. *
  1346. * tapeFsVolCheck - verify that volume descriptor is current
  1347. *
  1348. * This routine is called at the beginning of most operations on
  1349. * the device.  The status field in the volume descriptor is examined,
  1350. * and the appropriate action is taken.  In particular, the tape is
  1351. * mounted if it is currently unmounted or a ready-change has occurred.
  1352. *
  1353. * If the tape is already mounted or is successfully mounted as a
  1354. * result of this routine calling tapeFsVolMount, this routine returns
  1355. * OK.  If the tape cannot be mounted, ERROR is returned.
  1356. *
  1357. * RETURNS: OK, or ERROR.
  1358. */
  1359. LOCAL STATUS tapeFsVolCheck
  1360.     (
  1361.     FAST TAPE_VOL_DESC   *pTapeVol          /* pointer to volume descriptor   */
  1362.     )
  1363.     {
  1364.     FAST int status; /* return status value      */
  1365. /* ptr to sequential device */
  1366.     FAST SEQ_DEV * pSeqDev = pTapeVol->tapevd_pSeqDev;
  1367.     status = OK; /* init return value */
  1368.     /* Check if device driver announced ready-change */
  1369.     if (pSeqDev->sd_readyChanged)
  1370. {
  1371. pTapeVol->tapevd_state   = TAPE_VD_READY_CHANGED;
  1372. pSeqDev->sd_readyChanged = FALSE;
  1373. }
  1374.     /* Check volume status */
  1375.     switch (pTapeVol->tapevd_state)
  1376. {
  1377. case TAPE_VD_MOUNTED:
  1378.     /* Tape is already mounted. Do nothing */
  1379.     break;
  1380.         case TAPE_VD_UNMOUNTED:
  1381.             /*
  1382.      * This case should cause an error because a volume has been 
  1383.      * unmounted and a ready-change did not occur since then.
  1384.              */
  1385. case TAPE_VD_READY_CHANGED:
  1386.     /* Ready change occurred; try to mount volume */
  1387.     if (tapeFsVolMount (pTapeVol) != OK)
  1388. {
  1389. TAPE_DEBUG_MSG ("tapeFsVolCheck: tapeFsVolMount failedn",
  1390. 0,0,0,0,0,0);
  1391. status = ERROR; /* can't mount */
  1392. break;
  1393. }
  1394.     pTapeVol->tapevd_state = TAPE_VD_MOUNTED; /* volume mounted */
  1395.     break; /* ready to go as is */
  1396. }
  1397.     return (status); /* return status value */
  1398.     }
  1399. /*******************************************************************************
  1400. *
  1401. * tapeFsVolMount - prepare to use tape volume
  1402. *
  1403. * This routine prepares the library to use the tape volume on the device
  1404. * specified.
  1405. *
  1406. * This routine should be called every time a tape is changed (i.e. a tape
  1407. * is swapped, or whatever), or before every open and create, if the driver
  1408. * can't tell when tape are changed.
  1409. *
  1410. * RETURNS: OK or ERROR.
  1411. */
  1412. LOCAL STATUS tapeFsVolMount
  1413.     (
  1414.     FAST TAPE_VOL_DESC   *pTapeVol          /* pointer to volume descriptor */
  1415.     )
  1416.     {
  1417. /* ptr to sequential device */
  1418.     FAST SEQ_DEV * pSeqDev = pTapeVol->tapevd_pSeqDev;
  1419.    /* XXX */
  1420.     pTapeVol->tapevd_status = OK;
  1421.     if (pSeqDev->sd_load != NULL)
  1422. {
  1423.         if ((*pSeqDev->sd_load) (pSeqDev, TRUE, FALSE, FALSE) != OK)
  1424.     {
  1425.             TAPE_DEBUG_MSG ("tapeFsVolMount: pSeqDev->sd_load failedn",
  1426. 0,0,0,0,0,0);
  1427.          return (ERROR);
  1428.     }
  1429.         }
  1430.     else
  1431. {
  1432. return (ERROR);
  1433. }
  1434.     return (OK);
  1435.     }
  1436. /*******************************************************************************
  1437. *
  1438. * tapeFsVolUnmount - disable a tape device volume
  1439. *
  1440. * This routine is called when I/O operations on a volume are to be
  1441. * discontinued.  This is commonly done before changing removable tape.
  1442. * All buffered data for the volume is written to the device (if possible),
  1443. * any open file descriptors are marked obsolete, and the volume is
  1444. * marked not mounted.
  1445. *
  1446. * Because this routine flushes data from memory to the physical
  1447. * device, it should not be used in situations where the tape-change is
  1448. * not recognized until after a new tape has been inserted.  In these
  1449. * circumstances, use the ready-change mechanism.  (See the manual entry for 
  1450. * tapeFsReadyChange().)
  1451. *
  1452. * This routine may also be called by issuing an ioctl() call using the
  1453. * FIOUNMOUNT function code.
  1454. *
  1455. * RETURNS: OK, or ERROR if the routine cannot access the volume.
  1456. *
  1457. * ERRNO:
  1458. * S_tapeFsLib_VOLUME_NOT_AVAILABLE,
  1459. * S_tapeFsLib_FILE_DESCRIPTOR_BUSY,
  1460. * S_tapeFsLib_SERVICE_NOT_AVAILABLE
  1461. *
  1462. * SEE ALSO: tapeFsReadyChange()
  1463. */
  1464. STATUS tapeFsVolUnmount
  1465.     (
  1466.     FAST TAPE_VOL_DESC   *pTapeVol      /* pointer to volume descriptor */
  1467.     )
  1468.     {
  1469. /* pointer to file descriptor   */
  1470.     FAST TAPE_FILE_DESC *pTapeFd = pTapeVol->tapevd_pTapeFd;
  1471. /* pointer to seq device        */
  1472.     FAST SEQ_DEV *  pSeqDev = pTapeVol->tapevd_pSeqDev;
  1473.     FAST BOOL  failed  = FALSE;
  1474.     /* Check that volume is available */
  1475.     semTake (pTapeVol->tapevd_semId, WAIT_FOREVER);/* get ownership of volume */
  1476.     if (pTapeVol->tapevd_state == TAPE_VD_UNMOUNTED)
  1477.         {
  1478.         errno = S_tapeFsLib_VOLUME_NOT_AVAILABLE;
  1479.         semGive (pTapeVol->tapevd_semId); /* release volume */
  1480.         return (ERROR); /* cannot access volume */
  1481.         }
  1482.     /* Check if the file descriptor is being used. It should be available */
  1483.     if (pTapeFd->tapefd_inUse == TRUE)
  1484.         {
  1485.         errno = S_tapeFsLib_FILE_DESCRIPTOR_BUSY;
  1486.         semGive (pTapeVol->tapevd_semId); /* release volume */
  1487.         return (ERROR); /* file descriptor busy */
  1488.         }
  1489.     /* Unload the volume */
  1490.     if (pSeqDev->sd_load != NULL)
  1491. {
  1492. if ((*pSeqDev->sd_load) (pSeqDev, FALSE, FALSE, FALSE) != OK)
  1493.     failed = TRUE;
  1494.         }
  1495.     else
  1496.         {
  1497.         errno = S_tapeFsLib_SERVICE_NOT_AVAILABLE;
  1498. failed = TRUE;
  1499.         }
  1500.     semGive (pTapeVol->tapevd_semId); /* release volume */
  1501.     if (failed)
  1502. {
  1503.         return (ERROR); /* cannot access volume */
  1504. }
  1505.     return (OK);
  1506.     }
  1507. /*******************************************************************************
  1508. *
  1509. * tapeFsWrite - write to a tape volume
  1510. *
  1511. * This routine writes to the tape volume specified by the file descriptor
  1512. * from the specified buffer.  If the block containing the tape locations
  1513. * to be written is already in the file descriptor's read/write buffer,
  1514. * the buffer won't be flushed.  If another in-memory block is needed,
  1515. * any block already in memory will be flushed.
  1516. *
  1517. * This routine calls the device driver block-writing routine directly
  1518. * to write (possibly multiple) whole blocks.
  1519. *
  1520. * RETURNS: Number of bytes written (error if != maxBytes), or
  1521. * ERROR if maxBytes < 0, or no more space for the file,
  1522. * or can't write block.
  1523. */
  1524. LOCAL int tapeFsWrite
  1525.     (
  1526.     FAST TAPE_FILE_DESC *pTapeFd,       /* file descriptor pointer  */
  1527.     char                *pBuf,          /* data to be written       */
  1528.     int                 maxBytes        /* number of bytes to write */
  1529.     )
  1530.     {
  1531.     FAST int nBytes; /* byte count for individual write */
  1532.     FAST int numBlks; /* number of blocks to write */
  1533. /* pointer to vol descriptor */
  1534.     FAST TAPE_VOL_DESC *pTapeVol = pTapeFd->tapefd_pTapeVol;
  1535. /* pointer to sequential device info */
  1536.     FAST SEQ_DEV *pSeqDev = pTapeFd->tapefd_pTapeVol->tapevd_pSeqDev;
  1537.     FAST int bytesLeft; /* remaining bytes to write */
  1538.     semTake (pTapeVol->tapevd_semId, WAIT_FOREVER); /* take control of volume */
  1539.     TAPE_DEBUG_MSG ("tapeFsWrite: Device block size is: %dn",
  1540. pSeqDev->sd_blkSize, 0,0,0,0,0);
  1541.     /* Check that device was opened for writing */
  1542.     if (pTapeFd->tapefd_mode == O_RDONLY)
  1543. {
  1544. semGive (pTapeVol->tapevd_semId);
  1545.         errno = EROFS; /* posix errno */
  1546. TAPE_DEBUG_MSG ("tapeFsWrite: read only volumen",0,0,0,0,0,0);
  1547. return (ERROR);
  1548. }
  1549.     /* Check for valid length of write */
  1550.     if (maxBytes < 0)
  1551. {
  1552. semGive (pTapeVol->tapevd_semId);
  1553. /* errnoSet (S_tapeFsLib_INVALID_NUMBER_OF_BYTES); */
  1554. TAPE_DEBUG_MSG ("tapeFsWrite: maxBytes < 0n",0,0,0,0,0,0);
  1555. return (ERROR);
  1556. }
  1557.     /* Device blockSize and FD buffer size should be identical */
  1558.     if (pSeqDev->sd_blkSize != pTapeFd->tapefd_bufSize)
  1559. {
  1560. semGive (pTapeVol->tapevd_semId);
  1561. errno = S_tapeFsLib_INVALID_BLOCK_SIZE;
  1562. TAPE_DEBUG_MSG ("tapeFsWrite: invalid blkSizen",0,0,0,0,0,0);
  1563. return (ERROR);
  1564. }
  1565.     /* Write into successive blocks until all of caller's buffer written */
  1566.     bytesLeft = maxBytes;
  1567.     /* Variable block write */
  1568.     if (pSeqDev->sd_blkSize == VARIABLE_BLOCK_SIZE)
  1569. {
  1570. while (bytesLeft > 0)
  1571.     {
  1572.     /* Read a variable block upto a maximum size */
  1573.     nBytes = (bytesLeft > pSeqDev->sd_maxVarBlockLimit) ?
  1574.   pSeqDev->sd_maxVarBlockLimit  : bytesLeft;
  1575.             if (tapeFsBlkWrt (pTapeVol, nBytes, pBuf, VARIABLE_BLK) != OK)
  1576. goto writeFailed;
  1577.             bytesLeft -= nBytes;
  1578.     pBuf      += nBytes;
  1579.     }
  1580.         semGive (pTapeVol->tapevd_semId);           /* release volume */
  1581.         return (maxBytes - bytesLeft);
  1582.         }
  1583.     /* Fixed block write */
  1584.     while (bytesLeft > 0)
  1585. {
  1586. nBytes = 0; /* init individual write count*/
  1587. /* Do direct whole-block write if possible */
  1588. if ((bytesLeft >= pSeqDev->sd_blkSize) &&
  1589.             (pTapeFd->tapefd_bufIndex == 0))
  1590.     {
  1591.     /* Calculate starting block and number to write */
  1592.     numBlks = bytesLeft / pSeqDev->sd_blkSize;
  1593.     /* Write as many blocks as possible */
  1594.     if (tapeFsBlkWrt (pTapeVol, numBlks, pBuf, FIXED_BLK) != OK)
  1595. goto writeFailed;
  1596.     nBytes = numBlks * pSeqDev->sd_blkSize;
  1597.     }
  1598.    /* Handle partially written blocks with buffering */
  1599. else
  1600.     {
  1601.             if ((nBytes = tapeFsPartWrt (pTapeFd, pBuf, bytesLeft)) == ERROR)
  1602. break;
  1603.     }
  1604. pBuf += nBytes;
  1605. bytesLeft -= nBytes;
  1606. }
  1607.     semGive (pTapeVol->tapevd_semId); /* release volume */
  1608.     return (maxBytes - bytesLeft); /* return actual copy count */
  1609. writeFailed:
  1610.     semGive (pTapeVol->tapevd_semId);
  1611.     TAPE_DEBUG_MSG ("tapeFsWrite: write failed n",0,0,0,0,0,0);
  1612.     return (ERROR);
  1613.     }
  1614. /*******************************************************************************
  1615. *
  1616. * tapeFsPartWrt - write a partial tape block 
  1617. *
  1618. * This routine writes to the tape volume specified by the file descriptor
  1619. * from the specified buffer.  The partial block data is written into a 
  1620. * buffer, until that buffer is full and at that point the full buffer is
  1621. * written to tape.
  1622. *
  1623. * This routine calls the device driver block-writing routine directly
  1624. * to write (possibly) a whole block.
  1625. *
  1626. * RETURNS: Number of bytes written (error if != maxBytes), or
  1627. * ERROR if maxBytes < 0, or no more space for the file,
  1628. * or can't write block.
  1629. */
  1630. LOCAL int tapeFsPartWrt 
  1631.     (
  1632.     TAPE_FILE_DESC * pTapeFd, /* pointer to a tape file descriptor      */
  1633.     char *      pBuf,      /* pointer to data buffer                 */
  1634.     int      nBytes /* number of partial block bytes to write */
  1635.     )
  1636.     {
  1637.     int blkSize = pTapeFd->tapefd_pTapeVol->tapevd_pSeqDev->sd_blkSize;
  1638.     TAPE_VOL_DESC * pTapeVol = pTapeFd->tapefd_pTapeVol;
  1639.     /*
  1640.      * If there are less bytes to be written than the remainder of the
  1641.      * buffered block, write those bytes to the buffer.
  1642.      */
  1643.     if (nBytes <= (blkSize - pTapeFd->tapefd_bufIndex))
  1644.         {
  1645.         bcopy (pBuf, pTapeFd->tapefd_buffer + pTapeFd->tapefd_bufIndex, nBytes);
  1646. pTapeFd->tapefd_bufIndex += nBytes;
  1647.         /*
  1648.  * If the entire block is filled, write out the block and reset the
  1649.  * bufIndex.
  1650.  */
  1651. if (pTapeFd->tapefd_bufIndex == blkSize)
  1652.     {
  1653.     if (tapeFsBlkWrt (pTapeVol, 1, pTapeFd->tapefd_buffer, FIXED_BLK)
  1654. != OK)
  1655. return (ERROR);
  1656.     pTapeFd->tapefd_bufIndex = 0;
  1657.     }
  1658.         }
  1659.     /*
  1660.      * If there are more bytes to be written than the remainder of the 
  1661.      * buffered block, write until block is full and then write that full block
  1662.      * out to tape.
  1663.      */
  1664.     else
  1665. {
  1666. nBytes = blkSize - pTapeFd->tapefd_bufIndex;
  1667. bcopy (pBuf, pTapeFd->tapefd_buffer + pTapeFd->tapefd_bufIndex, nBytes);
  1668. if (tapeFsBlkWrt (pTapeVol, 1, pTapeFd->tapefd_buffer, FIXED_BLK) != OK)
  1669.     return (ERROR);
  1670.         pTapeFd->tapefd_bufIndex = 0;
  1671. }
  1672.     /* Return the number of bytes actually written to buffer or tape */
  1673.     return (nBytes);
  1674.     }
  1675.