/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 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. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include #include #include "h5tools_ref.h" #include "H5private.h" #include "H5SLprivate.h" #include "h5tools.h" #include "h5tools_utils.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) */ const 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; extern char *progname; extern int d_status; static int ref_path_table_put(const char *, haddr_t objno); static hbool_t ref_path_table_find(haddr_t objno); static herr_t fill_ref_path_table_cb(hid_t group, const char *obj_name, const H5L_info_t *linfo, void *op_data); /*------------------------------------------------------------------------- * 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 UNUSED *key, void UNUSED *operator_data/*in,out*/) { ref_path_node_t *node = (ref_path_node_t *)item; HDfree((void *)node->path); HDfree(node); return(0); } /*------------------------------------------------------------------------- * 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; /* Allow lookups on the root group, even though it doesn't have any link info */ if(HDstrcmp(thepath, "/")) { 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_name(thefile, thepath, &oi, H5P_DEFAULT) < 0) return HADDR_UNDEF; /* All existing objects in the file had better be in the table */ HDassert(ref_path_table_find(oi.addr)); /* Return OID */ return(oi.addr); } /*------------------------------------------------------------------------- * Function: ref_path_table_find * * Purpose: Looks up a table entry given a object number. * Used during construction of the table. * * Return: TRUE/FALSE on success, can't fail * * Programmer: Quincey Koziol * * Modifications: * *------------------------------------------------------------------------- */ static hbool_t ref_path_table_find(haddr_t objno) { HDassert(ref_path_table); if(H5SL_search(ref_path_table, &objno) == NULL) return FALSE; else return TRUE; } /*------------------------------------------------------------------------- * 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; HDassert(ref_path_table); HDassert(path); if((new_node = HDmalloc(sizeof(ref_path_node_t))) == NULL) return(-1); new_node->objno = objno; new_node->path = path; return(H5SL_insert(ref_path_table, new_node, &(new_node->objno))); } /* * 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) { const char *dup_path; haddr_t fake_objno; if((dup_path = HDstrdup(path)) == NULL) return HADDR_UNDEF; /* Generate fake ID for string */ fake_objno = get_fake_xid(); /* Insert "fake" object into table (takes ownership of path) */ ref_path_table_put(dup_path, fake_objno); return(fake_objno); } /*------------------------------------------------------------------------- * Function: lookup_ref_path * * Purpose: Lookup the path to the object with refernce '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(!ref_path_table) return(NULL); node = H5SL_search(ref_path_table, &ref); return(node ? node->path : NULL); } /*------------------------------------------------------------------------- * Function: fill_ref_path_table_cb * * Purpose: Called by interator to create references for * all objects and enter them in the table. * * Return: Error status. * * Programmer: REMcG * * Modifications: * *------------------------------------------------------------------------- */ static herr_t fill_ref_path_table_cb(hid_t group, const char *obj_name, const H5L_info_t *linfo, void *op_data) { if(linfo->type == H5L_TYPE_HARD) { H5O_info_t oinfo; H5Oget_info_by_name(group, obj_name, &oinfo, H5P_DEFAULT); /* Check if the object is already in the path table */ if(!ref_path_table_find(oinfo.addr)) { const char *obj_prefix = (const char *)op_data; size_t tmp_len; char *thepath; /* Compute length for this object's path */ tmp_len = HDstrlen(obj_prefix) + HDstrlen(obj_name) + 2; /* Allocate room for the path for this object */ if((thepath = (char *)HDmalloc(tmp_len)) == NULL) return FAIL; /* Build the name for this object */ HDstrcpy(thepath, obj_prefix); HDstrcat(thepath, "/"); HDstrcat(thepath, obj_name); /* Insert the object into the path table (takes ownership of the path) */ ref_path_table_put(thepath, oinfo.addr); if(oinfo.type == H5O_TYPE_GROUP) { /* Iterate over objects in this group, using this group's * name as their prefix */ if(H5Literate_by_name(group, obj_name, H5_INDEX_NAME, H5_ITER_INC, NULL, fill_ref_path_table_cb, thepath, H5P_DEFAULT) < 0) { error_msg(progname, "unable to dump group \"%s\"\n", thepath); d_status = EXIT_FAILURE; } /* end if */ } /* end if */ } /* end if */ } /* end if */ return 0; } /*------------------------------------------------------------------------- * 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 * * Modifications: * *------------------------------------------------------------------------- */ herr_t fill_ref_path_table(hid_t fid) { H5O_info_t oinfo; char *root_path; /* Set file ID for later queries (XXX: this should be fixed) */ thefile = fid; /* Create skip list to store reference path information */ if((ref_path_table = H5SL_create(H5SL_TYPE_HADDR, 0.5, (size_t)16))==NULL) return (-1); /* Build the name for root group */ root_path = HDstrdup("/"); /* Get info for root group */ H5Oget_info_by_name(fid, root_path, &oinfo, H5P_DEFAULT); /* Insert the root group into the path table (takes ownership of path) */ ref_path_table_put(root_path, oinfo.addr); /* Iterate over objects in this file */ if(H5Literate(fid, H5_INDEX_NAME, H5_ITER_INC, NULL, fill_ref_path_table_cb, (void *)"") < 0) { error_msg(progname, "unable to dump root group\n"); d_status = EXIT_FAILURE; } /* end if */ return 0; }