Coverage Report

Created: 2026-10-17 06:56

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/hdf5/src/H5Ocopy.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:     H5Ocopy.c
16
 *
17
 * Purpose:     Object copying routines.
18
 *
19
 *-------------------------------------------------------------------------
20
 */
21
22
/****************/
23
/* Module Setup */
24
/****************/
25
26
#include "H5Omodule.h" /* This source code file is part of the H5O module */
27
28
/***********/
29
/* Headers */
30
/***********/
31
#include "H5private.h"   /* Generic Functions                        */
32
#include "H5Aprivate.h"  /* Attributes                               */
33
#include "H5Eprivate.h"  /* Error handling                           */
34
#include "H5FLprivate.h" /* Free lists                               */
35
#include "H5Iprivate.h"  /* IDs                                      */
36
#include "H5FOprivate.h" /* File objects                             */
37
#include "H5Lprivate.h"  /* Links                                    */
38
#include "H5MFprivate.h" /* File memory management                   */
39
#include "H5MMprivate.h" /* Memory management                        */
40
#include "H5Opkg.h"      /* Object headers                           */
41
#include "H5Pprivate.h"  /* Property lists                           */
42
#include "H5SLprivate.h" /* Skip Lists                               */
43
44
/****************/
45
/* Local Macros */
46
/****************/
47
48
/******************/
49
/* Local Typedefs */
50
/******************/
51
52
/* Key object for skiplist of committed datatypes */
53
typedef struct H5O_copy_search_comm_dt_key_t {
54
    H5T_t        *dt;     /* Datatype */
55
    unsigned long fileno; /* File number */
56
} H5O_copy_search_comm_dt_key_t;
57
58
/* Callback struct for building a list of committed datatypes */
59
typedef struct H5O_copy_search_comm_dt_ud_t {
60
    H5SL_t    *dst_dt_list;  /* Skip list of committed datatypes */
61
    H5G_loc_t *dst_root_loc; /* Starting location for iteration */
62
    H5O_loc_t  obj_oloc;     /* Object location (for attribute iteration callback) */
63
} H5O_copy_search_comm_dt_ud_t;
64
65
/********************/
66
/* Package Typedefs */
67
/********************/
68
69
/********************/
70
/* Local Prototypes */
71
/********************/
72
73
static herr_t H5O__copy_free_addrmap_cb(void *item, void *key, void *op_data);
74
static herr_t H5O__copy_header_real(const H5O_loc_t *oloc_src, H5O_loc_t *oloc_dst /*out*/,
75
                                    H5O_copy_t *cpy_info, H5O_type_t *obj_type, void **udata);
76
static herr_t H5O__copy_header(const H5O_loc_t *oloc_src, H5O_loc_t *oloc_dst /*out*/, hid_t ocpypl_id,
77
                               hid_t lcpl_id);
78
static herr_t H5O__copy_obj(H5G_loc_t *src_loc, H5G_loc_t *dst_loc, const char *dst_name, hid_t ocpypl_id,
79
                            hid_t lcpl_id);
80
static herr_t H5O__copy_free_comm_dt_cb(void *item, void *key, void *op_data);
81
static int    H5O__copy_comm_dt_cmp(const void *dt1, const void *dt2);
82
static herr_t H5O__copy_search_comm_dt_cb(hid_t group, const char *name, const H5O_loc_t *obj_oloc,
83
                                          void *udata);
84
static htri_t H5O__copy_search_comm_dt(H5F_t *file_src, H5O_t *oh_src, H5O_loc_t *oloc_dst /*in, out*/,
85
                                       H5O_copy_t *cpy_info);
86
static herr_t H5O__copy_insert_comm_dt(H5F_t *file_src, H5O_t *oh_src, H5O_loc_t *oloc_dst,
87
                                       H5O_copy_t *cpy_info);
88
89
/*********************/
90
/* Package Variables */
91
/*********************/
92
93
/* Declare a free list to manage the H5O_addr_map_t struct */
94
H5FL_DEFINE(H5O_addr_map_t);
95
96
/* Declare a free list to manage the H5O_copy_search_comm_dt_key_t struct */
97
H5FL_DEFINE(H5O_copy_search_comm_dt_key_t);
98
99
/* Declare a free list to manage haddr_t variables */
100
H5FL_DEFINE(haddr_t);
101
102
/*****************************/
103
/* Library Private Variables */
104
/*****************************/
105
106
/*******************/
107
/* Local Variables */
108
/*******************/
109
110
/*-------------------------------------------------------------------------
111
 * Function:    H5O__copy
112
 *
113
 * Purpose:     Private version of H5Ocopy
114
 *
115
 * Return:      SUCCEED/FAIL
116
 *
117
 *-------------------------------------------------------------------------
118
 */
119
herr_t
120
H5O__copy(const H5G_loc_t *loc, const char *src_name, H5G_loc_t *dst_loc, const char *dst_name,
121
          hid_t ocpypl_id, hid_t lcpl_id)
122
0
{
123
0
    H5G_loc_t  src_loc;             /* Source object group location */
124
0
    H5G_name_t src_path;            /* Opened source object hier. path */
125
0
    H5O_loc_t  src_oloc;            /* Opened source object object location */
126
0
    bool       dst_exists;          /* Does destination name exist already? */
127
0
    bool       loc_found = false;   /* Location at 'name' found */
128
0
    bool       obj_open  = false;   /* Entry at 'name' found */
129
0
    herr_t     ret_value = SUCCEED; /* Return value */
130
131
0
    FUNC_ENTER_PACKAGE
132
133
    /* Check arguments */
134
0
    assert(loc);
135
0
    assert(src_name && *src_name);
136
0
    assert(dst_loc);
137
0
    assert(dst_name && *dst_name);
138
139
    /* Check if destination name already exists */
140
0
    dst_exists = false;
141
0
    if (H5L_exists_tolerant(dst_loc, dst_name, &dst_exists) < 0)
142
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "unable to check if destination name exists");
143
0
    if (dst_exists)
144
0
        HGOTO_ERROR(H5E_OHDR, H5E_EXISTS, FAIL, "destination object already exists");
145
146
    /* Set up opened group location to fill in */
147
0
    src_loc.oloc = &src_oloc;
148
0
    src_loc.path = &src_path;
149
0
    H5G_loc_reset(&src_loc);
150
151
    /* Find the source object to copy */
152
0
    if (H5G_loc_find(loc, src_name, &src_loc /*out*/) < 0)
153
0
        HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "source object not found");
154
0
    loc_found = true;
155
156
    /* Open source object's object header */
157
0
    if (H5O_open(&src_oloc) < 0)
158
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTOPENOBJ, FAIL, "unable to open object");
159
0
    obj_open = true;
160
161
    /* Do the actual copying of the object */
162
0
    if (H5O__copy_obj(&src_loc, dst_loc, dst_name, ocpypl_id, lcpl_id) < 0)
163
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, FAIL, "unable to copy object");
164
165
0
done:
166
0
    if (loc_found && H5G_loc_free(&src_loc) < 0)
167
0
        HDONE_ERROR(H5E_OHDR, H5E_CANTRELEASE, FAIL, "can't free location");
168
0
    if (obj_open && H5O_close(&src_oloc, NULL) < 0)
169
0
        HDONE_ERROR(H5E_OHDR, H5E_CLOSEERROR, FAIL, "unable to release object header");
170
171
0
    FUNC_LEAVE_NOAPI(ret_value)
172
0
} /* end H5O__copy() */
173
174
/*-------------------------------------------------------------------------
175
 * Function:    H5O__copy_header_real
176
 *
177
 * Purpose:     Copy header object from one location to another using
178
 *              pre-copy, copy, and post-copy callbacks for each message
179
 *              type.
180
 *
181
 *              The source header object is compressed into a single chunk
182
 *              (since we know how big it is) and any continuation messages
183
 *              are converted into NULL messages.
184
 *
185
 *              By default, NULL messages are not copied.
186
 *
187
 * Return:      Non-negative on success/Negative on failure
188
 *
189
 *-------------------------------------------------------------------------
190
 */
191
static herr_t
192
H5O__copy_header_real(const H5O_loc_t *oloc_src, H5O_loc_t *oloc_dst /*out*/, H5O_copy_t *cpy_info,
193
                      H5O_type_t *obj_type, void **udata /*out*/)
