⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tape-device.c

📁 开源备份软件源码 AMANDA, the Advanced Maryland Automatic Network Disk Archiver, is a backup system that a
💻 C
📖 第 1 页 / 共 3 页
字号:
    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 + -