summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--MANIFEST1
-rw-r--r--src/H5O.c34
-rw-r--r--src/H5Oalloc.c209
-rw-r--r--src/H5Ocache.c61
-rw-r--r--src/H5Ocopy.c68
-rw-r--r--src/H5Opkg.h9
-rw-r--r--src/H5Oprivate.h8
-rw-r--r--src/H5Orefcount.c324
-rwxr-xr-xsrc/Makefile.am3
-rw-r--r--src/Makefile.in5
-rwxr-xr-xtest/objcopy.c4
-rw-r--r--test/stab.c8
-rw-r--r--test/tattr.c88
-rw-r--r--test/tfile.c2
-rw-r--r--tools/testfiles/h5copytst.out.ls68
-rw-r--r--tools/testfiles/h5mkgrp_nested.ls4
-rw-r--r--tools/testfiles/h5mkgrp_nested_latest.ls4
-rw-r--r--tools/testfiles/h5mkgrp_nested_mult.ls8
-rw-r--r--tools/testfiles/h5mkgrp_nested_mult_latest.ls8
-rw-r--r--tools/testfiles/h5mkgrp_several.ls4
-rw-r--r--tools/testfiles/h5mkgrp_several_latest.ls4
-rw-r--r--tools/testfiles/h5mkgrp_single.ls2
-rw-r--r--tools/testfiles/h5mkgrp_single_latest.ls2
23 files changed, 710 insertions, 218 deletions
diff --git a/MANIFEST b/MANIFEST
index 806dd35..d457145 100644
--- a/MANIFEST
+++ b/MANIFEST
@@ -608,6 +608,7 @@
./src/H5Opline.c
./src/H5Oprivate.h
./src/H5Opublic.h
+./src/H5Orefcount.c
./src/H5Osdspace.c
./src/H5Oshared.c
./src/H5Oshared.h
diff --git a/src/H5O.c b/src/H5O.c
index d2ff41d..5f3e507 100644
--- a/src/H5O.c
+++ b/src/H5O.c
@@ -103,6 +103,7 @@ const H5O_msg_class_t *const H5O_msg_class_g[] = {
H5O_MSG_BTREEK, /*0x0013 Non-default v1 B-tree 'K' values */
H5O_MSG_DRVINFO, /*0x0014 Driver info settings */
H5O_MSG_AINFO, /*0x0015 Attribute information */
+ H5O_MSG_REFCOUNT, /*0x0016 Object's ref. count */
};
/* Header object ID to class mapping */
@@ -989,8 +990,7 @@ H5O_link(const H5O_loc_t *loc, int adjust, hid_t dxpl_id)
HGOTO_ERROR(H5E_OHDR, H5E_WRITEERROR, FAIL, "no write intent on file")
/* get header */
- if(NULL == (oh = H5AC_protect(loc->file, dxpl_id, H5AC_OHDR, loc->addr,
- NULL, NULL, H5AC_WRITE)))
+ if(NULL == (oh = H5AC_protect(loc->file, dxpl_id, H5AC_OHDR, loc->addr, NULL, NULL, H5AC_WRITE)))
HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "unable to load object header")
/* adjust link count */
@@ -1033,6 +1033,36 @@ H5O_link(const H5O_loc_t *loc, int adjust, hid_t dxpl_id)
oh_flags |= H5AC__DIRTIED_FLAG;
} /* end if */
+ /* Check for operations on refcount message */
+ if(oh->version > H5O_VERSION_1) {
+ /* Check if the object has a refcount message already */
+ if(oh->has_refcount_msg) {
+ /* Check for removing refcount message */
+ if(oh->nlink <= 1) {
+ if(H5O_msg_remove_real(loc->file, oh, H5O_MSG_REFCOUNT, H5O_ALL, NULL, NULL, TRUE, dxpl_id) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTDELETE, FAIL, "unable to delete refcount message")
+ oh->has_refcount_msg = FALSE;
+ } /* end if */
+ /* Update refcount message with new link count */
+ else {
+ H5O_refcount_t refcount = oh->nlink;
+
+ if(H5O_msg_write_real(loc->file, dxpl_id, oh, H5O_MSG_REFCOUNT, H5O_MSG_FLAG_DONTSHARE, 0, &refcount) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTUPDATE, FAIL, "unable to update refcount message")
+ } /* end else */
+ } /* end if */
+ else {
+ /* Check for adding refcount message to object */
+ if(oh->nlink > 1) {
+ H5O_refcount_t refcount = oh->nlink;
+
+ if(H5O_msg_append_real(loc->file, dxpl_id, oh, H5O_MSG_REFCOUNT, H5O_MSG_FLAG_DONTSHARE, 0, &refcount) < 0)
+ HGOTO_ERROR(H5E_ATTR, H5E_CANTINSERT, FAIL, "unable to create new refcount message")
+ oh->has_refcount_msg = TRUE;
+ } /* end if */
+ } /* end else */
+ } /* end if */
+
/* Set return value */
ret_value = oh->nlink;
diff --git a/src/H5Oalloc.c b/src/H5Oalloc.c
index b03a774..ce20a27 100644
--- a/src/H5Oalloc.c
+++ b/src/H5Oalloc.c
@@ -632,6 +632,15 @@ done:
*
* SIZE need not be aligned.
*
+ * Note: The algorithm for finding a message to replace with a
+ * continuation message is still fairly limited. It's possible
+ * that two (or more) messages smaller than a continuation message
+ * might occupy a chunk and need to be moved in order to make
+ * room for the continuation message.
+ *
+ * Also, we aren't checking for NULL messages in front of another
+ * message right now...
+ *
* 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
@@ -651,11 +660,20 @@ H5O_alloc_new_chunk(H5F_t *f,
H5O_t *oh,
size_t size)
{
+ /* Struct for storing information about "best" messages to allocate from */
+ typedef struct {
+ int msgno; /* Index in message array */
+ size_t gap_size; /* Size of any "gap" in the chunk immediately after message */
+ size_t null_size; /* Size of any null message in the chunk immediately after message */
+ size_t total_size; /* Total size of "available" space around message */
+ unsigned null_msgno; /* Message index of null message immediately after message */
+ } alloc_info;
+
+ H5O_mesg_t *curr_msg; /* Pointer to current message to operate on */
size_t cont_size; /*continuation message size */
- int found_null = (-1); /*best fit null message */
- int found_attr = (-1); /*best fit attribute message */
- int found_link = (-1); /*best fit link message */
- int found_other = (-1); /*best fit other message */
+ int found_null = (-1); /* Best fit null message */
+ alloc_info found_attr = {-1, 0, 0, 0, 0}; /* Best fit attribute message */
+ alloc_info found_other = {-1, 0, 0, 0, 0}; /* Best fit other message */
unsigned idx; /*message number */
uint8_t *p = NULL; /*ptr into new chunk */
H5O_cont_t *cont = NULL; /*native continuation message */
@@ -677,81 +695,114 @@ H5O_alloc_new_chunk(H5F_t *f,
* that could be moved to make room for the continuation message.
*
* Don't ever move continuation message from one chunk to another.
- * Prioritize link messages moving to later chunks, instead of
- * more "important" messages.
+ *
* Avoid moving attributes when possible to preserve their
* ordering (although ordering is *not* guaranteed!).
*
*/
cont_size = H5O_ALIGN_OH(oh, H5F_SIZEOF_ADDR(f) + H5F_SIZEOF_SIZE(f));
- for(u = 0; u < oh->nmesgs; u++) {
- int msg_id = oh->mesg[u].type->id; /* Temp. copy of message type ID */
+ for(u = 0, curr_msg = &oh->mesg[0]; u < oh->nmesgs; u++, curr_msg++) {
+ if(curr_msg->type->id == H5O_NULL_ID) {
+ if(cont_size == curr_msg->raw_size) {
+ found_null = u;
+ break;
+ } /* end if */
+ else if(curr_msg->raw_size > cont_size &&
+ (found_null < 0 || curr_msg->raw_size < oh->mesg[found_null].raw_size))
+ found_null = u;
+ } /* end if */
+ else if(curr_msg->type->id == H5O_CONT_ID) {
+ /* Don't consider continuation messages (for now) */
+ } /* end if */
+ else {
+ unsigned msg_chunkno = curr_msg->chunkno; /* Chunk that the message is in */
+ uint8_t *end_chunk_data = (oh->chunk[msg_chunkno].image + oh->chunk[msg_chunkno].size) - (H5O_SIZEOF_CHKSUM_OH(oh) + oh->chunk[msg_chunkno].gap); /* End of message data in chunk */
+ uint8_t *end_msg = curr_msg->raw + curr_msg->raw_size; /* End of current message */
+ size_t gap_size = 0; /* Size of gap after current message */
+ size_t null_size = 0; /* Size of NULL message after current message */
+ unsigned null_msgno; /* Index of NULL message after current message */
+ size_t total_size; /* Total size of available space "around" current message */
+
+ /* Check if the message is the last one in the chunk */
+ if(end_msg == end_chunk_data)
+ gap_size = oh->chunk[msg_chunkno].gap;
+ else {
+ H5O_mesg_t *tmp_msg; /* Temp. pointer to message to operate on */
+ unsigned v; /* Local index variable */
+
+ /* Check for null message after this message, in same chunk */
+ for(v = 0, tmp_msg = &oh->mesg[0]; v < oh->nmesgs; v++, tmp_msg++) {
+ if(tmp_msg->type->id == H5O_NULL_ID && (tmp_msg->raw - H5O_SIZEOF_MSGHDR_OH(oh)) == end_msg) {
+ null_msgno = v;
+ null_size = H5O_SIZEOF_MSGHDR_OH(oh) + tmp_msg->raw_size;
+ break;
+ } /* end if */
- if(H5O_NULL_ID == msg_id) {
- if(cont_size == oh->mesg[u].raw_size) {
- found_null = u;
- break;
- } else if(oh->mesg[u].raw_size >= cont_size &&
- (found_null < 0 ||
- oh->mesg[u].raw_size < oh->mesg[found_null].raw_size)) {
- found_null = u;
- }
- } else if(H5O_CONT_ID == msg_id) {
- /*don't consider continuation messages */
- } else if(H5O_ATTR_ID == msg_id) {
- if(oh->mesg[u].raw_size >= cont_size &&
- (found_attr < 0 ||
- oh->mesg[u].raw_size < oh->mesg[found_attr].raw_size))
- found_attr = u;
- } else if(H5O_LINK_ID == msg_id) {
- if(oh->mesg[u].raw_size >= cont_size &&
- (found_link < 0 ||
- oh->mesg[u].raw_size < oh->mesg[found_link].raw_size))
- found_link = u;
- } else {
- if(oh->mesg[u].raw_size >= cont_size &&
- (found_other < 0 ||
- oh->mesg[u].raw_size < oh->mesg[found_other].raw_size))
- found_other = u;
- } /* end else */
+ /* XXX: Should also check for NULL message in front of current message... */
+
+ } /* end for */
+ } /* end else */
+
+ /* Add up current message's total available space */
+ total_size = curr_msg->raw_size + gap_size + null_size;
+
+ /* Check if message is large enough to hold continuation info */
+ if(total_size >= cont_size) {
+ if(curr_msg->type->id == H5O_ATTR_ID) {
+ if(found_attr.msgno < 0 || total_size < found_attr.total_size) {
+ found_attr.msgno = u;
+ found_attr.gap_size = gap_size;
+ found_attr.null_size = null_size;
+ found_attr.total_size = total_size;
+ found_attr.null_msgno = null_msgno;
+ } /* end if */
+ } /* end if */
+ else {
+ if(found_other.msgno < 0 || total_size < found_other.total_size) {
+ found_other.msgno = u;
+ found_other.gap_size = gap_size;
+ found_other.null_size = null_size;
+ found_other.total_size = total_size;
+ found_other.null_msgno = null_msgno;
+ } /* end if */
+ } /* end else */
+ } /* end if */
+ } /* end else */
} /* end for */
- HDassert(found_null >= 0 || found_attr >= 0 || found_link >= 0 || found_other >= 0);
+ if(found_null < 0 && found_attr.msgno < 0 && found_other.msgno < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, UFAIL, "unable to locate message to move")
/*
* If we must move some other message to make room for the null
* message, then make sure the new chunk has enough room for that
* other message.
*
- * Move link messages first, then other messages, and attributes
- * only as a last resort.
+ * Move other messages first, and attributes only as a last resort.
*
*/
if(found_null < 0) {
- if(found_link >= 0)
- found_other = found_link;
-
- if(found_other < 0)
+ if(found_other.msgno < 0)
found_other = found_attr;
- HDassert(found_other >= 0);
- size += H5O_SIZEOF_MSGHDR_OH(oh) + oh->mesg[found_other].raw_size;
+ HDassert(found_other.msgno >= 0);
+ size += H5O_SIZEOF_MSGHDR_OH(oh) + oh->mesg[found_other.msgno].raw_size;
} /* end if */
/*
+ * The total chunk size must include the requested space plus enough
+ * for the message header. This must be at least some minimum and
+ * aligned propertly.
+ */
+ size = MAX(H5O_MIN_SIZE, size + H5O_SIZEOF_MSGHDR_OH(oh));
+ HDassert(size == H5O_ALIGN_OH(oh, size));
+
+ /*
* The total chunk size must include enough space for the checksum
* on the chunk and the continuation chunk magic #. (which are only present
* in later versions of the object header)
*/
size += H5O_SIZEOF_CHKHDR_OH(oh);
- /*
- * The total chunk size must include the requested space plus enough
- * for the message header. This must be at least some minimum and a
- * multiple of the alignment size.
- */
- size = MAX(H5O_MIN_SIZE, size + H5O_SIZEOF_MSGHDR_OH(oh));
- HDassert(size == H5O_ALIGN_OH(oh, size));
-
/* allocate space in file to hold the new chunk */
new_chunk_addr = H5MF_alloc(f, H5FD_MEM_OHDR, dxpl_id, (hsize_t)size);
if(HADDR_UNDEF == new_chunk_addr)
@@ -806,22 +857,51 @@ H5O_alloc_new_chunk(H5F_t *f,
null_msg->type = H5O_MSG_NULL;
null_msg->dirty = TRUE;
null_msg->native = NULL;
- null_msg->raw = oh->mesg[found_other].raw;
- null_msg->raw_size = oh->mesg[found_other].raw_size;
- null_msg->chunkno = oh->mesg[found_other].chunkno;
+ null_msg->raw = oh->mesg[found_other.msgno].raw;
+ null_msg->raw_size = oh->mesg[found_other.msgno].raw_size;
+ null_msg->chunkno = oh->mesg[found_other.msgno].chunkno;
- /* Copy the message to move to its new location */
+ /* Copy the message to move (& its prefix) to its new location */
/* (Chunk is already dirty, no need to mark it) */
- HDmemcpy(p, oh->mesg[found_other].raw - H5O_SIZEOF_MSGHDR_OH(oh),
- oh->mesg[found_other].raw_size + H5O_SIZEOF_MSGHDR_OH(oh));
+ HDmemcpy(p, oh->mesg[found_other.msgno].raw - H5O_SIZEOF_MSGHDR_OH(oh),
+ oh->mesg[found_other.msgno].raw_size + H5O_SIZEOF_MSGHDR_OH(oh));
- /* Switch message to point to new location */
- oh->mesg[found_other].raw = p + H5O_SIZEOF_MSGHDR_OH(oh);
- oh->mesg[found_other].chunkno = chunkno;
+ /* Switch moved message to point to new location */
+ oh->mesg[found_other.msgno].raw = p + H5O_SIZEOF_MSGHDR_OH(oh);
+ oh->mesg[found_other.msgno].chunkno = chunkno;
/* Account for copied message in new chunk */
- p += H5O_SIZEOF_MSGHDR_OH(oh) + oh->mesg[found_other].raw_size;
- size -= H5O_SIZEOF_MSGHDR_OH(oh) + oh->mesg[found_other].raw_size;
+ p += H5O_SIZEOF_MSGHDR_OH(oh) + oh->mesg[found_other.msgno].raw_size;
+ size -= H5O_SIZEOF_MSGHDR_OH(oh) + oh->mesg[found_other.msgno].raw_size;
+
+ /* Add any available space after the message to move to the new null message */
+ if(found_other.gap_size > 0) {
+ /* Absorb a gap after the moved message */
+ HDassert(oh->chunk[null_msg->chunkno].gap == found_other.gap_size);
+ null_msg->raw_size += found_other.gap_size;
+ oh->chunk[null_msg->chunkno].gap = 0;
+ } /* end if */
+ else if(found_other.null_size > 0) {
+ H5O_mesg_t *old_null_msg = &oh->mesg[found_other.null_msgno]; /* Pointer to NULL message to eliminate */
+
+ /* Absorb a null message after the moved message */
+ HDassert((null_msg->raw + null_msg->raw_size) == (old_null_msg->raw - H5O_SIZEOF_MSGHDR_OH(oh)));
+ null_msg->raw_size += found_other.null_size;
+
+ /* Release any information/memory for message */
+ H5O_msg_free_mesg(old_null_msg);
+
+ /* Remove null message from list of messages */
+ if(found_other.null_msgno < (oh->nmesgs - 1))
+ HDmemmove(old_null_msg, old_null_msg + 1, ((oh->nmesgs - 1) - found_other.null_msgno) * sizeof(H5O_mesg_t));
+
+ /* Decrement # of messages */
+ /* (Don't bother reducing size of message array for now -QAK) */
+ oh->nmesgs--;
+
+ /* Adjust message index for new NULL message */
+ found_null--;
+ } /* end if */
} /* end if */
HDassert(found_null >= 0);
@@ -832,8 +912,7 @@ H5O_alloc_new_chunk(H5F_t *f,
oh->mesg[idx].dirty = TRUE;
oh->mesg[idx].native = NULL;
oh->mesg[idx].raw = p + H5O_SIZEOF_MSGHDR_OH(oh);
- oh->mesg[idx].raw_size = size -
- (H5O_SIZEOF_CHKHDR_OH(oh) + H5O_SIZEOF_MSGHDR_OH(oh));
+ oh->mesg[idx].raw_size = size - (H5O_SIZEOF_CHKHDR_OH(oh) + H5O_SIZEOF_MSGHDR_OH(oh));
oh->mesg[idx].chunkno = chunkno;
/* Initialize the continuation information */
diff --git a/src/H5Ocache.c b/src/H5Ocache.c
index 142d23f..2a76526 100644
--- a/src/H5Ocache.c
+++ b/src/H5Ocache.c
@@ -44,8 +44,8 @@
/* Set the object header size to speculatively read in */
/* (needs to be more than the object header prefix size to work at all and
- * should be larger than the default dataset object header to save the
- * extra I/O operations) */
+ * should be larger than the largest object type's default object header
+ * size to save the extra I/O operations) */
#define H5O_SPEC_READ_SIZE 512
@@ -283,28 +283,10 @@ H5O_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void UNUSED * _udata1,
/* Number of messages (to allocate initially) */
nmesgs = 1;
- } /* end if */
- else {
- /* Version */
- oh->version = *p++;
- if(H5O_VERSION_1 != oh->version)
- HGOTO_ERROR(H5E_OHDR, H5E_VERSION, NULL, "bad object header version number")
-
- /* Flags */
- oh->flags = H5O_CRT_OHDR_FLAGS_DEF;
-
- /* Reserved */
- p++;
-
- /* Number of messages */
- UINT16DECODE(p, nmesgs);
- } /* end else */
- /* Link count */
- UINT32DECODE(p, oh->nlink);
+ /* Number of links to object (unless overridden by refcount message) */
+ oh->nlink = 1;
- /* Version-specific fields */
- if(oh->version > H5O_VERSION_1) {
/* Time fields */
if(oh->flags & H5O_HDR_STORE_TIMES) {
UINT32DECODE(p, oh->atime);
@@ -348,6 +330,23 @@ H5O_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void UNUSED * _udata1,
} /* end switch */
} /* end if */
else {
+ /* Version */
+ oh->version = *p++;
+ if(H5O_VERSION_1 != oh->version)
+ HGOTO_ERROR(H5E_OHDR, H5E_VERSION, NULL, "bad object header version number")
+
+ /* Flags */
+ oh->flags = H5O_CRT_OHDR_FLAGS_DEF;
+
+ /* Reserved */
+ p++;
+
+ /* Number of messages */
+ UINT16DECODE(p, nmesgs);
+
+ /* Link count */
+ UINT32DECODE(p, oh->nlink);
+
/* Reset unused time fields */
oh->atime = oh->mtime = oh->ctime = oh->btime = 0;
@@ -592,6 +591,21 @@ H5O_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void UNUSED * _udata1,
chunk_addr = cont->addr;
chunk_size = cont->size;
} /* end if */
+ /* Check if next message to examine is a ref. count message */
+ else if(H5O_REFCOUNT_ID == oh->mesg[curmesg].type->id) {
+ H5O_refcount_t *refcount;
+
+ /* Decode ref. count message */
+ HDassert(oh->version > H5O_VERSION_1);
+ refcount = (H5O_refcount_t *)(H5O_MSG_REFCOUNT->decode)(f, dxpl_id, 0, oh->mesg[curmesg].raw);
+
+ /* Save 'native' form of ref. count message */
+ oh->mesg[curmesg].native = refcount;
+
+ /* Set object header values */
+ oh->has_refcount_msg = TRUE;
+ oh->nlink = *refcount;
+ } /* end if */
} /* end for */
} /* end while */
@@ -681,9 +695,6 @@ H5O_assert(oh);
/* Flags */
*p++ = oh->flags;
- /* Link count */
- UINT32ENCODE(p, oh->nlink);
-
/* Time fields */
if(oh->flags & H5O_HDR_STORE_TIMES) {
UINT32ENCODE(p, oh->atime);
diff --git a/src/H5Ocopy.c b/src/H5Ocopy.c
index ee2a63e..ec51f00 100644
--- a/src/H5Ocopy.c
+++ b/src/H5Ocopy.c
@@ -295,12 +295,15 @@ H5O_copy_header_real(const H5O_loc_t *oloc_src, H5O_loc_t *oloc_dst /*out */,
haddr_t addr_new = HADDR_UNDEF;
hbool_t *deleted = NULL; /* Array of flags indicating whether messages should be copied */
size_t null_msgs; /* Number of NULL messages found in each loop */
+ size_t orig_dst_msgs; /* Original # of messages in dest. object */
H5O_mesg_t *mesg_src; /* Message in source object header */
H5O_mesg_t *mesg_dst; /* Message in source object header */
const H5O_msg_class_t *copy_type; /* Type of message to use for copying */
const H5O_obj_class_t *obj_class = NULL; /* Type of object we are copying */
void *udata = NULL; /* User data for passing to message callbacks */
size_t dst_oh_size; /* Total size of the destination OH */
+ size_t dst_oh_null; /* Size of the null message to add to destination OH */
+ unsigned dst_oh_gap; /* Size of the gap in chunk #0 of destination OH */
uint8_t *current_pos; /* Current position in destination image */
size_t msghdr_size;
hbool_t shared; /* Whether copy_file callback created a shared message */
@@ -535,6 +538,27 @@ H5O_copy_header_real(const H5O_loc_t *oloc_src, H5O_loc_t *oloc_dst /*out */,
oh_dst->flags |= H5O_HDR_CHUNK0_2;
} /* end if */
+ /* Check if the chunk's data portion is too small */
+ dst_oh_gap = dst_oh_null = 0;
+ if(dst_oh_size < H5O_MIN_SIZE) {
+ size_t delta = (H5O_MIN_SIZE - dst_oh_size); /* Delta in chunk size needed */
+
+ /* Sanity check */
+ HDassert((oh_dst->flags & H5O_HDR_CHUNK0_SIZE) == H5O_HDR_CHUNK0_1);
+
+ /* Determine whether to create gap or NULL message */
+ if(delta < H5O_SIZEOF_MSGHDR_OH(oh_dst))
+ dst_oh_gap = delta;
+ else
+ dst_oh_null = delta;
+
+ /* Increase destination object header size */
+ dst_oh_size += delta;
+
+ /* Sanity check */
+ HDassert(dst_oh_size <= 255);
+ } /* end if */
+
/* Add in destination's object header size now */
dst_oh_size += H5O_SIZEOF_HDR(oh_dst);
@@ -550,7 +574,7 @@ H5O_copy_header_real(const H5O_loc_t *oloc_src, H5O_loc_t *oloc_dst /*out */,
/* Set dest. chunk information */
oh_dst->chunk[0].dirty = TRUE;
oh_dst->chunk[0].size = dst_oh_size;
- oh_dst->chunk[0].gap = 0;
+ oh_dst->chunk[0].gap = dst_oh_gap;
/* Set up raw pointers and copy messages that didn't need special
* treatment. This has to happen after the destination header has been
@@ -568,7 +592,7 @@ H5O_copy_header_real(const H5O_loc_t *oloc_src, H5O_loc_t *oloc_dst /*out */,
HDmemcpy(current_pos, H5O_HDR_MAGIC, (size_t)H5O_SIZEOF_MAGIC);
current_pos += H5O_SIZEOF_HDR(oh_dst) - H5O_SIZEOF_CHKSUM_OH(oh_dst);
- /* Copy each message that wasn't dirtied above */
+ /* Loop through destination messages, updating their "raw" info */
null_msgs = 0;
for(mesgno = 0; mesgno < oh_dst->nmesgs; mesgno++) {
/* Skip any deleted or NULL messages in the source unless the
@@ -585,17 +609,43 @@ H5O_copy_header_real(const H5O_loc_t *oloc_src, H5O_loc_t *oloc_dst /*out */,
mesg_src = &(oh_src->mesg[mesgno + null_msgs]);
mesg_dst = &(oh_dst->mesg[mesgno]);
- if(!mesg_dst->dirty) {
+ /* Copy each message that wasn't dirtied above */
+ if(!mesg_dst->dirty)
/* Copy the message header plus the message's raw data. */
- HDmemcpy(current_pos, mesg_src->raw - msghdr_size,
- msghdr_size + mesg_src->raw_size);
- } /* end if */
+ HDmemcpy(current_pos, mesg_src->raw - msghdr_size, msghdr_size + mesg_src->raw_size);
+
+ /* Set message's raw pointer to destination chunk's new "image" */
mesg_dst->raw = current_pos + msghdr_size;
+
+ /* Move to location where next message should go */
current_pos += mesg_dst->raw_size + msghdr_size;
} /* end for */
+ /* Save this in case more messages are added during NULL message checking */
+ orig_dst_msgs = oh_dst->nmesgs;
+
+ /* Check if we need to add a NULL message to this header */
+ if(dst_oh_null > 0) {
+ unsigned null_idx; /* Index of new NULL message */
+
+ /* Make sure we have enough space for new NULL message */
+ if(oh_dst->nmesgs + 1 > oh_dst->alloc_nmesgs)
+ if(H5O_alloc_msgs(oh_dst, (size_t)1) < 0)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate more space for messages")
+
+ /* Create null message for [rest of] space in new chunk */
+ /* (account for chunk's magic # & checksum) */
+ null_idx = oh_dst->nmesgs++;
+ oh_dst->mesg[null_idx].type = H5O_MSG_NULL;
+ oh_dst->mesg[null_idx].dirty = TRUE;
+ oh_dst->mesg[null_idx].native = NULL;
+ oh_dst->mesg[null_idx].raw = current_pos + msghdr_size;
+ oh_dst->mesg[null_idx].raw_size = dst_oh_null - msghdr_size;
+ oh_dst->mesg[null_idx].chunkno = 0;
+ } /* end if */
+
/* Make sure we filled the chunk, except for room at the end for a checksum */
- HDassert(current_pos + H5O_SIZEOF_CHKSUM_OH(oh_dst) == dst_oh_size + oh_dst->chunk[0].image);
+ HDassert(current_pos + dst_oh_gap + dst_oh_null + H5O_SIZEOF_CHKSUM_OH(oh_dst) == dst_oh_size + oh_dst->chunk[0].image);
/* Set the dest. object location to the first chunk address */
HDassert(H5F_addr_defined(addr_new));
@@ -620,7 +670,7 @@ H5O_copy_header_real(const H5O_loc_t *oloc_src, H5O_loc_t *oloc_dst /*out */,
* object header for destination object
*/
null_msgs = 0;
- for(mesgno = 0; mesgno < oh_dst->nmesgs; mesgno++) {
+ for(mesgno = 0; mesgno < orig_dst_msgs; mesgno++) {
/* Skip any deleted or NULL messages in the source unless the
* preserve_null flag is set
*/
@@ -657,7 +707,7 @@ H5O_copy_header_real(const H5O_loc_t *oloc_src, H5O_loc_t *oloc_dst /*out */,
/* Indicate that the destination address will no longer be locked */
addr_map->is_locked = FALSE;
- /* Increment object header's reference count, if any descendents have created links to link to this object */
+ /* Increment object header's reference count, if any descendents have created links to this object */
if(addr_map->inc_ref_count) {
H5_CHECK_OVERFLOW(addr_map->inc_ref_count, hsize_t, unsigned);
oh_dst->nlink += (unsigned)addr_map->inc_ref_count;
diff --git a/src/H5Opkg.h b/src/H5Opkg.h
index 0eed076..68a286d 100644
--- a/src/H5Opkg.h
+++ b/src/H5Opkg.h
@@ -29,8 +29,8 @@
/* Object header macros */
#define H5O_NMESGS 8 /*initial number of messages */
#define H5O_NCHUNKS 2 /*initial number of chunks */
-#define H5O_MIN_SIZE 32 /*min obj header data size */
-#define H5O_MSG_TYPES 22 /* # of types of messages */
+#define H5O_MIN_SIZE 22 /* Min. obj header data size (must be big enough for a message prefix and a continuation message) */
+#define H5O_MSG_TYPES 23 /* # of types of messages */
#define H5O_MAX_CRT_ORDER_IDX 65535 /* Max. creation order index value */
/* Versions of object header structure */
@@ -109,7 +109,6 @@
(H5O_SIZEOF_MAGIC + /*magic number */ \
1 + /*version number */ \
1 + /*flags */ \
- 4 + /*reference count */ \
(((O)->flags & H5O_HDR_STORE_TIMES) ? ( \
4 + /*access time */ \
4 + /*modification time */ \
@@ -247,6 +246,7 @@ struct H5O_t {
size_t sizeof_addr; /* Size of file addresses */
/* Object information (stored) */
+ hbool_t has_refcount_msg; /* Whether the object has a ref. count message */
unsigned nlink; /*link count */
uint8_t version; /*version number */
uint8_t flags; /*flags */
@@ -434,6 +434,9 @@ H5_DLLVAR const H5O_msg_class_t H5O_MSG_DRVINFO[1];
/* Attribute Information Message. (0x0015) */
H5_DLLVAR const H5O_msg_class_t H5O_MSG_AINFO[1];
+/* Reference Count Message. (0x0016) */
+H5_DLLVAR const H5O_msg_class_t H5O_MSG_REFCOUNT[1];
+
/*
* Object header "object" types
diff --git a/src/H5Oprivate.h b/src/H5Oprivate.h
index eca29e2..60d7a1d 100644
--- a/src/H5Oprivate.h
+++ b/src/H5Oprivate.h
@@ -135,6 +135,7 @@ typedef struct H5O_copy_t {
#define H5O_BTREEK_ID 0x0013 /* v1 B-tree 'K' values message. */
#define H5O_DRVINFO_ID 0x0014 /* Driver info message. */
#define H5O_AINFO_ID 0x0015 /* Attribute info message. */
+#define H5O_REFCOUNT_ID 0x0016 /* Reference count message. */
/* Shared object message flags.
@@ -429,6 +430,13 @@ typedef struct H5O_ainfo_t {
haddr_t name_bt2_addr; /* Address of v2 B-tree for indexing names of "dense" attributes */
} H5O_ainfo_t;
+/*
+ * Reference Count Message.
+ * (Contains # of links to object, if >1)
+ * (Data structure in memory)
+ */
+typedef uint32_t H5O_refcount_t;
+
/* Typedef for iteration operations */
typedef herr_t (*H5O_operator_t)(const void *mesg/*in*/, unsigned idx,
diff --git a/src/H5Orefcount.c b/src/H5Orefcount.c
new file mode 100644
index 0000000..8f49b8c
--- /dev/null
+++ b/src/H5Orefcount.c
@@ -0,0 +1,324 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * 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: H5Orefcount.c
+ * Mar 10 2007
+ * Quincey Koziol <koziol@hdfgroup.org>
+ *
+ * Purpose: Object ref. count messages.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#define H5O_PACKAGE /*suppress error about including H5Opkg */
+
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5FLprivate.h" /* Free lists */
+#include "H5Opkg.h" /* Object headers */
+
+
+/* PRIVATE PROTOTYPES */
+static void *H5O_refcount_decode(H5F_t *f, hid_t dxpl_id, unsigned mesg_flags, const uint8_t *p);
+static herr_t H5O_refcount_encode(H5F_t *f, hbool_t disable_shared, uint8_t *p, const void *_mesg);
+static void *H5O_refcount_copy(const void *_mesg, void *_dest);
+static size_t H5O_refcount_size(const H5F_t *f, hbool_t disable_shared, const void *_mesg);
+static herr_t H5O_refcount_free(void *_mesg);
+static herr_t H5O_refcount_pre_copy_file(H5F_t *file_src, const void *mesg_src,
+ hbool_t *deleted, const H5O_copy_t *cpy_info, void *udata);
+static herr_t H5O_refcount_debug(H5F_t *f, hid_t dxpl_id, const void *_mesg,
+ FILE * stream, int indent, int fwidth);
+
+/* This message derives from H5O message class */
+const H5O_msg_class_t H5O_MSG_REFCOUNT[1] = {{
+ H5O_REFCOUNT_ID, /*message id number */
+ "refcount", /*message name for debugging */
+ sizeof(H5O_refcount_t), /*native message size */
+ FALSE, /* messages are sharable? */
+ H5O_refcount_decode, /*decode message */
+ H5O_refcount_encode, /*encode message */
+ H5O_refcount_copy, /*copy the native value */
+ H5O_refcount_size, /*size of symbol table entry */
+ NULL, /*default reset method */
+ H5O_refcount_free, /* free method */
+ NULL, /* file delete method */
+ NULL, /* link method */
+ NULL, /*set share method */
+ NULL, /*can share method */
+ H5O_refcount_pre_copy_file, /* pre copy native value to file */
+ NULL, /* copy native value to file */
+ NULL, /* post copy native value to file */
+ NULL, /* get creation index */
+ NULL, /* set creation index */
+ H5O_refcount_debug /*debug the message */
+}};
+
+/* Current version of ref. count information */
+#define H5O_REFCOUNT_VERSION 0
+
+/* Declare a free list to manage the H5O_refcount_t struct */
+H5FL_DEFINE_STATIC(H5O_refcount_t);
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_refcount_decode
+ *
+ * Purpose: Decode a message and return a pointer to a newly allocated one.
+ *
+ * Return: Success: Ptr to new message in native form.
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Mar 10 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5O_refcount_decode(H5F_t *f, hid_t UNUSED dxpl_id, unsigned UNUSED mesg_flags,
+ const uint8_t *p)
+{
+ H5O_refcount_t *refcount = NULL; /* Reference count */
+ void *ret_value; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT(H5O_refcount_decode)
+
+ /* check args */
+ HDassert(f);
+ HDassert(p);
+
+ /* Version of message */
+ if(*p++ != H5O_REFCOUNT_VERSION)
+ HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "bad version number for message")
+
+ /* Allocate space for message */
+ if(NULL == (refcount = H5FL_MALLOC(H5O_refcount_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* Get ref. count for object */
+ UINT32DECODE(p, *refcount)
+
+ /* Set return value */
+ ret_value = refcount;
+
+done:
+ if(ret_value == NULL && refcount != NULL)
+ H5FL_FREE(H5O_refcount_t, refcount);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_refcount_decode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_refcount_encode
+ *
+ * Purpose: Encodes a message.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Mar 10 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_refcount_encode(H5F_t *f, hbool_t UNUSED disable_shared, uint8_t *p, const void *_mesg)
+{
+ const H5O_refcount_t *refcount = (const H5O_refcount_t *)_mesg;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5O_refcount_encode)
+
+ /* check args */
+ HDassert(f);
+ HDassert(p);
+ HDassert(refcount);
+
+ /* Message version */
+ *p++ = H5O_REFCOUNT_VERSION;
+
+ /* Object's ref. count */
+ UINT32ENCODE(p, *refcount);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_refcount_encode() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_refcount_copy
+ *
+ * Purpose: Copies a message from _MESG to _DEST, allocating _DEST if
+ * necessary.
+ *
+ * Return: Success: Ptr to _DEST
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Mar 10 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5O_refcount_copy(const void *_mesg, void *_dest)
+{
+ const H5O_refcount_t *refcount = (const H5O_refcount_t *)_mesg;
+ H5O_refcount_t *dest = (H5O_refcount_t *) _dest;
+ void *ret_value; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT(H5O_refcount_copy)
+
+ /* check args */
+ HDassert(refcount);
+ if(!dest && NULL == (dest = H5FL_MALLOC(H5O_refcount_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+
+ /* copy */
+ *dest = *refcount;
+
+ /* Set return value */
+ ret_value = dest;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_refcount_copy() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_refcount_size
+ *
+ * Purpose: Returns the size of the raw message in bytes not counting
+ * the message type or size fields, but only the data fields.
+ * This function doesn't take into account alignment.
+ *
+ * Return: Success: Message data size in bytes without alignment.
+ * Failure: zero
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Mar 10 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static size_t
+H5O_refcount_size(const H5F_t *f, hbool_t UNUSED disable_shared, const void *_mesg)
+{
+ const H5O_refcount_t *refcount = (const H5O_refcount_t *)_mesg;
+ size_t ret_value; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5O_refcount_size)
+
+ /* Set return value */
+ ret_value = 1 /* Version */
+ + 4; /* Ref. count */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5O_refcount_size() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_refcount_free
+ *
+ * Purpose: Free's the message
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, March 10, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_refcount_free(void *mesg)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5O_refcount_free)
+
+ HDassert(mesg);
+
+ H5FL_FREE(H5O_refcount_t, mesg);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_refcount_free() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_refcount_pre_copy_file
+ *
+ * Purpose: Perform any necessary actions before copying message between
+ * files.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Saturday, March 10, 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_refcount_pre_copy_file(H5F_t UNUSED *file_src, const void UNUSED *native_src,
+ hbool_t *deleted, const H5O_copy_t *cpy_info, void UNUSED *udata)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5O_refcount_pre_copy_file)
+
+ /* check args */
+ HDassert(deleted);
+ HDassert(cpy_info);
+
+ /* Always delete this message when copying objects between files. Let
+ * the copy routine set the correct ref. count.
+ */
+ *deleted = TRUE;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_refcount_pre_copy_file() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5O_refcount_debug
+ *
+ * Purpose: Prints debugging info for a message.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * koziol@hdfgroup.org
+ * Mar 6 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5O_refcount_debug(H5F_t UNUSED *f, hid_t UNUSED dxpl_id, const void *_mesg, FILE * stream,
+ int indent, int fwidth)
+{
+ const H5O_refcount_t *refcount = (const H5O_refcount_t *) _mesg;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5O_refcount_debug)
+
+ /* check args */
+ HDassert(f);
+ HDassert(refcount);
+ HDassert(stream);
+ HDassert(indent >= 0);
+ HDassert(fwidth >= 0);
+
+ HDfprintf(stream, "%*s%-*s %u\n", indent, "", fwidth,
+ "Number of links:", (unsigned)*refcount);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5O_refcount_debug() */
+
diff --git a/src/Makefile.am b/src/Makefile.am
index 8375f3a1..ced4713 100755
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -67,7 +67,8 @@ libhdf5_la_SOURCES= H5.c H5checksum.c H5dbg.c H5system.c H5timer.c H5trace.c \
H5Ofill.c H5Oginfo.c \
H5Olayout.c \
H5Olinfo.c H5Olink.c H5Omessage.c H5Omtime.c \
- H5Oname.c H5Onull.c H5Opline.c H5Osdspace.c H5Oshared.c H5Ostab.c \
+ H5Oname.c H5Onull.c H5Opline.c H5Orefcount.c \
+ H5Osdspace.c H5Oshared.c H5Ostab.c \
H5Oshmesg.c H5Otest.c \
H5P.c H5Pacpl.c H5Pdcpl.c H5Pdxpl.c H5Pfapl.c H5Pfcpl.c H5Pfmpl.c \
H5Pgcpl.c \
diff --git a/src/Makefile.in b/src/Makefile.in
index bc614d6..1c1bb6e 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -105,7 +105,7 @@ am_libhdf5_la_OBJECTS = H5.lo H5checksum.lo H5dbg.lo H5system.lo \
H5Obtreek.lo H5Ocache.lo H5Ocont.lo H5Ocopy.lo H5Odbg.lo \
H5Odrvinfo.lo H5Odtype.lo H5Oefl.lo H5Ofill.lo H5Oginfo.lo \
H5Olayout.lo H5Olinfo.lo H5Olink.lo H5Omessage.lo H5Omtime.lo \
- H5Oname.lo H5Onull.lo H5Opline.lo H5Osdspace.lo H5Oshared.lo \
+ H5Oname.lo H5Onull.lo H5Opline.lo H5Orefcount.lo H5Osdspace.lo H5Oshared.lo \
H5Ostab.lo H5Oshmesg.lo H5Otest.lo H5P.lo H5Pacpl.lo \
H5Pdcpl.lo H5Pdxpl.lo H5Pfapl.lo H5Pfcpl.lo H5Pfmpl.lo \
H5Pgcpl.lo H5Plapl.lo H5Plcpl.lo H5Pocpl.lo H5Pocpypl.lo \
@@ -426,7 +426,7 @@ libhdf5_la_SOURCES = H5.c H5checksum.c H5dbg.c H5system.c H5timer.c H5trace.c \
H5Ofill.c H5Oginfo.c \
H5Olayout.c \
H5Olinfo.c H5Olink.c H5Omessage.c H5Omtime.c \
- H5Oname.c H5Onull.c H5Opline.c H5Osdspace.c H5Oshared.c H5Ostab.c \
+ H5Oname.c H5Onull.c H5Opline.c H5Orefcount.c H5Osdspace.c H5Oshared.c H5Ostab.c \
H5Oshmesg.c H5Otest.c \
H5P.c H5Pacpl.c H5Pdcpl.c H5Pdxpl.c H5Pfapl.c H5Pfcpl.c H5Pfmpl.c \
H5Pgcpl.c \
@@ -694,6 +694,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Oname.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Onull.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Opline.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Orefcount.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Osdspace.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Oshared.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/H5Oshmesg.Plo@am__quote@
diff --git a/test/objcopy.c b/test/objcopy.c
index 71cd247..8cc1027 100755
--- a/test/objcopy.c
+++ b/test/objcopy.c
@@ -1255,11 +1255,11 @@ compare_groups(hid_t gid, hid_t gid2, hid_t pid, int depth, unsigned copy_flags)
* of messages hasn't increased.
*/
if(H5O_COPY_PRESERVE_NULL_FLAG & copy_flags) {
- if(objstat.ohdr.nmesgs != objstat2.ohdr.nmesgs);
+ if(objstat.ohdr.nmesgs != objstat2.ohdr.nmesgs)
+ ;
else
if(objstat.ohdr.nmesgs < objstat2.ohdr.nmesgs) TEST_ERROR
}
- if(1 != objstat2.ohdr.nchunks) TEST_ERROR
} /* end if */
/* Get link info */
diff --git a/test/stab.c b/test/stab.c
index adf9803..73e1645 100644
--- a/test/stab.c
+++ b/test/stab.c
@@ -427,9 +427,9 @@ lifecycle(hid_t fapl)
/* Check that the object header is only one chunk and the space has been allocated correctly */
if(H5Gget_objinfo(gid, ".", FALSE, &obj_stat) < 0) TEST_ERROR
#ifdef H5_HAVE_LARGE_HSIZET
- if(obj_stat.ohdr.size != 163) TEST_ERROR
+ if(obj_stat.ohdr.size != 159) TEST_ERROR
#else /* H5_HAVE_LARGE_HSIZET */
- if(obj_stat.ohdr.size != 143) TEST_ERROR
+ if(obj_stat.ohdr.size != 139) TEST_ERROR
#endif /* H5_HAVE_LARGE_HSIZET */
if(obj_stat.ohdr.free != 0) TEST_ERROR
if(obj_stat.ohdr.nmesgs != 6) TEST_ERROR
@@ -453,9 +453,9 @@ lifecycle(hid_t fapl)
/* Check that the object header is still one chunk and the space has been allocated correctly */
if(H5Gget_objinfo(gid, ".", FALSE, &obj_stat) < 0) TEST_ERROR
#ifdef H5_HAVE_LARGE_HSIZET
- if(obj_stat.ohdr.size != 163) TEST_ERROR
+ if(obj_stat.ohdr.size != 159) TEST_ERROR
#else /* H5_HAVE_LARGE_HSIZET */
- if(obj_stat.ohdr.size != 143) TEST_ERROR
+ if(obj_stat.ohdr.size != 139) TEST_ERROR
#endif /* H5_HAVE_LARGE_HSIZET */
if(obj_stat.ohdr.free != 92) TEST_ERROR
if(obj_stat.ohdr.nmesgs != 3) TEST_ERROR
diff --git a/test/tattr.c b/test/tattr.c
index 897b713..d9ce186 100644
--- a/test/tattr.c
+++ b/test/tattr.c
@@ -6259,16 +6259,6 @@ test_attr_shared_write(hid_t fcpl, hid_t fapl)
ret = H5Pclose(my_fcpl);
CHECK(ret, FAIL, "H5Pclose");
- /* Commit datatype to file */
- if(test_shared == 2) {
- ret = H5Tcommit(fid, TYPE1_NAME, attr_tid);
- CHECK(ret, FAIL, "H5Tcommit");
-
- /* Close attribute's datatype */
- ret = H5Tclose(attr_tid);
- CHECK(ret, FAIL, "H5Tclose");
- } /* end switch */
-
/* Close file */
ret = H5Fclose(fid);
CHECK(ret, FAIL, "H5Fclose");
@@ -6283,10 +6273,10 @@ test_attr_shared_write(hid_t fcpl, hid_t fapl)
fid = H5Fopen(FILENAME, H5F_ACC_RDWR, fapl);
CHECK(fid, FAIL, "H5Fopen");
- /* Re-open attribute datatype as necessary */
+ /* Commit datatype to file */
if(test_shared == 2) {
- attr_tid = H5Topen(fid, TYPE1_NAME);
- CHECK(attr_tid, FAIL, "H5Topen");
+ ret = H5Tcommit(fid, TYPE1_NAME, attr_tid);
+ CHECK(ret, FAIL, "H5Tcommit");
} /* end if */
/* Set up to query the object creation properties */
@@ -6466,6 +6456,12 @@ test_attr_shared_write(hid_t fcpl, hid_t fapl)
ret = H5Gunlink(fid, DSET2_NAME);
CHECK(ret, FAIL, "H5Gunlink");
+ /* Unlink committed datatype */
+ if(test_shared == 2) {
+ ret = H5Gunlink(fid, TYPE1_NAME);
+ CHECK(ret, FAIL, "H5Gunlink");
+ } /* end if */
+
/* Check on attribute storage status */
ret = H5F_get_sohm_mesg_count_test(fid, H5O_ATTR_ID, &mesg_count);
CHECK(ret, FAIL, "H5F_get_sohm_mesg_count_test");
@@ -6588,16 +6584,6 @@ test_attr_shared_rename(hid_t fcpl, hid_t fapl)
ret = H5Pclose(my_fcpl);
CHECK(ret, FAIL, "H5Pclose");
- /* Commit datatype to file */
- if(test_shared == 2) {
- ret = H5Tcommit(fid, TYPE1_NAME, attr_tid);
- CHECK(ret, FAIL, "H5Tcommit");
-
- /* Close attribute's datatype */
- ret = H5Tclose(attr_tid);
- CHECK(ret, FAIL, "H5Tclose");
- } /* end switch */
-
/* Close file */
ret = H5Fclose(fid);
CHECK(ret, FAIL, "H5Fclose");
@@ -6612,10 +6598,10 @@ test_attr_shared_rename(hid_t fcpl, hid_t fapl)
fid = H5Fopen(FILENAME, H5F_ACC_RDWR, fapl);
CHECK(fid, FAIL, "H5Fopen");
- /* Re-open attribute datatype as necessary */
+ /* Commit datatype to file */
if(test_shared == 2) {
- attr_tid = H5Topen(fid, TYPE1_NAME);
- CHECK(attr_tid, FAIL, "H5Topen");
+ ret = H5Tcommit(fid, TYPE1_NAME, attr_tid);
+ CHECK(ret, FAIL, "H5Tcommit");
} /* end if */
/* Set up to query the object creation properties */
@@ -6911,6 +6897,12 @@ test_attr_shared_rename(hid_t fcpl, hid_t fapl)
ret = H5Gunlink(fid, DSET2_NAME);
CHECK(ret, FAIL, "H5Gunlink");
+ /* Unlink committed datatype */
+ if(test_shared == 2) {
+ ret = H5Gunlink(fid, TYPE1_NAME);
+ CHECK(ret, FAIL, "H5Gunlink");
+ } /* end if */
+
/* Check on attribute storage status */
ret = H5F_get_sohm_mesg_count_test(fid, H5O_ATTR_ID, &mesg_count);
CHECK(ret, FAIL, "H5F_get_sohm_mesg_count_test");
@@ -7032,16 +7024,6 @@ test_attr_shared_delete(hid_t fcpl, hid_t fapl)
ret = H5Pclose(my_fcpl);
CHECK(ret, FAIL, "H5Pclose");
- /* Commit datatype to file */
- if(test_shared == 2) {
- ret = H5Tcommit(fid, TYPE1_NAME, attr_tid);
- CHECK(ret, FAIL, "H5Tcommit");
-
- /* Close attribute's datatype */
- ret = H5Tclose(attr_tid);
- CHECK(ret, FAIL, "H5Tclose");
- } /* end switch */
-
/* Close file */
ret = H5Fclose(fid);
CHECK(ret, FAIL, "H5Fclose");
@@ -7056,10 +7038,10 @@ test_attr_shared_delete(hid_t fcpl, hid_t fapl)
fid = H5Fopen(FILENAME, H5F_ACC_RDWR, fapl);
CHECK(fid, FAIL, "H5Fopen");
- /* Re-open attribute datatype as necessary */
+ /* Commit datatype to file */
if(test_shared == 2) {
- attr_tid = H5Topen(fid, TYPE1_NAME);
- CHECK(attr_tid, FAIL, "H5Topen");
+ ret = H5Tcommit(fid, TYPE1_NAME, attr_tid);
+ CHECK(ret, FAIL, "H5Tcommit");
} /* end if */
/* Set up to query the object creation properties */
@@ -7278,6 +7260,12 @@ test_attr_shared_delete(hid_t fcpl, hid_t fapl)
ret = H5Gunlink(fid, DSET2_NAME);
CHECK(ret, FAIL, "H5Gunlink");
+ /* Unlink committed datatype */
+ if(test_shared == 2) {
+ ret = H5Gunlink(fid, TYPE1_NAME);
+ CHECK(ret, FAIL, "H5Gunlink");
+ } /* end if */
+
/* Check on attribute storage status */
ret = H5F_get_sohm_mesg_count_test(fid, H5O_ATTR_ID, &mesg_count);
CHECK(ret, FAIL, "H5F_get_sohm_mesg_count_test");
@@ -7399,16 +7387,6 @@ test_attr_shared_unlink(hid_t fcpl, hid_t fapl)
ret = H5Pclose(my_fcpl);
CHECK(ret, FAIL, "H5Pclose");
- /* Commit datatype to file */
- if(test_shared == 2) {
- ret = H5Tcommit(fid, TYPE1_NAME, attr_tid);
- CHECK(ret, FAIL, "H5Tcommit");
-
- /* Close attribute's datatype */
- ret = H5Tclose(attr_tid);
- CHECK(ret, FAIL, "H5Tclose");
- } /* end switch */
-
/* Close file */
ret = H5Fclose(fid);
CHECK(ret, FAIL, "H5Fclose");
@@ -7423,10 +7401,10 @@ test_attr_shared_unlink(hid_t fcpl, hid_t fapl)
fid = H5Fopen(FILENAME, H5F_ACC_RDWR, fapl);
CHECK(fid, FAIL, "H5Fopen");
- /* Re-open attribute datatype as necessary */
+ /* Commit datatype to file */
if(test_shared == 2) {
- attr_tid = H5Topen(fid, TYPE1_NAME);
- CHECK(attr_tid, FAIL, "H5Topen");
+ ret = H5Tcommit(fid, TYPE1_NAME, attr_tid);
+ CHECK(ret, FAIL, "H5Tcommit");
} /* end if */
/* Set up to query the object creation properties */
@@ -7631,6 +7609,12 @@ test_attr_shared_unlink(hid_t fcpl, hid_t fapl)
ret = H5Gunlink(fid, DSET1_NAME);
CHECK(ret, FAIL, "H5Gunlink");
+ /* Unlink committed datatype */
+ if(test_shared == 2) {
+ ret = H5Gunlink(fid, TYPE1_NAME);
+ CHECK(ret, FAIL, "H5Gunlink");
+ } /* end if */
+
/* Check on attribute storage status */
ret = H5F_get_sohm_mesg_count_test(fid, H5O_ATTR_ID, &mesg_count);
CHECK(ret, FAIL, "H5F_get_sohm_mesg_count_test");
diff --git a/test/tfile.c b/test/tfile.c
index 34a304b..91cfa58 100644
--- a/test/tfile.c
+++ b/test/tfile.c
@@ -1247,7 +1247,7 @@ test_file_freespace(void)
free_space = H5Fget_freespace(file);
CHECK(free_space, FAIL, "H5Fget_freespace");
#ifdef H5_HAVE_LARGE_HSIZET
- VERIFY(free_space, 2368, "H5Fget_freespace");
+ VERIFY(free_space, 2376, "H5Fget_freespace");
#else /* H5_HAVE_LARGE_HSIZET */
VERIFY(free_space, 588, "H5Fget_freespace"); /* XXX: fix me */
#endif /* H5_HAVE_LARGE_HSIZET */
diff --git a/tools/testfiles/h5copytst.out.ls b/tools/testfiles/h5copytst.out.ls
index 1e8cd16..378aa0f 100644
--- a/tools/testfiles/h5copytst.out.ls
+++ b/tools/testfiles/h5copytst.out.ls
@@ -6,7 +6,7 @@ Opened "../testfiles/h5copytst.out.h5" with sec2 driver.
Location: 1:90344
Links: 1
/A/B1 Group
- Location: 1:91056
+ Location: 1:91048
Links: 1
/A/B1/simple Dataset {6/6}
Location: 1:90216
@@ -15,50 +15,50 @@ Opened "../testfiles/h5copytst.out.h5" with sec2 driver.
Storage: <details removed for portability>
Type: 32-bit little-endian integer
/A/B2 Group
- Location: 1:94600
+ Location: 1:94584
Links: 1
/A/B2/simple2 Dataset {6/6}
- Location: 1:94472
+ Location: 1:94456
Links: 1
Modified: XXXX-XX-XX XX:XX:XX XXX
Storage: <details removed for portability>
Type: 32-bit little-endian integer
/C Group
- Location: 1:97816
+ Location: 1:97792
Links: 1
/C/D Group
- Location: 1:98528
+ Location: 1:98496
Links: 1
/C/D/simple Dataset {6/6}
- Location: 1:97688
+ Location: 1:97664
Links: 1
Modified: XXXX-XX-XX XX:XX:XX XXX
Storage: <details removed for portability>
Type: 32-bit little-endian integer
/E Group
- Location: 1:103960
+ Location: 1:103920
Links: 1
/E/F Group
- Location: 1:113216
+ Location: 1:103960
Links: 1
/E/F/grp_dsets Group
- Location: 1:100648
+ Location: 1:100608
Links: 1
/E/F/grp_dsets/chunk Dataset {6/6}
- Location: 1:102784
+ Location: 1:102744
Links: 1
Modified: XXXX-XX-XX XX:XX:XX XXX
Chunks: {2} 8 bytes
Storage: <details removed for portability>
Type: 32-bit little-endian integer
/E/F/grp_dsets/compact Dataset {6/6}
- Location: 1:103240
+ Location: 1:103200
Links: 1
Modified: XXXX-XX-XX XX:XX:XX XXX
Storage: <details removed for portability>
Type: 32-bit little-endian integer
/E/F/grp_dsets/compound Dataset {2/2}
- Location: 1:103376
+ Location: 1:103336
Links: 1
Modified: XXXX-XX-XX XX:XX:XX XXX
Storage: <details removed for portability>
@@ -67,7 +67,7 @@ Opened "../testfiles/h5copytst.out.h5" with sec2 driver.
"str2" +20 20-byte null-terminated ASCII string
} 40 bytes
/E/F/grp_dsets/compressed Dataset {6/6}
- Location: 1:103592
+ Location: 1:103552
Links: 1
Modified: XXXX-XX-XX XX:XX:XX XXX
Chunks: {2} 8 bytes
@@ -75,14 +75,14 @@ Opened "../testfiles/h5copytst.out.h5" with sec2 driver.
Filter-0: deflate-1 OPT {1}
Type: 32-bit little-endian integer
/E/F/grp_dsets/named_vl Dataset {2/2}
- Location: 1:103808
+ Location: 1:103768
Links: 1
Modified: XXXX-XX-XX XX:XX:XX XXX
Storage: <details removed for portability>
- Type: shared-1:103760 variable length of
+ Type: shared-1:103720 variable length of
32-bit little-endian integer
/E/F/grp_dsets/nested_vl Dataset {2/2}
- Location: 1:112280
+ Location: 1:112240
Links: 1
Modified: XXXX-XX-XX XX:XX:XX XXX
Storage: <details removed for portability>
@@ -90,43 +90,43 @@ Opened "../testfiles/h5copytst.out.h5" with sec2 driver.
variable length of
32-bit little-endian integer
/E/F/grp_dsets/simple Dataset {6/6}
- Location: 1:112424
+ Location: 1:112384
Links: 1
Modified: XXXX-XX-XX XX:XX:XX XXX
Storage: <details removed for portability>
Type: 32-bit little-endian integer
/E/F/grp_dsets/vl Type
- Location: 1:103760
+ Location: 1:103720
Links: 2
- Type: shared-1:103760 variable length of
+ Type: shared-1:103720 variable length of
32-bit little-endian integer
/G Group
- Location: 1:128264
+ Location: 1:128176
Links: 1
/G/H Group
- Location: 1:128976
+ Location: 1:128880
Links: 1
/G/H/grp_nested Group
- Location: 1:115248
+ Location: 1:115160
Links: 1
/G/H/grp_nested/grp_dsets Group
- Location: 1:116040
+ Location: 1:115952
Links: 1
/G/H/grp_nested/grp_dsets/chunk Dataset {6/6}
- Location: 1:118176
+ Location: 1:118088
Links: 1
Modified: XXXX-XX-XX XX:XX:XX XXX
Chunks: {2} 8 bytes
Storage: <details removed for portability>
Type: 32-bit little-endian integer
/G/H/grp_nested/grp_dsets/compact Dataset {6/6}
- Location: 1:120776
+ Location: 1:120688
Links: 1
Modified: XXXX-XX-XX XX:XX:XX XXX
Storage: <details removed for portability>
Type: 32-bit little-endian integer
/G/H/grp_nested/grp_dsets/compound Dataset {2/2}
- Location: 1:120912
+ Location: 1:120824
Links: 1
Modified: XXXX-XX-XX XX:XX:XX XXX
Storage: <details removed for portability>
@@ -135,7 +135,7 @@ Opened "../testfiles/h5copytst.out.h5" with sec2 driver.
"str2" +20 20-byte null-terminated ASCII string
} 40 bytes
/G/H/grp_nested/grp_dsets/compressed Dataset {6/6}
- Location: 1:123224
+ Location: 1:123136
Links: 1
Modified: XXXX-XX-XX XX:XX:XX XXX
Chunks: {2} 8 bytes
@@ -143,14 +143,14 @@ Opened "../testfiles/h5copytst.out.h5" with sec2 driver.
Filter-0: deflate-1 OPT {1}
Type: 32-bit little-endian integer
/G/H/grp_nested/grp_dsets/named_vl Dataset {2/2}
- Location: 1:127536
+ Location: 1:127448
Links: 1
Modified: XXXX-XX-XX XX:XX:XX XXX
Storage: <details removed for portability>
- Type: shared-1:123392 variable length of
+ Type: shared-1:123304 variable length of
32-bit little-endian integer
/G/H/grp_nested/grp_dsets/nested_vl Dataset {2/2}
- Location: 1:127664
+ Location: 1:127576
Links: 1
Modified: XXXX-XX-XX XX:XX:XX XXX
Storage: <details removed for portability>
@@ -158,15 +158,15 @@ Opened "../testfiles/h5copytst.out.h5" with sec2 driver.
variable length of
32-bit little-endian integer
/G/H/grp_nested/grp_dsets/simple Dataset {6/6}
- Location: 1:127808
+ Location: 1:127720
Links: 1
Modified: XXXX-XX-XX XX:XX:XX XXX
Storage: <details removed for portability>
Type: 32-bit little-endian integer
/G/H/grp_nested/grp_dsets/vl Type
- Location: 1:123392
+ Location: 1:123304
Links: 2
- Type: shared-1:123392 variable length of
+ Type: shared-1:123304 variable length of
32-bit little-endian integer
/chunk Dataset {6/6}
Location: 1:6216
@@ -471,7 +471,7 @@ Opened "../testfiles/h5copytst.out.h5" with sec2 driver.
"str2" +20 20-byte null-terminated ASCII string
} 40 bytes
/simple Dataset {6/6}
- Location: 1:808
+ Location: 1:800
Links: 1
Modified: XXXX-XX-XX XX:XX:XX XXX
Storage: <details removed for portability>
diff --git a/tools/testfiles/h5mkgrp_nested.ls b/tools/testfiles/h5mkgrp_nested.ls
index acc3aba..5f3d479 100644
--- a/tools/testfiles/h5mkgrp_nested.ls
+++ b/tools/testfiles/h5mkgrp_nested.ls
@@ -3,8 +3,8 @@ Expected output for 'h5ls ../testfiles/h5mkgrp_nested.h5'
#############################
Opened "../testfiles/h5mkgrp_nested.h5" with sec2 driver.
/one Group
- Location: 1:1520
+ Location: 1:1504
Links: 1
/one/two Group
- Location: 1:808
+ Location: 1:800
Links: 1
diff --git a/tools/testfiles/h5mkgrp_nested_latest.ls b/tools/testfiles/h5mkgrp_nested_latest.ls
index 320e19d..93364de 100644
--- a/tools/testfiles/h5mkgrp_nested_latest.ls
+++ b/tools/testfiles/h5mkgrp_nested_latest.ls
@@ -3,10 +3,10 @@ Expected output for 'h5ls ../testfiles/h5mkgrp_nested_latest.h5'
#############################
Opened "../testfiles/h5mkgrp_nested_latest.h5" with sec2 driver.
/one Group
- Location: 1:366
+ Location: 1:358
Links: 1
Modified: XXXX-XX-XX XX:XX:XX XXX
/one/two Group
- Location: 1:207
+ Location: 1:203
Links: 1
Modified: XXXX-XX-XX XX:XX:XX XXX
diff --git a/tools/testfiles/h5mkgrp_nested_mult.ls b/tools/testfiles/h5mkgrp_nested_mult.ls
index 162da0c..99082b6 100644
--- a/tools/testfiles/h5mkgrp_nested_mult.ls
+++ b/tools/testfiles/h5mkgrp_nested_mult.ls
@@ -3,14 +3,14 @@ Expected output for 'h5ls ../testfiles/h5mkgrp_nested_mult.h5'
#############################
Opened "../testfiles/h5mkgrp_nested_mult.h5" with sec2 driver.
/one Group
- Location: 1:1520
+ Location: 1:1504
Links: 1
/one/two Group
- Location: 1:808
+ Location: 1:800
Links: 1
/three Group
- Location: 1:3600
+ Location: 1:3568
Links: 1
/three/four Group
- Location: 1:2888
+ Location: 1:2864
Links: 1
diff --git a/tools/testfiles/h5mkgrp_nested_mult_latest.ls b/tools/testfiles/h5mkgrp_nested_mult_latest.ls
index c3a4cf1..98edd64 100644
--- a/tools/testfiles/h5mkgrp_nested_mult_latest.ls
+++ b/tools/testfiles/h5mkgrp_nested_mult_latest.ls
@@ -3,18 +3,18 @@ Expected output for 'h5ls ../testfiles/h5mkgrp_nested_mult_latest.h5'
#############################
Opened "../testfiles/h5mkgrp_nested_mult_latest.h5" with sec2 driver.
/one Group
- Location: 1:366
+ Location: 1:358
Links: 1
Modified: XXXX-XX-XX XX:XX:XX XXX
/one/two Group
- Location: 1:207
+ Location: 1:203
Links: 1
Modified: XXXX-XX-XX XX:XX:XX XXX
/three Group
- Location: 1:684
+ Location: 1:668
Links: 1
Modified: XXXX-XX-XX XX:XX:XX XXX
/three/four Group
- Location: 1:525
+ Location: 1:513
Links: 1
Modified: XXXX-XX-XX XX:XX:XX XXX
diff --git a/tools/testfiles/h5mkgrp_several.ls b/tools/testfiles/h5mkgrp_several.ls
index e71e7a5..dcbe3eb 100644
--- a/tools/testfiles/h5mkgrp_several.ls
+++ b/tools/testfiles/h5mkgrp_several.ls
@@ -3,8 +3,8 @@ Expected output for 'h5ls ../testfiles/h5mkgrp_several.h5'
#############################
Opened "../testfiles/h5mkgrp_several.h5" with sec2 driver.
/one Group
- Location: 1:808
+ Location: 1:800
Links: 1
/two Group
- Location: 1:1848
+ Location: 1:1832
Links: 1
diff --git a/tools/testfiles/h5mkgrp_several_latest.ls b/tools/testfiles/h5mkgrp_several_latest.ls
index f43e6c2..91eff51 100644
--- a/tools/testfiles/h5mkgrp_several_latest.ls
+++ b/tools/testfiles/h5mkgrp_several_latest.ls
@@ -3,10 +3,10 @@ Expected output for 'h5ls ../testfiles/h5mkgrp_several_latest.h5'
#############################
Opened "../testfiles/h5mkgrp_several_latest.h5" with sec2 driver.
/one Group
- Location: 1:207
+ Location: 1:203
Links: 1
Modified: XXXX-XX-XX XX:XX:XX XXX
/two Group
- Location: 1:366
+ Location: 1:358
Links: 1
Modified: XXXX-XX-XX XX:XX:XX XXX
diff --git a/tools/testfiles/h5mkgrp_single.ls b/tools/testfiles/h5mkgrp_single.ls
index 800b002..1f7e828 100644
--- a/tools/testfiles/h5mkgrp_single.ls
+++ b/tools/testfiles/h5mkgrp_single.ls
@@ -3,5 +3,5 @@ Expected output for 'h5ls ../testfiles/h5mkgrp_single.h5'
#############################
Opened "../testfiles/h5mkgrp_single.h5" with sec2 driver.
/single Group
- Location: 1:808
+ Location: 1:800
Links: 1
diff --git a/tools/testfiles/h5mkgrp_single_latest.ls b/tools/testfiles/h5mkgrp_single_latest.ls
index 72901cf..294db66 100644
--- a/tools/testfiles/h5mkgrp_single_latest.ls
+++ b/tools/testfiles/h5mkgrp_single_latest.ls
@@ -3,6 +3,6 @@ Expected output for 'h5ls ../testfiles/h5mkgrp_single_latest.h5'
#############################
Opened "../testfiles/h5mkgrp_single_latest.h5" with sec2 driver.
/latest Group
- Location: 1:207
+ Location: 1:203
Links: 1
Modified: XXXX-XX-XX XX:XX:XX XXX