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