summaryrefslogtreecommitdiff
path: root/libstore
diff options
context:
space:
mode:
Diffstat (limited to 'libstore')
-rw-r--r--libstore/ChangeLog152
-rw-r--r--libstore/Makefile75
-rw-r--r--libstore/argp.c425
-rw-r--r--libstore/bunzip2.c13
-rw-r--r--libstore/clone.c25
-rw-r--r--libstore/copy.c267
-rw-r--r--libstore/create.c41
-rw-r--r--libstore/decode.c125
-rw-r--r--libstore/derive.c37
-rw-r--r--libstore/device.c326
-rw-r--r--libstore/enc.c41
-rw-r--r--libstore/encode.c87
-rw-r--r--libstore/file.c284
-rw-r--r--libstore/flags.c26
-rw-r--r--libstore/gunzip.c55
-rw-r--r--libstore/kids.c234
-rw-r--r--libstore/make.c80
-rw-r--r--libstore/map.c79
-rw-r--r--libstore/memobj.c197
-rw-r--r--libstore/module.c178
-rw-r--r--libstore/mvol.c158
-rw-r--r--libstore/nbd.c529
-rw-r--r--libstore/null.c109
-rw-r--r--libstore/open.c65
-rw-r--r--libstore/part.c197
-rw-r--r--libstore/rdwr.c152
-rw-r--r--libstore/remap.c345
-rw-r--r--libstore/set.c22
-rw-r--r--libstore/std.c37
-rw-r--r--libstore/store.h573
-rw-r--r--libstore/storecat.c29
-rw-r--r--libstore/storeread.c100
-rw-r--r--libstore/stripe.c145
-rw-r--r--libstore/task.c205
-rw-r--r--libstore/typed.c177
-rw-r--r--libstore/unknown.c231
-rw-r--r--libstore/unzipstore.c267
-rw-r--r--libstore/url.c92
-rw-r--r--libstore/xinl.c2
-rw-r--r--libstore/zero.c196
40 files changed, 5324 insertions, 1054 deletions
diff --git a/libstore/ChangeLog b/libstore/ChangeLog
deleted file mode 100644
index 07d6041b..00000000
--- a/libstore/ChangeLog
+++ /dev/null
@@ -1,152 +0,0 @@
-Fri Jul 19 16:16:46 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * decode.c (store_std_leaf_decode): Decode name too.
- Deal with NAME_LENGTH being 0.
-
-Sun Jun 16 22:49:55 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * argp.c (parse_opt): Use argp_failure.
-
-Thu May 23 10:54:06 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * argp.c (parse_opt): Honor ARGP_NO_ERRS.
- <error.h>: New include.
-
-Wed May 22 00:14:18 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * argp.c (parse_opt): Use error instead of ERR for non-parsing errors.
- Rename ERR to PERR.
-
-Tue May 21 00:01:02 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * storecat.c (main): Delete most everything and use store arg parsing.
- (options, doc, args_doc): Variables removed.
-
- * create.c (store_create): Add FLAGS & CLASSES params.
- * rdwr.c (store_write): Return an error if STORE is readonly.
- * decode.c (store_decode): Add CLASSES param, use it instead of big
- hardwired switch statement.
- (store_default_leaf_decode): Use typedef for CREATE param. Pass in
- FLAGS arg when calling it.
- * encode.c (store_std_leaf_allocate_encoding): Renamed from
- store_default_leaf_allocate_encoding. Make STORE const.
- (store_std_leaf_encode): Renamed from store_default_leaf_encode.
- Make STORE const. Get class id from store->class->id.
- (store_encode): Use CLASS field instead of METHS field.
- * clone.c (store_clone): Copy the flags by passing them to _make_store.
- Use CLASS field instead of METHS field.
- * file.c (store_file_open, file_decode): New functions.
- (store_file_create): Always set STORE_ENFORCED.
- (file_class): Renamed from file_meths. Add more fields. Make std
- with _STORE_STD_CLASS.
- (file_byte_class): Renamed from file_byte_meths.
- <fcntl.h>, <hurd.h>: New includes.
- * device.c (store_device_open, dev_decode): New functions.
- (store_device_create): Always set STORE_ENFORCED.
- (device_class): Renamed from device_meths. Add more fields. Make std
- with _STORE_STD_CLASS.
- <hurd.h>: New include.
- * stripe.c (ileave_allocate_encoding, ileave_encode, ileave_decode,
- concat_allocate_encoding, concat_encode, concat_decode): New functions.
- (concat_class): New variable.
- (ileave_class): Renamed from stripe_class. More fields added.
- * store.h (struct store): Remove CLASS field. METHS field renamed
- CLASS.
- (STORE_IMMUTABLE_FLAGS, STORE_GENERIC_FLAGS, STORE_BACKEND_SPEC_BASE,
- STORE_BACKEND_FLAGS, STORE_READONLY, STORE_HARD_READONLY,
- STORE_ENFORCED): New macros.
- (struct store_class): Renamed from store_meths; all uses changed.
- Add ID, NAME, DECODE, SET_FLAGS, CLEAR_FLAGS, and NEXT fields.
- (store_std_leaf_decode): Renamed from store_default_leaf_decode.
- (store_std_leaf_create_t): New type.
- (_STORE_STD_CLASS): New macro.
- (struct store_argp_params): READONLY field deleted, FLAGS field added.
- (store_allocate_child_encodings, store_encode_children,
- store_decode_children, store_set_flags, store_clear_flags,
- store_file_open, store_device_open, store_null_create,
- store_std_classes, _store_add_std_class,
- store_allocate_child_encodings, store_encode_children,
- store_decode_children): New declarations
- (store_decode, store_create, store_device_create, _store_device_create,
- store_file_create, _store_file_create, store_ileave_create,
- store_concat_create, _make_store): Declarations updated.
- * make.c (_make_store): CLASS param removed, METHS param renamed
- CLASS; all callers changed. FLAGS param added.
- * stripe.c (store_ileave_create, store_concat_create): Likewise.
- * file.c (store_file_create, _store_file_create): Likewise.
- * device.c (store_device_create, _store_device_create): Likewise.
- * argp.c (open_machdev): Function removed.
- (parse_opt): Use store_device_open instead of open_machdev.
- (open_file, parse_opt): Add FLAGS arg to various function calls.
- * set.c (store_set_children): Function moved to kids.c.
- * null.c, flags.c, std.c, kids.c: New files.
- * Makefile (SRCS): Add null.c, flags.c, std.c, & kids.c.
-
-Sun May 12 10:12:24 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * argp.c (store_parse_opt): Put result in the passed-in params struct.
- Pass hook to open_{file,machdev}.
- (open_machdev): Use params to determine readonly-ness.
- (open_file): New function.
- * store.h (store_argp): New declaration.
- (struct store_argp_params): New type.
- * Makefile (SRCS): Add argp.c.
-
- * create.c (store_create): Steal SOURCE instead of cloning it.
-
-Sat May 11 01:17:39 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * argp.c: New file.
-
- * storeread.c (parse_opt): Use ARGP_ERR_UNKNOWN instead of EINVAL.
- * storecat.c (parse_opt): Likewise.
-
-Fri May 10 13:23:36 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * store.h (struct store_run): New type.
- (struct store): RUNS is a vector of runs, not offsets.
- (_store_device_create, _store_file_create, _make_store,
- store_set_runs, store_default_leaf_decode): Update declaration.
- * rdwr.c (store_find_first_run, store_next_run, store_write,
- store_read): Use store_run, not off_t, vectors; tweak accordingly.
- Rename variables called `RUNS' to `RUN', because although they're
- always vectors, they're used more often for their first element.
- * derive.c (_store_derive): Use store_run, not off_t, vectors; tweak
- accordingly.
- * device.c (store_device_create, _store_device_create): Likewise.
- * set.c (store_set_runs): Likewise.
- * storecat.c (main): Likewise.
- * storeread.c (main): Likewise.
- * make.c (_make_store): Likewise.
- * stripe.c (store_ileave_create, store_concat_create): Likewise.
- * file.c (store_file_create, _store_file_create): Likewise.
- * decode.c (store_default_leaf_decode): Convert the slice of the
- offset vector we're using into a vector of store_runs to pass to
- CREATE. Change type of CREATE accordingly.
- * encode.c (store_default_leaf_encode): Convert from the store_run
- vector to a off_t vector for encoding.
-
- * create.c (store_create): Use the real file_get_storage_info.
- (fgsi): Function removed.
-
- * store.h (struct store): Add CHILDREN & NUM_CHILDREN fields.
- Rename RUNS_LEN to NUM_RUNS (all uses changed).
- (store_set_children): New declaration.
- * make.c (_make_store): Initialize CHILDREN & NUM_CHILDREN.
- (store_free): Free all children too.
- * clone.c (store_clone): Clone children too.
- * set.c (store_set_children): New function.
- * stripe.c (store_ileave_create, store_concat_create): Use
- store_set_children.
- (stripe_clone): Function removed.
- (stripe_read, stripe_write): Get stripes from CHILDREN, not HOOK.
-
- * Makefile (storeread, storecat): Remove explicit dependency on
- program object file.
- Put include of ../Makeconf before dependencies.
-
-Mon May 6 15:20:53 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * store.h: Move big comment describing file_get_storage_info
- encoding to <hurd/hurd_types.h>.
-
diff --git a/libstore/Makefile b/libstore/Makefile
index b33fc913..56c1fdfd 100644
--- a/libstore/Makefile
+++ b/libstore/Makefile
@@ -1,7 +1,7 @@
# Makefile for libstore
-#
-# Copyright (C) 1995, 1996 Free Software Foundation
-# Written by Miles Bader <miles@gnu.ai.mit.edu>
+#
+# Copyright (C) 1995,96,97,2001,02 Free Software Foundation, Inc.
+# Written by Miles Bader <miles@gnu.org>
#
# This file is part of the GNU Hurd.
#
@@ -17,22 +17,75 @@
#
# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
dir := libstore
makemode := library
libname = libstore
-SRCS = create.c derive.c make.c rdwr.c set.c device.c file.c stripe.c \
- storeread.c storecat.c enc.c encode.c decode.c clone.c argp.c \
- std.c kids.c null.c flags.c
+SRCS = create.c derive.c make.c rdwr.c set.c \
+ enc.c encode.c decode.c clone.c argp.c kids.c flags.c \
+ open.c xinl.c typed.c map.c url.c unknown.c \
+ stripe.c $(filter-out ileave.c concat.c,$(store-types:=.c))
+
+# This has to be evaluated after config.make has been included;
+# as a consequence, using 'ifneq' or similar is not an option.
+maybe_part = $(and $(PARTED_LIBS),part)
+
+store-types = \
+ bunzip2 \
+ concat \
+ copy \
+ device \
+ file \
+ gunzip \
+ ileave \
+ memobj \
+ module \
+ mvol \
+ nbd \
+ $(maybe_part) \
+ remap \
+ task \
+ zero
+
+libstore.so-LDLIBS += $(PARTED_LIBS) -ldl
LCLHDRS=store.h
installhdrs=store.h
-UTIL_OBJS = storeread.o storecat.o
-OBJS = $(filter-out $(UTIL_OBJS), $(SRCS:.c=.o))
+HURDLIBS = shouldbeinlibc
+GUNZIP_OBJS = unzip.o inflate.o util.o
+BUNZIP2_OBJS = do-bunzip2.o
+OBJS = $(SRCS:.c=.o) $(GUNZIP_OBJS) $(BUNZIP2_OBJS)
+DIST_FILES = unzipstore.c
include ../Makeconf
-storeread: libstore.so ../libshouldbeinlibc/libshouldbeinlibc.so
-storecat: libstore.so ../libshouldbeinlibc/libshouldbeinlibc.so
+# Look for zip stuff
+vpath %.c $(srcdir)/../exec
+CPPFLAGS += -I$(srcdir)/../exec
+
+module-CPPFLAGS = -D'STORE_SONAME_SUFFIX=".so.$(hurd-version)"'
+
+libstore_gunzip.so.$(hurd-version): $(GUNZIP_OBJS:.o=_pic.o)
+libstore_bunzip2.so.$(hurd-version): $(BUNZIP2_OBJS:.o=_pic.o)
+
+# You can use this rule to make a dynamically-loadable version of any
+# of the modules. We don't make any of these by default, since we
+# just include all the standard store types in libstore.so itself.
+libstore_%.so.$(hurd-version): %_pic.o libstore.so
+ $(CC) -shared -Wl,-soname=$@ -o $@ \
+ $(rpath) $(CFLAGS) $(LDFLAGS) $(libstore_$*.so-LDFLAGS) $^
+
+# Each libstore_TYPE.a is in fact an object file script so that `-lstore_TYPE'
+# just has the same effect as `-u store_TYPE_class'.
+$(store-types:%=libstore_%.a): libstore_%.a: $(srcdir)/Makefile
+ $(CC) -r -nostdlib -nostartfiles -x c /dev/null \
+ -o $@ -u store_$*_class
+cleantarg += $(store-types:%=libstore_%.a)
+
+all: $(store-types:%=libstore_%.a)
+
+install: $(store-types:%=$(libdir)/libstore_%.a)
+$(store-types:%=$(libdir)/libstore_%.a): $(libdir)/%: %
+ $(INSTALL_DATA) $< $@
diff --git a/libstore/argp.c b/libstore/argp.c
index 86b7eae2..6ed79964 100644
--- a/libstore/argp.c
+++ b/libstore/argp.c
@@ -1,9 +1,7 @@
/* Store argument parsing
- Copyright (C) 1996 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
-
+ Copyright (C) 1996,97,98,99,2001,02 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
This file is part of the GNU Hurd.
The GNU Hurd is free software; you can redistribute it and/or
@@ -18,190 +16,371 @@
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.,
- 675 Mass Ave, Cambridge, MA 02139, USA. */
+ 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
-#include <stdlib.h>
#include <string.h>
-#include <fcntl.h>
+#include <assert.h>
#include <hurd.h>
#include <argp.h>
-#include <error.h>
+#include <argz.h>
#include "store.h"
+/* We use this class variable instead of just the name so that we ensure
+ linking in store_open to define it. */
+#define DEFAULT_STORE_CLASS store_query_class
+
static const struct argp_option options[] = {
- {"machdev", 'm', 0, 0, "DEVICE is a mach device, not a file"},
- {"interleave", 'i', "BLOCKS", 0, "Interleave in runs of length BLOCKS"},
- {"layer", 'l', 0, 0, "Layer multiple devices for redundancy"},
+ {"store-type",'T', "TYPE", 0, "Each DEVICE names a store of type TYPE"},
+ {"machdev", 'm', 0, OPTION_HIDDEN}, /* deprecated */
+ {"interleave",'I', "BLOCKS", 0, "Interleave in runs of length BLOCKS"},
+ {"layer", 'L', 0, 0, "Layer multiple devices for redundancy"},
{0}
};
static const char args_doc[] = "DEVICE...";
-static const char doc[] = "If multiple DEVICEs are specified, they are"
-" concatenated unless either --interleave or --layer is specified (mutually"
-" exlusive).";
+static const char doc[] = "\vIf neither --interleave or --layer is specified,"
+" multiple DEVICEs are concatenated.";
-/* Used to hold data during argument parsing. */
-struct store_parse_hook
+struct store_parsed
{
- /* A malloced vector of stores specified on the command line, NUM_STORES
- long. */
- struct store **stores;
- size_t num_stores;
+ /* Names of devices parsed. */
+ char *names;
+ size_t names_len;
+
+ /* Prefix that should be applied to each member of NAMES. */
+ char *name_prefix;
- /* Pointer to params struct passed in by user. */
- struct store_argp_params *params;
+ /* --store-type specified. This defaults to the `query' type. */
+ const struct store_class *type;
- off_t interleave; /* --interleave value */
- int machdev : 1; /* --machdev specified */
+ /* A vector of class pointers used to lookup class names. Defaults to
+ STORE_STD_CLASSES. */
+ const struct store_class *const *classes;
+
+ /* DEFAULT_TYPE field passed to parser. */
+ const struct store_class *default_type;
+
+ store_offset_t interleave; /* --interleave value */
int layer : 1; /* --layer specified */
};
-/* Free the parse hook H. If FREE_STORES is true, also free the stores in
- H's store vector, otherwise just free the vector itself. */
-static void
-free_hook (struct store_parse_hook *h, int free_stores)
+void
+store_parsed_free (struct store_parsed *parsed)
{
- int i;
- if (free_stores)
- for (i = 0; i < h->num_stores; i++)
- store_free (h->stores[i]);
- if (h->stores)
- free (h->stores);
- free (h);
+ if (parsed->names_len > 0)
+ free (parsed->names);
+ if (parsed->name_prefix)
+ free (parsed->name_prefix);
+ free (parsed);
}
-
-static error_t
-open_file (char *name, struct store_parse_hook *h, struct store **s)
+
+/* Add the arguments PARSED, and return the corresponding store in STORE. */
+error_t
+store_parsed_append_args (const struct store_parsed *parsed,
+ char **args, size_t *args_len)
{
- error_t err;
- int flags = h->params->flags;
- int open_flags = (flags & STORE_HARD_READONLY) ? O_RDONLY : O_RDWR;
- file_t node = file_name_lookup (name, open_flags, 0);
+ char buf[40];
+ error_t err = 0;
+ size_t num_names = argz_count (parsed->names, parsed->names_len);
- if (node == MACH_PORT_NULL)
- return errno;
+ if (!err && num_names > 1 && (parsed->interleave || parsed->layer))
+ {
+ if (parsed->interleave)
+ snprintf (buf, sizeof buf, "--interleave=%Ld", parsed->interleave);
+ else
+ snprintf (buf, sizeof buf, "--layer=%d", parsed->layer);
+ err = argz_add (args, args_len, buf);
+ }
- err = store_create (node, flags, 0, s);
- if (err)
+ if (!err && parsed->type != parsed->default_type)
{
- if (! h->params->no_file_io)
- /* Try making a store that does file io to NODE. */
- err = store_file_create (node, flags, s);
- if (err)
- mach_port_deallocate (mach_task_self (), node);
+ if (parsed->name_prefix)
+ /* A name prefix of "PFX" is equivalent to appending ":PFX" to the
+ type name. */
+ {
+ size_t npfx_len = strlen (parsed->name_prefix);
+ char tname[strlen ("--store-type=")
+ + strlen (parsed->type->name) + 1 + npfx_len + 1];
+ snprintf (tname, sizeof tname, "--store-type=%s:%.*s",
+ parsed->type->name, (int) npfx_len, parsed->name_prefix);
+ err = argz_add (args, args_len, tname);
+ }
+ else
+ /* A simple type name. */
+ {
+ snprintf (buf, sizeof buf, "--store-type=%s", parsed->type->name);
+ err = argz_add (args, args_len, buf);
+ }
}
+ if (! err)
+ err = argz_append (args, args_len, parsed->names, parsed->names_len);
+
return err;
}
-static error_t
-parse_opt (int opt, char *arg, struct argp_state *state)
+error_t
+store_parsed_name (const struct store_parsed *parsed, char **name)
{
- error_t err = 0;
- struct store_parse_hook *h = state->hook;
+ char buf[40];
+ char *pfx = 0;
+
+ if (argz_count (parsed->names, parsed->names_len) > 1)
+ {
+ if (parsed->interleave)
+ {
+ snprintf (buf, sizeof buf, "interleave(%Ld,", parsed->interleave);
+ pfx = buf;
+ }
+ else if (parsed->layer)
+ pfx = "layer(";
+ }
+
+ if (pfx)
+ *name = malloc (strlen (pfx) + parsed->names_len + 1);
+ else
+ *name = malloc (parsed->names_len);
+
+ if (! *name)
+ return ENOMEM;
+
+ if (pfx)
+ {
+ char *end = stpcpy (*name, pfx);
+ bcopy (parsed->names, end, parsed->names_len);
+ argz_stringify (end, parsed->names_len, ',');
+ strcpy (end + parsed->names_len, ")");
+ }
+ else
+ {
+ bcopy (parsed->names, *name, parsed->names_len);
+ argz_stringify (*name, parsed->names_len, ',');
+ }
+
+ return 0;
+}
+
+/* Open PARSED, and return the corresponding store in STORE. */
+error_t
+store_parsed_open (const struct store_parsed *parsed, int flags,
+ struct store **store)
+{
+ size_t pfx_len = parsed->name_prefix ? strlen (parsed->name_prefix) : 0;
+ size_t num = argz_count (parsed->names, parsed->names_len);
+
+ error_t open (char *name, struct store **store)
+ {
+ const struct store_class *type = parsed->type;
+ if (type->open)
+ {
+ if (parsed->name_prefix)
+ /* If there's a name prefix, we prefix any names we open with that
+ and a colon. */
+ {
+ char pfxed_name[pfx_len + 1 + strlen (name) + 1];
+ stpcpy (stpcpy (stpcpy (pfxed_name, parsed->name_prefix),
+ ":"),
+ name);
+ return (*type->open) (pfxed_name, flags, parsed->classes, store);
+ }
+ else
+ return (*type->open) (name, flags, parsed->classes, store);
+ }
+ else
+ return EOPNOTSUPP;
+ }
+
+ if (num == 1)
+ return open (parsed->names, store);
+ else if (num == 0)
+ return open (0, store);
+ else
+ {
+ int i;
+ char *name;
+ error_t err = 0;
+ struct store **stores = malloc (sizeof (struct store *) * num);
+
+ if (! stores)
+ return ENOMEM;
- /* Print a parsing error message and (if exiting is turned off) return the
- error code ERR. */
+ for (i = 0, name = parsed->names;
+ !err && i < num;
+ i++, name = argz_next (parsed->names, parsed->names_len, name))
+ err = open (name, &stores[i]);
+
+ if (! err)
+ {
+ if (parsed->interleave)
+ err =
+ store_ileave_create (stores, num, parsed->interleave,
+ flags, store);
+ else if (parsed->layer)
+ assert (! parsed->layer);
+ else
+ err = store_concat_create (stores, num, flags, store);
+ }
+
+ if (err)
+ {
+ while (i > 0)
+ store_free (stores[i--]);
+ free (stores);
+ }
+
+ return err;
+ }
+}
+
+static const struct store_class *
+find_class (const char *name, const struct store_class *const *const classes)
+{
+ const struct store_class *const *cl;
+ for (cl = classes ?: __start_store_std_classes;
+ classes ? *cl != 0 : cl < __stop_store_std_classes;
+ ++cl)
+ if ((*cl)->name && strcmp (name, (*cl)->name) == 0)
+ return *cl;
+
+# pragma weak store_module_find_class
+ if (! classes && store_module_find_class)
+ {
+ const struct store_class *cl;
+ if (store_module_find_class (name, strchr (name, '\0'), &cl) == 0)
+ return cl;
+ }
+
+ return 0;
+}
+
+/* Print a parsing error message and (if exiting is turned off) return the
+ error code ERR. Requires a variable called STATE to be in scope. */
#define PERR(err, fmt, args...) \
do { argp_error (state, fmt , ##args); return err; } while (0)
- switch (opt)
+/* Parse a --store-type/-T option. */
+static error_t
+parse_type (char *arg, struct argp_state *state, struct store_parsed *parsed)
+{
+ char *name_prefix = 0;
+ char *type_name = arg;
+ const struct store_class *type;
+ char *class_sep = strchr (arg, ':');
+
+ if (class_sep)
+ /* A `:'-separated class name "T1:T2" is equivalent to prepending "T2:"
+ to the device name passed to T1, and is useful for the case where T1
+ takes typed names of the form "T:NAME". A trailing `:', like "T1:" is
+ equivalent to prefixing `:' to the device name, which causes NAME to
+ be opened with store_open, as a file. */
{
- struct store *s;
+ type_name = strndupa (arg, class_sep - arg);
+ name_prefix = class_sep + 1;
+ }
+
+ type = find_class (type_name, parsed->classes);
+ if (!type || !type->open)
+ PERR (EINVAL, "%s: Invalid argument to --store-type", arg);
+ else if (type != parsed->type && parsed->type != parsed->default_type)
+ PERR (EINVAL, "--store-type specified multiple times");
+
+ parsed->type = type;
+ parsed->name_prefix = name_prefix;
+
+ return 0;
+}
+
+static error_t
+parse_opt (int opt, char *arg, struct argp_state *state)
+{
+ error_t err;
+ struct store_parsed *parsed = state->hook;
+ switch (opt)
+ {
case 'm':
- h->machdev = 1; break;
+ arg = "device";
+ /* fall through */
+ case 'T':
+ return parse_type (arg, state, parsed);
- case 'i':
- if (h->layer)
+ case 'I':
+ if (parsed->layer)
PERR (EINVAL, "--layer and --interleave are exclusive");
- if (h->interleave)
+ if (parsed->interleave)
/* Actually no reason why we couldn't support this.... */
PERR (EINVAL, "--interleave specified multiple times");
- h->interleave = atoi (arg);
- if (! h->interleave)
+ parsed->interleave = atoi (arg);
+ if (! parsed->interleave)
PERR (EINVAL, "%s: Bad value for --interleave", arg);
break;
- case 'l':
- if (h->interleave)
+ case 'L':
+#if 1
+ argp_failure (state, 5, 0, "--layer not implemented");
+ return EINVAL;
+#else
+ if (parsed->interleave)
PERR (EINVAL, "--layer and --interleave are exclusive");
- h->layer = 1;
+ parsed->layer = 1;
+#endif
break;
case ARGP_KEY_ARG:
/* A store device to use! */
- if (h->machdev)
- err = store_device_open (arg, h->params->flags, &s);
+ if (parsed->type->validate_name)
+ err = (*parsed->type->validate_name) (arg, parsed->classes);
else
- err = open_file (arg, h, &s);
+ err = 0;
+ if (! err)
+ err = argz_add (&parsed->names, &parsed->names_len, arg);
if (err)
- {
- argp_failure (state, 1, err, "%s", arg);
- return err;
- }
- else
- {
- struct store **stores = realloc (h->stores, h->num_stores + 1);
- if (stores)
- {
- stores[h->num_stores++] = s;
- h->stores = stores;
- }
- else
- return ENOMEM; /* Just fucking lovely */
- }
+ argp_failure (state, 1, err, "%s", arg);
+ return err;
break;
case ARGP_KEY_INIT:
/* Initialize our parsing state. */
- if (! state->input)
- return EINVAL; /* Need at least a way to return a result. */
- h = malloc (sizeof (struct store_parse_hook));
- if (! h)
- return ENOMEM;
- bzero (h, sizeof (struct store_parse_hook));
- h->params = state->input;
- state->hook = h;
+ {
+ struct store_argp_params *params = state->input;
+ if (! params)
+ return EINVAL; /* Need at least a way to return a result. */
+ parsed = state->hook = malloc (sizeof (struct store_parsed));
+ if (! parsed)
+ return ENOMEM;
+ bzero (parsed, sizeof (struct store_parsed));
+ parsed->classes = params->classes;
+ parsed->default_type =
+ find_class (params->default_type ?: DEFAULT_STORE_CLASS.name,
+ parsed->classes);
+ if (! parsed->default_type)
+ {
+ free (parsed);
+ return EINVAL;
+ }
+ parsed->type = parsed->default_type;
+ }
break;
case ARGP_KEY_ERROR:
- /* Parsing error occured, free everything. */
- free_hook (h, 1); break;
+ /* Parsing error occurred, free everything. */
+ store_parsed_free (parsed); break;
case ARGP_KEY_SUCCESS:
/* Successfully finished parsing, return a result. */
-
- if (h->num_stores == 0)
+ if (parsed->names == 0
+ && (!parsed->type->validate_name
+ || (*parsed->type->validate_name) (0, parsed->classes) != 0))
{
- free_hook (h, 1);
- PERR (EINVAL, "No store specified");
+ struct store_argp_params *params = state->input;
+ store_parsed_free (parsed);
+ if (!params->store_optional)
+ PERR (EINVAL, "No store specified");
+ parsed = 0;
}
-
- if (state->input == 0)
- /* No way to return a value! */
- err = EINVAL;
- else if (h->num_stores == 1)
- s = h->stores[0]; /* Just a single store. */
- else if (h->interleave)
- err =
- store_ileave_create (h->stores, h->num_stores, h->interleave,
- h->params->flags, &s);
- else if (h->layer)
- {
- free_hook (h, 1);
- PERR (EINVAL, "--layer not implemented");
- }
- else
- err =
- store_concat_create (h->stores, h->num_stores, h->params->flags, &s);
-
- free_hook (h, err);
- if (! err)
- h->params->result = s;
-
+ ((struct store_argp_params *)state->input)->result = parsed;
break;
default:
diff --git a/libstore/bunzip2.c b/libstore/bunzip2.c
new file mode 100644
index 00000000..ec0630ec
--- /dev/null
+++ b/libstore/bunzip2.c
@@ -0,0 +1,13 @@
+#include <errno.h>
+
+extern void do_bunzip2 (void); /* Entry point to bunzip2 engine. */
+
+static error_t
+DO_UNZIP (void)
+{
+ do_bunzip2 ();
+ return 0;
+}
+
+#define UNZIP bunzip2
+#include "unzipstore.c"
diff --git a/libstore/clone.c b/libstore/clone.c
index bec2e88d..cdbd5747 100644
--- a/libstore/clone.c
+++ b/libstore/clone.c
@@ -1,9 +1,7 @@
/* Store cloning
- Copyright (C) 1996 Free Software Foundation, Inc.
-
+ Copyright (C) 1996, 1997 Free Software Foundation, Inc.
Written by Miles Bader <miles@gnu.ai.mit.edu>
-
This file is part of the GNU Hurd.
The GNU Hurd is free software; you can redistribute it and/or
@@ -18,7 +16,7 @@
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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
#include <string.h>
#include <stdlib.h>
@@ -29,13 +27,20 @@
error_t
store_clone (struct store *from, struct store **to)
{
- error_t err = 0;
- struct store *c =
- _make_store (from->class, from->port, from->flags, from->block_size,
- from->runs, from->num_runs, from->end);
+ struct store *c;
+ error_t err =
+ _store_create (from->class, from->port, from->flags, from->block_size,
+ from->runs, from->num_runs, from->end, &c);
+
+ if (err)
+ return err;
- if (! c)
- return ENOMEM;
+ if (from->name)
+ {
+ c->name = strdup (from->name);
+ if (! c->name)
+ err = ENOMEM;
+ }
if (from->misc_len)
{
diff --git a/libstore/copy.c b/libstore/copy.c
new file mode 100644
index 00000000..c670ebf3
--- /dev/null
+++ b/libstore/copy.c
@@ -0,0 +1,267 @@
+/* Copy store backend
+
+ Copyright (C) 1995,96,97,99,2000,01,02 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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.
+
+ The GNU Hurd 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, USA. */
+
+#include <stdio.h>
+#include <string.h>
+#include <malloc.h>
+#include <sys/mman.h>
+#include <mach.h>
+
+#define page_aligned(addr) (((size_t) addr & (vm_page_size - 1)) == 0)
+
+#include "store.h"
+
+static error_t
+copy_read (struct store *store, store_offset_t addr, size_t index,
+ size_t amount, void **buf, size_t *len)
+{
+ char *data = store->hook + (addr * store->block_size);
+
+ if (page_aligned (data) && page_aligned (amount))
+ /* When reading whole pages, we can avoid any real copying. */
+ return vm_read (mach_task_self (),
+ (vm_address_t) data, amount,
+ (pointer_t *) buf, len);
+
+ if (*len < amount)
+ /* Have to allocate memory for the return value. */
+ {
+ *buf = mmap (0, amount, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ if (*buf == MAP_FAILED)
+ return errno;
+ }
+
+ memcpy (*buf, data, amount);
+ *len = amount;
+ return 0;
+}
+
+static error_t
+copy_write (struct store *store,
+ store_offset_t addr, size_t index,
+ const void *buf, size_t len, size_t *amount)
+{
+ char *data = store->hook + (addr * store->block_size);
+
+ if (page_aligned (data) && page_aligned (len) && page_aligned (buf))
+ {
+ /* When writing whole pages, we can avoid any real copying. */
+ error_t err = vm_write (mach_task_self (),
+ (vm_address_t) data, (vm_address_t) buf, len);
+ *amount = len;
+ return err;
+ }
+
+ memcpy (data, buf, len);
+ *amount = len;
+ return 0;
+}
+
+static error_t
+copy_set_size (struct store *store, size_t newsize)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+copy_allocate_encoding (const struct store *store, struct store_enc *enc)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+copy_encode (const struct store *store, struct store_enc *enc)
+{
+ return EOPNOTSUPP;
+}
+
+static error_t
+copy_decode (struct store_enc *enc, const struct store_class *const *classes,
+ struct store **store)
+{
+ return EOPNOTSUPP;
+}
+
+static error_t
+copy_open (const char *name, int flags,
+ const struct store_class *const *classes,
+ struct store **store)
+{
+ return store_copy_open (name, flags, classes, store);
+}
+
+static error_t
+copy_set_flags (struct store *store, int flags)
+{
+ if ((flags & ~(STORE_INACTIVE | STORE_ENFORCED)) != 0)
+ /* Trying to set flags we don't support. */
+ return EINVAL;
+
+ /* ... */
+
+ store->flags |= flags; /* When inactive, anything goes. */
+
+ return 0;
+}
+
+static error_t
+copy_clear_flags (struct store *store, int flags)
+{
+ error_t err = 0;
+ if ((flags & ~(STORE_INACTIVE | STORE_ENFORCED)) != 0)
+ err = EINVAL;
+ /* ... */
+ if (! err)
+ store->flags &= ~flags;
+ return err;
+}
+
+/* Called just before deallocating STORE. */
+void
+copy_cleanup (struct store *store)
+{
+ if (store->size > 0)
+ munmap (store->hook, store->size);
+}
+
+/* Copy any format-dependent fields in FROM to TO; if there's some reason
+ why the copy can't be made, an error should be returned. This call is
+ made after all format-indendependent fields have been cloned. */
+error_t
+copy_clone (const struct store *from, struct store *to)
+{
+ void *buf;
+ buf = mmap (0, to->size, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ if (buf != (void *) -1)
+ {
+ to->hook = buf;
+ memcpy (to->hook, from->hook, from->size);
+ return 0;
+ }
+ return errno;
+}
+
+const struct store_class
+store_copy_class =
+{
+ STORAGE_COPY, "copy", copy_read, copy_write, copy_set_size,
+ copy_allocate_encoding, copy_encode, copy_decode,
+ copy_set_flags, copy_clear_flags, copy_cleanup, copy_clone, 0, copy_open
+};
+STORE_STD_CLASS (copy);
+
+/* Return a new store in STORE which contains a snapshot of the contents of
+ the store FROM; FROM is consumed. */
+error_t
+store_copy_create (struct store *from, int flags, struct store **store)
+{
+ error_t err;
+ struct store_run run;
+
+ run.start = 0;
+ run.length = from->size;
+
+ flags |= STORE_ENFORCED; /* Only uses local resources. */
+
+ err =
+ _store_create (&store_copy_class,
+ MACH_PORT_NULL, flags, from->block_size, &run, 1, 0,
+ store);
+ if (! err)
+ {
+ size_t buf_len = 0;
+
+ /* Copy the input store. */
+ err = store_read (from, 0, from->size, &(*store)->hook, &buf_len);
+
+ if (! err)
+ /* Set the store name. */
+ {
+ if (from->name)
+ {
+ size_t len =
+ strlen (from->class->name) + 1 + strlen (from->name) + 1;
+ (*store)->name = malloc (len);
+ if ((*store)->name)
+ snprintf ((*store)->name, len,
+ "%s:%s", from->class->name, from->name);
+ }
+ else
+ (*store)->name = strdup (from->class->name);
+
+ if (! (*store)->name)
+ err = ENOMEM;
+ }
+
+ if (err)
+ store_free (*store);
+ }
+
+ return err;
+}
+
+/* Return a new store in STORE which contains the memory buffer BUF, of
+ length BUF_LEN, and uses the block size BLOCK_SIZE. BUF must be
+ vm_allocated, and will be consumed, and BUF_LEN must be a multiple of
+ BLOCK_SIZE. */
+error_t
+store_buffer_create (void *buf, size_t buf_len, int flags,
+ struct store **store)
+{
+ error_t err;
+ struct store_run run;
+
+ run.start = 0;
+ run.length = buf_len;
+
+ flags |= STORE_ENFORCED; /* Only uses local resources. */
+
+ err =
+ _store_create (&store_copy_class,
+ MACH_PORT_NULL, flags, 1, &run, 1, 0, store);
+ if (! err)
+ (*store)->hook = buf;
+
+ return err;
+}
+
+/* Open the copy store NAME -- which consists of another store-class name, a
+ ':', and a name for that store class to open -- and return the
+ corresponding store in STORE. CLASSES is used to select classes specified
+ by the type name; if it is 0, STORE_STD_CLASSES is used. */
+error_t
+store_copy_open (const char *name, int flags,
+ const struct store_class *const *classes,
+ struct store **store)
+{
+ struct store *from;
+ error_t err =
+ store_typed_open (name, flags | STORE_HARD_READONLY, classes, &from);
+
+ if (! err)
+ {
+ err = store_copy_create (from, flags, store);
+ if (err)
+ store_free (from);
+ }
+
+ return err;
+}
diff --git a/libstore/create.c b/libstore/create.c
index e332e85c..010a053e 100644
--- a/libstore/create.c
+++ b/libstore/create.c
@@ -1,9 +1,7 @@
/* Store creation
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
-
+ Copyright (C) 1995,96,97,2001 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
This file is part of the GNU Hurd.
The GNU Hurd is free software; you can redistribute it and/or
@@ -18,19 +16,23 @@
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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
#include <hurd/fs.h>
#include "store.h"
-/* Return a new store in STORE, which refers to the storage underlying
- SOURCE. CLASSES is used to select classes specified by the provider; if
- it is 0, STORE_STD_CLASSES is used. FLAGS is set with store_set_flags. A
- reference to SOURCE is created (but may be destroyed with
- store_close_source). */
+/* Return a new store in STORE, which refers to the storage underlying SOURCE.
+ CLASSES is used to select classes specified by the provider; if it is 0,
+ STORE_STD_CLASSES is used. FLAGS is set with store_set_flags, with the
+ exception of STORE_INACTIVE, which merely indicates that no attempt should
+ be made to activate an inactive store; if STORE_INACTIVE is not specified,
+ and the store returned for SOURCE is inactive, an attempt is made to
+ activate it (failure of which causes an error to be returned). A reference
+ to SOURCE is created (but may be destroyed with store_close_source). */
error_t
-store_create (file_t source, int flags, struct store_class *classes,
+store_create (file_t source, int flags,
+ const struct store_class *const *classes,
struct store **store)
{
error_t err;
@@ -52,9 +54,20 @@ store_create (file_t source, int flags, struct store_class *classes,
return err;
err = store_decode (&enc, classes, store);
-
- if (!err && flags)
- store_set_flags (*store, flags);
+ if (! err)
+ {
+ if (flags & STORE_INACTIVE)
+ flags &= ~STORE_INACTIVE; /* Don't actually make store inactive. */
+ else if ((*store)->flags & STORE_INACTIVE)
+ err = store_clear_flags (*store, STORE_INACTIVE);
+ if (!err && flags)
+ err = store_set_flags (*store, flags);
+ if (err)
+ store_free (*store);
+ }
+ else if (err == EINVAL && (flags &~ STORE_INACTIVE) == STORE_NO_FILEIO)
+ /* Open a generic "unknown" store that can regurgitate this encoding. */
+ err = store_unknown_decode (&enc, classes, store);
store_enc_dealloc (&enc);
diff --git a/libstore/decode.c b/libstore/decode.c
index 5231b33d..64405ecd 100644
--- a/libstore/decode.c
+++ b/libstore/decode.c
@@ -1,9 +1,7 @@
/* Store wire decoding
- Copyright (C) 1996 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
-
+ Copyright (C) 1996,97,98,2001,02 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
This file is part of the GNU Hurd.
The GNU Hurd is free software; you can redistribute it and/or
@@ -18,7 +16,7 @@
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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
#include <string.h>
#include <malloc.h>
@@ -37,10 +35,15 @@ store_std_leaf_decode (struct store_enc *enc,
{
char *misc, *name;
error_t err;
- int type, flags, i;
+ int type, flags;
mach_port_t port;
size_t block_size, num_runs, name_len, misc_len;
-
+ /* Call CREATE appriately from within store_with_decoded_runs. */
+ error_t call_create (const struct store_run *runs, size_t num_runs)
+ {
+ return (*create)(port, flags, block_size, runs, num_runs, store);
+ }
+
/* Make sure there are enough encoded ints and ports. */
if (enc->cur_int + 6 > enc->num_ints || enc->cur_port + 1 > enc->num_ports)
return EINVAL;
@@ -61,25 +64,63 @@ store_std_leaf_decode (struct store_enc *enc,
if (name_len > 0 && enc->data[enc->cur_data + name_len - 1] != '\0')
return EINVAL; /* Name not terminated. */
- misc = malloc (misc_len);
- if (! misc)
- return ENOMEM;
-
if (name_len > 0)
{
name = strdup (enc->data + enc->cur_data);
if (! name)
+ return ENOMEM;
+ enc->cur_data += name_len;
+ }
+ else
+ name = 0;
+
+ if (misc_len > 0)
+ {
+ misc = malloc (misc_len);
+ if (! misc)
{
- free (misc);
+ if (name)
+ free (name);
return ENOMEM;
}
+ memcpy (misc, enc->data + enc->cur_data + name_len, misc_len);
+ enc->cur_data += misc_len;
}
else
- name = 0;
+ misc = 0;
/* Read encoded ports (be careful to deallocate this if we barf). */
port = enc->ports[enc->cur_port++];
+ err = store_with_decoded_runs (enc, num_runs, call_create);
+ if (err)
+ {
+ mach_port_deallocate (mach_task_self (), port);
+ if (misc)
+ free (misc);
+ if (name)
+ free (name);
+ }
+ else
+ {
+ (*store)->flags = flags;
+ (*store)->name = name;
+ (*store)->misc = misc;
+ (*store)->misc_len = misc_len;
+ }
+
+ return err;
+}
+
+/* Call FUN with the vector RUNS of length RUNS_LEN extracted from ENC. */
+error_t
+store_with_decoded_runs (struct store_enc *enc, size_t num_runs,
+ error_t (*fun) (const struct store_run *runs,
+ size_t num_runs))
+{
+ int i;
+ error_t err;
+
/* Since the runs are passed in an array of off_t pairs, and we use struct
store_run, we have to make a temporary array to hold the (probably
bitwise identical) converted representation to pass to CREATE. */
@@ -92,7 +133,8 @@ store_std_leaf_decode (struct store_enc *enc,
runs[i].start = *e++;
runs[i].length = *e++;
}
- err = (*create)(port, flags, block_size, runs, num_runs, store);
+ enc->cur_offset = e - enc->offsets;
+ err = (*fun)(runs, num_runs);
}
else
/* Ack. Too many runs to allocate the temporary RUNS array on the stack.
@@ -107,28 +149,14 @@ store_std_leaf_decode (struct store_enc *enc,
runs[i].start = *e++;
runs[i].length = *e++;
}
- err = (*create)(port, flags, block_size, runs, num_runs, store);
+ enc->cur_offset = e - enc->offsets;
+ err = (*fun) (runs, num_runs);
free (runs);
}
else
err = ENOMEM;
}
- if (err)
- {
- mach_port_deallocate (mach_task_self (), port);
- free (misc);
- if (name)
- free (name);
- }
- else
- {
- (*store)->flags = flags;
- (*store)->name = name;
- (*store)->misc = misc;
- (*store)->misc_len = misc_len;
- }
-
return err;
}
@@ -137,22 +165,39 @@ store_std_leaf_decode (struct store_enc *enc,
0, STORE_STD_CLASSES is used. If nothing else is to be done with ENC, its
contents may then be freed using store_enc_dealloc. */
error_t
-store_decode (struct store_enc *enc, struct store_class *classes,
+store_decode (struct store_enc *enc, const struct store_class *const *classes,
struct store **store)
{
+ const struct store_class *const *cl;
+
if (enc->cur_int >= enc->num_ints)
/* The first int should always be the type. */
return EINVAL;
- if (! classes)
- classes = store_std_classes;
-
- while (classes)
- if (classes->id == enc->ints[enc->cur_int])
- if (classes->decode)
- return (*classes->decode) (enc, classes, store);
- else
- return EOPNOTSUPP;
+ if (enc->ints[enc->cur_int] == STORAGE_NETWORK)
+ /* This is a special case because store classes supporting
+ individual URL types will also use STORAGE_NETWORK,
+ and we want the generic dispatcher to come first. */
+ return store_url_decode (enc, classes, store);
+
+ for (cl = classes ?: __start_store_std_classes;
+ classes ? *cl != 0 : cl < __stop_store_std_classes;
+ ++cl)
+ if ((*cl)->id == enc->ints[enc->cur_int])
+ {
+ if ((*cl)->decode)
+ return (*(*cl)->decode) (enc, classes, store);
+ else
+ return EOPNOTSUPP;
+ }
+
+# pragma weak store_module_decode
+ if (! classes && store_module_decode)
+ {
+ error_t err = store_module_decode (enc, classes, store);
+ if (err != ENOENT)
+ return err;
+ }
return EINVAL;
}
diff --git a/libstore/derive.c b/libstore/derive.c
index 63cf3430..a76fbe1c 100644
--- a/libstore/derive.c
+++ b/libstore/derive.c
@@ -1,9 +1,7 @@
/* Calculation of various derived store fields
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
-
+ Copyright (C) 1995-97,2001 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
This file is part of the GNU Hurd.
The GNU Hurd is free software; you can redistribute it and/or
@@ -18,7 +16,11 @@
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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <assert.h>
+#include <sys/types.h>
+#include <mach.h>
#include "store.h"
@@ -34,6 +36,7 @@ _store_derive (struct store *store)
/* BLOCK & SIZE */
store->blocks = 0;
+ store->wrap_src = 0;
for (i = 0; i < num_runs; i++)
{
@@ -50,7 +53,7 @@ _store_derive (struct store *store)
to include all iterations. */
{
size_t num_iters = store->end / store->wrap_src;
- off_t last_part_base = num_iters * store->wrap_src;
+ store_offset_t last_part_base = num_iters * store->wrap_src;
store->blocks *= num_iters;
@@ -68,17 +71,17 @@ _store_derive (struct store *store)
store->size = store->end * bsize;
- /* LOG2_BLOCK_SIZE */
store->log2_block_size = 0;
- while ((1 << store->log2_block_size) < bsize)
- store->log2_block_size++;
- if ((1 << store->log2_block_size) != bsize)
- store->log2_block_size = 0;
-
- /* LOG2_BLOCKS_PER_PAGE */
store->log2_blocks_per_page = 0;
- while ((bsize << store->log2_blocks_per_page) < vm_page_size)
- store->log2_blocks_per_page++;
- if ((bsize << store->log2_blocks_per_page) != vm_page_size)
- store->log2_blocks_per_page = 0;
+
+ if (bsize != 0)
+ {
+ while ((1 << store->log2_block_size) < bsize)
+ store->log2_block_size++;
+ assert ((1 << store->log2_block_size) == bsize);
+
+ while ((bsize << store->log2_blocks_per_page) < vm_page_size)
+ store->log2_blocks_per_page++;
+ assert ((bsize << store->log2_blocks_per_page) == vm_page_size);
+ }
}
diff --git a/libstore/device.c b/libstore/device.c
index 9036699f..3a72df48 100644
--- a/libstore/device.c
+++ b/libstore/device.c
@@ -1,9 +1,7 @@
/* Mach device store backend
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
-
+ Copyright (C) 1995,96,97,99,2001,02 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
This file is part of the GNU Hurd.
The GNU Hurd is free software; you can redistribute it and/or
@@ -18,7 +16,7 @@
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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
#include <assert.h>
#include <stdio.h>
@@ -28,47 +26,229 @@
#include "store.h"
+static inline error_t
+dev_error (error_t err)
+{
+ /* Give the canonical POSIX error codes,
+ rather than letting the Mach code propagate up. */
+ switch (err)
+ {
+ case D_IO_ERROR: return EIO;
+ case D_WOULD_BLOCK: return EAGAIN;
+ case D_NO_SUCH_DEVICE: return ENXIO;
+ case D_ALREADY_OPEN: return EBUSY;
+ case D_DEVICE_DOWN: return ENXIO; /* ? */
+ case D_INVALID_OPERATION: return EBADF; /* ? */
+ case D_NO_MEMORY: return ENOMEM;
+ default:
+ break;
+ }
+ /* Anything unexpected propagates up where weirdness will get noticed. */
+ return err;
+}
+
static error_t
dev_read (struct store *store,
- off_t addr, size_t index, mach_msg_type_number_t amount,
- char **buf, mach_msg_type_number_t *len)
-{
- error_t err = device_read (store->port, 0, addr, amount, (io_buf_ptr_t *)buf, len);
- char rep_buf[20];
- if (err)
- strcpy (rep_buf, "-");
- else if (*len > sizeof rep_buf - 3)
- sprintf (rep_buf, "\"%.*s\"...", (int)(sizeof rep_buf - 6), *buf);
- else
- sprintf (rep_buf, "\"%.*s\"", (int)(sizeof rep_buf - 3), *buf);
- fprintf (stderr, "; dev_read (%ld, %d, %d) [%d] => %s, %s, %d\n",
- addr, index, amount, store->block_size, err ? strerror (err) : "-",
- rep_buf, err ? 0 : *len);
- return err;
+ store_offset_t addr, size_t index, mach_msg_type_number_t amount,
+ void **buf, mach_msg_type_number_t *len)
+{
+ return dev_error (device_read (store->port, 0, addr, amount,
+ (io_buf_ptr_t *)buf, len));
}
static error_t
dev_write (struct store *store,
- off_t addr, size_t index, char *buf, mach_msg_type_number_t len,
+ store_offset_t addr, size_t index,
+ const void *buf, mach_msg_type_number_t len,
mach_msg_type_number_t *amount)
{
- return device_write (store->port, 0, addr, (io_buf_ptr_t)buf, len, amount);
+ error_t err = dev_error (device_write (store->port, 0, addr,
+ (io_buf_ptr_t)buf, len,
+ (int *) amount));
+ *amount = *(int *) amount; /* stupid device.defs uses int */
+ return err;
+}
+
+static error_t
+dev_set_size (struct store *store, size_t newsize)
+{
+ return EOPNOTSUPP;
}
static error_t
-dev_decode (struct store_enc *enc, struct store_class *classes,
+dev_decode (struct store_enc *enc, const struct store_class *const *classes,
struct store **store)
{
return store_std_leaf_decode (enc, _store_device_create, store);
}
-static struct store_class
-dev_class =
+static error_t
+dev_open (const char *name, int flags,
+ const struct store_class *const *classes,
+ struct store **store)
{
- STORAGE_DEVICE, "device", dev_read, dev_write,
- store_std_leaf_allocate_encoding, store_std_leaf_encode, dev_decode
+ return dev_error (store_device_open (name, flags, store));
+}
+
+static error_t
+dopen (const char *name, device_t *device, int *mod_flags)
+{
+ device_t dev_master;
+ error_t err = get_privileged_ports (0, &dev_master);
+ if (! err)
+ {
+ if (*mod_flags & STORE_HARD_READONLY)
+ err = device_open (dev_master, D_READ, (char *)name, device);
+ else
+ {
+ err = device_open (dev_master, D_WRITE | D_READ, (char *)name, device);
+ if (err == ED_READ_ONLY)
+ {
+ err = device_open (dev_master, D_READ, (char *)name, device);
+ if (! err)
+ *mod_flags |= STORE_HARD_READONLY;
+ }
+ else if (! err)
+ *mod_flags &= ~STORE_HARD_READONLY;
+ }
+ mach_port_deallocate (mach_task_self (), dev_master);
+ }
+ return err;
+}
+
+static void
+dclose (struct store *store)
+{
+ mach_port_deallocate (mach_task_self (), store->port);
+ store->port = MACH_PORT_NULL;
+}
+
+/* Return 0 if STORE's range is enforce by the kernel, otherwise an error. */
+static error_t
+enforced (struct store *store)
+{
+ error_t err;
+ dev_status_data_t sizes;
+ size_t sizes_len = DEV_STATUS_MAX;
+
+ if (store->num_runs != 1 || store->runs[0].start != 0)
+ /* Can't enforce non-contiguous ranges, or one not starting at 0. */
+ return EINVAL;
+ else
+ /* See if the the current (one) range is that the kernel is enforcing. */
+ {
+#ifdef DEV_GET_RECORDS
+ err =
+ device_get_status (store->port, DEV_GET_RECORDS, sizes, &sizes_len);
+
+ if (err && err != D_INVALID_OPERATION)
+ return EINVAL;
+
+ if (!err)
+ {
+ assert (sizes_len == DEV_GET_RECORDS_COUNT);
+
+ if (sizes[DEV_GET_RECORDS_RECORD_SIZE] != store->block_size
+ || (store->runs[0].length !=
+ sizes[DEV_GET_RECORDS_DEVICE_RECORDS]))
+ return EINVAL;
+
+ return 0;
+ }
+ else
+#endif
+ {
+ sizes_len = DEV_STATUS_MAX;
+ err =
+ device_get_status (store->port, DEV_GET_SIZE, sizes, &sizes_len);
+
+ if (err)
+ return EINVAL;
+
+ assert (sizes_len == DEV_GET_SIZE_COUNT);
+
+ if (sizes[DEV_GET_SIZE_RECORD_SIZE] != store->block_size
+ || (store->runs[0].length !=
+ sizes[DEV_GET_SIZE_DEVICE_SIZE] >> store->log2_block_size))
+ return EINVAL;
+
+ return 0;
+ }
+ }
+}
+
+static error_t
+dev_set_flags (struct store *store, int flags)
+{
+ if ((flags & ~(STORE_INACTIVE | STORE_ENFORCED)) != 0)
+ /* Trying to set flags we don't support. */
+ return EINVAL;
+
+ if (! ((store->flags | flags) & STORE_INACTIVE))
+ /* Currently active and staying that way, so we must be trying to set the
+ STORE_ENFORCED flag. */
+ {
+ error_t err = enforced (store);
+ if (err)
+ return err;
+ }
+
+ if (flags & STORE_INACTIVE)
+ dclose (store);
+
+ store->flags |= flags; /* When inactive, anything goes. */
+
+ return 0;
+}
+
+static error_t
+dev_clear_flags (struct store *store, int flags)
+{
+ error_t err = 0;
+ if ((flags & ~(STORE_INACTIVE | STORE_ENFORCED)) != 0)
+ err = EINVAL;
+ if (!err && (flags & STORE_INACTIVE))
+ err = store->name ? dopen (store->name, &store->port, &store->flags) : ENODEV;
+ if (! err)
+ store->flags &= ~flags;
+ return err;
+}
+
+static error_t
+dev_map (const struct store *store, vm_prot_t prot, mach_port_t *memobj)
+{
+ size_t nruns = store->num_runs;
+
+ if (nruns > 1 || (nruns == 1 && store->runs[0].start != 0))
+ return EOPNOTSUPP;
+ else
+ {
+ /* Note that older Mach drivers (through GNU Mach 1.x) ignore
+ the OFFSET and SIZE parameters. The OSKit-Mach drivers obey
+ them, and so the size we pass must be large enough (or zero
+ only if the size is indeterminable). If using only the newer
+ drivers, we could remove the `start != 0' condition above and
+ support kernel mapping of partial devices. However, since
+ the older drivers silently ignore the OFFSET argument, that
+ would produce scrambled results on old kernels. */
+ error_t err = device_map (store->port, prot,
+ store->runs[0].start,
+ store->runs[0].length,
+ memobj, 0);
+ if (err == ED_INVALID_OPERATION)
+ err = EOPNOTSUPP; /* This device doesn't support paging. */
+ return err;
+ }
+}
+
+const struct store_class
+store_device_class =
+{
+ STORAGE_DEVICE, "device", dev_read, dev_write, dev_set_size,
+ store_std_leaf_allocate_encoding, store_std_leaf_encode, dev_decode,
+ dev_set_flags, dev_clear_flags, 0, 0, 0, dev_open, 0, dev_map
};
-_STORE_STD_CLASS (dev_class);
+STORE_STD_CLASS (device);
/* Return a new store in STORE referring to the mach device DEVICE. Consumes
the send right DEVICE. */
@@ -76,22 +256,57 @@ error_t
store_device_create (device_t device, int flags, struct store **store)
{
struct store_run run;
- size_t sizes[DEV_GET_SIZE_COUNT], block_size;
- size_t sizes_len = DEV_GET_SIZE_COUNT;
- error_t err = device_get_status (device, DEV_GET_SIZE, sizes, &sizes_len);
+ size_t block_size = 0;
+ dev_status_data_t sizes;
+ size_t sizes_len = DEV_STATUS_MAX;
+ error_t err;
- if (err)
- return err;
+#ifdef DEV_GET_RECORDS
+ err = device_get_status (device, DEV_GET_RECORDS, sizes, &sizes_len);
+ if (! err && sizes_len == DEV_GET_RECORDS_COUNT)
+ {
+ block_size = sizes[DEV_GET_RECORDS_RECORD_SIZE];
- assert (sizes_len == DEV_GET_SIZE_COUNT);
+ if (block_size)
+ {
+ run.start = 0;
+ run.length = sizes[DEV_GET_RECORDS_DEVICE_RECORDS];
+ }
+ }
+ else
+#endif
+ {
+ /* Some Mach devices do not implement device_get_status, but do not
+ return an error. To detect these devices we set the size of the
+ input buffer to something larger than DEV_GET_SIZE_COUNT. If the
+ size of the returned device status is not equal to
+ DEV_GET_SIZE_COUNT, we know that something is wrong. */
+ sizes_len = DEV_STATUS_MAX;
+ err = device_get_status (device, DEV_GET_SIZE, sizes, &sizes_len);
+ if (! err && sizes_len == DEV_GET_SIZE_COUNT)
+ {
+ block_size = sizes[DEV_GET_SIZE_RECORD_SIZE];
- block_size = sizes[DEV_GET_SIZE_RECORD_SIZE];
- run.start = 0;
- run.length = sizes[DEV_GET_SIZE_DEVICE_SIZE] / block_size;
+ if (block_size)
+ {
+ run.start = 0;
+ run.length = sizes[DEV_GET_SIZE_DEVICE_SIZE] / block_size;
+
+ if (run.length * block_size != sizes[DEV_GET_SIZE_DEVICE_SIZE])
+ /* Bogus results (which some mach devices return). */
+ block_size = 0;
+ }
+ }
+ }
flags |= STORE_ENFORCED; /* 'cause it's the whole device. */
- return _store_device_create (device, flags, block_size, &run, 1, store);
+ if (block_size == 0)
+ /* Treat devices that can't do device_get_status as zero-length. */
+ return _store_device_create (device, flags, 0, &run, 0, store);
+ else
+ /* Make a store with one run covering the whole device. */
+ return _store_device_create (device, flags, block_size, &run, 1, store);
}
/* Like store_device_create, but doesn't query the device for information. */
@@ -100,29 +315,28 @@ _store_device_create (device_t device, int flags, size_t block_size,
const struct store_run *runs, size_t num_runs,
struct store **store)
{
- *store =
- _make_store (&dev_class, device, flags, block_size, runs, num_runs, 0);
- return *store ? 0 : ENOMEM;
+ return
+ _store_create (&store_device_class, device, flags, block_size,
+ runs, num_runs, 0, store);
}
/* Open the device NAME, and return the corresponding store in STORE. */
error_t
store_device_open (const char *name, int flags, struct store **store)
{
- device_t dev_master, device;
- int open_flags = ((flags & STORE_HARD_READONLY) ? 0 : D_WRITE) | D_READ;
- error_t err = get_privileged_ports (0, &dev_master);
-
- if (err)
- return err;
-
- err = device_open (dev_master, open_flags, (char *)name, &device);
-
- mach_port_deallocate (mach_task_self (), dev_master);
-
- err = store_device_create (device, flags, store);
- if (err)
- mach_port_deallocate (mach_task_self (), device);
-
+ device_t device;
+ error_t err = dopen (name, &device, &flags);
+ if (! err)
+ {
+ err = store_device_create (device, flags, store);
+ if (! err)
+ {
+ err = store_set_name (*store, name);
+ if (err)
+ store_free (*store);
+ }
+ if (err)
+ mach_port_deallocate (mach_task_self (), device);
+ }
return err;
}
diff --git a/libstore/enc.c b/libstore/enc.c
index 9706dfc9..d5002a0e 100644
--- a/libstore/enc.c
+++ b/libstore/enc.c
@@ -1,9 +1,7 @@
/* Store wire encoding/decoding
- Copyright (C) 1996 Free Software Foundation, Inc.
-
+ Copyright (C) 1996, 1997, 1999 Free Software Foundation, Inc.
Written by Miles Bader <miles@gnu.ai.mit.edu>
-
This file is part of the GNU Hurd.
The GNU Hurd is free software; you can redistribute it and/or
@@ -18,9 +16,10 @@
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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
#include <string.h>
+#include <sys/mman.h>
#include "store.h"
@@ -62,26 +61,38 @@ store_enc_dealloc (struct store_enc *enc)
}
if (enc->ports != enc->init_ports)
- vm_deallocate (mach_task_self (),
- (vm_address_t)enc->ports,
- enc->num_ports * sizeof (*enc->ports));
+ munmap ((caddr_t) enc->ports, enc->num_ports * sizeof (*enc->ports));
}
if (enc->ints && enc->num_ints > 0 && enc->ints != enc->init_ints)
- vm_deallocate (mach_task_self (),
- (vm_address_t)enc->ints,
- enc->num_ints * sizeof (*enc->ints));
+ munmap ((caddr_t) enc->ints, enc->num_ints * sizeof (*enc->ints));
if (enc->offsets && enc->num_offsets > 0
&& enc->offsets != enc->init_offsets)
- vm_deallocate (mach_task_self (),
- (vm_address_t)enc->offsets,
- enc->num_offsets * sizeof (*enc->offsets));
+ munmap ((caddr_t) enc->offsets, enc->num_offsets * sizeof (*enc->offsets));
if (enc->data && enc->data_len > 0 && enc->data != enc->init_data)
- vm_deallocate (mach_task_self (),
- (vm_address_t)enc->data, enc->data_len);
+ munmap (enc->data, enc->data_len);
/* For good measure... */
bzero (enc, sizeof (*enc));
}
+
+/* Copy out the parameters from ENC into the given variables suitably for
+ returning from a file_get_storage_info rpc, and deallocate ENC. */
+void
+store_enc_return (struct store_enc *enc,
+ mach_port_t **ports, mach_msg_type_number_t *num_ports,
+ int **ints, mach_msg_type_number_t *num_ints,
+ off_t **offsets, mach_msg_type_number_t *num_offsets,
+ char **data, mach_msg_type_number_t *data_len)
+{
+ *ports = enc->ports;
+ *num_ports = enc->num_ports;
+ *ints = enc->ints;
+ *num_ints = enc->num_ints;
+ *offsets = enc->offsets;
+ *num_offsets = enc->num_offsets;
+ *data = enc->data;
+ *data_len = enc->data_len;
+}
diff --git a/libstore/encode.c b/libstore/encode.c
index 38490cc0..df27250d 100644
--- a/libstore/encode.c
+++ b/libstore/encode.c
@@ -1,9 +1,7 @@
/* Store wire encoding
- Copyright (C) 1996 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
-
+ Copyright (C) 1996,97,99,2001,02 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
This file is part of the GNU Hurd.
The GNU Hurd is free software; you can redistribute it and/or
@@ -18,9 +16,10 @@
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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
#include <string.h>
+#include <sys/mman.h>
#include "store.h"
@@ -32,13 +31,20 @@ store_std_leaf_allocate_encoding (const struct store *store,
{
enc->num_ports++;
enc->num_ints += 6;
- enc->num_offsets += store->num_runs;
+ enc->num_offsets += store->num_runs * 2;
if (store->name)
enc->data_len += strlen (store->name) + 1;
enc->data_len += store->misc_len;
return 0;
}
+/* The RPC protocol uses 32-bit off_t's, but store_offset_t is now 64 bits. */
+static inline int too_big (store_offset_t ofs)
+{
+ off_t o = (off_t) ofs;
+ return o < 0 || ((store_offset_t) o != ofs);
+}
+
error_t
store_std_leaf_encode (const struct store *store, struct store_enc *enc)
{
@@ -56,6 +62,10 @@ store_std_leaf_encode (const struct store *store, struct store_enc *enc)
for (i = 0; i < store->num_runs; i++)
{
+ if (sizeof (*enc->offsets) != sizeof (store->runs[i].start)
+ && (too_big (store->runs[i].start)
+ || too_big (store->runs[i].start + store->runs[i].length)))
+ return EOVERFLOW;
enc->offsets[enc->cur_offset++] = store->runs[i].start;
enc->offsets[enc->cur_offset++] = store->runs[i].length;
}
@@ -82,8 +92,9 @@ store_std_leaf_encode (const struct store *store, struct store_enc *enc)
error_t
store_encode (const struct store *store, struct store_enc *enc)
{
+ void *buf;
error_t err;
- struct store_class *class = store->class;
+ const struct store_class *class = store->class;
/* We zero each vector length for the allocate_encoding method to work, so
save the old values. */
mach_msg_type_number_t init_num_ports = enc->num_ports;
@@ -102,19 +113,36 @@ store_encode (const struct store *store, struct store_enc *enc)
if (err)
return err;
+ errno = 0;
if (enc->num_ports > init_num_ports)
- err = vm_allocate (mach_task_self (),
- (vm_address_t *)&enc->ports, enc->num_ports, 1);
- if (!err && enc->num_ints > init_num_ints)
- err = vm_allocate (mach_task_self (),
- (vm_address_t *)&enc->ints, enc->num_ints, 1);
- if (!err && enc->num_offsets > init_num_offsets)
- err = vm_allocate (mach_task_self (),
- (vm_address_t *)&enc->offsets, enc->num_offsets, 1);
- if (!err && enc->data_len > init_data_len)
- err = vm_allocate (mach_task_self (),
- (vm_address_t *)&enc->data, enc->data_len, 1);
+ {
+ buf = mmap (0, enc->num_ports * sizeof *enc->ports,
+ PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ if (buf != (void *) -1)
+ enc->ports = buf;
+ }
+ if (!errno && enc->num_ints > init_num_ints)
+ {
+ buf = mmap (0, enc->num_ints * sizeof *enc->ints,
+ PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ if (buf != (void *) -1)
+ enc->ints = buf;
+ }
+ if (!errno && enc->num_offsets > init_num_offsets)
+ {
+ buf = mmap (0, enc->num_offsets * sizeof *enc->offsets,
+ PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ if (buf != (void *) -1)
+ enc->offsets = buf;
+ }
+ if (!errno && enc->data_len > init_data_len)
+ {
+ buf = mmap (0, enc->data_len, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ if (buf != (void *) -1)
+ enc->data = buf;
+ }
+ err = errno;
if (! err)
err = (*class->encode) (store, enc);
@@ -125,3 +153,26 @@ store_encode (const struct store *store, struct store_enc *enc)
return err;
}
+
+/* Encode STORE into the given return variables, suitably for returning from a
+ file_get_storage_info rpc. */
+error_t
+store_return (const struct store *store,
+ mach_port_t **ports, mach_msg_type_number_t *num_ports,
+ int **ints, mach_msg_type_number_t *num_ints,
+ off_t **offsets, mach_msg_type_number_t *num_offsets,
+ char **data, mach_msg_type_number_t *data_len)
+{
+ error_t err;
+ struct store_enc enc;
+
+ store_enc_init (&enc, *ports, *num_ports, *ints, *num_ints,
+ *offsets, *num_offsets, *data, *data_len);
+ err = store_encode (store, &enc);
+ if (err)
+ store_enc_dealloc (&enc);
+ else
+ store_enc_return (&enc, ports, num_ports, ints, num_ints,
+ offsets, num_offsets, data, data_len);
+ return err;
+}
diff --git a/libstore/file.c b/libstore/file.c
index 44cb7b9d..49f1c3fb 100644
--- a/libstore/file.c
+++ b/libstore/file.c
@@ -1,9 +1,7 @@
-/* Mach file store backend
-
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
+/* File store backend
+ Copyright (C) 1995,96,97,98,2001, 2002 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
This file is part of the GNU Hurd.
The GNU Hurd is free software; you can redistribute it and/or
@@ -18,7 +16,7 @@
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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
#include <stdio.h>
#include <string.h>
@@ -29,94 +27,225 @@
#include "store.h"
+/* Return 0 if STORE's range is enforced by the filesystem, otherwise an
+ error. */
+static error_t
+enforced (struct store *store)
+{
+ if (store->num_runs != 1 || store->runs[0].start != 0)
+ /* Can't enforce non-contiguous ranges, or one not starting at 0. */
+ return EINVAL;
+ else
+ {
+ /* See if the the current (one) range is that the kernel is enforcing. */
+ struct stat st;
+ error_t err = io_stat (store->port, &st);
+
+ if (!err
+ && store->runs[0].length != (st.st_size >> store->log2_block_size))
+ /* The single run is not the whole file. */
+ err = EINVAL;
+
+ return err;
+ }
+}
+
static error_t
file_read (struct store *store,
- off_t addr, size_t index, mach_msg_type_number_t amount,
- char **buf, mach_msg_type_number_t *len)
+ store_offset_t addr, size_t index, size_t amount, void **buf,
+ size_t *len)
{
size_t bsize = store->block_size;
- error_t err = io_read (store->port, buf, len, addr * bsize, amount);
- char rep_buf[20];
- if (err)
- strcpy (rep_buf, "-");
- else if (*len > sizeof rep_buf - 3)
- sprintf (rep_buf, "\"%.*s\"...", (int)(sizeof rep_buf - 6), *buf);
- else
- sprintf (rep_buf, "\"%.*s\"", (int)(sizeof rep_buf - 3), *buf);
- fprintf (stderr, "; file_read (%ld, %d, %d) [%d] => %s, %s, %d\n",
- addr, index, amount, store->block_size, err ? strerror (err) : "-",
- rep_buf, err ? 0 : *len);
- return err;
+ return io_read (store->port, (char **)buf, len, addr * bsize, amount);
}
static error_t
file_write (struct store *store,
- off_t addr, size_t index, char *buf, mach_msg_type_number_t len,
- mach_msg_type_number_t *amount)
+ store_offset_t addr, size_t index, const void *buf, size_t len,
+ size_t *amount)
{
size_t bsize = store->block_size;
- char rep_buf[20];
- if (len > sizeof rep_buf - 3)
- sprintf (rep_buf, "\"%.*s\"...", (int)(sizeof rep_buf - 6), buf);
- else
- sprintf (rep_buf, "\"%.*s\"", (int)(sizeof rep_buf - 3), buf);
- fprintf (stderr, "; file_write (%ld, %d, %s, %d)\n",
- addr, index, rep_buf, len);
return io_write (store->port, buf, len, addr * bsize, amount);
}
static error_t
-file_decode (struct store_enc *enc, struct store_class *classes,
+file_store_set_size (struct store *store, size_t newsize)
+{
+ error_t err;
+
+ if (enforced (store) != 0)
+ /* Bail out if there is more than a single run. */
+ return EOPNOTSUPP;
+
+ err = file_set_size (store->port, newsize);
+
+ if (!err)
+ {
+ /* Update STORE's size and run. */
+ store->size = newsize;
+ store->runs[0].length = newsize >> store->log2_block_size;
+ }
+
+ return err;
+}
+
+static error_t
+file_decode (struct store_enc *enc, const struct store_class *const *classes,
struct store **store)
{
return store_std_leaf_decode (enc, _store_file_create, store);
}
-static struct store_class
-file_class =
+static error_t
+file_open (const char *name, int flags,
+ const struct store_class *const *classes,
+ struct store **store)
{
- STORAGE_HURD_FILE, "file", file_read, file_write,
- store_std_leaf_allocate_encoding, store_std_leaf_encode, file_decode
-};
-_STORE_STD_CLASS (file_class);
+ return store_file_open (name, flags, store);
+}
static error_t
-file_byte_read (struct store *store,
- off_t addr, size_t index, mach_msg_type_number_t amount,
- char **buf, mach_msg_type_number_t *len)
+fiopen (const char *name, file_t *file, int *mod_flags)
+{
+ if (*mod_flags & STORE_HARD_READONLY)
+ *file = file_name_lookup (name, O_RDONLY, 0);
+ else
+ {
+ *file = file_name_lookup (name, O_RDWR, 0);
+ if (*file == MACH_PORT_NULL
+ && (errno == EACCES || errno == EROFS))
+ {
+ *file = file_name_lookup (name, O_RDONLY, 0);
+ if (*file != MACH_PORT_NULL)
+ *mod_flags |= STORE_HARD_READONLY;
+ }
+ else if (*file != MACH_PORT_NULL)
+ *mod_flags &= ~STORE_HARD_READONLY;
+ }
+ return *file == MACH_PORT_NULL ? errno : 0;
+}
+
+static void
+ficlose (struct store *store)
+{
+ mach_port_deallocate (mach_task_self (), store->port);
+ store->port = MACH_PORT_NULL;
+}
+
+
+
+static error_t
+file_set_flags (struct store *store, int flags)
{
- error_t err = io_read (store->port, buf, len, addr, amount);
- char rep_buf[20];
+ if ((flags & ~(STORE_INACTIVE | STORE_ENFORCED)) != 0)
+ /* Trying to set flags we don't support. */
+ return EINVAL;
+
+ if (! ((store->flags | flags) & STORE_INACTIVE))
+ /* Currently active and staying that way, so we must be trying to set the
+ STORE_ENFORCED flag. */
+ {
+ error_t err = enforced (store);
+ if (err)
+ return err;
+ }
+
+ if (flags & STORE_INACTIVE)
+ ficlose (store);
+
+ store->flags |= flags; /* When inactive, anything goes. */
+
+ return 0;
+}
+
+static error_t
+file_clear_flags (struct store *store, int flags)
+{
+ error_t err = 0;
+ if ((flags & ~(STORE_INACTIVE | STORE_ENFORCED)) != 0)
+ err = EINVAL;
+ if (!err && (flags & STORE_INACTIVE))
+ err = store->name
+ ? fiopen (store->name, &store->port, &store->flags)
+ : ENOENT;
+ if (! err)
+ store->flags &= ~flags;
+ return err;
+}
+
+static error_t
+file_map (const struct store *store, vm_prot_t prot, mach_port_t *memobj)
+{
+ error_t err;
+ mach_port_t rd_memobj, wr_memobj;
+ int ro = (store->flags & STORE_HARD_READONLY);
+
+ if (store->num_runs != 1 || store->runs[0].start != 0)
+ return EOPNOTSUPP;
+
+ if ((prot & VM_PROT_WRITE) && ro)
+ return EACCES;
+
+ err = io_map (store->port, &rd_memobj, &wr_memobj);
if (err)
- strcpy (rep_buf, "-");
- else if (*len > sizeof rep_buf - 3)
- sprintf (rep_buf, "\"%.*s\"...", (int)(sizeof rep_buf - 6), *buf);
+ return err;
+
+ *memobj = rd_memobj;
+
+ if (ro && wr_memobj == MACH_PORT_NULL)
+ return 0;
+ else if (rd_memobj == wr_memobj)
+ {
+ if (rd_memobj != MACH_PORT_NULL)
+ mach_port_mod_refs (mach_task_self (), rd_memobj,
+ MACH_PORT_RIGHT_SEND, -1);
+ }
else
- sprintf (rep_buf, "\"%.*s\"", (int)(sizeof rep_buf - 3), *buf);
- fprintf (stderr, "; file_byte_read (%ld, %d, %d) => %s, %s, %d\n",
- addr, index, amount, err ? strerror (err) : "-",
- rep_buf, err ? 0 : *len);
+ {
+ if (rd_memobj != MACH_PORT_NULL)
+ mach_port_deallocate (mach_task_self (), rd_memobj);
+ if (wr_memobj != MACH_PORT_NULL)
+ mach_port_deallocate (mach_task_self (), wr_memobj);
+ err = EOPNOTSUPP;
+ }
+
return err;
}
+const struct store_class
+store_file_class =
+{
+ STORAGE_HURD_FILE, "file", file_read, file_write, file_store_set_size,
+ store_std_leaf_allocate_encoding, store_std_leaf_encode, file_decode,
+ file_set_flags, file_clear_flags, 0, 0, 0, file_open, 0, file_map
+};
+STORE_STD_CLASS (file);
+
+static error_t
+file_byte_read (struct store *store,
+ store_offset_t addr, size_t index, size_t amount,
+ void **buf, size_t *len)
+{
+ return io_read (store->port, (char **)buf, len, addr, amount);
+}
+
static error_t
file_byte_write (struct store *store,
- off_t addr, size_t index,
- char *buf, mach_msg_type_number_t len,
- mach_msg_type_number_t *amount)
+ store_offset_t addr, size_t index,
+ const void *buf, size_t len,
+ size_t *amount)
{
- char rep_buf[20];
- if (len > sizeof rep_buf - 3)
- sprintf (rep_buf, "\"%.*s\"...", (int)(sizeof rep_buf - 6), buf);
- else
- sprintf (rep_buf, "\"%.*s\"", (int)(sizeof rep_buf - 3), buf);
- fprintf (stderr, "; file_byte_write (%ld, %d, %s, %d)\n",
- addr, index, rep_buf, len);
return io_write (store->port, buf, len, addr, amount);
}
-static struct store_class
-file_byte_class = {STORAGE_HURD_FILE, "file", file_byte_read, file_byte_write};
+struct store_class
+store_file_byte_class =
+{
+ STORAGE_HURD_FILE, "file", file_byte_read, file_byte_write,
+ file_store_set_size,
+ store_std_leaf_allocate_encoding, store_std_leaf_encode, file_decode,
+ file_set_flags, file_clear_flags, 0, 0, 0, file_open, 0, file_map
+};
/* Return a new store in STORE referring to the mach file FILE. Consumes
the send right FILE. */
@@ -145,29 +274,30 @@ _store_file_create (file_t file, int flags, size_t block_size,
struct store **store)
{
if (block_size == 1)
- *store = _make_store (&file_byte_class, file, flags, 1, runs, num_runs, 0);
- else if ((block_size & (block_size - 1)) == 0)
- *store =
- _make_store (&file_class, file, flags, block_size, runs, num_runs, 0);
+ return _store_create (&store_file_byte_class,
+ file, flags, 1, runs, num_runs, 0, store);
else
- return EINVAL; /* block size not a power of two */
- return *store ? 0 : ENOMEM;
+ return _store_create (&store_file_class,
+ file, flags, block_size, runs, num_runs, 0, store);
}
/* Open the file NAME, and return the corresponding store in STORE. */
error_t
store_file_open (const char *name, int flags, struct store **store)
{
- error_t err;
- int open_flags = (flags & STORE_HARD_READONLY) ? O_RDONLY : O_RDWR;
- file_t node = file_name_lookup (name, open_flags, 0);
-
- if (node == MACH_PORT_NULL)
- return errno;
-
- err = store_file_create (node, flags, store);
- if (err)
- mach_port_deallocate (mach_task_self (), node);
-
+ file_t file;
+ error_t err = fiopen (name, &file, &flags);
+ if (! err)
+ {
+ err = store_file_create (file, flags, store);
+ if (! err)
+ {
+ err = store_set_name (*store, name);
+ if (err)
+ store_free (*store);
+ }
+ if (err)
+ mach_port_deallocate (mach_task_self (), file);
+ }
return err;
}
diff --git a/libstore/flags.c b/libstore/flags.c
index 5d2ce74b..d80181ac 100644
--- a/libstore/flags.c
+++ b/libstore/flags.c
@@ -1,9 +1,7 @@
/* Setting various store flags
- Copyright (C) 1996 Free Software Foundation, Inc.
-
+ Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
Written by Miles Bader <miles@gnu.ai.mit.edu>
-
This file is part of the GNU Hurd.
The GNU Hurd is free software; you can redistribute it and/or
@@ -18,7 +16,7 @@
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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
#include <malloc.h>
#include <string.h>
@@ -33,10 +31,12 @@ store_set_flags (struct store *store, int flags)
int orig = store->flags, new = flags & ~orig;
if (new & STORE_BACKEND_FLAGS)
- if (store->class->set_flags)
- err = (*store->class->set_flags) (store, new);
- else
- err = EINVAL;
+ {
+ if (store->class->set_flags)
+ err = (*store->class->set_flags) (store, new);
+ else
+ err = EINVAL;
+ }
if (! err)
store->flags |= (new & ~STORE_BACKEND_FLAGS);
@@ -52,10 +52,12 @@ store_clear_flags (struct store *store, int flags)
int orig = store->flags, kill = flags & orig;
if (kill & STORE_BACKEND_FLAGS)
- if (store->class->clear_flags)
- err = (*store->class->clear_flags) (store, kill);
- else
- err = EINVAL;
+ {
+ if (store->class->clear_flags)
+ err = (*store->class->clear_flags) (store, kill);
+ else
+ err = EINVAL;
+ }
if (! err)
store->flags &= ~(kill & ~STORE_BACKEND_FLAGS);
diff --git a/libstore/gunzip.c b/libstore/gunzip.c
new file mode 100644
index 00000000..3bff6ead
--- /dev/null
+++ b/libstore/gunzip.c
@@ -0,0 +1,55 @@
+/* Decompressing store backend
+
+ Copyright (C) 1997, 1999, 2002 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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.
+
+ The GNU Hurd 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, USA. */
+
+#include <stdio.h>
+#include <string.h>
+#include <setjmp.h>
+#include <cthreads.h>
+#include <sys/mman.h>
+
+#include "store.h"
+
+/* gzip.h makes several annoying defines & decls, which we have to work
+ around. */
+#define file_t gzip_file_t
+#include "gzip.h"
+#undef file_t
+#undef head
+
+static error_t
+DO_UNZIP (void)
+{
+ /* Entry points to unzip engine. */
+ int get_method (int);
+ extern long int bytes_out;
+
+ if (get_method (0) != 0)
+ /* Not a happy gzip file. */
+ return EINVAL;
+
+ /* Matched gzip magic number. Ready to unzip.
+ Set up the output stream and let 'er rip. */
+ bytes_out = 0;
+ unzip (17, 23); /* Arguments ignored. */
+ return 0;
+}
+
+#define UNZIP gunzip
+#include "unzipstore.c"
diff --git a/libstore/kids.c b/libstore/kids.c
index 7c6cf51d..901a7f85 100644
--- a/libstore/kids.c
+++ b/libstore/kids.c
@@ -1,8 +1,7 @@
/* Managing sub-stores
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
+ Copyright (C) 1995,96,97,2001,02 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
This file is part of the GNU Hurd.
@@ -18,19 +17,21 @@
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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
-#include <malloc.h>
+#include <stdlib.h>
#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
#include "store.h"
/* Set STORE's current children list to (a copy of) CHILDREN and NUM_CHILDREN. */
error_t
store_set_children (struct store *store,
- struct store *const *children, unsigned num_children)
+ struct store *const *children, size_t num_children)
{
- unsigned size = num_children * sizeof (struct store_run);
+ unsigned size = num_children * sizeof (struct store *);
struct store **copy = malloc (size);
if (!copy)
@@ -39,13 +40,13 @@ store_set_children (struct store *store,
if (store->children)
free (store->children);
- bcopy (children, copy, size);
+ memcpy (copy, children, size);
store->children = copy;
store->num_children = num_children;
return 0;
}
-
+
/* Calls the allocate_encoding method in each child store of STORE,
propagating any errors. If any child does not hae such a method,
EOPNOTSUPP is returned. */
@@ -59,7 +60,7 @@ store_allocate_child_encodings (const struct store *store,
{
struct store *k = store->children[i];
if (k->class->allocate_encoding)
- (*k->class->allocate_encoding) (store, enc);
+ (*k->class->allocate_encoding) (k, enc);
else
err = EOPNOTSUPP;
}
@@ -77,7 +78,7 @@ store_encode_children (const struct store *store, struct store_enc *enc)
{
struct store *k = store->children[i];
if (k->class->encode)
- (*k->class->encode) (store, enc);
+ (*k->class->encode) (k, enc);
else
err = EOPNOTSUPP;
}
@@ -88,7 +89,8 @@ store_encode_children (const struct store *store, struct store_enc *enc)
positions in CHILDREN. */
error_t
store_decode_children (struct store_enc *enc, int num_children,
- struct store_class *classes, struct store **children)
+ const struct store_class *const *classes,
+ struct store **children)
{
int i;
error_t err = 0;
@@ -100,3 +102,211 @@ store_decode_children (struct store_enc *enc, int num_children,
store_free (children[i]);
return err;
}
+
+/* Set FLAGS in all children of STORE, and if successful, add FLAGS to
+ STORE's flags. */
+error_t
+store_set_child_flags (struct store *store, int flags)
+{
+ int i;
+ error_t err = 0;
+ int old_child_flags[store->num_children];
+
+ for (i = 0; i < store->num_children && !err; i++)
+ {
+ old_child_flags[i] = store->children[i]->flags;
+ err = store_set_flags (store->children[i], flags);
+ }
+
+ if (err)
+ while (i-- > 0)
+ store_clear_flags (store->children[i], flags & ~old_child_flags[i]);
+ else
+ store->flags |= flags;
+
+ return err;
+}
+
+/* Clear FLAGS in all children of STORE, and if successful, remove FLAGS from
+ STORE's flags. */
+error_t
+store_clear_child_flags (struct store *store, int flags)
+{
+ int i;
+ error_t err = 0;
+ int old_child_flags[store->num_children];
+
+ for (i = 0; i < store->num_children && !err; i++)
+ {
+ old_child_flags[i] = store->children[i]->flags;
+ err = store_clear_flags (store->children[i], flags);
+ }
+
+ if (err)
+ while (i-- > 0)
+ store_set_flags (store->children[i], flags & ~old_child_flags[i]);
+ else
+ store->flags &= ~flags;
+
+ return err;
+}
+
+/* Parse multiple store names in NAME, and open each individually, returning
+ all in the vector STORES, and the number in NUM_STORES. The syntax of
+ NAME is a single non-alpha-numeric separator character, followed by each
+ child store name separated by the same separator; each child name is
+ TYPE:NAME notation as parsed by store_typed_open. If every child uses the
+ same TYPE: prefix, then it may be factored out and put before the child
+ list instead (the two types of notation are differentiated by whether the
+ first character of name is alpha-numeric or not). */
+error_t
+store_open_children (const char *name, int flags,
+ const struct store_class *const *classes,
+ struct store ***stores, size_t *num_stores)
+{
+ char *pfx = 0; /* Prefix applied to each part name. */
+ size_t pfx_len = 0; /* Space PFX + separator takes up. */
+ char sep = *name; /* Character separating individual names. */
+
+ if (sep && isalnum (sep))
+ /* If the first character is a `name' character, it's likely to be either
+ a type prefix (e.g, TYPE:@NAME1@NAME2@), so we distribute the type
+ prefix among the elements (@TYPE:NAME1@TYPE:NAME2@). */
+ {
+ const char *pfx_end = name;
+
+ while (isalnum (*pfx_end))
+ pfx_end++;
+
+ if (*pfx_end++ != ':')
+ return EINVAL;
+
+ /* Make a copy of the prefix. */
+ pfx = strndupa (name, pfx_end - name);
+ pfx_len = pfx_end - name;
+
+ sep = *pfx_end;
+ }
+
+ if (sep)
+ /* Parse a list of store specs separated by SEP. */
+ {
+ int k;
+ const char *p, *end;
+ error_t err = 0;
+ size_t count = 0;
+
+ /* First, see how many there are. */
+ for (p = name; p && p[1]; p = strchr (p + 1, sep))
+ count++;
+
+ /* Make a vector to hold them. */
+ *stores = malloc (count * sizeof (struct store *));
+ *num_stores = count;
+ if (! *stores)
+ return ENOMEM;
+
+ bzero (*stores, count * sizeof (struct store *));
+
+ /* Open each child store. */
+ for (p = name, k = 0; !err && p && p[1]; p = end, k++)
+ {
+ size_t kname_len;
+
+ end = strchr (p + 1, sep);
+ kname_len = (end ? end - p - 1 : strlen (p + 1));
+
+ {
+ /* Allocate temporary child name on the stack. */
+ char kname[pfx_len + kname_len + 1];
+
+ if (pfx)
+ /* Add type prefix to child name. */
+ memcpy (kname, pfx, pfx_len);
+
+ memcpy (kname + pfx_len, p + 1, kname_len);
+ kname[pfx_len + kname_len] = '\0';
+
+ err = store_typed_open (kname, flags, classes, &(*stores)[k]);
+ }
+ }
+
+ if (err)
+ /* Failure opening some child, deallocate what we've done so far. */
+ {
+ while (--k >= 0)
+ store_free ((*stores)[k]);
+ free (*stores);
+ }
+
+ return err;
+ }
+ else
+ /* Empty list. */
+ {
+ *stores = 0;
+ *num_stores = 0;
+ return 0;
+ }
+}
+
+/* Try to come up with a name for the children in STORE, combining the names
+ of each child in a way that could be used to parse them with
+ store_open_children. This is done heuristically, and so may not succeed.
+ If a child doesn't have a name, EINVAL is returned. */
+error_t
+store_children_name (const struct store *store, char **name)
+{
+ static char try_seps[] = "@+=,._%|;^!~'&";
+ struct store **kids = store->children;
+ size_t num_kids = store->num_children;
+
+ if (num_kids == 0)
+ {
+ *name = strdup ("");
+ return *name ? 0 : ENOMEM;
+ }
+ else
+ {
+ int k;
+ char *s; /* Current separator in search for one. */
+ int fail; /* If we couldn't use *S as as sep. */
+ size_t total_len = 0; /* Length of name we will return. */
+
+ /* Detect children without names, and calculate the total length of the
+ name we will return (which is the sum of the lengths of the child
+ names plus room for the types and separator characters. */
+ for (k = 0; k < num_kids; k++)
+ if (!kids[k] || !kids[k]->name)
+ return EINVAL;
+ else
+ total_len +=
+ /* separator + type name + type separator + child name */
+ 1 + strlen (kids[k]->class->name) + 1 + strlen (kids[k]->name);
+
+ /* Look for a separator character from those in TRY_SEPS that doesn't
+ occur in any of the the child names. */
+ for (s = try_seps, fail = 1; *s && fail; s++)
+ for (k = 0, fail = 0; k < num_kids && !fail; k++)
+ if (strchr (kids[k]->name, *s))
+ fail = 1;
+
+ if (*s)
+ /* We found a usable separator! */
+ {
+ char *p = malloc (total_len + 1);
+
+ if (! p)
+ return ENOMEM;
+ *name = p;
+
+ for (k = 0; k < num_kids; k++)
+ p +=
+ sprintf (p, "%c%s:%s", *s, kids[k]->class->name, kids[k]->name);
+
+ return 0;
+ }
+ else
+ return EGRATUITOUS;
+ }
+}
diff --git a/libstore/make.c b/libstore/make.c
index 6f5e557a..8f289533 100644
--- a/libstore/make.c
+++ b/libstore/make.c
@@ -1,9 +1,7 @@
/* Store allocation/deallocation
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
-
+ Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc.
Written by Miles Bader <miles@gnu.ai.mit.edu>
-
This file is part of the GNU Hurd.
The GNU Hurd is free software; you can redistribute it and/or
@@ -18,7 +16,7 @@
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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
#include <malloc.h>
@@ -26,42 +24,54 @@
/* Allocate a new store structure with meths METHS, and the various other
fields initialized to the given parameters. */
-struct store *
-_make_store (struct store_class *class,
- mach_port_t port, int flags, size_t block_size,
- const struct store_run *runs, size_t num_runs, off_t end)
+error_t
+_store_create (const struct store_class *class,
+ mach_port_t port, int flags, size_t block_size,
+ const struct store_run *runs, size_t num_runs,
+ store_offset_t end, struct store **store)
{
- if (block_size & (block_size - 1))
- return 0; /* block size not a power of two. */
+ if ((block_size & (block_size - 1)) || (block_size == 0 && num_runs > 0))
+ return EINVAL; /* block size not a power of two. */
else
{
- struct store *store = malloc (sizeof (struct store));
- if (store)
+ struct store *new = malloc (sizeof (struct store));
+ if (new)
{
- store->name = 0;
- store->port = port;
- store->runs = 0;
- store->num_runs = 0;
- store->wrap_src = 0;
- store->wrap_dst = 0;
- store->flags = flags;
- store->end = end;
- store->block_size = block_size;
- store->source = MACH_PORT_NULL;
- store->blocks = 0;
- store->size = 0;
- store->log2_block_size = 0;
- store->log2_blocks_per_page = 0;
- store->misc = 0;
- store->hook = 0;
- store->children = 0;
- store->num_children = 0;
-
- store->class = class;
-
- store_set_runs (store, runs, num_runs); /* Calls _store_derive() */
+ error_t err;
+
+ new->name = 0;
+ new->port = port;
+ new->runs = 0;
+ new->num_runs = 0;
+ new->wrap_src = 0;
+ new->wrap_dst = 0;
+ new->flags = flags;
+ new->end = end;
+ new->block_size = block_size;
+ new->source = MACH_PORT_NULL;
+ new->blocks = 0;
+ new->size = 0;
+ new->log2_block_size = 0;
+ new->log2_blocks_per_page = 0;
+ new->misc = 0;
+ new->misc_len = 0;
+ new->hook = 0;
+ new->children = 0;
+ new->num_children = 0;
+
+ new->class = class;
+
+ /* store_set_runs calls _store_derive to derive other fields. */
+ err = store_set_runs (new, runs, num_runs);
+ if (err)
+ free (new);
+ else
+ *store = new;
+
+ return err;
}
- return store;
+ else
+ return ENOMEM;
}
}
diff --git a/libstore/map.c b/libstore/map.c
new file mode 100644
index 00000000..b7533cbb
--- /dev/null
+++ b/libstore/map.c
@@ -0,0 +1,79 @@
+/* Direct store mapping
+
+ Copyright (C) 1997 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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.
+
+ The GNU Hurd 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, USA. */
+
+#include <hurd.h>
+#include <hurd/io.h>
+
+#include "store.h"
+
+/* Return a memory object paging on STORE. [among other reasons,] this may
+ fail because store contains non-contiguous regions on the underlying
+ object. In such a case you can try calling some of the routines below to
+ get a pager. */
+error_t
+store_map (const struct store *store, vm_prot_t prot,
+ mach_port_t *memobj)
+{
+ error_t (*map) (const struct store *store, vm_prot_t prot,
+ mach_port_t *memobj) =
+ store->class->map;
+ error_t err = map ? (*map) (store, prot, memobj) : EOPNOTSUPP;
+
+ if (err == EOPNOTSUPP && store->source != MACH_PORT_NULL)
+ /* Can't map the store directly, but we know it represents the file
+ STORE->source, so we can try mapping that instead. */
+ {
+ mach_port_t rd_memobj, wr_memobj;
+ int ro = (store->flags & STORE_HARD_READONLY);
+
+ if ((prot & VM_PROT_WRITE) && ro)
+ return EACCES;
+
+ err = io_map (store->port, &rd_memobj, &wr_memobj);
+ if (! err)
+ {
+ *memobj = rd_memobj;
+
+ if (!ro || wr_memobj != MACH_PORT_NULL)
+ /* If either we or the server think this object is writable, then
+ the write-memory-object must be the same as the read one (if
+ we only care about reading, then it can be null too). */
+ {
+ if (rd_memobj == wr_memobj)
+ {
+ if (rd_memobj != MACH_PORT_NULL)
+ mach_port_mod_refs (mach_task_self (), rd_memobj,
+ MACH_PORT_RIGHT_SEND, -1);
+ }
+ else
+ {
+ if (rd_memobj != MACH_PORT_NULL)
+ mach_port_deallocate (mach_task_self (), rd_memobj);
+ if (wr_memobj != MACH_PORT_NULL)
+ mach_port_deallocate (mach_task_self (), wr_memobj);
+ err = EOPNOTSUPP;
+ }
+ }
+ }
+ }
+
+ return err;
+}
diff --git a/libstore/memobj.c b/libstore/memobj.c
new file mode 100644
index 00000000..0d5c816e
--- /dev/null
+++ b/libstore/memobj.c
@@ -0,0 +1,197 @@
+/* Store backend using a Mach memory object
+ Copyright (C) 2001, 2002 Free Software Foundation, Inc.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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.
+
+ The GNU Hurd 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, USA. */
+
+#include "store.h"
+#include <hurd.h>
+#include <hurd/sigpreempt.h>
+#include <sys/mman.h>
+#include <string.h>
+#include <assert.h>
+
+
+/* Return a new store in STORE referring to the memory object MEMOBJ.
+ Consumes the send right MEMOBJ. */
+error_t
+store_memobj_create (memory_object_t memobj, int flags, size_t block_size,
+ const struct store_run *runs, size_t num_runs,
+ struct store **store)
+{
+ return _store_create (&store_memobj_class,
+ memobj, flags, block_size, runs, num_runs, 0, store);
+}
+
+
+/* This one is pretty easy. */
+static error_t
+memobj_map (const struct store *store, vm_prot_t prot, mach_port_t *memobj)
+{
+ *memobj = store->port;
+ return mach_port_mod_refs (mach_task_self (), *memobj,
+ MACH_PORT_RIGHT_SEND, +1);
+}
+
+
+static error_t /* swiped from libpager's pager_memcpy */
+memobj_memcpy (memory_object_t memobj,
+ vm_offset_t offset, void *other, size_t *size,
+ vm_prot_t prot)
+{
+ vm_address_t window = 0;
+ vm_size_t windowsize = 8 * vm_page_size;
+ size_t to_copy = *size;
+ error_t err;
+
+ error_t copy (struct hurd_signal_preemptor *preemptor)
+ {
+ while (to_copy > 0)
+ {
+ size_t pageoff = offset & (vm_page_size - 1);
+
+ if (window)
+ /* Deallocate the old window. */
+ munmap ((caddr_t) window, windowsize);
+
+ /* Map in and copy a standard-sized window, unless that is
+ more than the total left to be copied. */
+
+ if (windowsize > pageoff + to_copy)
+ windowsize = pageoff + to_copy;
+
+ window = 0;
+ err = vm_map (mach_task_self (), &window, windowsize, 0, 1,
+ memobj, offset - pageoff, 0,
+ prot, prot, VM_INHERIT_NONE);
+ if (err)
+ return 0;
+
+ /* Realign the fault preemptor for the new mapping window. */
+ preemptor->first = window;
+ preemptor->last = window + windowsize;
+
+ if (prot == VM_PROT_READ)
+ memcpy (other, (const void *) window + pageoff,
+ windowsize - pageoff);
+ else
+ memcpy ((void *) window + pageoff, other, windowsize - pageoff);
+
+ offset += windowsize - pageoff;
+ other += windowsize - pageoff;
+ to_copy -= windowsize - pageoff;
+ }
+ return 0;
+ }
+
+ jmp_buf buf;
+ void fault (int signo, long int sigcode, struct sigcontext *scp)
+ {
+ assert (scp->sc_error == EKERN_MEMORY_ERROR);
+ err = EIO;
+ to_copy -= sigcode - window;
+ longjmp (buf, 1);
+ }
+
+ if (to_copy == 0)
+ /* Short-circuit return if nothing to do.
+ ERR would not be initialized by the copy loop in this case. */
+ return 0;
+
+ if (setjmp (buf) == 0)
+ hurd_catch_signal (sigmask (SIGSEGV) | sigmask (SIGBUS),
+ window, window + windowsize,
+ &copy, (sighandler_t) &fault);
+
+ if (window)
+ munmap ((caddr_t) window, windowsize);
+
+ *size -= to_copy;
+
+ return err;
+}
+
+static error_t
+memobj_read (struct store *store,
+ store_offset_t addr, size_t index, size_t amount,
+ void **buf, size_t *len)
+{
+ addr <<= store->log2_block_size;
+ if (((size_t) addr & (vm_page_size - 1)) == 0)
+ {
+ *len = amount;
+ return vm_map (mach_task_self (), (vm_address_t *) buf, amount,
+ 0, 1, store->port, addr << store->log2_block_size, 0,
+ VM_PROT_READ, VM_PROT_ALL, VM_INHERIT_NONE);
+ }
+ else
+ {
+ error_t err;
+ int alloced = 0;
+ if (*len < amount)
+ {
+ *buf = mmap (0, amount, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ if (*buf == MAP_FAILED)
+ return errno;
+ alloced = 1;
+ }
+ *len = amount;
+ err = memobj_memcpy (store->port, addr, *buf, len, VM_PROT_READ);
+ if (err && alloced)
+ munmap (*buf, amount);
+ else if (alloced && round_page (*len) < round_page (amount))
+ munmap (*buf + round_page (*len),
+ round_page (amount) - round_page (*len));
+ return err;
+ }
+}
+
+static error_t
+memobj_write (struct store *store,
+ store_offset_t addr, size_t index,
+ const void *buf, size_t len, size_t *amount)
+{
+ *amount = len;
+ return memobj_memcpy (store->port, addr << store->log2_block_size,
+ (void *) buf, amount, VM_PROT_WRITE);
+}
+
+static error_t
+memobj_set_size (struct store *store, size_t newsize)
+{
+ return EOPNOTSUPP;
+}
+
+static error_t
+memobj_decode (struct store_enc *enc, const struct store_class *const *classes,
+ struct store **store)
+{
+ return store_std_leaf_decode (enc, store_memobj_create, store);
+}
+
+const struct store_class
+store_memobj_class =
+{
+ STORAGE_MEMORY, "memobj",
+ map: memobj_map,
+ read: memobj_read,
+ set_size: memobj_set_size,
+ write: memobj_write,
+ allocate_encoding: store_std_leaf_allocate_encoding,
+ encode: store_std_leaf_encode,
+ decode: memobj_decode,
+};
+STORE_STD_CLASS (memobj);
diff --git a/libstore/module.c b/libstore/module.c
new file mode 100644
index 00000000..6e75099a
--- /dev/null
+++ b/libstore/module.c
@@ -0,0 +1,178 @@
+/* Dynamic loading of store class modules
+ Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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.
+
+ The GNU Hurd 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, USA. */
+
+#include "store.h"
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <error.h> /* XXX */
+
+static error_t
+open_class (int need_open,
+ const char *name, const char *clname_end,
+ const struct store_class **classp)
+{
+ char *modname, *clsym;
+ void *mod;
+
+ /* Construct the name of the shared object for this module. */
+ if (asprintf (&modname,
+ "libstore_%.*s%s", (int) (clname_end - name), name,
+ STORE_SONAME_SUFFIX) < 0)
+ return ENOMEM;
+
+ /* Now try to load the module.
+
+ Note we never dlclose the module, and add a ref every time we open it
+ anew. We can't dlclose it until no stores of this class exist, so
+ we'd need a creation/deletion hook for that. */
+
+ errno = 0;
+ mod = dlopen (modname, RTLD_LAZY);
+ if (mod == NULL)
+ {
+ const char *errstring = dlerror (); /* Must always call or it leaks! */
+ if (errno != ENOENT)
+ /* XXX not good, but how else to report the error? */
+ error (0, 0, "cannot load %s: %s", modname, errstring);
+ }
+ free (modname);
+ if (mod == NULL)
+ return errno ?: ENOENT;
+
+ if (asprintf (&clsym, "store_%.*s_class",
+ (int) (clname_end - name), name) < 0)
+ {
+ dlclose (mod);
+ return ENOMEM;
+ }
+
+ *classp = dlsym (mod, clsym);
+ free (clsym);
+ if (*classp == NULL)
+ {
+ error (0, 0, "invalid store module %.*s: %s",
+ (int) (clname_end - name), name, dlerror ());
+ dlclose (mod);
+ return EGRATUITOUS;
+ }
+
+ if (need_open && ! (*classp)->open)
+ {
+ /* This class cannot be opened as needed. */
+ dlclose (mod);
+ return EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+error_t
+store_module_find_class (const char *name, const char *clname_end,
+ const struct store_class **classp)
+{
+ return open_class (0, name, clname_end, classp);
+}
+
+error_t
+store_module_open (const char *name, int flags,
+ const struct store_class *const *classes,
+ struct store **store)
+{
+ const struct store_class *cl;
+ const char *clname_end = strchrnul (name, ':');
+ error_t err;
+
+ err = open_class (1, name, clname_end, &cl);
+ if (err)
+ return err;
+
+ if (*clname_end)
+ /* Skip the ':' separating the class-name from the device name. */
+ clname_end++;
+
+ if (! *clname_end)
+ /* The class-specific portion of the name is empty, so make it *really*
+ empty. */
+ clname_end = 0;
+
+ return (*cl->open) (clname_end, flags, classes, store);
+}
+
+const struct store_class store_module_open_class =
+{ -1, "module", open: store_module_open };
+STORE_STD_CLASS (module_open);
+
+error_t
+store_module_decode (struct store_enc *enc,
+ const struct store_class *const *classes,
+ struct store **store)
+{
+ char *modname;
+ void *mod;
+ const struct store_class *const *cl, *const *clend;
+ enum file_storage_class id;
+
+ if (enc->cur_int >= enc->num_ints)
+ /* The first int should always be the type. */
+ return EINVAL;
+
+ id = enc->ints[enc->cur_int];
+
+ /* Construct the name of the shared object for this module. */
+ if (asprintf (&modname, "libstore_type-%d%s", id, STORE_SONAME_SUFFIX) < 0)
+ return ENOMEM;
+
+ /* Try to open the module. */
+ mod = dlopen (modname, RTLD_LAZY);
+ free (modname);
+ if (mod == NULL)
+ {
+ (void) dlerror (); /* otherwise it leaks */
+ return ENOENT;
+ }
+
+ /* Now find its "store_std_classes" section, which points to each
+ `struct store_class' defined in this module. */
+ cl = dlsym (mod, "__start_store_std_classes");
+ if (cl == NULL)
+ {
+ error (0, 0, "invalid store module type-%d: %s", id, dlerror ());
+ dlclose (mod);
+ return EGRATUITOUS;
+ }
+ clend = dlsym (mod, "__stop_store_std_classes");
+ if (clend == NULL)
+ {
+ error (0, 0, "invalid store module type-%d: %s", id, dlerror ());
+ dlclose (mod);
+ return EGRATUITOUS;
+ }
+
+ while (cl < clend)
+ if ((*cl)->decode && (*cl)->id == id)
+ return (*(*cl)->decode) (enc, classes, store);
+ else
+ ++cl;
+
+ /* This class cannot be opened via store_decode. */
+ dlclose (mod);
+ return EOPNOTSUPP;
+}
diff --git a/libstore/mvol.c b/libstore/mvol.c
new file mode 100644
index 00000000..d243cc8a
--- /dev/null
+++ b/libstore/mvol.c
@@ -0,0 +1,158 @@
+/* Multiple-volume store backend
+
+ Copyright (C) 1996,97,2001, 2002 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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.
+
+ The GNU Hurd 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, USA. */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "store.h"
+
+struct mvol_state
+{
+ /* The current `volume'. */
+ ssize_t cur_vol;
+
+ /* A function to change volumes, making NEW_VOL readable on the store
+ instead of OLD_VOL. OLD_VOL is initially -1, */
+ error_t (*swap_vols) (struct store *store, size_t new_vol, ssize_t old_vol);
+};
+
+static error_t
+ensure_vol (struct store *store, size_t vol)
+{
+ error_t err = 0;
+ struct mvol_state *mv = store->hook;
+ if (vol != mv->cur_vol)
+ {
+ err = (*mv->swap_vols) (store, vol, mv->cur_vol);
+ if (! err)
+ mv->cur_vol = vol;
+ }
+ return err;
+}
+
+static error_t
+mvol_read (struct store *store,
+ store_offset_t addr, size_t index, size_t amount,
+ void **buf, size_t *len)
+{
+ error_t err = ensure_vol (store, index);
+ if (! err)
+ err = store_read (store->children[0], addr, amount, buf, len);
+ return err;
+}
+
+static error_t
+mvol_write (struct store *store,
+ store_offset_t addr, size_t index,
+ const void *buf, size_t len, size_t *amount)
+{
+ error_t err = ensure_vol (store, index);
+ if (! err)
+ err = store_write (store->children[0], addr, buf, len, amount);
+ return err;
+}
+
+static error_t
+mvol_set_size (struct store *store, size_t newsize)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+mvol_remap (struct store *source,
+ const struct store_run *runs, size_t num_runs,
+ struct store **store)
+{
+ return store_remap_create (source, runs, num_runs, 0, store);
+}
+
+const struct store_class
+store_mvol_class =
+{
+ -1, "mvol", mvol_read, mvol_write, mvol_set_size,
+ 0, 0, 0,
+ store_set_child_flags, store_clear_child_flags, 0, 0, mvol_remap
+};
+STORE_STD_CLASS (mvol);
+
+/* Return a new store in STORE that multiplexes multiple physical volumes
+ from PHYS as one larger virtual volume. SWAP_VOLS is a function that will
+ be called whenever the volume currently active isn't correct. PHYS is
+ consumed. */
+error_t
+store_mvol_create (struct store *phys,
+ error_t (*swap_vols) (struct store *store, size_t new_vol,
+ ssize_t old_vol),
+ int flags,
+ struct store **store)
+{
+ error_t err;
+ struct store_run run;
+
+ run.start = 0;
+ run.length = phys->end;
+
+ err = _store_create (&store_mvol_class, MACH_PORT_NULL,
+ flags | phys->flags, phys->block_size,
+ &run, 1, 0, store);
+ if (! err)
+ {
+ struct mvol_state *mv = malloc (sizeof (struct mvol_state));
+ if (mv)
+ {
+ mv->swap_vols = swap_vols;
+ mv->cur_vol = -1;
+ (*store)->hook = mv;
+ }
+ else
+ err = ENOMEM;
+
+ if (! err)
+ err = store_set_children (*store, &phys, 1);
+
+ if (! err)
+ {
+ if (phys->name)
+ {
+ size_t nlen =
+ strlen (phys->class->name) + 1 + strlen (phys->name) + 1;
+ char *name = malloc (nlen);
+
+ if (name)
+ {
+ snprintf (name, nlen, "%s:%s", phys->class->name, phys->name);
+ (*store)->name = name;
+ }
+ else
+ err = ENOMEM;
+ }
+ }
+
+ if (err)
+ {
+ if (mv)
+ free (mv);
+ store_free (*store);
+ }
+ }
+
+ return err;
+}
diff --git a/libstore/nbd.c b/libstore/nbd.c
new file mode 100644
index 00000000..3138af01
--- /dev/null
+++ b/libstore/nbd.c
@@ -0,0 +1,529 @@
+/* "Network Block Device" store backend compatible with Linux `nbd' driver
+ Copyright (C) 2001, 2002, 2008 Free Software Foundation, Inc.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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.
+
+ The GNU Hurd 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, USA. */
+
+#include "store.h"
+#include <hurd.h>
+#include <hurd/io.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/mman.h>
+
+
+// Avoid dragging in the resolver when linking statically.
+#pragma weak gethostbyname
+
+
+/* The nbd protocol, such as it is, is not really specified anywhere.
+ These message layouts and constants were culled from the nbd-server and
+ Linux kernel nbd module sources. */
+
+#define NBD_INIT_MAGIC "NBDMAGIC\x00\x00\x42\x02\x81\x86\x12\x53"
+
+#define NBD_REQUEST_MAGIC (htonl (0x25609513))
+#define NBD_REPLY_MAGIC (htonl (0x67446698))
+
+#define NBD_IO_MAX 10240
+
+struct nbd_startup
+{
+ char magic[16]; /* NBD_INIT_MAGIC */
+ uint64_t size; /* size in bytes, 64 bits in net order */
+ char reserved[128]; /* zeros, we don't check it */
+};
+
+struct nbd_request
+{
+ uint32_t magic; /* NBD_REQUEST_MAGIC */
+ uint32_t type; /* 0 read, 1 write, 2 disconnect */
+ uint64_t handle; /* returned in reply */
+ uint64_t from;
+ uint32_t len;
+} __attribute__ ((packed));
+
+struct nbd_reply
+{
+ uint32_t magic; /* NBD_REPLY_MAGIC */
+ uint32_t error;
+ uint64_t handle; /* value from request */
+} __attribute__ ((packed));
+
+
+/* i/o functions. */
+
+#if BYTE_ORDER == BIG_ENDIAN
+# define htonll(x) (x)
+#elif BYTE_ORDER == LITTLE_ENDIAN
+# include <byteswap.h>
+# define htonll(x) (bswap_64 (x))
+#else
+# error what endian?
+#endif
+#define ntohll htonll
+
+
+static inline error_t
+read_reply (struct store *store, uint64_t handle)
+{
+ struct nbd_reply reply;
+ char *buf = (void *) &reply;
+ mach_msg_type_number_t cc = sizeof reply;
+ error_t err = io_read (store->port, &buf, &cc, -1, cc);
+ if (err)
+ return err;
+ if (buf != (void *) &reply)
+ {
+ memcpy (&reply, buf, sizeof reply);
+ munmap (buf, cc);
+ }
+ if (cc != sizeof reply)
+ return EIO;
+ if (reply.magic != NBD_REPLY_MAGIC)
+ return EIO;
+ if (reply.handle != handle)
+ return EIO;
+ if (reply.error != 0)
+ return EIO;
+ return 0;
+}
+
+static error_t
+nbd_write (struct store *store,
+ store_offset_t addr, size_t index, const void *buf, size_t len,
+ size_t *amount)
+{
+ struct nbd_request req =
+ {
+ magic: NBD_REQUEST_MAGIC,
+ type: htonl (1), /* WRITE */
+ };
+ error_t err;
+ mach_msg_type_number_t cc;
+
+ addr <<= store->log2_block_size;
+ *amount = 0;
+
+ do
+ {
+ size_t chunk = len < NBD_IO_MAX ? len : NBD_IO_MAX, nwrote;
+ req.from = htonll (addr);
+ req.len = htonl (chunk);
+
+ err = io_write (store->port, (char *) &req, sizeof req, -1, &cc);
+ if (err)
+ return err;
+ if (cc != sizeof req)
+ return EIO;
+
+ nwrote = 0;
+ do
+ {
+ err = io_write (store->port, (char *) buf, chunk - nwrote, -1, &cc);
+ if (err)
+ return err;
+ buf += cc;
+ nwrote += cc;
+ } while (nwrote < chunk);
+
+ err = read_reply (store, req.handle);
+ if (err)
+ return err;
+
+ addr += chunk;
+ *amount += chunk;
+ len -= chunk;
+ } while (len > 0);
+
+ return 0;
+}
+
+static error_t
+nbd_read (struct store *store,
+ store_offset_t addr, size_t index, size_t amount,
+ void **buf, size_t *len)
+{
+ struct nbd_request req =
+ {
+ magic: NBD_REQUEST_MAGIC,
+ type: htonl (0), /* READ */
+ };
+ error_t err;
+ size_t ofs, chunk;
+ char *databuf, *piecebuf;
+ size_t databuflen, piecelen;
+
+ /* Send a request for the largest possible piece of remaining data and
+ read the first piece of its reply into PIECEBUF, PIECELEN. The amount
+ requested can be found in CHUNK. */
+ inline error_t request_chunk (char **buf, size_t *len)
+ {
+ mach_msg_type_number_t cc;
+
+ chunk = (amount - ofs) < NBD_IO_MAX ? (amount - ofs) : NBD_IO_MAX;
+
+ req.from = htonll (addr);
+ req.len = htonl (chunk);
+
+ /* Advance ADDR immediately, so it always points past what we've
+ already requested. */
+ addr += chunk;
+
+ return (io_write (store->port, (char *) &req, sizeof req, -1, &cc) ?
+ : cc != sizeof req ? EIO
+ : read_reply (store, req.handle) ?
+ : io_read (store->port, buf, len, (off_t) -1, chunk));
+ }
+
+ addr <<= store->log2_block_size;
+
+ /* Read the first piece, which can go directly into the caller's buffer. */
+ databuf = *buf;
+ piecelen = databuflen = *len;
+ err = request_chunk (&databuf, &piecelen);
+ if (err)
+ return err;
+ if (databuflen >= amount)
+ {
+ /* That got it all. We're done. */
+ *buf = databuf;
+ *len = piecelen;
+ return 0;
+ }
+
+ /* We haven't read the entire amount yet. */
+ ofs = 0;
+ do
+ {
+ /* Account for what we just read. */
+ ofs += piecelen;
+ chunk -= piecelen;
+ if (ofs == amount)
+ {
+ /* That got it all. We're done. */
+ *buf = databuf;
+ *len = ofs;
+ return 0;
+ }
+
+ /* Now we'll read another piece of the data, hopefully
+ into the latter part of the existing buffer. */
+ piecebuf = databuf + ofs;
+ piecelen = databuflen - ofs;
+
+ if (chunk > 0)
+ /* We haven't finishing reading the last chunk we requested. */
+ err = io_read (store->port, &piecebuf, &piecelen,
+ (off_t) -1, chunk);
+ else
+ /* Request the next chunk from the server. */
+ err = request_chunk (&piecebuf, &piecelen);
+
+ if (!err && piecebuf != databuf + ofs)
+ {
+ /* Now we have two discontiguous pieces of the buffer. */
+ size_t newbuflen = round_page (databuflen + piecelen);
+ char *newbuf = mmap (0, newbuflen,
+ PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ if (newbuf == MAP_FAILED)
+ {
+ err = errno;
+ break;
+ }
+ memcpy (newbuf, databuf, ofs);
+ memcpy (newbuf + ofs, piecebuf, piecelen);
+ if (databuf != *buf)
+ munmap (databuf, databuflen);
+ databuf = newbuf;
+ databuflen = newbuflen;
+ }
+ } while (! err);
+
+ if (databuf != *buf)
+ munmap (databuf, databuflen);
+ return err;
+}
+
+static error_t
+nbd_set_size (struct store *store, size_t newsize)
+{
+ return EOPNOTSUPP;
+}
+
+
+
+/* Setup hooks. */
+
+static error_t
+nbd_decode (struct store_enc *enc, const struct store_class *const *classes,
+ struct store **store)
+{
+ return store_std_leaf_decode (enc, _store_nbd_create, store);
+}
+
+static error_t
+nbd_open (const char *name, int flags,
+ const struct store_class *const *classes,
+ struct store **store)
+{
+ return store_nbd_open (name, flags, store);
+}
+
+static const char url_prefix[] = "nbd://";
+
+/* Valid name syntax is [nbd://]HOSTNAME:PORT[/BLOCKSIZE].
+ If "/BLOCKSIZE" is omitted, the block size is 1. */
+static error_t
+nbd_validate_name (const char *name,
+ const struct store_class *const *classes)
+{
+ char *p, *endp;
+
+ if (!strncmp (name, url_prefix, sizeof url_prefix - 1))
+ name += sizeof url_prefix - 1;
+
+ p = strchr (name, ':');
+ if (p == 0)
+ return EINVAL;
+ endp = 0;
+ strtoul (++p, &endp, 0);
+ if (endp == 0 || endp == p)
+ return EINVAL;
+ switch (*endp)
+ {
+ default:
+ return EINVAL;
+ case '\0':
+ break;
+ case '/':
+ p = endp + 1;
+ strtoul (p, &endp, 0);
+ if (endp == 0 || endp == p)
+ return EINVAL;
+ if (*endp != '\0')
+ return EINVAL;
+ }
+ return 0;
+}
+
+static error_t
+nbdopen (const char *name, int *mod_flags,
+ socket_t *sockport, size_t *blocksize, store_offset_t *size)
+{
+ int sock;
+ struct sockaddr_in sin;
+ const struct hostent *he;
+ char **ap;
+ struct nbd_startup ns;
+ ssize_t cc;
+ size_t ofs;
+ unsigned long int port;
+ char *hostname, *p, *endp;
+
+ if (!strncmp (name, url_prefix, sizeof url_prefix - 1))
+ name += sizeof url_prefix - 1;
+
+ /* First we have to parse the store name to get the host name and TCP
+ port number to connect to and the block size to use. */
+
+ hostname = strdupa (name);
+ p = strchr (hostname, ':');
+
+ if (p == 0)
+ return EINVAL;
+ *p++ = '\0';
+ port = strtoul (p, &endp, 0);
+ if (endp == 0 || endp == p || port > 0xffffUL)
+ return EINVAL;
+ switch (*endp)
+ {
+ default:
+ return EINVAL;
+ case '\0':
+ *blocksize = 1;
+ break;
+ case '/':
+ p = endp + 1;
+ *blocksize = strtoul (p, &endp, 0);
+ if (endp == 0 || endp == p)
+ return EINVAL;
+ if (*endp != '\0')
+ return EINVAL;
+ }
+
+ /* Now look up the host name and get a TCP connection. */
+
+ he = gethostbyname (hostname);
+ if (he == 0) /* XXX emit an error message? */
+ return errno; /* XXX what value will this have? */
+
+ sock = socket (PF_INET, SOCK_STREAM, 0);
+ if (sock < 0)
+ return errno;
+
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons (port);
+ for (ap = he->h_addr_list; *ap != 0; ++ap)
+ {
+ sin.sin_addr = *(const struct in_addr *) *ap;
+ errno = 0;
+ if (connect (sock, &sin, sizeof sin) == 0 || errno == ECONNREFUSED)
+ break;
+ }
+ if (errno != 0) /* last connect failed */
+ {
+ error_t err = errno;
+ close (sock);
+ return err;
+ }
+
+ /* Read the startup packet, which tells us the size of the store. */
+ ofs = 0;
+ do {
+ cc = read (sock, (char *) &ns + ofs, sizeof ns - ofs);
+ if (cc < 0)
+ {
+ error_t err = errno;
+ close (sock);
+ return err;
+ }
+ ofs += cc;
+ } while (cc > 0 && ofs < sizeof ns);
+
+ if (ofs != sizeof ns
+ || memcmp (ns.magic, NBD_INIT_MAGIC, sizeof ns.magic) != 0)
+ {
+ close (sock);
+ return EGRATUITOUS; /* ? */
+ }
+
+ *size = ntohll (ns.size);
+ *sockport = getdport (sock);
+ close (sock);
+
+ return 0;
+}
+
+static void
+nbdclose (struct store *store)
+{
+ if (store->port != MACH_PORT_NULL)
+ {
+ /* Send a disconnect message, but don't wait for a reply. */
+ struct nbd_request req =
+ {
+ magic: NBD_REQUEST_MAGIC,
+ type: htonl (2), /* disconnect */
+ };
+ mach_msg_type_number_t cc;
+ (void) io_write (store->port, (char *) &req, sizeof req, -1, &cc);
+
+ /* Close the socket. */
+ mach_port_deallocate (mach_task_self (), store->port);
+ store->port = MACH_PORT_NULL;
+ }
+}
+
+static error_t
+nbd_set_flags (struct store *store, int flags)
+{
+ if ((flags & ~STORE_INACTIVE) != 0)
+ /* Trying to set flags we don't support. */
+ return EINVAL;
+
+ nbdclose (store);
+ store->flags |= STORE_INACTIVE;
+
+ return 0;
+}
+
+static error_t
+nbd_clear_flags (struct store *store, int flags)
+{
+ error_t err = 0;
+ if ((flags & ~STORE_INACTIVE) != 0)
+ err = EINVAL;
+ err = store->name
+ ? nbdopen (store->name, &store->flags,
+ &store->port, &store->block_size, &store->size)
+ : ENOENT;
+ if (! err)
+ store->flags &= ~STORE_INACTIVE;
+ return err;
+}
+
+const struct store_class store_nbd_class =
+{
+ STORAGE_NETWORK, "nbd",
+ open: nbd_open,
+ validate_name: nbd_validate_name,
+ read: nbd_read,
+ write: nbd_write,
+ set_size: nbd_set_size,
+ allocate_encoding: store_std_leaf_allocate_encoding,
+ encode: store_std_leaf_encode,
+ decode: nbd_decode,
+ set_flags: nbd_set_flags, clear_flags: nbd_clear_flags,
+};
+STORE_STD_CLASS (nbd);
+
+/* Create a store from an existing socket to an nbd server.
+ The initial handshake has already been done. */
+error_t
+_store_nbd_create (mach_port_t port, int flags, size_t block_size,
+ const struct store_run *runs, size_t num_runs,
+ struct store **store)
+{
+ return _store_create (&store_nbd_class,
+ port, flags, block_size, runs, num_runs, 0, store);
+}
+
+/* Open a new store backed by the named nbd server. */
+error_t
+store_nbd_open (const char *name, int flags, struct store **store)
+{
+ error_t err;
+ socket_t sock;
+ struct store_run run;
+ size_t blocksize;
+
+ run.start = 0;
+ err = nbdopen (name, &flags, &sock, &blocksize, &run.length);
+ if (!err)
+ {
+ run.length /= blocksize;
+ err = _store_nbd_create (sock, flags, blocksize, &run, 1, store);
+ if (! err)
+ {
+ if (!strncmp (name, url_prefix, sizeof url_prefix - 1))
+ err = store_set_name (*store, name);
+ else
+ asprintf (&(*store)->name, "%s%s", url_prefix, name);
+ if (err)
+ store_free (*store);
+ }
+ if (err)
+ mach_port_deallocate (mach_task_self (), sock);
+ }
+ return err;
+}
diff --git a/libstore/null.c b/libstore/null.c
deleted file mode 100644
index dd30ded1..00000000
--- a/libstore/null.c
+++ /dev/null
@@ -1,109 +0,0 @@
-/* Null store backend
-
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
-
- This file is part of the GNU Hurd.
-
- The GNU Hurd 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.
-
- The GNU Hurd 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
-
-#include <assert.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "store.h"
-
-static error_t
-null_read (struct store *store,
- off_t addr, size_t index, mach_msg_type_number_t amount,
- char **buf, mach_msg_type_number_t *len)
-{
- if (*len < amount)
- {
- error_t err =
- vm_allocate (mach_task_self (), (vm_address_t *)buf, amount, 1);
- if (! err)
- *len = amount;
- return err;
- }
- else
- {
- bzero (*buf, amount);
- *len = amount;
- return 0;
- }
-}
-
-static error_t
-null_write (struct store *store,
- off_t addr, size_t index, char *buf, mach_msg_type_number_t len,
- mach_msg_type_number_t *amount)
-{
- return 0;
-}
-
-error_t
-null_allocate_encoding (const struct store *store, struct store_enc *enc)
-{
- enc->num_ints += 2;
- enc->num_offsets += 1;
- return 0;
-}
-
-error_t
-null_encode (const struct store *store, struct store_enc *enc)
-{
- enc->ints[enc->cur_int++] = store->class->id;
- enc->ints[enc->cur_int++] = store->flags;
- enc->offsets[enc->cur_offset++] = store->size;
- return 0;
-}
-
-error_t
-null_decode (struct store_enc *enc, struct store_class *classes,
- struct store **store)
-{
- off_t size;
- int type, flags;
-
- if (enc->cur_int + 2 > enc->num_ints
- || enc->cur_offset + 1 > enc->num_offsets)
- return EINVAL;
-
- type = enc->ints[enc->cur_int++];
- flags = enc->ints[enc->cur_int++];
- size = enc->offsets[enc->cur_offset++];
-
- return store_null_create (size, flags, store);
-}
-
-static struct store_class
-null_class =
-{
- STORAGE_NULL, "null", null_read, null_write,
- null_allocate_encoding, null_encode, null_decode
-};
-_STORE_STD_CLASS (null_class);
-
-/* Return a new null store SIZE bytes long in STORE. */
-error_t
-store_null_create (size_t size, int flags, struct store **store)
-{
- struct store_run run = { 0, size };
- *store = _make_store (&null_class, MACH_PORT_NULL, flags, 1, &run, 1, 0);
- return *store ? 0 : ENOMEM;
-}
diff --git a/libstore/open.c b/libstore/open.c
new file mode 100644
index 00000000..5c00e107
--- /dev/null
+++ b/libstore/open.c
@@ -0,0 +1,65 @@
+/* Store creation from a file name
+
+ Copyright (C) 1996,97,98,2001, 2002 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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.
+
+ The GNU Hurd 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, USA. */
+
+#include <fcntl.h>
+#include <hurd.h>
+
+#include "store.h"
+
+/* Open the file NAME, and return a new store in STORE, which refers to the
+ storage underlying it. CLASSES is used to select classes specified by the
+ provider; if it is 0, STORE_STD_CLASSES is used. FLAGS is set with
+ store_set_flags. A reference to the open file is created (but may be
+ destroyed with store_close_source). */
+error_t
+store_open (const char *name, int flags,
+ const struct store_class *const *classes,
+ struct store **store)
+{
+ error_t err;
+ int open_flags = (flags & STORE_HARD_READONLY) ? O_RDONLY : O_RDWR;
+ file_t node = file_name_lookup (name, open_flags, 0);
+
+ if (node == MACH_PORT_NULL && !(flags & STORE_HARD_READONLY)
+ && (errno == EACCES || errno == EROFS))
+ {
+ flags |= STORE_HARD_READONLY;
+ node = file_name_lookup (name, O_RDONLY, 0);
+ }
+
+ if (node == MACH_PORT_NULL)
+ return errno;
+
+ err = store_create (node, flags, classes, store);
+ if (err)
+ {
+ if (! (flags & STORE_NO_FILEIO))
+ /* Try making a store that does file io to NODE. */
+ err = store_file_create (node, flags, store);
+ if (err)
+ mach_port_deallocate (mach_task_self (), node);
+ }
+
+ return err;
+}
+
+const struct store_class
+store_query_class = { -1, "query", open: store_open };
+STORE_STD_CLASS (query);
diff --git a/libstore/part.c b/libstore/part.c
new file mode 100644
index 00000000..439340be
--- /dev/null
+++ b/libstore/part.c
@@ -0,0 +1,197 @@
+/* Partition store backend
+ Copyright (C) 2001, 2002 Free Software Foundation, Inc.
+ Written by Neal H Walfield <neal@cs.uml.edu>
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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.
+
+ The GNU Hurd 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, USA. */
+
+#include "store.h"
+#include <stdlib.h>
+#include <errno.h>
+#include <assert.h>
+#include <cthreads.h>
+
+#include <parted/parted.h>
+/*#include <parted/device_gnu.h>*/
+#include <string.h>
+#include <error.h>
+
+#define NEED_PARTED_VERSION "1.5.4"
+#ifndef PED_SECTOR_SIZE
+#define PED_SECTOR_SIZE PED_SECTOR_SIZE_DEFAULT
+#endif
+
+/* Return a new store in STORE which contains a remap store of partition
+ PART from the contents of SOURCE; SOURCE is consumed. */
+error_t
+store_part_create (struct store *source, int index, int flags,
+ struct store **store)
+{
+ static struct mutex parted_lock = MUTEX_INITIALIZER;
+ static int version_check;
+ error_t err = 0;
+ PedDevice *dev;
+ PedDisk *disk;
+ PedPartition *part;
+ struct store_run run;
+
+ if ((source->block_size < PED_SECTOR_SIZE
+ && PED_SECTOR_SIZE % source->block_size != 0)
+ || (source->block_size > PED_SECTOR_SIZE
+ && source->block_size % PED_SECTOR_SIZE != 0))
+ return EINVAL;
+
+ mutex_lock (&parted_lock);
+
+ /* Since Parted provides no source-level information about
+ version compatibility, we have to check at run time. */
+ if (version_check == 0)
+ {
+ const char *version = ped_get_version ();
+ version_check = -1;
+ if (version == 0)
+ error (0, 0, "cannot get version of Parted library!");
+ else if (strverscmp (version, NEED_PARTED_VERSION) < 0)
+ error (0, 0, "Parted library version %s older than needed %s",
+ version, NEED_PARTED_VERSION);
+ else
+ version_check = 1;
+ }
+ if (version_check <= 0)
+ {
+ error (0, 0, "the `part' store type is not available");
+ mutex_unlock (&parted_lock);
+ return ENOTSUP;
+ }
+
+ ped_exception_fetch_all ();
+
+ dev = ped_device_new_from_store (source);
+ if (! dev)
+ {
+ ped_exception_catch ();
+ err = EIO;
+ goto out;
+ }
+
+ assert (ped_device_open (dev) != 0);
+
+ disk = ped_disk_new (dev);
+ if (! disk)
+ {
+ ped_exception_catch ();
+ err = EIO;
+ goto out_with_dev;
+ }
+
+ for (part = ped_disk_next_partition (disk, NULL); part;
+ part = ped_disk_next_partition (disk, part))
+ {
+ if (part->type != PED_PARTITION_LOGICAL
+ && part->type != 0 /* PED_PARTITION_PRIMARY */)
+ continue;
+
+ assert (part->num);
+ if (part->num == index)
+ break;
+ }
+
+ if (! part)
+ {
+ err = EIO;
+ goto out_with_disk;
+ }
+
+ if (source->block_size == PED_SECTOR_SIZE)
+ {
+ run.start = part->geom.start;
+ run.length = part->geom.length;
+ }
+ else if (source->block_size < PED_SECTOR_SIZE)
+ {
+ run.start = part->geom.start * (PED_SECTOR_SIZE / source->block_size);
+ run.length = part->geom.length * (PED_SECTOR_SIZE / source->block_size);
+ }
+ else
+ /* source->block_size > PED_SECTOR_SIZE */
+ {
+ run.start = part->geom.start * PED_SECTOR_SIZE;
+ if (run.start % source->block_size != 0)
+ err = EIO;
+ else
+ {
+ run.start /= source->block_size;
+ run.length = part->geom.length * PED_SECTOR_SIZE;
+ if (run.length % source->block_size != 0)
+ err = EIO;
+ else
+ run.length /= source->block_size;
+ }
+ }
+
+out_with_disk:
+ assert (ped_device_close (dev) != 0);
+ ped_disk_destroy (disk);
+out_with_dev:
+ ped_device_destroy (dev);
+out:
+ ped_exception_leave_all ();
+ mutex_unlock (&parted_lock);
+
+ if (! err)
+ err = store_remap (source, &run, 1, store);
+
+ return err;
+}
+
+/* Open the part NAME. NAME consists of a partition number, a ':', a another
+ store class name, a ':' and a name for to by passed to the store class.
+ E.g. "2:device:hd0" would open the second partition on a DEVICE store
+ named "hd0". FLAGS indicate how to open the store. CLASSES is used to
+ select classes specified by the type NAME; if it is 0, STORE_STD_CLASSES
+ is used. The new store is returned in *STORE. */
+error_t
+store_part_open (const char *name, int flags,
+ const struct store_class *const *classes,
+ struct store **store)
+{
+ int part;
+ char *endp;
+ struct store *source;
+ error_t err;
+
+ part = strtol (name, &endp, 0);
+ if (endp == name || *endp != ':')
+ return EINVAL;
+
+ name = endp + 1;
+ if (*name == '\0')
+ return EINVAL;
+
+ err = store_typed_open (name, flags, classes, &source);
+ if (! err)
+ {
+ err = store_part_create (source, part, flags, store);
+ if (err)
+ store_free (source);
+ }
+
+ return err;
+}
+
+const struct store_class
+store_part_class = { -1, "part", open: store_part_open };
+STORE_STD_CLASS (part);
diff --git a/libstore/rdwr.c b/libstore/rdwr.c
index 9e9d3f84..9737c515 100644
--- a/libstore/rdwr.c
+++ b/libstore/rdwr.c
@@ -1,9 +1,7 @@
/* Store I/O
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
-
+ Copyright (C) 1995-1999,2001,2002,2003 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
This file is part of the GNU Hurd.
The GNU Hurd is free software; you can redistribute it and/or
@@ -18,9 +16,10 @@
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.,
- 675 Mass Ave, Cambridge, MA 02139, USA. */
+ 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
#include <string.h>
+#include <sys/mman.h>
#include "store.h"
@@ -28,13 +27,13 @@
ADDR, and is not a hole, and in RUNS_END a pointer pointing at the end of
the run list. Returns the offset within it at which ADDR occurs. Also
returns BASE, which should be added to offsets from RUNS. */
-static inline off_t
-store_find_first_run (struct store *store, off_t addr,
+static inline store_offset_t
+store_find_first_run (struct store *store, store_offset_t addr,
struct store_run **run, struct store_run **runs_end,
- off_t *base, size_t *index)
+ store_offset_t *base, size_t *index)
{
struct store_run *tail = store->runs, *tail_end = tail + store->num_runs;
- off_t wrap_src = store->wrap_src;
+ store_offset_t wrap_src = store->wrap_src;
if (addr >= wrap_src && addr < store->end)
/* Locate the correct position within a repeating pattern of runs. */
@@ -50,7 +49,7 @@ store_find_first_run (struct store *store, off_t addr,
binary search or something. */
while (tail < tail_end)
{
- off_t run_blocks = tail->length;
+ store_offset_t run_blocks = tail->length;
if (run_blocks > addr)
{
@@ -73,7 +72,7 @@ store_find_first_run (struct store *store, off_t addr,
things are still kosher. */
static inline int
store_next_run (struct store *store, struct store_run *runs_end,
- struct store_run **run, off_t *base, size_t *index)
+ struct store_run **run, store_offset_t *base, size_t *index)
{
(*run)++;
(*index)++;
@@ -94,11 +93,11 @@ store_next_run (struct store *store, struct store_run *runs_end,
in AMOUNT. ADDR is in BLOCKS (as defined by STORE->block_size). */
error_t
store_write (struct store *store,
- off_t addr, char *buf, size_t len, size_t *amount)
+ store_offset_t addr, const void *buf, size_t len, size_t *amount)
{
error_t err;
size_t index;
- off_t base;
+ store_offset_t base;
struct store_run *run, *runs_end;
int block_shift = store->log2_block_size;
store_write_meth_t write = store->class->write;
@@ -106,19 +105,27 @@ store_write (struct store *store,
if (store->flags & STORE_READONLY)
return EROFS; /* XXX */
+ if ((addr << block_shift) + len > store->size)
+ return EIO;
+
+ if (store->block_size != 0 && (len & (store->block_size - 1)) != 0)
+ return EINVAL;
+
addr = store_find_first_run (store, addr, &run, &runs_end, &base, &index);
if (addr < 0)
err = EIO;
- else if ((run->length << block_shift) >= len)
+ else if ((len >> block_shift) <= run->length - addr)
/* The first run has it all... */
err = (*write)(store, base + run->start + addr, index, buf, len, amount);
else
/* ARGH, we've got to split up the write ... */
{
- mach_msg_type_number_t try = run->length << block_shift, written;
+ mach_msg_type_number_t try, written;
/* Write the initial bit in the first run. Errors here are returned. */
- err = (*write)(store, base + run->start + addr, index, buf, try, &written);
+ try = (run->length - addr) << block_shift;
+ err = (*write) (store, base + run->start + addr, index, buf, try,
+ &written);
if (!err && written == try)
/* Wrote the first bit successfully, now do the rest. Any errors
@@ -132,22 +139,25 @@ store_write (struct store *store,
/* Ok, we can write in this run, at least a bit. */
{
mach_msg_type_number_t seg_written;
- off_t run_len = (run->length << block_shift);
- try = run_len > len ? len : run_len;
+ if ((len >> block_shift) <= run->length)
+ try = len;
+ else
+ try = run->length << block_shift;
+
err = (*write)(store, base + run->start, index, buf, try,
&seg_written);
if (err)
break; /* Ack */
-
written += seg_written;
+
+ if (seg_written < try)
+ break; /* Didn't use up the run, we're done. */
+
len -= seg_written;
if (len == 0)
break; /* Nothing left to write! */
- if (seg_written < run_len)
- break; /* Didn't use up the run, we're done. */
-
buf += seg_written;
}
}
@@ -158,54 +168,64 @@ store_write (struct store *store,
return err;
}
-/* Read AMOUNT bytes from STORE at ADDR into BUF & LEN (which following the
+/* Read AMOUNT bytes from STORE at ADDR into BUF & LEN (which follows the
usual mach buffer-return semantics) to STORE at ADDR. ADDR is in BLOCKS
(as defined by STORE->block_size). */
error_t
store_read (struct store *store,
- off_t addr, size_t amount, char **buf, size_t *len)
+ store_offset_t addr, size_t amount, void **buf, size_t *len)
{
- error_t err;
size_t index;
- off_t base;
+ store_offset_t base;
struct store_run *run, *runs_end;
int block_shift = store->log2_block_size;
store_read_meth_t read = store->class->read;
addr = store_find_first_run (store, addr, &run, &runs_end, &base, &index);
- if (addr < 0)
- err = EIO;
- else if ((run->length << block_shift) >= amount)
+ if (addr < 0 || run->start < 0)
+ return EIO; /* Reading from a hole. */
+
+ if ((addr << block_shift) + amount > store->size)
+ amount = store->size - (addr << block_shift);
+
+ if (store->block_size != 0 && (amount & (store->block_size - 1)) != 0)
+ return EINVAL;
+
+ if ((amount >> block_shift) <= run->length - addr)
/* The first run has it all... */
- err = (*read)(store, base + run->start + addr, index, amount, buf, len);
+ return (*read) (store, base + run->start + addr, index, amount, buf, len);
else
/* ARGH, we've got to split up the read ... This isn't fun. */
{
+ error_t err;
int all;
/* WHOLE_BUF and WHOLE_BUF_LEN will point to a buff that's large enough
to hold the entire request. This is initially whatever the user
passed in, but we'll change it as necessary. */
- char *whole_buf = *buf, *buf_end;
+ void *whole_buf = *buf, *buf_end;
size_t whole_buf_len = *len;
/* Read LEN bytes from the store address ADDR into BUF_END. BUF_END
and AMOUNT are adjusted by the amount actually read. Whether or not
the amount read is the same as what was request is returned in ALL. */
- inline error_t seg_read (off_t addr, off_t len, int *all)
+ inline error_t seg_read (store_offset_t addr, size_t len, int *all)
{
/* SEG_BUF and SEG_LEN are the buffer for a particular bit of the
whole (within one run). */
- char *seg_buf = buf_end;
+ void *seg_buf = buf_end;
size_t seg_buf_len = len;
error_t err =
(*read)(store, addr, index, len, &seg_buf, &seg_buf_len);
if (!err)
{
/* If for some bizarre reason, the underlying storage chose not
- to use the buffer space we so kindly gave it, bcopy it to
+ to use the buffer space we so kindly gave it, copy it to
that space. */
if (seg_buf != buf_end)
- bcopy (seg_buf, buf_end, seg_buf_len);
+ {
+ memcpy (buf_end, seg_buf, seg_buf_len);
+ munmap (seg_buf, seg_buf_len);
+ }
buf_end += seg_buf_len;
amount -= seg_buf_len;
*all = (seg_buf_len == len);
@@ -218,30 +238,27 @@ store_read (struct store *store,
make room. */
{
whole_buf_len = amount;
- err = vm_allocate (mach_task_self (),
- (vm_address_t *)&whole_buf, amount, 1);
- if (err)
- return err; /* Punt early, there's nothing to clean up. */
+ whole_buf = mmap (0, amount, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ if (whole_buf == (void *) -1)
+ return errno; /* Punt early, there's nothing to clean up. */
}
buf_end = whole_buf;
- err = seg_read (base + run->start + addr, run->length << block_shift, &all);
+ err = seg_read (base + run->start + addr,
+ (run->length - addr) << block_shift, &all);
while (!err && all && amount > 0
&& store_next_run (store, runs_end, &run, &base, &index))
{
- off_t run_addr = run->start;
- off_t run_blocks = run->length;
-
- if (run_addr < 0)
+ if (run->start < 0)
/* A hole! Can't read here. Must stop. */
break;
else
- {
- off_t run_len = (run_blocks << block_shift);
- off_t seg_len = run_len > amount ? amount : run_len;
- err = seg_read (base + run_addr, seg_len, &all);
- }
+ err = seg_read (base + run->start,
+ (amount >> block_shift) <= run->length
+ ? amount /* This run has the rest. */
+ : (run->length << block_shift), /* Whole run. */
+ &all);
}
/* The actual amount read. */
@@ -251,20 +268,31 @@ store_read (struct store *store,
/* Deallocate any amount of WHOLE_BUF we didn't use. */
if (whole_buf != *buf)
- if (err)
- vm_deallocate (mach_task_self (),
- (vm_address_t)whole_buf, whole_buf_len);
- else
- {
- vm_size_t unused = whole_buf_len - round_page (*len);
- if (unused)
- vm_deallocate (mach_task_self (),
- (vm_address_t)whole_buf + whole_buf_len - unused,
- unused);
- *buf = whole_buf;
- }
+ {
+ if (err)
+ munmap (whole_buf, whole_buf_len);
+ else
+ {
+ vm_size_t unused = whole_buf_len - round_page (*len);
+ if (unused)
+ munmap (whole_buf + whole_buf_len - unused, unused);
+ *buf = whole_buf;
+ }
+ }
+
+ return err;
}
+}
+
+/* Set STORE's size to NEWSIZE (in bytes). */
+error_t
+store_set_size (struct store *store, size_t newsize)
+{
+ error_t err;
+ store_set_size_meth_t set_size = store->class->set_size;
+
+ /* Updating the runs list is up to the class set_size method. */
+ err = (* set_size) (store, newsize);
return err;
}
-
diff --git a/libstore/remap.c b/libstore/remap.c
new file mode 100644
index 00000000..55ab51ac
--- /dev/null
+++ b/libstore/remap.c
@@ -0,0 +1,345 @@
+/* Block address translation
+
+ Copyright (C) 1996,97,99,2001, 2002 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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.
+
+ The GNU Hurd 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, USA. */
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <hurd/fs.h>
+
+#include "store.h"
+
+static error_t
+remap_read (struct store *store,
+ store_offset_t addr, size_t index, size_t amount,
+ void **buf, size_t *len)
+{
+ return store_read (store->children[0], addr, amount, buf, len);
+}
+
+static error_t
+remap_write (struct store *store,
+ store_offset_t addr, size_t index, const void *buf, size_t len,
+ size_t *amount)
+{
+ return store_write (store->children[0], addr, buf, len, amount);
+}
+
+static error_t
+remap_set_size (struct store *store, size_t newsize)
+{
+ return store_set_size (store->children[0], newsize);
+}
+
+error_t
+remap_allocate_encoding (const struct store *store, struct store_enc *enc)
+{
+ enc->num_ints += 3;
+ enc->num_offsets += store->num_runs * 2;
+ return store_allocate_child_encodings (store, enc);
+}
+
+error_t
+remap_encode (const struct store *store, struct store_enc *enc)
+{
+ int i;
+ enc->ints[enc->cur_int++] = store->class->id;
+ enc->ints[enc->cur_int++] = store->flags;
+ enc->ints[enc->cur_int++] = store->num_runs;
+ for (i = 0; i < store->num_runs; i++)
+ {
+ enc->offsets[enc->cur_offset++] = store->runs[i].start;
+ enc->offsets[enc->cur_offset++] = store->runs[i].length;
+ }
+ return store_encode_children (store, enc);
+}
+
+error_t
+remap_decode (struct store_enc *enc, const struct store_class *const *classes,
+ struct store **store)
+{
+ if (enc->cur_int + 3 > enc->num_ints)
+ return EINVAL;
+ else
+ {
+ int type __attribute__((unused)) = enc->ints[enc->cur_int++];
+ int flags = enc->ints[enc->cur_int++];
+ int num_runs = enc->ints[enc->cur_int++];
+ error_t create_remap (const struct store_run *runs, size_t num_runs)
+ {
+ struct store *source;
+ error_t err = store_decode_children (enc, 1, classes, &source);
+ if (! err)
+ err = store_remap_create (source, runs, num_runs, flags, store);
+ return err;
+ }
+ return store_with_decoded_runs (enc, num_runs, create_remap);
+ }
+}
+
+error_t
+remap_open (const char *name, int flags,
+ const struct store_class *const *classes,
+ struct store **store)
+{
+ error_t err;
+ struct store *from;
+ const char *end, *p;
+ struct store_run *runs;
+ size_t nruns;
+
+ end = strchr (name, ':');
+ if (!end)
+ return EINVAL;
+
+ runs = alloca ((end - name) * sizeof runs[0]);
+
+ nruns = 0;
+ p = name;
+ do
+ {
+ char *endp;
+ runs[nruns].start = strtoul (p, &endp, 0);
+ if (*endp == '+')
+ {
+ if (endp == p) /* Syntax "+5,+7" means "0+5,0+7". */
+ runs[nruns].start = 0;
+ p = endp + 1;
+ if (p == end || *p == ',')
+ {
+ /* Syntax "100+" means block 100 to the end of the store.
+ Since we don't know the size yet, we use -1 as a marker
+ for the code below. */
+ runs[nruns++].length = (store_offset_t) -1;
+ break;
+ }
+ runs[nruns].length = strtoul (p, &endp, 0);
+ if (endp == p)
+ return EINVAL;
+ }
+ else if (endp == p) /* Must have a number unless starts with +. */
+ return EINVAL;
+ else
+ runs[nruns].length = 1;
+ ++nruns;
+ p = endp;
+ if (*p == ',')
+ ++p;
+ } while (p < end);
+
+ err = store_typed_open (end + 1, flags, classes, &from);
+ if (!err)
+ {
+ /* Check for any runs marked as "through the end of the store"
+ and update them to use the actual size of the store. */
+ size_t i;
+ for (i = 0; i < nruns; ++i)
+ if (runs[i].length == (store_offset_t) -1)
+ runs[i].length = from->blocks - runs[i].start;
+
+ /* Now do the remapping according to RUNS. */
+ err = store_remap (from, runs, nruns, store);
+ if (err)
+ store_free (from);
+ }
+ return err;
+}
+
+error_t
+remap_validate_name (const char *name,
+ const struct store_class *const *classes)
+{
+ const char *end = strchr (name, ':');
+ const char *p;
+
+ if (!end)
+ return EINVAL;
+
+ p = name;
+ do
+ {
+ if (*p != '+')
+ {
+ if (!isdigit (*p))
+ return EINVAL;
+ do
+ ++p;
+ while (isdigit (*p));
+ }
+
+ if (*p == '+')
+ {
+ ++p;
+ if (!isdigit (*p))
+ return EINVAL;
+ do
+ ++p;
+ while (isdigit (*p));
+ }
+
+ if (*p == ',')
+ ++p;
+ else if (*p == ':')
+ return 0;
+ } while (*p != '\0');
+
+ return EINVAL;
+}
+
+
+const struct store_class
+store_remap_class =
+{
+ STORAGE_REMAP, "remap", remap_read, remap_write, remap_set_size,
+ remap_allocate_encoding, remap_encode, remap_decode,
+ store_set_child_flags, store_clear_child_flags,
+ NULL, NULL, NULL, /* cleanup, clone, remap */
+ remap_open, remap_validate_name
+};
+STORE_STD_CLASS (remap);
+
+/* Return a new store in STORE that reflects the blocks in RUNS & RUNS_LEN
+ from SOURCE; SOURCE is consumed, but RUNS is not. Unlike the
+ store_remap function, this function always operates by creating a new
+ store of type `remap' which has SOURCE as a child, and so may be less
+ efficient than store_remap for some types of stores. */
+error_t
+store_remap_create (struct store *source,
+ const struct store_run *runs, size_t num_runs,
+ int flags, struct store **store)
+{
+ error_t err =
+ _store_create (&store_remap_class, MACH_PORT_NULL, flags | source->flags,
+ source->block_size, runs, num_runs, 0, store);
+
+ if (! err)
+ {
+ err = store_set_children (*store, &source, 1);
+ if (err)
+ store_free (*store);
+ }
+
+ return err;
+}
+
+/* For each run in RUNS, of length NUM_RUNS, translate the */
+error_t
+store_remap_runs (const struct store_run *runs, size_t num_runs,
+ const struct store_run *base_runs, size_t num_base_runs,
+ struct store_run **xruns, size_t *num_xruns)
+{
+ int i, j;
+ size_t xruns_alloced = num_runs + num_base_runs;
+
+ /* Add the single run [ADDR, LEN) to *XRUNS, returning true if successful. */
+ int add_run (store_offset_t addr, store_offset_t len)
+ {
+ if (*num_xruns == xruns_alloced)
+ /* Make some more space in *XRUNS. */
+ {
+ struct store_run *new;
+ xruns_alloced *= 2;
+ new = realloc (*xruns, xruns_alloced * sizeof (struct store_run));
+ if (! new)
+ return 0;
+ *xruns = new;
+ }
+ (*xruns)[(*num_xruns)++] = (struct store_run){ addr, len };
+ return 1;
+ }
+
+ *xruns = malloc (xruns_alloced * sizeof (struct store_run));
+ if (! *xruns)
+ return ENOMEM;
+
+ /* Clean up and return error code CODE. */
+#define ERR(code) do { free (*xruns); return (code); } while (0)
+
+ for (i = 0; i < num_runs; i++)
+ {
+ store_offset_t addr = runs[i].start, left = runs[i].length;
+
+ if (addr >= 0)
+ for (j = 0; j < num_base_runs && left > 0; j++)
+ {
+ store_offset_t baddr = base_runs[j].start;
+ store_offset_t blen = base_runs[j].length;
+
+ if (addr >= blen)
+ addr -= blen;
+ else if (baddr < 0)
+ /* A hole, which is invalid. */
+ ERR (EINVAL);
+ else
+ /* Add another output run. */
+ {
+ store_offset_t len = blen - addr; /* Size of next output run. */
+ if (! add_run (baddr + addr, len > left ? left : len))
+ ERR (ENOMEM);
+ addr = 0;
+ left -= len;
+ }
+ }
+ else
+ /* a hole */
+ if (! add_run (-1, left))
+ ERR (ENOMEM);
+ }
+
+ if (xruns_alloced > *num_xruns)
+ *xruns = realloc (*xruns, *num_xruns * sizeof (struct store_run));
+
+ return 0;
+}
+
+/* Return a store in STORE that reflects the blocks in RUNS & RUNS_LEN from
+ SOURCE; SOURCE is consumed, but not RUNS. Unlike the store_remap_create
+ function, this may simply modify SOURCE and return it. */
+error_t
+store_remap (struct store *source,
+ const struct store_run *runs, size_t num_runs,
+ struct store **store)
+{
+ if (source->class->remap)
+ /* Use the class-specific remaping function. */
+ return (* source->class->remap) (source, runs, num_runs, store);
+ else
+ /* Just replace SOURCE's runs-list by an appropiately translated RUNS. */
+ {
+ struct store_run *xruns = 0;
+ size_t num_xruns = 0;
+ error_t err =
+ store_remap_runs (runs, num_runs, source->runs, source->num_runs,
+ &xruns, &num_xruns);
+ if (! err)
+ {
+ /* Don't use store_set_runs -- we've already allocated the
+ storage. */
+ free (source->runs);
+ source->runs = xruns;
+ source->num_runs = num_xruns;
+ source->flags &= ~STORE_ENFORCED;
+ source->end = 0; /* Needed to make _store_derive work. */
+ store_close_source (source);
+ _store_derive (source);
+ *store = source;
+ }
+ return err;
+ }
+}
diff --git a/libstore/set.c b/libstore/set.c
index 479184d4..b9ff4f41 100644
--- a/libstore/set.c
+++ b/libstore/set.c
@@ -1,9 +1,7 @@
/* Setting various store fields
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
-
+ Copyright (C) 1995,96,97,2001,02 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
This file is part of the GNU Hurd.
The GNU Hurd is free software; you can redistribute it and/or
@@ -18,16 +16,19 @@
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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
-#include <malloc.h>
+#include <stdlib.h>
#include <string.h>
+#include <errno.h>
+#include <mach.h>
#include "store.h"
/* Set STORE's current runs list to (a copy of) RUNS and NUM_RUNS. */
error_t
-store_set_runs (struct store *store, const struct store_run *runs, unsigned num_runs)
+store_set_runs (struct store *store,
+ const struct store_run *runs, size_t num_runs)
{
unsigned size = num_runs * sizeof (struct store_run);
struct store_run *copy = malloc (size);
@@ -38,7 +39,7 @@ store_set_runs (struct store *store, const struct store_run *runs, unsigned num_
if (store->runs)
free (store->runs);
- bcopy (runs, copy, size);
+ memcpy (copy, runs, size);
store->runs = copy;
store->num_runs = num_runs;
@@ -52,7 +53,7 @@ store_set_runs (struct store *store, const struct store_run *runs, unsigned num_
error_t
store_set_name (struct store *store, const char *name)
{
- char *copy = malloc (strlen (name) + 1);
+ char *copy = strdup (name);
if (!copy)
return ENOMEM;
@@ -60,7 +61,6 @@ store_set_name (struct store *store, const char *name)
if (store->name)
free (store->name);
- strcpy (copy, name);
store->name = copy;
return 0;
@@ -70,7 +70,7 @@ store_set_name (struct store *store, const char *name)
source from which it was created. */
void store_close_source (struct store *store)
{
- if (store->source)
+ if (store->source != MACH_PORT_NULL)
{
mach_port_deallocate (mach_task_self (), store->source);
store->source = MACH_PORT_NULL;
diff --git a/libstore/std.c b/libstore/std.c
index 37edc73b..4784a8a5 100644
--- a/libstore/std.c
+++ b/libstore/std.c
@@ -1,9 +1,7 @@
/* List of standard store classes
- Copyright (C) 1996 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
-
+ Copyright (C) 1996,97,2001 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
This file is part of the GNU Hurd.
The GNU Hurd is free software; you can redistribute it and/or
@@ -18,16 +16,29 @@
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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
#include "store.h"
-struct store_class *
-store_std_classes = 0;
-
-void
-_store_add_std_class (struct store_class *class)
+const struct store_class *const __attribute__ ((section ("store_std_classes")))
+store_std_classes[] =
{
- class->next = store_std_classes;
- store_std_classes = class;
-}
+ &store_device_class,
+#if HAVE_PARTED_PARTED_H
+ &store_part_class,
+#endif
+ &store_file_class,
+ &store_zero_class,
+ &store_task_class,
+ &store_ileave_class, &store_concat_class, &store_remap_class,
+ &store_query_class,
+ &store_copy_class, &store_gunzip_class, &store_bunzip2_class,
+
+ /* This pseudo-class must appear before any real STORAGE_NETWORK class,
+ to parse STORAGE_NETWORK file_get_storage_info results properly. */
+ &store_url_open_class,
+ &store_nbd_class,
+
+ &store_typed_open_class,
+ 0
+};
diff --git a/libstore/store.h b/libstore/store.h
index 84e8aae3..ae334a1d 100644
--- a/libstore/store.h
+++ b/libstore/store.h
@@ -1,9 +1,7 @@
/* Store I/O
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
-
+ Copyright (C) 1995,96,97,98,99,2001,02,04,05 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
This file is part of the GNU Hurd.
The GNU Hurd is free software; you can redistribute it and/or
@@ -18,21 +16,38 @@
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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+/* A `store' is a fixed-size block of storage, which can be read and perhaps
+ written to. This library implements many different backends which allow
+ the abstract store interface to be used with common types of storage --
+ devices, files, memory, tasks, etc. It also allows stores to be combined
+ and filtered in various ways. */
#ifndef __STORE_H__
#define __STORE_H__
#include <sys/types.h>
+#include <fcntl.h>
#include <mach.h>
#include <device/device.h>
#include <hurd/hurd_types.h>
+#include <features.h>
+
+#ifdef STORE_DEFINE_EI
+#define STORE_EI
+#else
+#define STORE_EI __extern_inline
+#endif
+/* Type for addresses inside the store. */
+typedef off64_t store_offset_t;
+
/* A portion of a store. If START == -1, it's a hole. */
struct store_run
{
- off_t start, length;
+ store_offset_t start, length;
};
struct store
@@ -47,13 +62,13 @@ struct store
size_t num_runs; /* Length of RUNS. */
/* Maximum valid offset. This is the same as SIZE, but in blocks. */
- off_t end;
+ store_offset_t end;
/* WRAP_SRC is the sum of the run lengths in RUNS. If this is less than
END, then RUNS describes a repeating pattern, of length WRAP_SRC -- each
successive iteration having an additional offset of WRAP_DST. */
- off_t wrap_src;
- off_t wrap_dst; /* Only meaningful if WRAP_SRC < END */
+ store_offset_t wrap_src;
+ store_offset_t wrap_dst; /* Only meaningful if WRAP_SRC < END */
/* Handles for the underlying storage. */
char *name; /* Malloced */
@@ -63,14 +78,14 @@ struct store
size_t block_size;
/* The number of blocks (of size BLOCK_SIZE) in this storage. */
- size_t blocks;
+ store_offset_t blocks;
/* The number of bytes in this storage, including holes. */
- size_t size;
+ store_offset_t size;
/* Log_2 (BLOCK_SIZE) or 0 if not a power of 2. */
- int log2_block_size;
+ unsigned log2_block_size;
/* Log_2 (VM_PAGE_SIZE / BLOCK_SIZE); only valid if LOG2_BLOCK_SIZE is. */
- int log2_blocks_per_page;
+ unsigned log2_blocks_per_page;
/* Random flags. */
int flags;
@@ -78,7 +93,7 @@ struct store
void *misc; /* malloced */
size_t misc_len;
- struct store_class *class;
+ const struct store_class *class;
/* A list of sub-stores. The interpretation of this is type-specific. */
struct store **children;
@@ -91,27 +106,36 @@ struct store
<hurd/hurd_types.h>. XXX synchronize these values. */
/* Flags that reflect something immutable about the object. */
-#define STORE_IMMUTABLE_FLAGS 0xFF
+#define STORE_IMMUTABLE_FLAGS 0x00FF
/* Flags implemented by generic store code. */
-#define STORE_READONLY 0x100 /* No writing allowed. */
-#define STORE_GENERIC_FLAGS STORE_READONLY
+#define STORE_READONLY 0x0100 /* No writing allowed. */
+#define STORE_NO_FILEIO 0x0200 /* If store_create can't fetch store
+ information, don't create a store
+ using file io instead. */
+#define STORE_GENERIC_FLAGS (STORE_READONLY | STORE_NO_FILEIO)
/* Flags implemented by each backend. */
-#define STORE_HARD_READONLY 0x200 /* Can't be made writable. */
-#define STORE_ENFORCED 0x400 /* Range is enforced by device. */
-#define STORE_BACKEND_SPEC_BASE 0x1000 /* Here up are backend-specific */
+#define STORE_HARD_READONLY 0x1000 /* Can't be made writable. */
+#define STORE_ENFORCED 0x2000 /* Range is enforced by device. */
+#define STORE_INACTIVE 0x4000 /* Not in a usable state. */
+#define STORE_INNOCUOUS 0x8000 /* Cannot modify anything dangerous. */
+#define STORE_BACKEND_SPEC_BASE 0x10000 /* Here up are backend-specific */
#define STORE_BACKEND_FLAGS (STORE_HARD_READONLY | STORE_ENFORCED \
+ | STORE_INACTIVE \
| ~(STORE_BACKEND_SPEC_BASE - 1))
typedef error_t (*store_write_meth_t)(struct store *store,
- off_t addr, size_t index,
- char *buf, mach_msg_type_number_t len,
+ store_offset_t addr, size_t index,
+ const void *buf,
+ mach_msg_type_number_t len,
mach_msg_type_number_t *amount);
typedef error_t (*store_read_meth_t)(struct store *store,
- off_t addr, size_t index,
+ store_offset_t addr, size_t index,
mach_msg_type_number_t amount,
- char **buf, mach_msg_type_number_t *len);
+ void **buf, mach_msg_type_number_t *len);
+typedef error_t (*store_set_size_meth_t)(struct store *store,
+ size_t newsize);
struct store_enc; /* fwd decl */
@@ -121,14 +145,16 @@ struct store_class
enum file_storage_class id;
/* Name of the class. */
- char *name;
+ const char *name;
/* Read up to AMOUNT bytes at the underlying address ADDR from the storage
- into BUF and LEN. INDEX varies from 0 to the number of runs in STORE. */
+ into BUF and LEN. INDEX varies from 0 to the number of runs in STORE. */
store_read_meth_t read;
/* Write up to LEN bytes from BUF to the storage at the underlying address
- ADDR. INDEX varies from 0 to the number of runs in STORE. */
+ ADDR. INDEX varies from 0 to the number of runs in STORE. */
store_write_meth_t write;
+ /* Set store's size to NEWSIZE (in bytes). */
+ store_set_size_meth_t set_size;
/* To the lengths of each for the four arrays in ENC, add how much STORE
would need to be encoded. */
@@ -139,7 +165,8 @@ struct store_class
/* Decode from ENC a new store, which return in STORE. CLASSES is used to
lookup child classes. */
- error_t (*decode) (struct store_enc *enc, struct store_class *classes,
+ error_t (*decode) (struct store_enc *enc,
+ const struct store_class *const *classes,
struct store **store);
/* Modify flags that reflect backend state, such as STORE_HARD_READONLY and
@@ -155,26 +182,63 @@ struct store_class
made after all format-indendependent fields have been cloned. */
error_t (*clone) (const struct store *from, struct store *to);
- /* For making a list of classes to pass to e.g. store_create. */
- struct store_class *next;
+ /* Return in STORE a store that only contains the parts of SOURCE as
+ enumerated in RUNS & RUNS_LEN, consuming SOURCE in the process. The
+ default behavior, if REMAP is 0, is to replace SOURCE's run list with
+ the subset selected by RUNS, and return SOURCE. */
+ error_t (*remap) (struct store *source,
+ const struct store_run *runs, size_t num_runs,
+ struct store **store);
+
+ /* Open a new store called NAME in this class. CLASSES is supplied in case
+ it's desirable to open a sub-store in some manner. */
+ error_t (*open) (const char *name, int flags,
+ const struct store_class *const *classes,
+ struct store **store);
+
+ /* Given a user argument ARG, this function should check it for syntactic
+ validity, or print a syntax error, using ARGP_STATE in the normal
+ manner; if zero is returned, then this argument is assumed valid, and
+ can be passed to the open function. If ARG is 0, then there were *no*
+ arguments specified; in this case, returning EINVAL means that this is
+ not kosher. If PARSE is 0, then it is assumed that if this class has an
+ OPEN function, then validity can't be syntactically determined. */
+ error_t (*validate_name) (const char *name,
+ const struct store_class *const *classes);
+
+ /* Return a memory object paging on STORE. */
+ error_t (*map) (const struct store *store, vm_prot_t prot, mach_port_t *memobj);
};
/* Return a new store in STORE, which refers to the storage underlying
- SOURCE. CLASSES is used to select classes specified by the provider; if
- it is 0, STORE_STD_CLASSES is used. FLAGS is set with store_set_flags. A
- reference to SOURCE is created (but may be destroyed with
- store_close_source). */
-error_t store_create (file_t source, int flags, struct store_class *classes,
+ SOURCE. CLASSES is as if passed to store_find_class, which see. FLAGS
+ is set with store_set_flags, with the exception of STORE_INACTIVE, which
+ merely indicates that no attempt should be made to activate an inactive
+ store; if STORE_INACTIVE is not specified, and the store returned for
+ SOURCE is inactive, an attempt is made to activate it (failure of which
+ causes an error to be returned). A reference to SOURCE is created (but
+ may be destroyed with store_close_source). */
+error_t store_create (file_t source, int flags,
+ const struct store_class *const *classes,
struct store **store);
void store_free (struct store *store);
-/* Allocate a new store structure with class CLASS, and the various other
- fields initialized to the given parameters. */
-struct store *
-_make_store (struct store_class *class, mach_port_t port, int flags,
- size_t block_size, const struct store_run *runs, size_t num_runs,
- off_t end);
+/* Open the file NAME, and return a new store in STORE, which refers to the
+ storage underlying it. CLASSES is as if passed to store_find_class,
+ which see. FLAGS is set with store_set_flags. A reference to the open
+ file is created (but may be destroyed with store_close_source). */
+error_t store_open (const char *name, int flags,
+ const struct store_class *const *classes,
+ struct store **store);
+
+/* Allocate a new store structure, returned in STORE, with class CLASS and
+ the various other fields initialized to the given parameters. */
+error_t
+_store_create (const struct store_class *class, mach_port_t port,
+ int flags, size_t block_size,
+ const struct store_run *runs, size_t num_runs,
+ store_offset_t end, struct store **store);
/* Set STORE's current runs list to (a copy of) RUNS and NUM_RUNS. */
error_t store_set_runs (struct store *store,
@@ -185,6 +249,12 @@ error_t store_set_runs (struct store *store,
error_t store_set_children (struct store *store,
struct store *const *children, size_t num_children);
+/* Try to come up with a name for the children in STORE, combining the names
+ of each child in a way that could be used to parse them with
+ store_open_children. This is done heuristically, and so may not succeed.
+ If a child doesn't have a name, EINVAL is returned. */
+error_t store_children_name (const struct store *store, char **name);
+
/* Sets the name associated with STORE to a copy of NAME. */
error_t store_set_name (struct store *store, const char *name);
@@ -194,52 +264,85 @@ error_t store_set_flags (struct store *store, int flags);
/* Remove FLAGS from STORE's currently set flags. */
error_t store_clear_flags (struct store *store, int flags);
+/* Set FLAGS in all children of STORE, and if successful, add FLAGS to
+ STORE's flags. */
+error_t store_set_child_flags (struct store *store, int flags);
+
+/* Clear FLAGS in all children of STORE, and if successful, remove FLAGS from
+ STORE's flags. */
+error_t store_clear_child_flags (struct store *store, int flags);
+
+extern int store_is_securely_returnable (struct store *store, int open_flags);
+
+#if defined(__USE_EXTERN_INLINES) || defined(STORE_DEFINE_EI)
+
+/* Returns true if STORE can safely be returned to a user who has accessed it
+ via a node using OPEN_FLAGS, without compromising security. */
+STORE_EI int
+store_is_securely_returnable (struct store *store, int open_flags)
+{
+ int flags = store->flags;
+ return
+ (flags & (STORE_INNOCUOUS | STORE_INACTIVE))
+ || ((flags & STORE_ENFORCED)
+ && (((open_flags & O_ACCMODE) == O_RDWR)
+ || (flags & STORE_HARD_READONLY)));
+}
+
+#endif /* Use extern inlines. */
+
/* Fills in the values of the various fields in STORE that are derivable from
the set of runs & the block size. */
void _store_derive (struct store *store);
/* Return in TO a copy of FROM. */
error_t store_clone (struct store *from, struct store **to);
+
+/* Return a store in STORE that reflects the blocks in RUNS & RUNS_LEN from
+ source; SOURCE is consumed, but not RUNS. Unlike the store_remap_create
+ function, this may simply modify SOURCE and return it. */
+error_t store_remap (struct store *source,
+ const struct store_run *runs, size_t num_runs,
+ struct store **store);
/* Write LEN bytes from BUF to STORE at ADDR. Returns the amount written in
AMOUNT (in bytes). ADDR is in BLOCKS (as defined by STORE->block_size). */
error_t store_write (struct store *store,
- off_t addr, char *buf, size_t len, size_t *amount);
+ store_offset_t addr, const void *buf, size_t len,
+ size_t *amount);
/* Read AMOUNT bytes from STORE at ADDR into BUF & LEN (which following the
usual mach buffer-return semantics) to STORE at ADDR. ADDR is in BLOCKS
(as defined by STORE->block_size). Note that LEN is in bytes. */
error_t store_read (struct store *store,
- off_t addr, size_t amount, char **buf, size_t *len);
+ store_offset_t addr, size_t amount, void **buf, size_t *len);
+
+/* Set STORE's size to NEWSIZE (in bytes). */
+error_t store_set_size (struct store *store, size_t newsize);
/* If STORE was created using store_create, remove the reference to the
source from which it was created. */
void store_close_source (struct store *store);
-#if 0
-
-/* Return a memory object paging on STORE. [among other reasons,] this may
- fail because store contains non-contiguous regions on the underlying
- object. In such a case you can try calling some of the routines below to
- get a pager. */
-error_t store_map (struct store *store, vm_prot_t prot, ...,
- mach_port_t *pager);
+/* Return a memory object paging on STORE. If this call fails with
+ EOPNOTSUPP, you can try calling some of the routines below to get a pager. */
+error_t store_map (const struct store *store, vm_prot_t prot,
+ mach_port_t *memobj);
-/* Returns a memory object paging on the file from which STORE was created.
- If STORE wasn't created using store_create, or the source was destroyed
- using store_close_source, this will fail. */
-error_t store_map_source (struct store *store, vm_prot_t prot, ...,
- mach_port_t *pager)
+#if 0
/* Create a new pager and paging threads paging on STORE, and return the
resulting memory object in PAGER. */
error_t store_create_pager (struct store *store, vm_prot_t prot, ...,
- mach_port_t *pager)
+ mach_port_t *memobj)
#endif
/* Creating specific types of stores. */
+/* Return a new zero store SIZE bytes long in STORE. */
+error_t store_zero_create (store_offset_t size, int flags, struct store **store);
+
/* Return a new store in STORE referring to the mach device DEVICE. Consumes
the send right DEVICE. */
error_t store_device_create (device_t device, int flags, struct store **store);
@@ -252,6 +355,21 @@ error_t _store_device_create (device_t device, int flags, size_t block_size,
/* Open the device NAME, and return the corresponding store in STORE. */
error_t store_device_open (const char *name, int flags, struct store **store);
+/* Return a new store in STORE which contains a remap store of partition
+ PART from the contents of SOURCE; SOURCE is consumed. */
+error_t store_part_create (struct store *source, int index, int flags,
+ struct store **store);
+
+/* Open the part NAME. NAME consists of a partition number, a ':', a
+ another store class name, a ':' and a name for to by passed to the
+ store class. E.g. "2:device:hd0" would open the second partition
+ on a DEVICE store named "hd0". FLAGS indicate how to open the
+ store. CLASSES is as if passed to store_find_class, which see.
+ The new store is returned in *STORE. */
+error_t store_part_open (const char *name, int flags,
+ const struct store_class *const *classes,
+ struct store **store);
+
/* Return a new store in STORE referring to the file FILE. Unlike
store_create, this will always use file i/o, even it would be possible to
be more direct. This may work in more cases, for instance if the file has
@@ -266,13 +384,53 @@ error_t _store_file_create (file_t file, int flags, size_t block_size,
/* Open the file NAME, and return the corresponding store in STORE. */
error_t store_file_open (const char *name, int flags, struct store **store);
+/* Return a new store in STORE referring to the task TASK, consuming TASK. */
+error_t store_task_create (task_t task, int flags, struct store **store);
+
+/* Like store_task_create, but doesn't query the task for information. */
+error_t _store_task_create (task_t task, int flags, size_t block_size,
+ const struct store_run *runs, size_t num_runs,
+ struct store **store);
+
+/* Open the task NAME (NAME should be the task's pid), and return the
+ corresponding store in STORE. */
+error_t store_task_open (const char *name, int flags, struct store **store);
+
+/* Return a new store in STORE referring to the memory object MEMOBJ.
+ Consumes the send right MEMOBJ. */
+error_t store_memobj_create (memory_object_t memobj, int flags,
+ size_t block_size,
+ const struct store_run *runs, size_t num_runs,
+ struct store **store);
+
+/* Open the network block device NAME (parsed as "HOSTNAME:PORT[/BLOCKSIZE]"),
+ and return the corresponding store in STORE. This opens a socket and
+ initial connection handshake, which determine the size of the device,
+ and then uses _store_nbd_create with the open socket port. */
+error_t store_nbd_open (const char *name, int flags, struct store **store);
+
+/* Create a store that works by talking to an nbd server on an existing
+ socket port. */
+error_t _store_nbd_create (mach_port_t port, int flags, size_t block_size,
+ const struct store_run *runs, size_t num_runs,
+ struct store **store);
+
+/* Return a new store of type "unknown" that holds a copy of the
+ given encoding. The name of the store is taken from ENC->data.
+ Future calls to store_encode/store_return will produce exactly
+ the encoding supplied here. All i/o operations fail with EFTYPE. */
+error_t store_unknown_decode (struct store_enc *enc,
+ const struct store_class *const *classes,
+ struct store **store);
+
/* Return a new store in STORE that interleaves all the stores in STRIPES
(NUM_STRIPES of them) every INTERLEAVE bytes; INTERLEAVE must be an
integer multiple of each stripe's block size. The stores in STRIPES are
consumed -- that is, will be freed when this store is (however, the
*array* STRIPES is copied, and so should be freed by the caller). */
error_t store_ileave_create (struct store * const *stripes, size_t num_stripes,
- off_t interleave, int flags, struct store **store);
+ store_offset_t interleave, int flags,
+ struct store **store);
/* Return a new store in STORE that concatenates all the stores in STORES
(NUM_STORES of them). The stores in STRIPES are consumed -- that is, will
@@ -281,24 +439,208 @@ error_t store_ileave_create (struct store * const *stripes, size_t num_stripes,
error_t store_concat_create (struct store * const *stores, size_t num_stores,
int flags, struct store **store);
-/* Return a new null store SIZE bytes long in STORE. */
-error_t store_null_create (size_t size, int flags, struct store **store);
+/* Return a new store that concatenates the stores created by opening all the
+ individual stores described in NAME; for the syntax of NAME, see
+ store_open_children. */
+error_t store_concat_open (const char *name, int flags,
+ const struct store_class *const *classes,
+ struct store **store);
+
+/* Return a new store in STORE that reflects the blocks in RUNS & RUNS_LEN
+ from SOURCE; SOURCE is consumed, but RUNS is not. Unlike the store_remap
+ function, this function always operates by creating a new store of type
+ `remap' which has SOURCE as a child, and so may be less efficient than
+ store_remap for some types of stores. */
+error_t store_remap_create (struct store *source,
+ const struct store_run *runs, size_t num_runs,
+ int flags, struct store **store);
+
+/* Return a new store in STORE which contains a snapshot of the contents of
+ the store FROM; FROM is consumed. */
+error_t store_copy_create (struct store *from, int flags, struct store **store);
+
+/* Open the copy store NAME -- which consists of another store-class
+ name, a ':', and a name for that store class to open -- and return
+ the corresponding store in STORE. CLASSES is as if passed to
+ store_find_class, which see. */
+error_t store_copy_open (const char *name, int flags,
+ const struct store_class *const *classes,
+ struct store **store);
+
+/* Return a new store in STORE which contains the memory buffer BUF, of
+ length BUF_LEN. BUF must be vm_allocated, and will be consumed. */
+error_t store_buffer_create (void *buf, size_t buf_len, int flags,
+ struct store **store);
+
+/* Return a new store in STORE which contains a snapshot of the uncompressed
+ contents of the store FROM; FROM is consumed. BLOCK_SIZE is the desired
+ block size of the result. */
+error_t store_gunzip_create (struct store *from, int flags,
+ struct store **store);
+
+/* Open the gunzip NAME -- which consists of another store-class name, a
+ ':', and a name for that store class to open -- and return the
+ corresponding store in STORE. CLASSES is as if passed to
+ store_find_class, which see. */
+error_t store_gunzip_open (const char *name, int flags,
+ const struct store_class *const *classes,
+ struct store **store);
+
+/* Return a new store in STORE which contains a snapshot of the uncompressed
+ contents of the store FROM; FROM is consumed. BLOCK_SIZE is the desired
+ block size of the result. */
+error_t store_bunzip2_create (struct store *from, int flags,
+ struct store **store);
+
+/* Open the bunzip2 NAME -- which consists of another store-class name, a ':',
+ and a name for that store class to open -- and return the corresponding
+ store in STORE. CLASSES is as if passed to store_find_class, which see. */
+error_t store_bunzip2_open (const char *name, int flags,
+ const struct store_class *const *classes,
+ struct store **store);
+
+/* Return a new store in STORE that multiplexes multiple physical volumes
+ from PHYS as one larger virtual volume. SWAP_VOLS is a function that will
+ be called whenever the volume currently active isn't correct. PHYS is
+ consumed. */
+error_t store_mvol_create (struct store *phys,
+ error_t (*swap_vols) (struct store *store, size_t new_vol,
+ ssize_t old_vol),
+ int flags,
+ struct store **store);
+
+/* Opening stores from a standard set of store classes.
+
+ These first two functions underlie the following functions, and
+ other functions such as store_open taking a CLASSES argument that
+ can be null. The standard set of classes to be searched when that
+ argument is null includes all the `const struct store_class *'
+ pointers found in the `store_std_classes' section of the executable
+ and all loaded shared objects; store_find_class searches that set
+ for the named class. The store_typed_open and store_url_open
+ functions also try store_module_find_class, but only if the
+ function has already been linked in; it's always available in the
+ shared library, and available for static linking with
+ -lstore_module -ldl.
+
+ The macro STORE_STD_CLASS produces a reference in the `store_std_classes'
+ section, so that linking in a module containing that definition will add
+ the referenced class to the standard search list. In the shared library,
+ the various standard classes are included this way. In the static
+ library, only the pseudo classes like `query' and `typed' will normally
+ be linked in (via referenced to store_open and so forth); to force
+ specific store type modules to be linked in, you must specify an
+ `-lstore_CLASS' option for each individual class to be statically linked.
+*/
+
+/* Find a store class by name. CLNAME_END points to the character
+ after the class name NAME points to; if null, then NAME is just the
+ null-terminated class name. */
+const struct store_class *
+store_find_class (const char *name,
+ const char *clname_end,
+ const struct store_class *const *classes);
+
+/* This is the underlying function that tries to load a module to
+ define the store type called NAME. On success, returns zero
+ and sets *CLASSP to the descriptor found. Returns ENOENT if
+ there is no such module, or other error codes if there is a
+ module but it does not load correctly. */
+error_t store_module_find_class (const char *name,
+ const char *clname_end,
+ const struct store_class **classp);
+
+
+/* Open the store indicated by NAME, which should consist of a store
+ type name followed by a ':' and any type-specific name, returning the
+ new store in STORE. CLASSES is as if passed to store_find_class,
+ which see. */
+error_t store_typed_open (const char *name, int flags,
+ const struct store_class *const *classes,
+ struct store **store);
+
+/* Similar to store_typed_open, but NAME must be in URL format, i.e. a
+ class name followed by a ':' and any type-specific name. A leading ':'
+ or no ':' at all is invalid syntax. (See store_module_open, below.) */
+error_t store_url_open (const char *name, int flags,
+ const struct store_class *const *classes,
+ struct store **store);
+
+/* This attempts to decode a standard-form STORAGE_NETWORK encoding whose
+ encoded name is in URL format, by finding the store type indicated in
+ the URL (as for store_url_open) and that type's decode function. */
+error_t store_url_decode (struct store_enc *enc,
+ const struct store_class *const *classes,
+ struct store **store);
+
+
+/* Similar to store_typed_open, but the store type's code is found
+ dynamically rather than statically in CLASSES. A shared object name
+ for `dlopen' and symbol names for `dlsym' are derived from the type
+ name and used to find the `struct store_class' for the named type.
+ (CLASSES is used only by the type's own open function, e.g. if that
+ type accepts a child-store syntax in its name.)
+
+ In fact, when this code is linked in (always in the shared library,
+ only with `-lstore_module -ldl -lstore' for static linking), all
+ the functions documented as using STORE_STD_CLASSES will also
+ check for loadable modules if the type name is not found statically. */
+error_t store_module_open (const char *name, int flags,
+ const struct store_class *const *classes,
+ struct store **store);
+
+
+/* This attempts to find a module that can decode ENC. If no such
+ module can be found it returns ENOENT. Otherwise it returns
+ the result of the loaded store type's `decode' function. */
+error_t store_module_decode (struct store_enc *enc,
+ const struct store_class *const *classes,
+ struct store **store);
+
+/* Parse multiple store names in NAME, and open each individually, returning
+ all in the vector STORES, and the number in NUM_STORES. The syntax of
+ NAME is a single non-alpha-numeric separator character, followed by each
+ child store name separated by the same separator; each child name is
+ TYPE:NAME notation as parsed by store_typed_open. If every child uses the
+ same TYPE: prefix, then it may be factored out and put before the child
+ list instead (the two types of notation are differentiated by whether the
+ first character of name is alpha-numeric or not). */
+error_t store_open_children (const char *name, int flags,
+ const struct store_class *const *classes,
+ struct store ***stores, size_t *num_stores);
+
/* Standard store classes implemented by libstore. */
-extern struct store_class *store_std_classes;
-
-/* Add CLASS to the list of standard classes. It must not already be in the
- list, or in any other, as its next field is simply written over. */
-void _store_add_std_class (struct store_class *class);
-
-/* Use this macro to automagically add a class to STORE_STD_CLASSES at
- startup. */
-#define _STORE_STD_CLASS(class_struct) \
-static void _store_init_std_##class_struct () __attribute__ ((constructor));\
-static void _store_init_std_##class_struct () \
-{ \
- _store_add_std_class (&class_struct); \
-}
+extern const struct store_class store_device_class;
+extern const struct store_class store_part_class;
+extern const struct store_class store_file_class;
+extern const struct store_class store_task_class;
+extern const struct store_class store_nbd_class;
+extern const struct store_class store_memobj_class;
+extern const struct store_class store_zero_class;
+extern const struct store_class store_ileave_class;
+extern const struct store_class store_concat_class;
+extern const struct store_class store_remap_class;
+extern const struct store_class store_query_class;
+extern const struct store_class store_copy_class;
+extern const struct store_class store_gunzip_class;
+extern const struct store_class store_bunzip2_class;
+extern const struct store_class store_typed_open_class;
+extern const struct store_class store_url_open_class;
+extern const struct store_class store_module_open_class;
+extern const struct store_class store_unknown_class;
+
+/* The following are not included in STORE_STD_CLASSES. */
+extern const struct store_class store_mvol_class;
+
+#define STORE_STD_CLASS(name) \
+ static const struct store_class *const store_std_classes_##name[] \
+ __attribute_used__ __attribute__ ((section ("store_std_classes"))) \
+ = { &store_##name##_class }
+
+
+extern const struct store_class *const __start_store_std_classes[] __attribute__ ((weak));
+extern const struct store_class *const __stop_store_std_classes[] __attribute__ ((weak));
/* Used to hold the various bits that make up the representation of a store
for transmission via rpc. See <hurd/hurd_types.h> for an explanation of
@@ -308,7 +650,7 @@ struct store_enc
/* Each of the four vectors used. All are vm_allocated. */
mach_port_t *ports;
int *ints;
- off_t *offsets;
+ loff_t *offsets;
char *data;
/* The sizes of the vectors. */
@@ -322,7 +664,7 @@ struct store_enc
version won't be deallocated. */
mach_port_t *init_ports;
int *init_ints;
- off_t *init_offsets;
+ loff_t *init_offsets;
char *init_data;
};
@@ -332,13 +674,29 @@ struct store_enc
void store_enc_init (struct store_enc *enc,
mach_port_t *ports, mach_msg_type_number_t num_ports,
int *ints, mach_msg_type_number_t num_ints,
- off_t *offsets, mach_msg_type_number_t num_offsets,
+ loff_t *offsets, mach_msg_type_number_t num_offsets,
char *data, mach_msg_type_number_t data_len);
/* Deallocate storage used by the fields in ENC (but nothing is done with ENC
itself). */
void store_enc_dealloc (struct store_enc *enc);
+
+/* Copy out the parameters from ENC into the given variables suitably for
+ returning from a file_get_storage_info rpc, and deallocate ENC. */
+void store_enc_return (struct store_enc *enc,
+ mach_port_t **ports, mach_msg_type_number_t *num_ports,
+ int **ints, mach_msg_type_number_t *num_ints,
+ loff_t **offsets, mach_msg_type_number_t *num_offsets,
+ char **data, mach_msg_type_number_t *data_len);
+/* Encode STORE into the given return variables, suitably for returning from a
+ file_get_storage_info rpc. */
+error_t store_return (const struct store *store,
+ mach_port_t **ports, mach_msg_type_number_t *num_ports,
+ int **ints, mach_msg_type_number_t *num_ints,
+ loff_t **offsets, mach_msg_type_number_t *num_offsets,
+ char **data, mach_msg_type_number_t *data_len);
+
/* Encode STORE into ENC, which should have been prepared with
store_enc_init, or return an error. The contents of ENC may then be
return as the value of file_get_storage_info; if for some reason this
@@ -346,11 +704,12 @@ void store_enc_dealloc (struct store_enc *enc);
used by the unsent vectors. */
error_t store_encode (const struct store *store, struct store_enc *enc);
-/* Decode ENC, either returning a new store in STORE, or an error. CLASSES
- defines the mapping from hurd storage class ids to store classes; if it is
- 0, STORE_STD_CLASSES is used. If nothing else is to be done with ENC, its
- contents may then be freed using store_enc_dealloc. */
-error_t store_decode (struct store_enc *enc, struct store_class *classes,
+/* Decode ENC, either returning a new store in STORE, or an error.
+ CLASSES is as if passed to store_find_class, which see. If nothing
+ else is to be done with ENC, its contents may then be freed using
+ store_enc_dealloc. */
+error_t store_decode (struct store_enc *enc,
+ const struct store_class *const *classes,
struct store **store);
/* Calls the allocate_encoding method in each child store of STORE,
@@ -367,9 +726,14 @@ error_t store_encode_children (const struct store *store,
/* Decodes NUM_CHILDREN from ENC, storing the results into successive
positions in CHILDREN. */
error_t store_decode_children (struct store_enc *enc, int num_children,
- struct store_class *classes,
+ const struct store_class *const *classes,
struct store **children);
+/* Call FUN with the vector RUNS of length NUM_RUNS extracted from ENC. */
+error_t store_with_decoded_runs (struct store_enc *enc, size_t num_runs,
+ error_t (*fun) (const struct store_run *runs,
+ size_t num_runs));
+
/* Standard encoding used for most leaf store types. */
error_t store_std_leaf_allocate_encoding (const struct store *store,
struct store_enc *enc);
@@ -392,22 +756,45 @@ error_t store_std_leaf_decode (struct store_enc *enc,
/* An argument parser that may be used for parsing a simple command line
specification for stores. The accompanying input parameter must be a
- pointer to a structure of type struct store_argp_param. */
+ pointer to a struct store_argp_params. */
extern struct argp store_argp;
-/* Structure used to pass in arguments and return the result from
- STORE_ARGP. */
+/* The structure used to pass args back and forth from STORE_ARGP. */
struct store_argp_params
{
- /* An initial set of flags desired to be set. */
- int flags;
+ /* The resulting parsed result. */
+ struct store_parsed *result;
+
+ /* If --store-type isn't specified use this; 0 is equivalent to "query". */
+ const char *default_type;
- /* If true, don't attempt use store_file_create to create a store on files
- upon which store_create has failed. */
- int no_file_io : 1;
+ /* The set of classes used to validate store-types and argument syntax. */
+ const struct store_class *const *classes;
- /* Parsed store returned here. */
- struct store *result;
+ /* This controls the behavior when no store arguments are specified.
+ If zero, the parser fails with the error message "No store specified".
+ If nonzero, the parser succeeds and sets `result' to null. */
+ int store_optional;
};
+/* The result of parsing a store, which should be enough information to open
+ it, or return the arguments. */
+struct store_parsed;
+
+/* Free all resources used by PARSED. */
+void store_parsed_free (struct store_parsed *parsed);
+
+/* Open PARSED, and return the corresponding store in STORE. */
+error_t store_parsed_open (const struct store_parsed *parsed, int flags,
+ struct store **store);
+
+/* Add the arguments used to create PARSED to ARGZ & ARGZ_LEN. */
+error_t store_parsed_append_args (const struct store_parsed *parsed,
+ char **argz, size_t *argz_len);
+
+/* Make a string describing PARSED, and return it in malloced storage in
+ NAME. */
+error_t store_parsed_name (const struct store_parsed *parsed, char **name);
+
+
#endif /* __STORE_H__ */
diff --git a/libstore/storecat.c b/libstore/storecat.c
deleted file mode 100644
index f1374390..00000000
--- a/libstore/storecat.c
+++ /dev/null
@@ -1,29 +0,0 @@
-/* Test program for libstore -- outputs the concatenation of stores */
-
-#include <argp.h>
-#include <error.h>
-#include <unistd.h>
-
-#include "store.h"
-
-int
-main (int argc, char **argv)
-{
- error_t err;
- struct store *s;
- char buf[4096], *data = buf;
- size_t data_len = sizeof (buf);
- struct store_argp_params params = { 0, 0, 0 };
-
- argp_parse (&store_argp, argc, argv, 0, 0, &params);
- s = params.result;
-
- err = store_read (s, 0, s->size, &data, &data_len);
- if (err)
- error (5, err, s->name ? "%s" : "<store>", s->name);
-
- if (write (1, data, data_len) < 0)
- error (6, errno, "stdout");
-
- exit (0);
-}
diff --git a/libstore/storeread.c b/libstore/storeread.c
deleted file mode 100644
index ea012727..00000000
--- a/libstore/storeread.c
+++ /dev/null
@@ -1,100 +0,0 @@
-/* Test program for libstore -- outputs a portion of a store */
-
-#include <argp.h>
-#include <error.h>
-#include <unistd.h>
-#include <hurd.h>
-#include <sys/fcntl.h>
-
-#include "store.h"
-
-struct argp_option options[] = {
- {"file", 'f', 0, 0, "Use file IO instead of the raw device"},
- {"block-size", 'b', "BYTES", 0, "Set the file block size"},
- {0, 0}
-};
-char *arg_doc = "FILE [ADDR [LENGTH]]...";
-char *doc = "ADDR is in blocks, and defaults to 0; LENGTH is in bytes, and defaults to the remainder of FILE.";
-
-int
-main (int argc, char **argv)
-{
- struct store *store = 0;
- off_t addr = -1;
- int dumped = 0, use_file_io = 0, block_size = 0;
-
- void dump (off_t addr, ssize_t len)
- {
- char buf[4096], *data = buf;
- size_t data_len = sizeof (buf);
- error_t err =
- store_read (store, addr, len < 0 ? store->size : len,
- &data, &data_len);
- if (err)
- error (5, err, store->name ? "%s" : "<store>", store->name);
- if (write (1, data, data_len) < 0)
- error (6, errno, "stdout");
- if (data != buf)
- vm_deallocate (mach_task_self (), (vm_address_t)data, data_len);
- }
-
- error_t parse_opt (int key, char *arg, struct argp_state *state)
- {
- switch (key)
- {
- case 'f': use_file_io = 1; break;
- case 'b': block_size = atoi (arg); break;
-
- case ARGP_KEY_ARG:
- if (! store)
- {
- error_t err;
- file_t source = file_name_lookup (arg, O_READ, 0);
- if (errno)
- error (2, errno, "%s", arg);
- if (use_file_io)
- if (block_size)
- {
- struct stat stat;
- err = io_stat (source, &stat);
- if (! err)
- {
- struct store_run run = {0, stat.st_size / block_size};
- err = _store_file_create (source, block_size, &run, 1,
- &store);
- }
- }
- else
- err = store_file_create (source, &store);
- else
- err = store_create (source, &store);
- if (err)
- error (err, 3, "%s", arg);
- }
- else if (addr < 0)
- addr = atoi (arg);
- else
- {
- dump (addr, atoi (arg));
- dumped = 1;
- addr = -1;
- }
- break;
-
- case ARGP_KEY_END:
- if (addr >= 0)
- dump (addr, -1);
- else if (! dumped)
- dump (0, -1);
- break;
-
- case ARGP_KEY_NO_ARGS:
- default:
- return ARGP_ERR_UNKNOWN;
- }
- return 0;
- }
- struct argp argp = {options, parse_opt, arg_doc, doc};
- argp_parse (&argp, argc, argv, 0, 0, 0);
- exit (0);
-}
diff --git a/libstore/stripe.c b/libstore/stripe.c
index 055c548f..e9c58466 100644
--- a/libstore/stripe.c
+++ b/libstore/stripe.c
@@ -1,9 +1,7 @@
/* Striped store backend
- Copyright (C) 1996 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
-
+ Copyright (C) 1996,97,99,2001, 2002 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
This file is part of the GNU Hurd.
The GNU Hurd is free software; you can redistribute it and/or
@@ -18,7 +16,7 @@
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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
#include <stdlib.h>
#include <string.h>
@@ -29,8 +27,8 @@ extern long lcm (long p, long q);
/* Return ADDR adjust for any block size difference between STORE and
STRIPE. We assume that STORE's block size is no less than STRIPE's. */
-static inline off_t
-addr_adj (off_t addr, struct store *store, struct store *stripe)
+static inline store_offset_t
+addr_adj (store_offset_t addr, struct store *store, struct store *stripe)
{
unsigned common_bs = store->log2_block_size;
unsigned stripe_bs = stripe->log2_block_size;
@@ -42,8 +40,8 @@ addr_adj (off_t addr, struct store *store, struct store *stripe)
static error_t
stripe_read (struct store *store,
- off_t addr, size_t index, mach_msg_type_number_t amount,
- char **buf, mach_msg_type_number_t *len)
+ store_offset_t addr, size_t index, size_t amount,
+ void **buf, size_t *len)
{
struct store *stripe = store->children[index];
return store_read (stripe, addr_adj (addr, store, stripe), amount, buf, len);
@@ -51,13 +49,27 @@ stripe_read (struct store *store,
static error_t
stripe_write (struct store *store,
- off_t addr, size_t index, char *buf, mach_msg_type_number_t len,
- mach_msg_type_number_t *amount)
+ store_offset_t addr, size_t index,
+ const void *buf, size_t len, size_t *amount)
{
struct store *stripe = store->children[index];
return
store_write (stripe, addr_adj (addr, store, stripe), buf, len, amount);
}
+
+error_t
+stripe_set_size (struct store *store, size_t newsize)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+stripe_remap (struct store *source,
+ const struct store_run *runs, size_t num_runs,
+ struct store **store)
+{
+ return store_remap_create (source, runs, num_runs, 0, store);
+}
error_t
ileave_allocate_encoding (const struct store *store, struct store_enc *enc)
@@ -77,14 +89,14 @@ ileave_encode (const struct store *store, struct store_enc *enc)
}
error_t
-ileave_decode (struct store_enc *enc, struct store_class *classes,
+ileave_decode (struct store_enc *enc, const struct store_class *const *classes,
struct store **store)
{
if (enc->cur_int + 4 > enc->num_ints)
return EINVAL;
else
{
- int type = enc->ints[enc->cur_int++];
+ int type __attribute__((unused)) = enc->ints[enc->cur_int++];
int flags = enc->ints[enc->cur_int++];
int interleave = enc->ints[enc->cur_int++];
int nkids = enc->ints[enc->cur_int++];
@@ -96,13 +108,14 @@ ileave_decode (struct store_enc *enc, struct store_class *classes,
}
}
-static struct store_class
-ileave_class =
+const struct store_class
+store_ileave_class =
{
- STORAGE_INTERLEAVE, "interleave", stripe_read, stripe_write,
+ STORAGE_INTERLEAVE, "interleave", stripe_read, stripe_write, stripe_set_size,
ileave_allocate_encoding, ileave_encode, ileave_decode,
+ store_set_child_flags, store_clear_child_flags, 0, 0, stripe_remap
};
-_STORE_STD_CLASS (ileave_class);
+STORE_STD_CLASS (ileave);
error_t
concat_allocate_encoding (const struct store *store, struct store_enc *enc)
@@ -121,14 +134,14 @@ concat_encode (const struct store *store, struct store_enc *enc)
}
error_t
-concat_decode (struct store_enc *enc, struct store_class *classes,
+concat_decode (struct store_enc *enc, const struct store_class *const *classes,
struct store **store)
{
if (enc->cur_int + 3 > enc->num_ints)
return EINVAL;
else
{
- int type = enc->ints[enc->cur_int++];
+ int type __attribute__((unused)) = enc->ints[enc->cur_int++];
int flags = enc->ints[enc->cur_int++];
int nkids = enc->ints[enc->cur_int++];
struct store *kids[nkids];
@@ -139,13 +152,15 @@ concat_decode (struct store_enc *enc, struct store_class *classes,
}
}
-static struct store_class
-concat_class =
+const struct store_class
+store_concat_class =
{
- STORAGE_CONCAT, "concat", stripe_read, stripe_write,
- concat_allocate_encoding, concat_encode, concat_decode
+ STORAGE_CONCAT, "concat", stripe_read, stripe_write, stripe_set_size,
+ concat_allocate_encoding, concat_encode, concat_decode,
+ store_set_child_flags, store_clear_child_flags, 0, 0, stripe_remap,
+ store_concat_open
};
-_STORE_STD_CLASS (concat_class);
+STORE_STD_CLASS (concat);
/* Return a new store in STORE that interleaves all the stores in STRIPES
(NUM_STRIPES of them) every INTERLEAVE bytes; INTERLEAVE must be an
@@ -154,12 +169,15 @@ _STORE_STD_CLASS (concat_class);
*array* STRIPES is copied, and so should be freed by the caller). */
error_t
store_ileave_create (struct store *const *stripes, size_t num_stripes,
- off_t interleave, int flags, struct store **store)
+ store_offset_t interleave, int flags,
+ struct store **store)
{
size_t i;
error_t err;
- off_t block_size = 1, min_end = 0;
+ size_t block_size = 1;
+ store_offset_t min_end = 0;
struct store_run runs[num_stripes];
+ int common_flags = STORE_BACKEND_FLAGS;
/* Find a common block size. */
for (i = 0; i < num_stripes; i++)
@@ -173,31 +191,34 @@ store_ileave_create (struct store *const *stripes, size_t num_stripes,
for (i = 0; i < num_stripes; i++)
{
/* The stripe's end adjusted to the common block size. */
- off_t end = stripes[i]->end;
+ store_offset_t end = stripes[i]->end;
runs[i].start = 0;
runs[i].length = interleave;
if (stripes[i]->block_size != block_size)
end /= (block_size / stripes[i]->block_size);
-
+
if (min_end < 0)
min_end = end;
else if (min_end > end)
/* Only use as much space as the smallest stripe has. */
min_end = end;
- }
- *store = _make_store (&ileave_class, MACH_PORT_NULL, flags, block_size,
- runs, num_stripes, min_end);
- if (! *store)
- return ENOMEM;
+ common_flags &= stripes[i]->flags;
+ }
- (*store)->wrap_dst = interleave;
+ err = _store_create (&store_ileave_class, MACH_PORT_NULL,
+ common_flags | flags, block_size,
+ runs, num_stripes, min_end, store);
+ if (! err)
+ {
+ (*store)->wrap_dst = interleave;
- err = store_set_children (*store, stripes, num_stripes);
- if (err)
- store_free (*store);
+ err = store_set_children (*store, stripes, num_stripes);
+ if (err)
+ store_free (*store);
+ }
return err;
}
@@ -212,7 +233,8 @@ store_concat_create (struct store * const *stores, size_t num_stores,
{
size_t i;
error_t err;
- off_t block_size = 1;
+ size_t block_size = 1;
+ int common_flags = STORE_BACKEND_FLAGS;
struct store_run runs[num_stores];
/* Find a common block size. */
@@ -223,16 +245,49 @@ store_concat_create (struct store * const *stores, size_t num_stores,
{
runs[i].start = 0;
runs[i].length = stores[i]->end;
+ common_flags &= stores[i]->flags;
}
- *store = _make_store (&concat_class, MACH_PORT_NULL, flags, block_size,
- runs, num_stores * 2, 0);
- if (! *store)
- return ENOMEM;
+ err = _store_create (&store_concat_class, MACH_PORT_NULL,
+ flags | common_flags, block_size,
+ runs, num_stores, 0, store);
+ if (! err)
+ {
+ err = store_set_children (*store, stores, num_stores);
+ if (! err)
+ {
+ err = store_children_name (*store, &(*store)->name);
+ if (err == EINVAL)
+ err = 0; /* Can't find a name; deal. */
+ }
+ if (err)
+ store_free (*store);
+ }
- err = store_set_children (*store, stores, num_stores);
- if (err)
- store_free (*store);
+ return err;
+}
+/* Return a new store that concatenates the stores created by opening all the
+ individual stores described in NAME; for the syntax of NAME, see
+ store_open_children. */
+error_t
+store_concat_open (const char *name, int flags,
+ const struct store_class *const *classes,
+ struct store **store)
+{
+ struct store **stores;
+ size_t num_stores;
+ error_t err =
+ store_open_children (name, flags, classes, &stores, &num_stores);
+ if (! err)
+ {
+ err = store_concat_create (stores, num_stores, flags, store);
+ if (err)
+ {
+ size_t k;
+ for (k = 0; k < (*store)->num_children; k++)
+ store_free ((*store)->children[k]);
+ }
+ }
return err;
}
diff --git a/libstore/task.c b/libstore/task.c
new file mode 100644
index 00000000..ea1475c8
--- /dev/null
+++ b/libstore/task.c
@@ -0,0 +1,205 @@
+/* Mach task store backend
+
+ Copyright (C) 1995,96,97,2001, 2002 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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.
+
+ The GNU Hurd 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, USA. */
+
+#include <stdio.h>
+#include <string.h>
+#include <hurd.h>
+
+#include <mach/machine/vm_param.h>
+
+#include "store.h"
+
+static process_t
+proc_server ()
+{
+ static process_t proc = MACH_PORT_NULL;
+ if (proc == MACH_PORT_NULL)
+ proc = getproc ();
+ return proc;
+}
+
+static error_t
+topen (const char *name, task_t *task)
+{
+ char *name_end;
+ pid_t pid = strtoul (name, &name_end, 0);
+
+ if (*name == '\0' || *name_end != '\0')
+ return EINVAL;
+
+ return proc_pid2task (proc_server (), pid, task);
+}
+
+static void
+tclose (struct store *store)
+{
+ mach_port_deallocate (mach_task_self (), store->port);
+ store->port = MACH_PORT_NULL;
+}
+
+static error_t
+task_read (struct store *store,
+ store_offset_t addr, size_t index, size_t amount, void **buf, size_t *len)
+{
+ size_t bsize = store->block_size;
+ return vm_read (store->port, addr * bsize, amount, (vm_address_t *)buf, len);
+}
+
+static error_t
+task_write (struct store *store,
+ store_offset_t addr, size_t index,
+ const void *buf, size_t len, size_t *amount)
+{
+ size_t bsize = store->block_size;
+ error_t err = vm_write (store->port, addr * bsize, (vm_address_t)buf, len);
+ if (! err)
+ *amount = len;
+ return err;
+}
+
+static error_t
+task_set_size (struct store *store, size_t newsize)
+{
+ return EOPNOTSUPP;
+}
+
+static error_t
+task_decode (struct store_enc *enc, const struct store_class *const *classes,
+ struct store **store)
+{
+ return store_std_leaf_decode (enc, _store_task_create, store);
+}
+
+static error_t
+task_open (const char *name, int flags,
+ const struct store_class *const *classes,
+ struct store **store)
+{
+ return store_task_open (name, flags, store);
+}
+
+static error_t
+task_set_flags (struct store *store, int flags)
+{
+ if ((flags & ~(STORE_INACTIVE | STORE_ENFORCED)) != 0)
+ /* Trying to set flags we don't support. */
+ return EINVAL;
+
+ if ((flags & STORE_ENFORCED)
+ && (store->num_runs > 0
+ || store->runs[0].start != 0
+ || store->runs[0].length != (VM_MAX_ADDRESS >> store->log2_block_size)))
+ /* Kernel only enforces the whole thing... */
+ return EINVAL;
+
+ if (flags & STORE_INACTIVE)
+ tclose (store);
+
+ store->flags |= flags; /* When inactive, anything goes. */
+
+ return 0;
+}
+
+static error_t
+task_clear_flags (struct store *store, int flags)
+{
+ error_t err = 0;
+ if ((flags & ~(STORE_INACTIVE | STORE_ENFORCED)) != 0)
+ err = EINVAL;
+ if (!err && (flags & STORE_INACTIVE))
+ err = store->name ? topen (store->name, &store->port) : ESRCH;
+ if (! err)
+ store->flags &= ~flags;
+ return err;
+}
+
+const struct store_class
+store_task_class =
+{
+ STORAGE_TASK, "task", task_read, task_write, task_set_size,
+ store_std_leaf_allocate_encoding, store_std_leaf_encode, task_decode,
+ task_set_flags, task_clear_flags, 0, 0, 0, task_open
+};
+STORE_STD_CLASS (task);
+
+/* Return a new store in STORE referring to the mach task TASK. Consumes
+ the send right TASK. */
+error_t
+store_task_create (task_t task, int flags, struct store **store)
+{
+ struct store_run run;
+
+ run.start = 0;
+ run.length = VM_MAX_ADDRESS / vm_page_size;
+
+ flags |= STORE_ENFORCED; /* 'cause it's the whole task. */
+
+ return _store_task_create (task, flags, vm_page_size, &run, 1, store);
+}
+
+/* Like store_task_create, but doesn't query the task for information. */
+error_t
+_store_task_create (task_t task, int flags, size_t block_size,
+ const struct store_run *runs, size_t num_runs,
+ struct store **store)
+{
+ error_t err = 0;
+
+ if (block_size >= vm_page_size)
+ err = _store_create (&store_task_class,
+ task, flags, block_size, runs, num_runs, 0, store);
+ else
+ err = EINVAL; /* block size less than page size. */
+
+ if (! err)
+ {
+ pid_t pid;
+
+ err = proc_task2pid (proc_server (), task, &pid);
+ if (! err)
+ {
+ char buf[20];
+ snprintf (buf, sizeof buf, "%u", pid);
+ err = store_set_name (*store, buf);
+ }
+
+ if (err)
+ store_free (*store);
+ }
+
+ return err;
+}
+
+/* Open the task NAME, and return the corresponding store in STORE. */
+error_t
+store_task_open (const char *name, int flags, struct store **store)
+{
+ task_t task;
+ error_t err = topen (name, &task);
+
+ if (! err)
+ {
+ err = store_task_create (task, flags, store);
+ if (err)
+ mach_port_deallocate (mach_task_self (), task);
+ }
+
+ return err;
+}
diff --git a/libstore/typed.c b/libstore/typed.c
new file mode 100644
index 00000000..b1be747d
--- /dev/null
+++ b/libstore/typed.c
@@ -0,0 +1,177 @@
+/* Support for opening `typed' stores
+
+ Copyright (C) 1997,1998,2001,2002,2003,2004 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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.
+
+ The GNU Hurd 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, USA. */
+
+#include "store.h"
+#include <string.h>
+#include <dlfcn.h>
+#include <link.h>
+
+
+const struct store_class *
+store_find_class (const char *name, const char *clname_end,
+ const struct store_class *const *classes)
+{
+ const struct store_class *const *cl;
+
+ if (! clname_end)
+ clname_end = strchr (name, '\0');
+
+ if (classes != 0)
+ {
+ /* The caller gave a class list, so that's is all we'll use. */
+ for (cl = classes; *cl != 0; ++cl)
+ if (strlen ((*cl)->name) == (clname_end - name)
+ && !memcmp (name, (*cl)->name, (clname_end - name)))
+ break;
+ return *cl;
+ }
+
+ /* Check the statically-linked set of classes found in the
+ "store_std_classes" section. For static linking, this is the section
+ in the program executable itself and it has been populated by the set
+ of -lstore_TYPE pseudo-libraries included in the link. For dynamic
+ linking with just -lstore, these symbols will be found in libstore.so
+ and have the set statically included when the shared object was built.
+ If a dynamically-linked program has its own "store_std_classes"
+ section, e.g. by -lstore_TYPE objects included in the link, this will
+ be just that section and libstore.so itself is covered below. */
+ for (cl = __start_store_std_classes; cl < __stop_store_std_classes; ++cl)
+ if (strlen ((*cl)->name) == (clname_end - name)
+ && strncmp (name, (*cl)->name, (clname_end - name)) == 0)
+ return *cl;
+
+ /* Now we will iterate through all of the dynamic objects loaded
+ and examine each one's "store_std_classes" section. */
+# pragma weak _r_debug
+# pragma weak dlsym
+# pragma weak dlopen
+# pragma weak dlclose
+# pragma weak dlerror
+ if (dlsym)
+ {
+ struct link_map *map;
+ for (map = _r_debug.r_map; map != 0; map = map->l_next)
+ {
+ const struct store_class *const *start, *const *stop;
+
+ /* We cannot just use MAP directly because it may not have been
+ opened by dlopen such that its data structures are fully set
+ up for dlsym. */
+ void *module = dlopen (map->l_name, RTLD_NOLOAD);
+ if (module == 0)
+ {
+ (void) dlerror (); /* Required to avoid a leak! */
+ continue;
+ }
+
+ start = dlsym (map, "__start_store_std_classes");
+ if (start == 0)
+ (void) dlerror (); /* Required to avoid a leak! */
+ else if (start != __start_store_std_classes) /* */
+ {
+ stop = dlsym (map, "__stop_store_std_classes");
+ if (stop == 0)
+ (void) dlerror (); /* Required to avoid a leak! */
+ else
+ for (cl = start; cl < stop; ++cl)
+ if (strlen ((*cl)->name) == (clname_end - name)
+ && strncmp (name, (*cl)->name, (clname_end - name)) == 0)
+ {
+ dlclose (module);
+ return *cl;
+ }
+ }
+ dlclose (module);
+ }
+ }
+
+ return 0;
+}
+
+
+/* Open the store indicated by NAME, which should consist of a store type
+ name followed by a ':' and any type-specific name, returning the new store
+ in STORE. If NAME doesn't contain a `:', then it will be interpreted as
+ either a class name, if such a class occurs in CLASSES, or a filename,
+ which is opened by calling store_open on NAME; a `:' at the end or the
+ beginning of NAME unambiguously causes the remainder to be treated as a
+ class-name or a filename, respectively. CLASSES is used to select classes
+ specified by the type name; if it is 0, STORE_STD_CLASSES is used. */
+error_t
+store_typed_open (const char *name, int flags,
+ const struct store_class *const *classes,
+ struct store **store)
+{
+ const struct store_class *cl;
+ const char *clname_end = strchrnul (name, ':');
+
+ if (clname_end == name && *clname_end)
+ /* Open NAME with store_open. */
+ return store_open (name + 1, flags, classes, store);
+
+ /* Try to find an existing class by the given name. */
+ cl = store_find_class (name, clname_end, classes);
+ if (cl != 0)
+ {
+ if (! cl->open)
+ /* CL cannot be opened. */
+ return EOPNOTSUPP;
+
+ if (*clname_end)
+ /* Skip the ':' separating the class-name from the device name. */
+ clname_end++;
+
+ if (! *clname_end)
+ /* The class-specific portion of the name is empty, so make it *really*
+ empty. */
+ clname_end = 0;
+
+ return (*cl->open) (clname_end, flags, classes, store);
+ }
+
+ /* Try to open a store by loading a module to define the class, if we
+ have the module-loading support linked in. We don't just use
+ store_module_find_class, because store_module_open will unload the new
+ module if the open doesn't succeed and we have no other way to unload
+ it. We always leave modules loaded once a store from the module has
+ been successfully opened and so can leave unbounded numbers of old
+ modules loaded after closing all the stores using them. But at least
+ we can avoid having modules loaded for stores we never even opened. */
+# pragma weak store_module_open
+ if (store_module_open)
+ {
+ error_t err = store_module_open (name, flags, classes, store);
+ if (err != ENOENT)
+ return err;
+ }
+
+ /* No class with the given name found. */
+ if (*clname_end)
+ /* NAME really should be a class name, which doesn't exist. */
+ return EINVAL;
+ else
+ /* Try opening NAME by querying it as a file instead. */
+ return store_open (name, flags, classes, store);
+}
+
+const struct store_class
+store_typed_open_class = { -1, "typed", open: store_typed_open };
+STORE_STD_CLASS (typed_open);
diff --git a/libstore/unknown.c b/libstore/unknown.c
new file mode 100644
index 00000000..8b7f4268
--- /dev/null
+++ b/libstore/unknown.c
@@ -0,0 +1,231 @@
+/* Store backend for unknown encodings
+
+ Copyright (C) 2001,02 Free Software Foundation, Inc.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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.
+
+ The GNU Hurd 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, USA. */
+
+#include "store.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+
+/* You can't do anything with an unknown store but encode it. */
+
+static error_t
+noread (struct store *store, store_offset_t addr, size_t index,
+ size_t amount, void **buf, size_t *len)
+{
+ return EFTYPE;
+}
+
+static error_t
+nowrite (struct store *store,
+ store_offset_t addr, size_t index,
+ const void *buf, size_t len, size_t *amount)
+{
+ return EFTYPE;
+}
+
+static error_t
+noset_size (struct store *store, size_t newsize)
+{
+ return EFTYPE;
+}
+
+static error_t
+noflags (struct store *store, int flags)
+{
+ return EINVAL;
+}
+
+/* This is the only way that stores of the "unknown" class get created.
+ We save the store encoding verbatim and regurgitate it as our own. */
+
+static struct store_enc *
+duplicate_encoding (struct store_enc *enc)
+{
+ struct store_enc *us;
+ size_t i;
+
+ us = calloc (1, sizeof *us);
+ if (us == NULL)
+ return NULL;
+
+ us->ports = mmap (0, enc->num_ports * sizeof *enc->ports,
+ PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ if (us->ports == MAP_FAILED)
+ {
+ no_memory:
+ store_enc_dealloc (us);
+ free (us);
+ return NULL;
+ }
+ us->ints = mmap (0, enc->num_ints * sizeof *enc->ints,
+ PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ if (us->ints == MAP_FAILED)
+ goto no_memory;
+ us->offsets = mmap (0, enc->num_offsets * sizeof *enc->offsets,
+ PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ if (us->offsets == MAP_FAILED)
+ goto no_memory;
+ us->data = mmap (0, enc->data_len, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ if (us->data == MAP_FAILED)
+ goto no_memory;
+
+ memcpy (us->ports, enc->ports, enc->num_ports * sizeof *enc->ports);
+ memcpy (us->ints, enc->ints, enc->num_ints * sizeof *enc->ints);
+ memcpy (us->offsets, enc->offsets, enc->num_offsets * sizeof *enc->offsets);
+ memcpy (us->data, enc->data, enc->data_len);
+
+ us->num_ports = enc->num_ports;
+ us->num_ints = enc->num_ints;
+ us->num_offsets = enc->num_offsets;
+ us->data_len = enc->data_len;
+
+ for (i = 0; i < us->num_ports; ++i)
+ mach_port_mod_refs (mach_task_self (), us->ports[i],
+ MACH_PORT_RIGHT_SEND, +1);
+
+ return us;
+}
+
+error_t
+store_unknown_decode (struct store_enc *enc,
+ const struct store_class *const *classes,
+ struct store **store)
+{
+ struct store_enc *us;
+ error_t err = _store_create (&store_unknown_class,
+ MACH_PORT_NULL, STORE_ENFORCED, 0, NULL, 0, 0,
+ store);
+ if (err)
+ return err;
+
+ us = duplicate_encoding (enc);
+ if (us == NULL)
+ {
+ store_free (*store);
+ return ENOMEM;
+ }
+ (*store)->hook = us;
+
+ /* Derive a name for this unknown store from its encoded type field
+ (or lack thereof) and the leading string of its encoded data bytes. */
+ if (enc->cur_int == enc->num_ints)
+ asprintf (&(*store)->name, "notype:%.*s",
+ (int) (us->data_len - us->cur_data), us->data + us->cur_data);
+ else
+ asprintf (&(*store)->name, "type-%d:%.*s", enc->ints[enc->cur_int],
+ (int) ( us->data_len - us->cur_data), us->data + us->cur_data);
+
+ return 0;
+}
+
+/* Re-encode just the way we got it. */
+error_t
+unknown_allocate_encoding (const struct store *store, struct store_enc *enc)
+{
+ const struct store_enc *us = store->hook;
+ if (us == NULL)
+ return EOPNOTSUPP;
+ enc->num_ports += us->num_ports;
+ enc->num_ints += us->num_ints;
+ enc->num_offsets += us->num_offsets;
+ enc->data_len += us->data_len;
+ return 0;
+}
+
+error_t
+unknown_encode (const struct store *store, struct store_enc *enc)
+{
+ const struct store_enc *us = store->hook;
+ if (us == NULL)
+ return EOPNOTSUPP;
+
+ memcpy (enc->ports, us->ports, us->num_ports * sizeof enc->ports[0]);
+ enc->ports += us->num_ports;
+ memcpy (enc->ints, us->ints, us->num_ints * sizeof enc->ints[0]);
+ enc->ints += us->num_ints;
+ memcpy (enc->offsets, us->offsets, us->num_offsets * sizeof enc->offsets[0]);
+ enc->offsets += us->num_offsets;
+ memcpy (enc->data + enc->cur_data, us->data, us->data_len);
+ enc->cur_data += us->data_len;
+
+ return 0;
+}
+
+
+/* Called just before deallocating STORE. */
+static void
+unknown_cleanup (struct store *store)
+{
+ if (store->hook != NULL)
+ {
+ store_enc_dealloc (store->hook);
+ free (store->hook);
+ }
+}
+
+/* Copy any format-dependent fields in FROM to TO; if there's some reason
+ why the copy can't be made, an error should be returned. This call is
+ made after all format-independent fields have been cloned. */
+static error_t
+unknown_clone (const struct store *from, struct store *to)
+{
+ if (from->hook == NULL)
+ return 0;
+ to->hook = duplicate_encoding (from->hook);
+ return to->hook ? 0 : ENOMEM;
+}
+
+/* Unknown stores cannot be opened with a name. */
+static error_t
+unknown_validate_name (const char *name,
+ const struct store_class *const *classes)
+{
+ return name == NULL ? 0 : EINVAL;
+}
+
+static error_t
+unknown_open (const char *name, int flags,
+ const struct store_class *const *classes,
+ struct store **store)
+{
+ return (name == NULL
+ ? _store_create (&store_unknown_class, MACH_PORT_NULL,
+ STORE_ENFORCED, 0, NULL, 0, 0, store)
+ : EINVAL);
+}
+
+const struct store_class store_unknown_class =
+{
+ -1, "unknown",
+ read: noread,
+ write: nowrite,
+ set_size: noset_size,
+ allocate_encoding: unknown_allocate_encoding,
+ encode: unknown_encode,
+ decode: store_unknown_decode,
+ set_flags: noflags,
+ clear_flags: noflags,
+ cleanup: unknown_cleanup,
+ clone: unknown_clone,
+ open: unknown_open,
+ validate_name: unknown_validate_name,
+};
+STORE_STD_CLASS (unknown);
diff --git a/libstore/unzipstore.c b/libstore/unzipstore.c
new file mode 100644
index 00000000..35e9e7af
--- /dev/null
+++ b/libstore/unzipstore.c
@@ -0,0 +1,267 @@
+/* Decompressing store backend (common code for gunzip and bunzip2)
+
+ Copyright (C) 1998, 1999, 2002 Free Software Foundation, Inc.
+ Written by okuji@kuicr.kyoto-u.ac.jp <okuji@kuicr.kyoto-u.ac.jp>
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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.
+
+ The GNU Hurd 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, USA. */
+
+#include <stdio.h>
+#include <string.h>
+#include <setjmp.h>
+#include <cthreads.h>
+#include <sys/mman.h>
+
+#include "store.h"
+
+#define IN_BUFFERING (256*1024)
+#define OUT_BUFFERING (512*1024)
+
+static struct mutex unzip_lock = MUTEX_INITIALIZER;
+
+#define STORE_UNZIP(name) STORE_UNZIP_1 (UNZIP, name)
+#define STORE_UNZIP_1(unzip,name) STORE_UNZIP_2 (unzip, name)
+#define STORE_UNZIP_2(unzip,name) store_##unzip##_##name
+#define STORE_STD_CLASS_1(name) STORE_STD_CLASS(name)
+#define STRINGIFY(name) STRINGIFY_1(name)
+#define STRINGIFY_1(name) #name
+
+
+/* Uncompress the contents of FROM, which should contain a valid bzip2 file,
+ into memory, returning the result buffer in BUF & BUF_LEN. */
+static error_t
+unzip_store (struct store *from, void **buf, size_t *buf_len)
+{
+ /* Callbacks from decompression engine for I/O and error interface. */
+ extern int (*unzip_read) (char *buf, size_t maxread);
+ extern void (*unzip_write) (const char *buf, size_t nwrite);
+ extern void (*unzip_read_error) (void);
+ extern void (*unzip_error) (const char *msg);
+
+ /* How we return errors from our hook functions. */
+ jmp_buf zerr_jmp_buf;
+ error_t zerr;
+
+ /* vm_alloced buffer for the input store. */
+ void *in_buf = 0;
+ size_t in_buf_len = 0; /* Amount of valid data in IN_BUF. */
+ size_t in_buf_size = 0; /* Allocated space for IN_BUF. */
+ size_t in_buf_offs = 0; /* Offset of read point in IN_BUF. */
+ off_t in_buf_addr = 0; /* Address in FROM of *next* IN_BUF. */
+
+ /* Buffer input in units that are least IN_BUFFERING bytes, but are also a
+ multiple of FROM's block size. */
+ size_t in_addr_mask = ((1 << from->log2_block_size) - 1);
+ size_t in_buffering = ((IN_BUFFERING + in_addr_mask) & ~in_addr_mask);
+
+ /* Read at most MAXREAD (or 0 if eof) bytes into BUF from our current
+ position in FROM. */
+ int zread (char *buf, size_t maxread)
+ {
+ size_t did_read = 0;
+
+ while (maxread > 0)
+ {
+ size_t left = in_buf_len - in_buf_offs;
+
+ if (left > 0)
+ /* Fill BUF with what we can from IN_BUF. */
+ {
+ if (left > maxread)
+ left = maxread;
+ bcopy (in_buf + in_buf_offs, buf, left);
+ in_buf_offs += left;
+ buf += left;
+ maxread -= left;
+ did_read += left;
+ }
+
+ /* Limit MAXREAD to the number of bytes left in the input. */
+ if (maxread > (from->size - (in_buf_addr << from->log2_block_size)))
+ maxread = from->size - (in_buf_addr << from->log2_block_size);
+
+ if (maxread > 0)
+ /* Have to fill IN_BUF again. */
+ {
+ void *new_in_buf = in_buf;
+ size_t new_in_buf_len = in_buf_len;
+
+ zerr = store_read (from, in_buf_addr, in_buffering,
+ &new_in_buf, &new_in_buf_len);
+ if (zerr)
+ longjmp (zerr_jmp_buf, 1);
+
+ in_buf_addr += (new_in_buf_len >> from->log2_block_size);
+
+ if (new_in_buf != in_buf)
+ {
+ if (in_buf_size > 0)
+ munmap (in_buf, in_buf_size);
+ in_buf = new_in_buf;
+ in_buf_size = new_in_buf_len;
+ }
+
+ in_buf_len = new_in_buf_len;
+ in_buf_offs = 0;
+ }
+ }
+ return did_read;
+ }
+
+ size_t out_buf_offs = 0; /* Position in the output buffer. */
+
+ /* Write compress data to our output buffer. */
+ void zwrite (const char *wbuf, size_t nwrite)
+ {
+ size_t old_buf_len = *buf_len;
+
+ if (out_buf_offs + nwrite > old_buf_len)
+ /* Have to grow the output buffer. */
+ {
+ void *old_buf = *buf;
+ void *new_buf = old_buf + old_buf_len; /* First try. */
+ size_t new_buf_len = round_page (old_buf_len + old_buf_len + nwrite);
+
+ /* Try to grow the buffer. */
+ zerr =
+ vm_allocate (mach_task_self (),
+ (vm_address_t *)&new_buf, new_buf_len - old_buf_len,
+ 0);
+ if (zerr)
+ /* Can't do that, try to make a bigger buffer elsewhere. */
+ {
+ new_buf = mmap (0, new_buf_len, PROT_READ|PROT_WRITE,
+ MAP_ANON, 0, 0);
+ zerr = (new_buf == (void *) -1) ? errno : 0;
+ if (zerr)
+ longjmp (zerr_jmp_buf, 1);
+
+ if (out_buf_offs > 0)
+ /* Copy the old buffer into the start of the new & free it. */
+ bcopy (old_buf, new_buf, out_buf_offs);
+
+ munmap (old_buf, old_buf_len);
+
+ *buf = new_buf;
+ }
+
+ *buf_len = new_buf_len;
+ }
+
+ bcopy (wbuf, *buf + out_buf_offs, nwrite);
+ out_buf_offs += nwrite;
+ }
+
+ void zreaderr (void)
+ {
+ zerr = EIO;
+ longjmp (zerr_jmp_buf, 1);
+ }
+ void zerror (const char *msg)
+ {
+ zerr = EINVAL;
+ longjmp (zerr_jmp_buf, 2);
+ }
+
+ /* Try to guess a reasonable output buffer size. */
+ *buf_len = round_page (from->size * 2);
+ *buf = mmap (0, *buf_len, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ zerr = (*buf == (void *) -1) ? errno : 0;
+ if (zerr)
+ return zerr;
+
+ mutex_lock (&unzip_lock);
+
+ unzip_read = zread;
+ unzip_write = zwrite;
+ unzip_read_error = zreaderr;
+ unzip_error = zerror;
+
+ if (! setjmp (zerr_jmp_buf))
+ {
+ /* Call the decompression engine. */
+ zerr = DO_UNZIP ();
+ }
+
+ mutex_unlock (&unzip_lock);
+
+ if (in_buf_size > 0)
+ munmap (in_buf, in_buf_size);
+
+ if (zerr)
+ {
+ if (*buf_len > 0)
+ munmap (*buf, *buf_len);
+ }
+ else if (out_buf_offs < *buf_len)
+ /* Trim the output buffer to be the right length. */
+ {
+ size_t end = round_page (out_buf_offs);
+ if (end < *buf_len)
+ munmap (*buf + end, *buf_len - end);
+ *buf_len = out_buf_offs;
+ }
+
+ return zerr;
+}
+
+
+/* Return a new store in STORE which contains a snapshot of the uncompressed
+ contents of the store FROM; FROM is consumed. */
+error_t
+STORE_UNZIP(create) (struct store *from, int flags, struct store **store)
+{
+ void *buf;
+ size_t buf_len;
+ error_t err = unzip_store (from, &buf, &buf_len);
+
+ if (! err)
+ {
+ err = store_buffer_create (buf, buf_len, flags, store);
+ if (err)
+ munmap (buf, buf_len);
+ else
+ store_free (from);
+ }
+
+ return err;
+}
+
+/* Open the compressed store NAME -- which consists of another store-class
+ name, a ':', and a name for that store class to open -- and return the
+ corresponding store in STORE. CLASSES is used to select classes
+ specified by the type name; if it is 0, STORE_STD_CLASSES is used. */
+error_t
+STORE_UNZIP(open) (const char *name, int flags,
+ const struct store_class *const *classes,
+ struct store **store)
+{
+ struct store *from;
+ error_t err =
+ store_typed_open (name, flags | STORE_HARD_READONLY, classes, &from);
+
+ if (! err)
+ {
+ err = STORE_UNZIP(create) (from, flags, store);
+ if (err)
+ store_free (from);
+ }
+
+ return err;
+}
+
+const struct store_class STORE_UNZIP(class) =
+{ -1, STRINGIFY(UNZIP), open: STORE_UNZIP(open) };
+STORE_STD_CLASS_1 (UNZIP);
diff --git a/libstore/url.c b/libstore/url.c
new file mode 100644
index 00000000..9b5f524e
--- /dev/null
+++ b/libstore/url.c
@@ -0,0 +1,92 @@
+/* Support for opening stores named in URL syntax.
+
+ Copyright (C) 2001,02 Free Software Foundation, Inc.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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.
+
+ The GNU Hurd 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, USA. */
+
+#include "store.h"
+#include <string.h>
+#include <stdlib.h>
+
+
+/* Similar to store_typed_open, but NAME must be in URL format,
+ i.e. a class name followed by a ':' and any type-specific name.
+ Store classes opened this way must strip off the "class:" prefix.
+ A leading ':' or no ':' at all is invalid syntax. */
+
+error_t
+store_url_open (const char *name, int flags,
+ const struct store_class *const *classes,
+ struct store **store)
+{
+ if (name == 0 || name[0] == ':' || strchr (name, ':') == 0)
+ return EINVAL;
+
+ return store_typed_open (name, flags, classes, store);
+}
+
+error_t
+store_url_decode (struct store_enc *enc,
+ const struct store_class *const *classes,
+ struct store **store)
+{
+ const struct store_class *cl;
+
+ /* This is pretty bogus. We use decode.c's code just to validate
+ the generic format and extract the name from the data. */
+ struct store dummy, *dummyptr;
+ error_t dummy_create (mach_port_t port, int flags, size_t block_size,
+ const struct store_run *runs, size_t num_runs,
+ struct store **store)
+ {
+ *store = &dummy;
+ return 0;
+ }
+ struct store_enc dummy_enc = *enc;
+ error_t err = store_std_leaf_decode (&dummy_enc, &dummy_create, &dummyptr);
+ if (err)
+ return err;
+
+ /* Find the class matching this name. */
+ cl = store_find_class (dummy.name, strchr (dummy.name, ':'), classes);
+# pragma weak store_module_find_class
+ if (cl == 0 && store_module_find_class)
+ err = store_module_find_class (dummy.name, strchr (dummy.name, ':'),
+ &cl);
+ free (dummy.name);
+ free (dummy.misc);
+
+ if (cl == 0)
+ return EINVAL;
+
+ /* Now that we have the class, we just punt to its own decode hook. */
+
+ return (!cl->decode ? EOPNOTSUPP : (*cl->decode) (enc, classes, store));
+}
+
+/* This class is only trivially different from the "typed" class when used
+ by name. Its real purpose is to decode file_get_storage_info results
+ that use the STORAGE_NETWORK type, for which the convention is that the
+ name be in URL format (i.e. "type:something"). */
+
+const struct store_class store_url_open_class =
+{
+ STORAGE_NETWORK, "url",
+ open: store_url_open,
+ decode: store_url_decode
+};
+STORE_STD_CLASS (url_open);
diff --git a/libstore/xinl.c b/libstore/xinl.c
new file mode 100644
index 00000000..90242212
--- /dev/null
+++ b/libstore/xinl.c
@@ -0,0 +1,2 @@
+#define STORE_DEFINE_EI
+#include "store.h"
diff --git a/libstore/zero.c b/libstore/zero.c
new file mode 100644
index 00000000..2fba72cc
--- /dev/null
+++ b/libstore/zero.c
@@ -0,0 +1,196 @@
+/* Zero store backend
+
+ Copyright (C) 1995,96,97,99,2000,01, 02 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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.
+
+ The GNU Hurd 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, USA. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <sys/mman.h>
+
+#include "store.h"
+
+static error_t
+zero_read (struct store *store,
+ store_offset_t addr, size_t index, size_t amount, void **buf,
+ size_t *len)
+{
+ if (*len < amount)
+ {
+ *buf = mmap (0, amount, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ if (*buf == MAP_FAILED)
+ return errno;
+ *len = amount;
+ return 0;
+ }
+ else
+ memset (*buf, 0, amount);
+
+ *len = amount;
+ return 0;
+}
+
+static error_t
+zero_write (struct store *store,
+ store_offset_t addr, size_t index, const void *buf, size_t len,
+ size_t *amount)
+{
+ return 0;
+}
+
+static error_t
+zero_set_size (struct store *store, size_t newsize)
+{
+ return EOPNOTSUPP;
+}
+
+/* Modify SOURCE to reflect those runs in RUNS, and return it in STORE. */
+error_t
+zero_remap (struct store *source,
+ const struct store_run *runs, size_t num_runs,
+ struct store **store)
+{
+ /* Because all blocks are the same, a zero store always contains just one
+ run; here we simply count up the number of blocks specified by RUNS, and
+ modify SOURCE's one run to reflect that. */
+ int i;
+ store_offset_t length = 0, old_length = source->runs[0].length;
+ for (i = 0; i < num_runs; i++)
+ if (runs[i].start < 0 || runs[i].start + runs[i].length >= old_length)
+ return EINVAL;
+ else
+ length += runs[i].length;
+ source->runs[0].length = length;
+ *store = source;
+ return 0;
+}
+
+error_t
+zero_allocate_encoding (const struct store *store, struct store_enc *enc)
+{
+ enc->num_ints += 2;
+ enc->num_offsets += 1;
+ return 0;
+}
+
+error_t
+zero_encode (const struct store *store, struct store_enc *enc)
+{
+ enc->ints[enc->cur_int++] = store->class->id;
+ enc->ints[enc->cur_int++] = store->flags;
+ enc->offsets[enc->cur_offset++] = store->size;
+ return 0;
+}
+
+error_t
+zero_decode (struct store_enc *enc, const struct store_class *const *classes,
+ struct store **store)
+{
+ store_offset_t size;
+ int type, flags;
+
+ if (enc->cur_int + 2 > enc->num_ints
+ || enc->cur_offset + 1 > enc->num_offsets)
+ return EINVAL;
+
+ type = enc->ints[enc->cur_int++];
+ flags = enc->ints[enc->cur_int++];
+ size = enc->offsets[enc->cur_offset++];
+
+ return store_zero_create (size, flags, store);
+}
+
+static error_t
+zero_open (const char *name, int flags,
+ const struct store_class *const *classes,
+ struct store **store)
+{
+ if (name)
+ {
+ char *end;
+ store_offset_t size = strtoull (name, &end, 0);
+ if (end == name || end == NULL)
+ return EINVAL;
+ switch (*end)
+ {
+ case 'b':
+ size *= 512;
+ break;
+ case 'k':
+ case 'K':
+ size *= 1024;
+ break;
+ case 'm':
+ case 'M':
+ size *= 1024 * 1024;
+ break;
+ case 'g':
+ case 'G':
+ size *= 1024 * 1024 * 1024;
+ break;
+ }
+ return store_zero_create (size, flags, store);
+ }
+ else
+ {
+ store_offset_t max_offs = ~((store_offset_t)1
+ << (CHAR_BIT * sizeof (store_offset_t) - 1));
+ return store_zero_create (max_offs, flags, store);
+ }
+}
+
+static error_t
+zero_validate_name (const char *name, const struct store_class *const *classes)
+{
+ if (name)
+ {
+ char *end;
+ strtoul (name, &end, 0);
+ return end == name ? EINVAL : 0;
+ }
+ else
+ return 0; /* `maximum size' */
+}
+
+static error_t
+zero_map (const struct store *store, vm_prot_t prot, mach_port_t *memobj)
+{
+ *memobj = MACH_PORT_NULL;
+ return 0;
+}
+
+const struct store_class
+store_zero_class =
+{
+ STORAGE_ZERO, "zero", zero_read, zero_write, zero_set_size,
+ zero_allocate_encoding, zero_encode, zero_decode,
+ 0, 0, 0, 0, zero_remap, zero_open, zero_validate_name,
+ zero_map
+};
+STORE_STD_CLASS (zero);
+
+/* Return a new zero store SIZE bytes long in STORE. */
+error_t
+store_zero_create (store_offset_t size, int flags, struct store **store)
+{
+ struct store_run run = { 0, size };
+ return
+ _store_create (&store_zero_class, MACH_PORT_NULL,
+ flags | STORE_INNOCUOUS, 1, &run, 1, 0, store);
+}