diff options
Diffstat (limited to 'libstore')
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, + ©, (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, ¶ms); - 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); +} |