Variable and fixed block read/write processing

In Windows 200x, tape APIs can be configured to manipulate tapes that use either fixed block size or variable block size.

If variable block size is wanted, the block size must be set to zero. The SetTapeParameters function must be called specifying the SET_TAPE_MEDIA_INFORMATION operation. The function requires the use of a TAPE_SET_MEDIA_PARAMETERS structure. The BlockSize member of the structure must be set to the wanted block size. Any block size other than 0 sets the media parameters to fixed block size. The size of the block is equal to the BlockSize member.

In fixed block mode, the size of all data buffers used for reading and writing must be a multiple of the block size. To determine the fixed block size, the GetTapeParameters function must be used. Specifying the GET_TAPE_MEDIA_INFORMATION operation yields a TAPE_GET_MEDIA_PARAMETERS structure. The BlockSize member of this structure reports the block size of the tape. The size of buffers that are used in read and write operations must be a multiple of the block size. This mode allows multiple blocks to be transferred in a single operation. In fixed block mode, transfer of odd block sizes (for example, 999 bytes) is not supported.

When reading or writing variable sized blocks, the operation cannot exceed the maximum transfer length of the Host Bus Adapter. This length is the length of each transfer page (typically 4 K) times the number of transfer pages (if set to 16, the maximum transfer length for variable sized transfers is 64 K). This number can be modified by changing the scatter-gather variable in the system registry, but this action is not recommended because it uses up scarce system resources.

Reading a tape that contains variable sized blocks can be accomplished even without knowing what size the blocks are. If a buffer is large enough to read the data in a block, then the data is read without any errors. If the buffer is larger than a block, then only data in a single block is read and the tape is advanced to the next block.

The size of the block is returned by the read operation in the *pBytesRead parameter. If a data buffer is too small to contain all of the data in a block, then a couple of things occur. First, the data buffer contains data from the tape, but the read operation fails and GetLastError returns ERROR_MORE_DATA. This error value indicates that more data is in the block to be read. Second, the tape is advanced to the next block. To reread the previous block, the tape must be repositioned to the wanted block and a larger buffer must be specified. It is best to specify as large a buffer as possible so that this issue does not occur.

If a tape contains fixed size blocks, but the tape media parameters are set to variable block size, then no assumptions are made regarding the size of the blocks on the tape. Each read operation behaves as described. The sizes of the blocks on the tape are treated as variable, but happen to be the same size. If a tape has variable size blocks, but the tape media parameters are set to fixed block size, then the size of all blocks on the tape are expected to be the same fixed size. Reading a block of a tape in this situation fails and GetLastError returns ERROR_INVALID_BLOCK_LENGTH. The only exception is if the block size in the media parameters is the same as the size of the variable block and the size of the read buffer happens to be a multiple of the size of the variable block.

If ReadFile encounters a tapemark, the data up to the tapemark is read and the function fails. (The GetLastError function returns an error code that indicates that a tapemark was encountered.) The tape is positioned past the tapemark, and an application can call ReadFile again to continue reading.