Line | Count | Source (jump to first uncovered line) |
1 | | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
2 | | * Copyright by The HDF Group. * |
3 | | * All rights reserved. * |
4 | | * * |
5 | | * This file is part of HDF5. The full HDF5 copyright notice, including * |
6 | | * terms governing use, modification, and redistribution, is contained in * |
7 | | * the COPYING file, which can be found at the root of the source code * |
8 | | * distribution tree, or in https://www.hdfgroup.org/licenses. * |
9 | | * If you do not have access to either file, you may request a copy from * |
10 | | * help@hdfgroup.org. * |
11 | | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
12 | | |
13 | | /*------------------------------------------------------------------------- |
14 | | * |
15 | | * Created: H5Gname.c |
16 | | * |
17 | | * Purpose: Functions for handling group hierarchy paths. |
18 | | * |
19 | | *------------------------------------------------------------------------- |
20 | | */ |
21 | | |
22 | | /****************/ |
23 | | /* Module Setup */ |
24 | | /****************/ |
25 | | |
26 | | #include "H5Gmodule.h" /* This source code file is part of the H5G module */ |
27 | | |
28 | | /***********/ |
29 | | /* Headers */ |
30 | | /***********/ |
31 | | #include "H5private.h" /* Generic Functions */ |
32 | | #include "H5Dprivate.h" /* Datasets */ |
33 | | #include "H5Eprivate.h" /* Error handling */ |
34 | | #include "H5Fprivate.h" /* File access */ |
35 | | #include "H5Gpkg.h" /* Groups */ |
36 | | #include "H5Iprivate.h" /* IDs */ |
37 | | #include "H5Lprivate.h" /* Links */ |
38 | | #include "H5MMprivate.h" /* Memory wrappers */ |
39 | | |
40 | | #include "H5VLnative_private.h" /* Native VOL connector */ |
41 | | |
42 | | /****************/ |
43 | | /* Local Macros */ |
44 | | /****************/ |
45 | | |
46 | | /******************/ |
47 | | /* Local Typedefs */ |
48 | | /******************/ |
49 | | |
50 | | /* Struct used by change name callback function */ |
51 | | typedef struct H5G_names_t { |
52 | | H5G_names_op_t op; /* Operation performed on file */ |
53 | | H5F_t *src_file; /* Top file in src location's mounted file hier. */ |
54 | | H5RS_str_t *src_full_path_r; /* Source location's full path */ |
55 | | H5F_t *dst_file; /* Destination location's file */ |
56 | | H5RS_str_t *dst_full_path_r; /* Destination location's full path */ |
57 | | } H5G_names_t; |
58 | | |
59 | | /* Info to pass to the iteration function when building name */ |
60 | | typedef struct H5G_gnba_iter_t { |
61 | | /* In */ |
62 | | const H5O_loc_t *loc; /* The location of the object we're looking for */ |
63 | | |
64 | | /* Out */ |
65 | | char *path; /* Name of the object */ |
66 | | } H5G_gnba_iter_t; |
67 | | |
68 | | /********************/ |
69 | | /* Package Typedefs */ |
70 | | /********************/ |
71 | | |
72 | | /********************/ |
73 | | /* Local Prototypes */ |
74 | | /********************/ |
75 | | |
76 | | static htri_t H5G__common_path(const H5RS_str_t *fullpath_r, const H5RS_str_t *prefix_r); |
77 | | static H5RS_str_t *H5G__build_fullpath(const char *prefix, const char *name); |
78 | | static herr_t H5G__name_move_path(H5RS_str_t **path_r_ptr, const char *full_suffix, const char *src_path, |
79 | | const char *dst_path); |
80 | | static int H5G__name_replace_cb(void *obj_ptr, hid_t obj_id, void *key); |
81 | | |
82 | | /*********************/ |
83 | | /* Package Variables */ |
84 | | /*********************/ |
85 | | |
86 | | /*****************************/ |
87 | | /* Library Private Variables */ |
88 | | /*****************************/ |
89 | | |
90 | | /*******************/ |
91 | | /* Local Variables */ |
92 | | /*******************/ |
93 | | |
94 | | /*------------------------------------------------------------------------- |
95 | | * Function: H5G__component |
96 | | * |
97 | | * Purpose: Returns the pointer to the first component of the |
98 | | * specified name by skipping leading slashes. Returns |
99 | | * the size in characters of the component through SIZE_P not |
100 | | * counting leading slashes or the null terminator. |
101 | | * |
102 | | * Return: Success: Ptr into NAME. |
103 | | * |
104 | | * Failure: Ptr to the null terminator of NAME. |
105 | | * |
106 | | *------------------------------------------------------------------------- |
107 | | */ |
108 | | const char * |
109 | | H5G__component(const char *name, size_t *size_p) |
110 | 944 | { |
111 | 944 | FUNC_ENTER_PACKAGE_NOERR |
112 | | |
113 | 944 | assert(name); |
114 | | |
115 | 1.08k | while ('/' == *name) |
116 | 138 | name++; |
117 | 944 | if (size_p) |
118 | 802 | *size_p = strcspn(name, "/"); |
119 | | |
120 | 944 | FUNC_LEAVE_NOAPI(name) |
121 | 944 | } /* end H5G__component() */ |
122 | | |
123 | | /*------------------------------------------------------------------------- |
124 | | * Function: H5G_normalize |
125 | | * |
126 | | * Purpose: Returns a pointer to a new string which has duplicate and |
127 | | * trailing slashes removed from it. |
128 | | * |
129 | | * Return: Success: Ptr to normalized name. |
130 | | * Failure: NULL |
131 | | * |
132 | | *------------------------------------------------------------------------- |
133 | | */ |
134 | | char * |
135 | | H5G_normalize(const char *name) |
136 | 0 | { |
137 | 0 | char *norm; /* Pointer to the normalized string */ |
138 | 0 | size_t s, d; /* Positions within the strings */ |
139 | 0 | unsigned last_slash; /* Flag to indicate last character was a slash */ |
140 | 0 | char *ret_value = NULL; /* Return value */ |
141 | |
|
142 | 0 | FUNC_ENTER_NOAPI_NOINIT |
143 | | |
144 | | /* Sanity check */ |
145 | 0 | assert(name); |
146 | | |
147 | | /* Duplicate the name, to return */ |
148 | 0 | if (NULL == (norm = H5MM_strdup(name))) |
149 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for normalized string"); |
150 | | |
151 | | /* Walk through the characters, omitting duplicated '/'s */ |
152 | 0 | s = d = 0; |
153 | 0 | last_slash = 0; |
154 | 0 | while (name[s] != '\0') { |
155 | 0 | if (name[s] == '/') |
156 | 0 | if (last_slash) |
157 | 0 | ; |
158 | 0 | else { |
159 | 0 | norm[d++] = name[s]; |
160 | 0 | last_slash = 1; |
161 | 0 | } /* end else */ |
162 | 0 | else { |
163 | 0 | norm[d++] = name[s]; |
164 | 0 | last_slash = 0; |
165 | 0 | } /* end else */ |
166 | 0 | s++; |
167 | 0 | } /* end while */ |
168 | | |
169 | | /* Terminate normalized string */ |
170 | 0 | norm[d] = '\0'; |
171 | | |
172 | | /* Check for final '/' on normalized name & eliminate it */ |
173 | 0 | if (d > 1 && last_slash) |
174 | 0 | norm[d - 1] = '\0'; |
175 | | |
176 | | /* Set return value */ |
177 | 0 | ret_value = norm; |
178 | |
|
179 | 0 | done: |
180 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
181 | 0 | } /* end H5G_normalize() */ |
182 | | |
183 | | /*------------------------------------------------------------------------- |
184 | | * Function: H5G__common_path |
185 | | * |
186 | | * Purpose: Determine if one path is a valid prefix of another path |
187 | | * |
188 | | * Return: true for valid prefix, false for not a valid prefix, FAIL |
189 | | * on error |
190 | | * |
191 | | * |
192 | | *------------------------------------------------------------------------- |
193 | | */ |
194 | | static htri_t |
195 | | H5G__common_path(const H5RS_str_t *fullpath_r, const H5RS_str_t *prefix_r) |
196 | 0 | { |
197 | 0 | const char *fullpath; /* Pointer to actual fullpath string */ |
198 | 0 | const char *prefix; /* Pointer to actual prefix string */ |
199 | 0 | size_t nchars1, nchars2; /* Number of characters in components */ |
200 | 0 | htri_t ret_value = false; /* Return value */ |
201 | |
|
202 | 0 | FUNC_ENTER_PACKAGE_NOERR |
203 | | |
204 | | /* Get component of each name */ |
205 | 0 | fullpath = H5RS_get_str(fullpath_r); |
206 | 0 | assert(fullpath); |
207 | 0 | fullpath = H5G__component(fullpath, &nchars1); |
208 | 0 | assert(fullpath); |
209 | 0 | prefix = H5RS_get_str(prefix_r); |
210 | 0 | assert(prefix); |
211 | 0 | prefix = H5G__component(prefix, &nchars2); |
212 | 0 | assert(prefix); |
213 | | |
214 | | /* Check if we have a real string for each component */ |
215 | 0 | while (*fullpath && *prefix) { |
216 | | /* Check that the components we found are the same length */ |
217 | 0 | if (nchars1 == nchars2) { |
218 | | /* Check that the two components are equal */ |
219 | 0 | if (strncmp(fullpath, prefix, nchars1) == 0) { |
220 | | /* Advance the pointers in the names */ |
221 | 0 | fullpath += nchars1; |
222 | 0 | prefix += nchars2; |
223 | | |
224 | | /* Get next component of each name */ |
225 | 0 | fullpath = H5G__component(fullpath, &nchars1); |
226 | 0 | assert(fullpath); |
227 | 0 | prefix = H5G__component(prefix, &nchars2); |
228 | 0 | assert(prefix); |
229 | 0 | } /* end if */ |
230 | 0 | else |
231 | 0 | HGOTO_DONE(false); |
232 | 0 | } /* end if */ |
233 | 0 | else |
234 | 0 | HGOTO_DONE(false); |
235 | 0 | } /* end while */ |
236 | | |
237 | | /* If we reached the end of the prefix path to check, it must be a valid prefix */ |
238 | 0 | if (*prefix == '\0') |
239 | 0 | ret_value = true; |
240 | |
|
241 | 0 | done: |
242 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
243 | 0 | } /* end H5G__common_path() */ |
244 | | |
245 | | /*------------------------------------------------------------------------- |
246 | | * Function: H5G__build_fullpath |
247 | | * |
248 | | * Purpose: Build a full path from a prefix & base pair of strings |
249 | | * |
250 | | * Return: Pointer to reference counted string on success, NULL on error |
251 | | * |
252 | | *------------------------------------------------------------------------- |
253 | | */ |
254 | | static H5RS_str_t * |
255 | | H5G__build_fullpath(const char *prefix, const char *name) |
256 | 280 | { |
257 | 280 | H5RS_str_t *ret_value = NULL; /* Return value */ |
258 | | |
259 | 280 | FUNC_ENTER_PACKAGE |
260 | | |
261 | | /* Sanity check */ |
262 | 280 | assert(prefix); |
263 | 280 | assert(name); |
264 | | |
265 | | /* Create full path */ |
266 | 280 | if (NULL == (ret_value = H5RS_create(prefix))) |
267 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTCREATE, NULL, "can't create ref-counted string"); |
268 | 280 | if (prefix[strlen(prefix) - 1] != '/') |
269 | 30 | H5RS_aputc(ret_value, '/'); /* Add separator, if the prefix doesn't end in one */ |
270 | 280 | H5RS_acat(ret_value, name); |
271 | | |
272 | 280 | done: |
273 | 280 | FUNC_LEAVE_NOAPI(ret_value) |
274 | 280 | } /* end H5G__build_fullpath() */ |
275 | | |
276 | | /*------------------------------------------------------------------------- |
277 | | * Function: H5G_build_fullpath_refstr_str |
278 | | * |
279 | | * Purpose: Append an object path to an existing ref-counted path |
280 | | * |
281 | | * Return: Success: Non-NULL, combined path |
282 | | * Failure: NULL |
283 | | * |
284 | | *------------------------------------------------------------------------- |
285 | | */ |
286 | | H5RS_str_t * |
287 | | H5G_build_fullpath_refstr_str(H5RS_str_t *prefix_r, const char *name) |
288 | 280 | { |
289 | 280 | const char *prefix; /* Pointer to raw string for path */ |
290 | 280 | H5RS_str_t *ret_value = NULL; /* Return value */ |
291 | | |
292 | 280 | FUNC_ENTER_NOAPI_NOINIT_NOERR |
293 | | |
294 | 280 | assert(prefix_r); |
295 | 280 | assert(name); |
296 | | |
297 | | /* Get the raw string for the user path */ |
298 | 280 | prefix = H5RS_get_str(prefix_r); |
299 | 280 | assert(prefix); |
300 | | |
301 | | /* Create reference counted string for path */ |
302 | 280 | ret_value = H5G__build_fullpath(prefix, name); |
303 | | |
304 | 280 | FUNC_LEAVE_NOAPI(ret_value) |
305 | 280 | } /* end H5G_build_fullpath_refstr_str() */ |
306 | | |
307 | | /*------------------------------------------------------------------------- |
308 | | * Function: H5G__name_init |
309 | | * |
310 | | * Purpose: Set the initial path for a group hierarchy name |
311 | | * |
312 | | * Return: Success: Non-negative |
313 | | * Failure: Negative |
314 | | * |
315 | | *------------------------------------------------------------------------- |
316 | | */ |
317 | | herr_t |
318 | | H5G__name_init(H5G_name_t *name, const char *path) |
319 | 7 | { |
320 | 7 | FUNC_ENTER_PACKAGE_NOERR |
321 | | |
322 | | /* Check arguments */ |
323 | 7 | assert(name); |
324 | | |
325 | | /* Set the initial paths for a name object */ |
326 | 7 | name->full_path_r = H5RS_create(path); |
327 | 7 | assert(name->full_path_r); |
328 | 7 | name->user_path_r = H5RS_create(path); |
329 | 7 | assert(name->user_path_r); |
330 | 7 | name->obj_hidden = 0; |
331 | | |
332 | 7 | FUNC_LEAVE_NOAPI(SUCCEED) |
333 | 7 | } /* end H5G__name_init() */ |
334 | | |
335 | | /*------------------------------------------------------------------------- |
336 | | * Function: H5G_name_set |
337 | | * |
338 | | * Purpose: Set the name of a symbol entry OBJ, located at LOC |
339 | | * |
340 | | * Return: Success: Non-negative |
341 | | * Failure: Negative |
342 | | * |
343 | | *------------------------------------------------------------------------- |
344 | | */ |
345 | | herr_t |
346 | | H5G_name_set(const H5G_name_t *loc, H5G_name_t *obj, const char *name) |
347 | 140 | { |
348 | 140 | herr_t ret_value = SUCCEED; |
349 | | |
350 | 140 | FUNC_ENTER_NOAPI(FAIL) |
351 | | |
352 | 140 | assert(loc); |
353 | 140 | assert(obj); |
354 | 140 | assert(name); |
355 | | |
356 | | /* Free & reset the object's previous paths info (if they exist) */ |
357 | 140 | H5G_name_free(obj); |
358 | | |
359 | | /* Create the object's full path, if a full path exists in the location */ |
360 | 140 | if (loc->full_path_r) { |
361 | | /* Go build the new full path */ |
362 | 140 | if ((obj->full_path_r = H5G_build_fullpath_refstr_str(loc->full_path_r, name)) == NULL) |
363 | 0 | HGOTO_ERROR(H5E_SYM, H5E_PATH, FAIL, "can't build user path name"); |
364 | 140 | } /* end if */ |
365 | | |
366 | | /* Create the object's user path, if a user path exists in the location */ |
367 | 140 | if (loc->user_path_r) { |
368 | | /* Go build the new user path */ |
369 | 140 | if ((obj->user_path_r = H5G_build_fullpath_refstr_str(loc->user_path_r, name)) == NULL) |
370 | 0 | HGOTO_ERROR(H5E_SYM, H5E_PATH, FAIL, "can't build user path name"); |
371 | 140 | } /* end if */ |
372 | | |
373 | 140 | done: |
374 | 140 | FUNC_LEAVE_NOAPI(ret_value) |
375 | 140 | } /* end H5G_name_set() */ |
376 | | |
377 | | /*------------------------------------------------------------------------- |
378 | | * Function: H5G_name_copy |
379 | | * |
380 | | * Purpose: Do a copy of group hier. names |
381 | | * |
382 | | * Return: Success: Non-negative |
383 | | * Failure: Negative |
384 | | * |
385 | | * Notes: 'depth' parameter determines how much of the group entry |
386 | | * structure we want to copy. The depths are: |
387 | | * H5_COPY_SHALLOW - Copy all the fields from the source |
388 | | * to the destination, including the user path and |
389 | | * canonical path. (Destination "takes ownership" of |
390 | | * user and canonical paths) |
391 | | * H5_COPY_DEEP - Copy all the fields from the source to |
392 | | * the destination, deep copying the user and canonical |
393 | | * paths. |
394 | | * |
395 | | *------------------------------------------------------------------------- |
396 | | */ |
397 | | herr_t |
398 | | H5G_name_copy(H5G_name_t *dst, const H5G_name_t *src, H5_copy_depth_t depth) |
399 | 1.13k | { |
400 | 1.13k | FUNC_ENTER_NOAPI_NOINIT_NOERR |
401 | | |
402 | | /* Check arguments */ |
403 | 1.13k | assert(src); |
404 | 1.13k | assert(dst); |
405 | | #if defined(H5_USING_MEMCHECKER) || !defined(NDEBUG) |
406 | | assert(dst->full_path_r == NULL); |
407 | | assert(dst->user_path_r == NULL); |
408 | | #endif /* H5_USING_MEMCHECKER */ |
409 | 1.13k | assert(depth == H5_COPY_SHALLOW || depth == H5_COPY_DEEP); |
410 | | |
411 | | /* Copy the top level information */ |
412 | 1.13k | H5MM_memcpy(dst, src, sizeof(H5G_name_t)); |
413 | | |
414 | | /* Deep copy the names */ |
415 | 1.13k | if (depth == H5_COPY_DEEP) { |
416 | 669 | dst->full_path_r = H5RS_dup(src->full_path_r); |
417 | 669 | dst->user_path_r = H5RS_dup(src->user_path_r); |
418 | 669 | } |
419 | 467 | else { |
420 | 467 | H5_GCC_CLANG_DIAG_OFF("cast-qual") |
421 | 467 | H5G_name_reset((H5G_name_t *)src); |
422 | 467 | H5_GCC_CLANG_DIAG_ON("cast-qual") |
423 | 467 | } |
424 | | |
425 | 1.13k | FUNC_LEAVE_NOAPI(SUCCEED) |
426 | 1.13k | } /* end H5G_name_copy() */ |
427 | | |
428 | | /*------------------------------------------------------------------------- |
429 | | * Function: H5G_get_name |
430 | | * |
431 | | * Purpose: Gets a name of an object from its ID. |
432 | | * |
433 | | * Notes: Internal routine for H5Iget_name(). |
434 | | |
435 | | * Return: Success: Non-negative, length of name |
436 | | * Failure: Negative |
437 | | * |
438 | | *------------------------------------------------------------------------- |
439 | | */ |
440 | | herr_t |
441 | | H5G_get_name(const H5G_loc_t *loc, char *name /*out*/, size_t size, size_t *name_len, bool *cached) |
442 | 0 | { |
443 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
444 | |
|
445 | 0 | FUNC_ENTER_NOAPI(FAIL) |
446 | | |
447 | | /* Sanity check */ |
448 | 0 | assert(loc); |
449 | | |
450 | | /* If the user path is available and it's not "hidden", use it */ |
451 | 0 | if (loc->path->user_path_r != NULL && loc->path->obj_hidden == 0) { |
452 | 0 | size_t len; /* Length of object's name */ |
453 | |
|
454 | 0 | len = H5RS_len(loc->path->user_path_r); |
455 | |
|
456 | 0 | if (name) { |
457 | 0 | strncpy(name, H5RS_get_str(loc->path->user_path_r), MIN((len + 1), size)); |
458 | 0 | if (len >= size) |
459 | 0 | name[size - 1] = '\0'; |
460 | 0 | } /* end if */ |
461 | | |
462 | | /* Set name length, if requested */ |
463 | 0 | if (name_len) |
464 | 0 | *name_len = len; |
465 | | |
466 | | /* Indicate that the name is cached, if requested */ |
467 | | /* (Currently only used for testing - QAK, 2010/07/26) */ |
468 | 0 | if (cached) |
469 | 0 | *cached = true; |
470 | 0 | } /* end if */ |
471 | 0 | else if (!loc->path->obj_hidden) { |
472 | | /* Search for name of object */ |
473 | 0 | if (H5G_get_name_by_addr(loc->oloc->file, loc->oloc, name, size, name_len) < 0) |
474 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't determine name"); |
475 | | |
476 | | /* Indicate that the name is _not_ cached, if requested */ |
477 | | /* (Currently only used for testing - QAK, 2010/07/26) */ |
478 | 0 | if (cached) |
479 | 0 | *cached = false; |
480 | 0 | } /* end else */ |
481 | | |
482 | 0 | done: |
483 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
484 | 0 | } /* end H5G_get_name() */ |
485 | | |
486 | | /*------------------------------------------------------------------------- |
487 | | * Function: H5G_name_reset |
488 | | * |
489 | | * Purpose: Reset a group hierarchy name to an empty state |
490 | | * |
491 | | * Return: Success: Non-negative |
492 | | * Failure: Negative |
493 | | * |
494 | | *------------------------------------------------------------------------- |
495 | | */ |
496 | | herr_t |
497 | | H5G_name_reset(H5G_name_t *name) |
498 | 2.00k | { |
499 | 2.00k | FUNC_ENTER_NOAPI_NOINIT_NOERR |
500 | | |
501 | | /* Check arguments */ |
502 | 2.00k | assert(name); |
503 | | |
504 | | /* Clear the group hier. name to an empty state */ |
505 | 2.00k | memset(name, 0, sizeof(H5G_name_t)); |
506 | | |
507 | 2.00k | FUNC_LEAVE_NOAPI(SUCCEED) |
508 | 2.00k | } /* end H5G_name_reset() */ |
509 | | |
510 | | /*------------------------------------------------------------------------- |
511 | | * Function: H5G_name_free |
512 | | * |
513 | | * Purpose: Free the 'ID to name' buffers. |
514 | | * |
515 | | * Return: Success |
516 | | * |
517 | | *------------------------------------------------------------------------- |
518 | | */ |
519 | | herr_t |
520 | | H5G_name_free(H5G_name_t *name) |
521 | 1.72k | { |
522 | 1.72k | FUNC_ENTER_NOAPI_NOINIT_NOERR |
523 | | |
524 | | /* Check args */ |
525 | 1.72k | assert(name); |
526 | | |
527 | 1.72k | if (name->full_path_r) { |
528 | 716 | H5RS_decr(name->full_path_r); |
529 | 716 | name->full_path_r = NULL; |
530 | 716 | } /* end if */ |
531 | 1.72k | if (name->user_path_r) { |
532 | 716 | H5RS_decr(name->user_path_r); |
533 | 716 | name->user_path_r = NULL; |
534 | 716 | } /* end if */ |
535 | 1.72k | name->obj_hidden = 0; |
536 | | |
537 | 1.72k | FUNC_LEAVE_NOAPI(SUCCEED) |
538 | 1.72k | } /* end H5G_name_free() */ |
539 | | |
540 | | /*------------------------------------------------------------------------- |
541 | | * Function: H5G__name_move_path |
542 | | * |
543 | | * Purpose: Update a user or canonical path after an object moves |
544 | | * |
545 | | * Return: Success: Non-negative |
546 | | * Failure: Negative |
547 | | * |
548 | | *------------------------------------------------------------------------- |
549 | | */ |
550 | | static herr_t |
551 | | H5G__name_move_path(H5RS_str_t **path_r_ptr, const char *full_suffix, const char *src_path, |
552 | | const char *dst_path) |
553 | 0 | { |
554 | 0 | const char *path; /* Path to update */ |
555 | 0 | size_t path_len; /* Length of path */ |
556 | 0 | size_t full_suffix_len; /* Length of full suffix */ |
557 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
558 | |
|
559 | 0 | FUNC_ENTER_PACKAGE |
560 | | |
561 | | /* Check arguments */ |
562 | 0 | assert(path_r_ptr && *path_r_ptr); |
563 | 0 | assert(full_suffix); |
564 | 0 | assert(src_path); |
565 | 0 | assert(dst_path); |
566 | | |
567 | | /* Get pointer to path to update */ |
568 | 0 | path = H5RS_get_str(*path_r_ptr); |
569 | 0 | assert(path); |
570 | | |
571 | | /* Check if path needs to be updated */ |
572 | 0 | full_suffix_len = strlen(full_suffix); |
573 | 0 | path_len = strlen(path); |
574 | 0 | if (full_suffix_len < path_len) { |
575 | 0 | const char *dst_suffix; /* Destination suffix that changes */ |
576 | 0 | const char *src_suffix; /* Source suffix that changes */ |
577 | 0 | size_t path_prefix_len; /* Length of path prefix */ |
578 | 0 | const char *path_prefix2; /* 2nd prefix for path */ |
579 | 0 | size_t path_prefix2_len; /* Length of 2nd path prefix */ |
580 | 0 | size_t common_prefix_len; /* Length of common prefix */ |
581 | 0 | H5RS_str_t *rs; /* Ref-counted string for new path */ |
582 | | |
583 | | /* Compute path prefix before full suffix */ |
584 | 0 | path_prefix_len = path_len - full_suffix_len; |
585 | | |
586 | | /* Determine the common prefix for src & dst paths */ |
587 | 0 | common_prefix_len = 0; |
588 | | /* Find first character that is different */ |
589 | 0 | while (*(src_path + common_prefix_len) == *(dst_path + common_prefix_len)) |
590 | 0 | common_prefix_len++; |
591 | | /* Back up to previous '/' */ |
592 | 0 | while (*(src_path + common_prefix_len) != '/') |
593 | 0 | common_prefix_len--; |
594 | | /* Include '/' */ |
595 | 0 | common_prefix_len++; |
596 | | |
597 | | /* Determine source suffix */ |
598 | 0 | src_suffix = src_path + (common_prefix_len - 1); |
599 | | |
600 | | /* Determine destination suffix */ |
601 | 0 | dst_suffix = dst_path + (common_prefix_len - 1); |
602 | | |
603 | | /* Compute path prefix before src suffix */ |
604 | 0 | path_prefix2 = path; |
605 | 0 | path_prefix2_len = path_prefix_len - strlen(src_suffix); |
606 | | |
607 | | /* Allocate new ref-counted string */ |
608 | 0 | if (NULL == (rs = H5RS_create(NULL))) |
609 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTCREATE, FAIL, "can't create ref-counted string"); |
610 | | |
611 | | /* Create the new path */ |
612 | 0 | if (path_prefix2_len > 0) |
613 | 0 | H5RS_ancat(rs, path_prefix2, path_prefix2_len); |
614 | 0 | H5RS_acat(rs, dst_suffix); |
615 | 0 | if (full_suffix_len > 0) |
616 | 0 | H5RS_acat(rs, full_suffix); |
617 | | |
618 | | /* Release previous path */ |
619 | 0 | H5RS_decr(*path_r_ptr); |
620 | | |
621 | | /* Take ownership of the new full path */ |
622 | 0 | *path_r_ptr = rs; |
623 | 0 | } /* end if */ |
624 | | |
625 | 0 | done: |
626 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
627 | 0 | } /* end H5G__name_move_path() */ |
628 | | |
629 | | /*------------------------------------------------------------------------- |
630 | | * Function: H5G__name_replace_cb |
631 | | * |
632 | | * Purpose: H5I_iterate callback function to replace group entry names |
633 | | * |
634 | | * Return: Success: 0, Failure: -1 |
635 | | * |
636 | | *------------------------------------------------------------------------- |
637 | | */ |
638 | | static int |
639 | | H5G__name_replace_cb(void *obj_ptr, hid_t obj_id, void *key) |
640 | 0 | { |
641 | 0 | const H5G_names_t *names = (const H5G_names_t *)key; /* Get operation's information */ |
642 | 0 | H5O_loc_t *oloc; /* Object location for object that the ID refers to */ |
643 | 0 | H5G_name_t *obj_path; /* Pointer to group hier. path for obj */ |
644 | 0 | H5F_t *top_obj_file; /* Top file in object's mounted file hier. */ |
645 | 0 | bool obj_in_child = false; /* Flag to indicate that the object is in the child mount hier. */ |
646 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
647 | |
|
648 | 0 | FUNC_ENTER_PACKAGE |
649 | |
|
650 | 0 | assert(obj_ptr); |
651 | | |
652 | | /* Get the symbol table entry */ |
653 | 0 | switch (H5I_get_type(obj_id)) { |
654 | 0 | case H5I_GROUP: |
655 | 0 | oloc = H5G_oloc((H5G_t *)obj_ptr); |
656 | 0 | obj_path = H5G_nameof((H5G_t *)obj_ptr); |
657 | 0 | break; |
658 | | |
659 | 0 | case H5I_DATASET: |
660 | 0 | oloc = H5D_oloc((H5D_t *)obj_ptr); |
661 | 0 | obj_path = H5D_nameof((H5D_t *)obj_ptr); |
662 | 0 | break; |
663 | | |
664 | 0 | case H5I_DATATYPE: |
665 | | /* Avoid non-named datatypes */ |
666 | 0 | if (!H5T_is_named((H5T_t *)obj_ptr)) |
667 | 0 | HGOTO_DONE(SUCCEED); /* Do not exit search over IDs */ |
668 | | |
669 | 0 | oloc = H5T_oloc((H5T_t *)obj_ptr); |
670 | 0 | obj_path = H5T_nameof((H5T_t *)obj_ptr); |
671 | 0 | break; |
672 | | |
673 | 0 | case H5I_MAP: |
674 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "maps not supported in native VOL connector"); |
675 | | |
676 | 0 | case H5I_UNINIT: |
677 | 0 | case H5I_BADID: |
678 | 0 | case H5I_FILE: |
679 | 0 | case H5I_DATASPACE: |
680 | 0 | case H5I_ATTR: |
681 | 0 | case H5I_VFL: |
682 | 0 | case H5I_VOL: |
683 | 0 | case H5I_GENPROP_CLS: |
684 | 0 | case H5I_GENPROP_LST: |
685 | 0 | case H5I_ERROR_CLASS: |
686 | 0 | case H5I_ERROR_MSG: |
687 | 0 | case H5I_ERROR_STACK: |
688 | 0 | case H5I_SPACE_SEL_ITER: |
689 | 0 | case H5I_EVENTSET: |
690 | 0 | case H5I_NTYPES: |
691 | 0 | default: |
692 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "unknown data object"); |
693 | 0 | } /* end switch */ |
694 | 0 | assert(oloc); |
695 | 0 | assert(obj_path); |
696 | | |
697 | | /* Check if the object has a full path still */ |
698 | 0 | if (!obj_path->full_path_r) |
699 | 0 | HGOTO_DONE(SUCCEED); /* No need to look at object, it's path is already invalid */ |
700 | | |
701 | | /* Find the top file in object's mount hier. */ |
702 | 0 | if (H5F_PARENT(oloc->file)) { |
703 | | /* Check if object is in child file (for mount & unmount operations) */ |
704 | 0 | if (names->dst_file && H5F_SAME_SHARED(oloc->file, names->dst_file)) |
705 | 0 | obj_in_child = true; |
706 | | |
707 | | /* Find the "top" file in the chain of mounted files */ |
708 | 0 | top_obj_file = H5F_PARENT(oloc->file); |
709 | 0 | while (H5F_PARENT(top_obj_file) != NULL) { |
710 | | /* Check if object is in child mount hier. (for mount & unmount operations) */ |
711 | 0 | if (names->dst_file && H5F_SAME_SHARED(top_obj_file, names->dst_file)) |
712 | 0 | obj_in_child = true; |
713 | |
|
714 | 0 | top_obj_file = H5F_PARENT(top_obj_file); |
715 | 0 | } /* end while */ |
716 | 0 | } /* end if */ |
717 | 0 | else |
718 | 0 | top_obj_file = oloc->file; |
719 | | |
720 | | /* Check if object is in top of child mount hier. (for mount & unmount operations) */ |
721 | 0 | if (names->dst_file && H5F_SAME_SHARED(top_obj_file, names->dst_file)) |
722 | 0 | obj_in_child = true; |
723 | | |
724 | | /* Check if the object is in same file mount hier. */ |
725 | 0 | if (!H5F_SAME_SHARED(top_obj_file, names->src_file)) |
726 | 0 | HGOTO_DONE(SUCCEED); /* No need to look at object, it's path is already invalid */ |
727 | | |
728 | 0 | switch (names->op) { |
729 | | /*------------------------------------------------------------------------- |
730 | | * H5G_NAME_MOUNT |
731 | | *------------------------------------------------------------------------- |
732 | | */ |
733 | 0 | case H5G_NAME_MOUNT: |
734 | | /* Check if object is in child mount hier. */ |
735 | 0 | if (obj_in_child) { |
736 | 0 | const char *full_path; /* Full path of current object */ |
737 | 0 | const char *src_path; /* Full path of source object */ |
738 | 0 | H5RS_str_t *rs; /* Ref-counted string for new path */ |
739 | | |
740 | | /* Get pointers to paths of interest */ |
741 | 0 | full_path = H5RS_get_str(obj_path->full_path_r); |
742 | 0 | src_path = H5RS_get_str(names->src_full_path_r); |
743 | | |
744 | | /* Create new full path */ |
745 | 0 | if (NULL == (rs = H5RS_create(src_path))) |
746 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTCREATE, FAIL, "can't create ref-counted string"); |
747 | 0 | H5RS_acat(rs, full_path); |
748 | | |
749 | | /* Release previous full path */ |
750 | 0 | H5RS_decr(obj_path->full_path_r); |
751 | | |
752 | | /* Take ownership of the new full path */ |
753 | 0 | obj_path->full_path_r = rs; |
754 | 0 | } /* end if */ |
755 | | /* Object must be in parent mount file hier. */ |
756 | 0 | else { |
757 | | /* Check if the source is along the entry's path */ |
758 | | /* (But not actually the entry itself) */ |
759 | 0 | if (H5G__common_path(obj_path->full_path_r, names->src_full_path_r) && |
760 | 0 | H5RS_cmp(obj_path->full_path_r, names->src_full_path_r)) { |
761 | | /* Hide the user path */ |
762 | 0 | (obj_path->obj_hidden)++; |
763 | 0 | } /* end if */ |
764 | 0 | } /* end else */ |
765 | 0 | break; |
766 | | |
767 | | /*------------------------------------------------------------------------- |
768 | | * H5G_NAME_UNMOUNT |
769 | | *------------------------------------------------------------------------- |
770 | | */ |
771 | 0 | case H5G_NAME_UNMOUNT: |
772 | 0 | if (obj_in_child) { |
773 | 0 | const char *full_path; /* Full path of current object */ |
774 | 0 | const char *full_suffix; /* Full path after source path */ |
775 | 0 | const char *src_path; /* Full path of source object */ |
776 | 0 | H5RS_str_t *rs; /* Ref-counted string for new path */ |
777 | | |
778 | | /* Get pointers to paths of interest */ |
779 | 0 | full_path = H5RS_get_str(obj_path->full_path_r); |
780 | 0 | src_path = H5RS_get_str(names->src_full_path_r); |
781 | | |
782 | | /* Construct full path suffix */ |
783 | 0 | full_suffix = full_path + strlen(src_path); |
784 | | |
785 | | /* Create new full path suffix */ |
786 | 0 | if (NULL == (rs = H5RS_create(full_suffix))) |
787 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTCREATE, FAIL, "can't create ref-counted string"); |
788 | | |
789 | | /* Release previous full path */ |
790 | 0 | H5RS_decr(obj_path->full_path_r); |
791 | | |
792 | | /* Take ownership of the new full path */ |
793 | 0 | obj_path->full_path_r = rs; |
794 | | |
795 | | /* Check if the object's user path should be invalidated */ |
796 | 0 | if (obj_path->user_path_r && H5RS_len(rs) < H5RS_len(obj_path->user_path_r)) { |
797 | | /* Free user path */ |
798 | 0 | H5RS_decr(obj_path->user_path_r); |
799 | 0 | obj_path->user_path_r = NULL; |
800 | 0 | } /* end if */ |
801 | 0 | } /* end if */ |
802 | 0 | else { |
803 | | /* Check if file being unmounted was hiding the object */ |
804 | 0 | if (H5G__common_path(obj_path->full_path_r, names->src_full_path_r) && |
805 | 0 | H5RS_cmp(obj_path->full_path_r, names->src_full_path_r)) { |
806 | | /* Un-hide the user path */ |
807 | 0 | (obj_path->obj_hidden)--; |
808 | 0 | } /* end if */ |
809 | 0 | } /* end else */ |
810 | 0 | break; |
811 | | |
812 | | /*------------------------------------------------------------------------- |
813 | | * H5G_NAME_DELETE |
814 | | *------------------------------------------------------------------------- |
815 | | */ |
816 | 0 | case H5G_NAME_DELETE: |
817 | | /* Check if the location being unlinked is in the path for the current object */ |
818 | 0 | if (H5G__common_path(obj_path->full_path_r, names->src_full_path_r)) { |
819 | | /* Free paths for object */ |
820 | 0 | H5G_name_free(obj_path); |
821 | 0 | } /* end if */ |
822 | 0 | break; |
823 | | |
824 | | /*------------------------------------------------------------------------- |
825 | | * H5G_NAME_MOVE |
826 | | *------------------------------------------------------------------------- |
827 | | */ |
828 | 0 | case H5G_NAME_MOVE: /* Link move case, check for relative names case */ |
829 | | /* Check if the src object moved is in the current object's path */ |
830 | 0 | if (H5G__common_path(obj_path->full_path_r, names->src_full_path_r)) { |
831 | 0 | const char *full_path; /* Full path of current object */ |
832 | 0 | const char *full_suffix; /* Suffix of full path, after src_path */ |
833 | 0 | const char *src_path; /* Full path of source object */ |
834 | 0 | const char *dst_path; /* Full path of destination object */ |
835 | 0 | H5RS_str_t *rs; /* Ref-counted string for new path */ |
836 | | |
837 | | /* Sanity check */ |
838 | 0 | assert(names->dst_full_path_r); |
839 | | |
840 | | /* Get pointers to paths of interest */ |
841 | 0 | full_path = H5RS_get_str(obj_path->full_path_r); |
842 | 0 | src_path = H5RS_get_str(names->src_full_path_r); |
843 | 0 | dst_path = H5RS_get_str(names->dst_full_path_r); |
844 | | |
845 | | /* Make certain that the source and destination names are full (not relative) paths */ |
846 | 0 | assert(*src_path == '/'); |
847 | 0 | assert(*dst_path == '/'); |
848 | | |
849 | | /* Get pointer to "full suffix" */ |
850 | 0 | full_suffix = full_path + strlen(src_path); |
851 | | |
852 | | /* Update the user path, if one exists */ |
853 | 0 | if (obj_path->user_path_r) |
854 | 0 | if (H5G__name_move_path(&(obj_path->user_path_r), full_suffix, src_path, dst_path) < 0) |
855 | 0 | HGOTO_ERROR(H5E_SYM, H5E_PATH, FAIL, "can't build user path name"); |
856 | | |
857 | | /* Create new full path */ |
858 | 0 | if (NULL == (rs = H5RS_create(dst_path))) |
859 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTCREATE, FAIL, "can't create ref-counted string"); |
860 | 0 | H5RS_acat(rs, full_suffix); |
861 | | |
862 | | /* Release previous full path */ |
863 | 0 | H5RS_decr(obj_path->full_path_r); |
864 | | |
865 | | /* Take ownership of the new full path */ |
866 | 0 | obj_path->full_path_r = rs; |
867 | 0 | } /* end if */ |
868 | 0 | break; |
869 | | |
870 | 0 | default: |
871 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid operation"); |
872 | 0 | } /* end switch */ |
873 | | |
874 | 0 | done: |
875 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
876 | 0 | } /* end H5G__name_replace_cb() */ |
877 | | |
878 | | /*------------------------------------------------------------------------- |
879 | | * Function: H5G_name_replace |
880 | | * |
881 | | * Purpose: Search the list of open IDs and replace names according to a |
882 | | * particular operation. The operation occurred on the |
883 | | * SRC_FILE/SRC_FULL_PATH_R object. The new name (if there is |
884 | | * one) is NEW_NAME_R. Additional entry location information |
885 | | * (currently only needed for the 'move' operation) is passed in |
886 | | * DST_FILE/DST_FULL_PATH_R. |
887 | | * |
888 | | * Return: Success: 0, Failure: -1 |
889 | | * |
890 | | *------------------------------------------------------------------------- |
891 | | */ |
892 | | herr_t |
893 | | H5G_name_replace(const H5O_link_t *lnk, H5G_names_op_t op, H5F_t *src_file, H5RS_str_t *src_full_path_r, |
894 | | H5F_t *dst_file, H5RS_str_t *dst_full_path_r) |
895 | 0 | { |
896 | 0 | herr_t ret_value = SUCCEED; |
897 | |
|
898 | 0 | FUNC_ENTER_NOAPI(FAIL) |
899 | | |
900 | | /* Check arguments */ |
901 | 0 | assert(src_file); |
902 | | |
903 | | /* Check if the object we are manipulating has a path */ |
904 | 0 | if (src_full_path_r) { |
905 | 0 | bool search_group = false; /* Flag to indicate that groups are to be searched */ |
906 | 0 | bool search_dataset = false; /* Flag to indicate that datasets are to be searched */ |
907 | 0 | bool search_datatype = false; /* Flag to indicate that datatypes are to be searched */ |
908 | | |
909 | | /* Check for particular link to operate on */ |
910 | 0 | if (lnk) { |
911 | | /* Look up the object type for each type of link */ |
912 | 0 | switch (lnk->type) { |
913 | 0 | case H5L_TYPE_HARD: { |
914 | 0 | H5O_loc_t tmp_oloc; /* Temporary object location */ |
915 | 0 | H5O_type_t obj_type; /* Type of object at location */ |
916 | | |
917 | | /* Build temporary object location */ |
918 | 0 | tmp_oloc.file = src_file; |
919 | 0 | tmp_oloc.addr = lnk->u.hard.addr; |
920 | | |
921 | | /* Get the type of the object */ |
922 | 0 | if (H5O_obj_type(&tmp_oloc, &obj_type) < 0) |
923 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't get object type"); |
924 | | |
925 | | /* Determine which type of objects to operate on */ |
926 | 0 | switch (obj_type) { |
927 | 0 | case H5O_TYPE_GROUP: |
928 | | /* Search and replace names through group IDs */ |
929 | 0 | search_group = true; |
930 | 0 | break; |
931 | | |
932 | 0 | case H5O_TYPE_DATASET: |
933 | | /* Search and replace names through dataset IDs */ |
934 | 0 | search_dataset = true; |
935 | 0 | break; |
936 | | |
937 | 0 | case H5O_TYPE_NAMED_DATATYPE: |
938 | | /* Search and replace names through datatype IDs */ |
939 | 0 | search_datatype = true; |
940 | 0 | break; |
941 | | |
942 | 0 | case H5O_TYPE_MAP: |
943 | 0 | HGOTO_ERROR(H5E_SYM, H5E_BADTYPE, FAIL, |
944 | 0 | "maps not supported in native VOL connector"); |
945 | | |
946 | 0 | case H5O_TYPE_UNKNOWN: |
947 | 0 | case H5O_TYPE_NTYPES: |
948 | | /* Search and replace names through datatype IDs */ |
949 | 0 | default: |
950 | 0 | HGOTO_ERROR(H5E_SYM, H5E_BADTYPE, FAIL, "not valid object type"); |
951 | 0 | } /* end switch */ |
952 | 0 | } /* end case */ |
953 | 0 | break; |
954 | | |
955 | 0 | case H5L_TYPE_SOFT: |
956 | | /* Symbolic links might resolve to any object, so we need to search all IDs */ |
957 | 0 | search_group = search_dataset = search_datatype = true; |
958 | 0 | break; |
959 | | |
960 | 0 | case H5L_TYPE_ERROR: |
961 | 0 | case H5L_TYPE_EXTERNAL: |
962 | 0 | case H5L_TYPE_MAX: |
963 | 0 | default: /* User-defined link */ |
964 | | /* Check for unknown library-defined link type */ |
965 | 0 | if (lnk->type < H5L_TYPE_UD_MIN) |
966 | 0 | HGOTO_ERROR(H5E_SYM, H5E_BADVALUE, FAIL, "unknown link type"); |
967 | | |
968 | | /* User-defined & external links automatically wipe out |
969 | | * names (because it would be too much work to track them), |
970 | | * so there's no point in searching them. |
971 | | */ |
972 | 0 | break; |
973 | 0 | } /* end switch */ |
974 | 0 | } /* end if */ |
975 | 0 | else { |
976 | | /* We pass NULL as link pointer when we need to search all IDs */ |
977 | 0 | search_group = search_dataset = search_datatype = true; |
978 | 0 | } |
979 | | |
980 | | /* Check if we need to operate on the objects affected */ |
981 | 0 | if (search_group || search_dataset || search_datatype) { |
982 | 0 | H5G_names_t names; /* Structure to hold operation information for callback */ |
983 | | |
984 | | /* Find top file in src location's mount hierarchy */ |
985 | 0 | while (H5F_PARENT(src_file)) |
986 | 0 | src_file = H5F_PARENT(src_file); |
987 | | |
988 | | /* Set up common information for callback */ |
989 | 0 | names.src_file = src_file; |
990 | 0 | names.src_full_path_r = src_full_path_r; |
991 | 0 | names.dst_file = dst_file; |
992 | 0 | names.dst_full_path_r = dst_full_path_r; |
993 | 0 | names.op = op; |
994 | | |
995 | | /* Search through group IDs */ |
996 | 0 | if (search_group) |
997 | 0 | if (H5I_iterate(H5I_GROUP, H5G__name_replace_cb, &names, false) < 0) |
998 | 0 | HGOTO_ERROR(H5E_SYM, H5E_BADITER, FAIL, "can't iterate over groups"); |
999 | | |
1000 | | /* Search through dataset IDs */ |
1001 | 0 | if (search_dataset) |
1002 | 0 | if (H5I_iterate(H5I_DATASET, H5G__name_replace_cb, &names, false) < 0) |
1003 | 0 | HGOTO_ERROR(H5E_SYM, H5E_BADITER, FAIL, "can't iterate over datasets"); |
1004 | | |
1005 | | /* Search through datatype IDs */ |
1006 | 0 | if (search_datatype) |
1007 | 0 | if (H5I_iterate(H5I_DATATYPE, H5G__name_replace_cb, &names, false) < 0) |
1008 | 0 | HGOTO_ERROR(H5E_SYM, H5E_BADITER, FAIL, "can't iterate over datatypes"); |
1009 | 0 | } /* end if */ |
1010 | 0 | } /* end if */ |
1011 | | |
1012 | 0 | done: |
1013 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1014 | 0 | } /* end H5G_name_replace() */ |
1015 | | |
1016 | | /*------------------------------------------------------------------------- |
1017 | | * Function: H5G__get_name_by_addr_cb |
1018 | | * |
1019 | | * Purpose: Callback for retrieving object's name by address |
1020 | | * |
1021 | | * Return: Positive if path is for object desired |
1022 | | * 0 if not correct object |
1023 | | * negative on failure. |
1024 | | * |
1025 | | *------------------------------------------------------------------------- |
1026 | | */ |
1027 | | static herr_t |
1028 | | H5G__get_name_by_addr_cb(hid_t gid, const char *path, const H5L_info2_t *linfo, void *_udata) |
1029 | 0 | { |
1030 | 0 | H5G_gnba_iter_t *udata = (H5G_gnba_iter_t *)_udata; /* User data for iteration */ |
1031 | 0 | H5G_loc_t obj_loc; /* Location of object */ |
1032 | 0 | H5G_name_t obj_path; /* Object's group hier. path */ |
1033 | 0 | H5O_loc_t obj_oloc; /* Object's object location */ |
1034 | 0 | bool obj_found = false; /* Object at 'path' found */ |
1035 | 0 | herr_t ret_value = H5_ITER_CONT; /* Return value */ |
1036 | |
|
1037 | 0 | FUNC_ENTER_PACKAGE |
1038 | | |
1039 | | /* Sanity check */ |
1040 | 0 | assert(path); |
1041 | 0 | assert(linfo); |
1042 | 0 | assert(udata->loc); |
1043 | 0 | assert(udata->path == NULL); |
1044 | | |
1045 | | /* Check for hard link with correct address */ |
1046 | 0 | if (linfo->type == H5L_TYPE_HARD) { |
1047 | 0 | haddr_t link_addr; |
1048 | | |
1049 | | /* Retrieve hard link address from VOL token */ |
1050 | 0 | if (H5VL_native_token_to_addr(udata->loc->file, H5I_FILE, linfo->u.token, &link_addr) < 0) |
1051 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTUNSERIALIZE, FAIL, "can't deserialize object token into address"); |
1052 | | |
1053 | 0 | if (udata->loc->addr == link_addr) { |
1054 | 0 | H5G_loc_t grp_loc; /* Location of group */ |
1055 | | |
1056 | | /* Get group's location */ |
1057 | 0 | if (H5G_loc(gid, &grp_loc) < 0) |
1058 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5_ITER_ERROR, "bad group location"); |
1059 | | |
1060 | | /* Set up opened object location to fill in */ |
1061 | 0 | obj_loc.oloc = &obj_oloc; |
1062 | 0 | obj_loc.path = &obj_path; |
1063 | 0 | H5G_loc_reset(&obj_loc); |
1064 | | |
1065 | | /* Find the object */ |
1066 | 0 | if (H5G_loc_find(&grp_loc, path, &obj_loc /*out*/) < 0) |
1067 | 0 | HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, H5_ITER_ERROR, "object not found"); |
1068 | 0 | obj_found = true; |
1069 | | |
1070 | | /* Check for object in same file (handles mounted files) */ |
1071 | | /* (re-verify address, in case we traversed a file mount) */ |
1072 | 0 | if (udata->loc->addr == obj_loc.oloc->addr && udata->loc->file == obj_loc.oloc->file) { |
1073 | 0 | if (NULL == (udata->path = H5MM_strdup(path))) |
1074 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTALLOC, H5_ITER_ERROR, "can't duplicate path string"); |
1075 | | |
1076 | | /* We found a match so we return immediately */ |
1077 | 0 | HGOTO_DONE(H5_ITER_STOP); |
1078 | 0 | } /* end if */ |
1079 | 0 | } /* end if */ |
1080 | 0 | } /* end if */ |
1081 | | |
1082 | 0 | done: |
1083 | 0 | if (obj_found && H5G_loc_free(&obj_loc) < 0) |
1084 | 0 | HDONE_ERROR(H5E_SYM, H5E_CANTRELEASE, H5_ITER_ERROR, "can't free location"); |
1085 | |
|
1086 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1087 | 0 | } /* end H5G__get_name_by_addr_cb() */ |
1088 | | |
1089 | | /*------------------------------------------------------------------------- |
1090 | | * Function: H5G_get_name_by_addr |
1091 | | * |
1092 | | * Purpose: Tries to figure out the path to an object from it's address |
1093 | | * |
1094 | | * Return: Success: Returns size of path name, and copies it into buffer |
1095 | | * pointed to by name if that buffer is big enough. |
1096 | | * 0 if it cannot find the path |
1097 | | * |
1098 | | * Failure: -1 |
1099 | | * |
1100 | | *------------------------------------------------------------------------- |
1101 | | */ |
1102 | | herr_t |
1103 | | H5G_get_name_by_addr(H5F_t *f, const H5O_loc_t *loc, char *name, size_t size, size_t *name_len) |
1104 | 0 | { |
1105 | 0 | H5G_gnba_iter_t udata; /* User data for iteration */ |
1106 | 0 | size_t len; /* Length of path name */ |
1107 | 0 | H5G_loc_t root_loc; /* Root group's location */ |
1108 | 0 | bool found_obj = false; /* If we found the object */ |
1109 | 0 | herr_t status; /* Status from iteration */ |
1110 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
1111 | | |
1112 | | /* Portably clear udata struct (before FUNC_ENTER) */ |
1113 | 0 | memset(&udata, 0, sizeof(udata)); |
1114 | |
|
1115 | 0 | FUNC_ENTER_NOAPI(FAIL) |
1116 | | |
1117 | | /* Construct a group location for root group of the file */ |
1118 | 0 | if (H5G_root_loc(f, &root_loc) < 0) |
1119 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't get root group's location"); |
1120 | | |
1121 | | /* Check for root group being the object looked for */ |
1122 | 0 | if (root_loc.oloc->addr == loc->addr && root_loc.oloc->file == loc->file) { |
1123 | 0 | if (NULL == (udata.path = H5MM_strdup(""))) |
1124 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTALLOC, FAIL, "can't duplicate path string"); |
1125 | 0 | found_obj = true; |
1126 | 0 | } /* end if */ |
1127 | 0 | else { |
1128 | | /* Set up user data for iterator */ |
1129 | 0 | udata.loc = loc; |
1130 | 0 | udata.path = NULL; |
1131 | | |
1132 | | /* Visit all the links in the file */ |
1133 | 0 | if ((status = H5G_visit(&root_loc, "/", H5_INDEX_NAME, H5_ITER_NATIVE, H5G__get_name_by_addr_cb, |
1134 | 0 | &udata)) < 0) |
1135 | 0 | HGOTO_ERROR(H5E_SYM, H5E_BADITER, FAIL, "group traversal failed while looking for object name"); |
1136 | 0 | else if (status > 0) |
1137 | 0 | found_obj = true; |
1138 | 0 | } /* end else */ |
1139 | | |
1140 | | /* Check for finding the object */ |
1141 | 0 | if (found_obj) { |
1142 | | /* Set the length of the full path */ |
1143 | 0 | len = strlen(udata.path) + 1; /* Length of path + 1 (for "/") */ |
1144 | | |
1145 | | /* If there's a buffer provided, copy into it, up to the limit of its size */ |
1146 | 0 | if (name) { |
1147 | | /* Copy the initial path separator */ |
1148 | 0 | strncpy(name, "/", (size_t)2); |
1149 | | |
1150 | | /* Append the rest of the path */ |
1151 | | /* (less one character, for the initial path separator) */ |
1152 | 0 | strncat(name, udata.path, (size - 2)); |
1153 | 0 | if (len >= size) |
1154 | 0 | name[size - 1] = '\0'; |
1155 | 0 | } /* end if */ |
1156 | 0 | } /* end if */ |
1157 | 0 | else |
1158 | 0 | len = 0; |
1159 | | |
1160 | | /* Set path name length, if given */ |
1161 | 0 | if (name_len) |
1162 | 0 | *name_len = len; |
1163 | |
|
1164 | 0 | done: |
1165 | | /* Release resources */ |
1166 | 0 | H5MM_xfree(udata.path); |
1167 | |
|
1168 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1169 | 0 | } /* end H5G_get_name_by_addr() */ |