diff options
-rw-r--r-- | MANIFEST | 1 | ||||
-rw-r--r-- | src/H5E.c | 1 | ||||
-rw-r--r-- | src/H5Epublic.h | 3 | ||||
-rw-r--r-- | src/H5F.c | 2 | ||||
-rw-r--r-- | src/H5Ffamily.c | 2 | ||||
-rw-r--r-- | src/H5G.c | 428 | ||||
-rw-r--r-- | src/H5Gent.c | 26 | ||||
-rw-r--r-- | src/H5Gnode.c | 2 | ||||
-rw-r--r-- | src/H5Gprivate.h | 17 | ||||
-rw-r--r-- | src/H5Gpublic.h | 21 | ||||
-rw-r--r-- | src/H5Gstab.c | 117 | ||||
-rw-r--r-- | src/h5ls.c | 16 | ||||
-rw-r--r-- | test/.distdep | 38 | ||||
-rw-r--r-- | test/Makefile.in | 14 | ||||
-rw-r--r-- | test/big.c | 160 | ||||
-rw-r--r-- | test/links.c | 63 |
16 files changed, 807 insertions, 104 deletions
@@ -198,6 +198,7 @@ ./test/hyperslab.c ./test/iopipe.c ./test/istore.c +./test/links.c ./test/shtype.c ./test/testhdf5.c ./test/testhdf5.h @@ -100,6 +100,7 @@ static const H5E_minor_mesg_t H5E_minor_mesg_g[] = { {H5E_COMPLEN, "Name component is too long"}, {H5E_CWG, "Problem with current working group"}, {H5E_LINK, "Link count failure"}, + {H5E_SLINK, "Symbolic link error"}, }; /* Interface initialization? */ diff --git a/src/H5Epublic.h b/src/H5Epublic.h index 682be53..ee228e2 100644 --- a/src/H5Epublic.h +++ b/src/H5Epublic.h @@ -112,7 +112,8 @@ typedef enum H5E_minor_t { H5E_CANTOPENOBJ, /*Can't open object */ H5E_COMPLEN, /*name component is too long */ H5E_CWG, /*problem with current working group */ - H5E_LINK /*link count failure */ + H5E_LINK, /*link count failure */ + H5E_SLINK /*symbolic link error */ } H5E_minor_t; /* Information about an error */ @@ -1633,7 +1633,7 @@ H5F_debug(H5F_t *f, const haddr_t __unused__ *addr, FILE * stream, f->shared->root_grp ? "" : "(none)"); if (f->shared->root_grp) { H5G_ent_debug(f, H5G_entof (f->shared->root_grp), stream, - indent + 3, MAX(0, fwidth - 3)); + indent+3, MAX(0, fwidth-3), NULL); } FUNC_LEAVE(SUCCEED); } diff --git a/src/H5Ffamily.c b/src/H5Ffamily.c index a138fea..d20a380 100644 --- a/src/H5Ffamily.c +++ b/src/H5Ffamily.c @@ -197,7 +197,7 @@ H5F_fam_open(const char *name, const H5F_access_t *access_parms, * descriptors (all family members are open at once). */ #ifdef H5F_DEBUG - if (access_parms->u.fam.offset_bits+2>=8*sizeof(off_t)) { + if (access_parms->u.fam.offset_bits+2>8*sizeof(off_t)) { fprintf (stderr, "H5F: family member size may be too large.\n"); } #endif @@ -75,11 +75,12 @@ /* Packages needed by this file... */ #include <H5private.h> -#include <H5Iprivate.h> #include <H5Bprivate.h> +#include <H5Dprivate.h> #include <H5Eprivate.h> #include <H5Gpkg.h> #include <H5HLprivate.h> +#include <H5Iprivate.h> #include <H5MMprivate.h> #include <H5Oprivate.h> @@ -561,6 +562,7 @@ H5Glink (hid_t loc_id, H5G_link_t type, const char *cur_name, FUNC_ENTER (H5Glink, FAIL); + /* Check arguments */ if (NULL==(loc=H5G_loc (loc_id))) { HRETURN_ERROR (H5E_ARGS, H5E_BADTYPE, FAIL, "not a location"); } @@ -615,6 +617,93 @@ H5Gunlink (hid_t __unused__ loc_id, const char __unused__ *name) FUNC_LEAVE (SUCCEED); } + +/*------------------------------------------------------------------------- + * Function: H5Gstat + * + * Purpose: Returns information about an object. If FOLLOW_LINK is + * non-zero then all symbolic links are followed; otherwise all + * links except the last component of the name are followed. + * + * Return: Success: SUCCEED with the fields of STATBUF (if + * non-null) initialized. + * + * Failure: FAIL + * + * Programmer: Robb Matzke + * Monday, April 13, 1998 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t +H5Gstat (hid_t loc_id, const char *name, hbool_t follow_link, + H5G_stat_t *statbuf/*out*/) +{ + H5G_t *loc = NULL; + + FUNC_ENTER (H5Gstat, FAIL); + + /* Check arguments */ + if (NULL==(loc=H5G_loc (loc_id))) { + HRETURN_ERROR (H5E_ARGS, H5E_BADTYPE, FAIL, "not a location"); + } + if (!name || !*name) { + HRETURN_ERROR (H5E_ARGS, H5E_BADVALUE, FAIL, "no name specified"); + } + + /* Get info */ + if (H5G_stat (loc, name, follow_link, statbuf)<0) { + HRETURN_ERROR (H5E_ARGS, H5E_CANTINIT, FAIL, "cannot stat object"); + } + + FUNC_LEAVE (SUCCEED); +} + + +/*------------------------------------------------------------------------- + * Function: H5Gget_linkval + * + * Purpose: Returns the value of a symbolic link whose name is NAME. At + * most SIZE characters (counting the null terminator) are + * copied to the BUF result buffer. + * + * Return: Success: SUCCEED, the link value is in BUF. + * + * Failure: FAIL + * + * Programmer: Robb Matzke + * Monday, April 13, 1998 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t +H5Gget_linkval (hid_t loc_id, const char *name, size_t size, char *buf/*out*/) +{ + H5G_t *loc = NULL; + + FUNC_ENTER (H5Gget_linkval, FAIL); + + /* Check arguments */ + if (NULL==(loc=H5G_loc (loc_id))) { + HRETURN_ERROR (H5E_ARGS, H5E_BADTYPE, FAIL, "not a location"); + } + if (!name || !*name) { + HRETURN_ERROR (H5E_ARGS, H5E_BADVALUE, FAIL, "no name specified"); + } + + /* Get the link value */ + if (H5G_linkval (loc, name, size, buf)<0) { + HRETURN_ERROR (H5E_SYM, H5E_NOTFOUND, FAIL, + "unable to get link value"); + } + + FUNC_LEAVE (SUCCEED); +} + /* *------------------------------------------------------------------------- *------------------------------------------------------------------------- @@ -746,12 +835,18 @@ H5G_component(const char *name, size_t *size_p) * LOC_ENT. The component `.' is a no-op, but `..' is not * understood by this function (unless it appears as an entry in * the symbol table). + * + * Symbolic links are followed automatically, but if + * FOLLOW_SLINK is false and the last component of the name is a + * symbolic link then that link is not followed. At most NLINKS + * are followed and the next link generates an error. * * Errors: * * Return: Success: SUCCEED if name can be fully resolved. See * above for values of REST, GRP_ENT, and - * OBJ_ENT. + * OBJ_ENT. NLINKS has been decremented for + * each symbolic link that was followed. * * Failure: FAIL if the name could not be fully resolved. * See above for values of REST, GRP_ENT, and @@ -767,22 +862,21 @@ H5G_component(const char *name, size_t *size_p) */ static herr_t H5G_namei(H5G_entry_t *loc_ent, const char *name, const char **rest/*out*/, - H5G_entry_t *grp_ent/*out*/, H5G_entry_t *obj_ent/*out*/) + H5G_entry_t *grp_ent/*out*/, H5G_entry_t *obj_ent/*out*/, + hbool_t follow_slink, intn *nlinks) { H5G_entry_t _grp_ent; /*entry for current group */ H5G_entry_t _obj_ent; /*entry found */ size_t nchars; /*component name length */ char comp[1024]; /*component name buffer */ - - /* clear output args before FUNC_ENTER() in case it fails */ + int _nlinks = H5G_NLINKS; + const char *s = NULL; + if (rest) *rest = name; if (!grp_ent) grp_ent = &_grp_ent; if (!obj_ent) obj_ent = &_obj_ent; - memset(grp_ent, 0, sizeof(H5G_entry_t)); - H5F_addr_undef(&(grp_ent->header)); - memset(obj_ent, 0, sizeof(H5G_entry_t)); - H5F_addr_undef(&(obj_ent->header)); - + if (!nlinks) nlinks = &_nlinks; + FUNC_ENTER(H5G_namei, FAIL); /* @@ -799,6 +893,9 @@ H5G_namei(H5G_entry_t *loc_ent, const char *name, const char **rest/*out*/, } else { *obj_ent = *loc_ent; } + memset(grp_ent, 0, sizeof(H5G_entry_t)); + H5F_addr_undef(&(grp_ent->header)); + /* traverse the name */ while ((name = H5G_component(name, &nchars)) && *name) { @@ -837,6 +934,24 @@ H5G_namei(H5G_entry_t *loc_ent, const char *name, const char **rest/*out*/, */ HRETURN_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "component not found"); } + + /* + * If we found a symbolic link then we should follow it. But if this + * is the last component of the name and FOLLOW_SLINK is zero then we + * don't follow it. + */ + if (H5G_CACHED_SLINK==obj_ent->type && + (follow_slink || ((s=H5G_component(name+nchars, NULL)) && *s))) { + if ((*nlinks)-- <= 0) { + HRETURN_ERROR (H5E_SYM, H5E_SLINK, FAIL, + "too many symbolic links"); + } + if (H5G_traverse_slink (grp_ent, obj_ent, nlinks)<0) { + HRETURN_ERROR (H5E_SYM, H5E_NOTFOUND, FAIL, + "symbolic link traversal failed"); + } + } + /* next component */ name += nchars; } @@ -847,6 +962,63 @@ H5G_namei(H5G_entry_t *loc_ent, const char *name, const char **rest/*out*/, /*------------------------------------------------------------------------- + * Function: H5G_traverse_slink + * + * Purpose: Traverses symbolic link. The link head appears in the group + * whose entry is GRP_ENT and the link head entry is OBJ_ENT. + * + * Return: Success: SUCCEED, OBJ_ENT will contain information + * about the object to which the link points and + * GRP_ENT will contain the information about + * the group in which the link tail appears. + * + * Failure: FAIL + * + * Programmer: Robb Matzke + * Friday, April 10, 1998 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t +H5G_traverse_slink (H5G_entry_t *grp_ent/*in,out*/, + H5G_entry_t *obj_ent/*in,out*/, + intn *nlinks/*in,out*/) +{ + H5O_stab_t stab_mesg; /*info about local heap */ + const char *clv = NULL; /*cached link value */ + char *linkval = NULL; /*the copied link value */ + herr_t ret_value = FAIL; /*return value */ + + FUNC_ENTER (H5G_traverse_slink, FAIL); + + /* Get the link value */ + if (NULL==H5O_read (grp_ent, H5O_STAB, 0, &stab_mesg)) { + HGOTO_ERROR (H5E_SYM, H5E_NOTFOUND, FAIL, + "unable to determine local heap address"); + } + if (NULL==(clv=H5HL_peek (grp_ent->file, &(stab_mesg.heap_addr), + obj_ent->cache.slink.lval_offset))) { + HGOTO_ERROR (H5E_SYM, H5E_NOTFOUND, FAIL, + "unable to read symbolic link value"); + } + linkval = H5MM_xstrdup (clv); + + /* Traverse the link */ + if (H5G_namei (grp_ent, linkval, NULL, grp_ent, obj_ent, TRUE, nlinks)) { + HGOTO_ERROR (H5E_SYM, H5E_NOTFOUND, FAIL, + "unable to follow symbolic link"); + } + ret_value = SUCCEED; + + done: + H5MM_xfree (linkval); + FUNC_LEAVE (ret_value); +} + + +/*------------------------------------------------------------------------- * Function: H5G_mkroot * * Purpose: Creates a root group in an empty file and opens it. If a @@ -963,7 +1135,8 @@ H5G_create(H5G_t *loc, const char *name, size_t size_hint) assert(name && *name); /* lookup name */ - if (0 == H5G_namei(H5G_entof(loc), name, &rest, &grp_ent, NULL)) { + if (0 == H5G_namei(H5G_entof(loc), name, &rest, &grp_ent, NULL, + TRUE, NULL)) { HRETURN_ERROR(H5E_SYM, H5E_EXISTS, NULL, "already exists"); } H5E_clear(); /*it's OK that we didn't find it */ @@ -1338,7 +1511,7 @@ H5G_insert(H5G_t *loc, const char *name, H5G_entry_t *ent) /* * Look up the name -- it shouldn't exist yet. */ - if (H5G_namei(H5G_entof(loc), name, &rest, &grp, NULL) >= 0) { + if (H5G_namei(H5G_entof(loc), name, &rest, &grp, NULL, TRUE, NULL) >= 0) { HRETURN_ERROR(H5E_SYM, H5E_EXISTS, FAIL, "already exists"); } H5E_clear(); /*it's OK that we didn't find it */ @@ -1411,7 +1584,8 @@ H5G_find(H5G_t *loc, const char *name, assert (loc); assert (name && *name); - if (H5G_namei(H5G_entof(loc), name, NULL, grp_ent, obj_ent) < 0) { + if (H5G_namei(H5G_entof(loc), name, NULL, grp_ent, obj_ent, + TRUE, NULL)<0) { HRETURN_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "object not found"); } FUNC_LEAVE(SUCCEED); @@ -1531,7 +1705,13 @@ herr_t H5G_link (H5G_t *loc, H5G_type_t type, const char *cur_name, const char *new_name) { - H5G_entry_t cur_obj; + H5G_entry_t cur_obj; /*entry for the link tail */ + H5G_entry_t grp_ent; /*ent for grp containing link hd*/ + H5O_stab_t stab_mesg; /*symbol table message */ + const char *rest = NULL; /*last component of new name */ + char _comp[1024]; /*name component */ + size_t nchars; /*characters in component */ + size_t offset; /*offset to sym-link value */ FUNC_ENTER (H5G_link, FAIL); @@ -1542,8 +1722,74 @@ H5G_link (H5G_t *loc, H5G_type_t type, const char *cur_name, switch (type) { case H5G_LINK_SOFT: - HRETURN_ERROR (H5E_SYM, H5E_UNSUPPORTED, FAIL, - "unable to create soft link (not implemented yet)"); + /* + * Lookup the the new_name so we can get the group which will contain + * the new entry. The entry shouldn't exist yet. + */ + if (H5G_namei (H5G_entof(loc), new_name, &rest, &grp_ent, NULL, + TRUE, NULL)>=0) { + HRETURN_ERROR (H5E_SYM, H5E_EXISTS, FAIL, "already exists"); + } + H5E_clear (); /*it's okay that we didn't find it*/ + rest = H5G_component (rest, &nchars); + + /* + * There should be one component left. Make sure it's null + * terminated and that `rest' points to it. + */ + if (rest[nchars]) { + if (H5G_component (rest+nchars, NULL)) { + HRETURN_ERROR (H5E_SYM, H5E_NOTFOUND, FAIL, + "component not found"); + } else if (nchars+1 > sizeof _comp) { + HRETURN_ERROR (H5E_SYM, H5E_COMPLEN, FAIL, + "name component is too long"); + } else { + HDmemcpy (_comp, rest, nchars); + _comp[nchars] = '\0'; + rest = _comp; + } + } + + /* + * Add the link-value to the local heap for the symbol table which + * will contain the link. + */ + if (NULL==H5O_read (&grp_ent, H5O_STAB, 0, &stab_mesg)) { + HRETURN_ERROR (H5E_SYM, H5E_CANTINIT, FAIL, + "unable to determine local heap address"); + } + if ((size_t)(-1)==(offset=H5HL_insert (grp_ent.file, + &(stab_mesg.heap_addr), + strlen(cur_name)+1, + cur_name))) { + HRETURN_ERROR (H5E_SYM, H5E_CANTINIT, FAIL, + "unable to write link value to local heap"); + } + H5O_reset (H5O_STAB, &stab_mesg); + + /* + * Create a symbol table entry for the link. The object header is + * undefined and the cache contains the link-value offset. + */ + HDmemset (&cur_obj, 0, sizeof cur_obj); + H5F_addr_undef (&(cur_obj.header)); + cur_obj.file = grp_ent.file; + cur_obj.type = H5G_CACHED_SLINK; + cur_obj.cache.slink.lval_offset = offset; + + /* + * Insert the link head in the symbol table. This shouldn't ever + * fail because we've already checked that the link head doesn't + * exist and the file is writable (because the local heap is + * writable). But if it does, the only side effect is that the local + * heap has some extra garbage in it. + */ + if (H5G_stab_insert (&grp_ent, rest, &cur_obj)<0) { + HRETURN_ERROR (H5E_SYM, H5E_CANTINIT, FAIL, + "unable to create new name/link for object"); + } + break; case H5G_LINK_HARD: if (H5G_find (loc, cur_name, NULL, &cur_obj)<0) { @@ -1563,3 +1809,153 @@ H5G_link (H5G_t *loc, H5G_type_t type, const char *cur_name, FUNC_LEAVE (SUCCEED); } + + +/*------------------------------------------------------------------------- + * Function: H5G_stat + * + * Purpose: Returns information about an object. + * + * Return: Success: SUCCEED with info about the object returned + * through STATBUF if it isn't the null pointer. + * + * Failure: FAIL + * + * Programmer: Robb Matzke + * Monday, April 13, 1998 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t +H5G_stat (H5G_t *loc, const char *name, hbool_t follow_link, + H5G_stat_t *statbuf/*out*/) +{ + H5O_stab_t stab_mesg; + H5G_entry_t grp_ent, obj_ent; + const char *s = NULL; + H5D_t *temp_dset = NULL; + H5G_t *temp_grp = NULL; + + FUNC_ENTER (H5G_stat, FAIL); + + assert (loc); + assert (name && *name); + if (statbuf) HDmemset (statbuf, 0, sizeof *statbuf); + + /* Find the object's symbol table entry */ + if (H5G_namei (H5G_entof(loc), name, NULL, &grp_ent/*out*/, + &obj_ent/*out*/, follow_link, NULL)<0) { + HRETURN_ERROR (H5E_SYM, H5E_NOTFOUND, FAIL, "unable to stat object"); + } + + /* + * Initialize the stat buf. Symbolic links aren't normal objects and + * therefor don't have much of the normal info. However, the link value + * length is specific to symbolic links. + */ + if (statbuf) { + if (H5G_CACHED_SLINK!=obj_ent.type) { + statbuf->objno[0] = (unsigned long)(obj_ent.header.offset); + statbuf->objno[1] = (unsigned long)(obj_ent.header.offset >> + 8*sizeof(long)); + statbuf->nlink = H5O_link (&obj_ent, 0); + statbuf->type = H5G_LINK; + } else { + if (NULL==H5O_read (&grp_ent, H5O_STAB, 0, &stab_mesg) || + NULL==(s=H5HL_peek (grp_ent.file, &(stab_mesg.heap_addr), + obj_ent.cache.slink.lval_offset))) { + HRETURN_ERROR (H5E_SYM, H5E_CANTINIT, FAIL, + "unable to read symbolic link value"); + } + statbuf->linklen = strlen(s)+1; /*count the null terminator*/ + + /* + * Determining the type of an object is a rather expensive + * operation compared to the other stuff here. It's also not + * very flexible. + */ + if (NULL!=(temp_dset=H5D_open (loc, name))) { + statbuf->type = H5G_DATASET; + H5D_close (temp_dset); + } else if (NULL!=(temp_grp=H5G_open (loc, name))) { + statbuf->type = H5G_GROUP; + H5G_close (temp_grp); + } else { + statbuf->type = H5G_UNKNOWN; + } + H5E_clear(); /*clear errors resulting from checking type*/ + } + } + + FUNC_LEAVE (SUCCEED); +} + + +/*------------------------------------------------------------------------- + * Function: H5G_linkval + * + * Purpose: Returns the value of a symbolic link. + * + * Return: Success: SUCCEED, with at most SIZE bytes of the link + * value copied into the BUF buffer. If the + * link value is larger than SIZE characters + * counting the null terminator then the BUF + * result will not be null terminated. + * + * Failure: FAIL + * + * Programmer: Robb Matzke + * Monday, April 13, 1998 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t +H5G_linkval (H5G_t *loc, const char *name, size_t size, char *buf/*out*/) +{ + const char *s = NULL; + H5G_entry_t grp_ent, obj_ent; + H5O_stab_t stab_mesg; + + FUNC_ENTER (H5G_linkval, FAIL); + + /* + * Get the symbol table entry for the link head and the symbol table + * entry for the group in which the link head appears. + */ + if (H5G_namei (H5G_entof(loc), name, NULL, &grp_ent/*out*/, + &obj_ent/*out*/, FALSE, NULL)<0) { + HRETURN_ERROR (H5E_SYM, H5E_NOTFOUND, FAIL, + "symbolic link was not found"); + } + if (H5G_CACHED_SLINK!=obj_ent.type) { + HRETURN_ERROR (H5E_SYM, H5E_NOTFOUND, FAIL, + "object is not a symbolic link"); + } + + /* + * Get the address of the local heap for the link value and a pointer + * into that local heap. + */ + if (NULL==H5O_read (&grp_ent, H5O_STAB, 0, &stab_mesg)) { + HRETURN_ERROR (H5E_SYM, H5E_CANTINIT, FAIL, + "unable to determine local heap address"); + } + if (NULL==(s=H5HL_peek (grp_ent.file, &(stab_mesg.heap_addr), + obj_ent.cache.slink.lval_offset))) { + HRETURN_ERROR (H5E_SYM, H5E_CANTINIT, FAIL, + "unable to read symbolic link value"); + } + + /* Copy to output buffer */ + if (size>0 && buf) { + strncpy (buf, s, size); + } + + FUNC_LEAVE (SUCCEED); +} + + diff --git a/src/H5Gent.c b/src/H5Gent.c index 66c08ae..1bcd18f 100644 --- a/src/H5Gent.c +++ b/src/H5Gent.c @@ -10,6 +10,7 @@ #include <H5private.h> #include <H5Eprivate.h> #include <H5Gpkg.h> +#include <H5HLprivate.h> #include <H5MMprivate.h> #define PABLO_MASK H5G_ent_mask @@ -204,6 +205,10 @@ H5G_ent_decode(H5F_t *f, const uint8 **pp, H5G_entry_t *ent) H5F_addr_decode(f, pp, &(ent->cache.stab.heap_addr)); break; + case H5G_CACHED_SLINK: + UINT32DECODE (*pp, ent->cache.slink.lval_offset); + break; + default: HDabort(); } @@ -310,6 +315,10 @@ H5G_ent_encode(H5F_t *f, uint8 **pp, H5G_entry_t *ent) H5F_addr_encode(f, pp, &(ent->cache.stab.heap_addr)); break; + case H5G_CACHED_SLINK: + UINT32ENCODE (*pp, ent->cache.slink.lval_offset); + break; + default: HDabort(); } @@ -350,8 +359,10 @@ H5G_ent_encode(H5F_t *f, uint8 **pp, H5G_entry_t *ent) */ herr_t H5G_ent_debug(H5F_t __unused__ *f, H5G_entry_t *ent, FILE * stream, - intn indent, intn fwidth) + intn indent, intn fwidth, const haddr_t *heap) { + const char *lval = NULL; + FUNC_ENTER(H5G_ent_debug, FAIL); fprintf(stream, "%*s%-*s %lu\n", indent, "", fwidth, @@ -387,6 +398,19 @@ H5G_ent_debug(H5F_t __unused__ *f, H5G_entry_t *ent, FILE * stream, fprintf(stream, "\n"); break; + case H5G_CACHED_SLINK: + fprintf (stream, "Symbolic Link\n"); + fprintf (stream, "%*s%-*s %lu\n", indent, "", fwidth, + "Link value offset:", + (unsigned long)(ent->cache.slink.lval_offset)); + if (heap && H5F_addr_defined (heap)) { + lval = H5HL_peek (ent->file, heap, ent->cache.slink.lval_offset); + fprintf (stream, "%*s%-*s %s\n", indent, "", fwidth, + "Link value:", + lval); + } + break; + default: fprintf(stream, "*** Unknown symbol type %d\n", ent->type); break; diff --git a/src/H5Gnode.c b/src/H5Gnode.c index 02172da..5580993 100644 --- a/src/H5Gnode.c +++ b/src/H5Gnode.c @@ -985,7 +985,7 @@ H5G_node_debug(H5F_t *f, const haddr_t *addr, FILE * stream, intn indent, "Name:", s); } - H5G_ent_debug(f, sn->entry + i, stream, indent, fwidth); + H5G_ent_debug(f, sn->entry + i, stream, indent, fwidth, heap); } H5AC_unprotect(f, H5AC_SNODE, addr, sn); diff --git a/src/H5Gprivate.h b/src/H5Gprivate.h index 2d49e99..bbb2a1c 100644 --- a/src/H5Gprivate.h +++ b/src/H5Gprivate.h @@ -33,6 +33,7 @@ #define H5G_NODE_MAGIC "SNOD" /*symbol table node magic number */ #define H5G_NODE_SIZEOF_MAGIC 4 /*sizeof symbol node magic number */ #define H5G_NO_CHANGE (-1) /*see H5G_ent_modified() */ +#define H5G_NLINKS 16 /*max symlinks to follow per lookup */ /* * The disk size for a symbol table entry... @@ -54,8 +55,9 @@ typedef enum H5G_type_t { H5G_CACHED_ERROR = -1, /*force enum to be signed */ H5G_NOTHING_CACHED = 0, /*nothing is cached, must be 0 */ H5G_CACHED_STAB = 1, /*symbol table, `stab' */ + H5G_CACHED_SLINK = 2, /*symbolic link */ - H5G_NCACHED = 2 /*THIS MUST BE LAST */ + H5G_NCACHED = 3 /*THIS MUST BE LAST */ } H5G_type_t; /* @@ -70,6 +72,10 @@ typedef union H5G_cache_t { haddr_t btree_addr; /*file address of symbol table B-tree*/ haddr_t heap_addr; /*file address of stab name heap */ } stab; + + struct { + size_t lval_offset; /*link value offset */ + } slink; } H5G_cache_t; /* @@ -106,9 +112,16 @@ herr_t H5G_pop (H5F_t *f); H5G_t *H5G_getcwg(H5F_t *f); herr_t H5G_link (H5G_t *loc, H5G_type_t type, const char *cur_name, const char *new_name); +herr_t H5G_stat (H5G_t *loc, const char *name, hbool_t follow_link, + H5G_stat_t *statbuf/*out*/); +herr_t H5G_linkval (H5G_t *loc, const char *name, size_t size, + char *buf/*out*/); herr_t H5G_insert (H5G_t *cwg, const char *name, H5G_entry_t *ent); herr_t H5G_find (H5G_t *cwg, const char *name, H5G_entry_t *grp_ent/*out*/, H5G_entry_t *ent/*out*/); +herr_t H5G_traverse_slink (H5G_entry_t *grp_ent/*in,out*/, + H5G_entry_t *obj_ent/*in,out*/, + intn *nlinks/*in,out*/); herr_t H5G_ent_encode (H5F_t *f, uint8 **pp, H5G_entry_t *ent); herr_t H5G_ent_decode (H5F_t *f, const uint8 **pp, H5G_entry_t *ent/*out*/); @@ -127,6 +140,6 @@ H5G_entry_t *H5G_ent_calloc (H5G_entry_t *init); H5G_cache_t *H5G_ent_cache (H5G_entry_t *ent, H5G_type_t *cache_type); herr_t H5G_ent_modified (H5G_entry_t *ent, H5G_type_t cache_type); herr_t H5G_ent_debug (H5F_t *f, H5G_entry_t *ent, FILE * stream, intn indent, - intn fwidth); + intn fwidth, const haddr_t *heap); #endif diff --git a/src/H5Gpublic.h b/src/H5Gpublic.h index 8c6e7c6..d70dac7 100644 --- a/src/H5Gpublic.h +++ b/src/H5Gpublic.h @@ -27,12 +27,29 @@ extern "C" { #endif +/* Types of links */ typedef enum H5G_link_t { H5G_LINK_ERROR = -1, H5G_LINK_HARD = 0, H5G_LINK_SOFT = 1 } H5G_link_t; +/* An object has a certain type */ +#define H5G_UNKNOWN (-1) /* Unknown object type */ +#define H5G_LINK 0 /* Object is a symbolic link */ +#define H5G_GROUP 1 /* Object is a group */ +#define H5G_DATASET 2 /* Object is a dataset */ + +/* Information about an object */ +typedef struct H5G_stat_t { + unsigned long fileno[2]; + unsigned long objno[2]; + unsigned nlink; + int type; + size_t linklen; +} H5G_stat_t; + + typedef herr_t (*H5G_iterate_t)(hid_t group, const char *group_name, void *op_data); @@ -48,6 +65,10 @@ herr_t H5Gmove (hid_t loc_id, const char *src, const char *dst); herr_t H5Glink (hid_t loc_id, H5G_link_t type, const char *cur_name, const char *new_name); herr_t H5Gunlink (hid_t loc_id, const char *name); +herr_t H5Gstat (hid_t loc_id, const char *name, hbool_t follow_link, + H5G_stat_t *statbuf/*out*/); +herr_t H5Gget_linkval (hid_t loc_id, const char *name, size_t size, + char *buf/*out*/); #ifdef __cplusplus } diff --git a/src/H5Gstab.c b/src/H5Gstab.c index be43215..b2fa9d2 100644 --- a/src/H5Gstab.c +++ b/src/H5Gstab.c @@ -1,9 +1,9 @@ /* * Copyright (C) 1997 National Center for Supercomputing Applications - * All rights reserved. + * All rights reserved. * * Programmer: Robb Matzke <matzke@llnl.gov> - * Friday, September 19, 1997 + * Friday, September 19, 1997 * */ #define H5G_PACKAGE @@ -16,31 +16,31 @@ #include <H5MMprivate.h> #include <H5Oprivate.h> -#define PABLO_MASK H5G_stab_mask -static hbool_t interface_initialize_g = FALSE; -#define INTERFACE_INIT NULL +#define PABLO_MASK H5G_stab_mask +static hbool_t interface_initialize_g = FALSE; +#define INTERFACE_INIT NULL /*------------------------------------------------------------------------- - * Function: H5G_stab_create + * Function: H5G_stab_create * - * 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. The object header of the group is opened for - * write access. + * 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. The object header of the group is opened for + * write access. * - * In order for the B-tree to operate correctly, the first - * item in the heap is the empty string, and must appear at - * heap offset zero. + * In order for the B-tree to operate correctly, the first + * item in the heap is the empty string, and must appear at + * heap offset zero. * * Errors: * - * Return: Success: SUCCEED + * Return: Success: SUCCEED * - * Failure: FAIL + * Failure: FAIL * - * Programmer: Robb Matzke - * matzke@llnl.gov - * Aug 1 1997 + * Programmer: Robb Matzke + * matzke@llnl.gov + * Aug 1 1997 * * Modifications: * @@ -49,8 +49,8 @@ static hbool_t interface_initialize_g = FALSE; herr_t H5G_stab_create(H5F_t *f, size_t init, H5G_entry_t *self/*out*/) { - size_t name; /*offset of "" name */ - H5O_stab_t stab; /*symbol table message */ + size_t name; /*offset of "" name */ + H5O_stab_t stab; /*symbol table message */ FUNC_ENTER(H5G_stab_create, FAIL); @@ -63,11 +63,11 @@ H5G_stab_create(H5F_t *f, size_t init, H5G_entry_t *self/*out*/) /* Create symbol table private heap */ if (H5HL_create(f, init, &(stab.heap_addr)/*out*/)<0) { - HRETURN_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "can't create heap"); + HRETURN_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "can't create heap"); } name = H5HL_insert(f, &(stab.heap_addr), 1, ""); if ((size_t)(-1)==name) { - HRETURN_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "can't initialize heap"); + HRETURN_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "can't initialize heap"); } /* @@ -78,23 +78,25 @@ H5G_stab_create(H5F_t *f, size_t init, H5G_entry_t *self/*out*/) /* Create the B-tree */ if (H5B_create(f, H5B_SNODE, NULL, &(stab.btree_addr) /*out */ ) < 0) { - HRETURN_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "can't create B-tree"); + HRETURN_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "can't create B-tree"); } + /* * Create symbol table object header. It has a zero link count - * since nothing refers to it yet. The link count will be + * since nothing refers to it yet. The link count will be * incremented if the object is added to the group directed graph. */ if (H5O_create(f, 4 + 2 * H5F_SIZEOF_ADDR(f), self /*out */ ) < 0) { - HRETURN_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "can't create header"); + HRETURN_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "can't create header"); } + /* * Insert the symbol table message into the object header and the symbol * table entry. */ - if (H5O_modify(self, H5O_STAB, H5O_NEW_MESG, H5O_FLAG_CONSTANT, &stab) < 0) { - H5O_close(self); - HRETURN_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "can't create message"); + if (H5O_modify(self, H5O_STAB, H5O_NEW_MESG, H5O_FLAG_CONSTANT, &stab)<0) { + H5O_close(self); + HRETURN_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "can't create message"); } self->cache.stab.btree_addr = stab.btree_addr; self->cache.stab.heap_addr = stab.heap_addr; @@ -102,23 +104,24 @@ H5G_stab_create(H5F_t *f, size_t init, H5G_entry_t *self/*out*/) FUNC_LEAVE(SUCCEED); } + /*------------------------------------------------------------------------- - * Function: H5G_stab_find + * Function: H5G_stab_find * - * Purpose: Finds a symbol named NAME in the symbol table whose - * description is stored in GRP_ENT in file F and returns its - * symbol table entry through OBJ_ENT (which is optional). + * Purpose: Finds a symbol named NAME in the symbol table whose + * description is stored in GRP_ENT in file F and returns its + * symbol table entry through OBJ_ENT (which is optional). * * Errors: * - * Return: Success: SUCCEED + * Return: Success: SUCCEED * - * Failure: FAIL + * Failure: FAIL * - * Programmer: Robb Matzke - * matzke@llnl.gov - * Aug 1 1997 + * Programmer: Robb Matzke + * matzke@llnl.gov + * Aug 1 1997 * * Modifications: * @@ -126,10 +129,10 @@ H5G_stab_create(H5F_t *f, size_t init, H5G_entry_t *self/*out*/) */ herr_t H5G_stab_find(H5G_entry_t *grp_ent, const char *name, - H5G_entry_t *obj_ent /*out */ ) + H5G_entry_t *obj_ent/*out*/) { - H5G_bt_ud1_t udata; /*data to pass through B-tree */ - H5O_stab_t stab; /*symbol table message */ + H5G_bt_ud1_t udata; /*data to pass through B-tree */ + H5O_stab_t stab; /*symbol table message */ FUNC_ENTER(H5G_stab_find, FAIL); @@ -140,7 +143,7 @@ H5G_stab_find(H5G_entry_t *grp_ent, const char *name, /* set up the udata */ if (NULL == H5O_read(grp_ent, H5O_STAB, 0, &stab)) { - HRETURN_ERROR(H5E_SYM, H5E_BADMESG, FAIL, "can't read message"); + HRETURN_ERROR(H5E_SYM, H5E_BADMESG, FAIL, "can't read message"); } udata.operation = H5G_OPER_FIND; udata.name = name; @@ -148,29 +151,28 @@ H5G_stab_find(H5G_entry_t *grp_ent, const char *name, /* search the B-tree */ if (H5B_find(grp_ent->file, H5B_SNODE, &(stab.btree_addr), &udata) < 0) { - HRETURN_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "not found"); + HRETURN_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "not found"); } - if (obj_ent) - *obj_ent = udata.ent; + if (obj_ent) *obj_ent = udata.ent; FUNC_LEAVE(SUCCEED); } /*------------------------------------------------------------------------- - * Function: H5G_stab_insert + * Function: H5G_stab_insert * - * Purpose: Insert a new symbol into the table described by GRP_ENT in - * file F. The name of the new symbol is NAME and its symbol - * table entry is OBJ_ENT. + * Purpose: Insert a new symbol into the table described by GRP_ENT in + * file F. The name of the new symbol is NAME and its symbol + * table entry is OBJ_ENT. * * Errors: * - * Return: Success: SUCCEED + * Return: Success: SUCCEED * - * Failure: FAIL + * Failure: FAIL * - * Programmer: Robb Matzke - * matzke@llnl.gov - * Aug 1 1997 + * Programmer: Robb Matzke + * matzke@llnl.gov + * Aug 1 1997 * * Modifications: * @@ -179,8 +181,8 @@ H5G_stab_find(H5G_entry_t *grp_ent, const char *name, herr_t H5G_stab_insert(H5G_entry_t *grp_ent, const char *name, H5G_entry_t *obj_ent) { - H5O_stab_t stab; /*symbol table message */ - H5G_bt_ud1_t udata; /*data to pass through B-tree */ + H5O_stab_t stab; /*symbol table message */ + H5G_bt_ud1_t udata; /*data to pass through B-tree */ FUNC_ENTER(H5G_stab_insert, FAIL); @@ -192,7 +194,7 @@ H5G_stab_insert(H5G_entry_t *grp_ent, const char *name, H5G_entry_t *obj_ent) /* initialize data to pass through B-tree */ if (NULL == H5O_read(grp_ent, H5O_STAB, 0, &stab)) { - HRETURN_ERROR(H5E_SYM, H5E_BADMESG, FAIL, "not a symbol table"); + HRETURN_ERROR(H5E_SYM, H5E_BADMESG, FAIL, "not a symbol table"); } udata.operation = H5G_OPER_INSERT; udata.name = name; @@ -201,8 +203,9 @@ H5G_stab_insert(H5G_entry_t *grp_ent, const char *name, H5G_entry_t *obj_ent) /* insert */ if (H5B_insert(grp_ent->file, H5B_SNODE, &(stab.btree_addr), &udata) < 0) { - HRETURN_ERROR(H5E_SYM, H5E_CANTINSERT, FAIL, "can't insert entry"); + HRETURN_ERROR(H5E_SYM, H5E_CANTINSERT, FAIL, "can't insert entry"); } + /* update the name offset in the entry */ obj_ent->name_off = udata.ent.name_off; FUNC_LEAVE(SUCCEED); @@ -44,13 +44,22 @@ list (hid_t group, const char *name, void __unused__ *op_data) hid_t (*func)(void*); void *edata; int i; - + char linkval[512]; + H5G_stat_t statbuf; + /* Disable error reporting */ H5Eget_auto (&func, &edata); H5Eset_auto (NULL, NULL); /* Print info about each name */ printf ("%-30s", name); + + if (H5Gstat (group, name, TRUE, &statbuf)>=0) { + printf ("FILE={%lu,%lu}, OID={%lu,%lu} ", + statbuf.fileno[0], statbuf.fileno[1], + statbuf.objno[0], statbuf.objno[1]); + } + if ((obj=H5Dopen (group, name))>=0) { hsize_t size[64]; hid_t space = H5Dget_space (obj); @@ -65,6 +74,11 @@ list (hid_t group, const char *name, void __unused__ *op_data) } else if ((obj=H5Gopen (group, name))>=0) { printf (" Group\n"); H5Gclose (obj); + } else if (H5Gget_linkval (group, name, sizeof(linkval), linkval)>=0) { + if (NULL==HDmemchr (linkval, 0, sizeof(linkval))) { + strcpy (linkval+sizeof(linkval)-4, "..."); + } + printf (" -> %s\n", linkval); } else { printf (" Unknown Type\n"); } diff --git a/test/.distdep b/test/.distdep index 409acbb..cbe325d 100644 --- a/test/.distdep +++ b/test/.distdep @@ -3,7 +3,9 @@ testhdf5.o: \ testhdf5.h \ ../src/H5private.h \ ../src/H5public.h \ - ../src/H5config.h + ../src/H5config.h \ + ../src/H5Eprivate.h \ + ../src/H5Epublic.h tfile.o: \ tfile.c \ testhdf5.h \ @@ -147,14 +149,13 @@ dtypes.o: \ ../src/H5Iprivate.h \ ../src/H5private.h \ ../src/H5Tprivate.h \ - ../src/H5Gprivate.h + ../src/H5Gprivate.h \ + ../src/H5Bprivate.h hyperslab.o: \ hyperslab.c \ ../src/H5private.h \ ../src/H5public.h \ - ../src/H5config.h \ - ../src/H5MMprivate.h \ - ../src/H5MMpublic.h + ../src/H5config.h istore.o: \ istore.c \ ../src/H5private.h \ @@ -179,7 +180,8 @@ istore.o: \ ../src/H5HGpublic.h \ ../src/H5Tprivate.h \ ../src/H5Tpublic.h \ - ../src/H5Sprivate.h + ../src/H5Sprivate.h \ + ../src/H5Spublic.h dsets.o: \ dsets.c \ ../src/hdf5.h \ @@ -218,8 +220,7 @@ cmpd_dset.o: \ ../src/H5MMpublic.h \ ../src/H5Opublic.h \ ../src/H5Ppublic.h \ - ../src/H5Spublic.h \ - ../src/H5Tpublic.h + ../src/H5Spublic.h extend.o: \ extend.c \ ../src/hdf5.h \ @@ -332,4 +333,23 @@ big.o: \ ../src/H5MMpublic.h \ ../src/H5Opublic.h \ ../src/H5Ppublic.h \ - ../src/H5Spublic.h + ../src/H5Spublic.h \ + ../src/H5Tpublic.h +links.o: \ + links.c \ + ../src/hdf5.h \ + ../src/H5public.h \ + ../src/H5config.h \ + ../src/H5ACpublic.h \ + ../src/H5Bpublic.h \ + ../src/H5Dpublic.h \ + ../src/H5Ipublic.h \ + ../src/H5Epublic.h \ + ../src/H5Fpublic.h \ + ../src/H5Gpublic.h \ + ../src/H5HGpublic.h \ + ../src/H5HLpublic.h \ + ../src/H5MFpublic.h \ + ../src/H5MMpublic.h \ + ../src/H5Opublic.h \ + ../src/H5Ppublic.h diff --git a/test/Makefile.in b/test/Makefile.in index 6ee08ad..55da8cd 100644 --- a/test/Makefile.in +++ b/test/Makefile.in @@ -12,9 +12,9 @@ CPPFLAGS=-I. -I../src @CPPFLAGS@ # These are our main targets. They should be listed in the order to be # executed, generally most specific tests to least specific tests. PROGS=testhdf5 gheap hyperslab istore dtypes dsets cmpd_dset extend external \ - shtype iopipe big + shtype iopipe big links TESTS=testhdf5 gheap hyperslab istore dtypes dsets cmpd_dset extend external \ - shtype + shtype links TIMINGS=iopipe # Temporary files @@ -24,7 +24,7 @@ MOSTLYCLEAN=cmpd_dset.h5 dataset.h5 extend.h5 istore.h5 tfile1.h5 tfile2.h5 \ extern_2.raw extern_2b.raw extern_3.raw extern_3b.raw \ extern_4.raw extern_4b.raw iopipe.raw iopipe.h5 gheap0.h5 \ gheap1.h5 gheap2.h5 gheap3.h5 gheap4.h5 shtype0.h5 shtype1.h5 \ - shtype2a.h5 shtype2b.h5 shtype3.h5 + shtype2a.h5 shtype2b.h5 shtype3.h5 links.h5 # Source and object files for programs... The PROG_SRC list contains all the # source files and is used for things like dependencies, archiving, etc. The @@ -32,7 +32,7 @@ MOSTLYCLEAN=cmpd_dset.h5 dataset.h5 extend.h5 istore.h5 tfile1.h5 tfile2.h5 \ # overlap with other tests. PROG_SRC=testhdf5.c tfile.c theap.c tmeta.c tohdr.c tstab.c th5s.c dtypes.c \ hyperslab.c istore.c dsets.c cmpd_dset.c extend.c external.c \ - iopipe.c gheap.c shtype.c big.c + iopipe.c gheap.c shtype.c big.c links.c PROG_OBJ=$(PROG_SRC:.c=.o) TESTHDF5_SRC=testhdf5.c tfile.c theap.c tmeta.c tohdr.c tstab.c th5s.c @@ -74,6 +74,9 @@ IOPIPE_OBJ=$(IOPIPE_SRC:.c=.o) BIG_SRC=big.c BIG_OBJ=$(BIG_SRC:.c=.o) +LINKS_SRC=links.c +LINKS_OBJ=$(LINKS_SRC:.c=.o) + # Private header files (not to be installed)... PRIVATE_HDR=testhdf5.h @@ -127,4 +130,7 @@ grptime: $(GRPTIME_OBJ) ../src/libhdf5.a big: $(BIG_OBJ) ../src/libhdf5.a $(CC) $(CFLAGS) -o $@ $(BIG_OBJ) ../src/libhdf5.a $(LIBS) +links: $(LINKS_OBJ) ../src/libhdf5.a + $(CC) $(CFLAGS) -o $@ $(LINKS_OBJ) ../src/libhdf5.a $(LIBS) + @CONCLUDE@ @@ -6,7 +6,26 @@ * Wednesday, April 8, 1998 */ #include <assert.h> +#include <ctype.h> #include <hdf5.h> +#include <math.h> +#include <stdlib.h> + +#include <H5private.h> /*needed for HDfprintf() */ + +#define FNAME "big%05d.h5" +#define WRT_N 50 +#define WRT_SIZE 4*1024 + +static hsize_t +randll (hsize_t limit) +{ + hsize_t acc = rand (); + acc *= rand (); + + return acc % limit; +} + /*------------------------------------------------------------------------- @@ -25,12 +44,16 @@ * *------------------------------------------------------------------------- */ -int -main (void) +static void +writer (int wrt_n) { hsize_t size1[4] = {8, 1024, 1024, 1024}; hsize_t size2[1] = {8589934592LL}; - hid_t plist, file, space1, space2, dset; + hssize_t hs_start[1]; + hsize_t hs_size[1]; + hid_t plist, file, space1, space2, mem_space, d1, d2; + int *buf = malloc (sizeof(int) * WRT_SIZE); + int i, j; /* * Make sure that `hsize_t' is large enough to represent the entire data @@ -44,20 +67,137 @@ main (void) */ plist = H5Pcreate (H5P_FILE_ACCESS); H5Pset_family (plist, 30, H5P_DEFAULT); - file = H5Fcreate ("big%05d.h5", H5F_ACC_TRUNC, H5P_DEFAULT, plist); + file = H5Fcreate (FNAME, H5F_ACC_TRUNC, H5P_DEFAULT, plist); /* Create simple data spaces according to the size specified above. */ space1 = H5Screate_simple (4, size1, size1); space2 = H5Screate_simple (1, size2, size2); /* Create the datasets */ - dset = H5Dcreate (file, "d1", H5T_NATIVE_INT, space1, H5P_DEFAULT); - H5Dclose (dset); - dset = H5Dcreate (file, "d2", H5T_NATIVE_INT, space2, H5P_DEFAULT); - H5Dclose (dset); - + d1 = H5Dcreate (file, "d1", H5T_NATIVE_INT, space1, H5P_DEFAULT); + d2 = H5Dcreate (file, "d2", H5T_NATIVE_INT, space2, H5P_DEFAULT); + + /* Write some things to them randomly */ + hs_size[0] = WRT_SIZE; + mem_space = H5Screate_simple (1, hs_size, hs_size); + for (i=0; i<wrt_n; i++) { + hs_start[0] = randll (size2[0]); + HDfprintf (stdout, "#%03d 0x%016Hx\n", i, hs_start[0]); + H5Sset_hyperslab (space2, hs_start, hs_size, NULL); + for (j=0; j<WRT_SIZE; j++) { + buf[j] = i+1; + } + H5Dwrite (d2, H5T_NATIVE_INT, mem_space, space2, H5P_DEFAULT, buf); + } + + H5Dclose (d1); + H5Dclose (d2); + H5Sclose (mem_space); H5Sclose (space1); H5Sclose (space2); H5Fclose (file); - exit (0); + free (buf); +} + + +/*------------------------------------------------------------------------- + * Function: reader + * + * Purpose: Reads some data from random locations in the dataset. + * + * Return: void + * + * Programmer: Robb Matzke + * Friday, April 10, 1998 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static void +reader (const char *script_name) +{ + FILE *script; + hid_t plist, file, mspace, fspace, d2; + char ln[64], *s; + hssize_t hs_offset[1]; + hsize_t hs_size[1] = {WRT_SIZE}; + int *buf = malloc (sizeof(int) * WRT_SIZE); + int i, j, zero, wrong; + + /* Open script file */ + script = fopen (script_name, "r"); + + /* Open HDF5 file */ + plist = H5Pcreate (H5P_FILE_ACCESS); + H5Pset_family (plist, 30, H5P_DEFAULT); + file = H5Fopen (FNAME, H5F_ACC_RDONLY, plist); + + /* Open the dataset */ + d2 = H5Dopen (file, "d2"); + fspace = H5Dget_space (d2); + + /* Describe `buf' */ + mspace = H5Screate_simple (1, hs_size, hs_size); + + /* Read each region */ + while (fgets (ln, sizeof(ln), script)) { + if ('#'!=ln[0]) break; + i = strtol (ln+1, &s, 10); + hs_offset[0] = HDstrtoll (s, NULL, 0); + HDfprintf (stdout, "#%03d 0x%016Hx", i, hs_offset[0]); + fflush (stdout); + + H5Sset_hyperslab (fspace, hs_offset, hs_size, NULL); + H5Dread (d2, H5T_NATIVE_INT, mspace, fspace, H5P_DEFAULT, buf); + + /* Check */ + for (j=zero=wrong=0; j<WRT_SIZE; j++) { + if (0==buf[j]) zero++; + else if (buf[j]!=i+1) wrong++; + } + if (zero) { + printf (" *FAILED* (%d zeros)\n", zero); + } else if (wrong) { + printf (" *SKIPPED* (possible overlap with another region)\n"); + } else { + printf (" PASSED\n"); + } + } + + H5Dclose (d2); + H5Sclose (mspace); + H5Sclose (fspace); + H5Fclose (file); + fclose (script); +} + + +/*------------------------------------------------------------------------- + * Function: main + * + * Purpose: + * + * Return: Success: + * + * Failure: + * + * Programmer: Robb Matzke + * Friday, April 10, 1998 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +int +main (int argc, char *argv[]) +{ + if (1==argc) { + writer (WRT_N); + } else if (isdigit (argv[1][0])) { + writer (strtol (argv[1], NULL, 0)); + } else { + reader (argv[1]); + } + return 0; } diff --git a/test/links.c b/test/links.c new file mode 100644 index 0000000..ac4a3e1 --- /dev/null +++ b/test/links.c @@ -0,0 +1,63 @@ +/* + * Copyright (C) 1998 NCSA + * All rights reserved. + * + * Programmer: Robb Matzke <matzke@llnl.gov> + * Friday, April 10, 1998 + * + * Purpose: Tests hard and soft (symbolic) links. + */ +#include <hdf5.h> + + +/*------------------------------------------------------------------------- + * Function: main + * + * Purpose: Tests links. + * + * Return: Success: 0 + * + * Failure: non-zero + * + * Programmer: Robb Matzke + * Friday, April 10, 1998 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +int +main (void) +{ + hid_t file, scalar, grp, d1; + hsize_t size[1] = {1}; + + /* Create a file */ + file = H5Fcreate ("links.h5", H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + scalar = H5Screate_simple (1, size, size); + + /* Create a group */ + grp = H5Gcreate (file, "grp1", 0); + H5Gclose (grp); + + /* Create a dataset */ + d1 = H5Dcreate (file, "d1", H5T_NATIVE_INT, scalar, H5P_DEFAULT); + H5Dclose (d1); + + /* Create a hard link */ + H5Glink (file, H5G_LINK_HARD, "d1", "grp1/hard"); + + /* Create a symbolic link */ + H5Glink (file, H5G_LINK_SOFT, "/d1", "grp1/soft"); + + /* Create a symbolic link to something that doesn't exist */ + H5Glink (file, H5G_LINK_SOFT, "foobar", "grp1/dangle"); + + /* Create a recursive symbolic link */ + H5Glink (file, H5G_LINK_SOFT, "/grp1/recursive", "/grp1/recursive"); + + /* Close */ + H5Sclose (scalar); + H5Fclose (file); + return 0; +} |