summaryrefslogtreecommitdiffstats
path: root/src/H5L.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/H5L.c')
-rw-r--r--src/H5L.c1156
1 files changed, 880 insertions, 276 deletions
diff --git a/src/H5L.c b/src/H5L.c
index 082681f..ed73380 100644
--- a/src/H5L.c
+++ b/src/H5L.c
@@ -14,7 +14,7 @@
#define H5F_PACKAGE /*suppress error about including H5Fpkg */
#define H5G_PACKAGE /*suppress error about including H5Gpkg */
-#define H5L_PACKAGE /*suppress error about including H5Gpkg */
+#define H5L_PACKAGE /*suppress error about including H5Lpkg */
/* Interface initialization */
#define H5_INTERFACE_INIT_FUNC H5L_init_interface
@@ -37,35 +37,37 @@
/* User data for path traversal routine for getting link metadata */
typedef struct {
H5L_linkinfo_t *linfo; /* Buffer to return to user */
- hid_t dxpl_id; /* dxpl to use in callback */
+ hid_t dxpl_id; /* dxpl to use in callback */
} H5L_trav_ud1_t;
/* User data for path traversal callback to creating a link */
typedef struct {
- H5F_t *file; /* Pointer to the file */
- hid_t dxpl_id; /* Dataset transfer property list */
- H5G_name_t *path; /* Path to object being linked */
- H5O_link_t *lnk; /* Pointer to link information to insert */
+ H5F_t *file; /* Pointer to the file */
+ hid_t dxpl_id; /* Dataset transfer property list */
+ hid_t lcpl_id; /* Link creation property list */
+ H5G_name_t *path; /* Path to object being linked */
+ H5O_link_t *lnk; /* Pointer to link information to insert */
} H5L_trav_ud3_t;
/* User data for path traversal routine for moving and renaming a link */
typedef struct {
- const char *dst_name; /* Destination name for moving object */
- H5T_cset_t cset; /* Char set for new name */
- H5G_loc_t *dst_loc; /* Destination location for moving object */
- hbool_t copy; /* TRUE if this is a copy operation */
- hid_t dxpl_id; /* dxpl to use in callback */
+ const char *dst_name; /* Destination name for moving object */
+ H5T_cset_t cset; /* Char set for new name */
+ H5G_loc_t *dst_loc; /* Destination location for moving object */
+ hbool_t copy; /* TRUE if this is a copy operation */
+ hid_t lapl_id; /* lapl to use in callback */
+ hid_t dxpl_id; /* dxpl to use in callback */
} H5L_trav_ud4_t;
/* User data for path traversal routine for getting soft link value */
typedef struct {
- size_t size; /* Size of user buffer */
- char *buf; /* User buffer */
+ size_t size; /* Size of user buffer */
+ char *buf; /* User buffer */
} H5L_trav_ud5_t;
/* User data for path traversal routine for removing link (i.e. unlink) */
typedef struct {
- hid_t dxpl_id; /* Dataset transfer property list */
+ hid_t dxpl_id; /* Dataset transfer property list */
} H5L_trav_ud6_t;
/* User data for path traversal routine for retrieving link creation property list */
@@ -75,9 +77,10 @@ typedef struct {
/* User data for path traversal routine for moving and renaming an object */
typedef struct {
- H5F_t *file; /* Pointer to the file */
- H5O_link_t *lnk; /* Pointer to link information to insert */
- hid_t dxpl_id; /* Dataset transfer property list */
+ H5F_t *file; /* Pointer to the file */
+ H5O_link_t *lnk; /* Pointer to link information to insert */
+ hbool_t copy; /* TRUE if this is a copy operation */
+ hid_t dxpl_id; /* Dataset transfer property list */
} H5L_trav_ud10_t;
/* Package variables */
@@ -86,32 +89,196 @@ typedef struct {
/* Private prototypes */
static herr_t H5L_link_cb(H5G_loc_t *grp_loc/*in*/, const char *name,
- const H5O_link_t *lnk, H5G_loc_t *obj_loc, void *_udata/*in,out*/);
+ const H5O_link_t *lnk, H5G_loc_t *obj_loc, void *_udata/*in,out*/,
+ hbool_t *own_obj_loc/*out*/);
static herr_t H5L_create_real(H5G_loc_t *link_loc, const char *link_name,
- H5G_name_t *obj_path, H5F_t *obj_file, H5O_link_t *lnk, hid_t dxpl_id,
- hid_t lcpl_id);
+ H5G_name_t *obj_path, H5F_t *obj_file, H5O_link_t *lnk, hid_t lcpl_id,
+ hid_t lapl_id, hid_t dxpl_id);
static herr_t H5L_create_hard(H5G_loc_t *cur_loc, const char *cur_name,
- H5G_loc_t *link_loc, const char *link_name, hid_t dxpl_id, hid_t lcpl_id);
-static herr_t H5L_create_soft(const char *target_path, H5G_loc_t *loc,
- const char *name, hid_t dxpl_id, hid_t lcpl_id);
+ H5G_loc_t *link_loc, const char *link_name, hid_t lcpl_id,
+ hid_t lapl_id, hid_t dxpl_id);
+static herr_t H5L_create_soft(const char *target_path, H5G_loc_t *cur_loc,
+ const char *cur_name, hid_t lcpl_id, hid_t lapl_id, hid_t dxpl_id);
static herr_t H5L_linkval_cb(H5G_loc_t *grp_loc/*in*/, const char *name,
- const H5O_link_t *lnk, H5G_loc_t *obj_loc, void *_udata/*in,out*/);
+ const H5O_link_t *lnk, H5G_loc_t *obj_loc, void *_udata/*in,out*/,
+ hbool_t *own_obj_loc/*out*/);
static herr_t H5L_linkval(H5G_loc_t *loc, const char *name, size_t size,
- char *buf/*out*/, hid_t dxpl_id);
+ char *buf/*out*/, hid_t lapl_id, hid_t dxpl_id);
static herr_t H5L_unlink_cb(H5G_loc_t *grp_loc/*in*/, const char *name,
- const H5O_link_t *lnk, H5G_loc_t *obj_loc, void *_udata/*in,out*/);
-static herr_t H5L_unlink(H5G_loc_t *loc, const char *name, hid_t dxpl_id);
+ const H5O_link_t *lnk, H5G_loc_t *obj_loc, void *_udata/*in,out*/,
+ hbool_t *own_obj_loc/*out*/);
+static herr_t H5L_unlink(H5G_loc_t *loc, const char *name, hid_t lapl_id,
+ hid_t dxpl_id);
static herr_t H5L_move(H5G_loc_t *src_loc, const char *src_name,
H5G_loc_t *dst_loc, const char *dst_name, hbool_t copy_flag,
- hid_t lcpl_id, hid_t dxpl_id);
+ hid_t lcpl_id, hid_t lapl_id, hid_t dxpl_id);
static herr_t H5L_move_cb(H5G_loc_t *grp_loc/*in*/, const char *name,
- const H5O_link_t *lnk, H5G_loc_t *obj_loc, void *_udata/*in,out*/);
+ const H5O_link_t *lnk, H5G_loc_t *obj_loc, void *_udata/*in,out*/,
+ hbool_t *own_obj_loc/*out*/);
static herr_t H5L_move_dest_cb(H5G_loc_t *grp_loc/*in*/,
- const char *name, const H5O_link_t *lnk, H5G_loc_t *obj_loc, void *_udata/*in,out*/);
-static herr_t H5L_get_linkinfo(H5G_loc_t *loc, const char *name,
- H5L_linkinfo_t *linkbuf/*out*/, hid_t dxpl_id);
+ const char *name, const H5O_link_t *lnk, H5G_loc_t *obj_loc, void *_udata/*in,out*/,
+ hbool_t *own_obj_loc/*out*/);
static herr_t H5L_get_linfo_cb(H5G_loc_t UNUSED *grp_loc/*in*/, const char UNUSED *name,
- const H5O_link_t *lnk, H5G_loc_t UNUSED *obj_loc, void *_udata/*in,out*/);
+ const H5O_link_t *lnk, H5G_loc_t UNUSED *obj_loc, void *_udata/*in,out*/,
+ hbool_t *own_obj_loc/*out*/);
+static int H5L_find_class_idx(H5L_link_t id);
+
+
+/* Information about user-defined links */
+static size_t H5L_table_alloc_g = 0;
+static size_t H5L_table_used_g = 0;
+static H5L_link_class_t *H5L_table_g = NULL;
+
+
+
+#define H5L_MIN_TABLE_SIZE 32 /* Minimum size of the user-defined link type table if it is allocated */
+
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5L_init
+ *
+ * Purpose: Initialize the interface from some other package.
+ *
+ * Return: Success: non-negative
+ *
+ * Failure: negative
+ *
+ * Programmer: James Laird
+ * Thursday, July 13, 2006
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5L_init(void)
+{
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(H5L_init, FAIL);
+ /* FUNC_ENTER() does all the work */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Lregister
+ *
+ * Purpose: Registers a class of user-defined links, or changes the
+ * behavior of an existing class.
+ *
+ * The link class passed in will override any existing link
+ * class for the specified link class ID. It must at least
+ * include a H5L_link_class_t version (which should be
+ * H5L_LINK_CLASS_T_VERS), a link class ID, and a traversal
+ * function.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: James Laird
+ * Monday, July 10, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Lregister(const H5L_link_class_t *cls)
+{
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(H5Lregister, FAIL)
+ H5TRACE1("e","*x",cls);
+
+ /* Check args */
+ if (cls==NULL)
+ HGOTO_ERROR (H5E_ARGS, H5E_BADVALUE, FAIL, "invalid link class")
+
+ /* Check H5L_link_class_t version number; this is where a function to convert
+ * from an outdated version should be called.
+ */
+ if(cls->version != H5L_LINK_CLASS_T_VERS)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid H5L_link_class_t version number");
+
+ if (cls->id<H5L_LINK_UD_MIN || cls->id>H5L_LINK_MAX)
+ HGOTO_ERROR (H5E_ARGS, H5E_BADVALUE, FAIL, "invalid link identification number")
+ if (cls->trav_func==NULL)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no traversal function specified")
+
+ /* Do it */
+ if (H5L_register (cls)<0)
+ HGOTO_ERROR (H5E_LINK, H5E_NOTREGISTERED, FAIL, "unable to register link type")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5L_find_class_idx
+ *
+ * Purpose: Given a link class ID, return the offset in the global array
+ * that holds all the registered link classes.
+ *
+ * Return: Success: Non-negative index of entry in global
+ * link class table.
+ * Failure: Negative
+ *
+ * Programmer: James Laird
+ * Monday, July 10, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5L_find_class_idx(H5L_link_t id)
+{
+ size_t i; /* Local index variable */
+ int ret_value=FAIL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5L_find_class_idx)
+
+ for (i=0; i<H5L_table_used_g; i++)
+ if (H5L_table_g[i].id == id)
+ HGOTO_DONE((int)i)
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5L_find_class_idx */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5L_find_class
+ *
+ * Purpose: Given a link class ID return a pointer to a global struct that
+ * defines the link class.
+ *
+ * Return: Success: Ptr to entry in global link class table.
+ * Failure: NULL
+ *
+ * Programmer: James Laird
+ * Monday, July 10, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+const H5L_link_class_t *
+H5L_find_class(H5L_link_t id)
+{
+ int idx; /* Filter index in global table */
+ H5L_link_class_t *ret_value=NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI(H5L_find_class, NULL)
+
+ /* Get the index in the global table */
+ if((idx=H5L_find_class_idx(id))<0)
+ HGOTO_ERROR(H5E_LINK, H5E_NOTREGISTERED, NULL, "unable to find link class")
+
+ /* Set return value */
+ ret_value=H5L_table_g+idx;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5L_find_class */
/*-------------------------------------------------------------------------
@@ -130,6 +297,7 @@ static herr_t
H5L_init_interface(void)
{
H5P_genclass_t *crt_pclass;
+ H5P_genclass_t *acc_pclass;
size_t nprops; /* Number of properties */
unsigned intmd_group = H5L_CRT_INTERMEDIATE_GROUP_DEF;
herr_t ret_value = SUCCEED; /* Return value */
@@ -163,12 +331,57 @@ H5L_init_interface(void)
HGOTO_ERROR (H5E_PLIST, H5E_CANTREGISTER, FAIL, "can't register default property list")
} /* end if */
+ /* ========== Link Access Property Class Initialization ============*/
+ assert(H5P_CLS_LINK_ACCESS_g!=-1);
+
+ /* Get the pointer to link access class */
+ if(NULL == (acc_pclass = H5I_object(H5P_CLS_LINK_ACCESS_g)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property list class")
+
+ /* Only register the default property list if it hasn't been created yet */
+ if(H5P_LST_LINK_ACCESS_g == (-1)) {
+ /* Register the default link access property list */
+ if((H5P_LST_LINK_ACCESS_g = H5P_create_id(acc_pclass))<0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTREGISTER, FAIL, "can't register default LAPL")
+ } /* end if */
+
+
+ /* Initialize user-defined link classes */
+ if(H5L_register_external() <0)
+ HGOTO_ERROR(H5E_LINK, H5E_NOTREGISTERED, FAIL, "unable to register external link class")
+
done:
FUNC_LEAVE_NOAPI(ret_value)
}
/*-------------------------------------------------------------------------
+ * Function: H5L_term_interface
+ *
+ * Purpose: Terminate any resources allocated in H5L_init_interface.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: James Laird
+ * Tuesday, January 24, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5L_term_interface(void)
+{
+ int n=0;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5L_term_interface)
+
+ /* Free the table of link types */
+ H5L_table_g = H5MM_xfree(H5L_table_g);
+ H5L_table_used_g = H5L_table_alloc_g = 0;
+
+ FUNC_LEAVE_NOAPI(n)
+}
+
+/*-------------------------------------------------------------------------
* Function: H5Lmove
*
* Purpose: Renames an object within an HDF5 file and moves it to a new
@@ -187,14 +400,15 @@ done:
*/
herr_t
H5Lmove(hid_t src_loc_id, const char *src_name, hid_t dst_loc_id,
- const char *dst_name, hid_t lcpl_id)
+ const char *dst_name, hid_t lcpl_id, hid_t lapl_id)
{
H5G_loc_t src_loc, *src_loc_p;
H5G_loc_t dst_loc, *dst_loc_p;
herr_t ret_value=SUCCEED; /* Return value */
FUNC_ENTER_API(H5Lmove, FAIL)
- H5TRACE5("e","isisi",src_loc_id,src_name,dst_loc_id,dst_name,lcpl_id);
+ H5TRACE6("e","isisii",src_loc_id,src_name,dst_loc_id,dst_name,lcpl_id,
+ lapl_id);
/* Check arguments */
if(src_loc_id != H5L_SAME_LOC && H5G_loc(src_loc_id, &src_loc) < 0)
@@ -220,8 +434,8 @@ H5Lmove(hid_t src_loc_id, const char *src_name, hid_t dst_loc_id,
HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a link creation property list")
if(H5L_move(src_loc_p, src_name, dst_loc_p, dst_name,
- FALSE, lcpl_id, H5AC_dxpl_id) < 0)
- HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to move link")
+ FALSE, lcpl_id, lapl_id, H5AC_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTMOVE, FAIL, "unable to move link")
done:
FUNC_LEAVE_API(ret_value)
@@ -244,14 +458,15 @@ done:
*/
herr_t
H5Lcopy(hid_t src_loc_id, const char *src_name, hid_t dst_loc_id,
- const char *dst_name, hid_t lcpl_id)
+ const char *dst_name, hid_t lcpl_id, hid_t lapl_id)
{
H5G_loc_t src_loc, *src_loc_p;
H5G_loc_t dst_loc, *dst_loc_p;
herr_t ret_value=SUCCEED; /* Return value */
FUNC_ENTER_API(H5Lcopy, FAIL)
- H5TRACE5("e","isisi",src_loc_id,src_name,dst_loc_id,dst_name,lcpl_id);
+ H5TRACE6("e","isisii",src_loc_id,src_name,dst_loc_id,dst_name,lcpl_id,
+ lapl_id);
/* Check arguments */
if(src_loc_id != H5L_SAME_LOC && H5G_loc(src_loc_id, &src_loc) < 0)
@@ -276,8 +491,9 @@ H5Lcopy(hid_t src_loc_id, const char *src_name, hid_t dst_loc_id,
if(lcpl_id != H5P_DEFAULT && (TRUE != H5P_isa_class(lcpl_id, H5P_LINK_CREATE)))
HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a link creation property list")
- if(H5L_move(src_loc_p, src_name, dst_loc_p, dst_name, TRUE, lcpl_id, H5AC_dxpl_id) < 0)
- HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to move link")
+ if(H5L_move(src_loc_p, src_name, dst_loc_p, dst_name, TRUE, lcpl_id,
+ lapl_id, H5AC_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTMOVE, FAIL, "unable to move link")
done:
FUNC_LEAVE_API(ret_value)
@@ -306,14 +522,15 @@ done:
*-------------------------------------------------------------------------
*/
herr_t
-H5Llink(hid_t new_loc_id, const char *new_name, hid_t obj_id, hid_t lcpl_id)
+H5Llink(hid_t new_loc_id, const char *new_name, hid_t obj_id, hid_t lcpl_id,
+ hid_t lapl_id)
{
H5G_loc_t new_loc;
H5G_loc_t obj_loc;
herr_t ret_value=SUCCEED; /* Return value */
FUNC_ENTER_API(H5Llink, FAIL)
- H5TRACE4("e","isii",new_loc_id,new_name,obj_id,lcpl_id);
+ H5TRACE5("e","isiii",new_loc_id,new_name,obj_id,lcpl_id,lapl_id);
/* Check arguments */
if(new_loc_id == H5L_SAME_LOC)
@@ -328,8 +545,8 @@ H5Llink(hid_t new_loc_id, const char *new_name, hid_t obj_id, hid_t lcpl_id)
if(lcpl_id != H5P_DEFAULT && (TRUE != H5P_isa_class(lcpl_id, H5P_LINK_CREATE)))
HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a link creation property list")
- if(H5L_link(&new_loc, new_name, &obj_loc, H5AC_dxpl_id, lcpl_id ) < 0)
- HGOTO_ERROR(H5E_SYM, H5E_LINK, FAIL, "unable to create link")
+ if(H5L_link(&new_loc, new_name, &obj_loc, lcpl_id, lapl_id, H5AC_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTINIT, FAIL, "unable to create link")
done:
FUNC_LEAVE_API(ret_value)
@@ -356,20 +573,20 @@ done:
*/
herr_t
H5Lcreate_soft(const char *target_path,
- hid_t loc_id, const char *name, hid_t lcpl_id)
+ hid_t cur_loc, const char *cur_name, hid_t lcpl_id, hid_t lapl_id)
{
H5G_loc_t new_loc, *new_loc_p;
herr_t ret_value=SUCCEED; /* Return value */
FUNC_ENTER_API(H5Lcreate_soft, FAIL)
- H5TRACE4("e","sisi",target_path,loc_id,name,lcpl_id);
+ H5TRACE5("e","sisii",target_path,cur_loc,cur_name,lcpl_id,lapl_id);
/* Check arguments */
- if(H5G_loc(loc_id, &new_loc) < 0)
+ if(H5G_loc(cur_loc, &new_loc) < 0)
HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
if(!target_path || !*target_path)
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no target specified")
- if(!name || !*name)
+ if(!cur_name || !*cur_name)
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no new name specified")
if(lcpl_id != H5P_DEFAULT && (TRUE != H5P_isa_class(lcpl_id, H5P_LINK_CREATE)))
@@ -377,8 +594,9 @@ H5Lcreate_soft(const char *target_path,
new_loc_p = &new_loc;
- if(H5L_create_soft(target_path, new_loc_p, name, H5AC_dxpl_id, lcpl_id) < 0)
- HGOTO_ERROR(H5E_SYM, H5E_LINK, FAIL, "unable to create link")
+ if(H5L_create_soft(target_path, new_loc_p, cur_name,
+ lcpl_id, lapl_id, H5AC_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTINIT, FAIL, "unable to create link")
done:
FUNC_LEAVE_API(ret_value)
@@ -403,14 +621,15 @@ done:
*/
herr_t
H5Lcreate_hard(hid_t cur_loc_id, const char *cur_name,
- hid_t new_loc_id, const char *new_name, hid_t lcpl_id)
+ hid_t new_loc_id, const char *new_name, hid_t lcpl_id, hid_t lapl_id)
{
H5G_loc_t cur_loc, *cur_loc_p;
H5G_loc_t new_loc, *new_loc_p;
herr_t ret_value=SUCCEED; /* Return value */
FUNC_ENTER_API(H5Lcreate_hard, FAIL)
- H5TRACE5("e","isisi",cur_loc_id,cur_name,new_loc_id,new_name,lcpl_id);
+ H5TRACE6("e","isisii",cur_loc_id,cur_name,new_loc_id,new_name,lcpl_id,
+ lapl_id);
/* Check arguments */
if(cur_loc_id != H5L_SAME_LOC && H5G_loc(cur_loc_id, &cur_loc) < 0)
@@ -437,14 +656,66 @@ H5Lcreate_hard(hid_t cur_loc_id, const char *cur_name,
else if(cur_loc_p->oloc->file != new_loc_p->oloc->file)
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "source and destination should be in the same file.")
- if(H5L_create_hard(cur_loc_p, cur_name, new_loc_p, new_name, H5AC_dxpl_id, lcpl_id) < 0)
- HGOTO_ERROR(H5E_SYM, H5E_LINK, FAIL, "unable to create link")
+ if(H5L_create_hard(cur_loc_p, cur_name, new_loc_p, new_name,
+ lcpl_id, lapl_id, H5AC_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTINIT, FAIL, "unable to create link")
done:
FUNC_LEAVE_API(ret_value)
} /* end H5Lcreate_hard() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5Lcreate_ud
+ *
+ * Purpose: Creates a user-defined link of type LINK_TYPE named LINK_NAME
+ * with user-specified data UDATA.
+ *
+ * The format of the information pointed to by UDATA is
+ * defined by the user. UDATA_SIZE holds the size of this buffer.
+ *
+ * LINK_NAME is interpreted relative to LINK_LOC_ID.
+ *
+ * The property list specified by LCPL_ID holds properties used
+ * to create the link.
+ *
+ * The link class of the new link must already be registered
+ * with the library.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: James Laird
+ * Tuesday, December 13, 2005
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Lcreate_ud(hid_t link_loc_id, const char *link_name, H5L_link_t link_type, void *udata, size_t udata_size, hid_t lcpl_id, hid_t lapl_id)
+{
+ H5G_loc_t link_loc;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(H5Lcreate_ud, FAIL)
+ H5TRACE7("e","isLlxzii",link_loc_id,link_name,link_type,udata,udata_size,
+ lcpl_id,lapl_id);
+
+ /* Check arguments */
+ if(H5G_loc(link_loc_id, &link_loc) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
+ if(!link_name || !*link_name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no link name specified")
+
+ /* Create external link */
+ if(H5L_create_ud(&link_loc, link_name, udata, udata_size, link_type,
+ H5G_TARGET_NORMAL, lcpl_id, lapl_id, H5AC_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTINIT, FAIL, "unable to create link")
+
+done:
+ FUNC_LEAVE_API(ret_value);
+} /* end H5Lcreate_ud */
+
+
/*-------------------------------------------------------------------------
* Function: H5Lunlink
*
@@ -463,13 +734,13 @@ done:
*-------------------------------------------------------------------------
*/
herr_t
-H5Lunlink(hid_t loc_id, const char *name)
+H5Lunlink(hid_t loc_id, const char *name, hid_t lapl_id)
{
H5G_loc_t loc;
herr_t ret_value=SUCCEED; /* Return value */
FUNC_ENTER_API(H5Lunlink, FAIL)
- H5TRACE2("e","is",loc_id,name);
+ H5TRACE3("e","isi",loc_id,name,lapl_id);
/* Check arguments */
if(H5G_loc(loc_id, &loc) < 0)
@@ -478,8 +749,8 @@ H5Lunlink(hid_t loc_id, const char *name)
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name")
/* Unlink */
- if(H5L_unlink(&loc, name, H5AC_dxpl_id) < 0)
- HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to unlink object")
+ if(H5L_unlink(&loc, name, lapl_id, H5AC_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTDELETE, FAIL, "unable to unlink object")
done:
FUNC_LEAVE_API(ret_value)
@@ -506,13 +777,14 @@ done:
*-------------------------------------------------------------------------
*/
herr_t
-H5Lget_linkval(hid_t loc_id, const char *name, size_t size, char *buf/*out*/)
+H5Lget_linkval(hid_t loc_id, const char *name, size_t size, char *buf/*out*/,
+ hid_t lapl_id)
{
H5G_loc_t loc;
herr_t ret_value = SUCCEED; /* Return value */
FUNC_ENTER_API(H5Lget_linkval, FAIL)
- H5TRACE4("e","iszx",loc_id,name,size,buf);
+ H5TRACE5("e","iszxi",loc_id,name,size,buf,lapl_id);
/* Check arguments */
if(H5G_loc(loc_id, &loc))
@@ -521,7 +793,7 @@ H5Lget_linkval(hid_t loc_id, const char *name, size_t size, char *buf/*out*/)
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name specified")
/* Get the link value */
- if(H5L_linkval(&loc, name, size, buf, H5AC_ind_dxpl_id) < 0)
+ if(H5L_linkval(&loc, name, size, buf, lapl_id, H5AC_ind_dxpl_id) < 0)
HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "unable to get link value")
done:
@@ -544,12 +816,13 @@ done:
*-------------------------------------------------------------------------
*/
herr_t
-H5Lget_linkinfo(hid_t loc_id, const char *name, H5L_linkinfo_t *linkbuf /*out*/)
+H5Lget_linkinfo(hid_t loc_id, const char *name, H5L_linkinfo_t *linkbuf /*out*/,
+ hid_t lapl_id)
{
H5G_loc_t loc;
herr_t ret_value = SUCCEED;
FUNC_ENTER_API(H5Lget_linkinfo, FAIL)
- H5TRACE3("e","isx",loc_id,name,linkbuf);
+ H5TRACE4("e","isxi",loc_id,name,linkbuf,lapl_id);
/* Check arguments */
if(H5G_loc(loc_id, &loc))
@@ -558,7 +831,7 @@ H5Lget_linkinfo(hid_t loc_id, const char *name, H5L_linkinfo_t *linkbuf /*out*/)
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name specified")
/* Get the creation time */
- if(H5L_get_linkinfo(&loc, name, linkbuf, H5AC_ind_dxpl_id) < 0)
+ if(H5L_get_linkinfo(&loc, name, linkbuf, lapl_id, H5AC_ind_dxpl_id) < 0)
HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "unable to get link info")
done:
@@ -566,6 +839,79 @@ done:
}
+/*-------------------------------------------------------------------------
+ * Function: H5Lunregister
+ *
+ * Purpose: Unregisters a class of user-defined links, preventing them
+ * from being traversed, queried, moved, etc.
+ *
+ * A link class can be re-registered using H5Lregister().
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: James Laird
+ * Monday, July 10, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Lunregister(H5L_link_t id)
+{
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(H5Lunregister, FAIL)
+ H5TRACE1("e","Ll",id);
+
+ /* Check args */
+ if (id<0 || id>H5L_LINK_MAX)
+ HGOTO_ERROR (H5E_ARGS, H5E_BADVALUE, FAIL, "invalid link type")
+
+ /* Do it */
+ if (H5L_unregister (id)<0)
+ HGOTO_ERROR (H5E_LINK, H5E_NOTREGISTERED, FAIL, "unable to unregister link type")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Lunregister() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Lis_registered
+ *
+ * Purpose: Tests whether a user-defined link class has been registered
+ * or not.
+ *
+ * Return: Positive if the link class has been registered
+ * Zero if it is unregistered
+ * Negative on error (if the class is not a valid UD class ID)
+ *
+ * Programmer: James Laird
+ * Monday, July 10, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t H5Lis_registered(H5L_link_t id)
+{
+ size_t i; /* Local index variable */
+ htri_t ret_value=FALSE; /* Return value */
+
+ FUNC_ENTER_API(H5Lis_registered, FAIL)
+
+ /* Check args */
+ if(id<0 || id>H5L_LINK_MAX)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid link type id number")
+
+ /* Is the link class already registered? */
+ for(i=0; i<H5L_table_used_g; i++)
+ if(H5L_table_g[i].id==id) {
+ ret_value=TRUE;
+ break;
+ } /* end if */
+
+done:
+ FUNC_LEAVE_API(ret_value)
+}
+/* end H5Lis_registered */
/*
*-------------------------------------------------------------------------
@@ -576,6 +922,107 @@ done:
*/
/*-------------------------------------------------------------------------
+ * Function: H5L_register
+ *
+ * Purpose: Registers a class of user-defined links, or changes the
+ * behavior of an existing class.
+ *
+ * See H5Lregister for full documentation.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: James Laird
+ * Monday, July 10, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5L_register (const H5L_link_class_t *cls)
+{
+ size_t i;
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(H5L_register, FAIL)
+
+ assert (cls);
+ assert (cls->id>=0 && cls->id<=H5L_LINK_MAX);
+
+ /* Is the link type already registered? */
+ for (i=0; i<H5L_table_used_g; i++)
+ if (H5L_table_g[i].id==cls->id)
+ break;
+
+ /* Filter not already registered */
+ if (i>=H5L_table_used_g) {
+ if (H5L_table_used_g>=H5L_table_alloc_g) {
+ size_t n = MAX(H5L_MIN_TABLE_SIZE, 2*H5L_table_alloc_g);
+ H5L_link_class_t *table = H5MM_realloc(H5L_table_g,
+ n*sizeof(H5L_link_class_t));
+ if (!table)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to extend link type table")
+ H5L_table_g = table;
+ H5L_table_alloc_g = n;
+ } /* end if */
+
+ /* Initialize */
+ i = H5L_table_used_g++;
+ HDmemcpy(H5L_table_g+i, cls, sizeof(H5L_link_class_t));
+ } /* end if */
+ /* Filter already registered */
+ else {
+ /* Replace old contents */
+ HDmemcpy(H5L_table_g+i, cls, sizeof(H5L_link_class_t));
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5L_register */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5L_unregister
+ *
+ * Purpose: Unregisters a class of user-defined links.
+ *
+ * See H5Lunregister for full documentation.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: James Laird
+ * Monday, July 10, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5L_unregister (H5L_link_t id)
+{
+ size_t i; /* Local index variable */
+ herr_t ret_value=SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(H5L_unregister,FAIL)
+
+ assert (id>=0 && id<=H5L_LINK_MAX);
+
+ /* Is the filter already registered? */
+ for (i=0; i<H5L_table_used_g; i++)
+ if (H5L_table_g[i].id==id)
+ break;
+
+ /* Fail if filter not found */
+ if (i>=H5L_table_used_g)
+ HGOTO_ERROR(H5E_LINK, H5E_NOTREGISTERED, FAIL, "link class is not registered")
+
+ /* Remove filter from table */
+ /* Don't worry about shrinking table size (for now) */
+ HDmemmove(&H5L_table_g[i],&H5L_table_g[i+1],sizeof(H5L_link_class_t)*((H5L_table_used_g-1)-i));
+ H5L_table_used_g--;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5L_unregister() */
+
+
+/*-------------------------------------------------------------------------
* Function: H5L_link
*
* Purpose: Creates a link from OBJ_ID to CUR_NAME. See H5Llink() for
@@ -590,7 +1037,7 @@ done:
*/
herr_t
H5L_link(H5G_loc_t *new_loc, const char *new_name, H5G_loc_t *obj_loc,
- hid_t dxpl_id, hid_t lcpl_id)
+ hid_t lcpl_id, hid_t lapl_id, hid_t dxpl_id)
{
H5F_t *file = NULL; /* File link will be in */
H5O_link_t lnk; /* Link to insert */
@@ -614,8 +1061,8 @@ H5L_link(H5G_loc_t *new_loc, const char *new_name, H5G_loc_t *obj_loc,
lnk.u.hard.addr = obj_loc->oloc->addr;
/* Create the link */
- if( H5L_create_real(new_loc, new_name, obj_loc->path, obj_loc->oloc->file, &lnk, dxpl_id, lcpl_id) <0)
- HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to register new name for object")
+ if( H5L_create_real(new_loc, new_name, obj_loc->path, obj_loc->oloc->file, &lnk, lcpl_id, lapl_id, dxpl_id) <0)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTINIT, FAIL, "unable to create new link to object")
done:
FUNC_LEAVE_NOAPI(ret_value)
@@ -636,9 +1083,13 @@ done:
*/
static herr_t
H5L_link_cb(H5G_loc_t *grp_loc/*in*/, const char *name, const H5O_link_t UNUSED *lnk,
- H5G_loc_t *obj_loc, void *_udata/*in,out*/)
+ H5G_loc_t *obj_loc, void *_udata/*in,out*/, hbool_t *own_obj_loc/*out*/)
{
H5L_trav_ud3_t *udata = (H5L_trav_ud3_t *)_udata; /* User data passed in */
+ H5G_t *grp=NULL; /* H5G_t for this group, opened to pass to user callback */
+ hid_t grp_id = FAIL; /* Id for this group (passed to user callback */
+ H5G_loc_t temp_loc; /* For UD callback */
+ hbool_t temp_loc_init = FALSE;
herr_t ret_value = SUCCEED; /* Return value */
FUNC_ENTER_NOAPI_NOINIT(H5L_link_cb)
@@ -652,7 +1103,7 @@ H5L_link_cb(H5G_loc_t *grp_loc/*in*/, const char *name, const H5O_link_t UNUSED
if(udata->lnk->type == H5L_LINK_HARD) {
/* Check that both objects are in same file */
if(grp_loc->oloc->file->shared != udata->file->shared)
- HGOTO_ERROR(H5E_SYM, H5E_LINK, FAIL, "interfile hard links are not allowed")
+ HGOTO_ERROR(H5E_SYM, H5E_BADVALUE, FAIL, "interfile hard links are not allowed")
} /* end if */
/* Set the link's name correctly */
@@ -661,7 +1112,7 @@ H5L_link_cb(H5G_loc_t *grp_loc/*in*/, const char *name, const H5O_link_t UNUSED
/* Insert link into group */
if(H5G_obj_insert(grp_loc->oloc, name, udata->lnk, (hbool_t)(udata->lnk->type == H5L_LINK_HARD ? TRUE : FALSE), udata->dxpl_id) < 0)
- HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to create new name/link for object")
+ HGOTO_ERROR(H5E_LINK, H5E_CANTINIT, FAIL, "unable to create new link for object")
/* Set object's path if it has been passed in and is not set */
if(udata->path != NULL && udata->path->user_path_r == NULL)
@@ -670,15 +1121,59 @@ H5L_link_cb(H5G_loc_t *grp_loc/*in*/, const char *name, const H5O_link_t UNUSED
HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "cannot set name")
}
+ /* If link is a user-defined link, trigger its creation callback if it has one*/
+ if(udata->lnk->type >= H5L_LINK_UD_MIN)
+ {
+ const H5L_link_class_t *link_class; /* User-defined link class */
+ H5O_loc_t temp_oloc;
+ H5G_name_t temp_path;
+
+ /* Get the link class for this type of link. */
+ if(NULL == (link_class = H5L_find_class(udata->lnk->type)))
+ HGOTO_ERROR(H5E_LINK, H5E_NOTREGISTERED, FAIL, "unable to get class of UD link")
+
+ if(link_class->create_func != NULL)
+ {
+ /* Create a temporary location (or else H5G_open will do a shallow
+ * copy and wipe out grp_loc)
+ */
+ H5G_name_reset(&temp_path);
+ if(H5O_loc_copy(&temp_oloc, grp_loc->oloc, H5_COPY_DEEP) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTCOPY, FAIL, "unable to copy object location")
+
+ temp_loc.oloc = &temp_oloc;
+ temp_loc.path = &temp_path;
+ temp_loc_init = TRUE;
+
+ /* Set up location for user-defined callback */
+ if((grp = H5G_open(&temp_loc, udata->dxpl_id)) == NULL)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open group")
+ if((grp_id = H5I_register(H5I_GROUP, grp)) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL, "unable to register ID for group")
+
+ if((link_class->create_func)(name, grp_id, udata->lnk->u.ud.udata, udata->lnk->u.ud.size, H5P_DEFAULT) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CALLBACK, FAIL, "link creation callback failed")
+ }
+ }
+
done:
- if(ret_value < 0) {
- /* Release the group location for the object */
- /* (Group traversal callbacks are responsible for either taking ownership
- * of the group location for the object, or freeing it. - QAK)
- */
- if(obj_loc)
- H5G_loc_free(obj_loc);
- } /* end if */
+ /* Close the location given to the user callback if it was created */
+ if(grp_id >= 0)
+ {
+ if(H5I_dec_ref(grp_id) <0)
+ HDONE_ERROR(H5E_ATOM, H5E_CANTRELEASE, FAIL, "unable to close atom from UD callback")
+ }
+ else if(grp != NULL)
+ {
+ if(H5G_close(grp) <0)
+ HDONE_ERROR(H5E_FILE, H5E_CANTRELEASE, FAIL, "unable to close group given to UD callback")
+ }
+ else if(temp_loc_init)
+ H5G_loc_free(&temp_loc);
+
+ /* Indicate that this callback didn't take ownership of the group *
+ * location for the object */
+ *own_obj_loc = FALSE;
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5L_link_cb() */
@@ -706,7 +1201,7 @@ done:
*/
static herr_t
H5L_create_real(H5G_loc_t *link_loc, const char *link_name, H5G_name_t *obj_path,
- H5F_t *obj_file, H5O_link_t *lnk, hid_t dxpl_id, hid_t lcpl_id)
+ H5F_t *obj_file, H5O_link_t *lnk, hid_t lcpl_id, hid_t lapl_id, hid_t dxpl_id)
{
char *norm_link_name = NULL; /* Pointer to normalized link name */
unsigned target_flags = H5G_TARGET_NORMAL; /* Flags to pass to group traversal function */
@@ -718,9 +1213,10 @@ H5L_create_real(H5G_loc_t *link_loc, const char *link_name, H5G_name_t *obj_path
FUNC_ENTER_NOAPI_NOINIT(H5L_create_real)
/* Check args */
+ HDassert(lnk);
HDassert(link_loc);
HDassert(link_name && *link_name);
- HDassert(lnk);
+ HDassert(lnk->type >= H5L_LINK_HARD && lnk->type <= H5L_LINK_MAX);
/* Get normalized link name */
if((norm_link_name = H5G_normalize(link_name)) == NULL)
@@ -746,6 +1242,9 @@ H5L_create_real(H5G_loc_t *link_loc, const char *link_name, H5G_name_t *obj_path
HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get property value for character encoding")
} /* end if */
+ /* Pass the lcpl to the link creation callback */
+ udata.lcpl_id = lcpl_id;
+
/* Fill in common data for the link struct */
lnk->cset = char_encoding;
#ifdef H5_HAVE_GETTIMEOFDAY
@@ -776,7 +1275,7 @@ H5L_create_real(H5G_loc_t *link_loc, const char *link_name, H5G_name_t *obj_path
udata.path = obj_path;
/* Traverse the destination path & create new link */
- if(H5G_traverse(link_loc, link_name, target_flags, H5L_link_cb, &udata, dxpl_id) < 0)
+ if(H5G_traverse(link_loc, link_name, target_flags, H5L_link_cb, &udata, lapl_id, dxpl_id) < 0)
HGOTO_ERROR(H5E_SYM, H5E_CANTINSERT, FAIL, "can't insert link")
done:
@@ -802,7 +1301,8 @@ done:
*/
static herr_t
H5L_create_hard(H5G_loc_t *cur_loc, const char *cur_name,
- H5G_loc_t *link_loc, const char *link_name, hid_t dxpl_id, hid_t lcpl_id)
+ H5G_loc_t *link_loc, const char *link_name, hid_t lcpl_id, hid_t lapl_id,
+ hid_t dxpl_id)
{
char *norm_cur_name = NULL; /* Pointer to normalized current name */
H5F_t *link_file = NULL; /* Pointer to file to link to */
@@ -826,7 +1326,7 @@ H5L_create_hard(H5G_loc_t *cur_loc, const char *cur_name,
lnk.type = H5L_LINK_HARD;
/* Get object location for object pointed to */
- if(H5G_obj_find(cur_loc, norm_cur_name, H5G_TARGET_NORMAL, NULL, &obj_oloc, dxpl_id) < 0)
+ if(H5G_obj_find(cur_loc, norm_cur_name, H5G_TARGET_NORMAL, NULL, &obj_oloc, lapl_id, dxpl_id) < 0)
HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "source object not found")
/* Construct link information for eventual insertion */
@@ -837,8 +1337,9 @@ H5L_create_hard(H5G_loc_t *cur_loc, const char *cur_name,
/* Create actual link to the object. Pass in NULL for the path, since this
* function shouldn't change an object's user path. */
- if(H5L_create_real(link_loc, link_name, NULL, link_file, &lnk, dxpl_id, lcpl_id) < 0)
- HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to register new name for object")
+ if(H5L_create_real(link_loc, link_name, NULL, link_file, &lnk, lcpl_id,
+ lapl_id, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTINIT, FAIL, "unable to create new link to object")
done:
/* Free the normalized path name */
@@ -863,7 +1364,7 @@ done:
*/
static herr_t
H5L_create_soft( const char *target_path, H5G_loc_t *link_loc,
- const char *link_name, hid_t dxpl_id, hid_t lcpl_id)
+ const char *link_name, hid_t lcpl_id, hid_t lapl_id, hid_t dxpl_id)
{
char *norm_target = NULL; /* Pointer to normalized current name */
H5O_link_t lnk; /* Link to insert */
@@ -885,8 +1386,9 @@ H5L_create_soft( const char *target_path, H5G_loc_t *link_loc,
lnk.u.soft.name = norm_target;
/* Create actual link to the object */
- if(H5L_create_real(link_loc, link_name, NULL, NULL, &lnk, dxpl_id, lcpl_id) < 0)
- HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to register new name for object")
+ if(H5L_create_real(link_loc, link_name, NULL, NULL, &lnk, lcpl_id,
+ lapl_id, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTINIT, FAIL, "unable to create new link to object")
done:
/* Free the normalized target name */
@@ -898,9 +1400,65 @@ done:
/*-------------------------------------------------------------------------
+ * Function: H5L_create_ud
+ *
+ * Purpose: Creates a user-defined link. See H5Lcreate_ud for
+ * full documentation.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: James Laird
+ * Friday, May 19, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5L_create_ud(H5G_loc_t *link_loc, const char *link_name, void * ud_data,
+ size_t ud_data_size, H5L_link_t type, unsigned traverse_flags,
+ hid_t lcpl_id, hid_t lapl_id, hid_t dxpl_id)
+{
+ H5O_link_t lnk; /* Link to insert */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT(H5L_create_ud)
+
+ /* Check args */
+ HDassert(type >= H5L_LINK_UD_MIN && type <= H5L_LINK_MAX);
+ HDassert(link_loc);
+ HDassert(link_name && *link_name);
+ HDassert(ud_data_size >= 0);
+ HDassert(ud_data_size == 0 || ud_data);
+
+ /* Make sure that this link class is registered */
+ if(H5L_find_class_idx(type) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "link class has not been registered with library")
+
+ /* Fill in UD link-specific information in the link struct*/
+ if(ud_data_size > 0)
+ {
+ lnk.u.ud.udata = H5MM_malloc((size_t) ud_data_size);
+ HDmemcpy(lnk.u.ud.udata, ud_data, (size_t) ud_data_size);
+ }
+ else
+ lnk.u.ud.udata = NULL;
+
+ lnk.u.ud.size = ud_data_size;
+ lnk.type = type;
+
+ /* Create actual link to the object */
+ if(H5L_create_real(link_loc, link_name, NULL, NULL, &lnk, lcpl_id,
+ lapl_id, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTINIT, FAIL, "unable to register new name for object")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5L_create_ud() */
+
+
+/*-------------------------------------------------------------------------
* Function: H5L_linkval_cb
*
- * Purpose: Callback for retrieving soft link value for an object.
+ * Purpose: Callback for retrieving link value or udata.
*
* Return: Non-negative on success/Negative on failure
*
@@ -911,10 +1469,11 @@ done:
*/
static herr_t
H5L_linkval_cb(H5G_loc_t UNUSED *grp_loc/*in*/, const char UNUSED *name, const H5O_link_t *lnk,
- H5G_loc_t UNUSED *obj_loc, void *_udata/*in,out*/)
+ H5G_loc_t UNUSED *obj_loc, void *_udata/*in,out*/, hbool_t *own_obj_loc/*out*/)
{
H5L_trav_ud5_t *udata = (H5L_trav_ud5_t *)_udata; /* User data passed in */
- herr_t ret_value = SUCCEED; /* Return value */
+ const H5L_link_class_t *link_class; /* User-defined link class */
+ herr_t ret_value = SUCCEED; /* Return value */
FUNC_ENTER_NOAPI_NOINIT(H5L_linkval_cb)
@@ -922,23 +1481,35 @@ H5L_linkval_cb(H5G_loc_t UNUSED *grp_loc/*in*/, const char UNUSED *name, const H
if(lnk == NULL)
HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "name doesn't exist")
- if(H5L_LINK_SOFT != lnk->type)
- HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "object is not a symbolic link")
-
- /* Copy to output buffer */
- if(udata->size > 0 && udata->buf) {
- HDstrncpy(udata->buf, lnk->u.soft.name, udata->size);
- if(HDstrlen(lnk->u.soft.name) >= udata->size)
- udata->buf[udata->size - 1] = '\0';
- } /* end if */
+ if(H5L_LINK_SOFT == lnk->type)
+ {
+ /* Copy to output buffer */
+ if(udata->size > 0 && udata->buf) {
+ HDstrncpy(udata->buf, lnk->u.soft.name, udata->size);
+ if(HDstrlen(lnk->u.soft.name) >= udata->size)
+ udata->buf[udata->size - 1] = '\0';
+ } /* end if */
+ }
+ else if(lnk->type >= H5L_LINK_UD_MIN)
+ {
+ /* Get the link class for this type of link. It's okay if the class isn't registered, though--we
+ * just can't give any more information about it */
+ link_class = H5L_find_class(lnk->type);
+
+ if(link_class != NULL && link_class->query_func != NULL) {
+ if((link_class->query_func)(lnk->name, lnk->u.ud.udata, lnk->u.ud.size, udata->buf, udata->size) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CALLBACK, FAIL, "query callback returned failure")
+ }
+ else if(udata->buf && udata->size > 0)
+ udata->buf[0] = '\0';
+ }
+ else
+ HGOTO_ERROR(H5E_LINK, H5E_BADTYPE, FAIL, "object is not a symbolic or user-defined link")
done:
- /* Release the group location for the object */
- /* (Group traversal callbacks are responsible for either taking ownership
- * of the group location for the object, or freeing it. - QAK)
- */
- if(obj_loc)
- H5G_loc_free(obj_loc);
+ /* Indicate that this callback didn't take ownership of the group *
+ * location for the object */
+ *own_obj_loc = FALSE;
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5L_linkval_cb() */
@@ -947,7 +1518,8 @@ done:
/*-------------------------------------------------------------------------
* Function: H5L_linkval
*
- * Purpose: Returns the value of a symbolic link.
+ * Purpose: Returns the value of a symbolic link or the udata for a
+ * user-defined link.
*
* Return: Success: Non-negative, with at most SIZE bytes of the
* link value copied into the BUF buffer. If the
@@ -963,7 +1535,7 @@ done:
*-------------------------------------------------------------------------
*/
static herr_t
-H5L_linkval(H5G_loc_t *loc, const char *name, size_t size, char *buf/*out*/, hid_t dxpl_id)
+H5L_linkval(H5G_loc_t *loc, const char *name, size_t size, char *buf/*out*/, hid_t lapl_id, hid_t dxpl_id)
{
H5L_trav_ud5_t udata; /* User data for callback */
herr_t ret_value = SUCCEED; /* Return value */
@@ -975,8 +1547,8 @@ H5L_linkval(H5G_loc_t *loc, const char *name, size_t size, char *buf/*out*/, hid
udata.buf = buf;
/* Traverse the group hierarchy to locate the object to get info about */
- if(H5G_traverse(loc, name, H5G_TARGET_SLINK, H5L_linkval_cb, &udata, dxpl_id) < 0)
- HGOTO_ERROR(H5E_SYM, H5E_EXISTS, FAIL, "name doesn't exist")
+ if(H5G_traverse(loc, name, H5G_TARGET_SLINK | H5G_TARGET_UDLINK, H5L_linkval_cb, &udata, lapl_id, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "name doesn't exist")
done:
FUNC_LEAVE_NOAPI(ret_value)
@@ -998,10 +1570,14 @@ done:
*/
static herr_t
H5L_unlink_cb(H5G_loc_t *grp_loc/*in*/, const char *name, const H5O_link_t UNUSED *lnk,
- H5G_loc_t *obj_loc, void *_udata/*in,out*/)
+ H5G_loc_t *obj_loc, void *_udata/*in,out*/, hbool_t *own_obj_loc/*out*/)
{
+ H5G_t *grp=NULL; /* H5G_t for this group, opened to pass to user callback */
+ hid_t grp_id = FAIL; /* Id for this group (passed to user callback */
H5L_trav_ud6_t *udata = (H5L_trav_ud6_t *)_udata; /* User data passed in */
- herr_t ret_value = SUCCEED; /* Return value */
+ H5G_loc_t temp_loc; /* For UD callback */
+ hbool_t temp_loc_init = FALSE;
+ herr_t ret_value = SUCCEED;
FUNC_ENTER_NOAPI_NOINIT(H5L_unlink_cb)
@@ -1011,19 +1587,57 @@ H5L_unlink_cb(H5G_loc_t *grp_loc/*in*/, const char *name, const H5O_link_t UNUSE
/* Check for removing '.' */
if(lnk == NULL)
- HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "can't delete self")
+ HGOTO_ERROR(H5E_SYM, H5E_CANTDELETE, FAIL, "can't delete self")
+
+ /* If there is a user-defined callback, call it before deleting the link */
+ if(lnk->type >= H5L_LINK_UD_MIN)
+ {
+ const H5L_link_class_t *link_class; /* User-defined link class */
+ H5O_loc_t temp_oloc;
+ H5G_name_t temp_path;
+
+ /* Get the link class for this type of link. */
+ if(NULL == (link_class = H5L_find_class(lnk->type)))
+ HGOTO_ERROR(H5E_LINK, H5E_NOTREGISTERED, FAIL, "link class not registered")
+
+ if(link_class->del_func != NULL)
+ {
+ H5G_name_reset(&temp_path);
+
+ if(H5O_loc_copy(&temp_oloc, grp_loc->oloc, H5_COPY_DEEP) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTCOPY, FAIL, "unable to copy object location")
+
+ temp_loc.oloc = &temp_oloc;
+ temp_loc.path = &temp_path;
+ temp_loc_init = TRUE;
+
+ /* Set up location for user-defined callback */
+ if((grp = H5G_open(&temp_loc, udata->dxpl_id)) == NULL)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTOPENOBJ, FAIL, "unable to open group")
+ if((grp_id = H5I_register(H5I_GROUP, grp)) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL, "unable to register group")
+
+ if((link_class->del_func)(name, grp_id, lnk->u.ud.udata, lnk->u.ud.size) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CALLBACK, FAIL, "link deletion callback returned failure")
+ }
+ }
/* Remove the link from the group */
if(H5G_loc_remove(grp_loc, name, obj_loc, udata->dxpl_id) < 0)
HGOTO_ERROR(H5E_SYM, H5E_CANTDELETE, FAIL, "unable to unlink name from group")
done:
- /* Release the group location for the object */
- /* (Group traversal callbacks are responsible for either taking ownership
- * of the group location for the object, or freeing it. - QAK)
- */
- if(obj_loc)
- H5G_loc_free(obj_loc);
+ /* Close the location given to the user callback if it was created */
+ if(grp_id >= 0)
+ H5I_dec_ref(grp_id);
+ else if(grp != NULL)
+ H5G_close(grp);
+ else if(temp_loc_init)
+ H5G_loc_free(&temp_loc);
+
+ /* Indicate that this callback didn't take ownership of the group *
+ * location for the object */
+ *own_obj_loc = FALSE;
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5L_unlink_cb() */
@@ -1042,7 +1656,7 @@ done:
*-------------------------------------------------------------------------
*/
static herr_t
-H5L_unlink(H5G_loc_t *loc, const char *name, hid_t dxpl_id)
+H5L_unlink(H5G_loc_t *loc, const char *name, hid_t lapl_id, hid_t dxpl_id)
{
H5L_trav_ud6_t udata; /* User data for callback */
char *norm_name = NULL; /* Pointer to normalized name */
@@ -1061,7 +1675,7 @@ H5L_unlink(H5G_loc_t *loc, const char *name, hid_t dxpl_id)
/* Set up user data for unlink operation */
udata.dxpl_id = dxpl_id;
- if(H5G_traverse(loc, norm_name, H5G_TARGET_SLINK|H5G_TARGET_MOUNT, H5L_unlink_cb, &udata, dxpl_id) < 0)
+ if(H5G_traverse(loc, norm_name, H5G_TARGET_SLINK|H5G_TARGET_UDLINK|H5G_TARGET_MOUNT, H5L_unlink_cb, &udata, lapl_id, dxpl_id) < 0)
HGOTO_ERROR(H5E_SYM, H5E_EXISTS, FAIL, "name doesn't exist")
done:
@@ -1089,10 +1703,14 @@ done:
*/
static herr_t
H5L_move_dest_cb(H5G_loc_t *grp_loc/*in*/, const char *name, const H5O_link_t *lnk,
- H5G_loc_t *obj_loc, void *_udata/*in,out*/)
+ H5G_loc_t *obj_loc, void *_udata/*in,out*/, hbool_t *own_obj_loc/*out*/)
{
H5L_trav_ud10_t *udata = (H5L_trav_ud10_t *)_udata; /* User data passed in */
H5RS_str_t *dst_name_r = NULL; /* Ref-counted version of dest name */
+ H5G_t *grp=NULL; /* H5G_t for this group, opened to pass to user callback */
+ hid_t grp_id = FAIL; /* Id for this group (passed to user callback */
+ H5G_loc_t temp_loc; /* For UD callback */
+ hbool_t temp_loc_init = FALSE;
herr_t ret_value = SUCCEED; /* Return value */
FUNC_ENTER_NOAPI_NOINIT(H5L_move_dest_cb)
@@ -1105,25 +1723,78 @@ H5L_move_dest_cb(H5G_loc_t *grp_loc/*in*/, const char *name, const H5O_link_t *l
if(udata->lnk->type == H5L_LINK_HARD) {
/* Check that both objects are in same file */
if(grp_loc->oloc->file->shared != udata->file->shared)
- HGOTO_ERROR(H5E_SYM, H5E_LINK, FAIL, "moving a link across files is not allowed")
+ HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "moving a link across files is not allowed")
} /* end if */
/* Give the object its new name */
/* Casting away const okay -JML */
udata->lnk->name = H5MM_xfree(udata->lnk->name);
- udata->lnk->name=name;
+ udata->lnk->name= (char *)name;
/* Insert the link into the group */
if(H5G_obj_insert(grp_loc->oloc, name, udata->lnk, (hbool_t)(udata->lnk->type == H5L_LINK_HARD ? TRUE : FALSE), udata->dxpl_id) < 0)
- HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to create new name/link for object")
+ HGOTO_ERROR(H5E_LINK, H5E_CANTINIT, FAIL, "unable to create new link to object")
+ /* If the link was a user-defined link, call its move callback if it has one */
+ if(udata->lnk->type >= H5L_LINK_UD_MIN)
+ {
+ const H5L_link_class_t *link_class; /* User-defined link class */
+ H5O_loc_t temp_oloc;
+ H5G_name_t temp_path;
+
+ /* Get the link class for this type of link. */
+ if(NULL == (link_class = H5L_find_class(udata->lnk->type)))
+ HGOTO_ERROR(H5E_LINK, H5E_NOTREGISTERED, FAIL, "link class is not registered")
+
+ if((!udata->copy && link_class->move_func != NULL) || (udata->copy && link_class->move_func))
+ {
+ /* Create a temporary location (or else H5G_open will do a shallow
+ * copy and wipe out grp_loc)
+ */
+ H5G_name_reset(&temp_path);
+ if(H5O_loc_copy(&temp_oloc, grp_loc->oloc, H5_COPY_DEEP) < 0)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTCOPY, FAIL, "unable to copy object location")
+
+ temp_loc.oloc = &temp_oloc;
+ temp_loc.path = &temp_path;
+ temp_loc_init = TRUE;
+
+ /* Set up location for user-defined callback */
+ if((grp = H5G_open(&temp_loc, udata->dxpl_id)) == NULL)
+ HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open group")
+ if((grp_id = H5I_register(H5I_GROUP, grp)) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL, "unable to register group ID")
+
+ if(udata->copy)
+ {
+ if((link_class->copy_func)(udata->lnk->name, grp_id, udata->lnk->u.ud.udata, udata->lnk->u.ud.size) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CALLBACK, FAIL, "UD copy callback returned error")
+ }
+ else
+ {
+ if((link_class->move_func)(udata->lnk->name, grp_id, udata->lnk->u.ud.udata, udata->lnk->u.ud.size) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CALLBACK, FAIL, "UD move callback returned error")
+ }
+ }
+ }
done:
- /* Release the group location for the object */
- /* (Group traversal callbacks are responsible for either taking ownership
- * of the group location for the object, or freeing it. - QAK)
- */
- if(obj_loc)
- H5G_loc_free(obj_loc);
+ /* Close the location given to the user callback if it was created */
+ if(grp_id >= 0)
+ {
+ if(H5I_dec_ref(grp_id) <0)
+ HDONE_ERROR(H5E_ATOM, H5E_CANTRELEASE, FAIL, "unable to close atom from UD callback")
+ }
+ else if(grp != NULL)
+ {
+ if(H5G_close(grp) <0)
+ HDONE_ERROR(H5E_FILE, H5E_CANTRELEASE, FAIL, "unable to close group given to UD callback")
+ }
+ else if(temp_loc_init)
+ H5G_loc_free(&temp_loc);
+
+ /* Indicate that this callback didn't take ownership of the group *
+ * location for the object */
+ *own_obj_loc = FALSE;
if(dst_name_r)
H5RS_decr(dst_name_r);
@@ -1147,7 +1818,7 @@ done:
*/
static herr_t
H5L_move_cb(H5G_loc_t *grp_loc/*in*/, const char *name, const H5O_link_t *lnk,
- H5G_loc_t *obj_loc, void *_udata/*in,out*/)
+ H5G_loc_t *obj_loc, void *_udata/*in,out*/, hbool_t *own_obj_loc/*out*/)
{
H5L_trav_ud4_t *udata = (H5L_trav_ud4_t *)_udata; /* User data passed in */
H5L_trav_ud10_t udata_out; /* User data for H5L_move_dest_cb traversal */
@@ -1178,21 +1849,24 @@ H5L_move_cb(H5G_loc_t *grp_loc/*in*/, const char *name, const H5O_link_t *lnk,
break;
default:
- HGOTO_ERROR(H5E_SYM, H5E_BADVALUE, FAIL, "unrecognized link type")
+ if(lnk->type < H5L_LINK_UD_MIN)
+ HGOTO_ERROR(H5E_LINK, H5E_BADTYPE, FAIL, "unrecognized link type")
+ type = H5G_UDLINK;
} /* end switch */
/* Set up user data for move_dest_cb */
if((udata_out.lnk = H5O_link_copy(lnk, NULL, 0)) == NULL)
- HGOTO_ERROR(H5E_SYM, H5E_CANTCOPY, FAIL, "unable to copy link to be moved");
+ HGOTO_ERROR(H5E_LINK, H5E_CANTCOPY, FAIL, "unable to copy link to be moved");
udata_out.lnk->cset = udata->cset;
udata_out.file = grp_loc->oloc->file;
+ udata_out.copy = udata->copy;
udata_out.dxpl_id = udata->dxpl_id;
/* Remember the link's original name (in case it's changed by H5G_name_replace) */
orig_name = H5MM_xstrdup(name);
/* Insert the link into its new location */
- if(H5G_traverse(udata->dst_loc, udata->dst_name, H5G_TARGET_NORMAL, H5L_move_dest_cb, &udata_out, udata->dxpl_id) < 0)
+ if(H5G_traverse(udata->dst_loc, udata->dst_name, H5G_TARGET_NORMAL, H5L_move_dest_cb, &udata_out, udata->lapl_id, udata->dxpl_id) < 0)
HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "unable to follow symbolic link")
/* If this is a move and not a copy operation, change the object's name and remove the old link */
@@ -1214,12 +1888,9 @@ done:
if(orig_name)
H5MM_xfree(orig_name);
- /* Release the group location for the object */
- /* (Group traversal callbacks are responsible for either taking ownership
- * of the group location for the object, or freeing it. - QAK)
- */
- if(obj_loc)
- H5G_loc_free(obj_loc);
+ /* Indicate that this callback didn't take ownership of the group *
+ * location for the object */
+ *own_obj_loc = FALSE;
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5L_move_cb() */
@@ -1247,12 +1918,15 @@ done:
*/
static herr_t
H5L_move(H5G_loc_t *src_loc, const char *src_name, H5G_loc_t *dst_loc,
- const char *dst_name, hbool_t copy_flag, hid_t lcpl_id, hid_t dxpl_id)
+ const char *dst_name, hbool_t copy_flag, hid_t lcpl_id,
+ hid_t lapl_id, hid_t dxpl_id)
{
- unsigned target_flags = H5G_TARGET_MOUNT|H5G_TARGET_SLINK; /* Flags to pass to group traversal function */
+ unsigned target_flags = H5G_TARGET_MOUNT|H5G_TARGET_SLINK|H5G_TARGET_UDLINK;
H5T_cset_t char_encoding = H5F_CRT_DEFAULT_CSET; /* Character encoding for link */
H5P_genplist_t* lc_plist; /* Link creation property list */
+ H5P_genplist_t* la_plist; /* Link access property list */
H5L_trav_ud4_t udata; /* User data for traversal */
+ hid_t lapl_copy; /* Copy of lapl for this function */
herr_t ret_value = SUCCEED; /* Return value */
FUNC_ENTER_NOAPI_NOINIT(H5L_move)
@@ -1284,15 +1958,29 @@ H5L_move(H5G_loc_t *src_loc, const char *src_name, H5G_loc_t *dst_loc,
HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get property value for character encoding")
} /* end if */
+ /* Copy the link access property list because traversing UD links will
+ * decrease the NLINKS property. HDF5 should have NLINKS traversals to
+ * get to the source and NLINKS more to get to the destination. */
+ if(lapl_id == H5P_DEFAULT) {
+ lapl_copy = lapl_id;
+ }
+ else {
+ if (NULL==(la_plist=H5I_object(lapl_id)))
+ HGOTO_ERROR(H5E_PLIST, H5E_BADTYPE, FAIL, "not a valid access PL")
+ if((lapl_copy=H5P_copy_plist(la_plist)) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINIT, FAIL, "unable to copy access properties")
+ }
+
/* Set up user data */
udata.dst_loc = dst_loc;
udata.dst_name= dst_name;
udata.cset = char_encoding;
udata.copy = copy_flag;
+ udata.lapl_id = lapl_copy;
udata.dxpl_id = dxpl_id;
/* Do the move */
- if(H5G_traverse(src_loc, src_name, H5G_TARGET_MOUNT|H5G_TARGET_SLINK, H5L_move_cb, &udata, dxpl_id) < 0)
+ if(H5G_traverse(src_loc, src_name, target_flags, H5L_move_cb, &udata, lapl_id, dxpl_id) < 0)
HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "unable to find link")
done:
@@ -1301,110 +1989,6 @@ done:
/*-------------------------------------------------------------------------
- * Function: H5L_get_lcpl_cb
- *
- * Purpose: Callback for getting a link's creation property list. This
- * routine gets properties from the link and sets them on the
- * copy of the default property list passed in.
- *
- * Return: Non-negative on success/Negative on failure
- *
- * Programmer: James Laird
- * Friday, January 27, 2006
- *
- *-------------------------------------------------------------------------
- */
-static herr_t
-H5L_get_lcpl_cb(H5G_loc_t UNUSED *grp_loc/*in*/, const char UNUSED *name, const H5O_link_t *lnk,
- H5G_loc_t UNUSED *obj_loc, void *_udata/*in,out*/)
-{
- H5L_trav_ud8_t *udata = (H5L_trav_ud8_t *)_udata; /* User data passed in */
- herr_t ret_value = SUCCEED; /* Return value */
-
- FUNC_ENTER_NOAPI_NOINIT(H5L_get_lcpl_cb)
-
- /* Check if the name in this group resolved to a valid link */
- if(lnk == NULL)
- HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "name doesn't exist")
-
- /* Set appropriate character encoding */
- if(H5P_set(udata->lcpl, H5P_CHAR_ENCODING_NAME, &(lnk->cset)) < 0)
- HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set property value for character encoding")
-
-done:
- /* Release the group location for the object */
- /* (Group traversal callbacks are responsible for either taking ownership
- * of the group location for the object, or freeing it. - QAK)
- */
- if(obj_loc)
- H5G_loc_free(obj_loc);
-
- FUNC_LEAVE_NOAPI(ret_value)
-} /* end H5L_get_lcpl_cb() */
-
-
-/*-------------------------------------------------------------------------
- * Function: H5L_get_create_plist
- *
- * Purpose: Returns a copy of the link's creation property list given
- * given a link's location and name.
- *
- * Return: Success: ID of the property list
- *
- * Failure: Negative
- *
- * Programmer: James Laird
- * Friday, January 27, 2006
- *
- *-------------------------------------------------------------------------
- */
-hid_t H5L_get_create_plist(H5G_loc_t *loc, const char* name)
-{
- H5P_genplist_t *plist; /* Default property list */
- H5P_genplist_t *plist_copy; /* Copy of list to be modified */
- hid_t lcpl_id=-1;
- H5L_trav_ud8_t udata; /* User data for traversal */
- char *norm_name = NULL; /* Pointer to normalized name */
- hid_t ret_value;
-
- FUNC_ENTER_NOAPI(H5L_get_create_plist, FAIL)
-
- /* Check arguments */
- HDassert(loc);
- HDassert(name && *name);
-
- /* Get normalized copy of the name */
- if((norm_name = H5G_normalize(name)) == NULL)
- HGOTO_ERROR(H5E_SYM, H5E_BADVALUE, FAIL, "can't normalize name")
-
- /* Get copy of default lcpl */
- if (NULL==(plist=H5I_object(H5P_LST_LINK_CREATE_g)))
- HGOTO_ERROR(H5E_PLIST, H5E_BADTYPE, FAIL, "can't get default LCPL")
- if((lcpl_id=H5P_copy_plist(plist)) < 0)
- HGOTO_ERROR(H5E_PLIST, H5E_CANTINIT, FAIL, "unable to copy attribute creation properties")
- if (NULL==(plist_copy=H5I_object(lcpl_id)))
- HGOTO_ERROR(H5E_PLIST, H5E_BADTYPE, FAIL, "can't get copy of LCPL")
-
- /* Set up user data */
- udata.lcpl = plist_copy;
-
- if(H5G_traverse(loc, norm_name, H5G_TARGET_SLINK|H5G_TARGET_MOUNT, H5L_get_lcpl_cb, &udata, H5AC_dxpl_id) < 0)
- HGOTO_ERROR(H5E_SYM, H5E_EXISTS, FAIL, "name doesn't exist")
-
- ret_value = lcpl_id;
-
-done:
- /* Free the normalized path name */
- if(norm_name)
- H5MM_xfree(norm_name);
- /* If we've created a new lcpl, close it */
- if(ret_value <0 && lcpl_id >= 0)
- H5P_close(H5I_object(lcpl_id));
- FUNC_LEAVE_NOAPI(ret_value)
-} /* end H5L_get_create_plist */
-
-
-/*-------------------------------------------------------------------------
* Function: H5L_get_linfo_cb
*
* Purpose: Callback for retrieving a link's metadata
@@ -1418,10 +2002,12 @@ done:
*/
static herr_t
H5L_get_linfo_cb(H5G_loc_t UNUSED *grp_loc/*in*/, const char UNUSED *name, const H5O_link_t *lnk,
- H5G_loc_t UNUSED *obj_loc, void *_udata/*in,out*/)
+ H5G_loc_t *obj_loc, void *_udata/*in,out*/, hbool_t *own_obj_loc/*out*/)
{
H5L_trav_ud1_t *udata = (H5L_trav_ud1_t *)_udata; /* User data passed in */
H5L_linkinfo_t *linfo = udata->linfo;
+ const H5L_link_class_t *link_class; /* User-defined link class */
+ ssize_t cb_ret; /* Return value from UD callback */
herr_t ret_value = SUCCEED; /* Return value */
FUNC_ENTER_NOAPI_NOINIT(H5L_get_linfo_cb)
@@ -1431,31 +2017,49 @@ H5L_get_linfo_cb(H5G_loc_t UNUSED *grp_loc/*in*/, const char UNUSED *name, const
HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "name doesn't exist")
/* Get information from the link */
- linfo->cset = lnk->cset;
- linfo->ctime = lnk->ctime;
- linfo->linkclass = lnk->type;
-
- switch(lnk->type)
+ if(linfo)
{
- case H5L_LINK_HARD:
- linfo->u.objno = lnk->u.hard.addr;
- break;
-
- case H5L_LINK_SOFT:
- linfo->u.link_size = HDstrlen(lnk->u.soft.name) + 1; /*count the null terminator*/
- break;
-
- default:
- HGOTO_ERROR(H5E_SYM, H5E_BADTYPE, FAIL, "unknown link type");
- }
+ linfo->cset = lnk->cset;
+ linfo->ctime = lnk->ctime;
+ linfo->linkclass = lnk->type;
+
+ switch(lnk->type)
+ {
+ case H5L_LINK_HARD:
+ linfo->u.address = lnk->u.hard.addr;
+ break;
+
+ case H5L_LINK_SOFT:
+ linfo->u.link_size = HDstrlen(lnk->u.soft.name) + 1; /*count the null terminator*/
+ break;
+
+ default:
+ if(lnk->type < H5L_LINK_UD_MIN || lnk->type > H5L_LINK_MAX)
+ HGOTO_ERROR(H5E_LINK, H5E_BADTYPE, FAIL, "unknown link class")
+
+ /* User-defined link; call its query function to get the link udata size. */
+ /* Get the link class for this type of link. It's okay if the class
+ * isn't registered, though--we just can't give any more information
+ * about it
+ */
+ link_class = H5L_find_class(lnk->type);
+
+ if(link_class != NULL && link_class->query_func != NULL) {
+ if((cb_ret = (link_class->query_func)(lnk->name, lnk->u.ud.udata, lnk->u.ud.size, NULL, 0)) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CALLBACK, FAIL, "query buffer size callback returned failure")
+
+ linfo->u.link_size = cb_ret;
+ }
+ else {
+ linfo->u.link_size = 0;
+ }
+ } /* end switch */
+ } /* end if */
done:
- /* Release the group location for the object */
- /* (Group traversal callbacks are responsible for either taking ownership
- * of the group location for the object, or freeing it. - QAK)
- */
- if(obj_loc)
- H5G_loc_free(obj_loc);
+ /* Indicate that this callback didn't take ownership of the group *
+ * location for the object */
+ *own_obj_loc = FALSE;
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5L_get_linfo_cb() */
@@ -1473,8 +2077,8 @@ done:
*
*-------------------------------------------------------------------------
*/
-static herr_t
-H5L_get_linkinfo(H5G_loc_t *loc, const char *name, H5L_linkinfo_t *linkbuf/*out*/, hid_t dxpl_id)
+herr_t
+H5L_get_linkinfo(const H5G_loc_t *loc, const char *name, H5L_linkinfo_t *linkbuf/*out*/, hid_t lapl_id, hid_t dxpl_id)
{
H5L_trav_ud1_t udata;
herr_t ret_value = SUCCEED; /* Return value */
@@ -1485,7 +2089,7 @@ H5L_get_linkinfo(H5G_loc_t *loc, const char *name, H5L_linkinfo_t *linkbuf/*out*
udata.dxpl_id = dxpl_id;
/* Traverse the group hierarchy to locate the object to get info about */
- if(H5G_traverse(loc, name, H5G_TARGET_SLINK, H5L_get_linfo_cb, &udata, dxpl_id) < 0)
+ if(H5G_traverse(loc, name, H5G_TARGET_SLINK|H5G_TARGET_UDLINK, H5L_get_linfo_cb, &udata, lapl_id, dxpl_id) < 0)
HGOTO_ERROR(H5E_SYM, H5E_EXISTS, FAIL, "name doesn't exist")
done:
@@ -1494,7 +2098,7 @@ done:
/*-------------------------------------------------------------------------
- * Function: H5L get_default_lcpl
+ * Function: H5L_get_default_lcpl
*
* Purpose: Accessor for the default Link Creation Property List
*