ndmp9_error ndmos_tape_write (struct ndm_session *sess, char *buf, u_long count, u_long *done_count) { ndmp9_error err; struct ndm_tape_agent * ta = sess->tape_acb; if (ta->tape_fd < 0) { return NDMP9_DEV_NOT_OPEN_ERR; } if (!NDMTA_TAPE_IS_WRITABLE(ta)) { return NDMP9_PERMISSION_ERR; } if (count == 0) { /* * NDMPv4 clarification -- a tape read or write with * a count==0 is a no-op. This is undoubtedly influenced * by the SCSI Sequential Access specification which * says much the same thing. */ *done_count = 0; return NDMP9_NO_ERR; } if (sess->ntsc && sess->ntsc->tape_write) { err = sess->ntsc->tape_write(sess, buf, count, done_count); if (err != NDMP9_NO_ERR) return err; } return NDMP9_NO_ERR; }
ndmp9_error ndmos_tape_wfm (struct ndm_session *sess) { ndmp9_error err; struct ndm_tape_agent * ta = sess->tape_acb; ta->weof_on_close = 0; if (ta->tape_fd < 0) { return NDMP9_DEV_NOT_OPEN_ERR; } if (!NDMTA_TAPE_IS_WRITABLE(ta)) { return NDMP9_PERMISSION_ERR; } if (sess->ntsc && sess->ntsc->tape_wfm) { err = sess->ntsc->tape_wfm(sess); if (err != NDMP9_NO_ERR) return err; } return NDMP9_NO_ERR; }
ndmp9_error ndmos_tape_wfm (struct ndm_session *sess) { struct ndm_tape_agent * ta = &sess->tape_acb; int rc; struct simu_gap gap; off_t cur_pos; ndmp9_error err; u_long prev_size; ta->weof_on_close = 0; if (ta->tape_fd < 0) { return NDMP9_DEV_NOT_OPEN_ERR; } if (!NDMTA_TAPE_IS_WRITABLE(ta)) { return NDMP9_PERMISSION_ERR; } cur_pos = lseek (ta->tape_fd, (off_t)0, 1); if (o_tape_limit) { /* note: filemarks *never* trigger NDMP9_EOM_ERR */ /* if this write will put us over PEOM, then send NDMP9_IO_ERR */ if ((off_t)(cur_pos + sizeof gap) > o_tape_limit) { return NDMP9_IO_ERR; } } rc = read (ta->tape_fd, &gap, sizeof gap); if (rc != sizeof gap || gap.magic != SIMU_GAP_MAGIC) { lseek (ta->tape_fd, cur_pos, 0); return NDMP9_IO_ERR; } prev_size = gap.prev_size; gap.magic = SIMU_GAP_MAGIC; gap.rectype = SIMU_GAP_RT_FILE; gap.prev_size = prev_size; gap.size = 0; lseek (ta->tape_fd, cur_pos, 0); if (write (ta->tape_fd, &gap, sizeof gap) == sizeof gap) { cur_pos += sizeof gap; prev_size = 0; ta->tape_state.file_num.value++; ta->tape_state.blockno.value = 0; err = NDMP9_NO_ERR; } else { err = NDMP9_IO_ERR; } if (ftruncate (ta->tape_fd, cur_pos) < 0) return NDMP9_IO_ERR; lseek (ta->tape_fd, cur_pos, 0); gap.rectype = SIMU_GAP_RT_EOT; gap.size = 0; gap.prev_size = prev_size; if (write (ta->tape_fd, &gap, sizeof gap) < (int)sizeof gap) return NDMP9_IO_ERR; lseek (ta->tape_fd, cur_pos, 0); if (o_tape_limit) { ta->tape_state.space_remain.value = o_tape_limit - cur_pos; } return err; }
ndmp9_error ndmos_tape_write (struct ndm_session *sess, char *buf, u_long count, u_long *done_count) { struct ndm_tape_agent * ta = &sess->tape_acb; int rc; struct simu_gap gap; off_t cur_pos; ndmp9_error err; u_long prev_size; if (ta->tape_fd < 0) { return NDMP9_DEV_NOT_OPEN_ERR; } if (!NDMTA_TAPE_IS_WRITABLE(ta)) { return NDMP9_PERMISSION_ERR; } if (count == 0) { /* * NDMPv4 clarification -- a tape read or write with * a count==0 is a no-op. This is undoubtedly influenced * by the SCSI Sequential Access specification which * says much the same thing. */ *done_count = 0; return NDMP9_NO_ERR; } cur_pos = lseek (ta->tape_fd, (off_t)0, 1); if (o_tape_limit) { /* if cur_pos is past LEOM, but we haven't sent NDMP9_EOM_ERR yet, * then do so now */ if (!ta->sent_leom && cur_pos > o_tape_limit - TAPE_SIM_LOGICAL_EOM) { ta->sent_leom = 1; return NDMP9_EOM_ERR; } /* if this write will put us over PEOM, then send NDMP9_IO_ERR */ if ((off_t)(cur_pos + sizeof gap + count) > o_tape_limit) { return NDMP9_IO_ERR; } } rc = read (ta->tape_fd, &gap, sizeof gap); if (rc != sizeof gap || gap.magic != SIMU_GAP_MAGIC) { lseek (ta->tape_fd, cur_pos, 0); return NDMP9_IO_ERR; } prev_size = gap.prev_size; gap.magic = SIMU_GAP_MAGIC; gap.rectype = SIMU_GAP_RT_DATA; gap.prev_size = prev_size; gap.size = count; lseek (ta->tape_fd, cur_pos, 0); if (write (ta->tape_fd, &gap, sizeof gap) == sizeof gap && (u_long)write (ta->tape_fd, buf, count) == count) { cur_pos += count + sizeof gap; prev_size = count; ta->tape_state.blockno.value++; *done_count = count; err = NDMP9_NO_ERR; } else { err = NDMP9_IO_ERR; } if (ftruncate (ta->tape_fd, cur_pos) < 0) return NDMP9_IO_ERR; lseek (ta->tape_fd, cur_pos, 0); gap.rectype = SIMU_GAP_RT_EOT; gap.size = 0; gap.prev_size = prev_size; if (write (ta->tape_fd, &gap, sizeof gap) < (int)sizeof gap) return NDMP9_IO_ERR; lseek (ta->tape_fd, cur_pos, 0); if (o_tape_limit) { ta->tape_state.space_remain.value = o_tape_limit - cur_pos; } ta->weof_on_close = 1; return err; }
ndmp9_error ndmos_tape_mtio (struct ndm_session *sess, ndmp9_tape_mtio_op op, u_long count, u_long *resid) { struct ndm_tape_agent * ta = &sess->tape_acb; int rc; *resid = count; if (ta->tape_fd < 0) { return NDMP9_DEV_NOT_OPEN_ERR; } /* audit for valid op and for tape mode */ switch (op) { case NDMP9_MTIO_FSF: while (*resid > 0) { simu_flush_weof(sess); rc = simu_forw_one (sess, 1); if (rc < 0) return NDMP9_IO_ERR; if (rc == 0) break; if (rc == SIMU_GAP_RT_FILE) *resid -= 1; } break; case NDMP9_MTIO_BSF: while (*resid > 0) { simu_flush_weof(sess); rc = simu_back_one (sess, 1); if (rc < 0) return NDMP9_IO_ERR; if (rc == 0) break; if (rc == SIMU_GAP_RT_FILE) *resid -= 1; } break; case NDMP9_MTIO_FSR: while (*resid > 0) { simu_flush_weof(sess); rc = simu_forw_one (sess, 0); if (rc < 0) return NDMP9_IO_ERR; if (rc == 0) break; *resid -= 1; } break; case NDMP9_MTIO_BSR: while (*resid > 0) { simu_flush_weof(sess); rc = simu_back_one (sess, 0); if (rc < 0) return NDMP9_IO_ERR; if (rc == 0) break; *resid -= 1; } break; case NDMP9_MTIO_REW: simu_flush_weof(sess); *resid = 0; ta->tape_state.file_num.value = 0; ta->tape_state.blockno.value = 0; lseek (ta->tape_fd, (off_t)(sizeof (struct simu_gap)), 0); break; case NDMP9_MTIO_OFF: simu_flush_weof(sess); /* Hmmm. */ break; case NDMP9_MTIO_EOF: /* should be "WFM" write-file-mark */ if (!NDMTA_TAPE_IS_WRITABLE(ta)) { return NDMP9_PERMISSION_ERR; } while (*resid > 0) { ndmp9_error err; err = ndmos_tape_wfm (sess); if (err != NDMP9_NO_ERR) return err; *resid -= 1; } break; default: return NDMP9_ILLEGAL_ARGS_ERR; } return NDMP9_NO_ERR; }