194
0
{
195
0
    H5O_addr_map_t *addr_map = NULL; /* Address mapping of object copied */
196
0
    H5O_t          *oh_src   = NULL; /* Object header for source object */
197
0
    H5O_t          *oh_dst   = NULL; /* Object header for destination object */
198
0
    unsigned        mesgno   = 0;
199
0
    haddr_t         addr_new = HADDR_UNDEF;
200
0
    bool           *deleted  = NULL; /* Array of flags indicating whether messages should be copied */
201
0
    bool        inserted = false; /* Whether the destination object header has been inserted into the cache */
202
0
    size_t      null_msgs;        /* Number of NULL messages found in each loop */
203
0
    size_t      orig_dst_msgs;    /* Original # of messages in dest. object */
204
0
    H5O_mesg_t *mesg_src;         /* Message in source object header */
205
0
    H5O_mesg_t *mesg_dst;         /* Message in destination object header */
206
0
    const H5O_msg_class_t *copy_type;        /* Type of message to use for copying */
207
0
    const H5O_obj_class_t *obj_class = NULL; /* Type of object we are copying */
208
0
    void                  *cpy_udata = NULL; /* User data for passing to message callbacks */
209
0
    uint64_t               dst_oh_size;      /* Total size of the destination OH */
210
0
    size_t                 dst_oh_null;      /* Size of the null message to add to destination OH */
211
0
    size_t                 dst_oh_gap;       /* Size of the gap in chunk #0 of destination OH */
212
0
    uint8_t               *current_pos;      /* Current position in destination image */
213
0
    size_t                 msghdr_size;
214
0
    herr_t                 ret_value = SUCCEED;
215
216
0
    FUNC_ENTER_PACKAGE_TAG(oloc_src->addr)
217
218
0
    assert(oloc_src);
219
0
    assert(oloc_src->file);
220
0
    assert(H5_addr_defined(oloc_src->addr));
221
0
    assert(oloc_dst->file);
222
0
    assert(cpy_info);
223
224
    /* Get pointer to object class for this object */
225
0
    if (NULL == (obj_class = H5O__obj_class(oloc_src)))
226
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to determine object type");
227
228
    /* Set the pointer to the shared struct for the object if opened in the file */
229
0
    cpy_info->shared_fo = H5FO_opened(oloc_src->file, oloc_src->addr);
230
231
    /* Get source object header */
232
0
    if (NULL == (oh_src = H5O_protect(oloc_src, H5AC__READ_ONLY_FLAG, false)))
233
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header");
234
235
    /* Retrieve user data for particular type of object to copy */
236
0
    if (obj_class->get_copy_file_udata && (NULL == (cpy_udata = (obj_class->get_copy_file_udata)())))
237
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to retrieve copy user data");
238
239
    /* If we are merging committed datatypes, check for a match in the destination
240
     * file now */
241
0
    if (cpy_info->merge_comm_dt && obj_class->type == H5O_TYPE_NAMED_DATATYPE) {
242
0
        unsigned long fileno_src; /* fileno for source file */
243
0
        unsigned long fileno_dst; /* fileno for destination file */
244
0
        htri_t        merge;      /* Whether we found a match in the destination file */
245
246
        /* Check if the source and dest file are the same.  If so, just return
247
         * the source object address */
248
0
        H5F_GET_FILENO(oloc_src->file, fileno_src);
249
0
        H5F_GET_FILENO(oloc_dst->file, fileno_dst);
250
0
        if (fileno_src == fileno_dst) {
251
0
            merge          = true;
252
0
            oloc_dst->addr = oloc_src->addr;
253
0
        } /* end if */
254
0
        else
255
            /* Search for a matching committed datatype, building the list if
256
             * necessary */
257
0
            if ((merge = H5O__copy_search_comm_dt(oloc_src->file, oh_src, oloc_dst, cpy_info)) < 0)
258
0
                HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "can't search for matching committed datatype");
259
260
0
        if (merge) {
261
            /* Found a match, add to skip list and exit */
262
            /* Allocate space for the address mapping of the object copied */
263
0
            if (NULL == (addr_map = H5FL_MALLOC(H5O_addr_map_t)))
264
0
                HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed");
265
266
            /* Insert the address mapping for the found object into the copied
267
             * list */
268
0
            addr_map->src_obj_pos.fileno = fileno_src;
269
0
            addr_map->src_obj_pos.addr   = oloc_src->addr;
270
0
            addr_map->dst_addr           = oloc_dst->addr;
271
0
            addr_map->is_locked          = true; /* We've locked the object currently */
272
0
            addr_map->inc_ref_count      = 0;    /* Start with no additional ref counts to add */
273
0
            addr_map->obj_class          = obj_class;
274
0
            addr_map->udata              = cpy_udata;
275
276
            /* Insert into skip list */
277
0
            if (H5SL_insert(cpy_info->map_list, addr_map, &(addr_map->src_obj_pos)) < 0) {
278
0
                addr_map = H5FL_FREE(H5O_addr_map_t, addr_map);
279
0
                HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, FAIL, "can't insert object into skip list");
280
0
            } /* end if */
281
282
0
            HGOTO_DONE(SUCCEED);
283
0
        } /* end if */
284
0
    }     /* end if */
285
286
    /* Flush any dirty messages in source object header to update the header chunks */
287
0
    if (H5O__flush_msgs(oloc_src->file, oh_src) < 0)
288
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTFLUSH, FAIL, "unable to flush object header messages");
289
290
    /* Allocate the destination object header and fill in header fields */
291
0
    if (NULL == (oh_dst = H5FL_CALLOC(H5O_t)))
292
0
        HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed");
293
294
    /* Initialize header information */
295
0
    oh_dst->version = oh_src->version;
296
297
    /* Version bounds check for destination object header */
298
0
    if (oh_dst->version > H5O_obj_ver_bounds[H5F_HIGH_BOUND(oloc_dst->file)])
299
0
        HGOTO_ERROR(H5E_OHDR, H5E_BADRANGE, FAIL, "destination object header version out of bounds");
300
301
0
    oh_dst->flags          = oh_src->flags;
302
0
    oh_dst->link_msgs_seen = oh_src->link_msgs_seen;
303
0
    oh_dst->attr_msgs_seen = oh_src->attr_msgs_seen;
304
0
    oh_dst->sizeof_size    = H5F_SIZEOF_SIZE(oloc_dst->file);
305
0
    oh_dst->sizeof_addr    = H5F_SIZEOF_ADDR(oloc_dst->file);
306
0
    oh_dst->swmr_write     = !!(H5F_INTENT(oloc_dst->file) & H5F_ACC_SWMR_WRITE);
307
308
    /* Copy time fields */
309
0
    oh_dst->atime = oh_src->atime;
310
0
    oh_dst->mtime = oh_src->mtime;
311
0
    oh_dst->ctime = oh_src->ctime;
312
0
    oh_dst->btime = oh_src->btime;
313
314
    /* Copy attribute storage information */
315
0
    oh_dst->max_compact = oh_src->max_compact;
316
0
    oh_dst->min_dense   = oh_src->min_dense;
317
318
    /* Create object header proxy if doing SWMR writes */
319
0
    if (oh_dst->swmr_write) {
320
        /* Create virtual entry, for use as proxy */
321
0
        if (NULL == (oh_dst->proxy = H5AC_proxy_entry_create()))
322
0
            HGOTO_ERROR(H5E_OHDR, H5E_CANTCREATE, FAIL, "can't create object header proxy");
323
0
    } /* end if */
324
0
    else
325
0
        oh_dst->proxy = NULL;
326
327
    /* Initialize size of chunk array.  Start off with zero chunks so this field
328
     * is consistent with the current state of the chunk array.  This is
329
     * important if an error occurs.
330
     */
331
0
    oh_dst->alloc_nchunks = oh_dst->nchunks = 0;
332
333
    /* Allocate memory for the chunk array - always start with 1 chunk */
334
0
    if (NULL == (oh_dst->chunk = H5FL_SEQ_MALLOC(H5O_chunk_t, (size_t)1)))
335
0
        HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed");
336
337
    /* Update number of allocated chunks.  There are still no chunks used. */
338
0
    oh_dst->alloc_nchunks = 1;
339
340
    /* Allocate memory for "deleted" array.  This array marks the message in
341
     * the source that shouldn't be copied to the destination.
342
     */
343
0
    if (NULL == (deleted = (bool *)H5MM_malloc(sizeof(bool) * oh_src->nmesgs)))
344
0
        HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed");
345
0
    memset(deleted, false, sizeof(bool) * oh_src->nmesgs);
346
347
    /* "pre copy" pass over messages, to gather information for actual message copy operation
348
     * (for messages which depend on information from other messages)
349
     * Keep track of how many NULL or deleted messages we find (or create)
350
     */
351
0
    null_msgs = 0;
352
0
    for (mesgno = 0; mesgno < oh_src->nmesgs; mesgno++) {
353
        /* Set up convenience variables */
354
0
        mesg_src = &(oh_src->mesg[mesgno]);
355
356
        /* Sanity check */
357
0
        assert(!mesg_src->dirty); /* Should be cleared by earlier call to flush messages */
358
359
        /* Get message class to operate on */
360
0
        copy_type = mesg_src->type;
361
362
        /* Sanity check message for possible corruption */
363
0
        if (H5O_UNKNOWN_ID != mesg_src->type->id && H5O_NULL_ID != mesg_src->type->id)
364
0
            if (0 == mesg_src->raw_size)
365
0
                HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, FAIL, "message of type '%s' has zero size",
366
0
                            mesg_src->type->name);
367
368
        /* Check for continuation message; these are converted to NULL
369
         * messages because the destination OH will have only one chunk
370
         */
371
0
        if (H5O_CONT_ID == mesg_src->type->id || H5O_NULL_ID == mesg_src->type->id) {
372
0
            deleted[mesgno] = true;
373
0
            ++null_msgs;
374
0
            copy_type = H5O_MSG_NULL;
375
0
        } /* end if */
376
0
        assert(copy_type);
377
378
0
        if (copy_type->pre_copy_file) {
379
            /* Decode the message if necessary. */
380
0
            H5O_LOAD_NATIVE(oloc_src->file, 0, oh_src, mesg_src, FAIL)
381
382
            /* Save destination file pointer in cpy_info so that it can be used
383
               in the pre_copy_file callback to obtain the destination file's
384
               high bound.  The high bound is used to index into the corresponding
385
               message's array of versions for doing version bounds check. */
386
0
            cpy_info->file_dst = oloc_dst->file;
387
388
            /* Perform "pre copy" operation on message */
389
0
            if ((copy_type->pre_copy_file)(oloc_src->file, mesg_src->native, &(deleted[mesgno]), cpy_info,
390
0
                                           cpy_udata) < 0)
391
0
                HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL,
392
0
                            "unable to perform 'pre copy' operation on message");
393
394
            /* Check if the message should be deleted in the destination */
395
0
            if (deleted[mesgno])
396
                /* Mark message as deleted */
397
0
                ++null_msgs;
398
0
        } /* end if(copy_type->pre_copy_file) */
399
0
    }     /* end for */
400
401
    /* Initialize size of message list.  It may or may not include the NULL messages
402
     * detected above.
403
     */
404
0
    if (cpy_info->preserve_null)
405
0
        oh_dst->alloc_nmesgs = oh_dst->nmesgs = oh_src->nmesgs;
406
0
    else
407
0
        oh_dst->alloc_nmesgs = oh_dst->nmesgs = (oh_src->nmesgs - null_msgs);
408
409
    /* Allocate memory for destination message array */
410
0
    if (oh_dst->alloc_nmesgs > 0)
411
0
        if (NULL == (oh_dst->mesg = H5FL_SEQ_CALLOC(H5O_mesg_t, oh_dst->alloc_nmesgs)))
412
0
            HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed");
413
414
    /* "copy" pass over messages, to perform main message copying */
