/* * Foward space num records * * Returns: false on failure * true on success */ bool generic_tape_device::fsr(int num) { struct mtop mt_com; int status; if (!is_open()) { dev_errno = EBADF; Mmsg0(errmsg, _("Bad call to fsr. Device not open\n")); Emsg0(M_FATAL, 0, errmsg); return false; } if (!has_cap(CAP_FSR)) { Mmsg1(errmsg, _("ioctl MTFSR not permitted on %s.\n"), prt_name); return false; } Dmsg1(100, "fsr %d\n", num); mt_com.mt_op = MTFSR; mt_com.mt_count = num; status = d_ioctl(m_fd, MTIOCTOP, (char *)&mt_com); if (status == 0) { clear_eof(); block_num += num; } else { berrno be; struct mtget mt_stat; clrerror(mt_com.mt_op); Dmsg1(100, "FSF fail: ERR=%s\n", be.bstrerror()); if (dev_get_os_pos(this, &mt_stat)) { Dmsg4(100, "Adjust from %d:%d to %d:%d\n", file, block_num, mt_stat.mt_fileno, mt_stat.mt_blkno); file = mt_stat.mt_fileno; block_num = mt_stat.mt_blkno; } else { if (at_eof()) { set_eot(); } else { set_ateof(); } } Mmsg3(errmsg, _("ioctl MTFSR %d error on %s. ERR=%s.\n"), num, prt_name, be.bstrerror()); } return status == 0; }
/* * Position device to end of medium (end of data) * * Returns: true on succes * false on error */ bool DEVICE::eod(DCR *dcr) { boffset_t pos; if (m_fd < 0) { dev_errno = EBADF; Mmsg1(errmsg, _("Bad call to eod. Device %s not open\n"), print_name()); return false; } if (is_vtl()) { return true; } Dmsg0(100, "Enter eod\n"); if (at_eot()) { return true; } clear_eof(); /* remove EOF flag */ block_num = file = 0; file_size = 0; file_addr = 0; pos = lseek(dcr, (boffset_t)0, SEEK_END); Dmsg1(200, "====== Seek to %lld\n", pos); if (pos >= 0) { update_pos(dcr); set_eot(); return true; } dev_errno = errno; berrno be; Mmsg2(errmsg, _("lseek error on %s. ERR=%s.\n"), print_name(), be.bstrerror()); Dmsg0(100, errmsg); return false; }
/* * Foward space a file * * Returns: true on success * false on failure */ bool generic_tape_device::fsf(int num) { int32_t os_file = 0; struct mtop mt_com; int status = 0; if (!is_open()) { dev_errno = EBADF; Mmsg0(errmsg, _("Bad call to fsf. Device not open\n")); Emsg0(M_FATAL, 0, errmsg); return false; } if (at_eot()) { dev_errno = 0; Mmsg1(errmsg, _("Device %s at End of Tape.\n"), prt_name); return false; } if (at_eof()) { Dmsg0(200, "ST_EOF set on entry to FSF\n"); } Dmsg0(100, "fsf\n"); block_num = 0; /* * If Fast forward space file is set, then we * use MTFSF to forward space and MTIOCGET * to get the file position. We assume that * the SCSI driver will ensure that we do not * forward space past the end of the medium. */ if (has_cap(CAP_FSF) && has_cap(CAP_MTIOCGET) && has_cap(CAP_FASTFSF)) { int my_errno = 0; mt_com.mt_op = MTFSF; mt_com.mt_count = num; status = d_ioctl(m_fd, MTIOCTOP, (char *)&mt_com); if (status < 0) { my_errno = errno; /* save errno */ } else if ((os_file=get_os_tape_file()) < 0) { my_errno = errno; /* save errno */ } if (my_errno != 0) { berrno be; set_eot(); Dmsg0(200, "Set ST_EOT\n"); clrerror(mt_com.mt_op); Mmsg2(errmsg, _("ioctl MTFSF error on %s. ERR=%s.\n"), prt_name, be.bstrerror(my_errno)); Dmsg1(200, "%s", errmsg); return false; } Dmsg1(200, "fsf file=%d\n", os_file); set_ateof(); file = os_file; return true; /* * Here if CAP_FSF is set, and virtually all drives * these days support it, we read a record, then forward * space one file. Using this procedure, which is slow, * is the only way we can be sure that we don't read * two consecutive EOF marks, which means End of Data. */ } else if (has_cap(CAP_FSF)) { POOLMEM *rbuf; int rbuf_len; Dmsg0(200, "FSF has cap_fsf\n"); if (max_block_size == 0) { rbuf_len = DEFAULT_BLOCK_SIZE; } else { rbuf_len = max_block_size; } rbuf = get_memory(rbuf_len); mt_com.mt_op = MTFSF; mt_com.mt_count = 1; while (num-- && !at_eot()) { Dmsg0(100, "Doing read before fsf\n"); if ((status = this->read((char *)rbuf, rbuf_len)) < 0) { if (errno == ENOMEM) { /* tape record exceeds buf len */ status = rbuf_len; /* This is OK */ /* * On IBM drives, they return ENOSPC at EOM instead of EOF status */ } else if (at_eof() && errno == ENOSPC) { status = 0; } else if (has_cap(CAP_IOERRATEOM) && at_eof() && errno == EIO) { if (has_cap(CAP_IBMLINTAPE)) { Dmsg0(100, "Got EIO on read, checking lin_tape sense data\n"); if (check_scsi_at_eod(m_fd)) { Dmsg0(100, "Sense data confirms it's EOD\n"); status = 0; } else { Dmsg0(100, "Not at EOD, might be a real error. Check sense trace from lin_taped logs.\n"); set_eot(); clrerror(-1); Mmsg1(errmsg, _("read error on %s. ERR=Input/Output error.\n"), prt_name); break; } } else { Dmsg0(100, "Got EIO on read, assuming that's due to EOD\n"); status = 0; } } else { berrno be; set_eot(); clrerror(-1); Dmsg2(100, "Set ST_EOT read errno=%d. ERR=%s\n", dev_errno, be.bstrerror()); Mmsg2(errmsg, _("read error on %s. ERR=%s.\n"), prt_name, be.bstrerror()); Dmsg1(100, "%s", errmsg); break; } } if (status == 0) { /* EOF */ Dmsg1(100, "End of File mark from read. File=%d\n", file+1); /* * Two reads of zero means end of tape */ if (at_eof()) { set_eot(); Dmsg0(100, "Set ST_EOT\n"); break; } else { set_ateof(); continue; } } else { /* Got data */ clear_eot(); clear_eof(); } Dmsg0(100, "Doing MTFSF\n"); status = d_ioctl(m_fd, MTIOCTOP, (char *)&mt_com); if (status < 0) { /* error => EOT */ berrno be; set_eot(); Dmsg0(100, "Set ST_EOT\n"); clrerror(mt_com.mt_op); Mmsg2(errmsg, _("ioctl MTFSF error on %s. ERR=%s.\n"), prt_name, be.bstrerror()); Dmsg0(100, "Got < 0 for MTFSF\n"); Dmsg1(100, "%s", errmsg); } else { set_ateof(); } } free_memory(rbuf); /* * No FSF, so use FSR to simulate it */ } else { Dmsg0(200, "Doing FSR for FSF\n"); while (num-- && !at_eot()) { fsr(INT32_MAX); /* returns -1 on EOF or EOT */ } if (at_eot()) { dev_errno = 0; Mmsg1(errmsg, _("Device %s at End of Tape.\n"), prt_name); status = -1; } else { status = 0; } } Dmsg1(200, "Return %d from FSF\n", status); if (at_eof()) { Dmsg0(200, "ST_EOF set on exit FSF\n"); } if (at_eot()) { Dmsg0(200, "ST_EOT set on exit FSF\n"); } Dmsg1(200, "Return from FSF file=%d\n", file); return status == 0; }