Line | Count | Source (jump to first uncovered line) |
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 COPYING 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 | | /* Module Setup */ |
15 | | /****************/ |
16 | | |
17 | | #include "H5Gmodule.h" /* This source code file is part of the H5G module */ |
18 | | |
19 | | /***********/ |
20 | | /* Headers */ |
21 | | /***********/ |
22 | | #include "H5private.h" /* Generic Functions */ |
23 | | #include "H5Eprivate.h" /* Error handling */ |
24 | | #include "H5Fprivate.h" /* File access */ |
25 | | #include "H5Gpkg.h" /* Groups */ |
26 | | #include "H5HLprivate.h" /* Local Heaps */ |
27 | | #include "H5MMprivate.h" /* Memory management */ |
28 | | |
29 | | /****************/ |
30 | | /* Local Macros */ |
31 | | /****************/ |
32 | | |
33 | | /******************/ |
34 | | /* Local Typedefs */ |
35 | | /******************/ |
36 | | |
37 | | /********************/ |
38 | | /* Package Typedefs */ |
39 | | /********************/ |
40 | | |
41 | | /********************/ |
42 | | /* Local Prototypes */ |
43 | | /********************/ |
44 | | |
45 | | /*********************/ |
46 | | /* Package Variables */ |
47 | | /*********************/ |
48 | | |
49 | | /*****************************/ |
50 | | /* Library Private Variables */ |
51 | | /*****************************/ |
52 | | |
53 | | /*******************/ |
54 | | /* Local Variables */ |
55 | | /*******************/ |
56 | | |
57 | | /*------------------------------------------------------------------------- |
58 | | * Function: H5G__ent_decode_vec |
59 | | * |
60 | | * Purpose: Same as H5G_ent_decode() except it does it for an array of |
61 | | * symbol table entries. |
62 | | * |
63 | | * Return: Success: Non-negative, with *pp pointing to the first byte |
64 | | * after the last symbol. |
65 | | * |
66 | | * Failure: Negative |
67 | | * |
68 | | *------------------------------------------------------------------------- |
69 | | */ |
70 | | herr_t |
71 | | H5G__ent_decode_vec(const H5F_t *f, const uint8_t **pp, const uint8_t *p_end, H5G_entry_t *ent, unsigned n) |
72 | 19 | { |
73 | 19 | unsigned u; /* Local index variable */ |
74 | 19 | herr_t ret_value = SUCCEED; /* Return value */ |
75 | | |
76 | 19 | FUNC_ENTER_PACKAGE |
77 | | |
78 | | /* check arguments */ |
79 | 19 | assert(f); |
80 | 19 | assert(pp); |
81 | 19 | assert(ent); |
82 | | |
83 | | /* decode entries */ |
84 | 116 | for (u = 0; u < n; u++) { |
85 | 97 | if (*pp > p_end) |
86 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTDECODE, FAIL, "ran off the end of the image buffer"); |
87 | 97 | if (H5G_ent_decode(f, pp, ent + u, p_end) < 0) |
88 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTDECODE, FAIL, "can't decode"); |
89 | 97 | } |
90 | | |
91 | 19 | done: |
92 | 19 | FUNC_LEAVE_NOAPI(ret_value) |
93 | 19 | } /* end H5G__ent_decode_vec() */ |
94 | | |
95 | | /*------------------------------------------------------------------------- |
96 | | * Function: H5G_ent_decode |
97 | | * |
98 | | * Purpose: Decodes a symbol table entry pointed to by `*pp'. |
99 | | * |
100 | | * Return: Success: Non-negative with *pp pointing to the first byte |
101 | | * following the symbol table entry. |
102 | | * |
103 | | * Failure: Negative |
104 | | * |
105 | | *------------------------------------------------------------------------- |
106 | | */ |
107 | | herr_t |
108 | | H5G_ent_decode(const H5F_t *f, const uint8_t **pp, H5G_entry_t *ent, const uint8_t *p_end) |
109 | 104 | { |
110 | 104 | const uint8_t *p_ret = *pp; |
111 | 104 | uint32_t tmp; |
112 | 104 | herr_t ret_value = SUCCEED; /* Return value */ |
113 | | |
114 | 104 | FUNC_ENTER_NOAPI(FAIL) |
115 | | |
116 | | /* check arguments */ |
117 | 104 | assert(f); |
118 | 104 | assert(pp); |
119 | 104 | assert(ent); |
120 | | |
121 | 104 | if (H5_IS_BUFFER_OVERFLOW(*pp, ent->name_off, p_end)) |
122 | 0 | HGOTO_ERROR(H5E_FILE, H5E_OVERFLOW, FAIL, "image pointer is out of bounds"); |
123 | | |
124 | | /* decode header */ |
125 | 104 | H5F_DECODE_LENGTH(f, *pp, ent->name_off); |
126 | | |
127 | 104 | if (H5_IS_BUFFER_OVERFLOW(*pp, H5F_SIZEOF_ADDR(f) + sizeof(uint32_t), p_end)) |
128 | 0 | HGOTO_ERROR(H5E_FILE, H5E_OVERFLOW, FAIL, "image pointer is out of bounds"); |
129 | | |
130 | 104 | H5F_addr_decode(f, pp, &(ent->header)); |
131 | 104 | UINT32DECODE(*pp, tmp); |
132 | 104 | *pp += 4; /*reserved*/ |
133 | | |
134 | 104 | if (H5_IS_BUFFER_OVERFLOW(*pp, 1, p_end)) |
135 | 0 | HGOTO_ERROR(H5E_FILE, H5E_OVERFLOW, FAIL, "image pointer is out of bounds"); |
136 | | |
137 | 104 | ent->type = (H5G_cache_type_t)tmp; |
138 | | |
139 | | /* decode scratch-pad */ |
140 | 104 | switch (ent->type) { |
141 | 71 | case H5G_NOTHING_CACHED: |
142 | 71 | break; |
143 | | |
144 | 31 | case H5G_CACHED_STAB: |
145 | 31 | assert(2 * H5F_SIZEOF_ADDR(f) <= H5G_SIZEOF_SCRATCH); |
146 | 31 | if (H5_IS_BUFFER_OVERFLOW(*pp, H5F_SIZEOF_ADDR(f) * 2, p_end)) |
147 | 0 | HGOTO_ERROR(H5E_FILE, H5E_OVERFLOW, FAIL, "image pointer is out of bounds"); |
148 | 31 | H5F_addr_decode(f, pp, &(ent->cache.stab.btree_addr)); |
149 | 31 | H5F_addr_decode(f, pp, &(ent->cache.stab.heap_addr)); |
150 | 31 | break; |
151 | | |
152 | 2 | case H5G_CACHED_SLINK: |
153 | 2 | if (H5_IS_BUFFER_OVERFLOW(*pp, sizeof(uint32_t), p_end)) |
154 | 0 | HGOTO_ERROR(H5E_FILE, H5E_OVERFLOW, FAIL, "image pointer is out of bounds"); |
155 | 2 | UINT32DECODE(*pp, ent->cache.slink.lval_offset); |
156 | 2 | break; |
157 | | |
158 | 0 | case H5G_CACHED_ERROR: |
159 | 0 | case H5G_NCACHED: |
160 | 0 | default: |
161 | 0 | HGOTO_ERROR(H5E_SYM, H5E_BADVALUE, FAIL, "unknown symbol table entry cache type"); |
162 | 104 | } /* end switch */ |
163 | | |
164 | 104 | *pp = p_ret + H5G_SIZEOF_ENTRY_FILE(f); |
165 | | |
166 | 104 | done: |
167 | 104 | FUNC_LEAVE_NOAPI(ret_value) |
168 | 104 | } /* end H5G_ent_decode() */ |
169 | | |
170 | | /*------------------------------------------------------------------------- |
171 | | * Function: H5G__ent_encode_vec |
172 | | * |
173 | | * Purpose: Same as H5G_ent_encode() except it does it for an array of |
174 | | * symbol table entries. |
175 | | * |
176 | | * Return: Success: Non-negative, with *pp pointing to the first byte |
177 | | * after the last symbol. |
178 | | * |
179 | | * Failure: Negative |
180 | | * |
181 | | *------------------------------------------------------------------------- |
182 | | */ |
183 | | herr_t |
184 | | H5G__ent_encode_vec(const H5F_t *f, uint8_t **pp, const H5G_entry_t *ent, unsigned n) |
185 | 0 | { |
186 | 0 | unsigned u; /* Local index variable */ |
187 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
188 | |
|
189 | 0 | FUNC_ENTER_PACKAGE |
190 | | |
191 | | /* check arguments */ |
192 | 0 | assert(f); |
193 | 0 | assert(pp); |
194 | 0 | assert(ent); |
195 | | |
196 | | /* encode entries */ |
197 | 0 | for (u = 0; u < n; u++) |
198 | 0 | if (H5G_ent_encode(f, pp, ent + u) < 0) |
199 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTENCODE, FAIL, "can't encode"); |
200 | | |
201 | 0 | done: |
202 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
203 | 0 | } /* H5G__ent_encode_vec() */ |
204 | | |
205 | | /*------------------------------------------------------------------------- |
206 | | * Function: H5G_ent_encode |
207 | | * |
208 | | * Purpose: Encodes the specified symbol table entry into the buffer |
209 | | * pointed to by *pp. |
210 | | * |
211 | | * Return: Success: Non-negative, with *pp pointing to the first byte |
212 | | * after the symbol table entry. |
213 | | * |
214 | | * Failure: Negative |
215 | | * |
216 | | *------------------------------------------------------------------------- |
217 | | */ |
218 | | herr_t |
219 | | H5G_ent_encode(const H5F_t *f, uint8_t **pp, const H5G_entry_t *ent) |
220 | 0 | { |
221 | 0 | uint8_t *p_ret = *pp + H5G_SIZEOF_ENTRY_FILE(f); |
222 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
223 | |
|
224 | 0 | FUNC_ENTER_NOAPI(FAIL) |
225 | | |
226 | | /* check arguments */ |
227 | 0 | assert(f); |
228 | 0 | assert(pp); |
229 | | |
230 | | /* Check for actual entry to encode */ |
231 | 0 | if (ent) { |
232 | | /* encode header */ |
233 | 0 | H5F_ENCODE_LENGTH(f, *pp, ent->name_off); |
234 | 0 | H5F_addr_encode(f, pp, ent->header); |
235 | 0 | UINT32ENCODE(*pp, ent->type); |
236 | 0 | UINT32ENCODE(*pp, 0); /*reserved*/ |
237 | | |
238 | | /* encode scratch-pad */ |
239 | 0 | switch (ent->type) { |
240 | 0 | case H5G_NOTHING_CACHED: |
241 | 0 | break; |
242 | | |
243 | 0 | case H5G_CACHED_STAB: |
244 | 0 | assert(2 * H5F_SIZEOF_ADDR(f) <= H5G_SIZEOF_SCRATCH); |
245 | 0 | H5F_addr_encode(f, pp, ent->cache.stab.btree_addr); |
246 | 0 | H5F_addr_encode(f, pp, ent->cache.stab.heap_addr); |
247 | 0 | break; |
248 | | |
249 | 0 | case H5G_CACHED_SLINK: |
250 | 0 | UINT32ENCODE(*pp, ent->cache.slink.lval_offset); |
251 | 0 | break; |
252 | | |
253 | 0 | case H5G_CACHED_ERROR: |
254 | 0 | case H5G_NCACHED: |
255 | 0 | default: |
256 | 0 | HGOTO_ERROR(H5E_SYM, H5E_BADVALUE, FAIL, "unknown symbol table entry cache type"); |
257 | 0 | } /* end switch */ |
258 | 0 | } /* end if */ |
259 | 0 | else { |
260 | 0 | H5F_ENCODE_LENGTH(f, *pp, 0); |
261 | 0 | H5F_addr_encode(f, pp, HADDR_UNDEF); |
262 | 0 | UINT32ENCODE(*pp, H5G_NOTHING_CACHED); |
263 | 0 | UINT32ENCODE(*pp, 0); /*reserved*/ |
264 | 0 | } /* end else */ |
265 | | |
266 | | /* fill with zero */ |
267 | 0 | if (*pp < p_ret) |
268 | 0 | memset(*pp, 0, (size_t)(p_ret - *pp)); |
269 | 0 | *pp = p_ret; |
270 | |
|
271 | 0 | done: |
272 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
273 | 0 | } /* end H5G_ent_encode() */ |
274 | | |
275 | | /*------------------------------------------------------------------------- |
276 | | * Function: H5G__ent_copy |
277 | | * |
278 | | * Purpose: Do a deep copy of symbol table entries |
279 | | * |
280 | | * Return: Success: Non-negative |
281 | | * Failure: Negative |
282 | | * |
283 | | * Notes: 'depth' parameter determines how much of the group entry |
284 | | * structure we want to copy. The values are: |
285 | | * H5_COPY_SHALLOW - Copy all the fields from the source |
286 | | * to the destination, including the user path and |
287 | | * canonical path. (Destination "takes ownership" of |
288 | | * user and canonical paths) |
289 | | * H5_COPY_DEEP - Copy all the fields from the source to |
290 | | * the destination, deep copying the user and canonical |
291 | | * paths. |
292 | | * |
293 | | *------------------------------------------------------------------------- |
294 | | */ |
295 | | void |
296 | | H5G__ent_copy(H5G_entry_t *dst, H5G_entry_t *src, H5_copy_depth_t depth) |
297 | 0 | { |
298 | 0 | FUNC_ENTER_PACKAGE_NOERR |
299 | | |
300 | | /* Check arguments */ |
301 | 0 | assert(src); |
302 | 0 | assert(dst); |
303 | 0 | assert(depth == H5_COPY_SHALLOW || depth == H5_COPY_DEEP); |
304 | | |
305 | | /* Copy the top level information */ |
306 | 0 | H5MM_memcpy(dst, src, sizeof(H5G_entry_t)); |
307 | | |
308 | | /* Deep copy the names */ |
309 | 0 | if (depth == H5_COPY_DEEP) { |
310 | | /* Nothing currently */ |
311 | 0 | } |
312 | 0 | else if (depth == H5_COPY_SHALLOW) { |
313 | 0 | H5G__ent_reset(src); |
314 | 0 | } /* end if */ |
315 | |
|
316 | 0 | FUNC_LEAVE_NOAPI_VOID |
317 | 0 | } /* end H5G__ent_copy() */ |
318 | | |
319 | | /*------------------------------------------------------------------------- |
320 | | * Function: H5G__ent_reset |
321 | | * |
322 | | * Purpose: Reset a symbol table entry to an empty state |
323 | | * |
324 | | * Return: Success: Non-negative |
325 | | * Failure: Negative |
326 | | * |
327 | | *------------------------------------------------------------------------- |
328 | | */ |
329 | | void |
330 | | H5G__ent_reset(H5G_entry_t *ent) |
331 | 0 | { |
332 | 0 | FUNC_ENTER_PACKAGE_NOERR |
333 | | |
334 | | /* Check arguments */ |
335 | 0 | assert(ent); |
336 | | |
337 | | /* Clear the symbol table entry to an empty state */ |
338 | 0 | memset(ent, 0, sizeof(H5G_entry_t)); |
339 | 0 | ent->header = HADDR_UNDEF; |
340 | |
|
341 | 0 | FUNC_LEAVE_NOAPI_VOID |
342 | 0 | } /* end H5G__ent_reset() */ |
343 | | |
344 | | /*------------------------------------------------------------------------- |
345 | | * Function: H5G__ent_to_link |
346 | | * |
347 | | * Purpose: Convert a symbol table entry to a link |
348 | | * |
349 | | * Return: Non-negative on success/Negative on failure |
350 | | * |
351 | | *------------------------------------------------------------------------- |
352 | | */ |
353 | | herr_t |
354 | | H5G__ent_to_link(const H5G_entry_t *ent, const H5HL_t *heap, H5O_link_t *lnk) |
355 | 825 | { |
356 | 825 | const char *name; /* Pointer to link name in heap */ |
357 | 825 | size_t block_size; /* Size of the heap block */ |
358 | 825 | bool dup_soft = false; /* xstrdup the symbolic link name or not */ |
359 | 825 | herr_t ret_value = SUCCEED; /* Return value */ |
360 | | |
361 | 825 | FUNC_ENTER_PACKAGE |
362 | | |
363 | | /* check arguments */ |
364 | 825 | assert(ent); |
365 | 825 | assert(heap); |
366 | 825 | assert(lnk); |
367 | | |
368 | | /* Initialize structure and set (default) common info for link */ |
369 | 825 | lnk->type = H5L_TYPE_ERROR; |
370 | 825 | lnk->corder_valid = false; /* Creation order not valid for this link */ |
371 | 825 | lnk->corder = 0; |
372 | 825 | lnk->cset = H5F_DEFAULT_CSET; |
373 | 825 | lnk->name = NULL; |
374 | | |
375 | | /* Get the size of the heap block */ |
376 | 825 | block_size = H5HL_heap_get_size(heap); |
377 | | |
378 | | /* Get pointer to link's name in the heap */ |
379 | 825 | if (NULL == (name = (const char *)H5HL_offset_into(heap, ent->name_off))) |
380 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "unable to get symbol table link name"); |
381 | | |
382 | 825 | if (NULL == (lnk->name = H5MM_strndup(name, (block_size - ent->name_off)))) |
383 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "unable to duplicate link name"); |
384 | 825 | if (!*lnk->name) |
385 | 0 | HGOTO_ERROR(H5E_SYM, H5E_BADVALUE, FAIL, "invalid link name"); |
386 | | |
387 | | /* Object is a symbolic or hard link */ |
388 | 825 | if (ent->type == H5G_CACHED_SLINK) { |
389 | 0 | const char *s; /* Pointer to link value */ |
390 | |
|
391 | 0 | if (NULL == (s = (const char *)H5HL_offset_into(heap, ent->cache.slink.lval_offset))) |
392 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "unable to get symbolic link name"); |
393 | | |
394 | | /* Copy the link value */ |
395 | 0 | if (NULL == (lnk->u.soft.name = H5MM_strndup(s, (block_size - ent->cache.slink.lval_offset)))) |
396 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "unable to duplicate symbolic link name"); |
397 | | |
398 | 0 | dup_soft = true; |
399 | | |
400 | | /* Set link type */ |
401 | 0 | lnk->type = H5L_TYPE_SOFT; |
402 | 0 | } /* end if */ |
403 | 825 | else { |
404 | | /* Set address of object */ |
405 | 825 | lnk->u.hard.addr = ent->header; |
406 | | |
407 | | /* Set link type */ |
408 | 825 | lnk->type = H5L_TYPE_HARD; |
409 | 825 | } /* end else */ |
410 | | |
411 | 825 | done: |
412 | 825 | if (ret_value < 0) { |
413 | 0 | if (lnk->name) |
414 | 0 | H5MM_xfree(lnk->name); |
415 | 0 | if (ent->type == H5G_CACHED_SLINK && dup_soft) |
416 | 0 | H5MM_xfree(lnk->u.soft.name); |
417 | 0 | } |
418 | | |
419 | 825 | FUNC_LEAVE_NOAPI(ret_value) |
420 | 825 | } /* end H5G__ent_to_link() */ |
421 | | |
422 | | /*------------------------------------------------------------------------- |
423 | | * Function: H5G__ent_debug |
424 | | * |
425 | | * Purpose: Prints debugging information about a symbol table entry. |
426 | | * |
427 | | * Return: Non-negative on success/Negative on failure |
428 | | * |
429 | | *------------------------------------------------------------------------- |
430 | | */ |
431 | | herr_t |
432 | | H5G__ent_debug(const H5G_entry_t *ent, FILE *stream, int indent, int fwidth, const H5HL_t *heap) |
433 | 0 | { |
434 | 0 | const char *lval = NULL; |
435 | 0 | int nested_indent, nested_fwidth; |
436 | |
|
437 | 0 | FUNC_ENTER_PACKAGE_NOERR |
438 | | |
439 | | /* Calculate the indent & field width values for nested information */ |
440 | 0 | nested_indent = indent + 3; |
441 | 0 | nested_fwidth = MAX(0, fwidth - 3); |
442 | |
|
443 | 0 | fprintf(stream, "%*s%-*s %lu\n", indent, "", fwidth, |
444 | 0 | "Name offset into private heap:", (unsigned long)(ent->name_off)); |
445 | |
|
446 | 0 | fprintf(stream, "%*s%-*s %" PRIuHADDR "\n", indent, "", fwidth, "Object header address:", ent->header); |
447 | |
|
448 | 0 | fprintf(stream, "%*s%-*s ", indent, "", fwidth, "Cache info type:"); |
449 | 0 | switch (ent->type) { |
450 | 0 | case H5G_NOTHING_CACHED: |
451 | 0 | fprintf(stream, "Nothing Cached\n"); |
452 | 0 | break; |
453 | | |
454 | 0 | case H5G_CACHED_STAB: |
455 | 0 | fprintf(stream, "Symbol Table\n"); |
456 | |
|
457 | 0 | fprintf(stream, "%*s%-*s\n", indent, "", fwidth, "Cached entry information:"); |
458 | 0 | fprintf(stream, "%*s%-*s %" PRIuHADDR "\n", nested_indent, "", nested_fwidth, |
459 | 0 | "B-tree address:", ent->cache.stab.btree_addr); |
460 | |
|
461 | 0 | fprintf(stream, "%*s%-*s %" PRIuHADDR "\n", nested_indent, "", nested_fwidth, |
462 | 0 | "Heap address:", ent->cache.stab.heap_addr); |
463 | 0 | break; |
464 | | |
465 | 0 | case H5G_CACHED_SLINK: |
466 | 0 | fprintf(stream, "Symbolic Link\n"); |
467 | 0 | fprintf(stream, "%*s%-*s\n", indent, "", fwidth, "Cached information:"); |
468 | 0 | fprintf(stream, "%*s%-*s %lu\n", nested_indent, "", nested_fwidth, |
469 | 0 | "Link value offset:", (unsigned long)(ent->cache.slink.lval_offset)); |
470 | 0 | if (heap) { |
471 | 0 | lval = (const char *)H5HL_offset_into(heap, ent->cache.slink.lval_offset); |
472 | 0 | fprintf(stream, "%*s%-*s %s\n", nested_indent, "", nested_fwidth, |
473 | 0 | "Link value:", (lval == NULL) ? "" : lval); |
474 | 0 | } /* end if */ |
475 | 0 | else |
476 | 0 | fprintf(stream, "%*s%-*s\n", nested_indent, "", nested_fwidth, |
477 | 0 | "Warning: Invalid heap address given, name not displayed!"); |
478 | 0 | break; |
479 | | |
480 | 0 | case H5G_CACHED_ERROR: |
481 | 0 | case H5G_NCACHED: |
482 | 0 | default: |
483 | 0 | fprintf(stream, "*** Unknown symbol type %d\n", ent->type); |
484 | 0 | break; |
485 | 0 | } /* end switch */ |
486 | | |
487 | 0 | FUNC_LEAVE_NOAPI(SUCCEED) |
488 | 0 | } /* end H5G__ent_debug() */ |