/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Copyright by The HDF Group. *
* 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://hdfgroup.org/HDF5/doc/Copyright.html. If you do not have *
* access to either file, you may request a copy from help@hdfgroup.org. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*-------------------------------------------------------------------------
*
* Created: H5O.c
* Aug 5 1997
* Robb Matzke <matzke@llnl.gov>
*
* Purpose: Object header virtual functions.
*
*-------------------------------------------------------------------------
*/
#define H5F_PACKAGE /*suppress error about including H5Fpkg */
#define H5O_PACKAGE /*suppress error about including H5Opkg */
/* Interface initialization */
#define H5_INTERFACE_INIT_FUNC H5O_init_interface
#include "H5private.h" /* Generic Functions */
#include "H5ACprivate.h" /* Metadata cache */
#include "H5Eprivate.h" /* Error handling */
#include "H5Fpkg.h" /* File access */
#include "H5FLprivate.h" /* Free lists */
#include "H5Iprivate.h" /* IDs */
#include "H5MFprivate.h" /* File memory management */
#include "H5MMprivate.h" /* Memory management */
#include "H5Opkg.h" /* Object headers */
#include "H5Pprivate.h" /* Property lists */
#ifdef H5_HAVE_GETTIMEOFDAY
#include <sys/time.h>
#endif /* H5_HAVE_GETTIMEOFDAY */
/* Local macros */
/* 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 */
/* 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" iteration operations */
typedef herr_t (*H5O_operator_int_t)(H5O_mesg_t *mesg/*in,out*/, unsigned idx,
unsigned * oh_flags_ptr, void *operator_data/*in,out*/);
/* 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 */
NULL, /*0x0002 Data space (fiber bundle?) */
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 */
NULL, /*0x0006 Data storage -- compact object */
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 */
NULL, /*0x000A Not assigned */
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 */
};
/* 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 */
/*
* An array of functions indexed by symbol table entry cache type
* (H5G_type_t) that are called to retrieve constant messages cached in the
* symbol table entry.
*/
static void *(*H5O_fast_g[H5G_NCACHED]) (const H5G_cache_t *,
const H5O_msg_class_t *,
void *);
/* 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);
/* PRIVATE PROTOTYPES */
static herr_t H5O_new(H5F_t *f, hid_t dxpl_id, size_t size_hint,
H5G_entry_t *ent/*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 (H5G_entry_t *ent, const H5O_msg_class_t *type,
hid_t dxpl_id);
static htri_t H5O_exists_real(H5G_entry_t *ent, const H5O_msg_class_t *type,
int sequence, hid_t dxpl_id);
#ifdef NOT_YET
static herr_t H5O_share(H5F_t *f, hid_t dxpl_id, const H5O_msg_class_t *type, const void *mesg,
H5HG_t *hobj/*out*/);
#endif /* NOT_YET */
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(H5G_entry_t *ent, 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);
static herr_t H5O_remove_real(H5G_entry_t *ent, const H5O_msg_class_t *type,
int sequence, H5O_operator_t op, void *op_data, hbool_t adj_link, hid_t dxpl_id);
static unsigned H5O_alloc(H5F_t *f, H5O_t *oh, const H5O_msg_class_t *type,
size_t size);
static unsigned H5O_alloc_extend_chunk(H5F_t *f, H5O_t *oh, unsigned chunkno, size_t size);
static unsigned H5O_alloc_new_chunk(H5F_t *f, 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);
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);
static herr_t H5O_iterate_real(const H5G_entry_t *ent, const H5O_msg_class_t *type,
H5AC_protect_t prot, hbool_t internal, void *op, void *op_data, hid_t dxpl_id);
/*-------------------------------------------------------------------------
* Function: H5O_init
*
* Purpose: Initialize the interface from some other package.
*
* Return: Success: non-negative
*
* Failure: negative
*
* Programmer: Quincey Koziol
* Wednesday, September 28, 2005
*
*-------------------------------------------------------------------------
*/
herr_t
H5O_init(void)
{
herr_t ret_value = SUCCEED; /* Return value */
FUNC_ENTER_NOAPI(H5O_init, FAIL)
/* FUNC_ENTER() does all the work */
done:
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5O_init() */
/*-------------------------------------------------------------------------
* Function: H5O_init_interface
*
* Purpose: Initialize the H5O interface.
*
* Return: Non-negative on success/Negative on failure
*
* Programmer: Robb Matzke
* Tuesday, January 6, 1998
*
* Modifications:
*
*-------------------------------------------------------------------------
*/
static herr_t
H5O_init_interface(void)
{
FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5O_init_interface);
/*
* Initialize functions that decode messages from symbol table entries.
*/
H5O_fast_g[H5G_CACHED_STAB] = H5O_stab_fast;
FUNC_LEAVE_NOAPI(SUCCEED);
}
/*-------------------------------------------------------------------------
* 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, H5G_entry_t *ent/*out*/)
{
haddr_t header;
herr_t ret_value = SUCCEED; /* return value */
FUNC_ENTER_NOAPI(H5O_create, FAIL)
/* check args */
HDassert(f);
HDassert(ent);
size_hint = H5O_ALIGN(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) + 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, ent, 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 ENT 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 size_hint, H5G_entry_t *ent/*out*/, haddr_t header)
{
H5O_t *oh = NULL;
haddr_t tmp_addr;
herr_t ret_value = SUCCEED; /* return value */
FUNC_ENTER_NOAPI_NOINIT(H5O_new)
/* check args */
HDassert(f);
HDassert(ent);
size_hint = H5O_ALIGN(MAX(H5O_MIN_SIZE, size_hint));
ent->file = f;
ent->header = 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")
oh->cache_info.is_dirty = TRUE;
oh->version = H5O_VERSION;
oh->nlink = 0;
/* create the chunk list and initialize the first chunk */
oh->nchunks = 1;
oh->alloc_nchunks = H5O_NCHUNKS;
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")
tmp_addr = ent->header + (hsize_t)H5O_SIZEOF_HDR(f);
oh->chunk[0].dirty = TRUE;
oh->chunk[0].addr = tmp_addr;
oh->chunk[0].size = size_hint;
if(NULL == (oh->chunk[0].image = H5FL_BLK_CALLOC(chunk_image, size_hint)))
HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
/* create the message list and initialize the first message */
oh->nmesgs = 1;
oh->alloc_nmesgs = H5O_NMESGS;
if(NULL == (oh->mesg = H5FL_SEQ_CALLOC(H5O_mesg_t, (size_t)oh->alloc_nmesgs)))
HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
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_MSGHDR(f);
oh->mesg[0].raw_size = size_hint - H5O_SIZEOF_MSGHDR(f);
oh->mesg[0].chunkno = 0;
/* cache it */
if (H5AC_set(f, dxpl_id, H5AC_OHDR, ent->header, oh) < 0)
HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to cache object header")
/* open it */
if (H5O_open(ent) < 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 H5G_entry_t *obj_ent)
{
herr_t ret_value = SUCCEED;
FUNC_ENTER_NOAPI(H5O_open, FAIL)
/* Check args */
HDassert(obj_ent);
HDassert(obj_ent->file);
#ifdef H5O_DEBUG
if (H5DEBUG(O))
HDfprintf(H5DEBUG(O), "> %a\n", obj_ent->header);
#endif
/* Increment open-lock counters */
obj_ent->file->nopen_objs++;
done:
FUNC_LEAVE_NOAPI(ret_value)
} /* 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(H5G_entry_t *obj_ent)
{
herr_t ret_value = SUCCEED; /* Return value */
FUNC_ENTER_NOAPI(H5O_close, FAIL)
/* Check args */
HDassert(obj_ent);
HDassert(obj_ent->file);
HDassert(obj_ent->file->nopen_objs > 0);
/* Decrement open-lock counters */
--obj_ent->file->nopen_objs;
#ifdef H5O_DEBUG
if (H5DEBUG(O)) {
if (obj_ent->file->file_id < 0 && 1==obj_ent->file->shared->nrefs) {
HDfprintf(H5DEBUG(O), "< %a auto %lu remaining\n",
obj_ent->header,
(unsigned long)(obj_ent->file->nopen_objs));
} else {
HDfprintf(H5DEBUG(O), "< %a\n", obj_ent->header);
}
}
#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(obj_ent->file->nopen_objs == obj_ent->file->mtab.nmounts) {
/* Attempt to close down the file hierarchy */
if(H5F_try_close(obj_ent->file) < 0)
HGOTO_ERROR(H5E_OHDR, H5E_CANTCLOSEFILE, FAIL, "problem attempting file close")
} /* end if */
/* Free the ID to name buffers */
H5G_name_free(obj_ent);
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; /* Return value */
FUNC_ENTER_NOAPI(H5O_reset,FAIL);
/* check args */
assert(type_id < NELMTS(H5O_msg_class_g));
type=H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */
assert(type);
/* Call the "real" reset routine */
if((ret_value=H5O_reset_real(type, native)) < 0)
HGOTO_ERROR(H5E_OHDR, H5E_READERROR, 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 */
assert(type);
if (native) {
if (type->reset) {
if ((type->reset) (native) < 0)
HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "reset method failed");
} else {
HDmemset(native, 0, type->native_size);
}
}
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 = NULL; /* Return value */
FUNC_ENTER_NOAPI(H5O_free, 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" free routine */
ret_value = H5O_free_real(type, mesg);
done:
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 */
assert(type_id < NELMTS(H5O_msg_class_g));
type=H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */
assert(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
*
* Modifications:
*
*-------------------------------------------------------------------------
*/
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 */
assert (type);
assert (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 H5G_entry_t *ent, int adjust, hid_t dxpl_id)
{
H5O_t *oh = NULL;
hbool_t deleted=FALSE; /* Whether the object was deleted as a result of this action */
int ret_value = FAIL;
FUNC_ENTER_NOAPI(H5O_link, FAIL)
/* check args */
HDassert(ent);
HDassert(ent->file);
HDassert(H5F_addr_defined(ent->header));
if(adjust!=0 && 0==(ent->file->intent & H5F_ACC_RDWR))
HGOTO_ERROR (H5E_OHDR, H5E_WRITEERROR, FAIL, "no write intent on file")
/* get header */
if (NULL == (oh = H5AC_protect(ent->file, dxpl_id, H5AC_OHDR, ent->header,
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->cache_info.is_dirty = TRUE;
/* Check if the object should be deleted */
if(oh->nlink == 0) {
/* Check if the object is still open by the user */
if(H5FO_opened(ent->file,ent->header)!=NULL) {
/* Flag the object to be deleted when it's closed */
if(H5FO_mark(ent->file,ent->header,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(ent->file,dxpl_id,oh)<0)
HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, FAIL, "can't delete object from file")
/* Mark the object header as deleted */
deleted=TRUE;
} /* 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(ent->file,ent->header)>0) {
/* Remove "delete me" flag on the object */
if(H5FO_mark(ent->file,ent->header,FALSE)<0)
HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, FAIL, "can't mark object for deletion")
} /* end if */
} /* end if */
oh->nlink += adjust;
oh->cache_info.is_dirty = TRUE;
} /* end if */
/* Set return value */
ret_value = oh->nlink;
done:
if (oh && H5AC_unprotect(ent->file, dxpl_id, H5AC_OHDR, ent->header, oh, deleted) < 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(H5G_entry_t *ent, 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(ent);
HDassert(ent->file);
HDassert(H5F_addr_defined(ent->header));
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(ent, 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(H5G_entry_t *ent, 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(ent);
HDassert(ent->file);
HDassert(H5F_addr_defined(ent->header));
HDassert(type);
/* Load the object header */
if(NULL == (oh = H5AC_protect(ent->file, dxpl_id, H5AC_OHDR, ent->header, 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(ent->file, dxpl_id, H5AC_OHDR, ent->header, oh, FALSE) != 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(H5G_entry_t *ent, unsigned type_id, int sequence, hid_t dxpl_id)
{
const H5O_msg_class_t *type; /* Actual H5O class type for the ID */
htri_t ret_value; /* Return value */
FUNC_ENTER_NOAPI(H5O_exists, FAIL)
HDassert(ent);
HDassert(ent->file);
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" exists routine */
if((ret_value=H5O_exists_real(ent, type, sequence, dxpl_id))<0)
HGOTO_ERROR(H5E_OHDR, H5E_READERROR, FAIL, "unable to verify object header message");
done:
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5O_exists() */
/*-------------------------------------------------------------------------
* Function: H5O_exists_real
*
* 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
*
* Modifications:
*
*-------------------------------------------------------------------------
*/
static htri_t
H5O_exists_real(H5G_entry_t *ent, const H5O_msg_class_t *type, int sequence, hid_t dxpl_id)
{
H5O_t *oh=NULL;
unsigned u;
htri_t ret_value; /* Return value */
FUNC_ENTER_NOAPI_NOINIT(H5O_exists_real)
assert(ent);
assert(ent->file);
assert(type);
assert(sequence>=0);
/* Load the object header */
if (NULL == (oh = H5AC_protect(ent->file, dxpl_id, H5AC_OHDR, ent->header, NULL, NULL, H5AC_READ)))
HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "unable to load object header");
/* 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);
done:
if (oh && H5AC_unprotect(ent->file, dxpl_id, H5AC_OHDR, ent->header, oh, FALSE) != SUCCEED)
HDONE_ERROR(H5E_OHDR, H5E_PROTECT, FAIL, "unable to release object header")
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5O_exists_real() */
/*-------------------------------------------------------------------------
* 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 H5G_entry_t *ent, 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(ent);
HDassert(ent->file);
HDassert(H5F_addr_defined(ent->header));
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(ent, 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 H5G_entry_t *ent, const H5O_msg_class_t *type, int sequence, void *mesg, hid_t dxpl_id)
{
H5O_t *oh = NULL;
int idx;
const H5G_cache_t *cache = NULL;
H5G_type_t cache_type;
void *ret_value = NULL;
FUNC_ENTER_NOAPI_NOINIT(H5O_read_real)
/* check args */
HDassert(ent);
HDassert(ent->file);
HDassert(H5F_addr_defined(ent->header));
HDassert(type);
HDassert(sequence >= 0);
/* can we get it from the symbol table entry? */
cache = H5G_ent_cache(ent, &cache_type);
if (H5O_fast_g[cache_type]) {
ret_value = (H5O_fast_g[cache_type]) (cache, type, mesg);
if (ret_value)
HGOTO_DONE(ret_value);
H5E_clear(); /*don't care, try reading from header */
}
/* copy the message to the user-supplied buffer */
if (NULL == (oh = H5AC_protect(ent->file, dxpl_id, H5AC_OHDR, ent->header, 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(ent->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(ent->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(ent->file, dxpl_id, H5AC_OHDR, ent->header, oh, FALSE) < 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 */
assert(f);
assert(oh);
assert(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;
}
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);
}
/*-------------------------------------------------------------------------
* 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
*
*-------------------------------------------------------------------------
*/
int
H5O_modify(H5G_entry_t *ent, unsigned type_id, int overwrite,
unsigned flags, unsigned update_flags, const void *mesg, 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_modify, FAIL)
/* check args */
HDassert(ent);
HDassert(ent->file);
HDassert(H5F_addr_defined(ent->header));
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));
/* Call the "real" modify routine */
if((ret_value= H5O_modify_real(ent, 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(H5G_entry_t *ent, const H5O_msg_class_t *type, int overwrite,
unsigned flags, unsigned update_flags, const void *mesg, hid_t dxpl_id)
{
H5O_t *oh = NULL;
int sequence;
unsigned idx; /* Index of message to modify */
H5O_mesg_t *idx_msg; /* Pointer to message to modify */
H5O_shared_t sh_mesg;
int ret_value;
FUNC_ENTER_NOAPI_NOINIT(H5O_modify_real)
/* check args */
HDassert(ent);
HDassert(ent->file);
HDassert(H5F_addr_defined(ent->header));
HDassert(type);
HDassert(mesg);
HDassert(0 == (flags & ~H5O_FLAG_BITS));
if (0==(ent->file->intent & H5F_ACC_RDWR))
HGOTO_ERROR (H5E_OHDR, H5E_WRITEERROR, FAIL, "no write intent on file")
if (NULL == (oh = H5AC_protect(ent->file, dxpl_id, H5AC_OHDR, ent->header, 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) {
/* Check if we are trying to create a new message */
if(idx >= oh->nmesgs || sequence != overwrite) {
/* 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 */
else if(!(oh->mesg[idx].flags & H5O_FLAG_SHARED)) {
H5O_mesg_t *curr_msg = &oh->mesg[idx]; /* Message to overwrite */
size_t msg_size; /* Size of modified message */
/* Get the size of the modified message */
msg_size = curr_msg->type->raw_size(ent->file, mesg);
/* Adjust size for alignment, if necessary */
msg_size = H5O_ALIGN(msg_size);
/* Check if message grew */
if(msg_size > curr_msg->raw_size) {
/* Free any native information */
H5O_free_mesg(curr_msg);
/* Change message type to nil and zero it */
curr_msg->type = H5O_MSG_NULL;
HDmemset(curr_msg->raw, 0, curr_msg->raw_size);
/* Indicate that the message was modified */
curr_msg->dirty = TRUE;
/* Indicate that new space should be allocated for the modified message */
sequence = overwrite - 1;
overwrite = -1;
} /* end if */
} /* end if */
} /* end if */
/* Check for creating new message */
if(overwrite < 0) {
/* Create a new message */
if((idx=H5O_new_mesg(ent->file,oh,&flags,type,mesg,&sh_mesg,&type,&mesg,dxpl_id))==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) {
HGOTO_ERROR (H5E_OHDR, H5E_WRITEERROR, FAIL, "unable to modify shared (constant) message")
}
/* Write the information to the message */
if(H5O_write_mesg(oh,idx,type,mesg,flags,update_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(ent->file, oh, FALSE);
/* Set return value */
ret_value = sequence;
done:
if (oh && H5AC_unprotect(ent->file, dxpl_id, H5AC_OHDR, ent->header, oh, FALSE) < 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(H5G_entry_t *ent, hid_t dxpl_id)
{
H5O_t *ret_value; /* Return value */
FUNC_ENTER_NOAPI(H5O_protect, NULL)
/* check args */
HDassert(ent);
HDassert(ent->file);
HDassert(H5F_addr_defined(ent->header));
if(0==(ent->file->intent & H5F_ACC_RDWR))
HGOTO_ERROR (H5E_OHDR, H5E_WRITEERROR, NULL, "no write intent on file")
if (NULL == (ret_value = H5AC_protect(ent->file, dxpl_id, H5AC_OHDR, ent->header, 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(H5G_entry_t *ent, H5O_t *oh, hid_t dxpl_id)
{
herr_t ret_value = SUCCEED; /* Return value */
FUNC_ENTER_NOAPI(H5O_unprotect, FAIL)
/* check args */
HDassert(ent);
HDassert(ent->file);
HDassert(H5F_addr_defined(ent->header));
HDassert(oh);
if(H5AC_unprotect(ent->file, dxpl_id, H5AC_OHDR, ent->header, oh, FALSE) < 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,
const void *mesg)
{
const H5O_msg_class_t *type; /* Actual H5O class type for the ID */
int ret_value; /* Return value */
FUNC_ENTER_NOAPI(H5O_append,FAIL);
/* check args */
assert(f);
assert(oh);
assert(type_id < NELMTS(H5O_msg_class_g));
type=H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */
assert(type);
assert(0==(flags & ~H5O_FLAG_BITS));
assert(mesg);
/* Call the "real" append routine */
if((ret_value=H5O_append_real( f, dxpl_id, oh, type, flags, mesg))<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 idx; /* Index of message to modify */
H5O_shared_t sh_mesg;
int ret_value = FAIL;
FUNC_ENTER_NOAPI_NOINIT(H5O_append_real);
/* check args */
assert(f);
assert(oh);
assert(type);
assert(0==(flags & ~H5O_FLAG_BITS));
assert(mesg);
/* Create a new message */
if((idx=H5O_new_mesg(f,oh,&flags,type,mesg,&sh_mesg,&type,&mesg,dxpl_id))==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)<0)
HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to write message");
/* 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
*
* Modifications:
*
*-------------------------------------------------------------------------
*/
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)
{
size_t size; /* Size of space allocated for object header */
unsigned ret_value=UFAIL; /* Return value */
FUNC_ENTER_NOAPI_NOINIT(H5O_new_mesg);
/* check args */
assert(f);
assert(oh);
assert(flags);
assert(orig_type);
assert(orig_mesg);
assert(sh_mesg);
assert(new_mesg);
assert(new_type);
/* Check for shared message */
if (*flags & H5O_FLAG_SHARED) {
HDmemset(sh_mesg,0,sizeof(H5O_shared_t));
if (NULL==orig_type->get_share)
HGOTO_ERROR (H5E_OHDR, H5E_UNSUPPORTED, UFAIL, "message class is not sharable");
if ((orig_type->get_share)(f, orig_mesg, sh_mesg/*out*/) < 0) {
/*
* If the message isn't shared then turn off the shared bit
* and treat it as an unshared message.
*/
H5E_clear ();
*flags &= ~H5O_FLAG_SHARED;
} else {
/* Change type & message to use shared information */
*new_type=H5O_MSG_SHARED;
*new_mesg=sh_mesg;
} /* 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_MAX_SIZE)
HGOTO_ERROR (H5E_OHDR, H5E_CANTINIT, UFAIL, "object header message is too large");
/* Allocate space in the object headed for the message */
if ((ret_value = H5O_alloc(f, oh, orig_type, size)) == 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_LINK, 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)
{
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 */
assert(oh);
assert(type);
assert(mesg);
/* 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->cache_info.is_dirty = TRUE;
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, H5O_t *oh, hbool_t force)
{
unsigned idx;
time_t now;
size_t size;
herr_t ret_value=SUCCEED; /* Return value */
FUNC_ENTER_NOAPI_NOINIT(H5O_touch_oh);
assert(oh);
/* 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 (idx==oh->nmesgs) {
if (!force)
HGOTO_DONE(SUCCEED); /*nothing to do*/
size = (H5O_MSG_MTIME_NEW->raw_size)(f, &now);
if ((idx=H5O_alloc(f, oh, H5O_MSG_MTIME_NEW, size))==UFAIL)
HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to allocate space for modification time message");
}
/* Update the native part */
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");
}
*((time_t*)(oh->mesg[idx].native)) = now;
oh->mesg[idx].dirty = TRUE;
oh->cache_info.is_dirty = TRUE;
done:
FUNC_LEAVE_NOAPI(ret_value);
}
/*-------------------------------------------------------------------------
* 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(H5G_entry_t *ent, hbool_t force, hid_t dxpl_id)
{
H5O_t *oh = NULL;
herr_t ret_value = SUCCEED; /* Return value */
FUNC_ENTER_NOAPI(H5O_touch, FAIL)
/* check args */
HDassert(ent);
HDassert(ent->file);
HDassert(H5F_addr_defined(ent->header));
if(0==(ent->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(ent->file, dxpl_id, H5AC_OHDR, ent->header, 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(ent->file, oh, force)<0)
HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to update object modificaton time")
done:
if (oh && H5AC_unprotect(ent->file, dxpl_id, H5AC_OHDR, ent->header, oh, FALSE)<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
* <koziol@ncsa.uiuc.edu>
* Tuesday, January 21, 2003
*
*-------------------------------------------------------------------------
*/
herr_t
H5O_bogus_oh(H5F_t *f, H5O_t *oh)
{
int idx;
herr_t ret_value = SUCCEED; /* Return value */
FUNC_ENTER(H5O_bogus_oh, FAIL)
HDassert(f);
HDassert(oh);
/* 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, oh, H5O_MSG_BOGUS, size))<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->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
* <koziol@ncsa.uiuc.edu>
* Tuesday, January 21, 2003
*
*-------------------------------------------------------------------------
*/
herr_t
H5O_bogus(H5G_entry_t *ent, hid_t dxpl_id)
{
H5O_t *oh = NULL;
herr_t ret_value = SUCCEED;
FUNC_ENTER(H5O_bogus, FAIL)
/* check args */
HDassert(ent);
HDassert(ent->file);
HDassert(H5F_addr_defined(ent->header));
/* Verify write access to the file */
if (0==(ent->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(ent->file, dxpl_id, H5AC_OHDR, ent->header, 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, oh)<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, FALSE)<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(H5G_entry_t *ent, 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(ent);
HDassert(ent->file);
HDassert(H5F_addr_defined(ent->header));
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(ent, 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(H5G_entry_t *ent, unsigned type_id,
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(ent);
HDassert(ent->file);
HDassert(H5F_addr_defined(ent->header));
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(ent, type, H5O_ALL, 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_mesg_t *mesg/*in,out*/, unsigned idx, 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, idx, udata->op_data)) < 0)
HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, H5O_ITER_ERROR, "unable to delete file space for object header message")
} /* end if */
else {
/* If there's no callback routine, does the sequence # match? */
if ((int)idx == udata->sequence || H5O_ALL == udata->sequence)
try_remove = TRUE;
} /* end else */
/* Try removing the message, if indicated */
if(try_remove) {
/*
* Keep track of how many times we failed trying to remove constant
* messages.
* (OK to remove constant messages - QAK)
*/
/* Free any space referred to in the file from this message */
if(H5O_delete_mesg(udata->f, udata->dxpl_id, mesg, udata->adj_link) < 0)
HGOTO_ERROR(H5E_OHDR, H5E_CANTDELETE, H5O_ITER_ERROR, "unable to delete file space for object header message")
/* Free any native information */
H5O_free_mesg(mesg);
/* Change message type to nil and zero it */
mesg->type = H5O_MSG_NULL;
HDmemset(mesg->raw, 0, mesg->raw_size);
/* Indicate that the message was modified */
mesg->dirty = TRUE;
/* Indicate that the object header was modified */
*oh_flags_ptr = TRUE;
/* Break out now, if we've found the correct message */
if(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(H5G_entry_t *ent, const H5O_msg_class_t *type, int sequence,
H5O_operator_t op, void *op_data, hbool_t adj_link, hid_t dxpl_id)
{
H5O_iter_ud1_t udata; /* User data for iterator */
herr_t ret_value=SUCCEED; /* Return value */
FUNC_ENTER_NOAPI_NOINIT(H5O_remove_real)
/* check args */
HDassert(ent);
HDassert(ent->file);
HDassert(type);
if (0==(ent->file->intent & H5F_ACC_RDWR))
HGOTO_ERROR (H5E_HEAP, H5E_WRITEERROR, FAIL, "no write intent on file")
/* Set up iterator operator data */
udata.f = ent->file;
udata.dxpl_id = dxpl_id;
udata.sequence = sequence;
udata.nfailed = 0;
udata.op = op;
udata.op_data = op_data;
udata.adj_link = adj_link;
/* Iterate over the messages, deleting appropriate one(s) */
if(H5O_iterate_real(ent, type, H5AC_WRITE, TRUE, (void *)H5O_remove_cb, &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 (H5O_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_extend_chunk
*
* Purpose: Extends a chunk which hasn't been allocated on disk yet
* to make the chunk large enough to contain a message whose
* data size is exactly SIZE bytes (SIZE need not be aligned).
*
* 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: Success: Message index for null message which
* is large enough to hold SIZE bytes.
*
* Failure: Negative
*
* Programmer: Robb Matzke
* matzke@llnl.gov
* Aug 7 1997
*
*-------------------------------------------------------------------------
*/
static unsigned
H5O_alloc_extend_chunk(H5F_t *f, H5O_t *oh, unsigned chunkno, size_t size)
{
unsigned u;
unsigned idx;
size_t delta, old_size;
size_t aligned_size = H5O_ALIGN(size);
uint8_t *old_addr;
unsigned ret_value;
FUNC_ENTER_NOAPI_NOINIT(H5O_alloc_extend_chunk)
/* check args */
HDassert(oh);
HDassert(chunkno < oh->nchunks);
HDassert(size > 0);
if(H5F_addr_defined(oh->chunk[chunkno].addr))
HGOTO_ERROR(H5E_OHDR, H5E_NOSPACE, UFAIL, "chunk is on disk")
/* try to extend a null message */
for (idx=0; idx<oh->nmesgs; idx++) {
if (oh->mesg[idx].chunkno==chunkno) {
if (H5O_NULL_ID == oh->mesg[idx].type->id &&
(oh->mesg[idx].raw + oh->mesg[idx].raw_size ==
oh->chunk[chunkno].image + oh->chunk[chunkno].size)) {
delta = MAX (H5O_MIN_SIZE, aligned_size - oh->mesg[idx].raw_size);
assert (delta=H5O_ALIGN (delta));
/* Reserve space in the file to hold the increased chunk size */
if( H5MF_reserve(f, (hsize_t)delta) < 0 )
HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, UFAIL, "unable to reserve space in file");
oh->mesg[idx].dirty = TRUE;
oh->mesg[idx].raw_size += delta;
old_addr = oh->chunk[chunkno].image;
/* Be careful not to indroduce garbage */
oh->chunk[chunkno].image = H5FL_BLK_REALLOC(chunk_image,old_addr,
(oh->chunk[chunkno].size + delta));
if (NULL==oh->chunk[chunkno].image)
HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, UFAIL, "memory allocation failed");
HDmemset(oh->chunk[chunkno].image + oh->chunk[chunkno].size,
0, delta);
oh->chunk[chunkno].size += delta;
/* adjust raw addresses for messages of this chunk */
if (old_addr != oh->chunk[chunkno].image) {
for (u = 0; u < oh->nmesgs; u++) {
if (oh->mesg[u].chunkno == chunkno)
oh->mesg[u].raw = oh->chunk[chunkno].image +
(oh->mesg[u].raw - old_addr);
}
}
HGOTO_DONE(idx);
}
} /* end if */
}
/* Reserve space in the file */
delta = MAX(H5O_MIN_SIZE, aligned_size+H5O_SIZEOF_MSGHDR(f));
delta = H5O_ALIGN(delta);
if( H5MF_reserve(f, (hsize_t)delta) < 0 )
HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, UFAIL, "unable to reserve space in file")
/* create a new null message */
if(oh->nmesgs >= oh->alloc_nmesgs) {
if(H5O_alloc_msgs(oh, (size_t)0) < 0)
HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, UFAIL, "can't allocate more space for messages")
} /* end if */
idx = oh->nmesgs++;
oh->mesg[idx].type = H5O_MSG_NULL;
oh->mesg[idx].dirty = TRUE;
oh->mesg[idx].native = NULL;
oh->mesg[idx].raw = oh->chunk[chunkno].image +
oh->chunk[chunkno].size +
H5O_SIZEOF_MSGHDR(f);
oh->mesg[idx].raw_size = delta - H5O_SIZEOF_MSGHDR(f);
oh->mesg[idx].chunkno = chunkno;
/* Allocate more memory space for chunk's image */
old_addr = 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_addr,
oh->chunk[chunkno].size);
if(NULL == oh->chunk[chunkno].image)
HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, UFAIL, "memory allocation failed")
/* Wipe new space for chunk */
HDmemset(oh->chunk[chunkno].image + old_size, 0, oh->chunk[chunkno].size - old_size);
/* adjust raw addresses for messages of this chunk */
if (old_addr != oh->chunk[chunkno].image) {
for (u = 0; u < oh->nmesgs; u++) {
if (oh->mesg[u].chunkno == chunkno)
oh->mesg[u].raw = oh->chunk[chunkno].image +
(oh->mesg[u].raw - old_addr);
} /* end if */
} /* end for */
/* Set return value */
ret_value=idx;
done:
FUNC_LEAVE_NOAPI(ret_value)
} /* H5O_alloc_extend_chunk() */
/*-------------------------------------------------------------------------
* Function: H5O_alloc_new_chunk
*
* Purpose: Allocates a new chunk for the object header but doen't
* give the new chunk a file address yet. 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, H5O_t *oh, size_t size)
{
size_t cont_size; /*continuation message size */
int found_null = (-1); /*best fit null 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 */
int chunkno;
unsigned u;
unsigned ret_value; /*return value */
FUNC_ENTER_NOAPI_NOINIT(H5O_alloc_new_chunk)
/* check args */
HDassert(oh);
HDassert(size > 0);
size = H5O_ALIGN(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.
*/
cont_size = H5O_ALIGN (H5F_SIZEOF_ADDR(f) + H5F_SIZEOF_SIZE(f));
for(u = 0; u < oh->nmesgs; u++) {
if (H5O_NULL_ID == oh->mesg[u].type->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 == oh->mesg[u].type->id) {
/*don't consider continuation messages */
} 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_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.
*/
if(found_null < 0)
size += H5O_SIZEOF_MSGHDR(f) + oh->mesg[found_other].raw_size;
/*
* 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(f));
HDassert(size == H5O_ALIGN (size));
/* Reserve space in the file to hold the new chunk */
if( H5MF_reserve(f, (hsize_t)size) < 0 )
HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, UFAIL, "unable to reserve space in file for new chunk");
/*
* Create the new chunk without giving it a file address.
*/
if(oh->nchunks >= oh->alloc_nchunks) {
unsigned na = oh->alloc_nchunks + H5O_NCHUNKS;
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 = HADDR_UNDEF;
oh->chunk[chunkno].size = size;
if (NULL==(oh->chunk[chunkno].image = p = H5FL_BLK_CALLOC(chunk_image,size)))
HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, UFAIL, "memory allocation failed")
/*
* 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")
} /* end if */
/*
* Describe the messages of the new chunk.
*/
if(found_null < 0) {
found_null = u = oh->nmesgs++;
oh->mesg[u].type = H5O_MSG_NULL;
oh->mesg[u].dirty = TRUE;
oh->mesg[u].native = NULL;
oh->mesg[u].raw = oh->mesg[found_other].raw;
oh->mesg[u].raw_size = oh->mesg[found_other].raw_size;
oh->mesg[u].chunkno = oh->mesg[found_other].chunkno;
oh->mesg[found_other].dirty = TRUE;
/* Copy the message to the new location */
HDmemcpy(p + H5O_SIZEOF_MSGHDR(f),
oh->mesg[found_other].raw,
oh->mesg[found_other].raw_size);
oh->mesg[found_other].raw = p + H5O_SIZEOF_MSGHDR(f);
oh->mesg[found_other].chunkno = chunkno;
p += H5O_SIZEOF_MSGHDR(f) + oh->mesg[found_other].raw_size;
size -= H5O_SIZEOF_MSGHDR(f) + oh->mesg[found_other].raw_size;
} /* end if */
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(f);
oh->mesg[idx].raw_size = size - H5O_SIZEOF_MSGHDR(f);
oh->mesg[idx].chunkno = chunkno;
/*
* If the null message that will receive the continuation message
* is larger than the continuation message, then split it into
* two null messages.
*/
if(oh->mesg[found_null].raw_size > cont_size) {
u = oh->nmesgs++;
oh->mesg[u].type = H5O_MSG_NULL;
oh->mesg[u].dirty = TRUE;
oh->mesg[u].native = NULL;
oh->mesg[u].raw = oh->mesg[found_null].raw +
cont_size +
H5O_SIZEOF_MSGHDR(f);
oh->mesg[u].raw_size = oh->mesg[found_null].raw_size -
(cont_size + H5O_SIZEOF_MSGHDR(f));
oh->mesg[u].chunkno = oh->mesg[found_null].chunkno;
oh->mesg[found_null].dirty = TRUE;
oh->mesg[found_null].raw_size = cont_size;
} /* end if */
/*
* Initialize the continuation message.
*/
oh->mesg[found_null].type = H5O_MSG_CONT;
oh->mesg[found_null].dirty = TRUE;
if (NULL==(cont = H5FL_MALLOC(H5O_cont_t)))
HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, UFAIL, "memory allocation failed")
cont->addr = HADDR_UNDEF;
cont->size = 0;
cont->chunkno = chunkno;
oh->mesg[found_null].native = cont;
/* Set return value */
ret_value = idx;
done:
FUNC_LEAVE_NOAPI(ret_value)
} /* H5O_alloc_new_chunk() */
/*-------------------------------------------------------------------------
* 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, H5O_t *oh, const H5O_msg_class_t *type, size_t size)
{
H5O_mesg_t *msg; /* Pointer to newly allocated message */
size_t aligned_size = H5O_ALIGN(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);
/* 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;
} /* end for */
#ifdef LATER
/*
* Perhaps if we join adjacent null messages we could make one
* large enough... we leave this as an exercise for future
* programmers :-) This isn't a high priority because when an
* object header is read from disk the null messages are combined
* anyway.
*/
#endif
/* if we didn't find one, then allocate more header space */
if(idx >= oh->nmesgs) {
unsigned chunkno;
/*
* Look for a chunk which hasn't had disk space allocated yet
* since we can just increase the size of that chunk.
*/
for (chunkno = 0; chunkno < oh->nchunks; chunkno++) {
if ((idx = H5O_alloc_extend_chunk(f, oh, chunkno, size)) != UFAIL)
break;
H5E_clear();
}
/* 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, oh, size)) == UFAIL)
HGOTO_ERROR(H5E_OHDR, H5E_NOSPACE, UFAIL, "unable to create a new object header data chunk")
} /* end if */
/* Set pointer to newly allocated message */
msg = &(oh->mesg[idx]);
/* do we need to split the null message? */
if(msg->raw_size > aligned_size) {
H5O_mesg_t *null_msg; /* Pointer to null message */
size_t mesg_size = aligned_size + H5O_SIZEOF_MSGHDR(f); /* Total size of newly allocated message */
HDassert(msg->raw_size - aligned_size >= H5O_SIZEOF_MSGHDR(f));
/* Check if we need to extend message table */
if(oh->nmesgs >= oh->alloc_nmesgs) {
if(H5O_alloc_msgs(oh, (size_t)0) < 0)
HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, UFAIL, "can't allocate more space for messages")
/* "Retarget" local 'msg' pointer into newly allocated array of messages */
msg = &oh->mesg[idx];
} /* end if */
null_msg = &(oh->mesg[oh->nmesgs++]);
null_msg->type = H5O_MSG_NULL;
null_msg->dirty = TRUE;
null_msg->native = NULL;
null_msg->raw = msg->raw + mesg_size;
null_msg->raw_size = msg->raw_size - mesg_size;
null_msg->chunkno = msg->chunkno;
msg->raw_size = aligned_size;
} /* end if */
/* initialize the new message */
msg->type = type;
msg->dirty = TRUE;
msg->native = NULL;
oh->cache_info.is_dirty = TRUE;
/* Set return value */
ret_value = idx;
done:
FUNC_LEAVE_NOAPI(ret_value)
} /* H5O_alloc() */
#ifdef NOT_YET
/*-------------------------------------------------------------------------
* Function: H5O_share
*
* Purpose: Writes a message to the global heap.
*
* Return: Success: Non-negative, and HOBJ describes the global heap
* object.
*
* Failure: Negative
*
* Programmer: Robb Matzke
* Thursday, April 2, 1998
*
* Modifications:
*
*-------------------------------------------------------------------------
*/
static herr_t
H5O_share (H5F_t *f, hid_t dxpl_id, const H5O_msg_class_t *type, const void *mesg,
H5HG_t *hobj/*out*/)
{
size_t size;
void *buf = NULL;
herr_t ret_value=SUCCEED; /* Return value */
FUNC_ENTER_NOAPI_NOINIT(H5O_share);
/* Check args */
assert (f);
assert (type);
assert (mesg);
assert (hobj);
/* Encode the message put it in the global heap */
if ((size = (type->raw_size)(f, mesg))>0) {
if (NULL==(buf = H5MM_malloc (size)))
HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed");
if ((type->encode)(f, buf, mesg) < 0)
HGOTO_ERROR (H5E_OHDR, H5E_CANTENCODE, FAIL, "unable to encode message");
if (H5HG_insert (f, dxpl_id, size, buf, hobj) < 0)
HGOTO_ERROR (H5E_OHDR, H5E_CANTINIT, FAIL, "unable to store message in global heap");
}
done:
if(buf)
H5MM_xfree (buf);
FUNC_LEAVE_NOAPI(ret_value);
}
#endif /* NOT_YET */
/*-------------------------------------------------------------------------
* 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.
*
* 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)
{
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")
/* Adjust size for alignment, if necessary */
ret_value = H5O_ALIGN(ret_value);
/* Add space for message header */
ret_value += H5O_SIZEOF_MSGHDR(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);
/* Compute the raw data size 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_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, TRUE)<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 - H5O_SIZEOF_HDR(f)), (hsize_t)(oh->chunk[0].size + H5O_SIZEOF_HDR(f))) < 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);
mesg->native = (type->decode) (f, dxpl_id, mesg->raw);
if(NULL == mesg->native)
HGOTO_ERROR(H5E_OHDR, H5E_CANTDECODE, FAIL, "unable to decode message")
} /* end if */
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(H5G_entry_t *ent, 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(ent);
HDassert(ostat);
/* Get the object header information */
if (NULL == (oh = H5AC_protect(ent->file, dxpl_id, H5AC_OHDR, ent->header, 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(ent->file);
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(ent->file) + curr_msg->raw_size;
/* Check for this message being free space */
if(H5O_NULL_ID == curr_msg->type->id)
free_space+= H5O_SIZEOF_MSGHDR(ent->file) + 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(ent->file, dxpl_id, H5AC_OHDR, ent->header, oh, FALSE)<0)
HDONE_ERROR(H5E_OHDR, H5E_PROTECT, FAIL, "unable to release object header")
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5O_get_info() */
/*-------------------------------------------------------------------------
* 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 H5G_entry_t *ent, unsigned type_id, H5O_operator_t op,
void *op_data, 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_iterate, FAIL)
/* check args */
HDassert(ent);
HDassert(ent->file);
HDassert(H5F_addr_defined(ent->header));
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 */
if((ret_value=H5O_iterate_real(ent, type, H5AC_READ, FALSE, (void *)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 H5G_entry_t *ent, const H5O_msg_class_t *type, H5AC_protect_t prot,
hbool_t internal, void *op, void *op_data, hid_t dxpl_id)
{
H5O_t *oh = NULL; /* Pointer to actual object header */
unsigned oh_flags = FALSE; /* 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=0; /* Return value */
FUNC_ENTER_NOAPI_NOINIT(H5O_iterate_real)
/* check args */
HDassert(ent);
HDassert(ent->file);
HDassert(H5F_addr_defined(ent->header));
HDassert(type);
HDassert(op);
/* Protect the object header to iterate over */
if (NULL == (oh = H5AC_protect(ent->file, dxpl_id, H5AC_OHDR, ent->header, 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; idx++, idx_msg++) {
if (type->id == idx_msg->type->id) {
/*
* Decode the message if necessary. If the message is shared then decode
* a shared message, ignoring the message type.
*/
LOAD_NATIVE(ent->file, dxpl_id, idx_msg, FAIL)
/* Check for making an "internal" (i.e. within the H5O package) callback */
if(internal) {
/* Call the "internal" iterator callback */
if((ret_value = ((H5O_operator_int_t)op)(idx_msg, sequence, &oh_flags, op_data)) != 0)
break;
} /* end if */
else {
/* Call the iterator callback */
if((ret_value = ((H5O_operator_t)op)(idx_msg->native, sequence, op_data)) != 0)
break;
} /* end else */
/* Increment sequence value for message type */
sequence++;
} /* end if */
} /* end for */
/* Check if object header was modified */
if(oh_flags) {
/* Shouldn't be able to modify object header if we don't have write access */
HDassert(prot == H5AC_WRITE);
oh->cache_info.is_dirty = TRUE;
H5O_touch_oh(ent->file, oh, FALSE);
} /* end if */
done:
if (oh && H5AC_unprotect(ent->file, dxpl_id, H5AC_OHDR, ent->header, oh, FALSE) < 0)
HDONE_ERROR(H5E_OHDR, H5E_PROTECT, FAIL, "unable to release object header")
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5O_iterate_real() */
/*-------------------------------------------------------------------------
* 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 */
assert(type_id < NELMTS(H5O_msg_class_g));
type=H5O_msg_class_g[type_id]; /* map the type ID to the actual type object */
assert(type);
assert(type->debug);
assert(f);
assert(mesg);
assert(stream);
assert(indent >= 0);
assert(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
*
* 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;
unsigned i, chunkno;
size_t mesg_total = 0, chunk_total = 0;
int *sequence;
haddr_t tmp_addr;
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, 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 */
HDfprintf(stream, "%*sObject Header...\n", indent, "");
HDfprintf(stream, "%*s%-*s %d\n", indent, "", fwidth,
"Dirty:",
(int) (oh->cache_info.is_dirty));
HDfprintf(stream, "%*s%-*s %d\n", indent, "", fwidth,
"Version:",
(int) (oh->version));
HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
"Header size (in bytes):",
(unsigned) H5O_SIZEOF_HDR(f));
HDfprintf(stream, "%*s%-*s %d\n", indent, "", fwidth,
"Number of links:",
(int) (oh->nlink));
HDfprintf(stream, "%*s%-*s %u (%u)\n", indent, "", fwidth,
"Number of messages (allocated):",
(unsigned) (oh->nmesgs), (unsigned) (oh->alloc_nmesgs));
HDfprintf(stream, "%*s%-*s %u (%u)\n", indent, "", fwidth,
"Number of chunks (allocated):",
(unsigned) (oh->nchunks), (unsigned) (oh->alloc_nchunks));
/* debug each chunk */
for (i=0, chunk_total=0; i < oh->nchunks; i++) {
chunk_total += oh->chunk[i].size;
HDfprintf(stream, "%*sChunk %d...\n", indent, "", i);
HDfprintf(stream, "%*s%-*s %d\n", indent + 3, "", MAX(0, fwidth - 3),
"Dirty:",
(int) (oh->chunk[i].dirty));
HDfprintf(stream, "%*s%-*s %a\n", indent + 3, "", MAX(0, fwidth - 3),
"Address:", oh->chunk[i].addr);
tmp_addr = addr + (hsize_t)H5O_SIZEOF_HDR(f);
if (0 == i && H5F_addr_ne(oh->chunk[i].addr, tmp_addr))
HDfprintf(stream, "*** WRONG ADDRESS!\n");
HDfprintf(stream, "%*s%-*s %lu\n", indent + 3, "", MAX(0, fwidth - 3),
"Size in bytes:",
(unsigned long) (oh->chunk[i].size));
}
/* 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(f) + 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;
}
/* 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 %d\n", indent+3, "", MAX (0, fwidth-3),
"Dirty:",
(int)(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);
}
HDfprintf(stream, "%*s%-*s %lu bytes\n", indent+3, "", MAX(0,fwidth-3),
"Raw size in obj header:",
(unsigned long) (oh->mesg[i].raw_size));
HDfprintf(stream, "%*s%-*s %d\n", indent + 3, "", MAX(0, fwidth - 3),
"Chunk number:",
(int) (oh->mesg[i].chunkno));
chunkno = oh->mesg[i].chunkno;
if (chunkno >= oh->nchunks)
HDfprintf(stream, "*** BAD CHUNK NUMBER\n");
HDfprintf(stream, "%*s%-*s %u\n", indent + 3, "", MAX(0, fwidth - 3),
"Raw data offset in chunk:",
(unsigned) (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;
}
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<No info for this message>\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 = NULL;
mesg = H5O_read_real(&(shared->ent), oh->mesg[i].type, 0, NULL, dxpl_id);
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);
}
}
sequence = H5MM_xfree(sequence);
if (mesg_total != chunk_total)
HDfprintf(stream, "*** TOTAL SIZE DOES NOT MATCH ALLOCATED SIZE!\n");
done:
if (oh && H5AC_unprotect(f, dxpl_id, H5AC_OHDR, addr, oh, FALSE) < 0)
HDONE_ERROR(H5E_OHDR, H5E_PROTECT, FAIL, "unable to release object header")
FUNC_LEAVE_NOAPI(ret_value)
}
syntax highlighted by Code2HTML, v. 0.9.1