/*
- * Copyright (c) 2005 Zmanda, Inc. All Rights Reserved.
+ * Copyright (c) 2005-2008 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
* 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
+ * Contact information: Zmanda Inc., 465 S Mathlida Ave, Suite 300
+ * Sunnyvale, CA 94086, USA, or: http://www.zmanda.com
*/
#include "amanda.h"
#include "property.h"
+#include "glib-util.h"
+
+/*****
+ * Property-specific Types, etc.
+ */
static const GEnumValue _concurrency_paradigm_values[] = {
{ CONCURRENCY_PARADIGM_EXCLUSIVE,
/* Copy function for GBoxed QualifiedSize. */
static gpointer qualified_size_copy(gpointer source) {
- gpointer rval = malloc(sizeof(QualifiedSize));
+ gpointer rval = g_new(QualifiedSize, 1);
memcpy(rval, source, sizeof(QualifiedSize));
return rval;
}
return type;
}
-static const GFlagsValue _feature_support_flags_values[] = {
- { FEATURE_STATUS_ENABLED,
- "FEATURE_STATUS_ENABLED",
- "enabled" },
- { FEATURE_STATUS_DISABLED,
- "FEATURE_STATUS_DISABLED",
- "disabled" },
- { FEATURE_SURETY_BAD,
- "FEATURE_SURETY_BAD",
- "bad" },
- { FEATURE_SURETY_GOOD,
- "FEATURE_SURETY_GOOD",
- "good" },
- { FEATURE_SOURCE_DEFAULT,
- "FEATURE_SOURCE_DEFAULT",
- "default" },
- { FEATURE_SOURCE_DETECTED,
- "FEATURE_SOURCE_DETECTED",
- "detected" },
- { FEATURE_SOURCE_USER,
- "FEATURE_SOURCE_USER",
- "user"},
- { 0, NULL, NULL }
-};
+/******
+ * Property registration and lookup
+ */
-GType feature_support_get_type (void) {
- static GType type = 0;
- if (G_UNLIKELY(type == 0)) {
- type = g_flags_register_static ("FeatureSupportFlags",
- _feature_support_flags_values);
- }
- return type;
-}
+static GPtrArray *device_property_bases = NULL;
+static GHashTable *device_property_bases_by_name = NULL;
-gboolean feature_support_flags_is_valid(FeatureSupportFlags f) {
- int status = 0, surety = 0, source = 0;
-
- if (f & FEATURE_STATUS_ENABLED)
- status ++;
- if (f & FEATURE_STATUS_DISABLED)
- status ++;
- if (f & FEATURE_SURETY_BAD)
- surety ++;
- if (f & FEATURE_SURETY_GOOD)
- surety ++;
- if (f & FEATURE_SOURCE_DEFAULT)
- source ++;
- if (f & FEATURE_SOURCE_DETECTED)
- source ++;
- if (f & FEATURE_SOURCE_USER)
- source ++;
-
- return (!(f & ~FEATURE_SUPPORT_FLAGS_MASK) &&
- status == 1 && surety == 1 && source == 1);
+DevicePropertyBase* device_property_get_by_id(DevicePropertyId id) {
+ if (!device_property_bases || id >= device_property_bases->len)
+ return NULL;
+
+ return g_ptr_array_index(device_property_bases, id);
}
-static GSList* device_property_base_list = NULL;
+DevicePropertyBase* device_property_get_by_name(const char *name) {
+ gpointer rv;
-const DevicePropertyBase* device_property_get_by_id(DevicePropertyId id) {
- GSList *iter;
+ if (!device_property_bases_by_name)
+ return NULL;
- iter = device_property_base_list;
- while (iter != NULL) {
- DevicePropertyBase* rval = (DevicePropertyBase*)(iter->data);
- if (rval->ID == id) {
- return rval;
- }
- iter = g_slist_next(iter);
- }
+ rv = g_hash_table_lookup(device_property_bases_by_name, name);
+ if (rv)
+ return (DevicePropertyBase *)rv;
return NULL;
}
-const DevicePropertyBase* device_property_get_by_name(const char *name) {
- GSList *iter = device_property_base_list;
+#define toupper_and_underscore(c) (((c)=='-')? '_' : g_ascii_toupper((c)))
+static guint
+device_property_hash(
+ gconstpointer key)
+{
+ /* modified version of glib's hash function, copyright
+ * GLib Team and others 1997-2000. */
+ const char *p = key;
+ guint h = toupper_and_underscore(*p);
+
+ if (h)
+ for (p += 1; *p != '\0'; p++)
+ h = (h << 5) - h + toupper_and_underscore(*p);
+
+ return h;
+}
- g_return_val_if_fail(name != NULL, NULL);
+static gboolean
+device_property_equal(
+ gconstpointer v1,
+ gconstpointer v2)
+{
+ const char *s1 = v1, *s2 = v2;
- while (iter != NULL) {
- DevicePropertyBase* rval = (DevicePropertyBase*)(iter->data);
- if (strcasecmp(rval->name, name) == 0) {
- return rval;
- }
- iter = g_slist_next(iter);
+ while (*s1 && *s2) {
+ if (toupper_and_underscore(*s1) != toupper_and_underscore(*s2))
+ return FALSE;
+ s1++, s2++;
}
+ if (*s1 || *s2)
+ return FALSE;
- return NULL;
+ return TRUE;
}
-DevicePropertyId device_property_register(DevicePropertyBase* base) {
- static guint id = 0;
- g_assert(base != NULL);
- g_assert(base->ID == -1);
- g_assert(base->name != NULL);
- g_assert(base->description != NULL);
-
- base->ID = id++;
-
- device_property_base_list = g_slist_prepend(device_property_base_list,
- base);
- return id;
-}
+void
+device_property_fill_and_register(DevicePropertyBase *base,
+ GType type, const char * name, const char * desc) {
+
+ /* create the hash table and array if necessary */
+ if (!device_property_bases) {
+ device_property_bases = g_ptr_array_new();
+ device_property_bases_by_name = g_hash_table_new(device_property_hash, device_property_equal);
+ }
-/* Does the same thing, but fills in a new DevicePropertyBase. */
-static void
-device_property_fill_and_register(DevicePropertyBase * base,
- GType type,
- const char * name,
- const char * desc) {
+ /* check for a duplicate */
+ if (device_property_get_by_name(name)) {
+ g_critical("A property named '%s' already exists!", name);
+ }
+
+ /* allocate space for this DPB and fill it in */
+ base->ID = device_property_bases->len;
base->type = type;
- base->name = name;
- base->description = desc;
- base->ID = -1;
- device_property_register(base);
+ base->name = name; /* no strdup -- it's statically allocated */
+ base->description = desc; /* ditto */
+
+ /* add it to the array and hash table; note that its array index and its
+ * ID are the same. */
+ g_ptr_array_add(device_property_bases, base);
+ g_hash_table_insert(device_property_bases_by_name, (gpointer)name, (gpointer)base);
}
+/******
+ * Initialization
+ */
void device_property_init(void) {
device_property_fill_and_register(&device_property_concurrency,
"averaged for some (currently undefined) period of time)");
device_property_fill_and_register(&device_property_block_size,
G_TYPE_INT, "block_size",
- "Device blocking factor in bytes.");
+ "Block size to use while writing.");
device_property_fill_and_register(&device_property_min_block_size,
G_TYPE_UINT, "min_block_size",
"Minimum supported blocking factor.");
device_property_fill_and_register(&device_property_max_block_size,
G_TYPE_UINT, "max_block_size",
"Maximum supported blocking factor.");
+ device_property_fill_and_register(&device_property_read_buffer_size,
+ G_TYPE_UINT, "read_buffer_size",
+ "Minimum size of a read for this device (maximum expected block size)");
device_property_fill_and_register(&device_property_appendable,
G_TYPE_BOOLEAN, "appendable",
"Does device support appending to previously-written media?");
device_property_fill_and_register(&device_property_max_volume_usage,
G_TYPE_UINT64, "max_volume_usage",
"Artificial limit to data written to volume.");
- device_property_fill_and_register(&device_property_fsf,
- FEATURE_SUPPORT_FLAGS_TYPE, "fsf",
- "Does this drive support the MTFSF command?");
- device_property_fill_and_register(&device_property_bsf,
- FEATURE_SUPPORT_FLAGS_TYPE, "bsf",
- "Does this drive support the MTBSF command?" );
- device_property_fill_and_register(&device_property_fsr,
- FEATURE_SUPPORT_FLAGS_TYPE, "fsr",
- "Does this drive support the MTFSR command?");
- device_property_fill_and_register(&device_property_bsr,
- FEATURE_SUPPORT_FLAGS_TYPE, "bsr",
- "Does this drive support the MTBSR command?");
- /* FIXME: Is this feature even useful? */
- device_property_fill_and_register(&device_property_eom,
- FEATURE_SUPPORT_FLAGS_TYPE, "eom",
- "Does this drive support the MTEOM command?");
- device_property_fill_and_register(&device_property_bsf_after_eom,
- FEATURE_SUPPORT_FLAGS_TYPE,
- "bsf_after_eom",
- "Does this drive require an MTBSF after MTEOM in order to append?" );
- device_property_fill_and_register(&device_property_final_filemarks,
- G_TYPE_UINT, "final_filemarks",
- "How many filemarks to write after the last tape file?" );
- device_property_fill_and_register(&device_property_read_buffer_size,
- G_TYPE_UINT, "read_buffer_size",
- "What buffer size should be used for reading?");
- device_property_fill_and_register(&device_property_s3_secret_key,
- G_TYPE_STRING, "s3_secret_key",
- "Secret access key to authenticate with Amazon S3");
- device_property_fill_and_register(&device_property_s3_access_key,
- G_TYPE_STRING, "s3_access_key",
- "Access key ID to authenticate with Amazon S3");
-#ifdef WANT_DEVPAY
- device_property_fill_and_register(&device_property_s3_user_token,
- G_TYPE_STRING, "s3_user_token",
- "User token for authentication Amazon devpay requests");
-#endif
device_property_fill_and_register(&device_property_verbose,
G_TYPE_BOOLEAN, "verbose",
"Should the device produce verbose output?");
DevicePropertyBase device_property_block_size;
DevicePropertyBase device_property_min_block_size;
DevicePropertyBase device_property_max_block_size;
+DevicePropertyBase device_property_read_buffer_size;
DevicePropertyBase device_property_appendable;
DevicePropertyBase device_property_canonical_name;
DevicePropertyBase device_property_medium_access_type;
DevicePropertyBase device_property_partial_deletion;
DevicePropertyBase device_property_free_space;
DevicePropertyBase device_property_max_volume_usage;
-DevicePropertyBase device_property_fsf;
-DevicePropertyBase device_property_bsf;
-DevicePropertyBase device_property_fsr;
-DevicePropertyBase device_property_bsr;
-DevicePropertyBase device_property_eom;
-DevicePropertyBase device_property_bsf_after_eom;
-DevicePropertyBase device_property_final_filemarks;
-DevicePropertyBase device_property_read_buffer_size;
-DevicePropertyBase device_property_s3_access_key;
-DevicePropertyBase device_property_s3_secret_key;
-DevicePropertyBase device_property_s3_user_token;
DevicePropertyBase device_property_verbose;