Coverage Report

Created: 2025-12-14 06:32

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/hdf5/src/H5Olink.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
 *
15
 * Created:             H5Olink.c
16
 *
17
 * Purpose:             Link messages
18
 *
19
 *-------------------------------------------------------------------------
20
 */
21
22
#define H5L_FRIEND     /*suppress error about including H5Lpkg    */
23
#include "H5Omodule.h" /* This source code file is part of the H5O module */
24
25
#include "H5private.h"   /* Generic Functions     */
26
#include "H5Eprivate.h"  /* Error handling        */
27
#include "H5FLprivate.h" /* Free lists                           */
28
#include "H5Iprivate.h"  /* IDs                                  */
29
#include "H5Lpkg.h"      /* Links                                */
30
#include "H5MMprivate.h" /* Memory management     */
31
#include "H5Opkg.h"      /* Object headers      */
32
33
/* PRIVATE PROTOTYPES */
34
static void *H5O__link_decode(H5F_t *f, H5O_t *open_oh, unsigned mesg_flags, unsigned *ioflags, size_t p_size,
35
                              const uint8_t *p);
36
static herr_t H5O__link_encode(H5F_t *f, bool disable_shared, size_t H5_ATTR_UNUSED p_size, uint8_t *p,
37
                               const void *_mesg);
38
static void  *H5O__link_copy(const void *_mesg, void *_dest);
39
static size_t H5O__link_size(const H5F_t *f, bool disable_shared, const void *_mesg);
40
static herr_t H5O__link_reset(void *_mesg);
41
static herr_t H5O__link_free(void *_mesg);
42
static herr_t H5O__link_pre_copy_file(H5F_t *file_src, const void *mesg_src, bool *deleted,
43
                                      const H5O_copy_t *cpy_info, void *udata);
44
static void  *H5O__link_copy_file(H5F_t *file_src, void *native_src, H5F_t *file_dst, bool *recompute_size,
45
                                  unsigned *mesg_flags, H5O_copy_t *cpy_info, void *udata);
46
static herr_t H5O__link_post_copy_file(const H5O_loc_t *src_oloc, const void *mesg_src, H5O_loc_t *dst_oloc,
47
                                       void *mesg_dst, unsigned *mesg_flags, H5O_copy_t *cpy_info);
48
static herr_t H5O__link_debug(H5F_t *f, const void *_mesg, FILE *stream, int indent, int fwidth);
49
50
/* This message derives from H5O message class */
51
const H5O_msg_class_t H5O_MSG_LINK[1] = {{
52
    H5O_LINK_ID,              /*message id number             */
53
    "link",                   /*message name for debugging    */
54
    sizeof(H5O_link_t),       /*native message size           */
55
    0,                        /* messages are shareable?       */
56
    H5O__link_decode,         /*decode message                */
57
    H5O__link_encode,         /*encode message                */
58
    H5O__link_copy,           /*copy the native value         */
59
    H5O__link_size,           /*size of symbol table entry    */
60
    H5O__link_reset,          /* reset method     */
61
    H5O__link_free,           /* free method      */
62
    H5O_link_delete,          /* file delete method   */
63
    NULL,                     /* link method      */
64
    NULL,                     /*set share method    */
65
    NULL,                     /*can share method    */
66
    H5O__link_pre_copy_file,  /* pre copy native value to file */
67
    H5O__link_copy_file,      /* copy native value to file    */
68
    H5O__link_post_copy_file, /* post copy native value to file    */
69
    NULL,                     /* get creation index   */
70
    NULL,                     /* set creation index   */
71
    H5O__link_debug           /*debug the message             */
72
}};
73
74
/* Current version of link information */
75
39
#define H5O_LINK_VERSION 1
76
77
/* Flags for link flag encoding */
78
78
#define H5O_LINK_NAME_SIZE       0x03 /* 2-bit field for size of name length */
79
78
#define H5O_LINK_STORE_CORDER    0x04 /* Whether to store creation index */
80
78
#define H5O_LINK_STORE_LINK_TYPE 0x08 /* Whether to store non-default link type */
81
78
#define H5O_LINK_STORE_NAME_CSET 0x10 /* Whether to store non-default name character set */
82
#define H5O_LINK_ALL_FLAGS                                                                                   \
83
39
    (H5O_LINK_NAME_SIZE | H5O_LINK_STORE_CORDER | H5O_LINK_STORE_LINK_TYPE | H5O_LINK_STORE_NAME_CSET)
84
85
/* Individual definitions of name size values */
86
0
#define H5O_LINK_NAME_1 0x00 /* Use 1-byte value for name length */
87
0
#define H5O_LINK_NAME_2 0x01 /* Use 2-byte value for name length */
88
0
#define H5O_LINK_NAME_4 0x02 /* Use 4-byte value for name length */
89
0
#define H5O_LINK_NAME_8 0x03 /* Use 8-byte value for name length */
90
91
/* Declare a free list to manage the H5O_link_t struct */
92
H5FL_DEFINE_STATIC(H5O_link_t);
93
94
/*-------------------------------------------------------------------------
95
 * Function:    H5O__link_decode
96
 *
97
 * Purpose:     Decode a message and return a pointer to
98
 *              a newly allocated one.
99
 *
100
 * Return:      Success:    Pointer to new message in native order
101
 *              Failure:    NULL
102
 *-------------------------------------------------------------------------
103
 */
104
static void *
105
H5O__link_decode(H5F_t *f, H5O_t H5_ATTR_UNUSED *open_oh, unsigned H5_ATTR_UNUSED mesg_flags,
106
                 unsigned H5_ATTR_UNUSED *ioflags, size_t p_size, const uint8_t *p)
107
39
{
108
39
    H5O_link_t    *lnk = NULL;                 /* Pointer to link message */
109
39
    size_t         len = 0;                    /* Length of a string in the message */
110
39
    unsigned char  link_flags;                 /* Flags for encoding link info */
111
39
    const uint8_t *p_end     = p + p_size - 1; /* End of the p buffer */
112
39
    void          *ret_value = NULL;
113
114
39
    FUNC_ENTER_PACKAGE
115
116
39
    assert(f);
117
39
    assert(p);
118
119
39
    if (H5_IS_BUFFER_OVERFLOW(p, 1, p_end))
120
0
        HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, NULL, "ran off end of input buffer while decoding");
121
39
    if (*p++ != H5O_LINK_VERSION)
122
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "bad version number for message");
123
124
    /* Allocate space for message */
125
39
    if (NULL == (lnk = H5FL_CALLOC(H5O_link_t)))
126
0
        HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed");
127
128
    /* Get the encoding flags for the link */
129
39
    if (H5_IS_BUFFER_OVERFLOW(p, 1, p_end))
130
0
        HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, NULL, "ran off end of input buffer while decoding");
131
39
    link_flags = *p++;
132
39
    if (link_flags & ~H5O_LINK_ALL_FLAGS)
133
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "bad flag value for message");
134
135
    /* Check for non-default link type */
136
39
    if (link_flags & H5O_LINK_STORE_LINK_TYPE) {
137
        /* Get the type of the link */
138
0
        if (H5_IS_BUFFER_OVERFLOW(p, 1, p_end))
139
0
            HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, NULL, "ran off end of input buffer while decoding");
140
0
        lnk->type = (H5L_type_t)*p++;
141
0
        if (lnk->type < H5L_TYPE_HARD || lnk->type > H5L_TYPE_MAX)
142
0
            HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "bad link type");
143
0
    }
144
39
    else
145
39
        lnk->type = H5L_TYPE_HARD;
146
147
    /* Get the link creation time from the file */
148
39
    if (link_flags & H5O_LINK_STORE_CORDER) {
149
0
        if (H5_IS_BUFFER_OVERFLOW(p, 8, p_end))
150
0
            HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, NULL, "ran off end of input buffer while decoding");
151
0
        INT64DECODE(p, lnk->corder);
152
0
        lnk->corder_valid = true;
153
0
    }
154
39
    else {
155
39
        lnk->corder       = 0;
156
39
        lnk->corder_valid = false;
157
39
    }
158
159
    /* Check for non-default name character set */
160
39
    if (link_flags & H5O_LINK_STORE_NAME_CSET) {
161
        /* Get the link name's character set */
162
0
        if (H5_IS_BUFFER_OVERFLOW(p, 1, p_end))
163
0
            HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, NULL, "ran off end of input buffer while decoding");
164
0
        lnk->cset = (H5T_cset_t)*p++;
165
0
        if (lnk->cset < H5T_CSET_ASCII || lnk->cset > H5T_CSET_UTF8)
166
0
            HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "bad cset type");
167
0
    }
168
39
    else
169
39
        lnk->cset = H5T_CSET_ASCII;
170
171
    /* Get the length of the link's name */
172
39
    switch (link_flags & H5O_LINK_NAME_SIZE) {
173
39
        case 0: /* 1 byte size */
174
39
            if (H5_IS_BUFFER_OVERFLOW(p, 1, p_end))
175
0
                HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, NULL, "ran off end of input buffer while decoding");
176
39
            len = *p++;
177
39
            break;
178
179
0
        case 1: /* 2 byte size */
180
0
            if (H5_IS_BUFFER_OVERFLOW(p, 2, p_end))
181
0
                HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, NULL, "ran off end of input buffer while decoding");
182
0
            UINT16DECODE(p, len);
183
0
            break;
184
185
0
        case 2: /* 4 byte size */
186
0
            if (H5_IS_BUFFER_OVERFLOW(p, 4, p_end))
187
0
                HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, NULL, "ran off end of input buffer while decoding");
188
0
            UINT32DECODE(p, len);
189
0
            break;
190
191
0
        case 3: /* 8 byte size */
192
0
            if (H5_IS_BUFFER_OVERFLOW(p, 8, p_end))
193
0
                HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, NULL, "ran off end of input buffer while decoding");
194
0
            UINT64DECODE(p, len);
195
0
            break;
196
197
0
        default:
198
0
            HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, NULL, "no appropriate size for name length");
199
39
    }
200
39
    if (len == 0)
201
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "invalid name length");
202
203
    /* Get the link's name */
204
39
    if (H5_IS_BUFFER_OVERFLOW(p, len, p_end))
205
0
        HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, NULL, "ran off end of input buffer while decoding");
206
39
    if (NULL == (lnk->name = (char *)H5MM_malloc(len + 1)))
207
0
        HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed");
208
39
    H5MM_memcpy(lnk->name, p, len);
209
39
    lnk->name[len] = '\0';
210
39
    p += len;
211
212
    /* Get the appropriate information for each type of link */
213
39
    switch (lnk->type) {
214
39
        case H5L_TYPE_HARD:
215
            /* Get the address of the object the link points to */
216
39
            if (H5_IS_BUFFER_OVERFLOW(p, H5F_sizeof_addr(f), p_end))
217
0
                HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, NULL, "ran off end of input buffer while decoding");
218
39
            H5F_addr_decode(f, &p, &(lnk->u.hard.addr));
219
39
            break;
220
221
0
        case H5L_TYPE_SOFT:
222
            /* Get the link value */
223
0
            if (H5_IS_BUFFER_OVERFLOW(p, 2, p_end))
224
0
                HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, NULL, "ran off end of input buffer while decoding");
225
0
            UINT16DECODE(p, len);
226
0
            if (len == 0)
227
0
                HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "invalid link length");
228
229
0
            if (H5_IS_BUFFER_OVERFLOW(p, len, p_end))
230
0
                HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, NULL, "ran off end of input buffer while decoding");
231
0
            if (NULL == (lnk->u.soft.name = (char *)H5MM_malloc((size_t)len + 1)))
232
0
                HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed");
233
0
            H5MM_memcpy(lnk->u.soft.name, p, len);
234
0
            lnk->u.soft.name[len] = '\0';
235
0
            p += len;
236
0
            break;
237
238
        /* User-defined links */
239
0
        case H5L_TYPE_EXTERNAL:
240
0
        case H5L_TYPE_ERROR:
241
0
        case H5L_TYPE_MAX:
242
0
        default:
243
0
            if (lnk->type < H5L_TYPE_UD_MIN || lnk->type > H5L_TYPE_MAX)
244
0
                HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "unknown link type");
245
246
            /* A UD link.  Get the user-supplied data */
247
0
            if (H5_IS_BUFFER_OVERFLOW(p, 2, p_end))
248
0
                HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, NULL, "ran off end of input buffer while decoding");
249
0
            UINT16DECODE(p, len);
250
0
            if (lnk->type == H5L_TYPE_EXTERNAL && len < 3)
251
0
                HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, NULL, "external link information length < 3");
252
0
            lnk->u.ud.size = len;
253
0
            if (len > 0) {
254
0
                if (H5_IS_BUFFER_OVERFLOW(p, len, p_end))
255
0
                    HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, NULL, "ran off end of input buffer while decoding");
256
0
                if (NULL == (lnk->u.ud.udata = H5MM_malloc((size_t)len)))
257
0
                    HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed");
258
0
                H5MM_memcpy(lnk->u.ud.udata, p, len);
259
0
                p += len;
260
0
            }
261
0
            else
262
0
                lnk->u.ud.udata = NULL;
263
39
    }
264
265
    /* Set return value */
266
39
    ret_value = lnk;
267
268
39
done:
269
39
    if (!ret_value && lnk) {
270
0
        H5MM_xfree(lnk->name);
271
0
        if (lnk->type == H5L_TYPE_SOFT && lnk->u.soft.name != NULL)
272
0
            H5MM_xfree(lnk->u.soft.name);
273
0
        if (lnk->type >= H5L_TYPE_UD_MIN && lnk->u.ud.size > 0 && lnk->u.ud.udata != NULL)
274
0
            H5MM_xfree(lnk->u.ud.udata);
275
0
        H5FL_FREE(H5O_link_t, lnk);
276
0
    }
277
278
39
    FUNC_LEAVE_NOAPI(ret_value)
279
39
} /* end H5O__link_decode() */
280
281
/*-------------------------------------------------------------------------
282
 * Function:    H5O__link_encode
283
 *
284
 * Purpose:     Encodes a link message.
285
 *
286
 * Return:      Non-negative on success/Negative on failure
287
 *
288
 *-------------------------------------------------------------------------
289
 */
290
static herr_t
291
H5O__link_encode(H5F_t *f, bool H5_ATTR_UNUSED disable_shared, size_t H5_ATTR_UNUSED p_size, uint8_t *p,
292
                 const void *_mesg)
293
0
{
294
0
    const H5O_link_t *lnk = (const H5O_link_t *)_mesg;
295
0
    uint64_t          len;        /* Length of a string in the message */
296
0
    unsigned char     link_flags; /* Flags for encoding link info */
297
298
0
    FUNC_ENTER_PACKAGE_NOERR
299
300
    /* check args */
301
0
    assert(f);
302
0
    assert(p);
303
0
    assert(lnk);
304
305
    /* Get length of link's name */
306
0
    len = (uint64_t)strlen(lnk->name);
307
0
    assert(len > 0);
308
309
    /* encode */
310
0
    *p++ = H5O_LINK_VERSION;
311
312
    /* The encoding flags for the link */
313
0
    if (len > 4294967295)
314
0
        link_flags = H5O_LINK_NAME_8;
315
0
    else if (len > 65535)
316
0
        link_flags = H5O_LINK_NAME_4;
317
0
    else if (len > 255)
318
0
        link_flags = H5O_LINK_NAME_2;
319
0
    else
320
0
        link_flags = H5O_LINK_NAME_1;
321
0
    link_flags = (unsigned char)(link_flags | (lnk->corder_valid ? H5O_LINK_STORE_CORDER : 0));
322
0
    link_flags = (unsigned char)(link_flags | ((lnk->type != H5L_TYPE_HARD) ? H5O_LINK_STORE_LINK_TYPE : 0));
323
0
    link_flags = (unsigned char)(link_flags | ((lnk->cset != H5T_CSET_ASCII) ? H5O_LINK_STORE_NAME_CSET : 0));
324
0
    *p++       = link_flags;
325
326
    /* Store the type of a non-default link */
327
0
    if (link_flags & H5O_LINK_STORE_LINK_TYPE)
328
0
        *p++ = (uint8_t)lnk->type;
329
330
    /* Store the link creation order in the file, if its valid */
331
0
    if (lnk->corder_valid)
332
0
        INT64ENCODE(p, lnk->corder);
333
334
    /* Store a non-default link name character set */
335
0
    if (link_flags & H5O_LINK_STORE_NAME_CSET)
336
0
        *p++ = (uint8_t)lnk->cset;
337
338
    /* Store the link name's length */
339
0
    switch (link_flags & H5O_LINK_NAME_SIZE) {
340
0
        case 0: /* 1 byte size */
341
0
            *p++ = (uint8_t)len;
342
0
            break;
343
344
0
        case 1: /* 2 byte size */
345
0
            UINT16ENCODE(p, len);
346
0
            break;
347
348
0
        case 2: /* 4 byte size */
349
0
            UINT32ENCODE(p, len);
350
0
            break;
351
352
0
        case 3: /* 8 byte size */
353
0
            UINT64ENCODE(p, len);
354
0
            break;
355
356
0
        default:
357
0
            assert(0 && "bad size for name");
358
0
    } /* end switch */
359
360
    /* Store the link's name */
361
0
    H5MM_memcpy(p, lnk->name, (size_t)len);
362
0
    p += len;
363
364
    /* Store the appropriate information for each type of link */
365
0
    switch (lnk->type) {
366
0
        case H5L_TYPE_HARD:
367
            /* Store the address of the object the link points to */
368
0
            H5F_addr_encode(f, &p, lnk->u.hard.addr);
369
0
            break;
370
371
0
        case H5L_TYPE_SOFT:
372
            /* Store the link value */
373
0
            len = (uint16_t)strlen(lnk->u.soft.name);
374
0
            assert(len > 0);
375
0
            UINT16ENCODE(p, len);
376
0
            H5MM_memcpy(p, lnk->u.soft.name, (size_t)len);
377
0
            p += len;
378
0
            break;
379
380
        /* User-defined links */
381
0
        case H5L_TYPE_EXTERNAL:
382
0
        case H5L_TYPE_ERROR:
383
0
        case H5L_TYPE_MAX:
384
0
        default:
385
0
            assert(lnk->type >= H5L_TYPE_UD_MIN && lnk->type <= H5L_TYPE_MAX);
386
387
            /* Store the user-supplied data, however long it is */
388
0
            len = (uint16_t)lnk->u.ud.size;
389
0
            UINT16ENCODE(p, len);
390
0
            if (len > 0) {
391
0
                H5MM_memcpy(p, lnk->u.ud.udata, (size_t)len);
392
0
                p += len;
393
0
            }
394
0
            break;
395
0
    } /* end switch */
396
397
0
    FUNC_LEAVE_NOAPI(SUCCEED)
398
0
} /* end H5O__link_encode() */
399
400
/*-------------------------------------------------------------------------
401
 * Function:    H5O__link_copy
402
 *
403
 * Purpose:     Copies a message from _MESG to _DEST, allocating _DEST if
404
 *              necessary.
405
 *
406
 * Return:      Success:        Ptr to _DEST
407
 *
408
 *              Failure:        NULL
409
 *
410
 *-------------------------------------------------------------------------
411
 */
412
static void *
413
H5O__link_copy(const void *_mesg, void *_dest)
414
0
{
415
0
    const H5O_link_t *lnk       = (const H5O_link_t *)_mesg;
416
0
    H5O_link_t       *dest      = (H5O_link_t *)_dest;
417
0
    void             *ret_value = NULL; /* Return value */
418
419
0
    FUNC_ENTER_PACKAGE
420
421
    /* Check args */
422
0
    assert(lnk);
423
0
    if (!dest && NULL == (dest = H5FL_MALLOC(H5O_link_t)))
424
0
        HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed");
425
426
    /* Copy static information */
427
0
    *dest = *lnk;
428
429
    /* Duplicate the link's name */
430
0
    assert(lnk->name);
431
0
    if (NULL == (dest->name = H5MM_xstrdup(lnk->name)))
432
0
        HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "can't duplicate link name");
433
434
    /* Copy other information needed for different link types */
435
0
    if (lnk->type == H5L_TYPE_SOFT) {
436
0
        if (NULL == (dest->u.soft.name = H5MM_xstrdup(lnk->u.soft.name)))
437
0
            HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "can't duplicate soft link value");
438
0
    } /* end if */
439
0
    else if (lnk->type >= H5L_TYPE_UD_MIN) {
440
0
        if (lnk->u.ud.size > 0) {
441
0
            if (NULL == (dest->u.ud.udata = H5MM_malloc(lnk->u.ud.size)))
442
0
                HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed");
443
0
            H5MM_memcpy(dest->u.ud.udata, lnk->u.ud.udata, lnk->u.ud.size);
444
0
        } /* end if */
445
0
    }     /* end if */
446
447
    /* Set return value */
448
0
    ret_value = dest;
449
450
0
done:
451
0
    if (NULL == ret_value)
452
0
        if (dest) {
453
0
            if (dest->name && dest->name != lnk->name)
454
0
                dest->name = (char *)H5MM_xfree(dest->name);
455
0
            if (NULL == _dest)
456
0
                dest = H5FL_FREE(H5O_link_t, dest);
457
0
        } /* end if */
458
459
0
    FUNC_LEAVE_NOAPI(ret_value)
460
0
} /* end H5O__link_copy() */
461
462
/*-------------------------------------------------------------------------
463
 * Function:    H5O__link_size
464
 *
465
 * Purpose:     Returns the size of the raw message in bytes not counting
466
 *              the message type or size fields, but only the data fields.
467
 *              This function doesn't take into account alignment.
468
 *
469
 * Return:      Success:        Message data size in bytes without alignment.
470
 *
471
 *              Failure:        zero
472
 *
473
 *-------------------------------------------------------------------------
474
 */
475
static size_t
476
H5O__link_size(const H5F_t *f, bool H5_ATTR_UNUSED disable_shared, const void *_mesg)
477
0
{
478
0
    const H5O_link_t *lnk = (const H5O_link_t *)_mesg;
479
0
    uint64_t          name_len;      /* Length of name */
480
0
    size_t            name_size;     /* Size of encoded name length */
481
0
    size_t            ret_value = 0; /* Return value */
482
483
0
    FUNC_ENTER_PACKAGE_NOERR
484
485
    /* Sanity check */
486
0
    HDcompile_assert(sizeof(uint64_t) >= sizeof(size_t));
487
488
    /* Get name's length */
489
0
    name_len = (uint64_t)strlen(lnk->name);
490
491
    /* Determine correct value for name size bits */
492
0
    if (name_len > 4294967295)
493
0
        name_size = 8;
494
0
    else if (name_len > 65535)
495
0
        name_size = 4;
496
0
    else if (name_len > 255)
497
0
        name_size = 2;
498
0
    else
499
0
        name_size = 1;
500
501
    /* Set return value */
502
0
    ret_value = 1 +                                            /* Version */
503
0
                1 +                                            /* Link encoding flags */
504
0
                (lnk->type != H5L_TYPE_HARD ? (size_t)1 : 0) + /* Link type */
505
0
                (lnk->corder_valid ? 8 : 0) +                  /* Creation order */
506
0
                (lnk->cset != H5T_CSET_ASCII ? 1 : 0) +        /* Character set */
507
0
                name_size +                                    /* Name length */
508
0
                name_len;                                      /* Name */
509
510
    /* Add the appropriate length for each type of link */
511
0
    switch (lnk->type) {
512
0
        case H5L_TYPE_HARD:
513
0
            ret_value += H5F_SIZEOF_ADDR(f);
514
0
            break;
515
516
0
        case H5L_TYPE_SOFT:
517
0
            ret_value += 2 +                       /* Link value length */
518
0
                         strlen(lnk->u.soft.name); /* Link value */
519
0
            break;
520
521
0
        case H5L_TYPE_ERROR:
522
0
        case H5L_TYPE_EXTERNAL:
523
0
        case H5L_TYPE_MAX:
524
0
        default: /* Default is user-defined link type */
525
0
            assert(lnk->type >= H5L_TYPE_UD_MIN);
526
0
            ret_value += 2 +             /* User-defined data size */
527
0
                         lnk->u.ud.size; /* User-defined data */
528
0
            break;
529
0
    } /* end switch */
530
531
0
    FUNC_LEAVE_NOAPI(ret_value)
532
0
} /* end H5O__link_size() */
533
534
/*-------------------------------------------------------------------------
535
 * Function:  H5O__link_reset
536
 *
537
 * Purpose: Frees resources within a message, but doesn't free
538
 *    the message itself.
539
 *
540
 * Return:  Non-negative on success/Negative on failure
541
 *
542
 *-------------------------------------------------------------------------
543
 */
544
static herr_t
545
H5O__link_reset(void *_mesg)
546
407
{
547
407
    H5O_link_t *lnk = (H5O_link_t *)_mesg;
548
549
407
    FUNC_ENTER_PACKAGE_NOERR
550
551
407
    if (lnk) {
552
        /* Free information for link (but don't free link pointer) */
553
407
        if (lnk->type == H5L_TYPE_SOFT)
554
0
            lnk->u.soft.name = (char *)H5MM_xfree(lnk->u.soft.name);
555
407
        else if (lnk->type >= H5L_TYPE_UD_MIN) {
556
0
            if (lnk->u.ud.size > 0)
557
0
                lnk->u.ud.udata = H5MM_xfree(lnk->u.ud.udata);
558
0
        } /* end if */
559
407
        lnk->name = (char *)H5MM_xfree(lnk->name);
560
407
    } /* end if */
561
562
407
    FUNC_LEAVE_NOAPI(SUCCEED)
563
407
} /* end H5O__link_reset() */
564
565
/*-------------------------------------------------------------------------
566
 * Function:  H5O__link_free
567
 *
568
 * Purpose: Frees the message contents and the message itself
569
 *
570
 * Return:  Non-negative on success/Negative on failure
571
 *
572
 *-------------------------------------------------------------------------
573
 */
574
static herr_t
575
H5O__link_free(void *_mesg)
576
27
{
577
27
    H5O_link_t *lnk = (H5O_link_t *)_mesg;
578
579
27
    FUNC_ENTER_PACKAGE_NOERR
580
581
27
    assert(lnk);
582
583
27
    lnk = H5FL_FREE(H5O_link_t, lnk);
584
585
27
    FUNC_LEAVE_NOAPI(SUCCEED)
586
27
} /* end H5O__link_free() */
587
588
/*-------------------------------------------------------------------------
589
 * Function:    H5O_link_delete
590
 *
591
 * Purpose:     Free file space referenced by message
592
 *
593
 * Return:      Non-negative on success/Negative on failure
594
 *
595
 *-------------------------------------------------------------------------
596
 */
597
herr_t
598
H5O_link_delete(H5F_t *f, H5O_t H5_ATTR_UNUSED *open_oh, void *_mesg)
599
0
{
600
0
    H5O_link_t *lnk       = (H5O_link_t *)_mesg;
601
0
    hid_t       file_id   = -1;      /* ID for the file the link is located in (passed to user callback) */
602
0
    herr_t      ret_value = SUCCEED; /* Return value */
603
604
0
    FUNC_ENTER_NOAPI(FAIL)
605
606
    /* check args */
607
0
    assert(f);
608
0
    assert(lnk);
609
610
    /* Check for adjusting the link count when the link is removed */
611
    /* Adjust the reference count of the object when a hard link is removed */
612
0
    if (lnk->type == H5L_TYPE_HARD) {
613
0
        H5O_loc_t oloc;
614
615
        /* Construct object location for object, in order to decrement it's ref count */
616
0
        H5O_loc_reset(&oloc);
617
0
        oloc.file = f;
618
0
        assert(H5_addr_defined(lnk->u.hard.addr));
619
0
        oloc.addr = lnk->u.hard.addr;
620
621
        /* Decrement the ref count for the object */
622
0
        if (H5O_link(&oloc, -1) < 0)
623
0
            HGOTO_ERROR(H5E_OHDR, H5E_CANTFREE, FAIL, "unable to decrement object link count");
624
0
    } /* end if */
625
    /* Perform the "delete" callback when a user-defined link is removed */
626
0
    else if (lnk->type >= H5L_TYPE_UD_MIN) {
627
0
        const H5L_class_t *link_class; /* User-defined link class */
628
629
        /* Get the link class for this type of link. */
630
0
        if (NULL == (link_class = H5L_find_class(lnk->type)))
631
0
            HGOTO_ERROR(H5E_OHDR, H5E_NOTREGISTERED, FAIL, "link class not registered");
632
633
        /* Check for delete callback */
634
0
        if (link_class->del_func) {
635
            /* Get a file ID for the file the link is in */
636
0
            if ((file_id = H5F_get_id(f)) < 0)
637
0
                HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "unable to get file ID");
638
639
            /* Prepare & restore library for user callback */
640
0
            H5_BEFORE_USER_CB(FAIL)
641
0
                {
642
                    /* Call user-defined link's 'delete' callback */
643
0
                    ret_value = (link_class->del_func)(lnk->name, file_id, lnk->u.ud.udata, lnk->u.ud.size);
644
0
                }
645
0
            H5_AFTER_USER_CB(FAIL)
646
0
            if (ret_value < 0)
647
0
                HGOTO_ERROR(H5E_OHDR, H5E_CALLBACK, FAIL, "link deletion callback returned failure");
648
0
        } /* end if */
649
0
    }     /* end if */
