BOOL GetTapeParms( DWORD *total_low, // O - tape capacity lower 32 bits DWORD *total_high, // O - tape capacity upper 32 bits DWORD *freespace_low, // O - free space remaining lower 32 bits DWORD *freespace_high, // O - free space remaining upper 32 bits DWORD *blk_size, // O - block size DWORD *part, // O - number of partitions BOOL *write_protect // O - write protect on/off ) { TAPE_GET_MEDIA_PARAMETERS parms ; DWORD status ; DWORD StructSize ; if( gb_Tape_Handle != NULL ) { sizeof( TAPE_GET_MEDIA_PARAMETERS ) ; status = GetTapeParameters( gb_Tape_Handle, GET_TAPE_MEDIA_INFORMATION, &StructSize, &parms ) ; // If call to GetTapeParameters is successful, copy data to return if( status == NO_ERROR ) { *total_low = parms.Capacity.LowPart ; *total_high = parms.Capacity.HighPart ; *freespace_low = parms.Remaining.LowPart ; *freespace_high = parms.Remaining.HighPart ; *blk_size = parms.BlockSize ; *part = parms.PartitionCount ; *write_protect = parms.WriteProtected ; } else { DisplayDriverError( GetLastError( ) ) ; return TEST_ERROR ; } } return SUCCESS ; }
DLL_EXPORT ufd_t w32_open_tape ( const char* path, int oflag, ... ) { ifd_t ifd; HANDLE hFile; char szTapeDeviceName[10]; const char* pszTapeDevNum; DWORD dwDesiredAccess, dwSizeofDriveParms, dwRetCode; // Reserve an fd number right away and bail if none available... if ( (ifd = w32_alloc_ifd()) < 0 ) return -1; // If they specified a Windows device name, // use it as-is. if (1 && strnfilenamecmp( path, "\\\\.\\", 4 ) == 0 && path [4] != 0 ) { strlcpy( szTapeDeviceName, path, sizeof(szTapeDeviceName) ); } else // (not a Windows device name) { // The device name is a Cygwin/*nix device name. // Name must be either "/dev/nst0" or "/dev/st0" if (1 && strnfilenamecmp( path, "/dev/", 5 ) == 0 && ( strnfilenamecmp( (pszTapeDevNum=path+8)-3, "nst", 3 ) == 0 || strnfilenamecmp( (pszTapeDevNum=path+7)-2, "st", 2 ) == 0 ) && strlen(pszTapeDevNum) == 1 && isdigit(*pszTapeDevNum) ) { // Change it to a Windows device name (e.g. \\.\Tape0) strlcpy( szTapeDeviceName, WIN32_TAPE_DEVICE_NAME, sizeof(szTapeDeviceName) ); szTapeDeviceName[8] = *pszTapeDevNum; szTapeDeviceName[9] = 0; // PROGRAMMING NOTE: the "rewind at close" option (implied by // virtue of the filename being "/dev/st0" and not "/dev/nst0") // was handled (detected/remembered) by the higher-level caller. } else { VERIFY( w32_free_ifd( ifd ) == 0 ); errno = EINVAL; // (bad device name) return -1; // (open failure) } } // We only support O_BINARY with either O_RDWR or O_RDONLY if (1 && (( O_BINARY | O_RDWR ) != oflag) && (( O_BINARY | O_RDONLY) != oflag) ) { VERIFY( w32_free_ifd( ifd ) == 0 ); errno = EINVAL; // (invalid open flags) return -1; // (open failure) } // Set desired access dwDesiredAccess = GENERIC_READ; if ( oflag & O_RDWR ) dwDesiredAccess |= GENERIC_WRITE; // Open the tape drive... hFile = CreateFile ( szTapeDeviceName, // filename dwDesiredAccess, // desired access 0, // share mode (0 == exclusive) NULL, // security == default OPEN_EXISTING, // "file" (device actually) must already exist 0, // no special access flags needed NULL // not using template ); if ( INVALID_HANDLE_VALUE == hFile ) { int save_errno = w32_trans_w32error( GetLastError() ); VERIFY( w32_free_ifd( ifd ) == 0 ); errno = save_errno; return -1; } // Save drive parameters for later... memset( &g_drive_parms[ifd], 0, sizeof(TAPE_GET_DRIVE_PARAMETERS) ); dwSizeofDriveParms = sizeof(TAPE_GET_DRIVE_PARAMETERS); do { dwRetCode = GetTapeParameters ( hFile, GET_TAPE_DRIVE_INFORMATION, &dwSizeofDriveParms, &g_drive_parms[ifd] ); } while ((NO_ERROR != dwRetCode) // (if not normal completion, && // check for retry conditions) (0 || ERROR_MEDIA_CHANGED == dwRetCode // (likely but unimportant; retry) || ERROR_BUS_RESET == dwRetCode // (unlikely but possible; retry) )); // Did that work? if (NO_ERROR != dwRetCode) { int save_errno = w32_trans_w32error( GetLastError() ); CloseHandle( hFile ); VERIFY( w32_free_ifd( ifd ) == 0 ); errno = save_errno; return -1; } ASSERT( NO_ERROR == dwRetCode ); ASSERT( sizeof(TAPE_GET_DRIVE_PARAMETERS) == dwSizeofDriveParms ); // Save control info & return their file descriptor... g_handles [ ifd ] = hFile; // (WIN32 handle) g_fnames [ ifd ] = strdup( path ); // (for posterity) g_fstats [ ifd ] = GMT_ONLINE (0xFFFFFFFF); // (initial status) g_BOTmsk [ ifd ] = 0xFFFFFFFF; // (BOT block-id mask) g_BOTbot [ ifd ] = 0x00000000; // (BOT block-id value) return W32STAPE_IFD2UFD( ifd ); // (user fd result) }
static int w32_internal_mtget ( HANDLE hFile, U32* pStat, struct mtget* mtget, ifd_t ifd ) { TAPE_GET_MEDIA_PARAMETERS media_parms; DWORD dwRetCode, dwSize, dwLogicalPosition; ASSERT( pStat && mtget ); mtget->mt_resid = 0; // (unknown/unsupported) mtget->mt_erreg = 0; // (unknown/unsupported) mtget->mt_fileno = -1; // (unknown/unsupported) mtget->mt_blkno = -1; // (unknown as of yet; set further below) mtget->mt_type = MT_ISSCSI2; // "Generic ANSI SCSI-2 tape unit" mtget->mt_gstat = -1; // (purposely invalid; set correctly below) // Reset the mounted status; it will get set further below... *pStat &= ~GMT_DR_OPEN (0xFFFFFFFF); // Attempt to retrieve the status of the tape-drive... dwRetCode = w32_get_tape_status( hFile ); // Windows returns 'ERROR_NOT_READY' if no tape is mounted // instead of the usual expected 'ERROR_NO_MEDIA_IN_DRIVE' if ( ERROR_NOT_READY == dwRetCode ) dwRetCode = ERROR_NO_MEDIA_IN_DRIVE; // If there is not tape mounted OR a new tape was mounted, // then the following status bits are now unknown/obsolete if (0 || ERROR_NO_MEDIA_IN_DRIVE == dwRetCode || ERROR_MEDIA_CHANGED == dwRetCode ) { // (these statuse are now obsolete) *pStat &= ~GMT_WR_PROT (0xFFFFFFFF); *pStat &= ~GMT_BOT (0xFFFFFFFF); *pStat &= ~GMT_EOT (0xFFFFFFFF); *pStat &= ~GMT_EOD (0xFFFFFFFF); *pStat &= ~GMT_EOF (0xFFFFFFFF); *pStat &= ~GMT_SM (0xFFFFFFFF); } // There's no sense trying to get media parameters // unless there's some media loaded on the drive! if ( ERROR_NO_MEDIA_IN_DRIVE == dwRetCode ) { *pStat |= GMT_DR_OPEN (0xFFFFFFFF); // (no tape mounted in drive) mtget->mt_gstat = *pStat; // (return current status) return 0; // (nothing more we can do) } // A tape appears to be mounted on the drive... // Retrieve the media parameters information... dwSize = sizeof(media_parms); memset( &media_parms, 0, dwSize ); dwRetCode = GetTapeParameters( hFile, GET_TAPE_MEDIA_INFORMATION, &dwSize, &media_parms ); ASSERT( sizeof(media_parms) == dwSize ); if ( NO_ERROR == dwRetCode ) { mtget->mt_dsreg = media_parms.BlockSize; if (media_parms.WriteProtected) *pStat |= GMT_WR_PROT (0xFFFFFFFF); else *pStat &= ~GMT_WR_PROT (0xFFFFFFFF); } else mtget->mt_dsreg = 0; // (unknown; variable blocks presumed) // Lastly, attempt to determine if we are at BOT (i.e. load-point)... if ( 0 != ( errno = w32_internal_mtpos( hFile, pStat, &dwLogicalPosition, NULL, ifd ) ) ) { mtget->mt_gstat = *pStat; return -1; } mtget->mt_blkno = dwLogicalPosition; if ( ( dwLogicalPosition & g_BOTmsk[ ifd ] ) == g_BOTbot[ ifd ] ) *pStat |= GMT_BOT (0xFFFFFFFF); else *pStat &= ~GMT_BOT (0xFFFFFFFF); mtget->mt_gstat = *pStat; return 0; }
int win32_tape_device::tape_get(struct mtget *mt_get) { TAPE_POSITION_INFO pos_info; BOOL result; if (m_fd < 3 || m_fd >= (int)(NUMBER_HANDLE_ENTRIES + 3) || TapeHandleTable[m_fd - 3].OSHandle == INVALID_HANDLE_VALUE) { errno = EBADF; return -1; } PTAPE_HANDLE_INFO pHandleInfo = &TapeHandleTable[m_fd - 3]; if (GetTapePositionInfo(pHandleInfo->OSHandle, &pos_info) != NO_ERROR) { return -1; } DWORD density = 0; DWORD blocksize = 0; result = GetDensityBlockSize(pHandleInfo->OSHandle, &density, &blocksize); if (result != NO_ERROR) { TAPE_GET_DRIVE_PARAMETERS drive_params; DWORD size; size = sizeof(drive_params); result = GetTapeParameters(pHandleInfo->OSHandle, GET_TAPE_DRIVE_INFORMATION, &size, &drive_params); if (result == NO_ERROR) { blocksize = drive_params.DefaultBlockSize; } } mt_get->mt_type = MT_ISSCSI2; /* * Partition # */ mt_get->mt_resid = pos_info.PartitionBlockValid ? pos_info.Partition : (ULONG)-1; /* * Density / Block Size */ mt_get->mt_dsreg = ((density << MT_ST_DENSITY_SHIFT) & MT_ST_DENSITY_MASK) | ((blocksize << MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK); mt_get->mt_gstat = 0x00010000; /* Immediate report mode.*/ if (pHandleInfo->bEOF) { mt_get->mt_gstat |= 0x80000000; /* GMT_EOF */ } if (pos_info.PartitionBlockValid && pos_info.BlockNumber == 0) { mt_get->mt_gstat |= 0x40000000; /* GMT_BOT */ } if (pHandleInfo->bEOT) { mt_get->mt_gstat |= 0x20000000; /* GMT_EOT */ } if (pHandleInfo->bEOD) { mt_get->mt_gstat |= 0x08000000; /* GMT_EOD */ } TAPE_GET_MEDIA_PARAMETERS media_params; DWORD size = sizeof(media_params); result = GetTapeParameters(pHandleInfo->OSHandle, GET_TAPE_MEDIA_INFORMATION, &size, &media_params); if (result == NO_ERROR && media_params.WriteProtected) { mt_get->mt_gstat |= 0x04000000; /* GMT_WR_PROT */ } result = GetTapeStatus(pHandleInfo->OSHandle); if (result != NO_ERROR) { if (result == ERROR_NO_MEDIA_IN_DRIVE) { mt_get->mt_gstat |= 0x00040000; /* GMT_DR_OPEN */ } } else { mt_get->mt_gstat |= 0x01000000; /* GMT_ONLINE */ } /* * Recovered Error Count */ mt_get->mt_erreg = 0; /* * File Number */ mt_get->mt_fileno = (__daddr_t)pHandleInfo->ulFile; /* * Block Number */ mt_get->mt_blkno = (__daddr_t)(pHandleInfo->bBlockValid ? pos_info.BlockNumber - pHandleInfo->ullFileStart : (ULONGLONG)-1); return 0; }
int win32_tape_device::tape_op(struct mtop *mt_com) { DWORD result = NO_ERROR; int index; if (m_fd < 3 || m_fd >= (int)(NUMBER_HANDLE_ENTRIES + 3) || TapeHandleTable[m_fd - 3].OSHandle == INVALID_HANDLE_VALUE) { errno = EBADF; return -1; } PTAPE_HANDLE_INFO pHandleInfo = &TapeHandleTable[m_fd - 3]; switch (mt_com->mt_op) { case MTRESET: case MTNOP: case MTSETDRVBUFFER: break; case MTRAS1: case MTRAS2: case MTRAS3: case MTSETDENSITY: errno = ENOTTY; result = (DWORD)-1; break; case MTFSF: for (index = 0; index < mt_com->mt_count; index++) { result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_FILEMARKS, 0, 1, 0, FALSE); if (result == NO_ERROR) { pHandleInfo->ulFile++; pHandleInfo->bEOF = true; pHandleInfo->bEOT = false; } } break; case MTBSF: for (index = 0; index < mt_com->mt_count; index++) { result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_FILEMARKS, 0, (DWORD)-1, ~0, FALSE); if (result == NO_ERROR) { pHandleInfo->ulFile--; pHandleInfo->bBlockValid = false; pHandleInfo->bEOD = false; pHandleInfo->bEOF = false; pHandleInfo->bEOT = false; } } break; case MTFSR: result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_RELATIVE_BLOCKS, 0, mt_com->mt_count, 0, FALSE); if (result == NO_ERROR) { pHandleInfo->bEOD = false; pHandleInfo->bEOF = false; pHandleInfo->bEOT = false; } else if (result == ERROR_FILEMARK_DETECTED) { pHandleInfo->bEOF = true; } break; case MTBSR: result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_RELATIVE_BLOCKS, 0, -mt_com->mt_count, ~0, FALSE); if (result == NO_ERROR) { pHandleInfo->bEOD = false; pHandleInfo->bEOF = false; pHandleInfo->bEOT = false; } else if (result == ERROR_FILEMARK_DETECTED) { pHandleInfo->ulFile--; pHandleInfo->bBlockValid = false; pHandleInfo->bEOD = false; pHandleInfo->bEOF = false; pHandleInfo->bEOT = false; } break; case MTWEOF: result = WriteTapemark(pHandleInfo->OSHandle, TAPE_FILEMARKS, mt_com->mt_count, FALSE); if (result == NO_ERROR) { pHandleInfo->bEOF = true; pHandleInfo->bEOT = false; pHandleInfo->ulFile += mt_com->mt_count; pHandleInfo->bBlockValid = true; pHandleInfo->ullFileStart = 0; } break; case MTREW: result = SetTapePosition(pHandleInfo->OSHandle, TAPE_REWIND, 0, 0, 0, FALSE); if (result == NO_ERROR) { pHandleInfo->bEOD = false; pHandleInfo->bEOF = false; pHandleInfo->bEOT = false; pHandleInfo->ulFile = 0; pHandleInfo->bBlockValid = true; pHandleInfo->ullFileStart = 0; } break; case MTOFFL: result = PrepareTape(pHandleInfo->OSHandle, TAPE_UNLOAD, FALSE); if (result == NO_ERROR) { pHandleInfo->bEOD = false; pHandleInfo->bEOF = false; pHandleInfo->bEOT = false; pHandleInfo->ulFile = 0; pHandleInfo->ullFileStart = 0; } break; case MTRETEN: result = PrepareTape(pHandleInfo->OSHandle, TAPE_TENSION, FALSE); if (result == NO_ERROR) { pHandleInfo->bEOD = false; pHandleInfo->bEOF = false; pHandleInfo->bEOT = false; pHandleInfo->ulFile = 0; pHandleInfo->bBlockValid = true; pHandleInfo->ullFileStart = 0; } break; case MTBSFM: for (index = 0; index < mt_com->mt_count; index++) { result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_FILEMARKS, 0, (DWORD)-1, ~0, FALSE); if (result == NO_ERROR) { result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_FILEMARKS, 0, 1, 0, FALSE); pHandleInfo->bEOD = false; pHandleInfo->bEOF = false; pHandleInfo->bEOT = false; } } break; case MTFSFM: for (index = 0; index < mt_com->mt_count; index++) { result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_FILEMARKS, 0, mt_com->mt_count, 0, FALSE); if (result == NO_ERROR) { result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_FILEMARKS, 0, (DWORD)-1, ~0, FALSE); pHandleInfo->bEOD = false; pHandleInfo->bEOF = false; pHandleInfo->bEOT = false; } } break; case MTEOM: while (1) { result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_FILEMARKS, 0, 1, 0, FALSE); if (result != NO_ERROR) { pHandleInfo->bEOF = false; if (result == ERROR_END_OF_MEDIA) { pHandleInfo->bEOD = true; pHandleInfo->bEOT = true; return 0; } if (result == ERROR_NO_DATA_DETECTED) { pHandleInfo->bEOD = true; pHandleInfo->bEOT = false; return 0; } break; } else { pHandleInfo->bEOF = true; pHandleInfo->ulFile++; } } break; case MTERASE: result = EraseTape(pHandleInfo->OSHandle, TAPE_ERASE_LONG, FALSE); if (result == NO_ERROR) { pHandleInfo->bEOD = true; pHandleInfo->bEOF = false; pHandleInfo->bEOT = false; pHandleInfo->ulFile = 0; pHandleInfo->bBlockValid = true; pHandleInfo->ullFileStart = 0; } break; case MTSETBLK: { TAPE_SET_MEDIA_PARAMETERS SetMediaParameters; SetMediaParameters.BlockSize = mt_com->mt_count; result = SetTapeParameters(pHandleInfo->OSHandle, SET_TAPE_MEDIA_INFORMATION, &SetMediaParameters); break; } case MTSEEK: { TAPE_POSITION_INFO TapePositionInfo; result = SetTapePosition(pHandleInfo->OSHandle, TAPE_ABSOLUTE_BLOCK, 0, mt_com->mt_count, 0, FALSE); memset(&TapePositionInfo, 0, sizeof(TapePositionInfo)); DWORD dwPosResult = GetTapePositionInfo(pHandleInfo->OSHandle, &TapePositionInfo); if (dwPosResult == NO_ERROR && TapePositionInfo.FileSetValid) { pHandleInfo->ulFile = (ULONG)TapePositionInfo.FileNumber; } else { pHandleInfo->ulFile = ~0U; } break; } case MTTELL: { DWORD partition; DWORD offset; DWORD offsetHi; result = GetTapePosition(pHandleInfo->OSHandle, TAPE_ABSOLUTE_BLOCK, &partition, &offset, &offsetHi); if (result == NO_ERROR) { return offset; } break; } case MTFSS: result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_SETMARKS, 0, mt_com->mt_count, 0, FALSE); break; case MTBSS: result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_SETMARKS, 0, -mt_com->mt_count, ~0, FALSE); break; case MTWSM: result = WriteTapemark(pHandleInfo->OSHandle, TAPE_SETMARKS, mt_com->mt_count, FALSE); break; case MTLOCK: result = PrepareTape(pHandleInfo->OSHandle, TAPE_LOCK, FALSE); break; case MTUNLOCK: result = PrepareTape(pHandleInfo->OSHandle, TAPE_UNLOCK, FALSE); break; case MTLOAD: result = PrepareTape(pHandleInfo->OSHandle, TAPE_LOAD, FALSE); break; case MTUNLOAD: result = PrepareTape(pHandleInfo->OSHandle, TAPE_UNLOAD, FALSE); break; case MTCOMPRESSION: { TAPE_GET_DRIVE_PARAMETERS GetDriveParameters; TAPE_SET_DRIVE_PARAMETERS SetDriveParameters; DWORD size; size = sizeof(GetDriveParameters); result = GetTapeParameters(pHandleInfo->OSHandle, GET_TAPE_DRIVE_INFORMATION, &size, &GetDriveParameters); if (result == NO_ERROR) { SetDriveParameters.ECC = GetDriveParameters.ECC; SetDriveParameters.Compression = (BOOLEAN)mt_com->mt_count; SetDriveParameters.DataPadding = GetDriveParameters.DataPadding; SetDriveParameters.ReportSetmarks = GetDriveParameters.ReportSetmarks; SetDriveParameters.EOTWarningZoneSize = GetDriveParameters.EOTWarningZoneSize; result = SetTapeParameters(pHandleInfo->OSHandle, SET_TAPE_DRIVE_INFORMATION, &SetDriveParameters); } break; } case MTSETPART: result = SetTapePosition(pHandleInfo->OSHandle, TAPE_LOGICAL_BLOCK, mt_com->mt_count, 0, 0, FALSE); break; case MTMKPART: if (mt_com->mt_count == 0) { result = CreateTapePartition(pHandleInfo->OSHandle, TAPE_INITIATOR_PARTITIONS, 1, 0); } else { result = CreateTapePartition(pHandleInfo->OSHandle, TAPE_INITIATOR_PARTITIONS, 2, mt_com->mt_count); } break; default: errno = ENOTTY; result = (DWORD)-1; break; } if ((result == NO_ERROR && pHandleInfo->bEOF) || (result == ERROR_FILEMARK_DETECTED && mt_com->mt_op == MTFSR)) { TAPE_POSITION_INFO TapePositionInfo; if (GetTapePositionInfo(pHandleInfo->OSHandle, &TapePositionInfo) == NO_ERROR) { pHandleInfo->bBlockValid = true; pHandleInfo->ullFileStart = TapePositionInfo.BlockNumber; } } switch (result) { case NO_ERROR: case (DWORD)-1: /* Error has already been translated into errno */ break; case ERROR_FILEMARK_DETECTED: errno = EIO; break; case ERROR_END_OF_MEDIA: pHandleInfo->bEOT = true; errno = EIO; break; case ERROR_NO_DATA_DETECTED: pHandleInfo->bEOD = true; errno = EIO; break; case ERROR_NO_MEDIA_IN_DRIVE: pHandleInfo->bEOF = false; pHandleInfo->bEOT = false; pHandleInfo->bEOD = false; errno = ENOMEDIUM; break; case ERROR_INVALID_HANDLE: case ERROR_ACCESS_DENIED: case ERROR_LOCK_VIOLATION: errno = EBADF; break; default: errno = EIO; break; } return result == NO_ERROR ? 0 : -1; }
int win32_tape_device::d_open(const char *pathname, int flags, int mode) { HANDLE hDevice = INVALID_HANDLE_VALUE; char szDeviceName[256] = "\\\\.\\"; int idxFile; DWORD dwResult; for (idxFile = 0; idxFile < (int)NUMBER_HANDLE_ENTRIES; idxFile++) { if (TapeHandleTable[idxFile].OSHandle == INVALID_HANDLE_VALUE) { break; } } if (idxFile >= (int)NUMBER_HANDLE_ENTRIES) { return EMFILE; } memset(&TapeHandleTable[idxFile], 0, sizeof(TapeHandleTable[idxFile])); if (!IsPathSeparator(pathname[0])) { bstrncpy(&szDeviceName[4], pathname, sizeof(szDeviceName) - 4); } else { bstrncpy(&szDeviceName[0], pathname, sizeof(szDeviceName)); } hDevice = CreateFile(szDeviceName, FILE_ALL_ACCESS, 0, NULL, OPEN_EXISTING, 0, NULL); if (hDevice != INVALID_HANDLE_VALUE) { PTAPE_HANDLE_INFO pHandleInfo = &TapeHandleTable[idxFile]; memset(pHandleInfo, 0, sizeof(*pHandleInfo)); pHandleInfo->OSHandle = hDevice; TAPE_GET_DRIVE_PARAMETERS TapeDriveParameters; DWORD dwSize = sizeof(TapeDriveParameters); dwResult = GetTapeParameters(pHandleInfo->OSHandle, GET_TAPE_DRIVE_INFORMATION, &dwSize, &TapeDriveParameters); if (dwResult == NO_ERROR) { pHandleInfo->FeaturesLow = TapeDriveParameters.FeaturesLow; pHandleInfo->FeaturesHigh = TapeDriveParameters.FeaturesHigh; } TAPE_POSITION_INFO TapePositionInfo; dwResult = GetTapePositionInfo(pHandleInfo->OSHandle, &TapePositionInfo); if (dwResult == NO_ERROR) { if (TapePositionInfo.AtPartitionStart || TapePositionInfo.AtPartitionEnd || (TapePositionInfo.PartitionBlockValid && TapePositionInfo.BlockNumber == 0)) { pHandleInfo->ulFile = 0; pHandleInfo->bBlockValid = true; pHandleInfo->ullFileStart = 0; } else if (TapePositionInfo.FileSetValid) { pHandleInfo->ulFile = (ULONG)TapePositionInfo.FileNumber; } } } else { DWORD dwError = GetLastError(); switch (dwError) { case ERROR_FILE_NOT_FOUND: case ERROR_PATH_NOT_FOUND: errno = ENOENT; break; case ERROR_TOO_MANY_OPEN_FILES: errno = EMFILE; break; case ERROR_ACCESS_DENIED: case ERROR_SHARING_VIOLATION: case ERROR_LOCK_VIOLATION: case ERROR_INVALID_NAME: errno = EACCES; break; case ERROR_FILE_EXISTS: errno = EEXIST; break; case ERROR_INVALID_PARAMETER: errno = EINVAL; break; default: errno = EACCES; break; } return(int) -1; } return (int)idxFile + 3; }