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