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: H5Groot.c |
16 | | * |
17 | | * Purpose: Functions for operating on the root group. |
18 | | * |
19 | | *------------------------------------------------------------------------- |
20 | | */ |
21 | | |
22 | | /****************/ |
23 | | /* Module Setup */ |
24 | | /****************/ |
25 | | |
26 | | #define H5F_FRIEND /*suppress error about including H5Fpkg */ |
27 | | #include "H5Gmodule.h" /* This source code file is part of the H5G module */ |
28 | | |
29 | | /***********/ |
30 | | /* Headers */ |
31 | | /***********/ |
32 | | #include "H5private.h" /* Generic Functions */ |
33 | | #include "H5Eprivate.h" /* Error handling */ |
34 | | #include "H5Fpkg.h" /* File access */ |
35 | | #include "H5FLprivate.h" /* Free Lists */ |
36 | | #include "H5Gpkg.h" /* Groups */ |
37 | | #include "H5MMprivate.h" /* Memory management */ |
38 | | |
39 | | /****************/ |
40 | | /* Local Macros */ |
41 | | /****************/ |
42 | | |
43 | | /******************/ |
44 | | /* Local Typedefs */ |
45 | | /******************/ |
46 | | |
47 | | /********************/ |
48 | | /* Package Typedefs */ |
49 | | /********************/ |
50 | | |
51 | | /********************/ |
52 | | /* Local Prototypes */ |
53 | | /********************/ |
54 | | |
55 | | /*********************/ |
56 | | /* Package Variables */ |
57 | | /*********************/ |
58 | | |
59 | | /*****************************/ |
60 | | /* Library Private Variables */ |
61 | | /*****************************/ |
62 | | |
63 | | /*******************/ |
64 | | /* Local Variables */ |
65 | | /*******************/ |
66 | | |
67 | | /*------------------------------------------------------------------------- |
68 | | * Function: H5G_rootof |
69 | | * |
70 | | * Purpose: Return a pointer to the root group of the file. If the file |
71 | | * is part of a virtual file then the root group of the virtual |
72 | | * file is returned. |
73 | | * |
74 | | * Return: Success: Ptr to the root group of the file. Do not |
75 | | * free the pointer -- it points directly into |
76 | | * the file struct. |
77 | | * |
78 | | * Failure: NULL |
79 | | * |
80 | | *------------------------------------------------------------------------- |
81 | | */ |
82 | | H5G_t * |
83 | | H5G_rootof(H5F_t *f) |
84 | 0 | { |
85 | 0 | FUNC_ENTER_NOAPI_NOINIT_NOERR |
86 | | |
87 | | /* Sanity check */ |
88 | 0 | assert(f); |
89 | 0 | assert(f->shared); |
90 | | |
91 | | /* Walk to top of mounted files */ |
92 | 0 | while (f->parent) |
93 | 0 | f = f->parent; |
94 | | |
95 | | /* Sanity check */ |
96 | 0 | assert(f); |
97 | 0 | assert(f->shared); |
98 | 0 | assert(f->shared->root_grp); |
99 | | |
100 | | /* Check to see if the root group was opened through a different |
101 | | * "top" file, and switch it to point at the current "top" file. |
102 | | */ |
103 | 0 | if (f->shared->root_grp->oloc.file != f) |
104 | 0 | f->shared->root_grp->oloc.file = f; |
105 | |
|
106 | 0 | FUNC_LEAVE_NOAPI(f->shared->root_grp) |
107 | 0 | } /* end H5G_rootof() */ |
108 | | |
109 | | /*------------------------------------------------------------------------- |
110 | | * Function: H5G_mkroot |
111 | | * |
112 | | * Purpose: Creates a root group in an empty file and opens it. If a |
113 | | * root group is already open then this function immediately |
114 | | * returns. If ENT is non-null then it's the symbol table |
115 | | * entry for an existing group which will be opened as the root |
116 | | * group. Otherwise a new root group is created and then |
117 | | * opened. |
118 | | * |
119 | | * Return: Non-negative on success/Negative on failure |
120 | | * |
121 | | *------------------------------------------------------------------------- |
122 | | */ |
123 | | herr_t |
124 | | H5G_mkroot(H5F_t *f, bool create_root) |
125 | 205 | { |
126 | 205 | H5G_loc_t root_loc; /* Root location information */ |
127 | 205 | H5G_obj_create_t gcrt_info; /* Root group object creation info */ |
128 | 205 | htri_t stab_exists = -1; /* Whether the symbol table exists */ |
129 | 205 | bool sblock_dirty = false; /* Whether superblock was dirtied */ |
130 | 205 | bool path_init = false; /* Whether path was initialized */ |
131 | 205 | herr_t ret_value = SUCCEED; /* Return value */ |
132 | | |
133 | 205 | FUNC_ENTER_NOAPI(FAIL) |
134 | | |
135 | | /* check args */ |
136 | 205 | assert(f); |
137 | 205 | assert(f->shared); |
138 | 205 | assert(f->shared->sblock); |
139 | | |
140 | | /* Check if the root group is already initialized */ |
141 | 205 | if (f->shared->root_grp) |
142 | 0 | HGOTO_DONE(SUCCEED); |
143 | | |
144 | | /* Create information needed for group nodes */ |
145 | 205 | if (H5G__node_init(f) < 0) |
146 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to create group node info"); |
147 | | |
148 | | /* |
149 | | * Create the group pointer |
150 | | */ |
151 | 205 | if (NULL == (f->shared->root_grp = H5FL_CALLOC(H5G_t))) |
152 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed"); |
153 | 205 | if (NULL == (f->shared->root_grp->shared = H5FL_CALLOC(H5G_shared_t))) { |
154 | 0 | f->shared->root_grp = H5FL_FREE(H5G_t, f->shared->root_grp); |
155 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed"); |
156 | 0 | } /* end if */ |
157 | | |
158 | | /* Initialize the root_loc structure to point to fields in the newly created |
159 | | * f->shared->root_grp structure */ |
160 | 205 | root_loc.oloc = &(f->shared->root_grp->oloc); |
161 | 205 | root_loc.path = &(f->shared->root_grp->path); |
162 | 205 | H5G_loc_reset(&root_loc); |
163 | | |
164 | | /* |
165 | | * If there is no root object then create one. The root group always starts |
166 | | * with a hard link count of one since it's pointed to by the superblock. |
167 | | */ |
168 | 205 | if (create_root) { |
169 | | /* Create root group */ |
170 | | /* (Pass the FCPL which is a sub-class of the group creation property class) */ |
171 | 0 | gcrt_info.gcpl_id = f->shared->fcpl_id; |
172 | 0 | gcrt_info.cache_type = H5G_NOTHING_CACHED; |
173 | 0 | if (H5G__obj_create(f, &gcrt_info, root_loc.oloc /*out*/) < 0) |
174 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to create group entry"); |
175 | 0 | if (1 != H5O_link(root_loc.oloc, 1)) |
176 | 0 | HGOTO_ERROR(H5E_SYM, H5E_LINKCOUNT, FAIL, "internal error (wrong link count)"); |
177 | | |
178 | | /* Decrement refcount on root group's object header in memory */ |
179 | 0 | if (H5O_dec_rc_by_loc(root_loc.oloc) < 0) |
180 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTDEC, FAIL, |
181 | 0 | "unable to decrement refcount on root group's object header"); |
182 | | |
183 | | /* Mark superblock dirty, so root group info is flushed */ |
184 | 0 | sblock_dirty = true; |
185 | | |
186 | | /* Create the root group symbol table entry */ |
187 | 0 | assert(!f->shared->sblock->root_ent); |
188 | 0 | if (f->shared->sblock->super_vers < HDF5_SUPERBLOCK_VERSION_2) { |
189 | | /* Allocate space for the root group symbol table entry */ |
190 | 0 | if (NULL == (f->shared->sblock->root_ent = (H5G_entry_t *)H5MM_calloc(sizeof(H5G_entry_t)))) |
191 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "can't allocate space for symbol table entry"); |
192 | | |
193 | | /* Initialize the root group symbol table entry */ |
194 | 0 | f->shared->sblock->root_ent->type = gcrt_info.cache_type; |
195 | 0 | if (gcrt_info.cache_type != H5G_NOTHING_CACHED) |
196 | 0 | f->shared->sblock->root_ent->cache = gcrt_info.cache; |
197 | 0 | f->shared->sblock->root_ent->name_off = 0; /* No name (yet) */ |
198 | 0 | f->shared->sblock->root_ent->header = root_loc.oloc->addr; |
199 | 0 | } /* end if */ |
200 | 0 | } /* end if */ |
201 | 205 | else { |
202 | | /* Create root group object location from f */ |
203 | 205 | root_loc.oloc->addr = f->shared->sblock->root_addr; |
204 | 205 | root_loc.oloc->file = f; |
205 | | |
206 | | /* |
207 | | * Open the root object as a group. |
208 | | */ |
209 | 205 | if (H5O_open(root_loc.oloc) < 0) |
210 | 0 | HGOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "unable to open root group"); |
211 | | |
212 | | /* Actions to take if the symbol table information is cached */ |
213 | 205 | if (f->shared->sblock->root_ent && f->shared->sblock->root_ent->type == H5G_CACHED_STAB) { |
214 | | /* Check for the situation where the symbol table is cached but does |
215 | | * not exist. This can happen if, for example, an external link is |
216 | | * added to the root group. */ |
217 | 136 | if ((stab_exists = H5O_msg_exists(root_loc.oloc, H5O_STAB_ID)) < 0) |
218 | 69 | HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't check if symbol table message exists"); |
219 | | |
220 | | /* Remove the cache if the stab does not exist */ |
221 | 67 | if (!stab_exists) |
222 | 24 | f->shared->sblock->root_ent->type = H5G_NOTHING_CACHED; |
223 | 43 | #ifndef H5_STRICT_FORMAT_CHECKS |
224 | | /* If symbol table information is cached, check if we should replace the |
225 | | * symbol table message with the cached symbol table information */ |
226 | 43 | else if (H5F_INTENT(f) & H5F_ACC_RDWR) { |
227 | 43 | H5O_stab_t cached_stab; |
228 | | |
229 | | /* Retrieve the cached symbol table information */ |
230 | 43 | cached_stab.btree_addr = f->shared->sblock->root_ent->cache.stab.btree_addr; |
231 | 43 | cached_stab.heap_addr = f->shared->sblock->root_ent->cache.stab.heap_addr; |
232 | | |
233 | | /* Check if the symbol table message is valid, and replace with the |
234 | | * cached symbol table if necessary */ |
235 | 43 | if (H5G__stab_valid(root_loc.oloc, &cached_stab) < 0) |
236 | 13 | HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "unable to verify symbol table"); |
237 | 43 | } /* end if */ |
238 | 67 | #endif /* H5_STRICT_FORMAT_CHECKS */ |
239 | 67 | } /* end if */ |
240 | 205 | } /* end else */ |
241 | | |
242 | | /* Cache the root group's symbol table information in the root group symbol |
243 | | * table entry. It will have been allocated by now if it needs to be |
244 | | * present, so we don't need to check the superblock version. We do this if |
245 | | * we have write access, the root entry has been allocated (i.e. |
246 | | * super_vers < 2) and the stab info is not already cached. */ |
247 | 123 | if ((H5F_INTENT(f) & H5F_ACC_RDWR) && stab_exists != false && f->shared->sblock->root_ent && |
248 | 99 | f->shared->sblock->root_ent->type != H5G_CACHED_STAB) { |
249 | 69 | H5O_stab_t stab; /* Symbol table */ |
250 | | |
251 | | /* Check if the stab message exists. It's possible for the root group |
252 | | * to use the latest version while the superblock is an old version. |
253 | | * If stab_exists is not -1 then we have already checked. */ |
254 | 69 | if (stab_exists == -1 && (stab_exists = H5O_msg_exists(root_loc.oloc, H5O_STAB_ID)) < 0) |
255 | 58 | HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't check if symbol table message exists"); |
256 | | |
257 | 11 | if (stab_exists) { |
258 | | /* Read the root group's symbol table message */ |
259 | 0 | if (NULL == H5O_msg_read(root_loc.oloc, H5O_STAB_ID, &stab)) |
260 | 0 | HGOTO_ERROR(H5E_SYM, H5E_BADMESG, FAIL, "unable to read symbol table message"); |
261 | | |
262 | | /* Update the root group symbol table entry */ |
263 | 0 | f->shared->sblock->root_ent->type = H5G_CACHED_STAB; |
264 | 0 | f->shared->sblock->root_ent->cache.stab.btree_addr = stab.btree_addr; |
265 | 0 | f->shared->sblock->root_ent->cache.stab.heap_addr = stab.heap_addr; |
266 | | |
267 | | /* Mark superblock dirty, so root group info is flushed */ |
268 | 0 | sblock_dirty = true; |
269 | 0 | } /* end if */ |
270 | 11 | } /* end if */ |
271 | | |
272 | | /* Create the path names for the root group's entry */ |
273 | 65 | H5G__name_init(root_loc.path, "/"); |
274 | 65 | path_init = true; |
275 | | |
276 | 65 | f->shared->root_grp->shared->fo_count = 1; |
277 | | /* The only other open object should be the superblock extension, if it |
278 | | * exists. Don't count either the superblock extension or the root group |
279 | | * in the number of open objects in the file. |
280 | | */ |
281 | 65 | assert((1 == f->nopen_objs) || (2 == f->nopen_objs && HADDR_UNDEF != f->shared->sblock->ext_addr)); |
282 | 65 | f->nopen_objs--; |
283 | | |
284 | 205 | done: |
285 | | /* In case of error, free various memory locations that may have been |
286 | | * allocated */ |
287 | 205 | if (ret_value < 0) { |
288 | 140 | if (f->shared->root_grp) { |
289 | 140 | if (path_init) |
290 | 0 | H5G_name_free(root_loc.path); |
291 | 140 | if (f->shared->root_grp->shared) |
292 | 140 | f->shared->root_grp->shared = H5FL_FREE(H5G_shared_t, f->shared->root_grp->shared); |
293 | 140 | f->shared->root_grp = H5FL_FREE(H5G_t, f->shared->root_grp); |
294 | 140 | } /* end if */ |
295 | 140 | if (f->shared->sblock) |
296 | 140 | f->shared->sblock->root_ent = (H5G_entry_t *)H5MM_xfree(f->shared->sblock->root_ent); |
297 | 140 | } /* end if */ |
298 | | |
299 | | /* Mark superblock dirty in cache, if necessary */ |
300 | 205 | if (sblock_dirty) |
301 | 0 | if (H5AC_mark_entry_dirty(f->shared->sblock) < 0) |
302 | 0 | HDONE_ERROR(H5E_FILE, H5E_CANTMARKDIRTY, FAIL, "unable to mark superblock as dirty"); |
303 | | |
304 | 205 | FUNC_LEAVE_NOAPI(ret_value) |
305 | 205 | } /* end H5G_mkroot() */ |
306 | | |
307 | | /*------------------------------------------------------------------------- |
308 | | * Function: H5G_root_free |
309 | | * |
310 | | * Purpose: Free memory used by an H5G_t struct (and its H5G_shared_t). |
311 | | * Does not close the group or decrement the reference count. |
312 | | * Used to free memory used by the root group. |
313 | | * |
314 | | * Return: Success: Non-negative |
315 | | * Failure: Negative |
316 | | * |
317 | | *------------------------------------------------------------------------- |
318 | | */ |
319 | | herr_t |
320 | | H5G_root_free(H5G_t *grp) |
321 | 65 | { |
322 | 65 | FUNC_ENTER_NOAPI_NOINIT_NOERR |
323 | | |
324 | | /* Check args */ |
325 | 65 | assert(grp && grp->shared); |
326 | 65 | assert(grp->shared->fo_count > 0); |
327 | | |
328 | | /* Free the path */ |
329 | 65 | H5G_name_free(&(grp->path)); |
330 | | |
331 | 65 | grp->shared = H5FL_FREE(H5G_shared_t, grp->shared); |
332 | 65 | grp = H5FL_FREE(H5G_t, grp); |
333 | | |
334 | 65 | FUNC_LEAVE_NOAPI(SUCCEED) |
335 | 65 | } /* end H5G_root_free() */ |
336 | | |
337 | | /*------------------------------------------------------------------------- |
338 | | * Function: H5G_root_loc |
339 | | * |
340 | | * Purpose: Construct a "group location" for the root group of a file |
341 | | * |
342 | | * Return: Success: Non-negative |
343 | | * Failure: Negative |
344 | | * |
345 | | *------------------------------------------------------------------------- |
346 | | */ |
347 | | herr_t |
348 | | H5G_root_loc(H5F_t *f, H5G_loc_t *loc) |
349 | 0 | { |
350 | 0 | H5G_t *root_grp; /* Pointer to root group's info */ |
351 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
352 | |
|
353 | 0 | FUNC_ENTER_NOAPI(FAIL) |
354 | |
|
355 | 0 | assert(f); |
356 | 0 | assert(loc); |
357 | | |
358 | | /* Retrieve the root group for the file */ |
359 | 0 | root_grp = H5G_rootof(f); |
360 | 0 | assert(root_grp); |
361 | | |
362 | | /* Build the group location for the root group */ |
363 | 0 | if (NULL == (loc->oloc = H5G_oloc(root_grp))) |
364 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get object location for root group"); |
365 | 0 | if (NULL == (loc->path = H5G_nameof(root_grp))) |
366 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get path for root group"); |
367 | | |
368 | | /* Patch up root group's object location to reflect this file */ |
369 | | /* (Since the root group info is only stored once for files which |
370 | | * share an underlying low-level file) |
371 | | */ |
372 | | /* (but only for non-mounted files) */ |
373 | 0 | if (!H5F_is_mount(f)) { |
374 | 0 | loc->oloc->file = f; |
375 | 0 | loc->oloc->holding_file = false; |
376 | 0 | } /* end if */ |
377 | |
|
378 | 0 | done: |
379 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
380 | 0 | } /* end H5G_root_loc() */ |