650
651
0
done:
652
    /* Release the file ID */
653
0
    if (file_id > 0 && H5I_dec_ref(file_id) < 0)
654
0
        HDONE_ERROR(H5E_OHDR, H5E_CANTCLOSEFILE, FAIL, "can't close file");
655
656
0
    FUNC_LEAVE_NOAPI(ret_value)
657
0
} /* end H5O_link_delete() */
658
659
/*-------------------------------------------------------------------------
660
 * Function:    H5O__link_pre_copy_file
661
 *
662
 * Purpose:     Perform any necessary actions before copying message between
663
 *              files for link messages.
664
 *
665
 * Return:      Success:        Non-negative
666
 *
667
 *              Failure:        Negative
668
 *
669
 *-------------------------------------------------------------------------
670
 */
671
static herr_t
672
H5O__link_pre_copy_file(H5F_t H5_ATTR_UNUSED *file_src, const void H5_ATTR_UNUSED *native_src, bool *deleted,
673
                        const H5O_copy_t *cpy_info, void H5_ATTR_UNUSED *udata)
674
0
{
675
0
    FUNC_ENTER_PACKAGE_NOERR
676
677
    /* check args */
678
0
    assert(deleted);
679
0
    assert(cpy_info);
680
681
    /* If we are performing a 'shallow hierarchy' copy, and this link won't
682
     *  be included in the final group, indicate that it should be deleted
683
     *  in the destination object header before performing any other actions
684
     *  on it.
685
     */
686
0
    if (cpy_info->max_depth >= 0 && cpy_info->curr_depth >= cpy_info->max_depth)
687
0
        *deleted = true;
688
689
0
    FUNC_LEAVE_NOAPI(SUCCEED)
690
0
} /* end H5O__link_pre_copy_file() */
691
692
/*-------------------------------------------------------------------------
693
 * Function:    H5O__link_copy_file
694
 *
695
 * Purpose:     Copies a message from _MESG to _DEST in file
696
 *
697
 * Return:      Success:        Ptr to _DEST
698
 *
699
 *              Failure:        NULL
700
 *
701
 *-------------------------------------------------------------------------
702
 */
703
static void *
704
H5O__link_copy_file(H5F_t H5_ATTR_UNUSED *file_src, void *native_src, H5F_t H5_ATTR_UNUSED *file_dst,
705
                    bool H5_ATTR_UNUSED *recompute_size, unsigned H5_ATTR_UNUSED *mesg_flags,
706
                    H5O_copy_t H5_ATTR_UNUSED *cpy_info, void H5_ATTR_UNUSED *udata)
707
0
{
708
0
    H5O_link_t *link_src  = (H5O_link_t *)native_src;
709
0
    void       *ret_value = NULL; /* Return value */
710
711
0
    FUNC_ENTER_PACKAGE
712
713
    /* check args */
714
0
    assert(link_src);
715
0
    assert(cpy_info);
716
0
    assert(cpy_info->max_depth < 0 || cpy_info->curr_depth < cpy_info->max_depth);
717
718
    /* Sanity check source link type */
719
0
    if (link_src->type > H5L_TYPE_SOFT && link_src->type < H5L_TYPE_UD_MIN)
720
0
        HGOTO_ERROR(H5E_SYM, H5E_BADVALUE, NULL, "unrecognized built-in link type");
721
722
    /* Allocate "blank" link for destination */
723
    /* (values will be filled in during 'post copy' operation) */
724
0
    if (NULL == (ret_value = H5FL_CALLOC(H5O_link_t)))
725
0
        HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed");
726
727
0
done:
728
0
    FUNC_LEAVE_NOAPI(ret_value)
729
0
} /* H5O__link_copy_file() */
730
731
/*-------------------------------------------------------------------------
732
 * Function:    H5O__link_post_copy_file
733
 *
734
 * Purpose:     Finish copying a message from between files
735
 *
736
 * Return:      Non-negative on success/Negative on failure
737
 *
738
 *-------------------------------------------------------------------------
739
 */
740
static herr_t
741
H5O__link_post_copy_file(const H5O_loc_t *src_oloc, const void *mesg_src, H5O_loc_t *dst_oloc, void *mesg_dst,
742
                         unsigned H5_ATTR_UNUSED *mesg_flags, H5O_copy_t *cpy_info)
