1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2  * Copyright by The HDF Group.                                               *
3  * Copyright by the Board of Trustees of the University of Illinois.         *
4  * All rights reserved.                                                      *
5  *                                                                           *
6  * This file is part of HDF5.  The full HDF5 copyright notice, including     *
7  * terms governing use, modification, and redistribution, is contained in    *
8  * the COPYING file, which can be found at the root of the source code       *
9  * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases.  *
10  * If you do not have access to either file, you may request a copy from     *
11  * help@hdfgroup.org.                                                        *
12  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
13 
14 /*-------------------------------------------------------------------------
15  *
16  * Created:		H5Ocopy.c
17  *			Nov  6 2006
18  *			Quincey Koziol <koziol@hdfgroup.org>
19  *
20  * Purpose:		Object copying routines.
21  *
22  *-------------------------------------------------------------------------
23  */
24 
25 /****************/
26 /* Module Setup */
27 /****************/
28 
29 #include "H5Omodule.h"          /* This source code file is part of the H5O module */
30 
31 
32 /***********/
33 /* Headers */
34 /***********/
35 #include "H5private.h"		/* Generic Functions			*/
36 #include "H5Aprivate.h"         /* Attributes                           */
37 #include "H5CXprivate.h"        /* API Contexts                         */
38 #include "H5Eprivate.h"		/* Error handling		  	*/
39 #include "H5FLprivate.h"	/* Free lists                           */
40 #include "H5Iprivate.h"		/* IDs			  		*/
41 #include "H5HGprivate.h"        /* Global Heaps                         */
42 #include "H5FOprivate.h"        /* File objects                         */
43 #include "H5Lprivate.h"         /* Links			  	*/
44 #include "H5MFprivate.h"	/* File memory management		*/
45 #include "H5MMprivate.h"	/* Memory management			*/
46 #include "H5Opkg.h"             /* Object headers			*/
47 #include "H5Pprivate.h"         /* Property lists                       */
48 
49 
50 /****************/
51 /* Local Macros */
52 /****************/
53 
54 
55 /******************/
56 /* Local Typedefs */
57 /******************/
58 
59 /* Key object for skiplist of committed datatypes */
60 typedef struct H5O_copy_search_comm_dt_key_t {
61     H5T_t               *dt;    /* Datatype */
62     unsigned long       fileno; /* File number */
63 } H5O_copy_search_comm_dt_key_t;
64 
65 /* Callback struct for building a list of committed datatypes */
66 typedef struct H5O_copy_search_comm_dt_ud_t {
67     H5SL_t      *dst_dt_list;   /* Skip list of committed datatypes */
68     H5G_loc_t   *dst_root_loc;  /* Starting location for iteration */
69     H5O_loc_t   obj_oloc;       /* Object location (for attribute iteration callback) */
70 } H5O_copy_search_comm_dt_ud_t;
71 
72 
73 /********************/
74 /* Package Typedefs */
75 /********************/
76 
77 
78 /********************/
79 /* Local Prototypes */
80 /********************/
81 
82 static herr_t H5O__copy(const H5G_loc_t *loc, const char *src_name,
83     H5G_loc_t *dst_loc, const char *dst_name, hid_t ocpypl_id, hid_t lcpl_id);
84 static herr_t H5O__copy_free_addrmap_cb(void *item, void *key, void *op_data);
85 static herr_t H5O__copy_header_real(const H5O_loc_t *oloc_src, H5O_loc_t *oloc_dst /*out*/,
86     H5O_copy_t *cpy_info, H5O_type_t *obj_type, void **udata);
87 static herr_t H5O__copy_header(const H5O_loc_t *oloc_src, H5O_loc_t *oloc_dst /*out*/,
88     hid_t ocpypl_id, hid_t lcpl_id);
89 static herr_t H5O__copy_obj(H5G_loc_t *src_loc, H5G_loc_t *dst_loc,
90     const char *dst_name, hid_t ocpypl_id, hid_t lcpl_id);
91 static herr_t H5O__copy_obj_by_ref(H5O_loc_t *src_oloc, H5O_loc_t *dst_oloc,
92     H5G_loc_t *dst_root_loc, H5O_copy_t *cpy_info);
93 static herr_t H5O__copy_free_comm_dt_cb(void *item, void *key, void *op_data);
94 static int H5O__copy_comm_dt_cmp(const void *dt1, const void *dt2);
95 static herr_t H5O__copy_search_comm_dt_cb(hid_t group, const char *name,
96     const H5L_info_t *linfo, void *udata);
97 static htri_t H5O__copy_search_comm_dt(H5F_t *file_src, H5O_t *oh_src,
98     H5O_loc_t *oloc_dst/*in, out*/, H5O_copy_t *cpy_info);
99 static herr_t H5O__copy_insert_comm_dt(H5F_t *file_src, H5O_t *oh_src,
100     H5O_loc_t *oloc_dst, H5O_copy_t *cpy_info);
101 
102 
103 /*********************/
104 /* Package Variables */
105 /*********************/
106 
107 /* Declare a free list to manage the H5O_addr_map_t struct */
108 H5FL_DEFINE(H5O_addr_map_t);
109 
110 /* Declare a free list to manage the H5O_copy_search_comm_dt_key_t struct */
111 H5FL_DEFINE(H5O_copy_search_comm_dt_key_t);
112 
113 /* Declare a free list to manage haddr_t variables */
114 H5FL_DEFINE(haddr_t);
115 
116 
117 /*****************************/
118 /* Library Private Variables */
119 /*****************************/
120 
121 
122 /*******************/
123 /* Local Variables */
124 /*******************/
125 
126 
127 
128 /*-------------------------------------------------------------------------
129  * Function:    H5Ocopy
130  *
131  * Purpose:     Copy an object (group or dataset) to destination location
132  *              within a file or cross files. PLIST_ID is a property list
133  *              which is used to pass user options and properties to the
134  *              copy. The name, dst_name, must not already be taken by some
135  *              other object in the destination group.
136  *
137  *              H5Ocopy() will fail if the name of the destination object
138  *                  exists in the destination group.  For example,
139  *                  H5Ocopy(fid_src, "/dset", fid_dst, "/dset", ...)
140  *                  will fail if "/dset" exists in the destination file
141  *
142  *              OPTIONS THAT HAVE BEEN IMPLEMENTED.
143  *                  H5O_COPY_SHALLOW_HIERARCHY_FLAG
144  *                      If this flag is specified, only immediate members of
145  *                      the group are copied. Otherwise (default), it will
146  *                      recursively copy all objects below the group
147  *                  H5O_COPY_EXPAND_SOFT_LINK_FLAG
148  *                      If this flag is specified, it will copy the objects
149  *                      pointed by the soft links. Otherwise (default), it
150  *                      will copy the soft link as they are
151  *                  H5O_COPY_WITHOUT_ATTR_FLAG
152  *                      If this flag is specified, it will copy object without
153  *                      copying attributes. Otherwise (default), it will
154  *                      copy object along with all its attributes
155  *                  H5O_COPY_EXPAND_REFERENCE_FLAG
156  *                      1) Copy object between two different files:
157  *                          When this flag is specified, it will copy objects that
158  *                          are pointed by the references and update the values of
159  *                          references in the destination file.  Otherwise (default)
160  *                          the values of references in the destination will set to
161  *                          zero
162  *                          The current implementation does not handle references
163  *                          inside of other datatype structure. For example, if
164  *                          a member of compound datatype is reference, H5Ocopy()
165  *                          will copy that field as it is. It will not set the
166  *                          value to zero as default is used nor copy the object
167  *                          pointed by that field the flag is set
168  *                      2) Copy object within the same file:
169  *                          This flag does not have any effect to the H5Ocopy().
170  *                          Datasets or attributes of references are copied as they
171  *                          are, i.e. values of references of the destination object
172  *                          are the same as the values of the source object
173  *
174  *              OPTIONS THAT MAY APPLY TO COPY IN THE FUTURE.
175  *                  H5O_COPY_EXPAND_EXT_LINK_FLAG
176  *                      If this flag is specified, it will expand the external links
177  *                      into new objects, Otherwise (default), it will keep external
178  *                      links as they are (default)
179  *
180  *              PROPERTIES THAT MAY APPLY TO COPY IN FUTURE
181  *                  Change data layout such as chunk size
182  *                  Add filter such as data compression.
183  *                  Add an attribute to the copied object(s) that say the  date/time
184  *                      for the copy or other information about the source file.
185  *
186  *              The intermediate group creation property should be passed in
187  *              using the lcpl instead of the ocpypl.
188  *
189  * Usage:      H5Ocopy(src_loc_id, src_name, dst_loc_id, dst_name, ocpypl_id, lcpl_id)
190  *             hid_t src_loc_id         IN: Source file or group identifier.
191  *             const char *src_name     IN: Name of the source object to be copied
192  *             hid_t dst_loc_id         IN: Destination file or group identifier
193  *             const char *dst_name     IN: Name of the destination object
194  *             hid_t ocpypl_id          IN: Properties which apply to the copy
195  *             hid_t lcpl_id            IN: Properties which apply to the new hard link
196  *
197  *
198  * Return:      Non-negative on success/Negative on failure
199  *
200  * Programmer:  Peter Cao
201  *              June 4, 2005
202  *
203  *-------------------------------------------------------------------------
204  */
205 herr_t
H5Ocopy(hid_t src_loc_id,const char * src_name,hid_t dst_loc_id,const char * dst_name,hid_t ocpypl_id,hid_t lcpl_id)206 H5Ocopy(hid_t src_loc_id, const char *src_name, hid_t dst_loc_id,
207     const char *dst_name, hid_t ocpypl_id, hid_t lcpl_id)
208 {
209     H5G_loc_t	loc;                    /* Source group group location */
210     H5G_loc_t	dst_loc;                /* Destination group location */
211     herr_t      ret_value = SUCCEED;    /* Return value */
212 
213     FUNC_ENTER_API(FAIL)
214     H5TRACE6("e", "i*si*sii", src_loc_id, src_name, dst_loc_id, dst_name,
215              ocpypl_id, lcpl_id);
216 
217     /* Check arguments */
218     if(H5G_loc(src_loc_id, &loc) < 0)
219 	HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
220     if(H5G_loc(dst_loc_id, &dst_loc) < 0)
221 	HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location")
222     if(!src_name || !*src_name)
223 	HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no source name specified")
224     if(!dst_name || !*dst_name)
225 	HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no destination name specified")
226 
227     /* Set up collective metadata if appropriate */
228     if(H5CX_set_loc(src_loc_id) < 0)
229         HGOTO_ERROR(H5E_OHDR, H5E_CANTSET, FAIL, "can't set collective metadata read info")
230 
231     /* Call internal routine to copy object */
232     if(H5O__copy(&loc, src_name, &dst_loc, dst_name, ocpypl_id, lcpl_id) < 0)
233         HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, FAIL, "unable to copy object")
234 
235 done:
236     FUNC_LEAVE_API(ret_value)
237 } /* end H5Ocopy() */
238 
239 
240 /*-------------------------------------------------------------------------
241  * Function:    H5O__copy
242  *
243  * Purpose:     Internal routine to copy an object
244  *
245  * Return:	Success:	Non-negative
246  *		Failure:	Negative
247  *
248  * Programmer:	Quincey Koziol
249  *		December 29, 2017
250  *
251  *-------------------------------------------------------------------------
252  */
253 static herr_t
H5O__copy(const H5G_loc_t * loc,const char * src_name,H5G_loc_t * dst_loc,const char * dst_name,hid_t ocpypl_id,hid_t lcpl_id)254 H5O__copy(const H5G_loc_t *loc, const char *src_name, H5G_loc_t *dst_loc,
255     const char *dst_name, hid_t ocpypl_id, hid_t lcpl_id)
256 {
257     H5G_loc_t	src_loc;                /* Source object group location */
258     H5G_name_t  src_path;               /* Opened source object hier. path */
259     H5O_loc_t   src_oloc;               /* Opened source object object location */
260     htri_t      dst_exists;             /* Does destination name exist already? */
261     hbool_t     loc_found = FALSE;      /* Location at 'name' found */
262     hbool_t     obj_open = FALSE;       /* Entry at 'name' found */
263     herr_t      ret_value = SUCCEED;	/* Return value */
264 
265     FUNC_ENTER_STATIC
266 
267     /* Check arguments */
268     HDassert(loc);
269     HDassert(src_name && *src_name);
270     HDassert(dst_loc);
271     HDassert(dst_name && *dst_name);
272 
273     /* Check if destination name already exists */
274     if((dst_exists = H5L_exists_tolerant(dst_loc, dst_name)) < 0)
275 	HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "unable to check if destination name exists")
276     if(TRUE == dst_exists)
277         HGOTO_ERROR(H5E_OHDR, H5E_EXISTS, FAIL, "destination object already exists")
278 
279     /* Set up opened group location to fill in */
280     src_loc.oloc = &src_oloc;
281     src_loc.path = &src_path;
282     H5G_loc_reset(&src_loc);
283 
284     /* Find the source object to copy */
285     if(H5G_loc_find(loc, src_name, &src_loc/*out*/) < 0)
286         HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "source object not found")
287     loc_found = TRUE;
288 
289     /* Open source object's object header */
290     if(H5O_open(&src_oloc) < 0)
291         HGOTO_ERROR(H5E_OHDR, H5E_CANTOPENOBJ, FAIL, "unable to open object")
292     obj_open = TRUE;
293 
294     /* Get correct property lists */
295     if(H5P_DEFAULT == lcpl_id) {
296         if((lcpl_id = H5P_get_default(H5P_CLS_LCRT)) < 0)
297             HGOTO_ERROR(H5E_PLIST, H5E_CANTINIT, FAIL, "unable to get default lcpl")
298     } /* end if */
299     else
300         if(TRUE != H5P_isa_class(lcpl_id, H5P_LINK_CREATE))
301             HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not link creation property list")
302 
303     /* Get object copy property list */
304     if(H5P_DEFAULT == ocpypl_id) {
305         if((ocpypl_id = H5P_get_default(H5P_CLS_OCPY)) < 0)
306             HGOTO_ERROR(H5E_PLIST, H5E_CANTINIT, FAIL, "unable to get default ocpypl")
307     } /* end if */
308     else
309         if(TRUE != H5P_isa_class(ocpypl_id, H5P_OBJECT_COPY))
310             HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not object copy property list")
311 
312     /* Set the LCPL for the API context */
313     H5CX_set_lcpl(lcpl_id);
314 
315     /* Do the actual copying of the object */
316     if(H5O__copy_obj(&src_loc, dst_loc, dst_name, ocpypl_id, lcpl_id) < 0)
317         HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, FAIL, "unable to copy object")
318 
319 done:
320     if(loc_found && H5G_loc_free(&src_loc) < 0)
321         HDONE_ERROR(H5E_OHDR, H5E_CANTRELEASE, FAIL, "can't free location")
322     if(obj_open && H5O_close(&src_oloc, NULL) < 0)
323         HDONE_ERROR(H5E_OHDR, H5E_CLOSEERROR, FAIL, "unable to release object header")
324 
325     FUNC_LEAVE_NOAPI(ret_value)
326 } /* end H5O__copy() */
327 
328 
329 /*-------------------------------------------------------------------------
330  * Function:    H5O__copy_header_real
331  *
332  * Purpose:     Copy header object from one location to another using
333  *              pre-copy, copy, and post-copy callbacks for each message
334  *              type.
335  *
336  *              The source header object is compressed into a single chunk
337  *              (since we know how big it is) and any continuation messages
338  *              are converted into NULL messages.
339  *
340  *              By default, NULL messages are not copied.
341  *
342  * Return:      Non-negative on success/Negative on failure
343  *
344  * Programmer:  Peter Cao
345  *              May 30, 2005
346  *
347  *-------------------------------------------------------------------------
348  */
349 static herr_t
H5O__copy_header_real(const H5O_loc_t * oloc_src,H5O_loc_t * oloc_dst,H5O_copy_t * cpy_info,H5O_type_t * obj_type,void ** udata)350 H5O__copy_header_real(const H5O_loc_t *oloc_src, H5O_loc_t *oloc_dst /*out*/,
351     H5O_copy_t *cpy_info, H5O_type_t *obj_type, void **udata /*out*/)
352 {
353     H5O_addr_map_t         *addr_map = NULL;       /* Address mapping of object copied */
354     H5O_t                  *oh_src = NULL;         /* Object header for source object */
355     H5O_t                  *oh_dst = NULL;         /* Object header for destination object */
356     unsigned               mesgno = 0;
357     haddr_t                addr_new = HADDR_UNDEF;
358     hbool_t                *deleted = NULL;      /* Array of flags indicating whether messages should be copied */
359     hbool_t                inserted = FALSE;        /* Whether the destination object header has been inserted into the cache */
360     size_t                 null_msgs;               /* Number of NULL messages found in each loop */
361     size_t                 orig_dst_msgs;           /* Original # of messages in dest. object */
362     H5O_mesg_t             *mesg_src;               /* Message in source object header */
363     H5O_mesg_t             *mesg_dst;               /* Message in destination object header */
364     const H5O_msg_class_t  *copy_type;              /* Type of message to use for copying */
365     const H5O_obj_class_t  *obj_class = NULL;       /* Type of object we are copying */
366     void                   *cpy_udata = NULL;       /* User data for passing to message callbacks */
367     uint64_t               dst_oh_size;             /* Total size of the destination OH */
368     size_t                 dst_oh_null;             /* Size of the null message to add to destination OH */
369     size_t                 dst_oh_gap;              /* Size of the gap in chunk #0 of destination OH */
370     uint8_t                *current_pos;            /* Current position in destination image */
371     size_t                 msghdr_size;
372     herr_t                 ret_value = SUCCEED;
373 
374     FUNC_ENTER_STATIC_TAG(oloc_src->addr)
375 
376     HDassert(oloc_src);
377     HDassert(oloc_src->file);
378     HDassert(H5F_addr_defined(oloc_src->addr));
379     HDassert(oloc_dst->file);
380     HDassert(cpy_info);
381 
382     /* Get pointer to object class for this object */
383     if(NULL == (obj_class = H5O__obj_class(oloc_src)))
384         HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to determine object type")
385 
386     /* Set the pointer to the shared struct for the object if opened in the file */
387     cpy_info->shared_fo = H5FO_opened(oloc_src->file, oloc_src->addr);
388 
389     /* Get source object header */
390     if(NULL == (oh_src = H5O_protect(oloc_src, H5AC__READ_ONLY_FLAG, FALSE)))
391         HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header")
392 
393     /* Retrieve user data for particular type of object to copy */
394     if(obj_class->get_copy_file_udata && (NULL == (cpy_udata = (obj_class->get_copy_file_udata)())))
395         HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to retrieve copy user data")
396 
397     /* If we are merging committed datatypes, check for a match in the destination
398      * file now */
399     if(cpy_info->merge_comm_dt && obj_class->type == H5O_TYPE_NAMED_DATATYPE) {
400         unsigned long fileno_src; /* fileno for source file */
401         unsigned long fileno_dst; /* fileno for destination file */
402         htri_t merge; /* Whether we found a match in the destination file */
403 
404         /* Check if the source and dest file are the same.  If so, just return
405          * the source object address */
406         H5F_GET_FILENO(oloc_src->file, fileno_src);
407         H5F_GET_FILENO(oloc_dst->file, fileno_dst);
408         if(fileno_src == fileno_dst) {
409             merge = TRUE;
410             oloc_dst->addr = oloc_src->addr;
411         } /* end if */
412         else
413             /* Search for a matching committed datatype, building the list if
414              * necessary */
415             if((merge = H5O__copy_search_comm_dt(oloc_src->file, oh_src, oloc_dst, cpy_info)) < 0)
416                 HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "can't search for matching committed datatype")
417 
418         if(merge) {
419             /* Found a match, add to skip list and exit */
420             /* Allocate space for the address mapping of the object copied */
421             if(NULL == (addr_map = H5FL_MALLOC(H5O_addr_map_t)))
422                 HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
423 
424             /* Insert the address mapping for the found object into the copied
425              * list */
426             addr_map->src_obj_pos.fileno = fileno_src;
427             addr_map->src_obj_pos.addr = oloc_src->addr;
428             addr_map->dst_addr = oloc_dst->addr;
429             addr_map->is_locked = TRUE;                 /* We've locked the object currently */
430             addr_map->inc_ref_count = 0;                /* Start with no additional ref counts to add */
431             addr_map->obj_class = obj_class;
432             addr_map->udata = cpy_udata;
433 
434             /* Insert into skip list */
435             if(H5SL_insert(cpy_info->map_list, addr_map, &(addr_map->src_obj_pos)) < 0) {
436                 addr_map = H5FL_FREE(H5O_addr_map_t, addr_map);
437                 HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, FAIL, "can't insert object into skip list")
438             } /* end if */
439 
440             HGOTO_DONE(SUCCEED)
441         } /* end if */
442     } /* end if */
443 
444     /* Flush any dirty messages in source object header to update the header chunks */
445     if(H5O_flush_msgs(oloc_src->file, oh_src) < 0)
446         HGOTO_ERROR(H5E_OHDR, H5E_CANTFLUSH, FAIL, "unable to flush object header messages")
447 
448     /* Allocate the destination object header and fill in header fields */
449     if(NULL == (oh_dst = H5FL_CALLOC(H5O_t)))
450         HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
451 
452     /* Initialize header information */
453     oh_dst->version = oh_src->version;
454 
455     /* Version bounds check for destination object header */
456     if(oh_dst->version > H5O_obj_ver_bounds[H5F_HIGH_BOUND(oloc_dst->file)])
457         HGOTO_ERROR(H5E_OHDR, H5E_BADRANGE, FAIL, "destination object header version out of bounds")
458 
459     oh_dst->flags = oh_src->flags;
460     oh_dst->link_msgs_seen = oh_src->link_msgs_seen;
461     oh_dst->attr_msgs_seen = oh_src->attr_msgs_seen;
462     oh_dst->sizeof_size = H5F_SIZEOF_SIZE(oloc_dst->file);
463     oh_dst->sizeof_addr = H5F_SIZEOF_ADDR(oloc_dst->file);
464     oh_dst->swmr_write = !!(H5F_INTENT(oloc_dst->file) & H5F_ACC_SWMR_WRITE);
465 
466     /* Copy time fields */
467     oh_dst->atime = oh_src->atime;
468     oh_dst->mtime = oh_src->mtime;
469     oh_dst->ctime = oh_src->ctime;
470     oh_dst->btime = oh_src->btime;
471 
472     /* Copy attribute storage information */
473     oh_dst->max_compact = oh_src->max_compact;
474     oh_dst->min_dense = oh_src->min_dense;
475 
476     /* Create object header proxy if doing SWMR writes */
477     if(oh_dst->swmr_write) {
478         /* Create virtual entry, for use as proxy */
479         if(NULL == (oh_dst->proxy = H5AC_proxy_entry_create()))
480             HGOTO_ERROR(H5E_OHDR, H5E_CANTCREATE, FAIL, "can't create object header proxy")
481     } /* end if */
482     else
483         oh_dst->proxy = NULL;
484 
485     /* Initialize size of chunk array.  Start off with zero chunks so this field
486      * is consistent with the current state of the chunk array.  This is
487      * important if an error occurs.
488      */
489     oh_dst->alloc_nchunks = oh_dst->nchunks = 0;
490 
491     /* Allocate memory for the chunk array - always start with 1 chunk */
492     if(NULL == (oh_dst->chunk = H5FL_SEQ_MALLOC(H5O_chunk_t, (size_t)1)))
493         HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
494 
495     /* Update number of allocated chunks.  There are still no chunks used. */
496     oh_dst->alloc_nchunks = 1;
497 
498     /* Allocate memory for "deleted" array.  This array marks the message in
499      * the source that shouldn't be copied to the destination.
500      */
501     if(NULL == (deleted = (hbool_t *)H5MM_malloc(sizeof(hbool_t) * oh_src->nmesgs)))
502         HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
503     HDmemset(deleted, FALSE, sizeof(hbool_t) * oh_src->nmesgs);
504 
505     /* "pre copy" pass over messages, to gather information for actual message copy operation
506      * (for messages which depend on information from other messages)
507      * Keep track of how many NULL or deleted messages we find (or create)
508      */
509     null_msgs = 0;
510     for(mesgno = 0; mesgno < oh_src->nmesgs; mesgno++) {
511         /* Set up convenience variables */
512         mesg_src = &(oh_src->mesg[mesgno]);
513 
514         /* Sanity check */
515         HDassert(!mesg_src->dirty);     /* Should be cleared by earlier call to flush messages */
516 
517         /* Get message class to operate on */
518         copy_type = mesg_src->type;
519 
520         /* Check for continuation message; these are converted to NULL
521          * messages because the destination OH will have only one chunk
522          */
523         if(H5O_CONT_ID == mesg_src->type->id || H5O_NULL_ID == mesg_src->type->id) {
524             deleted[mesgno] = TRUE;
525             ++null_msgs;
526             copy_type = H5O_MSG_NULL;
527         } /* end if */
528         HDassert(copy_type);
529 
530         if(copy_type->pre_copy_file) {
531             /* Decode the message if necessary. */
532             H5O_LOAD_NATIVE(oloc_src->file, 0, oh_src, mesg_src, FAIL)
533 
534             /* Save destination file pointer in cpy_info so that it can be used
535                in the pre_copy_file callback to obtain the destination file's
536                high bound.  The high bound is used to index into the corresponding
537                message's array of versions for doing version bounds check. */
538             cpy_info->file_dst = oloc_dst->file;
539 
540             /* Perform "pre copy" operation on message */
541             if((copy_type->pre_copy_file)(oloc_src->file, mesg_src->native,
542                     &(deleted[mesgno]), cpy_info, cpy_udata) < 0)
543                 HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to perform 'pre copy' operation on message")
544 
545             /* Check if the message should be deleted in the destination */
546             if(deleted[mesgno])
547                 /* Mark message as deleted */
548                 ++null_msgs;
549         } /* end if(copy_type->pre_copy_file) */
550     } /* end for */
551 
552     /* Initialize size of message list.  It may or may not include the NULL messages
553      * detected above.
554      */
555     if(cpy_info->preserve_null)
556         oh_dst->alloc_nmesgs = oh_dst->nmesgs = oh_src->nmesgs;
557     else
558         oh_dst->alloc_nmesgs = oh_dst->nmesgs = (oh_src->nmesgs - null_msgs);
559 
560     /* Allocate memory for destination message array */
561     if(oh_dst->alloc_nmesgs > 0)
562         if(NULL == (oh_dst->mesg = H5FL_SEQ_CALLOC(H5O_mesg_t, oh_dst->alloc_nmesgs)))
563             HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
564 
565     /* "copy" pass over messages, to perform main message copying */
566     null_msgs = 0;
567     for(mesgno = 0; mesgno < oh_dst->nmesgs; mesgno++) {
568         /* Skip any deleted or NULL messages in the source unless the
569          * preserve_null flag is set
570          */
571         if(FALSE == cpy_info->preserve_null) {
572             while(deleted[mesgno + null_msgs]) {
573                 ++null_msgs;
574                 HDassert(mesgno + null_msgs < oh_src->nmesgs);
575             } /* end while */
576         } /* end if */
577 
578         /* Set up convenience variables */
579         mesg_src = &(oh_src->mesg[mesgno + null_msgs]);
580         mesg_dst = &(oh_dst->mesg[mesgno]);
581 
582         /* Initialize non-zero components of destination message */
583         mesg_dst->crt_idx = mesg_src->crt_idx;
584         mesg_dst->flags = mesg_src->flags;
585         mesg_dst->raw_size = mesg_src->raw_size;
586         mesg_dst->type = mesg_src->type;
587 
588         /* If we're preserving deleted messages, set their types to 'NULL'
589          * in the destination.
590          */
591         if(cpy_info->preserve_null && deleted[mesgno]) {
592             mesg_dst->type = H5O_MSG_NULL;
593             mesg_dst->flags = 0;
594             mesg_dst->dirty = TRUE;
595         } /* end if */
596 
597         /* Check for message class to operate on */
598         /* (Use destination message, in case the message has been removed (i.e
599          *      converted to a nil message) in the destination -QAK)
600          */
601         copy_type = mesg_dst->type;
602         HDassert(copy_type);
603 
604         /* copy this message into destination file */
605         if(copy_type->copy_file) {
606             hbool_t recompute_size;     /* Whether copy_file callback created a shared message */
607             unsigned mesg_flags;        /* Message flags */
608 
609             /* Decode the message if necessary. */
610             H5O_LOAD_NATIVE(oloc_src->file, 0, oh_src, mesg_src, FAIL)
611 
612             /* Get destination message flags, and unset shared and shareable
613              * flags.  mesg_dst->flags will contain the original flags for now.
614              */
615             mesg_flags = (unsigned)mesg_dst->flags & ~H5O_MSG_FLAG_SHARED
616                     & ~H5O_MSG_FLAG_SHAREABLE;
617 
618             /* Copy the source message */
619             recompute_size = FALSE;
620             if(NULL == (mesg_dst->native = H5O__msg_copy_file(copy_type, oloc_src->file,
621                     mesg_src->native, oloc_dst->file, &recompute_size,
622                     &mesg_flags, cpy_info, cpy_udata)))
623                 HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, FAIL, "unable to copy object header message")
624 
625             /* Check if the sharing state changed, and recompute the size if so
626              */
627             if(!(mesg_flags & H5O_MSG_FLAG_SHARED)
628                     != !(mesg_dst->flags & H5O_MSG_FLAG_SHARED))
629                 recompute_size = TRUE;
630 
631             /* Set destination message flags */
632             mesg_dst->flags = (uint8_t)mesg_flags;
633 
634             /* Recompute message's size */
635             /* (its sharing status or one of its components (for attributes)
636              *  could have changed)
637              */
638             if(recompute_size)
639                 mesg_dst->raw_size = H5O_ALIGN_OH(oh_dst,
640                         H5O_msg_raw_size(oloc_dst->file, mesg_dst->type->id, FALSE, mesg_dst->native));
641 
642             /* Mark the message in the destination as dirty, so it'll get encoded when the object header is flushed */
643             mesg_dst->dirty = TRUE;
644         } /* end if (mesg_src->type->copy_file) */
645     } /* end of mesgno loop */
646 
647 
648     /* Allocate the destination header and copy any messages that didn't have
649      * copy callbacks.  They get copied directly from the source image to the
650      * destination image.
651      */
652 
653     /* Calculate how big the destination object header will be on disk.
654      * This isn't necessarily the same size as the original.
655      */
656 
657     /* Compute space for messages. */
658     dst_oh_size = 0;
659     for(mesgno = 0; mesgno < oh_dst->nmesgs; mesgno++) {
660         dst_oh_size += (uint64_t)H5O_SIZEOF_MSGHDR_OH(oh_dst);
661         dst_oh_size += oh_dst->mesg[mesgno].raw_size;
662     } /* end for */
663 
664     /* Check if we need to determine correct value for chunk #0 size bits */
665     if(oh_dst->version > H5O_VERSION_1) {
666         /* Reset destination object header's "chunk 0 size" flags */
667         oh_dst->flags = (uint8_t)(oh_dst->flags & ~H5O_HDR_CHUNK0_SIZE);
668 
669         /* Determine correct value for chunk #0 size bits */
670         if(dst_oh_size > 4294967295)
671             oh_dst->flags |= H5O_HDR_CHUNK0_8;
672         else if(dst_oh_size > 65535)
673             oh_dst->flags |= H5O_HDR_CHUNK0_4;
674         else if(dst_oh_size > 255)
675             oh_dst->flags |= H5O_HDR_CHUNK0_2;
676     } /* end if */
677 
678     /* Check if the chunk's data portion is too small */
679     dst_oh_gap = dst_oh_null = 0;
680     if(dst_oh_size < H5O_MIN_SIZE) {
681         size_t delta = (size_t)(H5O_MIN_SIZE - dst_oh_size);    /* Delta in chunk size needed */
682 
683         /* Sanity check */
684         HDassert((oh_dst->flags & H5O_HDR_CHUNK0_SIZE) == H5O_HDR_CHUNK0_1);
685 
686         /* Determine whether to create gap or NULL message */
687         if(delta < H5O_SIZEOF_MSGHDR_OH(oh_dst))
688             dst_oh_gap = delta;
689         else
690             dst_oh_null = delta;
691 
692         /* Increase destination object header size */
693         dst_oh_size += delta;
694 
695         /* Sanity check */
696         HDassert(dst_oh_size <= 255);
697     } /* end if */
698 
699     /* Add in destination's object header size now */
700     dst_oh_size += (uint64_t)H5O_SIZEOF_HDR(oh_dst);
701 
702     /* Allocate space for chunk in destination file */
703     if(HADDR_UNDEF == (oh_dst->chunk[0].addr = H5MF_alloc(oloc_dst->file, H5FD_MEM_OHDR, (hsize_t)dst_oh_size)))
704         HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "file allocation failed for object header")
705     addr_new = oh_dst->chunk[0].addr;
706 
707     /* Create memory image for the new chunk */
708     /* Note: we use calloc() instead of malloc() here because older versions of
709      *  some messages don't initialize "unused" bytes and because we want to
710      *  write out the same version of the object header and older versions of
711      *  object headers aligned messages.  In both those situations, it's
712      *  complex and error-prone to determine all the proper ways/places to
713      *  clear to zero bytes, so we just set the buffer to zero's here.
714      *  (QAK - 2010/08/17)
715      */
716     if(NULL == (oh_dst->chunk[0].image = H5FL_BLK_CALLOC(chunk_image, (size_t)dst_oh_size)))
717         HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
718 
719     /* Set dest. chunk information */
720     oh_dst->chunk[0].size = (size_t)dst_oh_size;
721     oh_dst->chunk[0].gap = dst_oh_gap;
722 
723     /* Update size of chunk array.  The destination now has one chunk. */
724     oh_dst->nchunks = 1;
725 
726     /* Set up raw pointers and copy messages that didn't need special
727      * treatment.  This has to happen after the destination header has been
728      * allocated.
729      */
730     HDassert(H5O_SIZEOF_MSGHDR_OH(oh_src) == H5O_SIZEOF_MSGHDR_OH(oh_dst));
731     msghdr_size = H5O_SIZEOF_MSGHDR_OH(oh_dst);
732 
733     current_pos = oh_dst->chunk[0].image;
734 
735     /* Write the magic number for versions > 1 and skip the rest of the
736      * header.  This will be written when the header is flushed to disk.
737      */
738     if(oh_dst->version > H5O_VERSION_1)
739         HDmemcpy(current_pos, H5O_HDR_MAGIC, (size_t)H5_SIZEOF_MAGIC);
740     current_pos += H5O_SIZEOF_HDR(oh_dst) - H5O_SIZEOF_CHKSUM_OH(oh_dst);
741 
742     /* Loop through destination messages, updating their "raw" info */
743     null_msgs = 0;
744     for(mesgno = 0; mesgno < oh_dst->nmesgs; mesgno++) {
745         /* Skip any deleted or NULL messages in the source unless the
746          * preserve_null flag is set.
747          */
748         if(FALSE == cpy_info->preserve_null) {
749             while(deleted[mesgno + null_msgs]) {
750                 ++null_msgs;
751                 HDassert(mesgno + null_msgs < oh_src->nmesgs);
752             } /* end while */
753         } /* end if */
754 
755         /* Set up convenience variables */
756         mesg_src = &(oh_src->mesg[mesgno + null_msgs]);
757         mesg_dst = &(oh_dst->mesg[mesgno]);
758 
759         /* Copy each message that wasn't dirtied above */
760         if(!mesg_dst->dirty)
761             /* Copy the message header plus the message's raw data. */
762             HDmemcpy(current_pos, mesg_src->raw - msghdr_size, msghdr_size + mesg_src->raw_size);
763 
764         /* Set message's raw pointer to destination chunk's new "image" */
765         mesg_dst->raw = current_pos + msghdr_size;
766 
767         /* Move to location where next message should go */
768         current_pos += mesg_dst->raw_size + msghdr_size;
769     } /* end for */
770 
771     /* Save this in case more messages are added during NULL message checking */
772     orig_dst_msgs = oh_dst->nmesgs;
773 
774     /* Check if we need to add a NULL message to this header */
775     if(dst_oh_null > 0) {
776         size_t null_idx;                /* Index of new NULL message */
777 
778         /* Make sure we have enough space for new NULL message */
779         if(oh_dst->nmesgs + 1 > oh_dst->alloc_nmesgs)
780             if(H5O_alloc_msgs(oh_dst, (size_t)1) < 0)
781                 HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate more space for messages")
782 
783         /* Create null message for [rest of] space in new chunk */
784         /* (account for chunk's magic # & checksum) */
785         null_idx = oh_dst->nmesgs++;
786         oh_dst->mesg[null_idx].type = H5O_MSG_NULL;
787         oh_dst->mesg[null_idx].dirty = TRUE;
788         oh_dst->mesg[null_idx].native = NULL;
789         oh_dst->mesg[null_idx].raw = current_pos + msghdr_size;
790         oh_dst->mesg[null_idx].raw_size = dst_oh_null -  msghdr_size;
791         oh_dst->mesg[null_idx].chunkno = 0;
792     } /* end if */
793 
794     /* Make sure we filled the chunk, except for room at the end for a checksum */
795     HDassert(current_pos + dst_oh_gap + dst_oh_null + H5O_SIZEOF_CHKSUM_OH(oh_dst) == (size_t)dst_oh_size + oh_dst->chunk[0].image);
796 
797     /* Set the dest. object location to the first chunk address */
798     HDassert(H5F_addr_defined(addr_new));
799     oloc_dst->addr = addr_new;
800 
801 
802     /* If we are merging committed datatypes and this is a committed datatype, insert
803      * the copied datatype into the list of committed datatypes in the target file.
804      */
805     if(cpy_info->merge_comm_dt && obj_class->type == H5O_TYPE_NAMED_DATATYPE)
806         if(H5O__copy_insert_comm_dt(oloc_src->file, oh_src, oloc_dst, cpy_info) < 0)
807             HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "can't insert committed datatype into destination list")
808 
809     /* Allocate space for the address mapping of the object copied */
810     if(NULL == (addr_map = H5FL_MALLOC(H5O_addr_map_t)))
811         HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
812 
813     /* Insert the address mapping for the new object into the copied list */
814     /* (Do this here, because "post copy" possibly checks it) */
815     H5F_GET_FILENO(oloc_src->file, addr_map->src_obj_pos.fileno);
816     addr_map->src_obj_pos.addr = oloc_src->addr;
817     addr_map->dst_addr = oloc_dst->addr;
818     addr_map->is_locked = TRUE;                 /* We've locked the object currently */
819     addr_map->inc_ref_count = 0;                /* Start with no additional ref counts to add */
820     addr_map->obj_class = obj_class;
821     addr_map->udata = cpy_udata;
822 
823     /* Insert into skip list */
824     if(H5SL_insert(cpy_info->map_list, addr_map, &(addr_map->src_obj_pos)) < 0) {
825         addr_map = H5FL_FREE(H5O_addr_map_t, addr_map);
826         HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, FAIL, "can't insert object into skip list")
827     } /* end if */
828 
829     /* "post copy" loop over messages, to fix up any messages which require a complete
830      * object header for destination object
831      */
832     null_msgs = 0;
833     for(mesgno = 0; mesgno < orig_dst_msgs; mesgno++) {
834         /* Skip any deleted or NULL messages in the source unless the
835          * preserve_null flag is set
836          */
837         if(FALSE == cpy_info->preserve_null) {
838             while(deleted[mesgno + null_msgs]) {
839                 ++null_msgs;
840                 HDassert(mesgno + null_msgs < oh_src->nmesgs);
841             } /* end while */
842         } /* end if */
843 
844         /* Set up convenience variables */
845         mesg_src = &(oh_src->mesg[mesgno + null_msgs]);
846         mesg_dst = &(oh_dst->mesg[mesgno]);
847 
848         /* Check for message class to operate on */
849         /* (Use destination message, in case the message has been removed (i.e
850          *      converted to a nil message) in the destination -QAK)
851          */
852         copy_type = mesg_dst->type;
853         HDassert(copy_type);
854 
855         if(copy_type->post_copy_file && mesg_src->native) {
856             unsigned mesg_flags;        /* Message flags */
857 
858             /* Sanity check destination message */
859             HDassert(mesg_dst->type == mesg_src->type);
860             HDassert(mesg_dst->native);
861 
862             /* Get destination message flags.   mesg_dst->flags will contain the
863              * original flags for now. */
864             mesg_flags = (unsigned)mesg_dst->flags;
865 
866             /* the object header is needed in the post copy for shared message */
867             cpy_info->oh_dst = oh_dst;
868 
869             /* Perform "post copy" operation on message */
870             if((copy_type->post_copy_file)(oloc_src, mesg_src->native, oloc_dst,
871                     mesg_dst->native, &mesg_flags, cpy_info) < 0)
872                 HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to perform 'post copy' operation on message")
873 
874             /* Verify that the flags did not change */
875             HDassert(mesg_flags == (unsigned) mesg_dst->flags);
876         } /* end if */
877     } /* end for */
878 
879     /* Indicate that the destination address will no longer be locked */
880     addr_map->is_locked = FALSE;
881 
882     /* Increment object header's reference count, if any descendents have created links to this object */
883     if(addr_map->inc_ref_count) {
884         H5_CHECK_OVERFLOW(addr_map->inc_ref_count, hsize_t, unsigned);
885         oh_dst->nlink += (unsigned)addr_map->inc_ref_count;
886     } /* end if */
887 
888     /* Retag all copied metadata to apply the destination object's tag */
889     if(H5AC_retag_copied_metadata(oloc_dst->file, oloc_dst->addr) < 0)
890         HGOTO_ERROR(H5E_CACHE, H5E_CANTTAG, FAIL, "unable to re-tag metadata entries")
891 
892     /* Set metadata tag for destination object's object header */
893     H5_BEGIN_TAG(oloc_dst->addr);
894 
895     /* Insert destination object header in cache */
896     if(H5AC_insert_entry(oloc_dst->file, H5AC_OHDR, oloc_dst->addr, oh_dst, H5AC__NO_FLAGS_SET) < 0)
897         HGOTO_ERROR_TAG(H5E_OHDR, H5E_CANTINSERT, FAIL, "unable to cache object header")
898     oh_dst = NULL;
899     inserted = TRUE;
900 
901     /* Reset metadat tag */
902     H5_END_TAG
903 
904     /* Set obj_type and udata, if requested */
905     if(obj_type) {
906         HDassert(udata);
907         *obj_type = obj_class->type;
908         *udata = cpy_udata;
909     } /* end if */
910 
911 done:
912     /* Free deleted array */
913     if(deleted)
914         H5MM_free(deleted);
915 
916     /* Release pointer to source object header and its derived objects */
917     if(oh_src && H5O_unprotect(oloc_src, oh_src, H5AC__NO_FLAGS_SET) < 0)
918         HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header")
919 
920     /* Free destination object header on failure */
921     if(ret_value < 0) {
922         if(oh_dst && !inserted) {
923             if(H5O__free(oh_dst) < 0)
924                 HDONE_ERROR(H5E_OHDR, H5E_CANTFREE, FAIL, "unable to destroy object header data")
925             if(H5O_loc_reset(oloc_dst) < 0)
926                 HDONE_ERROR(H5E_OHDR, H5E_CANTFREE, FAIL, "unable to destroy object header data")
927         } /* end if */
928 
929         if(addr_map == NULL && cpy_udata) {
930             if(obj_class && obj_class->free_copy_file_udata)
931                 obj_class->free_copy_file_udata(cpy_udata);
932         } /* end if */
933     }
934 
935     FUNC_LEAVE_NOAPI_TAG(ret_value)
936 } /* end H5O__copy_header_real() */
937 
938 
939 /*-------------------------------------------------------------------------
940  * Function:    H5O_copy_header_map
941  *
942  * Purpose:     Copy header object from one location to another, detecting
943  *              already mapped objects, etc.
944  *
945  * Return:      Non-negative on success/Negative on failure
946  *
947  * Programmer:  Quincey Koziol
948  *              November 1, 2005
949  *
950  *-------------------------------------------------------------------------
951  */
952 herr_t
H5O_copy_header_map(const H5O_loc_t * oloc_src,H5O_loc_t * oloc_dst,H5O_copy_t * cpy_info,hbool_t inc_depth,H5O_type_t * obj_type,void ** udata)953 H5O_copy_header_map(const H5O_loc_t *oloc_src, H5O_loc_t *oloc_dst /*out*/,
954     H5O_copy_t *cpy_info, hbool_t inc_depth, H5O_type_t *obj_type,
955     void **udata /*out*/)
956 {
957     H5O_addr_map_t      *addr_map = NULL;       /* Address mapping of object copied */
958     H5_obj_t            src_obj_pos;            /* Position of source object */
959     hbool_t             inc_link;               /* Whether to increment the link count for the object */
960     herr_t              ret_value = SUCCEED;
961 
962     FUNC_ENTER_NOAPI(FAIL)
963 
964     /* Sanity check */
965     HDassert(oloc_src);
966     HDassert(oloc_src->file);
967     HDassert(oloc_dst);
968     HDassert(oloc_dst->file);
969     HDassert(cpy_info);
970 
971     /* Create object "position" struct */
972     H5F_GET_FILENO(oloc_src->file, src_obj_pos.fileno);
973     src_obj_pos.addr = oloc_src->addr;
974 
975     /* Search for the object in the skip list of copied objects */
976     addr_map = (H5O_addr_map_t *)H5SL_search(cpy_info->map_list,
977             &src_obj_pos);
978 
979     /* Check if address is already in list of objects copied */
980     if(addr_map == NULL) {
981         /* Copy object for the first time */
982 
983         /* Check for incrementing the depth of copy */
984         /* (Can't do this for all copies, since committed datatypes should always be copied) */
985         if(inc_depth)
986             cpy_info->curr_depth++;
987 
988         /* Copy object referred to */
989         if(H5O__copy_header_real(oloc_src, oloc_dst, cpy_info, obj_type, udata) < 0)
990             HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, FAIL, "unable to copy object")
991 
992         /* Check for incrementing the depth of copy */
993         if(inc_depth)
994             cpy_info->curr_depth--;
995 
996         /* When an object is copied for the first time, increment it's link */
997         inc_link = TRUE;
998 
999         /* indicate that a new object is created */
1000         ret_value++;
1001     } /* end if */
1002     else {
1003         /* Object has already been copied, set its address in destination file */
1004         oloc_dst->addr = addr_map->dst_addr;
1005 
1006         /* Return saved obj_type and udata, if requested */
1007         if(obj_type) {
1008             HDassert(udata);
1009             *obj_type = addr_map->obj_class->type;
1010             *udata = addr_map->udata;
1011         } /* end if */
1012 
1013         /* If the object is locked currently (because we are copying a group
1014          * hierarchy and this is a link to a group higher in the hierarchy),
1015          * increment it's deferred reference count instead of incrementing the
1016          * reference count now.
1017          */
1018         if(addr_map->is_locked) {
1019             addr_map->inc_ref_count++;
1020             inc_link = FALSE;
1021         } /* end if */
1022         else
1023             inc_link = TRUE;
1024     } /* end else */
1025 
1026     /* Increment destination object's link count, if allowed */
1027     if(inc_link)
1028         if(H5O_link(oloc_dst, 1) < 0)
1029             HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to increment object link count")
1030 
1031 done:
1032     FUNC_LEAVE_NOAPI(ret_value)
1033 } /* end H5O_copy_header_map() */
1034 
1035 
1036 /*--------------------------------------------------------------------------
1037  NAME
1038     H5O__copy_free_addrmap_cb
1039  PURPOSE
1040     Internal routine to free address maps from the skip list for copying objects
1041  USAGE
1042     herr_t H5O__copy_free_addrmap_cb(item, key, op_data)
1043         void *item;             IN/OUT: Pointer to addr
1044         void *key;              IN/OUT: (unused)
1045         void *op_data;          IN: (unused)
1046  RETURNS
1047     Returns zero on success, negative on failure.
1048  DESCRIPTION
1049         Releases the memory for the address.
1050  GLOBAL VARIABLES
1051  COMMENTS, BUGS, ASSUMPTIONS
1052  EXAMPLES
1053  REVISION LOG
1054 --------------------------------------------------------------------------*/
1055 static herr_t
H5O__copy_free_addrmap_cb(void * _item,void H5_ATTR_UNUSED * key,void H5_ATTR_UNUSED * op_data)1056 H5O__copy_free_addrmap_cb(void *_item, void H5_ATTR_UNUSED *key, void H5_ATTR_UNUSED *op_data)
1057 {
1058     H5O_addr_map_t *item = (H5O_addr_map_t *)_item;
1059 
1060     FUNC_ENTER_STATIC_NOERR
1061 
1062     HDassert(item);
1063 
1064     /* Release user data for particular type of object */
1065     if(item->udata) {
1066         HDassert(item->obj_class);
1067         HDassert(item->obj_class->free_copy_file_udata);
1068         (item->obj_class->free_copy_file_udata)(item->udata);
1069     } /* end if */
1070 
1071     /* Release the item */
1072     item = H5FL_FREE(H5O_addr_map_t, item);
1073 
1074     FUNC_LEAVE_NOAPI(0)
1075 }   /* H5O__copy_free_addrmap_cb() */
1076 
1077 
1078 /*-------------------------------------------------------------------------
1079  * Function:    H5O__copy_header
1080  *
1081  * Purpose:     copy header object from one location to another.
1082  *
1083  * Return:      Non-negative on success/Negative on failure
1084  *
1085  * Programmer:  Peter Cao
1086  *              May 30, 2005
1087  *
1088  *-------------------------------------------------------------------------
1089  */
1090 static herr_t
H5O__copy_header(const H5O_loc_t * oloc_src,H5O_loc_t * oloc_dst,hid_t ocpypl_id,hid_t lcpl_id)1091 H5O__copy_header(const H5O_loc_t *oloc_src, H5O_loc_t *oloc_dst /*out */,
1092     hid_t ocpypl_id, hid_t lcpl_id)
1093 {
1094     H5O_copy_t  cpy_info;               /* Information for copying object */
1095     H5P_genplist_t  *ocpy_plist;        /* Object copy property list created */
1096     H5O_copy_dtype_merge_list_t *dt_list = NULL; /* List of datatype merge suggestions */
1097     H5O_mcdt_cb_info_t   cb_info;      	/* Callback info struct */
1098     unsigned    cpy_option = 0;         /* Copy options */
1099     herr_t      ret_value = SUCCEED;
1100 
1101     FUNC_ENTER_STATIC
1102 
1103     /* Sanity check */
1104     HDassert(oloc_src);
1105     HDassert(oloc_src->file);
1106     HDassert(H5F_addr_defined(oloc_src->addr));
1107     HDassert(oloc_dst->file);
1108 
1109     /* Initialize copy info before errors can be thrown */
1110     HDmemset(&cpy_info, 0, sizeof(H5O_copy_t));
1111 
1112     /* Get the copy property list */
1113     if(NULL == (ocpy_plist = (H5P_genplist_t *)H5I_object(ocpypl_id)))
1114         HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property list")
1115 
1116     /* Retrieve the copy parameters */
1117     if(H5P_get(ocpy_plist, H5O_CPY_OPTION_NAME, &cpy_option) < 0)
1118         HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get object copy flag")
1119 
1120     /* Retrieve the marge committed datatype list */
1121     if(H5P_peek(ocpy_plist, H5O_CPY_MERGE_COMM_DT_LIST_NAME, &dt_list) < 0)
1122         HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get merge committed datatype list")
1123 
1124     /* Get callback info */
1125     if(H5P_get(ocpy_plist, H5O_CPY_MCDT_SEARCH_CB_NAME, &cb_info) < 0)
1126         HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get callback info")
1127 
1128     /* Convert copy flags into copy struct */
1129     if((cpy_option & H5O_COPY_SHALLOW_HIERARCHY_FLAG) > 0) {
1130         cpy_info.copy_shallow = TRUE;
1131         cpy_info.max_depth = 1;
1132     } /* end if */
1133     else
1134         cpy_info.max_depth = -1;        /* Current default is for full, recursive hier. copy */
1135     cpy_info.curr_depth = 0;
1136     if((cpy_option & H5O_COPY_EXPAND_SOFT_LINK_FLAG) > 0)
1137         cpy_info.expand_soft_link = TRUE;
1138     if((cpy_option & H5O_COPY_EXPAND_EXT_LINK_FLAG) > 0)
1139         cpy_info.expand_ext_link = TRUE;
1140     if((cpy_option & H5O_COPY_EXPAND_REFERENCE_FLAG) > 0)
1141         cpy_info.expand_ref = TRUE;
1142     if((cpy_option & H5O_COPY_WITHOUT_ATTR_FLAG) > 0)
1143         cpy_info.copy_without_attr = TRUE;
1144     if((cpy_option & H5O_COPY_PRESERVE_NULL_FLAG) > 0)
1145         cpy_info.preserve_null = TRUE;
1146     if((cpy_option & H5O_COPY_MERGE_COMMITTED_DTYPE_FLAG) > 0)
1147         cpy_info.merge_comm_dt = TRUE;
1148 
1149     /* Add dt_list to copy struct */
1150     cpy_info.dst_dt_suggestion_list = dt_list;
1151 
1152     /* Add set callback information */
1153     cpy_info.mcdt_cb = cb_info.func;
1154     cpy_info.mcdt_ud = cb_info.user_data;
1155 
1156     /* Add property lists needed by callbacks */
1157     cpy_info.lcpl_id = lcpl_id;
1158 
1159     /* Create a skip list to keep track of which objects are copied */
1160     if(NULL == (cpy_info.map_list = H5SL_create(H5SL_TYPE_OBJ, NULL)))
1161         HGOTO_ERROR(H5E_SLIST, H5E_CANTCREATE, FAIL, "cannot make skip list")
1162 
1163     /* copy the object from the source file to the destination file */
1164     if(H5O__copy_header_real(oloc_src, oloc_dst, &cpy_info, NULL, NULL) < 0)
1165         HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, FAIL, "unable to copy object")
1166 
1167 done:
1168     if(cpy_info.map_list)
1169         H5SL_destroy(cpy_info.map_list, H5O__copy_free_addrmap_cb, NULL);
1170     if(cpy_info.dst_dt_list)
1171         H5SL_destroy(cpy_info.dst_dt_list, H5O__copy_free_comm_dt_cb, NULL);
1172 
1173     FUNC_LEAVE_NOAPI(ret_value)
1174 } /* end H5O__copy_header() */
1175 
1176 
1177 /*-------------------------------------------------------------------------
1178  * Function:    H5O__copy_obj
1179  *
1180  * Purpose:     Copy an object to destination location
1181  *
1182  * Return:      Non-negative on success/Negative on failure
1183  *
1184  * Programmer:  Peter Cao
1185  *              June 4, 2005
1186  *
1187  *-------------------------------------------------------------------------
1188  */
1189 static herr_t
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)1190 H5O__copy_obj(H5G_loc_t *src_loc, H5G_loc_t *dst_loc, const char *dst_name,
1191     hid_t ocpypl_id, hid_t lcpl_id)
1192 {
1193     H5G_name_t      new_path;                   /* Copied object group hier. path */
1194     H5O_loc_t       new_oloc;                   /* Copied object object location */
1195     H5G_loc_t       new_loc;                    /* Group location of object copied */
1196     H5F_t           *cached_dst_file;           /* Cached destination file */
1197     hbool_t         entry_inserted = FALSE;     /* Flag to indicate that the new entry was inserted into a group */
1198     herr_t          ret_value = SUCCEED;        /* Return value */
1199 
1200     FUNC_ENTER_STATIC
1201 
1202     HDassert(src_loc);
1203     HDassert(src_loc->oloc->file);
1204     HDassert(dst_loc);
1205     HDassert(dst_loc->oloc->file);
1206     HDassert(dst_name);
1207 
1208     /* Set up copied object location to fill in */
1209     new_loc.oloc = &new_oloc;
1210     new_loc.path = &new_path;
1211     H5G_loc_reset(&new_loc);
1212     new_oloc.file = dst_loc->oloc->file;
1213 
1214     /* Make a copy of the destination file, in case the original is changed by
1215      * H5O__copy_header.  If and when oloc's point to the shared file struct,
1216      * this will no longer be necessary, so this code can be removed. */
1217     cached_dst_file = dst_loc->oloc->file;
1218 
1219     /* Copy the object from the source file to the destination file */
1220     if(H5O__copy_header(src_loc->oloc, &new_oloc, ocpypl_id, lcpl_id) < 0)
1221         HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, FAIL, "unable to copy object")
1222 
1223     /* Patch dst_loc.  Again, this can be removed once oloc's point to shared
1224      * file structs. */
1225     dst_loc->oloc->file = cached_dst_file;
1226 
1227     /* Insert the new object in the destination file's group */
1228     if(H5L_link(dst_loc, dst_name, &new_loc, lcpl_id) < 0)
1229 	HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to insert link")
1230     entry_inserted = TRUE;
1231 
1232 done:
1233     /* Free the ID to name buffers */
1234     if(entry_inserted)
1235         H5G_loc_free(&new_loc);
1236 
1237     FUNC_LEAVE_NOAPI(ret_value)
1238 } /* end H5O__copy_obj() */
1239 
1240 
1241 /*-------------------------------------------------------------------------
1242  * Function:    H5O__copy_obj_by_ref
1243  *
1244  * Purpose:     Copy the object pointed by _src_ref.
1245  *
1246  * Return:      Non-negative on success/Negative on failure
1247  *
1248  * Programmer:  Peter Cao
1249  *              Aug 7 2006
1250  *
1251  *-------------------------------------------------------------------------
1252  */
1253 static herr_t
H5O__copy_obj_by_ref(H5O_loc_t * src_oloc,H5O_loc_t * dst_oloc,H5G_loc_t * dst_root_loc,H5O_copy_t * cpy_info)1254 H5O__copy_obj_by_ref(H5O_loc_t *src_oloc, H5O_loc_t *dst_oloc,
1255     H5G_loc_t *dst_root_loc, H5O_copy_t *cpy_info)
1256 {
1257     herr_t  ret_value = SUCCEED;
1258 
1259     FUNC_ENTER_STATIC
1260 
1261     HDassert(src_oloc);
1262     HDassert(dst_oloc);
1263 
1264     /* Perform the copy, or look up existing copy */
1265     if((ret_value = H5O_copy_header_map(src_oloc, dst_oloc, cpy_info, FALSE, NULL, NULL)) < 0)
1266         HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, FAIL, "unable to copy object")
1267 
1268     /* Check if a new valid object is copied to the destination */
1269     if(H5F_addr_defined(dst_oloc->addr) && (ret_value > SUCCEED)) {
1270         char    tmp_obj_name[80];
1271         H5G_name_t      new_path;
1272         H5O_loc_t       new_oloc;
1273         H5G_loc_t       new_loc;
1274 
1275         /* Set up group location for new object */
1276         new_loc.oloc = &new_oloc;
1277         new_loc.path = &new_path;
1278         H5G_loc_reset(&new_loc);
1279         new_oloc.file = dst_oloc->file;
1280         new_oloc.addr = dst_oloc->addr;
1281 
1282         /* Pick a default name for the new object */
1283         HDsnprintf(tmp_obj_name, sizeof(tmp_obj_name), "~obj_pointed_by_%llu", (unsigned long long)dst_oloc->addr);
1284 
1285         /* Create a link to the newly copied object */
1286         /* Note: since H5O_copy_header_map actually copied the target object, it
1287          * must exist either in cache or on disk, therefore it is is safe to not
1288          * pass the obj_type and udata fields returned by H5O_copy_header_map.
1289          * This could be changed in the future to slightly improve performance
1290          * --NAF */
1291         if(H5L_link(dst_root_loc, tmp_obj_name, &new_loc, cpy_info->lcpl_id) < 0)
1292             HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to insert link")
1293 
1294         H5G_loc_free(&new_loc);
1295     } /* if (H5F_addr_defined(dst_oloc.addr)) */
1296 
1297 done:
1298     FUNC_LEAVE_NOAPI(ret_value)
1299 } /* end H5O__copy_obj_by_ref() */
1300 
1301 
1302 /*-------------------------------------------------------------------------
1303  * Function:	H5O_copy_expand_ref
1304  *
1305  * Purpose:	Copy the object pointed by _src_ref.
1306  *
1307  * Return:	Non-negative on success/Negative on failure
1308  *
1309  * Programmer:  Peter Cao
1310  *		Aug 7 2006
1311  *
1312  *-------------------------------------------------------------------------
1313  */
1314 herr_t
H5O_copy_expand_ref(H5F_t * file_src,void * _src_ref,H5F_t * file_dst,void * _dst_ref,size_t ref_count,H5R_type_t ref_type,H5O_copy_t * cpy_info)1315 H5O_copy_expand_ref(H5F_t *file_src, void *_src_ref, H5F_t *file_dst,
1316     void *_dst_ref, size_t ref_count, H5R_type_t ref_type, H5O_copy_t *cpy_info)
1317 {
1318     H5O_loc_t 	dst_oloc;         	/* Copied object object location */
1319     H5O_loc_t	src_oloc;          	/* Temporary object location for source object */
1320     H5G_loc_t   dst_root_loc;           /* The location of root group of the destination file */
1321     const uint8_t *q;                   /* Pointer to source OID to store */
1322     uint8_t     *p;                     /* Pointer to destination OID to store */
1323     size_t      i;                      /* Local index variable */
1324     herr_t	ret_value = SUCCEED;
1325 
1326     FUNC_ENTER_NOAPI(FAIL)
1327 
1328     /* Sanity checks */
1329     HDassert(file_src);
1330     HDassert(_src_ref);
1331     HDassert(file_dst);
1332     HDassert(_dst_ref);
1333     HDassert(ref_count);
1334     HDassert(cpy_info);
1335 
1336     /* Initialize object locations */
1337     H5O_loc_reset(&src_oloc);
1338     H5O_loc_reset(&dst_oloc);
1339     src_oloc.file = file_src;
1340     dst_oloc.file = file_dst;
1341 
1342     /* Set up the root group in the destination file */
1343     if(NULL == (dst_root_loc.oloc = H5G_oloc(H5G_rootof(file_dst))))
1344         HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get object location for root group")
1345     if(NULL == (dst_root_loc.path = H5G_nameof(H5G_rootof(file_dst))))
1346         HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get path for root group")
1347 
1348     /* Copy object references */
1349     if(H5R_OBJECT == ref_type) {
1350         hobj_ref_t *src_ref = (hobj_ref_t *)_src_ref;
1351         hobj_ref_t *dst_ref = (hobj_ref_t *)_dst_ref;
1352 
1353         /* Making equivalent references in the destination file */
1354         for(i = 0; i < ref_count; i++) {
1355             /* Set up for the object copy for the reference */
1356             q = (uint8_t *)(&src_ref[i]);
1357             H5F_addr_decode(src_oloc.file, (const uint8_t **)&q, &(src_oloc.addr));
1358             dst_oloc.addr = HADDR_UNDEF;
1359 
1360             /* Attempt to copy object from source to destination file */
1361             if(src_oloc.addr != (haddr_t)0) {
1362                 if(H5O__copy_obj_by_ref(&src_oloc, &dst_oloc, &dst_root_loc, cpy_info) < 0)
1363                     HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, FAIL, "unable to copy object")
1364             } /* end if */
1365             else
1366                 /* Set parameters so the reference is written as all 0's */
1367                 HDmemset(&dst_oloc.addr, 0, sizeof(dst_oloc.addr));
1368 
1369             /* Set the object reference info for the destination file */
1370             p = (uint8_t *)(&dst_ref[i]);
1371             H5F_addr_encode(dst_oloc.file, &p, dst_oloc.addr);
1372 	} /* end for */
1373     }  /* end if */
1374     /* Copy region references */
1375     else if(H5R_DATASET_REGION == ref_type) {
1376         hdset_reg_ref_t *src_ref = (hdset_reg_ref_t *)_src_ref;
1377         hdset_reg_ref_t *dst_ref = (hdset_reg_ref_t *)_dst_ref;
1378         uint8_t *buf = NULL;    /* Buffer to store serialized selection in */
1379         H5HG_t hobjid;          /* Heap object ID */
1380         size_t buf_size;        /* Length of object in heap */
1381 
1382         /* Making equivalent references in the destination file */
1383         for(i = 0; i < ref_count; i++) {
1384             /* Get the heap ID for the dataset region */
1385             q = (const uint8_t *)(&src_ref[i]);
1386             H5F_addr_decode(src_oloc.file, (const uint8_t **)&q, &(hobjid.addr));
1387             UINT32DECODE(q, hobjid.idx);
1388 
1389             if(hobjid.addr != (haddr_t)0) {
1390                 /* Get the dataset region from the heap (allocate inside routine) */
1391                 if((buf = (uint8_t *)H5HG_read(src_oloc.file, &hobjid, NULL, &buf_size)) == NULL)
1392                     HGOTO_ERROR(H5E_REFERENCE, H5E_READERROR, FAIL, "Unable to read dataset region information")
1393 
1394                 /* Get the object oid for the dataset */
1395                 q = (const uint8_t *)buf;
1396                 H5F_addr_decode(src_oloc.file, (const uint8_t **)&q, &(src_oloc.addr));
1397                 dst_oloc.addr = HADDR_UNDEF;
1398 
1399                 /* copy the object pointed by the ref to the destination */
1400                 if(H5O__copy_obj_by_ref(&src_oloc, &dst_oloc, &dst_root_loc, cpy_info) < 0) {
1401                     H5MM_xfree(buf);
1402                     HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, FAIL, "unable to copy object")
1403                 } /* end if */
1404 
1405                 /* Serialize object ID */
1406                 p = (uint8_t *)buf;
1407                 H5F_addr_encode(dst_oloc.file, &p, dst_oloc.addr);
1408 
1409                 /* Save the serialized buffer to the destination */
1410                 if(H5HG_insert(dst_oloc.file, buf_size, buf, &hobjid) < 0) {
1411                     H5MM_xfree(buf);
1412                     HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, FAIL, "Unable to write dataset region information")
1413                 } /* end if */
1414             } /* end if */
1415             else
1416                 /* Set parameters so the reference is written as all 0's */
1417                 HDmemset(&hobjid, 0, sizeof(hobjid));
1418 
1419             /* Set the dataset region reference info for the destination file */
1420             p = (uint8_t *)(&dst_ref[i]);
1421             H5F_addr_encode(dst_oloc.file, &p, hobjid.addr);
1422             UINT32ENCODE(p, hobjid.idx);
1423 
1424             /* Free the buffer allocated in H5HG_read() */
1425             H5MM_xfree(buf);
1426         } /* end for */
1427     } /* end if */
1428     else
1429         HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid reference type")
1430 
1431 done:
1432     FUNC_LEAVE_NOAPI(ret_value)
1433 } /* end H5O_copy_expand_ref() */
1434 
1435 
1436 /*-------------------------------------------------------------------------
1437  * Function:    H5O__copy_free_comm_dt_cb
1438  *
1439  * Purpose:     Frees the merge committed dt skip list key and object.
1440  *
1441  * Return:      SUCCEED (never fails)
1442  *
1443  * Programmer:  Neil Fortner
1444  *              Oct 6 2011
1445  *
1446  *-------------------------------------------------------------------------
1447  */
1448 static herr_t
H5O__copy_free_comm_dt_cb(void * item,void * _key,void H5_ATTR_UNUSED * _op_data)1449 H5O__copy_free_comm_dt_cb(void *item, void *_key, void H5_ATTR_UNUSED *_op_data)
1450 {
1451     haddr_t     *addr = (haddr_t *)item;
1452     H5O_copy_search_comm_dt_key_t *key = (H5O_copy_search_comm_dt_key_t *)_key;
1453 
1454     FUNC_ENTER_STATIC_NOERR
1455 
1456     HDassert(addr);
1457     HDassert(key);
1458     HDassert(key->dt);
1459 
1460     key->dt = (H5T_t *)H5O_msg_free(H5O_DTYPE_ID, key->dt);
1461     key = H5FL_FREE(H5O_copy_search_comm_dt_key_t, key);
1462     addr = H5FL_FREE(haddr_t, addr);
1463 
1464     FUNC_LEAVE_NOAPI(SUCCEED)
1465 } /* end H5O__copy_free_comm_dt_cb */
1466 
1467 
1468 /*-------------------------------------------------------------------------
1469  * Function:    H5O__copy_comm_dt_cmp
1470  *
1471  * Purpose:     Skiplist callback used to compare 2 keys for the merge
1472  *              committed dt list.  Mostly a wrapper for H5T_cmp.
1473  *
1474  * Return:      0 if key1 and key2 are equal.
1475  *              <0 if key1 is less than key2.
1476  *              >0 if key1 is greater than key2.
1477  *
1478  * Programmer:  Neil Fortner
1479  *              Oct 6 2011
1480  *
1481  *-------------------------------------------------------------------------
1482  */
1483 static int
H5O__copy_comm_dt_cmp(const void * _key1,const void * _key2)1484 H5O__copy_comm_dt_cmp(const void *_key1, const void *_key2)
1485 {
1486     const H5O_copy_search_comm_dt_key_t *key1 = (const H5O_copy_search_comm_dt_key_t *)_key1;
1487     const H5O_copy_search_comm_dt_key_t *key2 = (const H5O_copy_search_comm_dt_key_t *)_key2;
1488     int ret_value = 0;
1489 
1490     FUNC_ENTER_STATIC_NOERR
1491 
1492     /* Check fileno.  It is unlikely to be different so check if they are equal
1493      * first so only one comparison needs to be made. */
1494     if(key1->fileno != key2->fileno) {
1495         if(key1->fileno < key2->fileno)
1496             HGOTO_DONE(-1)
1497         if(key1->fileno > key2->fileno)
1498             HGOTO_DONE(1)
1499     } /* end if */
1500 
1501     ret_value = H5T_cmp(key1->dt, key2->dt, FALSE);
1502 
1503 done:
1504     FUNC_LEAVE_NOAPI(ret_value)
1505 } /* end H5O__copy_comm_dt_cmp */
1506 
1507 
1508 /*-------------------------------------------------------------------------
1509  * Function:    H5O_copy_search_comm_dt_attr_cb
1510  *
1511  * Purpose:     Callback for H5O_attr_iterate_real from
1512  *              H5O_copy_search_comm_dt_check.  Checks if the attribute's
1513  *              datatype is committed.  If it is, adds it to the merge
1514  *              committed dt skiplist present in udata if it does not match
1515  *              any already present.
1516  *
1517  * Return:      Non-negative on success/Negative on failure
1518  *
1519  * Programmer:  Neil Fortner
1520  *              Nov 3 2011
1521  *
1522  *-------------------------------------------------------------------------
1523  */
1524 static herr_t
H5O_copy_search_comm_dt_attr_cb(const H5A_t * attr,void * _udata)1525 H5O_copy_search_comm_dt_attr_cb(const H5A_t *attr, void *_udata)
1526 {
1527     H5O_copy_search_comm_dt_ud_t *udata = (H5O_copy_search_comm_dt_ud_t *)_udata;
1528     H5T_t       *dt = NULL;             /* Datatype */
1529     H5O_copy_search_comm_dt_key_t *key = NULL; /* Skiplist key */
1530     haddr_t     *addr = NULL;           /* Destination address */
1531     hbool_t     obj_inserted = FALSE;   /* Object inserted into skip list */
1532     herr_t      ret_value = SUCCEED;    /* Return value */
1533 
1534     FUNC_ENTER_NOAPI_NOINIT
1535 
1536     /* Sanity checks */
1537     HDassert(attr);
1538     HDassert(udata);
1539     HDassert(udata->dst_dt_list);
1540     HDassert(H5F_addr_defined(udata->obj_oloc.addr));
1541 
1542     /* Get attribute datatype */
1543     if(NULL == (dt = H5A_type(attr)))
1544         HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "can't get attribute datatype")
1545 
1546     /* Check if the datatype is committed and search the skip list if so */
1547     if(H5T_committed(dt)) {
1548         /* Allocate key */
1549         if(NULL == (key = H5FL_MALLOC(H5O_copy_search_comm_dt_key_t)))
1550             HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
1551 
1552         /* Copy datatype into key */
1553         if(NULL == (key->dt = (H5T_t *)H5O_msg_copy(H5O_DTYPE_ID, dt, NULL)))
1554             HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to copy datatype message")
1555 
1556         /* Get datatype object fileno */
1557         H5F_GET_FILENO(udata->obj_oloc.file, key->fileno);
1558 
1559         if(!H5SL_search(udata->dst_dt_list, key)) {
1560             /* Allocate destination address */
1561             if(NULL == (addr = H5FL_MALLOC(haddr_t)))
1562                 HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
1563 
1564             /* Add the destination datatype to the skip list */
1565             *addr = ((H5O_shared_t *)(key->dt))->u.loc.oh_addr;
1566             if(H5SL_insert(udata->dst_dt_list, addr, key) < 0)
1567                 HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, FAIL, "can't insert object into skip list")
1568             obj_inserted = TRUE;
1569         } /* end if */
1570     } /* end if */
1571 
1572 done:
1573     /* Release resources */
1574     if(!obj_inserted) {
1575         if(key) {
1576             if(key->dt)
1577                 key->dt = (H5T_t *)H5O_msg_free(H5O_DTYPE_ID, key->dt);
1578             key = H5FL_FREE(H5O_copy_search_comm_dt_key_t, key);
1579         } /* end if */
1580         if(addr) {
1581             HDassert(ret_value < 0);
1582             addr = H5FL_FREE(haddr_t, addr);
1583         } /* end if */
1584     } /* end if */
1585 
1586     FUNC_LEAVE_NOAPI(ret_value)
1587 } /* end H5O_copy_search_comm_dt_attr_cb */
1588 
1589 
1590 /*-------------------------------------------------------------------------
1591  * Function:    H5O_copy_search_comm_dt_check
1592  *
1593  * Purpose:     Check if the object at obj_oloc is or contains a reference
1594  *              to a committed datatype.  If it does, adds it to the merge
1595  *              committed dt skiplist present in udata if it does not match
1596  *              any already present.
1597  *
1598  * Return:      Non-negative on success/Negative on failure
1599  *
1600  * Programmer:  Neil Fortner
1601  *              Nov 3 2011
1602  *
1603  *-------------------------------------------------------------------------
1604  */
1605 static herr_t
H5O_copy_search_comm_dt_check(H5O_loc_t * obj_oloc,H5O_copy_search_comm_dt_ud_t * udata)1606 H5O_copy_search_comm_dt_check(H5O_loc_t *obj_oloc,
1607     H5O_copy_search_comm_dt_ud_t *udata)
1608 {
1609     H5O_copy_search_comm_dt_key_t *key = NULL; /* Skiplist key */
1610     haddr_t     *addr = NULL;           /* Destination address */
1611     hbool_t     obj_inserted = FALSE;   /* Object inserted into skip list */
1612     H5A_attr_iter_op_t attr_op;         /* Attribute iteration operator */
1613     const H5O_obj_class_t  *obj_class = NULL;       /* Type of object */
1614     herr_t      ret_value = SUCCEED;    /* Return value */
1615 
1616     FUNC_ENTER_NOAPI_NOINIT
1617 
1618     /* Sanity checks */
1619     HDassert(obj_oloc);
1620     HDassert(udata);
1621     HDassert(udata->dst_dt_list);
1622     HDassert(udata->dst_root_loc);
1623 
1624     /* Get pointer to object class for this object */
1625     if((obj_class = H5O__obj_class(obj_oloc)) == NULL)
1626         HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to determine object type")
1627 
1628     /* Check if the object is a datatype, a dataset using a committed
1629      * datatype, or contains an attribute using a committed datatype */
1630     if(obj_class->type == H5O_TYPE_NAMED_DATATYPE) {
1631         /* Allocate key */
1632         if(NULL == (key = H5FL_MALLOC(H5O_copy_search_comm_dt_key_t)))
1633             HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
1634 
1635         /* Read the destination datatype */
1636         if(NULL == (key->dt = (H5T_t *)H5O_msg_read(obj_oloc, H5O_DTYPE_ID, NULL)))
1637             HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "can't read DTYPE message")
1638 
1639         /* Get destination object fileno */
1640         H5F_GET_FILENO(obj_oloc->file, key->fileno);
1641 
1642         /* Check if the datatype is already present in the skip list */
1643         if(!H5SL_search(udata->dst_dt_list, key)) {
1644             /* Allocate destination address */
1645             if(NULL == (addr = H5FL_MALLOC(haddr_t)))
1646                 HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
1647 
1648             /* Add the destination datatype to the skip list */
1649             *addr = obj_oloc->addr;
1650             if(H5SL_insert(udata->dst_dt_list, addr, key) < 0)
1651                 HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, FAIL, "can't insert object into skip list")
1652             obj_inserted = TRUE;
1653         } /* end if */
1654     } /* end if */
1655     else if(obj_class->type == H5O_TYPE_DATASET) {
1656         /* Allocate key */
1657         if(NULL == (key = H5FL_MALLOC(H5O_copy_search_comm_dt_key_t)))
1658             HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
1659 
1660         /* Read the destination datatype */
1661         if(NULL == (key->dt = (H5T_t *)H5O_msg_read(obj_oloc, H5O_DTYPE_ID, NULL)))
1662             HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "can't read DTYPE message")
1663 
1664         /* Check if the datatype is committed and search the skip list if so
1665             */
1666         if(H5T_committed(key->dt)) {
1667             /* Get datatype object fileno */
1668             H5F_GET_FILENO(obj_oloc->file, key->fileno);
1669 
1670             if(!H5SL_search(udata->dst_dt_list, key)) {
1671                 /* Allocate destination address */
1672                 if(NULL == (addr = H5FL_MALLOC(haddr_t)))
1673                     HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
1674 
1675                 /* Add the destination datatype to the skip list */
1676                 *addr = ((H5O_shared_t *)(key->dt))->u.loc.oh_addr;
1677                 if(H5SL_insert(udata->dst_dt_list, addr, key) < 0)
1678                     HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, FAIL, "can't insert object into skip list")
1679                 obj_inserted = TRUE;
1680             } /* end if */
1681         } /* end if */
1682     } /* end else */
1683 
1684     /* Search within attributes */
1685     attr_op.op_type = H5A_ATTR_OP_LIB;
1686     attr_op.u.lib_op = H5O_copy_search_comm_dt_attr_cb;
1687     udata->obj_oloc.file = obj_oloc->file;
1688     udata->obj_oloc.addr = obj_oloc->addr;
1689     if(H5O_attr_iterate_real((hid_t)-1, obj_oloc, H5_INDEX_NAME, H5_ITER_NATIVE, (hsize_t)0, NULL, &attr_op, udata) < 0)
1690         HGOTO_ERROR(H5E_OHDR, H5E_BADITER, FAIL, "error iterating over attributes");
1691 
1692 done:
1693     /* Release resources */
1694     if(!obj_inserted) {
1695         if(key) {
1696             if(key->dt)
1697                 key->dt = (H5T_t *)H5O_msg_free(H5O_DTYPE_ID, key->dt);
1698             key = H5FL_FREE(H5O_copy_search_comm_dt_key_t, key);
1699         } /* end if */
1700         if(addr) {
1701             HDassert(ret_value < 0);
1702             addr = H5FL_FREE(haddr_t, addr);
1703         } /* end if */
1704     } /* end if */
1705 
1706     FUNC_LEAVE_NOAPI(ret_value)
1707 } /* end H5O_copy_search_comm_dt_check */
1708 
1709 
1710 /*-------------------------------------------------------------------------
1711  * Function:    H5O__copy_search_comm_dt_cb
1712  *
1713  * Purpose:     H5G_visit callback to add committed datatypes to the merge
1714  *              committed dt skiplist.  Mostly a wrapper for
1715  *              H5O_copy_search_comm_dt_check.
1716  *
1717  * Return:      Non-negative on success/Negative on failure
1718  *
1719  * Programmer:  Neil Fortner
1720  *              Oct 6 2011
1721  *
1722  *-------------------------------------------------------------------------
1723  */
1724 static herr_t
H5O__copy_search_comm_dt_cb(hid_t H5_ATTR_UNUSED group,const char * name,const H5L_info_t * linfo,void * _udata)1725 H5O__copy_search_comm_dt_cb(hid_t H5_ATTR_UNUSED group, const char *name,
1726     const H5L_info_t *linfo, void *_udata)
1727 {
1728     H5O_copy_search_comm_dt_ud_t *udata = (H5O_copy_search_comm_dt_ud_t *)_udata; /* Skip list of dtypes in dest file */
1729     H5G_loc_t   obj_loc;                /* Location of object */
1730     H5O_loc_t   obj_oloc;               /* Object's object location */
1731     H5G_name_t  obj_path;               /* Object's group hier. path */
1732     hbool_t     obj_found = FALSE;      /* Object at 'name' found */
1733     herr_t      ret_value = H5_ITER_CONT; /* Return value */
1734 
1735     FUNC_ENTER_STATIC
1736 
1737     /* Sanity checks */
1738     HDassert(name);
1739     HDassert(linfo);
1740     HDassert(udata);
1741     HDassert(udata->dst_dt_list);
1742     HDassert(udata->dst_root_loc);
1743 
1744     /* Check if this is a hard link */
1745     if(linfo->type == H5L_TYPE_HARD) {
1746         /* Set up opened group location to fill in */
1747         obj_loc.oloc = &obj_oloc;
1748         obj_loc.path = &obj_path;
1749         H5G_loc_reset(&obj_loc);
1750 
1751         /* Find the object */
1752         if(H5G_loc_find(udata->dst_root_loc, name, &obj_loc/*out*/) < 0)
1753             HGOTO_ERROR(H5E_OHDR, H5E_NOTFOUND, H5_ITER_ERROR, "object not found")
1754         obj_found = TRUE;
1755 
1756         /* Check object and add to skip list if appropriate */
1757         if(H5O_copy_search_comm_dt_check(&obj_oloc, udata) < 0)
1758             HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, H5_ITER_ERROR, "can't check object")
1759     } /* end if */
1760 
1761 done:
1762     /* Release resources */
1763     if(obj_found && H5G_loc_free(&obj_loc) < 0)
1764         HDONE_ERROR(H5E_OHDR, H5E_CANTRELEASE, H5_ITER_ERROR, "can't free location")
1765 
1766     FUNC_LEAVE_NOAPI(ret_value)
1767 } /* end H5O__copy_search_comm_dt_cb */
1768 
1769 
1770 /*-------------------------------------------------------------------------
1771  * Function:    H5O__copy_search_comm_dt
1772  *
1773  * Purpose:     Checks if the committed datatype present in oh_src matches any
1774  *              in the destination file, building the destination file
1775  *              skiplist as necessary.
1776  *
1777  * Return:      TRUE if a match is found in the destination file
1778  *                      - oloc_dst will contain the address
1779  *              FALSE if a match is not found
1780  *              Negative on failure
1781  *
1782  * Programmer:  Neil Fortner
1783  *              Sep 27 2011
1784  *
1785  *-------------------------------------------------------------------------
1786  */
1787 static htri_t
H5O__copy_search_comm_dt(H5F_t * file_src,H5O_t * oh_src,H5O_loc_t * oloc_dst,H5O_copy_t * cpy_info)1788 H5O__copy_search_comm_dt(H5F_t *file_src, H5O_t *oh_src,
1789     H5O_loc_t *oloc_dst/*in, out*/, H5O_copy_t *cpy_info)
1790 {
1791     H5O_copy_search_comm_dt_key_t *key = NULL; /* Skiplist key */
1792     haddr_t     *dst_addr;      /* Destination datatype address */
1793     H5G_loc_t   dst_root_loc = {NULL, NULL}; /* Destination root group location */
1794     H5O_copy_search_comm_dt_ud_t udata; /* Group iteration user data */
1795     herr_t      ret_value = FALSE; /* Return value */
1796 
1797     FUNC_ENTER_STATIC
1798 
1799     /* Sanity checks */
1800     HDassert(oh_src);
1801     HDassert(oloc_dst);
1802     HDassert(oloc_dst->file);
1803     HDassert(H5F_FILE_ID(oloc_dst->file) >= 0);
1804     HDassert(cpy_info);
1805 
1806     /* Allocate key */
1807     if(NULL == (key = H5FL_MALLOC(H5O_copy_search_comm_dt_key_t)))
1808         HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
1809 
1810     /* Read the source datatype */
1811     if(NULL == (key->dt = (H5T_t *)H5O_msg_read_oh(file_src, oh_src, H5O_DTYPE_ID, NULL)))
1812         HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "can't read DTYPE message")
1813 
1814     /* Get destination object fileno */
1815     H5F_GET_FILENO(oloc_dst->file, key->fileno);
1816 
1817     /* Check if the destination dtype list exists, create it if it does not */
1818     if(!cpy_info->dst_dt_list) {
1819         /* Create the skip list */
1820         if(NULL == (cpy_info->dst_dt_list = H5SL_create(H5SL_TYPE_GENERIC, H5O__copy_comm_dt_cmp)))
1821             HGOTO_ERROR(H5E_OHDR, H5E_CANTCREATE, FAIL, "can't create skip list for committed datatypes")
1822 
1823         /* Add suggested types to list, if they are present */
1824         if(cpy_info->dst_dt_suggestion_list) {
1825             H5O_copy_dtype_merge_list_t *suggestion = cpy_info->dst_dt_suggestion_list;
1826             H5G_loc_t   obj_loc;                /* Location of object */
1827             H5O_loc_t   obj_oloc;               /* Object's object location */
1828             H5G_name_t  obj_path;               /* Object's group hier. path */
1829 
1830             /* Set up the root group in the destination file */
1831             if(NULL == (dst_root_loc.oloc = H5G_oloc(H5G_rootof(oloc_dst->file))))
1832                 HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get object location for root group")
1833             if(NULL == (dst_root_loc.path = H5G_nameof(H5G_rootof(oloc_dst->file))))
1834                 HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get path for root group")
1835 
1836             /* Set up opened group location to fill in */
1837             obj_loc.oloc = &obj_oloc;
1838             obj_loc.path = &obj_path;
1839             H5G_loc_reset(&obj_loc);
1840 
1841             /* Build udata */
1842             udata.dst_dt_list = cpy_info->dst_dt_list;
1843             udata.dst_root_loc = &dst_root_loc;
1844             udata.obj_oloc.file = NULL;
1845             udata.obj_oloc.addr = HADDR_UNDEF;
1846 
1847             /* Walk through the list of datatype suggestions */
1848             while(suggestion) {
1849                 /* Find the object */
1850                 if(H5G_loc_find(&dst_root_loc, suggestion->path, &obj_loc/*out*/) < 0)
1851                     /* Ignore errors - i.e. suggestions not present in
1852                      * destination file */
1853                     H5E_clear_stack(NULL);
1854                 else
1855                     /* Check object and add to skip list if appropriate */
1856                     if(H5O_copy_search_comm_dt_check(&obj_oloc, &udata) < 0) {
1857                         if(H5G_loc_free(&obj_loc) < 0)
1858                             HERROR(H5E_OHDR, H5E_CANTRELEASE, "can't free location");
1859                         HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "can't check object")
1860                     } /* end if */
1861 
1862                 /* Free location */
1863                 if(H5G_loc_free(&obj_loc) < 0)
1864                     HGOTO_ERROR(H5E_OHDR, H5E_CANTRELEASE, FAIL, "can't free location");
1865 
1866                 /* Advance the suggestion pointer */
1867                 suggestion = suggestion->next;
1868             } /* end while */
1869         } /* end if */
1870     }
1871 
1872     if(!cpy_info->dst_dt_list_complete) {
1873         /* Search for the type in the destination file, and return its address
1874          * if found, but only if the list is populated with and only with
1875          * suggested types.  We will search complete lists later. */
1876         if(cpy_info->dst_dt_suggestion_list
1877                 && NULL != (dst_addr = (haddr_t *)H5SL_search(
1878                 cpy_info->dst_dt_list, key))) {
1879             oloc_dst->addr = *dst_addr;
1880             ret_value = TRUE;
1881         } /* end if */
1882         else {
1883             H5O_mcdt_search_ret_t search_cb_ret = H5O_MCDT_SEARCH_CONT;
1884 
1885             /* Make callback to see if we should search destination file */
1886             if(cpy_info->mcdt_cb)
1887                 if((search_cb_ret = cpy_info->mcdt_cb(cpy_info->mcdt_ud)) == H5O_MCDT_SEARCH_ERROR)
1888                     HGOTO_ERROR(H5E_OHDR, H5E_CALLBACK, FAIL, "callback returned error")
1889 
1890             if(search_cb_ret == H5O_MCDT_SEARCH_CONT) {
1891                 /* Build the complete dst dt list */
1892                 /* Set up the root group in the destination file, if necessary */
1893                 if(!dst_root_loc.oloc) {
1894                     HDassert(!dst_root_loc.path);
1895                     if(NULL == (dst_root_loc.oloc = H5G_oloc(H5G_rootof(oloc_dst->file))))
1896                         HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get object location for root group")
1897                     if(NULL == (dst_root_loc.path = H5G_nameof(H5G_rootof(oloc_dst->file))))
1898                         HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get path for root group")
1899                 } /* end if */
1900                 else
1901                     HDassert(dst_root_loc.path);
1902 
1903                 /* Build udata.  Note that this may be done twice in some cases, but
1904                 * it should be rare and should be cheaper on average than trying to
1905                 * keep track of whether it was done before. */
1906                 udata.dst_dt_list = cpy_info->dst_dt_list;
1907                 udata.dst_root_loc = &dst_root_loc;
1908                 udata.obj_oloc.file = NULL;
1909                 udata.obj_oloc.addr = HADDR_UNDEF;
1910 
1911                 /* Traverse the destination file, adding committed datatypes to the skip
1912                 * list */
1913                 if(H5G_visit(H5F_FILE_ID(oloc_dst->file), "/", H5_INDEX_NAME, H5_ITER_NATIVE, H5O__copy_search_comm_dt_cb, &udata) < 0)
1914                     HGOTO_ERROR(H5E_OHDR, H5E_BADITER, FAIL, "object visitation failed")
1915                 cpy_info->dst_dt_list_complete = TRUE;
1916             } /* end if */
1917             else
1918                 if(search_cb_ret != H5O_MCDT_SEARCH_STOP)
1919                     HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unknown return value for callback")
1920         } /* end if */
1921     } /* end if */
1922 
1923     /* Search for the type in the destination file, and return its address if
1924      * found, but only if the list is complete */
1925     if(cpy_info->dst_dt_list_complete) {
1926         if(NULL != (dst_addr = (haddr_t *)H5SL_search(cpy_info->dst_dt_list, key))) {
1927             oloc_dst->addr = *dst_addr;
1928             ret_value = TRUE;
1929         } /* end if */
1930     } /* end if */
1931 
1932 done:
1933     if(key) {
1934         if(key->dt)
1935             key->dt = (H5T_t *)H5O_msg_free(H5O_DTYPE_ID, key->dt);
1936         key = H5FL_FREE(H5O_copy_search_comm_dt_key_t, key);
1937     } /* end if */
1938 
1939     FUNC_LEAVE_NOAPI(ret_value)
1940 } /* end H5O__copy_search_comm_dt */
1941 
1942 
1943 /*-------------------------------------------------------------------------
1944  * Function:    H5O__copy_insert_comm_dt
1945  *
1946  * Purpose:     Insert the committed datatype at oloc_dst into the merge committed
1947  *              dt skiplist.  The datatype must not be present already.
1948  *
1949  * Return:      Non-negative on success/Negative on failure
1950  *
1951  * Programmer:  Neil Fortner
1952  *              Oct 6 2011
1953  *
1954  *-------------------------------------------------------------------------
1955  */
1956 static herr_t
H5O__copy_insert_comm_dt(H5F_t * file_src,H5O_t * oh_src,H5O_loc_t * oloc_dst,H5O_copy_t * cpy_info)1957 H5O__copy_insert_comm_dt(H5F_t *file_src, H5O_t *oh_src, H5O_loc_t *oloc_dst,
1958     H5O_copy_t *cpy_info)
1959 {
1960     H5O_copy_search_comm_dt_key_t *key = NULL; /* Skiplist key */
1961     haddr_t     *addr = NULL;   /* Destination object address */
1962     herr_t      ret_value = SUCCEED; /* Return value */
1963 
1964     FUNC_ENTER_STATIC
1965 
1966     /* Sanity checks */
1967     HDassert(oh_src);
1968     HDassert(oloc_dst);
1969     HDassert(oloc_dst->file);
1970     HDassert(oloc_dst->addr != HADDR_UNDEF);
1971     HDassert(cpy_info);
1972     HDassert(cpy_info->dst_dt_list);
1973 
1974     /* Allocate key */
1975     if(NULL == (key = H5FL_MALLOC(H5O_copy_search_comm_dt_key_t)))
1976         HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
1977 
1978     /* Read the datatype.  Read from the source file because the destination
1979      * object could be changed in the post-copy. */
1980     if(NULL == (key->dt = (H5T_t *)H5O_msg_read_oh(file_src, oh_src, H5O_DTYPE_ID, NULL)))
1981         HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "can't read DTYPE message")
1982 
1983     /* Get destination object fileno */
1984     H5F_GET_FILENO(oloc_dst->file, key->fileno);
1985 
1986     /* Allocate destination address */
1987     if(NULL == (addr = H5FL_MALLOC(haddr_t)))
1988         HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
1989 
1990     /* Add the destination datatype to the skip list */
1991     *addr = oloc_dst->addr;
1992     if(H5SL_insert(cpy_info->dst_dt_list, addr, key) < 0)
1993         HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, FAIL, "can't insert object into skip list")
1994 
1995 done:
1996     if(ret_value < 0) {
1997         if(key) {
1998             if(key->dt)
1999                 key->dt = (H5T_t *)H5O_msg_free(H5O_DTYPE_ID, key->dt);
2000             key = H5FL_FREE(H5O_copy_search_comm_dt_key_t, key);
2001         } /* end if */
2002         if(addr)
2003             addr = H5FL_FREE(haddr_t, addr);
2004     } /* end if */
2005 
2006     FUNC_LEAVE_NOAPI(ret_value)
2007 } /* end H5O__copy_insert_comm_dt */
2008 
2009