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 /*-------------------------------------------------------------------------
15 *
16 * Created: H5Glink.c
17 * Nov 13 2006
18 * Quincey Koziol <koziol@hdfgroup.org>
19 *
20 * Purpose: Functions for handling links in groups.
21 *
22 *-------------------------------------------------------------------------
23 */
24
25 /****************/
26 /* Module Setup */
27 /****************/
28
29 #define H5G_PACKAGE /*suppress error about including H5Gpkg */
30
31
32 /***********/
33 /* Headers */
34 /***********/
35 #include "H5private.h" /* Generic Functions */
36 #include "H5Eprivate.h" /* Error handling */
37 #include "H5Gpkg.h" /* Groups */
38 #include "H5HLprivate.h" /* Local Heaps */
39 #include "H5Iprivate.h" /* IDs */
40 #include "H5Lprivate.h" /* Links */
41 #include "H5MMprivate.h" /* Memory management */
42 #include "H5Ppublic.h" /* Property Lists */
43
44
45 /****************/
46 /* Local Macros */
47 /****************/
48
49
50 /******************/
51 /* Local Typedefs */
52 /******************/
53
54
55 /********************/
56 /* Package Typedefs */
57 /********************/
58
59
60 /********************/
61 /* Local Prototypes */
62 /********************/
63
64 static int H5G_link_cmp_name_inc(const void *lnk1, const void *lnk2);
65 static int H5G_link_cmp_name_dec(const void *lnk1, const void *lnk2);
66 static int H5G_link_cmp_corder_inc(const void *lnk1, const void *lnk2);
67 static int H5G_link_cmp_corder_dec(const void *lnk1, const void *lnk2);
68
69
70 /*********************/
71 /* Package Variables */
72 /*********************/
73
74
75 /*****************************/
76 /* Library Private Variables */
77 /*****************************/
78
79
80 /*******************/
81 /* Local Variables */
82 /*******************/
83
84
85
86 /*-------------------------------------------------------------------------
87 * Function: H5G_link_cmp_name_inc
88 *
89 * Purpose: Callback routine for comparing two link names, in
90 * increasing alphabetic order
91 *
92 * Return: An integer less than, equal to, or greater than zero if the
93 * first argument is considered to be respectively less than,
94 * equal to, or greater than the second. If two members compare
95 * as equal, their order in the sorted array is undefined.
96 * (i.e. same as strcmp())
97 *
98 * Programmer: Quincey Koziol
99 * koziol@ncsa.uiuc.edu
100 * Sep 5 2005
101 *
102 *-------------------------------------------------------------------------
103 */
104 static int
H5G_link_cmp_name_inc(const void * lnk1,const void * lnk2)105 H5G_link_cmp_name_inc(const void *lnk1, const void *lnk2)
106 {
107 FUNC_ENTER_NOAPI_NOINIT_NOERR
108
109 FUNC_LEAVE_NOAPI(HDstrcmp(((const H5O_link_t *)lnk1)->name, ((const H5O_link_t *)lnk2)->name))
110 } /* end H5G_link_cmp_name_inc() */
111
112
113 /*-------------------------------------------------------------------------
114 * Function: H5G_link_cmp_name_dec
115 *
116 * Purpose: Callback routine for comparing two link names, in
117 * decreasing alphabetic order
118 *
119 * Return: An integer less than, equal to, or greater than zero if the
120 * second argument is considered to be respectively less than,
121 * equal to, or greater than the first. If two members compare
122 * as equal, their order in the sorted array is undefined.
123 * (i.e. opposite strcmp())
124 *
125 * Programmer: Quincey Koziol
126 * koziol@ncsa.uiuc.edu
127 * Sep 25 2006
128 *
129 *-------------------------------------------------------------------------
130 */
131 static int
H5G_link_cmp_name_dec(const void * lnk1,const void * lnk2)132 H5G_link_cmp_name_dec(const void *lnk1, const void *lnk2)
133 {
134 FUNC_ENTER_NOAPI_NOINIT_NOERR
135
136 FUNC_LEAVE_NOAPI(HDstrcmp(((const H5O_link_t *)lnk2)->name, ((const H5O_link_t *)lnk1)->name))
137 } /* end H5G_link_cmp_name_dec() */
138
139
140 /*-------------------------------------------------------------------------
141 * Function: H5G_link_cmp_corder_inc
142 *
143 * Purpose: Callback routine for comparing two link creation orders, in
144 * increasing order
145 *
146 * Return: An integer less than, equal to, or greater than zero if the
147 * first argument is considered to be respectively less than,
148 * equal to, or greater than the second. If two members compare
149 * as equal, their order in the sorted array is undefined.
150 *
151 * Programmer: Quincey Koziol
152 * koziol@hdfgroup.org
153 * Nov 6 2006
154 *
155 *-------------------------------------------------------------------------
156 */
157 static int
H5G_link_cmp_corder_inc(const void * lnk1,const void * lnk2)158 H5G_link_cmp_corder_inc(const void *lnk1, const void *lnk2)
159 {
160 int ret_value; /* Return value */
161
162 FUNC_ENTER_NOAPI_NOINIT_NOERR
163
164 if(((const H5O_link_t *)lnk1)->corder < ((const H5O_link_t *)lnk2)->corder)
165 ret_value = -1;
166 else if(((const H5O_link_t *)lnk1)->corder > ((const H5O_link_t *)lnk2)->corder)
167 ret_value = 1;
168 else
169 ret_value = 0;
170
171 FUNC_LEAVE_NOAPI(ret_value)
172 } /* end H5G_link_cmp_corder_inc() */
173
174
175 /*-------------------------------------------------------------------------
176 * Function: H5G_link_cmp_corder_dec
177 *
178 * Purpose: Callback routine for comparing two link creation orders, in
179 * decreasing order
180 *
181 * Return: An integer less than, equal to, or greater than zero if the
182 * second argument is considered to be respectively less than,
183 * equal to, or greater than the first. If two members compare
184 * as equal, their order in the sorted array is undefined.
185 *
186 * Programmer: Quincey Koziol
187 * koziol@hdfgroup.org
188 * Nov 6 2006
189 *
190 *-------------------------------------------------------------------------
191 */
192 static int
H5G_link_cmp_corder_dec(const void * lnk1,const void * lnk2)193 H5G_link_cmp_corder_dec(const void *lnk1, const void *lnk2)
194 {
195 int ret_value; /* Return value */
196
197 FUNC_ENTER_NOAPI_NOINIT_NOERR
198
199 if(((const H5O_link_t *)lnk1)->corder < ((const H5O_link_t *)lnk2)->corder)
200 ret_value = 1;
201 else if(((const H5O_link_t *)lnk1)->corder > ((const H5O_link_t *)lnk2)->corder)
202 ret_value = -1;
203 else
204 ret_value = 0;
205
206 FUNC_LEAVE_NOAPI(ret_value)
207 } /* end H5G_link_cmp_corder_dec() */
208
209
210 /*-------------------------------------------------------------------------
211 * Function: H5G__ent_to_link
212 *
213 * Purpose: Convert a symbol table entry to a link
214 *
215 * Return: Non-negative on success/Negative on failure
216 *
217 * Programmer: Quincey Koziol
218 * koziol@hdfgroup.org
219 * Sep 16 2006
220 *
221 *-------------------------------------------------------------------------
222 */
223 herr_t
H5G__ent_to_link(H5O_link_t * lnk,const H5HL_t * heap,const H5G_entry_t * ent,const char * name)224 H5G__ent_to_link(H5O_link_t *lnk, const H5HL_t *heap,
225 const H5G_entry_t *ent, const char *name)
226 {
227 hbool_t dup_soft = FALSE; /* xstrdup the symbolic link name or not */
228 herr_t ret_value = SUCCEED; /* Return value */
229
230 FUNC_ENTER_PACKAGE
231
232 /* check arguments */
233 HDassert(lnk);
234 HDassert(heap);
235 HDassert(ent);
236 HDassert(name);
237
238 /* Set (default) common info for link */
239 lnk->cset = H5F_DEFAULT_CSET;
240 lnk->corder = 0;
241 lnk->corder_valid = FALSE; /* Creation order not valid for this link */
242 if((lnk->name = H5MM_xstrdup(name)) == NULL)
243 HGOTO_ERROR(H5E_LINK, H5E_CANTGET, FAIL, "unable to duplicate link name")
244
245 /* Object is a symbolic or hard link */
246 if(ent->type == H5G_CACHED_SLINK) {
247 const char *s; /* Pointer to link value */
248
249 if((s = (const char *)H5HL_offset_into(heap, ent->cache.slink.lval_offset)) == NULL)
250 HGOTO_ERROR(H5E_LINK, H5E_CANTGET, FAIL, "unable to get symbolic link name")
251
252 /* Copy the link value */
253 if((lnk->u.soft.name = H5MM_xstrdup(s)) == NULL)
254 HGOTO_ERROR(H5E_LINK, H5E_CANTGET, FAIL, "unable to duplicate symbolic link name")
255
256 dup_soft = TRUE;
257
258 /* Set link type */
259 lnk->type = H5L_TYPE_SOFT;
260 } /* end if */
261 else {
262 /* Set address of object */
263 lnk->u.hard.addr = ent->header;
264
265 /* Set link type */
266 lnk->type = H5L_TYPE_HARD;
267 } /* end else */
268
269 done:
270 if(ret_value < 0) {
271 if(lnk->name)
272 H5MM_xfree(lnk->name);
273 if(ent->type == H5G_CACHED_SLINK && dup_soft)
274 H5MM_xfree(lnk->u.soft.name);
275 }
276 FUNC_LEAVE_NOAPI(ret_value)
277 } /* end H5G__ent_to_link() */
278
279
280 /*-------------------------------------------------------------------------
281 * Function: H5G_link_to_info
282 *
283 * Purpose: Retrieve information from a link object
284 *
285 * Return: Non-negative on success/Negative on failure
286 *
287 * Programmer: Quincey Koziol
288 * Tuesday, November 7 2006
289 *
290 *-------------------------------------------------------------------------
291 */
292 herr_t
H5G_link_to_info(const H5O_link_t * lnk,H5L_info_t * info)293 H5G_link_to_info(const H5O_link_t *lnk, H5L_info_t *info)
294 {
295 herr_t ret_value = SUCCEED; /* Return value */
296
297 FUNC_ENTER_NOAPI(FAIL)
298
299 /* Sanity check */
300 HDassert(lnk);
301
302 /* Get information from the link */
303 if(info) {
304 info->cset = lnk->cset;
305 info->corder = lnk->corder;
306 info->corder_valid = lnk->corder_valid;
307 info->type = lnk->type;
308
309 switch(lnk->type) {
310 case H5L_TYPE_HARD:
311 info->u.address = lnk->u.hard.addr;
312 break;
313
314 case H5L_TYPE_SOFT:
315 info->u.val_size = HDstrlen(lnk->u.soft.name) + 1; /*count the null terminator*/
316 break;
317
318 case H5L_TYPE_ERROR:
319 case H5L_TYPE_EXTERNAL:
320 case H5L_TYPE_MAX:
321 default:
322 {
323 const H5L_class_t *link_class; /* User-defined link class */
324
325 if(lnk->type < H5L_TYPE_UD_MIN || lnk->type > H5L_TYPE_MAX)
326 HGOTO_ERROR(H5E_LINK, H5E_BADTYPE, FAIL, "unknown link class")
327
328 /* User-defined link; call its query function to get the link udata size. */
329 /* Get the link class for this type of link. It's okay if the class
330 * isn't registered, though--we just can't give any more information
331 * about it
332 */
333 link_class = H5L_find_class(lnk->type);
334
335 if(link_class != NULL && link_class->query_func != NULL) {
336 ssize_t cb_ret; /* Return value from UD callback */
337
338 /* Call the link's query routine to retrieve the user-defined link's value size */
339 /* (in case the query routine packs/unpacks the link value in some way that changes its size) */
340 if((cb_ret = (link_class->query_func)(lnk->name, lnk->u.ud.udata, lnk->u.ud.size, NULL, (size_t)0)) < 0)
341 HGOTO_ERROR(H5E_LINK, H5E_CALLBACK, FAIL, "query buffer size callback returned failure")
342
343 info->u.val_size = (size_t)cb_ret;
344 } /* end if */
345 else
346 info->u.val_size = 0;
347 } /* end case */
348 } /* end switch */
349 } /* end if */
350
351 done:
352 FUNC_LEAVE_NOAPI(ret_value)
353 } /* end H5G_link_to_info() */
354
355
356 /*-------------------------------------------------------------------------
357 * Function: H5G__link_to_loc
358 *
359 * Purpose: Build group location from group and link object
360 *
361 * Return: Non-negative on success/Negative on failure
362 *
363 * Programmer: Quincey Koziol
364 * Monday, November 20 2006
365 *
366 *-------------------------------------------------------------------------
367 */
368 herr_t
H5G__link_to_loc(const H5G_loc_t * grp_loc,const H5O_link_t * lnk,H5G_loc_t * obj_loc)369 H5G__link_to_loc(const H5G_loc_t *grp_loc, const H5O_link_t *lnk,
370 H5G_loc_t *obj_loc)
371 {
372 herr_t ret_value = SUCCEED; /* Return value */
373
374 FUNC_ENTER_PACKAGE
375
376 /* Sanity check */
377 HDassert(grp_loc);
378 HDassert(lnk);
379 HDassert(obj_loc);
380
381 /*
382 * Build location from the link
383 */
384
385 /* Check for unknown library-internal link */
386 if(lnk->type > H5L_TYPE_BUILTIN_MAX && lnk->type < H5L_TYPE_UD_MIN)
387 HGOTO_ERROR(H5E_SYM, H5E_UNSUPPORTED, FAIL, "unknown link type")
388
389 /* Build object's group hier. location */
390 if(H5G_name_set(grp_loc->path, obj_loc->path, lnk->name) < 0)
391 HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "cannot set name")
392
393 /* Set the object location, if it's a hard link set the address also */
394 obj_loc->oloc->file = grp_loc->oloc->file;
395 obj_loc->oloc->holding_file = FALSE;
396 if(lnk->type == H5L_TYPE_HARD)
397 obj_loc->oloc->addr = lnk->u.hard.addr;
398
399 done:
400 FUNC_LEAVE_NOAPI(ret_value)
401 } /* end H5G__link_to_loc() */
402
403
404 /*-------------------------------------------------------------------------
405 * Function: H5G__link_sort_table
406 *
407 * Purpose: Sort table containing a list of links for a group
408 *
409 * Return: Success: Non-negative
410 * Failure: Negative
411 *
412 * Programmer: Quincey Koziol
413 * Nov 20, 2006
414 *
415 *-------------------------------------------------------------------------
416 */
417 herr_t
H5G__link_sort_table(H5G_link_table_t * ltable,H5_index_t idx_type,H5_iter_order_t order)418 H5G__link_sort_table(H5G_link_table_t *ltable, H5_index_t idx_type,
419 H5_iter_order_t order)
420 {
421 FUNC_ENTER_PACKAGE_NOERR
422
423 /* Sanity check */
424 HDassert(ltable);
425
426 /* Pick appropriate sorting routine */
427 if(idx_type == H5_INDEX_NAME) {
428 if(order == H5_ITER_INC)
429 HDqsort(ltable->lnks, ltable->nlinks, sizeof(H5O_link_t), H5G_link_cmp_name_inc);
430 else if(order == H5_ITER_DEC)
431 HDqsort(ltable->lnks, ltable->nlinks, sizeof(H5O_link_t), H5G_link_cmp_name_dec);
432 else
433 HDassert(order == H5_ITER_NATIVE);
434 } /* end if */
435 else {
436 HDassert(idx_type == H5_INDEX_CRT_ORDER);
437 if(order == H5_ITER_INC)
438 HDqsort(ltable->lnks, ltable->nlinks, sizeof(H5O_link_t), H5G_link_cmp_corder_inc);
439 else if(order == H5_ITER_DEC)
440 HDqsort(ltable->lnks, ltable->nlinks, sizeof(H5O_link_t), H5G_link_cmp_corder_dec);
441 else
442 HDassert(order == H5_ITER_NATIVE);
443 } /* end else */
444
445 FUNC_LEAVE_NOAPI(SUCCEED)
446 } /* end H5G__link_sort_table() */
447
448
449 /*-------------------------------------------------------------------------
450 * Function: H5G__link_iterate_table
451 *
452 * Purpose: Iterate over table containing a list of links for a group,
453 * making appropriate callbacks
454 *
455 * Return: Success: Non-negative
456 * Failure: Negative
457 *
458 * Programmer: Quincey Koziol
459 * Nov 20, 2006
460 *
461 *-------------------------------------------------------------------------
462 */
463 herr_t
H5G__link_iterate_table(const H5G_link_table_t * ltable,hsize_t skip,hsize_t * last_lnk,const H5G_lib_iterate_t op,void * op_data)464 H5G__link_iterate_table(const H5G_link_table_t *ltable, hsize_t skip,
465 hsize_t *last_lnk, const H5G_lib_iterate_t op, void *op_data)
466 {
467 size_t u; /* Local index variable */
468 herr_t ret_value = H5_ITER_CONT; /* Return value */
469
470 FUNC_ENTER_PACKAGE_NOERR
471
472 /* Sanity check */
473 HDassert(ltable);
474 HDassert(op);
475
476 /* Skip over links, if requested */
477 if(last_lnk)
478 *last_lnk += skip;
479
480 /* Iterate over link messages */
481 H5_CHECKED_ASSIGN(u, size_t, skip, hsize_t)
482 for(; u < ltable->nlinks && !ret_value; u++) {
483 /* Make the callback */
484 ret_value = (op)(&(ltable->lnks[u]), op_data);
485
486 /* Increment the number of entries passed through */
487 if(last_lnk)
488 (*last_lnk)++;
489 } /* end for */
490
491 /* Check for callback failure and pass along return value */
492 if(ret_value < 0)
493 HERROR(H5E_SYM, H5E_CANTNEXT, "iteration operator failed");
494
495 FUNC_LEAVE_NOAPI(ret_value)
496 } /* end H5G__link_iterate_table() */
497
498
499 /*-------------------------------------------------------------------------
500 * Function: H5G__link_release_table
501 *
502 * Purpose: Release table containing a list of links for a group
503 *
504 * Return: Success: Non-negative
505 * Failure: Negative
506 *
507 * Programmer: Quincey Koziol
508 * Sep 6, 2005
509 *
510 *-------------------------------------------------------------------------
511 */
512 herr_t
H5G__link_release_table(H5G_link_table_t * ltable)513 H5G__link_release_table(H5G_link_table_t *ltable)
514 {
515 size_t u; /* Local index variable */
516 herr_t ret_value = SUCCEED; /* Return value */
517
518 FUNC_ENTER_PACKAGE
519
520 /* Sanity check */
521 HDassert(ltable);
522
523 /* Release link info, if any */
524 if(ltable->nlinks > 0) {
525 /* Free link message information */
526 for(u = 0; u < ltable->nlinks; u++)
527 if(H5O_msg_reset(H5O_LINK_ID, &(ltable->lnks[u])) < 0)
528 HGOTO_ERROR(H5E_SYM, H5E_CANTFREE, FAIL, "unable to release link message")
529
530 /* Free table of links */
531 H5MM_xfree(ltable->lnks);
532 } /* end if */
533 else
534 HDassert(ltable->lnks == NULL);
535
536 done:
537 FUNC_LEAVE_NOAPI(ret_value)
538 } /* end H5G__link_release_table() */
539
540
541 /*-------------------------------------------------------------------------
542 * Function: H5G__link_name_replace
543 *
544 * Purpose: Determine the type of object referred to (for hard links) or
545 * the link type (for soft links and user-defined links).
546 *
547 * Return: Non-negative on success/Negative on failure
548 *
549 * Programmer: Quincey Koziol
550 * koziol@hdfgroup.org
551 * Nov 13 2006
552 *
553 *-------------------------------------------------------------------------
554 */
555 herr_t
H5G__link_name_replace(H5F_t * file,hid_t dxpl_id,H5RS_str_t * grp_full_path_r,const H5O_link_t * lnk)556 H5G__link_name_replace(H5F_t *file, hid_t dxpl_id, H5RS_str_t *grp_full_path_r,
557 const H5O_link_t *lnk)
558 {
559 H5RS_str_t *obj_path_r = NULL; /* Full path for link being removed */
560 herr_t ret_value = SUCCEED; /* Return value */
561
562 FUNC_ENTER_PACKAGE
563
564 /* check arguments */
565 HDassert(file);
566
567 /* Search the open IDs and replace names for unlinked object */
568 if(grp_full_path_r) {
569 obj_path_r = H5G_build_fullpath_refstr_str(grp_full_path_r, lnk->name);
570 if(H5G_name_replace(lnk, H5G_NAME_DELETE, file, obj_path_r, NULL, NULL, dxpl_id) < 0)
571 HGOTO_ERROR(H5E_SYM, H5E_CANTDELETE, FAIL, "unable to replace name")
572 } /* end if */
573
574 done:
575 if(obj_path_r)
576 H5RS_decr(obj_path_r);
577
578 FUNC_LEAVE_NOAPI(ret_value)
579 } /* end H5G__link_name_replace() */
580
581