summaryrefslogtreecommitdiffstats
path: root/src/H5Lexternal.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/H5Lexternal.c')
-rw-r--r--src/H5Lexternal.c158
1 files changed, 102 insertions, 56 deletions
diff --git a/src/H5Lexternal.c b/src/H5Lexternal.c
index 5357f6a..074cb47 100644
--- a/src/H5Lexternal.c
+++ b/src/H5Lexternal.c
@@ -13,19 +13,20 @@
* access to either file, you may request a copy from help@hdfgroup.org. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-#define H5L_PACKAGE /*suppress error about including H5Lpkg */
#define H5G_PACKAGE /*suppress error about including H5Gpkg */
+#define H5L_PACKAGE /*suppress error about including H5Lpkg */
/* Interface initialization */
#define H5_INTERFACE_INIT_FUNC H5L_init_extern_interface
#include "H5private.h" /* Generic Functions */
-#include "H5Lpkg.h" /* Links */
#include "H5Eprivate.h" /* Error handling */
+#include "H5Gpkg.h" /* Groups */
+#include "H5Iprivate.h" /* IDs */
+#include "H5Lpkg.h" /* Links */
#include "H5MMprivate.h" /* Memory management */
#include "H5Opublic.h" /* File objects */
-#include "H5Ppublic.h" /* Property lists */
-#include "H5Gpkg.h" /* Groups */
+#include "H5Pprivate.h" /* Property lists */
static hid_t H5L_extern_traverse(const char UNUSED *link_name, hid_t cur_group,
void * udata, size_t UNUSED udata_size, hid_t lapl_id);
@@ -92,74 +93,117 @@ static hid_t
H5L_extern_traverse(const char UNUSED *link_name, hid_t cur_group,
void * udata, size_t UNUSED udata_size, hid_t lapl_id)
{
- hid_t fid;
- char *file_name;
- char *obj_name;
- ssize_t prefix_len; /* External link prefix length */
- size_t fname_len;
- hbool_t fname_alloc = FALSE;
- unsigned intent;
- hid_t fapl_id;
- hid_t ret_value = -1;
-
- file_name = (char *) udata;
+ H5P_genplist_t *plist; /* Property list pointer */
+ char *my_prefix; /* Library's copy of the prefix */
+ H5G_loc_t root_loc; /* Location of root group in external file */
+ H5G_loc_t loc; /* Location of object */
+ H5F_t *ext_file = NULL; /* File struct for external file */
+ char *file_name = (char *)udata;
+ char *obj_name;
+ size_t fname_len;
+ hbool_t fname_alloc = FALSE;
+ unsigned intent;
+ hid_t fapl_id = -1;
+ hid_t ret_value = -1;
+
+ FUNC_ENTER_NOAPI(H5L_extern_traverse, FAIL)
+
+ /* Sanity checks */
+ HDassert(file_name);
+
+ /* Gather some information from the external link's user data */
fname_len = HDstrlen(file_name);
- obj_name = ((char *) udata) + fname_len + 1;
+ obj_name = ((char *)udata) + fname_len + 1;
+
+ /* 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 the current prefix */
+ if(H5P_get(plist, H5L_ACS_ELINK_PREFIX_NAME, &my_prefix) < 0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get external link prefix")
- /* See if the external link prefix property is set */
- if((prefix_len = H5Pget_elink_prefix(lapl_id, NULL, (size_t)0)) < 0)
- goto error;
+ /* Check for prefix being set, if so, prepend it to the filename */
+ if(my_prefix) {
+ size_t prefix_len = HDstrlen(my_prefix);
- /* If so, prepend it to the filename */
- if(prefix_len > 0)
- {
/* Allocate a buffer to hold the filename plus prefix */
- file_name = H5MM_malloc(prefix_len + fname_len + 1);
+ if(NULL == (file_name = H5MM_malloc(prefix_len + fname_len + 1)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate filename buffer")
fname_alloc = TRUE;
/* Copy the prefix into the buffer */
- if(H5Pget_elink_prefix(lapl_id, file_name, (size_t)(prefix_len + 1)) < 0)
- goto error;
+ HDstrcpy(file_name, my_prefix);
/* Add the external link's filename to the prefix supplied */
HDstrcat(file_name, udata);
- }
+ } /* end if */
+
+ /* Get the location for the group holding the external link */
+ if(H5G_loc(cur_group, &loc) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTGET, FAIL, "can't get object location")
/* Whatever access properties and intent the user used on the old file,
* use the same ones to open the new file. If this is a bad default,
* users can override this callback using H5Lregister.
*/
- if((fid = H5Iget_file_id(cur_group)) < 0)
- goto error;
- if(H5Fget_intent(fid, &intent) < 0)
- goto error;
- if((fapl_id = H5Fget_access_plist(fid)) < 0)
- goto error;
- if(H5Fclose(fid) < 0)
- goto error;
-
- if((fid = H5Fopen(file_name, intent, fapl_id)) < 0)
- goto error;
-
- ret_value = H5Oopen(fid, obj_name, lapl_id); /* If this fails, our return value will be negative. */
- if(H5Pclose(fapl_id) < 0)
- goto error;
- if(H5Fclose(fid) < 0)
- goto error;
+ intent = H5F_INTENT(loc.oloc->file);
+ if((fapl_id = H5F_get_access_plist(loc.oloc->file)) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTGET, FAIL, "can't get file access property list")
+
+ /* Check for non-"weak" file close degree for parent file */
+ if(H5F_GET_FC_DEGREE(loc.oloc->file) != H5F_CLOSE_WEAK) {
+ H5P_genplist_t *fa_plist; /* Property list pointer */
+ H5F_close_degree_t fc_degree = H5F_CLOSE_WEAK; /* File close degree */
+
+ /* Get the plist structure */
+ 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")
+
+ /* 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")
+ } /* end if */
+
+ /* Open the external file */
+ /* (extra work with file intent to mask off inappropriate flags) */
+ if(NULL == (ext_file = H5F_open(file_name, ((intent & H5F_ACC_RDWR) ? H5F_ACC_RDWR : H5F_ACC_RDONLY), H5P_FILE_CREATE_DEFAULT, fapl_id, H5AC_dxpl_id)))
+ HGOTO_ERROR(H5E_LINK, H5E_CANTOPENFILE, FAIL, "unable to open external file")
+
+ /* Increment the number of open objects, to hold the file open */
+ H5F_incr_nopen_objs(ext_file);
+
+ /* Retrieve the "group location" for the file's root group */
+ if(H5G_loc_root(ext_file, &root_loc) < 0)
+ HGOTO_ERROR(H5E_SYM, H5E_BADVALUE, FAIL, "unable to create location for file")
+
+ /* Open the object referenced in the external file */
+ if((ret_value = H5O_open_name(&root_loc, obj_name, lapl_id)) < 0) {
+ H5F_decr_nopen_objs(ext_file);
+ HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open object")
+ } /* end if */
+
+ /* Decrement the number of open objects, to let the file close */
+ H5F_decr_nopen_objs(ext_file);
+
+ /* Close the external file */
+ if(H5F_try_close(ext_file) < 0)
+ HGOTO_ERROR(H5E_LINK, H5E_CANTCLOSEFILE, FAIL, "problem closing external file")
+ ext_file = NULL;
- /* Free file_name if it's been allocated */
- if(fname_alloc)
- H5MM_xfree(file_name);
-
- return ret_value;
+done:
+ /* Release resources */
+ if(fapl_id > 0 && H5I_dec_ref(fapl_id) < 0)
+ HDONE_ERROR(H5E_ATOM, H5E_CANTRELEASE, FAIL, "unable to close atom for file access property list")
+ if(ext_file && H5F_try_close(ext_file) < 0)
+ HDONE_ERROR(H5E_LINK, H5E_CANTCLOSEFILE, FAIL, "problem closing external file")
-error:
/* Free file_name if it's been allocated */
if(fname_alloc)
H5MM_xfree(file_name);
- return -1;
-}
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5L_extern_traverse() */
/*-------------------------------------------------------------------------
@@ -183,18 +227,20 @@ static ssize_t
H5L_extern_query(const char UNUSED * link_name, void * udata,
size_t udata_size, void * buf /*out*/, size_t buf_size)
{
+ FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5L_extern_query)
+
/* If the buffer is NULL, skip writing anything in it and just return
* the size needed */
if(buf) {
if(udata_size < buf_size)
buf_size = udata_size;
- /* Copy the udata verbatim up to buf_size*/
+ /* Copy the udata verbatim up to buf_size */
HDmemcpy(buf, udata, buf_size);
- }
+ } /* end if */
- return udata_size;
-}
+ FUNC_LEAVE_NOAPI(udata_size)
+} /* end H5L_extern_query() */
/*-------------------------------------------------------------------------
@@ -254,7 +300,7 @@ H5Lcreate_external(const char *file_name, const char *obj_name,
done:
if(temp_name != NULL)
H5MM_free(temp_name);
- FUNC_LEAVE_API(ret_value);
+ FUNC_LEAVE_API(ret_value)
} /* end H5Lcreate_external() */