summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeil Fortner <nfortne2@hdfgroup.org>2009-01-08 18:16:31 (GMT)
committerNeil Fortner <nfortne2@hdfgroup.org>2009-01-08 18:16:31 (GMT)
commitd6da56adb76db4d8f4394e5d812697dd5b25909c (patch)
treeb4b91c7578bddde67d39f7ebb87d15ca0417a8f8
parent634c7c5a93abb49a56336eec9e842a0bd694f828 (diff)
downloadhdf5-d6da56adb76db4d8f4394e5d812697dd5b25909c.zip
hdf5-d6da56adb76db4d8f4394e5d812697dd5b25909c.tar.gz
hdf5-d6da56adb76db4d8f4394e5d812697dd5b25909c.tar.bz2
[svn-r16281] Purpose: Add functions to allow more flexible traversal of external links.
Description: Added H5Pset/get_elink_cb to allow the user to specify a callback function to be called whenever an external link is traversed. Added H5Pset/get_elink_acc_flags to allow the user to specify the file access flags to use to open the target file of an external link. All these properties are set on a LAPL. Tested: jam, linew, smirom (h5committest)
-rw-r--r--release_docs/RELEASE.txt14
-rw-r--r--src/H5Fprivate.h3
-rw-r--r--src/H5Fpublic.h4
-rw-r--r--src/H5Fquery.c26
-rw-r--r--src/H5Glink.c1
-rw-r--r--src/H5Gnode.c1
-rw-r--r--src/H5Lexternal.c90
-rw-r--r--src/H5Lprivate.h14
-rw-r--r--src/H5Lpublic.h7
-rw-r--r--src/H5Odbg.c1
-rw-r--r--src/H5Plapl.c181
-rw-r--r--src/H5Ppublic.h8
-rw-r--r--src/H5Tdeprec.c1
-rw-r--r--src/H5public.h3
-rw-r--r--test/links.c278
15 files changed, 606 insertions, 26 deletions
diff --git a/release_docs/RELEASE.txt b/release_docs/RELEASE.txt
index bfb30f8..b2a5bee 100644
--- a/release_docs/RELEASE.txt
+++ b/release_docs/RELEASE.txt
@@ -51,12 +51,18 @@ New Features
Library:
--------
+ - Added H5Pset_elink_cb and H5Pget_elink_cb functions to support a
+ user-defined callback function for external link traversal.
+ (NAF - 2009/01/08)
+ - Added H5Pset_elink_acc_flags and H5Pget_elink_acc_flags functions to
+ allow the user to specify the file access flags used to open the target
+ file of an external link. (NAF - 2009/01/08)
- Added H5Pset_chunk_cache() and H5Pget_chunk_cache() functions to allow
- individual rdcc configuration for each dataset. Added
- H5Dget_access_plist() function to retrieve a dataset access property
- list form a dataset. (NAF - 2008/11/12)
+ individual rdcc configuration for each dataset. Added
+ H5Dget_access_plist() function to retrieve a dataset access property
+ list from a dataset. (NAF - 2008/11/12)
- Added H5Iis_valid() function to check if an id is valid without producing
- an error message. (NAF - 2008/11/5)
+ an error message. (NAF - 2008/11/5)
- Added two new public routines: H5Pget_elink_fapl() and
H5Pset_elink_fapl(). (see bug #1247) (VC - 2008/10/13)
- Improved free space tracking in file to be faster. (QAK - 2008/10/06)
diff --git a/src/H5Fprivate.h b/src/H5Fprivate.h
index fb28c4e..e717b99 100644
--- a/src/H5Fprivate.h
+++ b/src/H5Fprivate.h
@@ -259,6 +259,7 @@ typedef struct H5F_blk_aggr_t H5F_blk_aggr_t;
#define H5F_GC_REF(F) ((F)->shared->gc_ref)
#define H5F_USE_LATEST_FORMAT(F) ((F)->shared->latest_format)
#define H5F_EXTPATH(F) ((F)->extpath)
+#define H5F_NAME(F) ((F)->name)
#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_HAS_FEATURE(F,FL) ((F)->shared->lf->feature_flags & (FL))
@@ -280,6 +281,7 @@ typedef struct H5F_blk_aggr_t H5F_blk_aggr_t;
#define H5F_GC_REF(F) (H5F_gc_ref(F))
#define H5F_USE_LATEST_FORMAT(F) (H5F_use_latest_format(F))
#define H5F_EXTPATH(F) (H5F_get_extpath(F))
+#define H5F_NAME(F) (H5F_get_name(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_HAS_FEATURE(F,FL) (H5F_has_feature(F,FL))
@@ -466,6 +468,7 @@ H5_DLL unsigned H5F_decr_nopen_objs(H5F_t *f);
H5_DLL unsigned H5F_get_intent(const H5F_t *f);
H5_DLL hid_t H5F_get_access_plist(H5F_t *f, hbool_t app_ref);
H5_DLL char *H5F_get_extpath(const H5F_t *f);
+H5_DLL char *H5F_get_name(const H5F_t *f);
H5_DLL hid_t H5F_get_id(H5F_t *file, hbool_t app_ref);
H5_DLL size_t H5F_get_obj_count(const H5F_t *f, unsigned types, hbool_t app_ref);
H5_DLL size_t H5F_get_obj_ids(const H5F_t *f, unsigned types, size_t max_objs, hid_t *obj_id_list, hbool_t app_ref);
diff --git a/src/H5Fpublic.h b/src/H5Fpublic.h
index 312d92e..287e9b5 100644
--- a/src/H5Fpublic.h
+++ b/src/H5Fpublic.h
@@ -50,6 +50,10 @@
#define H5F_ACC_DEBUG (H5CHECK 0x0008u) /*print debug info */
#define H5F_ACC_CREAT (H5CHECK 0x0010u) /*create non-existing files */
+/* Value passed to H5Pset_elink_acc_flags to cause flags to be taken from the
+ * parent file. */
+#define H5F_ACC_DEFAULT (H5CHECK 0xffffu) /*ignore setting on lapl */
+
/* Flags for H5Fget_obj_count() & H5Fget_obj_ids() calls */
#define H5F_OBJ_FILE (0x0001u) /* File objects */
#define H5F_OBJ_DATASET (0x0002u) /* Dataset objects */
diff --git a/src/H5Fquery.c b/src/H5Fquery.c
index 550a507..275061d 100644
--- a/src/H5Fquery.c
+++ b/src/H5Fquery.c
@@ -130,6 +130,32 @@ H5F_get_extpath(const H5F_t *f)
/*-------------------------------------------------------------------------
+ * Function: H5F_get_name
+ *
+ * Purpose: Retrieve the name of a file.
+ *
+ * Return: Success: The name of the file.
+ *
+ * Failure: ? (should not happen)
+ *
+ * Programmer: Neil Fortner
+ * December 15 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+char *
+H5F_get_name(const H5F_t *f)
+{
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOFUNC here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5F_get_name)
+
+ HDassert(f);
+
+ FUNC_LEAVE_NOAPI(f->name)
+} /* end H5F_get_name() */
+
+
+/*-------------------------------------------------------------------------
* Function: H5F_get_fcpl
*
* Purpose: Retrieve the value of a file's FCPL.
diff --git a/src/H5Glink.c b/src/H5Glink.c
index 9527521..7051453 100644
--- a/src/H5Glink.c
+++ b/src/H5Glink.c
@@ -41,6 +41,7 @@
#include "H5Iprivate.h" /* IDs */
#include "H5Lprivate.h" /* Links */
#include "H5MMprivate.h" /* Memory management */
+#include "H5Ppublic.h" /* Property Lists */
/****************/
diff --git a/src/H5Gnode.c b/src/H5Gnode.c
index 9468302..6b16544 100644
--- a/src/H5Gnode.c
+++ b/src/H5Gnode.c
@@ -39,6 +39,7 @@
#include "H5HLprivate.h" /* Local Heaps */
#include "H5MFprivate.h" /* File memory management */
#include "H5MMprivate.h" /* Memory management */
+#include "H5Ppublic.h" /* Property Lists */
/* Private typedefs */
diff --git a/src/H5Lexternal.c b/src/H5Lexternal.c
index 46ed467..2c6b3a3 100644
--- a/src/H5Lexternal.c
+++ b/src/H5Lexternal.c
@@ -197,6 +197,9 @@ H5L_extern_traverse(const char UNUSED *link_name, hid_t cur_group,
const char *obj_name; /* Name external link's object */
size_t fname_len; /* Length of external link file name */
unsigned intent; /* File access permissions */
+ H5L_elink_cb_t cb_info; /* Callback info struct */
+ const char *parent_file_name = NULL; /* Parent file name */
+ const char *parent_group_name = NULL; /* Parent group name */
hid_t fapl_id = -1; /* File access property list for external link's file */
hid_t ext_obj = -1; /* ID for external link's object */
hid_t ret_value; /* Return value */
@@ -237,15 +240,68 @@ H5L_extern_traverse(const char UNUSED *link_name, hid_t cur_group,
if(H5G_loc(cur_group, &loc) < 0)
HGOTO_ERROR(H5E_LINK, H5E_CANTGET, FAIL, "can't get object location")
- /* get the file access mode flags for the parent file */
- intent = H5F_INTENT(loc.oloc->file);
+ /* get the access flags set for lapl_id if any */
+ if(H5P_get(plist, H5L_ACS_ELINK_FLAGS_NAME, &intent) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get elink file access flags")
- if ((fapl_id == H5P_DEFAULT) && ((fapl_id = H5F_get_access_plist(loc.oloc->file, FALSE)) < 0))
+ /* get the file access mode flags for the parent file, if they were not set
+ * on lapl_id */
+ if(intent == H5F_ACC_DEFAULT)
+ intent = H5F_INTENT(loc.oloc->file);
+
+ if((fapl_id == H5P_DEFAULT) && ((fapl_id = H5F_get_access_plist(loc.oloc->file, FALSE)) < 0))
HGOTO_ERROR(H5E_LINK, H5E_CANTGET, FAIL, "can't get parent's file access property list")
- /* Set file close degree for new file to "weak" */
+ /* Get callback_info */
+ if(H5P_get(plist, H5L_ACS_ELINK_CB_NAME, &cb_info)<0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get elink callback info")
+
+ /* Get file access property list */
if(NULL == (fa_plist = H5P_object_verify(fapl_id, H5P_FILE_ACCESS)))
HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Make callback if it exists */
+ if(cb_info.func) {
+ /* Get parent file name */
+ parent_file_name = H5F_NAME(loc.oloc->file);
+
+ /* Get parent group name */
+ if(loc.path->user_path_r != NULL && loc.path->obj_hidden == 0)
+ /* Use user_path_r if possible */
+ parent_group_name = H5RS_get_str(loc.path->user_path_r);
+ else {
+ /* Otherwise use H5G_get_name */
+ ssize_t group_name_len; /* Length of parent group name */
+
+ /* Get length of parent group name */
+ if((group_name_len = H5G_get_name(cur_group, NULL, (size_t) 0, lapl_id, H5AC_ind_dxpl_id)) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTGET, FAIL, "unable to retrieve length of group name")
+
+ /* account for null terminator */
+ group_name_len++;
+
+ /* Copy parent group name */
+ if(NULL == (tempname = (char *) H5MM_malloc((size_t) group_name_len)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
+ if(H5G_get_name(cur_group, tempname, (size_t) group_name_len, lapl_id, H5AC_ind_dxpl_id) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTGET, FAIL, "unable to retrieve group name")
+ parent_group_name = tempname;
+ } /* end else */
+
+ /* Make callback */
+ if((cb_info.func)(parent_file_name, parent_group_name, file_name, obj_name,
+ &intent, fapl_id, cb_info.user_data) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CALLBACK, FAIL, "traversal operator failed")
+
+ /* Free tempname */
+ tempname = (char *)H5MM_xfree(tempname);
+
+ /* Check access flags */
+ if((intent & H5F_ACC_TRUNC) || (intent & H5F_ACC_EXCL))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid file open flags")
+ } /* end if */
+
+ /* Set file close degree for new file to "weak" */
if(H5P_set(fa_plist, H5F_ACS_CLOSE_DEGREE_NAME, &fc_degree) < 0)
HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set file close degree")
@@ -277,7 +333,8 @@ H5L_extern_traverse(const char UNUSED *link_name, hid_t cur_group,
/* try searching from paths set in the environment variable */
if ((ext_file == NULL) && (env_prefix=HDgetenv("HDF5_EXT_PREFIX"))) {
- tmp_env_prefix = H5MM_strdup(env_prefix);
+ if ((tmp_env_prefix = H5MM_strdup(env_prefix)) == NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
pp = tmp_env_prefix;
while ((tmp_env_prefix) && (*tmp_env_prefix)) {
@@ -290,14 +347,13 @@ H5L_extern_traverse(const char UNUSED *link_name, hid_t cur_group,
ext_file = H5F_open(full_name, ((intent & H5F_ACC_RDWR) ? H5F_ACC_RDWR : H5F_ACC_RDONLY),
H5P_FILE_CREATE_DEFAULT, fapl_id, H5AC_dxpl_id);
if (full_name)
- H5MM_xfree(full_name);
+ H5MM_free(full_name);
if (ext_file != NULL)
break;
H5E_clear_stack(NULL);
}
} /* end while */
- if (pp)
- H5MM_xfree(pp);
+ pp = (char *)H5MM_xfree(pp);
}
/* try searching from property list */
@@ -311,7 +367,7 @@ H5L_extern_traverse(const char UNUSED *link_name, hid_t cur_group,
H5P_FILE_CREATE_DEFAULT, fapl_id, H5AC_dxpl_id)) == NULL)
H5E_clear_stack(NULL);
if (full_name)
- H5MM_xfree(full_name);
+ H5MM_free(full_name);
}
}
@@ -323,7 +379,7 @@ H5L_extern_traverse(const char UNUSED *link_name, hid_t cur_group,
H5P_FILE_CREATE_DEFAULT, fapl_id, H5AC_dxpl_id)) == NULL)
H5E_clear_stack(NULL);
if (full_name)
- H5MM_xfree(full_name);
+ H5MM_free(full_name);
}
/* try the relative file_name stored in tempname */
@@ -333,8 +389,7 @@ H5L_extern_traverse(const char UNUSED *link_name, hid_t cur_group,
HGOTO_ERROR(H5E_LINK, H5E_CANTOPENFILE, FAIL, "unable to open external file")
}
- if (tempname)
- H5MM_xfree(tempname);
+ tempname = (char *)H5MM_xfree(tempname);
/* Increment the number of open objects, to hold the file open */
H5F_incr_nopen_objs(ext_file);
@@ -367,9 +422,14 @@ done:
if(ext_file && H5F_try_close(ext_file) < 0)
HDONE_ERROR(H5E_LINK, H5E_CANTCLOSEFILE, FAIL, "problem closing external file")
- /* Close object if it's open and something failed */
- if(ret_value < 0 && ext_obj >= 0 && H5I_dec_ref(ext_obj, FALSE) < 0)
- HDONE_ERROR(H5E_ATOM, H5E_CANTRELEASE, FAIL, "unable to close atom for external object")
+ if(ret_value < 0) {
+ H5MM_xfree(tempname);
+ H5MM_xfree(pp);
+
+ /* Close object if it's open and something failed */
+ if(ext_obj >= 0 && H5I_dec_ref(ext_obj, FALSE) < 0)
+ HDONE_ERROR(H5E_ATOM, H5E_CANTRELEASE, FAIL, "unable to close atom for external object")
+ } /* end if */
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5L_extern_traverse() */
diff --git a/src/H5Lprivate.h b/src/H5Lprivate.h
index cd17a87..f3079bc 100644
--- a/src/H5Lprivate.h
+++ b/src/H5Lprivate.h
@@ -39,15 +39,23 @@
#define H5L_CRT_INTERMEDIATE_GROUP_NAME "intermediate_group" /* Create intermediate groups flag */
/* ======== Link access property names ======== */
-#define H5L_ACS_NLINKS_NAME "max soft links" /* Number of soft links to traverse */
-#define H5L_ACS_ELINK_PREFIX_NAME "external link prefix" /* External link prefix */
-#define H5L_ACS_ELINK_FAPL_NAME "external link fapl" /* file access property list for external link access */
+#define H5L_ACS_NLINKS_NAME "max soft links" /* Number of soft links to traverse */
+#define H5L_ACS_ELINK_PREFIX_NAME "external link prefix" /* External link prefix */
+#define H5L_ACS_ELINK_FAPL_NAME "external link fapl" /* file access property list for external link access */
+#define H5L_ACS_ELINK_FLAGS_NAME "external link flags" /* file access flags for external link traversal */
+#define H5L_ACS_ELINK_CB_NAME "external link callback" /* callback function for external link traversal */
/****************************/
/* Library Private Typedefs */
/****************************/
+/* Structure for external link traversal callback property */
+typedef struct H5L_elink_cb_t {
+ H5L_elink_traverse_t func;
+ void *user_data;
+} H5L_elink_cb_t;
+
/*****************************/
/* Library Private Variables */
diff --git a/src/H5Lpublic.h b/src/H5Lpublic.h
index eba09b2..620d2e9 100644
--- a/src/H5Lpublic.h
+++ b/src/H5Lpublic.h
@@ -29,7 +29,6 @@
/* Public headers needed by this file */
#include "H5public.h" /* Generic Functions */
#include "H5Ipublic.h" /* IDs */
-#include "H5Ppublic.h" /* Property lists */
#include "H5Tpublic.h" /* Datatypes */
/*****************/
@@ -131,6 +130,12 @@ typedef struct {
typedef herr_t (*H5L_iterate_t)(hid_t group, const char *name, const H5L_info_t *info,
void *op_data);
+/* Callback for external link traversal */
+typedef herr_t (*H5L_elink_traverse_t)(const char *parent_file_name,
+ const char *parent_group_name, const char *child_file_name,
+ const char *child_object_name, unsigned *acc_flags, hid_t fapl_id,
+ void *op_data);
+
/********************/
/* Public Variables */
diff --git a/src/H5Odbg.c b/src/H5Odbg.c
index 7a49f75..8a8b783 100644
--- a/src/H5Odbg.c
+++ b/src/H5Odbg.c
@@ -37,6 +37,7 @@
#include "H5Eprivate.h" /* Error handling */
#include "H5MMprivate.h" /* Memory management */
#include "H5Opkg.h" /* Object headers */
+#include "H5Ppublic.h" /* Property Lists */
/****************/
/* Local Macros */
diff --git a/src/H5Plapl.c b/src/H5Plapl.c
index e7b4381..664dab2 100644
--- a/src/H5Plapl.c
+++ b/src/H5Plapl.c
@@ -62,6 +62,14 @@
#define H5L_ACS_ELINK_FAPL_COPY H5P_lacc_elink_fapl_copy
#define H5L_ACS_ELINK_FAPL_CLOSE H5P_lacc_elink_fapl_close
+/* Definitions for file access flags for external link traversal */
+#define H5L_ACS_ELINK_FLAGS_SIZE sizeof(unsigned)
+#define H5L_ACS_ELINK_FLAGS_DEF H5F_ACC_DEFAULT
+
+/* Definitions for callback function for external link traversal */
+#define H5L_ACS_ELINK_CB_SIZE sizeof(H5L_elink_cb_t)
+#define H5L_ACS_ELINK_CB_DEF {NULL,NULL}
+
/******************/
/* Local Typedefs */
/******************/
@@ -142,6 +150,9 @@ H5P_lacc_reg_prop(H5P_genclass_t *pclass)
size_t nlinks = H5L_ACS_NLINKS_DEF; /* Default number of soft links to traverse */
char *elink_prefix = H5L_ACS_ELINK_PREFIX_DEF; /* Default external link prefix string */
hid_t def_fapl_id = H5L_ACS_ELINK_FAPL_DEF; /* Default fapl for external link access */
+ unsigned elink_flags = H5L_ACS_ELINK_FLAGS_DEF; /* Default file access flags for external link traversal */
+ H5L_elink_cb_t elink_cb = H5L_ACS_ELINK_CB_DEF; /* Default external link traversal callback */
+
herr_t ret_value = SUCCEED; /* Return value */
FUNC_ENTER_NOAPI_NOINIT(H5P_lacc_reg_prop)
@@ -160,6 +171,16 @@ H5P_lacc_reg_prop(H5P_genclass_t *pclass)
if(H5P_register(pclass, H5L_ACS_ELINK_FAPL_NAME, H5L_ACS_ELINK_FAPL_SIZE, &def_fapl_id, NULL, NULL, NULL, H5L_ACS_ELINK_FAPL_DEL, H5L_ACS_ELINK_FAPL_COPY, NULL, H5L_ACS_ELINK_FAPL_CLOSE) < 0)
HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+ /* Register property for external link file access flags */
+ if(H5P_register(pclass, H5L_ACS_ELINK_FLAGS_NAME, H5L_ACS_ELINK_FLAGS_SIZE,
+ &elink_flags, NULL, NULL, NULL, NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
+ /* Register property for external link file traversal callback */
+ if(H5P_register(pclass, H5L_ACS_ELINK_CB_NAME, H5L_ACS_ELINK_CB_SIZE,
+ &elink_cb, NULL, NULL, NULL, NULL, NULL, NULL, NULL) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")
+
done:
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5P_lacc_reg_prop() */
@@ -634,3 +655,163 @@ done:
FUNC_LEAVE_API(ret_value);
} /* end H5Pget_elink_fapl() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_elink_acc_flags
+ *
+ * Purpose: Sets the file access flags to be used when traversing an
+ * external link. This should be either H5F_ACC_RDONLY or
+ * H5F_ACC_RDWR, or H5F_ACC_DEFAULT to unset the value.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * Tuesday, December 9, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_elink_acc_flags(hid_t lapl_id, unsigned flags)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(H5Pset_elink_acc_flags, FAIL)
+
+ /* Check that flags are valid */
+ if((flags != H5F_ACC_RDWR) && (flags != H5F_ACC_RDONLY) && (flags != H5F_ACC_DEFAULT))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid file open flags")
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(lapl_id, H5P_LINK_ACCESS)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Set flags */
+ if(H5P_set(plist, H5L_ACS_ELINK_FLAGS_NAME, &flags) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set access flags")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_elink_acc_flags() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_elink_acc_flags
+ *
+ * Purpose: Gets the file access flags to be used when traversing an
+ * external link.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * Tuesday, December 9, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_elink_acc_flags(hid_t lapl_id, unsigned *flags)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(H5Pget_elink_acc_flags, FAIL)
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(lapl_id, H5P_LINK_ACCESS)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Get flags */
+ if (flags)
+ if(H5P_get(plist, H5L_ACS_ELINK_FLAGS_NAME, flags)<0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, 0, "can't get access flags")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_elink_acc_flags() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_elink_cb
+ *
+ * Purpose: Sets the file access flags to be used when traversing an
+ * external link. This should be either H5F_ACC_RDONLY or
+ * H5F_ACC_RDWR.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * Tuesday, December 15, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_elink_cb(hid_t lapl_id, H5L_elink_traverse_t func, void *op_data)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ H5L_elink_cb_t cb_info; /* Callback info struct */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(H5Pset_elink_cb, FAIL)
+
+ /* Check if the callback function is NULL and the user data is non-NULL.
+ * This is almost certainly an error as the user data will not be used. */
+ if(!func && op_data)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "callback is NULL while user data is not")
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(lapl_id, H5P_LINK_ACCESS)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Populate the callback info struct */
+ cb_info.func = func;
+ cb_info.user_data = op_data;
+
+ /* Set callback info */
+ if(H5P_set(plist, H5L_ACS_ELINK_CB_NAME, &cb_info) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set callback info")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_elink_acc_flags() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_elink_cb
+ *
+ * Purpose: Gets the file access flags to be used when traversing an
+ * external link.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Neil Fortner
+ * Tuesday, December 15, 2008
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_elink_cb(hid_t lapl_id, H5L_elink_traverse_t *func, void **op_data)
+{
+ H5P_genplist_t *plist; /* Property list pointer */
+ H5L_elink_cb_t cb_info; /* Callback info struct */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(H5Pget_elink_cb, FAIL)
+
+ /* Get the plist structure */
+ if(NULL == (plist = H5P_object_verify(lapl_id, H5P_LINK_ACCESS)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")
+
+ /* Get callback_info */
+ if(H5P_get(plist, H5L_ACS_ELINK_CB_NAME, &cb_info)<0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get callback info")
+
+ if(func)
+ *func = cb_info.func;
+
+ if(op_data)
+ *op_data = cb_info.user_data;
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_elink_cb() */
+
diff --git a/src/H5Ppublic.h b/src/H5Ppublic.h
index 498eecc..a67ea71 100644
--- a/src/H5Ppublic.h
+++ b/src/H5Ppublic.h
@@ -29,6 +29,7 @@
#include "H5Fpublic.h"
#include "H5FDpublic.h"
#include "H5Ipublic.h"
+#include "H5Lpublic.h"
#include "H5MMpublic.h"
#include "H5Tpublic.h"
#include "H5Zpublic.h"
@@ -46,9 +47,6 @@
#define H5OPEN
#endif /* _H5private_H */
-/* Default value for all property list classes */
-#define H5P_DEFAULT 0
-
/*
* The library's property list classes
*/
@@ -384,6 +382,10 @@ H5_DLL herr_t H5Pset_elink_prefix(hid_t plist_id, const char *prefix);
H5_DLL ssize_t H5Pget_elink_prefix(hid_t plist_id, char *prefix, size_t size);
H5_DLL hid_t H5Pget_elink_fapl(hid_t lapl_id);
H5_DLL herr_t H5Pset_elink_fapl(hid_t lapl_id, hid_t fapl_id);
+H5_DLL herr_t H5Pset_elink_acc_flags(hid_t lapl_id, unsigned flags);
+H5_DLL herr_t H5Pget_elink_acc_flags(hid_t lapl_id, unsigned *flags);
+H5_DLL herr_t H5Pset_elink_cb(hid_t lapl_id, H5L_elink_traverse_t func, void *op_data);
+H5_DLL herr_t H5Pget_elink_cb(hid_t lapl_id, H5L_elink_traverse_t *func, void **op_data);
/* Object copy property list (OCPYPL) routines */
H5_DLL herr_t H5Pset_copy_object(hid_t plist_id, unsigned crt_intmd);
diff --git a/src/H5Tdeprec.c b/src/H5Tdeprec.c
index df6238c..0314a38 100644
--- a/src/H5Tdeprec.c
+++ b/src/H5Tdeprec.c
@@ -44,6 +44,7 @@
#include "H5Eprivate.h" /* Error handling */
#include "H5FOprivate.h" /* File objects */
#include "H5Iprivate.h" /* IDs */
+#include "H5Ppublic.h" /* Property Lists */
#include "H5Tpkg.h" /* Datatypes */
diff --git a/src/H5public.h b/src/H5public.h
index e926473..cf9ff14 100644
--- a/src/H5public.h
+++ b/src/H5public.h
@@ -264,6 +264,9 @@ typedef signed long_long hssize_t;
# error "nothing appropriate for uint64_t"
#endif
+/* Default value for all property list classes */
+#define H5P_DEFAULT 0
+
/* Common iteration orders */
typedef enum {
H5_ITER_UNKNOWN = -1, /* Unknown order */
diff --git a/test/links.c b/test/links.c
index 433e9f8..cab5f6e 100644
--- a/test/links.c
+++ b/test/links.c
@@ -76,6 +76,10 @@ const char *FILENAME[] = {
"extlinks16A", /* 37: */ /* TESTS for H5P_set_elink_fapl */
"extlinks16B", /* 38: */
"extlinks17", /* 39: */
+ "extlinks18A", /* 40: */
+ "extlinks18B", /* 41: */
+ "extlinks19A", /* 42: */
+ "extlinks19B", /* 43: */
NULL
};
@@ -3947,6 +3951,278 @@ external_set_elink_fapl3(hbool_t new_format)
} /* end external_set_elink_fapl3() */
+/*-------------------------------------------------------------------------
+ * Function: external_set_elink_acc_flags
+ *
+ * Purpose: Verify functionality of H5P_set/get_elink_acc_flags
+ *
+ * Return: Success: 0
+ * Failure: -1
+ *
+ * Programmer: Neil Fortner
+ * Jan. 5, 2009
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+external_set_elink_acc_flags(hid_t fapl, hbool_t new_format)
+{
+ hid_t file1, file2, group, subgroup, gapl;
+ char filename1[NAME_BUF_SIZE],
+ filename2[NAME_BUF_SIZE];
+ unsigned flags;
+
+ if(new_format)
+ TESTING("H5Pset/get_elink_acc_flags() (w/new group format)")
+ else
+ TESTING("H5Pset/get_elink_acc_flags()")
+
+ /* Create parent and target files, and external link */
+ h5_fixname(FILENAME[40], fapl, filename1, sizeof filename1);
+ h5_fixname(FILENAME[41], fapl, filename2, sizeof filename2);
+ if ((file1 = H5Fcreate(filename1, H5F_ACC_TRUNC, H5P_DEFAULT, fapl)) < 0) TEST_ERROR
+ if ((file2 = H5Fcreate(filename2, H5F_ACC_TRUNC, H5P_DEFAULT, fapl)) < 0) TEST_ERROR
+ if (H5Lcreate_external(filename2, "/", file1, "ext_link", H5P_DEFAULT, H5P_DEFAULT) < 0) TEST_ERROR
+
+ /* Close file2, leave file1 open (should be read-write) */
+ if (H5Fclose(file2) < 0) TEST_ERROR
+
+ /* Create new gapl, and set elink access flags to be H5F_ACC_RDONLY */
+ if ((gapl = H5Pcreate(H5P_GROUP_ACCESS)) < 0) TEST_ERROR
+ if (H5Pset_elink_acc_flags(gapl, H5F_ACC_RDONLY) < 0) TEST_ERROR
+
+ /* Verify "get" routine functionality */
+ if (H5Pget_elink_acc_flags(gapl, &flags) < 0) TEST_ERROR
+ if (flags != H5F_ACC_RDONLY) TEST_ERROR
+
+ /* Attempt to create a group through the external link using gapl (should fail) */
+ H5E_BEGIN_TRY {
+ group = H5Gcreate2(file1, "/ext_link/group", H5P_DEFAULT, H5P_DEFAULT, gapl);
+ } H5E_END_TRY;
+ if (group != FAIL) TEST_ERROR
+
+ /* Close file1 and reopen with read only access */
+ if (H5Fclose(file1) < 0) TEST_ERROR
+ if ((file1 = H5Fopen(filename1, H5F_ACC_RDONLY, fapl)) < 0) TEST_ERROR
+
+ /* Set elink access flags on gapl to be H5F_ACC_RDWR */
+ if (H5Pset_elink_acc_flags(gapl, H5F_ACC_RDWR) < 0) TEST_ERROR
+
+ /* Create a group through the external link using gapl (should succeed) */
+ if ((group = H5Gcreate2(file1, "/ext_link/group", H5P_DEFAULT, H5P_DEFAULT, gapl)) < 0) TEST_ERROR
+
+ /* Unset elink access flags on gapl */
+ if (H5Pset_elink_acc_flags(gapl, H5F_ACC_DEFAULT) < 0) TEST_ERROR
+
+ /* Attempt to create a group through the external link using gapl (should fail) */
+ H5E_BEGIN_TRY {
+ subgroup = H5Gcreate2(file1, "/ext_link/group/subgroup", H5P_DEFAULT, H5P_DEFAULT, gapl);
+ } H5E_END_TRY;
+ if (subgroup != FAIL) TEST_ERROR
+
+ /* Close file1 and group */
+ if (H5Gclose(group) < 0) TEST_ERROR
+ if (H5Fclose(file1) < 0) TEST_ERROR
+
+ /* Verify that H5Fcreate and H5Fopen reject H5F_ACC_DEFAULT */
+ H5E_BEGIN_TRY {
+ file1 = H5Fcreate(filename1, H5F_ACC_DEFAULT, H5P_DEFAULT, fapl);
+ } H5E_END_TRY;
+ if (file1 != FAIL) TEST_ERROR
+ H5E_BEGIN_TRY {
+ file1 = H5Fcreate(filename1, H5F_ACC_TRUNC | H5F_ACC_DEFAULT, H5P_DEFAULT, fapl);
+ } H5E_END_TRY;
+ if (file1 != FAIL) TEST_ERROR
+ H5E_BEGIN_TRY {
+ file1 = H5Fopen(filename1, H5F_ACC_DEFAULT, fapl);
+ } H5E_END_TRY;
+ if (file1 != FAIL) TEST_ERROR
+ H5E_BEGIN_TRY {
+ file1 = H5Fopen(filename1, H5F_ACC_RDWR | H5F_ACC_DEFAULT, fapl);
+ } H5E_END_TRY;
+ if (file1 != FAIL) TEST_ERROR
+
+ /* Close gapl */
+ if (H5Pclose(gapl) < 0) TEST_ERROR
+
+ PASSED();
+ return 0;
+
+ error:
+ H5E_BEGIN_TRY {
+ H5Gclose(group);
+ H5Gclose(subgroup);
+ H5Fclose(file1);
+ H5Fclose(file2);
+ H5Pclose(gapl);
+ } H5E_END_TRY;
+ return -1;
+} /* end external_set_elink_acc_flags() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: external_set_elink_cb
+ *
+ * Purpose: Verify functionality of H5P_set/get_elink_cb
+ *
+ * Return: Success: 0
+ * Failure: -1
+ *
+ * Programmer: Neil Fortner
+ * Jan. 5, 2009
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+typedef struct {
+ const char *parent_file;
+ const char *target_file;
+ hid_t fapl;
+} set_elink_cb_t;
+
+/* Callback function */
+static herr_t
+external_set_elink_cb_cb(const char *parent_file, const char *parent_group,
+ const char *target_file, const char *target_obj, unsigned *flags,
+ hid_t fapl, void *_op_data)
+{
+ set_elink_cb_t *op_data = (set_elink_cb_t *)_op_data;
+ hid_t driver;
+ const void *driver_info;
+
+ /* Codes to cause an invalid condition (and verify that an error is issued */
+ if (op_data->fapl == -1) return FAIL;
+ if (op_data->fapl == -2) {
+ *flags = H5F_ACC_DEFAULT;
+ return 0;
+ } /* end if */
+
+ /* Verify file and object names are correct */
+ if (HDstrcmp(parent_file, op_data->parent_file)) return FAIL;
+ if (HDstrcmp(parent_group, "/group1")) return FAIL;
+ if (HDstrcmp(target_file, op_data->target_file)) return FAIL;
+ if (HDstrcmp(target_obj, "/")) return FAIL;
+
+ /* Set flags to be read-write */
+ *flags = (*flags & ~H5F_ACC_RDONLY) | H5F_ACC_RDWR;
+
+ /* Copy driver info from op_data->fapl to fapl */
+ driver = H5Pget_driver(op_data->fapl);
+ driver_info = H5Pget_driver_info(op_data->fapl);
+ if (H5Pset_driver(fapl, driver, driver_info) < 0) return FAIL;
+
+ return 0;
+}
+
+/* Main test function */
+static int
+external_set_elink_cb(hid_t fapl, hbool_t new_format)
+{
+ hid_t file1, file2, group, gapl, fam_fapl, ret_fapl;
+ set_elink_cb_t op_data,
+ *op_data_p;
+ H5L_elink_traverse_t cb;
+ char filename1[NAME_BUF_SIZE],
+ filename2[NAME_BUF_SIZE];
+ unsigned flags;
+
+ if(new_format)
+ TESTING("H5Pset/get_elink_cb() (w/new group format)")
+ else
+ TESTING("H5Pset/get_elink_cb()")
+
+ /* Create family fapl */
+ if ((fam_fapl = H5Pcopy(fapl)) < 0) TEST_ERROR
+ if (H5Pset_fapl_family(fam_fapl, (hsize_t) 100, fapl) < 0) TEST_ERROR
+
+ /* Create parent and target files, group, and external link */
+ h5_fixname(FILENAME[40], fapl, filename1, sizeof filename1);
+ h5_fixname(FILENAME[41], fam_fapl, filename2, sizeof filename2);
+ if ((file1 = H5Fcreate(filename1, H5F_ACC_TRUNC, H5P_DEFAULT, fapl)) < 0) TEST_ERROR
+ if ((file2 = H5Fcreate(filename2, H5F_ACC_TRUNC, H5P_DEFAULT, fam_fapl)) < 0) TEST_ERROR
+ if ((group = H5Gcreate2(file1, "group1",H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR
+ if (H5Lcreate_external(filename2, "/", group, "ext_link", H5P_DEFAULT, H5P_DEFAULT) < 0) TEST_ERROR
+
+ /* Close files and group */
+ if (H5Fclose(file1) < 0) TEST_ERROR
+ if (H5Fclose(file2) < 0) TEST_ERROR
+ if (H5Gclose(group) < 0) TEST_ERROR
+
+ /* Build user data for callback */
+ op_data.parent_file = filename1;
+ op_data.target_file = filename2;
+ op_data.fapl = fam_fapl;
+
+ /* Create new gapl, and set elink callback */
+ if ((gapl = H5Pcreate(H5P_GROUP_ACCESS)) < 0) TEST_ERROR
+ if (H5Pset_elink_cb(gapl, external_set_elink_cb_cb, &op_data) < 0) TEST_ERROR
+
+ /* Verify "get" routine functionality */
+ if (H5Pget_elink_cb(gapl, &cb, (void **) &op_data_p) < 0) TEST_ERROR
+ if (cb != external_set_elink_cb_cb) TEST_ERROR
+ if (op_data_p != &op_data) TEST_ERROR
+
+ /* Open file1 with read only access */
+ if ((file1 = H5Fopen(filename1, H5F_ACC_RDONLY, fapl)) < 0) TEST_ERROR
+
+ /* Create a group through the external link using gapl */
+ if ((group = H5Gcreate2(file1, "/group1/ext_link/group2", H5P_DEFAULT, H5P_DEFAULT, gapl)) < 0) TEST_ERROR
+
+ /* Verify that the correct parameters have been set on file2 (somewhat
+ * redundant as the library would be unable to create the group otherwise)
+ */
+ if ((file2 = H5Iget_file_id(group)) < 0) TEST_ERROR
+ if (H5Fget_intent(file2, &flags) < 0) TEST_ERROR
+ if (!(flags & H5F_ACC_RDWR)) TEST_ERROR
+ if ((ret_fapl = H5Fget_access_plist(file2)) < 0) TEST_ERROR
+ if (H5FD_FAMILY != H5Pget_driver(ret_fapl)) TEST_ERROR
+
+ if (H5Gclose(group) < 0) TEST_ERROR
+ if (H5Fclose(file2) < 0) TEST_ERROR
+ if (H5Pclose(ret_fapl) < 0) TEST_ERROR
+ if (H5Pclose(fam_fapl) < 0) TEST_ERROR
+
+ /* Modify the user data structure to cause the callback to fail next time */
+ op_data.fapl = -1;
+
+ /* Attempt to reopen group2 (should fail) */
+ H5E_BEGIN_TRY {
+ group = H5Gopen2(file1, "/group1/ext_link/group2", gapl);
+ } H5E_END_TRY;
+ if (group != FAIL) TEST_ERROR
+
+ /* Modify the user data structure to cause the callback to return invalid flags */
+ op_data.fapl = -2;
+
+ /* Attempt to reopen group2 (should fail) */
+ H5E_BEGIN_TRY {
+ group = H5Gopen2(file1, "/group1/ext_link/group2", gapl);
+ } H5E_END_TRY;
+ if (group != FAIL) TEST_ERROR
+
+ /* Close */
+ if (H5Fclose(file1) < 0) TEST_ERROR
+ if (H5Pclose(gapl) < 0) TEST_ERROR
+
+ PASSED();
+ return 0;
+
+ error:
+ H5E_BEGIN_TRY {
+ H5Gclose(group);
+ H5Fclose(file1);
+ H5Fclose(file2);
+ H5Pclose(gapl);
+ H5Pclose(ret_fapl);
+ H5Pclose(fam_fapl);
+ } H5E_END_TRY;
+ return -1;
+} /* end external_set_elink_cb() */
+
+
#ifdef H5_HAVE_WINDOW_PATH
/*-------------------------------------------------------------------------
@@ -12342,6 +12618,8 @@ main(void)
nerrors += external_set_elink_fapl1(my_fapl, new_format) < 0 ? 1 : 0;
nerrors += external_set_elink_fapl2(my_fapl, new_format) < 0 ? 1 : 0;
nerrors += external_set_elink_fapl3(new_format) < 0 ? 1 : 0;
+ nerrors += external_set_elink_acc_flags(my_fapl, new_format) < 0 ? 1 : 0;
+ nerrors += external_set_elink_cb(my_fapl, new_format) < 0 ? 1 : 0;
#ifdef H5_HAVE_WINDOW_PATH
nerrors += external_link_win1(my_fapl, new_format) < 0 ? 1 : 0;