From fb947c34b142578774d5bb657c0b3e2a9b4781c7 Mon Sep 17 00:00:00 2001 From: Robb Matzke Date: Tue, 12 Aug 1997 17:44:46 -0500 Subject: [svn-r25] ./src/H5AC.c We sort the cache before a complete flush because it might be more efficient to write things back to disk in order of increasing address. If you want the old way then undef the SORT_BY_ADDR constant at the top of H5AC.c I haven't determined which systems and I/O libraries this helps or hurts. (This is currently off because of a bug I need to track down that causes qsort() to run for a really long time). ./src/H5B.c Fixed a couple more bugs. ./src/H5Eprivate.h ./src/H5Eproto.h Added major H5E_DIRECTORY and minor H5E_EXISTS, H5E_COMPLEN. ./src/H5G.c Added directory-aware functions. The heap and B-tree are created when a directory is created instead of when the first symbol is added. This simplifies symbol table entry caching for the directory since the cached value never changes now. ./src/H5Gnode.c ./src/H5Gprivate.h Fine tuned the B-tree K values for symbol tables assuming an average number of symbols is about 100 per directory. The tuning minimizes storage space. Fixed a return value in H5G_node_cmp(). ./src/H5H.c ./src/H5Hprivate.h Moved some macros the the header file. ./src/H5O.c ./src/H5Ocont.c ./src/H5Onull.c ./src/H5Ostab.c Changed the arguments for the decode method for messages. The second argument is the raw message size. Added a class variable for native message size. Added H5O_reset() to free memory used internally by a message. ./src/H5Oname.c NEW ./src/H5Oprivate.h ./src/Makefile The object name message. ./src/hdf5port.h Added defn for HDstrdup() --- src/H5AC.c | 79 ++++++- src/H5B.c | 9 +- src/H5Eprivate.h | 3 + src/H5Eproto.h | 9 +- src/H5G.c | 643 ++++++++++++++++++++++++++++++++++++++++++++++++++----- src/H5Gnode.c | 4 +- src/H5Gprivate.h | 23 +- src/H5H.c | 10 - src/H5Hprivate.h | 11 + src/H5O.c | 61 ++++-- src/H5Ocont.c | 13 +- src/H5Oname.c | 283 ++++++++++++++++++++++++ src/H5Onull.c | 3 +- src/H5Oprivate.h | 20 +- src/H5Ostab.c | 16 +- src/Makefile | 6 +- src/hdf5port.h | 2 + 17 files changed, 1080 insertions(+), 115 deletions(-) create mode 100644 src/H5Oname.c diff --git a/src/H5AC.c b/src/H5AC.c index 41e2f88..ce8415e 100644 --- a/src/H5AC.c +++ b/src/H5AC.c @@ -27,9 +27,16 @@ #include "H5ACprivate.h" #include "H5MMprivate.h" +/* + * Sorting the cache by address before flushing is sometimes faster + * than flushing in cache order. + */ +/* #define SORT_BY_ADDR */ + #define PABLO_MASK H5AC_mask static int interface_initialize_g = FALSE; /*initialized?*/ +static H5AC_cache_t *current_cache_g = NULL; /*for sorting */ /*------------------------------------------------------------------------- @@ -200,6 +207,41 @@ H5AC_find_f (hdf5_file_t *f, const H5AC_class_t *type, haddr_t addr, /*------------------------------------------------------------------------- + * Function: H5AC_compare + * + * Purpose: Compare two hash entries by address. Unused entries are + * all equal to one another and greater than all used entries. + * + * Return: Success: -1, 0, 1 + * + * Failure: never fails + * + * Programmer: Robb Matzke + * robb@maya.nuance.com + * Aug 12 1997 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static int +H5AC_compare (const void *_a, const void *_b) +{ + intn a = *((const intn *)_a); + intn b = *((const intn *)_b); + + assert (current_cache_g); + + if (NULL==current_cache_g[a].type) return 1; + if (NULL==current_cache_g[b].type) return -1; + + if (current_cache_g[a].addr < current_cache_g[b].addr) return -1; + if (current_cache_g[a].addr > current_cache_g[b].addr) return 1; + return 0; +} + + +/*------------------------------------------------------------------------- * Function: H5AC_flush * * Purpose: Flushes (and destroys if DESTROY is non-zero) the specified @@ -226,6 +268,8 @@ H5AC_flush (hdf5_file_t *f, const H5AC_class_t *type, haddr_t addr, uintn i = H5AC_HASH(addr); herr_t status; herr_t (*flush)(hdf5_file_t*,hbool_t,haddr_t,void*)=NULL; + H5AC_cache_t *slot; + intn *map=NULL; FUNC_ENTER (H5AC_flush, NULL, FAIL); @@ -233,22 +277,43 @@ H5AC_flush (hdf5_file_t *f, const H5AC_class_t *type, haddr_t addr, assert (f->cache); if (!type || 0==addr) { + +#ifdef SORT_BY_ADDR + /* + * Sort the cache entries by address since flushing them in + * ascending order by address may be much more efficient. + */ + map = H5MM_xmalloc (H5AC_NSLOTS * sizeof(intn)); + for (i=0; icache; + qsort (map, H5AC_NSLOTS, sizeof(intn), H5AC_compare); + current_cache_g = NULL; +#endif + /* * Look at all cache entries. */ for (i=0; icache[i].type) continue; - if ((!type || type==f->cache[i].type) && - (0==addr || addr==f->cache[i].addr)) { - flush = f->cache[i].type->flush; - status = (flush)(f, destroy, f->cache[i].addr, - f->cache[i].thing); +#ifdef SORT_BY_ADDR + slot = f->cache + map[i]; + if (NULL==slot->type) break; /*the rest are empty*/ +#else + slot = f->cache + i; + if (NULL==slot->type) continue; +#endif + if ((!type || type==slot->type) && + (0==addr || addr==slot->addr)) { + flush = slot->type->flush; + status = (flush)(f, destroy, slot->addr, slot->thing); if (status<0) { + map = H5MM_xfree (map); HRETURN_ERROR (H5E_CACHE, H5E_CANTFLUSH, FAIL); } - if (destroy) f->cache[i].type = NULL; + if (destroy) slot->type = NULL; } } + map = H5MM_xfree (map); } else if (f->cache[i].type==type && f->cache[i].addr==addr) { /* diff --git a/src/H5B.c b/src/H5B.c index d700a7c..21dc174 100644 --- a/src/H5B.c +++ b/src/H5B.c @@ -113,7 +113,7 @@ #define PABLO_MASK H5B_mask -#define BOUND(MIN,X,MAX) ((MIN)<(X)?(MIN):((MAX)>(X)?(MAX):(X))) +#define BOUND(MIN,X,MAX) ((X)<(MIN)?(MIN):((X)>(MAX)?(MAX):(X))) #define false 0 #define true 1 @@ -173,7 +173,6 @@ H5B_new (hdf5_file_t *f, const H5B_class_t *type) */ assert (f); assert (type); - assert (sizeof_rkey>0); /* * Allocate file and memory data structures. @@ -608,7 +607,7 @@ H5B_split (hdf5_file_t *f, const H5B_class_t *type, haddr_t addr, intn anchor) */ memcpy (bt->page + H5B_SIZEOF_HDR(f), old->page + H5B_SIZEOF_HDR(f) + delta*recsize, - type->k * recsize); + type->k * recsize + bt->sizeof_rkey); memcpy (bt->native, old->native + delta * type->sizeof_nkey, (type->k+1) * type->sizeof_nkey); @@ -626,7 +625,7 @@ H5B_split (hdf5_file_t *f, const H5B_class_t *type, haddr_t addr, intn anchor) } } else { bt->key[i].dirty = 0; - bt->key[i].rkey = bt->native + offset; + bt->key[i].rkey = bt->page + offset; bt->key[i].nkey = NULL; } @@ -642,7 +641,7 @@ H5B_split (hdf5_file_t *f, const H5B_class_t *type, haddr_t addr, intn anchor) /* * Truncate the old node. */ - delta = H5B_ANCHOR_LT ? 0 : type->k; + delta = H5B_ANCHOR_LT==anchor ? 0 : type->k; old->dirty += 1; old->ndirty = BOUND (0, old->ndirty-delta, type->k); old->nchildren = type->k; diff --git a/src/H5Eprivate.h b/src/H5Eprivate.h index 4a6ad8f..c8678cc 100644 --- a/src/H5Eprivate.h +++ b/src/H5Eprivate.h @@ -62,6 +62,7 @@ static const hdf_maj_error_messages_t hdf_maj_error_messages[] = {H5E_SYM, "Symbol Table"}, {H5E_HEAP, "Heap"}, {H5E_OHDR, "Object Header"}, + {H5E_DIRECTORY, "Directory"}, }; typedef struct @@ -96,6 +97,7 @@ static const hdf_min_error_messages_t hdf_min_error_messages[] = {H5E_CANTFLUSH, "Can't flush object from cache"}, {H5E_CANTLOAD, "Can't load object into cache"}, {H5E_NOTFOUND, "Object not found"}, + {H5E_EXISTS, "Object already exists"}, {H5E_CANTENCODE, "Can't encode value"}, {H5E_CANTDECODE, "Can't decode value"}, {H5E_CANTSPLIT, "Can't split node"}, @@ -105,6 +107,7 @@ static const hdf_min_error_messages_t hdf_min_error_messages[] = {H5E_VERSION, "Wrong version number"}, {H5E_ALIGNMENT, "Alignment error"}, {H5E_BADMESG, "Unrecognized message"}, + {H5E_COMPLEN, "Name component is too long"}, }; /* We use a stack to hold the errors plus we keep track of the function, diff --git a/src/H5Eproto.h b/src/H5Eproto.h index 187737f..c61704c 100644 --- a/src/H5Eproto.h +++ b/src/H5Eproto.h @@ -81,7 +81,8 @@ typedef enum H5E_BTREE, /* B-Tree Node */ H5E_SYM, /* Symbol Table */ H5E_HEAP, /* Heap */ - H5E_OHDR /* Object Header */ + H5E_OHDR, /* Object Header */ + H5E_DIRECTORY /* Directory */ } hdf_maj_err_code_t; @@ -127,6 +128,7 @@ typedef enum /* B-tree related errors */ H5E_NOTFOUND, /* Object not found */ + H5E_EXISTS, /* Object already exists */ H5E_CANTENCODE, /* Can't encode value */ H5E_CANTDECODE, /* Can't decode value */ H5E_CANTSPLIT, /* Can't split node */ @@ -137,7 +139,10 @@ typedef enum H5E_LINKCOUNT, /* Bad object header link count */ H5E_VERSION, /* Wrong version number */ H5E_ALIGNMENT, /* Alignment error */ - H5E_BADMESG /* Unrecognized message */ + H5E_BADMESG, /* Unrecognized message */ + + /* Directory related errors */ + H5E_COMPLEN /* Name component is too long */ } hdf_min_err_code_t; diff --git a/src/H5G.c b/src/H5G.c index 458792b..45aada7 100644 --- a/src/H5G.c +++ b/src/H5G.c @@ -49,15 +49,570 @@ static intn interface_initialize_g = FALSE; /*------------------------------------------------------------------------- + * Function: H5G_component + * + * Purpose: Returns the pointer to the first component of the + * specified name by skipping leading slashes. Returns + * the size in characters of the component through SIZE_P not + * counting leading slashes or the null terminator. + * + * Return: Success: Ptr into NAME. + * + * Failure: Ptr to the null terminator of NAME. + * + * Programmer: Robb Matzke + * robb@maya.nuance.com + * Aug 11 1997 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static const char * +H5G_component (const char *name, size_t *size_p) +{ + assert (name); + + while ('/'==*name) name++; + if (size_p) *size_p = strcspn (name, "/"); + return name; +} + + +/*------------------------------------------------------------------------- + * Function: H5G_basename + * + * Purpose: Returns a pointer into NAME for the start of the last + * component of NAME. On return, the optional SIZE_P is + * initialized to point to the size of the base name not + * counting trailing slashes or the null character. + * + * Return: Success: Ptr to base name within NAME with SIZE_P + * pointing to the number of characters in the + * base name. + * + * Failure: Ptr to the null terminator of NAME. + * + * Programmer: Robb Matzke + * robb@maya.nuance.com + * Aug 11 1997 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static const char * +H5G_basename (const char *name, size_t *size_p) +{ + const char *s; + + assert (name); + + s = name + strlen(name); + while (s>name && '/'==s[-1]) --s; /*skip past trailing slashes*/ + while (s>name && '/'!=s[-1]) --s; /*skip past base name*/ + + /* + * If the input was the name of the root directory `/' (or + * equivalent) then return the null string. + */ + if ('/'==*s) { + if (size_p) *size_p = 0; + return s + strlen(s); /*null terminator*/ + } + + if (size_p) *size_p = strcspn (s, "/"); + return s; +} + + +/*------------------------------------------------------------------------- + * Function: H5G_namei + * + * Purpose: Given a name (absolute or relative) return the symbol table + * entry for that name and for the directory that contains the + * base name. These entries (DIR_ENT and BASE_ENT) are returned + * through memory passed into the function by the caller. Either + * or both pointers may be null. Absolute names are looked up + * relative to the root directory of file F while relative + * names are traversed beginning at the CWD argument. + * + * Consecutive slash characters are treated like single + * slash characters. Trailing slashes are ignored. The + * component `.' is recognized as the current directory + * during the traversal (initially CWD), but the component + * `..' is not internally recognized (it is recognized if + * such a name appears in the symbol table). + * + * As a special case, if the NAME is the string `/' (or + * equivalent) then DIR_ENT and BASE_ENT are both initialized + * to the contents of the root symbol table entry. However, + * the contents of the root symbol table entry may be + * uninitialized. + * + * If the name cannot be fully resolved, then REST will + * point to the part of NAME where the traversal failed + * (REST will always point to a relative name) and BASE_ENT + * will not be initialized. DIR_ENT will be initialized with + * information about the directory (or other object) at which + * the traversal failed. However, if the name can be fully + * resolved, then REST points to the null terminator of NAME. + * + * Return: Success: SUCCEED if the name can be fully + * resolved. + * + * Failure: FAIL if something bad happened (REST and + * DIR_ENT have undefined values). + * + * -2 if the name could not be fully resolved + * (REST and DIR_ENT are initialized). + * + * Programmer: Robb Matzke + * robb@maya.nuance.com + * Aug 11 1997 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static herr_t +H5G_namei (hdf5_file_t *f, H5G_entry_t *cwd, const char *name, + const char **rest, H5G_entry_t *dir_ent, H5G_entry_t *base_ent) +{ + H5G_entry_t ent[2]; + H5G_entry_t *tmp, *dir, *base; /*ptrs to DIR and BASE entries */ + size_t nchars; /*component name length */ + char comp[1024]; /*component name buffer */ + + FUNC_ENTER (H5G_namei, NULL, FAIL); + + /* check args */ + assert (f); + assert (f->root_sym); + assert (name && *name); + assert (cwd || '/'==*name); + + /* starting point */ + dir = ent+0; + base = ent+1; + if ('/'==*name) { + ent[0] = ent[1] = *(f->root_sym); + } else { + ent[0] = ent[1] = *cwd; + } + + /* traverse the name */ + while ((name=H5G_component (name, &nchars)) && *name) { + + /* + * The special name `.'. + */ + if ('.'==name[0] && !name[1]) continue; + + /* + * Advance. + */ + tmp=dir; dir=base; base=tmp; /*swap*/ + if (rest) *rest = name; + + /* + * Copy the component name into a null-terminated buffer so + * we can pass it down to the other symbol table functions. + */ + if (nchars+1 > sizeof(comp)) { + /* component name is too long */ + if (dir_ent) *dir_ent = *dir; + HRETURN_ERROR (H5E_DIRECTORY, H5E_COMPLEN, -2); + } + HDmemcpy (comp, name, nchars); + comp[nchars] = '\0'; + + /* + * Look for the component in the current symbol table. + */ + if (H5G_stab_find (f, dir, comp, base)<0) { + /* component not found */ + if (dir_ent) *dir_ent = *dir; + HRETURN_ERROR (H5E_DIRECTORY, H5E_NOTFOUND, -2); + } + + /* next component */ + name += nchars; + } + + /* output parameters */ + if (rest) *rest = name; /*final null*/ + if (dir_ent) *dir_ent = *dir; + if (base_ent) *base_ent = *base; + + FUNC_LEAVE (SUCCEED); +} + + +/*------------------------------------------------------------------------- + * Function: H5G_mkroot + * + * Purpose: Creates the root directory if it doesn't exist; otherwise + * nothing happens. If the root symbol table previously + * pointed to something other than a directory, then that + * object is made a member of the root directory and is + * given a name corresponding to the object name message. + * If the root object doesn't have an object name message + * then the name `Root Object' is used. + * + * Return: Success: SUCCEED + * + * Failure: FAIL + * + * Programmer: Robb Matzke + * robb@maya.nuance.com + * Aug 11 1997 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t +H5G_mkroot (hdf5_file_t *f, size_t size_hint) +{ + H5O_stab_t stab; /*symbol table message */ + H5O_name_t name; /*object name message */ + H5G_entry_t root; /*old root entry */ + const char *root_name=NULL; /*name of old root object */ + + FUNC_ENTER (H5G_mkroot, NULL, FAIL); + + /* + * Is there already a root object that needs to move into the new + * root symbol table? + */ + name.s = NULL; + if (f->root_sym->header>0) { + if (H5O_read (f, f->root_sym->header, f->root_sym, H5O_STAB, 0, &stab)) { + /* root directory already exists */ + HRETURN_ERROR (H5E_DIRECTORY, H5E_EXISTS, FAIL); + } else if (H5O_read (f, f->root_sym->header, f->root_sym, H5O_NAME, + 0, &name)) { + root = *(f->root_sym); + root_name = name.s; /*dont reset name until root_name is done*/ + } else { + root = *(f->root_sym); + root_name = "Root Object"; + } + } + + /* + * Create the root directory. + */ + if (H5G_stab_new (f, f->root_sym, size_hint)<0) { + H5O_reset (H5O_NAME, &name); + HRETURN_ERROR (H5E_DIRECTORY, H5E_CANTINIT, FAIL); /*can't create dir*/ + } + + /* + * Insert the old root object. + */ + if (root_name) { + if (H5G_stab_insert (f, f->root_sym, root_name, &root)) { + /* can't insert old root object in new root directory */ + H5O_reset (H5O_NAME, &name); + HRETURN_ERROR (H5E_DIRECTORY, H5E_CANTINIT, FAIL); + } + H5O_reset (H5O_NAME, &name); + } + + FUNC_LEAVE (SUCCEED); +} + + +/*------------------------------------------------------------------------- + * Function: H5G_new + * + * Purpose: Creates a new empty directory with the specified name. The + * name is either an absolute name or is relative to the + * directory whose symbol table entry is CWD. On return, the + * optional DIR_ENT pointer is initialized with the symbol + * table entry for the new directory's parent and ENT will + * contain the symbol table entry for the new directory. + * + * Do not use this function to create the root symbol table + * since it is a special case. Use H5G_mkroot() instead. + * Creating `/' with this function will return failure. + * + * Return: Success: SUCCEED, if DIR_ENT is not the null pointer + * then it will be initialized with the + * symbol table entry for the new directory. + * + * Failure: FAIL, the memory pointed to by CWD is + * not modified. + * + * Programmer: Robb Matzke + * robb@maya.nuance.com + * Aug 11 1997 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t +H5G_new (hdf5_file_t *f, H5G_entry_t *cwd, H5G_entry_t *dir_ent, + const char *name, size_t size_hint, H5G_entry_t *ent) +{ + const char *rest=NULL; + H5G_entry_t _parent, _child; + herr_t status; + char _comp[1024]; + size_t nchars; + + FUNC_ENTER (H5G_new, NULL, FAIL); + + /* check args */ + assert (f); + assert (name && *name); + assert (cwd || '/'==*name); + if (!dir_ent) dir_ent = &_parent; + if (!ent) ent = &_child; + + /* lookup name */ + status = H5G_namei (f, cwd, name, &rest, dir_ent, NULL); + if (status<0 && !rest) { + HRETURN_ERROR (H5E_DIRECTORY, H5E_CANTINIT, FAIL); /*lookup failed*/ + } else if (0==status) { + HRETURN_ERROR (H5E_DIRECTORY, H5E_EXISTS, FAIL); /*already exists*/ + } + H5ECLEAR; /*it's OK that we didn't find it*/ + + /* should be one null-terminated component left */ + rest = H5G_component (rest, &nchars); + assert (rest && *rest); + if (rest[nchars]) { + if (H5G_component (rest+nchars, NULL)) { + /* missing component */ + HRETURN_ERROR (H5E_DIRECTORY, H5E_NOTFOUND, FAIL); + } else if (nchars+1 > sizeof _comp) { + /* component name is too long */ + HRETURN_ERROR (H5E_DIRECTORY, H5E_COMPLEN, FAIL); + } else { + /* null terminate */ + memcpy (_comp, rest, nchars); + _comp[nchars] = '\0'; + rest = _comp; + } + } + + /* create directory */ + if (H5G_stab_new (f, ent, size_hint)<0) { + HRETURN_ERROR (H5E_DIRECTORY, H5E_CANTINIT, FAIL); /*can't create dir*/ + } + + /* insert child name into parent */ + if (H5G_stab_insert (f, dir_ent, rest, ent)<0) { + HRETURN_ERROR (H5E_DIRECTORY, H5E_CANTINIT, FAIL); /*can't insert*/ + } + + FUNC_LEAVE (SUCCEED); +} + + +/*------------------------------------------------------------------------- + * Function: H5G_find + * + * Purpose: Finds an object with the specified NAME in file F. If the + * name is relative then it is interpretted relative to CWD, + * a symbol table entry for a symbol table. On successful return, + * DIR_ENT (if non-null) will be initialized with the symbol table + * information for the directory in which the object appears + * and ENT will be initialized with the symbol table entry for + * the object. + * + * ENT is optional when the caller is interested only in the + * existence of the object. + * + * Return: Success: SUCCEED with DIR_ENT and ENT initialized. + * + * Failure: FAIL + * + * Programmer: Robb Matzke + * robb@maya.nuance.com + * Aug 12 1997 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t +H5G_find (hdf5_file_t *f, H5G_entry_t *cwd, H5G_entry_t *dir_ent, + const char *name, H5G_entry_t *ent) +{ + FUNC_ENTER (H5G_find, NULL, FAIL); + + /* check args */ + assert (f); + assert (name && *name); + assert (cwd || '/'==*name); + + if (H5G_namei (f, cwd, name, NULL, dir_ent, ent)<0) { + HRETURN_ERROR (H5E_DIRECTORY, H5E_NOTFOUND, FAIL); /*object not found*/ + } + + FUNC_LEAVE (SUCCEED); +} + + +/*------------------------------------------------------------------------- + * Function: H5G_insert + * + * Purpose: Inserts symbol table ENT into the directory hierarchy + * giving it the specified NAME. If NAME is relative then + * it is interpreted with respect to the CWD pointer. If + * non-null, DIR_ENT will be initialized with the symbol table + * entry for the directory which contains the new ENT. + * + * NAME must not be the name of the root symbol table entry + * ('/') since that is a special case. If NAME is the root + * symbol table entry, then this function will return failure. + * + * Return: Success: SUCCEED with optional DIR_ENT initialized with + * the symbol table entry for the directory + * which contains the new ENT. + * + * Failure: FAIL (DIR_ENT is not modified). + * + * Programmer: Robb Matzke + * robb@maya.nuance.com + * Aug 11 1997 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t +H5G_insert (hdf5_file_t *f, H5G_entry_t *cwd, H5G_entry_t *dir_ent, + const char *name, H5G_entry_t *ent) +{ + herr_t status; + const char *rest=NULL; + H5G_entry_t _parent; + size_t nchars; + char _comp[1024]; + + FUNC_ENTER (H5G_insert, NULL, FAIL); + + /* check args */ + assert (f); + assert (name && *name); + assert (cwd || '/'==*name); + assert (ent); + if (!dir_ent) dir_ent = &_parent; + + /* lookup name */ + status = H5G_namei (f, cwd, name, &rest, dir_ent, NULL); + if (status<0 && !rest) { + HRETURN_ERROR (H5E_DIRECTORY, H5E_CANTINIT, FAIL); /*lookup failed*/ + } else if (0==status) { + HRETURN_ERROR (H5E_DIRECTORY, H5E_EXISTS, FAIL); /*already exists*/ + } + H5ECLEAR; /*it's OK that we didn't find it*/ + + /* should be one null-terminated component left */ + rest = H5G_component (rest, &nchars); + assert (rest && *rest); + if (rest[nchars]) { + if (H5G_component (rest+nchars, NULL)) { + /* missing component */ + HRETURN_ERROR (H5E_DIRECTORY, H5E_NOTFOUND, FAIL); + } else if (nchars+1 > sizeof _comp) { + /* component name is too long */ + HRETURN_ERROR (H5E_DIRECTORY, H5E_COMPLEN, FAIL); + } else { + /* null terminate */ + memcpy (_comp, rest, nchars); + _comp[nchars] = '\0'; + rest = _comp; + } + } + + /* insert entry into parent */ + if (H5G_stab_insert (f, dir_ent, rest, ent)<0) { + HRETURN_ERROR (H5E_DIRECTORY, H5E_CANTINIT, FAIL); /*can't insert*/ + } + + FUNC_LEAVE (SUCCEED); +} + + +/*------------------------------------------------------------------------- + * Function: H5G_modify + * + * Purpose: Modifies the symbol table entry for the object with the + * specified NAME by copying the new symbol table entry ENT + * over the top of the old one. If NAME is relative then it + * is interpreted with respect to the CWD pointer. If non-null, + * DIR_ENT will be initialized with the symbol table entry for the + * directory which contains the new ENT. + * + * Do not use this function to change the entry for the root + * symbol since that's a special case. This function returns + * failure if that is attempted. + * + * Return: Success: SUCCEED with optional DIR_ENT initialized with + * the symbol table entry for the directory + * which contains the new ENT. + * + * Failure: FAIL (DIR_ENT is not modified). + * + * Programmer: Robb Matzke + * robb@maya.nuance.com + * Aug 11 1997 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t +H5G_modify (hdf5_file_t *f, H5G_entry_t *cwd, H5G_entry_t *dir_ent, + const char *name, H5G_entry_t *ent) +{ + const char *rest=NULL; + H5G_entry_t _parent; + size_t nchars; + + FUNC_ENTER (H5G_modify, NULL, FAIL); + + /* check args */ + assert (f); + assert (name && *name); + assert (cwd || '/'==*name); + assert (ent); + if (!dir_ent) dir_ent = &_parent; + + /* lookup name */ + if (H5G_namei (f, cwd, name, &rest, dir_ent, NULL)<0) { + HRETURN_ERROR (H5E_DIRECTORY, H5E_NOTFOUND, FAIL); /*entry not found*/ + } + + /* get the base name */ + rest = H5G_basename (name, &nchars); + + /* cannot modify the root symbol entry */ + if (!*rest) HRETURN_ERROR (H5E_DIRECTORY, H5E_NOTFOUND, FAIL); + + /* modify entry in parent */ + if (H5G_stab_modify (f, dir_ent, rest, ent)<0) { + HRETURN_ERROR (H5E_DIRECTORY, H5E_CANTINIT, FAIL); /*can't modify*/ + } + + FUNC_LEAVE (SUCCEED); +} + + + +/*------------------------------------------------------------------------- * Function: H5G_stab_new * * Purpose: Creates a new empty symbol table (object header, name heap, * and B-tree). The caller can specify an initial size for the - * name heap. If no size is specified then a default heap is - * created when the first symbol is added to the table. - * - * The B-tree is created when the first symbol is added to - * the table. + * name heap. * * In order for the B-tree to operate correctly, the first * item in the heap is the empty string, and must appear at @@ -91,40 +646,39 @@ H5G_stab_new (hdf5_file_t *f, H5G_entry_t *self, size_t init) * Check arguments. */ assert (f); + init = MAX(init, H5H_SIZEOF_FREE(f)+2); /* Create symbol table private heap */ - if (init>0) { - if ((stab.heap = H5H_new (f, H5H_LOCAL, init))<0) { - HRETURN_ERROR (H5E_SYM, H5E_CANTINIT, FAIL); - } - if ((name = H5H_insert (f, stab.heap, 1, "")<0)) { - HRETURN_ERROR (H5E_SYM, H5E_CANTINIT, FAIL); - } - if (0!=name) { - /* - * B-tree's won't work if the first name isn't at the beginning - * of the heap. - */ - HRETURN_ERROR (H5E_INTERNAL, H5E_CANTINIT, FAIL); - } - } else { - stab.heap = 0; /*we'll create it later*/ + if ((stab.heap = H5H_new (f, H5H_LOCAL, init))<0) { + HRETURN_ERROR (H5E_SYM, H5E_CANTINIT, FAIL); + } + if ((name = H5H_insert (f, stab.heap, 1, "")<0)) { + HRETURN_ERROR (H5E_SYM, H5E_CANTINIT, FAIL); + } + if (0!=name) { + /* + * B-tree's won't work if the first name isn't at the beginning + * of the heap. + */ + HRETURN_ERROR (H5E_INTERNAL, H5E_CANTINIT, FAIL); } - /* The B-tree is created on demand later */ - stab.btree = 0; + /* Create the B-tree */ + if ((stab.btree = H5B_new (f, H5B_SNODE))<0) { + HRETURN_ERROR (H5E_SYM, H5E_CANTINIT, FAIL); + } /* Create symbol table object header with a single link */ if ((addr = H5O_new (f, 1, 4+2*H5F_SIZEOF_OFFSET(f)))<0) { HRETURN_ERROR (H5E_SYM, H5E_CANTINIT, FAIL); } + + /* insert the symbol table message */ if (self) { self->name_off = 0; self->header = addr; self->type = H5G_NOTHING_CACHED; } - - /* insert the symbol table message */ if (H5O_modify(f, addr, self, NULL, H5O_STAB, H5O_NEW_MESG, &stab)<0) { HRETURN_ERROR (H5E_SYM, H5E_CANTINIT, FAIL); } @@ -165,15 +719,11 @@ H5G_stab_find (hdf5_file_t *f, H5G_entry_t *self, const char *name, assert (f); assert (self && self->header>=0); assert (name && *name); - assert (ent); /* set up the udata */ if (NULL==H5O_read (f, self->header, self, H5O_STAB, 0, &stab)) { HRETURN_ERROR (H5E_SYM, H5E_BADMESG, FAIL); } - if (stab.btree<=0 || stab.heap<=0) { - HRETURN_ERROR (H5E_SYM, H5E_NOTFOUND, FAIL); /*empty symbol table*/ - } udata.operation = H5G_OPER_FIND; udata.name = name; udata.heap = stab.heap; @@ -228,9 +778,6 @@ H5G_stab_modify (hdf5_file_t *f, H5G_entry_t *self, const char *name, if (NULL==H5O_read (f, self->header, self, H5O_STAB, 0, &stab)) { HRETURN_ERROR (H5E_SYM, H5E_BADMESG, FAIL); } - if (stab.btree<=0 || stab.heap<=0) { - HRETURN_ERROR (H5E_SYM, H5E_NOTFOUND, FAIL); /*empty symbol table*/ - } udata.operation = H5G_OPER_MODIFY; udata.name = name; udata.heap = stab.heap; @@ -270,7 +817,6 @@ H5G_stab_insert (hdf5_file_t *f, H5G_entry_t *self, const char *name, { H5O_stab_t stab; /*symbol table message */ H5G_node_ud1_t udata; /*data to pass through B-tree */ - off_t offset; /*offset of name within heap */ FUNC_ENTER (H5G_stab_insert, NULL, FAIL); @@ -280,34 +826,15 @@ H5G_stab_insert (hdf5_file_t *f, H5G_entry_t *self, const char *name, assert (name && *name); assert (ent); - /* make sure we have a B-tree and a heap */ + /* initialize data to pass through B-tree */ if (NULL==H5O_read (f, self->header, self, H5O_STAB, 0, &stab)) { HRETURN_ERROR (H5E_SYM, H5E_BADMESG, FAIL); } - if (stab.btree<=0 || stab.heap<=0) { - if (stab.btree<=0 && - (stab.btree = H5B_new (f, H5B_SNODE))<0) { - HRETURN_ERROR (H5E_SYM, H5E_CANTINIT, FAIL); - } - if (stab.heap<=0) { - stab.heap = H5H_new (f, H5H_LOCAL, - MAX(strlen(name)+1, H5G_INIT_HEAP)); - if (stab.heap<0) { - HRETURN_ERROR (H5E_SYM, H5E_CANTINIT, FAIL); - } - if (0!=(offset = H5H_insert (f, stab.heap, 1, ""))) { - HRETURN_ERROR (H5E_INTERNAL, H5E_CANTINIT, FAIL); - } - } - if (H5O_modify (f, self->header, self, NULL, H5O_STAB, 0, &stab)<0) { - HRETURN_ERROR (H5E_SYM, H5E_CANTINIT, FAIL); - } - } - - /* initialize data to pass through B-tree */ udata.name = name; udata.heap = stab.heap; udata.entry = *ent; + + /* insert */ if (H5B_insert (f, H5B_SNODE, stab.btree, &udata)<0) { HRETURN_ERROR (H5E_SYM, H5E_CANTINSERT, FAIL); } @@ -358,18 +885,18 @@ H5G_stab_list (hdf5_file_t *f, H5G_entry_t *self, intn maxentries, assert (self && self->header>=0); assert (maxentries>=0); + /* initialize data to pass through B-tree */ if (NULL==H5O_read (f, self->header, self, H5O_STAB, 0, &stab)) { HRETURN_ERROR (H5E_SYM, H5E_BADMESG, FAIL); } - if (stab.btree<=0 || stab.heap<=0) HRETURN (0); /*empty directory*/ - udata.entry = entries; udata.name = names; udata.heap = stab.heap; udata.maxentries = maxentries; udata.nsyms = 0; - if (names) HDmemset (names, 0, maxentries); + + /* list */ if (H5B_list (f, H5B_SNODE, stab.btree, &udata)<0) { if (names) { for (i=0; iheap, rt_key->offset))) { HRETURN_ERROR (H5E_SYM, H5E_NOTFOUND, FAIL); } - if (HDstrcmp (udata->name, s)>0) HRETURN(-1); + if (HDstrcmp (udata->name, s)>0) HRETURN(1); FUNC_LEAVE (0); } diff --git a/src/H5Gprivate.h b/src/H5Gprivate.h index 0e4057d..bbfe9a0 100644 --- a/src/H5Gprivate.h +++ b/src/H5Gprivate.h @@ -27,7 +27,7 @@ #define H5G_NODE_MAGIC "SNOD" /*symbol table node magic number */ #define H5G_NODE_SIZEOF_MAGIC 4 /*sizeof symbol node magic number */ #define H5G_NODE_VERS 1 /*symbol table node version number */ -#define H5G_NODE_K 64 /*min degree. max degree is twice this */ +#define H5G_NODE_K 4 /*min degree. max degree is twice this */ #define H5G_NODE_SIZEOF_HDR(F) (H5G_NODE_SIZEOF_MAGIC + 4) #define H5G_SIZEOF_ENTRY(F) \ (H5F_SIZEOF_OFFSET(F) + /*offset of name into heap */ \ @@ -133,8 +133,19 @@ extern const H5B_class_t H5B_SNODE[1]; /* * Library prototypes... */ -herr_t H5G_node_debug (hdf5_file_t *f, haddr_t addr, FILE *stream, intn indent, - intn fwidth, haddr_t heap); + +/* functions that understand directories */ +herr_t H5G_mkroot (hdf5_file_t *f, size_t size_hint); +herr_t H5G_new (hdf5_file_t *f, H5G_entry_t *cwd, H5G_entry_t *dir_ent, + const char *name, size_t size_hint, H5G_entry_t *ent); +herr_t H5G_find (hdf5_file_t *f, H5G_entry_t *cwd, H5G_entry_t *dir_ent, + const char *name, H5G_entry_t *ent); +herr_t H5G_insert (hdf5_file_t *f, H5G_entry_t *cwd, H5G_entry_t *dir_ent, + const char *name, H5G_entry_t *ent); +herr_t H5G_modify (hdf5_file_t *f, H5G_entry_t *cwd, H5G_entry_t *dir_ent, + const char *name, H5G_entry_t *ent); + +/* functions that understand symbol tables */ haddr_t H5G_stab_new (hdf5_file_t *f, H5G_entry_t *self, size_t init); haddr_t H5G_stab_find (hdf5_file_t *f, H5G_entry_t *self, const char *name, H5G_entry_t *ent); @@ -144,6 +155,12 @@ herr_t H5G_stab_insert (hdf5_file_t *f, H5G_entry_t *self, const char *name, H5G_entry_t *ent); intn H5G_stab_list (hdf5_file_t *f, H5G_entry_t *self, intn maxentries, char *names[], H5G_entry_t entries[]); + +/* functions that understand symbol table nodes */ +herr_t H5G_node_debug (hdf5_file_t *f, haddr_t addr, FILE *stream, intn indent, + intn fwidth, haddr_t heap); + +/* functions that understand symbol table entries */ herr_t H5G_decode (hdf5_file_t *f, uint8 **pp, H5G_entry_t *ent); herr_t H5G_decode_vec (hdf5_file_t *f, uint8 **pp, H5G_entry_t *ent, intn n); herr_t H5G_encode (hdf5_file_t *f, uint8 **pp, H5G_entry_t *ent); diff --git a/src/H5H.c b/src/H5H.c index 8c90095..ddf5055 100644 --- a/src/H5H.c +++ b/src/H5H.c @@ -30,16 +30,6 @@ #define H5H_FREE_NULL 1 /*end of free list on disk */ #define PABLO_MASK H5H_mask -#define H5H_SIZEOF_HDR(F) \ - (H5H_SIZEOF_MAGIC + /*heap signature */ \ - H5F_SIZEOF_SIZE (F) + /*data size */ \ - H5F_SIZEOF_OFFSET (F) + /*free list head */ \ - H5F_SIZEOF_OFFSET (F)) /*data address */ - -#define H5H_SIZEOF_FREE(F) \ - (H5F_SIZEOF_OFFSET (F) + /*ptr to next free block */ \ - H5F_SIZEOF_SIZE (F)) /*size of this free block */ - typedef struct H5H_free_t { off_t offset; /*offset of free block */ size_t size; /*size of free block */ diff --git a/src/H5Hprivate.h b/src/H5Hprivate.h index 6a05049..a11adde 100644 --- a/src/H5Hprivate.h +++ b/src/H5Hprivate.h @@ -24,6 +24,17 @@ #define H5H_SIZEOF_MAGIC 4 #define H5H_ALIGN(X) ((X)=((X)+1) & ~0x01) +#define H5H_SIZEOF_HDR(F) \ + (H5H_SIZEOF_MAGIC + /*heap signature */ \ + H5F_SIZEOF_SIZE (F) + /*data size */ \ + H5F_SIZEOF_OFFSET (F) + /*free list head */ \ + H5F_SIZEOF_OFFSET (F)) /*data address */ + +#define H5H_SIZEOF_FREE(F) \ + (H5F_SIZEOF_OFFSET (F) + /*ptr to next free block */ \ + H5F_SIZEOF_SIZE (F)) /*size of this free block */ + + typedef enum H5H_type_t { H5H_LOCAL =0, /*local symtab name heap */ H5H_GLOBAL =1 /*global small object heap */ diff --git a/src/H5O.c b/src/H5O.c index 1b259ba..c594964 100644 --- a/src/H5O.c +++ b/src/H5O.c @@ -62,7 +62,7 @@ static const H5O_class_t *const message_type_g[] = { NULL, /*0x000A Data storage -- sparse object */ NULL, /*0x000B Data storage -- compressed object */ NULL, /*0x000C Attribute list */ - NULL, /*0x000D Object name */ + H5O_NAME, /*0x000D Object name */ NULL, /*0x000E Object modification date and time */ NULL, /*0x000F Shared header message */ H5O_CONT, /*0x0010 Object header continuation */ @@ -273,8 +273,8 @@ H5O_load (hdf5_file_t *f, haddr_t addr, const void *_data) for (chunk_addr=0; 0==chunk_addr && curmesgnmesgs; curmesg++) { if (H5O_CONT_ID==oh->mesg[curmesg].type->id) { uint8 *p2 = oh->mesg[curmesg].raw; - oh->mesg[curmesg].native = (H5O_CONT->decode)(f, p2); - cont = (H5O_cont_t*)(oh->mesg[curmesg].native); + cont = (H5O_CONT->decode)(f, oh->mesg[curmesg].raw_size, p2); + oh->mesg[curmesg].native = cont; chunk_addr = cont->addr; chunk_size = cont->size; cont->chunkno = oh->nchunks; /*the next chunk to allocate*/ @@ -407,12 +407,8 @@ H5O_flush (hdf5_file_t *f, hbool_t destroy, haddr_t addr, H5O_t *oh) /* destroy messages */ for (i=0; inmesgs; i++) { if (oh->mesg[i].native) { - if (oh->mesg[i].type->free) { - (oh->mesg[i].type->free)(oh->mesg[i].native); - oh->mesg[i].native = NULL; - } else { - oh->mesg[i].native = H5MM_xfree (oh->mesg[i].native); - } + H5O_reset (oh->mesg[i].type, oh->mesg[i].native); + oh->mesg[i].native = H5MM_xfree (oh->mesg[i].native); } } oh->mesg = H5MM_xfree (oh->mesg); @@ -426,6 +422,43 @@ H5O_flush (hdf5_file_t *f, hbool_t destroy, haddr_t addr, H5O_t *oh) /*------------------------------------------------------------------------- + * Function: H5O_reset + * + * Purpose: Some message data structures have internal fields that + * need to be freed. This function does that if appropriate + * but doesn't free NATIVE. + * + * Return: Success: SUCCEED + * + * Failure: FAIL + * + * Programmer: Robb Matzke + * robb@maya.nuance.com + * Aug 12 1997 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t +H5O_reset (const H5O_class_t *type, void *native) +{ + FUNC_ENTER (H5O_reset, NULL, FAIL); + + if (type->reset) { + if ((type->reset)(native)<0) { + /* reset class method failed */ + HRETURN_ERROR (H5E_OHDR, H5E_CANTINIT, FAIL); + } + } else { + HDmemset (native, 0, type->native_size); + } + + FUNC_LEAVE (SUCCEED); +} + + +/*------------------------------------------------------------------------- * Function: H5O_link * * Purpose: Adjust the link count for an object header by adding @@ -586,7 +619,9 @@ H5O_find_in_ohdr (hdf5_file_t *f, haddr_t addr, const H5O_class_t **type_p, /* decode the message if necessary */ if (NULL==oh->mesg[i].native) { assert (oh->mesg[i].type->decode); - oh->mesg[i].native = (oh->mesg[i].type->decode)(f, oh->mesg[i].raw); + oh->mesg[i].native = (oh->mesg[i].type->decode)(f, + oh->mesg[i].raw_size, + oh->mesg[i].raw); if (NULL==oh->mesg[i].native) { HRETURN_ERROR (H5E_OHDR, H5E_CANTDECODE, FAIL); } @@ -709,7 +744,7 @@ H5O_modify (hdf5_file_t *f, haddr_t addr, H5G_entry_t *ent, /* Allocate space for the new message */ if (overwrite<0) { - size = (type->size)(f, mesg); + size = (type->raw_size)(f, mesg); H5O_ALIGN (size, oh->alignment); idx = H5O_alloc (f, oh, type, size); if (idx<0) HRETURN_ERROR (H5E_OHDR, H5E_CANTINIT, FAIL); @@ -1220,7 +1255,9 @@ H5O_debug (hdf5_file_t *f, haddr_t addr, FILE *stream, /* decode the message */ if (NULL==oh->mesg[i].native && oh->mesg[i].type->decode) { - oh->mesg[i].native = (oh->mesg[i].type->decode)(f, oh->mesg[i].raw); + oh->mesg[i].native = (oh->mesg[i].type->decode)(f, + oh->mesg[i].raw_size, + oh->mesg[i].raw); } /* print the message */ diff --git a/src/H5Ocont.c b/src/H5Ocont.c index 7b184cb..045489c 100644 --- a/src/H5Ocont.c +++ b/src/H5Ocont.c @@ -26,7 +26,7 @@ #define PABLO_MASK H5O_cont_mask /* PRIVATE PROTOTYPES */ -static void *H5O_cont_decode (hdf5_file_t *f, const uint8 *p); +static void *H5O_cont_decode (hdf5_file_t *f, size_t raw_size, const uint8 *p); static herr_t H5O_cont_encode (hdf5_file_t *f, size_t size, uint8 *p, const void *_mesg); static herr_t H5O_cont_debug (hdf5_file_t *f, const void *_mesg, FILE *stream, @@ -36,13 +36,14 @@ static herr_t H5O_cont_debug (hdf5_file_t *f, const void *_mesg, FILE *stream, const H5O_class_t H5O_CONT[1] = {{ H5O_CONT_ID, /*message id number */ "hdr continuation", /*message name for debugging */ + sizeof (H5O_cont_t), /*native message size */ H5O_cont_decode, /*decode message */ H5O_cont_encode, /*encode message */ NULL, /*no fast method */ NULL, /*no cache method */ NULL, /*no copy method */ NULL, /*no size method */ - NULL, /*default free method */ + NULL, /*default reset method */ H5O_cont_debug, /*debugging */ }}; @@ -68,12 +69,18 @@ static intn interface_initialize_g = FALSE; *------------------------------------------------------------------------- */ static void * -H5O_cont_decode (hdf5_file_t *f, const uint8 *p) +H5O_cont_decode (hdf5_file_t *f, size_t raw_size, const uint8 *p) { H5O_cont_t *cont = NULL; FUNC_ENTER (H5O_cont_decode, NULL, NULL); + /* check args */ + assert (f); + assert (raw_size == H5F_SIZEOF_OFFSET(f) + H5F_SIZEOF_SIZE(f)); + assert (p); + + /* decode */ cont = H5MM_xcalloc (1, sizeof(H5O_cont_t)); H5F_decode_offset (f, p, cont->addr); H5F_decode_length (f, p, cont->size); diff --git a/src/H5Oname.c b/src/H5Oname.c new file mode 100644 index 0000000..643efcc --- /dev/null +++ b/src/H5Oname.c @@ -0,0 +1,283 @@ +/*------------------------------------------------------------------------- + * Copyright (C) 1997 National Center for Supercomputing Applications. + * All rights reserved. + * + *------------------------------------------------------------------------- + * + * Created: H5Oname.c + * Aug 12 1997 + * Robb Matzke + * + * Purpose: Object name message. + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +#include + +#include "hdf5.h" + +#include "H5private.h" +#include "H5MMprivate.h" +#include "H5Oprivate.h" + +#define PABLO_MASK H5O_name_mask + +/* PRIVATE PROTOTYPES */ +static void *H5O_name_decode (hdf5_file_t *f, size_t raw_size, const uint8 *p); +static herr_t H5O_name_encode (hdf5_file_t *f, size_t raw_size, uint8 *p, + const void *_mesg); +static void *H5O_name_copy (const void *_mesg, void *_dest); +static size_t H5O_name_size (hdf5_file_t *f, const void *_mesg); +static herr_t H5O_name_reset (void *_mesg); +static herr_t H5O_name_debug (hdf5_file_t *f, const void *_mesg, FILE *stream, + intn indent, intn fwidth); + +/* This message derives from H5O */ +const H5O_class_t H5O_NAME[1] = {{ + H5O_NAME_ID, /*message id number */ + "name", /*message name for debugging */ + sizeof (H5O_name_t), /*native message size */ + H5O_name_decode, /*decode message */ + H5O_name_encode, /*encode message */ + NULL, /*no stab entry fields */ + NULL, /*no stab entry fields */ + H5O_name_copy, /*copy the native value */ + H5O_name_size, /*raw message size */ + H5O_name_reset, /*free internal memory */ + H5O_name_debug, /*debug the message */ +}}; + +/* Is the interface initialized? */ +static hbool_t interface_initialize_g = FALSE; + + +/*------------------------------------------------------------------------- + * Function: H5O_name_decode + * + * Purpose: Decode a name message and return a pointer to a new + * native message struct. + * + * Return: Success: Ptr to new message in native struct. + * + * Failure: NULL + * + * Programmer: Robb Matzke + * robb@maya.nuance.com + * Aug 12 1997 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static void * +H5O_name_decode (hdf5_file_t *f, size_t raw_size, const uint8 *p) +{ + H5O_name_t *mesg; + + FUNC_ENTER (H5O_name_decode, NULL, NULL); + + /* check args */ + assert (f); + assert (p); + + /* decode */ + mesg = H5MM_xcalloc (1, sizeof(H5O_name_t)); + mesg->s = H5MM_xmalloc (raw_size); + HDmemcpy (mesg->s, p, raw_size); + + FUNC_LEAVE (mesg); +} + + +/*------------------------------------------------------------------------- + * Function: H5O_name_encode + * + * Purpose: Encodes a name message. + * + * Return: Success: SUCCEED + * + * Failure: FAIL + * + * Programmer: Robb Matzke + * robb@maya.nuance.com + * Aug 12 1997 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static herr_t +H5O_name_encode (hdf5_file_t *f, size_t raw_size, uint8 *p, const void *_mesg) +{ + const H5O_name_t *mesg = (const H5O_name_t *)_mesg; + size_t size; + + FUNC_ENTER (H5O_name_encode, NULL, FAIL); + + /* check args */ + assert (f); + assert (p); + assert (mesg && mesg->s); + + /* message size */ + size = strlen (mesg->s)+1; + assert (size<=raw_size); + + /* encode */ + HDmemcpy (p, mesg->s, size); + HDmemset (p+size, 0, raw_size-size); + + FUNC_LEAVE (SUCCEED); +} + + +/*------------------------------------------------------------------------- + * Function: H5O_name_copy + * + * Purpose: Copies a message from _MESG to _DEST, allocating _DEST if + * necessary. + * + * Return: Success: Ptr to _DEST + * + * Failure: NULL + * + * Programmer: Robb Matzke + * robb@maya.nuance.com + * Aug 12 1997 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static void * +H5O_name_copy (const void *_mesg, void *_dest) +{ + const H5O_name_t *mesg = (const H5O_name_t *)_mesg; + H5O_name_t *dest = (H5O_name_t *)_dest; + + FUNC_ENTER (H5O_name_copy, NULL, NULL); + + /* check args */ + assert (mesg); + if (!dest) dest = H5MM_xcalloc (1, sizeof(H5O_name_t)); + + /* copy */ + *dest = *mesg; + dest->s = H5MM_xstrdup (mesg->s); + + FUNC_LEAVE ((void*)dest); +} + + +/*------------------------------------------------------------------------- + * Function: H5O_name_size + * + * Purpose: Returns the size of the raw message in bytes not + * counting the message typ or size fields, but only the data + * fields. This function doesn't take into account + * alignment. + * + * Return: Success: Message data size in bytes w/o alignment. + * + * Failure: FAIL + * + * Programmer: Robb Matzke + * robb@maya.nuance.com + * Aug 12 1997 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static size_t +H5O_name_size (hdf5_file_t *f, const void *_mesg) +{ + const H5O_name_t *mesg = (const H5O_name_t *)_mesg; + size_t size; + + FUNC_ENTER (H5O_stab_size, NULL, FAIL); + + /* check args */ + assert (f); + assert (mesg); + + size = mesg->s ? HDstrlen (mesg->s)+1 : 0; + FUNC_LEAVE (size); +} + + +/*------------------------------------------------------------------------- + * Function: H5O_name_reset + * + * Purpose: Frees internal pointers and resets the message to an + * initial state. + * + * Return: Success: SUCCEED + * + * Failure: FAIL + * + * Programmer: Robb Matzke + * robb@maya.nuance.com + * Aug 12 1997 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static herr_t +H5O_name_reset (void *_mesg) +{ + H5O_name_t *mesg = (H5O_name_t *)_mesg; + + FUNC_ENTER (H5O_name_reset, NULL, FAIL); + + /* check args */ + assert (mesg); + + /* reset */ + mesg->s = H5MM_xfree (mesg->s); + + FUNC_LEAVE (SUCCEED); +} + + +/*------------------------------------------------------------------------- + * Function: H5O_name_debug + * + * Purpose: Prints debugging info for the message. + * + * Return: Success: SUCCEED + * + * Failure: FAIL + * + * Programmer: Robb Matzke + * robb@maya.nuance.com + * Aug 12 1997 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static herr_t +H5O_name_debug (hdf5_file_t *f, const void *_mesg, FILE *stream, + intn indent, intn fwidth) +{ + const H5O_name_t *mesg = (const H5O_name_t *)_mesg; + + FUNC_ENTER (H5O_name_debug, NULL, FAIL); + + /* check args */ + assert (f); + assert (mesg); + assert (stream); + assert (indent>=0); + assert (fwidth>=0); + + fprintf (stream, "%*s%-*s `%s'\n", indent, "", fwidth, + "Name:", + mesg->s); + + FUNC_LEAVE (SUCCEED); +} diff --git a/src/H5Onull.c b/src/H5Onull.c index 965266d..7175273 100644 --- a/src/H5Onull.c +++ b/src/H5Onull.c @@ -24,12 +24,13 @@ const H5O_class_t H5O_NULL[1] = {{ H5O_NULL_ID, /*message id number */ "null", /*message name for debugging */ + 0, /*native message size */ NULL, /*no decode method */ NULL, /*no encode method */ NULL, /*no fast method */ NULL, /*no cache method */ NULL, /*no copy method */ NULL, /*no size method */ - NULL, /*no free method */ + NULL, /*no reset method */ NULL, /*no debug method */ }}; diff --git a/src/H5Oprivate.h b/src/H5Oprivate.h index 40d4a36..f56146c 100644 --- a/src/H5Oprivate.h +++ b/src/H5Oprivate.h @@ -41,13 +41,14 @@ typedef struct H5O_class_t { intn id; /*message type ID on disk */ const char *name; /*message name for debugging */ - void *(*decode)(hdf5_file_t*,const uint8*); /*decode mesg */ + size_t native_size; /*size of native message */ + void *(*decode)(hdf5_file_t*,size_t,const uint8*); herr_t (*encode)(hdf5_file_t*,size_t,uint8*,const void*); - void *(*fast)(const H5G_entry_t*, void*); /*get from stab ent */ + void *(*fast)(const H5G_entry_t*, void*); /*get from stab ent*/ hbool_t (*cache)(H5G_entry_t*,const void*); /*put into entry */ void *(*copy)(const void*,void*); /*copy native value */ - size_t (*size)(hdf5_file_t*,const void*); /*size of raw value */ - void *(*free)(void*); /*free native data struct */ + size_t (*raw_size)(hdf5_file_t*,const void*); /*sizeof raw val */ + herr_t (*reset)(void*); /*free nested data structures */ herr_t (*debug)(hdf5_file_t*,const void*, FILE*, intn, intn); } H5O_class_t; @@ -87,6 +88,16 @@ typedef struct H5O_t { extern const H5O_class_t H5O_NULL[1]; /* + * Object name message. + */ +#define H5O_NAME_ID 0x000d +extern const H5O_class_t H5O_NAME[1]; + +typedef struct H5O_name_t { + char *s; /*ptr to malloc'd memory */ +} H5O_name_t; + +/* * Object header continuation message. */ #define H5O_CONT_ID 0x0010 @@ -121,6 +132,7 @@ const void *H5O_peek (hdf5_file_t *f, haddr_t addr, const H5O_class_t *type, intn H5O_modify (hdf5_file_t *f, haddr_t addr, H5G_entry_t *ent, hbool_t *ent_modified, const H5O_class_t *type, intn overwrite, const void *mesg); +herr_t H5O_reset (const H5O_class_t *type, void *native); herr_t H5O_debug (hdf5_file_t *f, haddr_t addr, FILE *stream, intn indent, intn fwidth); diff --git a/src/H5Ostab.c b/src/H5Ostab.c index d2c1394..926eeef 100644 --- a/src/H5Ostab.c +++ b/src/H5Ostab.c @@ -26,7 +26,7 @@ #define PABLO_MASK H5O_stab_mask /* PRIVATE PROTOTYPES */ -static void *H5O_stab_decode (hdf5_file_t *f, const uint8 *p); +static void *H5O_stab_decode (hdf5_file_t *f, size_t raw_size, const uint8 *p); static herr_t H5O_stab_encode (hdf5_file_t *f, size_t size, uint8 *p, const void *_mesg); static void *H5O_stab_fast (const H5G_entry_t *ent, void *_mesg); @@ -40,18 +40,19 @@ static herr_t H5O_stab_debug (hdf5_file_t *f, const void *_mesg, const H5O_class_t H5O_STAB[1] = {{ H5O_STAB_ID, /*message id number */ "stab", /*message name for debugging */ + sizeof (H5O_stab_t), /*native message size */ H5O_stab_decode, /*decode message */ H5O_stab_encode, /*encode message */ H5O_stab_fast, /*get message from stab entry */ H5O_stab_cache, /*put message into stab entry */ H5O_stab_copy, /*copy the native value */ H5O_stab_size, /*size of symbol table entry */ - NULL, /*default free method */ + NULL, /*default reset method */ H5O_stab_debug, /*debug the message */ }}; /* Is the interface initialized? */ -static intn interface_initialize_g = FALSE; +static hbool_t interface_initialize_g = FALSE; /*------------------------------------------------------------------------- @@ -73,7 +74,7 @@ static intn interface_initialize_g = FALSE; *------------------------------------------------------------------------- */ static void * -H5O_stab_decode (hdf5_file_t *f, const uint8 *p) +H5O_stab_decode (hdf5_file_t *f, size_t raw_size, const uint8 *p) { H5O_stab_t *stab; @@ -81,6 +82,7 @@ H5O_stab_decode (hdf5_file_t *f, const uint8 *p) /* check args */ assert (f); + assert (raw_size == 2*H5F_SIZEOF_OFFSET(f)); assert (p); /* decode */ @@ -95,7 +97,7 @@ H5O_stab_decode (hdf5_file_t *f, const uint8 *p) /*------------------------------------------------------------------------- * Function: H5O_stab_encode * - * Purpose: Encodes a symbol table entry. + * Purpose: Encodes a symbol table message. * * Return: Success: SUCCEED * @@ -110,7 +112,7 @@ H5O_stab_decode (hdf5_file_t *f, const uint8 *p) *------------------------------------------------------------------------- */ static herr_t -H5O_stab_encode (hdf5_file_t *f, size_t size, uint8 *p, const void *_mesg) +H5O_stab_encode (hdf5_file_t *f, size_t raw_size, uint8 *p, const void *_mesg) { const H5O_stab_t *stab = (const H5O_stab_t *)_mesg; @@ -118,7 +120,7 @@ H5O_stab_encode (hdf5_file_t *f, size_t size, uint8 *p, const void *_mesg) /* check args */ assert (f); - assert (size == 2 * H5F_SIZEOF_OFFSET(f)); + assert (raw_size == 2 * H5F_SIZEOF_OFFSET(f)); assert (p); assert (stab); diff --git a/src/Makefile b/src/Makefile index 94dcd67..cfda7af 100644 --- a/src/Makefile +++ b/src/Makefile @@ -28,7 +28,8 @@ CFLAGS = -c $(MACHINE) $(DEFS) INCL = hdf5.h OBJ = H5.o H5E.o H5A.o H5F.o H5C.o H5M.o H5AC.o H5B.o H5MM.o H5MF.o H5T.o \ - H5Gnode.o H5H.o H5G.o H5P.o H5D.o H5O.o H5Onull.o H5Ocont.o H5Ostab.o + H5Gnode.o H5H.o H5G.o H5P.o H5D.o H5O.o H5Onull.o H5Ocont.o H5Ostab.o \ + H5Oname.o $(TARGET): $(OBJ) $(AR) $(ARFLAGS) $(TARGET) $(OBJ) @@ -111,3 +112,6 @@ H5Ocont.o: H5Ocont.c $(INCL) H5Oprivate.h H5Oproto.h H5Ostab.o: H5Ostab.c $(INCL) H5Oprivate.h H5Oproto.h $(CC) $(CFLAGS) H5Ostab.c + +H5Oname.o: H5Oname.c $(INCL) H5Oprivate.h H5Oproto.h + $(CC) $(CFLAGS) H5Oname.c diff --git a/src/hdf5port.h b/src/hdf5port.h index 3f3a5c2..4045435 100644 --- a/src/hdf5port.h +++ b/src/hdf5port.h @@ -170,6 +170,8 @@ typedef MPFILE *hdf_file_t; /* non-standard function, not defined on the following mahcines - */ #if !(defined VMS || defined macintosh || defined MAC || defined __MWERKS__ || defined SYMANTEC_C || defined MIPSEL || defined NEXT || defined CONVEX || defined IBM6000 || defined ANSISUN || defined IRIX) # define HDstrdup(s) ((char *)strdup((const char *)(s))) +#else +# define HDstrdup(s) strdup(s) #endif /* !(VMS | etc..) */ -- cgit v0.12