From 2f36ea99d4ad1b036d377719e49eaab2dec64444 Mon Sep 17 00:00:00 2001
From: Quincey Koziol <koziol@hdfgroup.org>
Date: Sat, 24 Nov 2007 11:49:36 -0500
Subject: [svn-r14284] Description: 	Add H5Lvisit_by_name() API routine to
 library.

	Eliminated all (five!) other group traversal routines and changed them
all to use the new API routine.

	Cleaned up output of h5ls & h5stat:
		- Issue error when requesting recursive traversal of a file
			with the "group info" flag, but no group given
		- Print info about root group in all(?) appropriate situations
		- Don't print "verbose" information about root group until the
			root group is in the list of objects to display
	(mostly because h5ls & h5stat had a different twist on traversing the
groups in a file that the other utilities)

Tested on:
        FreeBSD/32 6.2 (duty) in debug mode
        FreeBSD/64 6.2 (liberty) w/C++ & FORTRAN, in debug mode
        Linux/32 2.6 (kagiso) w/PGI compilers, w/C++ & FORTRAN, w/threadsafe,
                                in debug mode
        Linux/64-amd64 2.6 (smirom) w/default API=1.6.x, w/C++ & FORTRAN,
                                in production mode
        Linux/64-ia64 2.6 (cobalt) w/Intel compilers, w/C++ & FORTRAN,
                                in production mode
        Solaris/32 2.10 (linew) w/deprecated symbols disabled, w/C++ & FORTRAN,
                                w/szip filter, in production mode
        Mac OS X/32 10.4.10 (amazon) in debug mode
        Linux/64-ia64 2.4 (tg-login3) w/parallel, w/FORTRAN, in production mode
---
 MANIFEST                                       |   1 +
 src/H5F.c                                      |  12 +-
 src/H5FD.c                                     |  10 +-
 src/H5Fprivate.h                               |   2 +
 src/H5G.c                                      | 461 +++++++++++++++++++++-
 src/H5Gcompact.c                               |   8 +-
 src/H5Gdense.c                                 |  47 +--
 src/H5Gdeprec.c                                |   4 +-
 src/H5Glink.c                                  |  33 +-
 src/H5Gname.c                                  | 282 +++++--------
 src/H5Gnode.c                                  |  52 +--
 src/H5Gobj.c                                   |  45 +--
 src/H5Gpkg.h                                   |  43 +-
 src/H5Gprivate.h                               |   2 +-
 src/H5Gstab.c                                  |  10 +-
 src/H5L.c                                      |  72 +++-
 src/H5Lpublic.h                                |   3 +
 src/H5O.c                                      |  48 ++-
 src/H5Olinfo.c                                 |   7 +-
 src/H5Oprivate.h                               |   1 +
 src/H5R.c                                      |   2 +-
 src/H5SL.c                                     |  42 +-
 src/H5SLprivate.h                              |   3 +-
 src/H5private.h                                |   6 +
 test/getname.c                                 |  91 +++--
 test/mount.c                                   |  26 +-
 tools/h5copy/h5copy.c                          |   4 +-
 tools/h5dump/h5dump.c                          |  10 +-
 tools/h5ls/h5ls.c                              | 524 ++++++++++---------------
 tools/h5ls/testh5ls.sh                         |   1 +
 tools/h5stat/h5stat.c                          | 327 +++++----------
 tools/h5stat/testfiles/h5stat_filters-file.ddl |   1 -
 tools/h5stat/testfiles/h5stat_filters.ddl      |   1 -
 tools/h5stat/testfiles/h5stat_newgrat.ddl      |   1 -
 tools/h5stat/testfiles/h5stat_tsohm.ddl        |   1 -
 tools/lib/h5tools_ref.c                        | 192 ++++-----
 tools/lib/h5tools_utils.c                      | 186 +++------
 tools/lib/h5tools_utils.h                      |   2 +-
 tools/lib/h5trav.c                             | 276 ++++++-------
 tools/lib/h5trav.h                             |  14 +
 tools/testfiles/h5copytst.out.ls               |   3 +
 tools/testfiles/h5mkgrp_nested.ls              |   3 +
 tools/testfiles/h5mkgrp_nested_latest.ls       |   4 +
 tools/testfiles/h5mkgrp_nested_mult.ls         |   3 +
 tools/testfiles/h5mkgrp_nested_mult_latest.ls  |   4 +
 tools/testfiles/h5mkgrp_several.ls             |   3 +
 tools/testfiles/h5mkgrp_several_latest.ls      |   4 +
 tools/testfiles/h5mkgrp_single.ls              |   3 +
 tools/testfiles/h5mkgrp_single_latest.ls       |   4 +
 tools/testfiles/tall-2.ls                      |   1 +
 tools/testfiles/tarray1.ls                     |   1 +
 tools/testfiles/tattr2.ls                      | 143 -------
 tools/testfiles/tcomp-1.ls                     |   1 +
 tools/testfiles/tdset-1.ls                     |   1 +
 tools/testfiles/textlink-1.ls                  |   1 +
 tools/testfiles/tgroup-1.ls                    |  40 +-
 tools/testfiles/tgroup-2.ls                    |   4 +
 tools/testfiles/tloop-1.ls                     |   1 +
 tools/testfiles/tnestcomp-1.ls                 |   1 +
 tools/testfiles/tsaf.ls                        |   1 +
 tools/testfiles/tslink-1.ls                    |   1 +
 tools/testfiles/tstr-1.ls                      |   1 +
 tools/testfiles/tudlink-1.ls                   |   1 +
 tools/testfiles/tvldtypes1.ls                  |   1 +
 64 files changed, 1541 insertions(+), 1542 deletions(-)
 create mode 100644 tools/testfiles/tgroup-2.ls

diff --git a/MANIFEST b/MANIFEST
index bc6ef0a..00afbc9 100644
--- a/MANIFEST
+++ b/MANIFEST
@@ -1238,6 +1238,7 @@
 ./tools/testfiles/tcomp-1.ls
 ./tools/testfiles/tdset-1.ls
 ./tools/testfiles/tgroup-1.ls
+./tools/testfiles/tgroup-2.ls
 ./tools/testfiles/tgroup.ls
 ./tools/testfiles/thlink-1.ls
 ./tools/testfiles/tloop-1.ls
diff --git a/src/H5F.c b/src/H5F.c
index 8844b8d..045705f 100644
--- a/src/H5F.c
+++ b/src/H5F.c
@@ -2444,8 +2444,6 @@ H5F_get_driver_id(const H5F_t *f)
  * Programmer:	Quincey Koziol <koziol@ncsa.uiuc.edu>
  *		March 27, 2002
  *
- * Modifications:
- *
  *-------------------------------------------------------------------------
  */
 herr_t
@@ -2455,13 +2453,13 @@ H5F_get_fileno(const H5F_t *f, unsigned long *filenum)
 
     FUNC_ENTER_NOAPI(H5F_get_fileno, FAIL)
 
-    assert(f);
-    assert(f->shared);
-    assert(f->shared->lf);
-    assert(filenum);
+    HDassert(f);
+    HDassert(f->shared);
+    HDassert(f->shared->lf);
+    HDassert(filenum);
 
     /* Retrieve the file's serial number */
-    if(H5FD_get_fileno(f->shared->lf,filenum) < 0)
+    if(H5FD_get_fileno(f->shared->lf, filenum) < 0)
 	HGOTO_ERROR(H5E_FILE, H5E_BADRANGE, FAIL, "can't retrieve fileno")
 
 done:
diff --git a/src/H5FD.c b/src/H5FD.c
index 096509e..0cf70ca 100644
--- a/src/H5FD.c
+++ b/src/H5FD.c
@@ -3795,22 +3795,20 @@ done:
  * Programmer:	Quincey Koziol <koziol@ncsa.uiuc.edu>
  *		March 27, 2002
  *
- * Modifications:
- *
  *-------------------------------------------------------------------------
  */
 herr_t
 H5FD_get_fileno(const H5FD_t *file, unsigned long *filenum)
 {
-    herr_t ret_value=SUCCEED;   /* Return value */
+    herr_t ret_value = SUCCEED;   /* Return value */
 
     FUNC_ENTER_NOAPI(H5FD_get_fileno, FAIL)
 
-    assert(file);
-    assert(filenum);
+    HDassert(file);
+    HDassert(filenum);
 
     /* Retrieve the file's serial number */
-    HDmemcpy(filenum,&file->fileno,sizeof(file->fileno));
+    *filenum = file->fileno;
 
 done:
     FUNC_LEAVE_NOAPI(ret_value)
diff --git a/src/H5Fprivate.h b/src/H5Fprivate.h
index f9a1f57..1044b14 100644
--- a/src/H5Fprivate.h
+++ b/src/H5Fprivate.h
@@ -267,6 +267,7 @@ typedef struct H5F_t H5F_t;
 #define H5F_INTENT(F)           ((F)->intent)
 #define H5F_GET_FC_DEGREE(F)    ((F)->shared->fc_degree)
 #define H5F_STORE_MSG_CRT_IDX(F)    ((F)->shared->store_msg_crt_idx)
+#define H5F_GET_FILENO(F,FILENUM) ((FILENUM) = (F)->shared->lf->fileno)
 #else /* H5F_PACKAGE */
 #define H5F_FCPL(F)             (H5F_get_fcpl(F))
 #define H5F_SIZEOF_ADDR(F)      (H5F_sizeof_addr(F))
@@ -285,6 +286,7 @@ typedef struct H5F_t H5F_t;
 #define H5F_INTENT(F)           (H5F_get_intent(F))
 #define H5F_GET_FC_DEGREE(F)    (H5F_get_fc_degree(F))
 #define H5F_STORE_MSG_CRT_IDX(F)    (H5F_store_msg_crt_idx(F))
+#define H5F_GET_FILENO(F,FILENUM) (H5F_get_filenum((F), &(FILENUM)))
 #endif /* H5F_PACKAGE */
 
 
diff --git a/src/H5G.c b/src/H5G.c
index bca0332..116cdf8 100644
--- a/src/H5G.c
+++ b/src/H5G.c
@@ -88,6 +88,7 @@
 #include "H5Gpkg.h"		/* Groups		  		*/
 #include "H5Iprivate.h"		/* IDs			  		*/
 #include "H5Lprivate.h"         /* Links                                */
+#include "H5MMprivate.h"	/* Memory management			*/
 #include "H5Pprivate.h"         /* Property lists                       */
 
 /* Local macros */
@@ -100,14 +101,43 @@ typedef struct {
     H5G_loc_t *loc;         /* Pointer to the location for insertion */
 } H5G_trav_ins_t;
 
+/* User data for application-style iteration over links in a group */
+typedef struct {
+    hid_t       gid;            /* The group ID for the application callback */
+    H5G_link_iterate_t lnk_op;  /* Application callback */
+    void *op_data;              /* Application's op data */
+} H5G_iter_appcall_ud_t;
+
+/* User data for recursive traversal over links from a group */
+typedef struct {
+    hid_t       gid;            /* The group ID for the starting group */
+    H5G_loc_t	*curr_loc;      /* Location of starting group */
+    hid_t       lapl_id;        /* LAPL for walking across links */
+    hid_t       dxpl_id; 	/* DXPL for operations */
+    H5_index_t  idx_type;       /* Index to use */
+    H5_iter_order_t order;      /* Iteration order within index */
+    H5SL_t     *visited;        /* Skip list for tracking visited nodes */
+    char       *path;           /* Path name of the link */
+    size_t      curr_path_len;  /* Current length of the path in the buffer */
+    size_t      path_buf_size;  /* Size of path buffer */
+    H5L_iterate_t op;           /* Application callback */
+    void       *op_data;        /* Application's op data */
+} H5G_iter_visit_ud_t;
+
+
 /* Package variables */
 
+
 /* Local variables */
 
 /* Declare a free list to manage the H5G_t struct */
 H5FL_DEFINE(H5G_t);
 H5FL_DEFINE(H5G_shared_t);
 
+/* Declare the free list to manage H5_obj_t's */
+H5FL_DEFINE_STATIC(H5_obj_t);
+
+
 /* Private prototypes */
 static herr_t H5G_open_oid(H5G_t *grp, hid_t dxpl_id);
 
@@ -366,7 +396,7 @@ H5Gopen2(hid_t loc_id, const char *name, hid_t gapl_id)
     if((grp = H5G_open_name(&loc, name, gapl_id, H5AC_dxpl_id)) == NULL)
         HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open group")
 
-    /* Register an atom for the group */
+    /* Register an ID for the group */
     if((ret_value = H5I_register(H5I_GROUP, grp)) < 0)
         HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL, "unable to register group")
 
@@ -1019,8 +1049,8 @@ H5G_open_name(const H5G_loc_t *loc, const char *name, hid_t gapl_id,
     H5G_loc_t   grp_loc;                /* Location used to open group */
     H5G_name_t  grp_path;            	/* Opened object group hier. path */
     H5O_loc_t   grp_oloc;            	/* Opened object object location */
-    H5O_type_t  obj_type;               /* Type of object at location */
     hbool_t     loc_found = FALSE;      /* Location at 'name' found */
+    H5O_type_t  obj_type;               /* Type of object at location */
     H5G_t      *ret_value;              /* Return value */
 
     FUNC_ENTER_NOAPI(H5G_open_name, NULL)
@@ -1145,7 +1175,7 @@ H5G_open(const H5G_loc_t *loc, hid_t dxpl_id)
     ret_value = grp;
 
 done:
-    if (!ret_value && grp) {
+    if(!ret_value && grp) {
         H5O_loc_free(&(grp->oloc));
         H5G_name_free(&(grp->path));
         H5FL_FREE(H5G_t,grp);
@@ -1522,3 +1552,428 @@ H5G_unmount(H5G_t *grp)
     FUNC_LEAVE_NOAPI(SUCCEED)
 } /* end H5G_unmount() */
 
+
+/*-------------------------------------------------------------------------
+ * Function:	H5G_iterate_cb
+ *
+ * Purpose:     Callback function for iterating over links in a group
+ *
+ * Return:	Success:        Non-negative
+ *		Failure:	Negative
+ *
+ * Programmer:	Quincey Koziol
+ *	        Oct  3, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5G_iterate_cb(const H5O_link_t *lnk, void *_udata)
+{
+    H5G_iter_appcall_ud_t *udata = (H5G_iter_appcall_ud_t *)_udata;     /* User data for callback */
+    herr_t ret_value = H5_ITER_ERROR;   /* Return value */
+
+    FUNC_ENTER_NOAPI_NOINIT(H5G_iterate_cb)
+
+    /* Sanity check */
+    HDassert(lnk);
+    HDassert(udata);
+
+    switch(udata->lnk_op.op_type) {
+#ifndef H5_NO_DEPRECATED_SYMBOLS
+        case H5G_LINK_OP_OLD:
+            /* Make the old-type application callback */
+            ret_value = (udata->lnk_op.op_func.op_old)(udata->gid, lnk->name, udata->op_data);
+            break;
+#endif /* H5_NO_DEPRECATED_SYMBOLS */
+
+        case H5G_LINK_OP_NEW:
+            {
+                H5L_info_t info;    /* Link info */
+
+                /* Retrieve the info for the link */
+                if(H5G_link_to_info(lnk, &info) < 0)
+                    HGOTO_ERROR(H5E_SYM, H5E_CANTGET, H5_ITER_ERROR, "unable to get info for link")
+
+                /* Make the application callback */
+                ret_value = (udata->lnk_op.op_func.op_new)(udata->gid, lnk->name, &info, udata->op_data);
+            }
+            break;
+    } /* end switch */
+
+done:
+    FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_iterate_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function:	H5G_iterate
+ *
+ * Purpose:     Private function for iterating over links in a group
+ *
+ * Return:	Success:        Non-negative
+ *		Failure:	Negative
+ *
+ * Programmer:	Quincey Koziol
+ *	        Oct  3, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G_iterate(hid_t loc_id, const char *group_name,
+    H5_index_t idx_type, H5_iter_order_t order, hsize_t skip, hsize_t *last_lnk,
+    const H5G_link_iterate_t *lnk_op, void *op_data, hid_t lapl_id, hid_t dxpl_id)
+{
+    H5G_loc_t	loc;            /* Location of parent for group */
+    hid_t gid = -1;             /* ID of group to iterate over */
+    H5G_t *grp;                 /* Pointer to group data structure to iterate over */
+    H5G_iter_appcall_ud_t udata; /* User data for callback */
+    herr_t ret_value;           /* Return value */
+
+    FUNC_ENTER_NOAPI(H5G_iterate, FAIL)
+
+    /* Sanity check */
+    HDassert(group_name);
+    HDassert(last_lnk);
+    HDassert(lnk_op && lnk_op->op_func.op_new);
+
+    /*
+     * Open the group on which to operate.  We also create a group ID which
+     * we can pass to the application-defined operator.
+     */
+    if(H5G_loc(loc_id, &loc) < 0)
+        HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+    if(NULL == (grp = H5G_open_name(&loc, group_name, lapl_id, dxpl_id)))
+        HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open group")
+    if((gid = H5I_register(H5I_GROUP, grp)) < 0)
+        HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL, "unable to register group")
+
+    /* Set up user data for callback */
+    udata.gid = gid;
+    udata.lnk_op = *lnk_op;
+    udata.op_data = op_data;
+
+    /* Call the real group iteration routine */
+    if((ret_value = H5G_obj_iterate(&(grp->oloc), idx_type, order, skip, last_lnk, H5G_iterate_cb, &udata, dxpl_id)) < 0)
+        HGOTO_ERROR(H5E_SYM, H5E_BADITER, FAIL, "error iterating over links")
+
+done:
+    /* Release the group opened */
+    if(gid > 0) {
+        if(H5I_dec_ref(gid) < 0)
+            HDONE_ERROR(H5E_SYM, H5E_CANTRELEASE, FAIL, "unable to close group")
+    } /* end if */
+    else if(grp && H5G_close(grp) < 0)
+        HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "unable to release group")
+
+    FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_iterate() */
+
+
+/*-------------------------------------------------------------------------
+ * Function:    H5G_free_visit_visited
+ *
+ * Purpose:     Free the key for an object visited during a group traversal
+ *
+ * Return:      Non-negative on success, negative on failure
+ *
+ * Programmer:  Quincey Koziol
+ *	        Nov  4, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5G_free_visit_visited(void *item, void UNUSED *key, void UNUSED *operator_data/*in,out*/)
+{
+    FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5G_free_visit_visited)
+
+    H5FL_FREE(H5_obj_t, item);
+
+    FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5G_free_visit_visited() */
+
+
+/*-------------------------------------------------------------------------
+ * Function:	H5G_visit_cb
+ *
+ * Purpose:     Callback function for recursively visiting links from a group
+ *
+ * Return:	Success:        Non-negative
+ *		Failure:	Negative
+ *
+ * Programmer:	Quincey Koziol
+ *	        Nov  4, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5G_visit_cb(const H5O_link_t *lnk, void *_udata)
+{
+    H5G_iter_visit_ud_t *udata = (H5G_iter_visit_ud_t *)_udata;     /* User data for callback */
+    H5L_info_t info;                    /* Link info */
+    H5G_loc_t   obj_loc;                /* Location of object */
+    H5G_name_t  obj_path;            	/* Object's group hier. path */
+    H5O_loc_t   obj_oloc;            	/* Object's object location */
+    hbool_t     obj_found = FALSE;      /* Object at 'name' found */
+    size_t old_path_len = udata->curr_path_len; /* Length of path before appending this link's name */
+    size_t link_name_len;               /* Length of link's name */
+    size_t len_needed;                  /* Length of path string needed */
+    herr_t ret_value = H5_ITER_CONT;    /* Return value */
+
+    FUNC_ENTER_NOAPI_NOINIT(H5G_visit_cb)
+
+    /* Sanity check */
+    HDassert(lnk);
+    HDassert(udata);
+
+    /* Check if we will need more space to store this link's relative path */
+    /* ("+2" is for string terminator and possible '/' for group separator later) */
+    link_name_len = HDstrlen(lnk->name);
+    len_needed = udata->curr_path_len + link_name_len + 2;
+    if(len_needed > udata->path_buf_size) {
+        void *new_path;         /* Pointer to new path buffer */
+
+        /* Attempt to allocate larger buffer for path */
+        if(NULL == (new_path = H5MM_realloc(udata->path, len_needed)))
+            HGOTO_ERROR(H5E_SYM, H5E_NOSPACE, H5_ITER_ERROR, "can't allocate path string")
+        udata->path = new_path;
+        udata->path_buf_size = len_needed;
+    } /* end if */
+
+    /* Build the link's relative path name */
+    HDassert(udata->path[old_path_len] == '\0');
+    HDstrcpy(&(udata->path[old_path_len]), lnk->name); 
+    udata->curr_path_len += link_name_len;
+
+    /* Construct the link info from the link message */
+    if(H5G_link_to_info(lnk, &info) < 0)
+        HGOTO_ERROR(H5E_SYM, H5E_CANTGET, H5_ITER_ERROR, "unable to get info for link")
+
+    /* Make the application callback */
+    ret_value = (udata->op)(udata->gid, udata->path, &info, udata->op_data);
+
+    /* Check for doing more work */
+    if(ret_value == H5_ITER_CONT && lnk->type == H5L_TYPE_HARD) {
+        H5O_type_t otype;       /* Basic object type (group, dataset, etc.) */
+        H5_obj_t obj_pos;       /* Object "position" for this object */
+        unsigned rc;		/* Reference count of object    */
+
+        /* Set up opened group location to fill in */
+        obj_loc.oloc = &obj_oloc;
+        obj_loc.path = &obj_path;
+        H5G_loc_reset(&obj_loc);
+
+        /* Find the object using the LAPL passed in */
+        /* (Correctly handles mounted files) */
+        if(H5G_loc_find(udata->curr_loc, lnk->name, &obj_loc/*out*/, udata->lapl_id, udata->dxpl_id) < 0)
+            HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, H5_ITER_ERROR, "object not found")
+        obj_found = TRUE;
+
+        /* Construct unique "position" for this object */
+        H5F_GET_FILENO(obj_oloc.file, obj_pos.fileno);
+        obj_pos.addr = obj_oloc.addr;
+
+        /* Check if we've seen the object the link references before */
+        if(NULL == H5SL_search(udata->visited, &obj_pos)) {
+            /* Get the object's reference count and type */
+            if(H5O_get_rc_and_type(&obj_oloc, udata->dxpl_id, &rc, &otype) < 0)
+                HGOTO_ERROR(H5E_SYM, H5E_CANTGET, H5_ITER_ERROR, "unable to get object info")
+
+            /* If its ref count is > 1, we add it to the list of visited objects */
+            /* (because it could come up again during traversal) */
+            if(rc > 1) {
+                H5_obj_t *new_node;                  /* New object node for visited list */
+
+                /* Allocate new object "position" node */
+                if((new_node = H5FL_MALLOC(H5_obj_t)) == NULL)
+                    HGOTO_ERROR(H5E_SYM, H5E_NOSPACE, H5_ITER_ERROR, "can't allocate object node")
+
+                /* Set node information */
+                *new_node = obj_pos;
+
+                /* Add to list of visited objects */
+                if(H5SL_insert(udata->visited, new_node, new_node) < 0)
+                    HGOTO_ERROR(H5E_SYM, H5E_CANTINSERT, H5_ITER_ERROR, "can't insert object node into visited list")
+            } /* end if */
+
+            /* If it's a group, we recurse into it */
+            if(otype == H5O_TYPE_GROUP) {
+                H5G_loc_t *old_loc = udata->curr_loc;       /* Pointer to previous group location info */
+                H5_index_t idx_type = udata->idx_type;      /* Type of index to use */
+                H5O_linfo_t	linfo;		        /* Link info message */
+
+                /* Add the path separator to the current path */
+                HDassert(udata->path[udata->curr_path_len] == '\0');
+                HDstrcpy(&(udata->path[udata->curr_path_len]), "/"); 
+                udata->curr_path_len++;
+                    
+                /* Attempt to get the link info for this group */
+                if(H5G_obj_get_linfo(&obj_oloc, &linfo, udata->dxpl_id)) {
+                    /* Check for creation order tracking, if creation order index lookup requested */
+                    if(idx_type == H5_INDEX_CRT_ORDER) {
+                        /* Check if creation order is tracked */
+                        if(!linfo.track_corder)
+                            /* Switch to name order for this group */
+                            idx_type = H5_INDEX_NAME;
+                    } /* end if */
+                    else
+                        HDassert(idx_type == H5_INDEX_NAME);
+                } /* end if */
+                else {
+                    /* Clear error stack from not finding the link info message */
+                    H5E_clear_stack(NULL);
+
+                    /* Can only perform name lookups on groups with symbol tables */
+                    if(idx_type != H5_INDEX_NAME)
+                        /* Switch to name order for this group */
+                        idx_type = H5_INDEX_NAME;
+                } /* end if */
+
+                /* Point to this group's location info */
+                udata->curr_loc = &obj_loc;
+
+                /* Iterate over links in group */
+                ret_value = H5G_obj_iterate(&obj_oloc, idx_type, udata->order, (hsize_t)0, NULL, H5G_visit_cb, udata, udata->dxpl_id);
+
+                /* Restore location */
+                udata->curr_loc = old_loc;
+            } /* end if */
+        } /* end if */
+    } /* end if */
+
+done:
+    /* Reset path back to incoming path */
+    udata->path[old_path_len] = '\0';
+    udata->curr_path_len = old_path_len;
+
+    /* Release resources */
+    if(obj_found && H5G_loc_free(&obj_loc) < 0)
+        HDONE_ERROR(H5E_SYM, H5E_CANTRELEASE, H5_ITER_ERROR, "can't free location")
+
+    FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_visit_cb() */
+
+
+/*-------------------------------------------------------------------------
+ * Function:	H5G_visit
+ *
+ * Purpose:	Recursively visit all the links in a group and all
+ *              the groups that are linked to from that group.  Links within
+ *              each group are visited according to the order within the
+ *              specified index (unless the specified index does not exist for
+ *              a particular group, then the "name" index is used).
+ *
+ *              NOTE: Each _link_ reachable from the initial group will only be
+ *              visited once.  However, because an object may be reached from
+ *              more than one link, the visitation may call the application's
+ *              callback with more than one link that points to a particular
+ *              _object_.
+ *
+ * Return:	Success:	The return value of the first operator that
+ *				returns non-zero, or zero if all members were
+ *				processed with no operator returning non-zero.
+ *
+ *		Failure:	Negative if something goes wrong within the
+ *				library, or the negative value returned by one
+ *				of the operators.
+ *
+ *
+ *
+ * Programmer:	Quincey Koziol
+ *		November 4 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5G_visit(hid_t loc_id, const char *group_name, H5_index_t idx_type,
+    H5_iter_order_t order, H5L_iterate_t op, void *op_data, hid_t lapl_id,
+    hid_t dxpl_id)
+{
+    H5G_iter_visit_ud_t udata;       /* User data for callback */
+    H5O_linfo_t	linfo;		        /* Link info message */
+    hid_t       gid = (-1);             /* Group ID */
+    H5G_t      *grp = NULL;             /* Group opened */
+    H5G_loc_t	loc;                    /* Location of group passed in */
+    H5G_loc_t	start_loc;              /* Location of starting group */
+    herr_t      ret_value;              /* Return value */
+
+    FUNC_ENTER_NOAPI(H5G_visit, FAIL)
+
+    /* Check args */
+    if(H5G_loc(loc_id, &loc) < 0)
+        HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+
+    /* Open the group to begin visiting within */
+    if((grp = H5G_open_name(&loc, group_name, lapl_id, dxpl_id)) == NULL)
+        HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open group")
+
+    /* Register an ID for the starting group */
+    if((gid = H5I_register(H5I_GROUP, grp)) < 0)
+        HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL, "unable to register group")
+
+    /* Get the location of the starting group */
+    if(H5G_loc(gid, &start_loc) < 0)
+        HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+
+    /* Set up user data */
+    udata.gid = gid;
+    udata.curr_loc = &start_loc;
+    udata.lapl_id = lapl_id;
+    udata.dxpl_id = dxpl_id;
+    udata.idx_type = idx_type;
+    udata.order = order;
+    udata.op = op;
+    udata.op_data = op_data;
+
+    /* Allocate space for the path name */
+    if(NULL == (udata.path = H5MM_strdup("")))
+        HGOTO_ERROR(H5E_SYM, H5E_NOSPACE, FAIL, "can't allocate path name buffer")
+    udata.path_buf_size = 1;
+    udata.curr_path_len = 0;
+
+    /* Create skip list to store reference path information */
+    if((udata.visited = H5SL_create(H5SL_TYPE_OBJ, 0.5, (size_t)16)) == NULL)
+        HGOTO_ERROR(H5E_SYM, H5E_CANTCREATE, FAIL, "can't create skip list for visited objects")
+
+    /* Attempt to get the link info for this group */
+    if(H5G_obj_get_linfo(&(grp->oloc), &linfo, dxpl_id)) {
+        /* Check for creation order tracking, if creation order index lookup requested */
+        if(idx_type == H5_INDEX_CRT_ORDER) {
+            /* Check if creation order is tracked */
+            if(!linfo.track_corder)
+                /* Switch to name order for this group */
+                idx_type = H5_INDEX_NAME;
+        } /* end if */
+        else
+            HDassert(idx_type == H5_INDEX_NAME);
+    } /* end if */
+    else {
+        /* Clear error stack from not finding the link info message */
+        H5E_clear_stack(NULL);
+
+        /* Can only perform name lookups on groups with symbol tables */
+        if(idx_type != H5_INDEX_NAME)
+            /* Switch to name order for this group */
+            idx_type = H5_INDEX_NAME;
+    } /* end if */
+
+    /* Call the link iteration routine */
+    if((ret_value = H5G_obj_iterate(&(grp->oloc), idx_type, order, (hsize_t)0, NULL, H5G_visit_cb, &udata, dxpl_id)) < 0)
+        HGOTO_ERROR(H5E_SYM, H5E_BADITER, FAIL, "can't visit links")
+
+done:
+    /* Release user data resources */
+    H5MM_xfree(udata.path);
+    if(udata.visited)
+        H5SL_destroy(udata.visited, H5G_free_visit_visited, NULL);
+
+    /* Release the group opened */
+    if(gid > 0) {
+        if(H5I_dec_ref(gid) < 0)
+            HDONE_ERROR(H5E_SYM, H5E_CANTRELEASE, FAIL, "unable to close group")
+    } /* end if */
+    else if(grp && H5G_close(grp) < 0)
+        HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "unable to release group")
+
+    FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5G_visit() */
+
diff --git a/src/H5Gcompact.c b/src/H5Gcompact.c
index 042d29a..b0340a7 100644
--- a/src/H5Gcompact.c
+++ b/src/H5Gcompact.c
@@ -406,9 +406,9 @@ done:
  *-------------------------------------------------------------------------
  */
 herr_t
