From d6da56adb76db4d8f4394e5d812697dd5b25909c Mon Sep 17 00:00:00 2001 From: Neil Fortner Date: Thu, 8 Jan 2009 13:16:31 -0500 Subject: [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) --- release_docs/RELEASE.txt | 14 ++- src/H5Fprivate.h | 3 + src/H5Fpublic.h | 4 + src/H5Fquery.c | 26 +++++ src/H5Glink.c | 1 + src/H5Gnode.c | 1 + src/H5Lexternal.c | 90 ++++++++++++--- src/H5Lprivate.h | 14 ++- src/H5Lpublic.h | 7 +- src/H5Odbg.c | 1 + src/H5Plapl.c | 181 ++++++++++++++++++++++++++++++ src/H5Ppublic.h | 8 +- src/H5Tdeprec.c | 1 + src/H5public.h | 3 + test/links.c | 278 +++++++++++++++++++++++++++++++++++++++++++++++ 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; -- cgit v0.12