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