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