415
0
    null_msgs = 0;
416
0
    for (mesgno = 0; mesgno < oh_dst->nmesgs; mesgno++) {
417
        /* Skip any deleted or NULL messages in the source unless the
418
         * preserve_null flag is set
419
         */
420
0
        if (false == cpy_info->preserve_null) {
421
0
            while (deleted[mesgno + null_msgs]) {
422
0
                ++null_msgs;
423
0
                assert(mesgno + null_msgs < oh_src->nmesgs);
424
0
            } /* end while */
425
0
        }     /* end if */
426
427
        /* Set up convenience variables */
428
0
        mesg_src = &(oh_src->mesg[mesgno + null_msgs]);
429
0
        mesg_dst = &(oh_dst->mesg[mesgno]);
430
431
        /* Initialize non-zero components of destination message */
432
0
        mesg_dst->crt_idx  = mesg_src->crt_idx;
433
0
        mesg_dst->flags    = mesg_src->flags;
434
0
        mesg_dst->raw_size = mesg_src->raw_size;
435
0
        mesg_dst->type     = mesg_src->type;
436
437
        /* If we're preserving deleted messages, set their types to 'NULL'
438
         * in the destination.
439
         */
440
0
        if (cpy_info->preserve_null && deleted[mesgno]) {
441
0
            mesg_dst->type  = H5O_MSG_NULL;
442
0
            mesg_dst->flags = 0;
443
0
            mesg_dst->dirty = true;
444
0
        } /* end if */
445
446
        /* Check for message class to operate on */
447
        /* (Use destination message, in case the message has been removed (i.e
448
         *      converted to a nil message) in the destination -QAK)
449
         */
450
0
        copy_type = mesg_dst->type;
451
0
        assert(copy_type);
452
453
        /* copy this message into destination file */
454
0
        if (copy_type->copy_file) {
455
0
            bool     recompute_size; /* Whether copy_file callback created a shared message */
456
0
            unsigned mesg_flags;     /* Message flags */
457
458
            /* Decode the message if necessary. */
459
0
            H5O_LOAD_NATIVE(oloc_src->file, 0, oh_src, mesg_src, FAIL)
460
461
            /* Get destination message flags, and unset shared and shareable
462
             * flags.  mesg_dst->flags will contain the original flags for now.
463
             */
464
0
            mesg_flags = (unsigned)mesg_dst->flags & ~H5O_MSG_FLAG_SHARED & ~H5O_MSG_FLAG_SHAREABLE;
465
466
            /* Copy the source message */
467
0
            recompute_size = false;
468
0
            if (NULL == (mesg_dst->native =
469
0
                             H5O__msg_copy_file(copy_type, oloc_src->file, mesg_src->native, oloc_dst->file,
470
0
                                                &recompute_size, &mesg_flags, cpy_info, cpy_udata)))
471
0
                HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, FAIL, "unable to copy object header message");
472
473
            /* Check if the sharing state changed, and recompute the size if so
474
             */
475
0
            if (!(mesg_flags & H5O_MSG_FLAG_SHARED) != !(mesg_dst->flags & H5O_MSG_FLAG_SHARED))
476
0
                recompute_size = true;
477
478
            /* Set destination message flags */
479
0
            mesg_dst->flags = (uint8_t)mesg_flags;
480
481
            /* Recompute message's size */
482
            /* (its sharing status or one of its components (for attributes)
483
             *  could have changed)
484
             */
485
0
            if (recompute_size)
486
0
                mesg_dst->raw_size = H5O_ALIGN_OH(
487
0
                    oh_dst, H5O_msg_raw_size(oloc_dst->file, mesg_dst->type->id, false, mesg_dst->native));
488
489
            /* Mark the message in the destination as dirty, so it'll get encoded when the object header is
490
             * flushed */
491
0
            mesg_dst->dirty = true;
492
0
        } /* end if (mesg_src->type->copy_file) */
493
0
    }     /* end of mesgno loop */
494
495
    /* Allocate the destination header and copy any messages that didn't have
496
     * copy callbacks.  They get copied directly from the source image to the
497
     * destination image.
498
     */
499
500
    /* Calculate how big the destination object header will be on disk.
501
     * This isn't necessarily the same size as the original.
502
     */
503
504
    /* Compute space for messages. */
505
0
    dst_oh_size = 0;
506
0
    for (mesgno = 0; mesgno < oh_dst->nmesgs; mesgno++) {
507
0
        dst_oh_size += (uint64_t)H5O_SIZEOF_MSGHDR_OH(oh_dst);
508
0
        dst_oh_size += oh_dst->mesg[mesgno].raw_size;
509
0
    } /* end for */
510
511
    /* Check if we need to determine correct value for chunk #0 size bits */
512
0
    if (oh_dst->version > H5O_VERSION_1) {
513
        /* Reset destination object header's "chunk 0 size" flags */
514
0
        oh_dst->flags = (uint8_t)(oh_dst->flags & ~H5O_HDR_CHUNK0_SIZE);
515
516
        /* Determine correct value for chunk #0 size bits */
517
0
        if (dst_oh_size > 4294967295)
518
0
            oh_dst->flags |= H5O_HDR_CHUNK0_8;
519
0
        else if (dst_oh_size > 65535)
520
0
            oh_dst->flags |= H5O_HDR_CHUNK0_4;
521
0
        else if (dst_oh_size > 255)
522
0
            oh_dst->flags |= H5O_HDR_CHUNK0_2;
523
0
    } /* end if */
524
525
    /* Check if the chunk's data portion is too small */
526
0
    dst_oh_gap = dst_oh_null = 0;
527
0
    if (dst_oh_size < H5O_MIN_SIZE) {
528
0
        size_t delta = (size_t)(H5O_MIN_SIZE - dst_oh_size); /* Delta in chunk size needed */
529
530
        /* Sanity check */
531
0
        assert((oh_dst->flags & H5O_HDR_CHUNK0_SIZE) == H5O_HDR_CHUNK0_1);
532
533
        /* Determine whether to create gap or NULL message */
534
0
        if ((oh_dst->version > H5O_VERSION_1) && (delta < H5O_SIZEOF_MSGHDR_OH(oh_dst)))
535
0
            dst_oh_gap = delta;
536
0
        else {
537
            /* NULL message must be at least size of message header */
538
0
            if (delta < H5O_SIZEOF_MSGHDR_OH(oh_dst))
539
0
                delta = H5O_SIZEOF_MSGHDR_OH(oh_dst);
540
541
0
            dst_oh_null = delta;
542
0
        }
543
544
        /* Increase destination object header size */
545
0
        dst_oh_size += delta;
546
547
        /* Sanity check */
548
0
        assert(dst_oh_size <= 255);
549
0
    } /* end if */
550
551
    /* Add in destination's object header size now */
552
0
    dst_oh_size += (uint64_t)H5O_SIZEOF_HDR(oh_dst);
553
554
    /* Allocate space for chunk in destination file */
555
0
    if (HADDR_UNDEF ==
556
0
        (oh_dst->chunk[0].addr = H5MF_alloc(oloc_dst->file, H5FD_MEM_OHDR, (hsize_t)dst_oh_size)))
557
0
        HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "file allocation failed for object header");
558
0
    addr_new = oh_dst->chunk[0].addr;
559
560
    /* Create memory image for the new chunk */
561
    /* Note: we use calloc() instead of malloc() here because older versions of
562
     *  some messages don't initialize "unused" bytes and because we want to
563
     *  write out the same version of the object header and older versions of
564
     *  object headers aligned messages.  In both those situations, it's
565
     *  complex and error-prone to determine all the proper ways/places to
566
     *  clear to zero bytes, so we just set the buffer to zero's here.
567
     *  (QAK - 2010/08/17)
568
     */
569
0
    if (NULL == (oh_dst->chunk[0].image = H5FL_BLK_CALLOC(chunk_image, (size_t)dst_oh_size)))
570
0
        HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed");
571
572
    /* Set dest. chunk information */
573
0
    oh_dst->chunk[0].size = (size_t)dst_oh_size;
574
0
    oh_dst->chunk[0].gap  = dst_oh_gap;
575
576
    /* Update size of chunk array.  The destination now has one chunk. */
577
0
    oh_dst->nchunks = 1;
578
579
    /* Set up raw pointers and copy messages that didn't need special
580
     * treatment.  This has to happen after the destination header has been
581
     * allocated.
582
     */
583
0
    assert(H5O_SIZEOF_MSGHDR_OH(oh_src) == H5O_SIZEOF_MSGHDR_OH(oh_dst));
584
0
    msghdr_size = H5O_SIZEOF_MSGHDR_OH(oh_dst);
585
586
0
    current_pos = oh_dst->chunk[0].image;
587
588
    /* Write the magic number for versions > 1 and skip the rest of the
589
     * header.  This will be written when the header is flushed to disk.
590
     */
591
0
    if (oh_dst->version > H5O_VERSION_1)
592
0
        H5MM_memcpy(current_pos, H5O_HDR_MAGIC, (size_t)H5_SIZEOF_MAGIC);
593
0
    current_pos += H5O_SIZEOF_HDR(oh_dst) - H5O_SIZEOF_CHKSUM_OH(oh_dst);
594
595
    /* Loop through destination messages, updating their "raw" info */
596
0
    null_msgs = 0;
597
0
    for (mesgno = 0; mesgno < oh_dst->nmesgs; mesgno++) {
598
        /* Skip any deleted or NULL messages in the source unless the
599
         * preserve_null flag is set.
600
         */
601
0
        if (false == cpy_info->preserve_null) {
602
0
            while (deleted[mesgno + null_msgs]) {
603
0
                ++null_msgs;
604
0
                assert(mesgno + null_msgs < oh_src->nmesgs);
605
0
            } /* end while */
606
0
        }     /* end if */
607
608
        /* Set up convenience variables */
609
0
        mesg_src = &(oh_src->mesg[mesgno + null_msgs]);
610
0
        mesg_dst = &(oh_dst->mesg[mesgno]);
611
612
        /* Copy each message that wasn't dirtied above */
613
0
        if (!mesg_dst->dirty)
614
            /* Copy the message header plus the message's raw data. */
615
0
            H5MM_memcpy(current_pos, mesg_src->raw - msghdr_size, msghdr_size + mesg_src->raw_size);
616
617
        /* Set message's raw pointer to destination chunk's new "image" */
618
0
        mesg_dst->raw = current_pos + msghdr_size;
619
620
        /* Move to location where next message should go */
621
0
        current_pos += mesg_dst->raw_size + msghdr_size;
622
0
    } /* end for */
623
624
    /* Save this in case more messages are added during NULL message checking */
625
0
    orig_dst_msgs = oh_dst->nmesgs;
626
627
    /* Check if we need to add a NULL message to this header */
628
0
    if (dst_oh_null > 0) {
629
0
        size_t null_idx; /* Index of new NULL message */
630
631
        /* Make sure we have enough space for new NULL message */
632
0
        if (oh_dst->nmesgs + 1 > oh_dst->alloc_nmesgs)
633
0
            if (H5O__alloc_msgs(oh_dst, (size_t)1) < 0)
634
0
                HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate more space for messages");
635
636
        /* Create null message for [rest of] space in new chunk */
637
        /* (account for chunk's magic # & checksum) */
638
0
        null_idx                        = oh_dst->nmesgs++;
639
0
        oh_dst->mesg[null_idx].type     = H5O_MSG_NULL;
640
0
        oh_dst->mesg[null_idx].dirty    = true;
641
0
        oh_dst->mesg[null_idx].native   = NULL;
642
0
        oh_dst->mesg[null_idx].raw      = current_pos + msghdr_size;
643
0
        oh_dst->mesg[null_idx].raw_size = dst_oh_null - msghdr_size;
644
0
        oh_dst->mesg[null_idx].chunkno  = 0;
645
0
    } /* end if */
646
647
    /* Make sure we filled the chunk, except for room at the end for a checksum */
648
0
    assert(current_pos + dst_oh_gap + dst_oh_null + H5O_SIZEOF_CHKSUM_OH(oh_dst) ==
649
0
           (size_t)dst_oh_size + oh_dst->chunk[0].image);
650
651
    /* Set the dest. object location to the first chunk address */
652
0
    assert(H5_addr_defined(addr_new));
653
0
    oloc_dst->addr = addr_new;
654
655
    /* If we are merging committed datatypes and this is a committed datatype, insert
656
     * the copied datatype into the list of committed datatypes in the target file.
657
     */
658
0
    if (cpy_info->merge_comm_dt && obj_class->type == H5O_TYPE_NAMED_DATATYPE)
659
0
        if (H5O__copy_insert_comm_dt(oloc_src->file, oh_src, oloc_dst, cpy_info) < 0)
660
0
            HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "can't insert committed datatype into destination list");
661
662
    /* Allocate space for the address mapping of the object copied */
663
0
    if (NULL == (addr_map = H5FL_MALLOC(H5O_addr_map_t)))
664
0
        HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed");
665
666
    /* Insert the address mapping for the new object into the copied list */
667
    /* (Do this here, because "post copy" possibly checks it) */
668
0
    H5F_GET_FILENO(oloc_src->file, addr_map->src_obj_pos.fileno);
669
0
    addr_map->src_obj_pos.addr = oloc_src->addr;
670
0
    addr_map->dst_addr         = oloc_dst->addr;
671
0
    addr_map->is_locked        = true; /* We've locked the object currently */
672
0
    addr_map->inc_ref_count    = 0;    /* Start with no additional ref counts to add */
673
0
    addr_map->obj_class        = obj_class;
674
0
    addr_map->udata            = cpy_udata;
675
676
    /* Insert into skip list */
677
0
    if (H5SL_insert(cpy_info->map_list, addr_map, &(addr_map->src_obj_pos)) < 0) {
678
0
        addr_map = H5FL_FREE(H5O_addr_map_t, addr_map);
679
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, FAIL, "can't insert object into skip list");
680
0
    } /* end if */
681
682
    /* "post copy" loop over messages, to fix up any messages which require a complete
683
     * object header for destination object
684
     */
685
0
    null_msgs = 0;
686
0
    for (mesgno = 0; mesgno < orig_dst_msgs; mesgno++) {
687
        /* Skip any deleted or NULL messages in the source unless the
688
         * preserve_null flag is set
689
         */
690
0
        if (false == cpy_info->preserve_null) {
691
0
            while (deleted[mesgno + null_msgs]) {
692
0
                ++null_msgs;
693
0
                assert(mesgno + null_msgs < oh_src->nmesgs);
694
0
            } /* end while */
695
0
        }     /* end if */
696
697
        /* Set up convenience variables */
698
0
        mesg_src = &(oh_src->mesg[mesgno + null_msgs]);
699
0
        mesg_dst = &(oh_dst->mesg[mesgno]);
700
701
        /* Check for message class to operate on */
702
        /* (Use destination message, in case the message has been removed (i.e
703
         *      converted to a nil message) in the destination -QAK)
704
         */
705
0
        copy_type = mesg_dst->type;
706
0
        assert(copy_type);
707
708
0
        if (copy_type->post_copy_file && mesg_src->native) {
709
0
            unsigned mesg_flags; /* Message flags */
710
711
            /* Sanity check destination message */
712
0
            assert(mesg_dst->type == mesg_src->type);
713
0
            assert(mesg_dst->native);
714
715
            /* Get destination message flags.   mesg_dst->flags will contain the
716
             * original flags for now. */
717
0
            mesg_flags = (unsigned)mesg_dst->flags;
718
719
            /* the object header is needed in the post copy for shared message */
720
0
            cpy_info->oh_dst = oh_dst;
721
722
            /* Perform "post copy" operation on message */
723
0
            if ((copy_type->post_copy_file)(oloc_src, mesg_src->native, oloc_dst, mesg_dst->native,
724
0
                                            &mesg_flags, cpy_info) < 0)
725
0
                HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL,
726
0
                            "unable to perform 'post copy' operation on message");
727
728
            /* Verify that the flags did not change */
729
0
            assert(mesg_flags == (unsigned)mesg_dst->flags);
730
0
        } /* end if */
731
0
    }     /* end for */
732
733
    /* Indicate that the destination address will no longer be locked */
734
0
    addr_map->is_locked = false;
735
736
    /* Increment object header's reference count, if any descendents have created links to this object */
737
0
    if (addr_map->inc_ref_count) {
738
0
        H5_CHECK_OVERFLOW(addr_map->inc_ref_count, hsize_t, unsigned);
739
0
        oh_dst->nlink += (unsigned)addr_map->inc_ref_count;
740
0
    } /* end if */
741
742
    /* Retag all copied metadata to apply the destination object's tag */
743
0
    if (H5AC_retag_copied_metadata(oloc_dst->file, oloc_dst->addr) < 0)
744
0
        HGOTO_ERROR(H5E_CACHE, H5E_CANTTAG, FAIL, "unable to re-tag metadata entries");
745
746
    /* Set metadata tag for destination object's object header */
747
0
    H5_BEGIN_TAG(oloc_dst->addr)
748
749
    /* Insert destination object header in cache */
750
0
    if (H5AC_insert_entry(oloc_dst->file, H5AC_OHDR, oloc_dst->addr, oh_dst, H5AC__NO_FLAGS_SET) < 0)
751
0
        HGOTO_ERROR_TAG(H5E_OHDR, H5E_CANTINSERT, FAIL, "unable to cache object header");
752
0
    oh_dst   = NULL;
753
0
    inserted = true;
754
755
    /* Reset metadata tag */
756
0
    H5_END_TAG
757
758
    /* Set obj_type and udata, if requested */
759
0
    if (obj_type) {
760
0
        assert(udata);
761
0
        *obj_type = obj_class->type;
762
0
        *udata    = cpy_udata;
763
0
    } /* end if */
764
765
0
done:
766
    /* Free deleted array */
767
0
    if (deleted)
768
0
        H5MM_free(deleted);
769
770
    /* Release pointer to source object header and its derived objects */
771
0
    if (oh_src && H5O_unprotect(oloc_src, oh_src, H5AC__NO_FLAGS_SET) < 0)
772
0
        HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header");
773
774
    /* Free destination object header on failure */
775
0
    if (ret_value < 0) {
776
0
        if (oh_dst && !inserted) {
777
0
            if (H5O__free(oh_dst, true) < 0)
778
0
                HDONE_ERROR(H5E_OHDR, H5E_CANTFREE, FAIL, "unable to destroy object header data");
779
0
            if (H5O_loc_reset(oloc_dst) < 0)
780
0
                HDONE_ERROR(H5E_OHDR, H5E_CANTFREE, FAIL, "unable to destroy object header data");
781
0
        } /* end if */
782
783
0
        if (addr_map == NULL && cpy_udata) {
784
0
            if (obj_class && obj_class->free_copy_file_udata)
785
0
                obj_class->free_copy_file_udata(cpy_udata);
786
0
        } /* end if */
787
0
    }
788
789
0
    FUNC_LEAVE_NOAPI_TAG(ret_value)
790
0
} /* end H5O__copy_header_real() */
791
792
/*-------------------------------------------------------------------------
793
 * Function:    H5O_copy_header_map
794
 *
795
 * Purpose:     Copy header object from one location to another, detecting
796
 *              already mapped objects, etc.
797
 *
798
 * Return:      Non-negative on success/Negative on failure
799
 *
800
 *-------------------------------------------------------------------------
801
 */
802
herr_t
803
H5O_copy_header_map(const H5O_loc_t *oloc_src, H5O_loc_t *oloc_dst /*out*/, H5O_copy_t *cpy_info,
804
                    bool inc_depth, H5O_type_t *obj_type, void **udata /*out*/)
805
0
{
806
0
    H5O_addr_map_t *addr_map = NULL; /* Address mapping of object copied */
807
0
    H5_obj_t        src_obj_pos;     /* Position of source object */
808
0
    bool            inc_link;        /* Whether to increment the link count for the object */
809
0
    herr_t          ret_value = SUCCEED;
810
811
0
    FUNC_ENTER_NOAPI(FAIL)
812
813
    /* Sanity check */
814
0
    assert(oloc_src);
815
0
    assert(oloc_src->file);
816
0
    assert(oloc_dst);
817
0
    assert(oloc_dst->file);
818
0
    assert(cpy_info);
819
820
    /* Create object "position" struct */
821
0
    H5F_GET_FILENO(oloc_src->file, src_obj_pos.fileno);
822
0
    src_obj_pos.addr = oloc_src->addr;
823
824
    /* Search for the object in the skip list of copied objects */
825
0
    addr_map = (H5O_addr_map_t *)H5SL_search(cpy_info->map_list, &src_obj_pos);
826
827
    /* Check if address is already in list of objects copied */
828
0
    if (addr_map == NULL) {
829
        /* Copy object for the first time */
830
831
        /* Check for incrementing the depth of copy */
832
        /* (Can't do this for all copies, since committed datatypes should always be copied) */
833
0
        if (inc_depth)
834
0
            cpy_info->curr_depth++;
835
836
        /* Copy object referred to */
837
0
        if (H5O__copy_header_real(oloc_src, oloc_dst, cpy_info, obj_type, udata) < 0)
838
0
            HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, FAIL, "unable to copy object");
839
840
        /* Check for incrementing the depth of copy */
841
0
        if (inc_depth)
842
0
            cpy_info->curr_depth--;
843
844
        /* When an object is copied for the first time, increment it's link */
845
0
        inc_link = true;
846
847
        /* indicate that a new object is created */
848
0
        ret_value++;
849
0
    } /* end if */
850
0
    else {
851
        /* Object has already been copied, set its address in destination file */
852
0
        oloc_dst->addr = addr_map->dst_addr;
853
854
        /* Return saved obj_type and udata, if requested */
855
0
        if (obj_type) {
856
0
            assert(udata);
857
0
            *obj_type = addr_map->obj_class->type;
858
0
            *udata    = addr_map->udata;
859
0
        } /* end if */
860
861
        /* If the object is locked currently (because we are copying a group
862
         * hierarchy and this is a link to a group higher in the hierarchy),
863
         * increment it's deferred reference count instead of incrementing the
864
         * reference count now.
865
         */
866
0
        if (addr_map->is_locked) {
867
0
            addr_map->inc_ref_count++;
868
0
            inc_link = false;
869
0
        } /* end if */
870
0
        else
871
0
            inc_link = true;
872
0
    } /* end else */
873
874
    /* Increment destination object's link count, if allowed */
875
0
    if (inc_link)
876
0
        if (H5O_link(oloc_dst, 1) < 0)
877
0
            HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to increment object link count");
878
879
0
done:
880
0
    FUNC_LEAVE_NOAPI(ret_value)
881
0
} /* end H5O_copy_header_map() */
882
883
/*--------------------------------------------------------------------------
884
 NAME
885
    H5O__copy_free_addrmap_cb
886
 PURPOSE
887
    Internal routine to free address maps from the skip list for copying objects
888
 USAGE
889
    herr_t H5O__copy_free_addrmap_cb(item, key, op_data)
890
        void *item;             IN/OUT: Pointer to addr
891
        void *key;              IN/OUT: (unused)
892
        void *op_data;          IN: (unused)
893
 RETURNS
894
    Returns zero on success, negative on failure.
895
 DESCRIPTION
896
        Releases the memory for the address.
897
 GLOBAL VARIABLES
898
 COMMENTS, BUGS, ASSUMPTIONS
899
 EXAMPLES
900
 REVISION LOG
901
--------------------------------------------------------------------------*/
902
static herr_t
903
H5O__copy_free_addrmap_cb(void *_item, void H5_ATTR_UNUSED *key, void H5_ATTR_UNUSED *op_data)
904
0
{
905
0
    H5O_addr_map_t *item = (H5O_addr_map_t *)_item;
906
907
0
    FUNC_ENTER_PACKAGE_NOERR
908
909
0
    assert(item);
910
911
    /* Release user data for particular type of object */
912
0
    if (item->udata) {
913
0
        assert(item->obj_class);
914
0
        assert(item->obj_class->free_copy_file_udata);
915
0
        (item->obj_class->free_copy_file_udata)(item->udata);
916
0
    } /* end if */
917
918
    /* Release the item */
919
0
    item = H5FL_FREE(H5O_addr_map_t, item);
920
921
0
    FUNC_LEAVE_NOAPI(0)
922
0
} /* H5O__copy_free_addrmap_cb() */
923
924
/*-------------------------------------------------------------------------
925
 * Function:    H5O__copy_header
926
 *
927
 * Purpose:     copy header object from one location to another.
928
 *
929
 * Return:      Non-negative on success/Negative on failure
930
 *
931
 *-------------------------------------------------------------------------
932
 */
933
static herr_t
934
H5O__copy_header(const H5O_loc_t *oloc_src, H5O_loc_t *oloc_dst /*out */, hid_t ocpypl_id, hid_t lcpl_id)
935
0
{
936
0
    H5O_copy_t                   cpy_info;       /* Information for copying object */
937
0
    H5P_genplist_t              *ocpy_plist;     /* Object copy property list created */
938
0
    H5O_copy_dtype_merge_list_t *dt_list = NULL; /* List of datatype merge suggestions */
939
0
    H5O_mcdt_cb_info_t           cb_info;        /* Callback info struct */
940
0
    unsigned                     cpy_option = 0; /* Copy options */
941
0
    herr_t                       ret_value  = SUCCEED;
942
943
0
    FUNC_ENTER_PACKAGE
944
945
    /* Sanity check */
946
0
    assert(oloc_src);
947
0
    assert(oloc_src->file);
948
0
    assert(H5_addr_defined(oloc_src->addr));
949
0
    assert(oloc_dst->file);
950
951
    /* Initialize copy info before errors can be thrown */
952
0
    memset(&cpy_info, 0, sizeof(H5O_copy_t));
953
954
    /* Get the copy property list */
955
0
    if (NULL == (ocpy_plist = (H5P_genplist_t *)H5I_object(ocpypl_id)))
956
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property list");
957
958
    /* Retrieve the copy parameters */
959
0
    if (H5P_get(ocpy_plist, H5O_CPY_OPTION_NAME, &cpy_option) < 0)
960
0
        HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get object copy flag");
961
962
    /* Retrieve the merge committed datatype list */
963
0
    if (H5P_peek(ocpy_plist, H5O_CPY_MERGE_COMM_DT_LIST_NAME, &dt_list) < 0)
964
0
        HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get merge committed datatype list");
965
966
    /* Get callback info */
967
0
    if (H5P_get(ocpy_plist, H5O_CPY_MCDT_SEARCH_CB_NAME, &cb_info) < 0)
968
0
        HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get callback info");
969
970
    /* Convert copy flags into copy struct */
971
0
    if ((cpy_option & H5O_COPY_SHALLOW_HIERARCHY_FLAG) > 0) {
972
0
        cpy_info.copy_shallow = true;
973
0
        cpy_info.max_depth    = 1;
974
0
    } /* end if */
975
0
    else
976
0
        cpy_info.max_depth = -1; /* Current default is for full, recursive hier. copy */
977
0
    cpy_info.curr_depth = 0;
978
0
    if ((cpy_option & H5O_COPY_EXPAND_SOFT_LINK_FLAG) > 0)
979
0
        cpy_info.expand_soft_link = true;
980
0
    if ((cpy_option & H5O_COPY_EXPAND_EXT_LINK_FLAG) > 0)
981
0
        cpy_info.expand_ext_link = true;
982
0
    if ((cpy_option & H5O_COPY_EXPAND_REFERENCE_FLAG) > 0)
983
0
        cpy_info.expand_ref = true;
984
0
    if ((cpy_option & H5O_COPY_WITHOUT_ATTR_FLAG) > 0)
985
0
        cpy_info.copy_without_attr = true;
986
0
    if ((cpy_option & H5O_COPY_PRESERVE_NULL_FLAG) > 0)
987
0
        cpy_info.preserve_null = true;
988
0
    if ((cpy_option & H5O_COPY_MERGE_COMMITTED_DTYPE_FLAG) > 0)
989
0
        cpy_info.merge_comm_dt = true;
990
991
    /* Add dt_list to copy struct */
992
0
    cpy_info.dst_dt_suggestion_list = dt_list;
993
994
    /* Add set callback information */
995
0
    cpy_info.mcdt_cb = cb_info.func;
996
0
    cpy_info.mcdt_ud = cb_info.user_data;
997
998
    /* Add property lists needed by callbacks */
999
0
    cpy_info.lcpl_id = lcpl_id;
1000
1001
    /* Create a skip list to keep track of which objects are copied */
1002
0
    if (NULL == (cpy_info.map_list = H5SL_create(H5SL_TYPE_OBJ, NULL)))
1003
0
        HGOTO_ERROR(H5E_SLIST, H5E_CANTCREATE, FAIL, "cannot make skip list");
1004
1005
    /* copy the object from the source file to the destination file */
1006
0
    if (H5O__copy_header_real(oloc_src, oloc_dst, &cpy_info, NULL, NULL) < 0)
1007
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, FAIL, "unable to copy object");
1008
1009
0
done:
1010
0
    if (cpy_info.map_list)
1011
0
        H5SL_destroy(cpy_info.map_list, H5O__copy_free_addrmap_cb, NULL);
1012
0
    if (cpy_info.dst_dt_list)
1013
0
        H5SL_destroy(cpy_info.dst_dt_list, H5O__copy_free_comm_dt_cb, NULL);
1014
1015
0
    FUNC_LEAVE_NOAPI(ret_value)
1016
0
} /* end H5O__copy_header() */
1017
1018
/*-------------------------------------------------------------------------
1019
 * Function:    H5O__copy_obj
1020
 *
1021
 * Purpose:     Copy an object to destination location
1022
 *
1023
 * Return:      Non-negative on success/Negative on failure
1024
 *
1025
 *-------------------------------------------------------------------------
1026
 */
