/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Copyright by the Board of Trustees of the University of Illinois. * * All rights reserved. * * * * This file is part of HDF5. The full HDF5 copyright notice, including * * terms governing use, modification, and redistribution, is contained in * * the files COPYING and Copyright.html. COPYING can be found at the root * * of the source code distribution tree; Copyright.html can be found at the * * root level of an installed copy of the electronic HDF5 document set and * * is linked from the top-level documents page. It can also be found at * * http://hdf.ncsa.uiuc.edu/HDF5/doc/Copyright.html. If you do not have * * access to either file, you may request a copy from hdfhelp@ncsa.uiuc.edu. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /*------------------------------------------------------------------------- * * Created: H5O.c * Aug 5 1997 * Robb Matzke * * Purpose: Object header routines. * *------------------------------------------------------------------------- */ /****************/ /* Module Setup */ /****************/ #define H5F_PACKAGE /*suppress error about including H5Fpkg */ #define H5O_PACKAGE /*suppress error about including H5Opkg */ /***********/ /* Headers */ /***********/ #include "H5private.h" /* Generic Functions */ #include "H5Eprivate.h" /* Error handling */ #include "H5Fpkg.h" /* File access */ #include "H5FLprivate.h" /* Free lists */ #include "H5Iprivate.h" /* IDs */ #include "H5Lprivate.h" /* Links */ #include "H5MFprivate.h" /* File memory management */ #include "H5MMprivate.h" /* Memory management */ #include "H5Opkg.h" /* Object headers */ #include "H5Tprivate.h" #include "H5SMprivate.h" /* Shared object header messages */ #ifdef H5_HAVE_GETTIMEOFDAY #include #endif /* H5_HAVE_GETTIMEOFDAY */ /****************/ /* Local Macros */ /****************/ #define H5O_MIN_SIZE 32 /*min obj header data size */ /* Load native information for a message, if it's not already present */ /* (Only works for messages with decode callback) */ #define LOAD_NATIVE(F, DXPL, MSG, ERR) \ if(NULL == (MSG)->native) { \ const H5O_msg_class_t *decode_type; \ \ /* Check for shared message */ \ if ((MSG)->flags & H5O_FLAG_SHARED) \ decode_type = H5O_MSG_SHARED; \ else \ decode_type = (MSG)->type; \ \ /* Decode the message */ \ HDassert(decode_type->decode); \ if(NULL == ((MSG)->native = (decode_type->decode)((F), (DXPL), (MSG)->raw))) \ HGOTO_ERROR(H5E_OHDR, H5E_CANTDECODE, ERR, "unable to decode message") \ } /* end if */ /* Private typedefs */ /******************/ /* Local Typedefs */ /******************/ /* User data for iteration while removing a message */ typedef struct { H5F_t *f; /* Pointer to file for insertion */ hid_t dxpl_id; /* DXPL during iteration */ int sequence; /* Sequence # to search for */ unsigned nfailed; /* # of failed message removals */ H5O_operator_t op; /* Callback routine for removal operations */ void *op_data; /* Callback data for removal operations */ hbool_t adj_link; /* Whether to adjust links when removing messages */ } H5O_iter_ud1_t; /* Typedef for "internal library" iteration operations */ typedef herr_t (*H5O_lib_operator_t)(H5O_t *oh, H5O_mesg_t *mesg/*in,out*/, unsigned sequence, unsigned *oh_flags_ptr/*out*/, void *operator_data/*in,out*/); /* Some syntactic sugar to make the compiler happy with two different kinds of iterator callbacks */ typedef union { H5O_operator_t app_op; /* Application callback for each message */ H5O_lib_operator_t lib_op; /* Library internal callback for each message */ } H5O_mesg_operator_t; /* * This table contains a list of object types, descriptions, and the * functions that determine if some object is a particular type. The table * is allocated dynamically. */ typedef struct H5O_typeinfo_t { H5G_obj_t type; /*one of the public H5G_* types */ htri_t (*isa)(H5O_t*); /*function to determine type */ char *desc; /*description of object type */ } H5O_typeinfo_t; /********************/ /* Package Typedefs */ /********************/ /********************/ /* Local Prototypes */ /********************/ static hid_t H5O_open_by_loc(H5G_loc_t *obj_loc, hid_t dxpl_id); static H5O_loc_t * H5O_get_oloc(hid_t id); static herr_t H5O_new(H5F_t *f, hid_t dxpl_id, size_t chunk_size, H5O_loc_t *loc/*out*/, haddr_t header); static herr_t H5O_reset_real(const H5O_msg_class_t *type, void *native); static void * H5O_copy_real(const H5O_msg_class_t *type, const void *mesg, void *dst); static int H5O_count_real(H5O_loc_t *loc, const H5O_msg_class_t *type, hid_t dxpl_id); static unsigned H5O_find_in_ohdr(H5F_t *f, hid_t dxpl_id, H5O_t *oh, const H5O_msg_class_t **type_p, int sequence); static int H5O_modify_real(H5O_loc_t *loc, const H5O_msg_class_t *type, int overwrite, unsigned flags, unsigned update_flags, const void *mesg, hid_t dxpl_id); static int H5O_append_real(H5F_t *f, hid_t dxpl_id, H5O_t *oh, const H5O_msg_class_t *type, unsigned flags, const void *mesg, unsigned * oh_flags_ptr); static herr_t H5O_remove_real(const H5O_loc_t *loc, const H5O_msg_class_t *type, int sequence, H5O_operator_t op, void *op_data, hbool_t adj_link, hid_t dxpl_id); static herr_t H5O_eliminate_gap(H5O_t *oh, H5O_mesg_t *mesg, uint8_t *new_gap_loc, size_t new_gap_size); static herr_t H5O_add_gap(H5O_t *oh, unsigned chunkno, unsigned idx, uint8_t *new_gap_loc, size_t new_gap_size); static unsigned H5O_alloc(H5F_t *f, hid_t dxpl_id, H5O_t *oh, const H5O_msg_class_t *type, size_t size, hbool_t * oh_dirtied_ptr); static herr_t H5O_alloc_msgs(H5O_t *oh, size_t min_alloc); static herr_t H5O_alloc_null(H5O_t *oh, unsigned null_idx, const H5O_msg_class_t *new_type, void *new_native, size_t new_size); static herr_t H5O_release_mesg(H5F_t *f, hid_t dxpl_id, H5O_t *oh, H5O_mesg_t *mesg, hbool_t delete_mesg, hbool_t adj_link); static htri_t H5O_move_msgs_forward(H5O_t *oh); static htri_t H5O_merge_null(H5O_t *oh); static htri_t H5O_remove_empty_chunks(H5F_t *f, H5O_t *oh, hid_t dxpl_id); static herr_t H5O_condense_header(H5F_t *f, H5O_t *oh, hid_t dxpl_id); static htri_t H5O_alloc_extend_chunk(H5F_t *f, H5O_t *oh, unsigned chunkno, size_t size, unsigned * msg_idx); static unsigned H5O_alloc_new_chunk(H5F_t *f, hid_t dxpl_id, H5O_t *oh, size_t size); static herr_t H5O_delete_oh(H5F_t *f, hid_t dxpl_id, H5O_t *oh); static herr_t H5O_delete_mesg(H5F_t *f, hid_t dxpl_id, H5O_mesg_t *mesg, hbool_t adj_link); static unsigned H5O_new_mesg(H5F_t *f, H5O_t *oh, unsigned *flags, const H5O_msg_class_t *orig_type, const void *orig_mesg, H5O_shared_t *sh_mesg, const H5O_msg_class_t **new_type, const void **new_mesg, hid_t dxpl_id, unsigned * oh_flags_ptr); static herr_t H5O_write_mesg(H5O_t *oh, unsigned idx, const H5O_msg_class_t *type, const void *mesg, unsigned flags, unsigned update_flags, unsigned * oh_flags_ptr); static herr_t H5O_iterate_real(const H5O_loc_t *loc, const H5O_msg_class_t *type, H5AC_protect_t prot, hbool_t internal, H5O_mesg_operator_t op, void *op_data, hid_t dxpl_id); static const H5O_obj_class_t *H5O_obj_class(H5O_loc_t *loc, hid_t dxpl_id); static H5G_obj_t H5O_obj_type_real(H5O_t *oh); static const H5O_obj_class_t *H5O_obj_class_real(H5O_t *oh); static herr_t H5O_copy_header_real(const H5O_loc_t *oloc_src, H5O_loc_t *oloc_dst /*out */, hid_t dxpl_id, H5O_copy_t *cpy_info); static herr_t H5O_copy_free_addrmap_cb(void *item, void *key, void *op_data); /*********************/ /* Package Variables */ /*********************/ /* Header message ID to class mapping */ const H5O_msg_class_t *const H5O_msg_class_g[] = { H5O_MSG_NULL, /*0x0000 Null */ H5O_MSG_SDSPACE, /*0x0001 Simple Dimensionality */ H5O_MSG_LINFO, /*0x0002 Link information */ H5O_MSG_DTYPE, /*0x0003 Data Type */ H5O_MSG_FILL, /*0x0004 Old data storage -- fill value */ H5O_MSG_FILL_NEW, /*0x0005 New Data storage -- fill value */ H5O_MSG_LINK, /*0x0006 Link */ H5O_MSG_EFL, /*0x0007 Data storage -- external data files */ H5O_MSG_LAYOUT, /*0x0008 Data Layout */ #ifdef H5O_ENABLE_BOGUS H5O_MSG_BOGUS, /*0x0009 "Bogus" */ #else /* H5O_ENABLE_BOGUS */ NULL, /*0x0009 "Bogus" */ #endif /* H5O_ENABLE_BOGUS */ H5O_MSG_GINFO, /*0x000A Group Information */ H5O_MSG_PLINE, /*0x000B Data storage -- filter pipeline */ H5O_MSG_ATTR, /*0x000C Attribute list */ H5O_MSG_NAME, /*0x000D Object name */ H5O_MSG_MTIME, /*0x000E Object modification date and time */ H5O_MSG_SHARED, /*0x000F Shared header message */ H5O_MSG_CONT, /*0x0010 Object header continuation */ H5O_MSG_STAB, /*0x0011 Symbol table */ H5O_MSG_MTIME_NEW, /*0x0012 New Object modification date and time */ }; /* Header object ID to class mapping */ /* * Initialize the object class info table. Begin with the most general types * and end with the most specific. For instance, any object that has a * datatype message is a datatype but only some of them are datasets. */ const H5O_obj_class_t *const H5O_obj_class_g[] = { H5O_OBJ_DATATYPE, /* Datatype object (H5G_TYPE - 2) */ H5O_OBJ_DATASET, /* Dataset object (H5G_DATASET - 1) */ H5O_OBJ_GROUP, /* Group object (H5G_GROUP - 0) */ }; /* Declare a free list to manage the H5O_t struct */ H5FL_DEFINE(H5O_t); /* Declare a free list to manage the H5O_mesg_t sequence information */ H5FL_SEQ_DEFINE(H5O_mesg_t); /* Declare a free list to manage the H5O_chunk_t sequence information */ H5FL_SEQ_DEFINE(H5O_chunk_t); /* Declare a free list to manage the chunk image information */ H5FL_BLK_DEFINE(chunk_image); /*****************************/ /* Library Private Variables */ /*****************************/ /*******************/ /* Local Variables */ /*******************/ /* Declare external the free list for time_t's */ H5FL_EXTERN(time_t); /* Declare extern the free list for H5O_cont_t's */ H5FL_EXTERN(H5O_cont_t); /* Declare a free list to manage the H5O_addr_map_t struct */ H5FL_EXTERN(H5O_addr_map_t); /*------------------------------------------------------------------------- * Function: H5Oopen * * Purpose: Opens an object within an HDF5 file. * * This function opens an object in the same way that H5Gopen, * H5Topen, and H5Dopen do. However, H5Oopen doesn't require * the type of object to be known beforehand. This can be * useful in user-defined links, for instance, when only a * path is known. * * The opened object should be closed again with H5Oclose * or H5Gclose, H5Tclose, or H5Dclose. * * Return: Success: An open object identifier * Failure: Negative * * Programmer: James Laird * July 14 2006 * *------------------------------------------------------------------------- */ hid_t H5Oopen(hid_t loc_id, const char *name, hid_t lapl_id) { H5G_loc_t loc; H5G_loc_t obj_loc; /* Location used to open group */ H5G_name_t obj_path; /* Opened object group hier. path */ H5O_loc_t obj_oloc; /* Opened object object location */ hbool_t loc_found = FALSE; /* Entry at 'name' found */ hid_t ret_value = FAIL; FUNC_ENTER_API(H5Oopen, FAIL) H5TRACE3("i","isi",loc_id,name,lapl_id); /* Check args */ if(H5G_loc(loc_id, &loc) < 0) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location") if(!name || !*name) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name") /* Set up opened group location to fill in */ obj_loc.oloc = &obj_oloc; obj_loc.path = &obj_path; H5G_loc_reset(&obj_loc); /* Find the object's location */ if(H5G_loc_find(&loc, name, &obj_loc/*out*/, lapl_id, H5AC_dxpl_id) < 0) HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "group not found") loc_found = TRUE; if((ret_value = H5O_open_by_loc(&obj_loc, H5AC_dxpl_id)) < 0) HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open object") done: if(ret_value < 0) if(loc_found) if(H5G_loc_free(&obj_loc) < 0) HDONE_ERROR(H5E_SYM, H5E_CANTRELEASE, FAIL, "can't free location") FUNC_LEAVE_API(ret_value) } /* end H5Oopen() */ /*------------------------------------------------------------------------- * Function: H5Oopen_by_addr * * Purpose: Warning! This function is EXTREMELY DANGEROUS! * Improper use can lead to FILE CORRUPTION, INACCESSIBLE DATA, * and other VERY BAD THINGS! * * This function opens an object using its address within the * HDF5 file, similar to an HDF5 hard link. The open object * is identical to an object opened with H5Oopen() and should * be closed with H5Oclose() or a type-specific closing * function (such as H5Gclose() ). * * This function is very dangerous if called on an invalid * address. For this reason, H5Oincr_refcount() should be * used to prevent HDF5 from deleting any object that is * referenced by address (e.g. by a user-defined link). * H5Odecr_refcount() should be used when the object is * no longer being referenced by address (e.g. when the UD link * is deleted). * * The address of the HDF5 file on disk has no effect on * H5Oopen_by_addr(), nor does the use of any unusual file * drivers. The "address" is really the offset within the * HDF5 file, and HDF5's file drivers will transparently * map this to an address on disk for the filesystem. * * Return: Success: An open object identifier * Failure: Negative * * Programmer: James Laird * July 14 2006 * *------------------------------------------------------------------------- */ hid_t H5Oopen_by_addr(hid_t loc_id, haddr_t addr) { H5G_loc_t loc; H5G_loc_t obj_loc; /* Location used to open group */ H5G_name_t obj_path; /* Opened object group hier. path */ H5O_loc_t obj_oloc; /* Opened object object location */ hbool_t loc_found = FALSE; /* Location at 'name' found */ hid_t ret_value = FAIL; FUNC_ENTER_API(H5Oopen_by_addr, FAIL) H5TRACE2("i","ia",loc_id,addr); /* Check args */ if(H5G_loc(loc_id, &loc) < 0) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location") if(addr == 0) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no address supplied") /* Set up opened group location to fill in */ obj_loc.oloc = &obj_oloc; obj_loc.path = &obj_path; H5G_loc_reset(&obj_loc); obj_loc.oloc->addr = addr; obj_loc.oloc->file = loc.oloc->file; H5G_name_reset(obj_loc.path); if((ret_value = H5O_open_by_loc(&obj_loc, H5AC_dxpl_id)) < 0) HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open object") done: if(ret_value < 0) { if(loc_found) { if(H5G_loc_free(&obj_loc) < 0) HDONE_ERROR(H5E_SYM, H5E_CANTRELEASE, FAIL, "can't free location") } } /* end if */ FUNC_LEAVE_API(ret_value) } /* end H5Oopen_by_addr() */ /*------------------------------------------------------------------------- * Function: H5Oclose * * Purpose: Close an open file object. * * This is the companion to H5Oopen. It is used to close any * open object in an HDF5 file (but not IDs are that not file * objects, such as property lists and dataspaces). It has * the same effect as calling H5Gclose, H5Dclose, or H5Tclose. * * Return: Success: Non-negative * Failure: Negative * * Programmer: James Laird * July 14 2006 * *------------------------------------------------------------------------- */ herr_t H5Oclose(hid_t object_id) { herr_t ret_value = SUCCEED; FUNC_ENTER_API(H5Oclose, FAIL) H5TRACE1("e","i",object_id); /* Get the type of the object and close it in the correct way */ switch(H5I_get_type(object_id)) { case(H5I_GROUP): case(H5I_DATATYPE): case(H5I_DATASET): if(H5I_object(object_id) == NULL) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "not a valid object") if(H5I_dec_ref(object_id) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTRELEASE, FAIL, "unable to close object") break; default: HGOTO_ERROR(H5E_ARGS, H5E_CANTRELEASE, FAIL, "not a valid file object ID (dataset, group, or datatype)") break; } /* end switch */ done: FUNC_LEAVE_API(ret_value) } /* end H5Oclose() */ /*------------------------------------------------------------------------- * Function: H5Oincr_refcount * * Purpose: Warning! This function is EXTREMELY DANGEROUS! * Improper use can lead to FILE CORRUPTION, INACCESSIBLE DATA, * and other VERY BAD THINGS! * * This function increments the "hard link" reference count * for an object. It should be used when a user-defined link * that references an object by address is created. When the * link is deleted, H5Odecr_refcount should be used. * * Return: Success: Non-negative * Failure: Negative * * Programmer: James Laird * July 14 2006 * *------------------------------------------------------------------------- */ herr_t H5Oincr_refcount(hid_t object_id) { H5O_loc_t *oloc; herr_t ret_value = SUCCEED; FUNC_ENTER_API(H5Oincr_refcount, FAIL) H5TRACE1("e","i",object_id); /* Get the object's oloc so we can adjust its link count */ if((oloc = H5O_get_oloc(object_id)) == NULL) HGOTO_ERROR(H5E_ATOM, H5E_BADVALUE, FAIL, "unable to get object location from ID") if(H5O_link(oloc, 1, H5AC_dxpl_id) < 0) HGOTO_ERROR(H5E_OHDR, H5E_LINKCOUNT, FAIL, "modifying object link count failed") done: FUNC_LEAVE_API(ret_value) } /* end H5O_incr_refcount() */ /*------------------------------------------------------------------------- * Function: H5Odecr_refcount * * Purpose: Warning! This function is EXTREMELY DANGEROUS! * Improper use can lead to FILE CORRUPTION, INACCESSIBLE DATA, * and other VERY BAD THINGS! * * This function decrements the "hard link" reference count * for an object. It should be used when user-defined links * that reference an object by address are deleted, and only * after H5Oincr_refcount has already been used. * * Return: Success: Non-negative * Failure: Negative * * Programmer: James Laird * July 14 2006 * *------------------------------------------------------------------------- */ herr_t H5Odecr_refcount(hid_t object_id) { H5O_loc_t *oloc; herr_t ret_value = SUCCEED; FUNC_ENTER_API(H5Odecr_refcount, FAIL) H5TRACE1("e","i",object_id); /* Get the object's oloc so we can adjust its link count */ if((oloc = H5O_get_oloc(object_id)) == NULL) HGOTO_ERROR(H5E_ATOM, H5E_BADVALUE, FAIL, "unable to get object location from ID") if(H5O_link(oloc, -1, H5AC_dxpl_id) < 0) HGOTO_ERROR(H5E_OHDR, H5E_LINKCOUNT, FAIL, "modifying object link count failed") done: FUNC_LEAVE_API(ret_value) } /* end H5Odecr_refcount() */ /*------------------------------------------------------------------------- * Function: H5O_open_by_loc * * Purpose: Opens an object and returns an ID given its group loction. * * Return: Success: Open object identifier * Failure: Negative * * Programmer: James Laird * July 25 2006 * *------------------------------------------------------------------------- */ static hid_t H5O_open_by_loc(H5G_loc_t *obj_loc, hid_t dxpl_id) { const H5O_obj_class_t *obj_class; /* Class of object for location */ hid_t ret_value; /* Return value */ FUNC_ENTER_NOAPI_NOINIT(H5O_open_by_loc) HDassert(obj_loc); /* Get the object class for this location */ if(NULL == (obj_class = H5O_obj_class(obj_loc->oloc, dxpl_id))) HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "unable to determine object class") /* Call the object's 'open' routine */ HDassert(obj_class->open); if((ret_value = obj_class->open(obj_loc, dxpl_id)) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTOPENOBJ, FAIL, "unable to open object") done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_open_by_loc() */ /*------------------------------------------------------------------------- * Function: H5O_get_oloc * * Purpose: Gets the oloc for an object given its ID. * * Return: Success: Pointer to H5O_loc_t * Failure: NULL * * Programmer: James Laird * July 25 2006 * *------------------------------------------------------------------------- */ static H5O_loc_t * H5O_get_oloc(hid_t object_id) { H5O_loc_t *ret_value; /* Return value */ FUNC_ENTER_NOAPI_NOINIT(H5O_get_oloc) switch(H5I_get_type(object_id)) { case(H5I_GROUP): if(NULL == (ret_value = H5O_OBJ_GROUP->get_oloc(object_id))) HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, NULL, "unable to get object location from group ID") break; case(H5I_DATASET): if(NULL == (ret_value = H5O_OBJ_DATASET->get_oloc(object_id))) HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, NULL, "unable to get object location from dataset ID") break; case(H5I_DATATYPE): if(NULL == (ret_value = H5O_OBJ_DATATYPE->get_oloc(object_id))) HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, NULL, "unable to get object location from datatype ID") break; default: HGOTO_ERROR(H5E_OHDR, H5E_BADTYPE, NULL, "invalid object type") } /* end switch */ done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_get_oloc() */ /*------------------------------------------------------------------------- * Function: H5O_create * * Purpose: Creates a new object header. Allocates space for it and * then calls an initialization function. The object header * is opened for write access and should eventually be * closed by calling H5O_close(). * * Return: Success: Non-negative, the ENT argument contains * information about the object header, * including its address. * * Failure: Negative * * Programmer: Robb Matzke * matzke@llnl.gov * Aug 5 1997 * *------------------------------------------------------------------------- */ herr_t H5O_create(H5F_t *f, hid_t dxpl_id, size_t size_hint, H5O_loc_t *loc/*out*/) { haddr_t header; /* Address of object header */ herr_t ret_value = SUCCEED; /* return value */ FUNC_ENTER_NOAPI(H5O_create, FAIL) /* check args */ HDassert(f); HDassert(loc); /* Make certain we allocate at least a reasonable size for the object header */ size_hint = H5O_ALIGN_F(f, MAX(H5O_MIN_SIZE, size_hint)); /* allocate disk space for header and first chunk */ if(HADDR_UNDEF == (header = H5MF_alloc(f, H5FD_MEM_OHDR, dxpl_id, (hsize_t)H5O_SIZEOF_HDR_F(f) + size_hint))) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "file allocation failed for object header header") /* initialize the object header */ if(H5O_new(f, dxpl_id, size_hint, loc, header) != SUCCEED) HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to initialize object header") done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_create() */ /*------------------------------------------------------------------------- * Function: H5O_new * * Purpose: Initialize a new object header, sets the link count to 0, * and caches the header. The object header is opened for * write access and should eventually be closed by calling * H5O_close(). * * Return: Success: SUCCEED, the LOC argument contains * information about the object header, * including its address. * Failure: FAIL * * Programmer: Bill Wendling * 1, November 2002 * *------------------------------------------------------------------------- */ static herr_t H5O_new(H5F_t *f, hid_t dxpl_id, size_t chunk_size, H5O_loc_t *loc/*out*/, haddr_t header) { H5O_t *oh = NULL; size_t oh_size; /* Size of initial object header */ herr_t ret_value = SUCCEED; /* return value */ FUNC_ENTER_NOAPI_NOINIT(H5O_new) /* check args */ HDassert(f); HDassert(loc); /* Set up object location */ loc->file = f; loc->addr = header; /* Allocate the object header and fill in header fields */ if(NULL == (oh = H5FL_MALLOC(H5O_t))) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") /* Initialize rudimentary information object object header */ oh->version = H5F_USE_LATEST_FORMAT(f) ? H5O_VERSION_LATEST : H5O_VERSION_1; oh->nlink = 0; /* Compute total size of initial object header */ /* (i.e. object header prefix and first chunk) */ oh_size = H5O_SIZEOF_HDR_OH(oh) + chunk_size; /* Create the chunk list */ oh->nchunks = oh->alloc_nchunks = 1; if(NULL == (oh->chunk = H5FL_SEQ_MALLOC(H5O_chunk_t, (size_t)oh->alloc_nchunks))) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") /* Initialize the first chunk */ oh->chunk[0].dirty = TRUE; oh->chunk[0].addr = loc->addr; oh->chunk[0].size = oh_size; oh->chunk[0].gap = 0; /* Allocate enough space for the first chunk */ /* (including space for serializing the object header prefix */ if(NULL == (oh->chunk[0].image = H5FL_BLK_CALLOC(chunk_image, oh_size))) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") /* Put magic # for object header in first chunk */ if(oh->version > H5O_VERSION_1) HDmemcpy(oh->chunk[0].image, H5O_HDR_MAGIC, (size_t)H5O_SIZEOF_MAGIC); /* Create the message list */ oh->nmesgs = 1; oh->alloc_nmesgs = H5O_NMESGS; if(NULL == (oh->mesg = H5FL_SEQ_CALLOC(H5O_mesg_t, oh->alloc_nmesgs))) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") /* Initialize the first message */ oh->mesg[0].type = H5O_MSG_NULL; oh->mesg[0].dirty = TRUE; oh->mesg[0].native = NULL; oh->mesg[0].raw = oh->chunk[0].image + (H5O_SIZEOF_HDR_OH(oh) - H5O_SIZEOF_CHKSUM_OH(oh)) + H5O_SIZEOF_MSGHDR_OH(oh); oh->mesg[0].raw_size = chunk_size - H5O_SIZEOF_MSGHDR_OH(oh); oh->mesg[0].chunkno = 0; /* Cache object header */ if(H5AC_set(f, dxpl_id, H5AC_OHDR, loc->addr, oh, H5AC__NO_FLAGS_SET) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to cache object header") /* Open it */ if(H5O_open(loc) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTOPENOBJ, FAIL, "unable to open object header") done: if(ret_value < 0 && oh) { if(H5O_dest(f, oh) < 0) HDONE_ERROR(H5E_OHDR, H5E_CANTFREE, FAIL, "unable to destroy object header data") } /* end if */ FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_new() */ /*------------------------------------------------------------------------- * Function: H5O_open * * Purpose: Opens an object header which is described by the symbol table * entry OBJ_ENT. * * Return: Non-negative on success/Negative on failure * * Programmer: Robb Matzke * Monday, January 5, 1998 * *------------------------------------------------------------------------- */ herr_t H5O_open(const H5O_loc_t *loc) { FUNC_ENTER_NOAPI_NOFUNC(H5O_open) /* Check args */ HDassert(loc); HDassert(loc->file); #ifdef H5O_DEBUG if (H5DEBUG(O)) HDfprintf(H5DEBUG(O), "> %a\n", loc->addr); #endif /* Increment open-lock counters */ loc->file->nopen_objs++; FUNC_LEAVE_NOAPI(SUCCEED) } /* end H5O_open() */ /*------------------------------------------------------------------------- * Function: H5O_close * * Purpose: Closes an object header that was previously open. * * Return: Non-negative on success/Negative on failure * * Programmer: Robb Matzke * Monday, January 5, 1998 * *------------------------------------------------------------------------- */ herr_t H5O_close(H5O_loc_t *loc) { herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(H5O_close, FAIL) /* Check args */ HDassert(loc); HDassert(loc->file); HDassert(loc->file->nopen_objs > 0); /* Decrement open-lock counters */ --loc->file->nopen_objs; #ifdef H5O_DEBUG if(H5DEBUG(O)) { if(loc->file->file_id < 0 && 1 == loc->file->shared->nrefs) HDfprintf(H5DEBUG(O), "< %a auto %lu remaining\n", loc->addr, (unsigned long)(loc->file->nopen_objs)); else HDfprintf(H5DEBUG(O), "< %a\n", loc->addr); } /* end if */ #endif /* * If the file open object count has reached the number of open mount points * (each of which has a group open in the file) attempt to close the file. */ if(loc->file->nopen_objs == loc->file->mtab.nmounts) /* Attempt to close down the file hierarchy */ if(H5F_try_close(loc->file) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTCLOSEFILE, FAIL, "problem attempting file close") /* Release location information */ if(H5O_loc_free(loc) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTRELEASE, FAIL, "problem attempting to free location") done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_close() */ /*------------------------------------------------------------------------- * Function: H5O_reset * * Purpose: Some message data structures have internal fields that * need to be freed. This function does that if appropriate * but doesn't free NATIVE. * * Return: Non-negative on success/Negative on failure * * Programmer: Robb Matzke * matzke@llnl.gov * Aug 12 1997 * * Modifications: * Changed to use IDs for types, instead of type objects, then * call "real" routine. * Quincey Koziol * Feb 14 2003 * *------------------------------------------------------------------------- */ herr_t H5O_reset(unsigned type_id, void *native) { const H5O_msg_class_t *type; /* Actual H5O class type for the ID */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(H5O_reset, FAIL) /* check args */ HDassert(type_id < NELMTS(H5O_msg_class_g)); type = H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */ HDassert(type); /* Call the "real" reset routine */ if(H5O_reset_real(type, native) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTRESET, FAIL, "unable to reset object header") done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_reset() */ /*------------------------------------------------------------------------- * Function: H5O_reset_real * * Purpose: Some message data structures have internal fields that * need to be freed. This function does that if appropriate * but doesn't free NATIVE. * * Return: Non-negative on success/Negative on failure * * Programmer: Robb Matzke * matzke@llnl.gov * Aug 12 1997 * *------------------------------------------------------------------------- */ static herr_t H5O_reset_real(const H5O_msg_class_t *type, void *native) { herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI_NOINIT(H5O_reset_real) /* check args */ HDassert(type); if(native) { if(type->reset) { if((type->reset)(native) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTRELEASE, FAIL, "reset method failed") } else HDmemset(native, 0, type->native_size); } /* end if */ done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_reset_real() */ /*------------------------------------------------------------------------- * Function: H5O_free * * Purpose: Similar to H5O_reset() except it also frees the message * pointer. * * Return: Success: NULL * * Failure: NULL * * Programmer: Robb Matzke * Thursday, May 21, 1998 * * Modifications: * *------------------------------------------------------------------------- */ void * H5O_free(unsigned type_id, void *mesg) { const H5O_msg_class_t *type; /* Actual H5O class type for the ID */ void * ret_value; /* Return value */ FUNC_ENTER_NOAPI_NOFUNC(H5O_free) /* check args */ HDassert(type_id < NELMTS(H5O_msg_class_g)); type = H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */ HDassert(type); /* Call the "real" free routine */ ret_value = H5O_free_real(type, mesg); FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_free() */ /*------------------------------------------------------------------------- * Function: H5O_free_mesg * * Purpose: Call H5O_free_real() on a message. * * Return: Non-negative on success/Negative on failure * * Programmer: Quincey Koziol * Tuesday, Sep 6, 2005 * *------------------------------------------------------------------------- */ herr_t H5O_free_mesg(H5O_mesg_t *mesg) { FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5O_free_mesg) /* check args */ HDassert(mesg); /* Free any native information */ if(mesg->flags & H5O_FLAG_SHARED) mesg->native = H5O_free_real(H5O_MSG_SHARED, mesg->native); else mesg->native = H5O_free_real(mesg->type, mesg->native); FUNC_LEAVE_NOAPI(SUCCEED) } /* end H5O_free_mesg() */ /*------------------------------------------------------------------------- * Function: H5O_free_real * * Purpose: Similar to H5O_reset() except it also frees the message * pointer. * * Return: Success: NULL * * Failure: NULL * * Programmer: Robb Matzke * Thursday, May 21, 1998 * *------------------------------------------------------------------------- */ void * H5O_free_real(const H5O_msg_class_t *type, void *msg_native) { FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5O_free_real) /* check args */ HDassert(type); if(msg_native) { H5O_reset_real(type, msg_native); if (NULL!=(type->free)) (type->free)(msg_native); else H5MM_xfree(msg_native); } /* end if */ FUNC_LEAVE_NOAPI(NULL) } /* end H5O_free_real() */ /*------------------------------------------------------------------------- * Function: H5O_copy * * Purpose: Copies a message. If MESG is is the null pointer then a null * pointer is returned with no error. * * Return: Success: Ptr to the new message * * Failure: NULL * * Programmer: Robb Matzke * Thursday, May 21, 1998 * * Modifications: * Changed to use IDs for types, instead of type objects, then * call "real" routine. * Quincey Koziol * Feb 14 2003 * *------------------------------------------------------------------------- */ void * H5O_copy (unsigned type_id, const void *mesg, void *dst) { const H5O_msg_class_t *type; /* Actual H5O class type for the ID */ void *ret_value; /* Return value */ FUNC_ENTER_NOAPI(H5O_copy, NULL) /* check args */ HDassert(type_id < NELMTS(H5O_msg_class_g)); type = H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */ HDassert(type); /* Call the "real" copy routine */ if((ret_value = H5O_copy_real(type, mesg, dst)) == NULL) HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, NULL, "unable to copy object header message") done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_copy() */ /*------------------------------------------------------------------------- * Function: H5O_copy_real * * Purpose: Copies a message. If MESG is is the null pointer then a null * pointer is returned with no error. * * Return: Success: Ptr to the new message * * Failure: NULL * * Programmer: Robb Matzke * Thursday, May 21, 1998 * *------------------------------------------------------------------------- */ static void * H5O_copy_real(const H5O_msg_class_t *type, const void *mesg, void *dst) { void *ret_value = NULL; FUNC_ENTER_NOAPI_NOINIT(H5O_copy_real) /* check args */ HDassert(type); HDassert(type->copy); if(mesg) if(NULL == (ret_value = (type->copy)(mesg, dst, 0))) HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, NULL, "unable to copy object header message") done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_copy_real() */ /*------------------------------------------------------------------------- * Function: H5O_link * * Purpose: Adjust the link count for an object header by adding * ADJUST to the link count. * * Return: Success: New link count * * Failure: Negative * * Programmer: Robb Matzke * matzke@llnl.gov * Aug 5 1997 * *------------------------------------------------------------------------- */ int H5O_link(const H5O_loc_t *loc, int adjust, hid_t dxpl_id) { H5O_t *oh = NULL; unsigned oh_flags = H5AC__NO_FLAGS_SET; /* used to indicate whether the * object was deleted as a result * of this action. */ int ret_value = FAIL; FUNC_ENTER_NOAPI(H5O_link, FAIL) /* check args */ HDassert(loc); HDassert(loc->file); HDassert(H5F_addr_defined(loc->addr)); if(adjust != 0 && 0 == (loc->file->intent & H5F_ACC_RDWR)) HGOTO_ERROR(H5E_OHDR, H5E_WRITEERROR, FAIL, "no write intent on file") /* get header */ if(NULL == (oh = H5AC_protect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, NULL, NULL, H5AC_WRITE))) HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "unable to load object header") /* adjust link count */ if(adjust < 0) { if(oh->nlink + adjust < 0) HGOTO_ERROR(H5E_OHDR, H5E_LINKCOUNT, FAIL, "link count would be negative") oh->nlink += adjust; oh_flags |= H5AC__DIRTIED_FLAG; /* Check if the object should be deleted */ if(oh->nlink == 0) { /* Check if the object is still open by the user */ if(H5FO_opened(loc->file, loc->addr) != NULL) { /* Flag the object to be deleted when it's closed */ if(H5FO_mark(loc->file, loc->addr, TRUE) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, FAIL, "can't mark object for deletion") } /* end if */ else { /* Delete object right now */ if(H5O_delete_oh(loc->file, dxpl_id, oh) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, FAIL, "can't delete object from file") /* Mark the object header as deleted */ oh_flags = H5C__DELETED_FLAG; } /* end else */ } /* end if */ } else if (adjust > 0) { /* A new object, or one that will be deleted */ if(oh->nlink == 0) { /* Check if the object is current open, but marked for deletion */ if(H5FO_marked(loc->file, loc->addr) > 0) { /* Remove "delete me" flag on the object */ if(H5FO_mark(loc->file, loc->addr, FALSE) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, FAIL, "can't mark object for deletion") } /* end if */ } /* end if */ oh->nlink += adjust; oh_flags |= H5AC__DIRTIED_FLAG; } /* end if */ /* Set return value */ ret_value = oh->nlink; done: if (oh && H5AC_unprotect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, oh, oh_flags) < 0) HDONE_ERROR(H5E_OHDR, H5E_PROTECT, FAIL, "unable to release object header") FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_link() */ /*------------------------------------------------------------------------- * Function: H5O_count * * Purpose: Counts the number of messages in an object header which are a * certain type. * * Return: Success: Number of messages of specified type. * * Failure: Negative * * Programmer: Robb Matzke * Tuesday, April 21, 1998 * *------------------------------------------------------------------------- */ int H5O_count(H5O_loc_t *loc, unsigned type_id, hid_t dxpl_id) { const H5O_msg_class_t *type; /* Actual H5O class type for the ID */ int ret_value; /* Return value */ FUNC_ENTER_NOAPI(H5O_count, FAIL) /* Check args */ HDassert(loc); HDassert(loc->file); HDassert(H5F_addr_defined(loc->addr)); HDassert(type_id < NELMTS(H5O_msg_class_g)); type = H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */ HDassert(type); /* Call the "real" count routine */ if((ret_value = H5O_count_real(loc, type, dxpl_id)) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTCOUNT, FAIL, "unable to count object header messages") done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_count() */ /*------------------------------------------------------------------------- * Function: H5O_count_real * * Purpose: Counts the number of messages in an object header which are a * certain type. * * Return: Success: Number of messages of specified type. * * Failure: Negative * * Programmer: Robb Matzke * Tuesday, April 21, 1998 * *------------------------------------------------------------------------- */ static int H5O_count_real(H5O_loc_t *loc, const H5O_msg_class_t *type, hid_t dxpl_id) { H5O_t *oh = NULL; int acc; unsigned u; int ret_value; FUNC_ENTER_NOAPI(H5O_count_real, FAIL) /* Check args */ HDassert(loc); HDassert(loc->file); HDassert(H5F_addr_defined(loc->addr)); HDassert(type); /* Load the object header */ if(NULL == (oh = H5AC_protect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, NULL, NULL, H5AC_READ))) HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "unable to load object header") /* Loop over all messages, counting the ones of the type looked for */ for(u = acc = 0; u < oh->nmesgs; u++) if(oh->mesg[u].type == type) acc++; /* Set return value */ ret_value = acc; done: if (oh && H5AC_unprotect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, oh, H5AC__NO_FLAGS_SET) != SUCCEED) HDONE_ERROR(H5E_OHDR, H5E_PROTECT, FAIL, "unable to release object header") FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_count_real() */ /*------------------------------------------------------------------------- * Function: H5O_exists * * Purpose: Determines if a particular message exists in an object * header without trying to decode the message. * * Return: Success: FALSE if the message does not exist; TRUE if * th message exists. * * Failure: FAIL if the existence of the message could * not be determined due to some error such as * not being able to read the object header. * * Programmer: Robb Matzke * Monday, November 2, 1998 * *------------------------------------------------------------------------- */ htri_t H5O_exists(H5O_loc_t *loc, unsigned type_id, int sequence, hid_t dxpl_id) { H5O_t *oh = NULL; /* Object header for location */ htri_t ret_value; /* Return value */ FUNC_ENTER_NOAPI(H5O_exists, FAIL) HDassert(loc); HDassert(loc->file); HDassert(type_id < NELMTS(H5O_msg_class_g)); HDassert(sequence >= 0); /* Load the object header */ if(NULL == (oh = H5AC_protect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, NULL, NULL, H5AC_READ))) HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "unable to load object header") /* Call the "real" exists routine */ if((ret_value = H5O_exists_oh(oh, type_id, sequence)) < 0) HGOTO_ERROR(H5E_OHDR, H5E_READERROR, FAIL, "unable to verify object header message") done: if(oh && H5AC_unprotect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, oh, H5AC__NO_FLAGS_SET) != SUCCEED) HDONE_ERROR(H5E_OHDR, H5E_PROTECT, FAIL, "unable to release object header") FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_exists() */ /*------------------------------------------------------------------------- * Function: H5O_exists_oh * * Purpose: Determines if a particular message exists in an object * header without trying to decode the message. * * Return: Success: FALSE if the message does not exist; TRUE if * th message exists. * * Failure: FAIL if the existence of the message could * not be determined due to some error such as * not being able to read the object header. * * Programmer: Robb Matzke * Monday, November 2, 1998 * *------------------------------------------------------------------------- */ htri_t H5O_exists_oh(H5O_t *oh, unsigned type_id, int sequence) { const H5O_msg_class_t *type; /* Actual H5O class type for the ID */ unsigned u; /* Local index variable */ htri_t ret_value; /* Return value */ FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5O_exists_oh) HDassert(oh); HDassert(type_id < NELMTS(H5O_msg_class_g)); type = H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */ HDassert(type); HDassert(sequence >= 0); /* Scan through the messages looking for the right one */ for(u = 0; u < oh->nmesgs; u++) { if(type->id != oh->mesg[u].type->id) continue; if(--sequence < 0) break; } /* end for */ /* Set return value */ ret_value = (sequence < 0); FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_exists_oh() */ /*------------------------------------------------------------------------- * Function: H5O_read * * Purpose: Reads a message from an object header and returns a pointer * to it. The caller will usually supply the memory through * MESG and the return value will be MESG. But if MESG is * the null pointer, then this function will malloc() memory * to hold the result and return its pointer instead. * * Return: Success: Ptr to message in native format. The message * should be freed by calling H5O_reset(). If * MESG is a null pointer then the caller should * also call H5MM_xfree() on the return value * after calling H5O_reset(). * * Failure: NULL * * Programmer: Robb Matzke * matzke@llnl.gov * Aug 6 1997 * *------------------------------------------------------------------------- */ void * H5O_read(const H5O_loc_t *loc, unsigned type_id, int sequence, void *mesg, hid_t dxpl_id) { const H5O_msg_class_t *type; /* Actual H5O class type for the ID */ void *ret_value; /* Return value */ FUNC_ENTER_NOAPI(H5O_read, NULL) /* check args */ HDassert(loc); HDassert(loc->file); HDassert(H5F_addr_defined(loc->addr)); HDassert(type_id < NELMTS(H5O_msg_class_g)); type = H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */ HDassert(type); HDassert(sequence >= 0); /* Call the "real" read routine */ if((ret_value = H5O_read_real(loc, type, sequence, mesg, dxpl_id)) == NULL) HGOTO_ERROR(H5E_OHDR, H5E_READERROR, NULL, "unable to load object header") done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_read() */ /*------------------------------------------------------------------------- * Function: H5O_read_real * * Purpose: Reads a message from an object header and returns a pointer * to it. The caller will usually supply the memory through * MESG and the return value will be MESG. But if MESG is * the null pointer, then this function will malloc() memory * to hold the result and return its pointer instead. * * Return: Success: Ptr to message in native format. The message * should be freed by calling H5O_reset(). If * MESG is a null pointer then the caller should * also call H5MM_xfree() on the return value * after calling H5O_reset(). * * Failure: NULL * * Programmer: Robb Matzke * matzke@llnl.gov * Aug 6 1997 * *------------------------------------------------------------------------- */ void * H5O_read_real(const H5O_loc_t *loc, const H5O_msg_class_t *type, int sequence, void *mesg, hid_t dxpl_id) { H5O_t *oh = NULL; int idx; void *ret_value = NULL; FUNC_ENTER_NOAPI_NOINIT(H5O_read_real) /* check args */ HDassert(loc); HDassert(loc->file); HDassert(H5F_addr_defined(loc->addr)); HDassert(type); HDassert(sequence >= 0); /* copy the message to the user-supplied buffer */ if(NULL == (oh = H5AC_protect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, NULL, NULL, H5AC_READ))) HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "unable to load object header") /* can we get it from the object header? */ if((idx = H5O_find_in_ohdr(loc->file, dxpl_id, oh, &type, sequence)) < 0) HGOTO_ERROR(H5E_OHDR, H5E_NOTFOUND, NULL, "unable to find message in object header") if(oh->mesg[idx].flags & H5O_FLAG_SHARED) { /* * If the message is shared then then the native pointer points to an * H5O_MSG_SHARED message. We use that information to look up the real * message in the global heap or some other object header. */ H5O_shared_t *shared; shared = (H5O_shared_t *)(oh->mesg[idx].native); ret_value = H5O_shared_read(loc->file, dxpl_id, shared, type, mesg); } else { /* * The message is not shared, but rather exists in the object * header. The object header caches the native message (along with * the raw message) so we must copy the native message before * returning. */ if(NULL == (ret_value = (type->copy) (oh->mesg[idx].native, mesg, 0))) HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, NULL, "unable to copy message to user space") } /* end else */ done: if(oh && H5AC_unprotect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, oh, H5AC__NO_FLAGS_SET) < 0) HDONE_ERROR(H5E_OHDR, H5E_PROTECT, NULL, "unable to release object header") FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_read_real() */ /*------------------------------------------------------------------------- * Function: H5O_find_in_ohdr * * Purpose: Find a message in the object header without consulting * a symbol table entry. * * Return: Success: Index number of message. * Failure: Negative * * Programmer: Robb Matzke * matzke@llnl.gov * Aug 6 1997 * * Modifications: * Robb Matzke, 1999-07-28 * The ADDR argument is passed by value. * * Bill Wendling, 2003-09-30 * Modified so that the object header needs to be AC_protected * before calling this function. *------------------------------------------------------------------------- */ static unsigned H5O_find_in_ohdr(H5F_t *f, hid_t dxpl_id, H5O_t *oh, const H5O_msg_class_t **type_p, int sequence) { unsigned u; unsigned ret_value; FUNC_ENTER_NOAPI_NOINIT(H5O_find_in_ohdr) /* Check args */ HDassert(f); HDassert(oh); HDassert(type_p); /* Scan through the messages looking for the right one */ for(u = 0; u < oh->nmesgs; u++) { if(*type_p && (*type_p)->id != oh->mesg[u].type->id) continue; if(--sequence < 0) break; } /* end for */ if(sequence >= 0) HGOTO_ERROR(H5E_OHDR, H5E_NOTFOUND, UFAIL, "unable to find object header message") /* * Decode the message if necessary. If the message is shared then decode * a shared message, ignoring the message type. */ LOAD_NATIVE(f, dxpl_id, &(oh->mesg[u]), UFAIL) /* * Return the message type. If this is a shared message then return the * pointed-to type. */ *type_p = oh->mesg[u].type; /* Set return value */ ret_value = u; done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_find_in_ohdr() */ /*------------------------------------------------------------------------- * Function: H5O_modify * * Purpose: Modifies an existing message or creates a new message. * The cache fields in that symbol table entry ENT are *not* * updated, you must do that separately because they often * depend on multiple object header messages. Besides, we * don't know which messages will be constant and which will * not. * * The OVERWRITE argument is either a sequence number of a * message to overwrite (usually zero) or the constant * H5O_NEW_MESG (-1) to indicate that a new message is to * be created. If the message to overwrite doesn't exist then * it is created (but only if it can be inserted so its sequence * number is OVERWRITE; that is, you can create a message with * the sequence number 5 if there is no message with sequence * number 4). * * The UPDATE_TIME argument is a boolean that allows the caller * to skip updating the modification time. This is useful when * several calls to H5O_modify will be made in a sequence. * * Return: Success: The sequence number of the message that * was modified or created. * * Failure: Negative * * Programmer: Robb Matzke * matzke@llnl.gov * Aug 6 1997 * *------------------------------------------------------------------------- */ /* JAMES: this will probably get put through its paces when extending shared * dataspaces */ int H5O_modify(H5O_loc_t *loc, unsigned type_id, int overwrite, unsigned flags, unsigned update_flags, void *mesg, hid_t dxpl_id) { const H5O_msg_class_t *type; /* Actual H5O class type for the ID */ htri_t shared_mess; int ret_value; /* Return value */ FUNC_ENTER_NOAPI(H5O_modify, FAIL) /* check args */ HDassert(loc); HDassert(loc->file); HDassert(H5F_addr_defined(loc->addr)); HDassert(type_id < NELMTS(H5O_msg_class_g)); type = H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */ HDassert(type); HDassert(mesg); HDassert(0 == (flags & ~H5O_FLAG_BITS)); /* Should this message be written as a SOHM? */ if((shared_mess = H5SM_try_share(loc->file, dxpl_id, type_id, mesg)) >0) { /* Mark the message as shared */ flags |= H5O_FLAG_SHARED; } else if(shared_mess < 0) HGOTO_ERROR(H5E_OHDR, H5E_BADMESG, FAIL, "error while trying to share message"); /* Call the "real" modify routine */ if((ret_value = H5O_modify_real(loc, type, overwrite, flags, update_flags, mesg, dxpl_id)) < 0) HGOTO_ERROR(H5E_OHDR, H5E_WRITEERROR, FAIL, "unable to write object header message") done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_modify() */ /*------------------------------------------------------------------------- * Function: H5O_modify_real * * Purpose: Modifies an existing message or creates a new message. * The cache fields in that symbol table entry ENT are *not* * updated, you must do that separately because they often * depend on multiple object header messages. Besides, we * don't know which messages will be constant and which will * not. * * The OVERWRITE argument is either a sequence number of a * message to overwrite (usually zero) or the constant * H5O_NEW_MESG (-1) to indicate that a new message is to * be created. If the message to overwrite doesn't exist then * it is created (but only if it can be inserted so its sequence * number is OVERWRITE; that is, you can create a message with * the sequence number 5 if there is no message with sequence * number 4). * * The UPDATE_TIME argument is a boolean that allows the caller * to skip updating the modification time. This is useful when * several calls to H5O_modify will be made in a sequence. * * Return: Success: The sequence number of the message that * was modified or created. * * Failure: Negative * * Programmer: Robb Matzke * matzke@llnl.gov * Aug 6 1997 * *------------------------------------------------------------------------- */ static int H5O_modify_real(H5O_loc_t *loc, const H5O_msg_class_t *type, int overwrite, unsigned flags, unsigned update_flags, const void *mesg, hid_t dxpl_id) { H5O_t *oh = NULL; unsigned oh_flags = H5AC__NO_FLAGS_SET; int sequence; unsigned idx; /* Index of message to modify */ H5O_mesg_t *idx_msg; /* Pointer to message to modify */ H5O_shared_t sh_mesg; const H5O_msg_class_t *write_type = type; /* Type of message to be written */ const void *write_mesg = mesg; /* Actual message being written */ int ret_value; FUNC_ENTER_NOAPI_NOINIT(H5O_modify_real) /* check args */ HDassert(loc); HDassert(loc->file); HDassert(H5F_addr_defined(loc->addr)); HDassert(type); HDassert(mesg); HDassert(0 == (flags & ~H5O_FLAG_BITS)); /* Check for write access on the file */ if(0 == (loc->file->intent & H5F_ACC_RDWR)) HGOTO_ERROR(H5E_OHDR, H5E_WRITEERROR, FAIL, "no write intent on file") /* Protect the object header */ if(NULL == (oh = H5AC_protect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, NULL, NULL, H5AC_WRITE))) HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "unable to load object header") /* Count similar messages */ for(idx = 0, sequence = -1, idx_msg=&oh->mesg[0]; idx < oh->nmesgs; idx++, idx_msg++) { if(type->id != idx_msg->type->id) continue; if(++sequence == overwrite) break; } /* end for */ /* Was the right message found? */ if(overwrite >= 0 && (idx >= oh->nmesgs || sequence != overwrite)) { /* No, but can we insert a new one with this sequence number? */ if(overwrite == sequence + 1) overwrite = -1; else HGOTO_ERROR(H5E_OHDR, H5E_NOTFOUND, FAIL, "message not found") } /* end if */ /* Check for creating new message */ if(overwrite < 0) { /* Create a new message */ /* JAMES: why is sh_mesg passed in here? Is it ever used? */ if((idx = H5O_new_mesg(loc->file, oh, &flags, type, mesg, &sh_mesg, &type, &mesg, dxpl_id, &oh_flags)) == UFAIL) HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to create new message") /* Set the correct sequence number for the message created */ sequence++; } else if(oh->mesg[idx].flags & H5O_FLAG_CONSTANT) { HGOTO_ERROR(H5E_OHDR, H5E_WRITEERROR, FAIL, "unable to modify constant message") } else if(oh->mesg[idx].flags & H5O_FLAG_SHARED) { /* This message is shared, but it's being modified. This is valid if * it's shared in the heap . * First, make sure it's not a committed message; these can't ever * be modified. */ if(((H5O_shared_t*) oh->mesg[idx].native)->flags & H5O_COMMITTED_FLAG) HGOTO_ERROR(H5E_OHDR, H5E_WRITEERROR, FAIL, "unable to modify committed message") /* Remove the old message from the SOHM index */ if(H5SM_try_delete(loc->file, dxpl_id, oh->mesg[idx].type->id, oh->mesg[idx].native) < 0) HGOTO_ERROR (H5E_OHDR, H5E_CANTFREE, FAIL, "unable to delete message from SOHM table") /* Now this message is no longer shared and we can safely overwrite * it. * We need to make sure that the message we're writing is shared, * though, and that the library doesn't try to reset the current * message like it would in a normal overwrite (this message is * realy a shared pointer, not a real * message). * JAMES: will this break if a shared message is overwritten with a larger * non-shared message? */ HDassert(H5O_is_shared(type->id, mesg) > 0); /* JAMES: this should work with * replacement messages that aren't shared, too. */ if(H5O_get_share(type->id, loc->file, mesg, &sh_mesg)<0) HGOTO_ERROR (H5E_OHDR, H5E_BADMESG, FAIL, "can't get shared message") /* Instead of writing the original message, write a shared message */ write_type = H5O_msg_class_g[H5O_SHARED_ID]; write_mesg = &sh_mesg; } /* Write the information to the message */ if(H5O_write_mesg(oh, idx, write_type, write_mesg, flags, update_flags, &oh_flags) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to write message") /* Update the modification time message if any */ if(update_flags & H5O_UPDATE_TIME) H5O_touch_oh(loc->file, dxpl_id, oh, FALSE, &oh_flags); #ifdef H5O_DEBUG H5O_assert(oh); #endif /* H5O_DEBUG */ /* Set return value */ ret_value = sequence; done: if(oh && H5AC_unprotect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, oh, oh_flags) < 0) HDONE_ERROR(H5E_OHDR, H5E_PROTECT, FAIL, "unable to release object header") FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_modify_real() */ /*------------------------------------------------------------------------- * Function: H5O_protect * * Purpose: Wrapper around H5AC_protect for use during a H5O_protect-> * H5O_append->...->H5O_append->H5O_unprotect sequence of calls * during an object's creation. * * Return: Success: Pointer to the object header structure for the * object. * * Failure: NULL * * Programmer: Quincey Koziol * koziol@ncsa.uiuc.edu * Dec 31 2002 * *------------------------------------------------------------------------- */ H5O_t * H5O_protect(H5O_loc_t *loc, hid_t dxpl_id) { H5O_t *ret_value; /* Return value */ FUNC_ENTER_NOAPI(H5O_protect, NULL) /* check args */ HDassert(loc); HDassert(loc->file); HDassert(H5F_addr_defined(loc->addr)); /* Check for write access on the file */ if(0 == (loc->file->intent & H5F_ACC_RDWR)) HGOTO_ERROR(H5E_OHDR, H5E_WRITEERROR, NULL, "no write intent on file") /* Lock the object header into the cache */ if(NULL == (ret_value = H5AC_protect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, NULL, NULL, H5AC_WRITE))) HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "unable to load object header") done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_protect() */ /*------------------------------------------------------------------------- * Function: H5O_unprotect * * Purpose: Wrapper around H5AC_unprotect for use during a H5O_protect-> * H5O_append->...->H5O_append->H5O_unprotect sequence of calls * during an object's creation. * * Return: Success: Non-negative * * Failure: Negative * * Programmer: Quincey Koziol * koziol@ncsa.uiuc.edu * Dec 31 2002 * *------------------------------------------------------------------------- */ herr_t H5O_unprotect(H5O_loc_t *loc, H5O_t *oh, hid_t dxpl_id, unsigned oh_flags) { herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(H5O_unprotect, FAIL) /* check args */ HDassert(loc); HDassert(loc->file); HDassert(H5F_addr_defined(loc->addr)); HDassert(oh); /* Release the object header from the cache */ if(H5AC_unprotect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, oh, oh_flags) < 0) HGOTO_ERROR(H5E_OHDR, H5E_PROTECT, FAIL, "unable to release object header") done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_unprotect() */ /*------------------------------------------------------------------------- * Function: H5O_append * * Purpose: Simplified version of H5O_modify, used when creating a new * object header message (usually during object creation) * * Return: Success: The sequence number of the message that * was created. * * Failure: Negative * * Programmer: Quincey Koziol * koziol@ncsa.uiuc.edu * Dec 31 2002 * *------------------------------------------------------------------------- */ int H5O_append(H5F_t *f, hid_t dxpl_id, H5O_t *oh, unsigned type_id, unsigned flags, void *mesg, unsigned * oh_flags_ptr) { const H5O_msg_class_t *type; /* Actual H5O class type for the ID */ htri_t shared_mess; /* Should this message be stored in the Shared Message table? */ int ret_value; /* Return value */ FUNC_ENTER_NOAPI(H5O_append, FAIL) /* check args */ HDassert(f); HDassert(oh); HDassert(type_id < NELMTS(H5O_msg_class_g)); type = H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */ HDassert(type); HDassert(0 == (flags & ~H5O_FLAG_BITS)); HDassert(mesg); HDassert(oh_flags_ptr); /* Should this message be written as a SOHM? */ if((shared_mess = H5SM_try_share(f, dxpl_id, type_id, mesg)) >0) { /* Mark the message as shared */ flags |= H5O_FLAG_SHARED; } else if(shared_mess < 0) HGOTO_ERROR(H5E_OHDR, H5E_WRITEERROR, FAIL, "error determining if message should be shared"); if((ret_value = H5O_append_real( f, dxpl_id, oh, type, flags, mesg, oh_flags_ptr)) < 0) HGOTO_ERROR(H5E_OHDR, H5E_WRITEERROR, FAIL, "unable to append to object header") done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_append() */ /*------------------------------------------------------------------------- * Function: H5O_append_real * * Purpose: Simplified version of H5O_modify, used when creating a new * object header message (usually during object creation) * * Return: Success: The sequence number of the message that * was created. * * Failure: Negative * * Programmer: Quincey Koziol * koziol@ncsa.uiuc.edu * Dec 31 2002 * *------------------------------------------------------------------------- */ static int H5O_append_real(H5F_t *f, hid_t dxpl_id, H5O_t *oh, const H5O_msg_class_t *type, unsigned flags, const void *mesg, unsigned * oh_flags_ptr) { unsigned idx; /* Index of message to modify */ H5O_shared_t sh_mesg; int ret_value; FUNC_ENTER_NOAPI_NOINIT(H5O_append_real) /* check args */ HDassert(f); HDassert(oh); HDassert(type); HDassert(0 == (flags & ~H5O_FLAG_BITS)); HDassert(mesg); HDassert(oh_flags_ptr); /* Create a new message */ if((idx = H5O_new_mesg(f, oh, &flags, type, mesg, &sh_mesg, &type, &mesg, dxpl_id, oh_flags_ptr)) == UFAIL) HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to create new message") /* Write the information to the message */ if(H5O_write_mesg(oh, idx, type, mesg, flags, 0, oh_flags_ptr) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to write message") #ifdef H5O_DEBUG H5O_assert(oh); #endif /* H5O_DEBUG */ /* Set return value */ ret_value = idx; done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_append_real () */ /*------------------------------------------------------------------------- * Function: H5O_new_mesg * * Purpose: Create a new message in an object header * * Return: Success: Index of message * Failure: Negative * * Programmer: Quincey Koziol * Friday, September 3, 2003 * *------------------------------------------------------------------------- */ static unsigned H5O_new_mesg(H5F_t *f, H5O_t *oh, unsigned *flags, const H5O_msg_class_t *orig_type, const void *orig_mesg, H5O_shared_t *sh_mesg, const H5O_msg_class_t **new_type, const void **new_mesg, hid_t dxpl_id, unsigned * oh_flags_ptr) { size_t size; /* Size of space allocated for object header */ htri_t is_shared; /* Is this a shared message? */ unsigned ret_value = UFAIL; /* Return value */ FUNC_ENTER_NOAPI_NOINIT(H5O_new_mesg) /* check args */ HDassert(f); HDassert(oh); HDassert(flags); HDassert(orig_type); HDassert(orig_mesg); HDassert(sh_mesg); HDassert(new_mesg); HDassert(new_type); HDassert(oh_flags_ptr); /* Check for shared message */ if(*flags & H5O_FLAG_SHARED) { HDmemset(sh_mesg, 0, sizeof(H5O_shared_t)); if ((NULL == orig_type->is_shared) || (NULL == orig_type->get_share)) HGOTO_ERROR(H5E_OHDR, H5E_UNSUPPORTED, UFAIL, "message class is not sharable"); if ((is_shared = (orig_type->is_shared)(orig_mesg)) == FALSE) { /* * If the message isn't shared then turn off the shared bit * and treat it as an unshared message. */ *flags &= ~H5O_FLAG_SHARED; } else if(is_shared > 0) { /* Message is shared. Get shared message, change message type, * and use shared information */ if ((orig_type->get_share)(f, orig_mesg, sh_mesg/*out*/) < 0) HGOTO_ERROR(H5E_OHDR, H5E_BADMESG, UFAIL, "can't get shared message") *new_type = H5O_MSG_SHARED; *new_mesg = sh_mesg; } else { HGOTO_ERROR(H5E_OHDR, H5E_BADMESG, UFAIL, "can't determine if message is shared") }/* end else */ } /* end if */ else { *new_type = orig_type; *new_mesg = orig_mesg; } /* end else */ /* Compute the size needed to store the message on disk */ if((size = ((*new_type)->raw_size)(f, *new_mesg)) >= H5O_MESG_MAX_SIZE) HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, UFAIL, "object header message is too large") /* Allocate space in the object header for the message */ if((ret_value = H5O_alloc(f, dxpl_id, oh, orig_type, size, oh_flags_ptr)) == UFAIL) HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, UFAIL, "unable to allocate space for message") /* Increment any links in message */ if((*new_type)->link && ((*new_type)->link)(f, dxpl_id, (*new_mesg)) < 0) HGOTO_ERROR(H5E_OHDR, H5E_LINKCOUNT, UFAIL, "unable to adjust shared object link count") done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_new_mesg() */ /*------------------------------------------------------------------------- * Function: H5O_write_mesg * * Purpose: Write message to object header * * Return: Non-negative on success/Negative on failure * * Programmer: Quincey Koziol * Friday, September 3, 2003 * *------------------------------------------------------------------------- */ static herr_t H5O_write_mesg(H5O_t *oh, unsigned idx, const H5O_msg_class_t *type, const void *mesg, unsigned flags, unsigned update_flags, unsigned * oh_flags_ptr) { H5O_mesg_t *idx_msg; /* Pointer to message to modify */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI_NOINIT(H5O_write_mesg) /* check args */ HDassert(oh); HDassert(type); HDassert(mesg); HDassert(oh_flags_ptr); /* Set pointer to the correct message */ idx_msg = &oh->mesg[idx]; /* Reset existing native information */ if(!(update_flags & H5O_UPDATE_DATA_ONLY)) H5O_reset_real(type, idx_msg->native); /* Copy the native value for the message */ if(NULL == (idx_msg->native = (type->copy)(mesg, idx_msg->native, update_flags))) HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to copy message to object header") idx_msg->flags = flags; idx_msg->dirty = TRUE; *oh_flags_ptr |= H5AC__DIRTIED_FLAG; done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_write_mesg() */ /*------------------------------------------------------------------------- * Function: H5O_touch_oh * * Purpose: If FORCE is non-zero then create a modification time message * unless one already exists. Then update any existing * modification time message with the current time. * * Return: Non-negative on success/Negative on failure * * Programmer: Robb Matzke * Monday, July 27, 1998 * *------------------------------------------------------------------------- */ herr_t H5O_touch_oh(H5F_t *f, hid_t dxpl_id, H5O_t *oh, hbool_t force, unsigned * oh_flags_ptr) { time_t now; /* Current time */ unsigned idx; /* Index of modification time message to update */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI_NOINIT(H5O_touch_oh) HDassert(oh); HDassert(oh_flags_ptr); /* Look for existing message */ for(idx = 0; idx < oh->nmesgs; idx++) if(H5O_MSG_MTIME == oh->mesg[idx].type || H5O_MSG_MTIME_NEW == oh->mesg[idx].type) break; #ifdef H5_HAVE_GETTIMEOFDAY { struct timeval now_tv; HDgettimeofday(&now_tv, NULL); now = now_tv.tv_sec; } #else /* H5_HAVE_GETTIMEOFDAY */ now = HDtime(NULL); #endif /* H5_HAVE_GETTIMEOFDAY */ /* Create a new message, if necessary */ if(idx == oh->nmesgs) { size_t size; /* New modification time message size */ /* If we have to create a new message, but we aren't 'forcing' it, get out now */ if(!force) HGOTO_DONE(SUCCEED); /*nothing to do*/ size = (H5O_MSG_MTIME_NEW->raw_size)(f, &now); if((idx = H5O_alloc(f, dxpl_id, oh, H5O_MSG_MTIME_NEW, size, oh_flags_ptr)) == UFAIL) HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to allocate space for modification time message") } /* end if */ /* Allocate 'native' space, if necessary */ if(NULL == oh->mesg[idx].native) { if(NULL == (oh->mesg[idx].native = H5FL_MALLOC(time_t))) HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "memory allocation failed for modification time message") } /* end if */ /* Update the message */ *((time_t *)(oh->mesg[idx].native)) = now; /* Mark the message & object header as dirty */ oh->mesg[idx].dirty = TRUE; *oh_flags_ptr |= H5AC__DIRTIED_FLAG; done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_touch_oh() */ /*------------------------------------------------------------------------- * Function: H5O_touch * * Purpose: Touch an object by setting the modification time to the * current time and marking the object as dirty. Unless FORCE * is non-zero, nothing happens if there is no MTIME message in * the object header. * * Return: Non-negative on success/Negative on failure * * Programmer: Robb Matzke * Monday, July 27, 1998 * *------------------------------------------------------------------------- */ herr_t H5O_touch(H5O_loc_t *loc, hbool_t force, hid_t dxpl_id) { H5O_t *oh = NULL; unsigned oh_flags = H5AC__NO_FLAGS_SET; herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(H5O_touch, FAIL) /* check args */ HDassert(loc); HDassert(loc->file); HDassert(H5F_addr_defined(loc->addr)); if(0 == (loc->file->intent & H5F_ACC_RDWR)) HGOTO_ERROR(H5E_OHDR, H5E_WRITEERROR, FAIL, "no write intent on file") /* Get the object header */ if(NULL == (oh = H5AC_protect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, NULL, NULL, H5AC_WRITE))) HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "unable to load object header") /* Create/Update the modification time message */ if(H5O_touch_oh(loc->file, dxpl_id, oh, force, &oh_flags) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to update object modificaton time") done: if(oh && H5AC_unprotect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, oh, oh_flags) < 0) HDONE_ERROR(H5E_OHDR, H5E_PROTECT, FAIL, "unable to release object header") FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_touch() */ #ifdef H5O_ENABLE_BOGUS /*------------------------------------------------------------------------- * Function: H5O_bogus_oh * * Purpose: Create a "bogus" message unless one already exists. * * Return: Non-negative on success/Negative on failure * * Programmer: Quincey Koziol * * Tuesday, January 21, 2003 * *------------------------------------------------------------------------- */ herr_t H5O_bogus_oh(H5F_t *f, hid_t dxpl_id, H5O_t *oh, hbool_t * oh_flags_ptr) { int idx; herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER(H5O_bogus_oh, FAIL) HDassert(f); HDassert(oh); HDassert(oh_flags_ptr); /* Look for existing message */ for(idx = 0; idx < oh->nmesgs; idx++) if(H5O_MSG_BOGUS == oh->mesg[idx].type) break; /* Create a new message */ if(idx == oh->nmesgs) { size_t size = (H5O_MSG_BOGUS->raw_size)(f, NULL); if((idx = H5O_alloc(f, dxpl_id, oh, H5O_MSG_BOGUS, size, oh_flags_ptr)) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to allocate space for 'bogus' message") /* Allocate the native message in memory */ if(NULL == (oh->mesg[idx].native = H5MM_malloc(sizeof(H5O_bogus_t)))) HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "memory allocation failed for 'bogus' message") /* Update the native part */ ((H5O_bogus_t *)(oh->mesg[idx].native))->u = H5O_BOGUS_VALUE; /* Mark the message and object header as dirty */ *oh_flags_ptr = TRUE; oh->mesg[idx].dirty = TRUE; oh->dirty = TRUE; } /* end if */ done: FUNC_LEAVE(ret_value) } /* end H5O_bogus_oh() */ /*------------------------------------------------------------------------- * Function: H5O_bogus * * Purpose: Create a "bogus" message in an object. * * Return: Non-negative on success/Negative on failure * * Programmer: Quincey Koziol * * Tuesday, January 21, 2003 * *------------------------------------------------------------------------- */ herr_t H5O_bogus(H5O_loc_t *loc, hid_t dxpl_id) { H5O_t *oh = NULL; unsigned oh_flags = H5AC__NO_FLAGS_SET; herr_t ret_value = SUCCEED; FUNC_ENTER(H5O_bogus, FAIL) /* check args */ HDassert(loc); HDassert(loc->file); HDassert(H5F_addr_defined(loc->addr)); /* Verify write access to the file */ if(0 == (loc->file->intent & H5F_ACC_RDWR)) HGOTO_ERROR(H5E_OHDR, H5E_WRITEERROR, FAIL, "no write intent on file") /* Get the object header */ if(NULL == (oh = H5AC_protect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, NULL, NULL, H5AC_WRITE))) HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "unable to load object header") /* Create the "bogus" message */ if(H5O_bogus_oh(ent->file, dxpl_id, oh, &oh_flags) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to update object 'bogus' message") done: if(oh && H5AC_unprotect(ent->file, dxpl_id, H5AC_OHDR, ent->header, oh, oh_flags) < 0) HDONE_ERROR(H5E_OHDR, H5E_PROTECT, FAIL, "unable to release object header") FUNC_LEAVE(ret_value) } /* end H5O_bogus() */ #endif /* H5O_ENABLE_BOGUS */ /*------------------------------------------------------------------------- * Function: H5O_remove * * Purpose: Removes the specified message from the object header. * If sequence is H5O_ALL (-1) then all messages of the * specified type are removed. Removing a message causes * the sequence numbers to change for subsequent messages of * the same type. * * No attempt is made to join adjacent free areas of the * object header into a single larger free area. * * Return: Non-negative on success/Negative on failure * * Programmer: Robb Matzke * matzke@llnl.gov * Aug 28 1997 * * Modifications: * * Robb Matzke, 7 Jan 1998 * Does not remove constant messages. * * Changed to use IDs for types, instead of type objects, then * call "real" routine. * Quincey Koziol * Feb 14 2003 * *------------------------------------------------------------------------- */ herr_t H5O_remove(H5O_loc_t *loc, unsigned type_id, int sequence, hbool_t adj_link, hid_t dxpl_id) { const H5O_msg_class_t *type; /* Actual H5O class type for the ID */ herr_t ret_value; /* Return value */ FUNC_ENTER_NOAPI(H5O_remove, FAIL) /* check args */ HDassert(loc); HDassert(loc->file); HDassert(H5F_addr_defined(loc->addr)); HDassert(type_id < NELMTS(H5O_msg_class_g)); type = H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */ HDassert(type); /* Call the "real" remove routine */ if((ret_value = H5O_remove_real(loc, type, sequence, NULL, NULL, adj_link, dxpl_id)) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, FAIL, "unable to remove object header message") done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_remove() */ /*------------------------------------------------------------------------- * Function: H5O_remove_op * * Purpose: Removes messages from the object header that a callback * routine indicates should be removed. * * No attempt is made to join adjacent free areas of the * object header into a single larger free area. * * Return: Non-negative on success/Negative on failure * * Programmer: Quincey Koziol * koziol@ncsa.uiuc.edu * Sep 6 2005 * *------------------------------------------------------------------------- */ herr_t H5O_remove_op(const H5O_loc_t *loc, unsigned type_id, int sequence, H5O_operator_t op, void *op_data, hbool_t adj_link, hid_t dxpl_id) { const H5O_msg_class_t *type; /* Actual H5O class type for the ID */ herr_t ret_value; /* Return value */ FUNC_ENTER_NOAPI(H5O_remove_op, FAIL) /* check args */ HDassert(loc); HDassert(loc->file); HDassert(H5F_addr_defined(loc->addr)); HDassert(type_id < NELMTS(H5O_msg_class_g)); type = H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */ HDassert(type); /* Call the "real" remove routine */ if((ret_value = H5O_remove_real(loc, type, sequence, op, op_data, adj_link, dxpl_id)) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, FAIL, "unable to remove object header message") done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_remove_op() */ /*------------------------------------------------------------------------- * Function: H5O_remove_cb * * Purpose: Object header iterator callback routine to remove messages * of a particular type that match a particular sequence number, * or all messages if the sequence number is H5O_ALL (-1). * * Return: Non-negative on success/Negative on failure * * Programmer: Quincey Koziol * koziol@ncsa.uiuc.edu * Sep 6 2005 * *------------------------------------------------------------------------- */ static herr_t H5O_remove_cb(H5O_t *oh, H5O_mesg_t *mesg/*in,out*/, unsigned sequence, unsigned * oh_flags_ptr, void *_udata/*in,out*/) { H5O_iter_ud1_t *udata = (H5O_iter_ud1_t *)_udata; /* Operator user data */ htri_t try_remove = FALSE; /* Whether to try removing a message */ herr_t ret_value = H5O_ITER_CONT; /* Return value */ FUNC_ENTER_NOAPI_NOINIT(H5O_remove_cb) /* check args */ HDassert(mesg); /* Check for callback routine */ if(udata->op) { /* Call the iterator callback */ if((try_remove = (udata->op)(mesg->native, sequence, udata->op_data)) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, H5O_ITER_ERROR, "object header message deletion callback failed") } /* end if */ else { /* If there's no callback routine, does the sequence # match? */ if((int)sequence == udata->sequence || H5O_ALL == udata->sequence) try_remove = H5O_ITER_STOP; } /* end else */ /* Try removing the message, if indicated */ if(try_remove) { /* * Keep track of how many times we failed trying to remove constant * messages. */ if(mesg->flags & H5O_FLAG_CONSTANT) udata->nfailed++; else { /* Convert message into a null message */ if(H5O_release_mesg(udata->f, udata->dxpl_id, oh, mesg, TRUE, udata->adj_link) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, H5O_ITER_ERROR, "unable to convert into null message") /* Indicate that the object header was modified */ *oh_flags_ptr |= H5AC__DIRTIED_FLAG; } /* end else */ /* Break out now, if we've found the correct message */ if(udata->sequence == H5O_FIRST || udata->sequence != H5O_ALL) HGOTO_DONE(H5O_ITER_STOP) } /* end if */ done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_remove_cb() */ /*------------------------------------------------------------------------- * Function: H5O_remove_real * * Purpose: Removes the specified message from the object header. * If sequence is H5O_ALL (-1) then all messages of the * specified type are removed. Removing a message causes * the sequence numbers to change for subsequent messages of * the same type. * * No attempt is made to join adjacent free areas of the * object header into a single larger free area. * * Return: Non-negative on success/Negative on failure * * Programmer: Robb Matzke * matzke@llnl.gov * Aug 28 1997 * *------------------------------------------------------------------------- */ static herr_t H5O_remove_real(const H5O_loc_t *loc, const H5O_msg_class_t *type, int sequence, H5O_operator_t app_op, void *op_data, hbool_t adj_link, hid_t dxpl_id) { H5O_iter_ud1_t udata; /* User data for iterator */ H5O_mesg_operator_t op; /* Wrapper for operator */ herr_t ret_value=SUCCEED; /* Return value */ FUNC_ENTER_NOAPI_NOINIT(H5O_remove_real) /* check args */ HDassert(loc); HDassert(loc->file); HDassert(type); /* Make certain we are allowed to modify the file */ if(0 == (loc->file->intent & H5F_ACC_RDWR)) HGOTO_ERROR(H5E_HEAP, H5E_WRITEERROR, FAIL, "no write intent on file") /* Set up iterator operator data */ udata.f = loc->file; udata.dxpl_id = dxpl_id; udata.sequence = sequence; udata.nfailed = 0; udata.op = app_op; udata.op_data = op_data; udata.adj_link = adj_link; /* Iterate over the messages, deleting appropriate one(s) */ op.lib_op = H5O_remove_cb; if(H5O_iterate_real(loc, type, H5AC_WRITE, TRUE, op, &udata, dxpl_id) < 0) HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "error iterating over messages") /* Fail if we tried to remove any constant messages */ if(udata.nfailed) HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to remove constant message(s)") done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_remove_real() */ /*------------------------------------------------------------------------- * * Function: H5O_alloc_msgs * * Purpose: Allocate more messages for a header * * Return: Non-negative on success/Negative on failure * * Programmer: Quincey Koziol * koziol@ncsa.uiuc.edu * Nov 21 2005 * *------------------------------------------------------------------------- */ static herr_t H5O_alloc_msgs(H5O_t *oh, size_t min_alloc) { size_t old_alloc; /* Old number of messages allocated */ size_t na; /* New number of messages allocated */ H5O_mesg_t *new_mesg; /* Pointer to new message array */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI_NOINIT(H5O_alloc_msgs) /* check args */ HDassert(oh); /* Initialize number of messages information */ old_alloc = oh->alloc_nmesgs; na = oh->alloc_nmesgs + MAX(oh->alloc_nmesgs, min_alloc); /* Attempt to allocate more memory */ if(NULL == (new_mesg = H5FL_SEQ_REALLOC(H5O_mesg_t, oh->mesg, na))) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") /* Update ohdr information */ oh->alloc_nmesgs = na; oh->mesg = new_mesg; /* Set new object header info to zeros */ HDmemset(&oh->mesg[old_alloc], 0, (oh->alloc_nmesgs - old_alloc) * sizeof(H5O_mesg_t)); done: FUNC_LEAVE_NOAPI(ret_value) } /* H5O_alloc_msgs() */ /*------------------------------------------------------------------------- * * Function: H5O_alloc_null * * Purpose: Allocate room for a new message from a null message * * Return: Non-negative on success/Negative on failure * * Programmer: Quincey Koziol * koziol@hdfgroup.org * Oct 22 2006 * *------------------------------------------------------------------------- */ static herr_t H5O_alloc_null(H5O_t *oh, unsigned null_idx, const H5O_msg_class_t *new_type, void *new_native, size_t new_size) { H5O_mesg_t *alloc_msg; /* Pointer to null message to allocate out of */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI_NOINIT(H5O_alloc_null) /* check args */ HDassert(oh); HDassert(new_type); HDassert(new_size); /* Point to null message to allocate out of */ alloc_msg = &oh->mesg[null_idx]; /* Check if there's a need to split the null message */ if(alloc_msg->raw_size > new_size) { /* Check for producing a gap in the chunk */ if((alloc_msg->raw_size - new_size) < (size_t)H5O_SIZEOF_MSGHDR_OH(oh)) { size_t gap_size = alloc_msg->raw_size - new_size; /* Size of gap produced */ /* Adjust the size of the null message being eliminated */ alloc_msg->raw_size = new_size; /* Add the gap to the chunk */ if(H5O_add_gap(oh, alloc_msg->chunkno, null_idx, alloc_msg->raw + alloc_msg->raw_size, gap_size) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, UFAIL, "can't insert gap in chunk") } /* end if */ else { size_t new_mesg_size = new_size + H5O_SIZEOF_MSGHDR_OH(oh); /* Total size of newly allocated message */ H5O_mesg_t *null_msg; /* Pointer to new null message */ /* Check if we need to extend message table to hold the new null message */ if(oh->nmesgs >= oh->alloc_nmesgs) { if(H5O_alloc_msgs(oh, (size_t)1) < 0) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, UFAIL, "can't allocate more space for messages") /* "Retarget" 'alloc_msg' pointer into newly re-allocated array of messages */ alloc_msg = &oh->mesg[null_idx]; } /* end if */ /* Create new null message, with the tail of the previous null message */ null_msg = &(oh->mesg[oh->nmesgs++]); null_msg->type = H5O_MSG_NULL; null_msg->dirty = TRUE; null_msg->native = NULL; null_msg->raw = alloc_msg->raw + new_mesg_size; null_msg->raw_size = alloc_msg->raw_size - new_mesg_size; null_msg->chunkno = alloc_msg->chunkno; /* Check for gap in new null message's chunk */ if(oh->chunk[null_msg->chunkno].gap > 0) { unsigned null_chunkno = null_msg->chunkno; /* Chunk w/gap */ /* Eliminate the gap in the chunk */ if(H5O_eliminate_gap(oh, null_msg, ((oh->chunk[null_chunkno].image + oh->chunk[null_chunkno].size) - (H5O_SIZEOF_CHKSUM_OH(oh) + oh->chunk[null_chunkno].gap)), oh->chunk[null_chunkno].gap) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTREMOVE, UFAIL, "can't eliminate gap in chunk") /* Set the gap size to zero for the chunk */ oh->chunk[null_chunkno].gap = 0; } /* end if */ /* Set the size of the new "real" message */ alloc_msg->raw_size = new_size; } /* end else */ } /* end if */ /* Initialize the new message */ alloc_msg->type = new_type; alloc_msg->dirty = TRUE; alloc_msg->native = new_native; done: FUNC_LEAVE_NOAPI(ret_value) } /* H5O_alloc_null() */ /*------------------------------------------------------------------------- * * Function: H5O_release_mesg * * Purpose: Convert a message into a null message * * Return: Non-negative on success/Negative on failure * * Programmer: Quincey Koziol * koziol@hdfgroup.org * Oct 22 2006 * *------------------------------------------------------------------------- */ static herr_t H5O_release_mesg(H5F_t *f, hid_t dxpl_id, H5O_t *oh, H5O_mesg_t *mesg, hbool_t delete_mesg, hbool_t adj_link) { herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI_NOINIT(H5O_release_mesg) /* check args */ HDassert(f); HDassert(oh); HDassert(mesg); /* Check if we should operate on the message */ if(delete_mesg) { /* Free any space referred to in the file from this message */ if(H5O_delete_mesg(f, dxpl_id, mesg, adj_link) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, FAIL, "unable to delete file space for object header message") /* Free any native information */ H5O_free_mesg(mesg); } /* end if */ /* Change message type to nil and zero it */ mesg->type = H5O_MSG_NULL; HDassert(mesg->raw + mesg->raw_size <= (oh->chunk[mesg->chunkno].image + oh->chunk[mesg->chunkno].size) - (H5O_SIZEOF_CHKSUM_OH(oh) + oh->chunk[mesg->chunkno].gap)); HDmemset(mesg->raw, 0, mesg->raw_size); /* Clear message flags */ mesg->flags = 0; /* Indicate that the message was modified */ mesg->dirty = TRUE; /* Check if chunk has a gap currently */ if(oh->chunk[mesg->chunkno].gap) { /* Eliminate the gap in the chunk */ if(H5O_eliminate_gap(oh, mesg, ((oh->chunk[mesg->chunkno].image + oh->chunk[mesg->chunkno].size) - (H5O_SIZEOF_CHKSUM_OH(oh) + oh->chunk[mesg->chunkno].gap)), oh->chunk[mesg->chunkno].gap) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTREMOVE, FAIL, "can't eliminate gap in chunk") /* Set the gap size to zero for the chunk */ oh->chunk[mesg->chunkno].gap = 0; } /* end if */ done: FUNC_LEAVE_NOAPI(ret_value) } /* H5O_release_mesg() */ /*------------------------------------------------------------------------- * * Function: H5O_move_msgs_forward * * Purpose: Move messages toward first chunk * * Return: Non-negative on success/Negative on failure * * Programmer: Quincey Koziol * koziol@ncsa.uiuc.edu * Oct 17 2005 * *------------------------------------------------------------------------- */ static htri_t H5O_move_msgs_forward(H5O_t *oh) { hbool_t packed_msg; /* Flag to indicate that messages were packed */ hbool_t did_packing = FALSE; /* Whether any messages were packed */ htri_t ret_value; /* Return value */ FUNC_ENTER_NOAPI_NOINIT(H5O_move_msgs_forward) /* check args */ HDassert(oh); /* Loop until no messages packed */ /* (Double loop is not very efficient, but it would be some extra work to * add a list of messages to each chunk -QAK) */ do { H5O_mesg_t *curr_msg; /* Pointer to current message to operate on */ unsigned u; /* Local index variable */ /* Reset packed messages flag */ packed_msg = FALSE; /* Scan through messages for messages that can be moved earlier in chunks */ for(u = 0, curr_msg = &oh->mesg[0]; u < oh->nmesgs; u++, curr_msg++) { if(H5O_NULL_ID == curr_msg->type->id) { H5O_chunk_t *chunk; /* Pointer to chunk that null message is in */ /* Check if null message is not last in chunk */ chunk = &(oh->chunk[curr_msg->chunkno]); if((curr_msg->raw + curr_msg->raw_size) != ((chunk->image + chunk->size) - (H5O_SIZEOF_CHKSUM_OH(oh) + chunk->gap))) { H5O_mesg_t *nonnull_msg; /* Pointer to current message to operate on */ unsigned v; /* Local index variable */ /* Loop over messages again, looking for the message in the chunk after the null message */ for(v = 0, nonnull_msg = &oh->mesg[0]; v < oh->nmesgs; v++, nonnull_msg++) { /* Locate message that is immediately after the null message */ if((curr_msg->chunkno == nonnull_msg->chunkno) && ((curr_msg->raw + curr_msg->raw_size) == (nonnull_msg->raw - H5O_SIZEOF_MSGHDR_OH(oh)))) { /* Don't swap messages if the second message is also a null message */ /* (We'll merge them together later, in another routine) */ if(H5O_NULL_ID != nonnull_msg->type->id) { /* Copy raw data for non-null message to new location */ HDmemmove(curr_msg->raw - H5O_SIZEOF_MSGHDR_OH(oh), nonnull_msg->raw - H5O_SIZEOF_MSGHDR_OH(oh), nonnull_msg->raw_size + H5O_SIZEOF_MSGHDR_OH(oh)); /* Adjust non-null message's offset in chunk */ nonnull_msg->raw = curr_msg->raw; /* Adjust null message's offset in chunk */ curr_msg->raw = nonnull_msg->raw + nonnull_msg->raw_size + H5O_SIZEOF_MSGHDR_OH(oh); /* Mark null message dirty */ /* (since we need to re-encode its message header) */ /* (also, marking this message dirty means we * don't have to mark chunk as dirty) */ curr_msg->dirty = TRUE; /* Set the flag to indicate that the null message * was packed - if its not at the end its chunk, * we'll move it again on the next pass. */ packed_msg = TRUE; } /* end if */ /* Break out of loop */ break; } /* end if */ } /* end for */ /* Should have been message after null message */ HDassert(v < oh->nmesgs); } /* end if */ } /* end if */ else { H5O_mesg_t *null_msg; /* Pointer to current message to operate on */ unsigned v; /* Local index variable */ /* Loop over messages again, looking for large enough null message in earlier chunk */ for(v = 0, null_msg = &oh->mesg[0]; v < oh->nmesgs; v++, null_msg++) { if(H5O_NULL_ID == null_msg->type->id && curr_msg->chunkno > null_msg->chunkno && curr_msg->raw_size <= null_msg->raw_size) { unsigned old_chunkno; /* Old message information */ uint8_t *old_raw; /* Keep old information about non-null message */ old_chunkno = curr_msg->chunkno; old_raw = curr_msg->raw; /* Copy raw data for non-null message to new chunk */ HDmemcpy(null_msg->raw - H5O_SIZEOF_MSGHDR_OH(oh), curr_msg->raw - H5O_SIZEOF_MSGHDR_OH(oh), curr_msg->raw_size + H5O_SIZEOF_MSGHDR_OH(oh)); /* Mark null message's chunk as dirty, since the raw data image changed */ oh->chunk[null_msg->chunkno].dirty = TRUE; /* Point non-null message at null message's space */ curr_msg->chunkno = null_msg->chunkno; curr_msg->raw = null_msg->raw; /* Change information for null message */ if(curr_msg->raw_size == null_msg->raw_size) { /* Point null message at old non-null space */ /* (Instead of freeing it and allocating new message) */ null_msg->chunkno = old_chunkno; null_msg->raw = old_raw; /* Mark null message dirty */ null_msg->dirty = TRUE; } /* end if */ else { unsigned new_null_msg; /* Message index for new null message */ /* Check if null message is large enough to still exist */ if((null_msg->raw_size - curr_msg->raw_size) < (size_t)H5O_SIZEOF_MSGHDR_OH(oh)) { size_t gap_size = null_msg->raw_size - curr_msg->raw_size; /* Size of gap produced */ /* Adjust the size of the null message being eliminated */ null_msg->raw_size = curr_msg->raw_size; /* Add the gap to the chunk */ if(H5O_add_gap(oh, null_msg->chunkno, v, null_msg->raw + null_msg->raw_size, gap_size) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, FAIL, "can't insert gap in chunk") /* Re-use message # for new null message taking place of non-null message */ new_null_msg = v; } /* end if */ else { /* Adjust null message's size & offset */ null_msg->raw += curr_msg->raw_size + H5O_SIZEOF_MSGHDR_OH(oh); null_msg->raw_size -= curr_msg->raw_size + H5O_SIZEOF_MSGHDR_OH(oh); /* Mark null message dirty */ null_msg->dirty = TRUE; /* Create new null message for previous location of non-null message */ if(oh->nmesgs >= oh->alloc_nmesgs) { if(H5O_alloc_msgs(oh, (size_t)1) < 0) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate more space for messages") /* "Retarget" 'curr_msg' pointer into newly re-allocated array of messages */ curr_msg = &oh->mesg[u]; } /* end if */ /* Get message # for new null message */ new_null_msg = oh->nmesgs++; } /* end else */ /* Initialize new null message to take over non-null message's location */ oh->mesg[new_null_msg].type = H5O_MSG_NULL; oh->mesg[new_null_msg].dirty = TRUE; oh->mesg[new_null_msg].native = NULL; oh->mesg[new_null_msg].raw = old_raw; oh->mesg[new_null_msg].raw_size = curr_msg->raw_size; oh->mesg[new_null_msg].chunkno = old_chunkno; /* Check for gap in new null message's chunk */ if(oh->chunk[old_chunkno].gap > 0) { /* Eliminate the gap in the chunk */ if(H5O_eliminate_gap(oh, &oh->mesg[new_null_msg], ((oh->chunk[old_chunkno].image + oh->chunk[old_chunkno].size) - (H5O_SIZEOF_CHKSUM_OH(oh) + oh->chunk[old_chunkno].gap)), oh->chunk[old_chunkno].gap) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTREMOVE, FAIL, "can't eliminate gap in chunk") /* Set the gap size to zero for the chunk */ oh->chunk[old_chunkno].gap = 0; } /* end if */ } /* end else */ /* Indicate that we packed messages */ packed_msg = TRUE; /* Break out of loop */ /* (If it's possible to move message to even earlier chunk * we'll get it on the next pass - QAK) */ break; } /* end if */ } /* end for */ /* If we packed messages, get out of loop and start over */ /* (Don't know if this has any benefit one way or the other -QAK) */ if(packed_msg) break; } /* end else */ } /* end for */ /* If we did any packing, remember that */ if(packed_msg) did_packing = TRUE; } while(packed_msg); /* Set return value */ ret_value = did_packing; done: FUNC_LEAVE_NOAPI(ret_value) } /* H5O_move_msgs_forward() */ /*------------------------------------------------------------------------- * * Function: H5O_merge_null * * Purpose: Merge neighboring null messages in an object header * * Return: Non-negative on success/Negative on failure * * Programmer: Quincey Koziol * koziol@ncsa.uiuc.edu * Oct 10 2005 * *------------------------------------------------------------------------- */ static htri_t H5O_merge_null(H5O_t *oh) { hbool_t merged_msg; /* Flag to indicate that messages were merged */ hbool_t did_merging = FALSE; /* Whether any messages were merged */ htri_t ret_value; /* Return value */ FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5O_merge_null) /* check args */ HDassert(oh != NULL); /* Loop until no messages merged */ /* (Double loop is not very efficient, but it would be some extra work to add * a list of messages to each chunk -QAK) */ do { H5O_mesg_t *curr_msg; /* Pointer to current message to operate on */ unsigned u; /* Local index variable */ /* Reset merged messages flag */ merged_msg = FALSE; /* Scan messages for adjacent null messages & merge them */ for(u = 0, curr_msg = &oh->mesg[0]; u < oh->nmesgs; u++, curr_msg++) { if(H5O_NULL_ID == curr_msg->type->id) { H5O_mesg_t *curr_msg2; /* Pointer to current message to operate on */ unsigned v; /* Local index variable */ /* Should be no gaps in chunk with null message */ HDassert(oh->chunk[curr_msg->chunkno].gap == 0); /* Loop over messages again, looking for null message in same chunk */ for(v = 0, curr_msg2 = &oh->mesg[0]; v < oh->nmesgs; v++, curr_msg2++) { if(u != v && H5O_NULL_ID == curr_msg2->type->id && curr_msg->chunkno == curr_msg2->chunkno) { /* Check for second message after first message */ if((curr_msg->raw + curr_msg->raw_size) == (curr_msg2->raw - H5O_SIZEOF_MSGHDR_OH(oh))) { /* Extend first null message length to cover second null message */ curr_msg->raw_size += (H5O_SIZEOF_MSGHDR_OH(oh) + curr_msg2->raw_size); /* Message has been merged */ merged_msg = TRUE; } /* end if */ /* Check for second message before first message */ else if((curr_msg->raw - H5O_SIZEOF_MSGHDR_OH(oh)) == (curr_msg2->raw + curr_msg2->raw_size)) { /* Adjust first message address and extend length to cover second message */ curr_msg->raw -= (H5O_SIZEOF_MSGHDR_OH(oh) + curr_msg2->raw_size); curr_msg->raw_size += (H5O_SIZEOF_MSGHDR_OH(oh) + curr_msg2->raw_size); /* Message has been merged */ merged_msg = TRUE; } /* end if */ /* Second message has been merged, delete it */ if(merged_msg) { /* Release any information/memory for second message */ H5O_free_mesg(curr_msg2); /* Mark first message as dirty */ curr_msg->dirty = TRUE; /* Remove second message from list of messages */ if(v < (oh->nmesgs - 1)) HDmemmove(&oh->mesg[v], &oh->mesg[v + 1], ((oh->nmesgs - 1) - v) * sizeof(H5O_mesg_t)); /* Decrement # of messages */ /* (Don't bother reducing size of message array for now -QAK) */ oh->nmesgs--; /* Get out of loop */ break; } /* end if */ } /* end if */ } /* end for */ /* Get out of loop if we merged messages */ if(merged_msg) break; } /* end if */ } /* end for */ /* If we did any merging, remember that */ if(merged_msg) did_merging = TRUE; } while(merged_msg); /* Set return value */ ret_value = did_merging; FUNC_LEAVE_NOAPI(ret_value) } /* H5O_merge_null() */ /*------------------------------------------------------------------------- * * Function: H5O_remove_empty_chunks * * Purpose: Attempt to eliminate empty chunks from object header. * * This examines a chunk to see if it's empty * and removes it (and the continuation message that points to it) * from the object header. * * Return: Non-negative on success/Negative on failure * * Programmer: Quincey Koziol * koziol@ncsa.uiuc.edu * Oct 17 2005 * *------------------------------------------------------------------------- */ static htri_t H5O_remove_empty_chunks(H5F_t *f, H5O_t *oh, hid_t dxpl_id) { hbool_t deleted_chunk; /* Whether to a chunk was deleted */ hbool_t did_deleting = FALSE; /* Whether any chunks were deleted */ htri_t ret_value; /* Return value */ FUNC_ENTER_NOAPI_NOINIT(H5O_remove_empty_chunks) /* check args */ HDassert(oh != NULL); /* Loop until no chunks are freed */ do { H5O_mesg_t *null_msg; /* Pointer to null message found */ H5O_mesg_t *cont_msg; /* Pointer to continuation message found */ unsigned u, v; /* Local index variables */ /* Reset 'chunk deleted' flag */ deleted_chunk = FALSE; /* Scan messages for null messages that fill an entire chunk */ for(u = 0, null_msg = &oh->mesg[0]; u < oh->nmesgs; u++, null_msg++) { /* If a null message takes up an entire object header chunk (and * its not the "base" chunk), delete that chunk from object header */ if(H5O_NULL_ID == null_msg->type->id && null_msg->chunkno > 0 && (H5O_SIZEOF_MSGHDR_OH(oh) + null_msg->raw_size) == (oh->chunk[null_msg->chunkno].size - H5O_SIZEOF_CHKHDR_OH(oh))) { H5O_mesg_t *curr_msg; /* Pointer to current message to operate on */ unsigned null_msg_no; /* Message # for null message */ unsigned deleted_chunkno; /* Chunk # to delete */ /* Locate continuation message that points to chunk */ for(v = 0, cont_msg = &oh->mesg[0]; v < oh->nmesgs; v++, cont_msg++) { if(H5O_CONT_ID == cont_msg->type->id) { /* Decode current continuation message if necessary */ if(NULL == cont_msg->native) { HDassert(H5O_MSG_CONT->decode); cont_msg->native = (H5O_MSG_CONT->decode)(f, dxpl_id, cont_msg->raw); if(NULL == cont_msg->native) HGOTO_ERROR(H5E_OHDR, H5E_CANTDECODE, FAIL, "unable to decode message") } /* end if */ /* Check for correct chunk to delete */ if(oh->chunk[null_msg->chunkno].addr == ((H5O_cont_t *)(cont_msg->native))->addr) break; } /* end if */ } /* end for */ /* Must be a continuation message that points to chunk containing null message */ HDassert(v < oh->nmesgs); HDassert(cont_msg); /* Initialize information about null message */ null_msg_no = u; deleted_chunkno = null_msg->chunkno; /* Convert continuation message into a null message */ if(H5O_release_mesg(f, dxpl_id, oh, cont_msg, TRUE, TRUE) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, FAIL, "unable to convert into null message") /* * Remove chunk from object header's data structure */ /* Free memory for chunk image */ H5FL_BLK_FREE(chunk_image, oh->chunk[null_msg->chunkno].image); /* Remove chunk from list of chunks */ if(null_msg->chunkno < (oh->nchunks - 1)) HDmemmove(&oh->chunk[null_msg->chunkno], &oh->chunk[null_msg->chunkno + 1], ((oh->nchunks - 1) - null_msg->chunkno) * sizeof(H5O_chunk_t)); /* Decrement # of chunks */ /* (Don't bother reducing size of chunk array for now -QAK) */ oh->nchunks--; /* * Delete null message (in empty chunk that was be freed) from list of messages */ /* Release any information/memory for message */ H5O_free_mesg(null_msg); /* Remove null message from list of messages */ if(null_msg_no < (oh->nmesgs - 1)) HDmemmove(&oh->mesg[null_msg_no], &oh->mesg[null_msg_no + 1], ((oh->nmesgs - 1) - null_msg_no) * sizeof(H5O_mesg_t)); /* Decrement # of messages */ /* (Don't bother reducing size of message array for now -QAK) */ oh->nmesgs--; /* Adjust chunk # for messages in chunks after deleted chunk */ for(u = 0, curr_msg = &oh->mesg[0]; u < oh->nmesgs; u++, curr_msg++) { HDassert(curr_msg->chunkno != deleted_chunkno); if(curr_msg->chunkno > deleted_chunkno) curr_msg->chunkno--; } /* end for */ /* Found chunk to delete */ deleted_chunk = TRUE; break; } /* end if */ } /* end for */ /* If we deleted any chunks, remember that */ if(deleted_chunk) did_deleting = TRUE; } while(deleted_chunk); /* Set return value */ ret_value = did_deleting; done: FUNC_LEAVE_NOAPI(ret_value) } /* H5O_remove_empty_chunks() */ /*------------------------------------------------------------------------- * * Function: H5O_condense_header * * Purpose: Attempt to eliminate empty chunks from object header. * * Return: Non-negative on success/Negative on failure * * Programmer: Quincey Koziol * koziol@ncsa.uiuc.edu * Oct 4 2005 * *------------------------------------------------------------------------- */ static herr_t H5O_condense_header(H5F_t *f, H5O_t *oh, hid_t dxpl_id) { hbool_t rescan_header; /* Whether to rescan header */ htri_t result; /* Result from packing/merging/etc */ herr_t ret_value = SUCCEED; /* return value */ FUNC_ENTER_NOAPI_NOINIT(H5O_condense_header) /* check args */ HDassert(oh != NULL); /* Loop until no changed to the object header messages & chunks */ do { /* Reset 'rescan chunks' flag */ rescan_header = FALSE; /* Scan for messages that can be moved earlier in chunks */ result = H5O_move_msgs_forward(oh); if(result < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTPACK, FAIL, "can't move header messages forward") if(result > 0) rescan_header = TRUE; /* Scan for adjacent null messages & merge them */ result = H5O_merge_null(oh); if(result < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTPACK, FAIL, "can't pack null header messages") if(result > 0) rescan_header = TRUE; /* Scan for empty chunks to remove */ result = H5O_remove_empty_chunks(f, oh, dxpl_id); if(result < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTPACK, FAIL, "can't remove empty chunk") if(result > 0) rescan_header = TRUE; } while(rescan_header); #ifdef H5O_DEBUG H5O_assert(oh); #endif /* H5O_DEBUG */ done: FUNC_LEAVE_NOAPI(ret_value) } /* H5O_condense_header() */ /*------------------------------------------------------------------------- * * Function: H5O_alloc_extend_chunk * * Purpose: Attempt to extend a chunk that is allocated on disk. * * If the extension is successful, and if the last message * of the chunk is the null message, then that message will * be extended with the chunk. Otherwise a new null message * is created. * * f is the file in which the chunk will be written. It is * included to ensure that there is enough space to extend * this chunk. * * Return: TRUE: The chunk has been extended, and *msg_idx * contains the message index for null message * which is large enough to hold size bytes. * * FALSE: The chunk cannot be extended, and *msg_idx * is undefined. * * FAIL: Some internal error has been detected. * * Programmer: John Mainzer -- 8/16/05 * *------------------------------------------------------------------------- */ static htri_t H5O_alloc_extend_chunk(H5F_t *f, H5O_t *oh, unsigned chunkno, size_t size, unsigned * msg_idx) { size_t delta; /* Change in chunk's size */ size_t aligned_size = H5O_ALIGN_OH(oh, size); uint8_t *old_image; /* Old address of chunk's image in memory */ size_t old_size; /* Old size of chunk */ htri_t tri_result; /* Result from checking if chunk can be extended */ int extend_msg = -1;/* Index of null message to extend */ unsigned u; /* Local index variable */ htri_t ret_value = TRUE; /* return value */ FUNC_ENTER_NOAPI_NOINIT(H5O_alloc_extend_chunk) /* check args */ HDassert(f != NULL); HDassert(oh != NULL); HDassert(chunkno < oh->nchunks); HDassert(size > 0); HDassert(msg_idx != NULL); HDassert(H5F_addr_defined(oh->chunk[chunkno].addr)); /* Test to see if the specified chunk ends with a null messages. * If successful, set the index of the the null message in extend_msg. */ for(u = 0; u < oh->nmesgs; u++) { /* Check for null message at end of proper chunk */ /* (account for possible checksum at end of chunk) */ if(oh->mesg[u].chunkno == chunkno && H5O_NULL_ID == oh->mesg[u].type->id && ((oh->mesg[u].raw + oh->mesg[u].raw_size) == ((oh->chunk[chunkno].image + oh->chunk[chunkno].size) - (oh->chunk[chunkno].gap + H5O_SIZEOF_CHKSUM_OH(oh))))) { extend_msg = u; break; } /* end if */ } /* end for */ /* If we can extend an existing null message, adjust the delta appropriately */ if(extend_msg >= 0) { HDassert(oh->chunk[chunkno].gap == 0); delta = aligned_size - oh->mesg[extend_msg].raw_size; } /* end if */ else delta = (aligned_size + H5O_SIZEOF_MSGHDR_OH(oh)) - oh->chunk[chunkno].gap; delta = H5O_ALIGN_OH(oh, delta); /* Determine whether the chunk can be extended */ tri_result = H5MF_can_extend(f, H5FD_MEM_OHDR, oh->chunk[chunkno].addr, (hsize_t)(oh->chunk[chunkno].size), (hsize_t)delta); if(tri_result == FALSE) /* can't extend -- we are done */ HGOTO_DONE(FALSE) else if(tri_result < 0) /* error */ HGOTO_ERROR(H5E_RESOURCE, H5E_SYSTEM, FAIL, "can't tell if we can extend chunk") /* If we get this far, we should be able to extend the chunk */ if(H5MF_extend(f, H5FD_MEM_OHDR, oh->chunk[chunkno].addr, (hsize_t)(oh->chunk[chunkno].size), (hsize_t)delta) < 0 ) HGOTO_ERROR(H5E_RESOURCE, H5E_SYSTEM, FAIL, "can't extend chunk") /* If we can extend an existing null message, take care of that */ if(extend_msg >= 0) { /* Adjust message size of existing null message */ oh->mesg[extend_msg].dirty = TRUE; oh->mesg[extend_msg].raw_size += delta; } /* end if */ /* Create new null message for end of chunk */ else { /* Create a new null message */ if(oh->nmesgs >= oh->alloc_nmesgs) if(H5O_alloc_msgs(oh, (size_t)1) < 0) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate more space for messages") /* Set extension message */ extend_msg = oh->nmesgs++; /* Initialize new null message */ oh->mesg[extend_msg].type = H5O_MSG_NULL; oh->mesg[extend_msg].dirty = TRUE; oh->mesg[extend_msg].native = NULL; oh->mesg[extend_msg].raw = ((oh->chunk[chunkno].image + oh->chunk[chunkno].size) - (H5O_SIZEOF_CHKSUM_OH(oh) + oh->chunk[chunkno].gap)) + H5O_SIZEOF_MSGHDR_OH(oh); oh->mesg[extend_msg].raw_size = (delta + oh->chunk[chunkno].gap) - H5O_SIZEOF_MSGHDR_OH(oh); oh->mesg[extend_msg].chunkno = chunkno; } /* end else */ /* Allocate more memory space for chunk's image */ old_image = oh->chunk[chunkno].image; old_size = oh->chunk[chunkno].size; oh->chunk[chunkno].size += delta; oh->chunk[chunkno].image = H5FL_BLK_REALLOC(chunk_image, old_image, oh->chunk[chunkno].size); oh->chunk[chunkno].gap = 0; oh->chunk[chunkno].dirty = TRUE; if(NULL == oh->chunk[chunkno].image) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") /* Wipe new space for chunk */ HDmemset(oh->chunk[chunkno].image + old_size, 0, oh->chunk[chunkno].size - old_size); /* Spin through existing messages, adjusting them */ for(u = 0; u < oh->nmesgs; u++) { /* Adjust raw addresses for messages in this chunk to reflect new 'image' address */ if(oh->mesg[u].chunkno == chunkno) oh->mesg[u].raw = oh->chunk[chunkno].image + (oh->mesg[u].raw - old_image); /* Find continuation message which points to this chunk and adjust chunk's size */ /* (Chunk 0 doesn't have a continuation message that points to it and * it's size is directly encoded in the object header) */ if(chunkno > 0 && (H5O_CONT_ID == oh->mesg[u].type->id) && (((H5O_cont_t *)(oh->mesg[u].native))->chunkno == chunkno)) { /* Adjust size of continuation message */ HDassert(((H5O_cont_t *)(oh->mesg[u].native))->size == old_size); ((H5O_cont_t *)(oh->mesg[u].native))->size = oh->chunk[chunkno].size; /* Flag continuation message as dirty */ oh->mesg[u].dirty = TRUE; } /* end if */ } /* end for */ /* Set return value */ *msg_idx = extend_msg; done: FUNC_LEAVE_NOAPI(ret_value) } /* H5O_alloc_extend_chunk() */ /*------------------------------------------------------------------------- * Function: H5O_alloc_new_chunk * * Purpose: Allocates a new chunk for the object header, including * file space. * * One of the other chunks will get an object continuation * message. If there isn't room in any other chunk for the * object continuation message, then some message from * another chunk is moved into this chunk to make room. * * SIZE need not be aligned. * * Return: Success: Index number of the null message for the * new chunk. The null message will be at * least SIZE bytes not counting the message * ID or size fields. * * Failure: Negative * * Programmer: Robb Matzke * matzke@llnl.gov * Aug 7 1997 * *------------------------------------------------------------------------- */ static unsigned H5O_alloc_new_chunk(H5F_t *f, hid_t dxpl_id, H5O_t *oh, size_t size) { size_t cont_size; /*continuation message size */ int found_null = (-1); /*best fit null message */ int found_attr = (-1); /*best fit attribute message */ int found_link = (-1); /*best fit link message */ int found_other = (-1); /*best fit other message */ unsigned idx; /*message number */ uint8_t *p = NULL; /*ptr into new chunk */ H5O_cont_t *cont = NULL; /*native continuation message */ unsigned chunkno; /* Chunk allocated */ haddr_t new_chunk_addr; unsigned u; /* Local index variable */ unsigned ret_value; /* Return value */ FUNC_ENTER_NOAPI_NOINIT(H5O_alloc_new_chunk) /* check args */ HDassert(oh); HDassert(size > 0); size = H5O_ALIGN_OH(oh, size); /* * Find the smallest null message that will hold an object * continuation message. Failing that, find the smallest message * that could be moved to make room for the continuation message. * * Don't ever move continuation message from one chunk to another. * Prioritize link messages moving to later chunks, instead of * more "important" messages. * Avoid moving attributes when possible to preserve their * ordering (although ordering is *not* guaranteed!). * */ cont_size = H5O_ALIGN_OH(oh, H5F_SIZEOF_ADDR(f) + H5F_SIZEOF_SIZE(f)); for(u = 0; u < oh->nmesgs; u++) { int msg_id = oh->mesg[u].type->id; /* Temp. copy of message type ID */ if(H5O_NULL_ID == msg_id) { if(cont_size == oh->mesg[u].raw_size) { found_null = u; break; } else if(oh->mesg[u].raw_size >= cont_size && (found_null < 0 || oh->mesg[u].raw_size < oh->mesg[found_null].raw_size)) { found_null = u; } } else if(H5O_CONT_ID == msg_id) { /*don't consider continuation messages */ } else if(H5O_ATTR_ID == msg_id) { if(oh->mesg[u].raw_size >= cont_size && (found_attr < 0 || oh->mesg[u].raw_size < oh->mesg[found_attr].raw_size)) found_attr = u; } else if(H5O_LINK_ID == msg_id) { if(oh->mesg[u].raw_size >= cont_size && (found_link < 0 || oh->mesg[u].raw_size < oh->mesg[found_link].raw_size)) found_link = u; } else { if(oh->mesg[u].raw_size >= cont_size && (found_other < 0 || oh->mesg[u].raw_size < oh->mesg[found_other].raw_size)) found_other = u; } /* end else */ } /* end for */ HDassert(found_null >= 0 || found_attr >= 0 || found_link >= 0 || found_other >= 0); /* * If we must move some other message to make room for the null * message, then make sure the new chunk has enough room for that * other message. * * Move link messages first, then other messages, and attributes * only as a last resort. * */ if(found_null < 0) { if(found_link >= 0) found_other = found_link; if(found_other < 0) found_other = found_attr; HDassert(found_other >= 0); size += H5O_SIZEOF_MSGHDR_OH(oh) + oh->mesg[found_other].raw_size; } /* end if */ /* * The total chunk size must include enough space for the checksum * on the chunk and the continuation chunk magic #. (which are only present * in later versions of the object header) */ size += H5O_SIZEOF_CHKHDR_OH(oh); /* * The total chunk size must include the requested space plus enough * for the message header. This must be at least some minimum and a * multiple of the alignment size. */ size = MAX(H5O_MIN_SIZE, size + H5O_SIZEOF_MSGHDR_OH(oh)); HDassert(size == H5O_ALIGN_OH(oh, size)); /* allocate space in file to hold the new chunk */ new_chunk_addr = H5MF_alloc(f, H5FD_MEM_OHDR, dxpl_id, (hsize_t)size); if(HADDR_UNDEF == new_chunk_addr) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, UFAIL, "unable to allocate space for new chunk") /* * Create the new chunk giving it a file address. */ if(oh->nchunks >= oh->alloc_nchunks) { unsigned na = MAX(H5O_NCHUNKS, oh->alloc_nchunks * 2); /* Double # of chunks allocated */ H5O_chunk_t *x = H5FL_SEQ_REALLOC(H5O_chunk_t, oh->chunk, (size_t)na); if(!x) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, UFAIL, "memory allocation failed") oh->alloc_nchunks = na; oh->chunk = x; } /* end if */ chunkno = oh->nchunks++; oh->chunk[chunkno].dirty = TRUE; oh->chunk[chunkno].addr = new_chunk_addr; oh->chunk[chunkno].size = size; oh->chunk[chunkno].gap = 0; if(NULL == (oh->chunk[chunkno].image = p = H5FL_BLK_CALLOC(chunk_image, size))) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, UFAIL, "memory allocation failed") /* If this is a later version of the object header format, put the magic * # at the beginning of the chunk image. */ if(oh->version > H5O_VERSION_1) { HDmemcpy(p, H5O_CHK_MAGIC, (size_t)H5O_SIZEOF_MAGIC); p += H5O_SIZEOF_MAGIC; } /* end if */ /* * Make sure we have enough space for all possible new messages * that could be generated below. */ if(oh->nmesgs + 3 > oh->alloc_nmesgs) if(H5O_alloc_msgs(oh, (size_t)3) < 0) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, UFAIL, "can't allocate more space for messages") /* Move message (that will be replaced with continuation message) * to new chunk, if necessary. */ if(found_null < 0) { H5O_mesg_t *null_msg; /* Pointer to new null message */ /* Create null message for space that message to copy currently occupies */ found_null = oh->nmesgs++; null_msg = &(oh->mesg[found_null]); null_msg->type = H5O_MSG_NULL; null_msg->dirty = TRUE; null_msg->native = NULL; null_msg->raw = oh->mesg[found_other].raw; null_msg->raw_size = oh->mesg[found_other].raw_size; null_msg->chunkno = oh->mesg[found_other].chunkno; /* Copy the message to move to its new location */ /* (Chunk is already dirty, no need to mark it) */ HDmemcpy(p, oh->mesg[found_other].raw - H5O_SIZEOF_MSGHDR_OH(oh), oh->mesg[found_other].raw_size + H5O_SIZEOF_MSGHDR_OH(oh)); /* Switch message to point to new location */ oh->mesg[found_other].raw = p + H5O_SIZEOF_MSGHDR_OH(oh); oh->mesg[found_other].chunkno = chunkno; /* Account for copied message in new chunk */ p += H5O_SIZEOF_MSGHDR_OH(oh) + oh->mesg[found_other].raw_size; size -= H5O_SIZEOF_MSGHDR_OH(oh) + oh->mesg[found_other].raw_size; } /* end if */ HDassert(found_null >= 0); /* Create null message for [rest of] space in new chunk */ /* (account for chunk's magic # & checksum) */ idx = oh->nmesgs++; oh->mesg[idx].type = H5O_MSG_NULL; oh->mesg[idx].dirty = TRUE; oh->mesg[idx].native = NULL; oh->mesg[idx].raw = p + H5O_SIZEOF_MSGHDR_OH(oh); oh->mesg[idx].raw_size = size - (H5O_SIZEOF_CHKHDR_OH(oh) + H5O_SIZEOF_MSGHDR_OH(oh)); oh->mesg[idx].chunkno = chunkno; /* Initialize the continuation information */ if(NULL == (cont = H5FL_MALLOC(H5O_cont_t))) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, UFAIL, "memory allocation failed") cont->addr = oh->chunk[chunkno].addr; cont->size = oh->chunk[chunkno].size; cont->chunkno = chunkno; /* Split the null message and point at continuation message */ if(H5O_alloc_null(oh, (unsigned)found_null, H5O_MSG_CONT, cont, cont_size) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, UFAIL, "can't split null message") /* Set return value */ ret_value = idx; done: FUNC_LEAVE_NOAPI(ret_value) } /* H5O_alloc_new_chunk() */ /*------------------------------------------------------------------------- * Function: H5O_eliminate_gap * * Purpose: Eliminate a gap in a chunk with a null message * * Return: Non-negative on success/Negative on failure * * Programmer: Quincey Koziol * koziol@hdfgroup.org * Oct 17 2006 * *------------------------------------------------------------------------- */ static herr_t H5O_eliminate_gap(H5O_t *oh, H5O_mesg_t *mesg, uint8_t *gap_loc, size_t gap_size) { uint8_t *move_start, *move_end; /* Pointers to area of messages to move */ hbool_t null_before_gap; /* Flag whether the null message is before the gap or not */ FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5O_eliminate_gap) /* check args */ HDassert(oh); HDassert(oh->version > H5O_VERSION_1); HDassert(mesg); HDassert(gap_loc); HDassert(gap_size); /* Check if the null message is before or after the gap produced */ null_before_gap = (hbool_t)(mesg->raw < gap_loc); /* Set up information about region of messages to move */ if(null_before_gap) { move_start = mesg->raw + mesg->raw_size; move_end = gap_loc; } /* end if */ else { move_start = gap_loc + gap_size; move_end = mesg->raw - H5O_SIZEOF_MSGHDR_OH(oh); } /* end else */ /* Check for messages between null message and gap */ if(move_end > move_start) { unsigned u; /* Local index variable */ /* Look for messages that need to move, to adjust raw pointers in chunk */ for(u = 0; u < oh->nmesgs; u++) { uint8_t *msg_start; /* Start of encoded message in chunk */ msg_start = oh->mesg[u].raw - H5O_SIZEOF_MSGHDR_OH(oh); if(oh->mesg[u].chunkno == mesg->chunkno && (msg_start >= move_start && msg_start < move_end)) { /* Move message's raw pointer in appropriate direction */ if(null_before_gap) oh->mesg[u].raw += gap_size; else oh->mesg[u].raw -= gap_size; } /* end if */ } /* end for */ /* Slide raw message info in chunk image */ if(null_before_gap) /* Slide messages down */ HDmemmove(move_start + gap_size, move_start, (size_t)(move_end - move_start)); else { /* Slide messages up */ HDmemmove(move_start - gap_size, move_start, (size_t)(move_end - move_start)); /* Adjust start of null message */ mesg->raw -= gap_size; } /* end else */ } /* end if */ /* Zero out addition to null message */ HDmemset(mesg->raw + mesg->raw_size, 0, gap_size); /* Adjust size of null message */ mesg->raw_size += gap_size; /* Mark null message as dirty */ mesg->dirty = TRUE; FUNC_LEAVE_NOAPI(SUCCEED) } /* H5O_eliminate_gap() */ /*------------------------------------------------------------------------- * Function: H5O_add_gap * * Purpose: Add a gap to a chunk * * Return: Non-negative on success/Negative on failure * * Programmer: Quincey Koziol * koziol@hdfgroup.org * Oct 17 2006 * *------------------------------------------------------------------------- */ static herr_t H5O_add_gap(H5O_t *oh, unsigned chunkno, unsigned idx, uint8_t *new_gap_loc, size_t new_gap_size) { hbool_t merged_with_null; /* Whether the gap was merged with a null message */ unsigned u; /* Local index variable */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI_NOINIT(H5O_add_gap) /* check args */ HDassert(oh); HDassert(oh->version > H5O_VERSION_1); HDassert(new_gap_loc); HDassert(new_gap_size); /* Check for existing null message in chunk */ merged_with_null = FALSE; for(u = 0; u < oh->nmesgs && !merged_with_null; u++) { /* Find a null message in the chunk with the new gap */ /* (a null message that's not the one we are eliminating) */ if(H5O_NULL_ID == oh->mesg[u].type->id && oh->mesg[u].chunkno == chunkno && u != idx) { /* Sanity check - chunks with null messages shouldn't have a gap */ HDassert(oh->chunk[chunkno].gap == 0); /* Eliminate the gap in the chunk */ if(H5O_eliminate_gap(oh, &oh->mesg[u], new_gap_loc, new_gap_size) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, FAIL, "can't eliminate gap in chunk") /* Set flag to indicate that the gap was handled */ merged_with_null = TRUE; } /* end if */ } /* end for */ /* If we couldn't find a null message in the chunk, move the gap to the end */ if(!merged_with_null) { /* Adjust message offsets after new gap forward in chunk */ for(u = 0; u < oh->nmesgs; u++) if(oh->mesg[u].chunkno == chunkno && oh->mesg[u].raw > new_gap_loc) oh->mesg[u].raw -= new_gap_size; /* Slide raw message info forward in chunk image */ HDmemmove(new_gap_loc, new_gap_loc + new_gap_size, (size_t)((oh->chunk[chunkno].image + (oh->chunk[chunkno].size - H5O_SIZEOF_CHKSUM_OH(oh))) - (new_gap_loc + new_gap_size))); /* Add existing gap size to new gap size */ new_gap_size += oh->chunk[chunkno].gap; /* Merging with existing gap will allow for a new null message */ if(new_gap_size >= (size_t)H5O_SIZEOF_MSGHDR_OH(oh)) { H5O_mesg_t *null_msg; /* Pointer to new null message */ /* Check if we need to extend message table to hold the new null message */ if(oh->nmesgs >= oh->alloc_nmesgs) if(H5O_alloc_msgs(oh, (size_t)1) < 0) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, UFAIL, "can't allocate more space for messages") /* Increment new gap size */ oh->chunk[chunkno].gap += new_gap_size; /* Create new null message, with the tail of the previous null message */ null_msg = &(oh->mesg[oh->nmesgs++]); null_msg->type = H5O_MSG_NULL; null_msg->dirty = TRUE; null_msg->native = NULL; null_msg->raw_size = new_gap_size - H5O_SIZEOF_MSGHDR_OH(oh); null_msg->raw = (oh->chunk[chunkno].image + oh->chunk[chunkno].size) - (H5O_SIZEOF_CHKSUM_OH(oh) + null_msg->raw_size); null_msg->chunkno = chunkno; /* Zero out new null message's raw data */ if(null_msg->raw_size) HDmemset(null_msg->raw, 0, null_msg->raw_size); /* Reset size of gap in chunk */ oh->chunk[chunkno].gap = 0; } /* end if */ else oh->chunk[chunkno].gap = new_gap_size; } /* end if */ done: FUNC_LEAVE_NOAPI(ret_value) } /* H5O_add_gap() */ /*------------------------------------------------------------------------- * Function: H5O_alloc * * Purpose: Allocate enough space in the object header for this message. * * Return: Success: Index of message * * Failure: Negative * * Programmer: Robb Matzke * matzke@llnl.gov * Aug 6 1997 * *------------------------------------------------------------------------- */ static unsigned H5O_alloc(H5F_t *f, hid_t dxpl_id, H5O_t *oh, const H5O_msg_class_t *type, size_t size, unsigned * oh_flags_ptr) { size_t aligned_size = H5O_ALIGN_OH(oh, size); unsigned idx; /* Index of message which fits allocation */ unsigned ret_value; /* Return value */ FUNC_ENTER_NOAPI_NOINIT(H5O_alloc) /* check args */ HDassert(oh); HDassert(type); HDassert(oh_flags_ptr); /* look for a null message which is large enough */ for(idx = 0; idx < oh->nmesgs; idx++) if(H5O_NULL_ID == oh->mesg[idx].type->id && oh->mesg[idx].raw_size >= aligned_size) break; /* if we didn't find one, then allocate more header space */ if(idx >= oh->nmesgs) { unsigned chunkno; /* check to see if we can extend one of the chunks. If we can, * do so. Otherwise, we will have to allocate a new chunk. * * Note that in this new version of this function, all chunks * must have file space allocated to them. */ for(chunkno = 0; chunkno < oh->nchunks; chunkno++) { htri_t tri_result; HDassert(H5F_addr_defined(oh->chunk[chunkno].addr)); tri_result = H5O_alloc_extend_chunk(f, oh, chunkno, size, &idx); if(tri_result == TRUE) break; else if(tri_result == FALSE) idx = UFAIL; else HGOTO_ERROR(H5E_OHDR, H5E_SYSTEM, UFAIL, "H5O_alloc_extend_chunk failed unexpectedly") } /* end for */ /* If idx is still UFAIL, we were not able to extend a chunk, * create a new one. */ if(idx == UFAIL) if((idx = H5O_alloc_new_chunk(f, dxpl_id, oh, size)) == UFAIL) HGOTO_ERROR(H5E_OHDR, H5E_NOSPACE, UFAIL, "unable to create a new object header data chunk") } /* end if */ /* Split the null message and point at continuation message */ if(H5O_alloc_null(oh, idx, type, NULL, aligned_size) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, UFAIL, "can't split null message") /* Mark the object header as modified */ *oh_flags_ptr |= H5AC__DIRTIED_FLAG; #ifdef H5O_DEBUG H5O_assert(oh); #endif /* H5O_DEBUG */ /* Set return value */ ret_value = idx; done: FUNC_LEAVE_NOAPI(ret_value) } /* H5O_alloc() */ /*------------------------------------------------------------------------- * Function: H5O_raw_size * * Purpose: Call the 'raw_size' method for a * particular class of object header. * * Return: Size of message on success, 0 on failure * * Programmer: Quincey Koziol * koziol@ncsa.uiuc.edu * Feb 13 2003 * *------------------------------------------------------------------------- */ size_t H5O_raw_size(unsigned type_id, const H5F_t *f, const void *mesg) { const H5O_msg_class_t *type; /* Actual H5O class type for the ID */ size_t ret_value; /* Return value */ FUNC_ENTER_NOAPI(H5O_raw_size, 0) /* Check args */ HDassert(type_id < NELMTS(H5O_msg_class_g)); type = H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */ HDassert(type); HDassert(type->raw_size); HDassert(f); HDassert(mesg); /* Compute the raw data size for the mesg */ if((ret_value = (type->raw_size)(f, mesg)) == 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTCOUNT, 0, "unable to determine size of message") done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_raw_size() */ /*------------------------------------------------------------------------- * Function: H5O_mesg_size * * Purpose: Calculate the final size of an encoded message in an object * header. * * Note: This routine assumes that the message size will be used in the * creation of a new object header. * * Return: Size of message on success, 0 on failure * * Programmer: Quincey Koziol * koziol@ncsa.uiuc.edu * Sep 6 2005 * *------------------------------------------------------------------------- */ size_t H5O_mesg_size(unsigned type_id, const H5F_t *f, const void *mesg, size_t extra_raw) { const H5O_msg_class_t *type; /* Actual H5O class type for the ID */ size_t ret_value; /* Return value */ FUNC_ENTER_NOAPI(H5O_mesg_size, 0) /* Check args */ HDassert(type_id < NELMTS(H5O_msg_class_g)); type = H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */ HDassert(type); HDassert(type->raw_size); HDassert(f); HDassert(mesg); /* Compute the raw data size for the mesg */ if((ret_value = (type->raw_size)(f, mesg)) == 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTCOUNT, 0, "unable to determine size of message") /* Add in "extra" raw space */ ret_value += extra_raw; /* Adjust size for alignment, if necessary */ ret_value = H5O_ALIGN_F(f, ret_value); /* Add space for message header */ ret_value += H5O_SIZEOF_MSGHDR_F(f); done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_mesg_size() */ /*------------------------------------------------------------------------- * Function: H5O_get_share * * Purpose: Call the 'get_share' method for a * particular class of object header. * * Return: Success: Non-negative, and SHARE describes the shared * object. * * Failure: Negative * * Programmer: Quincey Koziol * koziol@ncsa.uiuc.edu * Oct 2 2003 * * Modifications: * *------------------------------------------------------------------------- */ herr_t H5O_get_share(unsigned type_id, H5F_t *f, const void *mesg, H5O_shared_t *share) { const H5O_msg_class_t *type; /* Actual H5O class type for the ID */ herr_t ret_value; /* Return value */ FUNC_ENTER_NOAPI(H5O_get_share,FAIL) /* Check args */ HDassert(type_id < NELMTS(H5O_msg_class_g)); type = H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */ HDassert(type); HDassert(type->get_share); HDassert(f); HDassert(mesg); HDassert(share); /* Get shared data for the mesg */ if((ret_value = (type->get_share)(f, mesg, share)) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "unable to retrieve shared message information") done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_get_share() */ /*------------------------------------------------------------------------- * Function: H5O_is_shared * * Purpose: Call the 'is_shared' method for a * particular class of object header. * * Return: Object is shared: TRUE * Object is not shared: FALSE * * Programmer: James Laird * jlaird@ncsa.uiuc.edu * April 5 2006 * * Modifications: * *------------------------------------------------------------------------- */ htri_t H5O_is_shared(unsigned type_id, const void *mesg) { const H5O_msg_class_t *type; /* Actual H5O class type for the ID */ htri_t ret_value; FUNC_ENTER_NOAPI_NOFUNC(H5O_is_shared) /* Check args */ HDassert(type_id < NELMTS(H5O_msg_class_g)); type = H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */ HDassert(type); HDassert(mesg); HDassert(type_id != H5O_SHARED_ID); /* JAMES: check for this mistake elsewhere, too */ /* If there is no is_shared function, then obviously it's not a shared message! */ if( !(type->is_shared)) ret_value = FALSE; else ret_value = (type->is_shared)(mesg); FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_is_shared() */ /*------------------------------------------------------------------------- * Function: H5O_set_share * * Purpose: Set the shared information for an object header message. * * Return: Success: Non-negative * Failure: Negative * * Programmer: James Laird * jlaird@hdfgroup.org * November 1 2006 * * Modifications: * *------------------------------------------------------------------------- */ herr_t H5O_set_share(H5F_t *f, hid_t dxpl_id, H5O_shared_t *share, unsigned type_id, void *mesg) { const H5O_msg_class_t *type; /* Actual H5O class type for the ID */ herr_t ret_value; /* Return value */ FUNC_ENTER_NOAPI(H5O_set_share,FAIL) /* Check args */ HDassert(f); HDassert(share); HDassert(type_id < NELMTS(H5O_msg_class_g)); type = H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */ HDassert(type); HDassert(type->set_share); HDassert(mesg); HDassert(share->flags != H5O_NOT_SHARED); /* Set this message as the shared message for the message, wiping out * any information that was there before */ if((ret_value = (type->set_share)(f, mesg, share)) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTSET, FAIL, "unable to set shared message information") done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_set_share() */ /*------------------------------------------------------------------------- * Function: H5O_reset_share * * Purpose: Reset the shared information for an object header message. * * Return: Success: Non-negative * Failure: Negative * * Programmer: James Laird * jlaird@hdfgroup.org * Oct 17 2006 * * Modifications: * *------------------------------------------------------------------------- */ herr_t H5O_reset_share(H5F_t *f, unsigned type_id, void *mesg) { const H5O_msg_class_t *type; /* Actual H5O class type for the ID */ H5O_shared_t sh_mesg; /* Shared message */ herr_t ret_value; /* Return value */ FUNC_ENTER_NOAPI(H5O_reset_share,FAIL) /* Check args */ HDassert(type_id < NELMTS(H5O_msg_class_g)); type = H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */ HDassert(type); HDassert(type->set_share); HDassert(mesg); /* Initialize the shared message to zero. */ HDmemset(&sh_mesg, 0, sizeof(H5O_shared_t)); /* Set this message as the shared message for the message, wiping out * any information that was there before */ if((ret_value = (type->set_share)(f, mesg, &sh_mesg)) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTSET, FAIL, "unable to reset shared message information") done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_reset_share() */ /*------------------------------------------------------------------------- * Function: H5O_delete * * Purpose: Delete an object header from a file. This frees the file * space used for the object header (and it's continuation blocks) * and also walks through each header message and asks it to * remove all the pieces of the file referenced by the header. * * Return: Non-negative on success/Negative on failure * * Programmer: Quincey Koziol * koziol@ncsa.uiuc.edu * Mar 19 2003 * *------------------------------------------------------------------------- */ herr_t H5O_delete(H5F_t *f, hid_t dxpl_id, haddr_t addr) { H5O_t *oh = NULL; /* Object header information */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(H5O_delete,FAIL) /* Check args */ HDassert(f); HDassert(H5F_addr_defined(addr)); /* Get the object header information */ if(NULL == (oh = H5AC_protect(f, dxpl_id, H5AC_OHDR, addr, NULL, NULL, H5AC_WRITE))) HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "unable to load object header") /* Delete object */ if(H5O_delete_oh(f, dxpl_id, oh) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, FAIL, "can't delete object from file") done: if(oh && H5AC_unprotect(f, dxpl_id, H5AC_OHDR, addr, oh, H5AC__DIRTIED_FLAG | H5C__DELETED_FLAG) < 0) HDONE_ERROR(H5E_OHDR, H5E_PROTECT, FAIL, "unable to release object header") FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_delete() */ /*------------------------------------------------------------------------- * Function: H5O_delete_oh * * Purpose: Internal function to: * Delete an object header from a file. This frees the file * space used for the object header (and it's continuation blocks) * and also walks through each header message and asks it to * remove all the pieces of the file referenced by the header. * * Return: Non-negative on success/Negative on failure * * Programmer: Quincey Koziol * koziol@ncsa.uiuc.edu * Mar 19 2003 * *------------------------------------------------------------------------- */ static herr_t H5O_delete_oh(H5F_t *f, hid_t dxpl_id, H5O_t *oh) { H5O_mesg_t *curr_msg; /* Pointer to current message being operated on */ unsigned u; herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI_NOINIT(H5O_delete_oh) /* Check args */ HDassert(f); HDassert(oh); /* Walk through the list of object header messages, asking each one to * delete any file space used */ for(u = 0, curr_msg = &oh->mesg[0]; u < oh->nmesgs; u++, curr_msg++) { /* Free any space referred to in the file from this message */ if(H5O_delete_mesg(f, dxpl_id, curr_msg, TRUE) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, FAIL, "unable to delete file space for object header message") } /* end for */ /* Free main (first) object header "chunk" */ if(H5MF_xfree(f, H5FD_MEM_OHDR, dxpl_id, oh->chunk[0].addr, (hsize_t)oh->chunk[0].size) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTFREE, FAIL, "unable to free object header") done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_delete_oh() */ /*------------------------------------------------------------------------- * Function: H5O_delete_mesg * * Purpose: Internal function to: * Delete an object header message from a file. This frees the file * space used for anything referred to in the object header message. * * Return: Non-negative on success/Negative on failure * * Programmer: Quincey Koziol * koziol@ncsa.uiuc.edu * September 26 2003 * *------------------------------------------------------------------------- */ static herr_t H5O_delete_mesg(H5F_t *f, hid_t dxpl_id, H5O_mesg_t *mesg, hbool_t adj_link) { const H5O_msg_class_t *type; /* Type of object to free */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI_NOINIT(H5O_delete_mesg) /* Check args */ HDassert(f); HDassert(mesg); /* Get the message to free's type */ if(mesg->flags & H5O_FLAG_SHARED) { type = H5O_MSG_SHARED; } else type = mesg->type; /* Check if there is a file space deletion callback for this type of message */ if(type->del) { /* Decode the message if necessary. */ if(NULL == mesg->native) { HDassert(type->decode); if(NULL == (mesg->native = (type->decode)(f, dxpl_id, mesg->raw))) HGOTO_ERROR(H5E_OHDR, H5E_CANTDECODE, FAIL, "unable to decode message") } /* end if */ /* Check if this message needs to be removed from the SOHM table */ /* JAMES: there should be a callback, maybe in H5O_shared_delete, to fiddle w/ the ref. count. * We shouldn't need to do a search in the SOHM table on delete. */ if(type == H5O_MSG_SHARED) { /* JAMES ugly! And not quite correct. */ void * mesg_orig; if(NULL == (mesg_orig = H5O_shared_read(f, dxpl_id, mesg->native, mesg->type, NULL))) HGOTO_ERROR (H5E_OHDR, H5E_BADMESG, FAIL, "unable to read shared message") if(H5SM_try_delete(f, dxpl_id, mesg->type->id, mesg->native) < 0) HGOTO_ERROR (H5E_OHDR, H5E_CANTFREE, FAIL, "unable to delete message from SOHM table") H5O_free(mesg->type->id, mesg_orig); } if((type->del)(f, dxpl_id, mesg->native, adj_link) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, FAIL, "unable to delete file space for object header message") } /* end if */ done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_delete_msg() */ /*------------------------------------------------------------------------- * Function: H5O_get_info * * Purpose: Retrieve information about an object header * * Return: Non-negative on success/Negative on failure * * Programmer: Quincey Koziol * koziol@ncsa.uiuc.edu * Oct 7 2003 * *------------------------------------------------------------------------- */ herr_t H5O_get_info(H5O_loc_t *loc, H5O_stat_t *ostat, hid_t dxpl_id) { H5O_t *oh = NULL; /* Object header information */ H5O_mesg_t *curr_msg; /* Pointer to current message being operated on */ hsize_t total_size; /* Total amount of space used in file */ hsize_t free_space; /* Free space in object header */ unsigned u; /* Local index variable */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(H5O_get_info, FAIL) /* Check args */ HDassert(loc); HDassert(ostat); /* Get the object header information */ if(NULL == (oh = H5AC_protect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, NULL, NULL, H5AC_READ))) HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "unable to load object header") /* Iterate over all the messages, accumulating the total size & free space */ total_size = H5O_SIZEOF_HDR_OH(oh); free_space = 0; for(u = 0, curr_msg = &oh->mesg[0]; u < oh->nmesgs; u++, curr_msg++) { /* Accumulate the size for this message */ total_size += H5O_SIZEOF_MSGHDR_OH(oh) + curr_msg->raw_size; /* Check for this message being free space */ if(H5O_NULL_ID == curr_msg->type->id) free_space += H5O_SIZEOF_MSGHDR_OH(oh) + curr_msg->raw_size; } /* end for */ /* Set the information for this object header */ ostat->size = total_size; ostat->free = free_space; ostat->nmesgs = oh->nmesgs; ostat->nchunks = oh->nchunks; done: if(oh && H5AC_unprotect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, oh, H5AC__NO_FLAGS_SET) < 0) HDONE_ERROR(H5E_OHDR, H5E_PROTECT, FAIL, "unable to release object header") FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_get_info() */ /*------------------------------------------------------------------------- * Function: H5O_encode * * Purpose: Encode an object(data type and simple data space only) * description into a buffer. * * Return: Success: Non-negative * * Failure: Negative * * Programmer: Raymond Lu * slu@ncsa.uiuc.edu * July 13, 2004 * *------------------------------------------------------------------------- */ herr_t H5O_encode(H5F_t *f, unsigned char *buf, const void *obj, unsigned type_id) { const H5O_msg_class_t *type; /* Actual H5O class type for the ID */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(H5O_encode,FAIL) /* check args */ HDassert(f); HDassert(type_id < NELMTS(H5O_msg_class_g)); type = H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */ HDassert(type); /* Encode */ if((type->encode)(f, buf, obj) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTENCODE, FAIL, "unable to encode message") done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_encode() */ /*------------------------------------------------------------------------- * Function: H5O_decode * * Purpose: Decode a binary object description and return a new * object handle. * * Note: This routine is not guaranteed to work with all possible * header messages, use with care. * * Return: Success: Pointer to object(data type or space) * * Failure: NULL * * Programmer: Raymond Lu * slu@ncsa.uiuc.edu * July 14, 2004 * *------------------------------------------------------------------------- */ void * H5O_decode(H5F_t *f, hid_t dxpl_id, const unsigned char *buf, unsigned type_id) { const H5O_msg_class_t *type; /* Actual H5O class type for the ID */ void *ret_value; /* Return value */ FUNC_ENTER_NOAPI(H5O_decode, NULL) /* check args */ HDassert(f); HDassert(type_id < NELMTS(H5O_msg_class_g)); type = H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */ HDassert(type); /* decode */ if((ret_value = (type->decode)(f, dxpl_id, buf)) == NULL) HGOTO_ERROR(H5E_OHDR, H5E_CANTDECODE, NULL, "unable to decode message") done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_decode() */ /*------------------------------------------------------------------------- * Function: H5O_iterate * * Purpose: Iterate through object headers of a certain type. * * Return: Returns a negative value if something is wrong, the return * value of the last operator if it was non-zero, or zero if all * object headers were processed. * * Programmer: Quincey Koziol * koziol@ncsa.uiuc.edu * Nov 19 2004 * * Description: * This function interates over the object headers of an object * specified with 'ent' of type 'type_id'. For each object header of the * object, the 'op_data' and some additional information (specified below) are * passed to the 'op' function. * The operation receives a pointer to the object header message for the * object being iterated over ('mesg'), and the pointer to the operator data * passed in to H5O_iterate ('op_data'). The return values from an operator * are: * A. Zero causes the iterator to continue, returning zero when all * object headers of that type have been processed. * B. Positive causes the iterator to immediately return that positive * value, indicating short-circuit success. * C. Negative causes the iterator to immediately return that value, * indicating failure. * *------------------------------------------------------------------------- */ herr_t H5O_iterate(const H5O_loc_t *loc, unsigned type_id, H5O_operator_t app_op, void *op_data, hid_t dxpl_id) { const H5O_msg_class_t *type; /* Actual H5O class type for the ID */ H5O_mesg_operator_t op; /* Wrapper for operator */ herr_t ret_value; /* Return value */ FUNC_ENTER_NOAPI(H5O_iterate, FAIL) /* check args */ HDassert(loc); HDassert(loc->file); HDassert(H5F_addr_defined(loc->addr)); HDassert(type_id < NELMTS(H5O_msg_class_g)); type = H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */ HDassert(type); /* Call the "real" iterate routine */ op.app_op = app_op; if((ret_value = H5O_iterate_real(loc, type, H5AC_READ, FALSE, op, op_data, dxpl_id)) < 0) HGOTO_ERROR(H5E_OHDR, H5E_BADITER, FAIL, "unable to iterate over object header messages") done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_iterate() */ /*------------------------------------------------------------------------- * Function: H5O_iterate_real * * Purpose: Iterate through object headers of a certain type. * * Return: Returns a negative value if something is wrong, the return * value of the last operator if it was non-zero, or zero if all * object headers were processed. * * Programmer: Quincey Koziol * koziol@ncsa.uiuc.edu * Sep 6 2005 * * Description: * This function interates over the object headers of an object * specified with 'ent' of type 'type_id'. For each object header of the * object, the 'op_data' and some additional information (specified below) are * passed to the 'op' function. * The operation receives a pointer to the object header message for the * object being iterated over ('mesg'), and the pointer to the operator data * passed in to H5O_iterate ('op_data'). The return values from an operator * are: * A. Zero causes the iterator to continue, returning zero when all * object headers of that type have been processed. * B. Positive causes the iterator to immediately return that positive * value, indicating short-circuit success. * C. Negative causes the iterator to immediately return that value, * indicating failure. * * Modifications: * *------------------------------------------------------------------------- */ static herr_t H5O_iterate_real(const H5O_loc_t *loc, const H5O_msg_class_t *type, H5AC_protect_t prot, hbool_t internal, H5O_mesg_operator_t op, void *op_data, hid_t dxpl_id) { H5O_t *oh = NULL; /* Pointer to actual object header */ unsigned oh_flags = H5AC__NO_FLAGS_SET; /* Start iteration with no flags set on object header */ unsigned idx; /* Absolute index of current message in all messages */ unsigned sequence; /* Relative index of current message for messages of type */ H5O_mesg_t *idx_msg; /* Pointer to current message */ herr_t ret_value = H5O_ITER_CONT; /* Return value */ FUNC_ENTER_NOAPI_NOINIT(H5O_iterate_real) /* check args */ HDassert(loc); HDassert(loc->file); HDassert(H5F_addr_defined(loc->addr)); HDassert(type); HDassert(op.app_op); /* Protect the object header to iterate over */ if (NULL == (oh = H5AC_protect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, NULL, NULL, prot))) HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "unable to load object header") /* Iterate over messages */ for(sequence = 0, idx = 0, idx_msg = &oh->mesg[0]; idx < oh->nmesgs && !ret_value; idx++, idx_msg++) { if(type->id == idx_msg->type->id) { void * unshared_mesg; /* JAMES */ /* * Decode the message if necessary. If the message is shared then decode * a shared message, ignoring the message type. */ LOAD_NATIVE(loc->file, dxpl_id, idx_msg, FAIL) /* JAMES: test */ if(idx_msg->flags & H5O_FLAG_SHARED) { if(NULL == (unshared_mesg = H5O_shared_read(loc->file, dxpl_id, idx_msg->native, idx_msg->type, NULL))) HGOTO_ERROR(H5E_OHDR, H5E_BADMESG, FAIL, "unable to read shared message"); } else unshared_mesg = idx_msg->native; /* Check for making an "internal" (i.e. within the H5O package) callback */ if(internal) { /* Call the "internal" iterator callback */ if((ret_value = (op.lib_op)(oh, idx_msg, sequence, &oh_flags, op_data)) != 0) break; } /* end if */ else { /* Call the iterator callback */ /* JAMES if((ret_value = (op.app_op)(idx_msg->native, sequence, op_data)) != 0) break; */ if((ret_value = (op.app_op)(unshared_mesg, sequence, op_data)) != 0) break; } /* end else */ /* JAMES again */ if(idx_msg->flags & H5O_FLAG_SHARED) { H5O_free_real(idx_msg->type, unshared_mesg); } /* Check for error from iterator */ if(ret_value < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "iterator function failed") /* Increment sequence value for message type */ sequence++; } /* end if */ } /* end for */ done: if(oh) { /* Check if object header was modified */ if(oh_flags & H5AC__DIRTIED_FLAG) { /* Shouldn't be able to modify object header if we don't have write access */ HDassert(prot == H5AC_WRITE); /* Try to condense object header info */ /* (Since this routine is invoked when a message is removed from * an object header, the header will be condensed after each * message removal) */ if(H5O_condense_header(loc->file, oh, dxpl_id) < 0) HDONE_ERROR(H5E_OHDR, H5E_CANTPACK, FAIL, "can't pack object header") H5O_touch_oh(loc->file, dxpl_id, oh, FALSE, &oh_flags); } /* end if */ if(H5AC_unprotect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, oh, oh_flags) < 0) HDONE_ERROR(H5E_OHDR, H5E_PROTECT, FAIL, "unable to release object header") } /* end if */ FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_iterate_real() */ /*------------------------------------------------------------------------- * Function: H5O_obj_type * * Purpose: Returns the type of object pointed to by `loc'. * * Return: Success: An object type defined in H5Gpublic.h * Failure: H5G_UNKNOWN * * Programmer: Robb Matzke * Wednesday, November 4, 1998 * *------------------------------------------------------------------------- */ H5G_obj_t H5O_obj_type(H5O_loc_t *loc, hid_t dxpl_id) { H5O_t *oh = NULL; /* Object header for location */ H5G_obj_t ret_value; /* Return value */ FUNC_ENTER_NOAPI(H5O_obj_type, H5G_UNKNOWN) /* Load the object header */ if(NULL == (oh = H5AC_protect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, NULL, NULL, H5AC_READ))) HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, H5G_UNKNOWN, "unable to load object header") /* Test whether entry qualifies as a particular type of object */ if((ret_value = H5O_obj_type_real(oh)) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, H5G_UNKNOWN, "unable to determine object type") done: if(oh && H5AC_unprotect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, oh, H5AC__NO_FLAGS_SET) != SUCCEED) HDONE_ERROR(H5E_OHDR, H5E_PROTECT, H5G_UNKNOWN, "unable to release object header") FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_obj_type() */ /*------------------------------------------------------------------------- * Function: H5O_obj_type_real * * Purpose: Returns the type of object pointed to by `oh'. * * Return: Success: An object type defined in H5Gpublic.h * Failure: H5G_UNKNOWN * * Programmer: Quincey Koziol * Monday, November 21, 2005 * *------------------------------------------------------------------------- */ static H5G_obj_t H5O_obj_type_real(H5O_t *oh) { const H5O_obj_class_t *obj_class; /* Class of object for header */ H5G_obj_t ret_value; /* Return value */ FUNC_ENTER_NOAPI_NOINIT(H5O_obj_type_real) /* Sanity check */ HDassert(oh); /* Look up class for object header */ if(NULL == (obj_class = H5O_obj_class_real(oh))) HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, H5G_UNKNOWN, "unable to determine object type") /* Set return value */ ret_value = obj_class->type; done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_obj_type_real() */ /*------------------------------------------------------------------------- * Function: H5O_obj_class * * Purpose: Returns the class of object pointed to by `loc'. * * Return: Success: An object class * Failure: NULL * * Programmer: Quincey Koziol * Monday, November 6, 2006 * *------------------------------------------------------------------------- */ static const H5O_obj_class_t * H5O_obj_class(H5O_loc_t *loc, hid_t dxpl_id) { H5O_t *oh = NULL; /* Object header for location */ const H5O_obj_class_t *ret_value; /* Return value */ FUNC_ENTER_NOAPI_NOINIT(H5O_obj_class) /* Load the object header */ if(NULL == (oh = H5AC_protect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, NULL, NULL, H5AC_READ))) HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "unable to load object header") /* Test whether entry qualifies as a particular type of object */ if(NULL == (ret_value = H5O_obj_class_real(oh))) HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, NULL, "unable to determine object type") done: if(oh && H5AC_unprotect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, oh, H5AC__NO_FLAGS_SET) != SUCCEED) HDONE_ERROR(H5E_OHDR, H5E_PROTECT, NULL, "unable to release object header") FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_obj_class() */ /*------------------------------------------------------------------------- * Function: H5O_obj_class_real * * Purpose: Returns the class of object pointed to by `oh'. * * Return: Success: An object class * Failure: NULL * * Programmer: Quincey Koziol * Monday, November 21, 2005 * *------------------------------------------------------------------------- */ static const H5O_obj_class_t * H5O_obj_class_real(H5O_t *oh) { size_t i; /* Local index variable */ const H5O_obj_class_t *ret_value; /* Return value */ FUNC_ENTER_NOAPI_NOINIT(H5O_obj_class_real) /* Sanity check */ HDassert(oh); /* Test whether entry qualifies as a particular type of object */ /* (Note: loop is in reverse order, to test specific objects first) */ for(i = NELMTS(H5O_obj_class_g); i > 0; --i) { htri_t isa; /* Is entry a particular type? */ if((isa = (H5O_obj_class_g[i - 1]->isa)(oh)) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, NULL, "unable to determine object type") else if(isa) HGOTO_DONE(H5O_obj_class_g[i - 1]) } /* end for */ if(0 == i) HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, NULL, "unable to determine object type") done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_obj_class_real() */ /*------------------------------------------------------------------------- * Function: H5O_loc_reset * * Purpose: Reset a object location to an empty state * * Return: Success: Non-negative * Failure: Negative * * Programmer: Quincey Koziol * Monday, September 19, 2005 * *------------------------------------------------------------------------- */ herr_t H5O_loc_reset(H5O_loc_t *loc) { FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5O_loc_reset) /* Check arguments */ HDassert(loc); /* Clear the object location to an empty state */ HDmemset(loc, 0, sizeof(H5O_loc_t)); loc->addr = HADDR_UNDEF; FUNC_LEAVE_NOAPI(SUCCEED) } /* end H5O_loc_reset() */ /*------------------------------------------------------------------------- * Function: H5O_loc_copy * * Purpose: Copy object location information * * Return: Success: Non-negative * Failure: Negative * * Programmer: Quincey Koziol * koziol@ncsa.uiuc.edu * Monday, September 19, 2005 * * Notes: 'depth' parameter determines how much of the group entry * structure we want to copy. The values are: * H5_COPY_SHALLOW - Copy all the field values from the source * to the destination, but not copying objects pointed to. * (Destination "takes ownership" of objects pointed to) * H5_COPY_DEEP - Copy all the fields from the source to * the destination, deep copying objects pointed to. * *------------------------------------------------------------------------- */ herr_t H5O_loc_copy(H5O_loc_t *dst, const H5O_loc_t *src, H5_copy_depth_t depth) { FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5O_loc_copy) /* Check arguments */ HDassert(src); HDassert(dst); HDassert(depth == H5_COPY_SHALLOW || depth == H5_COPY_DEEP); /* Copy the top level information */ HDmemcpy(dst, src, sizeof(H5O_loc_t)); /* Deep copy the names */ if(depth == H5_COPY_DEEP) { /* If the original entry was holding open the file, this one should * hold it open, too. */ if(src->holding_file) dst->file->nopen_objs++; } else if(depth == H5_COPY_SHALLOW) { /* Discarding 'const' qualifier OK - QAK */ H5O_loc_reset((H5O_loc_t *)src); } /* end if */ FUNC_LEAVE_NOAPI(SUCCEED) } /* end H5O_loc_copy() */ /*------------------------------------------------------------------------- * Function: H5O_loc_hold_file * * Purpose: Have this object header hold a file open until it is * released. * * Return: Success: Non-negative * Failure: Negative * * Programmer: James Laird * Wednesday, August 16, 2006 * *------------------------------------------------------------------------- */ herr_t H5O_loc_hold_file(H5O_loc_t *loc) { FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5O_loc_hold_file) /* Check arguments */ HDassert(loc); HDassert(loc->file); /* If this location is not already holding its file open, do so. */ if(!loc->holding_file) { loc->file->nopen_objs++; loc->holding_file = TRUE; } FUNC_LEAVE_NOAPI(SUCCEED) } /* end H5O_loc_hold_file() */ /*------------------------------------------------------------------------- * Function: H5O_loc_free * * Purpose: Release resources used by this object header location. * Not to be confused with H5O_close; this is used on * locations that don't correspond to open objects. * * Return: Success: Non-negative * Failure: Negative * * Programmer: James Laird * Wednesday, August 16, 2006 * *------------------------------------------------------------------------- */ herr_t H5O_loc_free(H5O_loc_t *loc) { herr_t ret_value = SUCCEED; FUNC_ENTER_NOAPI_NOINIT(H5O_loc_free) /* Check arguments */ HDassert(loc); /* If this location is holding its file open try to close the file. */ if(loc->holding_file) { loc->file->nopen_objs--; loc->holding_file = FALSE; if(loc->file->nopen_objs <= 0) { if(H5F_try_close(loc->file) < 0) HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "can't close file") } } done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_loc_free() */ /*------------------------------------------------------------------------- * Function: H5O_copy_mesg_file * * Purpose: Copies a message to file. If MESG is is the null pointer then a null * pointer is returned with no error. * * Return: Success: Ptr to the new message * * Failure: NULL * * Programmer: Peter Cao * June 4, 2005 * *------------------------------------------------------------------------- */ void * H5O_copy_mesg_file(const H5O_msg_class_t *copy_type, const H5O_msg_class_t *mesg_type, H5F_t *file_src, void *native_src, H5F_t *file_dst, hid_t dxpl_id, H5O_copy_t *cpy_info, void *udata) { void *ret_value; FUNC_ENTER_NOAPI_NOINIT(H5O_copy_mesg_file) /* check args */ HDassert(copy_type); HDassert(mesg_type); HDassert(copy_type->copy_file); HDassert(file_src); HDassert(native_src); HDassert(file_dst); HDassert(cpy_info); if(NULL == (ret_value = (copy_type->copy_file)(file_src, mesg_type, native_src, file_dst, dxpl_id, cpy_info, udata))) HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, NULL, "unable to copy object header message to file") done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_copy_mesg_file() */ /*------------------------------------------------------------------------- * Function: H5O_copy_header_real * * Purpose: Copy header object from one location to another using * pre-copy, copy, and post-copy callbacks for each message * type. * * The source header object is compressed into a single chunk * (since we know how big it is) and any continuation messages * are converted into NULL messages. * * By default, NULL messages are not copied. * * Return: Non-negative on success/Negative on failure * * Programmer: Peter Cao * May 30, 2005 * *------------------------------------------------------------------------- */ static herr_t H5O_copy_header_real(const H5O_loc_t *oloc_src, H5O_loc_t *oloc_dst /*out */, hid_t dxpl_id, H5O_copy_t *cpy_info) { H5O_addr_map_t *addr_map = NULL; /* Address mapping of object copied */ H5O_t *oh_src = NULL; /* Object header for source object */ H5O_t *oh_dst = NULL; /* Object header for destination object */ unsigned chunkno = 0, mesgno = 0; haddr_t addr_new = HADDR_UNDEF; hbool_t *deleted = NULL; /* Array of flags indicating whether messages should be copied */ size_t null_msgs; /* Number of NULL messages found in each loop */ H5O_mesg_t *mesg_src; /* Message in source object header */ H5O_mesg_t *mesg_dst; /* Message in source object header */ const H5O_msg_class_t *copy_type; /* Type of message to use for copying */ const H5O_obj_class_t *obj_class = NULL; /* Type of object we are copying */ void *udata = NULL; /* User data for passing to message callbacks */ size_t dst_oh_size; /* Total size of the destination OH */ uint8_t *current_pos; /* Current position in destination image */ size_t msghdr_size; herr_t ret_value = SUCCEED; FUNC_ENTER_NOAPI_NOINIT(H5O_copy_header_real) HDassert(oloc_src); HDassert(oloc_src->file); HDassert(H5F_addr_defined(oloc_src->addr)); HDassert(oloc_dst->file); HDassert(cpy_info); /* Get source object header */ if(NULL == (oh_src = H5AC_protect(oloc_src->file, dxpl_id, H5AC_OHDR, oloc_src->addr, NULL, NULL, H5AC_READ))) HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "unable to load object header") /* Get pointer to object class for this object */ if(NULL == (obj_class = H5O_obj_class_real(oh_src))) HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to determine object type") /* Retrieve user data for particular type of object to copy */ if(obj_class->get_copy_file_udata && (NULL == (udata = (obj_class->get_copy_file_udata)()))) HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to retrieve copy user data") /* Flush any dirty messages in source object header to update the header chunks */ if(H5O_flush_msgs(oloc_src->file, oh_src) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTFLUSH, FAIL, "unable to flush object header messages") /* Allocate the destination object header and fill in header fields */ if(NULL == (oh_dst = H5FL_MALLOC(H5O_t))) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") /* Initialize header information */ oh_dst->version = oh_src->version; oh_dst->nlink = 0; /* Initialize size of chunk array. The destination always has only one * chunk. */ oh_dst->alloc_nchunks = oh_dst->nchunks = 1; /* Allocate memory for the chunk array */ if(NULL == (oh_dst->chunk = H5FL_SEQ_MALLOC(H5O_chunk_t, oh_dst->alloc_nchunks))) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") /* Allocate memory for "deleted" array. This array marks the message in * the source that shouldn't be copied to the destination. */ if(NULL == (deleted = HDmalloc(sizeof(hbool_t) * oh_src->nmesgs))) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") HDmemset(deleted, FALSE, sizeof(hbool_t) * oh_src->nmesgs); /* "pre copy" pass over messages, to gather information for actual message copy operation * (for messages which depend on information from other messages) * Keep track of how many NULL or deleted messages we find (or create) */ null_msgs = 0; for(mesgno = 0; mesgno < oh_src->nmesgs; mesgno++) { /* Set up convenience variables */ mesg_src = &(oh_src->mesg[mesgno]); mesg_dst = &(oh_dst->mesg[mesgno]); /* Sanity check */ HDassert(!mesg_src->dirty); /* Should be cleared by earlier call to flush messages */ /* Check for shared message to operate on */ if(mesg_src->flags & H5O_FLAG_SHARED) copy_type = H5O_MSG_SHARED; else copy_type = mesg_src->type; /* Check for continuation message; these are converted to NULL * messages because the destination OH will have only one chunk */ if(H5O_CONT_ID == mesg_src->type->id || H5O_NULL_ID == mesg_src->type->id) { deleted[mesgno] = TRUE; ++null_msgs; copy_type = H5O_MSG_NULL; } HDassert(copy_type); if(copy_type->pre_copy_file ) { /* * Decode the message if necessary. If the message is shared then do * a shared message, ignoring the message type. */ if(NULL == mesg_src->native) { /* Decode the message if necessary */ HDassert(copy_type->decode); if(NULL == (mesg_src->native = (copy_type->decode)(oloc_src->file, dxpl_id, mesg_src->raw))) HGOTO_ERROR(H5E_OHDR, H5E_CANTDECODE, FAIL, "unable to decode a message") } /* end if (NULL == mesg_src->native) */ /* Perform "pre copy" operation on message */ if((copy_type->pre_copy_file)(oloc_src->file, mesg_src->type, mesg_src->native, &(deleted[mesgno]), cpy_info, udata) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to perform 'pre copy' operation on message") /* Check if the message should be deleted in the destination */ if(deleted[mesgno]) { /* Mark message as deleted */ ++null_msgs; } /* end if(deleted) */ } /* end if(copy_type->pre_copy_file) */ } /* end for */ /* Initialize size of message list. It may or may not include the NULL messages * detected above. */ if(cpy_info->preserve_null) oh_dst->alloc_nmesgs = oh_dst->nmesgs = oh_src->nmesgs; else oh_dst->alloc_nmesgs = oh_dst->nmesgs = (oh_src->nmesgs - null_msgs); /* Allocate memory for destination message array */ if(oh_dst->alloc_nmesgs > 0) { if(NULL == (oh_dst->mesg = H5FL_SEQ_CALLOC(H5O_mesg_t, oh_dst->alloc_nmesgs))) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") } /* "copy" pass over messages, to perform main message copying */ null_msgs = 0; for(mesgno = 0; mesgno < oh_dst->nmesgs; mesgno++) { /* Skip any deleted or NULL messages in the source unless the * preserve_null flag is set */ if(FALSE == cpy_info->preserve_null) { while(deleted[mesgno + null_msgs]) { ++null_msgs; HDassert(mesgno + null_msgs < oh_src->nmesgs); } } /* Set up convenience variables */ mesg_src = &(oh_src->mesg[mesgno + null_msgs]); mesg_dst = &(oh_dst->mesg[mesgno]); /* Initialize on destination message */ mesg_dst->chunkno = 0; mesg_dst->dirty = FALSE; mesg_dst->flags = mesg_src->flags; mesg_dst->native = NULL; mesg_dst->raw = NULL; mesg_dst->raw_size = mesg_src->raw_size; mesg_dst->type = mesg_src->type; /* If we're preserving deleted messages, set their types to 'NULL' * in the destination. */ if(cpy_info->preserve_null && deleted[mesgno]) { mesg_dst->type = H5O_MSG_NULL; } /* Check for shared message to operate on */ /* (Use destination message, in case the message has been removed (i.e * converted to a nil message) in the destination -QAK) */ if(mesg_dst->flags & H5O_FLAG_SHARED) copy_type = H5O_MSG_SHARED; else copy_type = mesg_dst->type; HDassert(copy_type); /* copy this message into destination file */ if(copy_type->copy_file) { /* * Decode the message if necessary. If the message is shared then do * a shared message, ignoring the message type. */ if(NULL == mesg_src->native) { /* Decode the message if necessary */ HDassert(copy_type->decode); if(NULL == (mesg_src->native = (copy_type->decode)(oloc_src->file, dxpl_id, mesg_src->raw))) HGOTO_ERROR(H5E_OHDR, H5E_CANTDECODE, FAIL, "unable to decode a message") } /* end if (NULL == mesg_src->native) */ /* Copy the source message */ if((mesg_dst->native = H5O_copy_mesg_file(copy_type, mesg_dst->type, oloc_src->file, mesg_src->native, oloc_dst->file, dxpl_id, cpy_info, udata)) == NULL) HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, FAIL, "unable to copy object header message") /* Mark the message in the destination as dirty, so it'll get encoded when the object header is flushed */ mesg_dst->dirty = TRUE; } /* end if (mesg_src->type->copy_file) */ } /* end of mesgno loop */ /* Allocate the destination header and copy any messages that didn't have * copy callbacks. They get copied directly from the source image to the * destination image. */ /* Calculate how big the destination object header will be on disk. * This isn't necessarily the same size as the original. */ dst_oh_size = H5O_SIZEOF_HDR_OH(oh_dst); /* Add space for messages. */ for(mesgno = 0; mesgno < oh_dst->nmesgs; mesgno++) { dst_oh_size += H5O_SIZEOF_MSGHDR_OH(oh_dst); dst_oh_size += H5O_ALIGN_OH(oh_dst, oh_dst->mesg[mesgno].raw_size); } /* Allocate space for chunk in destination file */ if(HADDR_UNDEF == (oh_dst->chunk[0].addr = H5MF_alloc(oloc_dst->file, H5FD_MEM_OHDR, dxpl_id, (hsize_t)dst_oh_size))) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "file allocation failed for object header") addr_new = oh_dst->chunk[0].addr; /* Create memory image for the new chunk */ if(NULL == (oh_dst->chunk[0].image = H5FL_BLK_MALLOC(chunk_image, dst_oh_size))) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") /* Set dest. chunk information */ oh_dst->chunk[0].dirty = TRUE; oh_dst->chunk[0].size = dst_oh_size; oh_dst->chunk[0].gap = 0; /* Set up raw pointers and copy messages that didn't need special * treatment. This has to happen after the destination header has been * allocated. */ HDassert(H5O_SIZEOF_HDR_OH(oh_src) == H5O_SIZEOF_HDR_OH(oh_dst)); HDassert(H5O_SIZEOF_MSGHDR_OH(oh_src) == H5O_SIZEOF_MSGHDR_OH(oh_dst)); msghdr_size = H5O_SIZEOF_MSGHDR_OH(oh_src); current_pos = oh_dst->chunk[0].image; /* Copy the message header. Most of this will be overwritten when * the header is flushed to disk, but later versions have a * magic number that isn't. */ HDmemcpy(current_pos, oh_src->chunk[0].image, H5O_SIZEOF_HDR_OH(oh_dst) - H5O_SIZEOF_CHKSUM_OH(oh_dst)); current_pos += H5O_SIZEOF_HDR_OH(oh_dst) - H5O_SIZEOF_CHKSUM_OH(oh_dst); /* JAMES: include this in loop above? Doesn't take deleted messages * into account */ /* Copy each message that wasn't dirtied above */ null_msgs = 0; for(mesgno = 0; mesgno < oh_dst->nmesgs; mesgno++) { /* Skip any deleted or NULL messages in the source unless the * preserve_null flag is set */ if(FALSE == cpy_info->preserve_null) { while(deleted[mesgno + null_msgs]) { ++null_msgs; HDassert(mesgno + null_msgs < oh_src->nmesgs); } } /* Set up convenience variables */ mesg_src = &(oh_src->mesg[mesgno + null_msgs]); mesg_dst = &(oh_dst->mesg[mesgno]); if(! mesg_dst->dirty) { /* Copy the message header plus the message's raw data. */ HDmemcpy(current_pos, mesg_src->raw - msghdr_size, msghdr_size + mesg_src->raw_size); } mesg_dst->raw = current_pos + msghdr_size; current_pos += mesg_dst->raw_size + msghdr_size; } /* Make sure we filled the chunk, except for room at the end for a checksum */ HDassert(current_pos + H5O_SIZEOF_CHKSUM_OH(oh_dst) == dst_oh_size + oh_dst->chunk[0].image); /* Set the dest. object location to the first chunk address */ HDassert(H5F_addr_defined(addr_new)); oloc_dst->addr = addr_new; /* Allocate space for the address mapping of the object copied */ if(NULL == (addr_map = H5FL_MALLOC(H5O_addr_map_t))) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") /* Insert the address mapping for the new object into the copied list */ /* (Do this here, because "post copy" possibly checks it) */ addr_map->src_addr = oloc_src->addr; addr_map->dst_addr = oloc_dst->addr; addr_map->is_locked = TRUE; /* We've locked the object currently */ addr_map->inc_ref_count = 0; /* Start with no additional ref counts to add */ if(H5SL_insert(cpy_info->map_list, addr_map, &(addr_map->src_addr)) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, FAIL, "can't insert object into skip list") /* "post copy" loop over messages, to fix up any messages which require a complete * object header for destination object */ null_msgs = 0; for(mesgno = 0; mesgno < oh_dst->nmesgs; mesgno++) { /* Skip any deleted or NULL messages in the source unless the * preserve_null flag is set */ if(FALSE == cpy_info->preserve_null) { while(deleted[mesgno + null_msgs]) { ++null_msgs; HDassert(mesgno + null_msgs < oh_src->nmesgs); } } /* Set up convenience variables */ mesg_src = &(oh_src->mesg[mesgno + null_msgs]); mesg_dst = &(oh_dst->mesg[mesgno]); /* Check for shared message to operate on */ /* (Use destination message, in case the message has been removed (i.e * converted to a nil message) in the destination -QAK) */ if(mesg_dst->flags & H5O_FLAG_SHARED) copy_type = H5O_MSG_SHARED; else copy_type = mesg_dst->type; HDassert(copy_type); if(copy_type->post_copy_file && mesg_src->native) { /* Sanity check destination message */ HDassert(mesg_dst->type == mesg_src->type); HDassert(mesg_dst->native); /* Perform "post copy" operation on message */ if((copy_type->post_copy_file)(oloc_src, mesg_src->native, oloc_dst, mesg_dst->native, dxpl_id, cpy_info) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to perform 'post copy' operation on message") } /* end if */ } /* end for */ /* Indicate that the destination address will no longer be locked */ addr_map->is_locked = FALSE; /* Increment object header's reference count, if any descendents have created links to link to this object */ if(addr_map->inc_ref_count) { H5_CHECK_OVERFLOW(addr_map->inc_ref_count, hsize_t, int); oh_dst->nlink += (int)addr_map->inc_ref_count; } /* end if */ /* Insert destination object header in cache */ if(H5AC_set(oloc_dst->file, dxpl_id, H5AC_OHDR, oloc_dst->addr, oh_dst, H5AC__DIRTIED_FLAG) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to cache object header") done: /* Free deleted array */ if(deleted) { HDfree(deleted); } /* Release pointer to source object header and its derived objects */ if(oh_src != NULL) { /* Unprotect the source object header */ if(H5AC_unprotect(oloc_src->file, dxpl_id, H5AC_OHDR, oloc_src->addr, oh_src, H5AC__NO_FLAGS_SET) < 0) HDONE_ERROR(H5E_OHDR, H5E_PROTECT, FAIL, "unable to release object header") } /* end if */ /* Release pointer to destination object header */ if(ret_value < 0 && oh_dst) { if(H5O_dest(oloc_dst->file, oh_dst) < 0) HDONE_ERROR(H5E_OHDR, H5E_CANTFREE, FAIL, "unable to destroy object header data") } /* end if */ /* Release user data for particular type of object to copy */ if(udata) { HDassert(obj_class); HDassert(obj_class->free_copy_file_udata); (obj_class->free_copy_file_udata)(udata); } /* end if */ FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_copy_header_real() */ /*------------------------------------------------------------------------- * Function: H5O_copy_header_map * * Purpose: Copy header object from one location to another, detecting * already mapped objects, etc. * * Return: Non-negative on success/Negative on failure * * Programmer: Quincey Koziol * November 1, 2005 * *------------------------------------------------------------------------- */ herr_t H5O_copy_header_map(const H5O_loc_t *oloc_src, H5O_loc_t *oloc_dst /*out */, hid_t dxpl_id, H5O_copy_t *cpy_info, hbool_t inc_depth) { H5O_addr_map_t *addr_map; /* Address mapping of object copied */ hbool_t inc_link; /* Whether to increment the link count for the object */ herr_t ret_value = SUCCEED; FUNC_ENTER_NOAPI(H5O_copy_header_map, FAIL) /* Sanity check */ HDassert(oloc_src); HDassert(oloc_dst); HDassert(oloc_dst->file); HDassert(cpy_info); /* Look up the address of the object to copy in the skip list */ addr_map = (H5O_addr_map_t *)H5SL_search(cpy_info->map_list, &(oloc_src->addr)); /* Check if address is already in list of objects copied */ if(addr_map == NULL) { /* Copy object for the first time */ /* Check for incrementing the depth of copy */ /* (Can't do this for all copies, since committed datatypes should always be copied) */ if(inc_depth) cpy_info->curr_depth++; /* Copy object referred to */ if(H5O_copy_header_real(oloc_src, oloc_dst, dxpl_id, cpy_info) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, FAIL, "unable to copy object") /* Check for incrementing the depth of copy */ if(inc_depth) cpy_info->curr_depth--; /* When an object is copied for the first time, increment it's link */ inc_link = TRUE; /* indicate that a new object is created */ ret_value++; } /* end if */ else { /* Object has already been copied, set its address in destination file */ oloc_dst->addr = addr_map->dst_addr; /* If the object is locked currently (because we are copying a group * hierarchy and this is a link to a group higher in the hierarchy), * increment it's deferred reference count instead of incrementing the * reference count now. */ if(addr_map->is_locked) { addr_map->inc_ref_count++; inc_link = FALSE; } /* end if */ else inc_link = TRUE; } /* end else */ /* Increment destination object's link count, if allowed */ if(inc_link) if(H5O_link(oloc_dst, 1, dxpl_id) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to increment object link count") done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_copy_header_map() */ /*-------------------------------------------------------------------------- NAME H5O_copy_free_addrmap_cb PURPOSE Internal routine to free address maps from the skip list for copying objects USAGE herr_t H5O_copy_free_addrmap_cb(item, key, op_data) void *item; IN/OUT: Pointer to addr void *key; IN/OUT: (unused) void *op_data; IN: (unused) RETURNS Returns zero on success, negative on failure. DESCRIPTION Releases the memory for the address. GLOBAL VARIABLES COMMENTS, BUGS, ASSUMPTIONS EXAMPLES REVISION LOG --------------------------------------------------------------------------*/ static herr_t H5O_copy_free_addrmap_cb(void *item, void UNUSED *key, void UNUSED *op_data) { FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5O_copy_free_addrmap_cb) HDassert(item); /* Release the item */ H5FL_FREE(H5O_addr_map_t, item); FUNC_LEAVE_NOAPI(0) } /* H5O_copy_free_addrmap_cb() */ /*------------------------------------------------------------------------- * Function: H5O_copy_header * * Purpose: copy header object from one location to another. * * Return: Non-negative on success/Negative on failure * * Programmer: Peter Cao * May 30, 2005 * *------------------------------------------------------------------------- */ herr_t H5O_copy_header(const H5O_loc_t *oloc_src, H5O_loc_t *oloc_dst /*out */, hid_t dxpl_id, unsigned cpy_option) { H5O_copy_t cpy_info; /* Information for copying object */ herr_t ret_value = SUCCEED; FUNC_ENTER_NOAPI(H5O_copy_header, FAIL) HDassert(oloc_src); HDassert(oloc_src->file); HDassert(H5F_addr_defined(oloc_src->addr)); HDassert(oloc_dst->file); /* Convert copy flags into copy struct */ HDmemset(&cpy_info, 0, sizeof(H5O_copy_t)); if((cpy_option & H5O_COPY_SHALLOW_HIERARCHY_FLAG) > 0) { cpy_info.copy_shallow = TRUE; cpy_info.max_depth = 1; } /* end if */ else cpy_info.max_depth = -1; /* Current default is for full, recursive hier. copy */ cpy_info.curr_depth = 0; if((cpy_option & H5O_COPY_EXPAND_SOFT_LINK_FLAG) > 0) cpy_info.expand_soft_link = TRUE; if((cpy_option & H5O_COPY_EXPAND_EXT_LINK_FLAG) > 0) cpy_info.expand_ext_link = TRUE; if((cpy_option & H5O_COPY_EXPAND_REFERENCE_FLAG) > 0) cpy_info.expand_ref = TRUE; if((cpy_option & H5O_COPY_WITHOUT_ATTR_FLAG) > 0) cpy_info.copy_without_attr = TRUE; if((cpy_option & H5O_COPY_PRESERVE_NULL_FLAG) > 0) cpy_info.preserve_null = TRUE; /* Create a skip list to keep track of which objects are copied */ if((cpy_info.map_list = H5SL_create(H5SL_TYPE_HADDR, 0.5, (size_t)16)) == NULL) HGOTO_ERROR(H5E_SLIST, H5E_CANTCREATE, FAIL, "cannot make skip list") /* copy the object from the source file to the destination file */ if(H5O_copy_header_real(oloc_src, oloc_dst, dxpl_id, &cpy_info) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, FAIL, "unable to copy object") done: if(cpy_info.map_list) H5SL_destroy(cpy_info.map_list, H5O_copy_free_addrmap_cb, NULL); FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_copy_header() */ /*------------------------------------------------------------------------- * Function: H5O_mesg_hash * * Purpose: Returns a hash value for an object header message. * * Return: Non-H5O_HASH_UNDEF hash value on success * H5O_HASH_UNDEF on failure * * Programmer: James Laird * April 13 2006 * *------------------------------------------------------------------------- */ uint32_t H5O_mesg_hash(unsigned type_id, H5F_t *f, const void *mesg) { size_t buf_size; unsigned char * buf = NULL; /* Buffer to be hashed */ uint32_t hash; uint32_t ret_value; FUNC_ENTER_NOAPI(H5O_mesg_hash, FAIL) /* Check args */ HDassert(type_id < NELMTS(H5O_msg_class_g)); HDassert(mesg); HDassert(f); /* Find out the size of buffer needed */ if((buf_size = H5O_raw_size(type_id, f, mesg)) <= 0) HGOTO_ERROR(H5E_OHDR, H5E_BADSIZE, FAIL, "can't find message size"); /* JAMES: revisit this! Some messages don't use as much space as they say * they need. Quincey may have fixed this. */ if((buf = HDmalloc(buf_size)) == NULL) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate buffer for message"); HDmemset(buf, 0, buf_size); if(H5O_encode(f, buf, mesg, type_id) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTENCODE, FAIL, "can't encode OH message"); /* * Compute the hash value for this message. type_id is used here to * initialize the hash algorithm, and affects the resulting value. */ hash = H5_checksum_lookup3(buf, buf_size, type_id); /* JAMES: this is a pretty good hash function. Do we need to version it? * If so, we'd do so here. */ /* A hash value of H5O_HASH_UNDEF indicates failure. If we naturally * generated this value, reset it to some valid value. */ if(hash == H5O_HASH_UNDEF) hash = (uint32_t) 1; ret_value = hash; done: if(buf) HDfree(buf); FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_mesg_hash() */ /*------------------------------------------------------------------------- * Function: H5O_copy_obj_by_ref * * Purpose: Copy the object pointed by _src_ref. * * Return: Non-negative on success/Negative on failure * * Programmer: Peter Cao * Aug 7 2006 * *------------------------------------------------------------------------- */ static herr_t H5O_copy_obj_by_ref(H5O_loc_t *src_oloc, hid_t dxpl_id, H5O_loc_t *dst_oloc, H5G_loc_t *dst_root_loc, H5O_copy_t *cpy_info) { herr_t ret_value = SUCCEED; FUNC_ENTER_NOAPI(H5O_copy_obj_by_ref, FAIL) HDassert(src_oloc); HDassert(dst_oloc); /* Perform the copy, or look up existing copy */ if((ret_value = H5O_copy_header_map(src_oloc, dst_oloc, dxpl_id, cpy_info, FALSE)) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, FAIL, "unable to copy object") /* Check if a new valid object is copied to the destination */ if(H5F_addr_defined(dst_oloc->addr) && (ret_value > SUCCEED)) { char tmp_obj_name[80]; H5G_name_t new_path; H5O_loc_t new_oloc; H5G_loc_t new_loc; /* Set up group location for new object */ new_loc.oloc = &new_oloc; new_loc.path = &new_path; H5G_loc_reset(&new_loc); new_oloc.file = dst_oloc->file; new_oloc.addr = dst_oloc->addr; /* Pick a default name for the new object */ sprintf(tmp_obj_name, "~obj_pointed_by_%llu", (unsigned long_long)dst_oloc->addr); /* Create a link to the newly copied object */ if(H5L_link(dst_root_loc, tmp_obj_name, &new_loc, H5P_DEFAULT, H5P_DEFAULT, dxpl_id) < 0) HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to insert link") H5G_loc_free(&new_loc); } /* if (H5F_addr_defined(dst_oloc.addr)) */ done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_copy_obj_by_ref() */ #ifdef H5O_DEBUG /*------------------------------------------------------------------------- * Function: H5O_assert * * Purpose: Sanity check the information for an object header data * structure. * * Return: Non-negative on success/Negative on failure * * Programmer: Quincey Koziol * koziol@hdfgroup.org * Oct 17 2006 * *------------------------------------------------------------------------- */ herr_t H5O_assert(const H5O_t *oh) { H5O_mesg_t *curr_msg; /* Pointer to current message to examine */ H5O_mesg_t *tmp_msg; /* Pointer to temporary message to examine */ unsigned u, v; /* Local index variables */ FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5O_assert) /* Loop over all chunks in object header */ for(u = 0; u < oh->nchunks; u++) { /* Check for valid raw data image */ HDassert(oh->chunk[u].image); HDassert(oh->chunk[u].size > (size_t)H5O_SIZEOF_CHKHDR_OH(oh)); /* All chunks must be allocated on disk */ HDassert(H5F_addr_defined(oh->chunk[u].addr)); /* Version specific checks */ if(oh->version > H5O_VERSION_1) { /* Make certain that the magic number is correct for each chunk */ HDassert(!HDmemcmp(oh->chunk[u].image, (u == 0 ? H5O_HDR_MAGIC : H5O_CHK_MAGIC), H5O_SIZEOF_MAGIC)); /* Check for valid gap size */ HDassert(oh->chunk[u].gap < (size_t)H5O_SIZEOF_MSGHDR_OH(oh)); } /* end if */ else /* Gaps should never occur in version 1 of the format */ HDassert(oh->chunk[u].gap == 0); } /* end for */ /* Loop over all messages in object header */ for(u = 0, curr_msg = &oh->mesg[0]; u < oh->nmesgs; u++, curr_msg++) { /* Make certain that the message is in a valid chunk */ HDassert(curr_msg->chunkno < oh->nchunks); /* Make certain null messages aren't in chunks with gaps */ if(H5O_NULL_ID == curr_msg->type->id) HDassert(oh->chunk[curr_msg->chunkno].gap == 0); /* Make certain that the message is completely in a chunk message area */ HDassert(curr_msg->raw_size <= (oh->chunk[curr_msg->chunkno].size) - (H5O_SIZEOF_CHKSUM_OH(oh) + oh->chunk[curr_msg->chunkno].gap)); if(curr_msg->chunkno == 0) HDassert(curr_msg->raw >= oh->chunk[curr_msg->chunkno].image + (H5O_SIZEOF_HDR_OH(oh) - H5O_SIZEOF_CHKSUM_OH(oh))); else HDassert(curr_msg->raw >= oh->chunk[curr_msg->chunkno].image + (H5O_SIZEOF_CHKHDR_OH(oh) - H5O_SIZEOF_CHKSUM_OH(oh))); HDassert(curr_msg->raw + curr_msg->raw_size <= (oh->chunk[curr_msg->chunkno].image + oh->chunk[curr_msg->chunkno].size) - (H5O_SIZEOF_CHKSUM_OH(oh) + oh->chunk[curr_msg->chunkno].gap)); /* Make certain that no other messages overlap this message */ for(v = 0, tmp_msg = &oh->mesg[0]; v < oh->nmesgs; v++, tmp_msg++) { if(u != v) HDassert(!(tmp_msg->raw >= curr_msg->raw && tmp_msg->raw < (curr_msg->raw + curr_msg->raw_size))); } /* end for */ } /* end for */ FUNC_LEAVE_NOAPI(SUCCEED) } /* end H5O_assert() */ #endif /* H5O_DEBUG */ /*------------------------------------------------------------------------- * Function: H5O_debug_id * * Purpose: Act as a proxy for calling the 'debug' method for a * particular class of object header. * * Return: Non-negative on success/Negative on failure * * Programmer: Quincey Koziol * koziol@ncsa.uiuc.edu * Feb 13 2003 * * Modifications: * *------------------------------------------------------------------------- */ herr_t H5O_debug_id(unsigned type_id, H5F_t *f, hid_t dxpl_id, const void *mesg, FILE *stream, int indent, int fwidth) { const H5O_msg_class_t *type; /* Actual H5O class type for the ID */ herr_t ret_value; /* Return value */ FUNC_ENTER_NOAPI(H5O_debug_id,FAIL) /* Check args */ HDassert(type_id < NELMTS(H5O_msg_class_g)); type = H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */ HDassert(type); HDassert(type->debug); HDassert(f); HDassert(mesg); HDassert(stream); HDassert(indent >= 0); HDassert(fwidth >= 0); /* Call the debug method in the class */ if((ret_value = (type->debug)(f, dxpl_id, mesg, stream, indent, fwidth)) < 0) HGOTO_ERROR(H5E_OHDR, H5E_BADTYPE, FAIL, "unable to debug message") done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_debug_id() */ /*------------------------------------------------------------------------- * Function: H5O_debug_real * * Purpose: Prints debugging info about an object header. * * Return: Non-negative on success/Negative on failure * * Programmer: Robb Matzke * matzke@llnl.gov * Aug 6 1997 * *------------------------------------------------------------------------- */ herr_t H5O_debug_real(H5F_t *f, hid_t dxpl_id, H5O_t *oh, haddr_t addr, FILE *stream, int indent, int fwidth) { unsigned i, chunkno; size_t mesg_total = 0, chunk_total = 0; int *sequence; void *(*decode)(H5F_t*, hid_t, const uint8_t*); herr_t (*debug)(H5F_t*, hid_t, const void*, FILE*, int, int)=NULL; herr_t ret_value = SUCCEED; FUNC_ENTER_NOAPI(H5O_debug_real, FAIL) /* check args */ HDassert(f); HDassert(oh); HDassert(H5F_addr_defined(addr)); HDassert(stream); HDassert(indent >= 0); HDassert(fwidth >= 0); /* debug */ HDfprintf(stream, "%*sObject Header...\n", indent, ""); HDfprintf(stream, "%*s%-*s %t\n", indent, "", fwidth, "Dirty:", oh->cache_info.is_dirty); HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth, "Version:", oh->version); HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth, "Header size (in bytes):", (unsigned)H5O_SIZEOF_HDR_OH(oh)); HDfprintf(stream, "%*s%-*s %d\n", indent, "", fwidth, "Number of links:", oh->nlink); HDfprintf(stream, "%*s%-*s %Zu (%Zu)\n", indent, "", fwidth, "Number of messages (allocated):", oh->nmesgs, oh->alloc_nmesgs); HDfprintf(stream, "%*s%-*s %Zu (%Zu)\n", indent, "", fwidth, "Number of chunks (allocated):", oh->nchunks, oh->alloc_nchunks); /* debug each chunk */ for(i = 0, chunk_total = 0; i < oh->nchunks; i++) { size_t chunk_size; chunk_total += oh->chunk[i].size; HDfprintf(stream, "%*sChunk %d...\n", indent, "", i); HDfprintf(stream, "%*s%-*s %t\n", indent + 3, "", MAX(0, fwidth - 3), "Dirty:", oh->chunk[i].dirty); HDfprintf(stream, "%*s%-*s %a\n", indent + 3, "", MAX(0, fwidth - 3), "Address:", oh->chunk[i].addr); if(0 == i) { if(H5F_addr_ne(oh->chunk[i].addr, addr)) HDfprintf(stream, "*** WRONG ADDRESS!\n"); chunk_size = oh->chunk[i].size - H5O_SIZEOF_HDR_OH(oh); } /* end if */ else chunk_size = oh->chunk[i].size; HDfprintf(stream, "%*s%-*s %Zu\n", indent + 3, "", MAX(0, fwidth - 3), "Size in bytes:", chunk_size); HDfprintf(stream, "%*s%-*s %Zu\n", indent + 3, "", MAX(0, fwidth - 3), "Gap:", oh->chunk[i].gap); } /* end for */ /* debug each message */ if(NULL == (sequence = H5MM_calloc(NELMTS(H5O_msg_class_g) * sizeof(int)))) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") for(i = 0, mesg_total = 0; i < oh->nmesgs; i++) { mesg_total += H5O_SIZEOF_MSGHDR_OH(oh) + oh->mesg[i].raw_size; HDfprintf(stream, "%*sMessage %d...\n", indent, "", i); /* check for bad message id */ if(oh->mesg[i].type->id >= (int)NELMTS(H5O_msg_class_g)) { HDfprintf(stream, "*** BAD MESSAGE ID 0x%04x\n", oh->mesg[i].type->id); continue; } /* end if */ /* message name and size */ HDfprintf(stream, "%*s%-*s 0x%04x `%s' (%d)\n", indent + 3, "", MAX(0, fwidth - 3), "Message ID (sequence number):", (unsigned) (oh->mesg[i].type->id), oh->mesg[i].type->name, sequence[oh->mesg[i].type->id]++); HDfprintf (stream, "%*s%-*s %t\n", indent+3, "", MAX (0, fwidth-3), "Dirty:", oh->mesg[i].dirty); HDfprintf (stream, "%*s%-*s %s\n", indent+3, "", MAX (0, fwidth-3), "Shared:", (oh->mesg[i].flags & H5O_FLAG_SHARED) ? "Yes" : "No"); HDfprintf(stream, "%*s%-*s %s\n", indent + 3, "", MAX(0, fwidth - 3), "Constant:", (oh->mesg[i].flags & H5O_FLAG_CONSTANT) ? "Yes" : "No"); if(oh->mesg[i].flags & ~H5O_FLAG_BITS) { HDfprintf (stream, "%*s%-*s 0x%02x\n", indent+3,"",MAX(0,fwidth-3), "*** ADDITIONAL UNKNOWN FLAGS --->", oh->mesg[i].flags & ~H5O_FLAG_BITS); } /* end if */ HDfprintf(stream, "%*s%-*s %Zu bytes\n", indent+3, "", MAX(0,fwidth-3), "Raw size in obj header:", oh->mesg[i].raw_size); HDfprintf(stream, "%*s%-*s %u\n", indent + 3, "", MAX(0, fwidth - 3), "Chunk number:", oh->mesg[i].chunkno); chunkno = oh->mesg[i].chunkno; if(chunkno >= oh->nchunks) HDfprintf(stream, "*** BAD CHUNK NUMBER\n"); HDfprintf(stream, "%*s%-*s %Zu\n", indent + 3, "", MAX(0, fwidth - 3), "Raw data offset in chunk:", (size_t)(oh->mesg[i].raw - oh->chunk[chunkno].image)); /* check the size */ if((oh->mesg[i].raw + oh->mesg[i].raw_size > oh->chunk[chunkno].image + oh->chunk[chunkno].size) || (oh->mesg[i].raw < oh->chunk[chunkno].image)) HDfprintf(stream, "*** BAD MESSAGE RAW ADDRESS\n"); /* decode the message */ if(oh->mesg[i].flags & H5O_FLAG_SHARED) { decode = H5O_MSG_SHARED->decode; debug = H5O_MSG_SHARED->debug; } else { decode = oh->mesg[i].type->decode; debug = oh->mesg[i].type->debug; } /* end else */ if(NULL==oh->mesg[i].native && decode) oh->mesg[i].native = (decode)(f, dxpl_id, oh->mesg[i].raw); if(NULL == oh->mesg[i].native) debug = NULL; /* print the message */ HDfprintf(stream, "%*s%-*s\n", indent + 3, "", MAX(0, fwidth - 3), "Message Information:"); if(debug) (debug)(f, dxpl_id, oh->mesg[i].native, stream, indent + 6, MAX(0, fwidth - 6)); else HDfprintf(stream, "%*s\n", indent + 6, ""); /* If the message is shared then also print the pointed-to message */ if(oh->mesg[i].flags & H5O_FLAG_SHARED) { H5O_shared_t *shared = (H5O_shared_t*)(oh->mesg[i].native); void *mesg; mesg = H5O_shared_read(f, dxpl_id, shared, oh->mesg[i].type, NULL); if(oh->mesg[i].type->debug) (oh->mesg[i].type->debug)(f, dxpl_id, mesg, stream, indent + 3, MAX (0, fwidth - 3)); H5O_free_real(oh->mesg[i].type, mesg); } /* end if */ } /* end for */ sequence = H5MM_xfree(sequence); if(mesg_total != chunk_total) HDfprintf(stream, "*** TOTAL SIZE DOES NOT MATCH ALLOCATED SIZE!\n"); done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_debug_real() */ /*------------------------------------------------------------------------- * Function: H5O_debug * * Purpose: Prints debugging info about an object header. * * Return: Non-negative on success/Negative on failure * * Programmer: Robb Matzke * matzke@llnl.gov * Aug 6 1997 * *------------------------------------------------------------------------- */ herr_t H5O_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr, FILE *stream, int indent, int fwidth) { H5O_t *oh = NULL; herr_t ret_value = SUCCEED; FUNC_ENTER_NOAPI(H5O_debug, FAIL) /* check args */ HDassert(f); HDassert(H5F_addr_defined(addr)); HDassert(stream); HDassert(indent >= 0); HDassert(fwidth >= 0); if(NULL == (oh = H5AC_protect(f, dxpl_id, H5AC_OHDR, addr, NULL, NULL, H5AC_READ))) HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "unable to load object header") /* debug */ H5O_debug_real(f, dxpl_id, oh, addr, stream, indent, fwidth); done: if(oh && H5AC_unprotect(f, dxpl_id, H5AC_OHDR, addr, oh, H5AC__NO_FLAGS_SET) < 0) HDONE_ERROR(H5E_OHDR, H5E_PROTECT, FAIL, "unable to release object header") FUNC_LEAVE_NOAPI(ret_value) } /* end H5O_debug() */