diff options
Diffstat (limited to 'libstore/decode.c')
-rw-r--r-- | libstore/decode.c | 125 |
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; } |