1027
static herr_t
1028
H5O__copy_obj(H5G_loc_t *src_loc, H5G_loc_t *dst_loc, const char *dst_name, hid_t ocpypl_id, hid_t lcpl_id)
1029
0
{
1030
0
    H5G_name_t new_path;                 /* Copied object group hier. path */
1031
0
    H5O_loc_t  new_oloc;                 /* Copied object object location */
1032
0
    H5G_loc_t  new_loc;                  /* Group location of object copied */
1033
0
    H5F_t     *cached_dst_file;          /* Cached destination file */
1034
0
    bool       entry_inserted = false;   /* Flag to indicate that the new entry was inserted into a group */
1035
0
    herr_t     ret_value      = SUCCEED; /* Return value */
1036
1037
0
    FUNC_ENTER_PACKAGE
1038
1039
0
    assert(src_loc);
1040
0
    assert(src_loc->oloc->file);
1041
0
    assert(dst_loc);
1042
0
    assert(dst_loc->oloc->file);
1043
0
    assert(dst_name);
1044
1045
    /* Set up copied object location to fill in */
1046
0
    new_loc.oloc = &new_oloc;
1047
0
    new_loc.path = &new_path;
1048
0
    H5G_loc_reset(&new_loc);
1049
0
    new_oloc.file = dst_loc->oloc->file;
1050
1051
    /* Make a copy of the destination file, in case the original is changed by
1052
     * H5O__copy_header.  If and when oloc's point to the shared file struct,
1053
     * this will no longer be necessary, so this code can be removed. */
1054
0
    cached_dst_file = dst_loc->oloc->file;
1055
1056
    /* Copy the object from the source file to the destination file */
1057
0
    if (H5O__copy_header(src_loc->oloc, &new_oloc, ocpypl_id, lcpl_id) < 0)
1058
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, FAIL, "unable to copy object");
1059
1060
    /* Patch dst_loc.  Again, this can be removed once oloc's point to shared
1061
     * file structs. */
1062
0
    dst_loc->oloc->file = cached_dst_file;
1063
1064
    /* Insert the new object in the destination file's group */
1065
0
    if (H5L_link(dst_loc, dst_name, &new_loc, lcpl_id) < 0)
1066
0
        HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to insert link");
1067
0
    entry_inserted = true;
1068
1069
0
done:
1070
    /* Free the ID to name buffers */
1071
0
    if (entry_inserted)
1072
0
        H5G_loc_free(&new_loc);
1073
1074
0
    FUNC_LEAVE_NOAPI(ret_value)
1075
0
} /* end H5O__copy_obj() */
1076
1077
/*-------------------------------------------------------------------------
1078
 * Function:    H5O__copy_free_comm_dt_cb
1079
 *
1080
 * Purpose:     Frees the merge committed dt skip list key and object.
1081
 *
1082
 * Return:      SUCCEED (never fails)
1083
 *
1084
 *-------------------------------------------------------------------------
1085
 */
1086
static herr_t
1087
H5O__copy_free_comm_dt_cb(void *item, void *_key, void H5_ATTR_UNUSED *_op_data)
1088
0
{
1089
0
    haddr_t                       *addr = (haddr_t *)item;
1090
0
    H5O_copy_search_comm_dt_key_t *key  = (H5O_copy_search_comm_dt_key_t *)_key;
1091
1092
0
    FUNC_ENTER_PACKAGE_NOERR
1093
1094
0
    assert(addr);
1095
0
    assert(key);
1096
0
    assert(key->dt);
1097
1098
0
    key->dt = (H5T_t *)H5O_msg_free(H5O_DTYPE_ID, key->dt);
1099
0
    key     = H5FL_FREE(H5O_copy_search_comm_dt_key_t, key);
1100
0
    addr    = H5FL_FREE(haddr_t, addr);
1101
1102
0
    FUNC_LEAVE_NOAPI(SUCCEED)
1103
0
} /* end H5O__copy_free_comm_dt_cb */
1104
1105
/*-------------------------------------------------------------------------
1106
 * Function:    H5O__copy_comm_dt_cmp
1107
 *
1108
 * Purpose:     Skiplist callback used to compare 2 keys for the merge
1109
 *              committed dt list.  Mostly a wrapper for H5T_cmp.
1110
 *
1111
 * Return:      0 if key1 and key2 are equal.
1112
 *              <0 if key1 is less than key2.
1113
 *              >0 if key1 is greater than key2.
1114
 *
1115
 *-------------------------------------------------------------------------
1116
 */
1117
static int
1118
H5O__copy_comm_dt_cmp(const void *_key1, const void *_key2)
1119
0
{
1120
0
    const H5O_copy_search_comm_dt_key_t *key1      = (const H5O_copy_search_comm_dt_key_t *)_key1;
1121
0
    const H5O_copy_search_comm_dt_key_t *key2      = (const H5O_copy_search_comm_dt_key_t *)_key2;
1122
0
    int                                  ret_value = 0;
1123
1124
0
    FUNC_ENTER_PACKAGE_NOERR
1125
1126
    /* Check fileno.  It is unlikely to be different so check if they are equal
1127
     * first so only one comparison needs to be made. */
1128
0
    if (key1->fileno != key2->fileno) {
1129
0
        if (key1->fileno < key2->fileno)
1130
0
            HGOTO_DONE(-1);
1131
0
        if (key1->fileno > key2->fileno)
1132
0
            HGOTO_DONE(1);
1133
0
    } /* end if */
1134
1135
0
    ret_value = H5T_cmp(key1->dt, key2->dt, false);
1136
1137
0
done:
1138
0
    FUNC_LEAVE_NOAPI(ret_value)
1139
0
} /* end H5O__copy_comm_dt_cmp */
1140
1141
/*-------------------------------------------------------------------------
1142
 * Function:    H5O__copy_search_comm_dt_attr_cb
1143
 *
1144
 * Purpose:     Callback for H5O_attr_iterate_real from
1145
 *              H5O__copy_search_comm_dt_check.  Checks if the attribute's
1146
 *              datatype is committed.  If it is, adds it to the merge
1147
 *              committed dt skiplist present in udata if it does not match
1148
 *              any already present.
1149
 *
1150
 * Return:      Non-negative on success/Negative on failure
1151
 *
1152
 *-------------------------------------------------------------------------
1153
 */
1154
static herr_t
1155
H5O__copy_search_comm_dt_attr_cb(const H5A_t *attr, void *_udata)
1156
0
{
1157
0
    H5O_copy_search_comm_dt_ud_t  *udata        = (H5O_copy_search_comm_dt_ud_t *)_udata;
1158
0
    H5T_t                         *dt           = NULL;    /* Datatype */
1159
0
    H5O_copy_search_comm_dt_key_t *key          = NULL;    /* Skiplist key */
1160
0
    haddr_t                       *addr         = NULL;    /* Destination address */
1161
0
    bool                           obj_inserted = false;   /* Object inserted into skip list */
1162
0
    herr_t                         ret_value    = SUCCEED; /* Return value */
1163
1164
0
    FUNC_ENTER_PACKAGE
1165
1166
    /* Sanity checks */
1167
0
    assert(attr);
1168
0
    assert(udata);
1169
0
    assert(udata->dst_dt_list);
1170
0
    assert(H5_addr_defined(udata->obj_oloc.addr));
1171
1172
    /* Get attribute datatype */
1173
0
    if (NULL == (dt = H5A_type(attr)))
1174
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "can't get attribute datatype");
1175
1176
    /* Check if the datatype is committed and search the skip list if so */
1177
0
    if (H5T_is_named(dt)) {
1178
        /* Allocate key */
1179
0
        if (NULL == (key = H5FL_MALLOC(H5O_copy_search_comm_dt_key_t)))
1180
0
            HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed");
1181
1182
        /* Copy datatype into key */
1183
0
        if (NULL == (key->dt = (H5T_t *)H5O_msg_copy(H5O_DTYPE_ID, dt, NULL)))
1184
0
            HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to copy datatype message");
1185
1186
        /* Get datatype object fileno */
1187
0
        H5F_GET_FILENO(udata->obj_oloc.file, key->fileno);
1188
1189
0
        if (!H5SL_search(udata->dst_dt_list, key)) {
1190
            /* Allocate destination address */
1191
0
            if (NULL == (addr = H5FL_MALLOC(haddr_t)))
1192
0
                HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed");
1193
1194
            /* Add the destination datatype to the skip list */
1195
0
            *addr = ((H5O_shared_t *)(key->dt))->u.loc.oh_addr;
1196
0
            if (H5SL_insert(udata->dst_dt_list, addr, key) < 0)
1197
0
                HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, FAIL, "can't insert object into skip list");
1198
0
            obj_inserted = true;
1199
0
        } /* end if */
1200
0
    }     /* end if */
1201
1202
0
done:
1203
    /* Release resources */
1204
0
    if (!obj_inserted) {
1205
0
        if (key) {
1206
0
            if (key->dt)
1207
0
                key->dt = (H5T_t *)H5O_msg_free(H5O_DTYPE_ID, key->dt);
1208
0
            key = H5FL_FREE(H5O_copy_search_comm_dt_key_t, key);
1209
0
        } /* end if */
1210
0
        if (addr) {
1211
0
            assert(ret_value < 0);
1212
0
            addr = H5FL_FREE(haddr_t, addr);
1213
0
        } /* end if */
1214
0
    }     /* end if */
1215
1216
0
    FUNC_LEAVE_NOAPI(ret_value)
1217
0
} /* end H5O__copy_search_comm_dt_attr_cb */
1218
1219
/*-------------------------------------------------------------------------
1220
 * Function:    H5O__copy_search_comm_dt_check
1221
 *
1222
 * Purpose:     Check if the object at obj_oloc is or contains a reference
1223
 *              to a committed datatype.  If it does, adds it to the merge
1224
 *              committed dt skiplist present in udata if it does not match
1225
 *              any already present.
1226
 *
1227
 * Return:      Non-negative on success/Negative on failure
1228
 *
1229
 *-------------------------------------------------------------------------
1230
 */
1231
static herr_t
1232
H5O__copy_search_comm_dt_check(const H5O_loc_t *obj_oloc, H5O_copy_search_comm_dt_ud_t *udata)
1233
0
{
1234
0
    H5O_copy_search_comm_dt_key_t *key          = NULL;  /* Skiplist key */
1235
0
    haddr_t                       *addr         = NULL;  /* Destination address */
1236
0
    bool                           obj_inserted = false; /* Object inserted into skip list */
1237
0
    H5A_attr_iter_op_t             attr_op;              /* Attribute iteration operator */
1238
0
    const H5O_obj_class_t         *obj_class = NULL;     /* Type of object */
1239
0
    herr_t                         ret_value = SUCCEED;  /* Return value */
1240
1241
0
    FUNC_ENTER_PACKAGE
1242
1243
    /* Sanity checks */
1244
0
    assert(obj_oloc);
1245
0
    assert(udata);
1246
0
    assert(udata->dst_dt_list);
1247
0
    assert(udata->dst_root_loc);
1248
1249
    /* Get pointer to object class for this object */
1250
0
    if ((obj_class = H5O__obj_class(obj_oloc)) == NULL)
1251
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to determine object type");
1252
1253
    /* Check if the object is a datatype, a dataset using a committed
1254
     * datatype, or contains an attribute using a committed datatype */
1255
0
    if (obj_class->type == H5O_TYPE_NAMED_DATATYPE) {
1256
        /* Allocate key */
1257
0
        if (NULL == (key = H5FL_MALLOC(H5O_copy_search_comm_dt_key_t)))
1258
0
            HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed");
1259
1260
        /* Read the destination datatype */
1261
0
        if (NULL == (key->dt = (H5T_t *)H5O_msg_read(obj_oloc, H5O_DTYPE_ID, NULL)))
1262
0
            HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "can't read DTYPE message");
1263
1264
        /* Get destination object fileno */
1265
0
        H5F_GET_FILENO(obj_oloc->file, key->fileno);
1266
1267
        /* Check if the datatype is already present in the skip list */
1268
0
        if (!H5SL_search(udata->dst_dt_list, key)) {
1269
            /* Allocate destination address */
1270
0
            if (NULL == (addr = H5FL_MALLOC(haddr_t)))
1271
0
                HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed");
1272
1273
            /* Add the destination datatype to the skip list */
1274
0
            *addr = obj_oloc->addr;
1275
0
            if (H5SL_insert(udata->dst_dt_list, addr, key) < 0)
1276
0
                HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, FAIL, "can't insert object into skip list");
1277
0
            obj_inserted = true;
1278
0
        } /* end if */
1279
0
    }     /* end if */
1280
0
    else if (obj_class->type == H5O_TYPE_DATASET) {
1281
        /* Allocate key */
1282
0
        if (NULL == (key = H5FL_MALLOC(H5O_copy_search_comm_dt_key_t)))
1283
0
            HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed");
1284
1285
        /* Read the destination datatype */
1286
0
        if (NULL == (key->dt = (H5T_t *)H5O_msg_read(obj_oloc, H5O_DTYPE_ID, NULL)))
1287
0
            HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "can't read DTYPE message");
1288
1289
        /* Check if the datatype is committed and search the skip list if so */
1290
0
        if (H5T_is_named(key->dt)) {
1291
            /* Get datatype object fileno */
1292
0
            H5F_GET_FILENO(obj_oloc->file, key->fileno);
1293
1294
0
            if (!H5SL_search(udata->dst_dt_list, key)) {
1295
                /* Allocate destination address */
1296
0
                if (NULL == (addr = H5FL_MALLOC(haddr_t)))
1297
0
                    HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed");
1298
1299
                /* Add the destination datatype to the skip list */
1300
0
                *addr = ((H5O_shared_t *)(key->dt))->u.loc.oh_addr;
1301
0
                if (H5SL_insert(udata->dst_dt_list, addr, key) < 0)
1302
0
                    HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, FAIL, "can't insert object into skip list");
1303
0
                obj_inserted = true;
1304
0
            } /* end if */
1305
0
        }     /* end if */
1306
0
    }         /* end else */
1307
1308
    /* Search within attributes */
1309
0
    attr_op.op_type      = H5A_ATTR_OP_LIB;
1310
0
    attr_op.u.lib_op     = H5O__copy_search_comm_dt_attr_cb;
1311
0
    udata->obj_oloc.file = obj_oloc->file;
1312
0
    udata->obj_oloc.addr = obj_oloc->addr;
1313
0
    if (H5O_attr_iterate_real((hid_t)-1, obj_oloc, H5_INDEX_NAME, H5_ITER_NATIVE, (hsize_t)0, NULL, &attr_op,
1314
0
                              udata) < 0)
1315
0
        HGOTO_ERROR(H5E_OHDR, H5E_BADITER, FAIL, "error iterating over attributes");
1316
1317
0
done:
1318
    /* Release resources */
1319
0
    if (!obj_inserted) {
1320
0
        if (key) {
1321
0
            if (key->dt)
1322
0
                key->dt = (H5T_t *)H5O_msg_free(H5O_DTYPE_ID, key->dt);
1323
0
            key = H5FL_FREE(H5O_copy_search_comm_dt_key_t, key);
1324
0
        } /* end if */
1325
0
        if (addr) {
1326
0
            assert(ret_value < 0);
1327
0
            addr = H5FL_FREE(haddr_t, addr);
1328
0
        } /* end if */
1329
0
    }     /* end if */
1330
1331
0
    FUNC_LEAVE_NOAPI(ret_value)
1332
0
} /* end H5O__copy_search_comm_dt_check */
1333
1334
/*-------------------------------------------------------------------------
1335
 * Function:    H5O__copy_search_comm_dt_cb
1336
 *
1337
 * Purpose:     H5G_visit callback to add committed datatypes to the merge
1338
 *              committed dt skiplist.  Mostly a wrapper for
1339
 *              H5O__copy_search_comm_dt_check.
1340
 *
1341
 * Return:      Non-negative on success/Negative on failure
1342
 *
1343
 *-------------------------------------------------------------------------
1344
 */
1345
static herr_t
1346
H5O__copy_search_comm_dt_cb(hid_t H5_ATTR_UNUSED group, const char H5_ATTR_UNUSED *name,
1347
                            const H5O_loc_t *obj_oloc, void *_udata)
1348
0
{
1349
0
    H5O_copy_search_comm_dt_ud_t *udata =
1350
0
        (H5O_copy_search_comm_dt_ud_t *)_udata; /* Skip list of dtypes in dest file */
1351
0
    herr_t ret_value = H5_ITER_CONT;            /* Return value */
1352
1353
0
    FUNC_ENTER_PACKAGE
1354
1355
    /* Sanity checks */
1356
0
    assert(name);
1357
0
    assert(obj_oloc);
1358
0
    assert(udata);
1359
0
    assert(udata->dst_dt_list);
1360
0
    assert(udata->dst_root_loc);
1361
1362
    /* Check object and add to skip list if appropriate */
1363
0
    if (H5O__copy_search_comm_dt_check(obj_oloc, udata) < 0)
1364
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, H5_ITER_ERROR, "can't check object");
1365
1366
0
done:
1367
0
    FUNC_LEAVE_NOAPI(ret_value)
1368
0
} /* end H5O__copy_search_comm_dt_cb */
1369
1370
/*-------------------------------------------------------------------------
1371
 * Function:    H5O__copy_search_comm_dt
1372
 *
1373
 * Purpose:     Checks if the committed datatype present in oh_src matches any
1374
 *              in the destination file, building the destination file
1375
 *              skiplist as necessary.
1376
 *
1377
 * Return:      true if a match is found in the destination file
1378
 *                      - oloc_dst will contain the address
1379
 *              false if a match is not found
1380
 *              Negative on failure
1381
 *
1382
 *-------------------------------------------------------------------------
1383
 */
1384
static htri_t
1385
H5O__copy_search_comm_dt(H5F_t *file_src, H5O_t *oh_src, H5O_loc_t *oloc_dst /*in, out*/,
1386
                         H5O_copy_t *cpy_info)
1387
0
{
1388
0
    H5O_copy_search_comm_dt_key_t *key = NULL;                  /* Skiplist key */
1389
0
    haddr_t                       *dst_addr;                    /* Destination datatype address */
1390
0
    H5G_loc_t                      dst_root_loc = {NULL, NULL}; /* Destination root group location */
1391
0
    H5O_copy_search_comm_dt_ud_t   udata;                       /* Group iteration user data */
1392
0
    herr_t                         ret_value = false;           /* Return value */
1393
1394
0
    FUNC_ENTER_PACKAGE
1395
1396
    /* Sanity checks */
1397
0
    assert(oh_src);
1398
0
    assert(oloc_dst);
1399
0
    assert(oloc_dst->file);
1400
0
    assert(H5F_ID_EXISTS(oloc_dst->file));
1401
0
    assert(cpy_info);
1402
1403
    /* Allocate key */
1404
0
    if (NULL == (key = H5FL_MALLOC(H5O_copy_search_comm_dt_key_t)))
1405
0
        HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed");
1406
1407
    /* Read the source datatype */
1408
0
    if (NULL == (key->dt = (H5T_t *)H5O_msg_read_oh(file_src, oh_src, H5O_DTYPE_ID, NULL)))
1409
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "can't read DTYPE message");
1410
1411
    /* Get destination object fileno */
1412
0
    H5F_GET_FILENO(oloc_dst->file, key->fileno);
1413
1414
    /* Check if the destination dtype list exists, create it if it does not */
