📄 rait-device.c
字号:
GValue value; /* IN/OUT */ gboolean label_changed; /* Did the device label change? OUT; _set only*/} PropertyOp;/* Creates a GPtrArray of PropertyOf for a get or set operation. */static GPtrArray * make_property_op_array(RaitDevice * self, DevicePropertyId id, GValue * value) { guint i; GPtrArray * ops; ops = g_ptr_array_sized_new(self->private->children->len); for (i = 0; i < self->private->children->len; i ++) { PropertyOp * op; op = malloc(sizeof(*op)); op->base.child = g_ptr_array_index(self->private->children, i); op->id = id; bzero(&(op->value), sizeof(op->value)); if (value != NULL) { g_value_unset_copy(value, &(op->value)); } g_ptr_array_add(ops, op); } return ops;}/* A GFunc. */static void property_get_do_op(gpointer data, gpointer user_data G_GNUC_UNUSED) { PropertyOp * op = data; bzero(&(op->value), sizeof(op->value)); op->base.result = GINT_TO_POINTER(device_property_get(op->base.child, op->id, &(op->value)));}/* Merge ConcurrencyParadigm results. */static gboolean property_get_concurrency(GPtrArray * ops, GValue * val) { ConcurrencyParadigm result = CONCURRENCY_PARADIGM_RANDOM_ACCESS; guint i = 0; for (i = 0; i < ops->len; i ++) { ConcurrencyParadigm cur; PropertyOp * op = g_ptr_array_index(ops, i); g_return_val_if_fail(G_VALUE_TYPE(&(op->value)) == CONCURRENCY_PARADIGM_TYPE, FALSE); cur = g_value_get_enum(&(op->value)); if (result == CONCURRENCY_PARADIGM_EXCLUSIVE || cur == CONCURRENCY_PARADIGM_EXCLUSIVE) { result = CONCURRENCY_PARADIGM_EXCLUSIVE; } else if (result == CONCURRENCY_PARADIGM_SHARED_READ || cur == CONCURRENCY_PARADIGM_SHARED_READ) { result = CONCURRENCY_PARADIGM_SHARED_READ; } else if (result == CONCURRENCY_PARADIGM_RANDOM_ACCESS && cur == CONCURRENCY_PARADIGM_RANDOM_ACCESS) { result = CONCURRENCY_PARADIGM_RANDOM_ACCESS; } else { g_return_val_if_fail(FALSE, FALSE); } } g_value_unset_init(val, CONCURRENCY_PARADIGM_TYPE); g_value_set_enum(val, result); return TRUE;}/* Merge StreamingRequirement results. */static gboolean property_get_streaming(GPtrArray * ops, GValue * val) { StreamingRequirement result = STREAMING_REQUIREMENT_NONE; guint i = 0; for (i = 0; i < ops->len; i ++) { StreamingRequirement cur; PropertyOp * op = g_ptr_array_index(ops, i); g_return_val_if_fail(G_VALUE_TYPE(&(op->value)) == STREAMING_REQUIREMENT_TYPE, FALSE); cur = g_value_get_enum(&(op->value)); if (result == STREAMING_REQUIREMENT_REQUIRED || cur == STREAMING_REQUIREMENT_REQUIRED) { result = STREAMING_REQUIREMENT_REQUIRED; } else if (result == STREAMING_REQUIREMENT_DESIRED || cur == STREAMING_REQUIREMENT_DESIRED) { result = STREAMING_REQUIREMENT_DESIRED; } else if (result == STREAMING_REQUIREMENT_NONE && cur == STREAMING_REQUIREMENT_NONE) { result = STREAMING_REQUIREMENT_NONE; } else { g_return_val_if_fail(FALSE, FALSE); } } g_value_unset_init(val, STREAMING_REQUIREMENT_TYPE); g_value_set_enum(val, result); return TRUE;} /* Merge MediaAccessMode results. */static gboolean property_get_medium_type(GPtrArray * ops, GValue * val) { MediaAccessMode result = 0; guint i = 0; for (i = 0; i < ops->len; i ++) { MediaAccessMode cur; PropertyOp * op = g_ptr_array_index(ops, i); g_return_val_if_fail(G_VALUE_TYPE(&(op->value)) == MEDIA_ACCESS_MODE_TYPE, FALSE); cur = g_value_get_enum(&(op->value)); if (i == 0) { result = cur; } else if ((result == MEDIA_ACCESS_MODE_READ_ONLY && cur == MEDIA_ACCESS_MODE_WRITE_ONLY) || (result == MEDIA_ACCESS_MODE_WRITE_ONLY && cur == MEDIA_ACCESS_MODE_READ_ONLY)) { /* Invalid combination; one device can only read, other can only write. */ return FALSE; } else if (result == MEDIA_ACCESS_MODE_READ_ONLY || cur == MEDIA_ACCESS_MODE_READ_ONLY) { result = MEDIA_ACCESS_MODE_READ_ONLY; } else if (result == MEDIA_ACCESS_MODE_WRITE_ONLY || cur == MEDIA_ACCESS_MODE_WRITE_ONLY) { result = MEDIA_ACCESS_MODE_WRITE_ONLY; } else if (result == MEDIA_ACCESS_MODE_WORM || cur == MEDIA_ACCESS_MODE_WORM) { result = MEDIA_ACCESS_MODE_WORM; } else if (result == MEDIA_ACCESS_MODE_READ_WRITE && cur == MEDIA_ACCESS_MODE_READ_WRITE) { result = MEDIA_ACCESS_MODE_READ_WRITE; } else { g_return_val_if_fail(FALSE, FALSE); } } g_value_unset_init(val, MEDIA_ACCESS_MODE_TYPE); g_value_set_enum(val, result); return TRUE;} /* Merge QualifiedSize results. */static gboolean property_get_free_space(GPtrArray * ops, GValue * val) { QualifiedSize result; guint i = 0; for (i = 0; i < ops->len; i ++) { QualifiedSize cur; PropertyOp * op = g_ptr_array_index(ops, i); g_return_val_if_fail(G_VALUE_TYPE(&(op->value)) == QUALIFIED_SIZE_TYPE, FALSE); cur = *(QualifiedSize*)(g_value_get_boxed(&(op->value))); if (result.accuracy != cur.accuracy) { result.accuracy = SIZE_ACCURACY_ESTIMATE; } if (result.accuracy == SIZE_ACCURACY_UNKNOWN && cur.accuracy != SIZE_ACCURACY_UNKNOWN) { result.bytes = cur.bytes; } else if (result.accuracy != SIZE_ACCURACY_UNKNOWN && cur.accuracy == SIZE_ACCURACY_UNKNOWN) { /* result.bytes unchanged. */ } else { result.bytes = MIN(result.bytes, cur.bytes); } } g_value_unset_init(val, QUALIFIED_SIZE_TYPE); g_value_set_boxed(val, &result); return TRUE;} /* Merge boolean results by ANDing them together. */static gboolean property_get_boolean_and(GPtrArray * ops, GValue * val) { gboolean result = FALSE; guint i = 0; for (i = 0; i < ops->len; i ++) { gboolean cur; PropertyOp * op = g_ptr_array_index(ops, i); g_return_val_if_fail(G_VALUE_HOLDS_BOOLEAN(&(op->value)), FALSE); cur = g_value_get_boolean(&(op->value)); result = result && cur; } g_value_unset_init(val, G_TYPE_BOOLEAN); g_value_set_boolean(val, result); return TRUE;} static gboolean rait_device_property_get (Device * dself, DevicePropertyId id, GValue * val) { GPtrArray * ops; guint i; gboolean success; GValue result; GValue * first_value; RaitDevice * self = RAIT_DEVICE(dself); g_return_val_if_fail(self != NULL, FALSE); /* Some properties are handled completely differently. */ if (id == PROPERTY_BLOCK_SIZE) { g_value_unset_init(val, G_TYPE_INT); g_value_set_int(val, self->private->block_size); return TRUE; } else if (id == PROPERTY_MIN_BLOCK_SIZE || id == PROPERTY_MAX_BLOCK_SIZE) { g_value_unset_init(val, G_TYPE_UINT); g_value_set_uint(val, self->private->block_size); return TRUE; } else if (id == PROPERTY_CANONICAL_NAME) { if (parent_class->property_get != NULL) { return parent_class->property_get(dself, id, val); } else { return FALSE; } } ops = make_property_op_array(self, id, NULL); do_rait_child_ops(property_get_do_op, ops, NULL); if (id == PROPERTY_CONCURRENCY) { success = property_get_concurrency(ops, val); } else if (id == PROPERTY_STREAMING) { success = property_get_streaming(ops, val); } else if (id == PROPERTY_APPENDABLE || id == PROPERTY_PARTIAL_DELETION) { success = property_get_boolean_and(ops, val); } else if (id == PROPERTY_MEDIUM_TYPE) { success = property_get_medium_type(ops, val); } else if (id == PROPERTY_FREE_SPACE) { success = property_get_free_space(ops, val); } else { /* Generic handling; if all results are the same, we succeed and return that result. If not, we fail. */ success = TRUE; /* Set up comparison value. */ bzero(&result, sizeof(result)); first_value = &(((PropertyOp*)g_ptr_array_index(ops,0))->value); if (G_IS_VALUE(first_value)) { g_value_unset_copy(first_value, &result); } else { success = FALSE; } for (i = 0; i < ops->len; i ++) { PropertyOp * op = g_ptr_array_index(ops, i); if (!GPOINTER_TO_INT(op->base.result) || !G_IS_VALUE(first_value) || !g_value_compare(&result, &(op->value))) { success = FALSE; } g_value_unset(&(op->value)); } if (success) { memcpy(val, &result, sizeof(result)); } else if (G_IS_VALUE(&result)) { g_value_unset(&result); } } g_ptr_array_free_full(ops); return success;}/* A GFunc. */static void property_set_do_op(gpointer data, gpointer user_data G_GNUC_UNUSED) { PropertyOp * op = data; gboolean label_set = (op->base.child->volume_label != NULL); op->base.result = GINT_TO_POINTER(device_property_set(op->base.child, op->id, &(op->value))); op->label_changed = (label_set != (op->base.child->volume_label != NULL));}/* A BooleanExtractor */static gboolean extract_label_changed_property_op(gpointer data) { PropertyOp * op = data; return op->label_changed;}/* A GFunc. */static void clear_volume_details_do_op(gpointer data, gpointer user_data G_GNUC_UNUSED) { GenericOp * op = data; device_clear_volume_details(op->child);}static gboolean rait_device_property_set (Device * d_self, DevicePropertyId id, GValue * val) { RaitDevice * self; GPtrArray * ops; gboolean success; gboolean label_changed; self = RAIT_DEVICE(d_self); g_return_val_if_fail(self != NULL, FALSE); ops = make_property_op_array(self, id, val); do_rait_child_ops(property_set_do_op, ops, NULL); success = g_ptr_array_union_robust(self, ops, extract_boolean_generic_op); label_changed = g_ptr_array_union_robust(self, ops, extract_label_changed_property_op); g_ptr_array_free_full(ops); if (label_changed) { /* At least one device considered this property set a label-changing * operation, so now we clear labels on all devices. */ ops = make_generic_boolean_op_array(self); do_rait_child_ops(clear_volume_details_do_op, ops, NULL); g_ptr_array_free_full(ops); } return success;}typedef struct { GenericOp base; guint filenum;} RecycleFileOp;/* A GFunc */static void recycle_file_do_op(gpointer data, gpointer user_data G_GNUC_UNUSED) { RecycleFileOp * op = data; op->base.result = GINT_TO_POINTER(device_recycle_file(op->base.child, op->filenum));}static gboolean rait_device_recycle_file (Device * dself, guint filenum) { GPtrArray * ops; guint i; gboolean success; RaitDevice * 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 ++) { RecycleFileOp * op; op = malloc(sizeof(*op)); op->base.child = g_ptr_array_index(self->private->children, i); op->filenum = filenum; g_ptr_array_add(ops, op); } do_rait_child_ops(recycle_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->recycle_file) { return parent_class->recycle_file(dself, filenum); } else { return TRUE; }}/* GFunc */static void finish_do_op(gpointer data, gpointer user_data G_GNUC_UNUSED) { GenericOp * op = data; op->result = GINT_TO_POINTER(device_finish(op->child));}static gboolean rait_device_finish (Device * self) { GPtrArray * ops; gboolean success; ops = make_generic_boolean_op_array(RAIT_DEVICE(self)); do_rait_child_ops(finish_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->finish) { return parent_class->finish(self); } else { return TRUE; }}Device *rait_device_factory (char * type, char * name) { Device * rval; g_assert(0 == strcmp(type, "rait")); rval = DEVICE(g_object_new(TYPE_RAIT_DEVICE, NULL)); if (!device_open_device(rval, name)) { g_object_unref(rval); return NULL; } else { return rval; }}Device * rait_device_new_from_devices(Device ** devices) { RaitDevice * rval; int i; gboolean success = TRUE; g_return_val_if_fail(devices != NULL && *devices != NULL, NULL); rval = RAIT_DEVICE(g_object_new(TYPE_RAIT_DEVICE, NULL)); for (i = 0; devices[i] != NULL; i ++) { g_assert(IS_DEVICE(devices[i])); if (devices[i]->access_mode != ACCESS_NULL) { success = FALSE; break; } g_object_ref(devices[i]); g_ptr_array_add(PRIVATE(rval)->children, devices[i]); } success = success && find_block_size(rval); if (!success) { g_ptr_array_free(PRIVATE(rval)->children, TRUE); return NULL; } else { register_properties(rval); return DEVICE(rval); }}void rait_device_register (void) { static const char * device_prefix_list[] = {"rait", NULL}; register_device(rait_device_factory, device_prefix_list);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -