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 | | * |
15 | | * Created: H5Gobj.c |
16 | | * |
17 | | * Purpose: Functions for abstract handling of objects in groups. |
18 | | * |
19 | | *------------------------------------------------------------------------- |
20 | | */ |
21 | | |
22 | | /****************/ |
23 | | /* Module Setup */ |
24 | | /****************/ |
25 | | |
26 | | #include "H5Gmodule.h" /* This source code file is part of the H5G module */ |
27 | | |
28 | | /***********/ |
29 | | /* Headers */ |
30 | | /***********/ |
31 | | #include "H5private.h" /* Generic Functions */ |
32 | | #include "H5Eprivate.h" /* Error handling */ |
33 | | #include "H5Fprivate.h" /* File access */ |
34 | | #include "H5Gpkg.h" /* Groups */ |
35 | | #include "H5Iprivate.h" /* IDs */ |
36 | | #include "H5Lprivate.h" /* Links */ |
37 | | #include "H5Pprivate.h" /* Property Lists */ |
38 | | |
39 | | /****************/ |
40 | | /* Local Macros */ |
41 | | /****************/ |
42 | | |
43 | | /******************/ |
44 | | /* Local Typedefs */ |
45 | | /******************/ |
46 | | |
47 | | /* User data for object header iterator when converting link messages to dense |
48 | | * link storage |
49 | | */ |
50 | | typedef struct { |
51 | | H5F_t *f; /* Pointer to file for insertion */ |
52 | | haddr_t oh_addr; /* Address of the object header */ |
53 | | H5O_linfo_t *linfo; /* Pointer to link info */ |
54 | | } H5G_obj_oh_it_ud1_t; |
55 | | |
56 | | /* User data for link iterator when converting dense link storage to link |
57 | | * messages |
58 | | */ |
59 | | typedef struct { |
60 | | H5O_link_t *lnk_table; /* Array of links to convert */ |
61 | | size_t nlinks; /* Number of links converted */ |
62 | | size_t alloc_links; /* Size of link table */ |
63 | | } H5G_obj_lnk_it_ud1_t; |
64 | | |
65 | | /* User data for symbol table iterator when converting old-format group to |
66 | | * a new-format group |
67 | | */ |
68 | | typedef struct { |
69 | | const H5O_loc_t *grp_oloc; /* Pointer to group for insertion */ |
70 | | } H5G_obj_stab_it_ud1_t; |
71 | | |
72 | | /********************/ |
73 | | /* Package Typedefs */ |
74 | | /********************/ |
75 | | |
76 | | /********************/ |
77 | | /* Local Prototypes */ |
78 | | /********************/ |
79 | | static herr_t H5G__obj_compact_to_dense_cb(const void *_mesg, unsigned idx, void *_udata); |
80 | | static herr_t H5G__obj_remove_update_linfo(const H5O_loc_t *oloc, H5O_linfo_t *linfo); |
81 | | |
82 | | /*********************/ |
83 | | /* Package Variables */ |
84 | | /*********************/ |
85 | | |
86 | | /*****************************/ |
87 | | /* Library Private Variables */ |
88 | | /*****************************/ |
89 | | |
90 | | /*******************/ |
91 | | /* Local Variables */ |
92 | | /*******************/ |
93 | | |
94 | | /*------------------------------------------------------------------------- |
95 | | * Function: H5G__obj_create |
96 | | * |
97 | | * Purpose: Create an object header for a group and update object location info |
98 | | * |
99 | | * Return: Non-negative on success/Negative on failure |
100 | | * |
101 | | *------------------------------------------------------------------------- |
102 | | */ |
103 | | herr_t |
104 | | H5G__obj_create(H5F_t *f, H5G_obj_create_t *gcrt_info, H5O_loc_t *oloc /*out*/) |
105 | 0 | { |
106 | 0 | H5P_genplist_t *gc_plist; /* Group creation property list */ |
107 | 0 | H5O_ginfo_t ginfo; /* Group info */ |
108 | 0 | H5O_linfo_t linfo; /* Link info */ |
109 | 0 | H5O_pline_t pline; /* Pipeline */ |
110 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
111 | |
|
112 | 0 | FUNC_ENTER_PACKAGE |
113 | | |
114 | | /* |
115 | | * Check arguments. |
116 | | */ |
117 | 0 | assert(f); |
118 | 0 | assert(oloc); |
119 | | |
120 | | /* Get the property list */ |
121 | 0 | if (NULL == (gc_plist = (H5P_genplist_t *)H5I_object(gcrt_info->gcpl_id))) |
122 | 0 | HGOTO_ERROR(H5E_SYM, H5E_BADTYPE, FAIL, "not a property list"); |
123 | | |
124 | | /* Get the group info property */ |
125 | 0 | if (H5P_get(gc_plist, H5G_CRT_GROUP_INFO_NAME, &ginfo) < 0) |
126 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't get group info"); |
127 | | |
128 | | /* Get the link info property */ |
129 | 0 | if (H5P_get(gc_plist, H5G_CRT_LINK_INFO_NAME, &linfo) < 0) |
130 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't get group info"); |
131 | | |
132 | | /* Get the pipeline property */ |
133 | 0 | if (H5P_peek(gc_plist, H5O_CRT_PIPELINE_NAME, &pline) < 0) |
134 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't get group info"); |
135 | | |
136 | | /* Call the "real" group creation routine now */ |
137 | 0 | if (H5G__obj_create_real(f, &ginfo, &linfo, &pline, gcrt_info, oloc) < 0) |
138 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTCREATE, FAIL, "unable to create group"); |
139 | | |
140 | 0 | done: |
141 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
142 | 0 | } /* end H5G__obj_create() */ |
143 | | |
144 | | /*------------------------------------------------------------------------- |
145 | | * Function: H5G__obj_create_real |
146 | | * |
147 | | * Purpose: Create an object header for a group and update object location info |
148 | | * |
149 | | * Return: Non-negative on success/Negative on failure |
150 | | * |
151 | | *------------------------------------------------------------------------- |
152 | | */ |
153 | | herr_t |
154 | | H5G__obj_create_real(H5F_t *f, const H5O_ginfo_t *ginfo, const H5O_linfo_t *linfo, const H5O_pline_t *pline, |
155 | | H5G_obj_create_t *gcrt_info, H5O_loc_t *oloc /*out*/) |
156 | 0 | { |
157 | 0 | size_t hdr_size; /* Size of object header to request */ |
158 | 0 | bool use_at_least_v18; /* Flag indicating the new group format should be used */ |
159 | 0 | hid_t gcpl_id = gcrt_info->gcpl_id; /* Group creation property list ID */ |
160 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
161 | |
|
162 | 0 | FUNC_ENTER_PACKAGE |
163 | | |
164 | | /* |
165 | | * Check arguments. |
166 | | */ |
167 | 0 | assert(f); |
168 | 0 | assert(ginfo); |
169 | 0 | assert(linfo); |
170 | 0 | assert(pline); |
171 | 0 | assert(oloc); |
172 | | |
173 | | /* Check for invalid access request */ |
174 | 0 | if (0 == (H5F_INTENT(f) & H5F_ACC_RDWR)) |
175 | 0 | HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "no write intent on file"); |
176 | | |
177 | | /* Check for using the latest version of the group format which is introduced in v18 */ |
178 | | /* (add more checks for creating "new format" groups when needed) */ |
179 | 0 | if ((H5F_LOW_BOUND(f) >= H5F_LIBVER_V18) || linfo->track_corder || (pline && pline->nused)) |
180 | 0 | use_at_least_v18 = true; |
181 | 0 | else |
182 | 0 | use_at_least_v18 = false; |
183 | | |
184 | | /* Make certain that the creation order is being tracked if an index is |
185 | | * going to be built on it. |
186 | | */ |
187 | 0 | if (linfo->index_corder && !linfo->track_corder) |
188 | 0 | HGOTO_ERROR(H5E_SYM, H5E_BADVALUE, FAIL, "must track creation order to create index for it"); |
189 | | |
190 | | /* Check if we should be using the latest version of the group format */ |
191 | 0 | if (use_at_least_v18) { |
192 | 0 | H5O_link_t lnk; /* Temporary link message info for computing message size */ |
193 | 0 | char null_char = '\0'; /* Character for creating null string */ |
194 | 0 | size_t ginfo_size; /* Size of the group info message */ |
195 | 0 | size_t linfo_size; /* Size of the link info message */ |
196 | 0 | size_t pline_size = 0; /* Size of the pipeline message */ |
197 | 0 | size_t link_size; /* Size of a link message */ |
198 | | |
199 | | /* Calculate message size information, for creating group's object header */ |
200 | 0 | linfo_size = H5O_msg_size_f(f, gcpl_id, H5O_LINFO_ID, linfo, (size_t)0); |
201 | 0 | assert(linfo_size); |
202 | |
|
203 | 0 | ginfo_size = H5O_msg_size_f(f, gcpl_id, H5O_GINFO_ID, ginfo, (size_t)0); |
204 | 0 | assert(ginfo_size); |
205 | |
|
206 | 0 | if (pline && pline->nused) { |
207 | 0 | pline_size = H5O_msg_size_f(f, gcpl_id, H5O_PLINE_ID, pline, (size_t)0); |
208 | 0 | assert(pline_size); |
209 | 0 | } /* end if */ |
210 | |
|
211 | 0 | lnk.type = H5L_TYPE_HARD; |
212 | 0 | lnk.corder = 0; |
213 | 0 | lnk.corder_valid = linfo->track_corder; |
214 | 0 | lnk.cset = H5T_CSET_ASCII; |
215 | 0 | lnk.name = &null_char; |
216 | 0 | link_size = H5O_msg_size_f(f, gcpl_id, H5O_LINK_ID, &lnk, (size_t)ginfo->est_name_len); |
217 | 0 | assert(link_size); |
218 | | |
219 | | /* Compute size of header to use for creation */ |
220 | | |
221 | | /* Basic header size */ |
222 | 0 | hdr_size = linfo_size + ginfo_size + pline_size; |
223 | | |
224 | | /* If this is likely to be a compact group, add space for the link |
225 | | * messages, unless the size of the link messages is greater than |
226 | | * the largest allowable object header message size, since the size |
227 | | * of the link messages is the size of the NIL spacer message that |
228 | | * would have to be written out to reserve enough space to hold the |
229 | | * links if the group were left empty. |
230 | | */ |
231 | 0 | bool compact = ginfo->est_num_entries <= ginfo->max_compact; |
232 | 0 | if (compact) { |
233 | |
|
234 | 0 | size_t size_of_links = ginfo->est_num_entries * link_size; |
235 | |
|
236 | 0 | if (size_of_links < H5O_MESG_MAX_SIZE) |
237 | 0 | hdr_size += size_of_links; |
238 | 0 | } |
239 | 0 | } /* end if */ |
240 | 0 | else |
241 | 0 | hdr_size = (size_t)(4 + 2 * H5F_SIZEOF_ADDR(f)); |
242 | | |
243 | | /* |
244 | | * Create group's object header. It has a zero link count |
245 | | * since nothing refers to it yet. The link count will be |
246 | | * incremented if the object is added to the group directed graph. |
247 | | */ |
248 | 0 | if (H5O_create(f, hdr_size, (size_t)1, gcpl_id, oloc /*out*/) < 0) |
249 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "can't create header"); |
250 | | |
251 | | /* Check for format of group to create */ |
252 | 0 | if (use_at_least_v18) { |
253 | 0 | H5_GCC_CLANG_DIAG_OFF("cast-qual") |
254 | | /* Insert link info message */ |
255 | 0 | if (H5O_msg_create(oloc, H5O_LINFO_ID, 0, H5O_UPDATE_TIME, (void *)linfo) < 0) |
256 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "can't create message"); |
257 | | |
258 | | /* Insert group info message */ |
259 | 0 | if (H5O_msg_create(oloc, H5O_GINFO_ID, H5O_MSG_FLAG_CONSTANT, 0, (void *)ginfo) < 0) |
260 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "can't create message"); |
261 | | |
262 | | /* Insert pipeline message */ |
263 | 0 | if (pline && pline->nused) |
264 | 0 | if (H5O_msg_create(oloc, H5O_PLINE_ID, H5O_MSG_FLAG_CONSTANT, 0, (void *)pline) < 0) |
265 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "can't create message"); |
266 | 0 | H5_GCC_CLANG_DIAG_ON("cast-qual") |
267 | 0 | } /* end if */ |
268 | 0 | else { |
269 | 0 | H5O_stab_t stab; /* Symbol table message */ |
270 | | |
271 | | /* The group doesn't currently have a 'stab' message, go create one */ |
272 | 0 | if (H5G__stab_create(oloc, ginfo, &stab) < 0) |
273 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to create symbol table"); |
274 | | |
275 | | /* Cache the symbol table information */ |
276 | 0 | gcrt_info->cache_type = H5G_CACHED_STAB; |
277 | 0 | gcrt_info->cache.stab.btree_addr = stab.btree_addr; |
278 | 0 | gcrt_info->cache.stab.heap_addr = stab.heap_addr; |
279 | 0 | } /* end else */ |
280 | | |
281 | 0 | done: |
282 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
283 | 0 | } /* end H5G__obj_create_real() */ |
284 | | |
285 | | /*------------------------------------------------------------------------- |
286 | | * Function: H5G__obj_get_linfo |
287 | | * |
288 | | * Purpose: Retrieves the "link info" message for an object. Also |
289 | | * sets the number of links correctly, if it isn't set up yet. |
290 | | * |
291 | | * Return: Success: true/false whether message was found & retrieved |
292 | | * Failure: FAIL if error occurred |
293 | | * |
294 | | *------------------------------------------------------------------------- |
295 | | */ |
296 | | htri_t |
297 | | H5G__obj_get_linfo(const H5O_loc_t *grp_oloc, H5O_linfo_t *linfo) |
298 | 363 | { |
299 | 363 | H5B2_t *bt2_name = NULL; /* v2 B-tree handle for name index */ |
300 | 363 | htri_t ret_value = FAIL; /* Return value */ |
301 | | |
302 | 363 | FUNC_ENTER_PACKAGE_TAG(grp_oloc->addr) |
303 | | |
304 | | /* check arguments */ |
305 | 363 | assert(grp_oloc); |
306 | 363 | assert(linfo); |
307 | | |
308 | | /* Check for the group having a link info message */ |
309 | 363 | if ((ret_value = H5O_msg_exists(grp_oloc, H5O_LINFO_ID)) < 0) |
310 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "unable to read object header"); |
311 | 363 | if (ret_value) { |
312 | | /* Retrieve the "link info" structure */ |
313 | 0 | if (NULL == H5O_msg_read(grp_oloc, H5O_LINFO_ID, linfo)) |
314 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "link info message not present"); |
315 | | |
316 | | /* Check if we don't know how many links there are */ |
317 | 0 | if (linfo->nlinks == HSIZET_MAX) { |
318 | | /* Check if we are using "dense" link storage */ |
319 | 0 | if (H5_addr_defined(linfo->fheap_addr)) { |
320 | | /* Open the name index v2 B-tree */ |
321 | 0 | if (NULL == (bt2_name = H5B2_open(grp_oloc->file, linfo->name_bt2_addr, NULL))) |
322 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open v2 B-tree for name index"); |
323 | | |
324 | | /* Retrieve # of records in "name" B-tree */ |
325 | | /* (should be same # of records in all indices) */ |
326 | 0 | if (H5B2_get_nrec(bt2_name, &linfo->nlinks) < 0) |
327 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't retrieve # of records in index"); |
328 | 0 | } /* end if */ |
329 | 0 | else { |
330 | | /* Retrieve # of links from object header */ |
331 | 0 | if (H5O_get_nlinks(grp_oloc, &linfo->nlinks) < 0) |
332 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't retrieve # of links for object"); |
333 | 0 | } /* end if */ |
334 | 0 | } /* end if */ |
335 | 0 | } /* end if */ |
336 | | |
337 | 363 | done: |
338 | | /* Release resources */ |
339 | 363 | if (bt2_name && H5B2_close(bt2_name) < 0) |
340 | 0 | HDONE_ERROR(H5E_SYM, H5E_CLOSEERROR, FAIL, "can't close v2 B-tree for name index"); |
341 | | |
342 | 363 | FUNC_LEAVE_NOAPI_TAG(ret_value) |
343 | 363 | } /* end H5G__obj_get_linfo() */ |
344 | | |
345 | | /*------------------------------------------------------------------------- |
346 | | * Function: H5G__obj_compact_to_dense_cb |
347 | | * |
348 | | * Purpose: Callback routine for converting "compact" to "dense" |
349 | | * link storage form. |
350 | | * |
351 | | * Return: Non-negative on success/Negative on failure |
352 | | * |
353 | | *------------------------------------------------------------------------- |
354 | | */ |
355 | | static herr_t |
356 | | H5G__obj_compact_to_dense_cb(const void *_mesg, unsigned H5_ATTR_UNUSED idx, void *_udata) |
357 | 0 | { |
358 | 0 | const H5O_link_t *lnk = (const H5O_link_t *)_mesg; /* Pointer to link */ |
359 | 0 | H5G_obj_oh_it_ud1_t *udata = (H5G_obj_oh_it_ud1_t *)_udata; /* 'User data' passed in */ |
360 | 0 | herr_t ret_value = H5_ITER_CONT; /* Return value */ |
361 | |
|
362 | 0 | FUNC_ENTER_PACKAGE |
363 | | |
364 | | /* check arguments */ |
365 | 0 | assert(lnk); |
366 | 0 | assert(udata); |
367 | | |
368 | | /* Insert link into dense link storage */ |
369 | 0 | if (H5G__dense_insert(udata->f, udata->linfo, lnk) < 0) |
370 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTINSERT, FAIL, "unable to insert link into dense storage"); |
371 | | |
372 | 0 | done: |
373 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
374 | 0 | } /* end H5G__obj_compact_to_dense_cb() */ |
375 | | |
376 | | /*------------------------------------------------------------------------- |
377 | | * Function: H5G__obj_stab_to_new_cb |
378 | | * |
379 | | * Purpose: Callback routine for converting "symbol table" link storage to |
380 | | * "new format" storage (either "compact" or "dense" storage). |
381 | | * |
382 | | * Return: Non-negative on success/Negative on failure |
383 | | * |
384 | | *------------------------------------------------------------------------- |
385 | | */ |
386 | | static herr_t |
387 | | H5G__obj_stab_to_new_cb(const H5O_link_t *lnk, void *_udata) |
388 | 0 | { |
389 | 0 | H5G_obj_stab_it_ud1_t *udata = (H5G_obj_stab_it_ud1_t *)_udata; /* 'User data' passed in */ |
390 | 0 | herr_t ret_value = H5_ITER_CONT; /* Return value */ |
391 | |
|
392 | 0 | FUNC_ENTER_PACKAGE |
393 | | |
394 | | /* check arguments */ |
395 | 0 | assert(lnk); |
396 | 0 | assert(udata); |
397 | | |
398 | | /* Insert link into group */ |
399 | 0 | H5_GCC_CLANG_DIAG_OFF("cast-qual") |
400 | 0 | if (H5G_obj_insert(udata->grp_oloc, (H5O_link_t *)lnk, false, H5O_TYPE_UNKNOWN, NULL) < 0) |
401 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTINSERT, H5_ITER_ERROR, "can't insert link into group"); |
402 | 0 | H5_GCC_CLANG_DIAG_ON("cast-qual") |
403 | | |
404 | 0 | done: |
405 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
406 | 0 | } /* end H5G__obj_stab_to_new_cb() */ |
407 | | |
408 | | /*------------------------------------------------------------------------- |
409 | | * Function: H5G_obj_insert |
410 | | * |
411 | | * Purpose: Insert a new symbol into the group described by GRP_OLOC. |
412 | | * file F. The name of the new symbol is OBJ_LNK->NAME and its |
413 | | * symbol table entry is OBJ_LNK. Increment the reference |
414 | | * count for the object the link points if OBJ_LNK is a hard link |
415 | | * and ADJ_LINK is true. |
416 | | * |
417 | | * Return: Non-negative on success/Negative on failure |
418 | | * |
419 | | *------------------------------------------------------------------------- |
420 | | */ |
421 | | herr_t |
422 | | H5G_obj_insert(const H5O_loc_t *grp_oloc, H5O_link_t *obj_lnk, bool adj_link, H5O_type_t obj_type, |
423 | | const void *crt_info) |
424 | 0 | { |
425 | 0 | H5O_pline_t tmp_pline; /* Pipeline message */ |
426 | 0 | H5O_pline_t *pline = NULL; /* Pointer to pipeline message */ |
427 | 0 | H5O_linfo_t linfo; /* Link info message */ |
428 | 0 | htri_t linfo_exists; /* Whether the link info message exists */ |
429 | 0 | bool use_old_format; /* Whether to use 'old format' (symbol table) for insertions or not */ |
430 | 0 | bool use_new_dense = false; /* Whether to use "dense" form of 'new format' group */ |
431 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
432 | |
|
433 | 0 | FUNC_ENTER_NOAPI_TAG(grp_oloc->addr, FAIL) |
434 | | |
435 | | /* check arguments */ |
436 | 0 | assert(grp_oloc && grp_oloc->file); |
437 | 0 | assert(obj_lnk); |
438 | | |
439 | | /* Check if we have information about the number of objects in this group */ |
440 | | /* (by attempting to get the link info message for this group) */ |
441 | 0 | if ((linfo_exists = H5G__obj_get_linfo(grp_oloc, &linfo)) < 0) |
442 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't check for link info message"); |
443 | 0 | if (linfo_exists) { |
444 | 0 | H5O_ginfo_t ginfo; /* Group info message */ |
445 | 0 | size_t link_msg_size; /* Size of new link message in the file */ |
446 | | |
447 | | /* Using the new format for groups */ |
448 | 0 | use_old_format = false; |
449 | | |
450 | | /* Check for tracking creation order on this group's links */ |
451 | 0 | if (linfo.track_corder) { |
452 | | /* Set the creation order for the new link & indicate that it's valid */ |
453 | 0 | obj_lnk->corder = linfo.max_corder; |
454 | 0 | obj_lnk->corder_valid = true; |
455 | | |
456 | | /* Increment the max. creation order used in the group */ |
457 | 0 | linfo.max_corder++; |
458 | 0 | } /* end if */ |
459 | | |
460 | | /* Get the link's message size */ |
461 | 0 | if ((link_msg_size = H5O_msg_raw_size(grp_oloc->file, H5O_LINK_ID, false, obj_lnk)) == 0) |
462 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTGETSIZE, FAIL, "can't get link size"); |
463 | | |
464 | | /* Get the group info */ |
465 | 0 | if (NULL == H5O_msg_read(grp_oloc, H5O_GINFO_ID, &ginfo)) |
466 | 0 | HGOTO_ERROR(H5E_SYM, H5E_BADMESG, FAIL, "can't get group info"); |
467 | | |
468 | | /* If there's still a small enough number of links, use the 'link' message */ |
469 | | /* (If the encoded form of the link is too large to fit into an object |
470 | | * header message, convert to using dense link storage instead of link messages) |
471 | | */ |
472 | 0 | if (H5_addr_defined(linfo.fheap_addr)) |
473 | 0 | use_new_dense = true; |
474 | 0 | else if (linfo.nlinks < ginfo.max_compact && link_msg_size < H5O_MESG_MAX_SIZE) |
475 | 0 | use_new_dense = false; |
476 | 0 | else { |
477 | 0 | htri_t pline_exists; /* Whether the pipeline message exists */ |
478 | 0 | H5G_obj_oh_it_ud1_t udata; /* User data for iteration */ |
479 | 0 | H5O_mesg_operator_t op; /* Message operator */ |
480 | | |
481 | | /* Get the pipeline message, if it exists */ |
482 | 0 | if ((pline_exists = H5O_msg_exists(grp_oloc, H5O_PLINE_ID)) < 0) |
483 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "unable to read object header"); |
484 | 0 | if (pline_exists) { |
485 | 0 | if (NULL == H5O_msg_read(grp_oloc, H5O_PLINE_ID, &tmp_pline)) |
486 | 0 | HGOTO_ERROR(H5E_SYM, H5E_BADMESG, FAIL, "can't get link pipeline"); |
487 | 0 | pline = &tmp_pline; |
488 | 0 | } /* end if */ |
489 | | |
490 | | /* The group doesn't currently have "dense" storage for links */ |
491 | 0 | if (H5G__dense_create(grp_oloc->file, &linfo, pline) < 0) |
492 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to create 'dense' form of new format group"); |
493 | | |
494 | | /* Set up user data for object header message iteration */ |
495 | 0 | udata.f = grp_oloc->file; |
496 | 0 | udata.oh_addr = grp_oloc->addr; |
497 | 0 | udata.linfo = &linfo; |
498 | | |
499 | | /* Iterate over the 'link' messages, inserting them into the dense link storage */ |
500 | 0 | op.op_type = H5O_MESG_OP_APP; |
501 | 0 | op.u.app_op = H5G__obj_compact_to_dense_cb; |
502 | 0 | if (H5O_msg_iterate(grp_oloc, H5O_LINK_ID, &op, &udata) < 0) |
503 | 0 | HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "error iterating over links"); |
504 | | |
505 | | /* Remove all the 'link' messages */ |
506 | 0 | if (H5O_msg_remove(grp_oloc, H5O_LINK_ID, H5O_ALL, false) < 0) |
507 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTDELETE, FAIL, "unable to delete link messages"); |
508 | | |
509 | 0 | use_new_dense = true; |
510 | 0 | } /* end else */ |
511 | 0 | } /* end if */ |
512 | 0 | else { |
513 | | /* Check for new-style link information */ |
514 | 0 | if (obj_lnk->cset != H5T_CSET_ASCII || obj_lnk->type > H5L_TYPE_BUILTIN_MAX) { |
515 | 0 | H5O_linfo_t new_linfo = H5G_CRT_LINK_INFO_DEF; /* Link information */ |
516 | 0 | H5O_ginfo_t new_ginfo = H5G_CRT_GROUP_INFO_DEF; /* Group information */ |
517 | 0 | H5G_obj_stab_it_ud1_t udata; /* User data for iteration */ |
518 | | |
519 | | /* Convert group to "new format" group, in order to hold the information */ |
520 | | |
521 | | /* Insert link info message */ |
522 | 0 | if (H5O_msg_create(grp_oloc, H5O_LINFO_ID, 0, 0, &new_linfo) < 0) |
523 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "can't create message"); |
524 | | |
525 | | /* Insert group info message */ |
526 | 0 | if (H5O_msg_create(grp_oloc, H5O_GINFO_ID, H5O_MSG_FLAG_CONSTANT, H5O_UPDATE_TIME, &new_ginfo) < |
527 | 0 | 0) |
528 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "can't create message"); |
529 | | |
530 | | /* Set up user data for iteration */ |
531 | 0 | udata.grp_oloc = grp_oloc; |
532 | | |
533 | | /* Iterate through all links in "old format" group and insert them into new format */ |
534 | 0 | if (H5G__stab_iterate(grp_oloc, H5_ITER_NATIVE, (hsize_t)0, NULL, H5G__obj_stab_to_new_cb, |
535 | 0 | &udata) < 0) |
536 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTNEXT, FAIL, "error iterating over old format links"); |
537 | | |
538 | | /* Remove the symbol table message from the group */ |
539 | 0 | if (H5O_msg_remove(grp_oloc, H5O_STAB_ID, 0, false) < 0) |
540 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTDELETE, FAIL, "unable to delete old format link storage"); |
541 | | |
542 | | /* Recursively call this routine to insert the new link, since the |
543 | | * group is in the "new format" now and the link info should be |
544 | | * set up, etc. |
545 | | */ |
546 | 0 | if (H5G_obj_insert(grp_oloc, obj_lnk, adj_link, obj_type, crt_info) < 0) |
547 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTINSERT, FAIL, "unable to insert link into group"); |
548 | | |
549 | | /* Done with insertion now */ |
550 | 0 | HGOTO_DONE(SUCCEED); |
551 | 0 | } /* end if */ |
552 | 0 | else |
553 | 0 | use_old_format = true; |
554 | 0 | } /* end if */ |
555 | | |
556 | | /* Insert into symbol table or "dense" storage */ |
557 | 0 | if (use_old_format) { |
558 | | /* Insert into symbol table */ |
559 | 0 | if (H5G__stab_insert(grp_oloc, obj_lnk, obj_type, crt_info) < 0) |
560 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTINSERT, FAIL, "unable to insert entry into symbol table"); |
561 | 0 | } /* end if */ |
562 | 0 | else { |
563 | 0 | if (use_new_dense) { |
564 | | /* Insert into dense link storage */ |
565 | 0 | if (H5G__dense_insert(grp_oloc->file, &linfo, obj_lnk) < 0) |
566 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTINSERT, FAIL, "unable to insert link into dense storage"); |
567 | 0 | } /* end if */ |
568 | 0 | else { |
569 | | /* Insert with link message */ |
570 | 0 | if (H5G__compact_insert(grp_oloc, obj_lnk) < 0) |
571 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTINSERT, FAIL, "unable to insert link as link message"); |
572 | 0 | } /* end else */ |
573 | 0 | } /* end else */ |
574 | | |
575 | | /* Increment the number of objects in this group */ |
576 | 0 | if (!use_old_format) { |
577 | 0 | linfo.nlinks++; |
578 | 0 | if (H5O_msg_write(grp_oloc, H5O_LINFO_ID, 0, H5O_UPDATE_TIME, &linfo) < 0) |
579 | 0 | HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "can't update link info message"); |
580 | 0 | } /* end if */ |
581 | | |
582 | | /* Increment link count on object, if requested and it's a hard link */ |
583 | 0 | if (adj_link && obj_lnk->type == H5L_TYPE_HARD) { |
584 | 0 | H5O_loc_t obj_oloc; /* Object location */ |
585 | 0 | H5O_loc_reset(&obj_oloc); |
586 | | |
587 | | /* Create temporary object location */ |
588 | 0 | obj_oloc.file = grp_oloc->file; |
589 | 0 | obj_oloc.addr = obj_lnk->u.hard.addr; |
590 | | |
591 | | /* Increment reference count for object */ |
592 | 0 | if (H5O_link(&obj_oloc, 1) < 0) |
593 | 0 | HGOTO_ERROR(H5E_SYM, H5E_LINKCOUNT, FAIL, "unable to increment hard link count"); |
594 | 0 | } /* end if */ |
595 | | |
596 | 0 | done: |
597 | | /* Free any space used by the pipeline message */ |
598 | 0 | if (pline && H5O_msg_reset(H5O_PLINE_ID, pline) < 0) |
599 | 0 | HDONE_ERROR(H5E_SYM, H5E_CANTFREE, FAIL, "can't release pipeline"); |
600 | |
|
601 | 0 | FUNC_LEAVE_NOAPI_TAG(ret_value) |
602 | 0 | } /* end H5G_obj_insert() */ |
603 | | |
604 | | /*------------------------------------------------------------------------- |
605 | | * Function: H5G__obj_iterate |
606 | | * |
607 | | * Purpose: Private function for H5Giterate. |
608 | | * Iterates over objects in a group |
609 | | * |
610 | | * Return: Success: Non-negative |
611 | | * |
612 | | * Failure: Negative |
613 | | * |
614 | | *------------------------------------------------------------------------- |
615 | | */ |
616 | | herr_t |
617 | | H5G__obj_iterate(const H5O_loc_t *grp_oloc, H5_index_t idx_type, H5_iter_order_t order, hsize_t skip, |
618 | | hsize_t *last_lnk, H5G_lib_iterate_t op, void *op_data) |
619 | 76 | { |
620 | 76 | H5O_linfo_t linfo; /* Link info message */ |
621 | 76 | htri_t linfo_exists; /* Whether the link info message exists */ |
622 | 76 | herr_t ret_value = FAIL; /* Return value */ |
623 | | |
624 | 76 | FUNC_ENTER_PACKAGE_TAG(grp_oloc->addr) |
625 | | |
626 | | /* Sanity check */ |
627 | 76 | assert(grp_oloc); |
628 | 76 | assert(op); |
629 | | |
630 | | /* Attempt to get the link info for this group */ |
631 | 76 | if ((linfo_exists = H5G__obj_get_linfo(grp_oloc, &linfo)) < 0) |
632 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't check for link info message"); |
633 | 76 | if (linfo_exists) { |
634 | | /* Check for going out of bounds */ |
635 | 0 | if (skip > 0 && (size_t)skip >= linfo.nlinks) |
636 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "index out of bound"); |
637 | | |
638 | | /* Check for creation order tracking, if creation order index lookup requested */ |
639 | 0 | if (idx_type == H5_INDEX_CRT_ORDER) { |
640 | | /* Check if creation order is tracked */ |
641 | 0 | if (!linfo.track_corder) |
642 | 0 | HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "creation order not tracked for links in group"); |
643 | 0 | } /* end if */ |
644 | | |
645 | 0 | if (H5_addr_defined(linfo.fheap_addr)) { |
646 | | /* Iterate over the links in the group, building a table of the link messages */ |
647 | 0 | if ((ret_value = H5G__dense_iterate(grp_oloc->file, &linfo, idx_type, order, skip, last_lnk, op, |
648 | 0 | op_data)) < 0) |
649 | 0 | HGOTO_ERROR(H5E_SYM, H5E_BADITER, FAIL, "can't iterate over dense links"); |
650 | 0 | } /* end if */ |
651 | 0 | else { |
652 | | /* Get the object's name from the link messages */ |
653 | 0 | if ((ret_value = H5G__compact_iterate(grp_oloc, &linfo, idx_type, order, skip, last_lnk, op, |
654 | 0 | op_data)) < 0) |
655 | 0 | HGOTO_ERROR(H5E_SYM, H5E_BADITER, FAIL, "can't iterate over compact links"); |
656 | 0 | } /* end else */ |
657 | 0 | } /* end if */ |
658 | 76 | else { |
659 | | /* Can only perform name lookups on groups with symbol tables */ |
660 | 76 | if (idx_type != H5_INDEX_NAME) |
661 | 0 | HGOTO_ERROR(H5E_SYM, H5E_BADVALUE, FAIL, "no creation order index to query"); |
662 | | |
663 | | /* Iterate over symbol table */ |
664 | 76 | if ((ret_value = H5G__stab_iterate(grp_oloc, order, skip, last_lnk, op, op_data)) < 0) |
665 | 50 | HGOTO_ERROR(H5E_SYM, H5E_BADITER, FAIL, "can't iterate over symbol table"); |
666 | 76 | } /* end else */ |
667 | | |
668 | 76 | done: |
669 | 76 | FUNC_LEAVE_NOAPI_TAG(ret_value) |
670 | 76 | } /* end H5G__obj_iterate() */ |
671 | | |
672 | | /*------------------------------------------------------------------------- |
673 | | * Function: H5G__obj_info |
674 | | * |
675 | | * Purpose: Retrieve information about a group |
676 | | * |
677 | | * Return: Non-negative on success/Negative on failure |
678 | | * |
679 | | *------------------------------------------------------------------------- |
680 | | */ |
681 | | herr_t |
682 | | H5G__obj_info(const H5O_loc_t *oloc, H5G_info_t *grp_info) |
683 | 7 | { |
684 | 7 | H5G_t *grp = NULL; /* Group to query */ |
685 | 7 | H5G_loc_t grp_loc; /* Entry of group to be queried */ |
686 | 7 | H5G_name_t grp_path; /* Group hier. path */ |
687 | 7 | H5O_loc_t grp_oloc; /* Group object location */ |
688 | 7 | H5O_linfo_t linfo; /* Link info message */ |
689 | 7 | htri_t linfo_exists; /* Whether the link info message exists */ |
690 | 7 | herr_t ret_value = SUCCEED; /* Return value */ |
691 | | |
692 | 7 | FUNC_ENTER_PACKAGE |
693 | | |
694 | | /* Sanity check */ |
695 | 7 | assert(oloc); |
696 | 7 | assert(grp_info); |
697 | | |
698 | | /* Set up group location to fill in */ |
699 | 7 | grp_loc.oloc = &grp_oloc; |
700 | 7 | grp_loc.path = &grp_path; |
701 | 7 | H5G_loc_reset(&grp_loc); |
702 | | |
703 | | /* Deep copy (duplicate) of the group location object */ |
704 | 7 | if (H5O_loc_copy_deep(&grp_oloc, oloc) < 0) |
705 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTCOPY, FAIL, "can't copy object location"); |
706 | | |
707 | | /* Open the group */ |
708 | 7 | if (NULL == (grp = H5G_open(&grp_loc))) |
709 | 0 | HGOTO_ERROR(H5E_FILE, H5E_MOUNT, FAIL, "mount point not found"); |
710 | | |
711 | | /* Get information from the group */ |
712 | 7 | grp_info->mounted = H5G_MOUNTED(grp); |
713 | | |
714 | | /* Attempt to get the link info for this group */ |
715 | 7 | if ((linfo_exists = H5G__obj_get_linfo(oloc, &linfo)) < 0) |
716 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't check for link info message"); |
717 | 7 | if (linfo_exists) { |
718 | | /* Retrieve the information about the links */ |
719 | 0 | grp_info->nlinks = linfo.nlinks; |
720 | 0 | grp_info->max_corder = linfo.max_corder; |
721 | | |
722 | | /* Check if the group is using compact or dense storage for its links */ |
723 | 0 | if (H5_addr_defined(linfo.fheap_addr)) |
724 | 0 | grp_info->storage_type = H5G_STORAGE_TYPE_DENSE; |
725 | 0 | else |
726 | 0 | grp_info->storage_type = H5G_STORAGE_TYPE_COMPACT; |
727 | 0 | } /* end if */ |
728 | 7 | else { |
729 | | /* Get the number of objects in this group by iterating over symbol table */ |
730 | 7 | if (H5G__stab_count(oloc, &grp_info->nlinks) < 0) |
731 | 1 | HGOTO_ERROR(H5E_SYM, H5E_CANTCOUNT, FAIL, "can't count objects"); |
732 | | |
733 | | /* Set the other information about the group */ |
734 | 6 | grp_info->storage_type = H5G_STORAGE_TYPE_SYMBOL_TABLE; |
735 | 6 | grp_info->max_corder = 0; |
736 | 6 | } /* end else */ |
737 | | |
738 | 7 | done: |
739 | | /* Clean up resources */ |
740 | 7 | if (grp && H5G_close(grp) < 0) |
741 | 0 | HDONE_ERROR(H5E_SYM, H5E_CANTCLOSEOBJ, FAIL, "unable to close queried group"); |
742 | | |
743 | 7 | FUNC_LEAVE_NOAPI(ret_value) |
744 | 7 | } /* end H5G__obj_info() */ |
745 | | |
746 | | /*------------------------------------------------------------------------- |
747 | | * Function: H5G_obj_get_name_by_idx |
748 | | * |
749 | | * Purpose: Returns the name of link in a group by giving index. |
750 | | * |
751 | | * Return: Success: Non-negative, length of name |
752 | | * Failure: Negative |
753 | | * |
754 | | *------------------------------------------------------------------------- |
755 | | */ |
756 | | herr_t |
757 | | H5G_obj_get_name_by_idx(const H5O_loc_t *oloc, H5_index_t idx_type, H5_iter_order_t order, hsize_t n, |
758 | | char *name, size_t name_size, size_t *name_len) |
759 | 138 | { |
760 | 138 | H5O_linfo_t linfo; /* Link info message */ |
761 | 138 | htri_t linfo_exists; /* Whether the link info message exists */ |
762 | 138 | herr_t ret_value = SUCCEED; /* Return value */ |
763 | | |
764 | 138 | FUNC_ENTER_NOAPI_TAG(oloc->addr, FAIL) |
765 | | |
766 | | /* Sanity check */ |
767 | 138 | assert(oloc && oloc->file); |
768 | | |
769 | | /* Attempt to get the link info for this group */ |
770 | 138 | if ((linfo_exists = H5G__obj_get_linfo(oloc, &linfo)) < 0) |
771 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't check for link info message"); |
772 | 138 | if (linfo_exists) { |
773 | | /* Check for creation order tracking, if creation order index lookup requested */ |
774 | 0 | if (idx_type == H5_INDEX_CRT_ORDER) |
775 | | /* Check if creation order is tracked */ |
776 | 0 | if (!linfo.track_corder) |
777 | 0 | HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "creation order not tracked for links in group"); |
778 | | |
779 | | /* Check for dense link storage */ |
780 | 0 | if (H5_addr_defined(linfo.fheap_addr)) { |
781 | | /* Get the object's name from the dense link storage */ |
782 | 0 | if (H5G__dense_get_name_by_idx(oloc->file, &linfo, idx_type, order, n, name, name_size, |
783 | 0 | name_len) < 0) |
784 | 0 | HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "can't locate name"); |
785 | 0 | } /* end if */ |
786 | 0 | else { |
787 | | /* Get the object's name from the link messages */ |
788 | 0 | if (H5G__compact_get_name_by_idx(oloc, &linfo, idx_type, order, n, name, name_size, name_len) < 0) |
789 | 0 | HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "can't locate name"); |
790 | 0 | } /* end else */ |
791 | 0 | } /* end if */ |
792 | 138 | else { |
793 | | /* Can only perform name lookups on groups with symbol tables */ |
794 | 138 | if (idx_type != H5_INDEX_NAME) |
795 | 0 | HGOTO_ERROR(H5E_SYM, H5E_BADVALUE, FAIL, "no creation order index to query"); |
796 | | |
797 | | /* Get the object's name from the symbol table */ |
798 | 138 | if (H5G__stab_get_name_by_idx(oloc, order, n, name, name_size, name_len) < 0) |
799 | 2 | HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "can't locate name"); |
800 | 138 | } /* end else */ |
801 | | |
802 | 138 | done: |
803 | 138 | FUNC_LEAVE_NOAPI_TAG(ret_value) |
804 | 138 | } /* end H5G_obj_get_name_by_idx() */ |
805 | | |
806 | | /*------------------------------------------------------------------------- |
807 | | * Function: H5G__obj_remove_update_linfo |
808 | | * |
809 | | * Purpose: Update the link info after removing a link from a group |
810 | | * |
811 | | * Return: Success: Non-negative |
812 | | * Failure: Negative |
813 | | * |
814 | | *------------------------------------------------------------------------- |
815 | | */ |
816 | | static herr_t |
817 | | H5G__obj_remove_update_linfo(const H5O_loc_t *oloc, H5O_linfo_t *linfo) |
818 | 0 | { |
819 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
820 | |
|
821 | 0 | FUNC_ENTER_PACKAGE |
822 | | |
823 | | /* Sanity check */ |
824 | 0 | assert(oloc); |
825 | 0 | assert(linfo); |
826 | | |
827 | | /* Decrement # of links in group */ |
828 | 0 | linfo->nlinks--; |
829 | | |
830 | | /* Reset the creation order min/max if there's no more links in group */ |
831 | 0 | if (linfo->nlinks == 0) |
832 | 0 | linfo->max_corder = 0; |
833 | | |
834 | | /* Check for transitioning out of dense storage, if we are using it */ |
835 | 0 | if (H5_addr_defined(linfo->fheap_addr)) { |
836 | | /* Check if there's no more links */ |
837 | 0 | if (linfo->nlinks == 0) { |
838 | | /* Delete the dense storage */ |
839 | 0 | if (H5G__dense_delete(oloc->file, linfo, false) < 0) |
840 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTDELETE, FAIL, "unable to delete dense link storage"); |
841 | 0 | } /* end if */ |
842 | | /* Check for switching back to compact storage */ |
843 | 0 | else { |
844 | 0 | H5O_ginfo_t ginfo; /* Group info message */ |
845 | | |
846 | | /* Get the group info */ |
847 | 0 | if (NULL == H5O_msg_read(oloc, H5O_GINFO_ID, &ginfo)) |
848 | 0 | HGOTO_ERROR(H5E_SYM, H5E_BADMESG, FAIL, "can't get group info"); |
849 | | |
850 | | /* Check if we should switch from dense storage back to link messages */ |
851 | 0 | if (linfo->nlinks < ginfo.min_dense) { |
852 | 0 | struct H5O_t *oh = NULL; /* Pointer to group's object header */ |
853 | 0 | H5G_link_table_t ltable; /* Table of links */ |
854 | 0 | bool can_convert = true; /* Whether converting to link messages is possible */ |
855 | 0 | size_t u; /* Local index */ |
856 | | |
857 | | /* Build the table of links for this group */ |
858 | 0 | if (H5G__dense_build_table(oloc->file, linfo, H5_INDEX_NAME, H5_ITER_NATIVE, <able) < 0) |
859 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTNEXT, FAIL, "error iterating over links"); |
860 | | |
861 | | /* Pin the object header */ |
862 | 0 | if (NULL == (oh = H5O_pin(oloc))) |
863 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTPIN, FAIL, "unable to pin group object header"); |
864 | | |
865 | | /* Inspect links in table for ones that can't be converted back |
866 | | * into link message form (currently only links which can't fit |
867 | | * into an object header message) |
868 | | */ |
869 | 0 | for (u = 0; u < linfo->nlinks; u++) |
870 | 0 | if (H5O_msg_size_oh(oloc->file, oh, H5O_LINK_ID, &(ltable.lnks[u]), (size_t)0) >= |
871 | 0 | H5O_MESG_MAX_SIZE) { |
872 | 0 | can_convert = false; |
873 | 0 | break; |
874 | 0 | } /* end if */ |
875 | | |
876 | | /* If ok, insert links as link messages */ |
877 | 0 | if (can_convert) { |
878 | | /* Insert link messages into group */ |
879 | 0 | for (u = 0; u < linfo->nlinks; u++) |
880 | 0 | if (H5O_msg_append_oh(oloc->file, oh, H5O_LINK_ID, 0, H5O_UPDATE_TIME, |
881 | 0 | &(ltable.lnks[u])) < 0) { |
882 | | /* Release object header */ |
883 | 0 | if (H5O_unpin(oh) < 0) |
884 | 0 | HDONE_ERROR(H5E_SYM, H5E_CANTUNPIN, FAIL, |
885 | 0 | "unable to unpin group object header"); |
886 | |
|
887 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "can't create message"); |
888 | 0 | } /* end if */ |
889 | | |
890 | | /* Remove the dense storage */ |
891 | 0 | if (H5G__dense_delete(oloc->file, linfo, false) < 0) |
892 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTDELETE, FAIL, "unable to delete dense link storage"); |
893 | 0 | } /* end if */ |
894 | | |
895 | | /* Release object header */ |
896 | 0 | if (H5O_unpin(oh) < 0) |
897 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTUNPIN, FAIL, "unable to unpin group object header"); |
898 | | |
899 | | /* Free link table information */ |
900 | 0 | if (H5G__link_release_table(<able) < 0) |
901 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTFREE, FAIL, "unable to release link table"); |
902 | 0 | } /* end if */ |
903 | 0 | } /* end else */ |
904 | 0 | } /* end if */ |
905 | | |
906 | | /* Update link info in the object header */ |
907 | 0 | if (H5O_msg_write(oloc, H5O_LINFO_ID, 0, H5O_UPDATE_TIME, linfo) < 0) |
908 | 0 | HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "can't update link info message"); |
909 | | |
910 | 0 | done: |
911 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
912 | 0 | } /* end H5G__obj_remove_update_linfo() */ |
913 | | |
914 | | /*------------------------------------------------------------------------- |
915 | | * Function: H5G_obj_remove |
916 | | * |
917 | | * Purpose: Remove a link from a group. |
918 | | * |
919 | | * Return: Success: Non-negative |
920 | | * Failure: Negative |
921 | | * |
922 | | *------------------------------------------------------------------------- |
923 | | */ |
924 | | herr_t |
925 | | H5G_obj_remove(const H5O_loc_t *oloc, H5RS_str_t *grp_full_path_r, const char *name) |
926 | 0 | { |
927 | 0 | H5O_linfo_t linfo; /* Link info message */ |
928 | 0 | htri_t linfo_exists; /* Whether the link info message exists */ |
929 | 0 | bool use_old_format; /* Whether to use 'old format' (symbol table) for deletion or not */ |
930 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
931 | |
|
932 | 0 | FUNC_ENTER_NOAPI_TAG(oloc->addr, FAIL) |
933 | | |
934 | | /* Sanity check */ |
935 | 0 | assert(oloc); |
936 | 0 | assert(name && *name); |
937 | | |
938 | | /* Attempt to get the link info for this group */ |
939 | 0 | if ((linfo_exists = H5G__obj_get_linfo(oloc, &linfo)) < 0) |
940 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't check for link info message"); |
941 | 0 | if (linfo_exists) { |
942 | | /* Using the new format for groups */ |
943 | 0 | use_old_format = false; |
944 | | |
945 | | /* Check for dense or compact storage */ |
946 | 0 | if (H5_addr_defined(linfo.fheap_addr)) { |
947 | | /* Remove object from the dense link storage */ |
948 | 0 | if (H5G__dense_remove(oloc->file, &linfo, grp_full_path_r, name) < 0) |
949 | 0 | HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "can't remove object"); |
950 | 0 | } /* end if */ |
951 | 0 | else |
952 | | /* Remove object from the link messages */ |
953 | 0 | if (H5G__compact_remove(oloc, grp_full_path_r, name) < 0) |
954 | 0 | HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "can't remove object"); |
955 | 0 | } /* end if */ |
956 | 0 | else { |
957 | | /* Using the old format for groups */ |
958 | 0 | use_old_format = true; |
959 | | |
960 | | /* Remove object from the symbol table */ |
961 | 0 | if (H5G__stab_remove(oloc, grp_full_path_r, name) < 0) |
962 | 0 | HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "can't remove object"); |
963 | 0 | } /* end else */ |
964 | | |
965 | | /* Update link info for a new-style group */ |
966 | 0 | if (!use_old_format) |
967 | 0 | if (H5G__obj_remove_update_linfo(oloc, &linfo) < 0) |
968 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTUPDATE, FAIL, "unable to update link info"); |
969 | | |
970 | 0 | done: |
971 | 0 | FUNC_LEAVE_NOAPI_TAG(ret_value) |
972 | 0 | } /* end H5G_obj_remove() */ |
973 | | |
974 | | /*------------------------------------------------------------------------- |
975 | | * Function: H5G_obj_remove_by_idx |
976 | | * |
977 | | * Purpose: Remove a link from a group, according to the order within an index. |
978 | | * |
979 | | * Return: Success: Non-negative |
980 | | * Failure: Negative |
981 | | * |
982 | | *------------------------------------------------------------------------- |
983 | | */ |
984 | | herr_t |
985 | | H5G_obj_remove_by_idx(const H5O_loc_t *grp_oloc, H5RS_str_t *grp_full_path_r, H5_index_t idx_type, |
986 | | H5_iter_order_t order, hsize_t n) |
987 | 0 | { |
988 | 0 | H5O_linfo_t linfo; /* Link info message */ |
989 | 0 | htri_t linfo_exists; /* Whether the link info message exists */ |
990 | 0 | bool use_old_format; /* Whether to use 'old format' (symbol table) for deletion or not */ |
991 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
992 | |
|
993 | 0 | FUNC_ENTER_NOAPI(FAIL) |
994 | | |
995 | | /* Sanity check */ |
996 | 0 | assert(grp_oloc && grp_oloc->file); |
997 | | |
998 | | /* Attempt to get the link info for this group */ |
999 | 0 | if ((linfo_exists = H5G__obj_get_linfo(grp_oloc, &linfo)) < 0) |
1000 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't check for link info message"); |
1001 | 0 | if (linfo_exists) { |
1002 | | /* Check for creation order tracking, if creation order index lookup requested */ |
1003 | 0 | if (idx_type == H5_INDEX_CRT_ORDER) { |
1004 | | /* Check if creation order is tracked */ |
1005 | 0 | if (!linfo.track_corder) |
1006 | 0 | HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "creation order not tracked for links in group"); |
1007 | 0 | } /* end if */ |
1008 | | |
1009 | | /* Using the new format for groups */ |
1010 | 0 | use_old_format = false; |
1011 | | |
1012 | | /* Check for dense or compact storage */ |
1013 | 0 | if (H5_addr_defined(linfo.fheap_addr)) { |
1014 | | /* Remove object from the dense link storage */ |
1015 | 0 | if (H5G__dense_remove_by_idx(grp_oloc->file, &linfo, grp_full_path_r, idx_type, order, n) < 0) |
1016 | 0 | HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "can't remove object"); |
1017 | 0 | } /* end if */ |
1018 | 0 | else { |
1019 | | /* Remove object from compact link storage */ |
1020 | 0 | if (H5G__compact_remove_by_idx(grp_oloc, &linfo, grp_full_path_r, idx_type, order, n) < 0) |
1021 | 0 | HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "can't remove object"); |
1022 | 0 | } /* end else */ |
1023 | 0 | } /* end if */ |
1024 | 0 | else { |
1025 | | /* Can only perform name lookups on groups with symbol tables */ |
1026 | 0 | if (idx_type != H5_INDEX_NAME) |
1027 | 0 | HGOTO_ERROR(H5E_SYM, H5E_BADVALUE, FAIL, "no creation order index to query"); |
1028 | | |
1029 | | /* Using the old format for groups */ |
1030 | 0 | use_old_format = true; |
1031 | | |
1032 | | /* Remove object from the symbol table */ |
1033 | 0 | if (H5G__stab_remove_by_idx(grp_oloc, grp_full_path_r, order, n) < 0) |
1034 | 0 | HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "can't remove object"); |
1035 | 0 | } /* end else */ |
1036 | | |
1037 | | /* Update link info for a new-style group */ |
1038 | 0 | if (!use_old_format) |
1039 | 0 | if (H5G__obj_remove_update_linfo(grp_oloc, &linfo) < 0) |
1040 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTUPDATE, FAIL, "unable to update link info"); |
1041 | | |
1042 | 0 | done: |
1043 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1044 | 0 | } /* end H5G_obj_remove() */ |
1045 | | |
1046 | | /*------------------------------------------------------------------------- |
1047 | | * Function: H5G__obj_lookup |
1048 | | * |
1049 | | * Purpose: Look up a link in a group, using the name as the key. |
1050 | | * |
1051 | | * Return: Non-negative on success/Negative on failure |
1052 | | * |
1053 | | *------------------------------------------------------------------------- |
1054 | | */ |
1055 | | herr_t |
1056 | | H5G__obj_lookup(const H5O_loc_t *grp_oloc, const char *name, bool *found, H5O_link_t *lnk) |
1057 | 142 | { |
1058 | 142 | H5O_linfo_t linfo; /* Link info message */ |
1059 | 142 | htri_t linfo_exists; /* Whether the link info message exists */ |
1060 | 142 | herr_t ret_value = SUCCEED; /* Return value */ |
1061 | | |
1062 | 142 | FUNC_ENTER_PACKAGE_TAG(grp_oloc->addr) |
1063 | | |
1064 | | /* check arguments */ |
1065 | 142 | assert(grp_oloc && grp_oloc->file); |
1066 | 142 | assert(name && *name); |
1067 | | |
1068 | | /* Attempt to get the link info message for this group */ |
1069 | 142 | if ((linfo_exists = H5G__obj_get_linfo(grp_oloc, &linfo)) < 0) |
1070 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't check for link info message"); |
1071 | 142 | if (linfo_exists) { |
1072 | | /* Check for dense link storage */ |
1073 | 0 | if (H5_addr_defined(linfo.fheap_addr)) { |
1074 | | /* Get the object's info from the dense link storage */ |
1075 | 0 | if (H5G__dense_lookup(grp_oloc->file, &linfo, name, found, lnk) < 0) |
1076 | 0 | HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "can't locate object"); |
1077 | 0 | } /* end if */ |
1078 | 0 | else { |
1079 | | /* Get the object's info from the link messages */ |
1080 | 0 | if (H5G__compact_lookup(grp_oloc, name, found, lnk) < 0) |
1081 | 0 | HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "can't locate object"); |
1082 | 0 | } /* end else */ |
1083 | 0 | } /* end if */ |
1084 | 142 | else |
1085 | | /* Get the object's info from the symbol table */ |
1086 | 142 | if (H5G__stab_lookup(grp_oloc, name, found, lnk) < 0) |
1087 | 0 | HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "can't locate object"); |
1088 | | |
1089 | 142 | done: |
1090 | 142 | FUNC_LEAVE_NOAPI_TAG(ret_value) |
1091 | 142 | } /* end H5G__obj_lookup() */ |
1092 | | |
1093 | | /*------------------------------------------------------------------------- |
1094 | | * Function: H5G_obj_lookup_by_idx |
1095 | | * |
1096 | | * Purpose: Look up link info in a group, according to an order within an |
1097 | | * index. |
1098 | | * |
1099 | | * Return: Non-negative on success/Negative on failure |
1100 | | * |
1101 | | *------------------------------------------------------------------------- |
1102 | | */ |
1103 | | herr_t |
1104 | | H5G_obj_lookup_by_idx(const H5O_loc_t *grp_oloc, H5_index_t idx_type, H5_iter_order_t order, hsize_t n, |
1105 | | H5O_link_t *lnk) |
1106 | 0 | { |
1107 | 0 | H5O_linfo_t linfo; /* Link info message */ |
1108 | 0 | htri_t linfo_exists; /* Whether the link info message exists */ |
1109 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
1110 | |
|
1111 | 0 | FUNC_ENTER_NOAPI_TAG(grp_oloc->addr, FAIL) |
1112 | | |
1113 | | /* check arguments */ |
1114 | 0 | assert(grp_oloc && grp_oloc->file); |
1115 | | |
1116 | | /* Attempt to get the link info message for this group */ |
1117 | 0 | if ((linfo_exists = H5G__obj_get_linfo(grp_oloc, &linfo)) < 0) |
1118 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't check for link info message"); |
1119 | 0 | if (linfo_exists) { |
1120 | | /* Check for creation order tracking, if creation order index lookup requested */ |
1121 | 0 | if (idx_type == H5_INDEX_CRT_ORDER) { |
1122 | | /* Check if creation order is tracked */ |
1123 | 0 | if (!linfo.track_corder) |
1124 | 0 | HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "creation order not tracked for links in group"); |
1125 | 0 | } /* end if */ |
1126 | | |
1127 | | /* Check for dense link storage */ |
1128 | 0 | if (H5_addr_defined(linfo.fheap_addr)) { |
1129 | | /* Get the link from the dense storage */ |
1130 | 0 | if (H5G__dense_lookup_by_idx(grp_oloc->file, &linfo, idx_type, order, n, lnk) < 0) |
1131 | 0 | HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "can't locate object"); |
1132 | 0 | } /* end if */ |
1133 | 0 | else { |
1134 | | /* Get the link from the link messages */ |
1135 | 0 | if (H5G__compact_lookup_by_idx(grp_oloc, &linfo, idx_type, order, n, lnk) < 0) |
1136 | 0 | HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "can't locate object"); |
1137 | 0 | } /* end else */ |
1138 | 0 | } /* end if */ |
1139 | 0 | else { |
1140 | | /* Can only perform name lookups on groups with symbol tables */ |
1141 | 0 | if (idx_type != H5_INDEX_NAME) |
1142 | 0 | HGOTO_ERROR(H5E_SYM, H5E_BADVALUE, FAIL, "no creation order index to query"); |
1143 | | |
1144 | | /* Get the object's info from the symbol table */ |
1145 | 0 | if (H5G__stab_lookup_by_idx(grp_oloc, order, n, lnk) < 0) |
1146 | 0 | HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "can't locate object"); |
1147 | 0 | } /* end else */ |
1148 | | |
1149 | 0 | done: |
1150 | 0 | FUNC_LEAVE_NOAPI_TAG(ret_value) |
1151 | 0 | } /* end H5G_obj_lookup_by_idx() */ |