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 /* This program demonstrates how to create and use "external links" in
15  * HDF5.
16  *
17  * External links point from one HDF5 file to an object (Group, Dataset, or
18  * committed Datatype) in another file.
19  */
20 
21 #include "hdf5.h"
22 #include <string.h>
23 
24 #define SOURCE_FILE "extlink_source.h5"
25 #define TARGET_FILE "extlink_target.h5"
26 
27 #define PREFIX_SOURCE_FILE "extlink_prefix_source.h5"
28 
29 #define SOFT_LINK_FILE "soft_link.h5"
30 #define SOFT_LINK_NAME "soft_link_to_group"
31 #define UD_SOFT_LINK_NAME "ud_soft_link"
32 #define TARGET_GROUP "target_group"
33 
34 #define UD_SOFT_CLASS 65
35 
36 #define HARD_LINK_FILE "hard_link.h5"
37 #define HARD_LINK_NAME "hard_link_to_group"
38 #define UD_HARD_LINK_NAME "ud_hard_link"
39 
40 #define UD_HARD_CLASS 66
41 
42 #define PLIST_LINK_PROP "plist_link_prop"
43 #define UD_PLIST_CLASS 66
44 
45 
46 
47 /* Basic external link example
48  *
49  * Creates two files and uses an external link to access an object in the
50  * second file from the first file.
51  */
extlink_example(void)52 static void extlink_example(void)
53 {
54     hid_t source_file_id, targ_file_id;
55     hid_t group_id, group2_id;
56 
57     /* Create two files, a source and a target */
58     source_file_id = H5Fcreate(SOURCE_FILE, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
59     targ_file_id = H5Fcreate(TARGET_FILE, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
60 
61     /* Create a group in the target file for the external link to point to. */
62     group_id = H5Gcreate2(targ_file_id, "target_group", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
63 
64     /* Close the group and the target file */
65     H5Gclose(group_id);
66 
67     /* Create an external link in the source file pointing to the target group.
68      * We could instead have created the external link first, then created the
69      * group it points to; the order doesn't matter.
70      */
71     H5Lcreate_external(TARGET_FILE, "target_group", source_file_id, "ext_link", H5P_DEFAULT, H5P_DEFAULT);
72 
73     /* Now we can use the external link to create a new group inside the
74      * target group (even though the target file is closed!).  The external
75      * link works just like a soft link.
76      */
77     group_id = H5Gcreate2(source_file_id, "ext_link/new_group", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
78 
79     /* The group is inside the target file and we can access it normally.
80      * Here, group_id and group2_id point to the same group inside the
81      * target file.
82      */
83     group2_id = H5Gopen2(targ_file_id, "target_group/new_group", H5P_DEFAULT);
84 
85     /* Don't forget to close the IDs we opened. */
86     H5Gclose(group2_id);
87     H5Gclose(group_id);
88 
89     H5Fclose(targ_file_id);
90     H5Fclose(source_file_id);
91 
92     /* The link from the source file to the target file will work as long as
93      * the target file can be found.  If the target file is moved, renamed,
94      * or deleted in the filesystem, HDF5 won't be able to find it and the
95      * external link will "dangle."
96      */
97 }
98 
99 
100 /* External link prefix example
101  *
102  * Uses a group access property list to set a "prefix" for the filenames
103  * accessed through an external link.
104  *
105  * Group access property lists inherit from link access property lists;
106  * the external link prefix property is actually a property of LAPLs.
107  *
108  * This example requires a "red" directory and a "blue" directory to exist
109  * where it is run (so to run this example on Unix, first mkdir red and mkdir
110  * blue).
111  */
extlink_prefix_example(void)112 static void extlink_prefix_example(void)
113 {
114     hid_t source_file_id, red_file_id, blue_file_id;
115     hid_t group_id, group2_id;
116     hid_t gapl_id;
117 
118     /* Create three files, a source and two targets.  The targets will have
119      * the same name, but one will be located in the red directory and one will
120      * be located in the blue directory */
121     source_file_id = H5Fcreate(PREFIX_SOURCE_FILE, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
122     red_file_id = H5Fcreate("red/prefix_target.h5", H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
123     blue_file_id = H5Fcreate("blue/prefix_target.h5", H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
124 
125     /* This test needs a red and a blue directory in the filesystem. If they're not present,
126      * trying to create the files above will fail.
127      */
128     if(red_file_id < 0 || blue_file_id < 0)
129       printf("This test requires directories named 'red' and 'blue' to exist. Did you forget to create them?\n");
130 
131     /* Create an external link in the source file pointing to the root group of
132      * a file named prefix_target.h5.  This file doesn't exist in the current
133      * directory, but the files in the red and blue directories both have this
134      * name.
135      */
136     H5Lcreate_external("prefix_target.h5", "/", source_file_id, "ext_link", H5P_DEFAULT, H5P_DEFAULT);
137 
138     /* If we tried to traverse the external link now, we would fail (since the
139      * file it points to doesn't exist).  Instead, we'll create a group access
140      * property list that will provide a prefix path to the external link.
141      * Group access property lists inherit the properties of link access
142      * property lists.
143      */
144     gapl_id = H5Pcreate(H5P_GROUP_ACCESS);
145     H5Pset_elink_prefix(gapl_id, "red/");
146 
147     /* Now if we traverse the external link, HDF5 will look for an external
148      * file named red/prefix_target.h5, which exists.
149      * To pass the group access property list, we need to use H5Gopen2.
150      */
151     group_id = H5Gopen2(source_file_id, "ext_link", gapl_id);
152 
153     /* Now we can use the open group ID to create a new group inside the
154      * "red" file.
155      */
156     group2_id = H5Gcreate2(group_id, "pink", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
157 
158     /* Close both groups. */
159     H5Gclose(group2_id);
160     H5Gclose(group_id);
161 
162     /* If we change the prefix, the same external link can find a file in the blue
163      * directory.
164      */
165     H5Pset_elink_prefix(gapl_id, "blue/");
166     group_id = H5Gopen2(source_file_id, "ext_link", gapl_id);
167     group2_id = H5Gcreate2(group_id, "sky blue", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
168 
169     /* Close both groups. */
170     H5Gclose(group2_id);
171     H5Gclose(group_id);
172 
173     /* Each file has had a group created inside it using the same external link. */
174     group_id = H5Gopen2(red_file_id, "pink", H5P_DEFAULT);
175     group2_id = H5Gopen2(blue_file_id, "sky blue", H5P_DEFAULT);
176 
177     /* Clean up our open IDs */
178     H5Gclose(group2_id);
179     H5Gclose(group_id);
180     H5Pclose(gapl_id);
181     H5Fclose(blue_file_id);
182     H5Fclose(red_file_id);
183     H5Fclose(source_file_id);
184 
185     /* User-defined links can expand on the ability to pass in parameters
186      * using an access property list; for instance, a user-defined link
187      * might function like an external link but allow the full filename to be
188      * passed in through the access property list.
189      */
190 }
191 
192 
193 /* Soft Link example
194  *
195  * Create a new class of user-defined links that behave like HDF5's built-in
196  * soft links.
197  *
198  * This isn't very useful by itself (HDF5's soft links already do the same
199  * thing), but it can serve as an example for how to reference objects by
200  * name.
201  */
202 
203 /* We need to define the callback function that the soft link will use.
204  * It is defined after the example below.
205  * To keep the example simple, these links don't have a query callback.
206  * In general, link classes should always be query-able.
207  * We might also have wanted to supply a creation callback that checks
208  * that a path was supplied in the udata.
209  */
210 static hid_t UD_soft_traverse(const char *link_name, hid_t cur_group,
211     const void *udata, size_t udata_size, hid_t lapl_id);
212 
soft_link_example(void)213 static void soft_link_example(void)
214 {
215     hid_t file_id;
216     hid_t group_id;
217     /* Define the link class that we'll use to register "user-defined soft
218      * links" using the callbacks we defined above.
219      * A link class can have NULL for any callback except its traverse
220      * callback.
221      */
222     const H5L_class_t UD_soft_class[1] = {{
223         H5L_LINK_CLASS_T_VERS,      /* Version number for this struct.
224                                      * This field is always H5L_LINK_CLASS_T_VERS */
225         (H5L_type_t)UD_SOFT_CLASS,  /* Link class id number. This can be any
226                                      * value between H5L_TYPE_UD_MIN (64) and
227                                      * H5L_TYPE_MAX (255). It should be a
228                                      * value that isn't already being used by
229                                      * another kind of link. We'll use 65. */
230         "UD_soft_link",             /* Link class name for debugging  */
231         NULL,                       /* Creation callback              */
232         NULL,                       /* Move callback                  */
233         NULL,                       /* Copy callback                  */
234         UD_soft_traverse,           /* The actual traversal function  */
235         NULL,                       /* Deletion callback              */
236         NULL                        /* Query callback                 */
237     }};
238 
239 
240     /* First, create a file and an object within the file for the link to
241      * point to.
242      */
243     file_id = H5Fcreate(SOFT_LINK_FILE, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
244     group_id = H5Gcreate2(file_id, TARGET_GROUP, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
245     H5Gclose(group_id);
246 
247     /* This is how we create a normal soft link to the group.
248      */
249     H5Lcreate_soft(TARGET_GROUP, file_id, SOFT_LINK_NAME, H5P_DEFAULT, H5P_DEFAULT);
250 
251     /* To do the same thing using a user-defined link, we first have to
252      * register the link class we defined.
253      */
254     H5Lregister(UD_soft_class);
255 
256     /* Now create a user-defined link.  We give it the path to the group
257      * as its udata.1
258      */
259     H5Lcreate_ud(file_id, UD_SOFT_LINK_NAME, (H5L_type_t)UD_SOFT_CLASS, TARGET_GROUP,
260                  strlen(TARGET_GROUP) + 1, H5P_DEFAULT, H5P_DEFAULT);
261 
262     /* We can access the group through the UD soft link like we would through
263      * a normal soft link. This link will still dangle if the object's
264      * original name is changed or unlinked.
265      */
266     group_id = H5Gopen2(file_id, UD_SOFT_LINK_NAME, H5P_DEFAULT);
267 
268     /* The group is now open normally.  Don't forget to close it! */
269     H5Gclose(group_id);
270 
271     H5Fclose(file_id);
272 }
273 
274 /* UD_soft_traverse
275  * The actual traversal function simply needs to open the correct object by
276  * name and return its ID.
277  */
278 
UD_soft_traverse(const char * link_name,hid_t cur_group,const void * udata,size_t udata_size,hid_t lapl_id)279 static hid_t UD_soft_traverse(const char *link_name, hid_t cur_group,
280     const void *udata, size_t udata_size, hid_t lapl_id)
281 {
282     const char *target = (const char *) udata;
283     hid_t ret_value;
284 
285     /* Pass the udata straight through to HDF5. If it's invalid, let HDF5
286      * return an error.
287      */
288     ret_value = H5Oopen(cur_group, target, lapl_id);
289     return ret_value;
290 }
291 
292 
293 /* Hard Link example
294  *
295  * Create a new class of user-defined links that behave like HDF5's built-in
296  * hard links.
297  *
298  * This isn't very useful by itself (HDF5's hard links already do the same
299  * thing), but it can serve as an example for how to reference objects by
300  * address.
301  */
302 
303 /* We need to define the callback functions that the hard link will use.
304  * These are defined after the example below.
305  * To keep the example simple, these links don't have a query callback.
306  * Generally, real link classes should always be query-able.
307  */
308 static herr_t UD_hard_create(const char *link_name, hid_t loc_group,
309     const void *udata, size_t udata_size, hid_t lcpl_id);
310 static herr_t UD_hard_delete(const char *link_name, hid_t loc_group,
311     const void *udata, size_t udata_size);
312 static hid_t UD_hard_traverse(const char *link_name, hid_t cur_group,
313     const void *udata, size_t udata_size, hid_t lapl_id);
314 
hard_link_example(void)315 static void hard_link_example(void)
316 {
317     hid_t file_id;
318     hid_t group_id;
319     H5L_info_t li;
320     /* Define the link class that we'll use to register "user-defined hard
321      * links" using the callbacks we defined above.
322      * A link class can have NULL for any callback except its traverse
323      * callback.
324      */
325     const H5L_class_t UD_hard_class[1] = {{
326         H5L_LINK_CLASS_T_VERS,      /* Version number for this struct.
327                                      * This field is always H5L_LINK_CLASS_T_VERS */
328         (H5L_type_t)UD_HARD_CLASS,  /* Link class id number. This can be any
329                                      * value between H5L_TYPE_UD_MIN (64) and
330                                      * H5L_TYPE_MAX (255). It should be a
331                                      * value that isn't already being used by
332                                      * another kind of link. We'll use 66. */
333         "UD_hard_link",             /* Link class name for debugging  */
334         UD_hard_create,             /* Creation callback              */
335         NULL,                       /* Move callback                  */
336         NULL,                       /* Copy callback                  */
337         UD_hard_traverse,           /* The actual traversal function  */
338         UD_hard_delete,             /* Deletion callback              */
339         NULL                        /* Query callback                 */
340     }};
341 
342 
343     /* First, create a file and an object within the file for the link to
344      * point to.
345      */
346     file_id = H5Fcreate(HARD_LINK_FILE, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
347     group_id = H5Gcreate2(file_id, TARGET_GROUP, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
348     H5Gclose(group_id);
349 
350     /* This is how we create a normal hard link to the group. This
351      * creates a second "name" for the group.
352      */
353     H5Lcreate_hard(file_id, TARGET_GROUP, file_id, HARD_LINK_NAME, H5P_DEFAULT, H5P_DEFAULT);
354 
355     /* To do the same thing using a user-defined link, we first have to
356      * register the link class we defined.
357      */
358     H5Lregister(UD_hard_class);
359 
360     /* Since hard links link by object address, we'll need to retrieve
361      * the target group's address. We do this by calling H5Lget_info
362      * on a hard link to the object.
363      */
364     H5Lget_info(file_id, TARGET_GROUP, &li, H5P_DEFAULT);
365 
366     /* Now create a user-defined link.  We give it the group's address
367      * as its udata.
368      */
369     H5Lcreate_ud(file_id, UD_HARD_LINK_NAME, (H5L_type_t)UD_HARD_CLASS, &(li.u.address),
370                  sizeof(li.u.address), H5P_DEFAULT, H5P_DEFAULT);
371 
372     /* The UD hard link has now incremented the group's reference count
373      * like a normal hard link would.  This means that we can unlink the
374      * other two links to that group and it won't be deleted until the
375      * UD hard link is deleted.
376      */
377     H5Ldelete(file_id, TARGET_GROUP, H5P_DEFAULT);
378     H5Ldelete(file_id, HARD_LINK_NAME, H5P_DEFAULT);
379 
380     /* The group is still accessible through the UD hard link. If this were
381      * a soft link instead, the object would have been deleted when the last
382      * hard link to it was unlinked. */
383     group_id = H5Gopen2(file_id, UD_HARD_LINK_NAME, H5P_DEFAULT);
384 
385     /* The group is now open normally.  Don't forget to close it! */
386     H5Gclose(group_id);
387 
388     /* Removing the user-defined hard link will delete the group. */
389     H5Ldelete(file_id, UD_HARD_LINK_NAME, H5P_DEFAULT);
390 
391     H5Fclose(file_id);
392 }
393 
394 /* Callbacks for User-defined hard links. */
395 /* UD_hard_create
396  * The most important thing this callback does is to increment the reference
397  * count on the target object. Without this step, the object could be
398  * deleted while this link still pointed to it, resulting in possible data
399  * corruption!
400  * The create callback also checks the arguments used to create this link.
401  * If this function returns a negative value, the call to H5Lcreate_ud()
402  * will also return failure and the link will not be created.
403  */
UD_hard_create(const char * link_name,hid_t loc_group,const void * udata,size_t udata_size,hid_t lcpl_id)404 static herr_t UD_hard_create(const char *link_name, hid_t loc_group,
405     const void *udata, size_t udata_size, hid_t lcpl_id)
406 {
407     haddr_t addr;
408     hid_t target_obj = -1;
409     herr_t ret_value = 0;
410 
411     /* Make sure that the address passed in looks valid */
412     if(udata_size != sizeof(haddr_t))
413     {
414       ret_value = -1;
415       goto done;
416     }
417 
418     addr = *((const haddr_t *) udata);
419 
420     /* Open the object this link points to so that we can increment
421      * its reference count. This also ensures that the address passed
422      * in points to a real object (although this check is not perfect!) */
423     target_obj= H5Oopen_by_addr(loc_group, addr);
424     if(target_obj < 0)
425     {
426       ret_value = -1;
427       goto done;
428     }
429 
430     /* Increment the reference count of the target object */
431     if(H5Oincr_refcount(target_obj) < 0)
432     {
433       ret_value = -1;
434       goto done;
435     }
436 
437 done:
438     /* Close the target object if we opened it */
439     if(target_obj >= 0)
440         H5Oclose(target_obj);
441     return ret_value;
442 }
443 
444 /* UD_hard_delete
445  * Since the creation function increments the object's reference count, it's
446  * important to decrement it again when the link is deleted.
447  */
UD_hard_delete(const char * link_name,hid_t loc_group,const void * udata,size_t udata_size)448 static herr_t UD_hard_delete(const char *link_name, hid_t loc_group,
449     const void *udata, size_t udata_size)
450 {
451     haddr_t addr;
452     hid_t target_obj = -1;
453     herr_t ret_value = 0;
454 
455     /* Sanity check; we have already verified the udata's size in the creation
456      * callback.
457      */
458     if(udata_size != sizeof(haddr_t))
459     {
460       ret_value = -1;
461       goto done;
462     }
463 
464     addr = *((const haddr_t *) udata);
465 
466     /* Open the object this link points to */
467     target_obj= H5Oopen_by_addr(loc_group, addr);
468     if(target_obj < 0)
469     {
470       ret_value = -1;
471       goto done;
472     }
473 
474     /* Decrement the reference count of the target object */
475     if(H5Odecr_refcount(target_obj) < 0)
476     {
477       ret_value = -1;
478       goto done;
479     }
480 
481 done:
482     /* Close the target object if we opened it */
483     if(target_obj >= 0)
484         H5Oclose(target_obj);
485     return ret_value;
486 }
487 
488 /* UD_hard_traverse
489  * The actual traversal function simply needs to open the correct object and
490  * return its ID.
491  */
UD_hard_traverse(const char * link_name,hid_t cur_group,const void * udata,size_t udata_size,hid_t lapl_id)492 static hid_t UD_hard_traverse(const char *link_name, hid_t cur_group,
493     const void *udata, size_t udata_size, hid_t lapl_id)
494 {
495     haddr_t       addr;
496     hid_t         ret_value = -1;
497 
498     /* Sanity check; we have already verified the udata's size in the creation
499      * callback.
500      */
501     if(udata_size != sizeof(haddr_t))
502       return -1;
503 
504     addr = *((const haddr_t *) udata);
505 
506     /* Open the object by address. If H5Oopen_by_addr fails, ret_value will
507      * be negative to indicate that the traversal function failed.
508      */
509     ret_value = H5Oopen_by_addr(cur_group, addr);
510 
511     return ret_value;
512 }
513 
514 
515 
516 /* Plist example
517  *
518  * Create a new class of user-defined links that open objects within a file
519  * based on a value passed in through a link access property list.
520  *
521  * Group, dataset, and datatype access property lists all inherit from link
522  * access property lists, so they can be used instead of LAPLs.
523  */
524 
525 /* We need to define the callback functions that this link type will use.
526  * These are defined after the example below.
527  * These links have no udata, so they don't need a query function.
528  */
529 static hid_t UD_plist_traverse(const char *link_name, hid_t cur_group,
530     const void *udata, size_t udata_size, hid_t lapl_id);
531 
plist_link_example(void)532 static void plist_link_example(void)
533 {
534     hid_t file_id;
535     hid_t group_id, group2_id;
536     hid_t gapl_id;
537     char *path = NULL;
538 
539     /* Define the link class that we'll use to register "plist
540      * links" using the callback we defined above.
541      * A link class can have NULL for any callback except its traverse
542      * callback.
543      */
544     const H5L_class_t UD_plist_class[1] = {{
545         H5L_LINK_CLASS_T_VERS,      /* Version number for this struct.
546                                      * This field is always H5L_LINK_CLASS_T_VERS */
547         (H5L_type_t)UD_PLIST_CLASS, /* Link class id number. This can be any
548                                      * value between H5L_TYPE_UD_MIN (64) and
549                                      * H5L_TYPE_MAX (255). It should be a
550                                      * value that isn't already being used by
551                                      * another kind of link. We'll use 67. */
552         "UD_plist_link",            /* Link class name for debugging  */
553         NULL,                       /* Creation callback              */
554         NULL,                       /* Move callback                  */
555         NULL,                       /* Copy callback                  */
556         UD_plist_traverse,          /* The actual traversal function  */
557         NULL,                       /* Deletion callback              */
558         NULL                        /* Query callback                 */
559     }};
560 
561 
562     /* First, create a file and two objects within the file for the link to
563      * point to.
564      */
565     file_id = H5Fcreate(HARD_LINK_FILE, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
566     group_id = H5Gcreate2(file_id, "group_1", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
567     H5Gclose(group_id);
568     group_id = H5Gcreate2(file_id, "group_1/group_2", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
569     H5Gclose(group_id);
570 
571     /* Register "plist links" and create one.  It has no udata at all. */
572     H5Lregister(UD_plist_class);
573     H5Lcreate_ud(file_id, "plist_link", (H5L_type_t)UD_PLIST_CLASS, NULL, 0,
574                  H5P_DEFAULT, H5P_DEFAULT);
575 
576     /* Create a group access property list to pass in the target for the
577      * plist link.
578      */
579     gapl_id = H5Pcreate(H5P_GROUP_ACCESS);
580 
581     /* There is no HDF5 API for setting the property that controls these
582      * links, so we have to add the property manually
583      */
584     H5Pinsert2(gapl_id, PLIST_LINK_PROP, sizeof(const char *), &(path), NULL, NULL, NULL, NULL, NULL, NULL);
585 
586     /* Set the property to point to the first group. */
587     path = "group_1";
588     H5Pset(gapl_id, PLIST_LINK_PROP, &path);
589 
590     /* Open the first group through the plist link using the GAPL we just
591      * created */
592     group_id = H5Gopen2(file_id, "plist_link", gapl_id);
593 
594     /* If we change the value set on the property list, it will change where
595      * the plist link points.
596      */
597     path = "group_1/group_2";
598     H5Pset(gapl_id, PLIST_LINK_PROP, &path);
599     group2_id = H5Gopen2(file_id, "plist_link", gapl_id);
600 
601     /* group_id points to group_1 and group2_id points to group_2, both opened
602      * through the same link.
603      * Using more than one of this type of link could quickly become confusing,
604      * since they will all use the same property list; however, there is
605      * nothing to prevent the links from changing the property list in their
606      * traverse callbacks.
607      */
608 
609     /* Clean up */
610     H5Pclose(gapl_id);
611     H5Gclose(group_id);
612     H5Gclose(group2_id);
613     H5Fclose(file_id);
614 }
615 
616 /* Traversal callback for User-defined plist links. */
617 /* UD_plist_traverse
618  * Open a path passed in through the property list.
619  */
UD_plist_traverse(const char * link_name,hid_t cur_group,const void * udata,size_t udata_size,hid_t lapl_id)620 static hid_t UD_plist_traverse(const char *link_name, hid_t cur_group,
621     const void *udata, size_t udata_size, hid_t lapl_id)
622 {
623     char *        path;
624     hid_t         ret_value = -1;
625 
626     /* If the link property isn't set or can't be found, traversal fails. */
627     if(H5Pexist(lapl_id, PLIST_LINK_PROP) < 0)
628         goto error;
629 
630     if(H5Pget(lapl_id, PLIST_LINK_PROP, &path) < 0)
631         goto error;
632 
633     /* Open the object by address. If H5Oopen_by_addr fails, ret_value will
634      * be negative to indicate that the traversal function failed.
635      */
636     ret_value = H5Oopen(cur_group, path, lapl_id);
637 
638     return ret_value;
639 
640 error:
641     return -1;
642 }
643 
644 
645 
646 /* Main function
647  *
648  * Invokes the example functions.
649  */
650  int
main(void)651 main(void)
652 {
653     printf("Testing basic external links.\n");
654     extlink_example();
655 
656     printf("Testing external link prefixes.\n");
657     extlink_prefix_example();
658 
659     printf("Testing user-defined soft links.\n");
660     soft_link_example();
661 
662     printf("Testing user-defined hard links.\n");
663     hard_link_example();
664 
665     printf("Testing user-defined property list links.\n");
666     plist_link_example();
667 
668     return 0;
669 }
670 
671 
672