mirror of
https://github.com/HDFGroup/hdf5.git
synced 2025-01-12 15:04:59 +08:00
63c90e5c67
- rename H5AC_dxpl_id to H5AC_ind_read_dxpl_id and update all usage in the library tested on bb-8 with parallel and serial.
734 lines
30 KiB
C
734 lines
30 KiB
C
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||
* Copyright by The HDF Group. *
|
||
* Copyright by the Board of Trustees of the University of Illinois. *
|
||
* All rights reserved. *
|
||
* *
|
||
* This file is part of HDF5. The full HDF5 copyright notice, including *
|
||
* terms governing use, modification, and redistribution, is contained in *
|
||
* the files COPYING and Copyright.html. COPYING can be found at the root *
|
||
* of the source code distribution tree; Copyright.html can be found at the *
|
||
* root level of an installed copy of the electronic HDF5 document set and *
|
||
* is linked from the top-level documents page. It can also be found at *
|
||
* http://hdfgroup.org/HDF5/doc/Copyright.html. If you do not have *
|
||
* access to either file, you may request a copy from help@hdfgroup.org. *
|
||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||
|
||
/****************/
|
||
/* Module Setup */
|
||
/****************/
|
||
|
||
#define H5G_FRIEND /*suppress error about including H5Gpkg */
|
||
#include "H5Lmodule.h" /* This source code file is part of the H5L module */
|
||
|
||
|
||
/***********/
|
||
/* Headers */
|
||
/***********/
|
||
#include "H5private.h" /* Generic Functions */
|
||
#include "H5ACprivate.h" /* Metadata cache */
|
||
#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 "H5Pprivate.h" /* Property lists */
|
||
|
||
|
||
/****************/
|
||
/* Local Macros */
|
||
/****************/
|
||
|
||
/* Version of external link format */
|
||
#define H5L_EXT_VERSION 0
|
||
|
||
/* Valid flags for external links */
|
||
#define H5L_EXT_FLAGS_ALL 0
|
||
|
||
/* Size of local link name buffer for traversing external links */
|
||
#define H5L_EXT_TRAVERSE_BUF_SIZE 256
|
||
|
||
|
||
/******************/
|
||
/* Local Typedefs */
|
||
/******************/
|
||
|
||
|
||
/********************/
|
||
/* Local Prototypes */
|
||
/********************/
|
||
|
||
static hid_t H5L_extern_traverse(const char H5_ATTR_UNUSED *link_name, hid_t cur_group,
|
||
const void *udata, size_t H5_ATTR_UNUSED udata_size, hid_t lapl_id);
|
||
static ssize_t H5L_extern_query(const char H5_ATTR_UNUSED * link_name, const void *udata,
|
||
size_t udata_size, void * buf /*out*/, size_t buf_size);
|
||
|
||
|
||
/*********************/
|
||
/* Package Variables */
|
||
/*********************/
|
||
|
||
|
||
/*****************************/
|
||
/* Library Private Variables */
|
||
/*****************************/
|
||
|
||
|
||
/*******************/
|
||
/* Local Variables */
|
||
/*******************/
|
||
|
||
/* Default External Link link class */
|
||
static const H5L_class_t H5L_EXTERN_LINK_CLASS[1] = {{
|
||
H5L_LINK_CLASS_T_VERS, /* H5L_class_t version */
|
||
H5L_TYPE_EXTERNAL, /* Link type id number */
|
||
"external", /* Link name for debugging */
|
||
NULL, /* Creation callback */
|
||
NULL, /* Move callback */
|
||
NULL, /* Copy callback */
|
||
H5L_extern_traverse, /* The actual traversal function */
|
||
NULL, /* Deletion callback */
|
||
H5L_extern_query /* Query callback */
|
||
}};
|
||
|
||
|
||
|
||
/*--------------------------------------------------------------------------
|
||
* Function: H5L_getenv_prefix_name --
|
||
*
|
||
* Purpose: Get the first pathname in the list of pathnames stored in ENV_PREFIX,
|
||
* which is separated by the environment delimiter.
|
||
* ENV_PREFIX is modified to point to the remaining pathnames
|
||
* in the list.
|
||
*
|
||
* Return: A pointer to a pathname
|
||
*
|
||
* Programmer: Vailin Choi, April 2, 2008
|
||
*
|
||
--------------------------------------------------------------------------*/
|
||
static char *
|
||
H5L_getenv_prefix_name(char **env_prefix/*in,out*/)
|
||
{
|
||
char *retptr=NULL;
|
||
char *strret=NULL;
|
||
|
||
FUNC_ENTER_NOAPI_NOINIT_NOERR
|
||
|
||
strret = HDstrchr(*env_prefix, H5_COLON_SEPC);
|
||
if (strret == NULL) {
|
||
retptr = *env_prefix;
|
||
*env_prefix = strret;
|
||
} else {
|
||
retptr = *env_prefix;
|
||
*env_prefix = strret + 1;
|
||
*strret = '\0';
|
||
}
|
||
|
||
FUNC_LEAVE_NOAPI(retptr)
|
||
} /* end H5L_getenv_prefix_name() */
|
||
|
||
|
||
/*--------------------------------------------------------------------------
|
||
* Function: H5L_build_name
|
||
*
|
||
* Purpose: Prepend PREFIX to FILE_NAME and store in FULL_NAME
|
||
*
|
||
* Return: Non-negative on success/Negative on failure
|
||
*
|
||
* Programmer: Vailin Choi, April 2, 2008
|
||
*
|
||
--------------------------------------------------------------------------*/
|
||
static herr_t
|
||
H5L_build_name(char *prefix, char *file_name, char **full_name/*out*/)
|
||
{
|
||
size_t prefix_len; /* length of prefix */
|
||
size_t fname_len; /* Length of external link file name */
|
||
herr_t ret_value = SUCCEED; /* Return value */
|
||
|
||
FUNC_ENTER_NOAPI_NOINIT
|
||
|
||
prefix_len = HDstrlen(prefix);
|
||
fname_len = HDstrlen(file_name);
|
||
|
||
/* Allocate a buffer to hold the filename + prefix + possibly the delimiter + terminating null byte */
|
||
if(NULL == (*full_name = (char *)H5MM_malloc(prefix_len + fname_len + 2)))
|
||
HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate filename buffer")
|
||
|
||
/* Compose the full file name */
|
||
HDsnprintf(*full_name, (prefix_len + fname_len + 2), "%s%s%s", prefix,
|
||
(H5_CHECK_DELIMITER(prefix[prefix_len - 1]) ? "" : H5_DIR_SEPS), file_name);
|
||
|
||
done:
|
||
FUNC_LEAVE_NOAPI(ret_value)
|
||
} /* H5L_build_name() */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5L_extern_traverse
|
||
*
|
||
* Purpose: Default traversal function for external links. This can
|
||
* be overridden using H5Lregister().
|
||
*
|
||
* Given a filename and path packed into the link udata,
|
||
* attempts to open an object within an external file.
|
||
* If the H5L_ELINK_PREFIX_NAME property is set in the
|
||
* link access property list, appends that prefix to the
|
||
* filename being opened.
|
||
*
|
||
* Return: ID of the opened object on success/Negative on failure
|
||
*
|
||
* Programmer: James Laird
|
||
* Monday, July 10, 2006
|
||
* Modifications:
|
||
* Vailin Choi, April 2, 2008
|
||
* Add handling to search for the target file
|
||
* See description in RM: H5Lcreate_external
|
||
*
|
||
* Vailin Choi; Sept. 12th, 2008; bug #1247
|
||
* Retrieve the file access property list identifer that is set
|
||
* for link access property via H5Pget_elink_fapl().
|
||
* If the return value is H5P_DEFAULT, the parent's file access
|
||
* property is used to H5F_open() the target file;
|
||
* Otherwise, the file access property retrieved from H5Pget_elink_fapl()
|
||
* is used to H5F_open() the target file.
|
||
*
|
||
* Vailin Choi; Nov 2010
|
||
* Free memory pointed to by tmp_env_prefix for HDF5_EXT_PREFIX case.
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
static hid_t
|
||
H5L_extern_traverse(const char H5_ATTR_UNUSED *link_name, hid_t cur_group,
|
||
const void *_udata, size_t H5_ATTR_UNUSED udata_size, hid_t lapl_id)
|
||
{
|
||
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 */
|
||
const uint8_t *p = (const uint8_t *)_udata; /* Pointer into external link buffer */
|
||
const char *file_name; /* Name of file containing external link's object */
|
||
char *full_name = NULL; /* File name with prefix */
|
||
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 */
|
||
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 */
|
||
char *parent_group_name = NULL;/* Temporary pointer to group name */
|
||
char local_group_name[H5L_EXT_TRAVERSE_BUF_SIZE]; /* Local buffer to hold group name */
|
||
char *temp_file_name = NULL; /* Temporary pointer to file name */
|
||
size_t temp_file_name_len; /* Length of temporary file name */
|
||
char *actual_file_name = NULL; /* Parent file's actual name */
|
||
H5P_genplist_t *fa_plist; /* File access property list pointer */
|
||
H5F_close_degree_t fc_degree = H5F_CLOSE_WEAK; /* File close degree for target file */
|
||
hid_t dxpl_id = H5AC_ind_read_dxpl_id; /* dxpl used by library */
|
||
hid_t ret_value = H5I_INVALID_HID; /* Return value */
|
||
|
||
FUNC_ENTER_NOAPI(FAIL)
|
||
|
||
/* Sanity checks */
|
||
HDassert(p);
|
||
|
||
/* Check external link version & flags */
|
||
if(((*p >> 4) & 0x0F) > H5L_EXT_VERSION)
|
||
HGOTO_ERROR(H5E_LINK, H5E_CANTDECODE, FAIL, "bad version number for external link")
|
||
if((*p & 0x0F) & ~H5L_EXT_FLAGS_ALL)
|
||
HGOTO_ERROR(H5E_LINK, H5E_CANTDECODE, FAIL, "bad flags for external link")
|
||
p++;
|
||
|
||
/* Gather some information from the external link's user data */
|
||
file_name = (const char *)p;
|
||
fname_len = HDstrlen(file_name);
|
||
obj_name = (const char *)p + 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")
|
||
|
||
/* Verify access property list and get correct dxpl */
|
||
if(H5P_verify_apl_and_dxpl(&lapl_id, H5P_CLS_LACC, &dxpl_id, cur_group, FALSE) < 0)
|
||
HGOTO_ERROR(H5E_LINK, H5E_CANTSET, FAIL, "can't set access and transfer property lists")
|
||
|
||
/* Get the fapl_id set for lapl_id if any */
|
||
if(H5P_get(plist, H5L_ACS_ELINK_FAPL_NAME, &fapl_id) < 0)
|
||
HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get fapl for links")
|
||
|
||
/* 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")
|
||
|
||
/* 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")
|
||
|
||
/* 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")
|
||
|
||
/* 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) {
|
||
const char *parent_file_name; /* Parent file name */
|
||
ssize_t group_name_len; /* Length of parent group name */
|
||
|
||
/* Get parent file name */
|
||
parent_file_name = H5F_OPEN_NAME(loc.oloc->file);
|
||
|
||
/* Query length of parent group name */
|
||
if((group_name_len = H5G_get_name(&loc, NULL, (size_t) 0, NULL, lapl_id, dxpl_id)) < 0)
|
||
HGOTO_ERROR(H5E_LINK, H5E_CANTGET, FAIL, "unable to retrieve length of group name")
|
||
|
||
/* Account for null terminator */
|
||
group_name_len++;
|
||
|
||
/* Check if we need to allocate larger buffer */
|
||
if((size_t)group_name_len > sizeof(local_group_name)) {
|
||
if(NULL == (parent_group_name = (char *)H5MM_malloc((size_t)group_name_len)))
|
||
HGOTO_ERROR(H5E_LINK, H5E_CANTALLOC, FAIL, "can't allocate buffer to hold group name, group_name_len = %zd", group_name_len)
|
||
} /* end if */
|
||
else
|
||
parent_group_name = local_group_name;
|
||
|
||
/* Get parent group name */
|
||
if(H5G_get_name(&loc, parent_group_name, (size_t) group_name_len, NULL, lapl_id, dxpl_id) < 0)
|
||
HGOTO_ERROR(H5E_LINK, H5E_CANTGET, FAIL, "unable to retrieve group name")
|
||
|
||
/* 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")
|
||
|
||
/* 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")
|
||
|
||
/*
|
||
* Start searching for the target file
|
||
*/
|
||
|
||
/* Simplify intent flags for open calls */
|
||
intent = ((intent & H5F_ACC_RDWR) ? H5F_ACC_RDWR : H5F_ACC_RDONLY);
|
||
|
||
/* Copy the file name to use */
|
||
if(NULL == (temp_file_name = H5MM_strdup(file_name)))
|
||
HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
|
||
temp_file_name_len = HDstrlen(temp_file_name);
|
||
|
||
/* target file_name is an absolute pathname: see RM for detailed description */
|
||
if(H5_CHECK_ABSOLUTE(file_name) || H5_CHECK_ABS_PATH(file_name)) {
|
||
/* Try opening file */
|
||
if(NULL == (ext_file = H5F_efc_open(loc.oloc->file, file_name, intent, H5P_FILE_CREATE_DEFAULT, fapl_id, dxpl_id))) {
|
||
char *ptr;
|
||
|
||
H5E_clear_stack(NULL);
|
||
|
||
/* get last component of file_name */
|
||
H5_GET_LAST_DELIMITER(file_name, ptr)
|
||
HDassert(ptr);
|
||
|
||
/* Increment past delimiter */
|
||
ptr++;
|
||
|
||
/* Copy into the temp. file name */
|
||
HDstrncpy(temp_file_name, ptr, temp_file_name_len);
|
||
temp_file_name[temp_file_name_len - 1] = '\0';
|
||
} /* end if */
|
||
} /* end if */
|
||
else if(H5_CHECK_ABS_DRIVE(file_name)) {
|
||
/* Try opening file */
|
||
if(NULL == (ext_file = H5F_efc_open(loc.oloc->file, file_name, intent, H5P_FILE_CREATE_DEFAULT, fapl_id, dxpl_id))) {
|
||
|
||
H5E_clear_stack(NULL);
|
||
|
||
/* strip "<drive-letter>:" */
|
||
HDstrncpy(temp_file_name, &file_name[2], temp_file_name_len);
|
||
temp_file_name[temp_file_name_len - 1] = '\0';
|
||
} /* end if */
|
||
} /* end if */
|
||
|
||
/* try searching from paths set in the environment variable */
|
||
if(ext_file == NULL) {
|
||
char *env_prefix;
|
||
|
||
if(NULL != (env_prefix = HDgetenv("HDF5_EXT_PREFIX"))) {
|
||
char *tmp_env_prefix, *saved_env;
|
||
|
||
if(NULL == (saved_env = tmp_env_prefix = H5MM_strdup(env_prefix)))
|
||
HGOTO_ERROR(H5E_LINK, H5E_NOSPACE, FAIL, "memory allocation failed")
|
||
|
||
while((tmp_env_prefix) && (*tmp_env_prefix)) {
|
||
char *out_prefix_name;
|
||
|
||
out_prefix_name = H5L_getenv_prefix_name(&tmp_env_prefix/*in,out*/);
|
||
if(out_prefix_name && (*out_prefix_name)) {
|
||
if(H5L_build_name(out_prefix_name, temp_file_name, &full_name/*out*/) < 0) {
|
||
saved_env = (char *)H5MM_xfree(saved_env);
|
||
HGOTO_ERROR(H5E_LINK, H5E_CANTGET, FAIL, "can't prepend prefix to filename")
|
||
} /* end if */
|
||
|
||
ext_file = H5F_efc_open(loc.oloc->file, full_name, intent, H5P_FILE_CREATE_DEFAULT, fapl_id, dxpl_id);
|
||
full_name = (char *)H5MM_xfree(full_name);
|
||
if(ext_file != NULL)
|
||
break;
|
||
H5E_clear_stack(NULL);
|
||
} /* end if */
|
||
} /* end while */
|
||
saved_env = (char *)H5MM_xfree(saved_env);
|
||
} /* end if */
|
||
} /* end if */
|
||
|
||
/* try searching from property list */
|
||
if(ext_file == NULL) {
|
||
if(H5P_peek(plist, H5L_ACS_ELINK_PREFIX_NAME, &my_prefix) < 0)
|
||
HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get external link prefix")
|
||
if(my_prefix) {
|
||
if(H5L_build_name(my_prefix, temp_file_name, &full_name/*out*/) < 0)
|
||
HGOTO_ERROR(H5E_LINK, H5E_CANTGET, FAIL, "can't prepend prefix to filename")
|
||
if(NULL == (ext_file = H5F_efc_open(loc.oloc->file, full_name, intent, H5P_FILE_CREATE_DEFAULT, fapl_id, dxpl_id)))
|
||
H5E_clear_stack(NULL);
|
||
full_name = (char *)H5MM_xfree(full_name);
|
||
} /* end if */
|
||
} /* end if */
|
||
|
||
/* try searching from main file's "extpath": see description in H5F_open() & H5_build_extpath() */
|
||
if(ext_file == NULL) {
|
||
char *extpath;
|
||
|
||
if(NULL != (extpath = H5F_EXTPATH(loc.oloc->file))) {
|
||
if(H5L_build_name(extpath, temp_file_name, &full_name/*out*/) < 0)
|
||
HGOTO_ERROR(H5E_LINK, H5E_CANTGET, FAIL, "can't prepend prefix to filename")
|
||
if(NULL == (ext_file = H5F_efc_open(loc.oloc->file, full_name, intent, H5P_FILE_CREATE_DEFAULT, fapl_id, dxpl_id)))
|
||
H5E_clear_stack(NULL);
|
||
full_name = (char *)H5MM_xfree(full_name);
|
||
} /* end if */
|
||
} /* end if */
|
||
|
||
/* try the relative file_name stored in temp_file_name */
|
||
if(ext_file == NULL) {
|
||
if(NULL == (ext_file = H5F_efc_open(loc.oloc->file, temp_file_name, intent, H5P_FILE_CREATE_DEFAULT, fapl_id, dxpl_id)))
|
||
H5E_clear_stack(NULL);
|
||
} /* end if */
|
||
|
||
/* try the 'resolved' name for the parent file (i.e. the name after symlinks
|
||
* were resolved)
|
||
*/
|
||
if(ext_file == NULL) {
|
||
char *ptr = NULL;
|
||
|
||
/* Copy resolved file name */
|
||
if(NULL == (actual_file_name = H5MM_strdup(H5F_ACTUAL_NAME(loc.oloc->file))))
|
||
HGOTO_ERROR(H5E_LINK, H5E_CANTALLOC, FAIL, "can't duplicate resolved file name string")
|
||
|
||
/* get last component of file_name */
|
||
H5_GET_LAST_DELIMITER(actual_file_name, ptr)
|
||
if(!ptr)
|
||
HGOTO_ERROR(H5E_LINK, H5E_CANTOPENFILE, FAIL, "unable to open external file, external link file name = '%s', temp_file_name = '%s'", file_name, temp_file_name)
|
||
|
||
/* Truncate filename portion from actual file name path */
|
||
*ptr = '\0';
|
||
|
||
/* Build new file name for the external file */
|
||
if(H5L_build_name(actual_file_name, temp_file_name, &full_name/*out*/) < 0)
|
||
HGOTO_ERROR(H5E_LINK, H5E_CANTGET, FAIL, "can't prepend prefix to filename")
|
||
|
||
/* Try opening with the resolved name */
|
||
if(NULL == (ext_file = H5F_efc_open(loc.oloc->file, full_name, intent, H5P_FILE_CREATE_DEFAULT, fapl_id, dxpl_id)))
|
||
HGOTO_ERROR(H5E_LINK, H5E_CANTOPENFILE, FAIL, "unable to open external file, external link file name = '%s', temp_file_name = '%s'", file_name, temp_file_name)
|
||
full_name = (char *)H5MM_xfree(full_name);
|
||
} /* end if */
|
||
|
||
|
||
/* Retrieve the "group location" for the file's root group */
|
||
if(H5G_root_loc(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((ext_obj = H5O_open_name(&root_loc, obj_name, lapl_id, dxpl_id, FALSE)) < 0)
|
||
HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open object")
|
||
|
||
/* Set return value */
|
||
ret_value = ext_obj;
|
||
|
||
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_efc_close(loc.oloc->file, ext_file) < 0)
|
||
HDONE_ERROR(H5E_LINK, H5E_CANTCLOSEFILE, FAIL, "problem closing external file")
|
||
if(parent_group_name && parent_group_name != local_group_name)
|
||
parent_group_name = (char *)H5MM_xfree(parent_group_name);
|
||
full_name = (char *)H5MM_xfree(full_name);
|
||
temp_file_name = (char *)H5MM_xfree(temp_file_name);
|
||
actual_file_name = (char *)H5MM_xfree(actual_file_name);
|
||
|
||
if(ret_value < 0) {
|
||
/* Close object if it's open and something failed */
|
||
if(ext_obj >= 0 && H5I_dec_ref(ext_obj) < 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() */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5L_extern_query
|
||
*
|
||
* Purpose: Default query function for external links. This can
|
||
* be overridden using H5Lregister().
|
||
*
|
||
* Returns the size of the link's user data. If a buffer of
|
||
* is provided, copies at most buf_size bytes of the udata
|
||
* into it.
|
||
*
|
||
* Return: Size of buffer on success/Negative on failure
|
||
*
|
||
* Programmer: James Laird
|
||
* Monday, July 10, 2006
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
static ssize_t
|
||
H5L_extern_query(const char H5_ATTR_UNUSED * link_name, const void *_udata, size_t udata_size,
|
||
void *buf /*out*/, size_t buf_size)
|
||
{
|
||
const uint8_t *udata = (const uint8_t *)_udata; /* Pointer to external link buffer */
|
||
ssize_t ret_value = SUCCEED; /* Return value */
|
||
|
||
FUNC_ENTER_NOAPI_NOINIT
|
||
|
||
/* Check external link version & flags */
|
||
if(((*udata >> 4) & 0x0F) != H5L_EXT_VERSION)
|
||
HGOTO_ERROR(H5E_LINK, H5E_CANTDECODE, FAIL, "bad version number for external link")
|
||
if((*udata & 0x0F) & ~H5L_EXT_FLAGS_ALL)
|
||
HGOTO_ERROR(H5E_LINK, H5E_CANTDECODE, FAIL, "bad flags for external link")
|
||
|
||
/* 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 */
|
||
HDmemcpy(buf, udata, buf_size);
|
||
} /* end if */
|
||
|
||
/* Set return value */
|
||
ret_value = (ssize_t)udata_size;
|
||
|
||
done:
|
||
FUNC_LEAVE_NOAPI(ret_value)
|
||
} /* end H5L_extern_query() */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5Lcreate_external
|
||
*
|
||
* Purpose: Creates an external link from LINK_NAME to OBJ_NAME.
|
||
*
|
||
* External links are links to objects in other HDF5 files. They
|
||
* are allowed to "dangle" like soft links internal to a file.
|
||
* FILE_NAME is the name of the file that OBJ_NAME is is contained
|
||
* within. If OBJ_NAME is given as a relative path name, the
|
||
* path will be relative to the root group of FILE_NAME.
|
||
* LINK_NAME is interpreted relative to LINK_LOC_ID, which is
|
||
* either a file ID or a group ID.
|
||
*
|
||
* Return: Non-negative on success/Negative on failure
|
||
*
|
||
* Programmer: Quincey Koziol
|
||
* Wednesday, May 18, 2005
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
herr_t
|
||
H5Lcreate_external(const char *file_name, const char *obj_name,
|
||
hid_t link_loc_id, const char *link_name, hid_t lcpl_id, hid_t lapl_id)
|
||
{
|
||
H5G_loc_t link_loc; /* Group location to create link */
|
||
char *norm_obj_name = NULL; /* Pointer to normalized current name */
|
||
void *ext_link_buf = NULL; /* Buffer to contain external link */
|
||
size_t buf_size; /* Size of buffer to hold external link */
|
||
size_t file_name_len; /* Length of file name string */
|
||
size_t norm_obj_name_len; /* Length of normalized object name string */
|
||
uint8_t *p; /* Pointer into external link buffer */
|
||
hid_t dxpl_id = H5AC_ind_read_dxpl_id; /* dxpl used by library */
|
||
herr_t ret_value = SUCCEED; /* Return value */
|
||
|
||
FUNC_ENTER_API(FAIL)
|
||
H5TRACE6("e", "*s*si*sii", file_name, obj_name, link_loc_id, link_name,
|
||
lcpl_id, lapl_id);
|
||
|
||
/* Check arguments */
|
||
if(!file_name || !*file_name)
|
||
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no file name specified")
|
||
if(!obj_name || !*obj_name)
|
||
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no object name specified")
|
||
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")
|
||
|
||
/* Get normalized copy of the link target */
|
||
if(NULL == (norm_obj_name = H5G_normalize(obj_name)))
|
||
HGOTO_ERROR(H5E_SYM, H5E_BADVALUE, FAIL, "can't normalize object name")
|
||
|
||
/* Combine the filename and link name into a single buffer to give to the UD link */
|
||
file_name_len = HDstrlen(file_name) + 1;
|
||
norm_obj_name_len = HDstrlen(norm_obj_name) + 1;
|
||
buf_size = 1 + file_name_len + norm_obj_name_len;
|
||
if(NULL == (ext_link_buf = H5MM_malloc(buf_size)))
|
||
HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate udata buffer")
|
||
|
||
/* Encode the external link information */
|
||
p = (uint8_t *)ext_link_buf;
|
||
*p++ = (H5L_EXT_VERSION << 4) | H5L_EXT_FLAGS_ALL; /* External link version & flags */
|
||
HDstrncpy((char *)p, file_name, buf_size - 1); /* Name of file containing external link's object */
|
||
p += file_name_len;
|
||
HDstrncpy((char *)p, norm_obj_name, buf_size - (file_name_len + 1)); /* External link's object */
|
||
|
||
/* Verify access property list and get correct dxpl */
|
||
if(H5P_verify_apl_and_dxpl(&lapl_id, H5P_CLS_LACC, &dxpl_id, link_loc_id, TRUE) < 0)
|
||
HGOTO_ERROR(H5E_LINK, H5E_CANTSET, FAIL, "can't set access and transfer property lists")
|
||
|
||
/* Create an external link */
|
||
if(H5L_create_ud(&link_loc, link_name, ext_link_buf, buf_size, H5L_TYPE_EXTERNAL, lcpl_id, lapl_id, dxpl_id) < 0)
|
||
HGOTO_ERROR(H5E_LINK, H5E_CANTINIT, FAIL, "unable to create link")
|
||
|
||
done:
|
||
H5MM_xfree(ext_link_buf);
|
||
H5MM_xfree(norm_obj_name);
|
||
|
||
FUNC_LEAVE_API(ret_value)
|
||
} /* end H5Lcreate_external() */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5L_register_external
|
||
*
|
||
* Purpose: Registers default "External Link" link class.
|
||
* Use during library initialization or to restore the default
|
||
* after users change it.
|
||
*
|
||
* Return: Non-negative on success/ negative on failure
|
||
*
|
||
* Programmer: James Laird
|
||
* Monday, July 17, 2006
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
herr_t
|
||
H5L_register_external(void)
|
||
{
|
||
herr_t ret_value = SUCCEED; /* Return value */
|
||
|
||
FUNC_ENTER_NOAPI(FAIL)
|
||
|
||
if(H5L_register(H5L_EXTERN_LINK_CLASS) < 0)
|
||
HGOTO_ERROR(H5E_LINK, H5E_NOTREGISTERED, FAIL, "unable to register external link class")
|
||
|
||
done:
|
||
FUNC_LEAVE_NOAPI(ret_value)
|
||
} /* end H5L_register_external() */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5Lunpack_elink_val
|
||
*
|
||
* Purpose: Given a buffer holding the "link value" from an external link,
|
||
* gets pointers to the information within the link value buffer.
|
||
*
|
||
* External link link values contain some flags and
|
||
* two NULL-terminated strings, one after the other.
|
||
*
|
||
* The FLAGS value will be filled in and FILENAME and
|
||
* OBJ_PATH will be set to pointers within ext_linkval (unless
|
||
* any of these values is NULL).
|
||
*
|
||
* Using this function on strings that aren't external link
|
||
* udata buffers can result in segmentation faults.
|
||
*
|
||
* Return: Non-negative on success/ Negative on failure
|
||
*
|
||
* Programmer: James Laird
|
||
* Monday, July 17, 2006
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
herr_t
|
||
H5Lunpack_elink_val(const void *_ext_linkval, size_t link_size,
|
||
unsigned *flags, const char **filename, const char **obj_path)
|
||
{
|
||
const uint8_t *ext_linkval = (const uint8_t *)_ext_linkval; /* Pointer to the link value */
|
||
unsigned lnk_version; /* External link format version */
|
||
unsigned lnk_flags; /* External link flags */
|
||
size_t len; /* Length of the filename in the linkval*/
|
||
herr_t ret_value = SUCCEED; /* Return value */
|
||
|
||
FUNC_ENTER_API(FAIL)
|
||
H5TRACE5("e", "*xz*Iu**s**s", _ext_linkval, link_size, flags, filename,
|
||
obj_path);
|
||
|
||
/* Sanity check external link buffer */
|
||
if(ext_linkval == NULL )
|
||
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "not an external link linkval buffer")
|
||
lnk_version = (*ext_linkval >> 4) & 0x0F;
|
||
lnk_flags = *ext_linkval & 0x0F;
|
||
if(lnk_version > H5L_EXT_VERSION)
|
||
HGOTO_ERROR(H5E_LINK, H5E_CANTDECODE, FAIL, "bad version number for external link")
|
||
if(lnk_flags & (unsigned)~H5L_EXT_FLAGS_ALL)
|
||
HGOTO_ERROR(H5E_LINK, H5E_CANTDECODE, FAIL, "bad flags for external link")
|
||
if(link_size <= 2)
|
||
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "not a valid external link buffer")
|
||
|
||
/* Try to do some error checking. If the last character in the linkval
|
||
* (the last character of obj_path) isn't NULL, then something's wrong.
|
||
*/
|
||
if(ext_linkval[link_size - 1] != '\0')
|
||
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "linkval buffer is not NULL-terminated")
|
||
|
||
/* We're now guaranteed that HDstrlen won't segfault, since the buffer has
|
||
* at least one NULL in it.
|
||
*/
|
||
len = HDstrlen((const char *)ext_linkval + 1);
|
||
|
||
/* If the first NULL we found was at the very end of the buffer, then
|
||
* this external link value has no object name and is invalid.
|
||
*/
|
||
if((len + 1) >= (link_size - 1))
|
||
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "linkval buffer doesn't contain an object path")
|
||
|
||
/* If we got here then the buffer contains (at least) two strings packed
|
||
* in the correct way. Assume it's correct and return pointers to the
|
||
* filename and object path.
|
||
*/
|
||
if(filename)
|
||
*filename = (const char *)ext_linkval + 1;
|
||
if(obj_path)
|
||
*obj_path = ((const char *)ext_linkval + 1) + len + 1; /* Add one for NULL terminator */
|
||
|
||
/* Set the flags to return */
|
||
if(flags)
|
||
*flags = lnk_flags;
|
||
|
||
done:
|
||
FUNC_LEAVE_API(ret_value)
|
||
} /* end H5Lunpack_elink_val() */
|
||
|