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