2006-08-03 07:41:53 +08:00
|
|
|
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
|
|
|
* 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://hdf.ncsa.uiuc.edu/HDF5/doc/Copyright.html. If you do not have *
|
|
|
|
|
* access to either file, you may request a copy from hdfhelp@ncsa.uiuc.edu. *
|
|
|
|
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
|
|
|
|
|
|
|
|
|
#define H5L_PACKAGE /*suppress error about including H5Lpkg */
|
|
|
|
|
#define H5G_PACKAGE /*suppress error about including H5Gpkg */
|
|
|
|
|
|
|
|
|
|
/* 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 "H5MMprivate.h" /* Memory management */
|
|
|
|
|
#include "H5Opublic.h" /* File objects */
|
|
|
|
|
#include "H5Ppublic.h" /* Property lists */
|
|
|
|
|
#include "H5Gpkg.h" /* Groups */
|
|
|
|
|
|
2006-09-06 08:38:48 +08:00
|
|
|
|
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);
|
|
|
|
|
static ssize_t H5L_extern_query(const char UNUSED * link_name, void * udata,
|
|
|
|
|
size_t udata_size, void * buf /*out*/, size_t buf_size);
|
|
|
|
|
|
|
|
|
|
/* Default External Link link class */
|
2006-10-02 18:24:03 +08:00
|
|
|
|
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 */
|
2006-09-06 08:38:48 +08:00
|
|
|
|
"external_link", /* 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 */
|
|
|
|
|
}};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*--------------------------------------------------------------------------
|
|
|
|
|
NAME
|
|
|
|
|
H5L_init_extern_interface -- Initialize interface-specific information
|
|
|
|
|
USAGE
|
|
|
|
|
herr_t H5L_init_extern_interface()
|
|
|
|
|
|
|
|
|
|
RETURNS
|
|
|
|
|
Non-negative on success/Negative on failure
|
|
|
|
|
|
|
|
|
|
DESCRIPTION
|
|
|
|
|
Initializes any interface-specific data or routines. (Just calls
|
2006-11-07 01:47:02 +08:00
|
|
|
|
H5L_init() currently).
|
2006-09-06 08:38:48 +08:00
|
|
|
|
|
|
|
|
|
--------------------------------------------------------------------------*/
|
|
|
|
|
static herr_t
|
|
|
|
|
H5L_init_extern_interface(void)
|
|
|
|
|
{
|
|
|
|
|
FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5L_init_extern_interface)
|
|
|
|
|
|
|
|
|
|
FUNC_LEAVE_NOAPI(H5L_init())
|
|
|
|
|
} /* H5L_init_extern_interface() */
|
|
|
|
|
|
|
|
|
|
|
2006-08-03 07:41:53 +08:00
|
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
|
* 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.
|
2006-10-31 07:46:27 +08:00
|
|
|
|
* If the H5L_ELINK_PREFIX_NAME property is set in the
|
2006-08-03 07:41:53 +08:00
|
|
|
|
* 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
|
|
|
|
|
*
|
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
*/
|
2006-09-06 08:38:48 +08:00
|
|
|
|
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)
|
2006-08-03 07:41:53 +08:00
|
|
|
|
{
|
|
|
|
|
hid_t fid;
|
|
|
|
|
char *file_name;
|
|
|
|
|
char *obj_name;
|
2006-11-03 05:37:24 +08:00
|
|
|
|
ssize_t prefix_len; /* External link prefix length */
|
2006-08-03 07:41:53 +08:00
|
|
|
|
size_t fname_len;
|
|
|
|
|
hbool_t fname_alloc = FALSE;
|
2006-08-24 08:52:21 +08:00
|
|
|
|
unsigned intent;
|
2006-10-05 06:40:06 +08:00
|
|
|
|
hid_t fapl_id;
|
2006-08-03 07:41:53 +08:00
|
|
|
|
hid_t ret_value = -1;
|
|
|
|
|
|
|
|
|
|
file_name = (char *) udata;
|
2006-09-06 08:38:48 +08:00
|
|
|
|
fname_len = HDstrlen(file_name);
|
2006-08-03 07:41:53 +08:00
|
|
|
|
obj_name = ((char *) udata) + fname_len + 1;
|
|
|
|
|
|
|
|
|
|
/* See if the external link prefix property is set */
|
2006-11-03 05:37:24 +08:00
|
|
|
|
if((prefix_len = H5Pget_elink_prefix(lapl_id, NULL, (size_t)0)) < 0)
|
2006-08-03 07:41:53 +08:00
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
|
|
/* If so, prepend it to the filename */
|
2006-11-03 05:37:24 +08:00
|
|
|
|
if(prefix_len > 0)
|
2006-08-03 07:41:53 +08:00
|
|
|
|
{
|
|
|
|
|
/* Allocate a buffer to hold the filename plus prefix */
|
2006-11-03 05:37:24 +08:00
|
|
|
|
file_name = H5MM_malloc(prefix_len + fname_len + 1);
|
2006-08-03 07:41:53 +08:00
|
|
|
|
fname_alloc = TRUE;
|
|
|
|
|
|
2006-11-03 05:37:24 +08:00
|
|
|
|
/* Copy the prefix into the buffer */
|
|
|
|
|
if(H5Pget_elink_prefix(lapl_id, file_name, (size_t)(prefix_len + 1)) < 0)
|
|
|
|
|
goto error;
|
|
|
|
|
|
2006-08-03 07:41:53 +08:00
|
|
|
|
/* Add the external link's filename to the prefix supplied */
|
2006-09-06 08:38:48 +08:00
|
|
|
|
HDstrcat(file_name, udata);
|
2006-08-03 07:41:53 +08:00
|
|
|
|
}
|
|
|
|
|
|
2006-10-05 06:40:06 +08:00
|
|
|
|
/* 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.
|
|
|
|
|
*/
|
2006-08-24 08:52:21 +08:00
|
|
|
|
if((fid = H5Iget_file_id(cur_group)) < 0)
|
|
|
|
|
goto error;
|
|
|
|
|
if(H5Fget_intent(fid, &intent) < 0)
|
|
|
|
|
goto error;
|
2006-10-05 06:40:06 +08:00
|
|
|
|
if((fapl_id = H5Fget_access_plist(fid)) < 0)
|
|
|
|
|
goto error;
|
2006-08-24 08:52:21 +08:00
|
|
|
|
if(H5Fclose(fid) < 0)
|
|
|
|
|
goto error;
|
|
|
|
|
|
2006-10-05 06:40:06 +08:00
|
|
|
|
if((fid = H5Fopen(file_name, intent, fapl_id)) < 0)
|
2006-08-03 07:41:53 +08:00
|
|
|
|
goto error;
|
2006-10-11 04:07:16 +08:00
|
|
|
|
|
2006-08-03 07:41:53 +08:00
|
|
|
|
ret_value = H5Oopen(fid, obj_name, lapl_id); /* If this fails, our return value will be negative. */
|
2006-10-05 06:40:06 +08:00
|
|
|
|
if(H5Pclose(fapl_id) < 0)
|
|
|
|
|
goto error;
|
2006-08-03 07:41:53 +08:00
|
|
|
|
if(H5Fclose(fid) < 0)
|
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
|
|
/* Free file_name if it's been allocated */
|
|
|
|
|
if(fname_alloc)
|
2006-09-06 08:38:48 +08:00
|
|
|
|
H5MM_xfree(file_name);
|
2006-08-03 07:41:53 +08:00
|
|
|
|
|
|
|
|
|
return ret_value;
|
|
|
|
|
|
|
|
|
|
error:
|
|
|
|
|
/* Free file_name if it's been allocated */
|
|
|
|
|
if(fname_alloc)
|
2006-09-06 08:38:48 +08:00
|
|
|
|
H5MM_xfree(file_name);
|
|
|
|
|
|
2006-08-03 07:41:53 +08:00
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
|
* 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
|
|
|
|
|
*
|
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
*/
|
2006-09-06 08:38:48 +08:00
|
|
|
|
static ssize_t
|
|
|
|
|
H5L_extern_query(const char UNUSED * link_name, void * udata,
|
|
|
|
|
size_t udata_size, void * buf /*out*/, size_t buf_size)
|
2006-08-03 07:41:53 +08:00
|
|
|
|
{
|
2006-11-17 23:48:41 +08:00
|
|
|
|
/* If the buffer is NULL, skip writing anything in it and just return
|
2006-08-03 07:41:53 +08:00
|
|
|
|
* the size needed */
|
2006-09-06 08:38:48 +08:00
|
|
|
|
if(buf) {
|
2006-08-03 07:41:53 +08:00
|
|
|
|
if(udata_size < buf_size)
|
|
|
|
|
buf_size = udata_size;
|
|
|
|
|
|
2006-11-17 23:48:41 +08:00
|
|
|
|
/* Copy the udata verbatim up to buf_size*/
|
|
|
|
|
HDmemcpy(buf, udata, buf_size);
|
2006-08-03 07:41:53 +08:00
|
|
|
|
}
|
|
|
|
|
|
2006-11-17 23:48:41 +08:00
|
|
|
|
return udata_size;
|
2006-08-03 07:41:53 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
|
* 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;
|
|
|
|
|
char *temp_name = NULL;
|
|
|
|
|
size_t buf_size;
|
|
|
|
|
herr_t ret_value = SUCCEED; /* Return value */
|
|
|
|
|
|
|
|
|
|
FUNC_ENTER_API(H5Lcreate_external, FAIL)
|
2006-12-19 03:16:17 +08:00
|
|
|
|
H5TRACE6("e", "ssisii", file_name, obj_name, link_loc_id, link_name, lcpl_id,
|
2006-08-03 07:41:53 +08:00
|
|
|
|
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")
|
|
|
|
|
|
|
|
|
|
/* Combine the filename and link name into a single buffer to give to the UD link */
|
|
|
|
|
buf_size = HDstrlen(file_name) + HDstrlen(obj_name) + 2;
|
|
|
|
|
if(NULL == (temp_name = H5MM_malloc(buf_size)))
|
|
|
|
|
HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate udata buffer")
|
|
|
|
|
HDstrcpy(temp_name, file_name);
|
|
|
|
|
HDstrcpy(temp_name + (HDstrlen(file_name) + 1), obj_name);
|
|
|
|
|
|
|
|
|
|
/* Create an external link */
|
2006-10-02 18:24:03 +08:00
|
|
|
|
if(H5L_create_ud(&link_loc, link_name, temp_name, buf_size, H5L_TYPE_EXTERNAL, lcpl_id, lapl_id, H5AC_dxpl_id) < 0)
|
2006-08-03 07:41:53 +08:00
|
|
|
|
HGOTO_ERROR(H5E_LINK, H5E_CANTINIT, FAIL, "unable to create link")
|
|
|
|
|
|
|
|
|
|
done:
|
|
|
|
|
if(temp_name != NULL)
|
|
|
|
|
H5MM_free(temp_name);
|
|
|
|
|
FUNC_LEAVE_API(ret_value);
|
|
|
|
|
} /* end H5Lcreate_external() */
|
|
|
|
|
|
2006-09-06 08:38:48 +08:00
|
|
|
|
|
2006-08-03 07:41:53 +08:00
|
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
|
* 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
|
2006-09-06 08:38:48 +08:00
|
|
|
|
H5L_register_external(void)
|
2006-08-03 07:41:53 +08:00
|
|
|
|
{
|
2006-09-06 08:38:48 +08:00
|
|
|
|
herr_t ret_value = SUCCEED; /* Return value */
|
2006-08-03 07:41:53 +08:00
|
|
|
|
|
|
|
|
|
FUNC_ENTER_NOAPI(H5L_register_external, 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)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------
|
2006-10-31 04:24:19 +08:00
|
|
|
|
* Function: H5Lunpack_elink_val
|
2006-08-03 07:41:53 +08:00
|
|
|
|
*
|
|
|
|
|
* Purpose: Given a buffer holding the "link value" from an external link,
|
|
|
|
|
* gets pointers to the filename and object path within the
|
|
|
|
|
* link value buffer.
|
|
|
|
|
*
|
|
|
|
|
* External link linkvalues are two NULL-terminated strings
|
|
|
|
|
* one after the other.
|
|
|
|
|
*
|
|
|
|
|
* FILENAME and OBJ_PATH will be set to pointers within
|
|
|
|
|
* ext_linkval unless they are 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
|
2006-10-31 04:24:19 +08:00
|
|
|
|
H5Lunpack_elink_val(char *ext_linkval, size_t link_size, char **filename,
|
|
|
|
|
char **obj_path)
|
2006-08-03 07:41:53 +08:00
|
|
|
|
{
|
|
|
|
|
size_t len; /* Length of the filename in the linkval*/
|
|
|
|
|
herr_t ret_value=SUCCEED; /* Return value */
|
|
|
|
|
|
|
|
|
|
FUNC_ENTER_API(H5Lunpack_elink_val, FAIL)
|
2006-12-19 03:16:17 +08:00
|
|
|
|
H5TRACE4("e", "sz*s*s", ext_linkval, link_size, filename, obj_path);
|
2006-08-03 07:41:53 +08:00
|
|
|
|
|
|
|
|
|
if(ext_linkval == NULL )
|
|
|
|
|
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "not an external link linkval buffer")
|
2006-10-31 04:24:19 +08:00
|
|
|
|
if(link_size <= 1)
|
|
|
|
|
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "not a valid external link buffer")
|
2006-08-03 07:41:53 +08:00
|
|
|
|
|
2006-10-31 04:24:19 +08:00
|
|
|
|
/* 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(ext_linkval);
|
|
|
|
|
|
|
|
|
|
/* 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)
|
|
|
|
|
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.
|
|
|
|
|
*/
|
2006-08-03 07:41:53 +08:00
|
|
|
|
if(filename != NULL)
|
|
|
|
|
*filename = ext_linkval;
|
|
|
|
|
|
|
|
|
|
if(obj_path != NULL)
|
|
|
|
|
*obj_path = ext_linkval + len + 1; /* Add one for NULL terminator */
|
|
|
|
|
|
|
|
|
|
done:
|
|
|
|
|
FUNC_LEAVE_API(ret_value)
|
|
|
|
|
}
|
2006-09-06 08:38:48 +08:00
|
|
|
|
|