DLL_EXPORT int w32_close_tape ( ufd_t ufd ) { ifd_t ifd = W32STAPE_UFD2IFD( ufd ); int rc = -1; errno = EBADF; lock(); if (1 && ifd >= 0 && ifd < W32STAPE_MAX_FDNUMS && g_ifds[ ifd ] != 0 ) { // Deallocate resources HANDLE hFile = g_handles[ ifd ]; char* pName = g_fnames [ ifd ]; g_handles[ ifd ] = NULL; g_fnames [ ifd ] = NULL; g_fstats [ ifd ] = GMT_DR_OPEN (0xFFFFFFFF); g_BOTmsk [ ifd ] = 0xFFFFFFFF; g_BOTbot [ ifd ] = 0x00000000; VERIFY( w32_free_ifd( ifd ) == 0 ); // Close the file... free( pName ); errno = CloseHandle( hFile ) ? 0 : w32_trans_w32error( GetLastError() ); rc = errno ? -1 : 0; } unlock(); return rc; }
static int w32_internal_rc ( U32* pStat ) { ASSERT( pStat ); // (sanity check) // PROGRAMMING NOTE: the 'door open' (no tape in drive) and the // 'write protected' statuses are "sticky" in that they never change // until a new/different tape is mounted. All the other statuses // however, change dynamically as one does i/o to the tape... if (0 || ERROR_BUS_RESET == errno // (See KB 111837: "ERROR_BUS_RESET May Be Benign") || ERROR_MEDIA_CHANGED == errno || ERROR_DEVICE_NOT_CONNECTED == errno // (shouldn't occur but we'll check anyway) || ERROR_DEV_NOT_EXIST == errno // (shouldn't occur but we'll check anyway) || ERROR_FILE_NOT_FOUND == errno // (shouldn't occur but we'll check anyway) ) { *pStat &= ~GMT_DR_OPEN (0xFFFFFFFF); *pStat &= ~GMT_WR_PROT (0xFFFFFFFF); } // (see PROGRAMMING NOTE above) *pStat &= ~GMT_BOT (0xFFFFFFFF); *pStat &= ~GMT_SM (0xFFFFFFFF); *pStat &= ~GMT_EOF (0xFFFFFFFF); *pStat &= ~GMT_EOT (0xFFFFFFFF); *pStat &= ~GMT_EOD (0xFFFFFFFF); if (0 || ERROR_BUS_RESET == errno // (spurious error; retry) || ERROR_MEDIA_CHANGED == errno // (spurious error; retry) // || ERROR_DEVICE_NOT_CONNECTED == errno // (PERM ERROR! NO RETRY!) // || ERROR_DEV_NOT_EXIST == errno // (PERM ERROR! NO RETRY!) // || ERROR_FILE_NOT_FOUND == errno // (PERM ERROR! NO RETRY!) ) { return EINTR; // (Interrupted system call; Retry) } // (see PROGRAMMING NOTE further above) switch (errno) { default: break; // (leave errno set to whatever it already is) case NO_ERROR: errno = 0; break; // (normal expected i/o result) case ERROR_BEGINNING_OF_MEDIA: *pStat |= GMT_BOT (0xFFFFFFFF); errno = EIO; break; case ERROR_END_OF_MEDIA: *pStat |= GMT_EOT (0xFFFFFFFF); errno = ENOSPC; break; // "ERROR_END_OF_MEDIA" // // Msg: "The physical end of the tape has been reached." // // The EOT warning reflector has been reached or passed (i.e. you're // now/still in the "EOT Warning Zone" area). Writing additional data // and/or tapemarks may still be possible depending on the size of the // EOT Warning Zone (as set by a SetTapeParameters call with a non-zero // EOTWarningZoneSize value (if supported; see further below)) and // how much data you've already written to the EOT Warning Zone area // (i.e. once you're in the warning area, this "error" occurs after // EACH and EVERY I/O [in the warning zone area] until the ABSOLUTE // physical end-of-tape (ERROR_EOM_OVERFLOW) is reached; see below). // // // *********************** // ** IMPORTANT NOTE! ** // *********************** // // This is NOT actually an "error"!!! // // // When this "error" occurs, your "ReadFile" and/or "WriteFile" call // returns 'FALSE' even though ALL of your requested data was actually // written successfully!! This can be verified by checking to ensure // the returned "number of bytes written" actually matches the amount // you asked to be written. If they're the same (and they ALWAYS will // be for this specific "error" code), then it means this "error" is // NOT actually an error at all, but rather just a WARNING instead!! // (Had it been an actual i/o error, the error code would have been // some other DIFFERENT error code value instead!!) // // // *********************** // ** ALSO IMPORTANT! ** // *********************** // See also: // // http://fixunix.com/storage/205622-bug-dlttape-sys-no-eot-warning.html // // for ADDITIONAL IMPORTANT INFORMATION regarding always having to // specifically request that this "error" code be returned to you: // // Even when a drive reports it does not support the setting of the // the 'EOTWarningZoneSize' value (i.e. the FeaturesLow field of the // GetTapeParameters call returns '0' for TAPE_DRIVE_SET_EOT_WZ_SIZE // field), it may still be possible for "ERROR_END_OF_MEDIA" warnings // to be generated anyway by simply calling SetTapeParameters with a // non-zero 'EOTWarningZoneSize' value anyway. // // The reason for this is because some drives may not allow CHANGING // the value (thus the reason for it reporting that setting the value // is not supported), but may nevertheless still support the ENABLING // of their own hard-coded internal value. That is to say, while the // size of the warning zone may not be modifiable (as it may be hard- // coded and thus unchangeable), the drive may still have the ability // to REPORT reaching the EOT Warning zone IF SPECIFICALLY REQUESTED // TO DO SO! (which is presumably what requesting a non-zero Warning // Zone size would end up doing: i.e. even though such calls APPEAR // to fail, they actually DO succeed in accomplishing SOMETHING, just // not what you originally/specifically requested). // // Thus calling SetTapeParameters with a non-zero 'EOTWarningZoneSize' // value might very well succeed anyway even though GetTapeParameters // reports that doing so is not supported, and by so doing, may cause // the drive to begin reporting of "ERROR_END_OF_MEDIA" (whereas not // attempting to do so would end up leaving the drive in its default // non-reporting mode. That is to say, you should ALWAYS try setting // a non-zero 'EOTWarningZoneSize' value, ignoring any "unsupported" // error code that may be returned from such a call.) case ERROR_EOM_OVERFLOW: *pStat |= GMT_EOT (0xFFFFFFFF); errno = EIO; break; // "ERROR_EOM_OVERFLOW" // // Msg: "Physical end of tape encountered." // // This error code means that the actual physical end-of-media has been // reached, and no more data can be written to the tape. This includes // tapemarks as well. // // *********************** // ** IMPORTANT NOTE! ** // *********************** // // This is a HARD (UNRECOVERABLE) error!! // // To be programmatically informed of when you are coming close to the // physical end-of-the-tape (such that you could be assured room still // remained to write logical end-of-volume labels for example), simply // call SetTapeParameters with a non-zero 'EOTWarningZoneSize' value // and treat any "ERROR_END_OF_MEDIA" "errors" received when writing // as warnings instead. (See prior discussion of "ERROR_END_OF_MEDIA" // return code further above) case ERROR_NO_DATA_DETECTED: *pStat |= GMT_EOD (0xFFFFFFFF); errno = EIO; break; case ERROR_FILEMARK_DETECTED: *pStat |= GMT_EOF (0xFFFFFFFF); errno = EIO; break; case ERROR_SETMARK_DETECTED: *pStat |= GMT_SM (0xFFFFFFFF); errno = EIO; break; case ERROR_NOT_READY: *pStat |= GMT_DR_OPEN (0xFFFFFFFF); errno = ENOMEDIUM; break; case ERROR_NO_MEDIA_IN_DRIVE: *pStat |= GMT_DR_OPEN (0xFFFFFFFF); errno = ENOMEDIUM; break; case ERROR_WRITE_PROTECT: *pStat |= GMT_WR_PROT (0xFFFFFFFF); errno = EROFS; break; } return errno; }
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; }
/* IOCTL routine called by kernel-interface code */ int _ftape_ioctl(unsigned int command, void *arg) { TRACE_FUN(8, "ftape_ioctl"); int result = EINVAL; union { struct mtop mtop; struct mtget mtget; } krnl_arg; int arg_size = (command & IOCSIZE_MASK) >> IOCSIZE_SHIFT; /* This check will only catch arguments that are too large ! */ if ((command & IOC_INOUT) && arg_size > sizeof(krnl_arg)) { TRACEi(1, "bad argument size:", arg_size); TRACE_EXIT; return -EINVAL; } if (command & IOC_IN) { int error = verify_area(VERIFY_READ, arg, arg_size); if (error) { TRACE_EXIT; return error; } memcpy_fromfs(&krnl_arg.mtop, arg, arg_size); } TRACEx1(5, "called with ioctl command: 0x%08x", command); switch (command) { /* cpio compatibility * mtrasx and mtreset are mt extension by Hennus Bergman * mtseek and mttell are mt extension by eddy olk */ case MTIOCTOP: TRACEx1(5, "calling MTIOCTOP command: 0x%08x", krnl_arg.mtop.mt_op); switch (krnl_arg.mtop.mt_op) { case MTNOP: /* gnu mt calls MTNOP before MTIOCGET to set status */ result = 0; break; case MTRESET: result = ftape_reset_drive(); init_drive_needed = 1; if (result < 0 || ftape_offline) { break; } result = ftape_seek_to_bot(); ftape_reset_position(); break; case MTREW: case MTOFFL: if (ftape_offline) { result = -EIO; break; } ftape_flush_buffers(); ftape_update_header_segments(NULL, 1); result = ftape_seek_to_bot(); ftape_reset_position(); if (krnl_arg.mtop.mt_op == MTOFFL) { going_offline = 1; TRACE(4, "Putting tape drive offline"); } result = 0; break; case MTRETEN: if (ftape_offline) { result = -EIO; break; } result = ftape_seek_to_eot(); if (result >= 0) { result = ftape_seek_to_bot(); } ftape_reset_position(); break; case MTERASE: if (ftape_offline) { result = -EIO; break; } result = ftape_erase(); break; case MTEOM: if (ftape_offline) { result = -EIO; break; } result = ftape_seek_eom(); break; case MTFSFM: if (ftape_offline) { result = -EIO; break; } eof_mark = 1; /* position ready to extend */ case MTFSF: if (ftape_offline) { result = -EIO; break; } result = ftape_seek_eof(krnl_arg.mtop.mt_count); break; case MTBSFM: if (ftape_offline) { result = -EIO; break; } eof_mark = 1; /* position ready to extend */ case MTBSF: if (ftape_offline) { result = -EIO; break; } result = ftape_seek_eof(-krnl_arg.mtop.mt_count); break; case MTFSR: if (ftape_offline) { result = -EIO; break; } tracing = krnl_arg.mtop.mt_count; TRACEx1(2, "tracing set to %d", tracing); result = 0; break; case MTBSR: if (ftape_offline) { result = -EIO; break; } #if 0 result = ftape_fix(); #else result = 0; #endif break; case MTWEOF: if (ftape_offline) { result = -EIO; break; } result = ftape_weof(krnl_arg.mtop.mt_count, ftape_seg_pos, 1); if (result >= 0) { ftape_seg_pos += krnl_arg.mtop.mt_count - 1; } break; /* MTRASx and MTRESET are mt extension by Hennus Bergman */ case MTRAS1: case MTRAS2: case MTRAS3: case MTSEEK: case MTTELL: default: TRACEi(1, "MTIOCTOP sub-command not implemented:", krnl_arg.mtop.mt_op); result = -EIO; break; } break; case MTIOCGET: krnl_arg.mtget.mt_type = drive_type.vendor_id + 0x800000; krnl_arg.mtget.mt_resid = 0; /* not implemented */ krnl_arg.mtget.mt_dsreg = 0; /* status register */ krnl_arg.mtget.mt_gstat = /* device independent status */ ((ftape_offline) ? 0 : GMT_ONLINE(-1L)) | ((write_protected) ? GMT_WR_PROT(-1L) : 0) | ((no_tape) ? GMT_DR_OPEN(-1L) : 0); krnl_arg.mtget.mt_erreg = ftape_last_error; /* error register */ result = ftape_file_no(&krnl_arg.mtget.mt_fileno, &krnl_arg.mtget.mt_blkno); break; case MTIOCPOS: TRACE(5, "Mag tape ioctl command: MTIOCPOS"); TRACE(1, "MTIOCPOS command not implemented"); break; default: result = -EINVAL; break; } if (command & IOC_OUT) { int error = verify_area(VERIFY_WRITE, arg, arg_size); if (error) { TRACE_EXIT; return error; } memcpy_tofs(arg, &krnl_arg, arg_size); } TRACE_EXIT; return result; }
/* * Return the status of the device. This was meant * to be a generic routine. Unfortunately, it doesn't * seem possible (at least I do not know how to do it * currently), which means that for the moment, this * routine has very little value. * * Returns: status */ uint32_t status_dev(DEVICE *dev) { struct mtget mt_stat; uint32_t stat = 0; if (dev->state & (ST_EOT | ST_WEOT)) { stat |= BMT_EOD; Pmsg0(-20, " EOD"); } if (dev->state & ST_EOF) { stat |= BMT_EOF; Pmsg0(-20, " EOF"); } if (dev->is_tape()) { stat |= BMT_TAPE; Pmsg0(-20,_(" Bacula status:")); Pmsg2(-20,_(" file=%d block=%d\n"), dev->file, dev->block_num); if (dev->d_ioctl(dev->fd(), MTIOCGET, (char *)&mt_stat) < 0) { berrno be; dev->dev_errno = errno; Mmsg2(dev->errmsg, _("ioctl MTIOCGET error on %s. ERR=%s.\n"), dev->print_name(), be.bstrerror()); return 0; } Pmsg0(-20, _(" Device status:")); #if defined(HAVE_LINUX_OS) if (GMT_EOF(mt_stat.mt_gstat)) { stat |= BMT_EOF; Pmsg0(-20, " EOF"); } if (GMT_BOT(mt_stat.mt_gstat)) { stat |= BMT_BOT; Pmsg0(-20, " BOT"); } if (GMT_EOT(mt_stat.mt_gstat)) { stat |= BMT_EOT; Pmsg0(-20, " EOT"); } if (GMT_SM(mt_stat.mt_gstat)) { stat |= BMT_SM; Pmsg0(-20, " SM"); } if (GMT_EOD(mt_stat.mt_gstat)) { stat |= BMT_EOD; Pmsg0(-20, " EOD"); } if (GMT_WR_PROT(mt_stat.mt_gstat)) { stat |= BMT_WR_PROT; Pmsg0(-20, " WR_PROT"); } if (GMT_ONLINE(mt_stat.mt_gstat)) { stat |= BMT_ONLINE; Pmsg0(-20, " ONLINE"); } if (GMT_DR_OPEN(mt_stat.mt_gstat)) { stat |= BMT_DR_OPEN; Pmsg0(-20, " DR_OPEN"); } if (GMT_IM_REP_EN(mt_stat.mt_gstat)) { stat |= BMT_IM_REP_EN; Pmsg0(-20, " IM_REP_EN"); } #elif defined(HAVE_WIN32) if (GMT_EOF(mt_stat.mt_gstat)) { stat |= BMT_EOF; Pmsg0(-20, " EOF"); } if (GMT_BOT(mt_stat.mt_gstat)) { stat |= BMT_BOT; Pmsg0(-20, " BOT"); } if (GMT_EOT(mt_stat.mt_gstat)) { stat |= BMT_EOT; Pmsg0(-20, " EOT"); } if (GMT_EOD(mt_stat.mt_gstat)) { stat |= BMT_EOD; Pmsg0(-20, " EOD"); } if (GMT_WR_PROT(mt_stat.mt_gstat)) { stat |= BMT_WR_PROT; Pmsg0(-20, " WR_PROT"); } if (GMT_ONLINE(mt_stat.mt_gstat)) { stat |= BMT_ONLINE; Pmsg0(-20, " ONLINE"); } if (GMT_DR_OPEN(mt_stat.mt_gstat)) { stat |= BMT_DR_OPEN; Pmsg0(-20, " DR_OPEN"); } if (GMT_IM_REP_EN(mt_stat.mt_gstat)) { stat |= BMT_IM_REP_EN; Pmsg0(-20, " IM_REP_EN"); } #endif /* !SunOS && !OSF */ if (dev->has_cap(CAP_MTIOCGET)) { Pmsg2(-20, _(" file=%d block=%d\n"), mt_stat.mt_fileno, mt_stat.mt_blkno); } else { Pmsg2(-20, _(" file=%d block=%d\n"), -1, -1); } } else { stat |= BMT_ONLINE | BMT_BOT; } return stat; }
uint32_t generic_tape_device::status_dev() { struct mtget mt_stat; uint32_t status = 0; if (state & (ST_EOT | ST_WEOT)) { status |= BMT_EOD; Pmsg0(-20, " EOD"); } if (state & ST_EOF) { status |= BMT_EOF; Pmsg0(-20, " EOF"); } status |= BMT_TAPE; Pmsg0(-20,_(" Bareos status:")); Pmsg2(-20,_(" file=%d block=%d\n"), file, block_num); if (d_ioctl(m_fd, MTIOCGET, (char *)&mt_stat) < 0) { berrno be; dev_errno = errno; Mmsg2(errmsg, _("ioctl MTIOCGET error on %s. ERR=%s.\n"), print_name(), be.bstrerror()); return 0; } Pmsg0(-20, _(" Device status:")); #if defined(HAVE_LINUX_OS) if (GMT_EOF(mt_stat.mt_gstat)) { status |= BMT_EOF; Pmsg0(-20, " EOF"); } if (GMT_BOT(mt_stat.mt_gstat)) { status |= BMT_BOT; Pmsg0(-20, " BOT"); } if (GMT_EOT(mt_stat.mt_gstat)) { status |= BMT_EOT; Pmsg0(-20, " EOT"); } if (GMT_SM(mt_stat.mt_gstat)) { status |= BMT_SM; Pmsg0(-20, " SM"); } if (GMT_EOD(mt_stat.mt_gstat)) { status |= BMT_EOD; Pmsg0(-20, " EOD"); } if (GMT_WR_PROT(mt_stat.mt_gstat)) { status |= BMT_WR_PROT; Pmsg0(-20, " WR_PROT"); } if (GMT_ONLINE(mt_stat.mt_gstat)) { status |= BMT_ONLINE; Pmsg0(-20, " ONLINE"); } if (GMT_DR_OPEN(mt_stat.mt_gstat)) { status |= BMT_DR_OPEN; Pmsg0(-20, " DR_OPEN"); } if (GMT_IM_REP_EN(mt_stat.mt_gstat)) { status |= BMT_IM_REP_EN; Pmsg0(-20, " IM_REP_EN"); } #elif defined(HAVE_WIN32) if (GMT_EOF(mt_stat.mt_gstat)) { status |= BMT_EOF; Pmsg0(-20, " EOF"); } if (GMT_BOT(mt_stat.mt_gstat)) { status |= BMT_BOT; Pmsg0(-20, " BOT"); } if (GMT_EOT(mt_stat.mt_gstat)) { status |= BMT_EOT; Pmsg0(-20, " EOT"); } if (GMT_EOD(mt_stat.mt_gstat)) { status |= BMT_EOD; Pmsg0(-20, " EOD"); } if (GMT_WR_PROT(mt_stat.mt_gstat)) { status |= BMT_WR_PROT; Pmsg0(-20, " WR_PROT"); } if (GMT_ONLINE(mt_stat.mt_gstat)) { status |= BMT_ONLINE; Pmsg0(-20, " ONLINE"); } if (GMT_DR_OPEN(mt_stat.mt_gstat)) { status |= BMT_DR_OPEN; Pmsg0(-20, " DR_OPEN"); } if (GMT_IM_REP_EN(mt_stat.mt_gstat)) { status |= BMT_IM_REP_EN; Pmsg0(-20, " IM_REP_EN"); } #endif /* HAVE_LINUX_OS || HAVE_WIN32 */ if (has_cap(CAP_MTIOCGET)) { Pmsg2(-20, _(" file=%d block=%d\n"), mt_stat.mt_fileno, mt_stat.mt_blkno); } else { Pmsg2(-20, _(" file=%d block=%d\n"), -1, -1); } return status; }