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