743
0
{
744
0
    const H5O_link_t *link_src  = (const H5O_link_t *)mesg_src;
745
0
    H5O_link_t       *link_dst  = (H5O_link_t *)mesg_dst;
746
0
    herr_t            ret_value = SUCCEED; /* Return value */
747
748
0
    FUNC_ENTER_PACKAGE
749
750
    /* check args */
751
0
    assert(link_src);
752
0
    assert(dst_oloc);
753
0
    assert(H5_addr_defined(dst_oloc->addr));
754
0
    assert(dst_oloc->file);
755
0
    assert(link_dst);
756
0
    assert(cpy_info);
757
0
    assert(cpy_info->max_depth < 0 || cpy_info->curr_depth < cpy_info->max_depth);
758
759
    /* Copy the link (and the object it points to) */
760
0
    if (H5L__link_copy_file(dst_oloc->file, link_src, src_oloc, link_dst, cpy_info) < 0)
761
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, FAIL, "unable to copy link");
762
763
0
done:
764
0
    FUNC_LEAVE_NOAPI(ret_value)
765
0
} /* H5O__link_post_copy_file() */
766
767
/*-------------------------------------------------------------------------
768
 * Function:    H5O__link_debug
769
 *
770
 * Purpose:     Prints debugging info for a message.
771
 *
772
 * Return:      Non-negative on success/Negative on failure
773
 *
774
 *-------------------------------------------------------------------------
775
 */
776
static herr_t
777
H5O__link_debug(H5F_t H5_ATTR_UNUSED *f, const void *_mesg, FILE *stream, int indent, int fwidth)
778
0
{
779
0
    const H5O_link_t *lnk       = (const H5O_link_t *)_mesg;
780
0
    herr_t            ret_value = SUCCEED; /* Return value */
781
782
0
    FUNC_ENTER_PACKAGE
783
784
    /* check args */
785
0
    assert(f);
786
0
    assert(lnk);
787
0
    assert(stream);
788
0
    assert(indent >= 0);
789
0
    assert(fwidth >= 0);
790
791
0
    fprintf(stream, "%*s%-*s %s\n", indent, "", fwidth, "Link Type:",
792
0
            (lnk->type == H5L_TYPE_HARD
793
0
                 ? "Hard"
794
0
                 : (lnk->type == H5L_TYPE_SOFT
795
0
                        ? "Soft"
796
0
                        : (lnk->type == H5L_TYPE_EXTERNAL
797
0
                               ? "External"
798
0
                               : (lnk->type >= H5L_TYPE_UD_MIN ? "User-defined" : "Unknown")))));
799
800
0
    if (lnk->corder_valid)
801
0
        fprintf(stream, "%*s%-*s %" PRId64 "\n", indent, "", fwidth, "Creation Order:", lnk->corder);
802
803
0
    fprintf(stream, "%*s%-*s %s\n", indent, "", fwidth, "Link Name Character Set:",
804
0
            (lnk->cset == H5T_CSET_ASCII ? "ASCII" : (lnk->cset == H5T_CSET_UTF8 ? "UTF-8" : "Unknown")));
805
0
    fprintf(stream, "%*s%-*s '%s'\n", indent, "", fwidth, "Link Name:", lnk->name);
806
807
    /* Display link-specific information */
808
0
    switch (lnk->type) {
809
0
        case H5L_TYPE_HARD:
810
0
            fprintf(stream, "%*s%-*s %" PRIuHADDR "\n", indent, "", fwidth,
811
0
                    "Object address:", lnk->u.hard.addr);
812
0
            break;
813
814
0
        case H5L_TYPE_SOFT:
815
0
            fprintf(stream, "%*s%-*s '%s'\n", indent, "", fwidth, "Link Value:", lnk->u.soft.name);
816
0
            break;
817
818
0
        case H5L_TYPE_ERROR:
819
0
        case H5L_TYPE_EXTERNAL:
820
0
        case H5L_TYPE_MAX:
821
0
        default:
822
0
            if (lnk->type >= H5L_TYPE_UD_MIN) {
823
0
                if (lnk->type == H5L_TYPE_EXTERNAL) {
824
0
                    const char *objname =
825
0
                        (const char *)lnk->u.ud.udata + (strlen((const char *)lnk->u.ud.udata) + 1);
826
827
0
                    fprintf(stream, "%*s%-*s %s\n", indent, "", fwidth,
828
0
                            "External File Name:", (const char *)lnk->u.ud.udata);
829
0
                    fprintf(stream, "%*s%-*s %s\n", indent, "", fwidth, "External Object Name:", objname);
830
0
                } /* end if */
831
0
                else {
832
0
                    fprintf(stream, "%*s%-*s %zu\n", indent, "", fwidth,
833
0
                            "User-Defined Link Size:", lnk->u.ud.size);
834
0
                } /* end else */
835
0
            }     /* end if */
836
0
            else
837
0
                HGOTO_ERROR(H5E_SYM, H5E_BADVALUE, FAIL, "unrecognized link type");
838
0
            break;
839
0
    } /* end switch */
840
841
0
done:
842
0
    FUNC_LEAVE_NOAPI(ret_value)
843
0
} /* end H5O__link_debug() */