diff options
Diffstat (limited to 'libstore')
-rw-r--r-- | libstore/ChangeLog | 716 | ||||
-rw-r--r-- | libstore/Makefile | 40 | ||||
-rw-r--r-- | libstore/argp.c | 379 | ||||
-rw-r--r-- | libstore/bunzip2.c | 259 | ||||
-rw-r--r-- | libstore/clone.c | 91 | ||||
-rw-r--r-- | libstore/copy.c | 241 | ||||
-rw-r--r-- | libstore/create.c | 76 | ||||
-rw-r--r-- | libstore/decode.c | 180 | ||||
-rw-r--r-- | libstore/derive.c | 84 | ||||
-rw-r--r-- | libstore/device.c | 280 | ||||
-rw-r--r-- | libstore/enc.c | 98 | ||||
-rw-r--r-- | libstore/encode.c | 167 | ||||
-rw-r--r-- | libstore/file.c | 275 | ||||
-rw-r--r-- | libstore/flags.c | 66 | ||||
-rw-r--r-- | libstore/gunzip.c | 275 | ||||
-rw-r--r-- | libstore/kids.c | 311 | ||||
-rw-r--r-- | libstore/make.c | 100 | ||||
-rw-r--r-- | libstore/map.c | 77 | ||||
-rw-r--r-- | libstore/mvol.c | 151 | ||||
-rw-r--r-- | libstore/open.c | 64 | ||||
-rw-r--r-- | libstore/rdwr.c | 281 | ||||
-rw-r--r-- | libstore/remap.c | 338 | ||||
-rw-r--r-- | libstore/set.c | 77 | ||||
-rw-r--r-- | libstore/std.c | 32 | ||||
-rw-r--r-- | libstore/store.h | 646 | ||||
-rw-r--r-- | libstore/stripe.c | 282 | ||||
-rw-r--r-- | libstore/task.c | 197 | ||||
-rw-r--r-- | libstore/typed.c | 85 | ||||
-rw-r--r-- | libstore/xinl.c | 2 | ||||
-rw-r--r-- | libstore/zero.c | 169 |
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); +} |