1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2  * Copyright by The HDF Group.                                               *
3  * Copyright by the Board of Trustees of the University of Illinois.         *
4  * All rights reserved.                                                      *
5  *                                                                           *
6  * This file is part of HDF5.  The full HDF5 copyright notice, including     *
7  * terms governing use, modification, and redistribution, is contained in    *
8  * the COPYING file, which can be found at the root of the source code       *
9  * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases.  *
10  * If you do not have access to either file, you may request a copy from     *
11  * help@hdfgroup.org.                                                        *
12  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
13 
14 /*-------------------------------------------------------------------------
15  *
16  * Created:		H5Ocache.c
17  *			Sep 28 2005
18  *			Quincey Koziol <koziol@ncsa.uiuc.edu>
19  *
20  * Purpose:		Object header metadata cache virtual functions.
21  *
22  *-------------------------------------------------------------------------
23  */
24 
25 /****************/
26 /* Module Setup */
27 /****************/
28 
29 #include "H5Omodule.h"          /* This source code file is part of the H5O module */
30 
31 
32 /***********/
33 /* Headers */
34 /***********/
35 #include "H5private.h"		/* Generic Functions			*/
36 #include "H5Eprivate.h"		/* Error handling		  	*/
37 #include "H5FLprivate.h"	/* Free lists                           */
38 #include "H5MFprivate.h"	/* File memory management		*/
39 #include "H5Opkg.h"             /* Object headers			*/
40 #include "H5WBprivate.h"        /* Wrapped Buffers                      */
41 
42 
43 /****************/
44 /* Local Macros */
45 /****************/
46 
47 
48 /******************/
49 /* Local Typedefs */
50 /******************/
51 
52 
53 /********************/
54 /* Package Typedefs */
55 /********************/
56 
57 
58 /********************/
59 /* Local Prototypes */
60 /********************/
61 
62 /* Metadata cache callbacks */
63 static herr_t H5O__cache_get_initial_load_size(void *udata, size_t *image_len);
64 static herr_t H5O__cache_get_final_load_size(const void *image_ptr, size_t image_len,
65     void *udata, size_t *actual_len);
66 static htri_t H5O__cache_verify_chksum(const void *image_ptr, size_t len, void *udata_ptr);
67 static void *H5O__cache_deserialize(const void *image, size_t len,
68     void *udata, hbool_t *dirty);
69 static herr_t H5O__cache_image_len(const void *thing, size_t *image_len);
70 static herr_t H5O__cache_serialize(const H5F_t *f, void *image, size_t len,
71     void *thing);
72 static herr_t H5O__cache_notify(H5AC_notify_action_t action, void *_thing);
73 static herr_t H5O__cache_free_icr(void *thing);
74 
75 static herr_t H5O__cache_chk_get_initial_load_size(void *udata, size_t *image_len);
76 static htri_t H5O__cache_chk_verify_chksum(const void *image_ptr, size_t len, void *udata_ptr);
77 static void *H5O__cache_chk_deserialize(const void *image, size_t len,
78     void *udata, hbool_t *dirty);
79 static herr_t H5O__cache_chk_image_len(const void *thing, size_t *image_len);
80 static herr_t H5O__cache_chk_serialize(const H5F_t *f, void *image, size_t len,
81     void *thing);
82 static herr_t H5O__cache_chk_notify(H5AC_notify_action_t action, void *_thing);
83 static herr_t H5O__cache_chk_free_icr(void *thing);
84 
85 /* Prefix routines */
86 static herr_t H5O__prefix_deserialize(const uint8_t *image,
87     H5O_cache_ud_t *udata);
88 
89 /* Chunk routines */
90 static herr_t H5O__chunk_deserialize(H5O_t *oh, haddr_t addr, size_t len,
91     const uint8_t *image, H5O_common_cache_ud_t *udata, hbool_t *dirty);
92 static herr_t H5O__chunk_serialize(const H5F_t *f, H5O_t *oh, unsigned chunkno);
93 
94 /* Misc. routines */
95 static herr_t H5O__add_cont_msg(H5O_cont_msgs_t *cont_msg_info,
96     const H5O_cont_t *cont);
97 
98 
99 /*********************/
100 /* Package Variables */
101 /*********************/
102 
103 /* H5O object header prefix inherits cache-like properties from H5AC */
104 const H5AC_class_t H5AC_OHDR[1] = {{
105     H5AC_OHDR_ID,                       /* Metadata client ID */
106     "object header",                    /* Metadata client name (for debugging) */
107     H5FD_MEM_OHDR,                      /* File space memory type for client */
108     H5AC__CLASS_SPECULATIVE_LOAD_FLAG,  /* Client class behavior flags */
109     H5O__cache_get_initial_load_size,   /* 'get_initial_load_size' callback */
110     H5O__cache_get_final_load_size,     /* 'get_final_load_size' callback */
111     H5O__cache_verify_chksum, 		/* 'verify_chksum' callback */
112     H5O__cache_deserialize,             /* 'deserialize' callback */
113     H5O__cache_image_len,               /* 'image_len' callback */
114     NULL,                               /* 'pre_serialize' callback */
115     H5O__cache_serialize,               /* 'serialize' callback */
116     H5O__cache_notify,                  /* 'notify' callback */
117     H5O__cache_free_icr,                /* 'free_icr' callback */
118     NULL,                               /* 'fsf_size' callback */
119 }};
120 
121 /* H5O object header chunk inherits cache-like properties from H5AC */
122 const H5AC_class_t H5AC_OHDR_CHK[1] = {{
123     H5AC_OHDR_CHK_ID,                   /* Metadata client ID */
124     "object header continuation chunk", /* Metadata client name (for debugging) */
125     H5FD_MEM_OHDR,                      /* File space memory type for client */
126     H5AC__CLASS_NO_FLAGS_SET,           /* Client class behavior flags */
127     H5O__cache_chk_get_initial_load_size, /* 'get_initial_load_size' callback */
128     NULL,				/* 'get_final_load_size' callback */
129     H5O__cache_chk_verify_chksum,	/* 'verify_chksum' callback */
130     H5O__cache_chk_deserialize,         /* 'deserialize' callback */
131     H5O__cache_chk_image_len,           /* 'image_len' callback */
132     NULL,                               /* 'pre_serialize' callback */
133     H5O__cache_chk_serialize,           /* 'serialize' callback */
134     H5O__cache_chk_notify,              /* 'notify' callback */
135     H5O__cache_chk_free_icr,            /* 'free_icr' callback */
136     NULL,                               /* 'fsf_size' callback */
137 }};
138 
139 /* Declare external the free list for H5O_unknown_t's */
140 H5FL_EXTERN(H5O_unknown_t);
141 
142 /* Declare extern the free list for H5O_chunk_proxy_t's */
143 H5FL_EXTERN(H5O_chunk_proxy_t);
144 
145 /* Declare the free list for H5O_cont_t sequences */
146 H5FL_SEQ_DEFINE(H5O_cont_t);
147 
148 
149 /*****************************/
150 /* Library Private Variables */
151 /*****************************/
152 
153 
154 /*******************/
155 /* Local Variables */
156 /*******************/
157 
158 
159 
160 /*-------------------------------------------------------------------------
161  * Function:    H5O__cache_get_initial_load_size()
162  *
163  * Purpose:	Tell the metadata cache how much data to read from file in
164  *		the first speculative read for the object header.
165  *
166  * Return:      Success:        SUCCEED
167  *              Failure:        FAIL
168  *
169  * Programmer:  John Mainzer
170  *              7/28/14
171  *
172  *-------------------------------------------------------------------------
173  */
174 static herr_t
H5O__cache_get_initial_load_size(void H5_ATTR_UNUSED * _udata,size_t * image_len)175 H5O__cache_get_initial_load_size(void H5_ATTR_UNUSED *_udata, size_t *image_len)
176 {
177     FUNC_ENTER_STATIC_NOERR
178 
179     /* Check arguments */
180     HDassert(image_len);
181 
182     /* Set the image length size */
183     *image_len = H5O_SPEC_READ_SIZE;
184 
185     FUNC_LEAVE_NOAPI(SUCCEED)
186 } /* end H5O__cache_get_initial_load_size() */
187 
188 
189 /*-------------------------------------------------------------------------
190  * Function:    H5O__cache_get_final_load_size()
191  *
192  * Purpose:	Tell the metadata cache the final size of an object header.
193  *
194  * Return:      Success:        SUCCEED
195  *              Failure:        FAIL
196  *
197  * Programmer:  Quincey Koziol
198  *              November 18, 2016
199  *
200  *-------------------------------------------------------------------------
201  */
202 static herr_t
H5O__cache_get_final_load_size(const void * image,size_t image_len,void * _udata,size_t * actual_len)203 H5O__cache_get_final_load_size(const void *image, size_t image_len,
204     void *_udata, size_t *actual_len)
205 {
206     H5O_cache_ud_t *udata = (H5O_cache_ud_t *)_udata;   /* User data for callback */
207     herr_t ret_value = SUCCEED;         /* Return value */
208 
209     FUNC_ENTER_STATIC
210 
211     /* Check arguments */
212     HDassert(image);
213     HDassert(udata);
214     HDassert(actual_len);
215     HDassert(*actual_len == image_len);
216 
217     /* Deserialize the object header prefix */
218     if(H5O__prefix_deserialize((const uint8_t *)image, udata) < 0)
219         HGOTO_ERROR(H5E_OHDR, H5E_CANTDECODE, FAIL, "can't deserialize object header prefix")
220 
221     /* Sanity check */
222     HDassert(udata->oh);
223 
224     /* Set the final size for the cache image */
225     *actual_len = udata->chunk0_size + (size_t)H5O_SIZEOF_HDR(udata->oh);
226 
227 done:
228     FUNC_LEAVE_NOAPI(ret_value)
229 } /* end H5O__cache_get_final_load_size() */
230 
231 
232 /*-------------------------------------------------------------------------
233  * Function:    H5O__cache_verify_chksum
234  *
235  * Purpose:     Verify the computed checksum of the data structure is the
236  *              same as the stored chksum.
237  *
238  * Return:      Success:        TRUE/FALSE
239  *              Failure:        Negative
240  *
241  * Programmer:  Vailin Choi
242  *              Aug 2015
243  *
244  *-------------------------------------------------------------------------
245  */
246 static htri_t
H5O__cache_verify_chksum(const void * _image,size_t len,void * _udata)247 H5O__cache_verify_chksum(const void *_image, size_t len, void *_udata)
248 {
249     const uint8_t *image = (const uint8_t *)_image;    	/* Pointer into raw data buffer */
250     H5O_cache_ud_t *udata = (H5O_cache_ud_t *)_udata;  	/* User data for callback */
251     htri_t ret_value = TRUE;	/* Return value */
252 
253     FUNC_ENTER_STATIC_NOERR
254 
255     /* Check arguments */
256     HDassert(image);
257     HDassert(udata);
258     HDassert(udata->oh);
259 
260     /* There is no checksum for version 1 */
261     if(udata->oh->version != H5O_VERSION_1) {
262         uint32_t stored_chksum;     /* Stored metadata checksum value */
263         uint32_t computed_chksum;   /* Computed metadata checksum value */
264 
265         /* Get stored and computed checksums */
266         H5F_get_checksums(image, len, &stored_chksum, &computed_chksum);
267 
268         if(stored_chksum != computed_chksum) {
269             /* These fields are not deserialized yet in H5O__prefix_deserialize() */
270             HDassert(udata->oh->chunk == NULL);
271             HDassert(udata->oh->mesg == NULL);
272             HDassert(udata->oh->proxy == NULL);
273 
274             /* Indicate that udata->oh is to be freed later
275                in H5O__prefix_deserialize() */
276             udata->free_oh = TRUE;
277             ret_value = FALSE;
278         } /* end if */
279     } /* end if */
280     else
281         HDassert(!(udata->common.file_intent & H5F_ACC_SWMR_WRITE));
282 
283     FUNC_LEAVE_NOAPI(ret_value)
284 } /* end H5O__cache_verify_chksum() */
285 
286 
287 /*-------------------------------------------------------------------------
288  * Function:    H5O__cache_deserialize
289  *
290  * Purpose:	Attempt to deserialize the object header contained in the
291  *		supplied buffer, load the data into an instance of H5O_t, and
292  *		return a pointer to the new instance.
293  *
294  *		Note that the object header is read with with a speculative read.
295  *		If the initial read is too small, make note of this fact and return
296  *     		without error.  H5C_load_entry() will note the size discrepency
297  *		and retry the deserialize operation with the correct size read.
298  *
299  * Return:      Success:        Pointer to in core representation
300  *              Failure:        NULL
301  *
302  * Programmer:  John Mainzer
303  *              7/28/14
304  *
305  *-------------------------------------------------------------------------
306  */
307 static void *
H5O__cache_deserialize(const void * image,size_t len,void * _udata,hbool_t * dirty)308 H5O__cache_deserialize(const void *image, size_t len, void *_udata,
309     hbool_t *dirty)
310 {
311     H5O_t          *oh = NULL;          /* Object header read in */
312     H5O_cache_ud_t *udata = (H5O_cache_ud_t *)_udata;   /* User data for callback */
313     void *          ret_value = NULL;   /* Return value */
314 
315     FUNC_ENTER_STATIC
316 
317     /* Check arguments */
318     HDassert(image);
319     HDassert(len > 0);
320     HDassert(udata);
321     HDassert(udata->common.f);
322     HDassert(udata->common.cont_msg_info);
323     HDassert(dirty);
324 
325     /* Check for partially deserialized object header */
326     /* (Object header prefix will be deserialized if the object header came
327      *  through the 'get_final_load_size' callback and not deserialized if
328      *  the object header is coming from a cache image - QAK, 2016/12/14)
329      */
330     if(NULL == udata->oh) {
331         /* Deserialize the object header prefix */
332         if(H5O__prefix_deserialize((const uint8_t *)image, udata) < 0)
333             HGOTO_ERROR(H5E_OHDR, H5E_CANTDECODE, NULL, "can't deserialize object header prefix")
334 
335         /* Sanity check */
336         HDassert(udata->oh);
337     } /* end if */
338 
339     /* Retrieve partially deserialized object header from user data */
340     oh = udata->oh;
341 
342     /* Set SWMR flag, if appropriate */
343     oh->swmr_write = !!(H5F_INTENT(udata->common.f) & H5F_ACC_SWMR_WRITE);
344 
345     /* Create object header proxy if doing SWMR writes */
346     if(oh->swmr_write) {
347         /* Create virtual entry, for use as proxy */
348         if(NULL == (oh->proxy = H5AC_proxy_entry_create()))
349             HGOTO_ERROR(H5E_OHDR, H5E_CANTCREATE, NULL, "can't create object header proxy")
350     } /* end if */
351     else
352         oh->proxy = NULL;
353 
354     /* Parse the first chunk */
355     if(H5O__chunk_deserialize(oh, udata->common.addr, udata->chunk0_size, (const uint8_t *)image, &(udata->common), dirty) < 0)
356         HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, NULL, "can't deserialize first object header chunk")
357 
358     /* Note that we've loaded the object header from the file */
359     udata->made_attempt = TRUE;
360 
361     /* Set return value */
362     ret_value = oh;
363 
364 done:
365     /* Release the [possibly partially initialized] object header on errors */
366     if(!ret_value && oh)
367         if(H5O__free(oh) < 0)
368             HDONE_ERROR(H5E_OHDR, H5E_CANTRELEASE, NULL, "unable to destroy object header data")
369 
370     FUNC_LEAVE_NOAPI(ret_value)
371 } /* end H5O__cache_deserialize() */
372 
373 
374 /*-------------------------------------------------------------------------
375  * Function:    H5O__cache_image_len
376  *
377  * Purpose:	Compute the size in bytes of the specified instance of
378  *		H5O_t on disk, and return it in *image_len.  On failure,
379  *		the value of *image_len is undefined.
380  *
381  * Return:      Success:        SUCCEED
382  *              Failure:        FAIL
383  *
384  * Programmer:  John Mainzer
385  *              7/28/14
386  *
387  *-------------------------------------------------------------------------
388  */
389 static herr_t
H5O__cache_image_len(const void * _thing,size_t * image_len)390 H5O__cache_image_len(const void *_thing, size_t *image_len)
391 {
392     const H5O_t *oh = (const H5O_t *)_thing;    /* Object header to query */
393 
394     FUNC_ENTER_STATIC_NOERR
395 
396     /* Check arguments */
397     HDassert(oh);
398     HDassert(oh->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
399     HDassert(oh->cache_info.type == H5AC_OHDR);
400     HDassert(image_len);
401 
402     /* Report the object header's prefix+first chunk length */
403     *image_len = oh->chunk[0].size;
404 
405     FUNC_LEAVE_NOAPI(SUCCEED)
406 } /* end H5O__cache_image_len() */
407 
408 
409 /*-------------------------------------------------------------------------
410  * Function:    H5O__cache_serialize
411  *
412  * Purpose:	Serialize the contents of the supplied object header, and
413  *		load this data into the supplied buffer.
414  *
415  * Return:      Success:        SUCCEED
416  *              Failure:        FAIL
417  *
418  * Programmer:  John Mainzer
419  *              7/28/14
420  *
421  *-------------------------------------------------------------------------
422  */
423 static herr_t
H5O__cache_serialize(const H5F_t * f,void * image,size_t len,void * _thing)424 H5O__cache_serialize(const H5F_t *f, void *image, size_t len, void *_thing)
425 {
426     H5O_t      *oh = (H5O_t *)_thing;   /* Object header to encode */
427     uint8_t     *chunk_image;           /* Pointer to object header prefix buffer */
428     herr_t      ret_value = SUCCEED;    /* Return value */
429 
430     FUNC_ENTER_STATIC
431 
432     /* Check arguments */
433     HDassert(f);
434     HDassert(image);
435     HDassert(oh);
436     HDassert(oh->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
437     HDassert(oh->cache_info.type == H5AC_OHDR);
438     HDassert(oh->chunk[0].size == len);
439 #ifdef H5O_DEBUG
440     H5O_assert(oh);
441 #endif /* H5O_DEBUG */
442 
443     /* Point to raw data 'image' for first chunk, which
444      * has room for the prefix
445      */
446     chunk_image = oh->chunk[0].image;
447 
448     /* Later versions of object header prefix have different format and
449      * also require that chunk 0 always be updated, since the checksum
450      * on the entire block of memory needs to be updated if anything is
451      * modified
452      */
453     if(oh->version > H5O_VERSION_1) {
454         uint64_t chunk0_size;       /* Size of chunk 0's data */
455 
456         HDassert(oh->chunk[0].size >= (size_t)H5O_SIZEOF_HDR(oh));
457         chunk0_size = oh->chunk[0].size - (size_t)H5O_SIZEOF_HDR(oh);
458 
459         /* Verify magic number */
460         HDassert(!HDmemcmp(chunk_image, H5O_HDR_MAGIC, H5_SIZEOF_MAGIC));
461         chunk_image += H5_SIZEOF_MAGIC;
462 
463         /* Version */
464         *chunk_image++ = oh->version;
465 
466         /* Flags */
467         *chunk_image++ = oh->flags;
468 
469         /* Time fields */
470         if(oh->flags & H5O_HDR_STORE_TIMES) {
471             UINT32ENCODE(chunk_image, oh->atime);
472             UINT32ENCODE(chunk_image, oh->mtime);
473             UINT32ENCODE(chunk_image, oh->ctime);
474             UINT32ENCODE(chunk_image, oh->btime);
475         } /* end if */
476 
477         /* Attribute fields */
478         if(oh->flags & H5O_HDR_ATTR_STORE_PHASE_CHANGE) {
479             UINT16ENCODE(chunk_image, oh->max_compact);
480             UINT16ENCODE(chunk_image, oh->min_dense);
481         } /* end if */
482 
483         /* First chunk size */
484         switch(oh->flags & H5O_HDR_CHUNK0_SIZE) {
485             case 0:     /* 1 byte size */
486                 HDassert(chunk0_size < 256);
487                 *chunk_image++ = (uint8_t)chunk0_size;
488                 break;
489 
490             case 1:     /* 2 byte size */
491                 HDassert(chunk0_size < 65536);
492                 UINT16ENCODE(chunk_image, chunk0_size);
493                 break;
494 
495             case 2:     /* 4 byte size */
496                 /* use <= 2**32 -1 to stay within 4 bytes integer range */
497                 HDassert(chunk0_size <= 4294967295UL);
498                 UINT32ENCODE(chunk_image, chunk0_size);
499                 break;
500 
501             case 3:     /* 8 byte size */
502                 UINT64ENCODE(chunk_image, chunk0_size);
503                 break;
504 
505             default:
506                 HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, FAIL, "bad size for chunk 0")
507         } /* end switch */
508     } /* end if */
509     else {
510         /* Version */
511         *chunk_image++ = oh->version;
512 
513         /* Reserved */
514         *chunk_image++ = 0;
515 
516         /* Number of messages */
517 #ifdef H5O_ENABLE_BAD_MESG_COUNT
518         if(oh->store_bad_mesg_count)
519            UINT16ENCODE(chunk_image, (oh->nmesgs - 1))
520         else
521 #endif /* H5O_ENABLE_BAD_MESG_COUNT */
522             UINT16ENCODE(chunk_image, oh->nmesgs);
523 
524         /* Link count */
525         UINT32ENCODE(chunk_image, oh->nlink);
526 
527         /* First chunk size */
528         UINT32ENCODE(chunk_image, (oh->chunk[0].size - (size_t)H5O_SIZEOF_HDR(oh)));
529 
530         /* Zero to alignment */
531         HDmemset(chunk_image, 0, (size_t)(H5O_SIZEOF_HDR(oh) - 12));
532         chunk_image += (size_t)(H5O_SIZEOF_HDR(oh) - 12);
533     } /* end else */
534 
535     HDassert((size_t)(chunk_image - oh->chunk[0].image) == (size_t)(H5O_SIZEOF_HDR(oh) - H5O_SIZEOF_CHKSUM_OH(oh)));
536 
537     /* Serialize messages for this chunk */
538     if(H5O__chunk_serialize(f, oh, (unsigned)0) < 0)
539         HGOTO_ERROR(H5E_OHDR, H5E_CANTSERIALIZE, FAIL, "unable to serialize first object header chunk")
540 
541     /* copy the chunk into the image -- this is potentially expensive.
542      * Can we rework things so that the object header and the cache
543      * share a buffer?
544      */
545     HDmemcpy(image, oh->chunk[0].image, len);
546 
547 done:
548     FUNC_LEAVE_NOAPI(ret_value)
549 } /* end H5O__cache_serialize() */
550 
551 
552 /*-------------------------------------------------------------------------
553  * Function:    H5O__cache_notify
554  *
555  * Purpose:     Handle cache action notifications
556  *
557  * Return:      Non-negative on success/Negative on failure
558  *
559  * Programmer:  Quincey Koziol
560  *              Jul 23 2016
561  *
562  *-------------------------------------------------------------------------
563  */
564 static herr_t
H5O__cache_notify(H5AC_notify_action_t action,void * _thing)565 H5O__cache_notify(H5AC_notify_action_t action, void *_thing)
566 {
567     H5O_t *oh = (H5O_t *)_thing;
568     herr_t ret_value = SUCCEED;         /* Return value */
569 
570     FUNC_ENTER_STATIC
571 
572     /*
573      * Check arguments.
574      */
575     HDassert(oh);
576 
577     switch(action) {
578         case H5AC_NOTIFY_ACTION_AFTER_INSERT:
579         case H5AC_NOTIFY_ACTION_AFTER_LOAD:
580             if(oh->swmr_write) {
581                 /* Sanity check */
582                 HDassert(oh->proxy);
583 
584                 /* Register the object header as a parent of the virtual entry */
585                 if(H5AC_proxy_entry_add_parent(oh->proxy, oh) < 0)
586                     HGOTO_ERROR(H5E_OHDR, H5E_CANTSET, FAIL, "can't add object header as parent of proxy")
587             } /* end if */
588             break;
589 
590         case H5AC_NOTIFY_ACTION_AFTER_FLUSH:
591         case H5AC_NOTIFY_ACTION_ENTRY_DIRTIED:
592             /* do nothing */
593             break;
594 
595         case H5AC_NOTIFY_ACTION_ENTRY_CLEANED:
596             {
597                 unsigned            u;                      /* Local index variable */
598 
599                 /* Mark messages stored with the object header (i.e. messages in chunk 0) as clean */
600                 for(u = 0; u < oh->nmesgs; u++)
601                     if(oh->mesg[u].chunkno == 0)
602                         oh->mesg[u].dirty = FALSE;
603 #ifndef NDEBUG
604                 /* Reset the number of messages dirtied by decoding */
605                 oh->ndecode_dirtied = 0;
606 #endif /* NDEBUG */
607             }
608             break;
609 
610         case H5AC_NOTIFY_ACTION_CHILD_DIRTIED:
611         case H5AC_NOTIFY_ACTION_CHILD_CLEANED:
612 	case H5AC_NOTIFY_ACTION_CHILD_UNSERIALIZED:
613 	case H5AC_NOTIFY_ACTION_CHILD_SERIALIZED:
614             /* do nothing */
615             break;
616 
617         case H5AC_NOTIFY_ACTION_BEFORE_EVICT:
618             if(oh->swmr_write) {
619                 /* Unregister the object header as a parent of the virtual entry */
620                 if(H5AC_proxy_entry_remove_parent(oh->proxy, oh) < 0)
621                     HGOTO_ERROR(H5E_OHDR, H5E_CANTSET, FAIL, "can't remove object header as parent of proxy")
622             } /* end if */
623             break;
624 
625         default:
626             HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, FAIL, "unknown action from metadata cache")
627     } /* end switch */
628 
629 done:
630     FUNC_LEAVE_NOAPI(ret_value)
631 } /* end H5O__cache_notify() */
632 
633 
634 /*-------------------------------------------------------------------------
635  * Function:    H5O__cache_free_icr
636  *
637  * Purpose:	Free the in core representation of the supplied object header.
638  *
639  * Note:	The metadata cache sets the object's cache_info.magic to
640  *		H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC before calling a free_icr
641  *		callback (checked in assert).
642  *
643  * Return:      Success:        SUCCEED
644  *              Failure:        FAIL
645  *
646  * Programmer:  John Mainzer
647  *              7/28/14
648  *
649  *-------------------------------------------------------------------------
650  */
651 static herr_t
H5O__cache_free_icr(void * _thing)652 H5O__cache_free_icr(void *_thing)
653 {
654     H5O_t      *oh = (H5O_t *)_thing;   /* Object header to destroy */
655     herr_t      ret_value = SUCCEED;    /* Return value */
656 
657     FUNC_ENTER_STATIC
658 
659     /* Check arguments */
660     HDassert(oh);
661     HDassert(oh->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC);
662     HDassert(oh->cache_info.type == H5AC_OHDR);
663 
664     /* Destroy object header */
665     if(H5O__free(oh) < 0)
666         HGOTO_ERROR(H5E_OHDR, H5E_CANTRELEASE, FAIL, "can't destroy object header")
667 
668 done:
669     FUNC_LEAVE_NOAPI(ret_value)
670 } /* end H5O__cache_free_icr() */
671 
672 
673 /*-------------------------------------------------------------------------
674  * Function:    H5O__cache_chk_get_initial_load_size()
675  *
676  * Purpose:	Tell the metadata cache how large the on disk image of the
677  *		chunk proxy is, so it can load the image into a buffer for the
678  *		deserialize call.
679  *
680  * Return:      Success:        SUCCEED
681  *              Failure:        FAIL
682  *
683  * Programmer:  John Mainzer
684  *              7/28/14
685  *
686  *-------------------------------------------------------------------------
687  */
688 static herr_t
H5O__cache_chk_get_initial_load_size(void * _udata,size_t * image_len)689 H5O__cache_chk_get_initial_load_size(void *_udata, size_t *image_len)
690 {
691     const H5O_chk_cache_ud_t *udata = (const H5O_chk_cache_ud_t *)_udata; /* User data for callback */
692 
693     FUNC_ENTER_STATIC_NOERR
694 
695     /* Check arguments */
696     HDassert(udata);
697     HDassert(udata->oh);
698     HDassert(image_len);
699 
700     /* Set the image length size */
701     *image_len = udata->size;
702 
703     FUNC_LEAVE_NOAPI(SUCCEED)
704 } /* end H5O__cache_chk_get_initial_load_size() */
705 
706 
707 /*-------------------------------------------------------------------------
708  * Function:    H5B2__cache_chk_verify_chksum
709  *
710  * Purpose:     Verify the computed checksum of the data structure is the
711  *              same as the stored chksum.
712  *
713  * Return:      Success:        TRUE/FALSE
714  *              Failure:        Negative
715  *
716  * Programmer:  Vailin Choi
717  *		Aug 2015
718  *
719  *-------------------------------------------------------------------------
720  */
721 static htri_t
H5O__cache_chk_verify_chksum(const void * _image,size_t len,void * _udata)722 H5O__cache_chk_verify_chksum(const void *_image, size_t len, void *_udata)
723 {
724     const uint8_t *image = (const uint8_t *)_image;       	/* Pointer into raw data buffer */
725     H5O_chk_cache_ud_t *udata = (H5O_chk_cache_ud_t *)_udata;   /* User data for callback */
726     htri_t ret_value = TRUE;	/* Return value */
727 
728     FUNC_ENTER_STATIC_NOERR
729 
730     /* Check arguments */
731     HDassert(image);
732 
733     /* There is no checksum for version 1 */
734     if(udata->oh->version != H5O_VERSION_1) {
735         uint32_t stored_chksum;     /* Stored metadata checksum value */
736         uint32_t computed_chksum;   /* Computed metadata checksum value */
737 
738 	/* Get stored and computed checksums */
739 	H5F_get_checksums(image, len, &stored_chksum, &computed_chksum);
740 
741 	if(stored_chksum != computed_chksum)
742 	    ret_value = FALSE;
743     } /* end if */
744 
745     FUNC_LEAVE_NOAPI(ret_value)
746 } /* end H5O__cache_chk_verify_chksum() */
747 
748 
749 /*-------------------------------------------------------------------------
750  * Function:    H5O__cache_chk_deserialize
751  *
752  * Purpose:	Attempt to deserialize the object header continuation chunk
753  *		contained in the supplied buffer, load the data into an instance
754  *		of H5O_chunk_proxy_t, and return a pointer to the new instance.
755  *
756  * Return:      Success:        Pointer to in core representation
757  *              Failure:        NULL
758  *
759  * Programmer:  John Mainzer
760  *              7/28/14
761  *
762  *-------------------------------------------------------------------------
763  */
764 static void *
H5O__cache_chk_deserialize(const void * image,size_t len,void * _udata,hbool_t * dirty)765 H5O__cache_chk_deserialize(const void *image, size_t len, void *_udata,
766     hbool_t *dirty)
767 {
768     H5O_chunk_proxy_t  *chk_proxy = NULL;       /* Chunk proxy object */
769     H5O_chk_cache_ud_t *udata = (H5O_chk_cache_ud_t *)_udata;   /* User data for callback */
770     void		*ret_value = NULL;      /* Return value */
771 
772     FUNC_ENTER_STATIC
773 
774     /* Check arguments */
775     HDassert(image);
776     HDassert(len > 0);
777     HDassert(udata);
778     HDassert(udata->oh);
779     HDassert(dirty);
780 
781     /* Allocate space for the object header data structure */
782     if(NULL == (chk_proxy = H5FL_CALLOC(H5O_chunk_proxy_t)))
783         HGOTO_ERROR(H5E_OHDR, H5E_CANTALLOC, NULL, "memory allocation failed")
784 
785     /* Check if we are still decoding the object header */
786     /* (as opposed to bringing a piece of it back from the file) */
787     if(udata->decoding) {
788         /* Sanity check */
789         HDassert(udata->common.f);
790         HDassert(udata->common.cont_msg_info);
791 
792         /* Parse the chunk */
793         if(H5O__chunk_deserialize(udata->oh, udata->common.addr, udata->size, (const uint8_t *)image, &(udata->common), dirty) < 0)
794             HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, NULL, "can't deserialize object header chunk")
795 
796         /* Set the chunk number for the chunk proxy */
797         H5_CHECKED_ASSIGN(chk_proxy->chunkno, unsigned, udata->oh->nchunks - 1, size_t);
798     } /* end if */
799     else {
800         /* Sanity check */
801         HDassert(udata->chunkno < udata->oh->nchunks);
802 
803         /* Set the chunk number for the chunk proxy */
804         chk_proxy->chunkno = udata->chunkno;
805 
806         /* Sanity check that the chunk representation we have in memory is
807          * the same as the one being brought in from disk.
808          */
809         HDassert(0 == HDmemcmp(image, udata->oh->chunk[chk_proxy->chunkno].image, udata->oh->chunk[chk_proxy->chunkno].size));
810     } /* end else */
811 
812     /* Increment reference count of object header */
813     if(H5O__inc_rc(udata->oh) < 0)
814         HGOTO_ERROR(H5E_OHDR, H5E_CANTINC, NULL, "can't increment reference count on object header")
815     chk_proxy->oh = udata->oh;
816 
817     /* Set return value */
818     ret_value = chk_proxy;
819 
820 done:
821     if(NULL == ret_value)
822         if(chk_proxy && H5O__chunk_dest(chk_proxy) < 0)
823             HDONE_ERROR(H5E_OHDR, H5E_CANTRELEASE, NULL, "unable to destroy object header chunk")
824 
825     FUNC_LEAVE_NOAPI(ret_value)
826 } /* end H5O__cache_chk_deserialize() */
827 
828 
829 /*-------------------------------------------------------------------------
830  * Function:    H5O__cache_chk_image_len
831  *
832  * Purpose:	Return the on disk image size of a object header chunk to the
833  *		metadata cache via the image_len.
834  *
835  * Return:      Success:        SUCCEED
836  *              Failure:        FAIL
837  *
838  * Programmer:  John Mainzer
839  *              7/28/14
840  *
841  *-------------------------------------------------------------------------
842  */
843 static herr_t
H5O__cache_chk_image_len(const void * _thing,size_t * image_len)844 H5O__cache_chk_image_len(const void *_thing, size_t *image_len)
845 {
846     const H5O_chunk_proxy_t * chk_proxy = (const H5O_chunk_proxy_t *)_thing;    /* Chunk proxy to query */
847 
848     FUNC_ENTER_STATIC_NOERR
849 
850     /* Check arguments */
851     HDassert(chk_proxy);
852     HDassert(chk_proxy->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
853     HDassert(chk_proxy->cache_info.type == H5AC_OHDR_CHK);
854     HDassert(chk_proxy->oh);
855     HDassert(image_len);
856 
857     *image_len = chk_proxy->oh->chunk[chk_proxy->chunkno].size;
858 
859     FUNC_LEAVE_NOAPI(SUCCEED)
860 } /* end H5O__cache_chk_image_len() */
861 
862 
863 /*-------------------------------------------------------------------------
864  * Function:    H5O__cache_chk_serialize
865  *
866  * Purpose:	Given a pointer to an instance of an object header chunk and an
867  *		appropriately sized buffer, serialize the contents of the
868  *		instance for writing to disk, and copy the serialized data
869  *		into the buffer.
870  *
871  * Return:      Success:        SUCCEED
872  *              Failure:        FAIL
873  *
874  * Programmer:  John Mainzer
875  *              7/28/14
876  *
877  *-------------------------------------------------------------------------
878  */
879 static herr_t
H5O__cache_chk_serialize(const H5F_t * f,void * image,size_t len,void * _thing)880 H5O__cache_chk_serialize(const H5F_t *f, void *image, size_t len, void *_thing)
881 {
882     H5O_chunk_proxy_t * chk_proxy = (H5O_chunk_proxy_t *)_thing;        /* Object header chunk to serialize */
883     herr_t              ret_value = SUCCEED;    /* Return value */
884 
885     FUNC_ENTER_STATIC
886 
887     /* Check arguments */
888     HDassert(f);
889     HDassert(image);
890     HDassert(chk_proxy);
891     HDassert(chk_proxy->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
892     HDassert(chk_proxy->cache_info.type == H5AC_OHDR_CHK);
893     HDassert(chk_proxy->oh);
894     HDassert(chk_proxy->oh->chunk[chk_proxy->chunkno].size == len);
895 
896     /* Serialize messages for this chunk */
897     if(H5O__chunk_serialize(f, chk_proxy->oh, chk_proxy->chunkno) < 0)
898         HGOTO_ERROR(H5E_OHDR, H5E_CANTSERIALIZE, FAIL, "unable to serialize object header continuation chunk")
899 
900     /* copy the chunk into the image -- this is potentially expensive.
901      * Can we rework things so that the chunk and the cache share a buffer?
902      */
903     HDmemcpy(image, chk_proxy->oh->chunk[chk_proxy->chunkno].image, len);
904 
905 done:
906     FUNC_LEAVE_NOAPI(ret_value)
907 } /* end H5O__cache_chk_serialize() */
908 
909 
910 /*-------------------------------------------------------------------------
911  * Function:    H5O__cache_chk_notify
912  *
913  * Purpose:     Handle cache action notifications
914  *
915  * Return:      Non-negative on success/Negative on failure
916  *
917  * Programmer:  Neil Fortner
918  *              Mar 20 2012
919  *
920  *-------------------------------------------------------------------------
921  */
922 static herr_t
H5O__cache_chk_notify(H5AC_notify_action_t action,void * _thing)923 H5O__cache_chk_notify(H5AC_notify_action_t action, void *_thing)
924 {
925     H5O_chunk_proxy_t *chk_proxy = (H5O_chunk_proxy_t *)_thing;
926     herr_t ret_value = SUCCEED;         /* Return value */
927 
928     FUNC_ENTER_STATIC
929 
930     /*
931      * Check arguments.
932      */
933     HDassert(chk_proxy);
934     HDassert(chk_proxy->oh);
935 
936     switch(action) {
937         case H5AC_NOTIFY_ACTION_AFTER_INSERT:
938         case H5AC_NOTIFY_ACTION_AFTER_LOAD:
939             if(chk_proxy->oh->swmr_write) {
940                 /* Add flush dependency on chunk with continuation, if one exists */
941                 if(chk_proxy->fd_parent) {
942                     /* Sanity checks */
943                     HDassert(((H5C_cache_entry_t *)(chk_proxy->fd_parent))->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
944                     HDassert(((H5C_cache_entry_t *)(chk_proxy->fd_parent))->type);
945                     HDassert((((H5C_cache_entry_t *)(chk_proxy->fd_parent))->type->id == H5AC_OHDR_ID)
946                              || (((H5C_cache_entry_t *)(chk_proxy->fd_parent))->type->id == H5AC_OHDR_CHK_ID));
947 
948                     /* Add flush dependency from chunk containing the continuation message
949                      * that points to this chunk (either oh or another chunk proxy object)
950                      */
951                     if(H5AC_create_flush_dependency(chk_proxy->fd_parent, chk_proxy) < 0)
952                         HGOTO_ERROR(H5E_OHDR, H5E_CANTDEPEND, FAIL, "unable to create flush dependency")
953                 } /* end if */
954 
955                 /* Add flush dependency on object header */
956                 {
957                     if(H5AC_create_flush_dependency(chk_proxy->oh, chk_proxy) < 0)
958                         HGOTO_ERROR(H5E_OHDR, H5E_CANTDEPEND, FAIL, "unable to create flush dependency")
959                 } /* end if */
960 
961                 /* Add flush dependency on object header proxy, if proxy exists */
962                 {
963                     /* Sanity check */
964                     HDassert(chk_proxy->oh->proxy);
965 
966                     /* Register the object header chunk as a parent of the virtual entry */
967                     if(H5AC_proxy_entry_add_parent(chk_proxy->oh->proxy, chk_proxy) < 0)
968                         HGOTO_ERROR(H5E_OHDR, H5E_CANTSET, FAIL, "can't add object header chunk as parent of proxy")
969                 }
970             } /* end if */
971             break;
972 
973         case H5AC_NOTIFY_ACTION_AFTER_FLUSH:
974         case H5AC_NOTIFY_ACTION_ENTRY_DIRTIED:
975             /* do nothing */
976             break;
977 
978         case H5AC_NOTIFY_ACTION_ENTRY_CLEANED:
979             {
980                 unsigned            u;                      /* Local index variable */
981 
982                 /* Mark messages in chunk as clean */
983                 for(u = 0; u < chk_proxy->oh->nmesgs; u++)
984                     if(chk_proxy->oh->mesg[u].chunkno == chk_proxy->chunkno)
985                         chk_proxy->oh->mesg[u].dirty = FALSE;
986             }
987             break;
988 
989         case H5AC_NOTIFY_ACTION_CHILD_DIRTIED:
990         case H5AC_NOTIFY_ACTION_CHILD_CLEANED:
991 	case H5AC_NOTIFY_ACTION_CHILD_UNSERIALIZED:
992 	case H5AC_NOTIFY_ACTION_CHILD_SERIALIZED:
993             /* do nothing */
994             break;
995 
996         case H5AC_NOTIFY_ACTION_BEFORE_EVICT:
997             if(chk_proxy->oh->swmr_write) {
998                 /* Remove flush dependency on parent object header chunk, if one is set */
999                 if(chk_proxy->fd_parent) {
1000                     /* Sanity checks */
1001                     HDassert(((H5C_cache_entry_t *)(chk_proxy->fd_parent))->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
1002                     HDassert(((H5C_cache_entry_t *)(chk_proxy->fd_parent))->type);
1003                     HDassert((((H5C_cache_entry_t *)(chk_proxy->fd_parent))->type->id == H5AC_OHDR_ID) || (((H5C_cache_entry_t *)(chk_proxy->fd_parent))->type->id == H5AC_OHDR_CHK_ID));
1004 
1005                     if(H5AC_destroy_flush_dependency(chk_proxy->fd_parent, chk_proxy) < 0)
1006                         HGOTO_ERROR(H5E_OHDR, H5E_CANTUNDEPEND, FAIL, "unable to destroy flush dependency")
1007                     chk_proxy->fd_parent = NULL;
1008                 } /* end if */
1009 
1010                 /* Unregister the object header as a parent of the virtual entry */
1011                 if(H5AC_destroy_flush_dependency(chk_proxy->oh, chk_proxy) < 0)
1012                     HGOTO_ERROR(H5E_OHDR, H5E_CANTUNDEPEND, FAIL, "unable to destroy flush dependency")
1013 
1014                 /* Unregister the object header chunk as a parent of the virtual entry */
1015                 if(H5AC_proxy_entry_remove_parent(chk_proxy->oh->proxy, chk_proxy) < 0)
1016                     HGOTO_ERROR(H5E_OHDR, H5E_CANTSET, FAIL, "can't remove object header chunk as parent of proxy")
1017             } /* end if */
1018             break;
1019 
1020         default:
1021 #ifdef NDEBUG
1022             HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, FAIL, "unknown action from metadata cache")
1023 #else /* NDEBUG */
1024             HDassert(0 && "Unknown action?!?");
1025 #endif /* NDEBUG */
1026     } /* end switch */
1027 
1028 done:
1029     FUNC_LEAVE_NOAPI(ret_value)
1030 } /* end H5O__cache_chk_notify() */
1031 
1032 
1033 /*-------------------------------------------------------------------------
1034  * Function:    H5O__cache_chk_free_icr
1035  *
1036  * Purpose:	Free the in core memory associated with the supplied object
1037  *		header continuation chunk.
1038  *
1039  * Note:	The metadata cache sets the object's cache_info.magic to
1040  *		H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC before calling a free_icr
1041  *		callback (checked in assert).
1042  *
1043  * Return:      Success:        SUCCEED
1044  *              Failure:        FAIL
1045  *
1046  * Programmer:  John Mainzer
1047  *              7/28/14
1048  *
1049  *-------------------------------------------------------------------------
1050  */
1051 static herr_t
H5O__cache_chk_free_icr(void * _thing)1052 H5O__cache_chk_free_icr(void *_thing)
1053 {
1054     H5O_chunk_proxy_t * chk_proxy = (H5O_chunk_proxy_t *)_thing;        /* Object header chunk proxy to release */
1055     herr_t              ret_value = SUCCEED;    /* Return value */
1056 
1057     FUNC_ENTER_STATIC
1058 
1059     /* Check arguments */
1060     HDassert(chk_proxy);
1061     HDassert(chk_proxy->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC);
1062     HDassert(chk_proxy->cache_info.type == H5AC_OHDR_CHK);
1063 
1064     /* Destroy object header chunk proxy */
1065     if(H5O__chunk_dest(chk_proxy) < 0)
1066         HGOTO_ERROR(H5E_OHDR, H5E_CANTRELEASE, FAIL, "unable to destroy object header chunk proxy")
1067 
1068 done:
1069     FUNC_LEAVE_NOAPI(ret_value)
1070 } /* end H5O__cache_chk_free_icr() */
1071 
1072 
1073 /*-------------------------------------------------------------------------
1074  * Function:	H5O__add_cont_msg
1075  *
1076  * Purpose:	Add information from a continuation message to the list of
1077  *              continuation messages in the object header
1078  *
1079  * Return:	Success: SUCCEED
1080  *              Failure: FAIL
1081  *
1082  * Programmer:	Quincey Koziol
1083  *              koziol@hdfgroup.org
1084  *              July 12, 2008
1085  *
1086  *-------------------------------------------------------------------------
1087  */
1088 static herr_t
H5O__add_cont_msg(H5O_cont_msgs_t * cont_msg_info,const H5O_cont_t * cont)1089 H5O__add_cont_msg(H5O_cont_msgs_t *cont_msg_info, const H5O_cont_t *cont)
1090 {
1091     size_t contno;              /* Continuation message index */
1092     herr_t ret_value = SUCCEED; /* Return value */
1093 
1094     FUNC_ENTER_STATIC
1095 
1096     /* Check arguments */
1097     HDassert(cont_msg_info);
1098     HDassert(cont);
1099 
1100     /* Increase chunk array size, if necessary */
1101     if(cont_msg_info->nmsgs >= cont_msg_info->alloc_nmsgs) {
1102         size_t na = MAX(H5O_NCHUNKS, cont_msg_info->alloc_nmsgs * 2);        /* Double # of messages allocated */
1103         H5O_cont_t *x;
1104 
1105         if(NULL == (x = H5FL_SEQ_REALLOC(H5O_cont_t, cont_msg_info->msgs, na)))
1106             HGOTO_ERROR(H5E_OHDR, H5E_NOSPACE, FAIL, "memory allocation failed")
1107         cont_msg_info->alloc_nmsgs = na;
1108         cont_msg_info->msgs = x;
1109     } /* end if */
1110 
1111     /* Init the continuation message info */
1112     contno = cont_msg_info->nmsgs++;
1113     cont_msg_info->msgs[contno].addr = cont->addr;
1114     cont_msg_info->msgs[contno].size = cont->size;
1115     cont_msg_info->msgs[contno].chunkno = cont->chunkno;
1116 
1117 done:
1118     FUNC_LEAVE_NOAPI(ret_value)
1119 } /* H5O__add_cont_msg() */
1120 
1121 
1122 /*-------------------------------------------------------------------------
1123  * Function:    H5O__prefix_deserialize()
1124  *
1125  * Purpose:	Deserialize an object header prefix
1126  *
1127  * Return:      Success:        SUCCEED
1128  *              Failure:        FAIL
1129  *
1130  * Programmer:  Quincey Koziol
1131  *              December 14, 2016
1132  *
1133  *-------------------------------------------------------------------------
1134  */
1135 static herr_t
H5O__prefix_deserialize(const uint8_t * _image,H5O_cache_ud_t * udata)1136 H5O__prefix_deserialize(const uint8_t *_image, H5O_cache_ud_t *udata)
1137 {
1138     const uint8_t *image = (const uint8_t *)_image;   	/* Pointer into raw data buffer */
1139     H5O_t *oh = NULL;                   /* Object header read in */
1140     herr_t ret_value = SUCCEED;         /* Return value */
1141 
1142     FUNC_ENTER_STATIC
1143 
1144     /* Check arguments */
1145     HDassert(image);
1146     HDassert(udata);
1147 
1148     /* Allocate space for the new object header data structure */
1149     if(NULL == (oh = H5FL_CALLOC(H5O_t)))
1150         HGOTO_ERROR(H5E_OHDR, H5E_CANTALLOC, FAIL, "memory allocation failed")
1151 
1152     /* File-specific, non-stored information */
1153     oh->sizeof_size = H5F_SIZEOF_SIZE(udata->common.f);
1154     oh->sizeof_addr = H5F_SIZEOF_ADDR(udata->common.f);
1155 
1156     /* Check for presence of magic number */
1157     /* (indicates version 2 or later) */
1158     if(!HDmemcmp(image, H5O_HDR_MAGIC, (size_t)H5_SIZEOF_MAGIC)) {
1159         /* Magic number */
1160         image += H5_SIZEOF_MAGIC;
1161 
1162         /* Version */
1163         oh->version = *image++;
1164         if(H5O_VERSION_2 != oh->version)
1165             HGOTO_ERROR(H5E_OHDR, H5E_VERSION, FAIL, "bad object header version number")
1166 
1167         /* Flags */
1168         oh->flags = *image++;
1169         if(oh->flags & ~H5O_HDR_ALL_FLAGS)
1170             HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, FAIL, "unknown object header status flag(s)")
1171 
1172         /* Number of links to object (unless overridden by refcount message) */
1173         oh->nlink = 1;
1174 
1175         /* Time fields */
1176         if(oh->flags & H5O_HDR_STORE_TIMES) {
1177             uint32_t tmp;       /* Temporary value */
1178 
1179             UINT32DECODE(image, tmp);
1180             oh->atime = (time_t)tmp;
1181             UINT32DECODE(image, tmp);
1182             oh->mtime = (time_t)tmp;
1183             UINT32DECODE(image, tmp);
1184             oh->ctime = (time_t)tmp;
1185             UINT32DECODE(image, tmp);
1186             oh->btime = (time_t)tmp;
1187         } /* end if */
1188         else
1189             oh->atime = oh->mtime = oh->ctime = oh->btime = 0;
1190 
1191         /* Attribute fields */
1192         if(oh->flags & H5O_HDR_ATTR_STORE_PHASE_CHANGE) {
1193             UINT16DECODE(image, oh->max_compact);
1194             UINT16DECODE(image, oh->min_dense);
1195             if(oh->max_compact < oh->min_dense)
1196                 HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, FAIL, "bad object header attribute phase change values")
1197         } /* end if */
1198         else {
1199             oh->max_compact = H5O_CRT_ATTR_MAX_COMPACT_DEF;
1200             oh->min_dense = H5O_CRT_ATTR_MIN_DENSE_DEF;
1201         } /* end else */
1202 
1203         /* First chunk size */
1204         switch(oh->flags & H5O_HDR_CHUNK0_SIZE) {
1205             case 0:     /* 1 byte size */
1206                 udata->chunk0_size = *image++;
1207                 break;
1208 
1209             case 1:     /* 2 byte size */
1210                 UINT16DECODE(image, udata->chunk0_size);
1211                 break;
1212 
1213             case 2:     /* 4 byte size */
1214                 UINT32DECODE(image, udata->chunk0_size);
1215                 break;
1216 
1217             case 3:     /* 8 byte size */
1218                 UINT64DECODE(image, udata->chunk0_size);
1219                 break;
1220 
1221             default:
1222                 HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, FAIL, "bad size for chunk 0")
1223         } /* end switch */
1224         if(udata->chunk0_size > 0 && udata->chunk0_size < H5O_SIZEOF_MSGHDR_OH(oh))
1225             HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, FAIL, "bad object header chunk size")
1226     } /* end if */
1227     else {
1228         /* Version */
1229         oh->version = *image++;
1230         if(H5O_VERSION_1 != oh->version)
1231             HGOTO_ERROR(H5E_OHDR, H5E_VERSION, FAIL, "bad object header version number")
1232 
1233         /* Flags */
1234         oh->flags = H5O_CRT_OHDR_FLAGS_DEF;
1235 
1236         /* Reserved */
1237         image++;
1238 
1239         /* Number of messages */
1240         UINT16DECODE(image, udata->v1_pfx_nmesgs);
1241 
1242         /* Link count */
1243         UINT32DECODE(image, oh->nlink);
1244 
1245         /* Reset unused time fields */
1246         oh->atime = oh->mtime = oh->ctime = oh->btime = 0;
1247 
1248         /* Reset unused attribute fields */
1249         oh->max_compact = 0;
1250         oh->min_dense = 0;
1251 
1252         /* First chunk size */
1253         UINT32DECODE(image, udata->chunk0_size);
1254         if((udata->v1_pfx_nmesgs > 0 && udata->chunk0_size < H5O_SIZEOF_MSGHDR_OH(oh)) ||
1255                 (udata->v1_pfx_nmesgs == 0 && udata->chunk0_size > 0))
1256             HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, FAIL, "bad object header chunk size")
1257 
1258         /* Reserved, in version 1 (for 8-byte alignment padding) */
1259         image += 4;
1260     } /* end else */
1261 
1262     /* Verify object header prefix length */
1263     HDassert((size_t)(image - _image) == (size_t)(H5O_SIZEOF_HDR(oh) - H5O_SIZEOF_CHKSUM_OH(oh)));
1264 
1265     /* If udata->oh is to be freed (see H5O__cache_verify_chksum),
1266        save the pointer to udata->oh and free it later after setting
1267        udata->oh with the new object header */
1268     if(udata->free_oh) {
1269         H5O_t *saved_oh = udata->oh;
1270         HDassert(udata->oh);
1271 
1272         /* Save the object header for later use in 'deserialize' callback */
1273         udata->oh = oh;
1274         if(H5O__free(saved_oh) < 0)
1275             HGOTO_ERROR(H5E_OHDR, H5E_CANTRELEASE, FAIL, "can't destroy object header")
1276         udata->free_oh = FALSE;
1277     } else
1278         /* Save the object header for later use in 'deserialize' callback */
1279         udata->oh = oh;
1280 
1281     oh = NULL;
1282 
1283 done:
1284     /* Release the [possibly partially initialized] object header on errors */
1285     if(ret_value < 0 && oh)
1286         if(H5O__free(oh) < 0)
1287             HDONE_ERROR(H5E_OHDR, H5E_CANTRELEASE, FAIL, "unable to destroy object header data")
1288 
1289     FUNC_LEAVE_NOAPI(ret_value)
1290 } /* end H5O__prefix_deserialize() */
1291 
1292 
1293 /*-------------------------------------------------------------------------
1294  * Function:	H5O__chunk_deserialize
1295  *
1296  * Purpose:	Deserialize a chunk for an object header
1297  *
1298  * Return:	Success: SUCCEED
1299  *              Failure: FAIL
1300  *
1301  * Programmer:	Quincey Koziol
1302  *              koziol@hdfgroup.org
1303  *              July 12, 2008
1304  *
1305  *-------------------------------------------------------------------------
1306  */
1307 static herr_t
H5O__chunk_deserialize(H5O_t * oh,haddr_t addr,size_t len,const uint8_t * image,H5O_common_cache_ud_t * udata,hbool_t * dirty)1308 H5O__chunk_deserialize(H5O_t *oh, haddr_t addr, size_t len, const uint8_t *image,
1309     H5O_common_cache_ud_t *udata, hbool_t *dirty)
1310 {
1311     const uint8_t *chunk_image; /* Pointer into buffer to decode */
1312     uint8_t *eom_ptr;           /* Pointer to end of messages for a chunk */
1313     unsigned merged_null_msgs = 0;  /* Number of null messages merged together */
1314     unsigned chunkno;           /* Current chunk's index */
1315 #ifndef NDEBUG
1316     unsigned nullcnt;           /* Count of null messages (for sanity checking gaps in chunks) */
1317 #endif /* NDEBUG */
1318     hbool_t mesgs_modified = FALSE;     /* Whether any messages were modified when the object header was deserialized */
1319     herr_t ret_value = SUCCEED; /* Return value */
1320 
1321     FUNC_ENTER_STATIC
1322 
1323     /* Check arguments */
1324     HDassert(oh);
1325     HDassert(H5F_addr_defined(addr));
1326     HDassert(image);
1327     HDassert(udata->f);
1328     HDassert(udata->cont_msg_info);
1329 
1330     /* Increase chunk array size, if necessary */
1331     if(oh->nchunks >= oh->alloc_nchunks) {
1332         size_t na = MAX(H5O_NCHUNKS, oh->alloc_nchunks * 2);        /* Double # of chunks allocated */
1333         H5O_chunk_t *x;
1334 
1335         if(NULL == (x = H5FL_SEQ_REALLOC(H5O_chunk_t, oh->chunk, na)))
1336             HGOTO_ERROR(H5E_OHDR, H5E_CANTALLOC, FAIL, "memory allocation failed")
1337         oh->alloc_nchunks = na;
1338         oh->chunk = x;
1339     } /* end if */
1340 
1341     /* Init the chunk data info */
1342     chunkno = (unsigned)oh->nchunks++;
1343     oh->chunk[chunkno].gap = 0;
1344     oh->chunk[chunkno].addr = addr;
1345     if(chunkno == 0)
1346         /* First chunk's 'image' includes room for the object header prefix */
1347         oh->chunk[0].size = len + (size_t)H5O_SIZEOF_HDR(oh);
1348     else
1349         oh->chunk[chunkno].size = len;
1350     if(NULL == (oh->chunk[chunkno].image = H5FL_BLK_MALLOC(chunk_image, oh->chunk[chunkno].size)))
1351         HGOTO_ERROR(H5E_OHDR, H5E_CANTALLOC, FAIL, "memory allocation failed")
1352     oh->chunk[chunkno].chunk_proxy = NULL;
1353 
1354     /* Copy disk image into chunk's image */
1355     HDmemcpy(oh->chunk[chunkno].image, image, oh->chunk[chunkno].size);
1356 
1357     /* Point into chunk image to decode */
1358     chunk_image = oh->chunk[chunkno].image;
1359 
1360     /* Handle chunk 0 as special case */
1361     if(chunkno == 0)
1362         /* Skip over [already decoded] prefix */
1363         chunk_image += (size_t)(H5O_SIZEOF_HDR(oh) - H5O_SIZEOF_CHKSUM_OH(oh));
1364     /* Check for magic # on chunks > 0 in later versions of the format */
1365     else if(chunkno > 0 && oh->version > H5O_VERSION_1) {
1366         /* Magic number */
1367         if(HDmemcmp(chunk_image, H5O_CHK_MAGIC, (size_t)H5_SIZEOF_MAGIC))
1368             HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "wrong object header chunk signature")
1369         chunk_image += H5_SIZEOF_MAGIC;
1370     } /* end if */
1371 
1372     /* Decode messages from this chunk */
1373     eom_ptr = oh->chunk[chunkno].image + (oh->chunk[chunkno].size - H5O_SIZEOF_CHKSUM_OH(oh));
1374 #ifndef NDEBUG
1375     nullcnt = 0;
1376 #endif /* NDEBUG */
1377     while(chunk_image < eom_ptr) {
1378         size_t mesg_size;       /* Size of message read in */
1379         unsigned id;            /* ID (type) of current message */
1380         uint8_t	flags;          /* Flags for current message */
1381         H5O_msg_crt_idx_t crt_idx = 0;  /* Creation index for current message */
1382 
1383         /* Decode message prefix info */
1384 
1385         /* Version # */
1386         if(oh->version == H5O_VERSION_1)
1387             UINT16DECODE(chunk_image, id)
1388         else
1389             id = *chunk_image++;
1390 
1391         /* Message size */
1392         UINT16DECODE(chunk_image, mesg_size);
1393         if(mesg_size != H5O_ALIGN_OH(oh, mesg_size))
1394             HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "message not aligned")
1395 
1396         /* Message flags */
1397         flags = *chunk_image++;
1398         if(flags & ~H5O_MSG_FLAG_BITS)
1399             HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "unknown flag for message")
1400         if((flags & H5O_MSG_FLAG_SHARED) && (flags & H5O_MSG_FLAG_DONTSHARE))
1401             HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "bad flag combination for message")
1402         if((flags & H5O_MSG_FLAG_WAS_UNKNOWN) && (flags & H5O_MSG_FLAG_FAIL_IF_UNKNOWN_AND_OPEN_FOR_WRITE))
1403             HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "bad flag combination for message")
1404         if((flags & H5O_MSG_FLAG_WAS_UNKNOWN) && !(flags & H5O_MSG_FLAG_MARK_IF_UNKNOWN))
1405             HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "bad flag combination for message")
1406         /* Delay checking the "shareable" flag until we've made sure id
1407          * references a valid message class that this version of the library
1408          * knows about */
1409 
1410         /* Reserved bytes/creation index */
1411         if(oh->version == H5O_VERSION_1)
1412             chunk_image += 3; /*reserved*/
1413         else {
1414             /* Only decode creation index if they are being tracked */
1415             if(oh->flags & H5O_HDR_ATTR_CRT_ORDER_TRACKED)
1416                 UINT16DECODE(chunk_image, crt_idx);
1417         } /* end else */
1418 
1419         /* Try to detect invalidly formatted object header message that
1420          *  extends past end of chunk.
1421          */
1422         if(chunk_image + mesg_size > eom_ptr)
1423             HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "corrupt object header")
1424 
1425 #ifndef NDEBUG
1426         /* Increment count of null messages */
1427         if(H5O_NULL_ID == id)
1428             nullcnt++;
1429 #endif /* NDEBUG */
1430 
1431         /* Check for combining two adjacent 'null' messages */
1432         if((udata->file_intent & H5F_ACC_RDWR) &&
1433             H5O_NULL_ID == id && oh->nmesgs > 0 &&
1434             H5O_NULL_ID == oh->mesg[oh->nmesgs - 1].type->id &&
1435             oh->mesg[oh->nmesgs - 1].chunkno == chunkno) {
1436 
1437             size_t mesgno;          /* Current message to operate on */
1438 
1439             /* Combine adjacent null messages */
1440             mesgno = oh->nmesgs - 1;
1441             oh->mesg[mesgno].raw_size += (size_t)H5O_SIZEOF_MSGHDR_OH(oh) + mesg_size;
1442             oh->mesg[mesgno].dirty = TRUE;
1443             merged_null_msgs++;
1444         } /* end if */
1445         else {
1446             H5O_mesg_t *mesg;       /* Pointer to new message */
1447             unsigned ioflags = 0;   /* Flags for decode routine */
1448 
1449             /* Check if we need to extend message table to hold the new message */
1450             if(oh->nmesgs >= oh->alloc_nmesgs)
1451                 if(H5O_alloc_msgs(oh, (size_t)1) < 0)
1452                     HGOTO_ERROR(H5E_OHDR, H5E_CANTALLOC, FAIL, "can't allocate more space for messages")
1453 
1454             /* Get pointer to message to set up */
1455             mesg = &oh->mesg[oh->nmesgs];
1456 
1457             /* Increment # of messages */
1458             oh->nmesgs++;
1459 
1460             /* Initialize information about message */
1461             mesg->dirty = FALSE;
1462             mesg->flags = flags;
1463             mesg->crt_idx = crt_idx;
1464             mesg->native = NULL;
1465             mesg->raw = (uint8_t *)chunk_image;        /* Casting away const OK - QAK */
1466             mesg->raw_size = mesg_size;
1467             mesg->chunkno = chunkno;
1468 
1469             /* Point unknown messages at 'unknown' message class */
1470             /* (Usually from future versions of the library) */
1471             if(id >= H5O_UNKNOWN_ID ||
1472 #ifdef H5O_ENABLE_BOGUS
1473                id == H5O_BOGUS_VALID_ID ||
1474 #endif
1475                NULL == H5O_msg_class_g[id]) {
1476 
1477                 H5O_unknown_t *unknown;     /* Pointer to "unknown" message info */
1478 
1479                 /* Allocate "unknown" message info */
1480                 if(NULL == (unknown = H5FL_MALLOC(H5O_unknown_t)))
1481                     HGOTO_ERROR(H5E_OHDR, H5E_CANTALLOC, FAIL, "memory allocation failed")
1482 
1483                 /* Save the original message type ID */
1484                 *unknown = id;
1485 
1486                 /* Save 'native' form of unknown message */
1487                 mesg->native = unknown;
1488 
1489                 /* Set message to "unknown" class */
1490                 mesg->type = H5O_msg_class_g[H5O_UNKNOWN_ID];
1491 
1492                 /* Check for "fail if unknown" message flags */
1493                 if(((udata->file_intent & H5F_ACC_RDWR) &&
1494                     (flags & H5O_MSG_FLAG_FAIL_IF_UNKNOWN_AND_OPEN_FOR_WRITE))
1495                     || (flags & H5O_MSG_FLAG_FAIL_IF_UNKNOWN_ALWAYS))
1496                         HGOTO_ERROR(H5E_OHDR, H5E_BADMESG, FAIL, "unknown message with 'fail if unknown' flag found")
1497                 /* Check for "mark if unknown" message flag, etc. */
1498                 else if((flags & H5O_MSG_FLAG_MARK_IF_UNKNOWN) &&
1499                         !(flags & H5O_MSG_FLAG_WAS_UNKNOWN) &&
1500                         (udata->file_intent & H5F_ACC_RDWR)) {
1501 
1502                     /* Mark the message as "unknown" */
1503                     /* This is a bit aggressive, since the application may
1504                      * never change anything about the object (metadata or
1505                      * raw data), but we can sort out the finer details
1506                      * when/if we start using the flag - QAK
1507                      */
1508                     /* Also, it's possible that this functionality may not
1509                      * get invoked if the object header is brought into
1510                      * the metadata cache in some other "weird" way, like
1511                      * using H5Ocopy() - QAK
1512                      */
1513                     mesg->flags |= H5O_MSG_FLAG_WAS_UNKNOWN;
1514 
1515                     /* Mark the message and chunk as dirty */
1516                     mesg->dirty = TRUE;
1517                     mesgs_modified = TRUE;
1518                 } /* end if */
1519             } /* end if */
1520             else {
1521                 /* Check for message of unshareable class marked as "shareable"
1522                  */
1523                 if((flags & H5O_MSG_FLAG_SHAREABLE)
1524                         && H5O_msg_class_g[id]
1525                         && !(H5O_msg_class_g[id]->share_flags & H5O_SHARE_IS_SHARABLE))
1526                     HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "message of unshareable class flagged as shareable")
1527 
1528                 /* Set message class for "known" messages */
1529                 mesg->type = H5O_msg_class_g[id];
1530             } /* end else */
1531 
1532             /* Do some inspection/interpretation of new messages from this chunk */
1533             /* (detect continuation messages, ref. count messages, etc.) */
1534 
1535             /* Check if message is a continuation message */
1536             if(H5O_CONT_ID == id) {
1537                 H5O_cont_t *cont;
1538 
1539                 /* Decode continuation message */
1540                 cont = (H5O_cont_t *)(H5O_MSG_CONT->decode)(udata->f, NULL, 0, &ioflags, mesg->raw_size, mesg->raw);
1541                 H5_CHECKED_ASSIGN(cont->chunkno, unsigned, udata->cont_msg_info->nmsgs + 1, size_t); /* the next continuation message/chunk */
1542 
1543                 /* Save 'native' form of continuation message */
1544                 mesg->native = cont;
1545 
1546                 /* Add to continuation messages left to interpret */
1547                 if(H5O__add_cont_msg(udata->cont_msg_info, cont) < 0)
1548                     HGOTO_ERROR(H5E_OHDR, H5E_CANTSET, FAIL, "can't add continuation message")
1549             } /* end if */
1550             /* Check if message is a ref. count message */
1551             else if(H5O_REFCOUNT_ID == id) {
1552                 H5O_refcount_t *refcount;
1553 
1554                 /* Decode ref. count message */
1555                 if(oh->version <= H5O_VERSION_1)
1556                     HGOTO_ERROR(H5E_OHDR, H5E_VERSION, FAIL, "object header version does not support reference count message")
1557                 refcount = (H5O_refcount_t *)(H5O_MSG_REFCOUNT->decode)(udata->f, NULL, 0, &ioflags, mesg->raw_size, mesg->raw);
1558 
1559                 /* Save 'native' form of ref. count message */
1560                 mesg->native = refcount;
1561 
1562                 /* Set object header values */
1563                 oh->has_refcount_msg = TRUE;
1564                 if(!refcount)
1565                     HGOTO_ERROR(H5E_OHDR, H5E_CANTSET, FAIL, "can't decode refcount")
1566                 oh->nlink = *refcount;
1567             } /* end if */
1568             /* Check if message is a link message */
1569             else if(H5O_LINK_ID == id) {
1570                 /* Increment the count of link messages */
1571                 oh->link_msgs_seen++;
1572             } /* end if */
1573             /* Check if message is an attribute message */
1574             else if(H5O_ATTR_ID == id) {
1575                 /* Increment the count of attribute messages */
1576                 oh->attr_msgs_seen++;
1577             } /* end if */
1578 
1579             /* Mark the message & chunk as dirty if the message was changed by decoding */
1580             if((ioflags & H5O_DECODEIO_DIRTY) && (udata->file_intent & H5F_ACC_RDWR)) {
1581                 mesg->dirty = TRUE;
1582                 mesgs_modified = TRUE;
1583             } /* end if */
1584         } /* end else */
1585 
1586         /* Advance decode pointer past message */
1587         chunk_image += mesg_size;
1588 
1589         /* Check for 'gap' at end of chunk */
1590         if((eom_ptr - chunk_image) > 0 && (eom_ptr - chunk_image) < H5O_SIZEOF_MSGHDR_OH(oh)) {
1591             /* Gaps can only occur in later versions of the format */
1592             HDassert(oh->version > H5O_VERSION_1);
1593 
1594             /* Gaps should only occur in chunks with no null messages */
1595             HDassert(nullcnt == 0);
1596 
1597             /* Set gap information for chunk */
1598             oh->chunk[chunkno].gap = (size_t)(eom_ptr - chunk_image);
1599 
1600             /* Increment location in chunk */
1601             chunk_image += oh->chunk[chunkno].gap;
1602         } /* end if */
1603     } /* end while */
1604 
1605     /* Check for correct checksum on chunks, in later versions of the format */
1606     if(oh->version > H5O_VERSION_1) {
1607         uint32_t stored_chksum;     /* Checksum from file */
1608 
1609 	/* checksum verification already done in verify_chksum cb */
1610 
1611         /* Metadata checksum */
1612         UINT32DECODE(chunk_image, stored_chksum);
1613     } /* end if */
1614 
1615     /* Sanity check */
1616     HDassert(chunk_image == oh->chunk[chunkno].image + oh->chunk[chunkno].size);
1617 
1618     /* Mark the chunk dirty if we've modified messages */
1619     if(mesgs_modified)
1620 	*dirty = TRUE;
1621 
1622     /* Mark the chunk dirty if we've merged null messages */
1623     if(merged_null_msgs > 0) {
1624         udata->merged_null_msgs += merged_null_msgs;
1625 	*dirty = TRUE;
1626     } /* end if */
1627 
1628 done:
1629     if(ret_value < 0 && udata->cont_msg_info->msgs) {
1630         udata->cont_msg_info->msgs = H5FL_SEQ_FREE(H5O_cont_t, udata->cont_msg_info->msgs);
1631         udata->cont_msg_info->alloc_nmsgs = 0;
1632     }
1633     FUNC_LEAVE_NOAPI(ret_value)
1634 } /* H5O__chunk_deserialize() */
1635 
1636 
1637 /*-------------------------------------------------------------------------
1638  * Function:	H5O__chunk_serialize
1639  *
1640  * Purpose:	Serialize a chunk for an object header
1641  *
1642  * Return:	Success: SUCCEED
1643  *              Failure: FAIL
1644  *
1645  * Programmer:	Quincey Koziol
1646  *              koziol@hdfgroup.org
1647  *              July 12, 2008
1648  *
1649  *-------------------------------------------------------------------------
1650  */
1651 static herr_t
H5O__chunk_serialize(const H5F_t * f,H5O_t * oh,unsigned chunkno)1652 H5O__chunk_serialize(const H5F_t *f, H5O_t *oh, unsigned chunkno)
1653 {
1654     H5O_mesg_t *curr_msg;       /* Pointer to current message being operated on */
1655     unsigned	u;              /* Local index variable */
1656     herr_t ret_value = SUCCEED; /* Return value */
1657 
1658     FUNC_ENTER_STATIC
1659 
1660     /* Check arguments */
1661     HDassert(f);
1662     HDassert(oh);
1663 
1664     /* Encode any dirty messages in this chunk */
1665     for(u = 0, curr_msg = &oh->mesg[0]; u < oh->nmesgs; u++, curr_msg++)
1666         if(curr_msg->dirty && curr_msg->chunkno == chunkno)
1667             /* Casting away const OK -QAK */
1668             if(H5O_msg_flush((H5F_t *)f, oh, curr_msg) < 0)
1669                 HGOTO_ERROR(H5E_OHDR, H5E_CANTENCODE, FAIL, "unable to encode object header message")
1670 
1671     /* Sanity checks */
1672     if(oh->version > H5O_VERSION_1)
1673         /* Make certain the magic # is present */
1674         HDassert(!HDmemcmp(oh->chunk[chunkno].image, (chunkno == 0 ? H5O_HDR_MAGIC : H5O_CHK_MAGIC), H5_SIZEOF_MAGIC));
1675     else
1676         /* Gaps should never occur in version 1 of the format */
1677         HDassert(oh->chunk[chunkno].gap == 0);
1678 
1679     /* Extra work, for later versions of the format */
1680     if(oh->version > H5O_VERSION_1) {
1681         uint32_t metadata_chksum;   /* Computed metadata checksum value */
1682         uint8_t	*chunk_image;       /* Pointer into object header chunk */
1683 
1684         /* Check for gap in chunk & zero it out */
1685         if(oh->chunk[chunkno].gap)
1686             HDmemset((oh->chunk[chunkno].image + oh->chunk[chunkno].size) -
1687                 (H5O_SIZEOF_CHKSUM + oh->chunk[chunkno].gap), 0, oh->chunk[chunkno].gap);
1688 
1689         /* Compute metadata checksum */
1690         metadata_chksum = H5_checksum_metadata(oh->chunk[chunkno].image, (oh->chunk[chunkno].size - H5O_SIZEOF_CHKSUM), 0);
1691 
1692         /* Metadata checksum */
1693         chunk_image = oh->chunk[chunkno].image + (oh->chunk[chunkno].size - H5O_SIZEOF_CHKSUM);
1694         UINT32ENCODE(chunk_image, metadata_chksum);
1695     } /* end if */
1696 
1697 done:
1698     FUNC_LEAVE_NOAPI(ret_value)
1699 } /* H5O__chunk_serialize() */
1700 
1701