From f089da28865399e612072845aced7e40ec078dd7 Mon Sep 17 00:00:00 2001 From: Bradford Hovinen Date: Tue, 19 Dec 2000 14:05:04 +0000 Subject: [PATCH] Added archiver directory Imported archiver for time travel, location Tue Dec 19 09:04:00 2000 Bradford Hovinen * Makefile.am (SUBDIRS): Added archiver directory * archiver/*: Imported archiver for time travel, location management --- archiver/ChangeLog | 149 +++++ archiver/Makefile.am | 26 + archiver/TODO | 34 ++ archiver/archive.c | 523 ++++++++++++++++ archiver/archive.h | 77 +++ archiver/archiver-spec | 77 +++ archiver/backend-list.c | 305 ++++++++++ archiver/backend-list.h | 73 +++ archiver/config-log.c | 933 +++++++++++++++++++++++++++++ archiver/config-log.h | 92 +++ archiver/future-spec | 95 +++ archiver/location.c | 1232 ++++++++++++++++++++++++++++++++++++++ archiver/location.h | 112 ++++ archiver/main.c | 316 ++++++++++ archiver/util.c | 97 +++ archiver/util.h | 33 + archiver/versioning-spec | 193 ++++++ 17 files changed, 4367 insertions(+) create mode 100644 archiver/ChangeLog create mode 100644 archiver/Makefile.am create mode 100644 archiver/TODO create mode 100644 archiver/archive.c create mode 100644 archiver/archive.h create mode 100644 archiver/archiver-spec create mode 100644 archiver/backend-list.c create mode 100644 archiver/backend-list.h create mode 100644 archiver/config-log.c create mode 100644 archiver/config-log.h create mode 100644 archiver/future-spec create mode 100644 archiver/location.c create mode 100644 archiver/location.h create mode 100644 archiver/main.c create mode 100644 archiver/util.c create mode 100644 archiver/util.h create mode 100644 archiver/versioning-spec diff --git a/archiver/ChangeLog b/archiver/ChangeLog new file mode 100644 index 000000000..d4d918fb4 --- /dev/null +++ b/archiver/ChangeLog @@ -0,0 +1,149 @@ +2000-12-18 Bradford Hovinen + + * main.c (do_rollback): Support rolling back by steps + + * location.c (location_rollback_backend_by): Implement + (location_dump_rollback_data): Support passing steps as well as + date + + * config-log.c (config_log_get_rollback_id_by_steps): Implement + + * location.c (write_metadata_file): Don't support writing out the + master list any more + (save_metadata): Ditto + (load_metadata_file): Get backends list from BackendList object + (rather than finding it out oneself) if location is toplevel + (do_create): Ditto + (get_backends_cb): Implement + (location_add_backend): Add return values for error conditions + +2000-10-15 Bradford Hovinen + + * location.c (location_rollback_backends_to): Free id_array when done + + * config-log.c (config_log_reset_filenames): Implement + + * archive.c (archive_set_current_location_id): Move gnome_config_ + code from set_current_location + + * location.c (location_set_id): Implement + + * main.c (do_rename_location): Implement + + * archive.c (free_location_cb): Don't free locid + (archive_get_location): + (archive_register_location): Don't strdup the location id + (archive_set_current_location_id): Implement + + * main.c: Add options for renaming locations and specifying that + backends should be added to or removed from the master list + + * location.c (run_backend_proc): Close all descriptors other than + 0, 1, 2 + (location_set_id): Implement + (location_set_arg): Free previous locid if exists + + * archive.c (add_location_cb): Implement + (archive_set_current_location): Add location change algorithm + + * location.c (location_find_path_from_common_parent): Implement + (location_foreach_backend): Implement + + * archive.c (archive_set_current_location): Set + archive->current_location_id + + * main.c (do_add_location): Check parent_str for NULL before + loading location + (do_change_location): Implement + (main): Support changing location + + * archive.c (archive_register_location): Implement + + * location.c (do_create): + (do_load): Use archive_get_prefix + (do_create): Load global location metadata if this location does + not inherit from anything + (location_get_id): Implement + + * archive.c (archive_get_prefix): Implement + + * location.c (location_get_path): Implement + (load_metadata_file): Use archive_is_global + (location_set_arg): Set label when setting locid + + * location.[ch]: Make all data members private + + * main.c (main): Get current location name properly, create + location iff location id is "default"; bail out with error otherwise + (do_remove_location): + (do_add_location): Implement + + * config-log.c: Include ctype.h to fix implicit declarations + + * location.c (location_rollback_backends_to): Property initialize i + (location_contains): Fix precondition checks + (do_create): Remove unused variables + + * archive.c (archive_get_location): Make a copy of locid before + working with it + (do_load): Fix precondition checks + + * location.c (location_open): + (location_new): Make locid const + + * archive.c (archive_get_location): Make locid const + + * location.c (data_delete_cb): + (location_delete): Implement + + * config-log.c (config_log_iterate): Implement + (config_log_destroy): Make private, pass GtkObject + (config_log_delete): Implement + +2000-10-14 Bradford Hovinen + + * location.c (location_close): Add precondition checks + + * archive.c (archive_destroy): Make private; pass GtkObject + + * location.c (location_add_backend): + (location_remove_backend): Add precondition checks + (location_destroy): Make private + (location_destroy): Pass GtkObject pointer rather than Location + pointer; this cleans up assignment in _class_init + + * archive.c (archive_get_current_location_id): Implement + (archive_get_current_location): Implement + +2000-09-03 Bradford Hovinen + + * location.c (location_new): Set is_new + (save_metadata): Don't write file unless necessary + (save_metadata): + (write_metadata_file): Split out file writing into + write_metadata_file; write default data file as necessary + (location_add_backend): + (location_remove_backend): Implement + + * main.c: Add command line arguments for adding/removing locations + and backends; move backend id argument into global options + + * location.c (do_load): + (load_metadata_file): Split out file parsing logic into + load_metadata_file; call load_metadata_file on default file to get + contains list if current location doesn't inherit anything + (load_metadata_file): g_strdup backend string + (load_metadata_file): Warn if top-level location has contains clauses + (location_store): Check if the location contains the given backend + and try the location it inherits if it doesn't + + * archive.c (archive_load): Set is_global in archive object + + * Makefile.am (Locationmeta{dir|_DATA}): Added commands to install + data files + (INCLUDES): Added define for LOCATION_DIR + +2000-09-03 Bradford Hovinen + + * location.c (save_metadata): Write attributes when saving + diff --git a/archiver/Makefile.am b/archiver/Makefile.am new file mode 100644 index 000000000..88cc4a921 --- /dev/null +++ b/archiver/Makefile.am @@ -0,0 +1,26 @@ +Locationmetadir = $(datadir)/hcm/default +Locationmeta_DATA = default-user.xml default-global.xml + +INCLUDES = \ + -DGNOMELOCALEDIR=\""$(datadir)/locale"\" \ + -I$(includedir) $(GNOME_INCLUDEDIR) \ + -DVERSION=\""$(VERSION)"\" \ + -DCONFIGDIR=\""/etc"\" \ + -DLOCATION_DIR=\""$(datadir)/hcm/default"\" \ + $(XML_CFLAGS) + +bin_PROGRAMS = archiver + +archiver_SOURCES = \ + main.c \ + archive.c archive.h \ + location.c location.h \ + config-log.c config-log.h \ + backend-list.c backend-list.h \ + util.c util.h + +archiver_LDADD = \ + $(GNOME_LIBDIR) \ + $(GNOMEUI_LIBS) \ + $(INTLLIBS) \ + $(GNOME_XML_LIB) diff --git a/archiver/TODO b/archiver/TODO new file mode 100644 index 000000000..5bef1b999 --- /dev/null +++ b/archiver/TODO @@ -0,0 +1,34 @@ + * Add per-user master list + * Archiving changes in location metadata + * Fix race in lock handling and add timeout support (look in gnome-mime) + * Support multiple backends from CLI + +Long-term + * Add clustering support: + - Add Cluster class inheriting Archive class and overriding path + semantics + - Change location rollback functionality to send data through to + clients if the archive is a cluster + * Allow backend specs to identify an order in which they should be applied + - Specify this in the master list; have each location look up that + information before invoking multiple backends + +Questions + +Done + * Global list of configs for a given archive + * Location should store backend data in the location where it is valid + * Add support for dumping XML to stdout rather than running the backend + * Fix bug where EOF not sent through pipe + * Changing the name of a location + * Adding per-user/global backends + - Don't try to write out contains list on toplevel locations + - Give error if the user tries to add a backend to a toplevel location + * Consistency check on adding and removing backends + - Make sure the backend is included in the global metadata list before + adding + - When removing global and per-user backends, mark the backend + "invalid" and exclude from location_foreach_backend, + location_rollback_all_to, and location_contains. + * Refactor master list into an attribute of Archive + * Roll back x number of steps rather than by date diff --git a/archiver/archive.c b/archiver/archive.c new file mode 100644 index 000000000..aab4166e5 --- /dev/null +++ b/archiver/archive.c @@ -0,0 +1,523 @@ +/* -*- mode: c; style: linux -*- */ + +/* archive.c + * Copyright (C) 2000 Helix Code, Inc. + * + * Written by Bradford Hovinen (hovinen@helixcode.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include + +#include "archive.h" + +static GtkObjectClass *parent_class; + +enum { + ARG_0, + ARG_PREFIX +}; + +static void archive_init (Archive *archive); +static void archive_class_init (ArchiveClass *klass); + +static void archive_destroy (GtkObject *object); + +static void archive_set_arg (GtkObject *object, + GtkArg *arg, + guint arg_id); + +static void archive_get_arg (GtkObject *object, + GtkArg *arg, + guint arg_id); + +static gboolean do_load (Archive *archive); + +guint +archive_get_type (void) +{ + static guint archive_type; + + if (!archive_type) { + GtkTypeInfo archive_info = { + "Archive", + sizeof (Archive), + sizeof (ArchiveClass), + (GtkClassInitFunc) archive_class_init, + (GtkObjectInitFunc) archive_init, + (GtkArgSetFunc) NULL, + (GtkArgGetFunc) NULL + }; + + archive_type = + gtk_type_unique (gtk_object_get_type (), + &archive_info); + } + + return archive_type; +} + +static void +archive_init (Archive *archive) +{ + archive->prefix = NULL; + archive->locations = g_tree_new ((GCompareFunc) strcmp); + archive->current_location_id = NULL; +} + +static void +archive_class_init (ArchiveClass *klass) +{ + GtkObjectClass *object_class; + + object_class = GTK_OBJECT_CLASS (klass); + + object_class->destroy = archive_destroy; + object_class->set_arg = archive_set_arg; + object_class->get_arg = archive_get_arg; + + gtk_object_add_arg_type ("Archive::prefix", + GTK_TYPE_POINTER, + GTK_ARG_READWRITE, + ARG_PREFIX); + + parent_class = gtk_type_class (gtk_object_get_type ()); +} + +static void +archive_set_arg (GtkObject *object, GtkArg *arg, guint arg_id) +{ + Archive *archive; + + g_return_if_fail (object != NULL); + g_return_if_fail (IS_ARCHIVE (object)); + g_return_if_fail (arg != NULL); + + archive = ARCHIVE (object); + + switch (arg_id) { + case ARG_PREFIX: + if (GTK_VALUE_POINTER (*arg) != NULL) + archive->prefix = g_strdup (GTK_VALUE_POINTER (*arg)); + break; + default: + break; + } +} + +static void +archive_get_arg (GtkObject *object, GtkArg *arg, guint arg_id) +{ + Archive *archive; + + g_return_if_fail (object != NULL); + g_return_if_fail (IS_ARCHIVE (object)); + g_return_if_fail (arg != NULL); + + archive = ARCHIVE (object); + + switch (arg_id) { + case ARG_PREFIX: + GTK_VALUE_POINTER (*arg) = archive->prefix; + break; + default: + arg->type = GTK_TYPE_INVALID; + break; + } +} + +/** + * archive_load: + * @is_global: TRUE iff we should load the global archive + * + * Load either the global or per-user configuration archive + * + * Return value: Reference to archive + **/ + +GtkObject * +archive_load (gboolean is_global) +{ + GtkObject *object; + gchar *prefix; + + if (is_global) + prefix = CONFIGDIR "/helix-config"; + else + prefix = g_concat_dir_and_file (g_get_home_dir (), + ".gnome/helix-config"); + + object = gtk_object_new (archive_get_type (), + "prefix", prefix, + NULL); + + if (is_global) + g_free (prefix); + + if (do_load (ARCHIVE (object)) == FALSE) { + gtk_object_destroy (object); + return NULL; + } + + ARCHIVE (object)->is_global = is_global; + ARCHIVE (object)->backend_list = + BACKEND_LIST (backend_list_new (is_global)); + + return object; +} + +static gint +free_location_cb (gchar *locid, Location *location) +{ + location_close (location); + + return FALSE; +} + +static void +archive_destroy (GtkObject *object) +{ + Archive *archive; + + g_return_if_fail (object != NULL); + g_return_if_fail (IS_ARCHIVE (object)); + + archive = ARCHIVE (object); + + g_tree_traverse (archive->locations, + (GTraverseFunc) free_location_cb, + G_IN_ORDER, + NULL); + + g_tree_destroy (archive->locations); + + if (archive->current_location_id != NULL) + g_free (archive->current_location_id); + + GTK_OBJECT_CLASS (parent_class)->destroy (GTK_OBJECT (archive)); +} + +/** + * archive_close: + * @archive: + * + * Closes the given archive handle. Also closes all locations under this + * archive. + **/ + +void +archive_close (Archive *archive) +{ + g_return_if_fail (archive != NULL); + g_return_if_fail (IS_ARCHIVE (archive)); + + gtk_object_destroy (GTK_OBJECT (archive)); +} + +/** + * archive_get_location: + * @archive: + * @locid: + * + * Get a reference to the location with the given name. + * + * Return value: Reference to location, NULL if no such location exists + **/ + +Location * +archive_get_location (Archive *archive, const gchar *locid) +{ + GtkObject *loc_obj; + + g_return_val_if_fail (archive != NULL, NULL); + g_return_val_if_fail (IS_ARCHIVE (archive), NULL); + g_return_val_if_fail (locid != NULL, NULL); + + loc_obj = g_tree_lookup (archive->locations, locid); + + if (!loc_obj) { + loc_obj = location_open (archive, locid); + + if (!loc_obj) return NULL; + + if (loc_obj) + g_tree_insert (archive->locations, locid, loc_obj); + } + + if (loc_obj) { + gtk_object_ref (loc_obj); + return LOCATION (loc_obj); + } else { + return NULL; + } +} + +/** + * archive_register_location: + * @archive: + * @location: + * + * Register a location with the archive; invoked by location_new + **/ + +void +archive_register_location (Archive *archive, Location *location) +{ + g_return_if_fail (archive != NULL); + g_return_if_fail (IS_ARCHIVE (archive)); + g_return_if_fail (location != NULL); + g_return_if_fail (IS_LOCATION (location)); + + g_tree_insert (archive->locations, + location_get_id (location), + location); +} + +/** + * archive_unregister_location: + * @archive: + * @location: + * + * Unregisters a location from the archive + **/ + +void +archive_unregister_location (Archive *archive, Location *location) +{ + g_return_if_fail (archive != NULL); + g_return_if_fail (IS_ARCHIVE (archive)); + g_return_if_fail (location != NULL); + g_return_if_fail (IS_LOCATION (location)); + + /* FIXME: We might be screwing things up here if we're traversing... */ + g_tree_remove (archive->locations, location); +} + +/** + * archive_get_current_location: + * @archive: object + * + * Convenience function to get a pointer to the current location + * + * Return value: Pointer to current location + **/ + +Location * +archive_get_current_location (Archive *archive) +{ + g_return_val_if_fail (archive != NULL, NULL); + g_return_val_if_fail (IS_ARCHIVE (archive), NULL); + + return archive_get_location (archive, + archive_get_current_location_id + (archive)); +} + +static int +add_location_cb (Location *location, gchar *backend_id, GList *backends) +{ + g_list_insert (backends, backend_id, 1); + return 0; +} + +/** + * archive_set_current_location: + * @archive: object + * @location: Location to which to set archive + * + * Set the current location in an archive to the location given; apply + * configuration for the new location to all backends necessary + **/ + +void +archive_set_current_location (Archive *archive, Location *location) +{ + GList *location_path, *backends; + Location *old_location = archive_get_current_location (archive); + + g_return_if_fail (archive != NULL); + g_return_if_fail (IS_ARCHIVE (archive)); + g_return_if_fail (location != NULL); + g_return_if_fail (IS_LOCATION (location)); + + archive_set_current_location_id (archive, location_get_id (location)); + + location_path = location_find_path_from_common_parent + (location, old_location); + + backends = g_list_append (NULL, NULL); + + while (location_path != NULL) { + if (location_path->data != NULL) { + location_foreach_backend + (LOCATION (location_path->data), + (LocationBackendCB) add_location_cb, + backends); + } + + location_path = location_path->next; + } + + location_rollback_backends_to (location, NULL, backends->next, TRUE); + + g_list_free (backends); +} + +/** + * archive_set_current_location_id: + * @archive: + * @name: + * + * Sets the current location's name, but does not invoke any rollback + **/ + +void +archive_set_current_location_id (Archive *archive, const gchar *locid) +{ + g_return_if_fail (archive != NULL); + g_return_if_fail (IS_ARCHIVE (archive)); + g_return_if_fail (locid != NULL); + + if (archive->current_location_id != NULL) + g_free (archive->current_location_id); + + archive->current_location_id = g_strdup (locid); + + if (archive->is_global) + gnome_config_push_prefix ("=" LOCATION_DIR "="); + else + gnome_config_push_prefix ("helix-config/"); + + gnome_config_set_string ("config/current/location", + archive->current_location_id); + + gnome_config_pop_prefix (); + gnome_config_sync (); +} + +/** + * archive_get_current_location_id: + * @archive: object + * + * Get the name of the current location + * + * Return value: String containing current location, should not be freed + **/ + +const gchar * +archive_get_current_location_id (Archive *archive) +{ + g_return_val_if_fail (archive != NULL, NULL); + g_return_val_if_fail (IS_ARCHIVE (archive), NULL); + + if (archive->current_location_id == NULL) { + if (archive->is_global) + gnome_config_push_prefix ("=" LOCATION_DIR "="); + else + gnome_config_push_prefix ("helix-config/"); + + archive->current_location_id = + gnome_config_get_string + ("config/current/location=default"); + + gnome_config_pop_prefix (); + } + + return archive->current_location_id; +} + +/** + * archive_get_prefix: + * @archive: + * + * Get the prefix for locations in this archive + * + * Return value: String containing prefix; should not be freed + **/ + +const gchar * +archive_get_prefix (Archive *archive) +{ + g_return_val_if_fail (archive != NULL, FALSE); + g_return_val_if_fail (IS_ARCHIVE (archive), FALSE); + + return archive->prefix; +} + +/** + * archive_is_global: + * @archive: + * + * Tell whether the archive is global or per-user + * + * Return value: TRUE if global, FALSE if per-user + **/ + +gboolean +archive_is_global (Archive *archive) +{ + g_return_val_if_fail (archive != NULL, FALSE); + g_return_val_if_fail (IS_ARCHIVE (archive), FALSE); + + return archive->is_global; +} + +/** + * archive_get_backend_list: + * @archive: + * + * Get the master backend list for this archive + * + * Return value: Reference to the master backend list + **/ + +BackendList * +archive_get_backend_list (Archive *archive) +{ + g_return_val_if_fail (archive != NULL, FALSE); + g_return_val_if_fail (IS_ARCHIVE (archive), FALSE); + + return archive->backend_list; +} + +/* Load the archive information from disk; return TRUE on success and FALSE on + * failure + */ + +static gboolean +do_load (Archive *archive) +{ + gint ret = 0; + + g_return_val_if_fail (archive != NULL, FALSE); + g_return_val_if_fail (IS_ARCHIVE (archive), FALSE); + g_return_val_if_fail (archive->prefix != NULL, FALSE); + + if (g_file_test (archive->prefix, G_FILE_TEST_ISDIR) == FALSE) + ret = mkdir (archive->prefix, S_IREAD | S_IWRITE | S_IEXEC); + + if (ret == -1) return FALSE; + + return TRUE; +} diff --git a/archiver/archive.h b/archiver/archive.h new file mode 100644 index 000000000..36710a169 --- /dev/null +++ b/archiver/archive.h @@ -0,0 +1,77 @@ +/* -*- mode: c; style: linux -*- */ + +/* archive.h + * Copyright (C) 2000 Helix Code, Inc. + * + * Written by Bradford Hovinen (hovinen@helixcode.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef __ARCHIVE_H +#define __ARCHIVE_H + +#include + +#include "location.h" +#include "backend-list.h" + +#define ARCHIVE(obj) GTK_CHECK_CAST (obj, archive_get_type (), Archive) +#define ARCHIVE_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, archive_get_type (), ArchiveClass) +#define IS_ARCHIVE(obj) GTK_CHECK_TYPE (obj, archive_get_type ()) + +typedef struct _ArchiveClass ArchiveClass; + +struct _Archive +{ + GtkObject object; + + gchar *prefix; + GTree *locations; + gboolean is_global; + + gchar *current_location_id; + + BackendList *backend_list; +}; + +struct _ArchiveClass +{ + GtkObjectClass parent; +}; + +guint archive_get_type (void); + +GtkObject *archive_load (gboolean is_global); + +void archive_close (Archive *archive); + +Location *archive_get_location (Archive *archive, const gchar *location); +void archive_register_location (Archive *archive, Location *location); +void archive_unregister_location (Archive *archive, Location *location); + +Location *archive_get_current_location (Archive *archive); +void archive_set_current_location (Archive *archive, Location *location); + +const gchar *archive_get_current_location_id (Archive *archive); +void archive_set_current_location_id (Archive *archive, const gchar *locid); + +const gchar *archive_get_prefix (Archive *archive); +gboolean archive_is_global (Archive *archive); + +BackendList *archive_get_backend_list (Archive *archive); + +#endif /* __ARCHIVE */ diff --git a/archiver/archiver-spec b/archiver/archiver-spec new file mode 100644 index 000000000..04725d26a --- /dev/null +++ b/archiver/archiver-spec @@ -0,0 +1,77 @@ +Rollback archiving internals +Copyright (C) 2000 Helix Code, Inc. +Written by Bradford Hovinen + +1. Directory format + +Diagram: + + + toplevel + |-+ Location 1 + | |- CCYYMMDD-hhmm-.xml + | | . + | | . + | | . + | |- metadata.log: + | | [