1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2  * Copyright by The HDF Group.                                               *
3  * Copyright by the Board of Trustees of the University of Illinois.         *
4  * All rights reserved.                                                      *
5  *                                                                           *
6  * This file is part of HDF5.  The full HDF5 copyright notice, including     *
7  * terms governing use, modification, and redistribution, is contained in    *
8  * the COPYING file, which can be found at the root of the source code       *
9  * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases.  *
10  * If you do not have access to either file, you may request a copy from     *
11  * help@hdfgroup.org.                                                        *
12  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
13 
14 #include "h5tools_ref.h"
15 #include "H5private.h"
16 #include "H5SLprivate.h"
17 #include "h5tools.h"
18 #include "h5tools_utils.h"
19 #include "h5trav.h"
20 
21 
22 /*
23  *  Table to look up a path name for an object
24  *  reference.
25  *
26  *  This table stores mappings of reference -> path
27  *  for all objects in the file that may be the target of
28  *  an object reference.
29  *
30  *  The 'path' is an absolute path by which the object
31  *  can be accessed.  When an object has > 1 such path,
32  *  only one will be used in the table, with no particular
33  *  method of selecting which one.
34  */
35 
36 typedef struct {
37     haddr_t objno;      /* Object ID (i.e. address) */
38     char *path;         /* Object path */
39 } ref_path_node_t;
40 
41 static H5SL_t *ref_path_table = NULL;   /* the "table" (implemented with a skip list) */
42 static hid_t thefile = (-1);
43 
44 static int ref_path_table_put(const char *, haddr_t objno);
45 
46 /*-------------------------------------------------------------------------
47  * Function:    free_ref_path_info
48  *
49  * Purpose:     Free the key for a reference path table node
50  *
51  * Return:      Non-negative on success, negative on failure
52  *
53  * Programmer:  Quincey Koziol
54  *
55  * Modifications:
56  *
57  *-------------------------------------------------------------------------
58  */
59 static herr_t
free_ref_path_info(void * item,void H5_ATTR_UNUSED * key,void H5_ATTR_UNUSED * operator_data)60 free_ref_path_info(void *item, void H5_ATTR_UNUSED *key, void H5_ATTR_UNUSED *operator_data/*in,out*/)
61 {
62     ref_path_node_t *node = (ref_path_node_t *)item;
63 
64     HDfree(node->path);
65     HDfree(node);
66 
67     return(0);
68 }
69 
70 /*-------------------------------------------------------------------------
71  * Function:    init_ref_path_cb
72  *
73  * Purpose:     Called by interator to create references for
74  *              all objects and enter them in the table.
75  *
76  * Return:      Error status.
77  *
78  * Programmer:  REMcG
79  *
80  *-------------------------------------------------------------------------
81  */
82 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)83 init_ref_path_cb(const char *obj_name, const H5O_info_t *oinfo,
84     const char *already_seen, void H5_ATTR_UNUSED *_udata)
85 {
86     /* Check if the object is already in the path table */
87     if(NULL == already_seen) {
88         /* Insert the object into the path table */
89         ref_path_table_put(obj_name, oinfo->addr);
90     } /* end if */
91 
92     return 0;
93 }
94 
95 /*-------------------------------------------------------------------------
96  * Function:    init_ref_path_table
97  *
98  * Purpose:     Initalize the reference path table
99  *
100  * Return:      Non-negative on success, negative on failure
101  *
102  * Programmer:  Quincey Koziol
103  *
104  *-------------------------------------------------------------------------
105  */
106 static int
init_ref_path_table(void)107 init_ref_path_table(void)
108 {
109     /* Sanity check */
110     if(thefile > 0) {
111         /* Create skip list to store reference path information */
112         if((ref_path_table = H5SL_create(H5SL_TYPE_HADDR, NULL))==NULL)
113             return (-1);
114 
115         /* Iterate over objects in this file */
116         if(h5trav_visit(thefile, "/", TRUE, TRUE, init_ref_path_cb, NULL, NULL, H5O_INFO_BASIC) < 0) {
117             error_msg("unable to construct reference path table\n");
118             h5tools_setstatus(EXIT_FAILURE);
119         } /* end if */
120 
121         return(0);
122     }
123     else
124         return (-1);
125 }
126 
127 /*-------------------------------------------------------------------------
128  * Function:    term_ref_path_table
129  *
130  * Purpose:     Terminate the reference path table
131  *
132  * Return:      Non-negative on success, negative on failure
133  *
134  * Programmer:  Quincey Koziol
135  *
136  * Modifications:
137  *
138  *-------------------------------------------------------------------------
139  */
140 int
term_ref_path_table(void)141 term_ref_path_table(void)
142 {
143     /* Destroy reference path table, freeing all memory */
144     if(ref_path_table)
145         H5SL_destroy(ref_path_table, free_ref_path_info, NULL);
146 
147     return(0);
148 }
149 
150 /*-------------------------------------------------------------------------
151  * Function:    ref_path_table_lookup
152  *
153  * Purpose:     Looks up a table entry given a path name.
154  *              Used during construction of the table.
155  *
156  * Return:      The table entre (pte) or NULL if not in the
157  *              table.
158  *
159  * Programmer:  REMcG
160  *
161  * Modifications:
162  *
163  *-------------------------------------------------------------------------
164  */
165 haddr_t
ref_path_table_lookup(const char * thepath)166 ref_path_table_lookup(const char *thepath)
167 {
168     H5O_info_t  oi;
169 
170     if((thepath == NULL) || (HDstrlen(thepath) == 0))
171         return HADDR_UNDEF;
172     /* Allow lookups on the root group, even though it doesn't have any link info */
173     if(HDstrcmp(thepath, "/")) {
174         H5L_info_t  li;
175 
176         /* Check for external link first, so we don't return the OID of an object in another file */
177         if(H5Lget_info(thefile, thepath, &li, H5P_DEFAULT) < 0)
178             return HADDR_UNDEF;
179 
180         /* UD links can't be followed, so they always "dangle" like soft links.  */
181         if(li.type >= H5L_TYPE_UD_MIN)
182             return HADDR_UNDEF;
183     } /* end if */
184 
185     /* Get the object info now */
186     /* (returns failure for dangling soft links) */
187     if(H5Oget_info_by_name2(thefile, thepath, &oi, H5O_INFO_BASIC, H5P_DEFAULT) < 0)
188         return HADDR_UNDEF;
189 
190     /* Return OID */
191     return(oi.addr);
192 }
193 
194 /*-------------------------------------------------------------------------
195  * Function:    ref_path_table_put
196  *
197  * Purpose:     Enter the 'obj' with 'path' in the table (assumes its not
198  *              already there)
199  *
200  *              Create an object reference, pte, and store them
201  *              in the table.
202  *
203  *              NOTE: Takes ownership of the path name string passed in!
204  *
205  * Return:      Non-negative on success, negative on failure
206  *
207  * Programmer:  REMcG
208  *
209  * Modifications:
210  *
211  *-------------------------------------------------------------------------
212  */
213 static int
ref_path_table_put(const char * path,haddr_t objno)214 ref_path_table_put(const char *path, haddr_t objno)
215 {
216     ref_path_node_t *new_node;
217 
218     if(ref_path_table && path) {
219         if((new_node = (ref_path_node_t *)HDmalloc(sizeof(ref_path_node_t))) == NULL)
220             return(-1);
221 
222         new_node->objno = objno;
223         new_node->path = HDstrdup(path);
224 
225         return(H5SL_insert(ref_path_table, new_node, &(new_node->objno)));
226     }
227     else
228         return (-1);
229 }
230 
231 /*
232  *  counter used to disambiguate multiple instances of same object.
233  */
234 int xid = 1;
235 
get_next_xid(void)236 int get_next_xid(void) {
237     return xid++;
238 }
239 
240 /*
241  *  This counter is used to create fake object ID's
242  *  The idea is to set it to the largest possible offest, which
243  *  minimizes the chance of collision with a real object id.
244  *
245  */
246 haddr_t fake_xid = HADDR_MAX;
247 haddr_t
get_fake_xid(void)248 get_fake_xid (void) {
249     return (fake_xid--);
250 }
251 
252 /*
253  * for an object that does not have an object id (e.g., soft link),
254  * create a table entry with a fake object id as the key.
255  *
256  * Assumes 'path' is for an object that is not in the table.
257  *
258  */
259 
260 haddr_t
ref_path_table_gen_fake(const char * path)261 ref_path_table_gen_fake(const char *path)
262 {
263     haddr_t fake_objno;
264 
265     /* Generate fake ID for string */
266     fake_objno = get_fake_xid();
267 
268     /* Create ref path table, if it hasn't already been created */
269     if(ref_path_table == NULL)
270         init_ref_path_table();
271 
272     /* Insert "fake" object into table */
273     ref_path_table_put(path, fake_objno);
274 
275     return(fake_objno);
276 }
277 
278 /*-------------------------------------------------------------------------
279  * Function:    lookup_ref_path
280  *
281  * Purpose:     Lookup the path to the object with refernce 'ref'.
282  *
283  * Return:      Return a path to the object, or NULL if not found.
284  *
285  * Programmer:  REMcG
286  *
287  * Modifications:
288  *
289  *-------------------------------------------------------------------------
290  */
291 const char *
lookup_ref_path(haddr_t ref)292 lookup_ref_path(haddr_t ref)
293 {
294     ref_path_node_t *node;
295 
296     /* Be safer for h5ls */
297     if(thefile < 0)
298         return(NULL);
299 
300     /* Create ref path table, if it hasn't already been created */
301     if(ref_path_table == NULL)
302         init_ref_path_table();
303 
304     node = (ref_path_node_t *)H5SL_search(ref_path_table, &ref);
305 
306     return(node ? node->path : NULL);
307 }
308 
309 /*-------------------------------------------------------------------------
310  * Function:    fill_ref_path_table
311  *
312  * Purpose:     Called by interator to create references for
313  *              all objects and enter them in the table.
314  *
315  * Return:      Error status.
316  *
317  * Programmer:  REMcG
318  *
319  *-------------------------------------------------------------------------
320  */
321 herr_t
fill_ref_path_table(hid_t fid)322 fill_ref_path_table(hid_t fid)
323 {
324     /* Set file ID for later queries (XXX: this should be fixed) */
325     thefile = fid;
326 
327     /* Defer creating the ref path table until it's needed */
328 
329     return 0;
330 }
331 
332