summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--MANIFEST1
-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
-rw-r--r--test/.distdep38
-rw-r--r--test/Makefile.in14
-rw-r--r--test/big.c160
-rw-r--r--test/links.c63
16 files changed, 807 insertions, 104 deletions
diff --git a/MANIFEST b/MANIFEST
index 7b95534..0ad6edf 100644
--- a/MANIFEST
+++ b/MANIFEST
@@ -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
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");
}
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@
diff --git a/test/big.c b/test/big.c
index 44d550f..a75eb5d 100644
--- a/test/big.c
+++ b/test/big.c
@@ -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;
+}