summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorRobb Matzke <matzke@llnl.gov>1998-04-14 16:44:46 (GMT)
committerRobb Matzke <matzke@llnl.gov>1998-04-14 16:44:46 (GMT)
commitb6fc6ede10fee24e9ef0a21df81cc181f6d7fec0 (patch)
tree66321165e4bd58a9fe3722a1a3baee2f835d0544 /src
parent3f571b6b4499e09aa6db29cb389e1121624a081d (diff)
downloadhdf5-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.c1
-rw-r--r--src/H5Epublic.h3
-rw-r--r--src/H5F.c2
-rw-r--r--src/H5Ffamily.c2
-rw-r--r--src/H5G.c428
-rw-r--r--src/H5Gent.c26
-rw-r--r--src/H5Gnode.c2
-rw-r--r--src/H5Gprivate.h17
-rw-r--r--src/H5Gpublic.h21
-rw-r--r--src/H5Gstab.c117
-rw-r--r--src/h5ls.c16
11 files changed, 554 insertions, 81 deletions
diff --git a/src/H5E.c b/src/H5E.c
index afe031a..02a3852 100644
--- a/src/H5E.c
+++ b/src/H5E.c
@@ -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 */
diff --git a/src/H5F.c b/src/H5F.c
index 042273f..7a262e6 100644
--- a/src/H5F.c
+++ b/src/H5F.c
@@ -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
diff --git a/src/H5G.c b/src/H5G.c
index 4367b74..98399aa 100644
--- a/src/H5G.c
+++ b/src/H5G.c
@@ -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);
diff --git a/src/h5ls.c b/src/h5ls.c
index 45fcaa2..23ef00c 100644
--- a/src/h5ls.c
+++ b/src/h5ls.c
@@ -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");
}