1415
0
    if (!cpy_info->dst_dt_list) {
1416
        /* Create the skip list */
1417
0
        if (NULL == (cpy_info->dst_dt_list = H5SL_create(H5SL_TYPE_GENERIC, H5O__copy_comm_dt_cmp)))
1418
0
            HGOTO_ERROR(H5E_OHDR, H5E_CANTCREATE, FAIL, "can't create skip list for committed datatypes");
1419
1420
        /* Add suggested types to list, if they are present */
1421
0
        if (cpy_info->dst_dt_suggestion_list) {
1422
0
            H5O_copy_dtype_merge_list_t *suggestion = cpy_info->dst_dt_suggestion_list;
1423
0
            H5G_loc_t                    obj_loc;  /* Location of object */
1424
0
            H5O_loc_t                    obj_oloc; /* Object's object location */
1425
0
            H5G_name_t                   obj_path; /* Object's group hier. path */
1426
1427
            /* Set up the root group in the destination file */
1428
0
            if (NULL == (dst_root_loc.oloc = H5G_oloc(H5G_rootof(oloc_dst->file))))
1429
0
                HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get object location for root group");
1430
0
            if (NULL == (dst_root_loc.path = H5G_nameof(H5G_rootof(oloc_dst->file))))
1431
0
                HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get path for root group");
1432
1433
            /* Set up opened group location to fill in */
1434
0
            obj_loc.oloc = &obj_oloc;
1435
0
            obj_loc.path = &obj_path;
1436
0
            H5G_loc_reset(&obj_loc);
1437
1438
            /* Build udata */
1439
0
            udata.dst_dt_list   = cpy_info->dst_dt_list;
1440
0
            udata.dst_root_loc  = &dst_root_loc;
1441
0
            udata.obj_oloc.file = NULL;
1442
0
            udata.obj_oloc.addr = HADDR_UNDEF;
1443
1444
            /* Walk through the list of datatype suggestions */
1445
0
            while (suggestion) {
1446
0
                bool exists = false;
1447
1448
                /* Find the object */
1449
0
                if (H5G_loc_exists(&dst_root_loc, suggestion->path, &exists /*out*/) < 0)
1450
0
                    HGOTO_ERROR(H5E_OHDR, H5E_CANTFIND, FAIL, "can't check object's existence");
1451
1452
0
                if (exists) {
1453
                    /* Retrieve the object location info */
1454
0
                    if (H5G_loc_find(&dst_root_loc, suggestion->path, &obj_loc /*out*/) < 0)
1455
0
                        HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "can't retrieve object location");
1456
1457
                    /* Check object and add to skip list if appropriate */
1458
0
                    if (H5O__copy_search_comm_dt_check(&obj_oloc, &udata) < 0) {
1459
0
                        if (H5G_loc_free(&obj_loc) < 0)
1460
0
                            HERROR(H5E_OHDR, H5E_CANTRELEASE, "can't free location");
1461
0
                        HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "can't check object");
1462
0
                    } /* end if */
1463
1464
                    /* Free location */
1465
0
                    if (H5G_loc_free(&obj_loc) < 0)
1466
0
                        HGOTO_ERROR(H5E_OHDR, H5E_CANTRELEASE, FAIL, "can't free location");
1467
0
                } /* end if */
1468
1469
                /* Advance the suggestion pointer */
1470
0
                suggestion = suggestion->next;
1471
0
            } /* end while */
1472
0
        }     /* end if */
1473
0
    }
1474
1475
0
    if (!cpy_info->dst_dt_list_complete) {
1476
        /* Search for the type in the destination file, and return its address
1477
         * if found, but only if the list is populated with and only with
1478
         * suggested types.  We will search complete lists later. */
1479
0
        if (cpy_info->dst_dt_suggestion_list &&
1480
0
            NULL != (dst_addr = (haddr_t *)H5SL_search(cpy_info->dst_dt_list, key))) {
1481
0
            oloc_dst->addr = *dst_addr;
1482
0
            ret_value      = true;
1483
0
        } /* end if */
1484
0
        else {
1485
0
            H5O_mcdt_search_ret_t search_cb_ret = H5O_MCDT_SEARCH_CONT;
1486
1487
            /* Make callback to see if we should search destination file */
1488
0
            if (cpy_info->mcdt_cb) {
1489
                /* Prepare & restore library for user callback */
1490
0
                H5_BEFORE_USER_CB(FAIL)
1491
0
                    {
1492
0
                        search_cb_ret = cpy_info->mcdt_cb(cpy_info->mcdt_ud);
1493
0
                    }
1494
0
                H5_AFTER_USER_CB(FAIL)
1495
0
                if (H5O_MCDT_SEARCH_ERROR == search_cb_ret)
1496
0
                    HGOTO_ERROR(H5E_OHDR, H5E_CALLBACK, FAIL, "callback returned error");
1497
0
            }
1498
1499
0
            if (search_cb_ret == H5O_MCDT_SEARCH_CONT) {
1500
                /* Build the complete dst dt list */
1501
                /* Set up the root group in the destination file, if necessary */
1502
0
                if (!dst_root_loc.oloc) {
1503
0
                    assert(!dst_root_loc.path);
1504
0
                    if (NULL == (dst_root_loc.oloc = H5G_oloc(H5G_rootof(oloc_dst->file))))
1505
0
                        HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL,
1506
0
                                    "unable to get object location for root group");
1507
0
                    if (NULL == (dst_root_loc.path = H5G_nameof(H5G_rootof(oloc_dst->file))))
1508
0
                        HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get path for root group");
1509
0
                } /* end if */
1510
0
                else
1511
0
                    assert(dst_root_loc.path);
1512
1513
                /* Build udata.  Note that this may be done twice in some cases, but
1514
                 * it should be rare and should be cheaper on average than trying to
1515
                 * keep track of whether it was done before. */
1516
0
                udata.dst_dt_list   = cpy_info->dst_dt_list;
1517
0
                udata.dst_root_loc  = &dst_root_loc;
1518
0
                udata.obj_oloc.file = NULL;
1519
0
                udata.obj_oloc.addr = HADDR_UNDEF;
1520
1521
                /* Traverse the destination file, adding committed datatypes to the skip
1522
                 * list */
1523
0
                if (H5G_visit(&dst_root_loc, "/", H5_INDEX_NAME, H5_ITER_NATIVE, NULL,
1524
0
                              H5O__copy_search_comm_dt_cb, &udata) < 0)
1525
0
                    HGOTO_ERROR(H5E_OHDR, H5E_BADITER, FAIL, "object visitation failed");
1526
0
                cpy_info->dst_dt_list_complete = true;
1527
0
            } /* end if */
1528
0
            else if (search_cb_ret != H5O_MCDT_SEARCH_STOP)
1529
0
                HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unknown return value for callback");
1530
0
        } /* end if */
1531
0
    }     /* end if */
1532
1533
    /* Search for the type in the destination file, and return its address if
1534
     * found, but only if the list is complete */
1535
0
    if (cpy_info->dst_dt_list_complete) {
1536
0
        if (NULL != (dst_addr = (haddr_t *)H5SL_search(cpy_info->dst_dt_list, key))) {
1537
0
            oloc_dst->addr = *dst_addr;
1538
0
            ret_value      = true;
1539
0
        } /* end if */
1540
0
    }     /* end if */
1541
1542
0
done:
1543
0
    if (key) {
1544
0
        if (key->dt)
1545
0
            key->dt = (H5T_t *)H5O_msg_free(H5O_DTYPE_ID, key->dt);
1546
0
        key = H5FL_FREE(H5O_copy_search_comm_dt_key_t, key);
1547
0
    } /* end if */
1548
1549
0
    FUNC_LEAVE_NOAPI(ret_value)
1550
0
} /* end H5O__copy_search_comm_dt */
1551
1552
/*-------------------------------------------------------------------------
1553
 * Function:    H5O__copy_insert_comm_dt
1554
 *
1555
 * Purpose:     Insert the committed datatype at oloc_dst into the merge committed
1556
 *              dt skiplist.  The datatype must not be present already.
1557
 *
1558
 * Return:      Non-negative on success/Negative on failure
1559
 *
1560
 *-------------------------------------------------------------------------
1561
 */
1562
static herr_t
1563
H5O__copy_insert_comm_dt(H5F_t *file_src, H5O_t *oh_src, H5O_loc_t *oloc_dst, H5O_copy_t *cpy_info)
1564
0
{
1565
0
    H5O_copy_search_comm_dt_key_t *key       = NULL;    /* Skiplist key */
1566
0
    haddr_t                       *addr      = NULL;    /* Destination object address */
1567
0
    herr_t                         ret_value = SUCCEED; /* Return value */
1568
1569
0
    FUNC_ENTER_PACKAGE
1570
1571
    /* Sanity checks */
1572
0
    assert(oh_src);
1573
0
    assert(oloc_dst);
1574
0
    assert(oloc_dst->file);
1575
0
    assert(oloc_dst->addr != HADDR_UNDEF);
1576
0
    assert(cpy_info);
1577
0
    assert(cpy_info->dst_dt_list);
1578
1579
    /* Allocate key */
1580
0
    if (NULL == (key = H5FL_MALLOC(H5O_copy_search_comm_dt_key_t)))
1581
0
        HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed");
1582
1583
    /* Read the datatype.  Read from the source file because the destination
1584
     * object could be changed in the post-copy. */
1585
0
    if (NULL == (key->dt = (H5T_t *)H5O_msg_read_oh(file_src, oh_src, H5O_DTYPE_ID, NULL)))
1586
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "can't read DTYPE message");
1587
1588
    /* Get destination object fileno */
1589
0
    H5F_GET_FILENO(oloc_dst->file, key->fileno);
1590
1591
    /* Allocate destination address */
1592
0
    if (NULL == (addr = H5FL_MALLOC(haddr_t)))
1593
0
        HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed");
1594
1595
    /* Add the destination datatype to the skip list */
1596
0
    *addr = oloc_dst->addr;
1597
0
    if (H5SL_insert(cpy_info->dst_dt_list, addr, key) < 0)
1598
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, FAIL, "can't insert object into skip list");
1599
1600
0
done:
1601
0
    if (ret_value < 0) {
1602
0
        if (key) {
1603
0
            if (key->dt)
1604
0
                key->dt = (H5T_t *)H5O_msg_free(H5O_DTYPE_ID, key->dt);
1605
0
            key = H5FL_FREE(H5O_copy_search_comm_dt_key_t, key);
1606
0
        } /* end if */
1607
0
        if (addr)
1608
0
            addr = H5FL_FREE(haddr_t, addr);
1609
0
    } /* end if */
1610
1611
0
    FUNC_LEAVE_NOAPI(ret_value)
1612
0
} /* end H5O__copy_insert_comm_dt */