mirror of
https://github.com/HDFGroup/hdf5.git
synced 2024-12-27 08:01:04 +08:00
44a00ef876
* Strip HD prefix from string/char C API calls * HD(f)(put|get)(s|c) * HDstr* * HDv*printf * HD(s)(print|scan)f * HDperror But NOT: * HDstrcase* * HDvasprintf * HDstrtok_r * HDstrndup As those are not C99 and have portability work-around implementations. They will be handled later. * Fix th5_system.c screwup
372 lines
11 KiB
C
372 lines
11 KiB
C
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
* Copyright by The HDF Group. *
|
|
* 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 COPYING file, which can be found at the root of the source code *
|
|
* distribution tree, or in https://www.hdfgroup.org/licenses. *
|
|
* If you do not have access to either file, you may request a copy from *
|
|
* help@hdfgroup.org. *
|
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
|
|
|
#include "h5tools_ref.h"
|
|
#include "H5private.h"
|
|
#include "H5SLprivate.h"
|
|
#include "h5tools.h"
|
|
#include "h5tools_utils.h"
|
|
#include "h5trav.h"
|
|
#include "H5VLnative_private.h"
|
|
|
|
/*
|
|
* Table to look up a path name for an object
|
|
* reference.
|
|
*
|
|
* This table stores mappings of reference -> path
|
|
* for all objects in the file that may be the target of
|
|
* an object reference.
|
|
*
|
|
* The 'path' is an absolute path by which the object
|
|
* can be accessed. When an object has > 1 such path,
|
|
* only one will be used in the table, with no particular
|
|
* method of selecting which one.
|
|
*/
|
|
|
|
typedef struct {
|
|
H5O_token_t obj_token; /* Object token */
|
|
char *path; /* Object path */
|
|
} ref_path_node_t;
|
|
|
|
static H5SL_t *ref_path_table = NULL; /* the "table" (implemented with a skip list) */
|
|
static hid_t thefile = (-1);
|
|
|
|
static int ref_path_table_put(const char *, const H5O_token_t *token);
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: free_ref_path_info
|
|
*
|
|
* Purpose: Free the key for a reference path table node
|
|
*
|
|
* Return: Non-negative on success, negative on failure
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
static herr_t
|
|
free_ref_path_info(void *item, void H5_ATTR_UNUSED *key, void H5_ATTR_UNUSED *operator_data /*in,out*/)
|
|
{
|
|
ref_path_node_t *node = (ref_path_node_t *)item;
|
|
|
|
free(node->path);
|
|
free(node);
|
|
|
|
return (0);
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: init_ref_path_cb
|
|
*
|
|
* Purpose: Called by iterator to create references for
|
|
* all objects and enter them in the table.
|
|
*
|
|
* Return: Error status.
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
static herr_t
|
|
init_ref_path_cb(const char *obj_name, const H5O_info2_t *oinfo, const char *already_seen,
|
|
void H5_ATTR_UNUSED *_udata)
|
|
{
|
|
/* Check if the object is already in the path table */
|
|
if (NULL == already_seen) {
|
|
/* Insert the object into the path table */
|
|
ref_path_table_put(obj_name, &oinfo->token);
|
|
} /* end if */
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: ref_path_table_cmp
|
|
*
|
|
* Purpose: Skip list key comparison function which compares two
|
|
* H5O_token_t objects.
|
|
*
|
|
* Return: Negative (if token2 is greater than token1)
|
|
* 0 (if tokens are equal)
|
|
* or
|
|
* Positive (if token1 is greater than token2)
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
static int
|
|
ref_path_table_cmp(const void *key1, const void *key2)
|
|
{
|
|
const H5O_token_t *token1 = (const H5O_token_t *)key1;
|
|
const H5O_token_t *token2 = (const H5O_token_t *)key2;
|
|
int cmp_value = 0;
|
|
|
|
if (thefile > 0)
|
|
H5Otoken_cmp(thefile, token1, token2, &cmp_value);
|
|
else
|
|
cmp_value = memcmp(token1, token2, sizeof(H5O_token_t));
|
|
|
|
return cmp_value;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: init_ref_path_table
|
|
*
|
|
* Purpose: Initialize the reference path table
|
|
*
|
|
* Return: Non-negative on success, negative on failure
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
static int
|
|
init_ref_path_table(void)
|
|
{
|
|
/* Sanity check */
|
|
if (thefile > 0) {
|
|
/* Create skip list to store reference path information */
|
|
if ((ref_path_table = H5SL_create(H5SL_TYPE_GENERIC, ref_path_table_cmp)) == NULL)
|
|
return (-1);
|
|
|
|
/* Iterate over objects in this file */
|
|
if (h5trav_visit(thefile, "/", true, true, init_ref_path_cb, NULL, NULL, H5O_INFO_BASIC) < 0) {
|
|
error_msg("unable to construct reference path table\n");
|
|
h5tools_setstatus(EXIT_FAILURE);
|
|
} /* end if */
|
|
|
|
return (0);
|
|
}
|
|
else
|
|
return (-1);
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: term_ref_path_table
|
|
*
|
|
* Purpose: Terminate the reference path table
|
|
*
|
|
* Return: Non-negative on success, negative on failure
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
int
|
|
term_ref_path_table(void)
|
|
{
|
|
/* Destroy reference path table, freeing all memory */
|
|
if (ref_path_table)
|
|
H5SL_destroy(ref_path_table, free_ref_path_info, NULL);
|
|
|
|
return (0);
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: ref_path_table_lookup
|
|
*
|
|
* Purpose: Looks up a table entry given a path name.
|
|
* Used during construction of the table.
|
|
*
|
|
* Return: Negative on failure, Non-negative on success. The object
|
|
* token for the table entry is returned through the token
|
|
* parameter if the table entry is found by the given path
|
|
* name.
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
int
|
|
ref_path_table_lookup(const char *thepath, H5O_token_t *token)
|
|
{
|
|
H5O_info2_t oi;
|
|
|
|
if ((thepath == NULL) || (strlen(thepath) == 0))
|
|
return -1;
|
|
/* Allow lookups on the root group, even though it doesn't have any link info */
|
|
if (strcmp(thepath, "/") != 0) {
|
|
H5L_info2_t li;
|
|
|
|
/* Check for external link first, so we don't return the OID of an object in another file */
|
|
if (H5Lget_info2(thefile, thepath, &li, H5P_DEFAULT) < 0)
|
|
return -1;
|
|
|
|
/* UD links can't be followed, so they always "dangle" like soft links. */
|
|
if (li.type >= H5L_TYPE_UD_MIN)
|
|
return -1;
|
|
} /* end if */
|
|
|
|
/* Get the object info now */
|
|
/* (returns failure for dangling soft links) */
|
|
if (H5Oget_info_by_name3(thefile, thepath, &oi, H5O_INFO_BASIC, H5P_DEFAULT) < 0)
|
|
return -1;
|
|
|
|
/* Return object token through parameter */
|
|
memcpy(token, &oi.token, sizeof(H5O_token_t));
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: ref_path_table_put
|
|
*
|
|
* Purpose: Enter the 'obj' with 'path' in the table (assumes its not
|
|
* already there)
|
|
*
|
|
* Create an object reference, pte, and store them
|
|
* in the table.
|
|
*
|
|
* NOTE: Takes ownership of the path name string passed in!
|
|
*
|
|
* Return: Non-negative on success, negative on failure
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
static int
|
|
ref_path_table_put(const char *path, const H5O_token_t *token)
|
|
{
|
|
ref_path_node_t *new_node;
|
|
|
|
if (ref_path_table && path) {
|
|
if ((new_node = (ref_path_node_t *)malloc(sizeof(ref_path_node_t))) == NULL)
|
|
return (-1);
|
|
|
|
memcpy(&new_node->obj_token, token, sizeof(H5O_token_t));
|
|
new_node->path = strdup(path);
|
|
|
|
return (H5SL_insert(ref_path_table, new_node, &(new_node->obj_token)));
|
|
}
|
|
else
|
|
return (-1);
|
|
}
|
|
|
|
/*
|
|
* counter used to disambiguate multiple instances of same object.
|
|
*/
|
|
static int xid = 1;
|
|
|
|
int
|
|
get_next_xid(void)
|
|
{
|
|
return xid++;
|
|
}
|
|
|
|
/*
|
|
* This counter is used to create fake object ID's
|
|
* The idea is to set it to the largest possible offset, which
|
|
* minimizes the chance of collision with a real object id.
|
|
*
|
|
*/
|
|
static haddr_t fake_xid = HADDR_MAX;
|
|
|
|
void
|
|
get_fake_token(H5O_token_t *token)
|
|
{
|
|
if (thefile > 0) {
|
|
/* TODO: potential for this to be called with non-native connector objects */
|
|
if (H5VLnative_addr_to_token(thefile, fake_xid, token) < 0)
|
|
*token = H5O_TOKEN_UNDEF;
|
|
fake_xid--;
|
|
}
|
|
else
|
|
*token = H5O_TOKEN_UNDEF;
|
|
}
|
|
|
|
/*
|
|
* for an object that does not have an object token (e.g., soft link),
|
|
* create a table entry with a fake object token as the key.
|
|
*
|
|
* Assumes 'path' is for an object that is not in the table.
|
|
*
|
|
*/
|
|
|
|
void
|
|
ref_path_table_gen_fake(const char *path, H5O_token_t *token)
|
|
{
|
|
/* Generate fake object token for string */
|
|
get_fake_token(token);
|
|
|
|
/* Create ref path table, if it hasn't already been created */
|
|
if (ref_path_table == NULL)
|
|
init_ref_path_table();
|
|
|
|
/* Insert "fake" object into table */
|
|
ref_path_table_put(path, token);
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: lookup_ref_path
|
|
*
|
|
* Purpose: Lookup the path to the object with the reference 'refbuf'.
|
|
*
|
|
* Return: Return a path to the object, or NULL if not found.
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
const char *
|
|
lookup_ref_path(H5R_ref_t refbuf)
|
|
{
|
|
H5O_info2_t oinfo;
|
|
H5R_type_t ref_type;
|
|
hid_t ref_object;
|
|
ref_path_node_t *node;
|
|
|
|
/* Be safer for h5ls */
|
|
if (thefile < 0)
|
|
return (NULL);
|
|
|
|
/* Retrieve reference type */
|
|
if (H5R_BADTYPE == (ref_type = H5Rget_type(&refbuf)))
|
|
return (NULL);
|
|
|
|
/* Open the referenced object */
|
|
switch (ref_type) {
|
|
case H5R_OBJECT1:
|
|
case H5R_OBJECT2:
|
|
if ((ref_object = H5Ropen_object(&refbuf, H5P_DEFAULT, H5P_DEFAULT)) < 0)
|
|
return (NULL);
|
|
break;
|
|
|
|
/* Invalid referenced object type */
|
|
case H5R_DATASET_REGION1:
|
|
case H5R_DATASET_REGION2:
|
|
case H5R_ATTR:
|
|
case H5R_MAXTYPE:
|
|
case H5R_BADTYPE:
|
|
default:
|
|
return (NULL);
|
|
}
|
|
|
|
/* Retrieve info about the referenced object */
|
|
if (H5Oget_info3(ref_object, &oinfo, H5O_INFO_ALL) < 0)
|
|
return (NULL);
|
|
|
|
/* Create ref path table, if it hasn't already been created */
|
|
if (ref_path_table == NULL)
|
|
init_ref_path_table();
|
|
|
|
node = (ref_path_node_t *)H5SL_search(ref_path_table, &oinfo.token);
|
|
|
|
return (node ? node->path : NULL);
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: fill_ref_path_table
|
|
*
|
|
* Purpose: Called by iterator to create references for
|
|
* all objects and enter them in the table.
|
|
*
|
|
* Return: Error status.
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
herr_t
|
|
fill_ref_path_table(hid_t fid)
|
|
{
|
|
/* Set file ID for later queries (XXX: this should be fixed) */
|
|
thefile = fid;
|
|
|
|
/* Defer creating the ref path table until it's needed */
|
|
|
|
return 0;
|
|
}
|