aboutsummaryrefslogtreecommitdiff
path: root/libstore/decode.c
diff options
context:
space:
mode:
Diffstat (limited to 'libstore/decode.c')
-rw-r--r--libstore/decode.c125
1 files changed, 85 insertions, 40 deletions
diff --git a/libstore/decode.c b/libstore/decode.c
index 5231b33d..64405ecd 100644
--- a/libstore/decode.c
+++ b/libstore/decode.c
@@ -1,9 +1,7 @@
/* Store wire decoding
- Copyright (C) 1996 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
-
+ Copyright (C) 1996,97,98,2001,02 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
This file is part of the GNU Hurd.
The GNU Hurd is free software; you can redistribute it and/or
@@ -18,7 +16,7 @@
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
#include <string.h>
#include <malloc.h>
@@ -37,10 +35,15 @@ store_std_leaf_decode (struct store_enc *enc,
{
char *misc, *name;
error_t err;
- int type, flags, i;
+ int type, flags;
mach_port_t port;
size_t block_size, num_runs, name_len, misc_len;
-
+ /* Call CREATE appriately from within store_with_decoded_runs. */
+ error_t call_create (const struct store_run *runs, size_t num_runs)
+ {
+ return (*create)(port, flags, block_size, runs, num_runs, store);
+ }
+
/* Make sure there are enough encoded ints and ports. */
if (enc->cur_int + 6 > enc->num_ints || enc->cur_port + 1 > enc->num_ports)
return EINVAL;
@@ -61,25 +64,63 @@ store_std_leaf_decode (struct store_enc *enc,
if (name_len > 0 && enc->data[enc->cur_data + name_len - 1] != '\0')
return EINVAL; /* Name not terminated. */
- misc = malloc (misc_len);
- if (! misc)
- return ENOMEM;
-
if (name_len > 0)
{
name = strdup (enc->data + enc->cur_data);
if (! name)
+ return ENOMEM;
+ enc->cur_data += name_len;
+ }
+ else
+ name = 0;
+
+ if (misc_len > 0)
+ {
+ misc = malloc (misc_len);
+ if (! misc)
{
- free (misc);
+ if (name)
+ free (name);
return ENOMEM;
}
+ memcpy (misc, enc->data + enc->cur_data + name_len, misc_len);
+ enc->cur_data += misc_len;
}
else
- name = 0;
+ misc = 0;
/* Read encoded ports (be careful to deallocate this if we barf). */
port = enc->ports[enc->cur_port++];
+ err = store_with_decoded_runs (enc, num_runs, call_create);
+ if (err)
+ {
+ mach_port_deallocate (mach_task_self (), port);
+ if (misc)
+ free (misc);
+ if (name)
+ free (name);
+ }
+ else
+ {
+ (*store)->flags = flags;
+ (*store)->name = name;
+ (*store)->misc = misc;
+ (*store)->misc_len = misc_len;
+ }
+
+ return err;
+}
+
+/* Call FUN with the vector RUNS of length RUNS_LEN extracted from ENC. */
+error_t
+store_with_decoded_runs (struct store_enc *enc, size_t num_runs,
+ error_t (*fun) (const struct store_run *runs,
+ size_t num_runs))
+{
+ int i;
+ error_t err;
+
/* Since the runs are passed in an array of off_t pairs, and we use struct
store_run, we have to make a temporary array to hold the (probably
bitwise identical) converted representation to pass to CREATE. */
@@ -92,7 +133,8 @@ store_std_leaf_decode (struct store_enc *enc,
runs[i].start = *e++;
runs[i].length = *e++;
}
- err = (*create)(port, flags, block_size, runs, num_runs, store);
+ enc->cur_offset = e - enc->offsets;
+ err = (*fun)(runs, num_runs);
}
else
/* Ack. Too many runs to allocate the temporary RUNS array on the stack.
@@ -107,28 +149,14 @@ store_std_leaf_decode (struct store_enc *enc,
runs[i].start = *e++;
runs[i].length = *e++;
}
- err = (*create)(port, flags, block_size, runs, num_runs, store);
+ enc->cur_offset = e - enc->offsets;
+ err = (*fun) (runs, num_runs);
free (runs);
}
else
err = ENOMEM;
}
- if (err)
- {
- mach_port_deallocate (mach_task_self (), port);
- free (misc);
- if (name)
- free (name);
- }
- else
- {
- (*store)->flags = flags;
- (*store)->name = name;
- (*store)->misc = misc;
- (*store)->misc_len = misc_len;
- }
-
return err;
}
@@ -137,22 +165,39 @@ store_std_leaf_decode (struct store_enc *enc,
0, STORE_STD_CLASSES is used. If nothing else is to be done with ENC, its
contents may then be freed using store_enc_dealloc. */
error_t
-store_decode (struct store_enc *enc, struct store_class *classes,
+store_decode (struct store_enc *enc, const struct store_class *const *classes,
struct store **store)
{
+ const struct store_class *const *cl;
+
if (enc->cur_int >= enc->num_ints)
/* The first int should always be the type. */
return EINVAL;
- if (! classes)
- classes = store_std_classes;
-
- while (classes)
- if (classes->id == enc->ints[enc->cur_int])
- if (classes->decode)
- return (*classes->decode) (enc, classes, store);
- else
- return EOPNOTSUPP;
+ if (enc->ints[enc->cur_int] == STORAGE_NETWORK)
+ /* This is a special case because store classes supporting
+ individual URL types will also use STORAGE_NETWORK,
+ and we want the generic dispatcher to come first. */
+ return store_url_decode (enc, classes, store);
+
+ for (cl = classes ?: __start_store_std_classes;
+ classes ? *cl != 0 : cl < __stop_store_std_classes;
+ ++cl)
+ if ((*cl)->id == enc->ints[enc->cur_int])
+ {
+ if ((*cl)->decode)
+ return (*(*cl)->decode) (enc, classes, store);
+ else
+ return EOPNOTSUPP;
+ }
+
+# pragma weak store_module_decode
+ if (! classes && store_module_decode)
+ {
+ error_t err = store_module_decode (enc, classes, store);
+ if (err != ENOENT)
+ return err;
+ }
return EINVAL;
}