/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 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 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" /* * 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 { haddr_t objno; /* Object ID (i.e. address) */ 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 *, haddr_t objno); /*------------------------------------------------------------------------- * Function: free_ref_path_info * * Purpose: Free the key for a reference path table node * * Return: Non-negative on success, negative on failure * * Programmer: Quincey Koziol * * Modifications: * *------------------------------------------------------------------------- */ 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; HDfree(node->path); HDfree(node); return (0); } /*------------------------------------------------------------------------- * Function: init_ref_path_cb * * Purpose: Called by interator to create references for * all objects and enter them in the table. * * Return: Error status. * * Programmer: REMcG * *------------------------------------------------------------------------- */ static herr_t init_ref_path_cb(const char *obj_name, const H5O_info_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->addr); } /* end if */ return 0; } /*------------------------------------------------------------------------- * Function: init_ref_path_table * * Purpose: Initalize the reference path table * * Return: Non-negative on success, negative on failure * * Programmer: Quincey Koziol * *------------------------------------------------------------------------- */ 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_HADDR, NULL)) == 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 * * Programmer: Quincey Koziol * * Modifications: * *------------------------------------------------------------------------- */ 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: The table entre (pte) or NULL if not in the * table. * * Programmer: REMcG * * Modifications: * *------------------------------------------------------------------------- */ haddr_t ref_path_table_lookup(const char *thepath) { H5O_info_t oi; if ((thepath == NULL) || (HDstrlen(thepath) == 0)) return HADDR_UNDEF; /* Allow lookups on the root group, even though it doesn't have any link info */ if (HDstrcmp(thepath, "/") != 0) { H5L_info_t li; /* Check for external link first, so we don't return the OID of an object in another file */ if (H5Lget_info(thefile, thepath, &li, H5P_DEFAULT) < 0) return HADDR_UNDEF; /* UD links can't be followed, so they always "dangle" like soft links. */ if (li.type >= H5L_TYPE_UD_MIN) return HADDR_UNDEF; } /* end if */ /* Get the object info now */ /* (returns failure for dangling soft links) */ if (H5Oget_info_by_name2(thefile, thepath, &oi, H5O_INFO_BASIC, H5P_DEFAULT) < 0) return HADDR_UNDEF; /* Return OID */ return (oi.addr); } /*------------------------------------------------------------------------- * 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 * * Programmer: REMcG * * Modifications: * *------------------------------------------------------------------------- */ static int ref_path_table_put(const char *path, haddr_t objno) { ref_path_node_t *new_node; if (ref_path_table && path) { if ((new_node = (ref_path_node_t *)HDmalloc(sizeof(ref_path_node_t))) == NULL) return (-1); new_node->objno = objno; new_node->path = HDstrdup(path); return (H5SL_insert(ref_path_table, new_node, &(new_node->objno))); } else return (-1); } /* * counter used to disambiguate multiple instances of same object. */ 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 offest, which * minimizes the chance of collision with a real object id. * */ haddr_t fake_xid = HADDR_MAX; haddr_t get_fake_xid(void) { return (fake_xid--); } /* * for an object that does not have an object id (e.g., soft link), * create a table entry with a fake object id as the key. * * Assumes 'path' is for an object that is not in the table. * */ haddr_t ref_path_table_gen_fake(const char *path) { haddr_t fake_objno; /* Generate fake ID for string */ fake_objno = get_fake_xid(); /* 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, fake_objno); return (fake_objno); } /*------------------------------------------------------------------------- * Function: lookup_ref_path * * Purpose: Lookup the path to the object with reference 'ref'. * * Return: Return a path to the object, or NULL if not found. * * Programmer: REMcG * * Modifications: * *------------------------------------------------------------------------- */ const char * lookup_ref_path(haddr_t ref) { ref_path_node_t *node; /* Be safer for h5ls */ if (thefile < 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, &ref); return (node ? node->path : NULL); } /*------------------------------------------------------------------------- * Function: fill_ref_path_table * * Purpose: Called by interator to create references for * all objects and enter them in the table. * * Return: Error status. * * Programmer: REMcG * *------------------------------------------------------------------------- */ 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; }