summaryrefslogtreecommitdiff
path: root/libstore
diff options
context:
space:
mode:
Diffstat (limited to 'libstore')
-rw-r--r--libstore/ChangeLog716
-rw-r--r--libstore/Makefile40
-rw-r--r--libstore/argp.c379
-rw-r--r--libstore/bunzip2.c259
-rw-r--r--libstore/clone.c91
-rw-r--r--libstore/copy.c241
-rw-r--r--libstore/create.c76
-rw-r--r--libstore/decode.c180
-rw-r--r--libstore/derive.c84
-rw-r--r--libstore/device.c280
-rw-r--r--libstore/enc.c98
-rw-r--r--libstore/encode.c167
-rw-r--r--libstore/file.c275
-rw-r--r--libstore/flags.c66
-rw-r--r--libstore/gunzip.c275
-rw-r--r--libstore/kids.c311
-rw-r--r--libstore/make.c100
-rw-r--r--libstore/map.c77
-rw-r--r--libstore/mvol.c151
-rw-r--r--libstore/open.c64
-rw-r--r--libstore/rdwr.c281
-rw-r--r--libstore/remap.c338
-rw-r--r--libstore/set.c77
-rw-r--r--libstore/std.c32
-rw-r--r--libstore/store.h646
-rw-r--r--libstore/stripe.c282
-rw-r--r--libstore/task.c197
-rw-r--r--libstore/typed.c85
-rw-r--r--libstore/xinl.c2
-rw-r--r--libstore/zero.c169
30 files changed, 6039 insertions, 0 deletions
diff --git a/libstore/ChangeLog b/libstore/ChangeLog
new file mode 100644
index 00000000..74f6bcb4
--- /dev/null
+++ b/libstore/ChangeLog
@@ -0,0 +1,716 @@
+1999-11-20 Roland McGrath <roland@baalperazim.frob.com>
+
+ * store.h (struct store_class): Add const to type of `name' member.
+
+1999-11-14 Roland McGrath <roland@baalperazim.frob.com>
+
+ * device.c (dev_error): New static function.
+ Translate all expected D_* codes into POSIX codes.
+ (dev_read, dev_write, dev_open): Use it.
+
+1999-10-07 Roland McGrath <roland@baalperazim.frob.com>
+
+ * rdwr.c (store_read, store_write): Fix asserts in last change.
+
+1999-10-03 Roland McGrath <roland@baalperazim.frob.com>
+
+ * rdwr.c (store_read, store_write): Fix calculations broken in last
+ change, so they again properly account for starting intrarun offset.
+
+1999-09-09 Roland McGrath <roland@baalperazim.frob.com>
+
+ * rdwr.c (store_write, store_read): Carefully avoid scaling run
+ lengths from blocks to bytes except when we're already sure the
+ run's size in bytes won't overflow size_t.
+
+1999-07-11 Thomas Bushnell, BSG <tb@mit.edu>
+
+ * argp.c (store_parsed_open): Add more braces to clarify if-else
+ structure.
+
+ * encode.c: Include <sys/mman.h>
+ * zero.c: Likewise.
+
+ * encode.c (store_encode): Repair syntax.
+ * copy.c (copy_read): Likewise.
+
+ * enc.c (store_enc_dealloc): Cast first arg of munmap correctly.
+
+1999-07-10 Roland McGrath <roland@baalperazim.frob.com>
+
+ * rdwr.c: Add #include <sys/mman.h> for munmap decl.
+ * enc.c: Likewise.
+ * copy.c: Likewise.
+ * gunzip.c: Likewise.
+ * bunzip2.c: Likewise.
+
+1999-07-09 Thomas Bushnell, BSG <tb@mit.edu>
+
+ * bunzip2.c (bunzip2): Use mmap instead of vm_allocate.
+ * copy.c (copy_read): Likewise.
+ (copy_clone): Likewise.
+ * encode.c (store_encode): Likewise.
+ * gunzip.c (gunzip): Likewise.
+ * rdwr.c (store_read): Likewise.
+ * zero.c (zero_read): Likewise.
+
+1999-07-08 Roland McGrath <roland@baalperazim.frob.com>
+
+ * remap.c (remap_open): Recognize "N+" syntax in block list as from
+ block N through the end of the store.
+
+1999-07-03 Thomas Bushnell, BSG <tb@mit.edu>
+
+ * bunzip2.c (bunzip2): Use munmap instead of vm_deallocate.
+ (store_bunzip2_create): Likewise.
+ * rdwr.c (store_read): Likewise.
+ * gunzip.c (gunzip): Likewise.
+ (store_gunzip_create): Likewise.
+ * enc.c (store_enc_dealloc): Likewise.
+ * copy.c (copy_cleanup): Likewise.
+
+1999-05-23 Roland McGrath <roland@baalperazim.frob.com>
+
+ * remap.c (remap_open): Don't multiply by 512. Offsets and sizes are
+ in blocks, not bytes.
+
+ * stripe.c (concat_decode): Add __attribute__((unused)) to suppress
+ warning.
+ (ileave_decode): Likewise.
+
+ * bunzip2.c: Add extern decl for do_bunzip2.
+
+1999-05-16 Roland McGrath <roland@baalperazim.frob.com>
+
+ * remap.c (remap_decode): Add attribute((unused)) to suppress warning.
+
+1999-05-14 Roland McGrath <roland@baalperazim.frob.com>
+
+ * remap.c (remap_open, remap_validate_name): New functions, to support
+ parsing block lists a la GRUB.
+ (store_remap_class): Initialize those slots.
+
+1999-05-01 Mark Kettenis <kettenis@gnu.org>
+
+ * device.c (store_device_create): Deal with devices that return
+ sucessfully from device_get_status, but do not return any sensible
+ information.
+
+1998-09-06 OKUJI Yoshinori <okuji@kuicr.kyoto-u.ac.jp>
+
+ * bunzip2.c: New file.
+ * store.h (store_bunzip2_create): New declarations.
+ (store_bunzip2_open): Likewise.
+ (store_bunzip2_class): Likewise.
+ * std.c (store_std_classes): Add store_bunzip2_class.
+ * Makefile (SRCS): Add bunzip2.c.
+ (UNZIP_OBJS): Add do-bunzip2.o.
+
+1998-12-27 Roland McGrath <roland@baalperazim.frob.com>
+
+ * store.h: Remove defns of STORAGE_*, now in <hurd/hurd_types.h>.
+
+1998-12-21 Roland McGrath <roland@baalperazim.frob.com>
+
+ * open.c (store_open): Like file.c:fiopen, catch EACCES or EROFS
+ and try to open read-only.
+
+ * file.c (fiopen): Treat EROFS same as EACCES.
+
+1998-10-20 Roland McGrath <roland@baalperazim.frob.com>
+
+ * flags.c (store_clear_flags): Add braces to silence gcc warning.
+
+1998-10-19 Roland McGrath <roland@baalperazim.frob.com>
+
+ * rdwr.c (store_read): Add braces to silence gcc warning.
+ * flags.c (store_set_flags): Likewise.
+ * typed.c (store_typed_open): Likewise.
+ * decode.c (store_decode): Likewise.
+ * argp.c (store_parsed_append_args): Likewise.
+ (store_parsed_name): Likewise.
+ (store_parsed_open): Likewise.
+
+1998-09-05 Roland McGrath <roland@baalperazim.frob.com>
+
+ * argp.c (store_parsed_append_args): Use %d for layer, which is int.
+ Cast to int for %* field width arg.
+
+1997-09-22 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * encode.c (store_encode): Allocate the correct amount of memory
+ for the encoding vectors.
+
+ * make.c (_store_create): Initialize NEW->misc_len.
+
+ * mvol.c (store_mvol_class): Set correct members.
+ (store_mvol_create): Declare PHYS correctly.
+ <stdio.h>: New include.
+ * store.h (store_mvol_create): Declare PHYS correctly.
+ * Makefile (SRCS): Add mvol.c.
+
+1997-08-11 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * store.h (store_mvol_create): New declaration.
+ (store_mvol_class): New declaration.
+ * mvol.c: New file.
+
+1997-07-24 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * device.c (store_device_create): Treat devices that can't do
+ device_get_status as zero-length.
+ (dev_map): Pass 0 for OFFSET and SIZE arguments to device_map --
+ mach ignores them, and we often can't supply meaningful values.
+ * make.c (_store_create): If BLOCK_SIZE is zero, make sure there
+ are no runs.
+ * derive.c (_store_derive): Let BSIZE be zero.
+
+1997-07-21 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * argp.c (store_parsed_append_args): Correctly unparse complex
+ type names.
+
+1997-07-18 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * map.c (store_map): If we can't map STORE directly, and it has a
+ source file, try to map that instead.
+ * remap.c (store_remap): If we are mutating SOURCE, close any
+ source port it has.
+ * store.h (store_map_source): Declaration removed.
+
+1997-07-17 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * store.h (store_map): New declaration.
+ (struct store_class): Add map field.
+ * device.c (dev_map): New function.
+ (store_device_class): Use dev_map.
+ * zero.c (zero_map): New function.
+ (store_zero_class): Use zero_map.
+ * file.c (file_map): New function.
+ (store_file_class): Use file_map.
+ * map.c: New file.
+ * Makefile (SRCS): Add map.c.
+
+ * device.c (dev_read, dev_write): Remove debugging grot.
+
+1997-07-07 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * kids.c (store_open_children): Support factored type notation.
+
+1997-07-05 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * file.c (file_read, file_write, file_byte_read, file_byte_write):
+ Remove debugging noise.
+
+1997-06-30 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * store.h: Doc fix.
+
+1997-06-27 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * file.c (store_file_open): Use fiopen to open the file.
+ Set name of newly created store.
+ (fiopen, ficlose, enforced, file_set_flags, file_clear_flags): New
+ functions.
+ (store_file_class): Use new functions.
+ (store_file_byte_class): Fill in rest of functions.
+ * device.c (enforced): Move some checking here from dev_set_flags,
+ and correct the check for the number of stores.
+ (dev_set_flags): Move enforcement checking code to enforce.
+
+1997-06-26 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * argp.c (parse_type): Fill in name_prefix field.
+ (store_parsed_open): Apply it to any names we open.
+
+1997-06-22 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * argp.c (parse_type): New function.
+ (parse_opt): Use parse_type to parse the -T option.
+ (struct store_parsed): Add NAME_PREFIX field.
+ (store_parsed_free): Free it.
+ (store_parsed_append_args): Emit it.
+ (store_parsed_open): Use it in opens.
+
+ * typed.c (store_typed_open): If NAME doesn't contain a `:'
+ separator, try to use it as either a class name or a file name.
+ Interpret a trailing or leading `:' as unambiguously referring to
+ a class-name or a filename, respectively.
+
+1997-06-19 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * rdwr.c (store_read): Limit reads to the amount available.
+
+ * store.h (store_typed_open_class): Renamed from store_typed_class.
+ * std.c (store_std_classes): Use store_typed_open_class instead of
+ store_typed_class.
+
+ * Makefile (SRCS): Remove storeread.c & storecat.c.
+ (storeread, storecat): Rules removed.
+ * storeread.c, storecat.c: Moved to ../utils.
+
+1997-06-18 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * store.h (struct store): BLOCKS & SIZE are off_t, not size_t.
+ (store_zero_create): SIZE is off_t, not size_t.
+ * zero.c (store_zero_create, zero_open): Likewise.
+
+ * storecat.c (main): Update use of argp.
+ * storeread.c (main): DATA is void *.
+
+ * Makefile (UTILS_OBJS): Variable removed.
+ (UNZIP_OBJS): New variable.
+ (OBJS): Don't use $(UTILS_OBJS). Do use $(UNZIP_OBJS).
+ (VPATH, CPPFLAGS): Search for stuff in ../exec for unzip junk.
+
+ * derive.c: Include <assert.h>
+ (_store_derive): Assert that block_size & blocks_per_page are
+ powers of two (which should be enforced elsewhere).
+
+ * make.c (_store_create): Renamed from _make_store.
+ Return an error_t code, and add an additional argument STORE to
+ return the new store; all uses changed.
+ * store.h (_make_store): Likewise.
+
+ * Makefile (SRCS): Add typed.c, copy.c, and gunzip.c.
+
+ * typed.c: New file
+ * store.h (store_gunzip_class, store_typed_class): New declarations.
+ * std.c (store_std_classes): Add store_copy_class,
+ store_gunzip_class, and store_typed_class.
+
+ * kids.c (store_open_children, store_children_name): New functions.
+ * stripe.c (store_concat_open): New function.
+ (store_concat_create): Set the store name if possible.
+ * store.h (store_concat_open, store_children_name,
+ store_open_children): New declaration.
+ * rdwr.c (store_read): Deallocate memory returned when reading
+ part of a multiple-segment read.
+
+1997-06-17 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * copy.c, gunzip.c: New files.
+ * store.h (store_copy_class): New declaration.
+ (store_copy_create, store_copy_open, store_buffer_create,
+ store_gunzip_create, store_gunzip_open): New declarations.
+
+ * decode.c (store_decode): Pass the original value of CLASSES to
+ any decode method, not our search tail.
+
+ * device.c (dopen): If *MOD_FLAGS already contains
+ STORE_HARD_READONLY, don't ever try to open for reading.
+
+Fri Feb 21 23:31:34 1997 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * device.c (dopen): Add MOD_FLAGS param, and detect read-only devices.
+ (dev_clear_flags, store_device_open): Use MOD_FLAGS arg to dopen.
+
+Wed Feb 19 15:40:18 1997 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * storeread.c (doc): Make doc string come after options.
+
+ * device.c (dev_set_flags): Correctly check for unenforcable runs.
+
+ * task.c: New file.
+ * Makefile (SRCS): Add task.c.
+ * store.h (store_task_class): New declaration.
+ (store_task_create, _store_task_create, store_open): New declarations.
+ * std.c (store_std_classes): Add &STORE_TASK_CLASS.
+
+ * xinl.c: Renamed from store.c.
+ * Makefile (SRCS): Change store.c to xinl.c.
+
+Mon Oct 21 22:03:19 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu>
+
+ * store.h: Add extern inline protection.
+ * store.c: New file.
+ * Makefile (SRCS): Add store.c.
+
+Tue Oct 8 14:31:51 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * kids.c (store_set_child_flags, store_clear_child_flags): New funcs.
+ * store.h (store_set_child_flags, store_clear_child_flags): New decls.
+ * stripe.c (stripe_set_flags, stripe_clear_flags): Remove functions.
+ * remap.c (store_remap_class): Init set_flags & clear_flags fields.
+ * stripe.c (store_ileave_class, store_concat_class): Likewise.
+
+ * clone.c (store_clone): Copy name field.
+
+Mon Oct 7 14:56:27 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * device.c (dev_set_flags, dev_clear_flags): New functions.
+ (store_device_class): Add dev_set_flags & dev_clear_flags.
+ (dopen, dclose, enforced): New functions.
+ (store_device_open): Use dopen.
+ * store.h <fcntl.h>: New include.
+ * stripe.c (stripe_set_flags, stripe_clear_flags): New functions.
+ (store_ileave_create, store_concat_create): Add common backend
+ flags from children to parent's flags.
+
+Sat Oct 5 00:23:45 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * create.c (store_create): Add special handling of STORE_INACTIVE
+ in FLAGS.
+
+Fri Oct 4 23:44:51 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * create.c (store_create): Free *STORE when store_set_flags fails.
+
+ * store.h (STORE_INNOCUOUS, STORE_INACTIVE): New macros.
+ (store_is_securely_returnable): New function.
+ * zero.c (store_zero_create): Set STORE_INNOCUOUS flags.
+
+Fri Sep 27 17:01:07 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * remap.c (store_remap): Zero SOURCE->end before calling _store_derive.
+ Turn off STORE_ENFORCED flag in source if munging it.
+
+ * device.c (store_device_open): Set *STORE's name appropriately.
+
+Tue Sep 24 15:15:27 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * zero.c <limits.h>: New include.
+ (zero_open): When no size is specified, use the maximum off_t
+ value, not the maximum size_t value.
+
+Mon Sep 23 12:55:43 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * storecat.c (main): Use new PARAMS var for passing args to STORE_ARGP.
+
+Thu Sep 19 11:12:44 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * argp.c (parse_opt): Correctly check for non-default type.
+
+ * kids.c (store_decode_children): Change CLASSES to **.
+ * encode.c (store_encode): Make CLASS var const.
+ * file.c (_store_file_create): Make CLASS arg const.
+ * store.h (struct store): Make CLASS field const.
+ (_make_store): Make CLASS arg const.
+ * make.c (_make_store): Make CLASS arg const.
+ * stripe.c (ileave_decode, concat_decode): Make CLASSES arg const.
+ * remap.c (remap_decode): Likewise.
+ * create.c (store_create): Likewise.
+
+Wed Sep 18 15:14:51 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * argp.c (struct store_parsed): Change CLASSES field to be a pointer to
+ a vector of class pointers.
+ (find_class): Change CLASSES to be a vector of class pointers.
+ * decode.c (store_decode): Change CLASSES to be a vector of class
+ pointers.
+ * store.h (struct store_class, struct store_argp_params, store_create,
+ store_open, store_decode, store_decode_children): Change CLASSES args
+ to be a pointer to a vector of class pointers.
+ (_store_add_std_class): Declaration removed.
+ (STORE_STD_CLASS): Macro removed.
+ * std.c (store_std_classes): Make an initialized array.
+ (_store_add_std_class): Function removed.
+ * device.c (store_device_class): Renamed from dev_class; export.
+ * file.c (store_file_class): Renamed from file_class; export.
+ (store_file_byte_class): Renamed from file_byte_class; export.
+ * zero.c (store_zero_class): Renamed from zero_class; export.
+ * remap.c (store_remap_class): Renamed from remap_class; export.
+ * open.c (store_query_class): Renamed from query_class; export.
+ * stripe.c (store_ileave_class): Renamed from ileave_class; export.
+ (store_concat_class): Renamed from concat_class; export.
+
+ * zero.c (zero_open, zero_validate_name): New functions.
+ (zero_class): Use them.
+
+ * argp.c (store_parsed_open): Remove CLASSES argument.
+ (struct store_parsed): Make some fields const.
+ * store.h (store_parsed_open): Remove CLASSES argument.
+
+Tue Sep 17 14:48:48 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * store.h (struct store_class): Add OPEN and PARSE fields.
+ (store_open): Make NAME const.
+ (struct store_argp_params): New type.
+ * device.c (dev_open): New function.
+ (dev_class): Point to it.
+ * file.c (fhile_open): New function.
+ (file_class): Point to it.
+ * argp.c (options, parse_opt): Add --store-type/-T & (hidden)
+ --machdev/-m options, remove --device/-d option.
+ (struct store_parsed): Rmove DEVICE field, add TYPE, DEFAULT_TYPE
+ and CLASSES fields.
+ (store_parsed_free): Free PARSED->type if it exists.
+ (store_parsed_append_args): Use --store-type=... instead of --device.
+ (store_parsed_open): When --store-type is specified, search
+ CLASSES for that type, and call it's open function.
+ * open.c (store_open): Make NAME const.
+ (query_class): New variable.
+
+Fri Sep 13 14:33:24 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * argp.c (store_parsed_append_args, store_parsed_open, struct
+ store_parsed): Use `device' instead of `machdev'.
+
+ * encode.c (store_return): Only call store_enc_dealloc upon failure.
+ (store_std_leaf_allocate_encoding): NUM_OFFSETS is NUM_RUNS * 2.
+
+ * enc.c (store_enc_return): Don't call store_enc_dealloc.
+
+Thu Sep 12 17:23:35 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * storecat.c (main): Limit reads to 1M, and iterate until done.
+ Use store_parsed_name to get store name for errors.
+ Add program description.
+
+ * store.h (STORAGE_REMAP, STORAGE_ZERO): New macros (temporary, to
+ avoid touching hurd/hurd_types.h).
+
+1996-09-12 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * remap.c (store_remap): Call _store_derive after changing runs.
+
+ * argp.c (store_parsed_name): New function.
+
+Wed Sep 11 12:38:44 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * decode.c (store_with_decoded_runs): New function.
+ (store_std_leaf_decode): Call it.
+ * store.h (store_with_decoded_runs): New declaration.
+
+ * stripe.c (ileave_class, concat_class): Initialize the REMAP field.
+ (stripe_remap): New function.
+ * store.h (store_remap_create): New declaration.
+ * zero.c (zero_remap): New function.
+ (zero_class): Initialize remap field with zero_remap.
+ * Makefile (SRCS): Add remap.c.
+
+ * zero.c: New file, from null.c.
+ * null.c: File removed.
+ * store.h (store_zero_create): Renamed from store_null_create.
+ * Makefile (SRCS): Replace null.c by zero.c.
+
+Tue Sep 10 17:05:03 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * remap.c: New file.
+ * store.h (struct store_class): Add remap field.
+ (store_remap): New declaration.
+
+ * encode.c (store_return): New function.
+ * enc.c (store_enc_return, store_return): New functions.
+ * store.h (store_enc_return, store_return): New declarations.
+
+Mon Sep 9 12:32:11 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * rdwr.c (store_write, store_read): Use void * for buffers, not char *.
+ * device.c (dev_write, dev_read): Likewise.
+ * file.c (file_read, file_write, file_byte_read, file_byte_write):
+ Likewise.
+ * stripe.c (stripe_read, stripe_write): Likewise.
+ * null.c (null_read, null_write): Likewise.
+ * store.h (store_write_meth_t, store_read_meth_t, store_read,
+ store_write): Make type of buffer void *, not char *.
+
+Sun Sep 8 14:14:05 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * device.c (dev_read, dev_write): Don't print debugging messages.
+ * argp.c (options, parse_opt): Change short option names around.
+
+Wed Sep 4 13:01:19 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * argp.c (parse_opt): --layer isn't implemented, so say so.
+
+ * storeread.c (main): Add new args to store_*_create calls.
+ * storecat.c (main): Use new interface to store_argp.
+
+Wed Sep 3 11:00:00 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * argp.c (struct store_parsed): New type.
+ (store_parsed_free, store_parsed_append_args, store_parsed_open):
+ New functions.
+ (parse_opt): Use new store_parsed structure instead of the old
+ store_pars_hook, and just fill in the names rather than doing the
+ open here. Don't take a struct store_argp_params as input any
+ more; instead just take the address of a location in which to
+ return a store_parsed structure.
+ (struct store_parse_hook): Type removed.
+ (free_hook, open_file): Functions removed.
+ <assert.h>: New include.
+ <stdlib.h>, <fcntl.h>: Includes removed.
+ (options): --machdev/-m renamed to --device/-D.
+ * store.h (struct store): Make log2_* fields unsigned.
+ (STORE_NO_FILEIO): New macro.
+ (STORE_HARD_READONLY, STORE_ENFORCED): Values changed.
+ (STORE_GENERIC_FLAGS): Add STORE_NO_FILEIO.
+ (struct store_argp_params): Type removed.
+ (store_parsed_Free, store_parsed_open, store_parsed_append_args):
+ New declarations.
+ (struct store_parsed): New incomplete type.
+
+Mon Sep 2 18:56:26 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * store.h (store_open): New declaration.
+ * open.c: New file.
+ * Makefile (SRCS): Add open.c.
+
+Wed Aug 21 14:40:15 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * device.c (store_device_open): Don't call store_device_create if
+ device_open fails.
+
+Tue Aug 20 14:37:33 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * argp.c (free_hook): Free H->params->args if necessary.
+ (parse_opt): Initialize and fill in H->params->args when appropriate.
+ <argz.h>: New include.
+
+Mon Aug 19 14:31:33 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * store.h (struct store_argp_params): Add return_args, args, &
+ args_len fields.
+
+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
new file mode 100644
index 00000000..35f74fdc
--- /dev/null
+++ b/libstore/Makefile
@@ -0,0 +1,40 @@
+# Makefile for libstore
+#
+# Copyright (C) 1995, 1996, 1997 Free Software Foundation
+# 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.
+
+dir := libstore
+makemode := library
+
+libname = libstore
+SRCS = create.c derive.c make.c rdwr.c set.c device.c file.c stripe.c \
+ enc.c encode.c decode.c clone.c argp.c std.c kids.c zero.c flags.c \
+ open.c remap.c xinl.c task.c typed.c copy.c gunzip.c map.c mvol.c \
+ bunzip2.c
+LCLHDRS=store.h
+installhdrs=store.h
+
+UNZIP_OBJS = unzip.o inflate.o util.o do-bunzip2.o
+OBJS = $(SRCS:.c=.o) $(UNZIP_OBJS)
+
+# Look for zip stuff
+VPATH += $(srcdir)/../exec
+CPPFLAGS += -I$(srcdir)/../exec
+
+include ../Makeconf
diff --git a/libstore/argp.c b/libstore/argp.c
new file mode 100644
index 00000000..97640e19
--- /dev/null
+++ b/libstore/argp.c
@@ -0,0 +1,379 @@
+/* Store argument parsing
+
+ Copyright (C) 1996, 1997, 1998, 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
+ 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 <string.h>
+#include <assert.h>
+#include <hurd.h>
+#include <argp.h>
+#include <argz.h>
+
+#include "store.h"
+
+#define DEFAULT_STORE_TYPE "query"
+
+static const struct argp_option options[] = {
+ {"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[] = "\vIf neither --interleave or --layer is specified,"
+" multiple DEVICEs are concatenated.";
+
+struct store_parsed
+{
+ /* Names of devices parsed. */
+ char *names;
+ size_t names_len;
+
+ /* Prefix that should be applied to each member of NAMES. */
+ char *name_prefix;
+
+ /* --store-type specified. This defaults to the `query' type. */
+ const struct store_class *type;
+
+ /* 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;
+
+ off_t interleave; /* --interleave value */
+ int layer : 1; /* --layer specified */
+};
+
+void
+store_parsed_free (struct store_parsed *parsed)
+{
+ if (parsed->names_len > 0)
+ free (parsed->names);
+ if (parsed->name_prefix)
+ free (parsed->name_prefix);
+ free (parsed);
+}
+
+/* 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)
+{
+ char buf[40];
+ error_t err = 0;
+ size_t num_names = argz_count (parsed->names, parsed->names_len);
+
+ 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);
+ }
+
+ if (!err && parsed->type != parsed->default_type)
+ {
+ 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;
+}
+
+error_t
+store_parsed_name (const struct store_parsed *parsed, char **name)
+{
+ 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;
+
+ 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 *classes)
+{
+ while (*classes)
+ if ((*classes)->name && strcmp (name, (*classes)->name) == 0)
+ return *classes;
+ else
+ classes++;
+ 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)
+
+/* 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. */
+ {
+ 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':
+ arg = "device";
+ /* fall through */
+ case 'T':
+ return parse_type (arg, state, parsed);
+
+ case 'I':
+ if (parsed->layer)
+ PERR (EINVAL, "--layer and --interleave are exclusive");
+ if (parsed->interleave)
+ /* Actually no reason why we couldn't support this.... */
+ PERR (EINVAL, "--interleave specified multiple times");
+
+ parsed->interleave = atoi (arg);
+ if (! parsed->interleave)
+ PERR (EINVAL, "%s: Bad value for --interleave", arg);
+ break;
+
+ 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");
+ parsed->layer = 1;
+#endif
+ break;
+
+ case ARGP_KEY_ARG:
+ /* A store device to use! */
+ if (parsed->type->validate_name)
+ err = (*parsed->type->validate_name) (arg, parsed->classes);
+ else
+ err = 0;
+ if (! err)
+ err = argz_add (&parsed->names, &parsed->names_len, arg);
+ if (err)
+ argp_failure (state, 1, err, "%s", arg);
+ return err;
+ break;
+
+ case ARGP_KEY_INIT:
+ /* Initialize our parsing state. */
+ {
+ 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 ?: store_std_classes;
+ parsed->default_type =
+ find_class (params->default_type ?: DEFAULT_STORE_TYPE,
+ 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. */
+ store_parsed_free (parsed); break;
+
+ case ARGP_KEY_SUCCESS:
+ /* Successfully finished parsing, return a result. */
+ if (parsed->names == 0
+ && (!parsed->type->validate_name
+ || (*parsed->type->validate_name) (0, parsed->classes) != 0))
+ {
+ store_parsed_free (parsed);
+ PERR (EINVAL, "No store specified");
+ }
+ else
+ ((struct store_argp_params *)state->input)->result = parsed;
+ break;
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+
+ return 0;
+}
+
+struct argp
+store_argp = { options, parse_opt, args_doc, doc };
diff --git a/libstore/bunzip2.c b/libstore/bunzip2.c
new file mode 100644
index 00000000..e1ec5808
--- /dev/null
+++ b/libstore/bunzip2.c
@@ -0,0 +1,259 @@
+/* Decompressing store backend
+
+ Copyright (C) 1998, 1999 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"
+
+extern void do_bunzip2 (void); /* Entry point to bunzip2 engine. */
+
+
+#define IN_BUFFERING (256*1024)
+#define OUT_BUFFERING (512*1024)
+
+static struct mutex bunzip2_lock = MUTEX_INITIALIZER;
+
+/* 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
+bunzip2 (struct store *from, void **buf, size_t *buf_len)
+{
+ /* Callbacks from bunzip2 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;
+ 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_len > 0)
+ munmap (in_buf, in_buf_len);
+ in_buf = new_in_buf;
+ 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 (&bunzip2_lock);
+
+ unzip_read = zread;
+ unzip_write = zwrite;
+ unzip_read_error = zreaderr;
+ unzip_error = zerror;
+
+ if (! setjmp (zerr_jmp_buf))
+ {
+ /* Call the bunzip2 engine. */
+ do_bunzip2 ();
+ zerr = 0;
+ }
+
+ mutex_unlock (&bunzip2_lock);
+
+ if (in_buf_len > 0)
+ munmap (in_buf, in_buf_len);
+
+ 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_bunzip2_create (struct store *from, int flags, struct store **store)
+{
+ void *buf;
+ size_t buf_len;
+ error_t err = bunzip2 (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 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 used to select classes specified by the type
+ name; if it is 0, STORE_STD_CLASSES is used. */
+error_t
+store_bunzip2_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_bunzip2_create (from, flags, store);
+ if (err)
+ store_free (from);
+ }
+
+ return err;
+}
+
+struct store_class
+store_bunzip2_class = { -1, "bunzip2", open: store_bunzip2_open };
diff --git a/libstore/clone.c b/libstore/clone.c
new file mode 100644
index 00000000..cdbd5747
--- /dev/null
+++ b/libstore/clone.c
@@ -0,0 +1,91 @@
+/* Store cloning
+
+ 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
+ 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 <string.h>
+#include <stdlib.h>
+
+#include "store.h"
+
+/* Return in TO a copy of FROM. */
+error_t
+store_clone (struct store *from, struct store **to)
+{
+ 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 (from->name)
+ {
+ c->name = strdup (from->name);
+ if (! c->name)
+ err = ENOMEM;
+ }
+
+ if (from->misc_len)
+ {
+ c->misc = malloc (from->misc_len);
+ if (! c->misc)
+ err = ENOMEM;
+ }
+
+ if (!err && c->port != MACH_PORT_NULL)
+ {
+ err = mach_port_mod_refs (mach_task_self (),
+ c->port, MACH_PORT_RIGHT_SEND, 1);
+ if (err)
+ c->port = MACH_PORT_NULL; /* Don't deallocate it. */
+ }
+ if (!err && from->source != MACH_PORT_NULL)
+ {
+ err = mach_port_mod_refs (mach_task_self (),
+ from->source, MACH_PORT_RIGHT_SEND, 1);
+ if (! err)
+ c->source = from->source;
+ }
+ if (!err && from->num_children > 0)
+ {
+ int k;
+
+ c->children = malloc (from->num_children * sizeof (struct store *));
+ if (! c->children)
+ err = ENOMEM;
+
+ for (k = 0; !err && k < from->num_children; k++)
+ {
+ err = store_clone (from->children[k], &c->children[k]);
+ if (! err)
+ c->num_children++;
+ }
+ }
+
+ if (!err && from->class->clone)
+ err = (*from->class->clone)(from, c);
+
+ if (err)
+ store_free (c);
+ else
+ *to = c;
+
+ return err;
+}
diff --git a/libstore/copy.c b/libstore/copy.c
new file mode 100644
index 00000000..3f838e5c
--- /dev/null
+++ b/libstore/copy.c
@@ -0,0 +1,241 @@
+/* Copy store backend
+
+ Copyright (C) 1995, 1996, 1997, 1999 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ This task 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 "store.h"
+
+static error_t
+copy_read (struct store *store,
+ off_t addr, size_t index, size_t amount, void **buf, size_t *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 == (void *)-1)
+ return errno;
+ }
+
+ bcopy (store->hook + (addr * store->block_size), *buf, amount);
+ *len = amount;
+ return 0;
+}
+
+static error_t
+copy_write (struct store *store,
+ off_t addr, size_t index, void *buf, size_t len, size_t *amount)
+{
+ bcopy (buf, store->hook + (addr * store->block_size), len);
+ *amount = len;
+ return 0;
+}
+
+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;
+ bcopy (from->hook, to->hook, from->size);
+ return 0;
+ }
+ return errno;
+}
+
+struct store_class
+store_copy_class =
+{
+ STORAGE_COPY, "copy", copy_read, copy_write,
+ copy_allocate_encoding, copy_encode, copy_decode,
+ copy_set_flags, copy_clear_flags, copy_cleanup, copy_clone, 0, copy_open
+};
+
+/* 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
new file mode 100644
index 00000000..71a4c62e
--- /dev/null
+++ b/libstore/create.c
@@ -0,0 +1,76 @@
+/* Store creation
+
+ 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
+ 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/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, 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)
+{
+ error_t err;
+ struct store_enc enc;
+ mach_port_t inline_ports[10];
+ int inline_ints[60];
+ off_t inline_offsets[60];
+ char inline_data[100];
+
+ store_enc_init (&enc, inline_ports, 10, inline_ints, 60,
+ inline_offsets, 60, inline_data, 100);
+
+ err = file_get_storage_info (source,
+ &enc.ports, &enc.num_ports,
+ &enc.ints, &enc.num_ints,
+ &enc.offsets, &enc.num_offsets,
+ &enc.data, &enc.data_len);
+ if (err)
+ return err;
+
+ err = store_decode (&enc, classes, store);
+ 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);
+ }
+
+ store_enc_dealloc (&enc);
+
+ if (! err)
+ /* Keep a reference to SOURCE around. */
+ (*store)->source = source;
+
+ return err;
+}
diff --git a/libstore/decode.c b/libstore/decode.c
new file mode 100644
index 00000000..33e99492
--- /dev/null
+++ b/libstore/decode.c
@@ -0,0 +1,180 @@
+/* Store wire decoding
+
+ 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
+ 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 <string.h>
+#include <malloc.h>
+
+#include "store.h"
+
+/* The maximum number of runs for which we allocate run vectors on the stack. */
+#define MAX_STACK_RUNS (16*1024 / sizeof (struct store_run))
+
+/* Decodes the standard leaf encoding that's common to various builtin
+ formats, and calls CREATE to actually create the store. */
+error_t
+store_std_leaf_decode (struct store_enc *enc,
+ store_std_leaf_create_t create,
+ struct store **store)
+{
+ char *misc, *name;
+ error_t err;
+ 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;
+
+ /* Read encoded ints. */
+ type = enc->ints[enc->cur_int++];
+ flags = enc->ints[enc->cur_int++];
+ block_size = enc->ints[enc->cur_int++];
+ num_runs = enc->ints[enc->cur_int++];
+ name_len = enc->ints[enc->cur_int++];
+ misc_len = enc->ints[enc->cur_int++];
+
+ /* Make sure there are enough encoded offsets and data. */
+ if (enc->cur_offset + num_runs * 2 > enc->num_offsets
+ || enc->cur_data + name_len + misc_len > enc->data_len)
+ return EINVAL;
+
+ 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)
+ {
+ free (misc);
+ return ENOMEM;
+ }
+ }
+ else
+ name = 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);
+ 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. */
+ if (num_runs <= MAX_STACK_RUNS)
+ {
+ struct store_run runs[num_runs];
+ off_t *e = enc->offsets + enc->cur_offset;
+ for (i = 0; i < num_runs; i++)
+ {
+ runs[i].start = *e++;
+ runs[i].length = *e++;
+ }
+ 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.
+ This will probably never happen. */
+ {
+ struct store_run *runs = malloc (num_runs * sizeof (struct store_run));
+ if (runs)
+ {
+ off_t *e = enc->offsets + enc->cur_offset;
+ for (i = 0; i < num_runs; i++)
+ {
+ runs[i].start = *e++;
+ runs[i].length = *e++;
+ }
+ enc->cur_offset = e - enc->offsets;
+ err = (*fun) (runs, num_runs);
+ free (runs);
+ }
+ else
+ err = ENOMEM;
+ }
+
+ return err;
+}
+
+/* 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, 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;
+
+ for (cl = classes; *classes; cl ++)
+ if ((*cl)->id == enc->ints[enc->cur_int])
+ {
+ if ((*cl)->decode)
+ return (*(*cl)->decode) (enc, classes, store);
+ else
+ return EOPNOTSUPP;
+ }
+
+ return EINVAL;
+}
diff --git a/libstore/derive.c b/libstore/derive.c
new file mode 100644
index 00000000..8c0b2790
--- /dev/null
+++ b/libstore/derive.c
@@ -0,0 +1,84 @@
+/* Calculation of various derived store fields
+
+ 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
+ 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 <assert.h>
+
+#include "store.h"
+
+/* 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)
+{
+ unsigned i;
+ struct store_run *runs = store->runs;
+ unsigned num_runs = store->num_runs;
+ size_t bsize = store->block_size;
+
+ /* BLOCK & SIZE */
+ store->blocks = 0;
+
+ for (i = 0; i < num_runs; i++)
+ {
+ store->wrap_src += runs[i].length;
+ if (runs[i].start >= 0) /* Not a hole */
+ store->blocks += runs[i].length;
+ }
+
+ if (store->end == 0)
+ /* END not set; set it using the info from RUNS. */
+ store->end = store->wrap_src;
+ else if (store->wrap_src < store->end)
+ /* A wrapped disk! RUNS is repeated N times to reach END. Adjust BLOCKS
+ to include all iterations. */
+ {
+ size_t num_iters = store->end / store->wrap_src;
+ off_t last_part_base = num_iters * store->wrap_src;
+
+ store->blocks *= num_iters;
+
+ for (i = 0; i < num_runs; i++)
+ if (last_part_base + runs[i].length < store->end)
+ {
+ store->blocks += store->end - (last_part_base + runs[i].length);
+ break;
+ }
+ else if (runs[i].start >= 0)
+ store->blocks += runs[i].length;
+
+ /* WRAP_DST must be set by the caller. */
+ }
+
+ store->size = store->end * bsize;
+
+ store->log2_block_size = 0;
+ 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
new file mode 100644
index 00000000..986ca25b
--- /dev/null
+++ b/libstore/device.c
@@ -0,0 +1,280 @@
+/* Mach device store backend
+
+ Copyright (C) 1995,96,97,99 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 <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <hurd.h>
+
+#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:
+ }
+ /* 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,
+ 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, void *buf, mach_msg_type_number_t len,
+ mach_msg_type_number_t *amount)
+{
+ return dev_error (device_write (store->port, 0, addr,
+ (io_buf_ptr_t)buf, len, amount));
+}
+
+static error_t
+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 error_t
+dev_open (const char *name, int flags,
+ const struct store_class *const *classes,
+ struct store **store)
+{
+ 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)
+{
+ 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. */
+ {
+ size_t sizes[DEV_GET_SIZE_COUNT];
+ size_t sizes_len = DEV_GET_SIZE_COUNT;
+ error_t 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
+ {
+ /* We pass in 0 for the OFFSET and SIZE argument because in many cases
+ we can't supply them (devices that can't otherwise do I/O are often
+ still mappable) and mach ignores them entirely. XXXX */
+ error_t err = device_map (store->port, prot, 0, 0, memobj, 0);
+ if (err == ED_INVALID_OPERATION)
+ err = EOPNOTSUPP; /* This device doesn't support paging. */
+ return err;
+ }
+}
+
+struct store_class
+store_device_class =
+{
+ STORAGE_DEVICE, "device", dev_read, dev_write,
+ 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
+};
+
+/* 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)
+{
+ struct store_run run;
+ size_t block_size = 0;
+ size_t sizes[DEV_STATUS_MAX];
+ size_t sizes_len = DEV_STATUS_MAX;
+ error_t err;
+
+ /* 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. */
+ 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];
+
+ 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. */
+
+ 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. */
+error_t
+_store_device_create (device_t device, int flags, size_t block_size,
+ const struct store_run *runs, size_t num_runs,
+ struct store **store)
+{
+ 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 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
new file mode 100644
index 00000000..d5002a0e
--- /dev/null
+++ b/libstore/enc.c
@@ -0,0 +1,98 @@
+/* Store wire encoding/decoding
+
+ 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
+ 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 <string.h>
+#include <sys/mman.h>
+
+#include "store.h"
+
+/* Initialize ENC. The given vector and sizes will be used for the encoding
+ if they are big enough (otherwise new ones will be automatically
+ allocated). */
+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,
+ char *data, mach_msg_type_number_t data_len)
+{
+ bzero (enc, sizeof (*enc));
+
+ enc->ports = enc->init_ports = ports;
+ enc->num_ports = num_ports;
+ enc->ints = enc->init_ints = ints;
+ enc->num_ints = num_ints;
+ enc->offsets = enc->init_offsets = offsets;
+ enc->num_offsets = num_offsets;
+ enc->data = enc->init_data = data;
+ enc->data_len = 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)
+{
+ if (enc->ports && enc->num_ports > 0)
+ /* For ports, we must deallocate each port as well. */
+ {
+ while (enc->cur_port < enc->num_ports)
+ {
+ mach_port_t port = enc->ports[enc->cur_port++];
+ if (port != MACH_PORT_NULL)
+ mach_port_deallocate (mach_task_self (), port);
+ }
+
+ if (enc->ports != enc->init_ports)
+ munmap ((caddr_t) enc->ports, enc->num_ports * sizeof (*enc->ports));
+ }
+
+ if (enc->ints && enc->num_ints > 0 && enc->ints != enc->init_ints)
+ munmap ((caddr_t) enc->ints, enc->num_ints * sizeof (*enc->ints));
+
+ if (enc->offsets && enc->num_offsets > 0
+ && enc->offsets != enc->init_offsets)
+ munmap ((caddr_t) enc->offsets, enc->num_offsets * sizeof (*enc->offsets));
+
+ if (enc->data && enc->data_len > 0 && enc->data != enc->init_data)
+ 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
new file mode 100644
index 00000000..48c5d26a
--- /dev/null
+++ b/libstore/encode.c
@@ -0,0 +1,167 @@
+/* Store wire encoding
+
+ 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
+ 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 <string.h>
+#include <sys/mman.h>
+
+#include "store.h"
+
+/* Standard encoding used for most leaf store types. */
+
+error_t
+store_std_leaf_allocate_encoding (const struct store *store,
+ struct store_enc *enc)
+{
+ enc->num_ports++;
+ enc->num_ints += 6;
+ 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;
+}
+
+error_t
+store_std_leaf_encode (const struct store *store, struct store_enc *enc)
+{
+ int i;
+ size_t name_len = (store->name ? strlen (store->name) + 1 : 0);
+
+ enc->ports[enc->cur_port++] = store->port;
+
+ enc->ints[enc->cur_int++] = store->class->id;
+ enc->ints[enc->cur_int++] = store->flags;
+ enc->ints[enc->cur_int++] = store->block_size;
+ enc->ints[enc->cur_int++] = store->num_runs;
+ enc->ints[enc->cur_int++] = name_len;
+ enc->ints[enc->cur_int++] = store->misc_len;
+
+ 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;
+ }
+
+ if (store->name)
+ {
+ bcopy (store->name, enc->data + enc->cur_data, name_len);
+ enc->cur_data += name_len;
+ }
+ if (store->misc_len)
+ {
+ bcopy (store->misc, enc->data + enc->cur_data, store->misc_len);
+ enc->cur_data += store->misc_len;
+ }
+
+ return 0;
+}
+
+/* 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
+ can't be done, store_enc_dealloc may be used to deallocate the mmemory
+ used by the unsent vectors. */
+error_t
+store_encode (const struct store *store, struct store_enc *enc)
+{
+ void *buf;
+ error_t err;
+ 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;
+ mach_msg_type_number_t init_num_ints = enc->num_ints;
+ mach_msg_type_number_t init_num_offsets = enc->num_offsets;
+ mach_msg_type_number_t init_data_len = enc->data_len;
+
+ if (!class->allocate_encoding || !class->encode)
+ return EOPNOTSUPP;
+
+ enc->num_ports = 0;
+ enc->num_ints = 0;
+ enc->num_offsets = 0;
+ enc->data_len = 0;
+ err = (*class->allocate_encoding) (store, enc);
+ if (err)
+ return err;
+
+ errno = 0;
+ if (enc->num_ports > init_num_ports)
+ {
+ 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);
+
+ enc->cur_port = enc->cur_int = enc->cur_offset = enc->cur_data = 0;
+
+ if (err)
+ store_enc_dealloc (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
new file mode 100644
index 00000000..e952a91e
--- /dev/null
+++ b/libstore/file.c
@@ -0,0 +1,275 @@
+/* File store backend
+
+ Copyright (C) 1995, 96, 97, 98 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 <fcntl.h>
+#include <hurd.h>
+
+#include <hurd/io.h>
+
+#include "store.h"
+
+static error_t
+file_read (struct store *store,
+ off_t addr, size_t index, size_t amount, void **buf, size_t *len)
+{
+ size_t bsize = store->block_size;
+ 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, void *buf, size_t len, size_t *amount)
+{
+ size_t bsize = store->block_size;
+ return io_write (store->port, buf, len, addr * bsize, amount);
+}
+
+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 error_t
+file_open (const char *name, int flags,
+ const struct store_class *const *classes,
+ struct store **store)
+{
+ return store_file_open (name, flags, store);
+}
+
+static error_t
+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;
+}
+
+/* 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_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)
+ 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)
+ 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
+ {
+ 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;
+}
+
+struct store_class
+store_file_class =
+{
+ STORAGE_HURD_FILE, "file", file_read, file_write,
+ 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
+};
+
+static error_t
+file_byte_read (struct store *store,
+ off_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, void *buf, size_t len,
+ size_t *amount)
+{
+ return io_write (store->port, buf, len, addr, amount);
+}
+
+struct store_class
+store_file_byte_class =
+{
+ STORAGE_HURD_FILE, "file", file_byte_read, file_byte_write,
+ 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. */
+error_t
+store_file_create (file_t file, int flags, struct store **store)
+{
+ struct store_run run;
+ struct stat stat;
+ error_t err = io_stat (file, &stat);
+
+ if (err)
+ return err;
+
+ run.start = 0;
+ run.length = stat.st_size;
+
+ flags |= STORE_ENFORCED; /* 'cause it's the whole file. */
+
+ return _store_file_create (file, flags, 1, &run, 1, store);
+}
+
+/* Like store_file_create, but doesn't query the file for information. */
+error_t
+_store_file_create (file_t file, int flags, size_t block_size,
+ const struct store_run *runs, size_t num_runs,
+ struct store **store)
+{
+ if (block_size == 1)
+ return _store_create (&store_file_byte_class,
+ file, flags, 1, runs, num_runs, 0, store);
+ else
+ 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)
+{
+ 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
new file mode 100644
index 00000000..d80181ac
--- /dev/null
+++ b/libstore/flags.c
@@ -0,0 +1,66 @@
+/* Setting various store flags
+
+ 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
+ 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 <malloc.h>
+#include <string.h>
+
+#include "store.h"
+
+/* Add FLAGS to STORE's currently set flags. */
+error_t
+store_set_flags (struct store *store, int flags)
+{
+ error_t err = 0;
+ 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 (! err)
+ store->flags |= (new & ~STORE_BACKEND_FLAGS);
+
+ return err;
+}
+
+/* Remove FLAGS from STORE's currently set flags. */
+error_t
+store_clear_flags (struct store *store, int flags)
+{
+ error_t err = 0;
+ 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 (! err)
+ store->flags &= ~(kill & ~STORE_BACKEND_FLAGS);
+
+ return err;
+}
diff --git a/libstore/gunzip.c b/libstore/gunzip.c
new file mode 100644
index 00000000..2e868219
--- /dev/null
+++ b/libstore/gunzip.c
@@ -0,0 +1,275 @@
+/* Decompressing store backend
+
+ Copyright (C) 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
+ 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
+
+#define IN_BUFFERING (256*1024)
+#define OUT_BUFFERING (512*1024)
+
+static struct mutex unzip_lock = MUTEX_INITIALIZER;
+
+/* Uncompress the contents of FROM, which should contain a valid gzip file,
+ into memory, returning the result buffer in BUF & BUF_LEN. */
+static error_t
+gunzip (struct store *from, void **buf, size_t *buf_len)
+{
+ /* Entry points to unzip engine. */
+ int get_method (int);
+ extern long int bytes_out;
+ /* Callbacks from unzip 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;
+ 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_len > 0)
+ munmap (in_buf, in_buf_len);
+ in_buf = new_in_buf;
+ 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))
+ {
+ if (get_method (0) != 0)
+ /* Not a happy gzip file. */
+ zerr = EINVAL;
+ else
+ /* Matched gzip magic number. Ready to unzip.
+ Set up the output stream and let 'er rip. */
+ {
+ /* Call the gunzip engine. */
+ bytes_out = 0;
+ unzip (17, 23); /* Arguments ignored. */
+ zerr = 0;
+ }
+ }
+
+ mutex_unlock (&unzip_lock);
+
+ if (in_buf_len > 0)
+ munmap (in_buf, in_buf_len);
+
+ 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_gunzip_create (struct store *from, int flags, struct store **store)
+{
+ void *buf;
+ size_t buf_len;
+ error_t err = gunzip (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 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 used to select classes specified by the type
+ name; if it is 0, STORE_STD_CLASSES is used. */
+error_t
+store_gunzip_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_gunzip_create (from, flags, store);
+ if (err)
+ store_free (from);
+ }
+
+ return err;
+}
+
+struct store_class
+store_gunzip_class = { -1, "gunzip", open: store_gunzip_open };
diff --git a/libstore/kids.c b/libstore/kids.c
new file mode 100644
index 00000000..ee00ace4
--- /dev/null
+++ b/libstore/kids.c
@@ -0,0 +1,311 @@
+/* Managing sub-stores
+
+ 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
+ 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 <malloc.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)
+{
+ unsigned size = num_children * sizeof (struct store_run);
+ struct store **copy = malloc (size);
+
+ if (!copy)
+ return ENOMEM;
+
+ if (store->children)
+ free (store->children);
+
+ bcopy (children, copy, 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. */
+error_t
+store_allocate_child_encodings (const struct store *store,
+ struct store_enc *enc)
+{
+ int i;
+ error_t err = 0;
+ for (i = 0; i < store->num_children && !err; i++)
+ {
+ struct store *k = store->children[i];
+ if (k->class->allocate_encoding)
+ (*k->class->allocate_encoding) (store, enc);
+ else
+ err = EOPNOTSUPP;
+ }
+ return err;
+}
+
+/* Calls the encode method in each child store of STORE, propagating any
+ errors. If any child does not hae such a method, EOPNOTSUPP is returned. */
+error_t
+store_encode_children (const struct store *store, struct store_enc *enc)
+{
+ int i;
+ error_t err = 0;
+ for (i = 0; i < store->num_children && !err; i++)
+ {
+ struct store *k = store->children[i];
+ if (k->class->encode)
+ (*k->class->encode) (store, enc);
+ else
+ err = EOPNOTSUPP;
+ }
+ return err;
+}
+
+/* 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,
+ const struct store_class *const *classes,
+ struct store **children)
+{
+ int i;
+ error_t err = 0;
+ for (i = 0; i < num_children && !err; i++)
+ err = store_decode (enc, classes, &children[i]);
+ if (err)
+ /* Deallocate anything we've already created. */
+ while (--i >= 0)
+ store_free (children[i]);
+ return err;
+}
+
+/* Set FLAGS in all children of STORE, and if successfull, 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 successfull, 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
new file mode 100644
index 00000000..ed476ba4
--- /dev/null
+++ b/libstore/make.c
@@ -0,0 +1,100 @@
+/* Store allocation/deallocation
+
+ 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
+ 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 <malloc.h>
+
+#include "store.h"
+
+/* Allocate a new store structure with meths METHS, 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, off_t end,
+ struct store **store)
+{
+ if ((block_size & (block_size - 1)) || (block_size == 0 && num_runs > 0))
+ return EINVAL; /* block size not a power of two. */
+ else
+ {
+ struct store *new = malloc (sizeof (struct store));
+ if (new)
+ {
+ 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;
+ }
+ else
+ return ENOMEM;
+ }
+}
+
+void
+store_free (struct store *store)
+{
+ int k;
+
+ if (store->class->cleanup)
+ (*store->class->cleanup) (store);
+
+ for (k = 0; k < store->num_children; k++)
+ store_free (store->children[k]);
+
+ if (store->port != MACH_PORT_NULL)
+ mach_port_deallocate (mach_task_self (), store->port);
+ if (store->source != MACH_PORT_NULL)
+ mach_port_deallocate (mach_task_self (), store->source);
+
+ if (store->name)
+ free (store->name);
+ if (store->runs)
+ free (store->runs);
+
+ free (store);
+}
diff --git a/libstore/map.c b/libstore/map.c
new file mode 100644
index 00000000..4ac8ce98
--- /dev/null
+++ b/libstore/map.c
@@ -0,0 +1,77 @@
+/* Direct store mapping
+
+ Copyright (C) 1997 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+ This task 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/mvol.c b/libstore/mvol.c
new file mode 100644
index 00000000..b0753dac
--- /dev/null
+++ b/libstore/mvol.c
@@ -0,0 +1,151 @@
+/* Multiple-volume store backend
+
+ 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
+ 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,
+ off_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,
+ off_t addr, size_t index, 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;
+}
+
+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);
+}
+
+struct store_class
+store_mvol_class =
+{
+ -1, "mvol", mvol_read, mvol_write,
+ 0, 0, 0,
+ store_set_child_flags, store_clear_child_flags, 0, 0, mvol_remap
+};
+
+/* 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/open.c b/libstore/open.c
new file mode 100644
index 00000000..ca3eb886
--- /dev/null
+++ b/libstore/open.c
@@ -0,0 +1,64 @@
+/* Store creation from a file name
+
+ Copyright (C) 1996, 97, 98 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 <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;
+}
+
+struct store_class
+store_query_class = { -1, "query", open: store_open };
diff --git a/libstore/rdwr.c b/libstore/rdwr.c
new file mode 100644
index 00000000..85d2ba2b
--- /dev/null
+++ b/libstore/rdwr.c
@@ -0,0 +1,281 @@
+/* Store I/O
+
+ Copyright (C) 1995, 96, 97, 98, 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
+ 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 <string.h>
+#include <sys/mman.h>
+
+#include "store.h"
+
+/* Returns in RUN the tail of STORE's run list, who's first run contains
+ 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,
+ struct store_run **run, struct store_run **runs_end,
+ off_t *base, size_t *index)
+{
+ struct store_run *tail = store->runs, *tail_end = tail + store->num_runs;
+ off_t wrap_src = store->wrap_src;
+
+ if (addr >= wrap_src && addr < store->end)
+ /* Locate the correct position within a repeating pattern of runs. */
+ {
+ *base = addr / store->wrap_dst;
+ addr %= wrap_src;
+ }
+ else
+ *base = 0;
+
+ /* XXX: this isn't going to be very efficient if RUNS is very complex...
+ But it should do dandy if it's short. For long run lists, we could do a
+ binary search or something. */
+ while (tail < tail_end)
+ {
+ off_t run_blocks = tail->length;
+
+ if (run_blocks > addr)
+ {
+ *run = tail;
+ *runs_end = tail_end;
+ *index = tail - store->runs;
+ return addr;
+ }
+
+ /* Not to the right place yet, move on... */
+ addr -= run_blocks;
+ tail++;
+ }
+
+ return -1;
+}
+
+/* Update RUN, BASE, & INDEX to point to the next elemement in the runs
+ array. RUNS_END is the point where RUNS will wrap. Returns true if
+ 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)
+{
+ (*run)++;
+ (*index)++;
+
+ if (*run == runs_end)
+ /* Wrap around in a repeating RUNS. */
+ {
+ *run = store->runs;
+ *base += store->wrap_dst;
+ *index = 0;
+ return (*base < store->end);
+ }
+ else
+ return 1;
+}
+
+#include <assert.h>
+
+/* Write LEN bytes from BUF to STORE at ADDR. Returns the amount written
+ in AMOUNT. ADDR is in BLOCKS (as defined by STORE->block_size). */
+error_t
+store_write (struct store *store,
+ off_t addr, void *buf, size_t len, size_t *amount)
+{
+ error_t err;
+ size_t index;
+ off_t base;
+ struct store_run *run, *runs_end;
+ int block_shift = store->log2_block_size;
+ store_write_meth_t write = store->class->write;
+
+ if (store->flags & STORE_READONLY)
+ return EROFS; /* XXX */
+
+ if (store->block_size != 0)
+ assert ((len & (store->block_size - 1)) == 0);
+
+ addr = store_find_first_run (store, addr, &run, &runs_end, &base, &index);
+ if (addr < 0)
+ err = EIO;
+ 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, written;
+
+ /* Write the initial bit in the first run. Errors here are returned. */
+ 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
+ will just result in a short write. */
+ {
+ buf += written;
+ len -= written;
+
+ while (store_next_run (store, runs_end, &run, &base, &index)
+ && run->start >= 0) /* Check for holes. */
+ /* Ok, we can write in this run, at least a bit. */
+ {
+ mach_msg_type_number_t seg_written;
+
+ 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! */
+
+ buf += seg_written;
+ }
+ }
+
+ *amount = written;
+ }
+
+ return err;
+}
+
+/* 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, void **buf, size_t *len)
+{
+ size_t index;
+ off_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 || run->start < 0)
+ return EIO; /* Reading from a hole. */
+
+ if (store->block_size != 0)
+ assert ((amount & (store->block_size - 1)) == 0);
+
+ if ((amount >> block_shift) <= run->length - addr)
+ /* The first run has it all... */
+ 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. */
+ 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)
+ {
+ /* SEG_BUF and SEG_LEN are the buffer for a particular bit of the
+ whole (within one run). */
+ 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
+ that space. */
+ if (seg_buf != buf_end)
+ {
+ bcopy (seg_buf, buf_end, seg_buf_len);
+ munmap (seg_buf, seg_buf_len);
+ }
+ buf_end += seg_buf_len;
+ amount -= seg_buf_len;
+ *all = (seg_buf_len == len);
+ }
+ return err;
+ }
+
+ if (whole_buf_len < amount)
+ /* Not enough room in the user's buffer to hold everything, better
+ make room. */
+ {
+ whole_buf_len = amount;
+ 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 - addr) << block_shift, &all);
+ while (!err && all && amount > 0
+ && store_next_run (store, runs_end, &run, &base, &index))
+ {
+ if (run->start < 0)
+ /* A hole! Can't read here. Must stop. */
+ break;
+ else
+ 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. */
+ *len = buf_end - whole_buf;
+ if (*len > 0)
+ err = 0; /* Return a short read instead of an error. */
+
+ /* Deallocate any amount of WHOLE_BUF we didn't use. */
+ if (whole_buf != *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;
+ }
+}
diff --git a/libstore/remap.c b/libstore/remap.c
new file mode 100644
index 00000000..e1965ea5
--- /dev/null
+++ b/libstore/remap.c
@@ -0,0 +1,338 @@
+/* Block address translation
+
+ 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
+ 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,
+ off_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,
+ off_t addr, size_t index, void *buf, size_t len,
+ size_t *amount)
+{
+ return store_write (store->children[0], addr, buf, len, amount);
+}
+
+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 = (off_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 == (off_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;
+}
+
+
+struct store_class
+store_remap_class =
+{
+ STORAGE_REMAP, "remap", remap_read, remap_write,
+ 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
+};
+
+/* 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 (off_t addr, off_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++)
+ {
+ off_t addr = runs[i].start, left = runs[i].length;
+
+ if (addr >= 0)
+ for (j = 0; j < num_base_runs && left > 0; j++)
+ {
+ off_t baddr = base_runs[j].start;
+ off_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. */
+ {
+ off_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
new file mode 100644
index 00000000..ab9747ff
--- /dev/null
+++ b/libstore/set.c
@@ -0,0 +1,77 @@
+/* Setting various store fields
+
+ 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
+ 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 <malloc.h>
+#include <string.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)
+{
+ unsigned size = num_runs * sizeof (struct store_run);
+ struct store_run *copy = malloc (size);
+
+ if (!copy)
+ return ENOMEM;
+
+ if (store->runs)
+ free (store->runs);
+
+ bcopy (runs, copy, size);
+ store->runs = copy;
+ store->num_runs = num_runs;
+
+ if (store->block_size > 0)
+ _store_derive (store);
+
+ return 0;
+}
+
+/* Sets the name associated with STORE to a copy of NAME. */
+error_t
+store_set_name (struct store *store, const char *name)
+{
+ char *copy = malloc (strlen (name) + 1);
+
+ if (!copy)
+ return ENOMEM;
+
+ if (store->name)
+ free (store->name);
+
+ strcpy (copy, name);
+ store->name = copy;
+
+ return 0;
+}
+
+/* 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 (store->source)
+ {
+ mach_port_deallocate (mach_task_self (), store->source);
+ store->source = MACH_PORT_NULL;
+ }
+}
diff --git a/libstore/std.c b/libstore/std.c
new file mode 100644
index 00000000..e42e2094
--- /dev/null
+++ b/libstore/std.c
@@ -0,0 +1,32 @@
+/* List of standard store classes
+
+ 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
+ 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"
+
+const struct store_class *const
+store_std_classes[] =
+{
+ &store_device_class, &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, &store_typed_open_class,
+ 0
+};
+
diff --git a/libstore/store.h b/libstore/store.h
new file mode 100644
index 00000000..c57e7fcf
--- /dev/null
+++ b/libstore/store.h
@@ -0,0 +1,646 @@
+/* Store I/O
+
+ Copyright (C) 1995, 96, 97, 98, 99 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. */
+
+/* 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>
+
+#ifndef STORE_EI
+#define STORE_EI extern inline
+#endif
+
+
+/* A portion of a store. If START == -1, it's a hole. */
+struct store_run
+{
+ off_t start, length;
+};
+
+struct store
+{
+ /* If this store was created using store_create, the file from which we got
+ our store. */
+ file_t source;
+
+ /* Address ranges in the underlying storage which make up our contiguous
+ address space. In units of BLOCK_SIZE, below. */
+ struct store_run *runs; /* Malloced */
+ size_t num_runs; /* Length of RUNS. */
+
+ /* Maximum valid offset. This is the same as SIZE, but in blocks. */
+ off_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 */
+
+ /* Handles for the underlying storage. */
+ char *name; /* Malloced */
+ mach_port_t port; /* Send right */
+
+ /* The size of a `block' on this storage. */
+ size_t block_size;
+
+ /* The number of blocks (of size BLOCK_SIZE) in this storage. */
+ off_t blocks;
+ /* The number of bytes in this storage, including holes. */
+ off_t size;
+
+ /* Log_2 (BLOCK_SIZE) or 0 if not a power of 2. */
+ unsigned log2_block_size;
+ /* Log_2 (VM_PAGE_SIZE / BLOCK_SIZE); only valid if LOG2_BLOCK_SIZE is. */
+ unsigned log2_blocks_per_page;
+
+ /* Random flags. */
+ int flags;
+
+ void *misc; /* malloced */
+ size_t misc_len;
+
+ const struct store_class *class;
+
+ /* A list of sub-stores. The interpretation of this is type-specific. */
+ struct store **children;
+ size_t num_children;
+
+ void *hook; /* Type specific noise. */
+};
+
+/* Store flags. These are in addition to the STORAGE_ flags defined in
+ <hurd/hurd_types.h>. XXX synchronize these values. */
+
+/* Flags that reflect something immutable about the object. */
+#define STORE_IMMUTABLE_FLAGS 0x00FF
+
+/* Flags implemented by generic store code. */
+#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 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,
+ 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,
+ mach_msg_type_number_t amount,
+ void **buf, mach_msg_type_number_t *len);
+
+struct store_enc; /* fwd decl */
+
+struct store_class
+{
+ /* The type of storage this is (see STORAGE_ in hurd/hurd_types.h). */
+ enum file_storage_class id;
+
+ /* Name of the class. */
+ 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. */
+ 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. */
+ store_write_meth_t write;
+
+ /* To the lengths of each for the four arrays in ENC, add how much STORE
+ would need to be encoded. */
+ error_t (*allocate_encoding)(const struct store *store,
+ struct store_enc *enc);
+ /* Append the encoding for STORE to ENC. */
+ error_t (*encode) (const struct store *store, struct store_enc *enc);
+
+ /* Decode from ENC a new store, which return in STORE. CLASSES is used to
+ lookup child 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
+ STORE_ENFORCED. */
+ error_t (*set_flags) (struct store *store, int flags);
+ error_t (*clear_flags) (struct store *store, int flags);
+
+ /* Called just before deallocating STORE. */
+ void (*cleanup) (struct store *store);
+
+ /* 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 (*clone) (const struct store *from, struct store *to);
+
+ /* 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
+ validaty, 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, 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);
+
+/* 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);
+
+/* 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,
+ off_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,
+ const struct store_run *runs, size_t num_runs);
+
+/* Set STORE's current children to (a copy of) CHILDREN and NUM_CHILDREN
+ (note that just the vector CHILDREN is copied, not the actual children). */
+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);
+
+/* Add FLAGS to STORE's currently set flags. */
+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 successfull, 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 successfull, remove FLAGS from
+ STORE's flags. */
+error_t store_clear_child_flags (struct store *store, int flags);
+
+/* 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)));
+}
+
+/* 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, 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, void **buf, size_t *len);
+
+/* 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);
+
+/* 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);
+
+#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 *memobj)
+
+#endif
+
+/* Creating specific types of stores. */
+
+/* Return a new zero store SIZE bytes long in STORE. */
+error_t store_zero_create (off_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);
+
+/* Like store_device_create, but doesn't query the device for information. */
+error_t _store_device_create (device_t device, int flags, size_t block_size,
+ const struct store_run *runs, size_t num_runs,
+ struct store **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);
+
+/* 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
+ holes. Consumes the send right FILE. */
+error_t store_file_create (file_t file, int flags, struct store **store);
+
+/* Like store_file_create, but doesn't query the file for information. */
+error_t _store_file_create (file_t file, int flags, size_t block_size,
+ const struct store_run *runs, size_t num_runs,
+ struct store **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);
+
+/* 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);
+
+/* 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);
+
+/* 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 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);
+
+/* 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);
+
+/* 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
+ be freed when this store is (however, the *array* STRIPES is copied, and
+ so should be freed by the caller). */
+error_t store_concat_create (struct store * const *stores, size_t num_stores,
+ 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 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);
+
+/* 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 used to select classes specified by the type
+ name; if it is 0, STORE_STD_CLASSES is used. */
+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 used to select classes specified by the type
+ name; if it is 0, STORE_STD_CLASSES is used. */
+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);
+
+/* Standard store classes implemented by libstore. */
+extern const struct store_class *const store_std_classes[];
+
+extern const struct store_class store_device_class;
+extern const struct store_class store_file_class;
+extern const struct store_class store_task_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;
+
+/* The following are not included in STORE_STD_CLASSES. */
+extern const struct store_class store_mvol_class;
+
+/* Concatenates the store class vectors in CV1 and CV2, and returns a new
+ (malloced) vector in CONCAT. */
+error_t store_concat_class_vectors (struct store_class **cv1,
+ struct store_class **cv2,
+ struct store_class ***concat);
+
+/* 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
+ the encodings for the various storage types. */
+struct store_enc
+{
+ /* Each of the four vectors used. All are vm_allocated. */
+ mach_port_t *ports;
+ int *ints;
+ off_t *offsets;
+ char *data;
+
+ /* The sizes of the vectors. */
+ mach_msg_type_number_t num_ports, num_ints, num_offsets, data_len;
+
+ /* Offsets into the above vectors, for an encoding/decoding in progress. */
+ size_t cur_port, cur_int, cur_offset, cur_data;
+
+ /* Each of these is an `initial' version of the associated vector. When
+ store_enc_dealloc is called, any vector that is the same as its `init_'
+ version won't be deallocated. */
+ mach_port_t *init_ports;
+ int *init_ints;
+ off_t *init_offsets;
+ char *init_data;
+};
+
+/* Initialize ENC. The given vector and sizes will be used for the encoding
+ if they are big enough (otherwise new ones will be automatically
+ allocated). */
+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,
+ 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,
+ off_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,
+ off_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
+ can't be done, store_enc_dealloc may be used to deallocate the mmemory
+ 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,
+ const struct store_class *const *classes,
+ struct store **store);
+
+/* 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. */
+error_t store_allocate_child_encodings (const struct store *store,
+ struct store_enc *enc);
+
+/* Calls the encode method in each child store of STORE, propagating any
+ errors. If any child does not hae such a method, EOPNOTSUPP is returned. */
+error_t store_encode_children (const struct store *store,
+ struct store_enc *enc);
+
+/* 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,
+ 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);
+error_t store_std_leaf_encode (const struct store *store,
+ struct store_enc *enc);
+
+/* Creation function signature used by store_std_leaf_decode. */
+typedef error_t (*store_std_leaf_create_t)(mach_port_t port,
+ int flags,
+ size_t block_size,
+ const struct store_run *runs,
+ size_t num_runs,
+ struct store **store);
+
+/* Decodes the standard leaf encoding that's common to various builtin
+ formats, and calls CREATE to actually create the store. */
+error_t store_std_leaf_decode (struct store_enc *enc,
+ store_std_leaf_create_t create,
+ struct store **store);
+
+/* 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 struct store_argp_params. */
+extern struct argp store_argp;
+
+/* The structure used to pass args back and forth from STORE_ARGP. */
+struct store_argp_params
+{
+ /* 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;
+
+ /* The set of classes used to validate store-types and argument syntax. */
+ const struct store_class *const *classes;
+};
+
+/* 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/stripe.c b/libstore/stripe.c
new file mode 100644
index 00000000..59fb504e
--- /dev/null
+++ b/libstore/stripe.c
@@ -0,0 +1,282 @@
+/* Striped store backend
+
+ Copyright (C) 1996,97,99 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 "store.h"
+
+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)
+{
+ unsigned common_bs = store->log2_block_size;
+ unsigned stripe_bs = stripe->log2_block_size;
+ if (common_bs == stripe_bs)
+ return addr;
+ else
+ return addr << (common_bs - stripe_bs);
+}
+
+static error_t
+stripe_read (struct store *store,
+ off_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);
+}
+
+static error_t
+stripe_write (struct store *store,
+ off_t addr, size_t index, 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_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)
+{
+ enc->num_ints += 4;
+ return store_allocate_child_encodings (store, enc);
+}
+
+error_t
+ileave_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->ints[enc->cur_int++] = store->wrap_dst; /* interleave factor */
+ enc->ints[enc->cur_int++] = store->num_children;
+ return store_encode_children (store, enc);
+}
+
+error_t
+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 __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++];
+ struct store *kids[nkids];
+ error_t err = store_decode_children (enc, nkids, classes, kids);
+ if (! err)
+ err = store_ileave_create (kids, nkids, interleave, flags, store);
+ return err;
+ }
+}
+
+struct store_class
+store_ileave_class =
+{
+ STORAGE_INTERLEAVE, "interleave", stripe_read, stripe_write,
+ ileave_allocate_encoding, ileave_encode, ileave_decode,
+ store_set_child_flags, store_clear_child_flags, 0, 0, stripe_remap
+};
+
+error_t
+concat_allocate_encoding (const struct store *store, struct store_enc *enc)
+{
+ enc->num_ints += 3;
+ return store_allocate_child_encodings (store, enc);
+}
+
+error_t
+concat_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->ints[enc->cur_int++] = store->num_children;
+ return store_encode_children (store, enc);
+}
+
+error_t
+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 __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];
+ error_t err = store_decode_children (enc, nkids, classes, kids);
+ if (! err)
+ err = store_concat_create (kids, nkids, flags, store);
+ return err;
+ }
+}
+
+struct store_class
+store_concat_class =
+{
+ STORAGE_CONCAT, "concat", stripe_read, stripe_write,
+ concat_allocate_encoding, concat_encode, concat_decode,
+ store_set_child_flags, store_clear_child_flags, 0, 0, stripe_remap
+};
+
+/* 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)
+{
+ size_t i;
+ error_t err;
+ off_t block_size = 1, 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++)
+ block_size = lcm (block_size, stripes[i]->block_size);
+
+ if (interleave < block_size || (interleave % block_size) != 0)
+ return EINVAL;
+
+ interleave /= block_size;
+
+ for (i = 0; i < num_stripes; i++)
+ {
+ /* The stripe's end adjusted to the common block size. */
+ off_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;
+
+ common_flags &= stripes[i]->flags;
+ }
+
+ 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);
+ }
+
+ return err;
+}
+
+/* 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
+ be freed when this store is (however, the *array* STRIPES is copied, and
+ so should be freed by the caller). */
+error_t
+store_concat_create (struct store * const *stores, size_t num_stores,
+ int flags, struct store **store)
+{
+ size_t i;
+ error_t err;
+ off_t block_size = 1;
+ int common_flags = STORE_BACKEND_FLAGS;
+ struct store_run runs[num_stores];
+
+ /* Find a common block size. */
+ for (i = 0; i < num_stores; i++)
+ block_size = lcm (block_size, stores[i]->block_size);
+
+ for (i = 0; i < num_stores; i++)
+ {
+ runs[i].start = 0;
+ runs[i].length = stores[i]->end;
+ common_flags &= stores[i]->flags;
+ }
+
+ err = _store_create (&store_concat_class, MACH_PORT_NULL,
+ flags | common_flags, block_size,
+ runs, num_stores * 2, 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);
+ }
+
+ 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..d2cce5f3
--- /dev/null
+++ b/libstore/task.c
@@ -0,0 +1,197 @@
+/* Mach task store backend
+
+ 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
+ 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,
+ off_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,
+ off_t addr, size_t index, 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_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;
+}
+
+struct store_class
+store_task_class =
+{
+ STORAGE_TASK, "task", task_read, task_write,
+ store_std_leaf_allocate_encoding, store_std_leaf_encode, task_decode,
+ task_set_flags, task_clear_flags, 0, 0, 0, task_open
+};
+
+/* 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..05083eea
--- /dev/null
+++ b/libstore/typed.c
@@ -0,0 +1,85 @@
+/* Support for opening `typed' stores
+
+ Copyright (C) 1997, 1998 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ This task 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 <string.h>
+
+#include "store.h"
+
+/* 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 *const *cl;
+ const char *clname_end = strchr (name, ':');
+
+ if (clname_end == name)
+ /* Open NAME with store_open. */
+ return store_open (name + 1, flags, classes, store);
+
+ if (! clname_end)
+ clname_end = name + strlen (name);
+
+ if (! classes)
+ classes = store_std_classes;
+ for (cl = classes; *cl; cl++)
+ if (strlen ((*cl)->name) == (clname_end - name)
+ && strncmp (name, (*cl)->name, (clname_end - name)) == 0)
+ break;
+
+ if (! *cl)
+ {
+ /* 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);
+ }
+
+ 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);
+}
+
+struct store_class
+store_typed_open_class = { -1, "typed", open: store_typed_open };
diff --git a/libstore/xinl.c b/libstore/xinl.c
new file mode 100644
index 00000000..a603d621
--- /dev/null
+++ b/libstore/xinl.c
@@ -0,0 +1,2 @@
+#define STORE_EI
+#include "store.h"
diff --git a/libstore/zero.c b/libstore/zero.c
new file mode 100644
index 00000000..55f84a2c
--- /dev/null
+++ b/libstore/zero.c
@@ -0,0 +1,169 @@
+/* Zero store backend
+
+ Copyright (C) 1995, 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
+ 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 <assert.h>
+#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,
+ off_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 == (void *) -1)
+ return errno;
+ *len = amount;
+ return 0;
+ }
+ else
+ bzero (*buf, amount);
+
+ *len = amount;
+ return 0;
+}
+
+static error_t
+zero_write (struct store *store,
+ off_t addr, size_t index, void *buf, size_t len, size_t *amount)
+{
+ return 0;
+}
+
+/* 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;
+ off_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)
+{
+ 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_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;
+ off_t size = strtoul (name, &end, 0);
+ if (end == name)
+ return EINVAL;
+ return store_zero_create (size, flags, store);
+ }
+ else
+ {
+ off_t max_offs = ~((off_t)1 << (CHAR_BIT * sizeof (off_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;
+}
+
+struct store_class
+store_zero_class =
+{
+ STORAGE_ZERO, "zero", zero_read, zero_write,
+ zero_allocate_encoding, zero_encode, zero_decode,
+ 0, 0, 0, 0, zero_remap, zero_open, zero_validate_name,
+ zero_map
+};
+
+/* Return a new zero store SIZE bytes long in STORE. */
+error_t
+store_zero_create (off_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);
+}