-H5G_compact_iterate(H5O_loc_t *oloc, hid_t dxpl_id, const H5O_linfo_t *linfo, 
+H5G_compact_iterate(const H5O_loc_t *oloc, hid_t dxpl_id, const H5O_linfo_t *linfo, 
     H5_index_t idx_type, H5_iter_order_t order, hsize_t skip, hsize_t *last_lnk,
-    hid_t gid, H5G_link_iterate_t *lnk_op, void *op_data)
+    H5G_lib_iterate_t op, void *op_data)
 {
     H5G_link_table_t    ltable = {0, NULL};     /* Link table */
     herr_t		ret_value;              /* Return value */
@@ -418,14 +418,14 @@ H5G_compact_iterate(H5O_loc_t *oloc, hid_t dxpl_id, const H5O_linfo_t *linfo,
     /* Sanity check */
     HDassert(oloc);
     HDassert(linfo);
-    HDassert(lnk_op && lnk_op->u.lib_op);
+    HDassert(op);
 
     /* Build table of all link messages */
     if(H5G_compact_build_table(oloc, dxpl_id, linfo, idx_type, order, &ltable) < 0)
         HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "can't create link message table")
 
     /* Iterate over links in table */
-    if((ret_value = H5G_link_iterate_table(&ltable, skip, last_lnk, gid, lnk_op, op_data)) < 0)
+    if((ret_value = H5G_link_iterate_table(&ltable, skip, last_lnk, op, op_data)) < 0)
         HERROR(H5E_SYM, H5E_CANTNEXT, "iteration operator failed");
 
 done:
diff --git a/src/H5Gdense.c b/src/H5Gdense.c
index 2b7493b..ed53a47 100644
--- a/src/H5Gdense.c
+++ b/src/H5Gdense.c
@@ -90,9 +90,8 @@ typedef struct {
     hsize_t     count;                  /* # of links examined               */
 
     /* downward (from application) */
-    hid_t       gid;                    /* Group ID for application callback */
     hsize_t     skip;                   /* Number of links to skip           */
-    const H5G_link_iterate_t *lnk_op;   /* Callback for each link            */
+    H5G_lib_iterate_t op;               /* Callback for each link            */
     void        *op_data;               /* Callback data for each link       */
 
     /* upward */
@@ -799,7 +798,6 @@ H5G_dense_build_table(H5F_t *f, hid_t dxpl_id, const H5O_linfo_t *linfo,
     /* Allocate space for the table entries */
     if(ltable->nlinks > 0) {
         H5G_dense_bt_ud_t udata;       /* User data for iteration callback */
-        H5G_link_iterate_t lnk_op;      /* Link operator */
 
         /* Allocate the table to store the links */
         if((ltable->lnks = H5MM_malloc(sizeof(H5O_link_t) * ltable->nlinks)) == NULL)
@@ -809,12 +807,8 @@ H5G_dense_build_table(H5F_t *f, hid_t dxpl_id, const H5O_linfo_t *linfo,
         udata.ltable = ltable;
         udata.curr_lnk = 0;
 
-        /* Build iterator operator */
-        lnk_op.op_type = H5G_LINK_OP_LIB;
-        lnk_op.u.lib_op = H5G_dense_build_table_cb;
-
         /* Iterate over the links in the group, building a table of the link messages */
-        if(H5G_dense_iterate(f, dxpl_id, linfo, H5_INDEX_NAME, H5_ITER_NATIVE, (hsize_t)0, NULL, (hid_t)0, &lnk_op, &udata) < 0)
+        if(H5G_dense_iterate(f, dxpl_id, linfo, H5_INDEX_NAME, H5_ITER_NATIVE, (hsize_t)0, NULL, H5G_dense_build_table_cb, &udata) < 0)
             HGOTO_ERROR(H5E_SYM, H5E_CANTNEXT, FAIL, "error iterating over links")
 
         /* Sort link table in correct iteration order */
@@ -904,32 +898,8 @@ H5G_dense_iterate_bt2_cb(const void *_record, void *_bt2_udata)
                 H5G_dense_iterate_fh_cb, &fh_udata) < 0)
             HGOTO_ERROR(H5E_SYM, H5E_CANTOPERATE, H5_ITER_ERROR, "heap op callback failed")
 
-        /* Check which type of callback to make */
-        switch(bt2_udata->lnk_op->op_type) {
-#ifndef H5_NO_DEPRECATED_SYMBOLS
-            case H5G_LINK_OP_OLD:
-                /* Make the old-type application callback */
-                ret_value = (bt2_udata->lnk_op->u.old_op)(bt2_udata->gid, fh_udata.lnk->name, bt2_udata->op_data);
-                break;
-#endif /* H5_NO_DEPRECATED_SYMBOLS */
-
-            case H5G_LINK_OP_APP:
-                {
-                    H5L_info_t info;    /* Link info */
-
-                    /* Retrieve the info for the link */
-                    if(H5G_link_to_info(fh_udata.lnk, &info) < 0)
-                        HGOTO_ERROR(H5E_SYM, H5E_CANTGET, H5_ITER_ERROR, "unable to get info for link")
-
-                    /* Make the application callback */
-                    ret_value = (bt2_udata->lnk_op->u.app_op)(bt2_udata->gid, fh_udata.lnk->name, &info, bt2_udata->op_data);
-                }
-                break;
-
-            case H5G_LINK_OP_LIB:
-                /* Call the library's callback */
-                ret_value = (bt2_udata->lnk_op->u.lib_op)(fh_udata.lnk, bt2_udata->op_data);
-        } /* end switch */
+        /* Make the callback */
+        ret_value = (bt2_udata->op)(fh_udata.lnk, bt2_udata->op_data);
 
         /* Release the space allocated for the link */
         H5O_msg_free(H5O_LINK_ID, fh_udata.lnk);
@@ -964,7 +934,7 @@ done:
 herr_t
 H5G_dense_iterate(H5F_t *f, hid_t dxpl_id, const H5O_linfo_t *linfo,
     H5_index_t idx_type, H5_iter_order_t order, hsize_t skip, hsize_t *last_lnk,
-    hid_t gid, const H5G_link_iterate_t *lnk_op, void *op_data)
+    H5G_lib_iterate_t op, void *op_data)
 {
     H5HF_t *fheap = NULL;               /* Fractal heap handle */
     H5G_link_table_t ltable = {0, NULL};      /* Table of links */
@@ -979,7 +949,7 @@ H5G_dense_iterate(H5F_t *f, hid_t dxpl_id, const H5O_linfo_t *linfo,
      */
     HDassert(f);
     HDassert(linfo);
-    HDassert(lnk_op && lnk_op->u.lib_op);
+    HDassert(op);
 
     /* Determine the address of the index to use */
     if(idx_type == H5_INDEX_NAME) {
@@ -1018,10 +988,9 @@ H5G_dense_iterate(H5F_t *f, hid_t dxpl_id, const H5O_linfo_t *linfo,
         udata.f = f;
         udata.dxpl_id = dxpl_id;
         udata.fheap = fheap;
-        udata.gid = gid;
         udata.skip = skip;
         udata.count = 0;
-        udata.lnk_op = lnk_op;
+        udata.op = op;
         udata.op_data = op_data;
 
         /* Iterate over the records in the v2 B-tree's "native" order */
@@ -1039,7 +1008,7 @@ H5G_dense_iterate(H5F_t *f, hid_t dxpl_id, const H5O_linfo_t *linfo,
             HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "error building table of links")
 
         /* Iterate over links in table */
-        if((ret_value = H5G_link_iterate_table(&ltable, skip, last_lnk, gid, lnk_op, op_data)) < 0)
+        if((ret_value = H5G_link_iterate_table(&ltable, skip, last_lnk, op, op_data)) < 0)
             HERROR(H5E_SYM, H5E_CANTNEXT, "iteration operator failed");
     } /* end else */
 
diff --git a/src/H5Gdeprec.c b/src/H5Gdeprec.c
index 52b607d..01c4edb 100644
--- a/src/H5Gdeprec.c
+++ b/src/H5Gdeprec.c
@@ -770,10 +770,10 @@ H5Giterate(hid_t loc_id, const char *name, int *idx_p, H5G_iterate_t op,
 
     /* Build link operator info */
     lnk_op.op_type = H5G_LINK_OP_OLD;
-    lnk_op.u.old_op = op;
+    lnk_op.op_func.op_old = op;
 
     /* Call private function. */
-    if((ret_value = H5G_obj_iterate(loc_id, name, H5_INDEX_NAME, H5_ITER_INC, idx, &last_obj, &lnk_op, op_data, H5P_DEFAULT, H5AC_ind_dxpl_id)) < 0)
+    if((ret_value = H5G_iterate(loc_id, name, H5_INDEX_NAME, H5_ITER_INC, idx, &last_obj, &lnk_op, op_data, H5P_DEFAULT, H5AC_ind_dxpl_id)) < 0)
 	HGOTO_ERROR(H5E_SYM, H5E_BADITER, FAIL, "group iteration failed")
 
     /* Set the index we stopped at */
diff --git a/src/H5Glink.c b/src/H5Glink.c
index 7292245..75a3e83 100644
--- a/src/H5Glink.c
+++ b/src/H5Glink.c
@@ -603,7 +603,7 @@ H5G_link_sort_table(H5G_link_table_t *ltable, H5_index_t idx_type,
  */
 herr_t
 H5G_link_iterate_table(const H5G_link_table_t *ltable, hsize_t skip,
-    hsize_t *last_lnk, hid_t gid, const H5G_link_iterate_t *lnk_op, void *op_data)
+    hsize_t *last_lnk, const H5G_lib_iterate_t op, void *op_data)
 {
     size_t u;                           /* Local index variable */
     herr_t ret_value = H5_ITER_CONT;   /* Return value */
@@ -612,7 +612,7 @@ H5G_link_iterate_table(const H5G_link_table_t *ltable, hsize_t skip,
 
     /* Sanity check */
     HDassert(ltable);
-    HDassert(lnk_op);
+    HDassert(op);
 
     /* Skip over links, if requested */
     if(last_lnk)
@@ -621,32 +621,8 @@ H5G_link_iterate_table(const H5G_link_table_t *ltable, hsize_t skip,
     /* Iterate over link messages */
     H5_ASSIGN_OVERFLOW(/* To: */ u, /* From: */ skip, /* From: */ hsize_t, /* To: */ size_t)
     for(; u < ltable->nlinks && !ret_value; u++) {
-        /* Check which kind of callback to make */
-        switch(lnk_op->op_type) {
-#ifndef H5_NO_DEPRECATED_SYMBOLS
-            case H5G_LINK_OP_OLD:
-                /* Make the old-type application callback */
-                ret_value = (lnk_op->u.old_op)(gid, ltable->lnks[u].name, op_data);
-                break;
-#endif /* H5_NO_DEPRECATED_SYMBOLS */
-
-            case H5G_LINK_OP_APP:
-                {
-                    H5L_info_t info;    /* Link info */
-
-                    /* Retrieve the info for the link */
-                    if(H5G_link_to_info(&(ltable->lnks[u]), &info) < 0)
-                        HGOTO_ERROR(H5E_SYM, H5E_CANTGET, H5_ITER_ERROR, "unable to get info for link")
-
-                    /* Make the application callback */
-                    ret_value = (lnk_op->u.app_op)(gid, ltable->lnks[u].name, &info, op_data);
-                }
-                break;
-
-            case H5G_LINK_OP_LIB:
-                /* Call the library's callback */
-                ret_value = (lnk_op->u.lib_op)(&(ltable->lnks[u]), op_data);
-        } /* end switch */
+        /* Make the callback */
+        ret_value = (op)(&(ltable->lnks[u]), op_data);
 
         /* Increment the number of entries passed through */
         if(last_lnk)
@@ -657,7 +633,6 @@ H5G_link_iterate_table(const H5G_link_table_t *ltable, hsize_t skip,
     if(ret_value < 0)
         HERROR(H5E_SYM, H5E_CANTNEXT, "iteration operator failed");
 
-done:
     FUNC_LEAVE_NOAPI(ret_value)
 } /* end H5G_link_iterate_table() */
 
diff --git a/src/H5Gname.c b/src/H5Gname.c
index e341ee7..bde9e23 100644
--- a/src/H5Gname.c
+++ b/src/H5Gname.c
@@ -50,21 +50,15 @@ typedef struct H5G_names_t {
 } H5G_names_t;
 
 /* Info to pass to the iteration function when building name */
-typedef struct H5G_ref_path_iter_t {
+typedef struct H5G_gnba_iter_t {
     /* In */
-    hid_t file; 		/* File id where it came from */
+    const H5O_loc_t *loc; 	/* The location of the object we're looking for */
     hid_t lapl_id; 		/* LAPL for operations */
     hid_t dxpl_id; 		/* DXPL for operations */
-    hbool_t is_root_group; 	/* Flag to indicate that the root group is being looked at */
-    const H5O_loc_t *loc; 	/* The location of the object we're looking for */
-
-    /* In/Out */
-    H5SL_t *ref_path_table;     /* Skip list for tracking visited nodes */
-    size_t max_container_len;   /* Maximum size of container */
 
     /* Out */
-    char *container;            /* full name of the container object */
-} H5G_ref_path_iter_t;
+    char *path;                 /* Name of the object */
+} H5G_gnba_iter_t;
 
 /* Private macros */
 
@@ -85,9 +79,6 @@ static H5RS_str_t *H5G_build_fullpath_refstr_refstr(const H5RS_str_t *prefix_r,
 static herr_t H5G_name_move_path(H5RS_str_t **path_r_ptr,
     const char *full_suffix, const char *src_path, const char *dst_path);
 static int H5G_name_replace_cb(void *obj_ptr, hid_t obj_id, void *key);
-static herr_t H5G_refname_iterator(hid_t group, const char *name,
-    const H5L_info_t *link_info, void *_udata);
-static herr_t H5G_free_ref_path_node(void *item, void *key, void *operator_data/*in,out*/);
 
 
 /*-------------------------------------------------------------------------
@@ -468,7 +459,7 @@ H5G_get_name(hid_t id, char *name/*out*/, size_t size, hid_t lapl_id,
 		HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't retrieve file ID")
 
             /* Search for name of object */
-	    if((len = H5G_get_refobj_name(file, lapl_id, dxpl_id, loc.oloc, name, size)) < 0) {
+	    if((len = H5G_get_name_by_addr(file, lapl_id, dxpl_id, loc.oloc, name, size)) < 0) {
                 H5I_dec_ref(file);
 		HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't determine name")
             } /* end if */
@@ -1039,222 +1030,139 @@ done:
 
 
 /*-------------------------------------------------------------------------
- * Function:    H5G_refname_iterator
+ * Function:    H5G_get_name_by_addr_cb
  *
- * Purpose:     The iterator which traverses all objects in a file looking for
- * 		one that matches the object that is being looked for.
+ * Purpose:     Callback for retrieving object's name by address
  *
- * Return:      1 on success, 0 to continue searching, negative on failure.
- *
- * Programmer:  Leon Arber, Nov 1, 2006.
+ * Return:      Positive if path is for object desired
+ * 		0 if not correct object
+ * 		negative on failure.
  *
- * Modifications:
- * 		Quincey Koziol, Nov. 3, 2006
- * 		Cleaned up code.
+ * Programmer:	Quincey Koziol
+ *		November 4 2007
  *
  *-------------------------------------------------------------------------
  */
 static herr_t
-H5G_refname_iterator(hid_t group, const char *name, const H5L_info_t *link_info,
+H5G_get_name_by_addr_cb(hid_t gid, const char *path, const H5L_info_t *linfo,
     void *_udata)
 {
-    H5G_ref_path_iter_t *udata = (H5G_ref_path_iter_t*)_udata;
-    herr_t ret_value = H5_ITER_CONT;       /* Return value */
-    
-    FUNC_ENTER_NOAPI_NOINIT(H5G_refname_iterator)
-    
-    /* We only care about hard links */
-    if(link_info->type == H5L_TYPE_HARD) {
-        H5G_loc_t loc;              /* Group location of parent */
-
-        /* Look up group's location */
-        if(H5G_loc(group, &loc) < 0)
-            HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5_ITER_ERROR, "not a location")
-
-        /* Check for finding the object */
-        /* (checks against the file in the location as well, to make certain that
-         *  the correct object is found in a mounted file hierarchy)
-         */
-        if(udata->loc->addr == link_info->u.address && udata->loc->file == loc.oloc->file) {
-            size_t len_needed;              /* Length of container string needed */
-
-            /* Build the object's full name */
-            len_needed = HDstrlen(udata->container) + HDstrlen(name) + 2;
-            if(len_needed > udata->max_container_len) {
-                void *new_container;    /* Pointer to new container */
-
-                if(NULL == (new_container = H5MM_realloc(udata->container, len_needed)))
-                    HGOTO_ERROR(H5E_SYM, H5E_NOSPACE, H5_ITER_ERROR, "can't allocate path string")
-                udata->container = new_container;
-                udata->max_container_len = len_needed;
-            } /* end if */
-            HDstrcat(udata->container, name); 
+    H5G_gnba_iter_t *udata = (H5G_gnba_iter_t *)_udata; /* User data for iteration */
+    H5G_loc_t   obj_loc;                /* Location of object */
+    H5G_name_t  obj_path;            	/* Object's group hier. path */
+    H5O_loc_t   obj_oloc;            	/* Object's object location */
+    hbool_t     obj_found = FALSE;      /* Object at 'path' found */
+    herr_t ret_value = H5_ITER_CONT;    /* Return value */
 
-            /* We found a match so we return immediately */
-            HGOTO_DONE(H5_ITER_STOP)
-        } /* end if */
-        else {
-            H5O_info_t oinfo;   /* Object information */
-            H5O_loc_t tmp_oloc; /* Temporary object location */
+    FUNC_ENTER_NOAPI_NOINIT(H5G_get_name_by_addr_cb)
 
-            /* Check if we've seen this object before */
-            if(H5SL_search(udata->ref_path_table, &link_info->u.address))
-                HGOTO_DONE(H5_ITER_CONT)
+    /* Sanity check */
+    HDassert(path);
+    HDassert(linfo);
+    HDassert(udata->loc);
+    HDassert(udata->path == NULL);
 
-            /* Go retrieve the object information */
-            tmp_oloc.file = loc.oloc->file;
-            tmp_oloc.addr = link_info->u.address;
-            if(H5O_get_info(&tmp_oloc, udata->dxpl_id, FALSE, &oinfo) < 0)
-                HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, H5_ITER_ERROR, "unable to get object info")
+    /* Check for hard link with correct address */
+    if(linfo->type == H5L_TYPE_HARD && udata->loc->addr == linfo->u.address) {
+        H5G_loc_t	grp_loc;                /* Location of group */
 
-            /* If its ref count is > 1, we add it to the list of visited objects */
-            if(oinfo.rc > 1) {
-                haddr_t *new_node;                  /* New path node for table */
+        /* Get group's location */
+        if(H5G_loc(gid, &grp_loc) < 0)
+            HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5_ITER_ERROR, "bad group location")
 
-                /* Allocate new path node */
-                if((new_node = H5FL_MALLOC(haddr_t)) == NULL)
-                    HGOTO_ERROR(H5E_SYM, H5E_NOSPACE, H5_ITER_ERROR, "can't allocate path node")
+        /* Set up opened object location to fill in */
+        obj_loc.oloc = &obj_oloc;
+        obj_loc.path = &obj_path;
+        H5G_loc_reset(&obj_loc);
 
-                /* Set node information */
-                *new_node = link_info->u.address;
+        /* Find the object */
+        if(H5G_loc_find(&grp_loc, path, &obj_loc/*out*/, udata->lapl_id, udata->dxpl_id) < 0)
+            HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, H5_ITER_ERROR, "object not found")
+        obj_found = TRUE;
 
-                /* Insert into skip list */
-                if(H5SL_insert(udata->ref_path_table, new_node, new_node) < 0)
-                    HGOTO_ERROR(H5E_SYM, H5E_CANTINSERT, H5_ITER_ERROR, "can't insert path node into table")
-            } /* end if */
+        /* Check for object in same file (handles mounted files) */
+        /* (re-verify address, in case we traversed a file mount) */
+        if(udata->loc->addr == obj_loc.oloc->addr && udata->loc->file == obj_loc.oloc->file) {
+            udata->path = H5MM_strdup(path);
 
-            /* If it's a group, we recurse into it */
-            if(oinfo.type == H5O_TYPE_GROUP) {
-                H5G_link_iterate_t lnk_op;          /* Link operator */
-                hsize_t last_obj;
-                size_t len_needed;                  /* Length of container string needed */
-                size_t len;
-
-                /* Build full path name of group to recurse into */
-                len = HDstrlen(udata->container);
-                len_needed = len + HDstrlen(name) + 2;
-                if(len_needed > udata->max_container_len) {
-                    void *new_container;    /* Pointer to new container */
-
-                    if(NULL == (new_container = H5MM_realloc(udata->container, len_needed)))
-                        HGOTO_ERROR(H5E_SYM, H5E_NOSPACE, H5_ITER_ERROR, "can't allocate path string")
-                    udata->container = new_container;
-                    udata->max_container_len = len_needed;
-                } /* end if */
-                if(!udata->is_root_group)
-                    HDstrcat(udata->container, name); 
-                else
-                    udata->is_root_group = FALSE;
-                HDstrcat(udata->container, "/"); 
-                    
-                /* Build iterator operator */
-                lnk_op.op_type = H5G_LINK_OP_APP;
-                lnk_op.u.app_op = H5G_refname_iterator;
-
-                ret_value = H5G_obj_iterate(udata->file, udata->container, H5_INDEX_NAME, H5_ITER_NATIVE, (hsize_t)0, &last_obj, &lnk_op, udata, udata->lapl_id, udata->dxpl_id);
-                
-                /* If we didn't find the object, truncate the name to not include group name anymore */
-                if(!ret_value)
-                    udata->container[len] = '\0'; 
-            } /* end if */
-        } /* end else */
+            /* We found a match so we return immediately */
+            HGOTO_DONE(H5_ITER_STOP)
+        } /* end if */
     } /* end if */
+   
+done:    
+    if(obj_found && H5G_loc_free(&obj_loc) < 0)
+        HDONE_ERROR(H5E_SYM, H5E_CANTRELEASE, H5_ITER_ERROR, "can't free location")
 
-done:
     FUNC_LEAVE_NOAPI(ret_value)
-} /* end H5G_refname_iterator() */
+} /* end H5G_get_name_by_addr_cb() */
 
 
 /*-------------------------------------------------------------------------
- * Function:    H5G_free_ref_path_node
- *
- * Purpose:     Free the key for a reference path table node
- *
- * Return:      Non-negative on success, negative on failure
+ * Function:    H5G_get_name_by_addr
  *
- * Programmer:  Quincey Koziol
- *
- * Modifications:
- * 		Leon Arber, Oct. 25, 2006.  Moved into H5G from h5ls
- * 		tools lib for looking up path to reference.
- *
- * 		Quincey Koziol, Nov. 3, 2006
- * 		Cleaned up code.
- *
- *-------------------------------------------------------------------------
- */
-static herr_t
-H5G_free_ref_path_node(void *item, void UNUSED *key, void UNUSED *operator_data/*in,out*/)
-{
-    FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5G_free_ref_path_node)
-
-    H5FL_FREE(haddr_t, item);
-
-    FUNC_LEAVE_NOAPI(SUCCEED)
-} /* end H5G_free_ref_path_node() */
-
-
-/*-------------------------------------------------------------------------
- * Function:    H5G_get_refobj_name
- *
- * Purpose:     Tries to figure out the path to a reference.
+ * Purpose:     Tries to figure out the path to an object from it's address
  *
  * Return:      returns size of path name, and copies it into buffer
  * 		pointed to by name if that buffer is big enough.
  * 		0 if it cannot find the path
  * 		negative on failure.
  *
- * Programmer:  Leon Arber, Nov 1, 2006.
- *
- * Modifications:
- * 		Quincey Koziol, Nov. 3, 2006
- * 		Cleaned up code.
+ * Programmer:	Quincey Koziol
+ *		November 4 2007
  *
  *-------------------------------------------------------------------------
  */
 ssize_t
-H5G_get_refobj_name(hid_t file, hid_t lapl_id, hid_t dxpl_id, const H5O_loc_t *loc,
+H5G_get_name_by_addr(hid_t file, hid_t lapl_id, hid_t dxpl_id, const H5O_loc_t *loc,
     char *name, size_t size)
 {
-    H5G_ref_path_iter_t udata;  /* User data for iteration */
-    H5G_loc_t root_loc;         /* Root location */
-    H5L_info_t root_info;       /* Link info for root group */
+    H5G_gnba_iter_t udata;      /* User data for iteration */
+    H5G_loc_t root_loc;         /* Root group's location */
+    hbool_t found_obj = FALSE;  /* If we found the object */
     herr_t status;              /* Status from iteration */
     ssize_t ret_value;          /* Return value */
 
-    FUNC_ENTER_NOAPI(H5G_get_refobj_name, FAIL)
+    FUNC_ENTER_NOAPI(H5G_get_name_by_addr, FAIL)
 
-    /* Construct the link info for the root group */
+    /* Construct the link info for the file's root group */
     if(H5G_loc(file, &root_loc) < 0)
 	HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't get root group's location")
-    HDmemset(&root_info, 0, sizeof(root_info));
-    root_info.type = H5L_TYPE_HARD;
-    root_info.u.address = root_loc.oloc->addr;
-
-    /* Set up user data for iterator */
-    udata.file = file;
-    udata.lapl_id = lapl_id;
-    udata.dxpl_id = dxpl_id;
-    udata.is_root_group = TRUE;
-    if(NULL == (udata.container = H5MM_strdup("")))
-        HGOTO_ERROR(H5E_SYM, H5E_NOSPACE, FAIL, "can't allocate root group name")
-    udata.max_container_len = 1;
-    udata.loc = loc;
-    
-    /* Create skip list to store reference path information */
-    if((udata.ref_path_table = H5SL_create(H5SL_TYPE_HADDR, 0.5, (size_t)16)) == NULL)
-        HGOTO_ERROR(H5E_SYM, H5E_CANTCREATE, FAIL, "can't create skip list for path nodes")
-
-    /* Iterate over all the objects in the file */
-    if((status = H5G_refname_iterator(file, "/", &root_info, &udata)) < 0)
-        HGOTO_ERROR(H5E_SYM, H5E_BADITER, FAIL, "group iteration failed while looking for object name")
-    else if(status > 0) {
+
+    /* Check for root group being the object looked for */
+    if(root_loc.oloc->addr == loc->addr && root_loc.oloc->file == loc->file) {
+        udata.path = H5MM_strdup("");
+        found_obj = TRUE;
+    } /* end if */
+    else {
+        /* Set up user data for iterator */
+        udata.loc = loc;
+        udata.lapl_id = lapl_id;
+        udata.dxpl_id = dxpl_id;
+        udata.path = NULL;
+        
+        /* Visit all the links in the file */
+        if((status = H5G_visit(file, "/", H5_INDEX_NAME, H5_ITER_NATIVE, H5G_get_name_by_addr_cb, &udata, lapl_id, dxpl_id)) < 0)
+            HGOTO_ERROR(H5E_SYM, H5E_BADITER, FAIL, "group traversal failed while looking for object name")
+        else if(status > 0)
+            found_obj = TRUE;
+    } /* end else */
+
+    /* Check for finding the object */
+    if(found_obj) {
+        size_t full_path_len = HDstrlen(udata.path) + 1;        /* Length of path + 1 (for "/") */
+
         /* Set the length of the full path */
-        ret_value = HDstrlen(udata.container);
+        ret_value = full_path_len;
 
         /* If there's a buffer provided, copy into it, up to the limit of its size */
         if(name) {
-            HDstrncpy(name, udata.container, size);
+            /* Copy the initial path separator */
+            HDstrcpy(name, "/");
+
+            /* Append the rest of the path */
+            /* (less one character, for the initial path separator) */
+            HDstrncat(name, udata.path, (size - 1));
             if((size_t)ret_value >= size)
                 name[size - 1] = '\0';
         } /* end if */
@@ -1264,10 +1172,8 @@ H5G_get_refobj_name(hid_t file, hid_t lapl_id, hid_t dxpl_id, const H5O_loc_t *l
    
 done:    
     /* Release resources */
-    H5MM_xfree(udata.container);
-    if(udata.ref_path_table)
-        H5SL_destroy(udata.ref_path_table, H5G_free_ref_path_node, NULL);
+    H5MM_xfree(udata.path);
 
     FUNC_LEAVE_NOAPI(ret_value)
-} /* end H5G_get_refobj_name() */
+} /* end H5G_get_name_by_addr() */
 
diff --git a/src/H5Gnode.c b/src/H5Gnode.c
index 6cff5a0..92d5717 100644
--- a/src/H5Gnode.c
+++ b/src/H5Gnode.c
@@ -1431,51 +1431,23 @@ H5G_node_iterate(H5F_t *f, hid_t dxpl_id, const void UNUSED *_lt_key, haddr_t ad
         if(udata->skip > 0)
             --udata->skip;
         else {
-            const char		*name;  /* Pointer to link name in heap */
+            H5O_link_t lnk;     /* Link for entry */
+            const char *name;   /* Pointer to link name in heap */
 
             /* Get the pointer to the name of the link in the heap */
             name = H5HL_offset_into(f, udata->heap, ents[u].name_off);
             HDassert(name);
 
-            /* Check which type of callback to make */
-            switch(udata->lnk_op->op_type) {
-#ifndef H5_NO_DEPRECATED_SYMBOLS
-                case H5G_LINK_OP_OLD:
-                    /* Make the old-type application callback */
-                    ret_value = (udata->lnk_op->u.old_op)(udata->group_id, name, udata->op_data);
-                    break;
-#endif /* H5_NO_DEPRECATED_SYMBOLS */
-
-                case H5G_LINK_OP_APP:
-                    {
-                        H5L_info_t info;        /* Link info for entry */
-
-                        /* Make a link info for an entry */
-                        if(H5G_ent_to_info(f, &info, udata->heap, &ents[u]) < 0)
-                            HGOTO_ERROR(H5E_SYM, H5E_CANTGET, H5_ITER_ERROR, "unable to get info for symbol table entry")
-
-                        /* Make the application callback */
-                        ret_value = (udata->lnk_op->u.app_op)(udata->group_id, name, &info, udata->op_data);
-                    }
-                    break;
-
-                case H5G_LINK_OP_LIB:
-                    /* Call the library's callback */
-                    {
-                        H5O_link_t lnk;         /* Link for entry */
-
-                        /* Convert the entry to a link */
-                        if(H5G_ent_to_link(f, &lnk, udata->heap, &ents[u], name) < 0)
-                            HGOTO_ERROR(H5E_SYM, H5E_CANTCONVERT, H5_ITER_ERROR, "unable to convert symbol table entry to link")
-
-                        /* Call the library's callback */
-                        ret_value = (udata->lnk_op->u.lib_op)(&lnk, udata->op_data);
-
-                        /* Release memory for link object */
-                        if(H5O_msg_reset(H5O_LINK_ID, &lnk) < 0)
-                            HGOTO_ERROR(H5E_SYM, H5E_CANTFREE, H5_ITER_ERROR, "unable to release link message")
-                    }
-            } /* end switch */
+            /* Convert the entry to a link */
+            if(H5G_ent_to_link(f, &lnk, udata->heap, &ents[u], name) < 0)
+                HGOTO_ERROR(H5E_SYM, H5E_CANTCONVERT, H5_ITER_ERROR, "unable to convert symbol table entry to link")
+
+            /* Make the callback */
+            ret_value = (udata->op)(&lnk, udata->op_data);
+
+            /* Release memory for link object */
+            if(H5O_msg_reset(H5O_LINK_ID, &lnk) < 0)
+                HGOTO_ERROR(H5E_SYM, H5E_CANTFREE, H5_ITER_ERROR, "unable to release link message")
         } /* end else */
 
         /* Increment the number of entries passed through */
diff --git a/src/H5Gobj.c b/src/H5Gobj.c
index 00bac73..af8f6df 100644
--- a/src/H5Gobj.c
+++ b/src/H5Gobj.c
@@ -533,7 +533,6 @@ H5G_obj_insert(const H5O_loc_t *grp_oloc, const char *name, H5O_link_t *obj_lnk,
             H5O_linfo_t new_linfo = H5G_CRT_LINK_INFO_DEF;  /* Link information */
             H5O_ginfo_t new_ginfo = H5G_CRT_GROUP_INFO_DEF; /* Group information */
             H5G_obj_stab_it_ud1_t udata;        /* User data for iteration */
-            H5G_link_iterate_t lnk_op;          /* Link operator */
 
             /* Convert group to "new format" group, in order to hold the information */
 
@@ -549,12 +548,8 @@ H5G_obj_insert(const H5O_loc_t *grp_oloc, const char *name, H5O_link_t *obj_lnk,
             udata.grp_oloc = grp_oloc;
             udata.dxpl_id = dxpl_id;
 
-            /* Build iterator operator */
-            lnk_op.op_type = H5G_LINK_OP_LIB;
-            lnk_op.u.lib_op = H5G_obj_stab_to_new_cb;
-
             /* Iterate through all links in "old format" group and insert them into new format */
-            if(H5G_stab_iterate(grp_oloc, dxpl_id, H5_ITER_NATIVE, (hsize_t)0, NULL, (hid_t)0, &lnk_op, &udata) < 0)
+            if(H5G_stab_iterate(grp_oloc, dxpl_id, H5_ITER_NATIVE, (hsize_t)0, NULL, H5G_obj_stab_to_new_cb, &udata) < 0)
                 HGOTO_ERROR(H5E_SYM, H5E_CANTNEXT, FAIL, "error iterating over old format links")
 
             /* Remove the symbol table message from the group */
@@ -636,36 +631,21 @@ done:
  *-------------------------------------------------------------------------
  */
 herr_t
-H5G_obj_iterate(hid_t loc_id, const char *group_name,
+H5G_obj_iterate(const H5O_loc_t *grp_oloc,
     H5_index_t idx_type, H5_iter_order_t order, hsize_t skip, hsize_t *last_lnk,
-    H5G_link_iterate_t *lnk_op, void *op_data, hid_t lapl_id, hid_t dxpl_id)
+    H5G_lib_iterate_t op, void *op_data, hid_t dxpl_id)
 {
-    H5G_loc_t	loc;            /* Location of parent for group */
     H5O_linfo_t	linfo;		/* Link info message */
-    hid_t gid = -1;             /* ID of group to iterate over */
-    H5G_t *grp;                 /* Pointer to group data structure to iterate over */
     herr_t ret_value;           /* Return value */
 
     FUNC_ENTER_NOAPI(H5G_obj_iterate, FAIL)
 
     /* Sanity check */
-    HDassert(group_name);
-    HDassert(last_lnk);
-    HDassert(lnk_op && lnk_op->u.lib_op);
-
-    /*
-     * Open the group on which to operate.  We also create a group ID which
-     * we can pass to the application-defined operator.
-     */
-    if(H5G_loc(loc_id, &loc) < 0)
-        HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
-    if(NULL == (grp = H5G_open_name(&loc, group_name, lapl_id, dxpl_id)))
-        HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open group")
-    if((gid = H5I_register(H5I_GROUP, grp)) < 0)
-        HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL, "unable to register group")
+    HDassert(grp_oloc);
+    HDassert(op);
 
     /* Attempt to get the link info for this group */
-    if(H5G_obj_get_linfo(&(grp->oloc), &linfo, dxpl_id)) {
+    if(H5G_obj_get_linfo(grp_oloc, &linfo, dxpl_id)) {
         /* Check for going out of bounds */
         if(skip > 0 && (size_t)skip >= linfo.nlinks)
             HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "index out of bound")
@@ -679,13 +659,13 @@ H5G_obj_iterate(hid_t loc_id, const char *group_name,
 
         if(H5F_addr_defined(linfo.fheap_addr)) {
             /* Iterate over the links in the group, building a table of the link messages */
-            if((ret_value = H5G_dense_iterate(grp->oloc.file, dxpl_id, &linfo, idx_type, order, skip, last_lnk, gid, lnk_op, op_data)) < 0)
-                HGOTO_ERROR(H5E_SYM, H5E_CANTNEXT, FAIL, "error iterating over links")
+            if((ret_value = H5G_dense_iterate(grp_oloc->file, dxpl_id, &linfo, idx_type, order, skip, last_lnk, op, op_data)) < 0)
+                HGOTO_ERROR(H5E_SYM, H5E_BADITER, FAIL, "can't iterate over dense links")
         } /* end if */
         else {
             /* Get the object's name from the link messages */
-            if((ret_value = H5G_compact_iterate(&(grp->oloc), dxpl_id, &linfo, idx_type, order, skip, last_lnk, gid, lnk_op, op_data)) < 0)
-                HGOTO_ERROR(H5E_SYM, H5E_BADITER, FAIL, "can't iterate over links")
+            if((ret_value = H5G_compact_iterate(grp_oloc, dxpl_id, &linfo, idx_type, order, skip, last_lnk, op, op_data)) < 0)
+                HGOTO_ERROR(H5E_SYM, H5E_BADITER, FAIL, "can't iterate over compact links")
         } /* end else */
     } /* end if */
     else {
@@ -697,14 +677,11 @@ H5G_obj_iterate(hid_t loc_id, const char *group_name,
             HGOTO_ERROR(H5E_SYM, H5E_BADVALUE, FAIL, "no creation order index to query")
 
         /* Iterate over symbol table */
-        if((ret_value = H5G_stab_iterate(&(grp->oloc), dxpl_id, order, skip, last_lnk, gid, lnk_op, op_data)) < 0)
+        if((ret_value = H5G_stab_iterate(grp_oloc, dxpl_id, order, skip, last_lnk, op, op_data)) < 0)
             HGOTO_ERROR(H5E_SYM, H5E_BADITER, FAIL, "can't iterate over symbol table")
     } /* end else */
 
 done:
-    if(gid > 0)
-        H5I_dec_ref(gid); /*also closes 'grp'*/
-
     FUNC_LEAVE_NOAPI(ret_value)
 } /* end H5G_obj_iterate() */
 
diff --git a/src/H5Gpkg.h b/src/H5Gpkg.h
index f5b2582..2d936a9 100644
--- a/src/H5Gpkg.h
+++ b/src/H5Gpkg.h
@@ -134,18 +134,16 @@ typedef herr_t (*H5G_lib_iterate_t)(const H5O_link_t *lnk, void *op_data);
 typedef struct {
     enum {
 #ifndef H5_NO_DEPRECATED_SYMBOLS
-        H5G_LINK_OP_OLD,                /* Old application callback */
+        H5G_LINK_OP_OLD,                /* "Old" application callback */
 #endif /* H5_NO_DEPRECATED_SYMBOLS */
-        H5G_LINK_OP_APP,                /* Application callback */
-        H5G_LINK_OP_LIB                 /* Library internal callback */
+        H5G_LINK_OP_NEW                 /* "New" application callback */
     } op_type;
     union {
 #ifndef H5_NO_DEPRECATED_SYMBOLS
-        H5G_iterate_t old_op;           /* Old application callback for each link */
+        H5G_iterate_t op_old;           /* "Old" application callback for each link */
 #endif /* H5_NO_DEPRECATED_SYMBOLS */
-        H5L_iterate_t app_op;           /* Application callback for each link */
-        H5G_lib_iterate_t lib_op;       /* Library internal callback for each link */
-    } u;
+        H5L_iterate_t op_new;           /* "New" application callback for each link */
+    } op_func;
 } H5G_link_iterate_t;
 
 /* Data structure to hold table of links for a group */
@@ -210,10 +208,9 @@ typedef struct H5G_bt_lkp_t {
  */
 typedef struct H5G_bt_it_it_t {
     /* downward */
-    hid_t	group_id;	/*group id to pass to iteration operator     */
     H5HL_t      *heap;          /*symbol table heap 			     */
     hsize_t	skip;		/*initial entries to skip		     */
-    H5G_link_iterate_t *lnk_op;	/*iteration operator			     */
+    H5G_lib_iterate_t op;	/*iteration operator			     */
     void	*op_data;	/*user-defined operator data		     */
 
     /* upward */
@@ -342,6 +339,12 @@ H5_DLL H5G_t *H5G_create_named(const H5G_loc_t *loc, const char *name,
     hid_t lcpl_id, hid_t gcpl_id, hid_t gapl_id, hid_t dxpl_id);
 H5_DLL H5G_t *H5G_open_name(const H5G_loc_t *loc, const char *name,
     hid_t gapl_id, hid_t dxpl_id);
+H5_DLL herr_t H5G_iterate(hid_t loc_id, const char *group_name,
+    H5_index_t idx_type, H5_iter_order_t order, hsize_t skip, hsize_t *last_lnk,
+    const H5G_link_iterate_t *lnk_op, void *op_data, hid_t lapl_id, hid_t dxpl_id);
+H5_DLL herr_t H5G_visit(hid_t loc_id, const char *group_name,
+    H5_index_t idx_type, H5_iter_order_t order, H5L_iterate_t op, void *op_data,
+    hid_t lapl_id, hid_t dxpl_id);
 
 /*
  * Group hierarchy traversal routines
@@ -374,9 +377,8 @@ H5_DLL herr_t H5G_stab_insert(const H5O_loc_t *grp_oloc, const char *name,
 H5_DLL herr_t H5G_stab_insert_real(H5F_t *f, H5O_stab_t *stab, const char *name,
     H5O_link_t *obj_lnk, hid_t dxpl_id);
 H5_DLL herr_t H5G_stab_delete(H5F_t *f, hid_t dxpl_id, const H5O_stab_t *stab);
-H5_DLL herr_t H5G_stab_iterate(const H5O_loc_t *oloc, hid_t dxpl_id,
-    H5_iter_order_t order, hsize_t skip, hsize_t *last_lnk, hid_t gid,
-    H5G_link_iterate_t *lnk_op, void *op_data);
+H5_DLL herr_t H5G_stab_iterate(const H5O_loc_t *oloc, hid_t dxpl_id, H5_iter_order_t order,
+    hsize_t skip, hsize_t *last_lnk, H5G_lib_iterate_t op, void *op_data);
 H5_DLL herr_t H5G_stab_count(struct H5O_loc_t *oloc, hsize_t *num_objs, hid_t dxpl_id);
 H5_DLL herr_t H5G_stab_bh_size(H5F_t *f, hid_t dxpl_id, const H5O_stab_t *stab,
     H5_ih_info_t *bh_info);
@@ -444,8 +446,7 @@ H5_DLL herr_t H5G_link_copy_file(H5F_t *dst_file, hid_t dxpl_id,
 H5_DLL herr_t H5G_link_sort_table(H5G_link_table_t *ltable, H5_index_t idx_type,
     H5_iter_order_t order);
 H5_DLL herr_t H5G_link_iterate_table(const H5G_link_table_t *ltable,
-    hsize_t skip, hsize_t *last_lnk, hid_t gid, const H5G_link_iterate_t *lnk_op,
-    void *op_data);
+    hsize_t skip, hsize_t *last_lnk, const H5G_lib_iterate_t op, void *op_data);
 H5_DLL herr_t H5G_link_release_table(H5G_link_table_t *ltable);
 H5_DLL herr_t H5G_link_name_replace(H5F_t *file, hid_t dxpl_id,
     H5RS_str_t *grp_full_path_r, const H5O_link_t *lnk);
@@ -461,9 +462,9 @@ H5_DLL herr_t H5G_compact_remove(const H5O_loc_t *oloc, hid_t dxpl_id,
 H5_DLL herr_t H5G_compact_remove_by_idx(const H5O_loc_t *oloc, hid_t dxpl_id,
     const H5O_linfo_t *linfo, H5RS_str_t *grp_full_path_r, H5_index_t idx_type,
     H5_iter_order_t order, hsize_t n);
-H5_DLL herr_t H5G_compact_iterate(H5O_loc_t *oloc, hid_t dxpl_id, const H5O_linfo_t *linfo, 
-    H5_index_t idx_type, H5_iter_order_t order, hsize_t skip, hsize_t *last_lnk,
-    hid_t gid, H5G_link_iterate_t *lnk_op, void *op_data);
+H5_DLL herr_t H5G_compact_iterate(const H5O_loc_t *oloc, hid_t dxpl_id,
+    const H5O_linfo_t *linfo, H5_index_t idx_type, H5_iter_order_t order,
+    hsize_t skip, hsize_t *last_lnk, H5G_lib_iterate_t op, void *op_data);
 H5_DLL herr_t H5G_compact_lookup(H5O_loc_t *grp_oloc, const char *name,
     H5O_link_t *lnk, hid_t dxpl_id);
 H5_DLL herr_t H5G_compact_lookup_by_idx(H5O_loc_t *oloc, hid_t dxpl_id,
@@ -487,7 +488,7 @@ H5_DLL herr_t H5G_dense_lookup_by_idx(H5F_t *f, hid_t dxpl_id,
     hsize_t n, H5O_link_t *lnk);
 H5_DLL herr_t H5G_dense_iterate(H5F_t *f, hid_t dxpl_id, const H5O_linfo_t *linfo,
     H5_index_t idx_type, H5_iter_order_t order, hsize_t skip, hsize_t *last_lnk,
-    hid_t gid, const H5G_link_iterate_t *lnk_op, void *op_data);
+    H5G_lib_iterate_t op, void *op_data);
 H5_DLL ssize_t H5G_dense_get_name_by_idx(H5F_t  *f, hid_t dxpl_id,
     H5O_linfo_t *linfo, H5_index_t idx_type, H5_iter_order_t order, hsize_t n,
     char *name, size_t size);
@@ -510,9 +511,9 @@ H5_DLL H5O_linfo_t * H5G_obj_get_linfo(const H5O_loc_t *grp_oloc,
     H5O_linfo_t *linfo, hid_t dxpl_id);
 H5_DLL herr_t H5G_obj_insert(const H5O_loc_t *grp_oloc, const char *name,
     H5O_link_t *obj_lnk, hbool_t adj_link, hid_t dxpl_id);
-H5_DLL herr_t H5G_obj_iterate(hid_t loc_id, const char *group_name,
-    H5_index_t idx_type, H5_iter_order_t order, hsize_t skip, hsize_t *last_obj,
-    H5G_link_iterate_t *lnk_op, void *op_data, hid_t lapl_id, hid_t dxpl_id);
+H5_DLL herr_t H5G_obj_iterate(const H5O_loc_t *grp_oloc,
+    H5_index_t idx_type, H5_iter_order_t order, hsize_t skip, hsize_t *last_lnk,
+    H5G_lib_iterate_t op, void *op_data, hid_t dxpl_id);
 H5_DLL herr_t H5G_obj_info(H5O_loc_t *oloc, H5G_info_t *grp_info, hid_t dxpl_id);
 H5_DLL ssize_t H5G_obj_get_name_by_idx(H5O_loc_t *oloc, H5_index_t idx_type,
     H5_iter_order_t order, hsize_t n, char* name, size_t size, hid_t dxpl_id);
diff --git a/src/H5Gprivate.h b/src/H5Gprivate.h
index 9717b77..0ddb3e9 100644
--- a/src/H5Gprivate.h
+++ b/src/H5Gprivate.h
@@ -189,7 +189,7 @@ H5_DLL herr_t H5G_name_copy(H5G_name_t *dst, const H5G_name_t *src, H5_copy_dept
 H5_DLL herr_t H5G_name_free(H5G_name_t *name);
 H5_DLL ssize_t H5G_get_name(hid_t id, char *name/*out*/, size_t size,
     hid_t lapl_id, hid_t dxpl_id);
-H5_DLL ssize_t H5G_get_refobj_name(hid_t fid, hid_t lapl_id, hid_t dxpl_id,
+H5_DLL ssize_t H5G_get_name_by_addr(hid_t fid, hid_t lapl_id, hid_t dxpl_id,
     const struct H5O_loc_t *loc, char* name, size_t size);
 
 /*
diff --git a/src/H5Gstab.c b/src/H5Gstab.c
index 1887943..61af068 100644
--- a/src/H5Gstab.c
+++ b/src/H5Gstab.c
@@ -484,8 +484,7 @@ done:
  */
 herr_t
 H5G_stab_iterate(const H5O_loc_t *oloc, hid_t dxpl_id, H5_iter_order_t order,
-    hsize_t skip, hsize_t *last_lnk, hid_t gid,
-    H5G_link_iterate_t *lnk_op, void *op_data)
+    hsize_t skip, hsize_t *last_lnk, H5G_lib_iterate_t op, void *op_data)
 {
     H5HL_t              *heap = NULL;           /* Local heap for group */
     H5O_stab_t		stab;		        /* Info about symbol table */
@@ -496,7 +495,7 @@ H5G_stab_iterate(const H5O_loc_t *oloc, hid_t dxpl_id, H5_iter_order_t order,
 
     /* Sanity check */
     HDassert(oloc);
-    HDassert(lnk_op && lnk_op->u.app_op);
+    HDassert(op);
 
     /* Get the B-tree info */
     if(NULL == H5O_msg_read(oloc, H5O_STAB_ID, &stab, dxpl_id))
@@ -512,11 +511,10 @@ H5G_stab_iterate(const H5O_loc_t *oloc, hid_t dxpl_id, H5_iter_order_t order,
         H5G_bt_it_it_t	udata;                  /* User data to pass to B-tree callback */
 
         /* Build udata to pass through H5B_iterate() to H5G_node_iterate() */
-        udata.group_id = gid;
         udata.heap = heap;
         udata.skip = skip;
         udata.final_ent = last_lnk;
-        udata.lnk_op = lnk_op;
+        udata.op = op;
         udata.op_data = op_data;
 
         /* Iterate over the group members */
@@ -550,7 +548,7 @@ H5G_stab_iterate(const H5O_loc_t *oloc, hid_t dxpl_id, H5_iter_order_t order,
             HGOTO_ERROR(H5E_SYM, H5E_CANTSORT, FAIL, "error sorting link messages")
 
         /* Iterate over links in table */
-        if((ret_value = H5G_link_iterate_table(&ltable, skip, last_lnk, gid, lnk_op, op_data)) < 0)
+        if((ret_value = H5G_link_iterate_table(&ltable, skip, last_lnk, op, op_data)) < 0)
             HERROR(H5E_SYM, H5E_CANTNEXT, "iteration operator failed");
     } /* end else */
 
diff --git a/src/H5L.c b/src/H5L.c
index 020f7c2..9917fe7 100644
--- a/src/H5L.c
+++ b/src/H5L.c
@@ -1170,11 +1170,11 @@ H5Literate(hid_t grp_id, H5_index_t idx_type, H5_iter_order_t order,
     last_lnk = 0;
 
     /* Build link operator info */
-    lnk_op.op_type = H5G_LINK_OP_APP;
-    lnk_op.u.app_op = op;
+    lnk_op.op_type = H5G_LINK_OP_NEW;
+    lnk_op.op_func.op_new = op;
 
     /* Iterate over the links */
-    if((ret_value = H5G_obj_iterate(grp_id, ".", idx_type, order, idx, &last_lnk, &lnk_op, op_data, H5P_DEFAULT, H5AC_ind_dxpl_id)) < 0)
+    if((ret_value = H5G_iterate(grp_id, ".", idx_type, order, idx, &last_lnk, &lnk_op, op_data, H5P_DEFAULT, H5AC_ind_dxpl_id)) < 0)
 	HGOTO_ERROR(H5E_SYM, H5E_BADITER, FAIL, "link iteration failed")
 
     /* Set the index we stopped at */
@@ -1242,11 +1242,11 @@ H5Literate_by_name(hid_t loc_id, const char *group_name,
     last_lnk = 0;
 
     /* Build link operator info */
-    lnk_op.op_type = H5G_LINK_OP_APP;
-    lnk_op.u.app_op = op;
+    lnk_op.op_type = H5G_LINK_OP_NEW;
+    lnk_op.op_func.op_new = op;
 
     /* Iterate over the links */
-    if((ret_value = H5G_obj_iterate(loc_id, group_name, idx_type, order, idx, &last_lnk, &lnk_op, op_data, lapl_id, H5AC_ind_dxpl_id)) < 0)
+    if((ret_value = H5G_iterate(loc_id, group_name, idx_type, order, idx, &last_lnk, &lnk_op, op_data, lapl_id, H5AC_ind_dxpl_id)) < 0)
 	HGOTO_ERROR(H5E_SYM, H5E_BADITER, FAIL, "link iteration failed")
 
     /* Set the index we stopped at */
@@ -1257,6 +1257,66 @@ done:
     FUNC_LEAVE_API(ret_value)
 } /* end H5Literate_by_name() */
 
+
+/*-------------------------------------------------------------------------
+ * Function:	H5Lvisit_by_name
+ *
+ * Purpose:	Recursively visit all the links in a group and all
+ *              the groups that are linked to from that group.  Links within
+ *              each group are visited according to the order within the
+ *              specified index (unless the specified index does not exist for
+ *              a particular group, then the "name" index is used).
+ *
+ *              NOTE: Each _link_ reachable from the initial group will only be
+ *              visited once.  However, because an object may be reached from
+ *              more than one link, the visitation may call the application's
+ *              callback with more than one link that points to a particular
+ *              _object_.
+ *
+ * Return:	Success:	The return value of the first operator that
+ *				returns non-zero, or zero if all members were
+ *				processed with no operator returning non-zero.
+ *
+ *		Failure:	Negative if something goes wrong within the
+ *				library, or the negative value returned by one
+ *				of the operators.
+ *
+ * Programmer:	Quincey Koziol
+ *		November 3 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Lvisit_by_name(hid_t loc_id, const char *group_name, H5_index_t idx_type,
+    H5_iter_order_t order, H5L_iterate_t op, void *op_data, hid_t lapl_id)
+{
+    herr_t      ret_value;              /* Return value */
+
+    FUNC_ENTER_API(H5Lvisit_by_name, FAIL)
+
+    /* Check args */
+    if(!group_name || !*group_name)
+	HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name specified")
+    if(idx_type <= H5_INDEX_UNKNOWN || idx_type >= H5_INDEX_N)
+	HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid index type specified")
+    if(order <= H5_ITER_UNKNOWN || order >= H5_ITER_N)
+	HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid iteration order specified")
+    if(!op)
+        HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no callback operator specified")
+    if(H5P_DEFAULT == lapl_id)
+        lapl_id = H5P_LINK_ACCESS_DEFAULT;
+    else
+        if(TRUE != H5P_isa_class(lapl_id, H5P_LINK_ACCESS))
+            HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not link access property list ID")
+
+    /* Call internal group visitation routine */
+    if((ret_value = H5G_visit(loc_id, group_name, idx_type, order, op, op_data, lapl_id, H5AC_ind_dxpl_id)) < 0)
+	HGOTO_ERROR(H5E_SYM, H5E_BADITER, FAIL, "link visitation failed")
+
+done:
+    FUNC_LEAVE_API(ret_value)
+} /* end H5Lvisit_by_name() */
+
 /*
  *-------------------------------------------------------------------------
  *-------------------------------------------------------------------------
diff --git a/src/H5Lpublic.h b/src/H5Lpublic.h
index 1645e4b..0dc3f65 100644
--- a/src/H5Lpublic.h
+++ b/src/H5Lpublic.h
@@ -170,6 +170,9 @@ H5_DLL herr_t H5Literate(hid_t grp_id, H5_index_t idx_type,
 H5_DLL herr_t H5Literate_by_name(hid_t loc_id, const char *group_name,
     H5_index_t idx_type, H5_iter_order_t order, hsize_t *idx,
     H5L_iterate_t op, void *op_data, hid_t lapl_id);
+H5_DLL herr_t H5Lvisit_by_name(hid_t loc_id, const char *group_name,
+    H5_index_t idx_type, H5_iter_order_t order, H5L_iterate_t op,
+    void *op_data, hid_t lapl_id);
 
 /* UD link functions */
 H5_DLL herr_t H5Lcreate_ud(hid_t link_loc_id, const char *link_name,
diff --git a/src/H5O.c b/src/H5O.c
index 94435f5..67aa960 100644
--- a/src/H5O.c
+++ b/src/H5O.c
@@ -2121,8 +2121,7 @@ H5O_get_info(H5O_loc_t *oloc, hid_t dxpl_id, hbool_t want_ih_info, H5O_info_t *o
     HDmemset(oinfo, 0, sizeof(*oinfo));
 
     /* Retrieve the file's fileno */
-    if(H5F_get_fileno(oloc->file, &oinfo->fileno) < 0)
-        HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, FAIL, "unable to read fileno")
+    H5F_GET_FILENO(oloc->file, oinfo->fileno);
 
     /* Set the object's address */
     oinfo->addr = oloc->addr;
@@ -2412,3 +2411,48 @@ H5O_get_oh_addr(const H5O_t *oh)
     FUNC_LEAVE_NOAPI(oh->chunk[0].addr)
 } /* end H5O_get_oh_addr() */
 
+
+/*-------------------------------------------------------------------------
+ * Function:	H5O_get_rc_and_type
+ *
+ * Purpose:	Retrieve an object's reference count and type
+ *
+ * Return:	Success:	Non-negative
+ *		Failure:	Negative
+ *
+ * Programmer:	Quincey Koziol
+ *		November  4 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5O_get_rc_and_type(const H5O_loc_t *oloc, hid_t dxpl_id, unsigned *rc, H5O_type_t *otype)
+{
+    H5O_t *oh = NULL;                   /* Object header */
+    herr_t ret_value = SUCCEED;         /* Return value */
+
+    FUNC_ENTER_NOAPI(H5O_get_rc_and_type, FAIL)
+
+    /* Check args */
+    HDassert(oloc);
+    HDassert(rc);
+    HDassert(otype);
+
+    /* Get the object header */
+    if(NULL == (oh = H5AC_protect(oloc->file, dxpl_id, H5AC_OHDR, oloc->addr, NULL, NULL, H5AC_READ)))
+	HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "unable to load object header")
+
+    /* Set the object's reference count */
+    *rc = oh->nlink;
+
+    /* Retrieve the type of the object */
+    if(H5O_obj_type_real(oh, otype) < 0)
+        HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to determine object type")
+
+done:
+    if(oh && H5AC_unprotect(oloc->file, dxpl_id, H5AC_OHDR, oloc->addr, oh, H5AC__NO_FLAGS_SET) < 0)
+	HDONE_ERROR(H5E_OHDR, H5E_PROTECT, FAIL, "unable to release object header")
+
+    FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_get_rc_and_type() */
+
diff --git a/src/H5Olinfo.c b/src/H5Olinfo.c
index 660b0e1..384353c 100644
--- a/src/H5Olinfo.c
+++ b/src/H5Olinfo.c
@@ -513,7 +513,6 @@ H5O_linfo_post_copy_file(const H5O_loc_t *src_oloc, const void *mesg_src,
     /* Check for copying dense link storage */
     if(H5F_addr_defined(linfo_src->fheap_addr)) {
         H5O_linfo_postcopy_ud_t udata;          /* User data for iteration callback */
-        H5G_link_iterate_t lnk_op;              /* Link operator */
 
         /* Set up dense link iteration user data */
         udata.src_oloc = src_oloc;
@@ -522,12 +521,8 @@ H5O_linfo_post_copy_file(const H5O_loc_t *src_oloc, const void *mesg_src,
         udata.dxpl_id = dxpl_id;
         udata.cpy_info = cpy_info;
 
-        /* Build iterator operator */
-        lnk_op.op_type = H5G_LINK_OP_LIB;
-        lnk_op.u.lib_op = H5O_linfo_post_copy_file_cb;
-
         /* Iterate over the links in the group, building a table of the link messages */
-        if(H5G_dense_iterate(src_oloc->file, dxpl_id, linfo_src, H5_INDEX_NAME, H5_ITER_NATIVE, (hsize_t)0, NULL, (hid_t)0, &lnk_op, &udata) < 0)
+        if(H5G_dense_iterate(src_oloc->file, dxpl_id, linfo_src, H5_INDEX_NAME, H5_ITER_NATIVE, (hsize_t)0, NULL, H5O_linfo_post_copy_file_cb, &udata) < 0)
             HGOTO_ERROR(H5E_SYM, H5E_CANTNEXT, FAIL, "error iterating over links")
     } /* end if */
 
diff --git a/src/H5Oprivate.h b/src/H5Oprivate.h
index 31738a9..ce7aba0 100644
--- a/src/H5Oprivate.h
+++ b/src/H5Oprivate.h
@@ -553,6 +553,7 @@ H5_DLL hid_t H5O_open_name(H5G_loc_t *loc, const char *name, hid_t lapl_id);
 H5_DLL herr_t H5O_get_nlinks(const H5O_loc_t *loc, hid_t dxpl_id, hsize_t *nlinks);
 H5_DLL void *H5O_obj_create(H5F_t *f, H5O_type_t obj_type, void *crt_info, H5G_loc_t *obj_loc, hid_t dxpl_id);
 H5_DLL haddr_t H5O_get_oh_addr(const H5O_t *oh);
+H5_DLL herr_t H5O_get_rc_and_type(const H5O_loc_t *oloc, hid_t dxpl_id, unsigned *rc, H5O_type_t *otype);
 
 /* Object header message routines */
 H5_DLL herr_t H5O_msg_create(const H5O_loc_t *loc, unsigned type_id, unsigned mesg_flags,
diff --git a/src/H5R.c b/src/H5R.c
index 627626b..ae8720e 100644
--- a/src/H5R.c
+++ b/src/H5R.c
@@ -885,7 +885,7 @@ H5R_get_name(H5F_t *f, hid_t lapl_id, hid_t dxpl_id, hid_t id, H5R_type_t ref_ty
         HGOTO_ERROR(H5E_REFERENCE, H5E_CANTGET, FAIL, "can't retrieve file ID")
 
     /* Get name, length, etc. */
-    if((ret_value = H5G_get_refobj_name(file_id, lapl_id, dxpl_id, &oloc, name, size)) < 0)
+    if((ret_value = H5G_get_name_by_addr(file_id, lapl_id, dxpl_id, &oloc, name, size)) < 0)
         HGOTO_ERROR(H5E_REFERENCE, H5E_CANTGET, FAIL, "can't determine name")
 
 done:
diff --git a/src/H5SL.c b/src/H5SL.c
index 53c0f2d..94f0d23 100644
--- a/src/H5SL.c
+++ b/src/H5SL.c
@@ -99,19 +99,27 @@
 
 /* Define a code template for comparing scalar keys for the "CMP" in the H5SL_LOCATE macro */
 #define H5SL_LOCATE_SCALAR_CMP(TYPE,PKEY1,PKEY2)                        \
-        (*(TYPE *)PKEY1<*(TYPE *)PKEY2)
+        (*(TYPE *)PKEY1 < *(TYPE *)PKEY2)
 
 /* Define a code template for comparing string keys for the "CMP" in the H5SL_LOCATE macro */
 #define H5SL_LOCATE_STRING_CMP(TYPE,PKEY1,PKEY2)                        \
-        (HDstrcmp(PKEY1,PKEY2)<0)
+        (HDstrcmp(PKEY1, PKEY2) < 0)
+
+/* Define a code template for comparing H5_obj_t keys for the "CMP" in the H5SL_LOCATE macro */
+#define H5SL_LOCATE_OBJ_CMP(TYPE,PKEY1,PKEY2)                           \
+        ((((TYPE *)PKEY1)->fileno < ((TYPE *)PKEY2)->fileno) ? TRUE : (((TYPE *)PKEY1)->addr < ((TYPE *)PKEY2)->addr))
 
 /* Define a code template for comparing scalar keys for the "EQ" in the H5SL_LOCATE macro */
 #define H5SL_LOCATE_SCALAR_EQ(TYPE,PKEY1,PKEY2)                         \
-        (*(TYPE *)PKEY1==*(TYPE *)PKEY2)
+        (*(TYPE *)PKEY1 == *(TYPE *)PKEY2)
 
 /* Define a code template for comparing string keys for the "EQ" in the H5SL_LOCATE macro */
 #define H5SL_LOCATE_STRING_EQ(TYPE,PKEY1,PKEY2)                         \
-        (HDstrcmp(PKEY1,PKEY2)==0)
+        (HDstrcmp(PKEY1, PKEY2) == 0)
+
+/* Define a code template for comparing H5_obj_ keys for the "EQ" in the H5SL_LOCATE macro */
+#define H5SL_LOCATE_OBJ_EQ(TYPE,PKEY1,PKEY2)                            \
+        ((((TYPE *)PKEY1)->fileno == ((TYPE *)PKEY2)->fileno) && (((TYPE *)PKEY1)->addr == ((TYPE *)PKEY2)->addr))
 
 /* Macro used to find node for operation */
 #define H5SL_LOCATE(OP,DOUPDATE,CMP,SLIST,X,UPDATE,I,TYPE,KEY,CHECKED)  \
@@ -378,6 +386,10 @@ H5SL_insert_common(H5SL_t *slist, void *item, const void *key)
         case H5SL_TYPE_SIZE:
             H5SL_INSERT(SCALAR, slist, x, update, i, const size_t, key, checked)
             break;
+
+        case H5SL_TYPE_OBJ:
+            H5SL_INSERT(OBJ, slist, x, update, i, const H5_obj_t, key, checked)
+            break;
     } /* end switch */
 
     /* 'key' must not have been found in existing list, if we get here */
@@ -571,7 +583,7 @@ H5SL_create(H5SL_type_t type, double p, size_t max_level)
     /* Check args */
     HDassert(p>0.0 && p<1.0);
     HDassert(max_level>0 && max_level<=H5SL_LEVEL_MAX);
-    HDassert(type>=H5SL_TYPE_INT && type<=H5SL_TYPE_SIZE);
+    HDassert(type>=H5SL_TYPE_INT && type<=H5SL_TYPE_OBJ);
 
     /* Allocate skip list structure */
     if((new_slist=H5FL_MALLOC(H5SL_t))==NULL)
@@ -808,6 +820,10 @@ H5SL_remove(H5SL_t *slist, const void *key)
         case H5SL_TYPE_SIZE:
             H5SL_REMOVE(SCALAR, slist, x, update, i, const size_t, key, checked)
             break;
+
+        case H5SL_TYPE_OBJ:
+            H5SL_REMOVE(OBJ, slist, x, update, i, const H5_obj_t, key, checked)
+            break;
     } /* end switch */
 
 done:
@@ -955,6 +971,10 @@ H5SL_search(H5SL_t *slist, const void *key)
         case H5SL_TYPE_SIZE:
             H5SL_SEARCH(SCALAR, slist, x, -, i, const size_t, key, checked)
             break;
+
+        case H5SL_TYPE_OBJ:
+            H5SL_SEARCH(OBJ, slist, x, -, i, const H5_obj_t, key, checked)
+            break;
     } /* end switch */
 
     /* 'key' must not have been found in list, if we get here */
@@ -1034,6 +1054,10 @@ H5SL_less(H5SL_t *slist, const void *key)
         case H5SL_TYPE_SIZE:
             H5SL_SEARCH(SCALAR, slist, x, -, i, const size_t, key, checked)
             break;
+
+        case H5SL_TYPE_OBJ:
+            H5SL_SEARCH(OBJ, slist, x, -, i, const H5_obj_t, key, checked)
+            break;
     } /* end switch */
 
     /* An exact match for 'key' must not have been found in list, if we get here */
@@ -1126,6 +1150,10 @@ H5SL_greater(H5SL_t *slist, const void *key)
         case H5SL_TYPE_SIZE:
             H5SL_SEARCH(SCALAR, slist, x, -, i, const size_t, key, checked)
             break;
+
+        case H5SL_TYPE_OBJ:
+            H5SL_SEARCH(OBJ, slist, x, -, i, const H5_obj_t, key, checked)
+            break;
     } /* end switch */
 
     /* An exact match for 'key' must not have been found in list, if we get here */
@@ -1208,6 +1236,10 @@ H5SL_find(H5SL_t *slist, const void *key)
         case H5SL_TYPE_SIZE:
             H5SL_FIND(SCALAR, slist, x, -, i, const size_t, key, checked)
             break;
+
+        case H5SL_TYPE_OBJ:
+            H5SL_FIND(OBJ, slist, x, -, i, const H5_obj_t, key, checked)
+            break;
     } /* end switch */
 
     /* 'key' must not have been found in list, if we get here */
diff --git a/src/H5SLprivate.h b/src/H5SLprivate.h
index 98c1b84..9f73893 100644
--- a/src/H5SLprivate.h
+++ b/src/H5SLprivate.h
@@ -46,7 +46,8 @@ typedef enum {
     H5SL_TYPE_STR,      /* Skip list keys are 'char *'s (ie. strings) */
     H5SL_TYPE_HSIZE,    /* Skip list keys are 'hsize_t's */
     H5SL_TYPE_UNSIGNED, /* Skip list keys are 'unsigned's */
-    H5SL_TYPE_SIZE      /* Skip list keys are 'size_t's */
+    H5SL_TYPE_SIZE,     /* Skip list keys are 'size_t's */
+    H5SL_TYPE_OBJ       /* Skip list keys are 'H5_obj_t's */
 } H5SL_type_t;
 
 /**********/
diff --git a/src/H5private.h b/src/H5private.h
index dad4e13..3ac4da3 100644
--- a/src/H5private.h
+++ b/src/H5private.h
@@ -485,6 +485,12 @@ typedef enum {
     H5_COPY_DEEP        /* Deep copy from source to destination, including duplicating fields pointed to */
 } H5_copy_depth_t;
 
+/* Unique object "position" */
+typedef struct {
+    unsigned long fileno;       /* The unique identifier for the file of the object */
+    haddr_t addr;               /* The unique address of the object's header in that file */
+} H5_obj_t;
+
 /*
  * Redefine all the POSIX functions.  We should never see a POSIX
  * function (or any other non-HDF5 function) in the source!
diff --git a/test/getname.c b/test/getname.c
index 685bfbf..22abb79 100644
--- a/test/getname.c
+++ b/test/getname.c
@@ -65,11 +65,11 @@ check_name(hid_t id, const char *chk_name, const char *chk_user_path)
 
     /* Get name */
     *name = '\0';
-    if(H5Iget_name(id, name, NAME_BUF_SIZE) < 0) goto error;
+    if(H5Iget_name(id, name, NAME_BUF_SIZE) < 0) TEST_ERROR
 
     /* Get user path */
     *user_path = '\0';
-    if(H5G_user_path_test(id, user_path, &user_path_len, &user_path_hidden) < 0) goto error;
+    if(H5G_user_path_test(id, user_path, &user_path_len, &user_path_hidden) < 0) TEST_ERROR
 
     /* Check on name from H5Iget_name() */
     if(HDstrcmp(name, chk_name)) goto error;
@@ -78,7 +78,7 @@ check_name(hid_t id, const char *chk_name, const char *chk_user_path)
     if(HDstrcmp(user_path, chk_user_path)) goto error;
 
     /* Check that if user path is hidden, the name from H5Iget_name() and the user path should be different */
-    if(user_path_hidden && !HDstrcmp(chk_name, chk_user_path)) goto error;
+    if(user_path_hidden && !HDstrcmp(chk_name, chk_user_path)) TEST_ERROR
 
     /* Everything matches */
     return 0;
@@ -713,10 +713,10 @@ test_main(hid_t file_id, hid_t fapl)
     PASSED();
 
 
-/*-------------------------------------------------------------------------
-    * Test H5Iget_name with H5Fmount; long name
-    *-------------------------------------------------------------------------
-    */
+    /*-------------------------------------------------------------------------
+     * Test H5Iget_name with H5Fmount; long name
+     *-------------------------------------------------------------------------
+     */
 
     TESTING("H5Iget_name with H5Fmount; long name");
 
@@ -726,9 +726,9 @@ test_main(hid_t file_id, hid_t fapl)
     if((group3_id = H5Gcreate2(file_id, "/g13/g1/g2", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) FAIL_STACK_ERROR
 
     /* Close */
-    H5Gclose(group_id);
-    H5Gclose(group2_id);
-    H5Gclose(group3_id);
+    if(H5Gclose(group_id) < 0) FAIL_STACK_ERROR
+    if(H5Gclose(group2_id) < 0) FAIL_STACK_ERROR
+    if(H5Gclose(group3_id) < 0) FAIL_STACK_ERROR
 
     /* Create second file and group "g" in it */
     file1_id = H5Fcreate(filename1, H5F_ACC_TRUNC, H5P_DEFAULT, fapl);
@@ -1144,6 +1144,7 @@ test_main(hid_t file_id, hid_t fapl)
     char    name2[SMALL_NAME_BUF_SIZE];
 
     /* Get name */
+    *name2 = '\0';
     name_len=H5Iget_name(group_id, name2, SMALL_NAME_BUF_SIZE);
 
     /* Check that name is longer */
@@ -1182,6 +1183,7 @@ test_main(hid_t file_id, hid_t fapl)
     if(!name3) TEST_ERROR
 
     /* Get name with dynamic buffer */
+    *name3 = '\0';
     if(H5Iget_name(group_id, name3, name_len + 1) < 0) TEST_ERROR
 
     /* Verify */
@@ -1189,6 +1191,7 @@ test_main(hid_t file_id, hid_t fapl)
     *name3 = '\0';
 
     /* Get name with smaller buffer */
+    *name3 = '\0';
     if(H5Iget_name(group_id, name3, 3) < 0) TEST_ERROR
 
     /* Verify */
@@ -2513,80 +2516,96 @@ test_obj_ref(hid_t fapl)
 
     TESTING("getting path to normal dataset in root group"); 
     if((dataset2 = H5Rdereference(dataset, H5R_OBJECT, &wbuf[0])) < 0) FAIL_STACK_ERROR
-    i = H5Iget_name(dataset2,(char*)buf, sizeof(buf));
+    *buf = '\0';
+    i = H5Iget_name(dataset2, (char*)buf, sizeof(buf));
     if(H5Dclose(dataset2) < 0) FAIL_STACK_ERROR
     if(!((HDstrcmp(buf, "/Dataset3") == 0) &&(i == 9))) TEST_ERROR
-    i = H5Rget_name(dataset, H5R_OBJECT, &wbuf[0],(char*)buf, sizeof(buf));
+    *buf = '\0';
+    i = H5Rget_name(dataset, H5R_OBJECT, &wbuf[0], (char*)buf, sizeof(buf));
     if(!((HDstrcmp(buf, "/Dataset3") == 0) &&(i == 9))) TEST_ERROR
     PASSED()
 
     HDmemset(buf, 0, sizeof(buf));
     TESTING("getting path to dataset in /Group1"); 
     if((dataset2 = H5Rdereference(dataset, H5R_OBJECT, &wbuf[1])) < 0) FAIL_STACK_ERROR
-    i = H5Iget_name(dataset2,(char*)buf, sizeof(buf));
+    *buf = '\0';
+    i = H5Iget_name(dataset2, (char*)buf, sizeof(buf));
     if(H5Dclose(dataset2) < 0) FAIL_STACK_ERROR
     if(!((HDstrcmp(buf, "/Group1/Dataset2") == 0) &&(i == 16))) TEST_ERROR
-    i = H5Rget_name(dataset, H5R_OBJECT, &wbuf[1],(char*)buf, sizeof(buf));
+    *buf = '\0';
+    i = H5Rget_name(dataset, H5R_OBJECT, &wbuf[1], (char*)buf, sizeof(buf));
     if(!((HDstrcmp(buf, "/Group1/Dataset2") == 0) &&(i == 16))) TEST_ERROR
     PASSED()
 
     HDmemset(buf, 0, sizeof(buf));
     TESTING("getting path to /Group1"); 
     if((group = H5Rdereference(dataset, H5R_OBJECT, &wbuf[2])) < 0) FAIL_STACK_ERROR
-    i = H5Iget_name(group,(char*)buf, sizeof(buf));
+    *buf = '\0';
+    i = H5Iget_name(group, (char*)buf, sizeof(buf));
     if(H5Gclose(group) < 0) FAIL_STACK_ERROR
     if(!((HDstrcmp(buf, "/Group1") == 0) &&(i == 7))) TEST_ERROR
-    i = H5Rget_name(dataset, H5R_OBJECT, &wbuf[2],(char*)buf, sizeof(buf));
+    *buf = '\0';
+    i = H5Rget_name(dataset, H5R_OBJECT, &wbuf[2], (char*)buf, sizeof(buf));
     if(!((HDstrcmp(buf, "/Group1") == 0) &&(i == 7))) TEST_ERROR
     PASSED()
 
     HDmemset(buf, 0, sizeof(buf));
     TESTING("getting path to datatype in /Group1"); 
     if((tid1 = H5Rdereference(dataset, H5R_OBJECT, &wbuf[3])) < 0) FAIL_STACK_ERROR
-    i = H5Iget_name(tid1,(char*)buf, sizeof(buf));
+    *buf = '\0';
+    i = H5Iget_name(tid1, (char*)buf, sizeof(buf));
     if(H5Tclose(tid1) < 0) FAIL_STACK_ERROR
     if(!((HDstrcmp(buf, "/Group1/Datatype1") == 0) &&(i == 17))) TEST_ERROR
-    i = H5Rget_name(dataset, H5R_OBJECT, &wbuf[3],(char*)buf, sizeof(buf));
+    *buf = '\0';
+    i = H5Rget_name(dataset, H5R_OBJECT, &wbuf[3], (char*)buf, sizeof(buf));
     if(!((HDstrcmp(buf, "/Group1/Datatype1") == 0) &&(i == 17))) TEST_ERROR
     PASSED()
 
     HDmemset(buf, 0, sizeof(buf));
     TESTING("getting path to dataset in nested group"); 
     if((dataset2 = H5Rdereference(dataset, H5R_OBJECT, &wbuf[4])) < 0) FAIL_STACK_ERROR
-    i = H5Iget_name(dataset2,(char*)buf, sizeof(buf));
+    *buf = '\0';
+    i = H5Iget_name(dataset2, (char*)buf, sizeof(buf));
     if(H5Dclose(dataset2) < 0) FAIL_STACK_ERROR
     if(!((HDstrcmp(buf, "/Group1/Group2/Dataset4") == 0) &&(i == 23))) TEST_ERROR
-    i = H5Rget_name(dataset, H5R_OBJECT, &wbuf[4],(char*)buf, sizeof(buf));
+    *buf = '\0';
+    i = H5Rget_name(dataset, H5R_OBJECT, &wbuf[4], (char*)buf, sizeof(buf));
     if(!((HDstrcmp(buf, "/Group1/Group2/Dataset4") == 0) &&(i == 23))) TEST_ERROR
     PASSED()
 
     HDmemset(buf, 0, sizeof(buf));
     TESTING("getting path to nested group"); 
     if((group = H5Rdereference(dataset, H5R_OBJECT, &wbuf[5])) < 0) FAIL_STACK_ERROR
-    i = H5Iget_name(group,(char*)buf, sizeof(buf));
+    *buf = '\0';
+    i = H5Iget_name(group, (char*)buf, sizeof(buf));
     if(H5Gclose(group) < 0) FAIL_STACK_ERROR
     if(!((HDstrcmp(buf, "/Group1/Group2") == 0) &&(i == 14))) TEST_ERROR
-    i = H5Rget_name(dataset, H5R_OBJECT, &wbuf[5],(char*)buf, sizeof(buf));
+    *buf = '\0';
+    i = H5Rget_name(dataset, H5R_OBJECT, &wbuf[5], (char*)buf, sizeof(buf));
     if(!((HDstrcmp(buf, "/Group1/Group2") == 0) &&(i == 14))) TEST_ERROR
     PASSED()
 
     HDmemset(buf, 0, sizeof(buf));
     TESTING("getting path to dataset created via hard link"); 
     if((dataset2 = H5Rdereference(dataset, H5R_OBJECT, &wbuf[6])) < 0) FAIL_STACK_ERROR
-    i = H5Iget_name(dataset2,(char*)buf, sizeof(buf));
+    *buf = '\0';
+    i = H5Iget_name(dataset2, (char*)buf, sizeof(buf));
     if(H5Dclose(dataset2) < 0) FAIL_STACK_ERROR
     if(!((HDstrcmp(buf, "/Group1/Dataset5") == 0) &&(i == 16))) TEST_ERROR
-    i = H5Rget_name(dataset, H5R_OBJECT, &wbuf[6],(char*)buf, sizeof(buf));
+    *buf = '\0';
+    i = H5Rget_name(dataset, H5R_OBJECT, &wbuf[6], (char*)buf, sizeof(buf));
     if(!((HDstrcmp(buf, "/Group1/Dataset5") == 0) &&(i == 16))) TEST_ERROR
     PASSED()
 
     HDmemset(buf, 0, sizeof(buf));
     TESTING("getting path to root group"); 
     if((group = H5Rdereference(dataset, H5R_OBJECT, &wbuf[7])) < 0) FAIL_STACK_ERROR
-    i = H5Iget_name(group,(char*)buf, sizeof(buf));
+    *buf = '\0';
+    i = H5Iget_name(group, (char*)buf, sizeof(buf));
     if(H5Gclose(group) < 0) FAIL_STACK_ERROR
     if(!((HDstrcmp(buf, "/") == 0) &&(i == 1))) TEST_ERROR
-    i = H5Rget_name(dataset, H5R_OBJECT, &wbuf[7],(char*)buf, sizeof(buf));
+    *buf = '\0';
+    i = H5Rget_name(dataset, H5R_OBJECT, &wbuf[7], (char*)buf, sizeof(buf));
     if(!((HDstrcmp(buf, "/") == 0) &&(i == 1))) TEST_ERROR
     PASSED()
 
@@ -2596,10 +2615,12 @@ test_obj_ref(hid_t fapl)
 
     TESTING("getting path to dataset hidden by a mounted file");
     if((dataset2 = H5Rdereference(dataset, H5R_OBJECT, &wbuf[4])) < 0) FAIL_STACK_ERROR
+    *buf = '\0';
     i = H5Iget_name(dataset2, (char*)buf, sizeof(buf));
     if(H5Dclose(dataset2) < 0) FAIL_STACK_ERROR
     if(i != 0) TEST_ERROR
-    i = H5Rget_name(dataset, H5R_OBJECT, &wbuf[4],(char*)buf, sizeof(buf));
+    *buf = '\0';
+    i = H5Rget_name(dataset, H5R_OBJECT, &wbuf[4], (char*)buf, sizeof(buf));
     if(i != 0) TEST_ERROR
     PASSED()
 
@@ -2610,10 +2631,12 @@ test_obj_ref(hid_t fapl)
         FAIL_STACK_ERROR
  
     TESTING("getting path to dataset that has been unlinked"); 
+    *buf = '\0';
     i = H5Iget_name(dataset2, (char*)buf, sizeof(buf));
     if(H5Dclose(dataset2) < 0) FAIL_STACK_ERROR
     if(i != 0) TEST_ERROR
-    i = H5Rget_name(dataset, H5R_OBJECT, &wbuf[1],(char*)buf, sizeof(buf));
+    *buf = '\0';
+    i = H5Rget_name(dataset, H5R_OBJECT, &wbuf[1], (char*)buf, sizeof(buf));
     if(i != 0) TEST_ERROR
     PASSED()
     
@@ -2735,7 +2758,8 @@ test_reg_ref(hid_t fapl)
 
     /* Get name of the dataset the first region reference points to using H5Rget_name */
     TESTING("H5Rget_name to get name from region reference(hyperslab)");
-    name_size1 = H5Rget_name(dsetr_id, H5R_DATASET_REGION, &ref_out[0],(char*)buf1, NAME_BUF_SIZE);
+    *buf1 = '\0';
+    name_size1 = H5Rget_name(dsetr_id, H5R_DATASET_REGION, &ref_out[0], (char*)buf1, NAME_BUF_SIZE);
     if(!((HDstrcmp(buf1, "/MATRIX") == 0) &&(name_size1 == 7))) TEST_ERROR 
     PASSED()
 
@@ -2745,7 +2769,8 @@ test_reg_ref(hid_t fapl)
     dsetv_id = H5Rdereference(dsetr_id, H5R_DATASET_REGION, &ref_out[0]);
 
     /* Get name of the dataset the first region reference points using H5Iget_name */
-    name_size2 = H5Iget_name(dsetv_id,(char*)buf2, NAME_BUF_SIZE); 
+    *buf2 = '\0';
+    name_size2 = H5Iget_name(dsetv_id, (char*)buf2, NAME_BUF_SIZE); 
     if(!((HDstrcmp(buf2, "/MATRIX") == 0) &&(name_size2 == 7))) TEST_ERROR
 
     if((status = H5Dclose(dsetv_id)) < 0) TEST_ERROR
@@ -2754,7 +2779,8 @@ test_reg_ref(hid_t fapl)
 
     /* Get name of the dataset the second region reference points to using H5Rget_name */
     TESTING("H5Rget_name to get name from region reference(pnt selec)");
-    name_size1 = H5Rget_name(dsetr_id, H5R_DATASET_REGION, &ref_out[1],(char*)buf1, NAME_BUF_SIZE);      
+    *buf1 = '\0';
+    name_size1 = H5Rget_name(dsetr_id, H5R_DATASET_REGION, &ref_out[1], (char*)buf1, NAME_BUF_SIZE);      
     if(!((HDstrcmp(buf1, "/MATRIX") == 0) &&(name_size1 == 7))) TEST_ERROR
     PASSED()
 
@@ -2764,7 +2790,8 @@ test_reg_ref(hid_t fapl)
     if((dsetv_id = H5Rdereference(dsetr_id, H5R_DATASET_REGION, &ref_out[1])) < 0) TEST_ERROR
 
     /* Get name of the dataset the first region reference points using H5Iget_name */
-    name_size2 = H5Iget_name(dsetv_id,(char*)buf2, NAME_BUF_SIZE); 
+    *buf2 = '\0';
+    name_size2 = H5Iget_name(dsetv_id, (char*)buf2, NAME_BUF_SIZE); 
     if(!((HDstrcmp(buf2, "/MATRIX") == 0) &&(name_size2 == 7))) TEST_ERROR
 
     if((status = H5Dclose(dsetv_id)) < 0) TEST_ERROR
diff --git a/test/mount.c b/test/mount.c
index 2ce9a2a..e6aa881 100644
--- a/test/mount.c
+++ b/test/mount.c
@@ -1170,6 +1170,7 @@ test_mount_after_close(hid_t fapl)
     if((gidABMX = H5Gopen2(gidAB, "M/X", H5P_DEFAULT)) < 0) FAIL_STACK_ERROR
 
     /* Check name */
+    *objname = '\0';
     if(H5Iget_name(gidABMX, objname, (size_t)NAME_BUF_SIZE) < 0) FAIL_STACK_ERROR
     if(HDstrcmp(objname, "/A/B/M/X")) TEST_ERROR
 
@@ -1180,6 +1181,7 @@ test_mount_after_close(hid_t fapl)
     if((gidABC = H5Gopen2(gidAB, "C", H5P_DEFAULT)) < 0) FAIL_STACK_ERROR
 
     /* Check name */
+    *objname = '\0';
     if(H5Iget_name(gidABC, objname, (size_t)NAME_BUF_SIZE) < 0) FAIL_STACK_ERROR
     if(HDstrcmp(objname, "/A/B/C")) TEST_ERROR
 
@@ -1190,6 +1192,7 @@ test_mount_after_close(hid_t fapl)
     if((gidABT = H5Gopen2(gidAB, "T", H5P_DEFAULT)) < 0) FAIL_STACK_ERROR
 
     /* Check name */
+    *objname = '\0';
     if(H5Iget_name(gidABT, objname, (size_t)NAME_BUF_SIZE) < 0) FAIL_STACK_ERROR
     if(HDstrcmp(objname, "/A/B/T")) TEST_ERROR
 
@@ -1200,6 +1203,7 @@ test_mount_after_close(hid_t fapl)
     if((didABMXYD = H5Dopen2(gidAB, "M/X/Y/D", H5P_DEFAULT)) < 0) FAIL_STACK_ERROR
 
     /* Check name */
+    *objname = '\0';
     if(H5Iget_name(didABMXYD, objname, (size_t)NAME_BUF_SIZE) < 0) FAIL_STACK_ERROR
     if(HDstrcmp(objname, "/A/B/M/X/Y/D")) TEST_ERROR
 
@@ -1370,6 +1374,7 @@ test_mount_after_unmount(hid_t fapl)
         TEST_ERROR
 
     /* Check name */
+    *objname = '\0';
     if(H5Iget_name( gidAMXX, objname, (size_t)NAME_BUF_SIZE ) < 0)
         TEST_ERROR
     if(HDstrcmp(objname, "/A/M/X/X"))
@@ -1389,6 +1394,7 @@ test_mount_after_unmount(hid_t fapl)
         TEST_ERROR
 
     /* Check name */
+    *objname = '\0';
     if(H5Iget_name( gidAMXMY, objname, (size_t)NAME_BUF_SIZE ) < 0)
         TEST_ERROR
     if(HDstrcmp(objname, "/A/M/X/M/Y"))
@@ -1435,6 +1441,7 @@ test_mount_after_unmount(hid_t fapl)
         TEST_ERROR
 
     /* Check name */
+    *objname = '\0';
     if(H5Iget_name( gidBMZ, objname, (size_t)NAME_BUF_SIZE ) < 0)
         TEST_ERROR
     if(HDstrcmp(objname, "/B/M/Z"))
@@ -2721,6 +2728,7 @@ test_mult_mount(hid_t fapl)
         TEST_ERROR
 
     /* Check name */
+    *name = '\0';
     if(H5Iget_name(gidAMT, name, (size_t)NAME_BUF_SIZE ) < 0)
         TEST_ERROR
     if(HDstrcmp(name, "/A/M/T"))
@@ -2738,6 +2746,7 @@ test_mult_mount(hid_t fapl)
         TEST_ERROR
 
     /* Check name */
+    *name = '\0';
     if(H5Iget_name(gidBS, name, (size_t)NAME_BUF_SIZE ) < 0)
         TEST_ERROR
     if(HDstrcmp(name, "/B/S"))
@@ -2924,6 +2933,7 @@ test_nested_survive(hid_t fapl)
         TEST_ERROR
 
     /* Check name */
+    *name = '\0';
     if((name_len = H5Iget_name(gidAM, name, (size_t)NAME_BUF_SIZE )) < 0)
         TEST_ERROR
     if(name_len == 0 || HDstrcmp(name, "/A/M"))
@@ -2934,9 +2944,10 @@ test_nested_survive(hid_t fapl)
         TEST_ERROR
 
     /* Check name */
+    *name = '\0';
     if((name_len = H5Iget_name(gidAM, name, (size_t)NAME_BUF_SIZE )) < 0)
         TEST_ERROR
-    if(name_len == 0 || HDstrcmp(name, "/M"))
+    if(name_len != 0 || HDstrcmp(name, ""))
         TEST_ERROR
 
     /* Open object in file #3 through file #1 mount path (should fail) */
@@ -2951,6 +2962,7 @@ test_nested_survive(hid_t fapl)
         TEST_ERROR
 
     /* Check name */
+    *name = '\0';
     if(H5Iget_name(gidMS, name, (size_t)NAME_BUF_SIZE ) < 0)
         TEST_ERROR
     if(HDstrcmp(name, "/M/S"))
@@ -2969,6 +2981,7 @@ test_nested_survive(hid_t fapl)
         TEST_ERROR
 
     /* Check name */
+    *name = '\0';
     if(H5Iget_name(gidAMS, name, (size_t)NAME_BUF_SIZE ) < 0)
         TEST_ERROR
     if(HDstrcmp(name, "/A/M/S"))
@@ -3122,6 +3135,7 @@ test_close_parent(hid_t fapl)
         TEST_ERROR
 
     /* Check the name of "M" is still defined */
+    *name = '\0';
     if((name_len = H5Iget_name(gidM, name, (size_t)NAME_BUF_SIZE )) < 0)
         TEST_ERROR
     if(name_len == 0 || HDstrcmp(name, "/A/M"))
@@ -3132,6 +3146,7 @@ test_close_parent(hid_t fapl)
         TEST_ERROR
 
     /* Check the name of "M" is defined in its file */
+    *name = '\0';
     if((name_len = H5Iget_name(gidM, name, (size_t)NAME_BUF_SIZE )) < 0)
         TEST_ERROR
     if(name_len == 0 || HDstrcmp(name, "/M"))
@@ -3407,6 +3422,7 @@ test_cut_graph(hid_t fapl)
         TEST_ERROR
 
     /* Check name */
+    *name = '\0';
     if((name_len = H5Iget_name(gidM, name, (size_t)NAME_BUF_SIZE )) < 0)
         TEST_ERROR
     if(name_len == 0 || HDstrcmp(name, "/A/E/M"))
@@ -3417,6 +3433,7 @@ test_cut_graph(hid_t fapl)
         TEST_ERROR
 
     /* Check name */
+    *name = '\0';
     if((name_len = H5Iget_name(gidQ, name, (size_t)NAME_BUF_SIZE )) < 0)
         TEST_ERROR
     if(name_len == 0 || HDstrcmp(name, "/B/I/Q"))
@@ -3477,6 +3494,7 @@ test_cut_graph(hid_t fapl)
         TEST_ERROR
 
     /* Check the name of "K" is correct */
+    *name = '\0';
     if((name_len = H5Iget_name(gidK, name, (size_t)NAME_BUF_SIZE )) < 0)
         TEST_ERROR
     if(name_len == 0 || HDstrcmp(name, "/D/K"))
@@ -3497,6 +3515,7 @@ test_cut_graph(hid_t fapl)
         TEST_ERROR
 
     /* Check the name of "O" is correct */
+    *name = '\0';
     if((name_len = H5Iget_name(gidO, name, (size_t)NAME_BUF_SIZE )) < 0)
         TEST_ERROR
     if(name_len == 0 || HDstrcmp(name, "/B/H/O"))
@@ -3506,12 +3525,14 @@ test_cut_graph(hid_t fapl)
         TEST_ERROR
 
     /* Check the name of "M" is defined in its file */
+    *name = '\0';
     if((name_len = H5Iget_name(gidM, name, (size_t)NAME_BUF_SIZE )) < 0)
         TEST_ERROR
     if(name_len == 0 || HDstrcmp(name, "/E/M"))
         TEST_ERROR
 
     /* Check the name of "Q" is still defined */
+    *name = '\0';
     if((name_len = H5Iget_name(gidQ, name, (size_t)NAME_BUF_SIZE )) < 0)
         TEST_ERROR
     if(name_len == 0 || HDstrcmp(name, "/B/I/Q"))
@@ -3539,6 +3560,7 @@ test_cut_graph(hid_t fapl)
         TEST_ERROR
 
     /* Check the name of "Q" is defined in its file */
+    *name = '\0';
     if((name_len = H5Iget_name(gidQ, name, (size_t)NAME_BUF_SIZE )) < 0)
         TEST_ERROR
     if(name_len == 0 || HDstrcmp(name, "/I/Q"))
@@ -3549,6 +3571,7 @@ test_cut_graph(hid_t fapl)
         TEST_ERROR
 
     /* Check the name of "O" is correct */
+    *name = '\0';
     if((name_len = H5Iget_name(gidO, name, (size_t)NAME_BUF_SIZE )) < 0)
         TEST_ERROR
     if(name_len == 0 || HDstrcmp(name, "/H/O"))
@@ -3719,6 +3742,7 @@ test_symlink(hid_t fapl)
         TEST_ERROR
 
     /* Check the name of "L" is correct */
+    *name = '\0';
     if((name_len = H5Iget_name(gidL, name, (size_t)NAME_BUF_SIZE )) < 0)
         TEST_ERROR
     if(name_len == 0 || HDstrcmp(name, "/L"))
diff --git a/tools/h5copy/h5copy.c b/tools/h5copy/h5copy.c
index cadb0d0..216b2bb 100644
--- a/tools/h5copy/h5copy.c
+++ b/tools/h5copy/h5copy.c
@@ -199,8 +199,8 @@ main (int argc, const char *argv[])
  unsigned     flag=0;
  unsigned     verbose=0;
  unsigned     parents=0;
- hid_t        ocpl_id;          /* Object copy property list */
- hid_t        lcpl_id;          /* Link creation property list */
+ hid_t        ocpl_id = (-1);          /* Object copy property list */
+ hid_t        lcpl_id = (-1);          /* Link creation property list */
  char         str_flag[20];
  int          opt;
 
diff --git a/tools/h5dump/h5dump.c b/tools/h5dump/h5dump.c
index c69c5d70..28534bf 100644
--- a/tools/h5dump/h5dump.c
+++ b/tools/h5dump/h5dump.c
@@ -3952,7 +3952,7 @@ main(int argc, const char *argv[])
     /* allocate and initialize internal data structure */
     init_prefix(&prefix, prefix_len);
 
-    /* find all objects that might be targets of a reference */
+    /* Prepare to find objects that might be targets of a reference */
     fill_ref_path_table(fid);
 
     if(doxml) {
@@ -4094,7 +4094,6 @@ done:
     free_table(type_table);
 
     HDfree(prefix);
-    HDfree(info.prefix);
     HDfree(fname);
 
     /* To Do:  clean up XML table */
@@ -5342,8 +5341,7 @@ xml_dump_group(hid_t gid, const char *name)
 
     if(HDstrcmp(name, "/") == 0) {
         isRoot = 1;
-        tmp = HDmalloc(2);
-        HDstrcpy(tmp, "/");
+        tmp = HDstrdup("/");
     } else {
         tmp = HDmalloc(HDstrlen(prefix) + HDstrlen(name) + 2);
         HDstrcpy(tmp, prefix);
@@ -5401,8 +5399,8 @@ xml_dump_group(hid_t gid, const char *name)
                 ptrstr = malloc(100);
                 t_objname = xml_escape_the_name(found_obj->objname);
                 par_name = xml_escape_the_name(par);
-                xml_name_to_XID(par,parentxid,100,1);
-                xml_name_to_XID(found_obj->objname,ptrstr,100,1);
+                xml_name_to_XID(found_obj->objname, ptrstr, 100, 1);
+                xml_name_to_XID(par, parentxid, 100, 1);
                 printf("<%sGroupPtr OBJ-XID=\"%s\" H5Path=\"%s\" "
                             "Parents=\"%s\" H5ParentPaths=\"%s\" />\n",
                             xmlnsprefix,
diff --git a/tools/h5ls/h5ls.c b/tools/h5ls/h5ls.c
index 2c56cb5..80b45d8 100644
--- a/tools/h5ls/h5ls.c
+++ b/tools/h5ls/h5ls.c
@@ -27,6 +27,15 @@
 #include "H5private.h"
 #include "h5tools.h"
 #include "h5tools_utils.h"
+#include "h5trav.h"
+
+#define NAME_BUF_SIZE   2048
+
+/* Struct to pass through to visitors */
+typedef struct {
+    hid_t fid;                          /* File ID */
+    const char *fname;                  /* Filename */
+}iter_t;
 
 /* Command-line switches */
 static int      verbose_g = 0;            /* lots of extra output */
@@ -43,21 +52,7 @@ static hbool_t  show_errors_g = FALSE;    /* print HDF5 error messages */
 static hbool_t  simple_output_g = FALSE;  /* make output more machine-readable */
 static hbool_t  show_file_name_g = FALSE; /* show file name for full names */
 static hbool_t  no_line_wrap_g = FALSE;   /* show data content without line wrap */
-
-/* Info to pass to the iteration functions */
-typedef struct iter_t {
-    const char *container;  /* full name of the container object */
-} iter_t;
-
-/* Table containing object id and object name */
-static struct {
-    int  nalloc;                /* number of slots allocated */
-    int  nobjs;                 /* number of objects */
-    struct {
-        haddr_t id;             /* object number */
-        char *name;             /* full object name */
-    } *obj;
-} idtab_g;
+static hbool_t  display_root_g = FALSE;   /* show root group in output? */
 
 /* Information about how to display each type of object */
 static struct dispatch_t {
@@ -68,17 +63,13 @@ static struct dispatch_t {
     herr_t (*list2)(hid_t obj, const char *name);
 } dispatch_g[H5O_TYPE_NTYPES];
 
-#define DISPATCH(TYPE, NAME, OPEN, CLOSE, LIST1, LIST2) {         \
+#define DISPATCH(TYPE, NAME, LIST1, LIST2) {         \
     dispatch_g[TYPE].name = (NAME);             \
-    dispatch_g[TYPE].open = (OPEN);             \
-    dispatch_g[TYPE].close = (CLOSE);           \
     dispatch_g[TYPE].list1 = (LIST1);           \
     dispatch_g[TYPE].list2 = (LIST2);           \
 }
 
-static herr_t list(hid_t group, const char *name, const H5L_info_t *linfo, void *cd);
 static void display_type(hid_t type, int ind);
-static char *fix_name(const char *path, const char *base);
 
 const char *progname="h5ls";
 int   d_status;
@@ -131,76 +122,6 @@ usage: %s [OPTIONS] [OBJECTS...]\n\
 
 
 /*-------------------------------------------------------------------------
- * Function: sym_insert
- *
- * Purpose: Add a symbol to the table.
- *
- * Return: void
- *
- * Programmer: Robb Matzke
- *              Thursday, January 21, 1999
- *
- * Modifications:
- *
- *-------------------------------------------------------------------------
- */
-static void
-sym_insert(const H5O_info_t *oi, const char *name)
-{
-    int  n;
-
-    /* Don't add it if the link count is 1 because such an object can only
-     * have one name. */
-    if(oi->rc < 2)
-        return;
-
-    /* Extend the table */
-    if(idtab_g.nobjs >= idtab_g.nalloc) {
-        idtab_g.nalloc = MAX(256, 2*idtab_g.nalloc);
-        idtab_g.obj = realloc(idtab_g.obj, idtab_g.nalloc*sizeof(idtab_g.obj[0]));
-    } /* end if */
-
-    /* Insert the entry */
-    n = idtab_g.nobjs++;
-    idtab_g.obj[n].id = oi->addr;
-    idtab_g.obj[n].name = HDstrdup(name);
-}
-
-
-/*-------------------------------------------------------------------------
- * Function: sym_lookup
- *
- * Purpose: Find another name for the specified object.
- *
- * Return: Success: Ptr to another name.
- *
- *  Failure: NULL
- *
- * Programmer: Robb Matzke
- *              Thursday, January 21, 1999
- *
- * Modifications:
- *
- *-------------------------------------------------------------------------
- */
-static char *
-sym_lookup(const H5O_info_t *oi)
-{
-    int  n;
-
-    /*only one name possible*/
-    if(oi->rc < 2)
-        return NULL;
-
-    for(n = 0; n < idtab_g.nobjs; n++)
-        if(idtab_g.obj[n].id == oi->addr)
-            return idtab_g.obj[n].name;
-
-    return NULL;
-}
-
-
-/*-------------------------------------------------------------------------
  * Function: display_string
  *
  * Purpose: Print a string value by escaping unusual characters. If
@@ -278,6 +199,55 @@ display_string(FILE *stream, const char *s, hbool_t escape_spaces)
 
 
 /*-------------------------------------------------------------------------
+ * Function: display_obj_name
+ *
+ * Purpose: Print an object name and another string.
+ *
+ * Return: Success: TRUE
+ *
+ *  Failure: FALSE, nothing printed
+ *
+ * Programmer: Quincey Koziol
+ *              Tuesday, November  6, 2007
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+display_obj_name(FILE *stream, const iter_t *iter, const char *oname,
+    const char *s)
+{
+    static char fullname[NAME_BUF_SIZE];     /* Buffer for file and/or object name */
+    const char *name = fullname;                /* Pointer to buffer for printing */
+    int  n;
+
+    if(show_file_name_g)
+        sprintf(fullname, "%s/%s", iter->fname, oname);
+    else
+        name = oname;
+
+    /* Print the object name, either full name or base name */
+    if(fullname_g)
+        n = display_string(stream, name, TRUE);
+    else {
+        const char *last_sep;   /* The location of the last group separator */
+
+        /* Find the last component of the path name */
+        if(NULL == (last_sep = HDstrrchr(name, '/')))
+            last_sep = name;
+        else {
+            last_sep++;
+        } /* end else */
+        n = display_string(stream, last_sep, TRUE);
+    } /* end else */
+    printf("%*s ", MAX(0, (24 - n)), s);
+
+    return TRUE;
+}
+
+
+/*-------------------------------------------------------------------------
  * Function: display_native_type
  *
  * Purpose: Prints the name of a native C data type.
@@ -1326,7 +1296,7 @@ list_attr(hid_t obj, const char *attr_name, const H5A_info_t UNUSED *ainfo,
     void UNUSED *op_data)
 {
     hid_t attr, space, type, p_type;
-    hsize_t size[64], nelmts = 1;
+    hsize_t size[H5S_MAX_RANK], nelmts = 1;
     int  ndims, i, n;
     size_t need;
     hsize_t     temp_need;
@@ -1460,8 +1430,8 @@ list_attr(hid_t obj, const char *attr_name, const H5A_info_t UNUSED *ainfo,
 static herr_t
 dataset_list1(hid_t dset)
 {
-    hsize_t     cur_size[64];   /* current dataset dimensions */
-    hsize_t     max_size[64];   /* maximum dataset dimensions */
+    hsize_t     cur_size[H5S_MAX_RANK];   /* current dataset dimensions */
+    hsize_t     max_size[H5S_MAX_RANK];   /* maximum dataset dimensions */
     hid_t       space;          /* data space                 */
     int         ndims;          /* dimensionality             */
     H5S_class_t space_type;     /* type of dataspace          */
@@ -1524,7 +1494,6 @@ dataset_list2(hid_t dset, const char UNUSED *name)
     off_t       f_offset;       /* offset in external file */
     hsize_t     f_size;         /* bytes used in external file */
     hsize_t     total, used;    /* total size or offset */
-    hsize_t     chsize[64];     /* chunk size in elements */
     int         ndims;          /* dimensionality */
     int         n, max_len;     /* max extern file name length */
     double      utilization;    /* percent utilization of storage */
@@ -1537,6 +1506,8 @@ dataset_list2(hid_t dset, const char UNUSED *name)
 
         /* Print information about chunked storage */
         if (H5D_CHUNKED==H5Pget_layout(dcpl)) {
+            hsize_t     chsize[64];     /* chunk size in elements */
+
             ndims = H5Pget_chunk(dcpl, NELMTS(chsize), chsize/*out*/);
             printf("    %-10s {", "Chunks:");
             total = H5Tget_size(type);
@@ -1645,39 +1616,9 @@ dataset_list2(hid_t dset, const char UNUSED *name)
 
 
 /*-------------------------------------------------------------------------
- * Function: group_list2
- *
- * Purpose: List information about a group which should appear after
- *  information which is general to all objects.
- *
- * Return: Success: 0
- *
- *  Failure: -1
- *
- * Programmer: Robb Matzke
- *              Thursday, January 21, 1999
- *
- * Modifications:
- *
- *-------------------------------------------------------------------------
- */
-static herr_t
-group_list2(hid_t grp, const char *name)
-{
-    iter_t iter;
-
-    if (recursive_g) {
-        iter.container = name;
-        H5Literate(grp, H5_INDEX_NAME, H5_ITER_INC, NULL, list, &iter);
-    }
-    return 0;
-}
-
-
-/*-------------------------------------------------------------------------
  * Function: datatype_list2
  *
- * Purpose: List information about a data type which should appear after
+ * Purpose: List information about a datatype which should appear after
  *  information which is general to all objects.
  *
  * Return: Success: 0
@@ -1704,80 +1645,56 @@ datatype_list2(hid_t type, const char UNUSED *name)
 
 
 /*-------------------------------------------------------------------------
- * Function: list
+ * Function: list_obj
  *
- * Purpose: Prints the group member name.
+ * Purpose: Prints information about an object
  *
  * Return: Success: 0
  *
  *  Failure: -1
  *
- * Programmer: Robb Matzke
- *              Monday, March 23, 1998
+ * Programmer: Quincey Koziol
+ *              Tuesday, November 6, 2007
  *
- * Modifications:
- *              Robb Matzke, LLNL, 2003-06-06
- *              If simple_output_g (set by `--simple') is turned on then
- *              the modification time is printed as UTC instead of the
- *              local timezone.
  *-------------------------------------------------------------------------
  */
 static herr_t
-list(hid_t group, const char *name, const H5L_info_t *linfo, void *_iter)
+list_obj(const char *name, const H5O_info_t *oinfo, const char *first_seen, void *_iter)
 {
+    H5O_type_t obj_type = oinfo->type;          /* Type of the object */
     iter_t *iter = (iter_t*)_iter;
-    char *fullname = NULL;
-    int  n;
 
-    /* Print the object name, either full name or base name */
-    fullname = fix_name(iter->container, name);
-    if(fullname_g)
-        n = display_string(stdout, fullname, TRUE);
-    else
-        n = display_string(stdout, name, TRUE);
-    printf("%*s ", MAX(0, (24 - n)), "");
-
-    /* Actions on objects */
-    if(linfo->type == H5L_TYPE_HARD) {
-        H5O_info_t oi;
-        char *s;
-        hid_t obj;
-
-        /* Get object information */
-        if(H5Oget_info_by_name(group, name, &oi, H5P_DEFAULT) < 0) {
-            puts("**NOT FOUND**");
-            return 0;
-        } else if(oi.type < 0 || oi.type >= H5O_TYPE_NTYPES) {
-            printf("Unknown type(%d)", (int)oi.type);
-            oi.type = H5O_TYPE_UNKNOWN;
-        }
-        if(oi.type >= 0 && dispatch_g[oi.type].name)
-            fputs(dispatch_g[oi.type].name, stdout);
-
-        /* If the object has already been printed then just show the object ID
-         * and return. */
-        if((s = sym_lookup(&oi))) {
-            printf(", same as ");
-            display_string(stdout, s, TRUE);
-            printf("\n");
-            goto done;
-        } /* end if */
-        else
-            sym_insert(&oi, fullname);
+    /* Print the link's name, either full name or base name */
+    display_obj_name(stdout, iter, name, "");
+
+    /* Check object information */
+    if(oinfo->type < 0 || oinfo->type >= H5O_TYPE_NTYPES) {
+        printf("Unknown type(%d)", (int)oinfo->type);
+        obj_type = H5O_TYPE_UNKNOWN;
+    }
+    if(obj_type >= 0 && dispatch_g[obj_type].name)
+        fputs(dispatch_g[obj_type].name, stdout);
+
+    /* Check if we've seen this object before */
+    if(first_seen) {
+        printf(", same as ");
+        display_string(stdout, first_seen, TRUE);
+        printf("\n");
+    } /* end if */
+    else {
+        hid_t obj = (-1);               /* ID of object opened */
 
         /* Open the object.  Not all objects can be opened.  If this is the case
          * then return right away.
          */
-        if(oi.type >= 0 &&
-                (NULL == dispatch_g[oi.type].open ||
-                (obj = (dispatch_g[oi.type].open)(group, name, H5P_DEFAULT)) < 0)) {
+        if(obj_type >= 0 && (obj = H5Oopen(iter->fid, name, H5P_DEFAULT)) < 0) {
             printf(" *ERROR*\n");
             goto done;
         } /* end if */
 
         /* List the first line of information for the object. */
-        if(oi.type >= 0 && dispatch_g[oi.type].list1)
-            (dispatch_g[oi.type].list1)(obj);
+        if(obj_type >= 0 && dispatch_g[obj_type].list1)
+            (dispatch_g[obj_type].list1)(obj);
         putchar('\n');
 
         /* Show detailed information about the object, beginning with information
@@ -1786,22 +1703,22 @@ list(hid_t group, const char *name, const H5L_info_t *linfo, void *_iter)
             char comment[50];
 
             /* Display attributes */
-            if(oi.type >= 0)
+            if(obj_type >= 0)
                 H5Aiterate2(obj, H5_INDEX_NAME, H5_ITER_INC, NULL, list_attr, NULL);
 
             /* Object location & reference count */
-            printf("    %-10s %lu:"H5_PRINTF_HADDR_FMT"\n", "Location:", oi.fileno, oi.addr);
-            printf("    %-10s %u\n", "Links:", (unsigned)oi.rc);
+            printf("    %-10s %lu:"H5_PRINTF_HADDR_FMT"\n", "Location:", oinfo->fileno, oinfo->addr);
+            printf("    %-10s %u\n", "Links:", (unsigned)oinfo->rc);
 
             /* Modification time */
-            if(oi.mtime > 0) {
+            if(oinfo->mtime > 0) {
                 char buf[256];
                 struct tm *tm;
 
                 if(simple_output_g)
-                    tm = HDgmtime(&(oi.mtime));
+                    tm = HDgmtime(&(oinfo->mtime));
                 else
-                    tm = HDlocaltime(&(oi.mtime));
+                    tm = HDlocaltime(&(oinfo->mtime));
                 if(tm) {
                     HDstrftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S %Z", tm);
                     printf("    %-10s %s\n", "Modified:", buf);
@@ -1810,7 +1727,7 @@ list(hid_t group, const char *name, const H5L_info_t *linfo, void *_iter)
 
             /* Object comment */
             comment[0] = '\0';
-            H5Oget_comment_by_name(group, name, comment, sizeof(comment), H5P_DEFAULT);
+            H5Oget_comment(obj, comment, sizeof(comment));
             HDstrcpy(comment + sizeof(comment) - 4, "...");
             if(comment[0]) {
                 printf("    %-10s \"", "Comment:");
@@ -1820,118 +1737,91 @@ list(hid_t group, const char *name, const H5L_info_t *linfo, void *_iter)
         } /* end if */
 
         /* Detailed list for object */
-        if(oi.type >= 0 && dispatch_g[oi.type].list2)
-            (dispatch_g[oi.type].list2)(obj, fullname);
+        if(obj_type >= 0 && dispatch_g[obj_type].list2)
+            (dispatch_g[obj_type].list2)(obj, name);
 
         /* Close the object. */
-        if(oi.type >= 0 && dispatch_g[oi.type].close)
-            (dispatch_g[oi.type].close)(obj);
-    } /* end if */
-    /* Actions on links */
-    else {
-        char *buf;
-
-        HDfputs("-> ", stdout);
-        switch(linfo->type) {
-            case H5L_TYPE_SOFT:
-                if((buf = HDmalloc(linfo->u.val_size)) == NULL)
-                    goto done;
-
-                if(H5Lget_val(group, name, buf, linfo->u.val_size, H5P_DEFAULT) < 0) {
-                    HDfree(buf);
-                    goto done;
-                } /* end if */
-
-                HDfputs(buf, stdout);
-                HDfree(buf);
-                break;
-
-            case H5L_TYPE_EXTERNAL:
-                {
-                const char *filename;
-                const char *path;
-
-                if((buf = HDmalloc(linfo->u.val_size)) == NULL)
-                    goto done;
-
-                if(H5Lget_val(group, name, buf, linfo->u.val_size, H5P_DEFAULT) < 0) {
-                    HDfree(buf);
-                    goto done;
-                } /* end if */
-                if(H5Lunpack_elink_val(buf, linfo->u.val_size, NULL, &filename, &path) < 0) {
-                    HDfree(buf);
-                    goto done;
-                } /* end if */
-
-                HDfputs("file: ", stdout);
-                HDfputs(filename, stdout);
-                HDfputs("    path: ", stdout);
-                HDfputs(path, stdout);
-                }
-                break;
-
-            default:
-                HDfputs("cannot follow UD links", stdout);
-                break;
-        } /* end switch */
-        HDfputc('\n', stdout);
+        if(obj_type >= 0)
+            H5Oclose(obj);
     } /* end else */
 
 done:
-    if(fullname)
-        free(fullname);
     return 0;
-} /* end list() */
+} /* end list_obj() */
 
 
 /*-------------------------------------------------------------------------
- * Function: fix_name
+ * Function: list_lnk
  *
- * Purpose: Returns a malloc'd buffer that contains the PATH and BASE
- *  names separated by a single slash. It also removes duplicate
- *  and trailing slashes.
+ * Purpose: Prints information about a link
  *
- * Return: Success: Ptr to fixed name from malloc()
- *
- *  Failure: NULL
+ * Return: Success: 0
  *
- * Programmer: Robb Matzke
- *              Thursday, January 21, 1999
+ *  Failure: -1
  *
- * Modifications:
+ * Programmer: Quincey Koziol
+ *              Thursday, November 8, 2007
  *
  *-------------------------------------------------------------------------
  */
-static char *
-fix_name(const char *path, const char *base)
+static herr_t
+list_lnk(const char *name, const H5L_info_t *linfo, void *_iter)
 {
-    size_t n = (path ? HDstrlen(path) : 0) + (base ? HDstrlen(base) : 0) + 3;
-    char *s = HDmalloc(n), prev='\0';
-    size_t len = 0;
-
-    if (path) {
-        /* Path, followed by slash */
-        for (/*void*/; *path; path++)
-            if ('/'!=*path || '/'!=prev)
-                prev = s[len++] = *path;
-        if ('/' != prev)
-            prev = s[len++] = '/';
-    }
+    char *buf;
+    iter_t *iter = (iter_t*)_iter;
 
-    if (base) {
-        /* Base name w/o trailing slashes */
-        const char *end = base + HDstrlen(base);
-        while (end > base && '/' == end[-1])
-            --end;
+    /* Print the link's name, either full name or base name */
+    display_obj_name(stdout, iter, name, "");
 
-        for (/*void*/; base < end; base++)
-            if ('/' != *base || '/' != prev)
-                prev = s[len++] = *base;
-    }
+    HDfputs("-> ", stdout);
+    switch(linfo->type) {
+        case H5L_TYPE_SOFT:
+            if((buf = HDmalloc(linfo->u.val_size)) == NULL)
+                goto done;
 
-    s[len] = '\0';
-    return s;
-}
+            if(H5Lget_val(iter->fid, name, buf, linfo->u.val_size, H5P_DEFAULT) < 0) {
+                HDfree(buf);
+                goto done;
+            } /* end if */
+
+            HDfputs(buf, stdout);
+            HDfree(buf);
+            break;
+
+        case H5L_TYPE_EXTERNAL:
+            {
+            const char *filename;
+            const char *path;
+
+            if((buf = HDmalloc(linfo->u.val_size)) == NULL)
+                goto done;
+
+            if(H5Lget_val(iter->fid, name, buf, linfo->u.val_size, H5P_DEFAULT) < 0) {
+                HDfree(buf);
+                goto done;
+            } /* end if */
+            if(H5Lunpack_elink_val(buf, linfo->u.val_size, NULL, &filename, &path) < 0) {
+                HDfree(buf);
+                goto done;
+            } /* end if */
+
+            HDfputs("file: ", stdout);
+            HDfputs(filename, stdout);
+            HDfputs("    path: ", stdout);
+            HDfputs(path, stdout);
+            HDfree(buf);
+            }
+            break;
+
+        default:
+            HDfputs("cannot follow UD links", stdout);
+            break;
+    } /* end switch */
+    HDfputc('\n', stdout);
+
+done:
+    return 0;
+} /* end list_lnk() */
 
 
 /*-------------------------------------------------------------------------
@@ -2059,10 +1949,10 @@ leave(int ret)
 int
 main(int argc, const char *argv[])
 {
-    hid_t file = -1, root = -1;
+    hid_t file = -1;
     char *fname = NULL, *oname = NULL, *x;
     const char *s = NULL;
-    char *rest, *container = NULL;
+    char *rest;
     int  argno;
     static char root_name[] = "/";
     char        drivername[50];
@@ -2072,9 +1962,9 @@ main(int argc, const char *argv[])
     h5tools_init();
 
     /* Build object display table */
-    DISPATCH(H5O_TYPE_GROUP, "Group", H5Gopen2, H5Gclose, NULL, group_list2);
-    DISPATCH(H5O_TYPE_DATASET, "Dataset", H5Dopen2, H5Dclose, dataset_list1, dataset_list2);
-    DISPATCH(H5O_TYPE_NAMED_DATATYPE, "Type", H5Topen2, H5Tclose, NULL, datatype_list2);
+    DISPATCH(H5O_TYPE_GROUP, "Group", NULL, NULL);
+    DISPATCH(H5O_TYPE_DATASET, "Dataset", dataset_list1, dataset_list2);
+    DISPATCH(H5O_TYPE_NAMED_DATATYPE, "Type", NULL, datatype_list2);
 
     /* Default output width */
     width_g = get_width();
@@ -2230,6 +2120,13 @@ main(int argc, const char *argv[])
         leave(1);
     } /* end if */
 
+    /* Check for conflicting arguments */
+    if(recursive_g && grp_literal_g) {
+        fprintf(stderr, "Error: 'recursive' option not compatible with 'group info' option!\n\n");
+        usage();
+        leave(1);
+    } /* end if */
+
     /* Turn off HDF5's automatic error printing unless you're debugging h5ls */
     if(!show_errors_g)
         H5Eset_auto2(H5E_DEFAULT, NULL, NULL);
@@ -2249,7 +2146,6 @@ main(int argc, const char *argv[])
      * doesn't exist). */
     show_file_name_g = (argc-argno > 1); /*show file names if more than one*/
     while(argno < argc) {
-        H5O_info_t oi;
         H5L_info_t li;
         iter_t iter;
 
@@ -2281,24 +2177,21 @@ main(int argc, const char *argv[])
         } /* end if */
         if(oname)
             oname++;
-        if(!oname || !*oname)
+        if(!oname || !*oname) {
             oname = root_name;
+            if(recursive_g)
+                display_root_g = TRUE;
+        } /* end if */
+
+        /* Remember the file information for later */
+        iter.fname = fname;
+        iter.fid = file;
 
         /* Check for root group as object name */
         if(HDstrcmp(oname, root_name)) {
             /* Check the type of link given */
             if(H5Lget_info(file, oname, &li, H5P_DEFAULT) < 0) {
-                char *fullname = NULL;
-                int n;
-
-                fullname = fix_name(oname, "/");
-                if(fullname_g)
-                    n = display_string(stdout, fullname, TRUE);
-                else
-                    n = display_string(stdout, oname, TRUE);
-                printf("%*s \n", MAX(0, (24 - n)), "**NOT FOUND**");
-
-                HDfree(fullname);
+                display_obj_name(stdout, &iter, oname, "**NOT FOUND**");
                 leave(1);
             } /* end if */
         } /* end if */
@@ -2306,34 +2199,25 @@ main(int argc, const char *argv[])
             li.type = H5L_TYPE_HARD;
 
         /* Open the object and display it's information */
-        if(li.type == H5L_TYPE_HARD && H5Oget_info_by_name(file, oname, &oi, H5P_DEFAULT) >= 0 && H5O_TYPE_GROUP == oi.type && !grp_literal_g) {
-            /* Specified name is a group. List the complete contents of the group. */
-            sym_insert(&oi, oname);
-            iter.container = container = fix_name((show_file_name_g ? fname : ""), oname);
-
-            /* list root attributes */
-            if(verbose_g > 0) {
-                if((root = H5Gopen2(file, "/", H5P_DEFAULT)) < 0)
-                    leave(1);
-                H5Aiterate2(root, H5_INDEX_NAME, H5_ITER_INC, NULL, list_attr, NULL);
-                if(H5Gclose(root) < 0)
-                    leave(1);
-            } /* end if */
+        if(li.type == H5L_TYPE_HARD) {
+            H5O_info_t oi;              /* Information for object */
 
-            /* list */
-            H5Literate_by_name(file, oname, H5_INDEX_NAME, H5_ITER_INC, NULL, list, &iter, H5P_DEFAULT);
-            free(container);
-        } else if((root = H5Gopen2(file, "/", H5P_DEFAULT)) < 0) {
-            leave(1); /*major problem!*/
-        } else {
-            /* Specified name is a non-group object -- list that object.  The
-             * container for the object is everything up to the base name.
-             */
-            iter.container = show_file_name_g ? fname : "/";
-            list(root, oname, &li, &iter);
-            if(H5Gclose(root) < 0)
+            /* Retrieve info for object to list */
+            if(H5Oget_info_by_name(file, oname, &oi, H5P_DEFAULT) < 0) {
+                display_obj_name(stdout, &iter, oname, "**NOT FOUND**");
                 leave(1);
-        }
+            } /* end if */
+
+            /* Check for group iteration */
+            if(H5O_TYPE_GROUP == oi.type && !grp_literal_g)
+                /* Specified name is a group. List the complete contents of the group. */
+                h5trav_visit(file, oname, display_root_g, recursive_g, list_obj, list_lnk, &iter);
+            else
+                /* Specified name is a non-group object -- list that object */
+                list_obj(oname, &oi, NULL, &iter);
+        } else
+            /* Specified name is not for object -- list that link */
+            list_lnk(oname, &li, &iter);
         H5Fclose(file);
         free(fname);
     } /* end while */
diff --git a/tools/h5ls/testh5ls.sh b/tools/h5ls/testh5ls.sh
index ab36eb4..f25db4e 100755
--- a/tools/h5ls/testh5ls.sh
+++ b/tools/h5ls/testh5ls.sh
@@ -112,6 +112,7 @@ TOOLTEST tgroup.ls -w80 tgroup.h5
 
 # test for displaying groups
 TOOLTEST tgroup-1.ls -w80 -r -g tgroup.h5
+TOOLTEST tgroup-2.ls -w80 -g tgroup.h5/g1
 
 # test for displaying simple space datasets
 TOOLTEST tdset-1.ls -w80 -r -d tdset.h5
diff --git a/tools/h5stat/h5stat.c b/tools/h5stat/h5stat.c
index c69d801..f03efd7 100644
--- a/tools/h5stat/h5stat.c
+++ b/tools/h5stat/h5stat.c
@@ -47,8 +47,7 @@ typedef struct ohdr_info_t {
 
 /* Info to pass to the iteration functions */
 typedef struct iter_t {
-    const char *container;              /* Full name of the container object */
-    unsigned long curr_depth;           /* Current depth of hierarchy */
+    hid_t fid;                          /* File ID */
 
     unsigned long uniq_groups;          /* Number of unique groups */
     unsigned long uniq_dsets;           /* Number of unique datasets */
@@ -56,7 +55,6 @@ typedef struct iter_t {
     unsigned long uniq_links;           /* Number of unique links */
     unsigned long uniq_others;          /* Number of other unique objects */
 
-    unsigned long max_depth;            /* Maximum depth of hierarchy */
     unsigned long max_links;            /* Maximum # of links to an object */
     hsize_t max_fanout;                 /* Maximum fanout from a group */
     unsigned long num_small_groups[SIZE_SMALL_GROUPS];     /* Size of small groups tracked */
@@ -95,16 +93,6 @@ typedef struct iter_t {
 } iter_t;
 
 
-/* Table containing object id and object name */
-static struct {
-    int  nalloc;                /* number of slots allocated */
-    int  nobjs;                 /* number of objects */
-    struct {
-        haddr_t id;             /* object number */
-        char *name;             /* full object name */
-    } *obj;
-} idtab_g;
-
 const char *progname = "h5stat";
 int               d_status = EXIT_SUCCESS;
 static int        display_all = TRUE;
@@ -260,123 +248,6 @@ ceil_log10(unsigned long x)
 
 
 /*-------------------------------------------------------------------------
- * Function: sym_insert
- *
- * Purpose: Add a symbol to the table.
- *
- * Return: void
- *
- * Programmer: Robb Matzke
- *              Thursday, January 21, 1999
- *
- *-------------------------------------------------------------------------
- */
-static void
-sym_insert(H5O_info_t *oi, const char *name)
-{
-    /* Don't add it if the link count is 1 because such an object can only
-     * have one name. */
-    if(oi->rc > 1) {
-        int  n;
-
-        /* Extend the table */
-        if(idtab_g.nobjs >= idtab_g.nalloc) {
-            idtab_g.nalloc = MAX(256, 2 * idtab_g.nalloc);
-            idtab_g.obj = realloc(idtab_g.obj, idtab_g.nalloc * sizeof(idtab_g.obj[0]));
-        } /* end if */
-
-        /* Insert the entry */
-        n = idtab_g.nobjs++;
-        idtab_g.obj[n].id = oi->addr;
-        idtab_g.obj[n].name = strdup(name);
-    } /* end if */
-} /* end sym_insert() */
-
-
-/*-------------------------------------------------------------------------
- * Function: sym_lookup
- *
- * Purpose: Find another name for the specified object.
- *
- * Return: Success: Ptr to another name.
- *
- *  Failure: NULL
- *
- * Programmer: Robb Matzke
- *              Thursday, January 21, 1999
- *
- * Modifications:
- *
- *-------------------------------------------------------------------------
- */
-static char *
-sym_lookup(H5O_info_t *oi)
-{
-    int  n;
-
-    /*only one name possible*/
-    if(oi->rc < 2)
-        return NULL;
-
-    for(n = 0; n < idtab_g.nobjs; n++)
-        if(idtab_g.obj[n].id == oi->addr)
-            return idtab_g.obj[n].name;
-
-    return NULL;
-} /* end sym_lookup() */
-
-
-/*-------------------------------------------------------------------------
- * Function: fix_name
- *
- * Purpose: Returns a malloc'd buffer that contains the PATH and BASE
- *  names separated by a single slash. It also removes duplicate
- *  and trailing slashes.
- *
- * Return: Success: Ptr to fixed name from malloc()
- *
- *  Failure: NULL
- *
- * Programmer: Robb Matzke
- *              Thursday, January 21, 1999
- *
- * Modifications:
- *
- *-------------------------------------------------------------------------
- */
-static char *
-fix_name(const char *path, const char *base)
-{
-    size_t n = (path ? strlen(path) : 0) + (base ? strlen(base) : 0) + 3;
-    char *s = malloc(n), prev='\0';
-    size_t len = 0;
-
-    if (path) {
-        /* Path, followed by slash */
-        for (/*void*/; *path; path++)
-            if ('/'!=*path || '/'!=prev)
-                prev = s[len++] = *path;
-        if ('/' != prev)
-            prev = s[len++] = '/';
-    }
-
-    if (base) {
-        /* Base name w/o trailing slashes */
-        const char *end = base + strlen(base);
-        while (end > base && '/' == end[-1])
-            --end;
-
-        for (/*void*/; base < end; base++)
-            if ('/' != *base || '/' != prev)
-                prev = s[len++] = *base;
-    }
-
-    s[len] = '\0';
-    return s;
-}
-
-
-/*-------------------------------------------------------------------------
  * Function: attribute_stats
  *
  * Purpose: Gather statistics about attributes on an object
@@ -453,25 +324,21 @@ attribute_stats(iter_t *iter, const H5O_info_t *oi)
  *-------------------------------------------------------------------------
  */
 static herr_t
-group_stats(hid_t group, const char *name, const char *fullname,
-    const H5O_info_t *oi, H5L_iterate_t walk, iter_t *iter)
+group_stats(iter_t *iter, const char *name, const H5O_info_t *oi)
 {
-    const char 		*last_container;
     H5G_info_t 		ginfo;                  /* Group information */
     unsigned 		bin;                   	/* "bin" the number of objects falls in */
     herr_t 		ret;
 
     /* Gather statistics about this type of object */
     iter->uniq_groups++;
-    if(iter->curr_depth > iter->max_depth)
-	iter->max_depth = iter->curr_depth;
 
     /* Get object header information */
     iter->group_ohdr_info.total_size += oi->hdr.space.total;
     iter->group_ohdr_info.free_size += oi->hdr.space.free;
 
     /* Get group information */
-    ret = H5Gget_info_by_name(group, name, &ginfo, H5P_DEFAULT);
+    ret = H5Gget_info_by_name(iter->fid, name, &ginfo, H5P_DEFAULT);
     assert(ret >= 0);
 
     /* Update link stats */
@@ -506,18 +373,6 @@ group_stats(hid_t group, const char *name, const char *fullname,
     ret = attribute_stats(iter, oi);
     assert(ret >= 0);
 
-    /* Update current container info */
-    last_container = iter->container;
-    iter->container = fullname;
-    iter->curr_depth++;
-
-    /* Recursively descend into current group's objects */
-    H5Literate_by_name(group, name, H5_INDEX_NAME, H5_ITER_INC, NULL, walk, iter, H5P_DEFAULT);
-
-    /* Revert current container info */
-    iter->container = last_container;
-    iter->curr_depth--;
-     
     return 0;
 } /* end group_stats() */
 
@@ -549,7 +404,7 @@ group_stats(hid_t group, const char *name, const char *fullname,
  *-------------------------------------------------------------------------
  */
 static herr_t
-dataset_stats(hid_t group, const char *name, const H5O_info_t *oi, iter_t *iter)
+dataset_stats(iter_t *iter, const char *name, const H5O_info_t *oi)
 {
     unsigned 		bin;               /* "bin" the number of objects falls in */
     hid_t 		did;               /* Dataset ID */
@@ -575,7 +430,7 @@ dataset_stats(hid_t group, const char *name, const H5O_info_t *oi, iter_t *iter)
     iter->dset_ohdr_info.total_size += oi->hdr.space.total;
     iter->dset_ohdr_info.free_size += oi->hdr.space.free;
 
-    did = H5Dopen2(group, name, H5P_DEFAULT);
+    did = H5Dopen2(iter->fid, name, H5P_DEFAULT);
     assert(did > 0);
 
     /* Update dataset metadata info */
@@ -710,89 +565,90 @@ dataset_stats(hid_t group, const char *name, const H5O_info_t *oi, iter_t *iter)
 
 
 /*-------------------------------------------------------------------------
- * Function: walk
+ * Function: obj_stats
  *
- * Purpose: Gather statistics about the file
+ * Purpose: Gather statistics about an object
  *
  * Return: Success: 0
- *  	   Failure: -1
  *
- * Programmer: Quincey Koziol
- *             Tuesday, August 16, 2005
+ *  Failure: -1
  *
- * Modifications:
+ * Programmer: Quincey Koziol
+ *             Tuesday, November 6, 2007
  *
  *-------------------------------------------------------------------------
  */
 static herr_t
-walk(hid_t group, const char *name, const H5L_info_t *linfo, void *_iter)
+obj_stats(const char *path, const H5O_info_t *oi, const char *already_visited,
+    void *_iter)
 {
     iter_t *iter = (iter_t *)_iter;
-    char *fullname = NULL;
-    herr_t ret;                     /* Generic return value */
-
-    if(!linfo || linfo->type == H5L_TYPE_HARD) {
-        H5O_info_t oi;
-        char *s;
-
-        /* Get object information */
-        ret = H5Oget_info_by_name(group, name, &oi, H5P_DEFAULT);
-        assert(ret >= 0);
-
-        /* If the object has already been printed then just show the object ID
-         * and return. */
-        if((s = sym_lookup(&oi))) {
-            printf("%s same as %s\n", name, s);
-        } else {
-            /* Get the full object name */
-            fullname = fix_name(iter->container, name);
-            sym_insert(&oi, fullname);
-
-            /* Gather some statistics about the object */
-            if(oi.rc > iter->max_links)
-                iter->max_links = oi.rc;
-
-            switch(oi.type) {
-                case H5O_TYPE_GROUP:
-                    group_stats(group, name, fullname, &oi, walk, iter);
-                    break;
-
-                case H5O_TYPE_DATASET:
-                    dataset_stats(group, name, &oi, iter);
-                    break;
-
-                case H5O_TYPE_NAMED_DATATYPE:
-                    /* Gather statistics about this type of object */
-                    iter->uniq_types++;
-                    break;
-
-                default:
-                    /* Gather statistics about this type of object */
-                    iter->uniq_others++;
-                    break;
-            } /* end switch */
-        }
-    } /* end if */
-    else {
-        switch(linfo->type) {
-            case H5L_TYPE_SOFT:
-            case H5L_TYPE_EXTERNAL:
-                /* Gather statistics about links and UD links */
-                iter->uniq_links++;
+
+    /* If the object has already been seen then just return */
+    if(NULL == already_visited) {
+        /* Gather some general statistics about the object */
+        if(oi->rc > iter->max_links)
+            iter->max_links = oi->rc;
+
+        switch(oi->type) {
+            case H5O_TYPE_GROUP:
+                group_stats(iter, path, oi);
+                break;
+
+            case H5O_TYPE_DATASET:
+                dataset_stats(iter, path, oi);
+                break;
+
+            case H5O_TYPE_NAMED_DATATYPE:
+                /* Gather statistics about this type of object */
+                iter->uniq_types++;
                 break;
 
             default:
                 /* Gather statistics about this type of object */
                 iter->uniq_others++;
                 break;
-        } /* end switch() */
-    } /* end else */
+        } /* end switch */
+    } /* end if */
 
-    if(fullname)
-        free(fullname);
+    return 0;
+} /* end obj_stats() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: lnk_stats
+ *
+ * Purpose: Gather statistics about a link
+ *
+ * Return: Success: 0
+ *
+ *  Failure: -1
+ *
+ * Programmer: Quincey Koziol
+ *             Tuesday, November 6, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+lnk_stats(const char UNUSED *path, const H5L_info_t *li, void *_iter)
+{
+    iter_t *iter = (iter_t *)_iter;
+
+    switch(li->type) {
+        case H5L_TYPE_SOFT:
+        case H5L_TYPE_EXTERNAL:
+            /* Gather statistics about links and UD links */
+            iter->uniq_links++;
+            break;
+
+        default:
+            /* Gather statistics about this type of object */
+            iter->uniq_others++;
+            break;
+    } /* end switch() */
 
     return 0;
-}
+} /* end lnk_stats() */
 
 
 /*-------------------------------------------------------------------------
@@ -915,13 +771,13 @@ parse_command_line(int argc, const char *argv[])
  *-------------------------------------------------------------------------
  */
 static herr_t
-iter_init(iter_t *iter)
+iter_init(iter_t *iter, hid_t fid)
 {
     /* Clear everything to zeros */
-    memset(iter, 0, sizeof(*iter));
+    HDmemset(iter, 0, sizeof(*iter));
 
-    /* Initialize non-zero information */
-    iter->container = "/";
+    /* Set the file ID for later use in callbacks */
+    iter->fid = fid;
 
     return 0;
 }
@@ -953,7 +809,6 @@ print_file_info(const iter_t *iter)
     printf("\t# of unique links: %lu\n", iter->uniq_links);
     printf("\t# of unique other: %lu\n", iter->uniq_others);
     printf("\tMax. # of links to object: %lu\n", iter->max_links);
-    printf("\tMax. depth of hierarchy: %lu\n", iter->max_depth);
     HDfprintf(stdout, "\tMax. # of objects in group: %Hu\n", iter->max_fanout);
 
     return 0;
@@ -1318,8 +1173,6 @@ main(int argc, const char *argv[])
     const char     	*fname = NULL;
     hid_t           	fid;
     struct handler_t   *hand;
-    char            	root[] = "/";
-    int             	i;
     H5F_info_t      	finfo;
 
 
@@ -1329,25 +1182,23 @@ main(int argc, const char *argv[])
     /* Initialize h5tools lib */
     h5tools_init();
     hand = parse_command_line (argc, argv);
-    if (!hand) {
+    if(!hand) {
         error_msg(progname, "unable to parse command line arguments \n");
         leave(EXIT_FAILURE);
-    }
+    } /* end if */
 
     fname = argv[opt_ind];
-    if(!display_object)
-        hand[0].obj = root;
 
     printf("Filename: %s\n", fname);
 
     fid = H5Fopen(fname, H5F_ACC_RDONLY, H5P_DEFAULT);
-    if (fid < 0) {
+    if(fid < 0) {
         error_msg(progname, "unable to open file \"%s\"\n", fname);
         leave(EXIT_FAILURE);
-    }
+    } /* end if */
 
     /* Initialize iter structure */
-    iter_init(&iter);
+    iter_init(&iter, fid);
     
     /* Get storge info for SOHM's btree/list/heap and superblock extension */
     if(H5Fget_info(fid, &finfo) < 0)
@@ -1357,15 +1208,23 @@ main(int argc, const char *argv[])
 	iter.SM_hdr_storage_size = finfo.sohm.hdr_size;
 	iter.SM_index_storage_size = finfo.sohm.msgs_info.index_size;
 	iter.SM_heap_storage_size = finfo.sohm.msgs_info.heap_size;
-    }
+    } /* end else */
 
     /* Walk the objects or all file */
-    i = 0;
-    while(hand[i].obj) {
-        walk(fid, hand[i].obj, NULL, &iter);
-        print_statistics(hand[i].obj, &iter);
-        i++;
-    } /* end while */
+    if(display_object) {
+        unsigned u;
+
+        u = 0;
+        while(hand[u].obj) {
+            h5trav_visit(fid, hand[u].obj, TRUE, TRUE, obj_stats, lnk_stats, &iter);
+            print_statistics(hand[u].obj, &iter);
+            u++;
+        } /* end while */
+    } /* end if */
+    else {
+        h5trav_visit(fid, "/", TRUE, TRUE, obj_stats, lnk_stats, &iter);
+        print_statistics("/", &iter);
+    } /* end else */
 
     free(hand);
 
diff --git a/tools/h5stat/testfiles/h5stat_filters-file.ddl b/tools/h5stat/testfiles/h5stat_filters-file.ddl
index c6aeef0..7b8f47f 100644
--- a/tools/h5stat/testfiles/h5stat_filters-file.ddl
+++ b/tools/h5stat/testfiles/h5stat_filters-file.ddl
@@ -9,5 +9,4 @@ File information
 	# of unique links: 0
 	# of unique other: 0
 	Max. # of links to object: 1
-	Max. depth of hierarchy: 0
 	Max. # of objects in group: 16
diff --git a/tools/h5stat/testfiles/h5stat_filters.ddl b/tools/h5stat/testfiles/h5stat_filters.ddl
index 4dd6aee..df2e304 100644
--- a/tools/h5stat/testfiles/h5stat_filters.ddl
+++ b/tools/h5stat/testfiles/h5stat_filters.ddl
@@ -9,7 +9,6 @@ File information
 	# of unique links: 0
 	# of unique other: 0
 	Max. # of links to object: 1
-	Max. depth of hierarchy: 0
 	Max. # of objects in group: 16
 Object header size: (total/unused)
 	Groups: 48/8
diff --git a/tools/h5stat/testfiles/h5stat_newgrat.ddl b/tools/h5stat/testfiles/h5stat_newgrat.ddl
index 228d565..6881ca9 100644
--- a/tools/h5stat/testfiles/h5stat_newgrat.ddl
+++ b/tools/h5stat/testfiles/h5stat_newgrat.ddl
@@ -9,7 +9,6 @@ File information
 	# of unique links: 0
 	# of unique other: 0
 	Max. # of links to object: 1
-	Max. depth of hierarchy: 1
 	Max. # of objects in group: 351
 Object header size: (total/unused)
 	Groups: 51597/32292
diff --git a/tools/h5stat/testfiles/h5stat_tsohm.ddl b/tools/h5stat/testfiles/h5stat_tsohm.ddl
index 572965e..15a058e 100644
--- a/tools/h5stat/testfiles/h5stat_tsohm.ddl
+++ b/tools/h5stat/testfiles/h5stat_tsohm.ddl
@@ -9,7 +9,6 @@ File information
 	# of unique links: 0
 	# of unique other: 0
 	Max. # of links to object: 1
-	Max. depth of hierarchy: 0
 	Max. # of objects in group: 2
 Object header size: (total/unused)
 	Groups: 51/2
diff --git a/tools/lib/h5tools_ref.c b/tools/lib/h5tools_ref.c
index 123065b..de1e2c3 100644
--- a/tools/lib/h5tools_ref.c
+++ b/tools/lib/h5tools_ref.c
@@ -20,6 +20,7 @@
 #include "H5SLprivate.h"
 #include "h5tools.h"
 #include "h5tools_utils.h"
+#include "h5trav.h"
 
 
 /*
@@ -42,15 +43,12 @@ typedef struct {
 } ref_path_node_t;
 
 static H5SL_t *ref_path_table = NULL;   /* the "table" (implemented with a skip list) */
-static hid_t thefile;
+static hid_t thefile = (-1);
 
 extern char  *progname;
 extern int   d_status;
 
 static int ref_path_table_put(const char *, haddr_t objno);
-static hbool_t ref_path_table_find(haddr_t objno);
-static herr_t fill_ref_path_table_cb(hid_t group, const char *obj_name,
-    const H5L_info_t *linfo, void *op_data);
 
 /*-------------------------------------------------------------------------
  * Function:    free_ref_path_info
@@ -77,6 +75,61 @@ free_ref_path_info(void *item, void UNUSED *key, void UNUSED *operator_data/*in,
 }
 
 /*-------------------------------------------------------------------------
+ * Function:    init_ref_path_cb
+ *
+ * Purpose:     Called by interator to create references for
+ *              all objects and enter them in the table.
+ *
+ * Return:      Error status.
+ *
+ * Programmer:  REMcG
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+init_ref_path_cb(const char *obj_name, const H5O_info_t *oinfo,
+    const char *already_seen, void UNUSED *_udata)
+{
+    /* Check if the object is already in the path table */
+    if(NULL == already_seen) {
+        /* Insert the object into the path table */
+        ref_path_table_put(obj_name, oinfo->addr);
+    } /* end if */
+
+    return 0;
+}
+
+/*-------------------------------------------------------------------------
+ * Function:    init_ref_path_table
+ *
+ * Purpose:     Initalize the reference path table
+ *
+ * Return:      Non-negative on success, negative on failure
+ *
+ * Programmer:  Quincey Koziol
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+init_ref_path_table(void)
+{
+    /* Sanity check */
+    HDassert(thefile > 0);
+
+    /* Create skip list to store reference path information */
+    if((ref_path_table = H5SL_create(H5SL_TYPE_HADDR, 0.5, (size_t)16))==NULL)
+        return (-1);
+
+    /* Iterate over objects in this file */
+    if(h5trav_visit(thefile, "/", TRUE, TRUE, init_ref_path_cb, NULL, NULL) < 0) {
+        error_msg(progname, "unable to construct reference path table\n");
+        d_status = EXIT_FAILURE;
+    } /* end if */
+
+    return(0);
+}
+
+/*-------------------------------------------------------------------------
  * Function:    term_ref_path_table
  *
  * Purpose:     Terminate the reference path table
@@ -137,39 +190,11 @@ ref_path_table_lookup(const char *thepath)
     if(H5Oget_info_by_name(thefile, thepath, &oi, H5P_DEFAULT) < 0)
         return HADDR_UNDEF;
 
-    /* All existing objects in the file had better be in the table */
-    HDassert(ref_path_table_find(oi.addr));
-
     /* Return OID */
     return(oi.addr);
 }
 
 /*-------------------------------------------------------------------------
- * Function:    ref_path_table_find
- *
- * Purpose:     Looks up a table entry given a object number.
- *              Used during construction of the table.
- *
- * Return:      TRUE/FALSE on success, can't fail
- *
- * Programmer:  Quincey Koziol
- *
- * Modifications:
- *
- *-------------------------------------------------------------------------
- */
-static hbool_t
-ref_path_table_find(haddr_t objno)
-{
-    HDassert(ref_path_table);
-
-    if(H5SL_search(ref_path_table, &objno) == NULL)
-        return FALSE;
-    else
-        return TRUE;
-}
-
-/*-------------------------------------------------------------------------
  * Function:    ref_path_table_put
  *
  * Purpose:     Enter the 'obj' with 'path' in the table (assumes its not
@@ -200,7 +225,7 @@ ref_path_table_put(const char *path, haddr_t objno)
         return(-1);
 
     new_node->objno = objno;
-    new_node->path = path;
+    new_node->path = HDstrdup(path);
 
     return(H5SL_insert(ref_path_table, new_node, &(new_node->objno)));
 }
@@ -237,17 +262,17 @@ get_fake_xid (void) {
 haddr_t
 ref_path_table_gen_fake(const char *path)
 {
-    const char *dup_path;
     haddr_t fake_objno;
 
-    if((dup_path = HDstrdup(path)) == NULL)
-        return HADDR_UNDEF;
-
     /* Generate fake ID for string */
     fake_objno = get_fake_xid();
 
-    /* Insert "fake" object into table (takes ownership of path) */
-    ref_path_table_put(dup_path, fake_objno);
+    /* Create ref path table, if it hasn't already been created */
+    if(ref_path_table == NULL)
+        init_ref_path_table();
+
+    /* Insert "fake" object into table */
+    ref_path_table_put(path, fake_objno);
 
     return(fake_objno);
 }
@@ -271,74 +296,19 @@ lookup_ref_path(haddr_t ref)
     ref_path_node_t *node;
 
     /* Be safer for h5ls */
-    if(!ref_path_table)
+    if(thefile < 0)
         return(NULL);
 
+    /* Create ref path table, if it hasn't already been created */
+    if(ref_path_table == NULL)
+        init_ref_path_table();
+
     node = H5SL_search(ref_path_table, &ref);
 
     return(node ? node->path : NULL);
 }
 
 /*-------------------------------------------------------------------------
- * Function:    fill_ref_path_table_cb
- *
- * Purpose:     Called by interator to create references for
- *              all objects and enter them in the table.
- *
- * Return:      Error status.
- *
- * Programmer:  REMcG
- *
- * Modifications:
- *
- *-------------------------------------------------------------------------
- */
-static herr_t
-fill_ref_path_table_cb(hid_t group, const char *obj_name, const H5L_info_t *linfo,
-    void *op_data)
-{
-    if(linfo->type == H5L_TYPE_HARD) {
-        H5O_info_t              oinfo;
-
-        H5Oget_info_by_name(group, obj_name, &oinfo, H5P_DEFAULT);
-
-        /* Check if the object is already in the path table */
-        if(!ref_path_table_find(oinfo.addr)) {
-            const char *obj_prefix = (const char *)op_data;
-            size_t                  tmp_len;
-            char                   *thepath;
-
-            /* Compute length for this object's path */
-            tmp_len = HDstrlen(obj_prefix) + HDstrlen(obj_name) + 2;
-
-            /* Allocate room for the path for this object */
-            if((thepath = (char *)HDmalloc(tmp_len)) == NULL)
-                return FAIL;
-
-            /* Build the name for this object */
-            HDstrcpy(thepath, obj_prefix);
-            HDstrcat(thepath, "/");
-            HDstrcat(thepath, obj_name);
-
-            /* Insert the object into the path table (takes ownership of the path) */
-            ref_path_table_put(thepath, oinfo.addr);
-
-            if(oinfo.type == H5O_TYPE_GROUP) {
-                /* Iterate over objects in this group, using this group's
-                 * name as their prefix
-                 */
-                if(H5Literate_by_name(group, obj_name, H5_INDEX_NAME, H5_ITER_INC, NULL, fill_ref_path_table_cb, thepath, H5P_DEFAULT) < 0) {
-                    error_msg(progname, "unable to dump group \"%s\"\n", thepath);
-                    d_status = EXIT_FAILURE;
-                } /* end if */
-            } /* end if */
-        } /* end if */
-    } /* end if */
-
-    return 0;
-}
-
-/*-------------------------------------------------------------------------
  * Function:    fill_ref_path_table
  *
  * Purpose:     Called by interator to create references for
@@ -348,37 +318,15 @@ fill_ref_path_table_cb(hid_t group, const char *obj_name, const H5L_info_t *linf
  *
  * Programmer:  REMcG
  *
- * Modifications:
- *
  *-------------------------------------------------------------------------
  */
 herr_t
 fill_ref_path_table(hid_t fid)
 {
-    H5O_info_t              oinfo;
-    char                   *root_path;
-
     /* Set file ID for later queries (XXX: this should be fixed) */
     thefile = fid;
 
-    /* Create skip list to store reference path information */
-    if((ref_path_table = H5SL_create(H5SL_TYPE_HADDR, 0.5, (size_t)16))==NULL)
-        return (-1);
-
-    /* Build the name for root group */
-    root_path = HDstrdup("/");
-
-    /* Get info for root group */
-    H5Oget_info_by_name(fid, root_path, &oinfo, H5P_DEFAULT);
-
-    /* Insert the root group into the path table (takes ownership of path) */
-    ref_path_table_put(root_path, oinfo.addr);
-
-    /* Iterate over objects in this file */
-    if(H5Literate(fid, H5_INDEX_NAME, H5_ITER_INC, NULL, fill_ref_path_table_cb, (void *)"") < 0) {
-        error_msg(progname, "unable to dump root group\n");
-        d_status = EXIT_FAILURE;
-    } /* end if */
+    /* Defer creating the ref path table until it's needed */
 
     return 0;
 }
diff --git a/tools/lib/h5tools_utils.c b/tools/lib/h5tools_utils.c
index cb38e7a..512a3fb 100644
--- a/tools/lib/h5tools_utils.c
+++ b/tools/lib/h5tools_utils.c
@@ -30,6 +30,7 @@
 
 #include "h5tools_utils.h"
 #include "H5private.h"
+#include "h5trav.h"
 
 /* global variables */
 int   nCols = 80;
@@ -44,10 +45,7 @@ static void init_table(table_t **tbl);
 #ifdef H5DUMP_DEBUG
 static void dump_table(char* tablename, table_t *table);
 #endif  /* H5DUMP_DEBUG */
-static void add_obj(table_t *table, haddr_t objno, char *objname, hbool_t recorded);
-static char * build_obj_path_name(const char *prefix, const char *name);
-static herr_t find_objs_cb(hid_t group, const char *name, const H5L_info_t *info,
-    void *op_data);
+static void add_obj(table_t *table, haddr_t objno, const char *objname, hbool_t recorded);
 
 
 /*-------------------------------------------------------------------------
@@ -428,44 +426,15 @@ search_obj(table_t *table, haddr_t objno)
 {
     unsigned u;
 
-    for (u = 0; u < table->nobjs; u++)
-        if (table->objs[u].objno == objno)
-        return &(table->objs[u]);
+    for(u = 0; u < table->nobjs; u++)
+        if(table->objs[u].objno == objno)
+            return &(table->objs[u]);
 
     return NULL;
 }
 
 
 /*-------------------------------------------------------------------------
- * Function:    build_obj_path_name
- *
- * Purpose:     Allocate space & build path name from prefix & name
- *
- * Return:      Success:    SUCCEED
- *
- *              Failure:    FAIL
- *
- * Programmer:  Quincey Koziol
- *
- * Modifications:
- *
- *-------------------------------------------------------------------------
- */
-static char *
-build_obj_path_name(const char *prefix, const char *name)
-{
-    char *path;
-
-    path = HDmalloc(HDstrlen(prefix) + HDstrlen(name) + 2);
-    HDstrcpy(path, prefix);
-    HDstrcat(path,"/");
-    HDstrcat(path,name); /* absolute name of the data set */
-
-    return(path);
-} /* end build_obj_path_name() */
-
-
-/*-------------------------------------------------------------------------
  * Function:    find_objs_cb
  *
  * Purpose:     Callback to find objects, committed types and store them in tables
@@ -481,90 +450,65 @@ build_obj_path_name(const char *prefix, const char *name)
  *-------------------------------------------------------------------------
  */
 static herr_t
-find_objs_cb(hid_t group, const char *name, const H5L_info_t UNUSED *linfo, void *op_data)
+find_objs_cb(const char *name, const H5O_info_t *oinfo, const char *already_seen,
+    void *op_data)
 {
-    H5O_info_t oinfo;
     find_objs_t *info = (find_objs_t*)op_data;
     herr_t ret_value = 0;
 
-    if(H5Oget_info_by_name(group, name, &oinfo, H5P_DEFAULT) < 0)
-        ;     /* keep going */
-    else {
-        switch(oinfo.type) {
-            char   *tmp;
-            size_t tmp_len;
-
-            case H5O_TYPE_GROUP:
-                if(search_obj(info->group_table, oinfo.addr) == NULL) {
-                    char *old_prefix;
+    switch(oinfo->type) {
+        case H5O_TYPE_GROUP:
+            if(NULL == already_seen)
+                add_obj(info->group_table, oinfo->addr, name, TRUE);
+            break;
 
-                    tmp = build_obj_path_name(info->prefix, name);
-                    add_obj(info->group_table, oinfo.addr, tmp, TRUE);
+        case H5O_TYPE_DATASET:
+            if(NULL == already_seen) {
+                hid_t dset;
 
-                    old_prefix = info->prefix;
-                    tmp_len = HDstrlen(tmp);
-                    info->prefix = HDmalloc(tmp_len+1);
-                    HDstrcpy(info->prefix, tmp);
+                /* Add the dataset to the list of objects */
+                add_obj(info->dset_table, oinfo->addr, name, TRUE);
 
-                    if(H5Literate_by_name(group, name, H5_INDEX_NAME, H5_ITER_INC, NULL, find_objs_cb, (void *)info, H5P_DEFAULT) < 0)
-                        ret_value = FAIL;
+                /* Check for a dataset that uses a named datatype */
+                if((dset = H5Dopen2(info->fid, name, H5P_DEFAULT)) >= 0) {
+                    hid_t type = H5Dget_type(dset);
 
-                    info->prefix = old_prefix;
-                } /* end if */
-                break;
-
-            case H5O_TYPE_DATASET:
-                if(search_obj(info->dset_table, oinfo.addr) == NULL) {
-                    hid_t dset;
-
-                    tmp = build_obj_path_name(info->prefix, name);
-                    add_obj(info->dset_table, oinfo.addr, tmp, TRUE);
-
-                    if((dset = H5Dopen2(group, name, H5P_DEFAULT)) >= 0) {
-                        hid_t type;
+                    if(H5Tcommitted(type) > 0) {
+                        H5O_info_t type_oinfo;
 
-                        type = H5Dget_type(dset);
-
-                        if(H5Tcommitted(type) > 0) {
-                            H5Oget_info(type, &oinfo);
-                            if(search_obj(info->type_table, oinfo.addr) == NULL) {
-                                char *type_name = HDstrdup(tmp);
-
-                                add_obj(info->type_table, oinfo.addr, type_name, FALSE);
-                            } /* end if */
-                        } /* end if */
-
-                        H5Tclose(type);
-                        H5Dclose(dset);
+                        H5Oget_info(type, &type_oinfo);
+                        if(search_obj(info->type_table, type_oinfo.addr) == NULL)
+                            add_obj(info->type_table, type_oinfo.addr, name, FALSE);
                     } /* end if */
-                    else
-                        ret_value = FAIL;
-                } /* end if */
-                break;
 
-            case H5O_TYPE_NAMED_DATATYPE:
-            {
-                obj_t *found_obj;
-
-                tmp = build_obj_path_name(info->prefix, name);
-                if((found_obj = search_obj(info->type_table, oinfo.addr)) == NULL)
-                    add_obj(info->type_table, oinfo.addr, tmp, TRUE);
-                else {
-                    /* Use latest version of name */
-                    HDfree(found_obj->objname);
-                    found_obj->objname = HDstrdup(tmp);
-
-                    /* Mark named datatype as having valid name */
-                    found_obj->recorded = TRUE;
-                } /* end else */
-                break;
-            }
-
-            default:
-                /* Ignore links, etc. */
-                break;
+                    H5Tclose(type);
+                    H5Dclose(dset);
+                } /* end if */
+                else
+                    ret_value = FAIL;
+            } /* end if */
+            break;
+
+        case H5O_TYPE_NAMED_DATATYPE:
+        {
+            obj_t *found_obj;
+
+            if((found_obj = search_obj(info->type_table, oinfo->addr)) == NULL)
+                add_obj(info->type_table, oinfo->addr, name, TRUE);
+            else {
+                /* Use latest version of name */
+                HDfree(found_obj->objname);
+                found_obj->objname = HDstrdup(name);
+
+                /* Mark named datatype as having valid name */
+                found_obj->recorded = TRUE;
+            } /* end else */
+            break;
         }
-    } /* end else */
+
+        default:
+            break;
+    } /* end switch */
 
     return ret_value;
 }
@@ -589,31 +533,19 @@ herr_t
 init_objs(hid_t fid, find_objs_t *info, table_t **group_table,
     table_t **dset_table, table_t **type_table)
 {
-    H5O_info_t oinfo;
-
     /* Initialize the tables */
     init_table(group_table);
     init_table(dset_table);
     init_table(type_table);
 
     /* Init the find_objs_t */
-    info->prefix = HDcalloc(1, 1);
+    info->fid = fid;
     info->group_table = *group_table;
     info->type_table = *type_table;
     info->dset_table = *dset_table;
 
-    /* add the root group as an object, it may have hard links to it */
-    if(H5Oget_info(fid, &oinfo) < 0)
-        return FAIL;
-    else {
-        /* call with an empty string, it appends '/' group separator */
-        char *tmp = build_obj_path_name(info->prefix, "");
-
-        add_obj(info->group_table, oinfo.addr, tmp, TRUE);
-    } /* end else */
-
     /* Find all shared objects */
-    return(H5Literate(fid, H5_INDEX_NAME, H5_ITER_INC, NULL, find_objs_cb, (void *)info));
+    return(h5trav_visit(fid, "/", TRUE, TRUE, find_objs_cb, NULL, info));
 }
 
 
@@ -632,22 +564,22 @@ init_objs(hid_t fid, find_objs_t *info, table_t **group_table,
  *-------------------------------------------------------------------------
  */
 static void
-add_obj(table_t *table, haddr_t objno, char *objname, hbool_t record)
+add_obj(table_t *table, haddr_t objno, const char *objname, hbool_t record)
 {
     unsigned u;
 
     /* See if we need to make table larger */
-    if (table->nobjs == table->size) {
+    if(table->nobjs == table->size) {
         table->size *= 2;
-        table->objs = HDrealloc(table->objs, table->size * sizeof(obj_t));
-    }
+        table->objs = HDrealloc(table->objs, table->size * sizeof(table->objs[0]));
+    } /* end if */
 
     /* Increment number of objects in table */
     u = table->nobjs++;
 
     /* Set information about object */
     table->objs[u].objno = objno;
-    table->objs[u].objname = objname;
+    table->objs[u].objname = HDstrdup(objname);
     table->objs[u].recorded = record;
     table->objs[u].displayed = 0;
 }
diff --git a/tools/lib/h5tools_utils.h b/tools/lib/h5tools_utils.h
index e604e5a..e7b175c 100644
--- a/tools/lib/h5tools_utils.h
+++ b/tools/lib/h5tools_utils.h
@@ -95,7 +95,7 @@ typedef struct table_t {
 
 /*this struct stores the information that is passed to the find_objs function*/
 typedef struct find_objs_t {
-    char *prefix;
+    hid_t fid;
     table_t *group_table;
     table_t *type_table;
     table_t *dset_table;
diff --git a/tools/lib/h5trav.c b/tools/lib/h5trav.c
index 97de021..14ced60 100644
--- a/tools/lib/h5trav.c
+++ b/tools/lib/h5trav.c
@@ -24,24 +24,25 @@
 typedef struct trav_addr_t {
     size_t      nalloc;
     size_t      nused;
-    haddr_t     *addrs;
+    struct {
+        haddr_t addr;
+        char *path;
+    } *objs;
 } trav_addr_t;
 
 typedef struct {
-    herr_t (*visit_obj)(const char *path_name, const H5O_info_t *oinfo, hbool_t already_visited, void *udata);
-    herr_t (*visit_lnk)(const char *path_name, const H5L_info_t *linfo, void *udata);
+    h5trav_obj_func_t visit_obj;        /* Callback for visiting objects */
+    h5trav_lnk_func_t visit_lnk;        /* Callback for visiting links */
     void *udata;                /* User data to pass to callbacks */
 } trav_visitor_t;
 
 typedef struct {
     trav_addr_t *seen;              /* List of addresses seen already */
-    const char *curr_path;          /* Current path to parent group */
     const trav_visitor_t *visitor;  /* Information for visiting each link/object */
 } trav_ud_traverse_t;
 
 typedef struct {
     hid_t fid;                      /* File ID being traversed */
-    trav_table_t *table;            /* Table for tracking name of objects with >1 hard link */
 } trav_print_udata_t;
 
 /*-------------------------------------------------------------------------
@@ -52,10 +53,8 @@ static void trav_table_add(trav_table_t *table,
                         const char *objname,
                         const H5O_info_t *oinfo);
 
-static size_t trav_table_search(const trav_table_t *table, haddr_t objno);
-
 static void trav_table_addlink(trav_table_t *table,
-                        size_t j /* the object index */,
+                        haddr_t objno,
                         const char *path);
 
 /*-------------------------------------------------------------------------
@@ -78,19 +77,20 @@ static void trav_table_addlink(trav_table_t *table,
  *-------------------------------------------------------------------------
  */
 static void
-trav_addr_add(trav_addr_t *visited, haddr_t addr)
+trav_addr_add(trav_addr_t *visited, haddr_t addr, const char *path)
 {
     size_t idx;         /* Index of address to use */
 
     /* Allocate space if necessary */
     if(visited->nused == visited->nalloc) {
         visited->nalloc = MAX(1, visited->nalloc * 2);;
-        visited->addrs = (haddr_t *)HDrealloc(visited->addrs, visited->nalloc * sizeof(haddr_t));
+        visited->objs = HDrealloc(visited->objs, visited->nalloc * sizeof(visited->objs[0]));
     } /* end if */
 
     /* Append it */
     idx = visited->nused++;
-    visited->addrs[idx] = addr;
+    visited->objs[idx].addr = addr;
+    visited->objs[idx].path = HDstrdup(path);
 } /* end trav_addr_add() */
 
 
@@ -107,7 +107,7 @@ trav_addr_add(trav_addr_t *visited, haddr_t addr)
  *
  *-------------------------------------------------------------------------
  */
-static hbool_t
+static const char *
 trav_addr_visited(trav_addr_t *visited, haddr_t addr)
 {
     size_t u;           /* Local index variable */
@@ -115,11 +115,11 @@ trav_addr_visited(trav_addr_t *visited, haddr_t addr)
     /* Look for address */
     for(u = 0; u < visited->nused; u++)
         /* Check for address already in array */
-        if(visited->addrs[u] == addr)
-            return(TRUE);
+        if(visited->objs[u].addr == addr)
+            return(visited->objs[u].path);
 
     /* Didn't find address */
-    return(FALSE);
+    return(NULL);
 } /* end trav_addr_visited() */
 
 
@@ -135,68 +135,44 @@ trav_addr_visited(trav_addr_t *visited, haddr_t addr)
  *-------------------------------------------------------------------------
  */
 static herr_t
-traverse_cb(hid_t loc_id, const char *link_name, const H5L_info_t *linfo,
+traverse_cb(hid_t loc_id, const char *path, const H5L_info_t *linfo,
     void *_udata)
 {
     trav_ud_traverse_t *udata = (trav_ud_traverse_t *)_udata;     /* User data */
-    hbool_t is_group = FALSE;           /* If the object is a group */
-    hbool_t already_visited = FALSE;    /* Whether the link/object was already visited */
-    char *link_path;            /* Full path name of a link */
+    char *full_name;
+    const char *already_visited = NULL; /* Whether the link/object was already visited */
 
-    /* Construct the full path name of this link */
-    link_path = (char*)HDmalloc(HDstrlen(udata->curr_path) + HDstrlen(link_name) + 2);
-    HDassert(link_path);
-    HDstrcpy(link_path, udata->curr_path);
-    HDstrcat(link_path, "/");
-    HDstrcat(link_path, link_name);
+    /* Create the full path name for the link */
+    full_name = HDmalloc(HDstrlen(path) + 2);
+    *full_name = '/';
+    HDstrcpy(full_name + 1, path);
 
     /* Perform the correct action for different types of links */
     if(linfo->type == H5L_TYPE_HARD) {
         H5O_info_t oinfo;
 
         /* Get information about the object */
-        if(H5Oget_info_by_name(loc_id, link_name, &oinfo, H5P_DEFAULT) < 0)
+        if(H5Oget_info_by_name(loc_id, path, &oinfo, H5P_DEFAULT) < 0)
             return(H5_ITER_ERROR);
 
         /* If the object has multiple links, add it to the list of addresses
          *  already visited, if it isn't there already
          */
-        if(oinfo.rc > 1) {
-            already_visited = trav_addr_visited(udata->seen, oinfo.addr);
-            if(!already_visited)
-                trav_addr_add(udata->seen, oinfo.addr);
-        } /* end if */
-
-        /* Check if object is a group, for later */
-        is_group = (oinfo.type == H5O_TYPE_GROUP) ? TRUE : FALSE;
+        if(oinfo.rc > 1)
+            if(NULL == (already_visited = trav_addr_visited(udata->seen, oinfo.addr)))
+                trav_addr_add(udata->seen, oinfo.addr, full_name);
 
         /* Make 'visit object' callback */
         if(udata->visitor->visit_obj)
-            (*udata->visitor->visit_obj)(link_path, &oinfo, already_visited, udata->visitor->udata);
+            (*udata->visitor->visit_obj)(full_name, &oinfo, already_visited, udata->visitor->udata);
     } /* end if */
     else {
         /* Make 'visit link' callback */
         if(udata->visitor->visit_lnk)
-            (*udata->visitor->visit_lnk)(link_path, linfo, udata->visitor->udata);
+            (*udata->visitor->visit_lnk)(full_name, linfo, udata->visitor->udata);
     } /* end else */
 
-    /* Check for group that we haven't visited yet & recurse */
-    if(is_group && !already_visited) {
-        const char *prev_path = udata->curr_path;     /* Previous path to link's parent group */
-
-        /* Set current path to this object */
-        udata->curr_path = link_path;
-
-        /* Iterate over all links in group object */
-        if(H5Literate_by_name(loc_id, link_name, H5_INDEX_NAME, H5_ITER_INC, NULL, traverse_cb, udata, H5P_DEFAULT) < 0)
-            return(H5_ITER_ERROR);
-
-        /* Restore path in udata */
-        udata->curr_path = prev_path;
-    } /* end if */
-
-    /* Free path name for current link/object */
-    HDfree(link_path);
+    HDfree(full_name);
 
     return(H5_ITER_CONT);
 } /* end traverse_cb() */
@@ -217,39 +193,58 @@ traverse_cb(hid_t loc_id, const char *link_name, const H5L_info_t *linfo,
  *-------------------------------------------------------------------------
  */
 static int
-traverse(hid_t file_id, const trav_visitor_t *visitor)
+traverse(hid_t file_id, const char *grp_name, hbool_t visit_start,
+    hbool_t recurse, const trav_visitor_t *visitor)
 {
-    H5O_info_t  oinfo;          /* Object info for root group */
-    trav_addr_t seen;           /* List of addresses seen */
-    trav_ud_traverse_t udata;   /* User data for iteration callback */
+    H5O_info_t  oinfo;          /* Object info for starting group */
 
-    /* Get info for root group */
-    if(H5Oget_info(file_id, &oinfo) < 0)
+    /* Get info for starting object */
+    if(H5Oget_info_by_name(file_id, grp_name, &oinfo, H5P_DEFAULT) < 0)
         return -1;
 
-    /* Visit the root group of the file */
-    (*visitor->visit_obj)("/", &oinfo, FALSE, visitor->udata);
+    /* Visit the starting object */
+    if(visit_start && visitor->visit_obj)
+        (*visitor->visit_obj)(grp_name, &oinfo, NULL, visitor->udata);
 
-    /* Init addresses seen */
-    seen.nused = seen.nalloc = 0;
-    seen.addrs = NULL;
+    /* Go visiting, if the object is a group */
+    if(oinfo.type == H5O_TYPE_GROUP) {
+        trav_addr_t seen;           /* List of addresses seen */
+        trav_ud_traverse_t udata;   /* User data for iteration callback */
 
-    /* Check for multiple links to root group */
-    if(oinfo.rc > 1)
-        trav_addr_add(&seen, oinfo.addr);
+        /* Init addresses seen */
+        seen.nused = seen.nalloc = 0;
+        seen.objs = NULL;
 
-    /* Set up user data structure */
-    udata.seen = &seen;
-    udata.curr_path = "";
-    udata.visitor = visitor;
+        /* Check for multiple links to top group */
+        if(oinfo.rc > 1)
+            trav_addr_add(&seen, oinfo.addr, grp_name);
 
-    /* Iterate over all links in root group */
-    if(H5Literate(file_id, H5_INDEX_NAME, H5_ITER_INC, NULL, traverse_cb, &udata) < 0)
-        return -1;
+        /* Set up user data structure */
+        udata.seen = &seen;
+        udata.visitor = visitor;
 
-    /* Free visited addresses table */
-    if(seen.addrs)
-        HDfree(seen.addrs);
+        /* Check for iteration of links vs. visiting all links recursively */
+        if(recurse) {
+            /* Visit all links in group, recursively */
+            if(H5Lvisit_by_name(file_id, grp_name, H5_INDEX_NAME, H5_ITER_INC, traverse_cb, &udata, H5P_DEFAULT) < 0)
+                return -1;
+        } /* end if */
+        else {
+            /* Iterate over links in group */
+            if(H5Literate_by_name(file_id, grp_name, H5_INDEX_NAME, H5_ITER_INC, NULL, traverse_cb, &udata, H5P_DEFAULT) < 0)
+                return -1;
+        } /* end else */
+
+        /* Free visited addresses table */
+        if(seen.objs) {
+            size_t u;       /* Local index variable */
+
+            /* Free paths to objects */
+            for(u = 0; u < seen.nused; u++)
+                HDfree(seen.objs[u].path);
+            HDfree(seen.objs);
+        } /* end if */
+    } /* end if */
 
     return 0;
 }
@@ -301,7 +296,7 @@ trav_info_add(trav_info_t *info, const char *path, h5trav_type_t obj_type)
  */
 static int
 trav_info_visit_obj(const char *path, const H5O_info_t *oinfo,
-    hbool_t UNUSED already_visited, void *udata)
+    const char UNUSED *already_visited, void *udata)
 {
     /* Add the object to the 'info' struct */
     /* (object types map directly to "traversal" types) */
@@ -359,7 +354,7 @@ h5trav_getinfo(hid_t file_id, trav_info_t *info)
     info_visitor.udata = info;
 
     /* Traverse all objects in the file, visiting each object & link */
-    if(traverse(file_id, &info_visitor) < 0)
+    if(traverse(file_id, "/", TRUE, TRUE, &info_visitor) < 0)
         return -1;
 
     return 0;
@@ -470,24 +465,17 @@ trav_info_free(trav_info_t *info)
  */
 static int
 trav_table_visit_obj(const char *path, const H5O_info_t *oinfo,
-    hbool_t already_visited, void *udata)
+    const char *already_visited, void *udata)
 {
     trav_table_t *table = (trav_table_t *)udata;
 
     /* Check if we've already seen this object */
-    if(!already_visited)
+    if(NULL == already_visited)
         /* add object to table */
         trav_table_add(table, path, oinfo);
-    else {
-        size_t found;           /* Index of original object seen */
-
-        /* Look for object in existing table */
-        found = trav_table_search(table, oinfo->addr);
-        HDassert(found < table->nobjs);
-
+    else
         /* Add alias for object to table */
-        trav_table_addlink(table, found, path);
-    } /* end else */
+        trav_table_addlink(table, oinfo->addr, path);
 
     return(0);
 } /* end trav_table_visit_obj() */
@@ -541,7 +529,7 @@ h5trav_gettable(hid_t fid, trav_table_t *table)
     table_visitor.udata = table;
 
     /* Traverse all objects in the file, visiting each object & link */
-    if(traverse(fid, &table_visitor) < 0)
+    if(traverse(fid, "/", TRUE, TRUE, &table_visitor) < 0)
         return -1;
     return 0;
 }
@@ -670,25 +658,33 @@ trav_table_add(trav_table_t *table,
  */
 
 static void
-trav_table_addlink(trav_table_t *table,
-                        size_t j /* the object index */,
-                        const char *path)
+trav_table_addlink(trav_table_t *table, haddr_t objno, const char *path)
 {
-    size_t new;
+    size_t i;           /* Local index variable */
 
-    /* already inserted */
-    if(HDstrcmp(table->objs[j].name, path) == 0)
-        return;
+    for(i = 0; i < table->nobjs; i++) {
+        if(table->objs[i].objno == objno) {
+            size_t n;
 
-    /* allocate space if necessary */
-    if(table->objs[j].nlinks == (unsigned)table->objs[j].sizelinks) {
-        table->objs[j].sizelinks = MAX(1, table->objs[j].sizelinks * 2);
-        table->objs[j].links = (trav_link_t*)HDrealloc(table->objs[j].links, table->objs[j].sizelinks * sizeof(trav_link_t));
-    } /* end if */
+            /* already inserted? */
+            if(HDstrcmp(table->objs[i].name, path) == 0)
+                return;
+
+            /* allocate space if necessary */
+            if(table->objs[i].nlinks == (unsigned)table->objs[i].sizelinks) {
+                table->objs[i].sizelinks = MAX(1, table->objs[i].sizelinks * 2);
+                table->objs[i].links = (trav_link_t*)HDrealloc(table->objs[i].links, table->objs[i].sizelinks * sizeof(trav_link_t));
+            } /* end if */
 
-    /* insert it */
-    new = table->objs[j].nlinks++;
-    table->objs[j].links[new].new_name = (char *)HDstrdup(path);
+            /* insert it */
+            n = table->objs[i].nlinks++;
+            table->objs[i].links[n].new_name = (char *)HDstrdup(path);
+
+            return;
+        } /* end for */
+    } /* end for */
+
+    HDassert(0 && "object not in table?!?");
 }
 
 
@@ -809,10 +805,8 @@ void trav_table_free( trav_table_t *table )
  */
 static int
 trav_print_visit_obj(const char *path, const H5O_info_t *oinfo,
-    hbool_t already_visited, void *udata)
+    const char *already_visited, void UNUSED *udata)
 {
-    trav_print_udata_t *print_udata = (trav_print_udata_t *)udata;
-
     /* Print the name of the object */
     /* (no new-line, so that objects that we've encountered before can print
      *  the name of the original object)
@@ -836,26 +830,12 @@ trav_print_visit_obj(const char *path, const H5O_info_t *oinfo,
     } /* end switch */
 
     /* Check if we've already seen this object */
-    if(!already_visited) {
+    if(NULL == already_visited)
         /* Finish printing line about object */
         printf("\n");
-
-        /* Check if we will encounter another hard link to this object */
-        if(oinfo->rc > 1) {
-            /* Add object to table */
-            trav_table_add(print_udata->table, path, oinfo);
-        } /* end if */
-    } /* end if */
-    else {
-        size_t found;           /* Index of original object seen */
-
-        /* Locate object in table */
-        found = trav_table_search(print_udata->table, oinfo->addr);
-        HDassert(found < print_udata->table->nobjs);
-
-        /* Print the link's destination */
-        printf(" -> %s\n", print_udata->table->objs[found].name);
-    } /* end else */
+    else
+        /* Print the link's original name */
+        printf(" -> %s\n", already_visited);
 
     return(0);
 } /* end trav_print_visit_obj() */
@@ -938,16 +918,11 @@ trav_print_visit_lnk(const char *path, const H5L_info_t *linfo, void *udata)
 int
 h5trav_print(hid_t fid)
 {
-    trav_table_t *table = NULL;         /* Table for objects w/multiple hard links */
     trav_print_udata_t print_udata;     /* User data for traversal */
     trav_visitor_t print_visitor;       /* Visitor structure for printing objects */
 
-    /* Initialize the table */
-    trav_table_init(&table);
-
     /* Init user data for printing */
     print_udata.fid = fid;
-    print_udata.table = table;
 
     /* Init visitor structure */
     print_visitor.visit_obj = trav_print_visit_obj;
@@ -955,11 +930,42 @@ h5trav_print(hid_t fid)
     print_visitor.udata = &print_udata;
 
     /* Traverse all objects in the file, visiting each object & link */
-    if(traverse(fid, &print_visitor) < 0)
+    if(traverse(fid, "/", TRUE, TRUE, &print_visitor) < 0)
         return -1;
 
-    /* Free table */
-    trav_table_free(table);
+    return 0;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: h5trav_visit
+ *
+ * Purpose: Generic traversal routine for visiting objects and links
+ *
+ * Return: 0, -1 on error
+ *
+ * Programmer: Quincey Koziol, koziol@hdfgroup.org
+ *
+ * Date: November 6, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+
+int
+h5trav_visit(hid_t fid, const char *grp_name, hbool_t visit_start,
+    hbool_t recurse, h5trav_obj_func_t visit_obj, h5trav_lnk_func_t visit_lnk,
+    void *udata)
+{
+    trav_visitor_t visitor;             /* Visitor structure for objects */
+
+    /* Init visitor structure */
+    visitor.visit_obj = visit_obj;
+    visitor.visit_lnk = visit_lnk;
+    visitor.udata = udata;
+
+    /* Traverse all objects in the file, visiting each object & link */
+    if(traverse(fid, grp_name, visit_start, recurse, &visitor) < 0)
+        return -1;
 
     return 0;
 }
diff --git a/tools/lib/h5trav.h b/tools/lib/h5trav.h
index 05bc3cb..5c07331 100644
--- a/tools/lib/h5trav.h
+++ b/tools/lib/h5trav.h
@@ -18,6 +18,12 @@
 
 #include "hdf5.h"
 
+/* Typedefs for visiting objects */
+typedef herr_t (*h5trav_obj_func_t)(const char *path_name, const H5O_info_t *oinfo,
+        const char *first_seen, void *udata);
+typedef herr_t (*h5trav_lnk_func_t)(const char *path_name, const H5L_info_t *linfo,
+        void *udata);
+
 /*-------------------------------------------------------------------------
  * public enum to specify type of an object
  * the TYPE can be:
@@ -101,6 +107,14 @@ extern "C" {
 #endif
 
 /*-------------------------------------------------------------------------
+ * "h5trav general" public functions
+ *-------------------------------------------------------------------------
+ */
+int h5trav_visit(hid_t file_id, const char *grp_name, hbool_t visit_start,
+    hbool_t recurse, h5trav_obj_func_t visit_obj, h5trav_lnk_func_t visit_lnk,
+    void *udata);
+
+/*-------------------------------------------------------------------------
  * "h5trav info" public functions
  *-------------------------------------------------------------------------
  */
diff --git a/tools/testfiles/h5copytst.out.ls b/tools/testfiles/h5copytst.out.ls
index c4d1778..785c3f0 100644
--- a/tools/testfiles/h5copytst.out.ls
+++ b/tools/testfiles/h5copytst.out.ls
@@ -2,6 +2,9 @@
 Expected output for 'h5ls ../testfiles/h5copytst.out.h5'
 #############################
 Opened "../testfiles/h5copytst.out.h5" with sec2 driver.
+/                        Group
+    Location:  1:96
+    Links:     1
 /A                       Group
     Location:  1:90344
     Links:     1
diff --git a/tools/testfiles/h5mkgrp_nested.ls b/tools/testfiles/h5mkgrp_nested.ls
index 2b9fb25..472656d 100644
--- a/tools/testfiles/h5mkgrp_nested.ls
+++ b/tools/testfiles/h5mkgrp_nested.ls
@@ -2,6 +2,9 @@
 Expected output for 'h5ls ../testfiles/h5mkgrp_nested.h5'
 #############################
 Opened "../testfiles/h5mkgrp_nested.h5" with sec2 driver.
+/                        Group
+    Location:  1:96
+    Links:     1
 /one                     Group
     Location:  1:800
     Links:     1
diff --git a/tools/testfiles/h5mkgrp_nested_latest.ls b/tools/testfiles/h5mkgrp_nested_latest.ls
index f0bab6f..c00292d 100644
--- a/tools/testfiles/h5mkgrp_nested_latest.ls
+++ b/tools/testfiles/h5mkgrp_nested_latest.ls
@@ -2,6 +2,10 @@
 Expected output for 'h5ls ../testfiles/h5mkgrp_nested_latest.h5'
 #############################
 Opened "../testfiles/h5mkgrp_nested_latest.h5" with sec2 driver.
+/                        Group
+    Location:  1:48
+    Links:     1
+    Modified:  XXXX-XX-XX XX:XX:XX XXX
 /one                     Group
     Location:  1:195
     Links:     1
diff --git a/tools/testfiles/h5mkgrp_nested_mult.ls b/tools/testfiles/h5mkgrp_nested_mult.ls
index 4fccd83..6a22ffd 100644
--- a/tools/testfiles/h5mkgrp_nested_mult.ls
+++ b/tools/testfiles/h5mkgrp_nested_mult.ls
@@ -2,6 +2,9 @@
 Expected output for 'h5ls ../testfiles/h5mkgrp_nested_mult.h5'
 #############################
 Opened "../testfiles/h5mkgrp_nested_mult.h5" with sec2 driver.
+/                        Group
+    Location:  1:96
+    Links:     1
 /one                     Group
     Location:  1:800
     Links:     1
diff --git a/tools/testfiles/h5mkgrp_nested_mult_latest.ls b/tools/testfiles/h5mkgrp_nested_mult_latest.ls
index 7835050..0b19ff9 100644
--- a/tools/testfiles/h5mkgrp_nested_mult_latest.ls
+++ b/tools/testfiles/h5mkgrp_nested_mult_latest.ls
@@ -2,6 +2,10 @@
 Expected output for 'h5ls ../testfiles/h5mkgrp_nested_mult_latest.h5'
 #############################
 Opened "../testfiles/h5mkgrp_nested_mult_latest.h5" with sec2 driver.
+/                        Group
+    Location:  1:48
+    Links:     1
+    Modified:  XXXX-XX-XX XX:XX:XX XXX
 /one                     Group
     Location:  1:195
     Links:     1
diff --git a/tools/testfiles/h5mkgrp_several.ls b/tools/testfiles/h5mkgrp_several.ls
index dcbe3eb..bbf5c92 100644
--- a/tools/testfiles/h5mkgrp_several.ls
+++ b/tools/testfiles/h5mkgrp_several.ls
@@ -2,6 +2,9 @@
 Expected output for 'h5ls ../testfiles/h5mkgrp_several.h5'
 #############################
 Opened "../testfiles/h5mkgrp_several.h5" with sec2 driver.
+/                        Group
+    Location:  1:96
+    Links:     1
 /one                     Group
     Location:  1:800
     Links:     1
diff --git a/tools/testfiles/h5mkgrp_several_latest.ls b/tools/testfiles/h5mkgrp_several_latest.ls
index c59107e..a3b5224 100644
--- a/tools/testfiles/h5mkgrp_several_latest.ls
+++ b/tools/testfiles/h5mkgrp_several_latest.ls
@@ -2,6 +2,10 @@
 Expected output for 'h5ls ../testfiles/h5mkgrp_several_latest.h5'
 #############################
 Opened "../testfiles/h5mkgrp_several_latest.h5" with sec2 driver.
+/                        Group
+    Location:  1:48
+    Links:     1
+    Modified:  XXXX-XX-XX XX:XX:XX XXX
 /one                     Group
     Location:  1:195
     Links:     1
diff --git a/tools/testfiles/h5mkgrp_single.ls b/tools/testfiles/h5mkgrp_single.ls
index 1f7e828..e9932f7 100644
--- a/tools/testfiles/h5mkgrp_single.ls
+++ b/tools/testfiles/h5mkgrp_single.ls
@@ -2,6 +2,9 @@
 Expected output for 'h5ls ../testfiles/h5mkgrp_single.h5'
 #############################
 Opened "../testfiles/h5mkgrp_single.h5" with sec2 driver.
+/                        Group
+    Location:  1:96
+    Links:     1
 /single                  Group
     Location:  1:800
     Links:     1
diff --git a/tools/testfiles/h5mkgrp_single_latest.ls b/tools/testfiles/h5mkgrp_single_latest.ls
index 7f5ee72..b6e6ea4 100644
--- a/tools/testfiles/h5mkgrp_single_latest.ls
+++ b/tools/testfiles/h5mkgrp_single_latest.ls
@@ -2,6 +2,10 @@
 Expected output for 'h5ls ../testfiles/h5mkgrp_single_latest.h5'
 #############################
 Opened "../testfiles/h5mkgrp_single_latest.h5" with sec2 driver.
+/                        Group
+    Location:  1:48
+    Links:     1
+    Modified:  XXXX-XX-XX XX:XX:XX XXX
 /latest                  Group
     Location:  1:195
     Links:     1
diff --git a/tools/testfiles/tall-2.ls b/tools/testfiles/tall-2.ls
index 5513214..2e4cd37 100644
--- a/tools/testfiles/tall-2.ls
+++ b/tools/testfiles/tall-2.ls
@@ -1,6 +1,7 @@
 #############################
  output for 'h5ls -w80 -r -d tall.h5'
 #############################
+/                        Group
 /g1                      Group
 /g1/g1.1                 Group
 /g1/g1.1/dset1.1.1       Dataset {10, 10}
diff --git a/tools/testfiles/tarray1.ls b/tools/testfiles/tarray1.ls
index 83a51a8..60c002d 100644
--- a/tools/testfiles/tarray1.ls
+++ b/tools/testfiles/tarray1.ls
@@ -1,6 +1,7 @@
 #############################
  output for 'h5ls -w80 -r -d tarray1.h5'
 #############################
+/                        Group
 /Dataset1                Dataset {4}
     Data:
         (0) [0,1,2,3], [10,11,12,13], [20,21,22,23], [30,31,32,33]
diff --git a/tools/testfiles/tattr2.ls b/tools/testfiles/tattr2.ls
index 88b24cd..0448868 100644
--- a/tools/testfiles/tattr2.ls
+++ b/tools/testfiles/tattr2.ls
@@ -2,149 +2,6 @@
  output for 'h5ls -w80 -v -S tattr2.h5'
 #############################
 Opened "tattr2.h5" with sec2 driver.
-    Attribute: array     {2}
-        Type:      [3] 32-bit little-endian integer
-        Data:  [1,2,3], [4,5,6]
-    Attribute: array2D   {3, 2}
-        Type:      [3] 32-bit little-endian integer
-        Data:
-            (0,0) [1,2,3], [4,5,6], [7,8,9], [10,11,12], [13,14,15], [16,17,18]
-    Attribute: array3D   {4, 3, 2}
-        Type:      [3] 32-bit little-endian integer
-        Data:
-            (0,0,0) [1,2,3], [4,5,6], [7,8,9], [10,11,12], [13,14,15],
-            (0,2,1) [16,17,18], [19,20,21], [22,23,24], [25,26,27], [28,29,30],
-            (1,2,0) [31,32,33], [34,35,36], [37,38,39], [40,41,42], [43,44,45],
-            (2,1,1) [46,47,48], [49,50,51], [52,53,54], [55,56,57], [58,59,60],
-            (3,1,0) [61,62,63], [64,65,66], [67,68,69], [70,71,72]
-    Attribute: bitfield  {2}
-        Type:      8-bit bitfield
-        Data:  0x01, 0x02
-    Attribute: bitfield2D {3, 2}
-        Type:      8-bit bitfield
-        Data:
-            (0,0) 0x01, 0x02, 0x03, 0x04, 0x05, 0x06
-    Attribute: bitfield3D {4, 3, 2}
-        Type:      8-bit bitfield
-        Data:
-            (0,0,0) 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
-            (1,2,0) 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14,
-            (3,1,0) 0x15, 0x16, 0x17, 0x18
-    Attribute: compound  {2}
-        Type:      struct {
-                   "a"                +0    8-bit integer
-                   "b"                +4    IEEE 64-bit little-endian float
-               } 12 bytes
-        Data:  {1, 2}, {3, 4}
-    Attribute: compound2D {3, 2}
-        Type:      struct {
-                   "a"                +0    8-bit integer
-                   "b"                +4    IEEE 64-bit little-endian float
-               } 12 bytes
-        Data:
-            (0,0) {1, 2}, {3, 4}, {5, 6}, {7, 8}, {9, 10}, {11, 12}
-    Attribute: compound3D {4, 3, 2}
-        Type:      struct {
-                   "a"                +0    8-bit integer
-                   "b"                +4    IEEE 64-bit little-endian float
-               } 12 bytes
-        Data:
-            (0,0,0) {1, 2}, {3, 4}, {5, 6}, {7, 8}, {9, 10}, {11, 12}, {13, 
-            (1,0,0)  14}, {15, 16}, {17, 18}, {19, 20}, {21, 22}, {23, 24},
-            (2,0,0) {25, 26}, {27, 28}, {29, 30}, {31, 32}, {33, 34}, {35, 36},
-            (3,0,0) {37, 38}, {39, 40}, {41, 42}, {43, 44}, {45, 46}, {47, 48}
-    Attribute: enum      {2}
-        Type:      enum 32-bit little-endian integer {
-                   RED              = 0
-                   GREEN            = 1
-               }
-        Data:  RED, RED
-    Attribute: enum2D    {3, 2}
-        Type:      enum 32-bit little-endian integer {
-                   RED              = 0
-                   GREEN            = 1
-               }
-        Data:
-            (0,0) RED, RED, RED, RED, RED, RED
-    Attribute: enum3D    {4, 3, 2}
-        Type:      enum 32-bit little-endian integer {
-                   RED              = 0
-                   GREEN            = 1
-               }
-        Data:
-            (0,0,0) RED, RED, RED, RED, RED, RED, RED, RED, RED, RED, RED, RED,
-            (2,0,0) RED, RED, RED, RED, RED, RED, RED, RED, RED, RED, RED, RED
-    Attribute: float     {2}
-        Type:      IEEE 32-bit little-endian float
-        Data:  1, 2
-    Attribute: float2D   {3, 2}
-        Type:      IEEE 32-bit little-endian float
-        Data:
-            (0,0) 1, 2, 3, 4, 5, 6
-    Attribute: float3D   {4, 3, 2}
-        Type:      IEEE 32-bit little-endian float
-        Data:
-            (0,0,0) 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
-            (2,2,1) 18, 19, 20, 21, 22, 23, 24
-    Attribute: integer   {2}
-        Type:      32-bit little-endian integer
-        Data:  1, 2
-    Attribute: integer2D {3, 2}
-        Type:      32-bit little-endian integer
-        Data:
-            (0,0) 1, 2, 3, 4, 5, 6
-    Attribute: integer3D {4, 3, 2}
-        Type:      32-bit little-endian integer
-        Data:
-            (0,0,0) 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
-            (2,2,1) 18, 19, 20, 21, 22, 23, 24
-    Attribute: opaque    {2}
-        Type:      1-byte opaque type
-               (tag = "1-byte opaque type")
-        Data:  0x01, 0x02
-    Attribute: opaque2D  {3, 2}
-        Type:      1-byte opaque type
-               (tag = "1-byte opaque type")
-        Data:
-            (0,0) 0x01, 0x02, 0x03, 0x04, 0x05, 0x06
-    Attribute: opaque3D  {4, 3, 2}
-        Type:      1-byte opaque type
-               (tag = "1-byte opaque type")
-        Data:
-            (0,0,0) 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
-            (1,2,0) 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14,
-            (3,1,0) 0x15, 0x16, 0x17, 0x18
-    Attribute: string    {2}
-        Type:      2-byte null-terminated ASCII string
-        Data:  "ab", "de"
-    Attribute: string2D  {3, 2}
-        Type:      2-byte null-terminated ASCII string
-        Data:
-            (0,0) "ab", "cd", "ef", "gh", "ij", "kl"
-    Attribute: string3D  {4, 3, 2}
-        Type:      2-byte null-terminated ASCII string
-        Data:
-            (0,0,0) "ab", "cd", "ef", "gh", "ij", "kl", "mn", "pq", "rs", "tu",
-            (1,2,0) "vw", "xz", "AB", "CD", "EF", "GH", "IJ", "KL", "MN", "PQ",
-            (3,1,0) "RS", "TU", "VW", "XZ"
-    Attribute: vlen      {2}
-        Type:      variable length of
-                   32-bit little-endian integer
-        Data:  (1), (2,3)
-    Attribute: vlen2D    {3, 2}
-        Type:      variable length of
-                   32-bit little-endian integer
-        Data:
-            (0,0) (0), (1), (2,3), (4,5), (6,7,8), (9,10,11)
-    Attribute: vlen3D    {4, 3, 2}
-        Type:      variable length of
-                   32-bit little-endian integer
-        Data:
-            (0,0,0) (0), (1), (2), (3), (4), (5), (6,7), (8,9), (10,11),
-            (1,1,1) (12,13), (14,15), (16,17), (18,19,20), (21,22,23),
-            (2,1,0) (24,25,26), (27,28,29), (30,31,32), (33,34,35),
-            (3,0,0) (36,37,38,39), (40,41,42,43), (44,45,46,47), (48,49,50,51),
-            (3,2,0) (52,53,54,55), (56,57,58,59)
 dset                     Dataset {2/2}
     Attribute: array     {2}
         Type:      [3] 32-bit little-endian integer
diff --git a/tools/testfiles/tcomp-1.ls b/tools/testfiles/tcomp-1.ls
index 599fe68..9cfb47d 100644
--- a/tools/testfiles/tcomp-1.ls
+++ b/tools/testfiles/tcomp-1.ls
@@ -1,6 +1,7 @@
 #############################
  output for 'h5ls -w80 -r -d tcompound.h5'
 #############################
+/                        Group
 /dset1                   Dataset {5}
     Data:
         (0) {0, 0, 1}, {1, 1, 0.5}, {2, 4, 0.333333333333333}, {3, 9, 0.25},
diff --git a/tools/testfiles/tdset-1.ls b/tools/testfiles/tdset-1.ls
index 6853429..b6e4671 100644
--- a/tools/testfiles/tdset-1.ls
+++ b/tools/testfiles/tdset-1.ls
@@ -1,6 +1,7 @@
 #############################
  output for 'h5ls -w80 -r -d tdset.h5'
 #############################
+/                        Group
 /dset1                   Dataset {10, 20}
     Data:
         (0,0) 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
diff --git a/tools/testfiles/textlink-1.ls b/tools/testfiles/textlink-1.ls
index f92786b..87be5a7 100644
--- a/tools/testfiles/textlink-1.ls
+++ b/tools/testfiles/textlink-1.ls
@@ -1,5 +1,6 @@
 #############################
  output for 'h5ls -w80 -r textlink.h5'
 #############################
+/                        Group
 /extlink1                -> file: filename    path: objname
 /extlink2                -> file: anotherfile    path: anotherobj
diff --git a/tools/testfiles/tgroup-1.ls b/tools/testfiles/tgroup-1.ls
index 62ebe70..0ca929d 100644
--- a/tools/testfiles/tgroup-1.ls
+++ b/tools/testfiles/tgroup-1.ls
@@ -1,17 +1,29 @@
 #############################
  output for 'h5ls -w80 -r -g tgroup.h5'
 #############################
-/                        Group
-/g1                      Group
-/g1/g1.1                 Group
-/g1/g1.2                 Group
-/g2                      Group
-/g2/g2.1                 Group
-/g2/g2.1/g2.1.1          Group
-/g2/g2.1/g2.1.2          Group
-/g2/g2.1/g2.1.3          Group
-/g3                      Group
-/g3/g3.1                 Group
-/g3/g3.2                 Group
-/g3/g3.3                 Group
-/g3/g3.4                 Group
+Error: 'recursive' option not compatible with 'group info' option!
+
+usage: h5ls [OPTIONS] [OBJECTS...]
+   OPTIONS
+      -h, -?, --help   Print a usage message and exit
+      -a, --address    Print addresses for raw data
+      -d, --data       Print the values of datasets
+      -e, --errors     Show all HDF5 error reporting
+      -f, --full       Print full path names instead of base names
+      -g, --group      Show information about a group, not its contents
+      -l, --label      Label members of compound datasets
+      -r, --recursive  List all groups recursively, avoiding cycles
+      -s, --string     Print 1-byte integer datasets as ASCII
+      -S, --simple     Use a machine-readable output format
+      -wN, --width=N   Set the number of columns of output
+      -v, --verbose    Generate more verbose output
+      -V, --version    Print version number and exit
+      --vfd=DRIVER     Use the specified virtual file driver
+      -x, --hexdump    Show raw data in hexadecimal format
+
+   OBJECTS
+      Each object consists of an HDF5 file name optionally followed by a
+      slash and an object name within the file (if no object is specified
+      within the file then the contents of the root group are displayed).
+      The file name may include a printf(3C) integer format such as
+      "%05d" to open a file family.
diff --git a/tools/testfiles/tgroup-2.ls b/tools/testfiles/tgroup-2.ls
new file mode 100644
index 0000000..0817d93
--- /dev/null
+++ b/tools/testfiles/tgroup-2.ls
@@ -0,0 +1,4 @@
+#############################
+ output for 'h5ls -w80 -g tgroup.h5/g1'
+#############################
+g1                       Group
diff --git a/tools/testfiles/tloop-1.ls b/tools/testfiles/tloop-1.ls
index b9631b7..22cb6c7 100644
--- a/tools/testfiles/tloop-1.ls
+++ b/tools/testfiles/tloop-1.ls
@@ -1,6 +1,7 @@
 #############################
  output for 'h5ls -w80 -r -d tloop.h5'
 #############################
+/                        Group
 /g1                      Group
 /g1/g1.1                 Group
 /g1/g1.1/g2.1            Group, same as /g1
diff --git a/tools/testfiles/tnestcomp-1.ls b/tools/testfiles/tnestcomp-1.ls
index eef41ef..9dc193d 100644
--- a/tools/testfiles/tnestcomp-1.ls
+++ b/tools/testfiles/tnestcomp-1.ls
@@ -1,6 +1,7 @@
 #############################
  output for 'h5ls -w80 -r -d tnestedcomp.h5'
 #############################
+/                        Group
 /ArrayOfStructures       Dataset {10}
     Data:
         (0) {0, 0, 1, {"A", [-100,100]}}, {1, 1, 0.5, {"B", [-100,100]}},
diff --git a/tools/testfiles/tsaf.ls b/tools/testfiles/tsaf.ls
index 8efc0f2..96d4811 100644
--- a/tools/testfiles/tsaf.ls
+++ b/tools/testfiles/tsaf.ls
@@ -1,6 +1,7 @@
 #############################
  output for 'h5ls -w80 -r -d tsaf.h5'
 #############################
+/                        Group
 /.DSL_METADATA           Dataset {5919/Inf}
     Data:
         (0) 47, 32, 67, 79, 78, 84, 65, 73, 78, 69, 82, 10, 47, 46, 97, 116,
diff --git a/tools/testfiles/tslink-1.ls b/tools/testfiles/tslink-1.ls
index 05b9bca..4c16958 100644
--- a/tools/testfiles/tslink-1.ls
+++ b/tools/testfiles/tslink-1.ls
@@ -1,5 +1,6 @@
 #############################
  output for 'h5ls -w80 -r tslink.h5'
 #############################
+/                        Group
 /slink1                  -> somevalue
 /slink2                  -> linkvalue
diff --git a/tools/testfiles/tstr-1.ls b/tools/testfiles/tstr-1.ls
index 1961fd4..8a223cc 100644
--- a/tools/testfiles/tstr-1.ls
+++ b/tools/testfiles/tstr-1.ls
@@ -1,6 +1,7 @@
 #############################
  output for 'h5ls -w80 -r -d tstr.h5'
 #############################
+/                        Group
 /comp1                   Dataset {3, 6}
     Data:
         (0,0) {[0,1,4,9,16,25,36,49,64,81,1,4,9,16,25,36,49,64,81,100,4,9,16,
diff --git a/tools/testfiles/tudlink-1.ls b/tools/testfiles/tudlink-1.ls
index e83fce7..b8578ce 100644
--- a/tools/testfiles/tudlink-1.ls
+++ b/tools/testfiles/tudlink-1.ls
@@ -1,5 +1,6 @@
 #############################
  output for 'h5ls -w80 -r tudlink.h5'
 #############################
+/                        Group
 /udlink1                 -> cannot follow UD links
 /udlink2                 -> cannot follow UD links
diff --git a/tools/testfiles/tvldtypes1.ls b/tools/testfiles/tvldtypes1.ls
index cf1688e..4c4c162 100644
--- a/tools/testfiles/tvldtypes1.ls
+++ b/tools/testfiles/tvldtypes1.ls
@@ -1,6 +1,7 @@
 #############################
  output for 'h5ls -w80 -r -d tvldtypes1.h5'
 #############################
+/                        Group
 /Dataset1.0              Dataset {4}
     Data:
         (0) (0), (10,11), (20,21,22), (30,31,32,33)
-- 
cgit v0.12