diff options
author | Robb Matzke <matzke@llnl.gov> | 1998-04-14 16:44:46 (GMT) |
---|---|---|
committer | Robb Matzke <matzke@llnl.gov> | 1998-04-14 16:44:46 (GMT) |
commit | b6fc6ede10fee24e9ef0a21df81cc181f6d7fec0 (patch) | |
tree | 66321165e4bd58a9fe3722a1a3baee2f835d0544 /src | |
parent | 3f571b6b4499e09aa6db29cb389e1121624a081d (diff) | |
download | hdf5-b6fc6ede10fee24e9ef0a21df81cc181f6d7fec0.zip hdf5-b6fc6ede10fee24e9ef0a21df81cc181f6d7fec0.tar.gz hdf5-b6fc6ede10fee24e9ef0a21df81cc181f6d7fec0.tar.bz2 |
[svn-r346] Changes since 19980410
----------------------
./html/H5.format.html
./src/H5E.c
./src/H5Epublic.h
./src/H5F.c
./src/H5G.c
./src/H5Gent.c
./src/H5Gnode.c
./src/H5Gprivate.h
./src/h5ls.c
./test/Makefile.in
Symbolic links are now supported. The ./test/links program
will create a `links.h5' file that demonstrates hard links,
soft links, dangling links, and recursive links. A symbolic
link is a symbol table entity and doesn't have an object
header. It's format is described in H5.format.hml.
./src/H5G.c
./src/H5Gpublic.h
./src/h5ls.c
Implemented H5Gstat() and H5Gget_linkval() as documented by
Quincey. The `H5G_type_t type' field of `H5G_stat_t' was
changed to `int type' because H5G_type_t was already used and
the `type' data type should be open-ended.
./src/H5Ffamily.c
Removed an incorrect diagnostic message.
./test/big.c
Added read/write calls to test partial I/O to big contiguous
datasets. With no arguments it writes to a dataset and prints
the list of points written which should be redirected to a
file. With an argument (the name of a file containing the
stdout of a run with no arguments) values are read from the
dataset. One would typically say `big >x && big x'.
Diffstat (limited to 'src')
-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 |
11 files changed, 554 insertions, 81 deletions
@@ -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"); } |