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

📄 rait-device.c

📁 开源备份软件源码 AMANDA, the Advanced Maryland Automatic Network Disk Archiver, is a backup system that a
💻 C
📖 第 1 页 / 共 4 页
字号:
/* A BooleanExtractor */static gboolean extract_boolean_generic_op(gpointer data) {    GenericOp * op = data;    return GPOINTER_TO_INT(op->result);}/* A BooleanExtractor */static gboolean extract_boolean_pointer_op(gpointer data) {    GenericOp * op = data;    return op->result != NULL;}/* Does the equivalent of this perl command:     ! (first { !extractor($_) } @_   That is, calls extractor on each element of the array, and returns   TRUE if and only if all calls to extractor return TRUE.*/static gboolean g_ptr_array_and(GPtrArray * array,                                BooleanExtractor extractor) {    guint i;    if (array == NULL || array->len <= 0)        return FALSE;    for (i = 0; i < array->len; i ++) {        if (!extractor(g_ptr_array_index(array, i)))            return FALSE;    }    return TRUE;}/* Takes a RaitDevice, and makes a GPtrArray of GenericOp. */static GPtrArray * make_generic_boolean_op_array(RaitDevice* self) {    GPtrArray * rval;    guint i;    rval = g_ptr_array_sized_new(self->private->children->len);    for (i = 0; i < self->private->children->len; i ++) {        GenericOp * op;        op = malloc(sizeof(*op));        op->child = g_ptr_array_index(self->private->children, i);        op->child_index = i;        g_ptr_array_add(rval, op);    }    return rval;}/* Takes a GPtrArray of GenericOp, and a BooleanExtractor, and does   all the proper handling for the result of operations that allow   device isolation. Returns FALSE only if an unrecoverable error   occured. */static gboolean g_ptr_array_union_robust(RaitDevice * self, GPtrArray * ops,                                         BooleanExtractor extractor) {    gboolean success;    gpointer isolated_op = NULL;    for (;;) {        success = g_ptr_array_and(ops, extractor);                if (success || self->private->status != RAIT_STATUS_COMPLETE) {            break;        } else {            guint i;            /* First device failure, note the device and march on. */            self->private->status = RAIT_STATUS_DEGRADED;            for (i = 0; i < ops->len; i ++) {                GenericOp * op = g_ptr_array_index(ops, i);                if (!(op->result)) {                    isolated_op = g_ptr_array_remove_index_fast(ops, i);                    self->private->failed = op->child_index;                    g_fprintf(stderr, "RAIT array %s Isolated device %s.\n",                            DEVICE(self)->device_name,                            op->child->device_name);                    break;                }            }        }    }    /* Return isolated op so any data members can be freed. */    if (isolated_op != NULL) {        g_ptr_array_add(ops, isolated_op);    }    return success;}typedef struct {    Device * result;    /* IN */    char * device_name; /* OUT */} OpenDeviceOp;/* A GFunc. */static void open_device_do_op(gpointer data,                              gpointer user_data G_GNUC_UNUSED) {    OpenDeviceOp * op = data;    op->result = device_open(op->device_name);    amfree(op->device_name);}/* Returns TRUE if and only if the volume label and time are equal. */static gboolean compare_volume_results(Device * a, Device * b) {    if (a->volume_time != b->volume_time)        return FALSE;    if (a->volume_label == NULL && b->volume_label == NULL)        return TRUE;    if (a->volume_label == NULL || b->volume_label == NULL)        return FALSE;    return 0 == strcmp(a->volume_label, b->volume_label);}static gboolean rait_device_open_device (Device * dself, char * device_name) {    char ** device_names;    GPtrArray * open_device_ops;    guint i;    gboolean failure;    RaitDevice * self;    self = RAIT_DEVICE(dself);    g_return_val_if_fail(self != NULL, FALSE);    g_return_val_if_fail (device_name != NULL, FALSE);    device_names = parse_device_name(device_name);        if (device_names == NULL)        return FALSE;    /* Open devices in a separate thread, in case they have to rewind etc. */    open_device_ops = g_ptr_array_new();    for (i = 0; device_names[i] != NULL; i ++) {        OpenDeviceOp *op;        op = malloc(sizeof(*op));        op->device_name = device_names[i];        op->result = NULL;        g_ptr_array_add(open_device_ops, op);    }    free(device_names);    do_rait_child_ops(open_device_do_op, open_device_ops, NULL);    failure = FALSE;    /* Check results of opening devices. */    for (i = 0; i < open_device_ops->len; i ++) {        OpenDeviceOp *op = g_ptr_array_index(open_device_ops, i);                if (op->result != NULL) {            g_ptr_array_add(self->private->children, op->result);        } else {            failure = TRUE;        }    }    g_ptr_array_free_full(open_device_ops);    failure = failure || !find_block_size(self);    if (failure)        return FALSE; /* This will clean up any created children. */    register_properties(self);    /* Chain up. */    if (parent_class->open_device) {        return parent_class->open_device(dself, device_name);    } else {        return TRUE;    }}/* A GFunc. */static void read_label_do_op(gpointer data,                             gpointer user_data G_GNUC_UNUSED) {    GenericOp * op = data;    op->result = GINT_TO_POINTER(device_read_label(op->child));}static ReadLabelStatusFlags rait_device_read_label(Device * dself) {    RaitDevice * self;    GPtrArray * ops;    ReadLabelStatusFlags failed_result = 0;    ReadLabelStatusFlags rval;    GenericOp * failed_op = NULL; /* If this is non-null, we will isolate. */    unsigned int i;    Device * first_success = NULL;    self = RAIT_DEVICE(dself);    g_return_val_if_fail(self != NULL, FALSE);    amfree(dself->volume_label);    ops = make_generic_boolean_op_array(self);        do_rait_child_ops(read_label_do_op, ops, NULL);        for (i = 0; i < ops->len; i ++) {        GenericOp * op = g_ptr_array_index(ops, i);        ReadLabelStatusFlags result = GPOINTER_TO_INT(op->result);        if (op->result == READ_LABEL_STATUS_SUCCESS) {            if (first_success == NULL) {                /* This is the first successful device. */                first_success = op->child;            } else if (!compare_volume_results(first_success, op->child)) {                /* Doesn't match. :-( */                g_fprintf(stderr, "Inconsistant volume labels: "                        "Got %s/%s against %s/%s.\n",                        first_success->volume_label,                        first_success->volume_time,                         op->child->volume_label,                        op->child->volume_time);                failed_result |= READ_LABEL_STATUS_VOLUME_ERROR;                failed_op = NULL;            }        } else {            if (failed_result == 0 &&                self->private->status == RAIT_STATUS_COMPLETE) {                /* This is the first failed device; note it and we'll isolate                   later. */                failed_op = op;                failed_result = result;            } else {                /* We've encountered multiple failures. OR them together. */                failed_result |= result;                failed_op = NULL;            }        }    }    if (failed_op != NULL) {        /* We have a single device to isolate. */        failed_result = READ_LABEL_STATUS_SUCCESS; /* Recover later */        self->private->failed = failed_op->child_index;        g_fprintf(stderr, "RAIT array %s Isolated device %s.\n",                dself->device_name,                failed_op->child->device_name);    }    if (failed_result != READ_LABEL_STATUS_SUCCESS) {        /* We had multiple failures or an inconsistency. */        rval = failed_result;    } else {        /* Everything peachy. */        rval = READ_LABEL_STATUS_SUCCESS;        g_assert(first_success != NULL);        if (first_success->volume_label != NULL) {            dself->volume_label = g_strdup(first_success->volume_label);        }        if (first_success->volume_time != NULL) {            dself->volume_time = g_strdup(first_success->volume_time);        }    }        g_ptr_array_free_full(ops);    return rval;}typedef struct {    GenericOp base;    DeviceAccessMode mode; /* IN */    char * label;          /* IN */    char * timestamp;      /* IN */} StartOp;/* A GFunc. */static void start_do_op(gpointer data, gpointer user_data G_GNUC_UNUSED) {    DeviceClass *klass;    StartOp * param = data;        klass = DEVICE_GET_CLASS(param->base.child);    if (klass->start) {        param->base.result =            GINT_TO_POINTER((klass->start)(param->base.child,                                            param->mode, param->label,                                            param->timestamp));    } else {        param->base.result = FALSE;    }}static gboolean rait_device_start (Device * dself, DeviceAccessMode mode, char * label,                   char * timestamp) {    GPtrArray * ops;    guint i;    gboolean success;    RaitDevice * self;    self = RAIT_DEVICE(dself);    g_return_val_if_fail(self != NULL, FALSE);    ops = g_ptr_array_sized_new(self->private->children->len);    for (i = 0; i < self->private->children->len; i ++) {        StartOp * op;        op = malloc(sizeof(*op));        op->base.child = g_ptr_array_index(self->private->children, i);        op->mode = mode;        op->label = g_strdup(label);        op->timestamp = g_strdup(timestamp);        g_ptr_array_add(ops, op);    }        do_rait_child_ops(start_do_op, ops, NULL);    success = g_ptr_array_and(ops, extract_boolean_generic_op);    g_ptr_array_free_full(ops);    if (!success) {        return FALSE;    } else if (parent_class->start) {        return parent_class->start(dself, mode, label, timestamp);    } else {        return TRUE;    }}typedef struct {    GenericOp base;    const dumpfile_t * info; /* IN */} StartFileOp;/* a GFunc */static void start_file_do_op(gpointer data, gpointer user_data G_GNUC_UNUSED) {    StartFileOp * op = data;    op->base.result = GINT_TO_POINTER(device_start_file(op->base.child,                                                        op->info));}static gbooleanrait_device_start_file (Device * dself, const dumpfile_t * info) {    GPtrArray * ops;    guint i;    gboolean success;    RaitDevice * self;    self = RAIT_DEVICE(dself);    g_return_val_if_fail(self != NULL, FALSE);    ops = g_ptr_array_sized_new(self->private->children->len);    for (i = 0; i < self->private->children->len; i ++) {        StartFileOp * op;        op = malloc(sizeof(*op));        op->base.child = g_ptr_array_index(self->private->children, i);        op->info = info;        g_ptr_array_add(ops, op);    }        do_rait_child_ops(start_file_do_op, ops, NULL);    success = g_ptr_array_and(ops, extract_boolean_generic_op);    g_ptr_array_free_full(ops);    if (!success) {        return FALSE;    } else if (parent_class->start_file) {        return parent_class->start_file(dself, info);    } else {        return TRUE;    }}static void find_simple_params(RaitDevice * self,                               guint * num_children,                               guint * data_children,                               int * blocksize) {    int num, data;        num = self->private->children->len;    if (num > 1)        data = num - 1;    else        data = num;    if (num_children != NULL)        *num_children = num;    if (data_children != NULL)        *data_children = data;    if (blocksize != NULL) {        *blocksize = device_write_min_size(DEVICE(self));    }}typedef struct {    GenericOp base;    guint size;           /* IN */    gpointer data;        /* IN */    gboolean short_block; /* IN */    gboolean data_needs_free; /* bookkeeping */} WriteBlockOp;/* a GFunc. */static void write_block_do_op(gpointer data,                              gpointer user_data G_GNUC_UNUSED) {    WriteBlockOp * op = data;    op->base.result =        GINT_TO_POINTER(device_write_block(op->base.child, op->size, op->data,                                           op->short_block));}/* Parity block generation. Performance of this function can be improved   considerably by using larger-sized integers or   assembly-coded vector instructions. Parameters are:   % data       - All data chunks in series (chunk_size * num_chunks bytes)   % parity     - Allocated space for parity block (chunk_size bytes) */static void make_parity_block(char * data, char * parity,                              guint chunk_size, guint num_chunks) {    guint i;    bzero(parity, chunk_size);    for (i = 0; i < num_chunks - 1; i ++) {        guint j;        for (j = 0; j < chunk_size; j ++) {            parity[j] ^= data[chunk_size*i + j];        }    }}/* Does the same thing as make_parity_block, but instead of using a   single memory chunk holding all chunks, it takes a GPtrArray of   chunks. */static void make_parity_block_extents(GPtrArray * data, char * parity,                                      guint chunk_size) {    guint i;    bzero(parity, chunk_size);    for (i = 0; i < data->len; i ++) {        guint j;        char * data_chunk;        data_chunk = g_ptr_array_index(data, i);        for (j = 0; j < chunk_size; j ++) {            parity[j] ^= data_chunk[j];        }    }}/* Does the parity creation algorithm. Allocates and returns a single   device block from a larger RAIT block. chunks and chunk are 1-indexed. */static char * extract_data_block(char * data, guint size,                                 guint chunks, guint chunk) {    char * rval;    guint chunk_size;    g_return_val_if_fail(chunks > 0 && chunk > 0 && chunk <= chunks, NULL);    g_return_val_if_fail(data != NULL, NULL);    g_return_val_if_fail(size > 0 && size % (chunks - 1) == 0, NULL);

⌨️ 快捷键说明

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