📄 tape-device.c
字号:
size = *size_req; result = tape_device_robust_read(self, buf, &size); switch (result) { case RESULT_SUCCESS: *size_req = size; return size; case RESULT_SMALL_BUFFER: { int new_size; /* If this happens, it means that we have: * (next block size) > (buffer size) >= (read_block_size) * The solution is to ask for an even bigger buffer. We also play * some games to refrain from reading above the SCSI limit or from * integer overflow. */ new_size = MIN(INT_MAX/2 - 1, *size_req) * 2; if (new_size > LARGEST_BLOCK_ESTIMATE && *size_req < LARGEST_BLOCK_ESTIMATE) { new_size = LARGEST_BLOCK_ESTIMATE; } if (new_size <= *size_req) { return -1; } else { *size_req = new_size; return 0; } } case RESULT_NO_DATA: pself->is_eof = TRUE; /* FALLTHROUGH */ default: return -1; } g_assert_not_reached();}/* Just a helper function for tape_device_start(). */static gboolean write_tapestart_header(TapeDevice * self, char * label, char * timestamp) { IoResult result; dumpfile_t * header; char * header_buf; int header_size; gboolean header_fits; Device * d_self = (Device*)self; tape_rewind(self->fd); header = make_tapestart_header(d_self, label, timestamp); g_assert(header != NULL); header_buf = device_build_amanda_header(d_self, header, &header_size, &header_fits); amfree(header); g_assert(header_buf != NULL); if (!header_fits) { amfree(header_buf); g_fprintf(stderr, "Tapestart header won't fit in a single block!\n"); return FALSE; } g_assert(header_size >= (int)self->min_block_size); result = tape_device_robust_write(self, header_buf, header_size); amfree(header_buf); return (result == RESULT_SUCCESS);}static gboolean tape_device_start (Device * d_self, DeviceAccessMode mode, char * label, char * timestamp) { TapeDevice * self; self = TAPE_DEVICE(d_self); g_return_val_if_fail(self != NULL, FALSE); if (IS_WRITABLE_ACCESS_MODE(mode)) { if (self->write_open_errno != 0) { /* We tried and failed to open the device in write mode. */ g_fprintf(stderr, "Can't open tape device %s for writing: %s\n", d_self->device_name, strerror(self->write_open_errno)); return FALSE; } else if (!tape_rewind(self->fd)) { g_fprintf(stderr, "Couldn't rewind device: %s\n", strerror(errno)); } } /* Position the tape */ switch (mode) { case ACCESS_APPEND: if (!tape_device_eod(self)) return FALSE; self->first_file = TRUE; break; case ACCESS_READ: if (!tape_rewind(self->fd)) { g_fprintf(stderr, "Error rewinding device %s\n", d_self->device_name); return FALSE; } d_self->file = 0; break; case ACCESS_WRITE: if (!write_tapestart_header(self, label, timestamp)) { return FALSE; } self->first_file = TRUE; break; default: g_assert_not_reached(); } if (parent_class->start) { return parent_class->start(d_self, mode, label, timestamp); } else { return TRUE; }}static gboolean tape_device_start_file(Device * d_self, const dumpfile_t * info) { TapeDevice * self; IoResult result; char * amanda_header; int header_size; gboolean header_fits; self = TAPE_DEVICE(d_self); g_return_val_if_fail(self != NULL, FALSE); g_return_val_if_fail (self->fd >= 0, FALSE); if (!(d_self->access_mode == ACCESS_APPEND && self->first_file)) { if (!tape_weof(self->fd, 1)) { g_fprintf(stderr, "Error writing filemark: %s\n", strerror(errno)); return FALSE; } } self->first_file = FALSE; /* Make the Amanda header suitable for writing to the device. */ /* Then write the damn thing. */ amanda_header = device_build_amanda_header(d_self, info, &header_size, &header_fits); g_return_val_if_fail(amanda_header != NULL, FALSE); g_return_val_if_fail(header_fits, FALSE); result = tape_device_robust_write(self, amanda_header, header_size); amfree(amanda_header); if (result == RESULT_SUCCESS) { /* Chain up. */ if (parent_class->start_file) { parent_class->start_file(d_self, info); } return TRUE; } else { return FALSE; }}static dumpfile_t * tape_device_seek_file (Device * d_self, guint file) { TapeDevice * self; int difference; char * header_buffer; dumpfile_t * rval; int buffer_len; IoResult result; self = TAPE_DEVICE(d_self); g_return_val_if_fail(d_self != NULL, NULL); d_self->in_file = FALSE; difference = file - d_self->file; /* Check if we already read a filemark. */ if (d_self->is_eof) { difference --; } if (difference > 0) { /* Seeking forwards */ if (!tape_device_fsf(self, difference)) { tape_rewind(self->fd); return NULL; } } else if (difference < 0) { /* Seeking backwards */ if (!tape_device_bsf(self, -difference, d_self->file)) { tape_rewind(self->fd); return NULL; } } buffer_len = self->read_block_size; header_buffer = malloc(buffer_len); d_self->is_eof = FALSE; result = tape_device_robust_read(self, header_buffer, &buffer_len); if (result != RESULT_SUCCESS) { free(header_buffer); tape_rewind(self->fd); if (result == RESULT_NO_DATA) { /* If we read 0 bytes, that means we encountered a double * filemark, which indicates end of tape. This should * work even with QIC tapes on operating systems with * proper support. */ return make_tapeend_header(); } /* I/O error. */ g_fprintf(stderr, "Error reading Amanda header.\n"); return FALSE; } rval = malloc(sizeof(*rval)); parse_file_header(header_buffer, rval, buffer_len); amfree(header_buffer); switch (rval->type) { case F_DUMPFILE: case F_CONT_DUMPFILE: case F_SPLIT_DUMPFILE: d_self->in_file = TRUE; d_self->file = file; return rval; default: tape_rewind(self->fd); amfree(rval); return NULL; }}static gboolean tape_device_seek_block (Device * d_self, guint64 block) { TapeDevice * self; int difference; self = TAPE_DEVICE(d_self); g_return_val_if_fail(d_self != NULL, FALSE); difference = block - d_self->block; if (difference > 0) { if (!tape_device_fsr(self, difference)) return FALSE; } else if (difference < 0) { if (!tape_device_bsr(self, difference, d_self->file, d_self->block)) return FALSE; } if (parent_class->seek_block) { return (parent_class->seek_block)(d_self, block); } else { return TRUE; }}/* Just checks that the flag is valid before setting it. */static gboolean get_feature_flag(GValue * val, FeatureSupportFlags f) { if (feature_support_flags_is_valid(f)) { g_value_set_flags(val, f); return TRUE; } else { return FALSE; }}static gboolean tape_device_property_get (Device * d_self, DevicePropertyId id, GValue * val) { TapeDevice * self; const DevicePropertyBase * base; self = TAPE_DEVICE(d_self); g_return_val_if_fail(self != NULL, FALSE); base = device_property_get_by_id(id); g_return_val_if_fail(self != NULL, FALSE); g_value_unset_init(val, base->type); if (id == PROPERTY_COMPRESSION) { g_value_set_boolean(val, self->compression); return TRUE; } else if (id == PROPERTY_MIN_BLOCK_SIZE) { g_value_set_uint(val, self->min_block_size); return TRUE; } else if (id == PROPERTY_MAX_BLOCK_SIZE) { g_value_set_uint(val, self->max_block_size); return TRUE; } else if (id == PROPERTY_BLOCK_SIZE) { if (self->fixed_block_size == 0) { g_value_set_int(val, -1); } else { g_value_set_int(val, self->fixed_block_size); } return TRUE; } else if (id == PROPERTY_FSF) { return get_feature_flag(val, self->fsf); } else if (id == PROPERTY_BSF) { return get_feature_flag(val, self->bsf); } else if (id == PROPERTY_FSR) { return get_feature_flag(val, self->fsr); } else if (id == PROPERTY_BSR) { return get_feature_flag(val, self->bsr); } else if (id == PROPERTY_EOM) { return get_feature_flag(val, self->eom); } else if (id == PROPERTY_BSF_AFTER_EOM) { return get_feature_flag(val, self->bsf_after_eom); } else if (id == PROPERTY_FINAL_FILEMARKS) { g_value_set_uint(val, self->final_filemarks); return TRUE; } else { /* Chain up */ if (parent_class->property_get) { return (parent_class->property_get)(d_self, id, val); } else { return FALSE; } } g_assert_not_reached();}/* We don't allow overriding of flags with _GOOD surety. That way, if e.g., a feature has no matching IOCTL on a given platform, we don't ever try to set it. */static gboolean flags_settable(FeatureSupportFlags request, FeatureSupportFlags existing) { if (!feature_support_flags_is_valid(request)) return FALSE; else if (!feature_support_flags_is_valid(existing)) return TRUE; else if (request == existing) return TRUE; else if (existing & FEATURE_SURETY_GOOD) return FALSE; else return TRUE;}/* If the access listed is NULL, and the provided flags can override the existing ones, then do it and return TRUE. */static gboolean try_set_feature(DeviceAccessMode mode, FeatureSupportFlags request, FeatureSupportFlags * existing) { if (mode != ACCESS_NULL) { return FALSE; } else if (flags_settable(request, *existing)) { *existing = request; return TRUE; } else { return FALSE; }} static gboolean tape_device_property_set (Device * d_self, DevicePropertyId id, GValue * val) { TapeDevice * self; FeatureSupportFlags feature_request_flags = 0; const DevicePropertyBase * base; self = TAPE_DEVICE(d_self); g_return_val_if_fail(self != NULL, FALSE); base = device_property_get_by_id(id); g_return_val_if_fail(self != NULL, FALSE); g_return_val_if_fail(G_VALUE_HOLDS(val, base->type), FALSE); if (base->type == FEATURE_SUPPORT_FLAGS_TYPE) { feature_request_flags = g_value_get_flags(val); g_return_val_if_fail( feature_support_flags_is_valid(feature_request_flags), FALSE); } if (id == PROPERTY_COMPRESSION) { /* We allow this property to be set at any time. This is mostly * because setting compression is a hit-and-miss proposition * at any time; some drives accept the mode setting but don't * actually support compression, while others do support * compression but do it via density settings or some other * way. Set this property whenever you want, but all we'll do * is report whether or not the ioctl succeeded. */ gboolean request = g_value_get_boolean(val); if (tape_setcompression(self->fd, request)) { self->compression = request; device_clear_volume_details(d_self); return TRUE; } else { return FALSE; } } else if (id == PROPERTY_MIN_BLOCK_SIZE) { if (d_self->access_mode != ACCESS_NULL) return FALSE; self->min_block_size = g_value_get_uint(val); device_clear_volume_details(d_self); return TRUE; } else if (id == PROPERTY_MAX_BLOCK_SIZE) { if (d_self->access_mode != ACCESS_NULL) return FALSE; self->max_block_size = g_value_get_uint(val); device_clear_volume_details(d_self); return TRUE; } else if (id == PROPERTY_BLOCK_SIZE) { if (d_self->access_mode != ACCESS_NULL) return FALSE; self->fixed_block_size = g_value_get_int(val); device_clear_volume_details(d_self); return TRUE; } else if (id == PROPERTY_READ_BUFFER_SIZE) { if (d_self->access_mode != ACCESS_NULL) return FALSE; self->read_block_size = g_value_get_uint(val); device_clear_volume_details(d_self); return TRUE; } else if (id == PROPERTY_FSF) { return try_set_feature(d_self->access_mode, feature_request_flags, &(self->fsf)); } else if (id == PROPERTY_BSF) { return try_set_feature(d_self->access_mode, feature_request_flags, &(self->bsf)); } else if (id == PROPERTY_FSR) { return try_set_feature(d_self->access_mode, feature_request_flags, &(self->fsr)); } else if (id == PROPERTY_BSR) { return try_set_feature(d_self->access_mode, feature_request_flags, &(self->bsr)); } else if (id == PROPERTY_EOM) { /* Setting this to disabled also clears BSF after EOM. */ if (try_set_feature(d_self->access_mode, feature_request_flags, &(self->eom))) { feature_request_flags &= ~FEATURE_SUPPORT_FLAGS_STATUS_MASK; feature_request_flags |= FEATURE_STATUS_DISABLED;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -