Coverage Report

Created: 2026-09-04 06:51

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/hdf5/src/H5Lint.c
Line
Count
Source
1
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2
 * Copyright by The HDF Group.                                               *
3
 * All rights reserved.                                                      *
4
 *                                                                           *
5
 * This file is part of HDF5.  The full HDF5 copyright notice, including     *
6
 * terms governing use, modification, and redistribution, is contained in    *
7
 * the LICENSE file, which can be found at the root of the source code       *
8
 * distribution tree, or in https://www.hdfgroup.org/licenses.               *
9
 * If you do not have access to either file, you may request a copy from     *
10
 * help@hdfgroup.org.                                                        *
11
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
12
13
/****************/
14
/* Module Setup */
15
/****************/
16
17
#include "H5Lmodule.h" /* This source code file is part of the H5L module */
18
19
/***********/
20
/* Headers */
21
/***********/
22
#include "H5private.h"   /* Generic Functions                        */
23
#include "H5CXprivate.h" /* API Contexts                             */
24
#include "H5Eprivate.h"  /* Error handling                           */
25
#include "H5Fprivate.h"  /* File access                              */
26
#include "H5Gprivate.h"  /* Groups                                   */
27
#include "H5Iprivate.h"  /* IDs                                      */
28
#include "H5Lpkg.h"      /* Links                                    */
29
#include "H5MMprivate.h" /* Memory management                        */
30
#include "H5Oprivate.h"  /* File objects                             */
31
#include "H5Pprivate.h"  /* Property lists                           */
32
#include "H5VLprivate.h" /* Virtual Object Layer                     */
33
34
/****************/
35
/* Local Macros */
36
/****************/
37
38
#define H5L_MIN_TABLE_SIZE 32 /* Minimum size of the user-defined link type table if it is allocated */
39
40
/******************/
41
/* Local Typedefs */
42
/******************/
43
44
/* User data for path traversal routine for getting link info by name */
45
typedef struct {
46
    H5L_info2_t *linfo; /* Buffer to return to user */
47
} H5L_trav_gi_t;
48
49
/* User data for path traversal routine for getting link value by index */
50
typedef struct {
51
    /* In */
52
    H5_index_t      idx_type; /* Index to use */
53
    H5_iter_order_t order;    /* Order to iterate in index */
54
    hsize_t         n;        /* Offset of link within index */
55
    size_t          size;     /* Size of user buffer */
56
57
    /* Out */
58
    void *buf; /* User buffer */
59
} H5L_trav_gvbi_t;
60
61
/* User data for path traversal routine for getting link info by index */
62
typedef struct {
63
    /* In */
64
    H5_index_t      idx_type; /* Index to use */
65
    H5_iter_order_t order;    /* Order to iterate in index */
66
    hsize_t         n;        /* Offset of link within index */
67
68
    /* Out */
69
    H5L_info2_t *linfo; /* Buffer to return to user */
70
} H5L_trav_gibi_t;
71
72
/* User data for path traversal routine for removing link by index */
73
typedef struct {
74
    /* In */
75
    H5_index_t      idx_type; /* Index to use */
76
    H5_iter_order_t order;    /* Order to iterate in index */
77
    hsize_t         n;        /* Offset of link within index */
78
} H5L_trav_rmbi_t;
79
80
/* User data for path traversal routine for getting name by index */
81
typedef struct {
82
    /* In */
83
    H5_index_t      idx_type; /* Index to use */
84
    H5_iter_order_t order;    /* Order to iterate in index */
85
    hsize_t         n;        /* Offset of link within index */
86
    size_t          size;     /* Size of name buffer */
87
88
    /* Out */
89
    char  *name;     /* Buffer to return name to user */
90
    size_t name_len; /* Length of full name */
91
} H5L_trav_gnbi_t;
92
93
/* User data for path traversal callback to creating a link */
94
struct H5L_trav_cr_t {
95
    H5F_t            *file;      /* Pointer to the file */
96
    H5P_genplist_t   *lc_plist;  /* Link creation property list */
97
    H5G_name_t       *path;      /* Path to object being linked */
98
    H5O_obj_create_t *ocrt_info; /* Pointer to object creation info */
99
    H5O_link_t       *lnk;       /* Pointer to link information to insert */
100
};
101
102
/* User data for path traversal routine for moving and renaming a link */
103
typedef struct {
104
    const char      *dst_name;         /* Destination name for moving object */
105
    H5T_cset_t       cset;             /* Char set for new name */
106
    const H5G_loc_t *dst_loc;          /* Destination location for moving object */
107
    unsigned         dst_target_flags; /* Target flags for destination object */
108
    bool             copy;             /* true if this is a copy operation */
109
    size_t           orig_nlinks; /* The original value for the # of soft / UD links that can be traversed */
110
} H5L_trav_mv_t;
111
112
/* User data for path traversal routine for moving and renaming an object */
113
typedef struct {
114
    H5F_t      *file; /* Pointer to the file */
115
    H5O_link_t *lnk;  /* Pointer to link information to insert */
116
    bool        copy; /* true if this is a copy operation */
117
} H5L_trav_mv2_t;
118
119
/* User data for path traversal routine for checking if a link exists */
120
typedef struct {
121
    /* Down */
122
    char *sep; /* Pointer to next separator in the string */
123
124
    /* Up */
125
    bool *exists; /* Whether the link exists or not */
126
} H5L_trav_le_t;
127
128
/* User data for path traversal routine for getting link value */
129
typedef struct {
130
    size_t size; /* Size of user buffer */
131
    void  *buf;  /* User buffer */
132
} H5L_trav_gv_t;
133
134
/********************/
135
/* Local Prototypes */
136
/********************/
137
138
static int    H5L__find_class_idx(H5L_type_t id);
139
static herr_t H5L__link_cb(H5G_loc_t *grp_loc /*in*/, const char *name, const H5O_link_t *lnk,
140
                           H5G_loc_t *obj_loc, void *_udata /*in,out*/, H5G_own_loc_t *own_loc /*out*/);
141
static herr_t H5L__create_real(const H5G_loc_t *link_loc, const char *link_name, H5G_name_t *obj_path,
142
                               H5F_t *obj_file, H5O_link_t *lnk, H5O_obj_create_t *ocrt_info, hid_t lcpl_id);
143
static herr_t H5L__get_val_real(const H5O_link_t *lnk, void *buf, size_t size);
144
static herr_t H5L__get_val_cb(H5G_loc_t *grp_loc /*in*/, const char *name, const H5O_link_t *lnk,
145
                              H5G_loc_t *obj_loc, void *_udata /*in,out*/, H5G_own_loc_t *own_loc /*out*/);
146
static herr_t H5L__get_val_by_idx_cb(H5G_loc_t *grp_loc /*in*/, const char *name, const H5O_link_t *lnk,
147
                                     H5G_loc_t *obj_loc, void *_udata /*in,out*/,
148
                                     H5G_own_loc_t *own_loc /*out*/);
149
static herr_t H5L__delete_cb(H5G_loc_t *grp_loc /*in*/, const char *name, const H5O_link_t *lnk,
150
                             H5G_loc_t *obj_loc, void *_udata /*in,out*/, H5G_own_loc_t *own_loc /*out*/);
151
static herr_t H5L__delete_by_idx_cb(H5G_loc_t *grp_loc /*in*/, const char *name, const H5O_link_t *lnk,
152
                                    H5G_loc_t *obj_loc, void *_udata /*in,out*/,
153
                                    H5G_own_loc_t *own_loc /*out*/);
154
static herr_t H5L__move_cb(H5G_loc_t *grp_loc /*in*/, const char *name, const H5O_link_t *lnk,
155
                           H5G_loc_t *obj_loc, void *_udata /*in,out*/, H5G_own_loc_t *own_loc /*out*/);
156
static herr_t H5L__move_dest_cb(H5G_loc_t *grp_loc /*in*/, const char *name, const H5O_link_t *lnk,
157
                                H5G_loc_t *obj_loc, void *_udata /*in,out*/, H5G_own_loc_t *own_loc /*out*/);
158
static herr_t H5L__exists_final_cb(H5G_loc_t *grp_loc /*in*/, const char *name, const H5O_link_t *lnk,
159
                                   H5G_loc_t *obj_loc, void *_udata /*in,out*/,
160
                                   H5G_own_loc_t *own_loc /*out*/);
161
static herr_t H5L__exists_inter_cb(H5G_loc_t *grp_loc /*in*/, const char *name, const H5O_link_t *lnk,
162
                                   H5G_loc_t *obj_loc, void *_udata /*in,out*/,
163
                                   H5G_own_loc_t *own_loc /*out*/);
164
static herr_t H5L__get_info_cb(H5G_loc_t *grp_loc /*in*/, const char *name, const H5O_link_t *lnk,
165
                               H5G_loc_t *obj_loc, void *_udata /*in,out*/, H5G_own_loc_t *own_loc /*out*/);
166
static herr_t H5L__get_info_by_idx_cb(H5G_loc_t *grp_loc /*in*/, const char *name, const H5O_link_t *lnk,
167
                                      H5G_loc_t *obj_loc, void *_udata /*in,out*/,
168
                                      H5G_own_loc_t *own_loc /*out*/);
169
static herr_t H5L__get_name_by_idx_cb(H5G_loc_t *grp_loc /*in*/, const char *name, const H5O_link_t *lnk,
170
                                      H5G_loc_t *obj_loc, void *_udata /*in,out*/,
171
                                      H5G_own_loc_t *own_loc /*out*/);
172
173
/*********************/
174
/* Package Variables */
175
/*********************/
176
177
/* Package initialization variable */
178
bool H5_PKG_INIT_VAR = false;
179
180
/*****************************/
181
/* Library Private Variables */
182
/*****************************/
183
184
/*******************/
185
/* Local Variables */
186
/*******************/
187
188
/* Information about user-defined links */
189
static size_t       H5L_table_alloc_g = 0;
190
static size_t       H5L_table_used_g  = 0;
191
static H5L_class_t *H5L_table_g       = NULL;
192
193
/*-------------------------------------------------------------------------
194
 * Function:    H5L_init
195
 *
196
 * Purpose:     Initialize the interface from some other package.
197
 *
198
 * Return:      Success:  non-negative
199
 *
200
 *              Failure:  negative
201
 *
202
 *-------------------------------------------------------------------------
203
 */
204
herr_t
205
H5L_init(void)
206
1
{
207
1
    herr_t ret_value = SUCCEED; /* Return value */
208
209
1
    FUNC_ENTER_NOAPI(FAIL)
210
    /* FUNC_ENTER() does all the work */
211
212
1
done:
213
1
    FUNC_LEAVE_NOAPI(ret_value)
214
1
} /* end H5L_init() */
215
216
/*-------------------------------------------------------------------------
217
 * Function:    H5L__init_package
218
 *
219
 * Purpose:     Initialize information specific to H5L interface.
220
 *
221
 * Return:      Non-negative on success/Negative on failure
222
 *
223
 *-------------------------------------------------------------------------
224
 */
225
herr_t
226
H5L__init_package(void)
227
1
{
228
1
    herr_t ret_value = SUCCEED; /* Return value */
229
230
1
    FUNC_ENTER_PACKAGE
231
232
    /* Initialize user-defined link classes */
233
1
    if (H5L_register_external() < 0)
234
0
        HGOTO_ERROR(H5E_LINK, H5E_NOTREGISTERED, FAIL, "unable to register external link class");
235
236
1
done:
237
1
    FUNC_LEAVE_NOAPI(ret_value)
238
1
} /* end H5L_init_package() */
239
240
/*-------------------------------------------------------------------------
241
 * Function:    H5L_term_package
242
 *
243
 * Purpose:     Terminate any resources allocated in H5L__init_package.
244
 *
245
 * Return:      Non-negative on success/Negative on failure
246
 *
247
 *-------------------------------------------------------------------------
248
 */
249
int
250
H5L_term_package(void)
251
101
{
252
101
    int n = 0;
253
254
101
    FUNC_ENTER_NOAPI_NOINIT_NOERR
255
256
2
    if (H5_PKG_INIT_VAR) {
257
        /* Free the table of link types */
258
2
        if (H5L_table_g) {
259
1
            H5L_table_g      = (H5L_class_t *)H5MM_xfree(H5L_table_g);
260
1
            H5L_table_used_g = H5L_table_alloc_g = 0;
261
1
            n++;
262
1
        } /* end if */
263
264
        /* Mark the interface as uninitialized */
265
2
        if (0 == n)
266
1
            H5_PKG_INIT_VAR = false;
267
2
    } /* end if */
268
269
2
    FUNC_LEAVE_NOAPI(n)
270
101
} /* H5L_term_package() */
271
272
/*-------------------------------------------------------------------------
273
 * Function:  H5L__find_class_idx
274
 *
275
 * Purpose: Given a link class ID, return the offset in the global array
276
 *              that holds all the registered link classes.
277
 *
278
 * Return:  Success:  Non-negative index of entry in global
279
 *                              link class table.
280
 *    Failure:  Negative
281
 *
282
 *-------------------------------------------------------------------------
283
 */
284
static int
285
H5L__find_class_idx(H5L_type_t id)
286
0
{
287
0
    size_t i;                /* Local index variable */
288
0
    int    ret_value = FAIL; /* Return value */
289
290
0
    FUNC_ENTER_PACKAGE_NOERR
291
292
0
    for (i = 0; i < H5L_table_used_g; i++)
293
0
        if (H5L_table_g[i].id == id)
294
0
            HGOTO_DONE((int)i);
295
296
0
done:
297
0
    FUNC_LEAVE_NOAPI(ret_value)
298
0
} /* end H5L__find_class_idx */
299
300
/*-------------------------------------------------------------------------
301
 * Function:  H5L_find_class
302
 *
303
 * Purpose: Given a link class ID return a pointer to a global struct that
304
 *    defines the link class.
305
 *
306
 * Return:  Success:  Ptr to entry in global link class table.
307
 *    Failure:  NULL
308
 *
309
 *-------------------------------------------------------------------------
310
 */
311
const H5L_class_t *
312
H5L_find_class(H5L_type_t id)
313
0
{
314
0
    int          idx;              /* Filter index in global table */
315
0
    H5L_class_t *ret_value = NULL; /* Return value */
316
317
0
    FUNC_ENTER_NOAPI(NULL)
318
319
    /* Get the index in the global table */
320
0
    if ((idx = H5L__find_class_idx(id)) < 0)
321
0
        HGOTO_ERROR(H5E_LINK, H5E_NOTREGISTERED, NULL, "unable to find link class");
322
323
    /* Set return value */
324
0
    ret_value = H5L_table_g + idx;
325
326
0
done:
327
0
    FUNC_LEAVE_NOAPI(ret_value)
328
0
} /* end H5L_find_class */
329
330
/*-------------------------------------------------------------------------
331
 * Function:  H5L_register
332
 *
333
 * Purpose: Registers a class of user-defined links, or changes the
334
 *              behavior of an existing class.
335
 *
336
 *              See H5Lregister for full documentation.
337
 *
338
 * Return:  Non-negative on success/Negative on failure
339
 *
340
 *-------------------------------------------------------------------------
341
 */
342
herr_t
343
H5L_register(const H5L_class_t *cls)
344
1
{
345
1
    size_t i;                   /* Local index variable */
346
1
    herr_t ret_value = SUCCEED; /* Return value */
347
348
1
    FUNC_ENTER_NOAPI(FAIL)
349
350
1
    assert(cls);
351
1
    assert(cls->id >= 0 && cls->id <= H5L_TYPE_MAX);
352
353
    /* Is the link type already registered? */
354
1
    for (i = 0; i < H5L_table_used_g; i++)
355
0
        if (H5L_table_g[i].id == cls->id)
356
0
            break;
357
358
    /* Filter not already registered */
359
1
    if (i >= H5L_table_used_g) {
360
1
        if (H5L_table_used_g >= H5L_table_alloc_g) {
361
1
            size_t       n     = MAX(H5L_MIN_TABLE_SIZE, (2 * H5L_table_alloc_g));
362
1
            H5L_class_t *table = (H5L_class_t *)H5MM_realloc(H5L_table_g, (n * sizeof(H5L_class_t)));
363
1
            if (!table)
364
0
                HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to extend link type table");
365
1
            H5L_table_g       = table;
366
1
            H5L_table_alloc_g = n;
367
1
        } /* end if */
368
369
        /* Initialize */
370
1
        i = H5L_table_used_g++;
371
1
    } /* end if */
372
373
    /* Copy link class info into table */
374
1
    H5MM_memcpy(H5L_table_g + i, cls, sizeof(H5L_class_t));
375
376
1
done:
377
1
    FUNC_LEAVE_NOAPI(ret_value)
378
1
} /* end H5L_register */
379
380
/*-------------------------------------------------------------------------
381
 * Function:  H5L_unregister
382
 *
383
 * Purpose: Unregisters a class of user-defined links.
384
 *
385
 *              See H5Lunregister for full documentation.
386
 *
387
 * Return:  Non-negative on success/Negative on failure
388
 *
389
 *-------------------------------------------------------------------------
390
 */
391
herr_t
392
H5L_unregister(H5L_type_t id)
393
0
{
394
0
    size_t i;                   /* Local index variable */
395
0
    herr_t ret_value = SUCCEED; /* Return value */
396
397
0
    FUNC_ENTER_NOAPI(FAIL)
398
399
0
    assert(id >= 0 && id <= H5L_TYPE_MAX);
400
401
    /* Is the filter already registered? */
402
0
    for (i = 0; i < H5L_table_used_g; i++)
403
0
        if (H5L_table_g[i].id == id)
404
0
            break;
405
406
    /* Fail if filter not found */
407
0
    if (i >= H5L_table_used_g)
408
0
        HGOTO_ERROR(H5E_LINK, H5E_NOTREGISTERED, FAIL, "link class is not registered");
409
410
    /* Remove filter from table */
411
    /* Don't worry about shrinking table size (for now) */
412
0
    memmove(&H5L_table_g[i], &H5L_table_g[i + 1], sizeof(H5L_class_t) * ((H5L_table_used_g - 1) - i));
413
0
    H5L_table_used_g--;
414
415
0
done:
416
0
    FUNC_LEAVE_NOAPI(ret_value)
417
0
} /* end H5L_unregister() */
418
419
/*-------------------------------------------------------------------------
420
 * Function:  H5L_is_registered
421
 *
422
 * Purpose:     Tests whether a user-defined link class has been registered
423
 *              or not.
424
 *
425
 * Return:      SUCCEED/FAIL
426
 *
427
 *-------------------------------------------------------------------------
428
 */
429
herr_t
430
H5L_is_registered(H5L_type_t id, bool *is_registered)
431
0
{
432
0
    size_t i; /* Local index variable */
433
434
0
    FUNC_ENTER_NOAPI_NOINIT_NOERR
435
436
    /* Check args */
437
0
    assert(is_registered);
438
439
    /* Is the link class already registered? */
440
0
    *is_registered = false;
441
0
    for (i = 0; i < H5L_table_used_g; i++)
442
0
        if (H5L_table_g[i].id == id) {
443
0
            *is_registered = true;
444
0
            break;
445
0
        }
446
447
0
    FUNC_LEAVE_NOAPI(SUCCEED)
448
0
} /* end H5L_is_registered() */
449
450
/*-------------------------------------------------------------------------
451
 * Function:  H5L_link
452
 *
453
 * Purpose: Creates a link from OBJ_ID to CUR_NAME.  See H5Olink() for
454
 *    full documentation.
455
 *
456
 * Return:  Non-negative on success/Negative on failure
457
 *
458
 *-------------------------------------------------------------------------
459
 */
460
herr_t
461
H5L_link(const H5G_loc_t *new_loc, const char *new_name, H5G_loc_t *obj_loc, hid_t lcpl_id)
462
0
{
463
0
    H5O_link_t lnk;                 /* Link to insert */
464
0
    herr_t     ret_value = SUCCEED; /* Return value */
465
466
0
    FUNC_ENTER_NOAPI_NOINIT
467
468
    /* Check args */
469
0
    assert(new_loc);
470
0
    assert(obj_loc);
471
0
    assert(new_name && *new_name);
472
473
    /* The link callback will check that the object isn't being hard linked
474
     * into a different file, so we don't need to do it here (there could be
475
     * external links along the path).
476
     */
477
478
    /* Construct link information for eventual insertion */
479
0
    lnk.type        = H5L_TYPE_HARD;
480
0
    lnk.u.hard.addr = obj_loc->oloc->addr;
481
482
    /* Create the link */
483
0
    if (H5L__create_real(new_loc, new_name, obj_loc->path, obj_loc->oloc->file, &lnk, NULL, lcpl_id) < 0)
484
0
        HGOTO_ERROR(H5E_LINK, H5E_CANTINIT, FAIL, "unable to create new link to object");
485
486
0
done:
487
0
    FUNC_LEAVE_NOAPI(ret_value)
488
0
} /* end H5L_link() */
489
490
/*-------------------------------------------------------------------------
491
 * Function:  H5L_link_object
492
 *
493
 * Purpose: Creates a new object and a link to it.
494
 *
495
 * Return:  Non-negative on success/Negative on failure
496
 *
497
 *-------------------------------------------------------------------------
498
 */
499
herr_t
500
H5L_link_object(const H5G_loc_t *new_loc, const char *new_name, H5O_obj_create_t *ocrt_info, hid_t lcpl_id)
501
0
{
502
0
    H5O_link_t lnk;                 /* Link to insert */
503
0
    herr_t     ret_value = SUCCEED; /* Return value */
504
505
0
    FUNC_ENTER_NOAPI_NOINIT
506
507
    /* Check args */
508
0
    assert(new_loc);
509
0
    assert(new_name && *new_name);
510
0
    assert(ocrt_info);
511
512
    /* The link callback will check that the object isn't being hard linked
513
     * into a different file, so we don't need to do it here (there could be
514
     * external links along the path).
515
     */
516
517
    /* Construct link information for eventual insertion */
518
0
    lnk.type = H5L_TYPE_HARD;
519
520
    /* Create the link */
521
0
    if (H5L__create_real(new_loc, new_name, NULL, NULL, &lnk, ocrt_info, lcpl_id) < 0)
522
0
        HGOTO_ERROR(H5E_LINK, H5E_CANTINIT, FAIL, "unable to create new link to object");
523
524
0
done:
525
0
    FUNC_LEAVE_NOAPI(ret_value)
526
0
} /* end H5L_link_object() */
527
528
/*-------------------------------------------------------------------------
529
 * Function:  H5L__link_cb
530
 *
531
 * Purpose: Callback for creating a link to an object.
532
 *
533
 * Return:  Non-negative on success/Negative on failure
534
 *
535
 *-------------------------------------------------------------------------
536
 */
537
static herr_t
538
H5L__link_cb(H5G_loc_t *grp_loc /*in*/, const char *name, const H5O_link_t H5_ATTR_UNUSED *lnk,
539
             H5G_loc_t *obj_loc, void *_udata /*in,out*/, H5G_own_loc_t *own_loc /*out*/)
540
0
{
541
0
    H5L_trav_cr_t *udata  = (H5L_trav_cr_t *)_udata; /* User data passed in */
542
0
    H5G_t         *grp    = NULL;   /* H5G_t for this group, opened to pass to user callback */
543
0
    hid_t          grp_id = FAIL;   /* Id for this group (passed to user callback */
544
0
    H5G_loc_t      temp_loc;        /* For UD callback */
545
0
    bool   temp_loc_init = false;   /* Temporary location for UD callback (temp_loc) has been initialized */
546
0
    bool   obj_created   = false;   /* Whether an object was created (through a hard link) */
547
0
    herr_t ret_value     = SUCCEED; /* Return value */
548
549
0
    FUNC_ENTER_PACKAGE
550
551
    /* Check if the name in this group resolved to a valid location */
552
    /* (which is not what we want) */
553
0
    if (obj_loc != NULL)
554
0
        HGOTO_ERROR(H5E_LINK, H5E_EXISTS, FAIL, "name already exists");
555
556
    /* Check for crossing file boundaries with a new hard link */
557
0
    if (udata->lnk->type == H5L_TYPE_HARD) {
558
        /* Check for creating an object */
559
        /* (only for hard links) */
560
0
        if (udata->ocrt_info) {
561
0
            H5G_loc_t new_loc; /* Group location for new object */
562
563
            /* Create new object at this location */
564
0
            if (NULL ==
565
0
                (udata->ocrt_info->new_obj = H5O_obj_create(grp_loc->oloc->file, udata->ocrt_info->obj_type,
566
0
                                                            udata->ocrt_info->crt_info, &new_loc)))
567
0
                HGOTO_ERROR(H5E_LINK, H5E_CANTINIT, FAIL, "unable to create object");
568
569
            /* Set address for hard link */
570
0
            udata->lnk->u.hard.addr = new_loc.oloc->addr;
571
572
            /* Set object path to use for setting object name (below) */
573
0
            udata->path = new_loc.path;
574
575
            /* Indicate that an object was created */
576
0
            obj_created = true;
577
0
        } /* end if */
578
0
        else {
579
            /* Check that both objects are in same file */
580
0
            if (!H5F_SAME_SHARED(grp_loc->oloc->file, udata->file))
581
0
                HGOTO_ERROR(H5E_LINK, H5E_BADVALUE, FAIL, "interfile hard links are not allowed");
582
0
        } /* end else */
583
0
    }     /* end if */
584
585
    /* Set 'standard' aspects of link */
586
0
    udata->lnk->corder =
587
0
        0; /* Will be re-written during group insertion, if the group is tracking creation order */
588
0
    udata->lnk->corder_valid = false; /* Creation order not valid (yet) */
589
590
    /* Check for non-default link creation properties */
591
0
    if (udata->lc_plist) {
592
        /* Get character encoding property */
593
0
        if (H5CX_get_encoding(&udata->lnk->cset) < 0)
594
0
            HGOTO_ERROR(H5E_LINK, H5E_CANTGET, FAIL, "can't get 'character set' property");
595
0
    } /* end if */
596
0
    else
597
0
        udata->lnk->cset = H5F_DEFAULT_CSET; /* Default character encoding for link */
598
599
    /* Set the link's name correctly */
600
0
    H5_WARN_CAST_AWAY_CONST_OFF
601
0
    udata->lnk->name = (char *)name;
602
0
    H5_WARN_CAST_AWAY_CONST_ON
603
604
    /* Insert link into group */
605
0
    if (H5G_obj_insert(grp_loc->oloc, udata->lnk, true,
606
0
                       udata->ocrt_info ? udata->ocrt_info->obj_type : H5O_TYPE_UNKNOWN,
607
0
                       udata->ocrt_info ? udata->ocrt_info->crt_info : NULL) < 0)
608
0
        HGOTO_ERROR(H5E_LINK, H5E_CANTINIT, FAIL, "unable to create new link for object");
609
610
    /* Set object's path if it has been passed in and is not set */
611
0
    if (udata->path != NULL && udata->path->user_path_r == NULL)
612
0
        if (H5G_name_set(grp_loc->path, udata->path, name) < 0)
613
0
            HGOTO_ERROR(H5E_LINK, H5E_CANTINIT, FAIL, "cannot set name");
614
615
    /* If link is a user-defined link, trigger its creation callback if it has one */
616
0
    if (udata->lnk->type >= H5L_TYPE_UD_MIN) {
617
0
        const H5L_class_t *link_class; /* User-defined link class */
618
619
        /* Get the link class for this type of link. */
620
0
        if (NULL == (link_class = H5L_find_class(udata->lnk->type)))
621
0
            HGOTO_ERROR(H5E_LINK, H5E_NOTREGISTERED, FAIL, "unable to get class of UD link");
622
623
0
        if (link_class->create_func != NULL) {
624
0
            H5O_loc_t  temp_oloc;
625
0
            H5G_name_t temp_path;
626
627
            /* Create a temporary location (or else H5G_open will do a shallow
628
             * copy and wipe out grp_loc)
629
             */
630
0
            H5G_name_reset(&temp_path);
631
0
            if (H5O_loc_copy_deep(&temp_oloc, grp_loc->oloc) < 0)
632
0
                HGOTO_ERROR(H5E_LINK, H5E_CANTCOPY, FAIL, "unable to copy object location");
633
634
0
            temp_loc.oloc = &temp_oloc;
635
0
            temp_loc.path = &temp_path;
636
0
            temp_loc_init = true;
637
638
            /* Set up location for user-defined callback */
639
0
            if (NULL == (grp = H5G_open(&temp_loc)))
640
0
                HGOTO_ERROR(H5E_LINK, H5E_CANTOPENOBJ, FAIL, "unable to open group");
641
0
            if ((grp_id = H5VL_wrap_register(H5I_GROUP, grp, true)) < 0)
642
0
                HGOTO_ERROR(H5E_LINK, H5E_CANTREGISTER, FAIL, "unable to register ID for group");
643
644
            /* Prepare & restore library for user callback */
645
0
            H5_BEFORE_USER_CB(FAIL)
646
0
                {
647
                    /* Make callback */
648
0
                    ret_value = (link_class->create_func)(name, grp_id, udata->lnk->u.ud.udata,
649
0
                                                          udata->lnk->u.ud.size, H5P_DEFAULT);
650
0
                }
651
0
            H5_AFTER_USER_CB(FAIL)
652
0
            if (ret_value < 0)
653
0
                HGOTO_ERROR(H5E_LINK, H5E_CALLBACK, FAIL, "link creation callback failed");
654
0
        } /* end if */
655
0
    }     /* end if */
656
657
0
done:
658
    /* Check if an object was created */
659
0
    if (obj_created) {
660
0
        H5O_loc_t oloc; /* Object location for created object */
661
662
        /* Set up object location */
663
0
        memset(&oloc, 0, sizeof(oloc));
664
0
        oloc.file = grp_loc->oloc->file;
665
0
        oloc.addr = udata->lnk->u.hard.addr;
666
667
        /* Decrement refcount on new object's object header in memory */
668
0
        if (H5O_dec_rc_by_loc(&oloc) < 0)
669
0
            HDONE_ERROR(H5E_LINK, H5E_CANTDEC, FAIL, "unable to decrement refcount on newly created object");
670
0
    } /* end if */
671
672
    /* Close the location given to the user callback if it was created */
673
0
    if (grp_id >= 0) {
674
0
        if (H5I_dec_app_ref(grp_id) < 0)
675
0
            HDONE_ERROR(H5E_LINK, H5E_CANTRELEASE, FAIL, "unable to close ID from UD callback");
676
0
    } /* end if */
677
0
    else if (grp != NULL) {
678
0
        if (H5G_close(grp) < 0)
679
0
            HDONE_ERROR(H5E_LINK, H5E_CANTRELEASE, FAIL, "unable to close group given to UD callback");
680
0
    } /* end if */
681
0
    else if (temp_loc_init)
682
0
        H5G_loc_free(&temp_loc);
683
684
    /* Indicate that this callback didn't take ownership of the group *
685
     * location for the object */
686
0
    *own_loc = H5G_OWN_NONE;
687
688
0
    FUNC_LEAVE_NOAPI(ret_value)
689
0
} /* end H5L__link_cb() */
690
691
/*-------------------------------------------------------------------------
692
 * Function:    H5L__create_real
693
 *
694
 * Purpose:     Creates a link at a path location
695
 *
696
 *              lnk should have linkclass-specific information already
697
 *              set, but this function will take care of setting name.
698
 *
699
 *              obj_path can be NULL if the object's path doesn't need to
700
 *              be set, and obj_file can be NULL if the object is not a
701
 *              hard link.
702
 *
703
 * Return:      Non-negative on success/Negative on failure
704
 *
705
 *-------------------------------------------------------------------------
706
 */
707
static herr_t
708
H5L__create_real(const H5G_loc_t *link_loc, const char *link_name, H5G_name_t *obj_path, H5F_t *obj_file,
709
                 H5O_link_t *lnk, H5O_obj_create_t *ocrt_info, hid_t lcpl_id)
710
0
{
711
0
    char           *norm_link_name = NULL;              /* Pointer to normalized link name */
712
0
    unsigned        target_flags   = H5G_TARGET_NORMAL; /* Flags to pass to group traversal function */
713
0
    H5P_genplist_t *lc_plist       = NULL;              /* Link creation property list */
714
0
    H5L_trav_cr_t   udata;                              /* User data for callback */
715
0
    herr_t          ret_value = SUCCEED;                /* Return value */
716
717
0
    FUNC_ENTER_PACKAGE
718
719
    /* Check args */
720
0
    assert(link_loc);
721
0
    assert(link_name && *link_name);
722
0
    assert(lnk);
723
0
    assert(lnk->type >= H5L_TYPE_HARD && lnk->type <= H5L_TYPE_MAX);
724
725
    /* Get normalized link name */
726
0
    if ((norm_link_name = H5G_normalize(link_name)) == NULL)
727
0
        HGOTO_ERROR(H5E_LINK, H5E_BADVALUE, FAIL, "can't normalize name");
728
729
    /* Check for flags present in creation property list */
730
0
    if (lcpl_id != H5P_DEFAULT) {
731
0
        unsigned crt_intmd_group;
732
733
        /* Get link creation property list */
734
0
        if (NULL == (lc_plist = (H5P_genplist_t *)H5I_object(lcpl_id)))
735
0
            HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property list");
736
737
        /* Get intermediate group creation property */
738
0
        if (H5CX_get_intermediate_group(&crt_intmd_group) < 0)
739
0
            HGOTO_ERROR(H5E_LINK, H5E_CANTGET, FAIL, "can't get 'create intermediate group' property");
740
741
0
        if (crt_intmd_group > 0)
742
0
            target_flags |= H5G_CRT_INTMD_GROUP;
743
0
    } /* end if */
744
745
0
    if (ocrt_info != NULL)
746
0
        target_flags |= H5G_CRT_OBJ;
747
748
    /* Set up user data
749
     * FILE is used to make sure that hard links don't cross files, and
750
     * should be NULL for other link types.
751
     * LC_PLIST is a pointer to the link creation property list.
752
     * PATH is a pointer to the path of the object being inserted if this is
753
     * a hard link; this is used to set the paths to objects when they are
754
     * created.  For other link types, this is NULL.
755
     * OCRT_INFO is a pointer to the structure for object creation.
756
     * LNK is the link struct passed into this function.  At this point all
757
     * of its fields should be populated except for name, which is set when
758
     * inserting it in the callback.
759
     */
760
0
    udata.file      = obj_file;
761
0
    udata.lc_plist  = lc_plist;
762
0
    udata.path      = obj_path;
763
0
    udata.ocrt_info = ocrt_info;
764
0
    udata.lnk       = lnk;
765
766
    /* Traverse the destination path & create new link */
767
0
    if (H5G_traverse(link_loc, link_name, target_flags, H5L__link_cb, &udata) < 0)
768
0
        HGOTO_ERROR(H5E_LINK, H5E_CANTINSERT, FAIL, "can't insert link");
769
770
0
done:
771
    /* Free the normalized path name */
772
0
    if (norm_link_name)
773
0
        H5MM_xfree(norm_link_name);
774
775
0
    FUNC_LEAVE_NOAPI(ret_value)
776
0
} /* end H5L__create_real() */
777
778
/*-------------------------------------------------------------------------
779
 * Function:  H5L__create_hard
780
 *
781
 * Purpose: Creates a hard link from NEW_NAME to CUR_NAME.
782
 *
783
 * Return:  Non-negative on success/Negative on failure
784
 *
785
 *-------------------------------------------------------------------------
786
 */
787
herr_t
788
H5L__create_hard(H5G_loc_t *cur_loc, const char *cur_name, const H5G_loc_t *link_loc, const char *link_name,
789
                 hid_t lcpl_id)
790
0
{
791
0
    char      *norm_cur_name = NULL; /* Pointer to normalized current name */
792
0
    H5F_t     *link_file     = NULL; /* Pointer to file to link to */
793
0
    H5O_link_t lnk;                  /* Link to insert */
794
0
    H5G_loc_t  obj_loc;              /* Location of object to link to */
795
0
    H5G_name_t path;                 /* obj_loc's path*/
796
0
    H5O_loc_t  oloc;                 /* obj_loc's oloc */
797
0
    bool       loc_valid = false;
798
0
    herr_t     ret_value = SUCCEED; /* Return value */
799
800
0
    FUNC_ENTER_PACKAGE
801
802
    /* Check args */
803
0
    assert(cur_loc);
804
0
    assert(cur_name && *cur_name);
805
0
    assert(link_loc);
806
0
    assert(link_name && *link_name);
807
808
    /* Get normalized copy of the current name */
809
0
    if ((norm_cur_name = H5G_normalize(cur_name)) == NULL)
810
0
        HGOTO_ERROR(H5E_LINK, H5E_BADVALUE, FAIL, "can't normalize name");
811
812
    /* Set up link data specific to hard links */
813
0
    lnk.type = H5L_TYPE_HARD;
814
815
    /* Get object location for object pointed to */
816
0
    obj_loc.path = &path;
817
0
    obj_loc.oloc = &oloc;
818
0
    H5G_loc_reset(&obj_loc);
819
0
    if (H5G_loc_find(cur_loc, norm_cur_name, &obj_loc) < 0)
820
0
        HGOTO_ERROR(H5E_LINK, H5E_NOTFOUND, FAIL, "source object not found");
821
0
    loc_valid = true;
822
823
    /* Construct link information for eventual insertion */
824
0
    lnk.u.hard.addr = obj_loc.oloc->addr;
825
826
    /* Set destination's file information */
827
0
    link_file = obj_loc.oloc->file;
828
829
    /* Create actual link to the object.  Pass in NULL for the path, since this
830
     * function shouldn't change an object's user path. */
831
0
    if (H5L__create_real(link_loc, link_name, NULL, link_file, &lnk, NULL, lcpl_id) < 0)
832
0
        HGOTO_ERROR(H5E_LINK, H5E_CANTINIT, FAIL, "unable to create new link to object");
833
834
0
done:
835
    /* Free the object header location */
836
0
    if (loc_valid)
837
0
        if (H5G_loc_free(&obj_loc) < 0)
838
0
            HDONE_ERROR(H5E_LINK, H5E_CANTRELEASE, FAIL, "unable to free location");
839
840
    /* Free the normalized path name */
841
0
    if (norm_cur_name)
842
0
        H5MM_xfree(norm_cur_name);
843
844
0
    FUNC_LEAVE_NOAPI(ret_value)
845
0
} /* end H5L__create_hard() */
846
847
/*-------------------------------------------------------------------------
848
 * Function:    H5L__create_soft
849
 *
850
 * Purpose:     Creates a soft link from LINK_NAME to TARGET_PATH.
851
 *
852
 * Return:      SUCCEED/FAIL
853
 *
854
 *-------------------------------------------------------------------------
855
 */
856
herr_t
857
H5L__create_soft(const char *target_path, const H5G_loc_t *link_loc, const char *link_name, hid_t lcpl_id)
858
0
{
859
0
    char      *norm_target = NULL;  /* Pointer to normalized current name */
860
0
    H5O_link_t lnk;                 /* Link to insert */
861
0
    herr_t     ret_value = SUCCEED; /* Return value */
862
863
0
    FUNC_ENTER_PACKAGE
864
865
    /* Check args */
866
0
    assert(link_loc);
867
0
    assert(target_path && *target_path);
868
0
    assert(link_name && *link_name);
869
870
    /* Get normalized copy of the link target */
871
0
    if ((norm_target = H5G_normalize(target_path)) == NULL)
872
0
        HGOTO_ERROR(H5E_LINK, H5E_BADVALUE, FAIL, "can't normalize name");
873
874
    /* Set up link data specific to soft links */
875
0
    lnk.type        = H5L_TYPE_SOFT;
876
0
    lnk.u.soft.name = norm_target;
877
878
    /* Create actual link to the object */
879
0
    if (H5L__create_real(link_loc, link_name, NULL, NULL, &lnk, NULL, lcpl_id) < 0)
880
0
        HGOTO_ERROR(H5E_LINK, H5E_CANTINIT, FAIL, "unable to create new link to object");
881
882
0
done:
883
    /* Free the normalized target name */
884
0
    if (norm_target)
885
0
        H5MM_xfree(norm_target);
886
887
0
    FUNC_LEAVE_NOAPI(ret_value)
888
0
} /* end H5L__create_soft() */
889
890
/*-------------------------------------------------------------------------
891
 * Function:  H5L__create_ud
892
 *
893
 * Purpose: Creates a user-defined link. See H5Lcreate_ud for
894
 *              full documentation.
895
 *
896
 * Return:  Non-negative on success/Negative on failure
897
 *
898
 *-------------------------------------------------------------------------
899
 */
900
herr_t
901
H5L__create_ud(const H5G_loc_t *link_loc, const char *link_name, const void *ud_data, size_t ud_data_size,
902
               H5L_type_t type, hid_t lcpl_id)
903
0
{
904
0
    H5O_link_t lnk;                 /* Link to insert */
905
0
    herr_t     ret_value = SUCCEED; /* Return value */
906
907
0
    FUNC_ENTER_PACKAGE
908
909
    /* Check args */
910
0
    assert(type >= H5L_TYPE_UD_MIN && type <= H5L_TYPE_MAX);
911
0
    assert(link_loc);
912
0
    assert(link_name && *link_name);
913
0
    assert(ud_data_size == 0 || ud_data);
914
915
    /* Initialize the link struct's pointer to its udata buffer */
916
0
    lnk.u.ud.udata = NULL;
917
918
    /* Make sure that this link class is registered */
919
0
    if (H5L__find_class_idx(type) < 0)
920
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "link class has not been registered with library");
921
922
    /* Fill in UD link-specific information in the link struct*/
923
0
    if (ud_data_size > 0) {
924
0
        lnk.u.ud.udata = H5MM_malloc((size_t)ud_data_size);
925
0
        H5MM_memcpy(lnk.u.ud.udata, ud_data, (size_t)ud_data_size);
926
0
    } /* end if */
927
0
    else
928
0
        lnk.u.ud.udata = NULL;
929
930
0
    lnk.u.ud.size = ud_data_size;
931
0
    lnk.type      = type;
932
933
    /* Create actual link to the object */
934
0
    if (H5L__create_real(link_loc, link_name, NULL, NULL, &lnk, NULL, lcpl_id) < 0)
935
0
        HGOTO_ERROR(H5E_LINK, H5E_CANTINIT, FAIL, "unable to register new name for object");
936
937
0
done:
938
    /* Free the link's udata buffer if it's been allocated */
939
0
    H5MM_xfree(lnk.u.ud.udata);
940
941
0
    FUNC_LEAVE_NOAPI(ret_value)
942
0
} /* end H5L__create_ud() */
943
944
/*-------------------------------------------------------------------------
945
 * Function:  H5L__get_val_real
946
 *
947
 * Purpose: Retrieve link value from a link object
948
 *
949
 * Return:  Non-negative on success/Negative on failure
950
 *
951
 *-------------------------------------------------------------------------
952
 */
953
static herr_t
954
H5L__get_val_real(const H5O_link_t *lnk, void *buf, size_t size)
955
0
{
956
0
    herr_t ret_value = SUCCEED; /* Return value */
957
958
0
    FUNC_ENTER_PACKAGE
959
960
    /* Sanity check */
961
0
    assert(lnk);
962
963
    /* Check for soft link */
964
0
    if (H5L_TYPE_SOFT == lnk->type) {
965
        /* Copy to output buffer */
966
0
        if (size > 0 && buf) {
967
0
            strncpy((char *)buf, lnk->u.soft.name, size);
968
0
            if (strlen(lnk->u.soft.name) >= size)
969
0
                ((char *)buf)[size - 1] = '\0';
970
0
        } /* end if */
971
0
    }     /* end if */
972
    /* Check for user-defined link */
973
0
    else if (lnk->type >= H5L_TYPE_UD_MIN) {
974
0
        const H5L_class_t *link_class; /* User-defined link class */
975
976
        /* Get the link class for this type of link.  It's okay if the class
977
         * isn't registered, though--we just can't give any more information
978
         * about it
979
         */
980
0
        link_class = H5L_find_class(lnk->type);
981
982
0
        if (link_class != NULL && link_class->query_func != NULL) {
983
0
            ssize_t len;
984
985
            /* Prepare & restore library for user callback */
986
0
            H5_BEFORE_USER_CB(FAIL)
987
0
                {
988
0
                    len = (link_class->query_func)(lnk->name, lnk->u.ud.udata, lnk->u.ud.size, buf, size);
989
0
                }
990
0
            H5_AFTER_USER_CB(FAIL)
991
0
            if (len < 0)
992
0
                HGOTO_ERROR(H5E_LINK, H5E_CALLBACK, FAIL, "query callback returned failure");
993
0
        } /* end if */
994
0
        else if (buf && size > 0)
995
0
            ((char *)buf)[0] = '\0';
996
0
    } /* end if */
997
0
    else
998
0
        HGOTO_ERROR(H5E_LINK, H5E_BADTYPE, FAIL, "object is not a symbolic or user-defined link");
999
1000
0
done:
1001
0
    FUNC_LEAVE_NOAPI(ret_value)
1002
0
} /* end H5L__get_val_real() */
1003
1004
/*-------------------------------------------------------------------------
1005
 * Function:  H5L__get_val_cb
1006
 *
1007
 * Purpose: Callback for retrieving link value or udata.
1008
 *
1009
 * Return:  Non-negative on success/Negative on failure
1010
 *
1011
 *-------------------------------------------------------------------------
1012
 */
1013
static herr_t
1014
H5L__get_val_cb(H5G_loc_t H5_ATTR_UNUSED *grp_loc /*in*/, const char *name, const H5O_link_t *lnk,
1015
                H5G_loc_t H5_ATTR_UNUSED *obj_loc, void *_udata /*in,out*/, H5G_own_loc_t *own_loc /*out*/)
1016
0
{
1017
0
    H5L_trav_gv_t *udata     = (H5L_trav_gv_t *)_udata; /* User data passed in */
1018
0
    herr_t         ret_value = SUCCEED;                 /* Return value */
1019
1020
0
    FUNC_ENTER_PACKAGE
1021
1022
    /* Check if the name in this group resolved to a valid link */
1023
0
    if (lnk == NULL)
1024
0
        HGOTO_ERROR(H5E_LINK, H5E_NOTFOUND, FAIL, "'%s' doesn't exist", name);
1025
1026
    /* Retrieve the value for the link */
1027
0
    if (H5L__get_val_real(lnk, udata->buf, udata->size) < 0)
1028
0
        HGOTO_ERROR(H5E_LINK, H5E_CANTGET, FAIL, "can't retrieve link value");
1029
1030
0
done:
1031
    /* Indicate that this callback didn't take ownership of the group *
1032
     * location for the object */
1033
0
    *own_loc = H5G_OWN_NONE;
1034
1035
0
    FUNC_LEAVE_NOAPI(ret_value)
1036
0
} /* end H5L__get_val_cb() */
1037
1038
/*-------------------------------------------------------------------------
1039
 * Function:  H5L__get_val
1040
 *
1041
 * Purpose: Returns the value of a symbolic link or the udata for a
1042
 *              user-defined link.
1043
 *
1044
 * Return:  Success:  Non-negative, with at most SIZE bytes of the
1045
 *        link value copied into the BUF buffer.  If the
1046
 *        link value is larger than SIZE characters
1047
 *        counting the null terminator then the BUF
1048
 *        result will not be null terminated.
1049
 *
1050
 *    Failure:  Negative
1051
 *
1052
 *-------------------------------------------------------------------------
1053
 */
1054
herr_t
1055
H5L__get_val(const H5G_loc_t *loc, const char *name, void *buf /*out*/, size_t size)
1056
0
{
1057
0
    H5L_trav_gv_t udata;               /* User data for callback */
1058
0
    herr_t        ret_value = SUCCEED; /* Return value */
1059
1060
0
    FUNC_ENTER_PACKAGE
1061
1062
    /* Sanity check */
1063
0
    assert(loc);
1064
0
    assert(name && *name);
1065
1066
    /* Set up user data for retrieving information */
1067
0
    udata.size = size;
1068
0
    udata.buf  = buf;
1069
1070
    /* Traverse the group hierarchy to locate the object to get info about */
1071
0
    if (H5G_traverse(loc, name, H5G_TARGET_SLINK | H5G_TARGET_UDLINK, H5L__get_val_cb, &udata) < 0)
1072
0
        HGOTO_ERROR(H5E_LINK, H5E_NOTFOUND, FAIL, "name doesn't exist");
1073
1074
0
done:
1075
0
    FUNC_LEAVE_NOAPI(ret_value)
1076
0
} /* H5L__get_val() */
1077
1078
/*-------------------------------------------------------------------------
1079
 * Function:  H5L__get_val_by_idx_cb
1080
 *
1081
 * Purpose: Callback for retrieving a link's value according to an
1082
 *              index's order.
1083
 *
1084
 * Return:  Non-negative on success/Negative on failure
1085
 *
1086
 *-------------------------------------------------------------------------
1087
 */
1088
static herr_t
1089
H5L__get_val_by_idx_cb(H5G_loc_t H5_ATTR_UNUSED *grp_loc /*in*/, const char H5_ATTR_UNUSED *name,
1090
                       const H5O_link_t H5_ATTR_UNUSED *lnk, H5G_loc_t *obj_loc, void *_udata /*in,out*/,
1091
                       H5G_own_loc_t *own_loc /*out*/)
1092
0
{
1093
0
    H5L_trav_gvbi_t *udata = (H5L_trav_gvbi_t *)_udata; /* User data passed in */
1094
0
    H5O_link_t       fnd_lnk;                           /* Link within group */
1095
0
    bool             lnk_copied = false;                /* Whether the link was copied */
1096
0
    herr_t           ret_value  = SUCCEED;              /* Return value */
1097
1098
0
    FUNC_ENTER_PACKAGE
1099
1100
    /* Check if the name of the group resolved to a valid object */
1101
0
    if (obj_loc == NULL)
1102
0
        HGOTO_ERROR(H5E_LINK, H5E_NOTFOUND, FAIL, "group doesn't exist");
1103
1104
    /* Query link */
1105
0
    if (H5G_obj_lookup_by_idx(obj_loc->oloc, udata->idx_type, udata->order, udata->n, &fnd_lnk) < 0)
1106
0
        HGOTO_ERROR(H5E_LINK, H5E_NOTFOUND, FAIL, "link not found");
1107
0
    lnk_copied = true;
1108
1109
    /* Retrieve the value for the link */
1110
0
    if (H5L__get_val_real(&fnd_lnk, udata->buf, udata->size) < 0)
1111
0
        HGOTO_ERROR(H5E_LINK, H5E_CANTGET, FAIL, "can't retrieve link value");
1112
1113
0
done:
1114
    /* Reset the link information, if we have a copy */
1115
0
    if (lnk_copied)
1116
0
        H5O_msg_reset(H5O_LINK_ID, &fnd_lnk);
1117
1118
    /* Indicate that this callback didn't take ownership of the group *
1119
     * location for the object */
1120
0
    *own_loc = H5G_OWN_NONE;
1121
1122
0
    FUNC_LEAVE_NOAPI(ret_value)
1123
0
} /* end H5L__get_val_by_idx_cb() */
1124
1125
/*-------------------------------------------------------------------------
1126
 * Function:    H5L__get_val_by_idx
1127
 *
1128
 * Purpose:     Internal routine to query a link value according to the
1129
 *              index within a group
1130
 *
1131
 * Return:      SUCCEED/FAIL
1132
 *
1133
 *-------------------------------------------------------------------------
1134
 */
1135
herr_t
1136
H5L__get_val_by_idx(const H5G_loc_t *loc, const char *name, H5_index_t idx_type, H5_iter_order_t order,
1137
                    hsize_t n, void *buf /*out*/, size_t size)
1138
0
{
1139
0
    H5L_trav_gvbi_t udata;               /* User data for callback */
1140
0
    herr_t          ret_value = SUCCEED; /* Return value */
1141
1142
0
    FUNC_ENTER_PACKAGE
1143
1144
    /* Check arguments */
1145
0
    assert(loc);
1146
0
    assert(name && *name);
1147
1148
    /* Set up user data for retrieving information */
1149
0
    udata.idx_type = idx_type;
1150
0
    udata.order    = order;
1151
0
    udata.n        = n;
1152
0
    udata.buf      = buf;
1153
0
    udata.size     = size;
1154
1155
    /* Traverse the group hierarchy to locate the object to get info about */
1156
0
    if (H5G_traverse(loc, name, H5G_TARGET_SLINK | H5G_TARGET_UDLINK, H5L__get_val_by_idx_cb, &udata) < 0)
1157
0
        HGOTO_ERROR(H5E_LINK, H5E_CANTGET, FAIL, "can't get link info for index: %llu",
1158
0
                    (unsigned long long)n);
1159
1160
0
done:
1161
0
    FUNC_LEAVE_NOAPI(ret_value)
1162
0
} /* end H5L__get_val_by_idx() */
1163
1164
/*-------------------------------------------------------------------------
1165
 * Function:  H5L__delete_cb
1166
 *
1167
 * Purpose: Callback for deleting a link.  This routine
1168
 *              actually deletes the link
1169
 *
1170
 * Return:  Non-negative on success/Negative on failure
1171
 *
1172
 *-------------------------------------------------------------------------
1173
 */
1174
static herr_t
1175
H5L__delete_cb(H5G_loc_t *grp_loc /*in*/, const char *name, const H5O_link_t *lnk,
1176
               H5G_loc_t H5_ATTR_UNUSED *obj_loc, void H5_ATTR_UNUSED *_udata /*in,out*/,
1177
               H5G_own_loc_t *own_loc /*out*/)
1178
0
{
1179
0
    herr_t ret_value = SUCCEED;
1180
1181
0
    FUNC_ENTER_PACKAGE
1182
1183
    /* Check if the group resolved to a valid link */
1184
0
    if (grp_loc == NULL)
1185
0
        HGOTO_ERROR(H5E_LINK, H5E_NOTFOUND, FAIL, "group doesn't exist");
1186
1187
    /* Check if the name in this group resolved to a valid link */
1188
0
    if (name == NULL)
1189
0
        HGOTO_ERROR(H5E_LINK, H5E_NOTFOUND, FAIL, "name doesn't exist");
1190
1191
    /* Check for non-existent (NULL) link.
1192
     * Note that this can also occur when attempting to remove '.'
1193
     */
1194
0
    if (lnk == NULL)
1195
0
        HGOTO_ERROR(H5E_LINK, H5E_CANTDELETE, FAIL,
1196
0
                    "callback link pointer is NULL (specified link may be '.' or not exist)");
1197
1198
    /* Remove the link from the group */
1199
0
    if (H5G_obj_remove(grp_loc->oloc, grp_loc->path->full_path_r, name) < 0)
1200
0
        HGOTO_ERROR(H5E_LINK, H5E_CANTDELETE, FAIL, "unable to remove link from group");
1201
1202
0
done:
1203
    /* Indicate that this callback didn't take ownership of the group *
1204
     * location for the object */
1205
0
    *own_loc = H5G_OWN_NONE;
1206
1207
0
    FUNC_LEAVE_NOAPI(ret_value)
1208
0
} /* end H5L__delete_cb() */
1209
1210
/*-------------------------------------------------------------------------
1211
 * Function:  H5L__delete
1212
 *
1213
 * Purpose: Delete a link from a group.
1214
 *
1215
 * Return:  Non-negative on success/Negative on failure
1216
 *
1217
 *-------------------------------------------------------------------------
1218
 */
1219
herr_t
1220
H5L__delete(const H5G_loc_t *loc, const char *name)
1221
0
{
1222
0
    char  *norm_name = NULL;    /* Pointer to normalized name */
1223
0
    herr_t ret_value = SUCCEED; /* Return value */
1224
1225
0
    FUNC_ENTER_PACKAGE
1226
1227
    /* Sanity check */
1228
0
    assert(loc);
1229
0
    assert(name && *name);
1230
1231
    /* Get normalized copy of the name */
1232
0
    if ((norm_name = H5G_normalize(name)) == NULL)
1233
0
        HGOTO_ERROR(H5E_LINK, H5E_BADVALUE, FAIL, "can't normalize name");
1234
1235
    /* Set up user data for unlink operation */
1236
0
    if (H5G_traverse(loc, norm_name, H5G_TARGET_SLINK | H5G_TARGET_UDLINK | H5G_TARGET_MOUNT, H5L__delete_cb,
1237
0
                     NULL) < 0)
1238
0
        HGOTO_ERROR(H5E_LINK, H5E_CANTREMOVE, FAIL, "can't unlink object");
1239
1240
0
done:
1241
    /* Free the normalized path name */
1242
0
    if (norm_name)
1243
0
        H5MM_xfree(norm_name);
1244
1245
0
    FUNC_LEAVE_NOAPI(ret_value)
1246
0
} /* end H5L__delete() */
1247
1248
/*-------------------------------------------------------------------------
1249
 * Function:  H5L__delete_by_idx_cb
1250
 *
1251
 * Purpose: Callback for removing a link according to an index's order.
1252
 *
1253
 * Return:  Non-negative on success/Negative on failure
1254
 *
1255
 *-------------------------------------------------------------------------
1256
 */
1257
static herr_t
1258
H5L__delete_by_idx_cb(H5G_loc_t H5_ATTR_UNUSED *grp_loc /*in*/, const char H5_ATTR_UNUSED *name,
1259
                      const H5O_link_t H5_ATTR_UNUSED *lnk, H5G_loc_t *obj_loc, void *_udata /*in,out*/,
1260
                      H5G_own_loc_t *own_loc /*out*/)
1261
0
{
1262
0
    H5L_trav_gvbi_t *udata     = (H5L_trav_gvbi_t *)_udata; /* User data passed in */
1263
0
    herr_t           ret_value = SUCCEED;                   /* Return value */
1264
1265
0
    FUNC_ENTER_PACKAGE_TAG((obj_loc) ? (obj_loc->oloc->addr) : HADDR_UNDEF)
1266
1267
    /* Check if the name of the group resolved to a valid object */
1268
0
    if (obj_loc == NULL)
1269
0
        HGOTO_ERROR(H5E_LINK, H5E_NOTFOUND, FAIL, "group doesn't exist");
1270
1271
    /* Delete link */
1272
0
    if (H5G_obj_remove_by_idx(obj_loc->oloc, obj_loc->path->full_path_r, udata->idx_type, udata->order,
1273
0
                              udata->n) < 0)
1274
0
        HGOTO_ERROR(H5E_LINK, H5E_NOTFOUND, FAIL, "link not found");
1275
1276
0
done:
1277
    /* Indicate that this callback didn't take ownership of the group *
1278
     * location for the object */
1279
0
    *own_loc = H5G_OWN_NONE;
1280
1281
0
    FUNC_LEAVE_NOAPI_TAG(ret_value)
1282
0
} /* end H5L__delete_by_idx_cb() */
1283
1284
/*-------------------------------------------------------------------------
1285
 * Function:    H5L__delete_by_idx
1286
 *
1287
 * Purpose:     Internal routine to delete a link according to its index
1288
 *              within a group.
1289
 *
1290
 * Return:      SUCCEED/FAIL
1291
 *
1292
 *-------------------------------------------------------------------------
1293
 */
1294
herr_t
1295
H5L__delete_by_idx(const H5G_loc_t *loc, const char *name, H5_index_t idx_type, H5_iter_order_t order,
1296
                   hsize_t n)
1297
0
{
1298
0
    H5L_trav_rmbi_t udata;               /* User data for callback */
1299
0
    herr_t          ret_value = SUCCEED; /* Return value */
1300
1301
0
    FUNC_ENTER_PACKAGE
1302
1303
    /* Sanity check */
1304
0
    assert(loc);
1305
0
    assert(name && *name);
1306
1307
    /* Set up user data for unlink operation */
1308
0
    udata.idx_type = idx_type;
1309
0
    udata.order    = order;
1310
0
    udata.n        = n;
1311
1312
    /* Traverse the group hierarchy to remove the link */
1313
0
    if (H5G_traverse(loc, name, H5G_TARGET_SLINK | H5G_TARGET_UDLINK | H5G_TARGET_MOUNT,
1314
0
                     H5L__delete_by_idx_cb, &udata) < 0)
1315
0
        HGOTO_ERROR(H5E_LINK, H5E_CANTDELETE, FAIL, "link doesn't exist");
1316
1317
0
done:
1318
0
    FUNC_LEAVE_NOAPI(ret_value)
1319
0
} /* end H5L__delete_by_idx() */
1320
1321
/*-------------------------------------------------------------------------
1322
 * Function:  H5L__move_dest_cb
1323
 *
1324
 * Purpose: Second callback for moving and renaming an object.  This routine
1325
 *              inserts a new link into the group returned by the traversal.
1326
 *              It is called by H5L__move_cb.
1327
 *
1328
 * Return:  Non-negative on success/Negative on failure
1329
 *
1330
 *-------------------------------------------------------------------------
1331
 */
1332
static herr_t
1333
H5L__move_dest_cb(H5G_loc_t *grp_loc /*in*/, const char *name, const H5O_link_t H5_ATTR_UNUSED *lnk,
1334
                  H5G_loc_t *obj_loc, void *_udata /*in,out*/, H5G_own_loc_t *own_loc /*out*/)
1335
0
{
1336
0
    H5L_trav_mv2_t *udata  = (H5L_trav_mv2_t *)_udata; /* User data passed in */
1337
0
    H5G_t          *grp    = NULL; /* H5G_t for this group, opened to pass to user callback */
1338
0
    hid_t           grp_id = FAIL; /* ID for this group (passed to user callback */
1339
0
    H5G_loc_t       temp_loc;      /* For UD callback */
1340
0
    bool            temp_loc_init = false;
1341
0
    herr_t          ret_value     = SUCCEED; /* Return value */
1342
1343
0
    FUNC_ENTER_PACKAGE
1344
1345
    /* Make sure an object with this name doesn't already exist */
1346
0
    if (obj_loc != NULL)
1347
0
        HGOTO_ERROR(H5E_LINK, H5E_NOTFOUND, FAIL, "an object with that name already exists");
1348
1349
    /* Check for crossing file boundaries with a new hard link */
1350
0
    if (udata->lnk->type == H5L_TYPE_HARD)
1351
        /* Check that both objects are in same file */
1352
0
        if (!H5F_SAME_SHARED(grp_loc->oloc->file, udata->file))
1353
0
            HGOTO_ERROR(H5E_LINK, H5E_CANTINIT, FAIL, "moving a link across files is not allowed");
1354
1355
    /* Give the object its new name */
1356
0
    assert(udata->lnk->name == NULL);
1357
0
    H5_WARN_CAST_AWAY_CONST_OFF
1358
0
    udata->lnk->name = (char *)name;
1359
0
    H5_WARN_CAST_AWAY_CONST_ON
1360
1361
    /* Insert the link into the group */
1362
0
    if (H5G_obj_insert(grp_loc->oloc, udata->lnk, true, H5O_TYPE_UNKNOWN, NULL) < 0)
1363
0
        HGOTO_ERROR(H5E_LINK, H5E_CANTINIT, FAIL, "unable to create new link to object");
1364
1365
    /* If the link was a user-defined link, call its move callback if it has one */
1366
0
    if (udata->lnk->type >= H5L_TYPE_UD_MIN) {
1367
0
        const H5L_class_t *link_class; /* User-defined link class */
1368
1369
        /* Get the link class for this type of link. */
1370
0
        if (NULL == (link_class = H5L_find_class(udata->lnk->type)))
1371
0
            HGOTO_ERROR(H5E_LINK, H5E_NOTREGISTERED, FAIL, "link class is not registered");
1372
1373
0
        if ((!udata->copy && link_class->move_func) || (udata->copy && link_class->copy_func)) {
1374
0
            H5O_loc_t  temp_oloc;
1375
0
            H5G_name_t temp_path;
1376
1377
            /* Create a temporary location (or else H5G_open will do a shallow
1378
             * copy and wipe out grp_loc)
1379
             */
1380
0
            H5G_name_reset(&temp_path);
1381
0
            if (H5O_loc_copy_deep(&temp_oloc, grp_loc->oloc) < 0)
1382
0
                HGOTO_ERROR(H5E_LINK, H5E_CANTCOPY, FAIL, "unable to copy object location");
1383
1384
0
            temp_loc.oloc = &temp_oloc;
1385
0
            temp_loc.path = &temp_path;
1386
0
            temp_loc_init = true;
1387
1388
            /* Set up location for user-defined callback */
1389
0
            if (NULL == (grp = H5G_open(&temp_loc)))
1390
0
                HGOTO_ERROR(H5E_LINK, H5E_CANTOPENOBJ, FAIL, "unable to open group");
1391
0
            if ((grp_id = H5VL_wrap_register(H5I_GROUP, grp, true)) < 0)
1392
0
                HGOTO_ERROR(H5E_LINK, H5E_CANTREGISTER, FAIL, "unable to register group ID");
1393
1394
0
            if (udata->copy) {
1395
                /* Prepare & restore library for user callback */
1396
0
                H5_BEFORE_USER_CB(FAIL)
1397
0
                    {
1398
0
                        ret_value = (link_class->copy_func)(udata->lnk->name, grp_id, udata->lnk->u.ud.udata,
1399
0
                                                            udata->lnk->u.ud.size);
1400
0
                    }
1401
0
                H5_AFTER_USER_CB(FAIL)
1402
0
                if (ret_value < 0)
1403
0
                    HGOTO_ERROR(H5E_LINK, H5E_CALLBACK, FAIL, "UD copy callback returned error");
1404
0
            } /* end if */
1405
0
            else {
1406
                /* Prepare & restore library for user callback */
1407
0
                H5_BEFORE_USER_CB(FAIL)
1408
0
                    {
1409
0
                        ret_value = (link_class->move_func)(udata->lnk->name, grp_id, udata->lnk->u.ud.udata,
1410
0
                                                            udata->lnk->u.ud.size);
1411
0
                    }
1412
0
                H5_AFTER_USER_CB(FAIL)
1413
0
                if (ret_value < 0)
1414
0
                    HGOTO_ERROR(H5E_LINK, H5E_CALLBACK, FAIL, "UD move callback returned error");
1415
0
            } /* end else */
1416
0
        }     /* end if */
1417
0
    }         /* end if */
1418
1419
0
done:
1420
    /* Close the location given to the user callback if it was created */
1421
0
    if (grp_id >= 0) {
1422
0
        if (H5I_dec_app_ref(grp_id) < 0)
1423
0
            HDONE_ERROR(H5E_LINK, H5E_CANTRELEASE, FAIL, "unable to close ID from UD callback");
1424
0
    } /* end if */
1425
0
    else if (grp != NULL) {
1426
0
        if (H5G_close(grp) < 0)
1427
0
            HDONE_ERROR(H5E_LINK, H5E_CANTRELEASE, FAIL, "unable to close group given to UD callback");
1428
0
    } /* end if */
1429
0
    else if (temp_loc_init)
1430
0
        H5G_loc_free(&temp_loc);
1431
1432
    /* Indicate that this callback didn't take ownership of the group *
1433
     * location for the object */
1434
0
    *own_loc = H5G_OWN_NONE;
1435
1436
    /* Reset the "name" field in udata->lnk because it is owned by traverse()
1437
     * and must not be manipulated after traverse closes */
1438
0
    udata->lnk->name = NULL;
1439
1440
0
    FUNC_LEAVE_NOAPI(ret_value)
1441
0
} /* end H5L__move_dest_cb() */
1442
1443
/*-------------------------------------------------------------------------
1444
 * Function:  H5L__move_cb
1445
 *
1446
 * Purpose: Callback for moving and renaming an object.  This routine
1447
 *              replaces the names of open objects with the moved object
1448
 *              in the path
1449
 *
1450
 * Return:  Non-negative on success/Negative on failure
1451
 *
1452
 *-------------------------------------------------------------------------
1453
 */
1454
static herr_t
1455
H5L__move_cb(H5G_loc_t *grp_loc /*in*/, const char *name, const H5O_link_t *lnk, H5G_loc_t *obj_loc,
1456
             void *_udata /*in,out*/, H5G_own_loc_t *own_loc /*out*/)
1457
0
{
1458
0
    H5L_trav_mv_t *udata = (H5L_trav_mv_t *)_udata; /* User data passed in */
1459
0
    H5L_trav_mv2_t udata_out;                       /* User data for H5L__move_dest_cb traversal */
1460
0
    char          *orig_name   = NULL;              /* The name of the link in this group */
1461
0
    bool           link_copied = false;             /* Has udata_out.lnk been allocated? */
1462
0
    herr_t         ret_value   = SUCCEED;           /* Return value */
1463
1464
0
    FUNC_ENTER_PACKAGE
1465
1466
    /* Check if the name in this group resolved to a valid link */
1467
0
    if (obj_loc == NULL)
1468
0
        HGOTO_ERROR(H5E_LINK, H5E_NOTFOUND, FAIL, "name doesn't exist");
1469
1470
    /* Check for operations on '.' */
1471
0
    if (lnk == NULL)
1472
0
        HGOTO_ERROR(H5E_LINK, H5E_NOTFOUND, FAIL, "the name of a link must be supplied to move or copy");
1473
1474
    /* Set up user data for move_dest_cb */
1475
0
    if (NULL == (udata_out.lnk = (H5O_link_t *)H5O_msg_copy(H5O_LINK_ID, lnk, NULL)))
1476
0
        HGOTO_ERROR(H5E_LINK, H5E_CANTCOPY, FAIL, "unable to copy link to be moved");
1477
1478
    /* In this special case, the link's name is going to be replaced at its
1479
     * destination, so we should free it here.
1480
     */
1481
0
    udata_out.lnk->name = (char *)H5MM_xfree(udata_out.lnk->name);
1482
0
    link_copied         = true;
1483
1484
0
    udata_out.lnk->cset = udata->cset;
1485
0
    udata_out.file      = grp_loc->oloc->file;
1486
0
    udata_out.copy      = udata->copy;
1487
1488
    /* Keep a copy of link's name (it's "owned" by the H5G_traverse() routine) */
1489
0
    orig_name = H5MM_xstrdup(name);
1490
1491
    /* Reset the # of soft / UD links that can be traversed, so that the second
1492
     * (destination) traversal has the correct value
1493
     */
1494
0
    if (H5CX_set_nlinks(udata->orig_nlinks) < 0)
1495
0
        HGOTO_ERROR(H5E_LINK, H5E_CANTSET, FAIL, "can't reset # of soft / UD links to traverse");
1496
1497
    /* Insert the link into its new location */
1498
0
    if (H5G_traverse(udata->dst_loc, udata->dst_name, udata->dst_target_flags, H5L__move_dest_cb,
1499
0
                     &udata_out) < 0)
1500
0
        HGOTO_ERROR(H5E_LINK, H5E_NOTFOUND, FAIL, "unable to follow symbolic link");
1501
1502
    /* If this is a move and not a copy operation, change the object's name and remove the old link */
1503
0
    if (!udata->copy) {
1504
0
        H5RS_str_t *dst_name_r; /* Ref-counted version of dest name */
1505
1506
        /* Make certain that the destination name is a full (not relative) path */
1507
0
        if (*(udata->dst_name) != '/') {
1508
0
            assert(udata->dst_loc->path->full_path_r);
1509
1510
            /* Create reference counted string for full dst path */
1511
0
            if ((dst_name_r = H5G_build_fullpath_refstr_str(udata->dst_loc->path->full_path_r,
1512
0
                                                            udata->dst_name)) == NULL)
1513
0
                HGOTO_ERROR(H5E_LINK, H5E_PATH, FAIL, "can't build destination path name");
1514
0
        } /* end if */
1515
0
        else
1516
0
            dst_name_r = H5RS_wrap(udata->dst_name);
1517
0
        assert(dst_name_r);
1518
1519
        /* Fix names up */
1520
0
        if (H5G_name_replace(lnk, H5G_NAME_MOVE, obj_loc->oloc->file, obj_loc->path->full_path_r,
1521
0
                             udata->dst_loc->oloc->file, dst_name_r) < 0) {
1522
0
            H5RS_decr(dst_name_r);
1523
0
            HGOTO_ERROR(H5E_LINK, H5E_CANTINIT, FAIL, "unable to replace name");
1524
0
        } /* end if */
1525
1526
        /* Remove the old link */
1527
0
        if (H5G_obj_remove(grp_loc->oloc, grp_loc->path->full_path_r, orig_name) < 0) {
1528
0
            H5RS_decr(dst_name_r);
1529
0
            HGOTO_ERROR(H5E_LINK, H5E_NOTFOUND, FAIL, "unable to remove old name");
1530
0
        } /* end if */
1531
1532
0
        H5RS_decr(dst_name_r);
1533
0
    } /* end if */
1534
1535
0
done:
1536
    /* Cleanup */
1537
0
    if (orig_name)
1538
0
        H5MM_xfree(orig_name);
1539
1540
    /* If udata_out.lnk was copied, free any memory allocated
1541
     * In this special case, the H5L__move_dest_cb callback resets the name
1542
     * so H5O_msg_free shouldn't try to free it
1543
     */
1544
0
    if (link_copied)
1545
0
        H5O_msg_free(H5O_LINK_ID, udata_out.lnk);
1546
1547
    /* Indicate that this callback didn't take ownership of the group *
1548
     * location for the object */
1549
0
    *own_loc = H5G_OWN_NONE;
1550
1551
0
    FUNC_LEAVE_NOAPI(ret_value)
1552
0
} /* end H5L__move_cb() */
1553
1554
/*-------------------------------------------------------------------------
1555
 * Function:  H5L__move
1556
 *
1557
 * Purpose: Atomically move or copy a link.
1558
 *
1559
 *              Creates a copy of a link in a new destination with a new name.
1560
 *              SRC_LOC and SRC_NAME together define the link's original
1561
 *              location, while DST_LOC and DST_NAME together define its
1562
 *              final location.
1563
 *
1564
 *              If copy_flag is false, the original link is removed
1565
 *              (effectively moving the link).
1566
 *
1567
 * Return:  Non-negative on success/Negative on failure
1568
 *
1569
 *-------------------------------------------------------------------------
1570
 */
1571
herr_t
1572
H5L__move(const H5G_loc_t *src_loc, const char *src_name, const H5G_loc_t *dst_loc, const char *dst_name,
1573
          bool copy_flag, hid_t lcpl_id)
1574
0
{
1575
0
    unsigned        dst_target_flags = H5G_TARGET_NORMAL;
1576
0
    H5T_cset_t      char_encoding    = H5F_DEFAULT_CSET; /* Character encoding for link */
1577
0
    H5P_genplist_t *lc_plist;                            /* Link creation property list */
1578
0
    H5L_trav_mv_t   udata;                               /* User data for traversal */
1579
0
    herr_t          ret_value = SUCCEED;                 /* Return value */
1580
1581
0
    FUNC_ENTER_PACKAGE
1582
1583
    /* Sanity check */
1584
0
    assert(src_loc);
1585
0
    assert(dst_loc);
1586
0
    assert(src_name && *src_name);
1587
0
    assert(dst_name && *dst_name);
1588
1589
    /* Check for flags present in creation property list */
1590
0
    if (lcpl_id != H5P_DEFAULT) {
1591
0
        unsigned crt_intmd_group;
1592
1593
0
        if (NULL == (lc_plist = (H5P_genplist_t *)H5I_object(lcpl_id)))
1594
0
            HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property list");
1595
1596
        /* Get intermediate group creation property */
1597
0
        if (H5CX_get_intermediate_group(&crt_intmd_group) < 0)
1598
0
            HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get property value for creating missing groups");
1599
1600
        /* Set target flags for source and destination */
1601
0
        if (crt_intmd_group > 0)
1602
0
            dst_target_flags |= H5G_CRT_INTMD_GROUP;
1603
1604
        /* Get character encoding property */
1605
0
        if (H5CX_get_encoding(&char_encoding) < 0)
1606
0
            HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get property value for character encoding");
1607
0
    } /* end if */
1608
1609
    /* Set up user data */
1610
0
    udata.dst_loc          = dst_loc;
1611
0
    udata.dst_name         = dst_name;
1612
0
    udata.dst_target_flags = dst_target_flags;
1613
0
    udata.cset             = char_encoding;
1614
0
    udata.copy             = copy_flag;
1615
1616
    /* Retrieve the original # of soft / UD links that can be traversed, so
1617
     *  that the countdown can be reset after the first path is traversed.
1618
     */
1619
0
    if (H5CX_get_nlinks(&udata.orig_nlinks) < 0)
1620
0
        HGOTO_ERROR(H5E_LINK, H5E_CANTGET, FAIL, "unable to retrieve # of soft / UD links to traverse");
1621
1622
    /* Do the move */
1623
0
    if (H5G_traverse(src_loc, src_name, H5G_TARGET_MOUNT | H5G_TARGET_SLINK | H5G_TARGET_UDLINK, H5L__move_cb,
1624
0
                     &udata) < 0)
1625
0
        HGOTO_ERROR(H5E_LINK, H5E_NOTFOUND, FAIL, "unable to find link");
1626
1627
0
done:
1628
0
    FUNC_LEAVE_NOAPI(ret_value)
1629
0
} /* end H5L__move() */
1630
1631
/*-------------------------------------------------------------------------
1632
 * Function:  H5L__exists_final_cb
1633
 *
1634
 * Purpose: Callback for checking whether a link exists, as the final
1635
 *              component of a path
1636
 *
1637
 * Return:  Non-negative on success/Negative on failure
1638
 *
1639
 *-------------------------------------------------------------------------
1640
 */
1641
static herr_t
1642
H5L__exists_final_cb(H5G_loc_t H5_ATTR_UNUSED *grp_loc /*in*/, const char H5_ATTR_UNUSED *name,
1643
                     const H5O_link_t *lnk, H5G_loc_t H5_ATTR_UNUSED *obj_loc, void *_udata /*in,out*/,
1644
                     H5G_own_loc_t *own_loc /*out*/)
1645
0
{
1646
0
    H5L_trav_le_t *udata = (H5L_trav_le_t *)_udata; /* User data passed in */
1647
1648
0
    FUNC_ENTER_PACKAGE_NOERR
1649
1650
    /* Check if the name in this group resolved to a valid link */
1651
0
    *udata->exists = (bool)(lnk != NULL);
1652
1653
    /* Indicate that this callback didn't take ownership of the group *
1654
     * location for the object */
1655
0
    *own_loc = H5G_OWN_NONE;
1656
1657
0
    FUNC_LEAVE_NOAPI(SUCCEED)
1658
0
} /* end H5L__exists_final_cb() */
1659
1660
/*-------------------------------------------------------------------------
1661
 * Function:  H5L__exists_inter_cb
1662
 *
1663
 * Purpose: Callback for checking whether a link exists, as an intermediate
1664
 *              component of a path
1665
 *
1666
 * Return:  Non-negative on success/Negative on failure
1667
 *
1668
 *-------------------------------------------------------------------------
1669
 */
1670
static herr_t
1671
H5L__exists_inter_cb(H5G_loc_t H5_ATTR_UNUSED *grp_loc /*in*/, const char H5_ATTR_UNUSED *name,
1672
                     const H5O_link_t *lnk, H5G_loc_t *obj_loc, void *_udata /*in,out*/,
1673
                     H5G_own_loc_t *own_loc /*out*/)
1674
0
{
1675
0
    H5L_trav_le_t *udata     = (H5L_trav_le_t *)_udata; /* User data passed in */
1676
0
    herr_t         ret_value = SUCCEED;                 /* Return value */
1677
1678
0
    FUNC_ENTER_PACKAGE
1679
1680
    /* Check if the name in this group resolved to a valid link */
1681
0
    if (lnk != NULL) {
1682
        /* Check for more components to the path */
1683
0
        if (udata->sep) {
1684
0
            H5G_traverse_t cb_func; /* Callback function for traversal */
1685
0
            char          *next;    /* Pointer to next component name */
1686
1687
            /* Look for another separator */
1688
0
            next = udata->sep;
1689
0
            if (NULL == (udata->sep = strchr(udata->sep, '/')))
1690
0
                cb_func = H5L__exists_final_cb;
1691
0
            else {
1692
                /* Chew through adjacent separators, if present */
1693
0
                do {
1694
0
                    *udata->sep = '\0';
1695
0
                    udata->sep++;
1696
0
                } while ('/' == *udata->sep);
1697
0
                cb_func = H5L__exists_inter_cb;
1698
0
            } /* end else */
1699
0
            if (H5G_traverse(obj_loc, next, H5G_TARGET_SLINK | H5G_TARGET_UDLINK, cb_func, udata) < 0)
1700
0
                HGOTO_ERROR(H5E_LINK, H5E_CANTGET, FAIL, "can't determine if link exists");
1701
0
        } /* end if */
1702
0
        else
1703
0
            *udata->exists = true;
1704
0
    } /* end if */
1705
0
    else
1706
0
        *udata->exists = false;
1707
1708
    /* Indicate that this callback didn't take ownership of the group *
1709
     * location for the object */
1710
0
    *own_loc = H5G_OWN_NONE;
1711
1712
0
done:
1713
0
    FUNC_LEAVE_NOAPI(ret_value)
1714
0
} /* end H5L__exists_inter_cb() */
1715
1716
/*-------------------------------------------------------------------------
1717
 * Function:  H5L_exists_tolerant
1718
 *
1719
 * Purpose: Returns whether a link exists in a group
1720
 *
1721
 * Note:  Same as H5L__exists, except that missing links are reported
1722
 *    as 'false' instead of causing failures
1723
 *
1724
 * Return:  Non-negative (true/false) on success/Negative on failure
1725
 *
1726
 *-------------------------------------------------------------------------
1727
 */
1728
herr_t
1729
H5L_exists_tolerant(const H5G_loc_t *loc, const char *name, bool *exists)
1730
0
{
1731
0
    H5L_trav_le_t  udata;               /* User data for traversal */
1732
0
    H5G_traverse_t cb_func;             /* Callback function for traversal */
1733
0
    char          *name_copy = NULL;    /* Duplicate of name */
1734
0
    char          *name_trav;           /* Name to traverse */
1735
0
    herr_t         ret_value = SUCCEED; /* Return value */
1736
1737
0
    FUNC_ENTER_NOAPI(FAIL)
1738
1739
    /* Sanity checks */
1740
0
    assert(loc);
1741
0
    assert(name);
1742
0
    assert(exists);
1743
1744
    /* Copy the name and skip leading '/'s */
1745
0
    name_trav = name_copy = H5MM_strdup(name);
1746
0
    while ('/' == *name_trav)
1747
0
        name_trav++;
1748
1749
    /* A path of "/" will always exist in a file */
1750
0
    if ('\0' == *name_trav)
1751
0
        *exists = true;
1752
0
    else {
1753
        /* Set up user data & correct callback */
1754
0
        udata.exists = exists;
1755
0
        if (NULL == (udata.sep = strchr(name_trav, '/')))
1756
0
            cb_func = H5L__exists_final_cb;
1757
0
        else {
1758
            /* Chew through adjacent separators, if present */
1759
0
            do {
1760
0
                *udata.sep = '\0';
1761
0
                udata.sep++;
1762
0
            } while ('/' == *udata.sep);
1763
0
            cb_func = H5L__exists_inter_cb;
1764
0
        } /* end else */
1765
1766
        /* Traverse the group hierarchy to locate the link to check */
1767
0
        if (H5G_traverse(loc, name_trav, H5G_TARGET_SLINK | H5G_TARGET_UDLINK, cb_func, &udata) < 0)
1768
0
            HGOTO_ERROR(H5E_LINK, H5E_CANTGET, FAIL, "can't determine if link exists");
1769
0
    }
1770
1771
0
done:
1772
    /* Release duplicated string */
1773
0
    H5MM_xfree(name_copy);
1774
1775
0
    FUNC_LEAVE_NOAPI(ret_value)
1776
0
} /* H5L_exists_tolerant() */
1777
1778
/*-------------------------------------------------------------------------
1779
 * Function:  H5L__exists
1780
 *
1781
 * Purpose: Returns whether a link exists in a group
1782
 *
1783
 * Note:  Same as H5L_exists_tolerant, except that missing links are reported
1784
 *    as failures
1785
 *
1786
 * Return:  Non-negative on success, with *exists set/Negative on failure
1787
 *
1788
 *-------------------------------------------------------------------------
1789
 */
1790
herr_t
1791
H5L__exists(const H5G_loc_t *loc, const char *name, bool *exists)
1792
0
{
1793
0
    H5L_trav_le_t udata;               /* User data for traversal */
1794
0
    herr_t        ret_value = SUCCEED; /* Return value */
1795
1796
0
    FUNC_ENTER_PACKAGE
1797
1798
    /* Sanity checks */
1799
0
    assert(loc);
1800
0
    assert(name);
1801
0
    assert(exists);
1802
1803
    /* A path of "/" will always exist in a file */
1804
0
    if (0 == strcmp(name, "/"))
1805
0
        *exists = true;
1806
0
    else {
1807
        /* Traverse the group hierarchy to locate the object to get info about */
1808
0
        udata.exists = exists;
1809
0
        if (H5G_traverse(loc, name, H5G_TARGET_SLINK | H5G_TARGET_UDLINK, H5L__exists_final_cb, &udata) < 0)
1810
0
            HGOTO_ERROR(H5E_LINK, H5E_EXISTS, FAIL, "link doesn't exist");
1811
0
    }
1812
1813
0
done:
1814
0
    FUNC_LEAVE_NOAPI(ret_value)
1815
0
} /* H5L__exists() */
1816
1817
/*-------------------------------------------------------------------------
1818
 * Function:  H5L__get_info_cb
1819
 *
1820
 * Purpose: Callback for retrieving a link's metadata
1821
 *
1822
 * Return:  Non-negative on success/Negative on failure
1823
 *
1824
 *-------------------------------------------------------------------------
1825
 */
1826
static herr_t
1827
H5L__get_info_cb(H5G_loc_t *grp_loc /*in*/, const char H5_ATTR_UNUSED *name, const H5O_link_t *lnk,
1828
                 H5G_loc_t H5_ATTR_UNUSED *obj_loc, void *_udata /*in,out*/, H5G_own_loc_t *own_loc /*out*/)
1829
0
{
1830
0
    H5L_trav_gi_t *udata     = (H5L_trav_gi_t *)_udata; /* User data passed in */
1831
0
    herr_t         ret_value = SUCCEED;                 /* Return value */
1832
1833
0
    FUNC_ENTER_PACKAGE
1834
1835
    /* Check if the name in this group resolved to a valid link */
1836
0
    if (lnk == NULL)
1837
0
        HGOTO_ERROR(H5E_LINK, H5E_NOTFOUND, FAIL, "name doesn't exist");
1838
1839
    /* Get information from the link */
1840
0
    if (H5G_link_to_info(grp_loc->oloc, lnk, udata->linfo) < 0)
1841
0
        HGOTO_ERROR(H5E_LINK, H5E_CANTGET, FAIL, "can't get link info");
1842
1843
0
done:
1844
    /* Indicate that this callback didn't take ownership of the group *
1845
     * location for the object */
1846
0
    *own_loc = H5G_OWN_NONE;
1847
1848
0
    FUNC_LEAVE_NOAPI(ret_value)
1849
0
} /* end H5L__get_info_cb() */
1850
1851
/*-------------------------------------------------------------------------
1852
 * Function:    H5L_get_info
1853
 *
1854
 * Purpose:     Returns metadata about a link.
1855
 *
1856
 * Return:      SUCCEED/FAIL
1857
 *
1858
 *-------------------------------------------------------------------------
1859
 */
1860
herr_t
1861
H5L_get_info(const H5G_loc_t *loc, const char *name, H5L_info2_t *linfo /*out*/)
1862
0
{
1863
0
    H5L_trav_gi_t udata;               /* User data for callback */
1864
0
    herr_t        ret_value = SUCCEED; /* Return value */
1865
1866
0
    FUNC_ENTER_NOAPI(FAIL)
1867
1868
0
    udata.linfo = linfo;
1869
1870
    /* Traverse the group hierarchy to locate the object to get info about */
1871
0
    if (H5G_traverse(loc, name, H5G_TARGET_SLINK | H5G_TARGET_UDLINK, H5L__get_info_cb, &udata) < 0)
1872
0
        HGOTO_ERROR(H5E_LINK, H5E_EXISTS, FAIL, "name doesn't exist");
1873
1874
0
done:
1875
0
    FUNC_LEAVE_NOAPI(ret_value)
1876
0
} /* H5L_get_info() */
1877
1878
/*-------------------------------------------------------------------------
1879
 * Function:  H5L__get_info_by_idx_cb
1880
 *
1881
 * Purpose: Callback for retrieving a link's metadata according to an
1882
 *              index's order.
1883
 *
1884
 * Return:  Non-negative on success/Negative on failure
1885
 *
1886
 *-------------------------------------------------------------------------
1887
 */
1888
static herr_t
1889
H5L__get_info_by_idx_cb(H5G_loc_t H5_ATTR_UNUSED *grp_loc /*in*/, const char H5_ATTR_UNUSED *name,
1890
                        const H5O_link_t H5_ATTR_UNUSED *lnk, H5G_loc_t *obj_loc, void *_udata /*in,out*/,
1891
                        H5G_own_loc_t *own_loc /*out*/)
1892
0
{
1893
0
    H5L_trav_gibi_t *udata = (H5L_trav_gibi_t *)_udata; /* User data passed in */
1894
0
    H5O_link_t       fnd_lnk;                           /* Link within group */
1895
0
    bool             lnk_copied = false;                /* Whether the link was copied */
1896
0
    herr_t           ret_value  = SUCCEED;              /* Return value */
1897
1898
0
    FUNC_ENTER_PACKAGE
1899
1900
    /* Check if the name of the group resolved to a valid object */
1901
0
    if (obj_loc == NULL)
1902
0
        HGOTO_ERROR(H5E_LINK, H5E_NOTFOUND, FAIL, "group doesn't exist");
1903
1904
    /* Query link */
1905
0
    if (H5G_obj_lookup_by_idx(obj_loc->oloc, udata->idx_type, udata->order, udata->n, &fnd_lnk) < 0)
1906
0
        HGOTO_ERROR(H5E_LINK, H5E_NOTFOUND, FAIL, "link not found");
1907
0
    lnk_copied = true;
1908
1909
    /* Get information from the link */
1910
0
    if (H5G_link_to_info(obj_loc->oloc, &fnd_lnk, udata->linfo) < 0)
1911
0
        HGOTO_ERROR(H5E_LINK, H5E_CANTGET, FAIL, "can't get link info");
1912
1913
0
done:
1914
    /* Reset the link information, if we have a copy */
1915
0
    if (lnk_copied)
1916
0
        H5O_msg_reset(H5O_LINK_ID, &fnd_lnk);
1917
1918
    /* Indicate that this callback didn't take ownership of the group *
1919
     * location for the object */
1920
0
    *own_loc = H5G_OWN_NONE;
1921
1922
0
    FUNC_LEAVE_NOAPI(ret_value)
1923
0
} /* end H5L__get_info_by_idx_cb() */
1924
1925
/*-------------------------------------------------------------------------
1926
 * Function:    H5L__get_info_by_idx
1927
 *
1928
 * Purpose:     Internal routine to retrieve link info according to an
1929
 *              index's order.
1930
 *
1931
 * Return:      SUCCEED/FAIL
1932
 *
1933
 *-------------------------------------------------------------------------
1934
 */
1935
herr_t
1936
H5L__get_info_by_idx(const H5G_loc_t *loc, const char *name, H5_index_t idx_type, H5_iter_order_t order,
1937
                     hsize_t n, H5L_info2_t *linfo /*out*/)
1938
0
{
1939
0
    H5L_trav_gibi_t udata;               /* User data for callback */
1940
0
    herr_t          ret_value = SUCCEED; /* Return value */
1941
1942
0
    FUNC_ENTER_PACKAGE
1943
1944
    /* Check arguments */
1945
0
    assert(loc);
1946
0
    assert(name && *name);
1947
0
    assert(linfo);
1948
1949
    /* Set up user data for callback */
1950
0
    udata.idx_type = idx_type;
1951
0
    udata.order    = order;
1952
0
    udata.n        = n;
1953
0
    udata.linfo    = linfo;
1954
1955
    /* Traverse the group hierarchy to locate the object to get info about */
1956
0
    if (H5G_traverse(loc, name, H5G_TARGET_SLINK | H5G_TARGET_UDLINK, H5L__get_info_by_idx_cb, &udata) < 0)
1957
0
        HGOTO_ERROR(H5E_LINK, H5E_CANTGET, FAIL, "unable to get link info");
1958
1959
0
done:
1960
0
    FUNC_LEAVE_NOAPI(ret_value)
1961
0
} /* end H5L__get_info_by_idx() */
1962
1963
/*-------------------------------------------------------------------------
1964
 * Function:  H5L__get_name_by_idx_cb
1965
 *
1966
 * Purpose: Callback for retrieving a link's name according to an
1967
 *              index's order.
1968
 *
1969
 * Return:  Non-negative on success/Negative on failure
1970
 *
1971
 *-------------------------------------------------------------------------
1972
 */
1973
static herr_t
1974
H5L__get_name_by_idx_cb(H5G_loc_t H5_ATTR_UNUSED *grp_loc /*in*/, const char H5_ATTR_UNUSED *name,
1975
                        const H5O_link_t H5_ATTR_UNUSED *lnk, H5G_loc_t *obj_loc, void *_udata /*in,out*/,
1976
                        H5G_own_loc_t *own_loc /*out*/)
1977
0
{
1978
0
    H5L_trav_gnbi_t *udata     = (H5L_trav_gnbi_t *)_udata; /* User data passed in */
1979
0
    herr_t           ret_value = SUCCEED;                   /* Return value */
1980
1981
0
    FUNC_ENTER_PACKAGE
1982
1983
    /* Check if the name of the group resolved to a valid object */
1984
0
    if (obj_loc == NULL)
1985
0
        HGOTO_ERROR(H5E_LINK, H5E_NOTFOUND, FAIL, "group doesn't exist");
1986
1987
    /* Query link */
1988
0
    if (H5G_obj_get_name_by_idx(obj_loc->oloc, udata->idx_type, udata->order, udata->n, udata->name,
1989
0
                                udata->size, &udata->name_len) < 0)
1990
0
        HGOTO_ERROR(H5E_LINK, H5E_NOTFOUND, FAIL, "link not found");
1991
1992
0
done:
1993
    /* Indicate that this callback didn't take ownership of the group *
1994
     * location for the object */
1995
0
    *own_loc = H5G_OWN_NONE;
1996
1997
0
    FUNC_LEAVE_NOAPI(ret_value)
1998
0
} /* end H5L__get_name_by_idx_cb() */
1999
2000
/*-------------------------------------------------------------------------
2001
 * Function:    H5L__get_name_by_idx
2002
 *
2003
 * Purpose:     Internal routine to retrieve link name according to an
2004
 *              index's order.
2005
 *
2006
 * Return:      SUCCEED/FAIL
2007
 *
2008
 *-------------------------------------------------------------------------
2009
 */
2010
herr_t
2011
H5L__get_name_by_idx(const H5G_loc_t *loc, const char *group_name, H5_index_t idx_type, H5_iter_order_t order,
2012
                     hsize_t n, char *name /*out*/, size_t size, size_t *link_name_len)
2013
0
{
2014
0
    H5L_trav_gnbi_t udata;               /* User data for callback */
2015
0
    herr_t          ret_value = SUCCEED; /* Return value */
2016
2017
0
    FUNC_ENTER_PACKAGE
2018
2019
    /* Check arguments */
2020
0
    assert(loc);
2021
0
    assert(group_name && *group_name);
2022
0
    assert(link_name_len);
2023
2024
    /* Set up user data for callback */
2025
0
    udata.idx_type = idx_type;
2026
0
    udata.order    = order;
2027
0
    udata.n        = n;
2028
0
    udata.name     = name;
2029
0
    udata.size     = size;
2030
0
    udata.name_len = 0;
2031
2032
    /* Traverse the group hierarchy to locate the link to get name of */
2033
0
    if (H5G_traverse(loc, group_name, H5G_TARGET_SLINK | H5G_TARGET_UDLINK, H5L__get_name_by_idx_cb, &udata) <
2034
0
        0)
2035
0
        HGOTO_ERROR(H5E_LINK, H5E_CANTGET, FAIL, "can't get name");
2036
2037
    /* Set the return value */
2038
0
    *link_name_len = udata.name_len;
2039
2040
0
done:
2041
0
    FUNC_LEAVE_NOAPI(ret_value)
2042
0
} /* end H5L__get_name_by_idx() */
2043
2044
/*-------------------------------------------------------------------------
2045
 * Function:  H5L__link_copy_file
2046
 *
2047
 * Purpose:     Copy a link and the object it points to from one file to
2048
 *              another.
2049
 *
2050
 * Return:  Non-negative on success/Negative on failure
2051
 *
2052
 *-------------------------------------------------------------------------
2053
 */
2054
herr_t
2055
H5L__link_copy_file(H5F_t *dst_file, const H5O_link_t *_src_lnk, const H5O_loc_t *src_oloc,
2056
                    H5O_link_t *dst_lnk, H5O_copy_t *cpy_info)
2057
0
{
2058
0
    H5O_link_t        tmp_src_lnk;                   /* Temporary copy of src link, when needed */
2059
0
    const H5O_link_t *src_lnk            = _src_lnk; /* Source link */
2060
0
    bool              dst_lnk_init       = false;    /* Whether the destination link is initialized */
2061
0
    bool              expanded_link_open = false;    /* Whether the target location has been opened */
2062
0
    H5G_loc_t         tmp_src_loc;                   /* Group location holding target object */
2063
0
    H5G_name_t        tmp_src_path;                  /* Path for target object */
2064
0
    H5O_loc_t         tmp_src_oloc;                  /* Object location for target object */
2065
0
    herr_t            ret_value = SUCCEED;           /* Return value */
2066
2067
0
    FUNC_ENTER_PACKAGE
2068
2069
    /* check arguments */
2070
0
    assert(dst_file);
2071
0
    assert(src_lnk);
2072
0
    assert(dst_lnk);
2073
0
    assert(cpy_info);
2074
2075
    /* Expand soft or external link, if requested */
2076
0
    if ((H5L_TYPE_SOFT == src_lnk->type && cpy_info->expand_soft_link) ||
2077
0
        (H5L_TYPE_EXTERNAL == src_lnk->type && cpy_info->expand_ext_link)) {
2078
0
        H5G_loc_t  lnk_grp_loc;        /* Group location holding link */
2079
0
        H5G_name_t lnk_grp_path;       /* Path for link */
2080
0
        bool       tar_exists = false; /* Whether the target object exists */
2081
2082
        /* Set up group location for link */
2083
0
        H5G_name_reset(&lnk_grp_path);
2084
0
        lnk_grp_loc.path = &lnk_grp_path;
2085
0
        H5_WARN_CAST_AWAY_CONST_OFF
2086
0
        lnk_grp_loc.oloc = (H5O_loc_t *)src_oloc;
2087
0
        H5_WARN_CAST_AWAY_CONST_ON
2088
2089
        /* Check if the target object exists */
2090
0
        if (H5G_loc_exists(&lnk_grp_loc, src_lnk->name, &tar_exists) < 0)
2091
0
            HGOTO_ERROR(H5E_LINK, H5E_CANTCOPY, FAIL, "unable to check if target object exists");
2092
2093
0
        if (tar_exists) {
2094
            /* Make a temporary copy of the link, so that it will not change the
2095
             * info in the cache when we change it to a hard link */
2096
0
            if (NULL == H5O_msg_copy(H5O_LINK_ID, src_lnk, &tmp_src_lnk))
2097
0
                HGOTO_ERROR(H5E_LINK, H5E_CANTCOPY, FAIL, "unable to copy message");
2098
2099
            /* Set up group location for target object.  Let H5G_traverse expand
2100
             * the link. */
2101
0
            tmp_src_loc.path = &tmp_src_path;
2102
0
            tmp_src_loc.oloc = &tmp_src_oloc;
2103
0
            if (H5G_loc_reset(&tmp_src_loc) < 0)
2104
0
                HGOTO_ERROR(H5E_LINK, H5E_CANTCOPY, FAIL, "unable to reset location");
2105
2106
            /* Find the target object */
2107
0
            if (H5G_loc_find(&lnk_grp_loc, src_lnk->name, &tmp_src_loc) < 0)
2108
0
                HGOTO_ERROR(H5E_LINK, H5E_CANTCOPY, FAIL, "unable to find target object");
2109
0
            expanded_link_open = true;
2110
2111
            /* Convert symbolic link to hard link */
2112
0
            if (tmp_src_lnk.type == H5L_TYPE_SOFT)
2113
0
                tmp_src_lnk.u.soft.name = (char *)H5MM_xfree(tmp_src_lnk.u.soft.name);
2114
0
            else if (tmp_src_lnk.u.ud.size > 0)
2115
0
                tmp_src_lnk.u.ud.udata = H5MM_xfree(tmp_src_lnk.u.ud.udata);
2116
0
            tmp_src_lnk.type        = H5L_TYPE_HARD;
2117
0
            tmp_src_lnk.u.hard.addr = tmp_src_oloc.addr;
2118
0
            src_lnk                 = &tmp_src_lnk;
2119
0
        } /* end if */
2120
0
    }     /* end if */
2121
2122
    /* Copy src link information to dst link information */
2123
0
    if (NULL == H5O_msg_copy(H5O_LINK_ID, src_lnk, dst_lnk))
2124
0
        HGOTO_ERROR(H5E_LINK, H5E_CANTCOPY, FAIL, "unable to copy message");
2125
0
    dst_lnk_init = true;
2126
2127
    /* Check if object in source group is a hard link & copy it */
2128
0
    if (H5L_TYPE_HARD == src_lnk->type) {
2129
0
        H5O_loc_t new_dst_oloc; /* Copied object location in destination */
2130
2131
        /* Set up copied object location to fill in */
2132
0
        H5O_loc_reset(&new_dst_oloc);
2133
0
        new_dst_oloc.file = dst_file;
2134
2135
0
        if (!expanded_link_open) {
2136
            /* Build temporary object location for source */
2137
0
            H5O_loc_reset(&tmp_src_oloc);
2138
0
            tmp_src_oloc.file = src_oloc->file;
2139
0
            tmp_src_oloc.addr = src_lnk->u.hard.addr;
2140
0
        } /* end if */
2141
0
        assert(H5_addr_defined(tmp_src_oloc.addr));
2142
2143
        /* Copy the shared object from source to destination */
2144
        /* Don't care about obj_type or udata because those are only important
2145
         * for old style groups */
2146
0
        if (H5O_copy_header_map(&tmp_src_oloc, &new_dst_oloc, cpy_info, true, NULL, NULL) < 0)
2147
0
            HGOTO_ERROR(H5E_LINK, H5E_CANTCOPY, FAIL, "unable to copy object");
2148
2149
        /* Copy new destination object's information for eventual insertion */
2150
0
        dst_lnk->u.hard.addr = new_dst_oloc.addr;
2151
0
    } /* end if */
2152
2153
0
done:
2154
    /* Check if we used a temporary src link */
2155
0
    if (src_lnk != _src_lnk) {
2156
0
        assert(src_lnk == &tmp_src_lnk);
2157
0
        H5O_msg_reset(H5O_LINK_ID, &tmp_src_lnk);
2158
0
    } /* end if */
2159
0
    if (ret_value < 0)
2160
0
        if (dst_lnk_init)
2161
0
            H5O_msg_reset(H5O_LINK_ID, dst_lnk);
2162
    /* Check if we need to free the temp source oloc */
2163
0
    if (expanded_link_open)
2164
0
        if (H5G_loc_free(&tmp_src_loc) < 0)
2165
0
            HDONE_ERROR(H5E_LINK, H5E_CANTFREE, FAIL, "unable to free object");
2166
2167
0
    FUNC_LEAVE_NOAPI(ret_value)
2168
0
} /* end H5L__link_copy_file() */
2169
2170
/*-------------------------------------------------------------------------
2171
 * Function:    H5L_iterate
2172
 *
2173
 * Purpose:     Iterates through links in a group
2174
 *
2175
 * Return:      SUCCEED/FAIL
2176
 *
2177
 *-------------------------------------------------------------------------
2178
 */
2179
herr_t
2180
H5L_iterate(H5G_loc_t *loc, const char *group_name, H5_index_t idx_type, H5_iter_order_t order,
2181
            hsize_t *idx_p, H5L_iterate2_t op, void *op_data)
2182
0
{
2183
0
    H5G_link_iterate_t lnk_op;           /* Link operator                    */
2184
0
    hsize_t            last_lnk;         /* Index of last object looked at   */
2185
0
    hsize_t            idx;              /* Internal location to hold index  */
2186
0
    herr_t             ret_value = FAIL; /* Return value                     */
2187
2188
0
    FUNC_ENTER_NOAPI_NOINIT
2189
2190
    /* Sanity checks */
2191
0
    assert(loc);
2192
0
    assert(group_name);
2193
0
    assert(op);
2194
2195
    /* Set up iteration beginning/end info */
2196
0
    idx      = (idx_p == NULL ? 0 : *idx_p);
2197
0
    last_lnk = 0;
2198
2199
    /* Build link operator info */
2200
0
    lnk_op.op_type        = H5G_LINK_OP_NEW;
2201
0
    lnk_op.op_func.op_new = op;
2202
2203
    /* Iterate over the links */
2204
0
    if ((ret_value = H5G_iterate(loc, group_name, idx_type, order, idx, &last_lnk, &lnk_op, op_data)) < 0)
2205
0
        HGOTO_ERROR(H5E_LINK, H5E_BADITER, FAIL, "link iteration failed");
2206
2207
    /* Set the index we stopped at */
2208
0
    if (idx_p)
2209
0
        *idx_p = last_lnk;
2210
2211
0
done:
2212
0
    FUNC_LEAVE_NOAPI(ret_value)
2213
0
} /* end H5L_iterate() */
2214
2215
/*-------------------------------------------------------------------------
2216
 * Function: H5L_get_ocrt_info
2217
 *
2218
 * Purpose:  Quick and dirty routine to retrieve the link's object_creation info
2219
 *
2220
 * Return:   'ocrt_info' on success/abort on failure (shouldn't fail)
2221
 *-------------------------------------------------------------------------
2222
 */
2223
H5O_obj_create_t *
2224
H5L_get_ocrt_info(const H5L_trav_cr_t *l)
2225
0
{
2226
    /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
2227
0
    FUNC_ENTER_NOAPI_NOINIT_NOERR
2228
2229
0
    assert(l);
2230
2231
0
    FUNC_LEAVE_NOAPI(l->ocrt_info);
2232
0
} /* end H5L_get_ocrt_info() */