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

📄 tape-device.c

📁 开源备份软件源码 AMANDA, the Advanced Maryland Automatic Network Disk Archiver, is a backup system that a
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * Copyright (c) 2005 Zmanda, Inc.  All Rights Reserved. *  * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 2.1 as  * published by the Free Software Foundation. *  * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public * License for more details. *  * You should have received a copy of the GNU Lesser General Public License * along with this library; if not, write to the Free Software Foundation, * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA. *  * Contact information: Zmanda Inc., 505 N Mathlida Ave, Suite 120 * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com */#include <string.h> /* memset() */#include "util.h"#include "tape-device.h"#include "tape-ops.h"/* This is equal to 2*1024*1024*1024 - 16*1024*1024 - 1, but written    explicitly to avoid overflow issues. */#define RESETOFS_THRESHOLD (0x7effffff)/* Largest possible block size on SCSI systems. */#define LARGEST_BLOCK_ESTIMATE (16 * 1024 * 1024)struct TapeDevicePrivate_s {    /* This holds the total number of bytes written to the device,       modulus RESETOFS_THRESHOLD. */    int write_count;};/* Possible (abstracted) results from a system I/O operation. */typedef enum {    RESULT_SUCCESS,    RESULT_ERROR,        /* Undefined error. */    RESULT_SMALL_BUFFER, /* Tried to read with a buffer that is too                            small. */    RESULT_NO_DATA,      /* End of File, while reading */    RESULT_NO_SPACE,     /* Out of space. Sometimes we don't know if                            it was this or I/O error, but this is the                            preferred explanation. */    RESULT_MAX} IoResult;/* here are local prototypes */static void tape_device_init (TapeDevice * o);static void tape_device_class_init (TapeDeviceClass * c);static gboolean tape_device_open_device (Device * self, char * device_name);static ReadLabelStatusFlags tape_device_read_label(Device * self);static gboolean tape_device_write_block(Device * self, guint size,                                        gpointer data, gboolean short_block);static gboolean tape_device_read_block(Device * self,  gpointer buf,                                       int * size_req);static gboolean tape_device_start (Device * self, DeviceAccessMode mode,                                   char * label, char * timestamp);static gboolean tape_device_start_file (Device * self, const dumpfile_t * ji);static dumpfile_t * tape_device_seek_file (Device * self, guint file);static gboolean tape_device_seek_block (Device * self, guint64 block);static gboolean tape_device_property_get (Device * self, DevicePropertyId id,                                          GValue * val);static gboolean tape_device_property_set (Device * self, DevicePropertyId id,                                          GValue * val);static gboolean tape_device_finish (Device * self);static IoResult tape_device_robust_read (TapeDevice * self, void * buf,                                               int * count);static IoResult tape_device_robust_write (TapeDevice * self, void * buf, int count);static gboolean tape_device_fsf (TapeDevice * self, guint count);static gboolean tape_device_bsf (TapeDevice * self, guint count, guint file);static gboolean tape_device_fsr (TapeDevice * self, guint count);static gboolean tape_device_bsr (TapeDevice * self, guint count, guint file, guint block);static gboolean tape_device_eod (TapeDevice * self);/* pointer to the class of our parent */static DeviceClass *parent_class = NULL;GType tape_device_get_type (void){    static GType type = 0;        if G_UNLIKELY(type == 0) {        static const GTypeInfo info = {            sizeof (TapeDeviceClass),            (GBaseInitFunc) NULL,            (GBaseFinalizeFunc) NULL,            (GClassInitFunc) tape_device_class_init,            (GClassFinalizeFunc) NULL,            NULL /* class_data */,            sizeof (TapeDevice),            0 /* n_preallocs */,            (GInstanceInitFunc) tape_device_init,            NULL        };                type = g_type_register_static (TYPE_DEVICE, "TapeDevice",                                       &info, (GTypeFlags)0);    }    return type;}static void tape_device_init (TapeDevice * self) {    Device * device_self;    DeviceProperty prop;    GValue response;    device_self = (Device*)self;    bzero(&response, sizeof(response));    self->private = malloc(sizeof(TapeDevicePrivate));    /* Clear all fields. */    self->min_block_size = self->fixed_block_size = 32768;    self->max_block_size = self->read_block_size = MAX_TAPE_BLOCK_BYTES;    self->fd = -1;        self->fsf = self->bsf = self->fsr = self->bsr = self->eom =        self->bsf_after_eom = self->compression = self->first_file = 0;    self->final_filemarks = 2;    self->private->write_count = 0;    /* Register properites */    prop.base = &device_property_concurrency;    prop.access = PROPERTY_ACCESS_GET_MASK;    g_value_init(&response, CONCURRENCY_PARADIGM_TYPE);    g_value_set_enum(&response, CONCURRENCY_PARADIGM_EXCLUSIVE);    device_add_property(device_self, &prop, &response);    g_value_unset(&response);    prop.base = &device_property_streaming;    g_value_init(&response, STREAMING_REQUIREMENT_TYPE);    g_value_set_enum(&response, STREAMING_REQUIREMENT_DESIRED);    device_add_property(device_self, &prop, &response);    g_value_unset(&response);    prop.base = &device_property_appendable;    g_value_init(&response, G_TYPE_BOOLEAN);    g_value_set_boolean(&response, TRUE);    device_add_property(device_self, &prop, &response);    prop.base = &device_property_partial_deletion;    g_value_set_boolean(&response, FALSE);    device_add_property(device_self, &prop, &response);    g_value_unset(&response);    prop.base = &device_property_medium_access_type;    g_value_init(&response, MEDIA_ACCESS_MODE_TYPE);    g_value_set_enum(&response, MEDIA_ACCESS_MODE_READ_WRITE);    device_add_property(device_self, &prop, &response);    g_value_unset(&response);    prop.access = PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_MASK;    prop.base = &device_property_compression;    device_add_property(device_self, &prop, NULL);    prop.access = PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START;    prop.base = &device_property_min_block_size;    device_add_property(device_self, &prop, NULL);    prop.base = &device_property_max_block_size;    device_add_property(device_self, &prop, NULL);    prop.base = &device_property_block_size;    device_add_property(device_self, &prop, NULL);    prop.base = &device_property_fsf;    device_add_property(device_self, &prop, NULL);    prop.base = &device_property_bsf;    device_add_property(device_self, &prop, NULL);    prop.base = &device_property_fsr;    device_add_property(device_self, &prop, NULL);    prop.base = &device_property_bsr;    device_add_property(device_self, &prop, NULL);    prop.base = &device_property_eom;    device_add_property(device_self, &prop, NULL);    prop.base = &device_property_bsf_after_eom;    device_add_property(device_self, &prop, NULL);    prop.base = &device_property_final_filemarks;    device_add_property(device_self, &prop, NULL);        prop.access = PROPERTY_ACCESS_GET_MASK;    prop.base = &device_property_canonical_name;    device_add_property(device_self, &prop, NULL);}static void tape_device_finalize(GObject * obj_self) {    TapeDevice * self = TAPE_DEVICE(obj_self);    if(G_OBJECT_CLASS(parent_class)->finalize) \           (* G_OBJECT_CLASS(parent_class)->finalize)(obj_self);    robust_close(self->fd);    self->fd = -1;    amfree(self->private);}static void tape_device_class_init (TapeDeviceClass * c){    DeviceClass *device_class = (DeviceClass *)c;    GObjectClass *g_object_class = (GObjectClass *)c;    parent_class = g_type_class_ref (TYPE_DEVICE);        device_class->open_device = tape_device_open_device;    device_class->read_label = tape_device_read_label;    device_class->write_block = tape_device_write_block;    device_class->read_block = tape_device_read_block;    device_class->start = tape_device_start;    device_class->start_file = tape_device_start_file;    device_class->seek_file = tape_device_seek_file;    device_class->seek_block = tape_device_seek_block;    device_class->property_get = tape_device_property_get;    device_class->property_set = tape_device_property_set;    device_class->finish = tape_device_finish;        g_object_class->finalize = tape_device_finalize;}void tape_device_register(void) {    static const char * device_prefix_list[] = { "tape", NULL };    register_device(tape_device_factory, device_prefix_list);}#ifdef O_NONBLOCK/* Open the tape device, trying various combinations of O_RDWR and   O_NONBLOCK. */static int try_open_tape_device(TapeDevice * self, char * device_name) {    int rval;    rval  = robust_open(device_name, O_RDWR | O_NONBLOCK, 0);    if (rval < 0 && (errno == EWOULDBLOCK || errno == EINVAL)) {        /* Maybe we don't support O_NONBLOCK for tape devices. */        rval = robust_open(device_name, O_RDWR, 0);    }    if (rval >= 0) {        self->write_open_errno = 0;    } else {        if (errno == EACCES || errno == EPERM) {            /* Device is write-protected. */            self->write_open_errno = errno;            rval = robust_open(device_name, O_RDONLY | O_NONBLOCK, 0);            if (rval < 0 && (errno == EWOULDBLOCK || errno == EINVAL)) {                rval = robust_open(device_name, O_RDONLY, 0);            }        }    }    /* Clear O_NONBLOCK for operations from now on. */    fcntl(rval, F_SETFL, fcntl(rval, F_GETFL, 0) & ~O_NONBLOCK);    return rval;}#else /* !defined(O_NONBLOCK) */static int try_open_tape_device(TapeDevice * self, char * device_name) {    int rval;    rval = robust_open(device_name, O_RDWR);    if (rval >= 0) {        self->write_open_errno = 0;    } else {        if (errno == EACCES || errno == EPERM) {            /* Device is write-protected. */            self->write_open_errno = errno;            rval = robust_open(device_name, O_RDONLY);        }    }    return rval;}#endif /* O_NONBLOCK */static gboolean tape_device_open_device (Device * d_self, char * device_name) {    TapeDevice * self;    self = TAPE_DEVICE(d_self);    g_return_val_if_fail (self != NULL, FALSE);    g_return_val_if_fail (device_name != NULL, FALSE);    self->fd = try_open_tape_device(self, device_name);    if (self->fd < 0) {        g_fprintf(stderr, "Can't open tape device %s: %s\n",                device_name, strerror(errno));        return FALSE;    }    /* Check that this is actually a tape device. */    if (tape_is_tape_device(self->fd) == TAPE_CHECK_FAILURE) {        g_fprintf(stderr, "File %s is not a tape device.\n",                device_name);        robust_close(self->fd);        return FALSE;    }    if (tape_is_ready(self->fd) == TAPE_CHECK_FAILURE) {        g_fprintf(stderr,                  "Tape device %s is not ready or is empty.\n",                  device_name);        robust_close(self->fd);        return FALSE;    }    /* Rewind it. */    if (!tape_rewind(self->fd)) {        g_fprintf(stderr, "Error rewinding device %s\n",                device_name);        robust_close(self->fd);        return FALSE;    }    /* Get tape drive/OS info */    tape_device_discover_capabilities(self);    /* And verify the above. */    g_assert(feature_support_flags_is_valid(self->fsf));    g_assert(feature_support_flags_is_valid(self->bsf));    g_assert(feature_support_flags_is_valid(self->fsr));    g_assert(feature_support_flags_is_valid(self->bsr));    g_assert(feature_support_flags_is_valid(self->eom));    g_assert(feature_support_flags_is_valid(self->bsf_after_eom));    g_assert(self->final_filemarks == 1 ||             self->final_filemarks == 2);    /* Chain up */    if (parent_class->open_device) {        if (!(parent_class->open_device)(d_self, device_name)) {            robust_close(self->fd);            return FALSE;        }    }    return TRUE;}static ReadLabelStatusFlags tape_device_read_label(Device * dself) {    TapeDevice * self;    char * header_buffer;    int buffer_len;    IoResult result;    dumpfile_t header;    self = TAPE_DEVICE(dself);    g_return_val_if_fail(self != NULL, FALSE);    if (!tape_rewind(self->fd)) {        g_fprintf(stderr, "Error rewinding device %s\n",                dself->device_name);        return (READ_LABEL_STATUS_DEVICE_ERROR |                READ_LABEL_STATUS_VOLUME_ERROR);    }       buffer_len = self->read_block_size;    header_buffer = malloc(buffer_len);    result = tape_device_robust_read(self, header_buffer, &buffer_len);    if (result != RESULT_SUCCESS) {        free(header_buffer);        tape_rewind(self->fd);        /* I/O error. */        g_fprintf(stderr, "Error reading Amanda header.\n");        if (result == RESULT_NO_DATA) {            return (READ_LABEL_STATUS_VOLUME_ERROR |                    READ_LABEL_STATUS_VOLUME_UNLABELED);        } else {            return (READ_LABEL_STATUS_DEVICE_ERROR |                    READ_LABEL_STATUS_VOLUME_ERROR |                    READ_LABEL_STATUS_VOLUME_UNLABELED);        }    }    parse_file_header(header_buffer, &header, buffer_len);    amfree(header_buffer);    if (header.type != F_TAPESTART) {        return READ_LABEL_STATUS_VOLUME_UNLABELED;    }         dself->volume_label = g_strdup(header.name);    dself->volume_time = g_strdup(header.datestamp);       if (parent_class->read_label) {        return parent_class->read_label(dself);    } else {        return READ_LABEL_STATUS_SUCCESS;    }}static gbooleantape_device_write_block(Device * pself, guint size,                        gpointer data, gboolean short_block) {    TapeDevice * self;    char *replacement_buffer = NULL;    IoResult result;    self = TAPE_DEVICE(pself);    g_return_val_if_fail (self != NULL, FALSE);    g_return_val_if_fail (self->fd >= 0, FALSE);       if (short_block && self->min_block_size > size) {        replacement_buffer = malloc(self->min_block_size);        memcpy(replacement_buffer, data, size);        bzero(replacement_buffer+size, self->min_block_size-size);                data = replacement_buffer;        size = self->min_block_size;    }    result = tape_device_robust_write(self, data, size);    if (result == RESULT_SUCCESS) {        if (parent_class->write_block) {            (parent_class->write_block)(pself, size, data, short_block);        }        amfree(replacement_buffer);        return TRUE;    } else {        amfree(replacement_buffer);        return FALSE;    }        g_assert_not_reached();}static int tape_device_read_block (Device * pself, gpointer buf,                                   int * size_req) {    TapeDevice * self;    int size;    IoResult result;        self = TAPE_DEVICE(pself);    g_return_val_if_fail (self != NULL, -1);    if (buf == NULL || *size_req < (int)self->read_block_size) {        /* Just a size query. */        *size_req = self->read_block_size;        return 0;    }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -