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 | | /* Module Setup */ |
15 | | /****************/ |
16 | | |
17 | | #include "H5Fmodule.h" /* This source code file is part of the H5F module */ |
18 | | |
19 | | /***********/ |
20 | | /* Headers */ |
21 | | /***********/ |
22 | | #include "H5private.h" /* Generic Functions */ |
23 | | #include "H5Aprivate.h" /* Attributes */ |
24 | | #include "H5ACprivate.h" /* Metadata cache */ |
25 | | #include "H5CXprivate.h" /* API Contexts */ |
26 | | #include "H5Dprivate.h" /* Datasets */ |
27 | | #include "H5Eprivate.h" /* Error handling */ |
28 | | #include "H5Fpkg.h" /* File access */ |
29 | | #include "H5FDprivate.h" /* File drivers */ |
30 | | #include "H5FLprivate.h" /* Free Lists */ |
31 | | #include "H5Gprivate.h" /* Groups */ |
32 | | #include "H5Iprivate.h" /* IDs */ |
33 | | #include "H5MFprivate.h" /* File memory management */ |
34 | | #include "H5MMprivate.h" /* Memory management */ |
35 | | #include "H5Pprivate.h" /* Property lists */ |
36 | | #include "H5SMprivate.h" /* Shared Object Header Messages */ |
37 | | #include "H5Tprivate.h" /* Datatypes */ |
38 | | #include "H5VLprivate.h" /* Virtual Object Layer */ |
39 | | |
40 | | #include "H5VLnative_private.h" /* Native VOL connector */ |
41 | | |
42 | | /****************/ |
43 | | /* Local Macros */ |
44 | | /****************/ |
45 | | |
46 | | /******************/ |
47 | | /* Local Typedefs */ |
48 | | /******************/ |
49 | | |
50 | | /* Struct only used by functions H5F__get_objects and H5F__get_objects_cb */ |
51 | | typedef struct H5F_olist_t { |
52 | | H5I_type_t obj_type; /* Type of object to look for */ |
53 | | hid_t *obj_id_list; /* Pointer to the list of open IDs to return */ |
54 | | size_t *obj_id_count; /* Number of open IDs */ |
55 | | struct { |
56 | | bool local; /* Set flag for "local" file searches */ |
57 | | union { |
58 | | H5F_shared_t *shared; /* Pointer to shared file to look inside */ |
59 | | const H5F_t *file; /* Pointer to file to look inside */ |
60 | | } ptr; |
61 | | } file_info; |
62 | | size_t list_index; /* Current index in open ID array */ |
63 | | size_t max_nobjs; /* Maximum # of IDs to put into array */ |
64 | | } H5F_olist_t; |
65 | | |
66 | | /********************/ |
67 | | /* Package Typedefs */ |
68 | | /********************/ |
69 | | |
70 | | /********************/ |
71 | | /* Local Prototypes */ |
72 | | /********************/ |
73 | | |
74 | | static herr_t H5F__close_cb(void *file_vol_obj, void **request); |
75 | | static herr_t H5F__set_vol_conn(H5F_t *file); |
76 | | static herr_t H5F__get_objects(const H5F_t *f, unsigned types, size_t max_index, hid_t *obj_id_list, |
77 | | bool app_ref, size_t *obj_id_count_ptr); |
78 | | static int H5F__get_objects_cb(void *obj_ptr, hid_t obj_id, void *key); |
79 | | static herr_t H5F__build_name(const char *prefix, const char *file_name, char **full_name /*out*/); |
80 | | static char *H5F__getenv_prefix_name(char **env_prefix /*in,out*/); |
81 | | static H5F_t *H5F__new(H5F_shared_t *shared, unsigned flags, hid_t fcpl_id, hid_t fapl_id, H5FD_t *lf); |
82 | | static herr_t H5F__check_if_using_file_locks(H5P_genplist_t *fapl, bool *use_file_locking, |
83 | | bool *ignore_disabled_locks); |
84 | | static herr_t H5F__dest(H5F_t *f, bool flush, bool free_on_failure); |
85 | | static herr_t H5F__build_actual_name(const H5F_t *f, const H5P_genplist_t *fapl, const char *name, |
86 | | char ** /*out*/ actual_name); |
87 | | static herr_t H5F__flush_phase1(H5F_t *f); |
88 | | static herr_t H5F__flush_phase2(H5F_t *f, bool closing); |
89 | | |
90 | | /*********************/ |
91 | | /* Package Variables */ |
92 | | /*********************/ |
93 | | |
94 | | /* Package initialization variable */ |
95 | | bool H5_PKG_INIT_VAR = false; |
96 | | |
97 | | /* Based on the value of the HDF5_USE_FILE_LOCKING environment variable. |
98 | | * true/false have obvious meanings. FAIL means the environment variable was |
99 | | * not set, so the code should ignore it and use the fapl value instead. |
100 | | */ |
101 | | htri_t use_locks_env_g = FAIL; |
102 | | htri_t ignore_disabled_locks_g = FAIL; |
103 | | |
104 | | /*****************************/ |
105 | | /* Library Private Variables */ |
106 | | /*****************************/ |
107 | | |
108 | | /*******************/ |
109 | | /* Local Variables */ |
110 | | /*******************/ |
111 | | |
112 | | /* Declare a free list to manage the H5F_t struct */ |
113 | | H5FL_DEFINE(H5F_t); |
114 | | |
115 | | /* Declare a free list to manage the H5F_shared_t struct */ |
116 | | H5FL_DEFINE(H5F_shared_t); |
117 | | |
118 | | /* File ID class */ |
119 | | static const H5I_class_t H5I_FILE_CLS[1] = {{ |
120 | | H5I_FILE, /* ID class value */ |
121 | | 0, /* Class flags */ |
122 | | 0, /* # of reserved IDs for class */ |
123 | | H5F__close_cb /* Callback routine for closing objects of this class */ |
124 | | }}; |
125 | | |
126 | | /*------------------------------------------------------------------------- |
127 | | * Function: H5F_init |
128 | | * |
129 | | * Purpose: Initialize the interface from some other layer. |
130 | | * |
131 | | * Return: Success: non-negative |
132 | | * |
133 | | * Failure: negative |
134 | | *------------------------------------------------------------------------- |
135 | | */ |
136 | | herr_t |
137 | | H5F_init(void) |
138 | 1 | { |
139 | 1 | herr_t ret_value = SUCCEED; /* Return value */ |
140 | | |
141 | 1 | FUNC_ENTER_NOAPI(FAIL) |
142 | | /* FUNC_ENTER() does all the work */ |
143 | | |
144 | 1 | done: |
145 | 1 | FUNC_LEAVE_NOAPI(ret_value) |
146 | 1 | } /* end H5F_init() */ |
147 | | |
148 | | /*-------------------------------------------------------------------------- |
149 | | NAME |
150 | | H5F__init_package -- Initialize interface-specific information |
151 | | USAGE |
152 | | herr_t H5F__init_package() |
153 | | RETURNS |
154 | | Non-negative on success/Negative on failure |
155 | | DESCRIPTION |
156 | | Initializes any interface-specific data or routines. |
157 | | |
158 | | --------------------------------------------------------------------------*/ |
159 | | herr_t |
160 | | H5F__init_package(void) |
161 | 1 | { |
162 | 1 | herr_t ret_value = SUCCEED; /* Return value */ |
163 | | |
164 | 1 | FUNC_ENTER_PACKAGE |
165 | | |
166 | | /* Initialize the ID group for the file IDs */ |
167 | 1 | if (H5I_register_type(H5I_FILE_CLS) < 0) |
168 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "unable to initialize interface"); |
169 | | |
170 | | /* Check the file locking environment variable */ |
171 | 1 | if (H5F__parse_file_lock_env_var(&use_locks_env_g, &ignore_disabled_locks_g) < 0) |
172 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "unable to parse file locking environment variable"); |
173 | | |
174 | 1 | done: |
175 | 1 | FUNC_LEAVE_NOAPI(ret_value) |
176 | 1 | } /* H5F__init_package() */ |
177 | | |
178 | | /*------------------------------------------------------------------------- |
179 | | * Function: H5F_term_package |
180 | | * |
181 | | * Purpose: Terminate this interface: free all memory and reset global |
182 | | * variables to their initial values. Release all ID groups |
183 | | * associated with this interface. |
184 | | * |
185 | | * Return: Success: Positive if anything was done that might |
186 | | * have affected other interfaces; |
187 | | * zero otherwise. |
188 | | * |
189 | | * Failure: Never fails |
190 | | * |
191 | | *------------------------------------------------------------------------- |
192 | | */ |
193 | | int |
194 | | H5F_term_package(void) |
195 | 100 | { |
196 | 100 | int n = 0; |
197 | | |
198 | 100 | FUNC_ENTER_NOAPI_NOINIT_NOERR |
199 | | |
200 | 2 | if (H5_PKG_INIT_VAR) { |
201 | 2 | if (H5I_nmembers(H5I_FILE) > 0) { |
202 | 1 | (void)H5I_clear_type(H5I_FILE, false, false); |
203 | 1 | n++; /*H5I*/ |
204 | 1 | } /* end if */ |
205 | 1 | else { |
206 | | /* Make certain we've cleaned up all the shared file objects */ |
207 | 1 | H5F_sfile_assert_num(0); |
208 | | |
209 | | /* Destroy the file object id group */ |
210 | 1 | n += (H5I_dec_type_ref(H5I_FILE) > 0); |
211 | | |
212 | | /* Mark closed */ |
213 | 1 | if (0 == n) |
214 | 1 | H5_PKG_INIT_VAR = false; |
215 | 1 | } /* end else */ |
216 | 2 | } /* end if */ |
217 | | |
218 | 2 | FUNC_LEAVE_NOAPI(n) |
219 | 100 | } /* end H5F_term_package() */ |
220 | | |
221 | | /*------------------------------------------------------------------------- |
222 | | * Function: H5F__close_cb |
223 | | * |
224 | | * Purpose: Closes a file or causes the close operation to be pended. |
225 | | * This function is called from the API and gets called |
226 | | * by H5Fclose->H5I_dec_ref->H5F__close_cb when H5I_dec_ref() |
227 | | * decrements the file ID reference count to zero. The file ID |
228 | | * is removed from the H5I_FILE group by H5I_dec_ref() just |
229 | | * before H5F__close_cb() is called. If there are open object |
230 | | * headers then the close is pended by moving the file to the |
231 | | * H5I_FILE_CLOSING ID group (the f->closing contains the ID |
232 | | * assigned to file). |
233 | | * |
234 | | * Return: SUCCEED/FAIL |
235 | | * |
236 | | *------------------------------------------------------------------------- |
237 | | */ |
238 | | static herr_t |
239 | | H5F__close_cb(void *file_vol_obj, void **request) |
240 | 12 | { |
241 | 12 | H5VL_object_t *file_vol_obj_p = (H5VL_object_t *)file_vol_obj; |
242 | 12 | herr_t ret_value = SUCCEED; /* Return value */ |
243 | | |
244 | 12 | FUNC_ENTER_PACKAGE |
245 | | |
246 | | /* Sanity check */ |
247 | 12 | assert(file_vol_obj_p); |
248 | | |
249 | | /* Close the file */ |
250 | 12 | if (H5VL_file_close(file_vol_obj_p, H5P_DATASET_XFER_DEFAULT, request) < 0) |
251 | 6 | HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "unable to close file"); |
252 | | |
253 | | /* Free the VOL object; it is unnecessary to unwrap the VOL |
254 | | * object before freeing it, as the object was not wrapped */ |
255 | 6 | if (H5VL_free_object(file_vol_obj_p) < 0) |
256 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTDEC, FAIL, "unable to free VOL object"); |
257 | | |
258 | 12 | done: |
259 | 12 | FUNC_LEAVE_NOAPI(ret_value) |
260 | 12 | } /* end H5F__close_cb() */ |
261 | | |
262 | | /*------------------------------------------------------------------------- |
263 | | * Function: H5F__parse_file_lock_env_var |
264 | | * |
265 | | * Purpose: Parses the HDF5_USE_FILE_LOCKING environment variable. |
266 | | * |
267 | | * NOTE: This is done in a separate function so we can call it from |
268 | | * the test code. |
269 | | * |
270 | | * Return: SUCCEED/FAIL |
271 | | * |
272 | | *------------------------------------------------------------------------- |
273 | | */ |
274 | | herr_t |
275 | | H5F__parse_file_lock_env_var(htri_t *use_locks, htri_t *ignore_disabled_locks) |
276 | 1 | { |
277 | 1 | char *lock_env_var = NULL; /* Environment variable pointer */ |
278 | | |
279 | 1 | FUNC_ENTER_PACKAGE_NOERR |
280 | | |
281 | | /* Check the file locking environment variable */ |
282 | 1 | lock_env_var = getenv(HDF5_USE_FILE_LOCKING); |
283 | 1 | if (lock_env_var && (!strcmp(lock_env_var, "FALSE") || !strcmp(lock_env_var, "0"))) { |
284 | 0 | *use_locks = false; /* Override: Never use locks */ |
285 | 0 | *ignore_disabled_locks = FAIL; |
286 | 0 | } |
287 | 1 | else if (lock_env_var && !strcmp(lock_env_var, "BEST_EFFORT")) { |
288 | 0 | *use_locks = true; /* Override: Always use locks */ |
289 | 0 | *ignore_disabled_locks = true; /* Override: Ignore disabled locks */ |
290 | 0 | } |
291 | 1 | else if (lock_env_var && (!strcmp(lock_env_var, "TRUE") || !strcmp(lock_env_var, "1"))) { |
292 | 0 | *use_locks = true; /* Override: Always use locks */ |
293 | 0 | *ignore_disabled_locks = false; /* Override: Don't ignore disabled locks */ |
294 | 0 | } |
295 | 1 | else { |
296 | | /* Environment variable not set, or not set correctly */ |
297 | 1 | *use_locks = FAIL; |
298 | 1 | *ignore_disabled_locks = FAIL; |
299 | 1 | } |
300 | | |
301 | 1 | FUNC_LEAVE_NOAPI(SUCCEED) |
302 | 1 | } /* end H5F__parse_file_lock_env_var() */ |
303 | | |
304 | | /*------------------------------------------------------------------------- |
305 | | * Function: H5F__set_vol_conn |
306 | | * |
307 | | * Purpose: Set the VOL connector ID and info for a file. |
308 | | * |
309 | | * Return: SUCCEED/FAIL |
310 | | * |
311 | | *------------------------------------------------------------------------- |
312 | | */ |
313 | | static herr_t |
314 | | H5F__set_vol_conn(H5F_t *file) |
315 | 15 | { |
316 | 15 | H5VL_connector_prop_t connector_prop; /* Property for VOL connector ID & info */ |
317 | 15 | void *new_connector_info = NULL; /* Copy of connector info */ |
318 | 15 | herr_t ret_value = SUCCEED; /* Return value */ |
319 | | |
320 | 15 | FUNC_ENTER_PACKAGE |
321 | | |
322 | | /* Sanity check */ |
323 | 15 | assert(file); |
324 | | |
325 | | /* Retrieve a copy of the "top-level" connector property, before any pass-through |
326 | | * connectors modified or unwrapped it. |
327 | | */ |
328 | 15 | if (H5CX_get_vol_connector_prop(&connector_prop) < 0) |
329 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "can't get VOL connector info from API context"); |
330 | | |
331 | | /* Sanity check */ |
332 | 15 | assert(connector_prop.connector); |
333 | | |
334 | | /* Allocate and copy connector info, if it exists */ |
335 | 15 | if (connector_prop.connector_info) |
336 | 0 | if (H5VL_copy_connector_info(connector_prop.connector, &new_connector_info, |
337 | 0 | connector_prop.connector_info) < 0) |
338 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTCOPY, FAIL, "connector info copy failed"); |
339 | | |
340 | | /* Cache the connector & info for the container */ |
341 | 15 | file->shared->vol_conn = connector_prop.connector; |
342 | 15 | file->shared->vol_info = new_connector_info; |
343 | 15 | if (H5VL_conn_inc_rc(file->shared->vol_conn) < 0) |
344 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTINC, FAIL, "incrementing VOL connector refcount failed"); |
345 | | |
346 | 15 | done: |
347 | 15 | FUNC_LEAVE_NOAPI(ret_value) |
348 | 15 | } /* end H5F__set_vol_conn() */ |
349 | | |
350 | | /*------------------------------------------------------------------------- |
351 | | * Function: H5F_get_access_plist |
352 | | * |
353 | | * Purpose: Returns a copy of the file access property list of the |
354 | | * specified file. |
355 | | * |
356 | | * NOTE: Make sure that, if you are going to overwrite |
357 | | * information in the copied property list that was |
358 | | * previously opened and assigned to the property list, then |
359 | | * you must close it before overwriting the values. |
360 | | * |
361 | | * Return: Success: Object ID for a copy of the file access |
362 | | * property list. |
363 | | * Failure: H5I_INVALID_HID |
364 | | *------------------------------------------------------------------------- |
365 | | */ |
366 | | hid_t |
367 | | H5F_get_access_plist(H5F_t *f, bool app_ref) |
368 | 0 | { |
369 | 0 | H5P_genplist_t *new_plist; /* New property list */ |
370 | 0 | H5P_genplist_t *old_plist; /* Old property list */ |
371 | 0 | H5FD_driver_prop_t driver_prop; /* Property for driver ID & info */ |
372 | 0 | bool driver_prop_copied = false; /* Whether the driver property has been set up */ |
373 | 0 | H5VL_connector_prop_t connector_prop; /* Property for VOL connector ID & info */ |
374 | 0 | unsigned efc_size = 0; |
375 | 0 | hid_t ret_value = H5I_INVALID_HID; /* Return value */ |
376 | |
|
377 | 0 | FUNC_ENTER_NOAPI(H5I_INVALID_HID) |
378 | | |
379 | | /* Check args */ |
380 | 0 | assert(f); |
381 | | |
382 | | /* Make a copy of the default file access property list */ |
383 | 0 | if (NULL == (old_plist = (H5P_genplist_t *)H5I_object(H5P_LST_FILE_ACCESS_ID_g))) |
384 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5I_INVALID_HID, "not a property list"); |
385 | 0 | if ((ret_value = H5P_copy_plist(old_plist, app_ref)) < 0) |
386 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, H5I_INVALID_HID, "can't copy file access property list"); |
387 | 0 | if (NULL == (new_plist = (H5P_genplist_t *)H5I_object(ret_value))) |
388 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5I_INVALID_HID, "not a property list"); |
389 | | |
390 | | /* Copy properties of the file access property list */ |
391 | 0 | if (H5P_set(new_plist, H5F_ACS_META_CACHE_INIT_CONFIG_NAME, &(f->shared->mdc_initCacheCfg)) < 0) |
392 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTSET, H5I_INVALID_HID, |
393 | 0 | "can't set initial metadata cache resize config."); |
394 | 0 | if (H5P_set(new_plist, H5F_ACS_DATA_CACHE_NUM_SLOTS_NAME, &(f->shared->rdcc_nslots)) < 0) |
395 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTSET, H5I_INVALID_HID, "can't set data cache number of slots"); |
396 | 0 | if (H5P_set(new_plist, H5F_ACS_DATA_CACHE_BYTE_SIZE_NAME, &(f->shared->rdcc_nbytes)) < 0) |
397 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTSET, H5I_INVALID_HID, "can't set data cache byte size"); |
398 | 0 | if (H5P_set(new_plist, H5F_ACS_PREEMPT_READ_CHUNKS_NAME, &(f->shared->rdcc_w0)) < 0) |
399 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTSET, H5I_INVALID_HID, "can't set preempt read chunks"); |
400 | 0 | if (H5P_set(new_plist, H5F_ACS_ALIGN_THRHD_NAME, &(f->shared->threshold)) < 0) |
401 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTSET, H5I_INVALID_HID, "can't set alignment threshold"); |
402 | 0 | if (H5P_set(new_plist, H5F_ACS_ALIGN_NAME, &(f->shared->alignment)) < 0) |
403 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTSET, H5I_INVALID_HID, "can't set alignment"); |
404 | 0 | if (H5P_set(new_plist, H5F_ACS_GARBG_COLCT_REF_NAME, &(f->shared->gc_ref)) < 0) |
405 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTSET, H5I_INVALID_HID, "can't set garbage collect reference"); |
406 | 0 | if (H5P_set(new_plist, H5F_ACS_META_BLOCK_SIZE_NAME, &(f->shared->meta_aggr.alloc_size)) < 0) |
407 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTSET, H5I_INVALID_HID, "can't set metadata cache size"); |
408 | 0 | if (H5P_set(new_plist, H5F_ACS_SIEVE_BUF_SIZE_NAME, &(f->shared->sieve_buf_size)) < 0) |
409 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTSET, H5I_INVALID_HID, "can't sieve buffer size"); |
410 | 0 | if (H5P_set(new_plist, H5F_ACS_SDATA_BLOCK_SIZE_NAME, &(f->shared->sdata_aggr.alloc_size)) < 0) |
411 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTSET, H5I_INVALID_HID, "can't set 'small data' cache size"); |
412 | 0 | if (H5P_set(new_plist, H5F_ACS_LIBVER_LOW_BOUND_NAME, &f->shared->low_bound) < 0) |
413 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTSET, H5I_INVALID_HID, |
414 | 0 | "can't set 'low' bound for library format versions"); |
415 | 0 | if (H5P_set(new_plist, H5F_ACS_LIBVER_HIGH_BOUND_NAME, &f->shared->high_bound) < 0) |
416 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTSET, H5I_INVALID_HID, |
417 | 0 | "can't set 'high' bound for library format versions"); |
418 | 0 | if (H5P_set(new_plist, H5F_ACS_USE_FILE_LOCKING_NAME, &f->shared->use_file_locking) < 0) |
419 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTSET, H5I_INVALID_HID, "can't set file locking property"); |
420 | 0 | if (H5P_set(new_plist, H5F_ACS_IGNORE_DISABLED_FILE_LOCKS_NAME, &f->shared->ignore_disabled_locks) < 0) |
421 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTSET, H5I_INVALID_HID, |
422 | 0 | "can't set 'ignore disabled file locks' property"); |
423 | 0 | if (H5P_set(new_plist, H5F_ACS_METADATA_READ_ATTEMPTS_NAME, &(f->shared->read_attempts)) < 0) |
424 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTSET, H5I_INVALID_HID, "can't set 'read attempts' flag"); |
425 | 0 | if (H5P_set(new_plist, H5F_ACS_OBJECT_FLUSH_CB_NAME, &(f->shared->object_flush)) < 0) |
426 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTSET, H5I_INVALID_HID, "can't set object flush callback"); |
427 | | |
428 | 0 | if (f->shared->efc) |
429 | 0 | efc_size = H5F__efc_max_nfiles(f->shared->efc); |
430 | 0 | if (H5P_set(new_plist, H5F_ACS_EFC_SIZE_NAME, &efc_size) < 0) |
431 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTSET, H5I_INVALID_HID, "can't set elink file cache size"); |
432 | 0 | if (f->shared->page_buf != NULL) { |
433 | 0 | if (H5P_set(new_plist, H5F_ACS_PAGE_BUFFER_SIZE_NAME, &(f->shared->page_buf->max_size)) < 0) |
434 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTSET, H5I_INVALID_HID, "can't set page buffer size"); |
435 | 0 | if (H5P_set(new_plist, H5F_ACS_PAGE_BUFFER_MIN_META_PERC_NAME, |
436 | 0 | &(f->shared->page_buf->min_meta_perc)) < 0) |
437 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTSET, H5I_INVALID_HID, |
438 | 0 | "can't set minimum metadata fraction of page buffer"); |
439 | 0 | if (H5P_set(new_plist, H5F_ACS_PAGE_BUFFER_MIN_RAW_PERC_NAME, &(f->shared->page_buf->min_raw_perc)) < |
440 | 0 | 0) |
441 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTSET, H5I_INVALID_HID, |
442 | 0 | "can't set minimum raw data fraction of page buffer"); |
443 | 0 | } /* end if */ |
444 | | #ifdef H5_HAVE_PARALLEL |
445 | | if (H5P_set(new_plist, H5_COLL_MD_READ_FLAG_NAME, &(f->shared->coll_md_read)) < 0) |
446 | | HGOTO_ERROR(H5E_FILE, H5E_CANTSET, H5I_INVALID_HID, "can't set collective metadata read flag"); |
447 | | if (H5P_set(new_plist, H5F_ACS_COLL_MD_WRITE_FLAG_NAME, &(f->shared->coll_md_write)) < 0) |
448 | | HGOTO_ERROR(H5E_FILE, H5E_CANTSET, H5I_INVALID_HID, "can't set collective metadata read flag"); |
449 | | if (H5F_HAS_FEATURE(f, H5FD_FEAT_HAS_MPI)) { |
450 | | MPI_Comm mpi_comm; |
451 | | MPI_Info mpi_info; |
452 | | |
453 | | /* Retrieve and set MPI communicator */ |
454 | | if (MPI_COMM_NULL == (mpi_comm = H5F_mpi_get_comm(f))) |
455 | | HGOTO_ERROR(H5E_FILE, H5E_CANTGET, H5I_INVALID_HID, "can't get MPI communicator"); |
456 | | if (H5P_set(new_plist, H5F_ACS_MPI_PARAMS_COMM_NAME, &mpi_comm) < 0) |
457 | | HGOTO_ERROR(H5E_FILE, H5E_CANTSET, H5I_INVALID_HID, "can't set MPI communicator"); |
458 | | |
459 | | /* Retrieve and set MPI info */ |
460 | | if (MPI_INFO_NULL == (mpi_info = H5F_mpi_get_info(f))) |
461 | | HGOTO_ERROR(H5E_FILE, H5E_CANTGET, H5I_INVALID_HID, "can't get MPI info"); |
462 | | if (H5P_set(new_plist, H5F_ACS_MPI_PARAMS_INFO_NAME, &mpi_info) < 0) |
463 | | HGOTO_ERROR(H5E_FILE, H5E_CANTSET, H5I_INVALID_HID, "can't set MPI info"); |
464 | | } |
465 | | #endif /* H5_HAVE_PARALLEL */ |
466 | 0 | if (H5P_set(new_plist, H5F_ACS_META_CACHE_INIT_IMAGE_CONFIG_NAME, &(f->shared->mdc_initCacheImageCfg)) < |
467 | 0 | 0) |
468 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTSET, H5I_INVALID_HID, |
469 | 0 | "can't set initial metadata cache resize config."); |
470 | 0 | if (H5P_set(new_plist, H5F_ACS_RFIC_FLAGS_NAME, &(f->shared->rfic_flags)) < 0) |
471 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTSET, H5I_INVALID_HID, "can't set RFIC flags value"); |
472 | | |
473 | | /* Prepare the driver property */ |
474 | 0 | driver_prop.driver_id = f->shared->lf->driver_id; |
475 | 0 | driver_prop.driver_info = H5FD_fapl_get(f->shared->lf); |
476 | 0 | driver_prop.driver_config_str = H5P_peek_driver_config_str(old_plist); |
477 | 0 | driver_prop_copied = true; |
478 | | |
479 | | /* Set the driver property */ |
480 | 0 | if (H5P_set(new_plist, H5F_ACS_FILE_DRV_NAME, &driver_prop) < 0) |
481 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTSET, H5I_INVALID_HID, "can't set file driver ID & info"); |
482 | | |
483 | | /* Set the VOL connector property */ |
484 | 0 | connector_prop.connector = f->shared->vol_conn; |
485 | 0 | connector_prop.connector_info = f->shared->vol_info; |
486 | 0 | if (H5P_set(new_plist, H5F_ACS_VOL_CONN_NAME, &connector_prop) < 0) |
487 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTSET, H5I_INVALID_HID, "can't set VOL connector ID & info"); |
488 | | |
489 | | /* Set the file close degree appropriately */ |
490 | 0 | if (f->shared->fc_degree == H5F_CLOSE_DEFAULT && |
491 | 0 | H5P_set(new_plist, H5F_ACS_CLOSE_DEGREE_NAME, &(f->shared->lf->cls->fc_degree)) < 0) |
492 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTSET, H5I_INVALID_HID, "can't set file close degree"); |
493 | 0 | else if (f->shared->fc_degree != H5F_CLOSE_DEFAULT && |
494 | 0 | H5P_set(new_plist, H5F_ACS_CLOSE_DEGREE_NAME, &(f->shared->fc_degree)) < 0) |
495 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTSET, H5I_INVALID_HID, "can't set file close degree"); |
496 | | |
497 | 0 | done: |
498 | | /* Release the copy of the driver info, if it was set up */ |
499 | 0 | if (driver_prop_copied && H5FD_free_driver_info(driver_prop.driver_id, driver_prop.driver_info) < 0) |
500 | 0 | HDONE_ERROR(H5E_FILE, H5E_CANTCLOSEOBJ, H5I_INVALID_HID, "can't close copy of driver info"); |
501 | |
|
502 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
503 | 0 | } /* end H5F_get_access_plist() */ |
504 | | |
505 | | /*------------------------------------------------------------------------- |
506 | | * Function: H5F_get_obj_count |
507 | | * |
508 | | * Purpose: Private function return the number of opened object IDs |
509 | | * (files, datasets, groups, datatypes) in the same file. |
510 | | * |
511 | | * Return: SUCCEED on success, FAIL on failure. |
512 | | *------------------------------------------------------------------------- |
513 | | */ |
514 | | herr_t |
515 | | H5F_get_obj_count(const H5F_t *f, unsigned types, bool app_ref, size_t *obj_id_count_ptr) |
516 | 0 | { |
517 | 0 | herr_t ret_value = SUCCEED; |
518 | |
|
519 | 0 | FUNC_ENTER_NOAPI(FAIL) |
520 | | |
521 | | /* Sanity check */ |
522 | 0 | assert(obj_id_count_ptr); |
523 | | |
524 | | /* Perform the query */ |
525 | 0 | if ((ret_value = H5F__get_objects(f, types, 0, NULL, app_ref, obj_id_count_ptr)) < 0) |
526 | 0 | HGOTO_ERROR(H5E_FILE, H5E_BADITER, FAIL, "H5F__get_objects failed"); |
527 | | |
528 | 0 | done: |
529 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
530 | 0 | } /* end H5F_get_obj_count() */ |
531 | | |
532 | | /*------------------------------------------------------------------------- |
533 | | * Function: H5F_get_obj_ids |
534 | | * |
535 | | * Purpose: Private function to return a list of opened object IDs. |
536 | | * |
537 | | * Return: Non-negative on success; can't fail. |
538 | | *------------------------------------------------------------------------- |
539 | | */ |
540 | | herr_t |
541 | | H5F_get_obj_ids(const H5F_t *f, unsigned types, size_t max_objs, hid_t *oid_list, bool app_ref, |
542 | | size_t *obj_id_count_ptr) |
543 | 0 | { |
544 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
545 | |
|
546 | 0 | FUNC_ENTER_NOAPI(FAIL) |
547 | | |
548 | | /* Sanity check */ |
549 | 0 | assert(obj_id_count_ptr); |
550 | | |
551 | | /* Perform the query */ |
552 | 0 | if ((ret_value = H5F__get_objects(f, types, max_objs, oid_list, app_ref, obj_id_count_ptr)) < 0) |
553 | 0 | HGOTO_ERROR(H5E_FILE, H5E_BADITER, FAIL, "H5F__get_objects failed"); |
554 | | |
555 | 0 | done: |
556 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
557 | 0 | } /* end H5F_get_obj_ids() */ |
558 | | |
559 | | /*--------------------------------------------------------------------------- |
560 | | * Function: H5F__get_objects |
561 | | * |
562 | | * Purpose: This function is called by H5F_get_obj_count or |
563 | | * H5F_get_obj_ids to get number of object IDs and/or a |
564 | | * list of opened object IDs (in return value). |
565 | | * |
566 | | * Return: SUCCEED/FAIL |
567 | | *--------------------------------------------------------------------------- |
568 | | */ |
569 | | static herr_t |
570 | | H5F__get_objects(const H5F_t *f, unsigned types, size_t max_nobjs, hid_t *obj_id_list, bool app_ref, |
571 | | size_t *obj_id_count_ptr) |
572 | 0 | { |
573 | 0 | size_t obj_id_count = 0; /* Number of open IDs */ |
574 | 0 | H5F_olist_t olist; /* Structure to hold search results */ |
575 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
576 | |
|
577 | 0 | FUNC_ENTER_PACKAGE |
578 | | |
579 | | /* Sanity check */ |
580 | 0 | assert(obj_id_count_ptr); |
581 | | |
582 | | /* Set up search information */ |
583 | 0 | olist.obj_id_list = (max_nobjs == 0 ? NULL : obj_id_list); |
584 | 0 | olist.obj_id_count = &obj_id_count; |
585 | 0 | olist.list_index = 0; |
586 | 0 | olist.max_nobjs = max_nobjs; |
587 | | |
588 | | /* Determine if we are searching for local or global objects */ |
589 | 0 | if (types & H5F_OBJ_LOCAL) { |
590 | 0 | olist.file_info.local = true; |
591 | 0 | olist.file_info.ptr.file = f; |
592 | 0 | } /* end if */ |
593 | 0 | else { |
594 | 0 | olist.file_info.local = false; |
595 | 0 | olist.file_info.ptr.shared = f ? f->shared : NULL; |
596 | 0 | } /* end else */ |
597 | | |
598 | | /* Iterate through file IDs to count the number, and put their |
599 | | * IDs on the object list. */ |
600 | 0 | if (types & H5F_OBJ_FILE) { |
601 | 0 | olist.obj_type = H5I_FILE; |
602 | 0 | if (H5I_iterate(H5I_FILE, H5F__get_objects_cb, &olist, app_ref) < 0) |
603 | 0 | HGOTO_ERROR(H5E_FILE, H5E_BADITER, FAIL, "iteration failed(1)"); |
604 | 0 | } /* end if */ |
605 | | |
606 | | /* If the caller just wants to count the number of objects (OLIST.MAX_NOBJS is zero), |
607 | | * or the caller wants to get the list of IDs and the list isn't full, |
608 | | * search through dataset IDs to count number of datasets, and put their |
609 | | * IDs on the object list */ |
610 | 0 | if (!olist.max_nobjs || (olist.max_nobjs && olist.list_index < olist.max_nobjs)) { |
611 | 0 | if (types & H5F_OBJ_DATASET) { |
612 | 0 | olist.obj_type = H5I_DATASET; |
613 | 0 | if (H5I_iterate(H5I_DATASET, H5F__get_objects_cb, &olist, app_ref) < 0) |
614 | 0 | HGOTO_ERROR(H5E_FILE, H5E_BADITER, FAIL, "iteration failed(2)"); |
615 | 0 | } /* end if */ |
616 | 0 | } |
617 | | |
618 | | /* If the caller just wants to count the number of objects (OLIST.MAX_NOBJS is zero), |
619 | | * or the caller wants to get the list of IDs and the list isn't full, |
620 | | * search through group IDs to count number of groups, and put their |
621 | | * IDs on the object list */ |
622 | 0 | if (!olist.max_nobjs || (olist.max_nobjs && olist.list_index < olist.max_nobjs)) { |
623 | 0 | if (types & H5F_OBJ_GROUP) { |
624 | 0 | olist.obj_type = H5I_GROUP; |
625 | 0 | if (H5I_iterate(H5I_GROUP, H5F__get_objects_cb, &olist, app_ref) < 0) |
626 | 0 | HGOTO_ERROR(H5E_FILE, H5E_BADITER, FAIL, "iteration failed(3)"); |
627 | 0 | } |
628 | 0 | } |
629 | | |
630 | | /* If the caller just wants to count the number of objects (OLIST.MAX_NOBJS is zero), |
631 | | * or the caller wants to get the list of IDs and the list isn't full, |
632 | | * search through datatype IDs to count number of named datatypes, and put their |
633 | | * IDs on the object list */ |
634 | 0 | if (!olist.max_nobjs || (olist.max_nobjs && olist.list_index < olist.max_nobjs)) { |
635 | 0 | if (types & H5F_OBJ_DATATYPE) { |
636 | 0 | olist.obj_type = H5I_DATATYPE; |
637 | 0 | if (H5I_iterate(H5I_DATATYPE, H5F__get_objects_cb, &olist, app_ref) < 0) |
638 | 0 | HGOTO_ERROR(H5E_FILE, H5E_BADITER, FAIL, "iteration failed(4)"); |
639 | 0 | } /* end if */ |
640 | 0 | } |
641 | | |
642 | | /* If the caller just wants to count the number of objects (OLIST.MAX_NOBJS is zero), |
643 | | * or the caller wants to get the list of IDs and the list isn't full, |
644 | | * search through attribute IDs to count number of attributes, and put their |
645 | | * IDs on the object list */ |
646 | 0 | if (!olist.max_nobjs || (olist.max_nobjs && olist.list_index < olist.max_nobjs)) { |
647 | 0 | if (types & H5F_OBJ_ATTR) { |
648 | 0 | olist.obj_type = H5I_ATTR; |
649 | 0 | if (H5I_iterate(H5I_ATTR, H5F__get_objects_cb, &olist, app_ref) < 0) |
650 | 0 | HGOTO_ERROR(H5E_FILE, H5E_BADITER, FAIL, "iteration failed(5)"); |
651 | 0 | } /* end if */ |
652 | 0 | } |
653 | | |
654 | | /* Set the number of objects currently open */ |
655 | 0 | *obj_id_count_ptr = obj_id_count; |
656 | |
|
657 | 0 | done: |
658 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
659 | 0 | } /* end H5F__get_objects() */ |
660 | | |
661 | | /*------------------------------------------------------------------------- |
662 | | * Function: H5F__get_objects_cb |
663 | | * |
664 | | * Purpose: H5F__get_objects' callback function. It verifies if an |
665 | | * object is in the file, and either count it or put its ID |
666 | | * on the list. |
667 | | * |
668 | | * Return: H5_ITER_STOP if the array of object IDs is filled up. |
669 | | * H5_ITER_CONT otherwise. |
670 | | *------------------------------------------------------------------------- |
671 | | */ |
672 | | static int |
673 | | H5F__get_objects_cb(void *obj_ptr, hid_t obj_id, void *key) |
674 | 0 | { |
675 | 0 | H5F_olist_t *olist = (H5F_olist_t *)key; /* Alias for search info */ |
676 | 0 | bool add_obj = false; |
677 | 0 | int ret_value = H5_ITER_CONT; /* Return value */ |
678 | |
|
679 | 0 | FUNC_ENTER_PACKAGE |
680 | |
|
681 | 0 | assert(obj_ptr); |
682 | 0 | assert(olist); |
683 | | |
684 | | /* Count file IDs */ |
685 | 0 | if (olist->obj_type == H5I_FILE) { |
686 | 0 | if ((olist->file_info.local && |
687 | 0 | (!olist->file_info.ptr.file || |
688 | 0 | (olist->file_info.ptr.file && (H5F_t *)obj_ptr == olist->file_info.ptr.file))) || |
689 | 0 | (!olist->file_info.local && |
690 | 0 | (!olist->file_info.ptr.shared || |
691 | 0 | (olist->file_info.ptr.shared && ((H5F_t *)obj_ptr)->shared == olist->file_info.ptr.shared)))) { |
692 | 0 | add_obj = true; |
693 | 0 | } /* end if */ |
694 | 0 | } /* end if */ |
695 | 0 | else { /* Either count opened object IDs or put the IDs on the list */ |
696 | 0 | H5O_loc_t *oloc; /* Group entry info for object */ |
697 | |
|
698 | 0 | switch (olist->obj_type) { |
699 | 0 | case H5I_ATTR: |
700 | 0 | oloc = H5A_oloc((H5A_t *)obj_ptr); |
701 | 0 | break; |
702 | | |
703 | 0 | case H5I_GROUP: |
704 | 0 | oloc = H5G_oloc((H5G_t *)obj_ptr); |
705 | 0 | break; |
706 | | |
707 | 0 | case H5I_DATASET: |
708 | 0 | oloc = H5D_oloc((H5D_t *)obj_ptr); |
709 | 0 | break; |
710 | | |
711 | 0 | case H5I_DATATYPE: |
712 | 0 | if (H5T_is_named((H5T_t *)obj_ptr) == true) |
713 | 0 | oloc = H5T_oloc((H5T_t *)obj_ptr); |
714 | 0 | else |
715 | 0 | oloc = NULL; |
716 | 0 | break; |
717 | | |
718 | 0 | case H5I_MAP: |
719 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5_ITER_ERROR, |
720 | 0 | "maps not supported in native VOL connector"); |
721 | | |
722 | 0 | case H5I_UNINIT: |
723 | 0 | case H5I_BADID: |
724 | 0 | case H5I_FILE: |
725 | 0 | case H5I_DATASPACE: |
726 | 0 | case H5I_VFL: |
727 | 0 | case H5I_VOL: |
728 | 0 | case H5I_GENPROP_CLS: |
729 | 0 | case H5I_GENPROP_LST: |
730 | 0 | case H5I_ERROR_CLASS: |
731 | 0 | case H5I_ERROR_MSG: |
732 | 0 | case H5I_ERROR_STACK: |
733 | 0 | case H5I_SPACE_SEL_ITER: |
734 | 0 | case H5I_EVENTSET: |
735 | 0 | case H5I_NTYPES: |
736 | 0 | default: |
737 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5_ITER_ERROR, "unknown or invalid data object"); |
738 | 0 | } /* end switch */ |
739 | | |
740 | 0 | if ((olist->file_info.local && ((!olist->file_info.ptr.file && olist->obj_type == H5I_DATATYPE && |
741 | 0 | H5T_is_immutable((H5T_t *)obj_ptr) == false) || |
742 | 0 | (!olist->file_info.ptr.file && olist->obj_type != H5I_DATATYPE) || |
743 | 0 | (oloc && oloc->file == olist->file_info.ptr.file))) || |
744 | 0 | (!olist->file_info.local && |
745 | 0 | ((!olist->file_info.ptr.shared && olist->obj_type == H5I_DATATYPE && |
746 | 0 | H5T_is_immutable((H5T_t *)obj_ptr) == false) || |
747 | 0 | (!olist->file_info.ptr.shared && olist->obj_type != H5I_DATATYPE) || |
748 | 0 | (oloc && oloc->file && oloc->file->shared == olist->file_info.ptr.shared)))) { |
749 | 0 | add_obj = true; |
750 | 0 | } /* end if */ |
751 | 0 | } /* end else */ |
752 | | |
753 | 0 | if (add_obj) { |
754 | | /* Add the object's ID to the ID list, if appropriate */ |
755 | 0 | if (olist->obj_id_list) { |
756 | 0 | olist->obj_id_list[olist->list_index] = obj_id; |
757 | 0 | olist->list_index++; |
758 | 0 | } /* end if */ |
759 | | |
760 | | /* Increment the number of open objects */ |
761 | 0 | if (olist->obj_id_count) |
762 | 0 | (*olist->obj_id_count)++; |
763 | | |
764 | | /* Check if we've filled up the array. Return H5_ITER_STOP only if |
765 | | * we have filled up the array. Otherwise return H5_ITER_CONT(RET_VALUE is |
766 | | * preset to H5_ITER_CONT) because H5I_iterate needs the return value of |
767 | | * H5_ITER_CONT to continue the iteration. |
768 | | */ |
769 | 0 | if (olist->max_nobjs > 0 && olist->list_index >= olist->max_nobjs) |
770 | 0 | HGOTO_DONE(H5_ITER_STOP); /* Indicate that the iterator should stop */ |
771 | 0 | } /* end if */ |
772 | | |
773 | 0 | done: |
774 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
775 | 0 | } /* end H5F__get_objects_cb() */ |
776 | | |
777 | | /*-------------------------------------------------------------------------- |
778 | | * Function: H5F__build_name |
779 | | * |
780 | | * Purpose: Prepend PREFIX to FILE_NAME and store in FULL_NAME |
781 | | * |
782 | | * Return: SUCCEED/FAIL |
783 | | *--------------------------------------------------------------------------*/ |
784 | | static herr_t |
785 | | H5F__build_name(const char *prefix, const char *file_name, char **full_name /*out*/) |
786 | 0 | { |
787 | 0 | size_t prefix_len; /* length of prefix */ |
788 | 0 | size_t fname_len; /* Length of external link file name */ |
789 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
790 | |
|
791 | 0 | FUNC_ENTER_PACKAGE |
792 | |
|
793 | 0 | prefix_len = strlen(prefix); |
794 | 0 | fname_len = strlen(file_name); |
795 | | |
796 | | /* Allocate a buffer to hold the filename + prefix + possibly the delimiter + terminating null byte */ |
797 | 0 | if (NULL == (*full_name = (char *)H5MM_malloc(prefix_len + fname_len + 2 + |
798 | 0 | 2))) /* Extra "+2" to quiet GCC warning - 2019/07/05, QAK */ |
799 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTALLOC, FAIL, "unable to allocate filename buffer"); |
800 | | |
801 | | /* Compose the full file name */ |
802 | 0 | snprintf(*full_name, (prefix_len + fname_len + 2 + 2), "%s%s%s", |
803 | 0 | prefix, /* Extra "+2" to quiet GCC warning - 2019/07/05, QAK */ |
804 | 0 | ((prefix_len == 0 || H5_CHECK_DELIMITER(prefix[prefix_len - 1])) ? "" : H5_DIR_SEPS), file_name); |
805 | |
|
806 | 0 | done: |
807 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
808 | 0 | } /* H5F__build_name() */ |
809 | | |
810 | | /*-------------------------------------------------------------------------- |
811 | | * Function: H5F__getenv_prefix_name |
812 | | * |
813 | | * Purpose: Get the first pathname in the list of pathnames stored in env_prefix, |
814 | | * which is separated by the environment delimiter. |
815 | | * env_prefix is modified to point to the remaining pathnames |
816 | | * in the list. |
817 | | * |
818 | | * Return: A pointer to a pathname (can't fail but can return NULL) |
819 | | --------------------------------------------------------------------------*/ |
820 | | static char * |
821 | | H5F__getenv_prefix_name(char **env_prefix /*in,out*/) |
822 | 0 | { |
823 | 0 | char *strret; /* Pointer to next separator */ |
824 | 0 | char *ret_value = NULL; /* Return value */ |
825 | |
|
826 | 0 | FUNC_ENTER_PACKAGE_NOERR |
827 | | |
828 | | /* Set return value now */ |
829 | 0 | ret_value = *env_prefix; |
830 | | |
831 | | /* Advance to next component, if possible */ |
832 | 0 | strret = strchr(*env_prefix, H5_COLON_SEPC); |
833 | 0 | if (strret == NULL) |
834 | 0 | *env_prefix = NULL; |
835 | 0 | else { |
836 | | /* Advance to next component */ |
837 | 0 | *env_prefix = strret + 1; |
838 | | |
839 | | /* Terminate current component (pointed to by ret_value) */ |
840 | 0 | *strret = '\0'; |
841 | 0 | } /* end else */ |
842 | |
|
843 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
844 | 0 | } /* end H5F__getenv_prefix_name() */ |
845 | | |
846 | | /*------------------------------------------------------------------------- |
847 | | * Function: H5F_prefix_open_file |
848 | | * |
849 | | * Purpose: Attempts to open a dataset file. |
850 | | * |
851 | | * Return: SUCCEED/FAIL |
852 | | *------------------------------------------------------------------------- |
853 | | */ |
854 | | herr_t |
855 | | H5F_prefix_open_file(bool try, H5F_t **_file, H5F_t *primary_file, H5F_prefix_open_t prefix_type, |
856 | | const char *prop_prefix, const char *file_name, unsigned file_intent, hid_t fapl_id) |
857 | 0 | { |
858 | 0 | H5F_t *src_file = NULL; /* Source file */ |
859 | 0 | H5F_efc_t *efc = NULL; /* External file cache */ |
860 | 0 | char *full_name = NULL; /* File name with prefix */ |
861 | 0 | char *actual_file_name = NULL; /* File's actual name */ |
862 | 0 | char *temp_file_name = NULL; /* Temporary pointer to file name */ |
863 | 0 | size_t temp_file_name_len; /* Length of temporary file name */ |
864 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
865 | |
|
866 | 0 | FUNC_ENTER_NOAPI(FAIL) |
867 | |
|
868 | 0 | assert(_file); |
869 | | |
870 | | /* Reset 'out' parameter */ |
871 | 0 | *_file = NULL; |
872 | |
|
873 | 0 | efc = primary_file->shared->efc; |
874 | | |
875 | | /* Simplify intent flags for open calls */ |
876 | 0 | file_intent &= (H5F_ACC_RDWR | H5F_ACC_SWMR_WRITE | H5F_ACC_SWMR_READ); |
877 | | |
878 | | /* Copy the file name to use */ |
879 | 0 | if (NULL == (temp_file_name = H5MM_strdup(file_name))) |
880 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTALLOC, FAIL, "memory allocation failed"); |
881 | 0 | temp_file_name_len = strlen(temp_file_name); |
882 | | |
883 | | /* Target file_name is an absolute pathname: see RM for detailed description */ |
884 | 0 | if (H5_CHECK_ABSOLUTE(file_name) || H5_CHECK_ABS_PATH(file_name)) { |
885 | | /* Try opening file */ |
886 | 0 | if (H5F__efc_open(true, efc, &src_file, file_name, file_intent, H5P_FILE_CREATE_DEFAULT, fapl_id) < 0) |
887 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, FAIL, "can't try opening file"); |
888 | | |
889 | | /* Adjust temporary file name if file not opened */ |
890 | 0 | if (NULL == src_file) { |
891 | 0 | char *ptr; |
892 | | |
893 | | /* Get last component of file_name */ |
894 | 0 | H5_GET_LAST_DELIMITER(file_name, ptr) |
895 | 0 | assert(ptr); |
896 | | |
897 | | /* Increment past delimiter */ |
898 | 0 | ptr++; |
899 | | |
900 | | /* Copy into the temp. file name */ |
901 | 0 | strncpy(temp_file_name, ptr, temp_file_name_len); |
902 | 0 | temp_file_name[temp_file_name_len - 1] = '\0'; |
903 | 0 | } /* end if */ |
904 | 0 | } /* end if */ |
905 | 0 | else if (H5_CHECK_ABS_DRIVE(file_name)) { |
906 | | /* Try opening file */ |
907 | 0 | if (H5F__efc_open(true, efc, &src_file, file_name, file_intent, H5P_FILE_CREATE_DEFAULT, fapl_id) < 0) |
908 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, FAIL, "can't try opening file"); |
909 | | |
910 | | /* Adjust temporary file name if file not opened */ |
911 | 0 | if (NULL == src_file) { |
912 | | /* Strip "<drive-letter>:" */ |
913 | 0 | strncpy(temp_file_name, &file_name[2], temp_file_name_len); |
914 | 0 | temp_file_name[temp_file_name_len - 1] = '\0'; |
915 | 0 | } /* end if */ |
916 | 0 | } /* end if */ |
917 | | |
918 | | /* Try searching from paths set in the environment variable */ |
919 | 0 | if (src_file == NULL) { |
920 | 0 | char *env_prefix; |
921 | | |
922 | | /* Get the appropriate environment variable */ |
923 | 0 | if (H5F_PREFIX_VDS == prefix_type) |
924 | 0 | env_prefix = getenv("HDF5_VDS_PREFIX"); |
925 | 0 | else if (H5F_PREFIX_ELINK == prefix_type) |
926 | 0 | env_prefix = getenv("HDF5_EXT_PREFIX"); |
927 | 0 | else |
928 | 0 | HGOTO_ERROR(H5E_FILE, H5E_BADTYPE, FAIL, "prefix type is not sensible"); |
929 | | |
930 | | /* If environment variable is defined, iterate through prefixes it defines */ |
931 | 0 | if (NULL != env_prefix) { |
932 | 0 | char *tmp_env_prefix, *saved_env; |
933 | | |
934 | | /* Make a copy of the environment variable string */ |
935 | 0 | if (NULL == (saved_env = tmp_env_prefix = H5MM_strdup(env_prefix))) |
936 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTALLOC, FAIL, "memory allocation failed"); |
937 | | |
938 | | /* Loop over prefixes in environment variable */ |
939 | 0 | while ((tmp_env_prefix) && (*tmp_env_prefix)) { |
940 | 0 | char *out_prefix_name; |
941 | |
|
942 | 0 | out_prefix_name = H5F__getenv_prefix_name(&tmp_env_prefix /*in,out*/); |
943 | 0 | if (out_prefix_name && (*out_prefix_name)) { |
944 | 0 | if (H5F__build_name(out_prefix_name, temp_file_name, &full_name /*out*/) < 0) { |
945 | 0 | saved_env = (char *)H5MM_xfree(saved_env); |
946 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "can't prepend prefix to filename"); |
947 | 0 | } /* end if */ |
948 | | |
949 | | /* Try opening file */ |
950 | 0 | if (H5F__efc_open(true, efc, &src_file, full_name, file_intent, H5P_FILE_CREATE_DEFAULT, |
951 | 0 | fapl_id) < 0) |
952 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, FAIL, "can't try opening file"); |
953 | | |
954 | | /* Release copy of file name */ |
955 | 0 | full_name = (char *)H5MM_xfree(full_name); |
956 | | |
957 | | /* Leave if file was opened */ |
958 | 0 | if (src_file) |
959 | 0 | break; |
960 | 0 | } /* end if */ |
961 | 0 | } /* end while */ |
962 | | |
963 | 0 | saved_env = (char *)H5MM_xfree(saved_env); |
964 | 0 | } /* end if */ |
965 | 0 | } /* end if */ |
966 | | |
967 | | /* Try searching from property list */ |
968 | 0 | if (src_file == NULL && prop_prefix) { |
969 | | /* Construct name to open */ |
970 | 0 | if (H5F__build_name(prop_prefix, temp_file_name, &full_name /*out*/) < 0) |
971 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "can't prepend prefix to filename"); |
972 | | |
973 | | /* Try opening file */ |
974 | 0 | if (H5F__efc_open(true, efc, &src_file, full_name, file_intent, H5P_FILE_CREATE_DEFAULT, fapl_id) < 0) |
975 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, FAIL, "can't try opening file"); |
976 | | |
977 | | /* Release name */ |
978 | 0 | full_name = (char *)H5MM_xfree(full_name); |
979 | 0 | } /* end if */ |
980 | | |
981 | | /* Try searching from main file's "extpath": see description in H5F_open() & H5_build_extpath() */ |
982 | 0 | if (src_file == NULL) { |
983 | 0 | char *dspath; |
984 | |
|
985 | 0 | if (NULL != (dspath = H5F_EXTPATH(primary_file))) { |
986 | | /* Construct name to open */ |
987 | 0 | if (H5F__build_name(dspath, temp_file_name, &full_name /*out*/) < 0) |
988 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "can't prepend prefix to filename"); |
989 | | |
990 | | /* Try opening file */ |
991 | 0 | if (H5F__efc_open(true, efc, &src_file, full_name, file_intent, H5P_FILE_CREATE_DEFAULT, |
992 | 0 | fapl_id) < 0) |
993 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, FAIL, "can't try opening file"); |
994 | | |
995 | | /* Release name */ |
996 | 0 | full_name = (char *)H5MM_xfree(full_name); |
997 | 0 | } /* end if */ |
998 | 0 | } /* end if */ |
999 | | |
1000 | | /* Try the relative file_name stored in temp_file_name */ |
1001 | 0 | if (src_file == NULL) { |
1002 | | /* Try opening file */ |
1003 | 0 | if (H5F__efc_open(true, efc, &src_file, temp_file_name, file_intent, H5P_FILE_CREATE_DEFAULT, |
1004 | 0 | fapl_id) < 0) |
1005 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, FAIL, "can't try opening file"); |
1006 | 0 | } /* end if */ |
1007 | | |
1008 | | /* try the 'resolved' name for the virtual file */ |
1009 | 0 | if (src_file == NULL) { |
1010 | 0 | char *ptr = NULL; |
1011 | | |
1012 | | /* Copy resolved file name */ |
1013 | 0 | if (NULL == (actual_file_name = H5MM_strdup(H5F_ACTUAL_NAME(primary_file)))) |
1014 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTALLOC, FAIL, "can't duplicate resolved file name string"); |
1015 | | |
1016 | | /* get last component of file_name */ |
1017 | 0 | H5_GET_LAST_DELIMITER(actual_file_name, ptr) |
1018 | 0 | if (ptr) |
1019 | | /* Truncate filename portion from actual file name path */ |
1020 | 0 | *ptr = '\0'; |
1021 | | |
1022 | | /* Build new file name for the external file */ |
1023 | 0 | if (H5F__build_name((ptr ? actual_file_name : ""), temp_file_name, &full_name /*out*/) < 0) |
1024 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "can't prepend prefix to filename"); |
1025 | 0 | actual_file_name = (char *)H5MM_xfree(actual_file_name); |
1026 | | |
1027 | | /* Try opening with the resolved name */ |
1028 | 0 | if (H5F__efc_open(true, efc, &src_file, full_name, file_intent, H5P_FILE_CREATE_DEFAULT, fapl_id) < 0) |
1029 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, FAIL, "can't try opening file"); |
1030 | | |
1031 | | /* Release name */ |
1032 | 0 | full_name = (char *)H5MM_xfree(full_name); |
1033 | 0 | } /* end if */ |
1034 | | |
1035 | | /* Set 'out' parameter */ |
1036 | 0 | *_file = src_file; |
1037 | | |
1038 | | /* See is we should return an error */ |
1039 | 0 | if (NULL == src_file && !try) |
1040 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, FAIL, "can't open file"); |
1041 | | |
1042 | 0 | done: |
1043 | 0 | if (ret_value < 0) |
1044 | 0 | if (src_file && H5F_efc_close(primary_file, src_file) < 0) |
1045 | 0 | HDONE_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "can't close source file"); |
1046 | 0 | if (full_name) |
1047 | 0 | full_name = (char *)H5MM_xfree(full_name); |
1048 | 0 | if (temp_file_name) |
1049 | 0 | temp_file_name = (char *)H5MM_xfree(temp_file_name); |
1050 | 0 | if (actual_file_name) |
1051 | 0 | actual_file_name = (char *)H5MM_xfree(actual_file_name); |
1052 | |
|
1053 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1054 | 0 | } /* H5F_prefix_open_file() */ |
1055 | | |
1056 | | /*------------------------------------------------------------------------- |
1057 | | * Function: H5F__is_hdf5 |
1058 | | * |
1059 | | * Purpose: Check the file signature to detect an HDF5 file. |
1060 | | * |
1061 | | * Return: SUCCEED/FAIL |
1062 | | *------------------------------------------------------------------------- |
1063 | | */ |
1064 | | herr_t |
1065 | | H5F__is_hdf5(const char *name, hid_t fapl_id, bool *is_hdf5) |
1066 | 0 | { |
1067 | 0 | H5FD_t *lf = NULL; /* Low-level file struct */ |
1068 | 0 | H5F_shared_t *shared = NULL; /* Shared part of file */ |
1069 | 0 | haddr_t sig_addr = HADDR_UNDEF; /* Address of hdf5 file signature */ |
1070 | 0 | bool found_hdf5 = false; /* Found an HDF5 file */ |
1071 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
1072 | |
|
1073 | 0 | FUNC_ENTER_PACKAGE |
1074 | | |
1075 | | /* Check output parameter */ |
1076 | 0 | if (!is_hdf5) |
1077 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid output param"); |
1078 | | |
1079 | | /* Open the file */ |
1080 | | /* NOTE: This now uses the fapl_id that was passed in, so H5Fis_accessible() |
1081 | | * should work with arbitrary VFDs, unlike H5Fis_hdf5(). |
1082 | | */ |
1083 | 0 | if (H5FD_open(false, &lf, name, H5F_ACC_RDONLY, fapl_id, HADDR_UNDEF) < 0) |
1084 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "unable to open file"); |
1085 | | |
1086 | | /* If the file is already open, it's an HDF5 file |
1087 | | * |
1088 | | * If the file is open with an exclusive lock on an operating system that enforces |
1089 | | * mandatory file locks (like Windows), creating a new file handle and attempting |
1090 | | * to read through it will fail so we have to try this first. |
1091 | | */ |
1092 | 0 | if (NULL != (shared = H5F__sfile_search(lf))) |
1093 | 0 | found_hdf5 = true; |
1094 | 0 | else { |
1095 | | /* The file is an HDF5 file if the HDF5 file signature can be found */ |
1096 | 0 | if (H5FD_locate_signature(lf, &sig_addr) < 0) { |
1097 | 0 | H5FD_close(lf); |
1098 | 0 | HGOTO_ERROR(H5E_FILE, H5E_NOTHDF5, FAIL, "error while trying to locate file signature"); |
1099 | 0 | } |
1100 | 0 | found_hdf5 = H5_addr_defined(sig_addr); |
1101 | 0 | } |
1102 | | |
1103 | | /* Close the file */ |
1104 | 0 | if (H5FD_close(lf) < 0 && found_hdf5) |
1105 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "unable to close file"); |
1106 | | |
1107 | | /* Set output parameter */ |
1108 | 0 | *is_hdf5 = found_hdf5; |
1109 | |
|
1110 | 0 | done: |
1111 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1112 | 0 | } /* end H5F__is_hdf5() */ |
1113 | | |
1114 | | /*------------------------------------------------------------------------- |
1115 | | * Function: H5F__new |
1116 | | * |
1117 | | * Purpose: Creates a new file object and initializes it. The |
1118 | | * H5Fopen and H5Fcreate functions then fill in various fields. |
1119 | | * If SHARED is a non-null pointer then the shared info |
1120 | | * to which it points has the reference count incremented. |
1121 | | * Otherwise a new, empty shared info struct is created and |
1122 | | * initialized with the specified file access property list. |
1123 | | * |
1124 | | * Return: Success: Pointer to a new file struct |
1125 | | * |
1126 | | * Failure: NULL |
1127 | | * |
1128 | | *------------------------------------------------------------------------- |
1129 | | */ |
1130 | | static H5F_t * |
1131 | | H5F__new(H5F_shared_t *shared, unsigned flags, hid_t fcpl_id, hid_t fapl_id, H5FD_t *lf) |
1132 | 15 | { |
1133 | 15 | H5F_t *f = NULL; |
1134 | 15 | H5F_t *ret_value = NULL; |
1135 | | |
1136 | 15 | FUNC_ENTER_PACKAGE |
1137 | | |
1138 | 15 | if (NULL == (f = H5FL_CALLOC(H5F_t))) |
1139 | 0 | HGOTO_ERROR(H5E_FILE, H5E_NOSPACE, NULL, "can't allocate top file structure"); |
1140 | 15 | f->id_exists = false; |
1141 | | |
1142 | 15 | if (shared) { |
1143 | 0 | assert(lf == NULL); |
1144 | 0 | f->shared = shared; |
1145 | 0 | } |
1146 | 15 | else { |
1147 | 15 | H5P_genplist_t *plist; /* Property list */ |
1148 | 15 | unsigned efc_size; /* External file cache size */ |
1149 | 15 | size_t u; /* Local index variable */ |
1150 | | |
1151 | 15 | assert(lf != NULL); |
1152 | 15 | if (NULL == (f->shared = H5FL_CALLOC(H5F_shared_t))) |
1153 | 0 | HGOTO_ERROR(H5E_FILE, H5E_NOSPACE, NULL, "can't allocate shared file structure"); |
1154 | | |
1155 | 15 | f->shared->flags = flags; |
1156 | 15 | f->shared->sohm_addr = HADDR_UNDEF; |
1157 | 15 | f->shared->sohm_vers = HDF5_SHAREDHEADER_VERSION; |
1158 | 15 | f->shared->accum.loc = HADDR_UNDEF; |
1159 | 15 | f->shared->lf = lf; |
1160 | | |
1161 | | /* Initialization for handling file space */ |
1162 | 210 | for (u = 0; u < NELMTS(f->shared->fs_addr); u++) { |
1163 | 195 | f->shared->fs_state[u] = H5F_FS_STATE_CLOSED; |
1164 | 195 | f->shared->fs_addr[u] = HADDR_UNDEF; |
1165 | 195 | f->shared->fs_man[u] = NULL; |
1166 | 195 | } |
1167 | | /* This will be stored as eoa_pre_fsm_fsalloc in the fsinfo message */ |
1168 | | /* This is done to be backward compatible with 1.10 library that has the FSM hack */ |
1169 | 15 | f->shared->eoa_fsm_fsalloc = HADDR_UNDEF; |
1170 | 15 | f->shared->eoa_post_mdci_fsalloc = HADDR_UNDEF; |
1171 | | |
1172 | | /* Initialization for handling file space (for paged aggregation) */ |
1173 | 15 | f->shared->pgend_meta_thres = H5F_FILE_SPACE_PGEND_META_THRES; |
1174 | | |
1175 | | /* initialize point of no return */ |
1176 | 15 | f->shared->point_of_no_return = false; |
1177 | | |
1178 | | /* Copy the file creation and file access property lists into the |
1179 | | * new file handle. We do this early because some values might need |
1180 | | * to change as the file is being opened. |
1181 | | */ |
1182 | 15 | if (NULL == (plist = (H5P_genplist_t *)H5I_object(fcpl_id))) |
1183 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "not property list"); |
1184 | 15 | f->shared->fcpl_id = H5P_copy_plist(plist, false); |
1185 | | |
1186 | | /* Get the FCPL values to cache */ |
1187 | 15 | if (H5P_get(plist, H5F_CRT_ADDR_BYTE_NUM_NAME, &f->shared->sizeof_addr) < 0) |
1188 | 0 | HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get byte number for address"); |
1189 | 15 | if (H5P_get(plist, H5F_CRT_OBJ_BYTE_NUM_NAME, &f->shared->sizeof_size) < 0) |
1190 | 0 | HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get byte number for object size"); |
1191 | 15 | if (H5P_get(plist, H5F_CRT_SHMSG_NINDEXES_NAME, &f->shared->sohm_nindexes) < 0) |
1192 | 0 | HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get number of SOHM indexes"); |
1193 | 15 | assert(f->shared->sohm_nindexes < 255); |
1194 | 15 | if (H5P_get(plist, H5F_CRT_FILE_SPACE_STRATEGY_NAME, &f->shared->fs_strategy) < 0) |
1195 | 0 | HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get file space strategy"); |
1196 | 15 | if (H5P_get(plist, H5F_CRT_FREE_SPACE_PERSIST_NAME, &f->shared->fs_persist) < 0) |
1197 | 0 | HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get file space persisting status"); |
1198 | 15 | if (H5P_get(plist, H5F_CRT_FREE_SPACE_THRESHOLD_NAME, &f->shared->fs_threshold) < 0) |
1199 | 0 | HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get free-space section threshold"); |
1200 | 15 | if (H5P_get(plist, H5F_CRT_FILE_SPACE_PAGE_SIZE_NAME, &f->shared->fs_page_size) < 0) |
1201 | 0 | HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get file space page size"); |
1202 | 15 | assert(f->shared->fs_page_size >= H5F_FILE_SPACE_PAGE_SIZE_MIN); |
1203 | | |
1204 | | /* Temporary for multi/split drivers: fail file creation |
1205 | | * when persisting free-space or using paged aggregation strategy. |
1206 | | */ |
1207 | 15 | if (H5F_HAS_FEATURE(f, H5FD_FEAT_PAGED_AGGR)) |
1208 | 0 | if (f->shared->fs_strategy == H5F_FSPACE_STRATEGY_PAGE || f->shared->fs_persist) |
1209 | 0 | HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't open with this strategy or persistent fs"); |
1210 | | |
1211 | | /* Get the FAPL values to cache */ |
1212 | 15 | if (NULL == (plist = (H5P_genplist_t *)H5I_object(fapl_id))) |
1213 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "not file access property list"); |
1214 | 15 | if (H5P_get(plist, H5F_ACS_META_CACHE_INIT_CONFIG_NAME, &(f->shared->mdc_initCacheCfg)) < 0) |
1215 | 0 | HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get initial metadata cache resize config"); |
1216 | 15 | if (H5P_get(plist, H5F_ACS_DATA_CACHE_NUM_SLOTS_NAME, &(f->shared->rdcc_nslots)) < 0) |
1217 | 0 | HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get data cache number of slots"); |
1218 | 15 | if (H5P_get(plist, H5F_ACS_DATA_CACHE_BYTE_SIZE_NAME, &(f->shared->rdcc_nbytes)) < 0) |
1219 | 0 | HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get data cache byte size"); |
1220 | 15 | if (H5P_get(plist, H5F_ACS_PREEMPT_READ_CHUNKS_NAME, &(f->shared->rdcc_w0)) < 0) |
1221 | 0 | HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get preempt read chunk"); |
1222 | 15 | if (H5P_get(plist, H5F_ACS_ALIGN_THRHD_NAME, &(f->shared->threshold)) < 0) |
1223 | 0 | HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get alignment threshold"); |
1224 | 15 | if (H5P_get(plist, H5F_ACS_ALIGN_NAME, &(f->shared->alignment)) < 0) |
1225 | 0 | HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get alignment"); |
1226 | 15 | if (H5P_get(plist, H5F_ACS_GARBG_COLCT_REF_NAME, &(f->shared->gc_ref)) < 0) |
1227 | 0 | HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get garbage collect reference"); |
1228 | 15 | if (H5P_get(plist, H5F_ACS_SIEVE_BUF_SIZE_NAME, &(f->shared->sieve_buf_size)) < 0) |
1229 | 0 | HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get sieve buffer size"); |
1230 | 15 | if (H5P_get(plist, H5F_ACS_LIBVER_LOW_BOUND_NAME, &(f->shared->low_bound)) < 0) |
1231 | 0 | HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get 'low' bound for library format versions"); |
1232 | 15 | if (H5P_get(plist, H5F_ACS_LIBVER_HIGH_BOUND_NAME, &(f->shared->high_bound)) < 0) |
1233 | 0 | HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get 'high' bound for library format versions"); |
1234 | 15 | if (H5P_get(plist, H5F_ACS_USE_MDC_LOGGING_NAME, &(f->shared->use_mdc_logging)) < 0) |
1235 | 0 | HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get 'use mdc logging' flag"); |
1236 | 15 | if (H5P_get(plist, H5F_ACS_START_MDC_LOG_ON_ACCESS_NAME, &(f->shared->start_mdc_log_on_access)) < 0) |
1237 | 0 | HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get 'start mdc log on access' flag"); |
1238 | 15 | if (H5P_get(plist, H5F_ACS_META_BLOCK_SIZE_NAME, &(f->shared->meta_aggr.alloc_size)) < 0) |
1239 | 0 | HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get metadata cache size"); |
1240 | 15 | f->shared->meta_aggr.feature_flag = H5FD_FEAT_AGGREGATE_METADATA; |
1241 | 15 | if (H5P_get(plist, H5F_ACS_SDATA_BLOCK_SIZE_NAME, &(f->shared->sdata_aggr.alloc_size)) < 0) |
1242 | 0 | HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get 'small data' cache size"); |
1243 | 15 | f->shared->sdata_aggr.feature_flag = H5FD_FEAT_AGGREGATE_SMALLDATA; |
1244 | 15 | if (H5P_get(plist, H5F_ACS_EFC_SIZE_NAME, &efc_size) < 0) |
1245 | 0 | HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get elink file cache size"); |
1246 | 15 | if (efc_size > 0) |
1247 | 0 | if (NULL == (f->shared->efc = H5F__efc_create(efc_size))) |
1248 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, NULL, "can't create external file cache"); |
1249 | | #ifdef H5_HAVE_PARALLEL |
1250 | | if (H5P_get(plist, H5_COLL_MD_READ_FLAG_NAME, &(f->shared->coll_md_read)) < 0) |
1251 | | HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get collective metadata read flag"); |
1252 | | if (H5P_get(plist, H5F_ACS_COLL_MD_WRITE_FLAG_NAME, &(f->shared->coll_md_write)) < 0) |
1253 | | HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get collective metadata write flag"); |
1254 | | #endif /* H5_HAVE_PARALLEL */ |
1255 | 15 | if (H5P_get(plist, H5F_ACS_META_CACHE_INIT_IMAGE_CONFIG_NAME, &(f->shared->mdc_initCacheImageCfg)) < |
1256 | 15 | 0) |
1257 | 0 | HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get initial metadata cache resize config"); |
1258 | 15 | if (H5P_get(plist, H5F_ACS_RFIC_FLAGS_NAME, &(f->shared->rfic_flags)) < 0) |
1259 | 0 | HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get RFIC flags value"); |
1260 | | |
1261 | | /* Get the VFD values to cache */ |
1262 | 15 | f->shared->maxaddr = H5FD_get_maxaddr(lf); |
1263 | 15 | if (!H5_addr_defined(f->shared->maxaddr)) |
1264 | 0 | HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, NULL, "bad maximum address from VFD"); |
1265 | 15 | if (H5FD_get_feature_flags(lf, &f->shared->feature_flags) < 0) |
1266 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTGET, NULL, "can't get feature flags from VFD"); |
1267 | | |
1268 | | /* Require the SWMR feature flag if SWMR I/O is desired */ |
1269 | 15 | if (!H5F_HAS_FEATURE(f, H5FD_FEAT_SUPPORTS_SWMR_IO) && |
1270 | 0 | (H5F_INTENT(f) & (H5F_ACC_SWMR_WRITE | H5F_ACC_SWMR_READ))) |
1271 | 0 | HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, NULL, |
1272 | 15 | "must use a SWMR-compatible VFD when SWMR is specified"); |
1273 | | |
1274 | 15 | if (H5FD_get_fs_type_map(lf, f->shared->fs_type_map) < 0) |
1275 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTGET, NULL, "can't get free space type mapping from VFD"); |
1276 | 15 | if (H5MF_init_merge_flags(f->shared) < 0) |
1277 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, NULL, "problem initializing free space merge flags"); |
1278 | 15 | f->shared->tmp_addr = f->shared->maxaddr; |
1279 | | /* Disable temp. space allocation for parallel I/O (for now) */ |
1280 | | /* (When we've arranged to have the relocated metadata addresses (and |
1281 | | * sizes) broadcast during the "end of epoch" metadata operations, |
1282 | | * this can be enabled - QAK) |
1283 | | */ |
1284 | | /* (This should be disabled when the metadata journaling branch is |
1285 | | * merged into the trunk and journaling is enabled, at least until |
1286 | | * we make it work. - QAK) |
1287 | | */ |
1288 | 15 | f->shared->use_tmp_space = !H5F_HAS_FEATURE(f, H5FD_FEAT_HAS_MPI); |
1289 | | |
1290 | | /* Retrieve the # of read attempts here so that sohm in superblock will get the correct # of attempts |
1291 | | */ |
1292 | 15 | if (H5P_get(plist, H5F_ACS_METADATA_READ_ATTEMPTS_NAME, &f->shared->read_attempts) < 0) |
1293 | 0 | HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get the # of read attempts"); |
1294 | | |
1295 | | /* When opening file with SWMR access, the # of read attempts is H5F_SWMR_METADATA_READ_ATTEMPTS if |
1296 | | * not set */ |
1297 | | /* When opening file without SWMR access, the # of read attempts is always H5F_METADATA_READ_ATTEMPTS |
1298 | | * (set or not set) */ |
1299 | 15 | if (H5F_INTENT(f) & (H5F_ACC_SWMR_READ | H5F_ACC_SWMR_WRITE)) { |
1300 | | /* If no value for read attempts has been set, use the default */ |
1301 | 0 | if (!f->shared->read_attempts) |
1302 | 0 | f->shared->read_attempts = H5F_SWMR_METADATA_READ_ATTEMPTS; |
1303 | | |
1304 | | /* Turn off accumulator with SWMR */ |
1305 | 0 | f->shared->feature_flags &= ~(unsigned)H5FD_FEAT_ACCUMULATE_METADATA; |
1306 | 0 | if (H5FD_set_feature_flags(f->shared->lf, f->shared->feature_flags) < 0) |
1307 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTSET, NULL, "can't set feature_flags in VFD"); |
1308 | 0 | } |
1309 | 15 | else { |
1310 | | /* If no value for read attempts has been set, use the default */ |
1311 | 15 | if (!f->shared->read_attempts) |
1312 | 15 | f->shared->read_attempts = H5F_METADATA_READ_ATTEMPTS; |
1313 | 15 | } |
1314 | | |
1315 | | /* Determine the # of bins for metadata read retries */ |
1316 | 15 | if (H5F_set_retries(f) < 0) |
1317 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, NULL, "can't set retries and retries_nbins"); |
1318 | | |
1319 | | /* Get the metadata cache log location (if we're logging) */ |
1320 | 15 | { |
1321 | 15 | char *mdc_log_location = NULL; /* location of metadata cache log location */ |
1322 | | |
1323 | 15 | if (H5P_get(plist, H5F_ACS_MDC_LOG_LOCATION_NAME, &mdc_log_location) < 0) |
1324 | 0 | HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get mdc log location"); |
1325 | 15 | if (mdc_log_location != NULL) { |
1326 | 0 | size_t len = strlen(mdc_log_location); |
1327 | 0 | if (NULL == (f->shared->mdc_log_location = (char *)H5MM_calloc((len + 1) * sizeof(char)))) |
1328 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, NULL, |
1329 | 0 | "can't allocate memory for mdc log file name"); |
1330 | 0 | strncpy(f->shared->mdc_log_location, mdc_log_location, len + 1); |
1331 | 0 | f->shared->mdc_log_location[len] = '\0'; |
1332 | 0 | } |
1333 | 15 | else |
1334 | 15 | f->shared->mdc_log_location = NULL; |
1335 | 15 | } /* end block */ |
1336 | | |
1337 | | /* Get object flush callback information */ |
1338 | 15 | if (H5P_get(plist, H5F_ACS_OBJECT_FLUSH_CB_NAME, &(f->shared->object_flush)) < 0) |
1339 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTGET, NULL, "can't get object flush cb info"); |
1340 | | |
1341 | | /* Get the VOL connector info */ |
1342 | 15 | if (H5F__set_vol_conn(f) < 0) |
1343 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, NULL, "can't cache VOL connector info"); |
1344 | | |
1345 | | /* Create a metadata cache with the specified number of elements. |
1346 | | * The cache might be created with a different number of elements and |
1347 | | * the access property list should be updated to reflect that. |
1348 | | */ |
1349 | 15 | if (H5AC_create(f, &(f->shared->mdc_initCacheCfg), &(f->shared->mdc_initCacheImageCfg)) < 0) |
1350 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, NULL, "unable to create metadata cache"); |
1351 | | |
1352 | | /* Create the file's "open object" information */ |
1353 | 15 | if (H5FO_create(f) < 0) |
1354 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, NULL, "unable to create open object data structure"); |
1355 | | |
1356 | | /* Add new "shared" struct to list of open files */ |
1357 | 15 | if (H5F__sfile_add(f->shared) < 0) |
1358 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, NULL, "unable to append to list of open files"); |
1359 | 15 | } /* end else */ |
1360 | | |
1361 | 15 | f->shared->nrefs++; |
1362 | | |
1363 | | /* Create the file's "top open object" information */ |
1364 | 15 | if (H5FO_top_create(f) < 0) |
1365 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, NULL, "unable to create open object data structure"); |
1366 | | |
1367 | | /* Set return value */ |
1368 | 15 | ret_value = f; |
1369 | | |
1370 | 15 | done: |
1371 | 15 | if (!ret_value && f) { |
1372 | 0 | assert(NULL == f->vol_obj); |
1373 | |
|
1374 | 0 | if (!shared) { |
1375 | | /* Attempt to clean up some of the shared file structures */ |
1376 | 0 | if (f->shared->efc) |
1377 | 0 | if (H5F__efc_destroy(f->shared->efc) < 0) |
1378 | 0 | HDONE_ERROR(H5E_FILE, H5E_CANTRELEASE, NULL, "can't destroy external file cache"); |
1379 | 0 | if (f->shared->fcpl_id > 0) |
1380 | 0 | if (H5I_dec_ref(f->shared->fcpl_id) < 0) |
1381 | 0 | HDONE_ERROR(H5E_FILE, H5E_CANTDEC, NULL, "can't close property list"); |
1382 | |
|
1383 | 0 | f->shared = H5FL_FREE(H5F_shared_t, f->shared); |
1384 | 0 | } |
1385 | |
|
1386 | 0 | f = H5FL_FREE(H5F_t, f); |
1387 | 0 | } |
1388 | | |
1389 | 15 | FUNC_LEAVE_NOAPI(ret_value) |
1390 | 15 | } /* end H5F__new() */ |
1391 | | |
1392 | | /*------------------------------------------------------------------------- |
1393 | | * Function: H5F__dest |
1394 | | * |
1395 | | * Purpose: Destroys a file structure. This function flushes the cache |
1396 | | * but doesn't do any other cleanup other than freeing memory |
1397 | | * for the file struct. The shared info for the file is freed |
1398 | | * only when its reference count reaches zero. |
1399 | | * |
1400 | | * Return: SUCCEED/FAIL |
1401 | | *------------------------------------------------------------------------- |
1402 | | */ |
1403 | | static herr_t |
1404 | | H5F__dest(H5F_t *f, bool flush, bool free_on_failure) |
1405 | 15 | { |
1406 | 15 | herr_t ret_value = SUCCEED; /* Return value */ |
1407 | | |
1408 | 15 | FUNC_ENTER_PACKAGE |
1409 | | |
1410 | | /* Sanity check */ |
1411 | 15 | assert(f); |
1412 | 15 | assert(f->shared); |
1413 | | |
1414 | 15 | if (1 == f->shared->nrefs) { |
1415 | 15 | int actype; /* metadata cache type (enum value) */ |
1416 | | |
1417 | | /* Mark this file as closing */ |
1418 | 15 | f->shared->closing = true; |
1419 | | |
1420 | | /* Flush at this point since the file will be closed (phase 1). |
1421 | | * Only try to flush the file if it was opened with write access, and if |
1422 | | * the caller requested a flush. |
1423 | | */ |
1424 | 15 | if ((H5F_ACC_RDWR & H5F_INTENT(f)) && flush) |
1425 | 6 | if (H5F__flush_phase1(f) < 0) |
1426 | | /* Push error, but keep going*/ |
1427 | 0 | HDONE_ERROR(H5E_FILE, H5E_CANTFLUSH, FAIL, "unable to flush cached data (phase 1)"); |
1428 | | |
1429 | | /* Notify the metadata cache that the file is about to be closed. |
1430 | | * This allows the cache to set up for creating a metadata cache |
1431 | | * image if this has been requested. |
1432 | | */ |
1433 | 15 | if (H5AC_prep_for_file_close(f) < 0) |
1434 | | /* Push error, but keep going */ |
1435 | 0 | HDONE_ERROR(H5E_FILE, H5E_CANTFLUSH, FAIL, "metadata cache prep for close failed"); |
1436 | | |
1437 | | /* Flush at this point since the file will be closed (phase 2). |
1438 | | * Only try to flush the file if it was opened with write access, and if |
1439 | | * the caller requested a flush. |
1440 | | */ |
1441 | 15 | if ((H5F_ACC_RDWR & H5F_INTENT(f)) && flush) |
1442 | 6 | if (H5F__flush_phase2(f, true) < 0) |
1443 | | /* Push error, but keep going */ |
1444 | 0 | HDONE_ERROR(H5E_FILE, H5E_CANTFLUSH, FAIL, "unable to flush cached data (phase 2)"); |
1445 | | |
1446 | | /* With the shutdown modifications, the contents of the metadata cache |
1447 | | * should be clean at this point, with the possible exception of the |
1448 | | * the superblock and superblock extension. |
1449 | | * |
1450 | | * Verify this. |
1451 | | */ |
1452 | 15 | assert(H5AC_cache_is_clean(f, H5AC_RING_MDFSM)); |
1453 | | |
1454 | | /* Release the external file cache */ |
1455 | 15 | if (f->shared->efc) { |
1456 | 0 | if (H5F__efc_destroy(f->shared->efc) < 0) |
1457 | | /* Push error, but keep going*/ |
1458 | 0 | HDONE_ERROR(H5E_FILE, H5E_CANTRELEASE, FAIL, "can't destroy external file cache"); |
1459 | 0 | f->shared->efc = NULL; |
1460 | 0 | } /* end if */ |
1461 | | |
1462 | | /* With the shutdown modifications, the contents of the metadata cache |
1463 | | * should be clean at this point, with the possible exception of the |
1464 | | * the superblock and superblock extension. |
1465 | | * |
1466 | | * Verify this. |
1467 | | */ |
1468 | 15 | assert(H5AC_cache_is_clean(f, H5AC_RING_MDFSM)); |
1469 | | |
1470 | | /* Release objects that depend on the superblock being initialized */ |
1471 | 15 | if (f->shared->sblock) { |
1472 | | /* Shutdown file free space manager(s) */ |
1473 | | /* (We should release the free space information now (before |
1474 | | * truncating the file and before the metadata cache is shut |
1475 | | * down) since the free space manager is holding some data |
1476 | | * structures in memory and also because releasing free space |
1477 | | * can shrink the file's 'eoa' value) |
1478 | | * |
1479 | | * Update 11/1/16: |
1480 | | * |
1481 | | * With recent library shutdown modifications, the free space |
1482 | | * managers should be settled and written to file at this point |
1483 | | * (assuming they are persistent). In this case, closing the |
1484 | | * free space managers should have no effect on EOA. |
1485 | | * |
1486 | | * -- JRM |
1487 | | */ |
1488 | 6 | if (H5F_ACC_RDWR & H5F_INTENT(f)) { |
1489 | 6 | if (H5MF_close(f) < 0) |
1490 | | /* Push error, but keep going*/ |
1491 | 0 | HDONE_ERROR(H5E_FILE, H5E_CANTRELEASE, FAIL, "can't release file free space info"); |
1492 | | |
1493 | | /* at this point, only the superblock and superblock |
1494 | | * extension should be dirty. |
1495 | | */ |
1496 | 6 | assert(H5AC_cache_is_clean(f, H5AC_RING_MDFSM)); |
1497 | | |
1498 | | /* Flush the file again (if requested), as shutting down the |
1499 | | * free space manager may dirty some data structures again. |
1500 | | */ |
1501 | 6 | if (flush) { |
1502 | | /* Clear status_flags */ |
1503 | 6 | f->shared->sblock->status_flags &= (uint8_t)(~H5F_SUPER_WRITE_ACCESS); |
1504 | 6 | f->shared->sblock->status_flags &= (uint8_t)(~H5F_SUPER_SWMR_WRITE_ACCESS); |
1505 | | |
1506 | | /* Mark EOA info dirty in cache, so change will get encoded */ |
1507 | 6 | if (H5F_eoa_dirty(f) < 0) |
1508 | | /* Push error, but keep going*/ |
1509 | 0 | HDONE_ERROR(H5E_FILE, H5E_CANTMARKDIRTY, FAIL, "unable to mark superblock as dirty"); |
1510 | | |
1511 | | /* Release any space allocated to space aggregators, |
1512 | | * so that the eoa value corresponds to the end of the |
1513 | | * space written to in the file. |
1514 | | * |
1515 | | * At most, this should change the superblock or the |
1516 | | * superblock extension messages. |
1517 | | */ |
1518 | 6 | if (H5MF_free_aggrs(f) < 0) |
1519 | | /* Push error, but keep going*/ |
1520 | 0 | HDONE_ERROR(H5E_FILE, H5E_CANTRELEASE, FAIL, "can't release file space"); |
1521 | | |
1522 | | /* Truncate the file to the current allocated size */ |
1523 | 6 | if (H5FD_truncate(f->shared->lf, true) < 0) |
1524 | | /* Push error, but keep going*/ |
1525 | 0 | HDONE_ERROR(H5E_FILE, H5E_WRITEERROR, FAIL, "low level truncate failed"); |
1526 | | |
1527 | | /* at this point, only the superblock and superblock |
1528 | | * extension should be dirty. |
1529 | | */ |
1530 | 6 | assert(H5AC_cache_is_clean(f, H5AC_RING_MDFSM)); |
1531 | 6 | } /* end if */ |
1532 | 6 | } /* end if */ |
1533 | | |
1534 | | /* if it exists, unpin the driver information block cache entry, |
1535 | | * since we're about to destroy the cache |
1536 | | */ |
1537 | 6 | if (f->shared->drvinfo) |
1538 | 6 | if (H5AC_unpin_entry(f->shared->drvinfo) < 0) |
1539 | | /* Push error, but keep going*/ |
1540 | 0 | HDONE_ERROR(H5E_FSPACE, H5E_CANTUNPIN, FAIL, "unable to unpin drvinfo"); |
1541 | | |
1542 | | /* Unpin the superblock, since we're about to destroy the cache */ |
1543 | 6 | if (H5AC_unpin_entry(f->shared->sblock) < 0) |
1544 | | /* Push error, but keep going*/ |
1545 | 0 | HDONE_ERROR(H5E_FSPACE, H5E_CANTUNPIN, FAIL, "unable to unpin superblock"); |
1546 | 6 | f->shared->sblock = NULL; |
1547 | 6 | } /* end if */ |
1548 | | |
1549 | | /* with the possible exception of the superblock and superblock |
1550 | | * extension, the metadata cache should be clean at this point. |
1551 | | * |
1552 | | * Verify this. |
1553 | | */ |
1554 | 15 | assert(H5AC_cache_is_clean(f, H5AC_RING_MDFSM)); |
1555 | | |
1556 | | /* Remove shared file struct from list of open files */ |
1557 | 15 | if (H5F__sfile_remove(f->shared) < 0) |
1558 | | /* Push error, but keep going*/ |
1559 | 0 | HDONE_ERROR(H5E_FILE, H5E_CANTRELEASE, FAIL, "problems closing file"); |
1560 | | |
1561 | | /* Shutdown the metadata cache */ |
1562 | | /* (Flushes any remaining dirty entries, which should only be the |
1563 | | * superblock and / or driver info at this point) |
1564 | | */ |
1565 | 15 | if (H5AC_dest(f)) |
1566 | | /* Push error, but keep going*/ |
1567 | 6 | HDONE_ERROR(H5E_FILE, H5E_CANTRELEASE, FAIL, "problems closing file"); |
1568 | | |
1569 | | /* Shutdown the page buffer cache */ |
1570 | 15 | if (H5PB_dest(f->shared) < 0) |
1571 | | /* Push error, but keep going*/ |
1572 | 0 | HDONE_ERROR(H5E_FILE, H5E_CANTRELEASE, FAIL, "problems closing page buffer cache"); |
1573 | | |
1574 | | /* Clean up the metadata cache log location string */ |
1575 | 15 | if (f->shared->mdc_log_location) |
1576 | 0 | f->shared->mdc_log_location = (char *)H5MM_xfree(f->shared->mdc_log_location); |
1577 | | |
1578 | | /* |
1579 | | * Do not close the root group since we didn't count it, but free |
1580 | | * the memory associated with it. |
1581 | | */ |
1582 | 15 | if (f->shared->root_grp) { |
1583 | | /* Free the root group */ |
1584 | 6 | if (H5G_root_free(f->shared->root_grp) < 0) |
1585 | | /* Push error, but keep going*/ |
1586 | 0 | HDONE_ERROR(H5E_FILE, H5E_CANTRELEASE, FAIL, "problems closing file"); |
1587 | 6 | f->shared->root_grp = NULL; |
1588 | 6 | } /* end if */ |
1589 | | |
1590 | | /* Destroy other components of the file */ |
1591 | 15 | if (H5F__accum_reset(f->shared, true, true) < 0) |
1592 | | /* Push error, but keep going*/ |
1593 | 0 | HDONE_ERROR(H5E_FILE, H5E_CANTRELEASE, FAIL, "problems closing file"); |
1594 | 15 | if (H5FO_dest(f) < 0) |
1595 | | /* Push error, but keep going*/ |
1596 | 0 | HDONE_ERROR(H5E_FILE, H5E_CANTRELEASE, FAIL, "problems closing file"); |
1597 | 15 | f->shared->cwfs = (struct H5HG_heap_t **)H5MM_xfree(f->shared->cwfs); |
1598 | 15 | if (H5G_node_close(f) < 0) |
1599 | | /* Push error, but keep going*/ |
1600 | 0 | HDONE_ERROR(H5E_FILE, H5E_CANTRELEASE, FAIL, "problems closing file"); |
1601 | | |
1602 | | /* Destroy file creation properties */ |
1603 | 15 | if (H5I_GENPROP_LST != H5I_get_type(f->shared->fcpl_id)) |
1604 | | /* Push error, but keep going*/ |
1605 | 0 | HDONE_ERROR(H5E_FILE, H5E_BADTYPE, FAIL, "not a property list"); |
1606 | 15 | if (H5I_dec_ref(f->shared->fcpl_id) < 0) |
1607 | | /* Push error, but keep going*/ |
1608 | 0 | HDONE_ERROR(H5E_FILE, H5E_CANTDEC, FAIL, "can't close property list"); |
1609 | | |
1610 | | /* Clean up the cached VOL connector ID & info */ |
1611 | 15 | if (f->shared->vol_info) |
1612 | 0 | if (H5VL_free_connector_info(f->shared->vol_conn, f->shared->vol_info) < 0) |
1613 | | /* Push error, but keep going*/ |
1614 | 0 | HDONE_ERROR(H5E_FILE, H5E_CANTRELEASE, FAIL, "unable to release VOL connector info object"); |
1615 | 15 | if (f->shared->vol_conn) |
1616 | 15 | if (H5VL_conn_dec_rc(f->shared->vol_conn) < 0) |
1617 | | /* Push error, but keep going*/ |
1618 | 0 | HDONE_ERROR(H5E_FILE, H5E_CANTDEC, FAIL, "can't close VOL connector"); |
1619 | | |
1620 | | /* Close the file */ |
1621 | 15 | if (H5FD_close(f->shared->lf) < 0) |
1622 | | /* Push error, but keep going*/ |
1623 | 0 | HDONE_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "unable to close file"); |
1624 | | |
1625 | | /* Free mount table */ |
1626 | 15 | f->shared->mtab.child = (H5F_mount_t *)H5MM_xfree(f->shared->mtab.child); |
1627 | 15 | f->shared->mtab.nalloc = 0; |
1628 | | |
1629 | | /* Free the external link file */ |
1630 | 15 | f->shared->extpath = (char *)H5MM_xfree(f->shared->extpath); |
1631 | | |
1632 | | /* Clean up the metadata retries array */ |
1633 | 465 | for (actype = 0; actype < (int)H5AC_NTYPES; actype++) |
1634 | 450 | if (f->shared->retries[actype]) |
1635 | 0 | f->shared->retries[actype] = (uint32_t *)H5MM_xfree(f->shared->retries[actype]); |
1636 | | |
1637 | | /* Destroy shared file struct */ |
1638 | 15 | f->shared = (H5F_shared_t *)H5FL_FREE(H5F_shared_t, f->shared); |
1639 | 15 | } |
1640 | 0 | else if (f->shared->nrefs > 0) { |
1641 | | /* |
1642 | | * There are other references to the shared part of the file. |
1643 | | * Only decrement the reference count. |
1644 | | */ |
1645 | 0 | --f->shared->nrefs; |
1646 | 0 | } |
1647 | | |
1648 | | /* Free the non-shared part of the file */ |
1649 | 15 | f->open_name = (char *)H5MM_xfree(f->open_name); |
1650 | 15 | f->actual_name = (char *)H5MM_xfree(f->actual_name); |
1651 | 15 | if (f->vol_obj) { |
1652 | 6 | void *vol_wrap_ctx = NULL; |
1653 | | |
1654 | | /* If a VOL wrapping context is available, retrieve it |
1655 | | * and unwrap file VOL object |
1656 | | */ |
1657 | 6 | if (H5CX_get_vol_wrap_ctx((void **)&vol_wrap_ctx) < 0) |
1658 | 0 | HDONE_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "can't get VOL object wrap context"); |
1659 | 6 | if (vol_wrap_ctx && (NULL == H5VL_object_unwrap(f->vol_obj))) |
1660 | 0 | HDONE_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "can't unwrap VOL object"); |
1661 | | |
1662 | | /* |
1663 | | * Clean up any cached type conversion path table entries that |
1664 | | * may have been keeping a reference to the file's VOL object |
1665 | | * in order to prevent the file from being closed out from |
1666 | | * underneath other places that may access the conversion path |
1667 | | * or its src/dst datatypes later on (currently, conversions on |
1668 | | * variable-length and reference datatypes involve this) |
1669 | | */ |
1670 | 6 | if (H5T_unregister(H5T_PERS_SOFT, NULL, NULL, NULL, f->vol_obj, NULL) < 0) |
1671 | 0 | HDONE_ERROR(H5E_FILE, H5E_CANTRELEASE, FAIL, |
1672 | 6 | "unable to free cached type conversion path table entries"); |
1673 | | |
1674 | 6 | if (H5VL_free_object(f->vol_obj) < 0) |
1675 | 0 | HDONE_ERROR(H5E_FILE, H5E_CANTDEC, FAIL, "unable to free VOL object"); |
1676 | 6 | f->vol_obj = NULL; |
1677 | 6 | } |
1678 | 15 | if (H5FO_top_dest(f) < 0) |
1679 | 0 | HDONE_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "problems closing file"); |
1680 | 15 | f->shared = NULL; |
1681 | | |
1682 | 15 | if ((ret_value >= 0) || free_on_failure) |
1683 | 9 | f = H5FL_FREE(H5F_t, f); |
1684 | | |
1685 | 15 | FUNC_LEAVE_NOAPI(ret_value) |
1686 | 15 | } /* end H5F__dest() */ |
1687 | | |
1688 | | /*------------------------------------------------------------------------- |
1689 | | * Function: H5F__check_if_using_file_locks |
1690 | | * |
1691 | | * Purpose: Determines if this file will use file locks and whether or |
1692 | | * not to ignore the case where file locking is disabled on |
1693 | | * the file system. |
1694 | | * |
1695 | | * There are three ways that file locking can be controlled: |
1696 | | * |
1697 | | * 1) The configure/cmake option that sets the H5_USE_FILE_LOCKING |
1698 | | * symbol (which is used as the default fapl value). |
1699 | | * |
1700 | | * 2) The H5Pset_file_locking() API call, which will override |
1701 | | * the configuration default. |
1702 | | * |
1703 | | * 3) The HDF5_USE_FILE_LOCKING environment variable, which overrides |
1704 | | * everything above. |
1705 | | * |
1706 | | * The main reason to disable file locking is to prevent errors on file |
1707 | | * systems where locking is not supported or has been disabled (as is |
1708 | | * often the case in parallel file systems). |
1709 | | * |
1710 | | * Return: SUCCEED/FAIL |
1711 | | *------------------------------------------------------------------------- |
1712 | | */ |
1713 | | static herr_t |
1714 | | H5F__check_if_using_file_locks(H5P_genplist_t *fapl, bool *use_file_locking, bool *ignore_disabled_locks) |
1715 | 15 | { |
1716 | 15 | herr_t ret_value = SUCCEED; /* Return value */ |
1717 | | |
1718 | 15 | FUNC_ENTER_PACKAGE |
1719 | | |
1720 | | /* Make sure the out parameters have a value */ |
1721 | 15 | *use_file_locking = true; |
1722 | 15 | *ignore_disabled_locks = false; |
1723 | | |
1724 | | /* Check file locking environment variable first */ |
1725 | 15 | if (use_locks_env_g != FAIL) { |
1726 | 0 | *use_file_locking = (use_locks_env_g == true); |
1727 | 0 | } |
1728 | 15 | else { |
1729 | | /* Check the file locking fapl property */ |
1730 | 15 | if (H5P_get(fapl, H5F_ACS_USE_FILE_LOCKING_NAME, use_file_locking) < 0) |
1731 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "can't get use file locking flag"); |
1732 | 15 | } |
1733 | | |
1734 | | /* Check "ignore disabled file locks" environment variable first */ |
1735 | 15 | if (ignore_disabled_locks_g != FAIL) { |
1736 | 0 | *ignore_disabled_locks = (ignore_disabled_locks_g == true); |
1737 | 0 | } |
1738 | 15 | else { |
1739 | | /* Check the "ignore disabled file locks" fapl property */ |
1740 | 15 | if (H5P_get(fapl, H5F_ACS_IGNORE_DISABLED_FILE_LOCKS_NAME, ignore_disabled_locks) < 0) |
1741 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "can't get ignore disabled file locks property"); |
1742 | 15 | } |
1743 | | |
1744 | 15 | done: |
1745 | 15 | FUNC_LEAVE_NOAPI(ret_value) |
1746 | 15 | } /* end H5F__check_if_using_file_locks() */ |
1747 | | |
1748 | | /*------------------------------------------------------------------------- |
1749 | | * Function: H5F_open |
1750 | | * |
1751 | | * Purpose: Attempts to open (or create) a file. This function understands |
1752 | | * the following flags which are similar in nature to the POSIX |
1753 | | * open(2) flags. |
1754 | | * |
1755 | | * H5F_ACC_RDWR: Open with read/write access. If the file is |
1756 | | * currently open for read-only access then it |
1757 | | * will be reopened. Absence of this flag |
1758 | | * implies read-only access. |
1759 | | * |
1760 | | * H5F_ACC_CREAT: Create a new file if it doesn't exist yet. |
1761 | | * The permissions are 0666 bit-wise AND with |
1762 | | * the current umask. H5F_ACC_WRITE must also |
1763 | | * be specified. |
1764 | | * |
1765 | | * H5F_ACC_EXCL: This flag causes H5F_open() to fail if the |
1766 | | * file already exists. |
1767 | | * |
1768 | | * H5F_ACC_TRUNC: The file is truncated and a new HDF5 superblock |
1769 | | * is written. This operation will fail if the |
1770 | | * file is already open. |
1771 | | * |
1772 | | * Unlinking the file name from the group directed graph while |
1773 | | * the file is opened causes the file to continue to exist but |
1774 | | * one will not be able to upgrade the file from read-only |
1775 | | * access to read-write access by reopening it. Disk resources |
1776 | | * for the file are released when all handles to the file are |
1777 | | * closed. NOTE: This paragraph probably only applies to Unix; |
1778 | | * deleting the file name in other OS's has undefined results. |
1779 | | * |
1780 | | * The CREATE_PARMS argument is optional. A null pointer will |
1781 | | * cause the default file creation parameters to be used. |
1782 | | * |
1783 | | * The ACCESS_PARMS argument is optional. A null pointer will |
1784 | | * cause the default file access parameters to be used. |
1785 | | * |
1786 | | * The following two tables show results of file opens for single and concurrent access: |
1787 | | * |
1788 | | * SINGLE PROCESS ACCESS CONCURRENT ACCESS |
1789 | | * |
1790 | | * #1st open# #1st open# |
1791 | | * -- SR SR -- -- SR SR -- -- SR SR -- -- SR SR -- |
1792 | | * -- -- SW SW SW SW -- -- -- -- SW SW SW SW -- -- |
1793 | | * W W W W R R R R W W W W R R R R |
1794 | | * #2nd open# #2nd open# |
1795 | | * -------------------------- -------------------------- |
1796 | | * -- -- W | s x x s x x f f | -- -- W | f x x f x x f f | |
1797 | | * SR -- W | x x x x x x x x | SR -- W | x x x x x x x x | |
1798 | | * SR SW W | x x x x x x x x | SR SW W | x x x x x x x x | |
1799 | | * -- SW W | f x x s x x f f | -- SW W | f x x f x x f f | |
1800 | | * -- SW R | x x x x x x x x | -- SW R | x x x x x x x x | |
1801 | | * SR SW R | x x x x x x x x | SR SW R | x x x x x x x x | |
1802 | | * SR -- R | s x x s x x s f | SR -- R | f x x s x x s s | |
1803 | | * -- -- R | s x x s x x s s | -- -- R | f x x f x x s s | |
1804 | | * -------------------------- -------------------------- |
1805 | | * |
1806 | | * Notations: |
1807 | | * W: H5F_ACC_RDWR |
1808 | | * R: H5F_ACC_RDONLY |
1809 | | * SW: H5F_ACC_SWMR_WRITE |
1810 | | * SR: H5F_ACC_SWMR_READ |
1811 | | * |
1812 | | * x: the first open or second open itself fails due to invalid flags combination |
1813 | | * f: the open fails with flags combination from both the first and second opens |
1814 | | * s: the open succeeds with flags combination from both the first and second opens |
1815 | | * |
1816 | | * NOTE: If the 'try' flag is true, not opening the file with the |
1817 | | * "non-tentative" VFD 'open' call is not treated as an error; SUCCEED is |
1818 | | * returned, with the file ptr set to NULL. If 'try' is false, failing |
1819 | | * the "non-tentative" VFD 'open' call generates an error. |
1820 | | * |
1821 | | * Return: SUCCEED/FAIL |
1822 | | * |
1823 | | *------------------------------------------------------------------------- |
1824 | | */ |
1825 | | herr_t |
1826 | | H5F_open(bool try, H5F_t **_file, const char *name, unsigned flags, hid_t fcpl_id, hid_t fapl_id) |
1827 | 15 | { |
1828 | 15 | H5F_t *file = NULL; /*the success return value */ |
1829 | 15 | H5F_shared_t *shared = NULL; /*shared part of `file' */ |
1830 | 15 | H5FD_t *lf = NULL; /*file driver part of `shared' */ |
1831 | 15 | unsigned tent_flags; /*tentative flags */ |
1832 | 15 | H5FD_class_t *drvr; /*file driver class info */ |
1833 | 15 | H5P_genplist_t *a_plist; /*file access property list */ |
1834 | 15 | H5F_close_degree_t fc_degree; /*file close degree */ |
1835 | 15 | size_t page_buf_size; |
1836 | 15 | unsigned page_buf_min_meta_perc = 0; |
1837 | 15 | unsigned page_buf_min_raw_perc = 0; |
1838 | 15 | bool set_flag = false; /*set the status_flags in the superblock */ |
1839 | 15 | bool clear = false; /*clear the status_flags */ |
1840 | 15 | bool evict_on_close; /* evict on close value from plist */ |
1841 | 15 | bool use_file_locking = true; /* Using file locks? */ |
1842 | 15 | bool ignore_disabled_locks = false; /* Ignore disabled file locks? */ |
1843 | 15 | bool ci_load = false; /* whether MDC ci load requested */ |
1844 | 15 | bool ci_write = false; /* whether MDC CI write requested */ |
1845 | 15 | herr_t ret_value = SUCCEED; /* Return value */ |
1846 | | |
1847 | 15 | FUNC_ENTER_NOAPI(FAIL) |
1848 | | |
1849 | | /* Reset 'out' parameter */ |
1850 | 15 | *_file = NULL; |
1851 | | |
1852 | | /* |
1853 | | * If the driver has a 'cmp' method then the driver is capable of |
1854 | | * determining when two file handles refer to the same file and the |
1855 | | * library can insure that when the application opens a file twice |
1856 | | * that the two handles coordinate their operations appropriately. |
1857 | | * Otherwise it is the application's responsibility to never open the |
1858 | | * same file more than once at a time. |
1859 | | */ |
1860 | 15 | if (NULL == (drvr = H5FD_get_class(fapl_id))) |
1861 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "unable to retrieve VFL class"); |
1862 | | |
1863 | | /* Get the file access property list, for future queries */ |
1864 | 15 | if (NULL == (a_plist = (H5P_genplist_t *)H5I_object(fapl_id))) |
1865 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not file access property list"); |
1866 | | |
1867 | | /* Check if we are using file locking */ |
1868 | 15 | if (H5F__check_if_using_file_locks(a_plist, &use_file_locking, &ignore_disabled_locks) < 0) |
1869 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "unable to get file locking flags"); |
1870 | | |
1871 | | /* |
1872 | | * Opening a file is a two step process. First we try to open the |
1873 | | * file in a way which doesn't affect its state (like not truncating |
1874 | | * or creating it) so we can compare it with files that are already |
1875 | | * open. If that fails then we try again with the full set of flags |
1876 | | * (only if they're different than the original failed attempt). |
1877 | | * However, if the file driver can't distinguish between files then |
1878 | | * there's no reason to open the file tentatively because it's the |
1879 | | * application's responsibility to prevent this situation (there's no |
1880 | | * way for us to detect it here anyway). |
1881 | | */ |
1882 | 15 | if (drvr->cmp) { |
1883 | 15 | tent_flags = flags & ~(H5F_ACC_CREAT | H5F_ACC_TRUNC | H5F_ACC_EXCL); |
1884 | | |
1885 | | /* |
1886 | | * When performing a tentative open of a file where we have stripped |
1887 | | * away flags such as H5F_ACC_CREAT from the specified file access |
1888 | | * flags, use 'try open' operation to avoid pushing error messages |
1889 | | * on the error stack since there is an expectation that the tentative |
1890 | | * open might fail. |
1891 | | * |
1892 | | * If the tentative file open call fails, another attempt at opening |
1893 | | * the file will be made without error output being suppressed. |
1894 | | * |
1895 | | * However, if stripping away the H5F_ACC_CREAT flag and others left |
1896 | | * us with the same file access flags as before, then we will skip |
1897 | | * this tentative file open and only make a single attempt at opening |
1898 | | * the file. In this case, we don't want to suppress errors since |
1899 | | * the underlying file driver might provide more details on why the |
1900 | | * file open failed. |
1901 | | */ |
1902 | 15 | if (tent_flags != flags) { |
1903 | | /* Make tentative attempt to open file */ |
1904 | 0 | if (H5FD_open(true, &lf, name, tent_flags, fapl_id, HADDR_UNDEF) < 0) |
1905 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, FAIL, "can't try opening file"); |
1906 | | |
1907 | | /* If the tentative open failed, reset the file access flags, |
1908 | | * then make another attempt at opening the file. |
1909 | | */ |
1910 | 0 | if (NULL == lf) |
1911 | 0 | tent_flags = flags; |
1912 | 0 | } |
1913 | 15 | } |
1914 | 0 | else |
1915 | 0 | tent_flags = flags; |
1916 | | |
1917 | | /* |
1918 | | * If a tentative attempt to open the file wasn't necessary, attempt |
1919 | | * to open the file now. Otherwise, if the tentative open failed, clear |
1920 | | * the error stack and reset the file access flags, then make another |
1921 | | * attempt at opening the file. |
1922 | | */ |
1923 | 15 | if (NULL == lf) { |
1924 | 15 | if (H5FD_open(try, &lf, name, tent_flags, fapl_id, HADDR_UNDEF) < 0) |
1925 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, FAIL, "can't try opening file"); |
1926 | | |
1927 | | /* Check if file was not opened */ |
1928 | 15 | if (NULL == lf) { |
1929 | 0 | assert(try); |
1930 | 0 | HGOTO_DONE(SUCCEED); |
1931 | 0 | } |
1932 | 15 | } |
1933 | | |
1934 | | /* Is the file already open? */ |
1935 | 15 | if ((shared = H5F__sfile_search(lf)) != NULL) { |
1936 | | /* |
1937 | | * The file is already open, so use that one instead of the one we |
1938 | | * just opened. We only one one H5FD_t* per file so one doesn't |
1939 | | * confuse the other. But fail if this request was to truncate the |
1940 | | * file (since we can't do that while the file is open), or if the |
1941 | | * request was to create a non-existent file (since the file already |
1942 | | * exists), or if the new request adds write access (since the |
1943 | | * readers don't expect the file to change under them), or if the |
1944 | | * SWMR write/read access flags don't agree. |
1945 | | */ |
1946 | 0 | if (H5FD_close(lf) < 0) |
1947 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, FAIL, "unable to close low-level file info"); |
1948 | 0 | if (flags & H5F_ACC_TRUNC) |
1949 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, FAIL, "unable to truncate a file which is already open"); |
1950 | 0 | if (flags & H5F_ACC_EXCL) |
1951 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, FAIL, "file exists"); |
1952 | 0 | if ((flags & H5F_ACC_RDWR) && 0 == (shared->flags & H5F_ACC_RDWR)) |
1953 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, FAIL, "file is already open for read-only"); |
1954 | | |
1955 | 0 | if ((flags & H5F_ACC_SWMR_WRITE) && 0 == (shared->flags & H5F_ACC_SWMR_WRITE)) |
1956 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, FAIL, |
1957 | 0 | "SWMR write access flag not the same for file that is already open"); |
1958 | 0 | if ((flags & H5F_ACC_SWMR_READ) && |
1959 | 0 | !((shared->flags & H5F_ACC_SWMR_WRITE) || (shared->flags & H5F_ACC_SWMR_READ) || |
1960 | 0 | (shared->flags & H5F_ACC_RDWR))) |
1961 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, FAIL, |
1962 | 0 | "SWMR read access flag not the same for file that is already open"); |
1963 | | |
1964 | | /* Allocate new "high-level" file struct */ |
1965 | 0 | if ((file = H5F__new(shared, flags, fcpl_id, fapl_id, NULL)) == NULL) |
1966 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, FAIL, "unable to create new file object"); |
1967 | 0 | } /* end if */ |
1968 | 15 | else { |
1969 | | /* Check if tentative open was good enough */ |
1970 | 15 | if (flags != tent_flags) { |
1971 | | /* |
1972 | | * This file is not yet open by the library and the flags we used to |
1973 | | * open it are different than the desired flags. Close the tentative |
1974 | | * file and open it for real. |
1975 | | */ |
1976 | 0 | if (H5FD_close(lf) < 0) |
1977 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, FAIL, "unable to close low-level file info"); |
1978 | 0 | lf = NULL; |
1979 | |
|
1980 | 0 | if (H5FD_open(false, &lf, name, flags, fapl_id, HADDR_UNDEF) < 0) |
1981 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, FAIL, "unable to open file"); |
1982 | 0 | assert(lf); |
1983 | 0 | } /* end if */ |
1984 | | |
1985 | | /* Place an advisory lock on the file */ |
1986 | 15 | if (use_file_locking) |
1987 | 15 | if (H5FD_lock(lf, (bool)((flags & H5F_ACC_RDWR) ? true : false)) < 0) { |
1988 | | /* Locking failed - Closing will remove the lock */ |
1989 | 0 | if (H5FD_close(lf) < 0) |
1990 | 0 | HDONE_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "unable to close low-level file info"); |
1991 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTLOCKFILE, FAIL, "unable to lock the file"); |
1992 | 0 | } /* end if */ |
1993 | | |
1994 | | /* Create the 'top' file structure */ |
1995 | 15 | if (NULL == (file = H5F__new(NULL, flags, fcpl_id, fapl_id, lf))) { |
1996 | | /* If this is the only time the file has been opened and the struct |
1997 | | * returned is NULL, H5FD_close() will never be called via H5F__dest() |
1998 | | * so we have to close lf here before heading to the error handling. |
1999 | | */ |
2000 | 0 | if (H5FD_close(lf) < 0) |
2001 | 0 | HDONE_ERROR(H5E_FILE, H5E_CANTOPENFILE, FAIL, "unable to close low-level file info"); |
2002 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, FAIL, "unable to initialize file structure"); |
2003 | 0 | } /* end if */ |
2004 | | |
2005 | | /* Need to set status_flags in the superblock if the driver has a 'lock' method */ |
2006 | 15 | if (drvr->lock) |
2007 | 15 | set_flag = true; |
2008 | 15 | } /* end else */ |
2009 | | |
2010 | | /* Check to see if both SWMR and cache image are requested. Fail if so */ |
2011 | 15 | if (H5C_cache_image_status(file, &ci_load, &ci_write) < 0) |
2012 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "can't get MDC cache image status"); |
2013 | 15 | if ((ci_load || ci_write) && (flags & (H5F_ACC_SWMR_READ | H5F_ACC_SWMR_WRITE))) |
2014 | 0 | HGOTO_ERROR(H5E_FILE, H5E_UNSUPPORTED, FAIL, "can't have both SWMR and cache image"); |
2015 | | |
2016 | | /* Retain the original filename. */ |
2017 | 15 | file->open_name = H5MM_xstrdup(name); |
2018 | | |
2019 | | /* Short cuts */ |
2020 | 15 | shared = file->shared; |
2021 | 15 | lf = shared->lf; |
2022 | | |
2023 | | /* Set the file locking flags. If the file is already open, the file |
2024 | | * requested file locking flag must match that of the open file. |
2025 | | */ |
2026 | 15 | if (shared->nrefs == 1) { |
2027 | 15 | file->shared->use_file_locking = use_file_locking; |
2028 | 15 | file->shared->ignore_disabled_locks = ignore_disabled_locks; |
2029 | 15 | } |
2030 | 0 | else if (shared->nrefs > 1) { |
2031 | 0 | if (file->shared->use_file_locking != use_file_locking) |
2032 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "file locking flag values don't match"); |
2033 | 0 | if (file->shared->use_file_locking && (file->shared->ignore_disabled_locks != ignore_disabled_locks)) |
2034 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, |
2035 | 0 | "file locking 'ignore disabled locks' flag values don't match"); |
2036 | 0 | } |
2037 | | |
2038 | | /* Retrieve page buffer size from FAPL and replace "default" value with actual default |
2039 | | * (H5PB_SIZE_DEFAULT_VALUE) */ |
2040 | 15 | if (H5P_get(a_plist, H5F_ACS_PAGE_BUFFER_SIZE_NAME, &page_buf_size) < 0) |
2041 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "can't get page buffer size"); |
2042 | 15 | if (page_buf_size == H5F_PAGE_BUFFER_SIZE_DEFAULT) |
2043 | 15 | page_buf_size = H5PB_SIZE_DEFAULT_VALUE; |
2044 | | |
2045 | | /* Check if page buffering is enabled */ |
2046 | 15 | if (page_buf_size) { |
2047 | | /* Query for other page buffer cache properties */ |
2048 | 0 | if (H5P_get(a_plist, H5F_ACS_PAGE_BUFFER_MIN_META_PERC_NAME, &page_buf_min_meta_perc) < 0) |
2049 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "can't get minimum metadata fraction of page buffer"); |
2050 | 0 | if (H5P_get(a_plist, H5F_ACS_PAGE_BUFFER_MIN_RAW_PERC_NAME, &page_buf_min_raw_perc) < 0) |
2051 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "can't get minimum raw data fraction of page buffer"); |
2052 | 0 | } /* end if */ |
2053 | | |
2054 | | /* Get the evict on close setting */ |
2055 | 15 | if (H5P_get(a_plist, H5F_ACS_EVICT_ON_CLOSE_FLAG_NAME, &evict_on_close) < 0) |
2056 | 0 | HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get evict on close value"); |
2057 | | |
2058 | | #ifdef H5_HAVE_PARALLEL |
2059 | | /* Check for unsupported settings in parallel */ |
2060 | | assert(file->shared); |
2061 | | if (H5F_SHARED_HAS_FEATURE(file->shared, H5FD_FEAT_HAS_MPI)) { |
2062 | | int mpi_size = H5F_shared_mpi_get_size(file->shared); |
2063 | | |
2064 | | /* |
2065 | | * While there shouldn't be any problems in general with using page buffering |
2066 | | * with only 1 MPI process, there are still some testing issues to be fixed. |
2067 | | * Until then, page buffering is disabled for any form of parallel access. |
2068 | | */ |
2069 | | if (page_buf_size) { |
2070 | | /* Collective metadata writes are not supported with page buffering */ |
2071 | | if (file->shared->coll_md_write) |
2072 | | HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, FAIL, |
2073 | | "collective metadata writes are not supported with page buffering"); |
2074 | | |
2075 | | /* Temporary: fail file create when page buffering feature is enabled for parallel */ |
2076 | | HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, FAIL, "page buffering is disabled for parallel"); |
2077 | | } |
2078 | | |
2079 | | if (mpi_size > 1) { |
2080 | | if (evict_on_close) |
2081 | | HGOTO_ERROR(H5E_FILE, H5E_UNSUPPORTED, FAIL, |
2082 | | "evict on close is currently not supported in parallel HDF5"); |
2083 | | } |
2084 | | } |
2085 | | #endif |
2086 | | |
2087 | | /* |
2088 | | * Read or write the file superblock, depending on whether the file is |
2089 | | * empty or not. |
2090 | | */ |
2091 | 15 | if (0 == (MAX(H5FD_get_eof(lf, H5FD_MEM_SUPER), H5FD_get_eoa(lf, H5FD_MEM_SUPER))) && |
2092 | 0 | (flags & H5F_ACC_RDWR)) { |
2093 | | /* |
2094 | | * We've just opened a fresh new file (or truncated one). We need |
2095 | | * to create & write the superblock. |
2096 | | */ |
2097 | | |
2098 | | /* Create the page buffer before initializing the superblock */ |
2099 | 0 | if (page_buf_size) |
2100 | 0 | if (H5PB_create(shared, page_buf_size, page_buf_min_meta_perc, page_buf_min_raw_perc) < 0) |
2101 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "unable to create page buffer"); |
2102 | | |
2103 | | /* Initialize information about the superblock and allocate space for it */ |
2104 | | /* (Writes superblock extension messages, if there are any) */ |
2105 | 0 | if (H5F__super_init(file) < 0) |
2106 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "unable to allocate file superblock"); |
2107 | | |
2108 | | /* Create and open the root group */ |
2109 | | /* (This must be after the space for the superblock is allocated in |
2110 | | * the file, since the superblock must be at offset 0) |
2111 | | */ |
2112 | 0 | if (H5G_mkroot(file, true) < 0) |
2113 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "unable to create/open root group"); |
2114 | 0 | } /* end if */ |
2115 | 15 | else if (1 == shared->nrefs) { |
2116 | | /* Read the superblock if it hasn't been read before. */ |
2117 | 15 | if (H5F__super_read(file, a_plist, true) < 0) |
2118 | 9 | HGOTO_ERROR(H5E_FILE, H5E_READERROR, FAIL, "unable to read superblock"); |
2119 | | |
2120 | | /* Skip trying to create a page buffer if the file space strategy |
2121 | | * stored in the superblock isn't paged. |
2122 | | */ |
2123 | 6 | if (shared->fs_strategy != H5F_FSPACE_STRATEGY_PAGE) |
2124 | 6 | page_buf_size = 0; |
2125 | | |
2126 | | /* If the page buffer is enabled, the strategy is paged, and the size in |
2127 | | * the fapl is smaller than the file's page size, bump the page buffer |
2128 | | * size up to the file's page size. |
2129 | | */ |
2130 | 6 | if (page_buf_size > 0 && shared->fs_strategy == H5F_FSPACE_STRATEGY_PAGE && |
2131 | 0 | shared->fs_page_size > page_buf_size) |
2132 | 0 | page_buf_size = shared->fs_page_size; |
2133 | | |
2134 | | /* Create the page buffer *after* reading the superblock */ |
2135 | 6 | if (page_buf_size) |
2136 | 0 | if (H5PB_create(shared, page_buf_size, page_buf_min_meta_perc, page_buf_min_raw_perc) < 0) |
2137 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "unable to create page buffer"); |
2138 | | |
2139 | | /* Open the root group */ |
2140 | 6 | if (H5G_mkroot(file, false) < 0) |
2141 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, FAIL, "unable to read root group"); |
2142 | 6 | } /* end if */ |
2143 | | |
2144 | | /* |
2145 | | * Decide the file close degree. If it's the first time to open the |
2146 | | * file, set the degree to access property list value; if it's the |
2147 | | * second time or later, verify the access property list value matches |
2148 | | * the degree in shared file structure. |
2149 | | */ |
2150 | 6 | if (H5P_get(a_plist, H5F_ACS_CLOSE_DEGREE_NAME, &fc_degree) < 0) |
2151 | 0 | HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get file close degree"); |
2152 | 6 | if (shared->nrefs == 1) { |
2153 | 6 | if (fc_degree == H5F_CLOSE_DEFAULT) |
2154 | 6 | shared->fc_degree = lf->cls->fc_degree; |
2155 | 0 | else |
2156 | 0 | shared->fc_degree = fc_degree; |
2157 | 6 | } /* end if */ |
2158 | 0 | else if (shared->nrefs > 1) { |
2159 | 0 | if (fc_degree == H5F_CLOSE_DEFAULT && shared->fc_degree != lf->cls->fc_degree) |
2160 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "file close degree doesn't match"); |
2161 | 0 | if (fc_degree != H5F_CLOSE_DEFAULT && fc_degree != shared->fc_degree) |
2162 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "file close degree doesn't match"); |
2163 | 0 | } /* end if */ |
2164 | | |
2165 | | /* This is a private property to clear the status_flags in the super block */ |
2166 | | /* Use by h5clear and a routine in test/flush2.c to clear the test file's status_flags */ |
2167 | 6 | if (H5P_exist_plist(a_plist, H5F_ACS_CLEAR_STATUS_FLAGS_NAME) > 0) { |
2168 | 6 | if (H5P_get(a_plist, H5F_ACS_CLEAR_STATUS_FLAGS_NAME, &clear) < 0) |
2169 | 0 | HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get clearance for status_flags"); |
2170 | 6 | else if (clear) |
2171 | 0 | file->shared->sblock->status_flags = 0; |
2172 | 6 | } /* end if */ |
2173 | | |
2174 | | /* Record the evict-on-close MDC behavior. If it's the first time opening |
2175 | | * the file, set it to access property list value; if it's the second time |
2176 | | * or later, verify that the access property list value matches the value |
2177 | | * in shared file structure. |
2178 | | */ |
2179 | 6 | if (shared->nrefs == 1) |
2180 | 6 | shared->evict_on_close = evict_on_close; |
2181 | 0 | else if (shared->nrefs > 1) { |
2182 | 0 | if (shared->evict_on_close != evict_on_close) |
2183 | 0 | HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, FAIL, "file evict-on-close value doesn't match"); |
2184 | 0 | } /* end if */ |
2185 | | |
2186 | | /* Formulate the absolute path for later search of target file for external links */ |
2187 | 6 | if (shared->nrefs == 1) { |
2188 | 6 | if (H5_build_extpath(name, &file->shared->extpath) < 0) |
2189 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "unable to build extpath"); |
2190 | 6 | } |
2191 | | |
2192 | | /* Formulate the actual file name, after following symlinks, etc. */ |
2193 | 6 | if (H5F__build_actual_name(file, a_plist, name, &file->actual_name) < 0) |
2194 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "unable to build actual name"); |
2195 | | |
2196 | 6 | if (set_flag) { |
2197 | 6 | if (H5F_INTENT(file) & H5F_ACC_RDWR) { /* Set and check consistency of status_flags */ |
2198 | | /* Skip check of status_flags for file with < superblock version 3 */ |
2199 | 6 | if (file->shared->sblock->super_vers >= HDF5_SUPERBLOCK_VERSION_3) { |
2200 | |
|
2201 | 0 | if (file->shared->sblock->status_flags & H5F_SUPER_WRITE_ACCESS || |
2202 | 0 | file->shared->sblock->status_flags & H5F_SUPER_SWMR_WRITE_ACCESS) |
2203 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, FAIL, |
2204 | 0 | "file is already open for write/SWMR write (may use <h5clear file> to clear " |
2205 | 0 | "file consistency flags)"); |
2206 | 0 | } /* version 3 superblock */ |
2207 | | |
2208 | 6 | file->shared->sblock->status_flags |= H5F_SUPER_WRITE_ACCESS; |
2209 | 6 | if (H5F_INTENT(file) & H5F_ACC_SWMR_WRITE) |
2210 | 0 | file->shared->sblock->status_flags |= H5F_SUPER_SWMR_WRITE_ACCESS; |
2211 | | |
2212 | | /* Flush the superblock & superblock extension */ |
2213 | 6 | if (H5F_super_dirty(file) < 0) |
2214 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTMARKDIRTY, FAIL, "unable to mark superblock as dirty"); |
2215 | 6 | if (H5F_flush_tagged_metadata(file, H5AC__SUPERBLOCK_TAG) < 0) |
2216 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTFLUSH, FAIL, "unable to flush superblock"); |
2217 | 6 | if (H5F_flush_tagged_metadata(file, file->shared->sblock->ext_addr) < 0) |
2218 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTFLUSH, FAIL, "unable to flush superblock extension"); |
2219 | | |
2220 | | /* Remove the file lock for SWMR_WRITE */ |
2221 | 6 | if (use_file_locking && (H5F_INTENT(file) & H5F_ACC_SWMR_WRITE)) { |
2222 | 0 | if (H5FD_unlock(file->shared->lf) < 0) |
2223 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTUNLOCKFILE, FAIL, "unable to unlock the file"); |
2224 | 0 | } /* end if */ |
2225 | 6 | } /* end if */ |
2226 | 0 | else { /* H5F_ACC_RDONLY: check consistency of status_flags */ |
2227 | | /* Skip check of status_flags for file with < superblock version 3 */ |
2228 | 0 | if (file->shared->sblock->super_vers >= HDF5_SUPERBLOCK_VERSION_3) { |
2229 | 0 | if (H5F_INTENT(file) & H5F_ACC_SWMR_READ) { |
2230 | 0 | if ((file->shared->sblock->status_flags & H5F_SUPER_WRITE_ACCESS && |
2231 | 0 | !(file->shared->sblock->status_flags & H5F_SUPER_SWMR_WRITE_ACCESS)) || |
2232 | 0 | (!(file->shared->sblock->status_flags & H5F_SUPER_WRITE_ACCESS) && |
2233 | 0 | file->shared->sblock->status_flags & H5F_SUPER_SWMR_WRITE_ACCESS)) |
2234 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, FAIL, |
2235 | 0 | "file is not already open for SWMR writing"); |
2236 | 0 | } /* end if */ |
2237 | 0 | else if ((file->shared->sblock->status_flags & H5F_SUPER_WRITE_ACCESS) || |
2238 | 0 | (file->shared->sblock->status_flags & H5F_SUPER_SWMR_WRITE_ACCESS)) |
2239 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, FAIL, |
2240 | 0 | "file is already open for write (may use <h5clear file> to clear file " |
2241 | 0 | "consistency flags)"); |
2242 | 0 | } /* version 3 superblock */ |
2243 | 0 | } /* end else */ |
2244 | 6 | } /* end if set_flag */ |
2245 | | |
2246 | | /* Set 'out' parameter */ |
2247 | 6 | *_file = file; |
2248 | | |
2249 | 15 | done: |
2250 | 15 | if (ret_value < 0 && file) |
2251 | 9 | if (H5F__dest(file, false, true) < 0) |
2252 | 0 | HDONE_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "problems closing file"); |
2253 | | |
2254 | 15 | FUNC_LEAVE_NOAPI(ret_value) |
2255 | 15 | } /* end H5F_open() */ |
2256 | | |
2257 | | /*------------------------------------------------------------------------- |
2258 | | * Function: H5F__post_open |
2259 | | * |
2260 | | * Purpose: Finishes file open after wrapper context for file has been |
2261 | | * set. |
2262 | | * |
2263 | | * Return: SUCCEED/FAIL |
2264 | | * |
2265 | | *------------------------------------------------------------------------- |
2266 | | */ |
2267 | | herr_t |
2268 | | H5F__post_open(H5F_t *f) |
2269 | 6 | { |
2270 | 6 | herr_t ret_value = SUCCEED; /* Return value */ |
2271 | | |
2272 | 6 | FUNC_ENTER_PACKAGE |
2273 | | |
2274 | | /* Sanity check arguments */ |
2275 | 6 | assert(f); |
2276 | | |
2277 | | /* Store a vol object in the file struct */ |
2278 | 6 | if (NULL == (f->vol_obj = H5VL_new_vol_obj(H5I_FILE, f, f->shared->vol_conn, true))) |
2279 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "can't create VOL object"); |
2280 | | |
2281 | 6 | done: |
2282 | 6 | FUNC_LEAVE_NOAPI(ret_value) |
2283 | 6 | } /* end H5F__post_open() */ |
2284 | | |
2285 | | /*------------------------------------------------------------------------- |
2286 | | * Function: H5F_flush_phase1 |
2287 | | * |
2288 | | * Purpose: First phase of flushing cached data. |
2289 | | * |
2290 | | * Return: SUCCEED/FAIL |
2291 | | * |
2292 | | *------------------------------------------------------------------------- |
2293 | | */ |
2294 | | static herr_t |
2295 | | H5F__flush_phase1(H5F_t *f) |
2296 | 6 | { |
2297 | 6 | herr_t ret_value = SUCCEED; /* Return value */ |
2298 | | |
2299 | 6 | FUNC_ENTER_PACKAGE |
2300 | | |
2301 | | /* Sanity check arguments */ |
2302 | 6 | assert(f); |
2303 | | |
2304 | | /* Flush any cached dataset storage raw data */ |
2305 | 6 | if (H5D_flush_all(f) < 0) |
2306 | | /* Push error, but keep going*/ |
2307 | 0 | HDONE_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "unable to flush dataset cache"); |
2308 | | |
2309 | | /* Release any space allocated to space aggregators, so that the eoa value |
2310 | | * corresponds to the end of the space written to in the file. |
2311 | | */ |
2312 | | /* (needs to happen before cache flush, with superblock write, since the |
2313 | | * 'eoa' value is written in superblock -QAK) |
2314 | | */ |
2315 | 6 | if (H5MF_free_aggrs(f) < 0) |
2316 | | /* Push error, but keep going*/ |
2317 | 0 | HDONE_ERROR(H5E_FILE, H5E_CANTRELEASE, FAIL, "can't release file space"); |
2318 | | |
2319 | 6 | FUNC_LEAVE_NOAPI(ret_value) |
2320 | 6 | } /* end H5F__flush_phase1() */ |
2321 | | |
2322 | | /*------------------------------------------------------------------------- |
2323 | | * Function: H5F__flush_phase2 |
2324 | | * |
2325 | | * Purpose: Second phase of flushing cached data. |
2326 | | * |
2327 | | * Return: SUCCEED/FAIL |
2328 | | * |
2329 | | *------------------------------------------------------------------------- |
2330 | | */ |
2331 | | static herr_t |
2332 | | H5F__flush_phase2(H5F_t *f, bool closing) |
2333 | 6 | { |
2334 | 6 | herr_t ret_value = SUCCEED; /* Return value */ |
2335 | | |
2336 | 6 | FUNC_ENTER_PACKAGE |
2337 | | |
2338 | | /* Sanity check arguments */ |
2339 | 6 | assert(f); |
2340 | | |
2341 | | /* Inform the metadata cache that we are about to flush */ |
2342 | 6 | if (H5AC_prep_for_file_flush(f) < 0) |
2343 | | /* Push error, but keep going*/ |
2344 | 0 | HDONE_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "prep for MDC flush failed"); |
2345 | | |
2346 | | /* Flush the entire metadata cache */ |
2347 | 6 | if (H5AC_flush(f) < 0) |
2348 | | /* Push error, but keep going*/ |
2349 | 0 | HDONE_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "unable to flush metadata cache"); |
2350 | | |
2351 | | #ifdef H5_HAVE_PARALLEL |
2352 | | if (H5F_HAS_FEATURE(f, H5FD_FEAT_HAS_MPI)) { |
2353 | | /* Since we just returned from a call to H5AC_flush(), we just |
2354 | | * passed through a barrier. Hence we can skip the barrier on |
2355 | | * entry to the mpio file driver truncate call below, and the first |
2356 | | * barrier in the following call to flush the cache again. |
2357 | | */ |
2358 | | H5CX_set_mpi_file_flushing(true); |
2359 | | } |
2360 | | #endif /* H5_HAVE_PARALLEL */ |
2361 | | |
2362 | | /* Truncate the file to the current allocated size */ |
2363 | 6 | if (H5FD_truncate(f->shared->lf, closing) < 0) |
2364 | | /* Push error, but keep going*/ |
2365 | 0 | HDONE_ERROR(H5E_FILE, H5E_WRITEERROR, FAIL, "low level truncate failed"); |
2366 | | |
2367 | | /* Flush the entire metadata cache again since the EOA could have changed in the truncate call. */ |
2368 | 6 | if (H5AC_flush(f) < 0) |
2369 | | /* Push error, but keep going*/ |
2370 | 0 | HDONE_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "unable to flush metadata cache"); |
2371 | | |
2372 | | #ifdef H5_HAVE_PARALLEL |
2373 | | if (H5F_HAS_FEATURE(f, H5FD_FEAT_HAS_MPI)) |
2374 | | /* Reset the "flushing the file" flag */ |
2375 | | H5CX_set_mpi_file_flushing(false); |
2376 | | #endif /* H5_HAVE_PARALLEL */ |
2377 | | |
2378 | | /* Inform the metadata cache that we are done with the flush */ |
2379 | 6 | if (H5AC_secure_from_file_flush(f) < 0) |
2380 | | /* Push error, but keep going*/ |
2381 | 0 | HDONE_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "secure from MDC flush failed"); |
2382 | | |
2383 | | /* Flush out the metadata accumulator */ |
2384 | 6 | if (H5F__accum_flush(f->shared) < 0) |
2385 | | /* Push error, but keep going*/ |
2386 | 0 | HDONE_ERROR(H5E_IO, H5E_CANTFLUSH, FAIL, "unable to flush metadata accumulator"); |
2387 | | |
2388 | | /* Flush the page buffer */ |
2389 | 6 | if (H5PB_flush(f->shared) < 0) |
2390 | | /* Push error, but keep going*/ |
2391 | 0 | HDONE_ERROR(H5E_IO, H5E_CANTFLUSH, FAIL, "page buffer flush failed"); |
2392 | | |
2393 | | /* Flush file buffers to disk. */ |
2394 | 6 | if (H5FD_flush(f->shared->lf, closing) < 0) |
2395 | | /* Push error, but keep going*/ |
2396 | 0 | HDONE_ERROR(H5E_IO, H5E_CANTFLUSH, FAIL, "low level flush failed"); |
2397 | | |
2398 | 6 | FUNC_LEAVE_NOAPI(ret_value) |
2399 | 6 | } /* end H5F__flush_phase2() */ |
2400 | | |
2401 | | /*------------------------------------------------------------------------- |
2402 | | * Function: H5F__flush |
2403 | | * |
2404 | | * Purpose: Flushes cached data. |
2405 | | * |
2406 | | * Return: SUCCEED/FAIL |
2407 | | * |
2408 | | *------------------------------------------------------------------------- |
2409 | | */ |
2410 | | herr_t |
2411 | | H5F__flush(H5F_t *f) |
2412 | 0 | { |
2413 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
2414 | |
|
2415 | 0 | FUNC_ENTER_PACKAGE |
2416 | | |
2417 | | /* Sanity check arguments */ |
2418 | 0 | assert(f); |
2419 | | |
2420 | | /* First phase of flushing data */ |
2421 | 0 | if (H5F__flush_phase1(f) < 0) |
2422 | | /* Push error, but keep going*/ |
2423 | 0 | HDONE_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "unable to flush file data"); |
2424 | | |
2425 | | /* Second phase of flushing data */ |
2426 | 0 | if (H5F__flush_phase2(f, false) < 0) |
2427 | | /* Push error, but keep going*/ |
2428 | 0 | HDONE_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "unable to flush file data"); |
2429 | |
|
2430 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
2431 | 0 | } /* end H5F__flush() */ |
2432 | | |
2433 | | /*------------------------------------------------------------------------- |
2434 | | * Function: H5F__close |
2435 | | * |
2436 | | * Purpose: Closes a file or causes the close operation to be pended. |
2437 | | * This function is called two ways: from the API it gets called |
2438 | | * by H5Fclose->H5I_dec_ref->H5F__close when H5I_dec_ref() |
2439 | | * decrements the file ID reference count to zero. The file ID |
2440 | | * is removed from the H5I_FILE group by H5I_dec_ref() just |
2441 | | * before H5F__close() is called. If there are open object |
2442 | | * headers then the close is pended by moving the file to the |
2443 | | * H5I_FILE_CLOSING ID group (the f->closing contains the ID |
2444 | | * assigned to file). |
2445 | | * |
2446 | | * This function is also called directly from H5O_close() when |
2447 | | * the last object header is closed for the file and the file |
2448 | | * has a pending close. |
2449 | | * |
2450 | | * Return: SUCCEED/FAIL |
2451 | | * |
2452 | | *------------------------------------------------------------------------- |
2453 | | */ |
2454 | | herr_t |
2455 | | H5F__close(H5F_t *f) |
2456 | 6 | { |
2457 | 6 | herr_t ret_value = SUCCEED; /* Return value */ |
2458 | | |
2459 | 6 | FUNC_ENTER_PACKAGE |
2460 | | |
2461 | | /* Sanity check */ |
2462 | 6 | assert(f); |
2463 | | |
2464 | | /* Perform checks for "semi" file close degree here, since closing the |
2465 | | * file is not allowed if there are objects still open. |
2466 | | */ |
2467 | 6 | if (f->shared->fc_degree == H5F_CLOSE_SEMI) { |
2468 | 0 | unsigned nopen_files = 0; /* Number of open files in file/mount hierarchy */ |
2469 | 0 | unsigned nopen_objs = 0; /* Number of open objects in file/mount hierarchy */ |
2470 | | |
2471 | | /* Get the number of open objects and open files on this file/mount hierarchy */ |
2472 | 0 | if (H5F__mount_count_ids(f, &nopen_files, &nopen_objs) < 0) |
2473 | 0 | HGOTO_ERROR(H5E_SYM, H5E_MOUNT, FAIL, "problem checking mount hierarchy"); |
2474 | | |
2475 | | /* If there are no other file IDs open on this file/mount hier., but |
2476 | | * there are still open objects, issue an error and bail out now, |
2477 | | * without decrementing the file ID's reference count and triggering |
2478 | | * a "real" attempt at closing the file. |
2479 | | */ |
2480 | 0 | if (nopen_files == 1 && nopen_objs > 0) |
2481 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "can't close file, there are objects still open"); |
2482 | 0 | } |
2483 | | |
2484 | | /* Reset the file ID for this file */ |
2485 | 6 | f->id_exists = false; |
2486 | | |
2487 | | /* Attempt to close the file/mount hierarchy */ |
2488 | 6 | if (H5F_try_close(f, NULL) < 0) |
2489 | 6 | HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "can't close file"); |
2490 | | |
2491 | 6 | done: |
2492 | 6 | FUNC_LEAVE_NOAPI(ret_value) |
2493 | 6 | } /* end H5F__close() */ |
2494 | | |
2495 | | /*------------------------------------------------------------------------- |
2496 | | * Function: H5F_delete |
2497 | | * |
2498 | | * Purpose: Deletes a file. |
2499 | | * |
2500 | | * Return: SUCCEED/FAIL |
2501 | | *------------------------------------------------------------------------- |
2502 | | */ |
2503 | | herr_t |
2504 | | H5F__delete(const char *filename, hid_t fapl_id) |
2505 | 0 | { |
2506 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
2507 | |
|
2508 | 0 | FUNC_ENTER_PACKAGE |
2509 | |
|
2510 | 0 | assert(filename); |
2511 | | |
2512 | | /* Delete the file */ |
2513 | 0 | if (H5FD_delete(filename, fapl_id) < 0) |
2514 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTDELETEFILE, FAIL, "unable to delete file"); |
2515 | | |
2516 | 0 | done: |
2517 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
2518 | 0 | } /* end H5F__delete() */ |
2519 | | |
2520 | | /*------------------------------------------------------------------------- |
2521 | | * Function: H5F_try_close |
2522 | | * |
2523 | | * Purpose: Attempts to close a file due to one of several actions: |
2524 | | * - The reference count on the file ID dropped to zero |
2525 | | * - The last open object was closed in the file |
2526 | | * - The file was unmounted |
2527 | | * |
2528 | | * Return: SUCCEED/FAIL |
2529 | | * |
2530 | | *------------------------------------------------------------------------- |
2531 | | */ |
2532 | | herr_t |
2533 | | H5F_try_close(H5F_t *f, bool *was_closed /*out*/) |
2534 | 6 | { |
2535 | 6 | unsigned nopen_files = 0; /* Number of open files in file/mount hierarchy */ |
2536 | 6 | unsigned nopen_objs = 0; /* Number of open objects in file/mount hierarchy */ |
2537 | 6 | herr_t ret_value = SUCCEED; /* Return value */ |
2538 | | |
2539 | 6 | FUNC_ENTER_NOAPI_NOINIT |
2540 | | |
2541 | | /* Sanity check */ |
2542 | 6 | assert(f); |
2543 | 6 | assert(f->shared); |
2544 | | |
2545 | | /* Set the was_closed flag to the default value. |
2546 | | * This flag lets downstream code know if the file struct is |
2547 | | * still accessible and/or likely to contain useful data. |
2548 | | * It's needed by the evict-on-close code. Clients can ignore |
2549 | | * this value by passing in NULL. |
2550 | | */ |
2551 | 6 | if (was_closed) |
2552 | 0 | *was_closed = false; |
2553 | | |
2554 | | /* Check if this file is already in the process of closing */ |
2555 | 6 | if (f->closing) { |
2556 | 0 | if (was_closed) |
2557 | 0 | *was_closed = true; |
2558 | 0 | HGOTO_DONE(SUCCEED); |
2559 | 0 | } |
2560 | | |
2561 | | /* Get the number of open objects and open files on this file/mount hierarchy */ |
2562 | 6 | if (H5F__mount_count_ids(f, &nopen_files, &nopen_objs) < 0) |
2563 | 0 | HGOTO_ERROR(H5E_SYM, H5E_MOUNT, FAIL, "problem checking mount hierarchy"); |
2564 | | |
2565 | | /* |
2566 | | * Close file according to close degree: |
2567 | | * |
2568 | | * H5F_CLOSE_WEAK: if there are still objects open, wait until |
2569 | | * they are all closed. |
2570 | | * H5F_CLOSE_SEMI: if there are still objects open, return fail; |
2571 | | * otherwise, close file. |
2572 | | * H5F_CLOSE_STRONG: if there are still objects open, close them |
2573 | | * first, then close file. |
2574 | | */ |
2575 | 6 | switch (f->shared->fc_degree) { |
2576 | 6 | case H5F_CLOSE_WEAK: |
2577 | | /* |
2578 | | * If file or object IDS are still open then delay deletion of |
2579 | | * resources until they have all been closed. Flush all |
2580 | | * caches and update the object header anyway so that failing to |
2581 | | * close all objects isn't a major problem. |
2582 | | */ |
2583 | 6 | if ((nopen_files + nopen_objs) > 0) |
2584 | 0 | HGOTO_DONE(SUCCEED); |
2585 | 6 | break; |
2586 | | |
2587 | 6 | case H5F_CLOSE_SEMI: |
2588 | | /* Can leave safely if file IDs are still open on this file */ |
2589 | 0 | if (nopen_files > 0) |
2590 | 0 | HGOTO_DONE(SUCCEED); |
2591 | | |
2592 | | /* Sanity check: If close degree if "semi" and we have gotten this |
2593 | | * far and there are objects left open, bail out now. |
2594 | | */ |
2595 | 0 | assert(nopen_files == 0 && nopen_objs == 0); |
2596 | | |
2597 | | /* If we've gotten this far (ie. there are no open objects in the file), fall through to flush & |
2598 | | * close */ |
2599 | 0 | break; |
2600 | | |
2601 | 0 | case H5F_CLOSE_STRONG: |
2602 | | /* If there are other open files in the hierarchy, we can leave now */ |
2603 | 0 | if (nopen_files > 0) |
2604 | 0 | HGOTO_DONE(SUCCEED); |
2605 | | |
2606 | | /* If we've gotten this far (ie. there are no open file IDs in the file/mount hierarchy), fall |
2607 | | * through to flush & close */ |
2608 | 0 | break; |
2609 | | |
2610 | 0 | case H5F_CLOSE_DEFAULT: |
2611 | 0 | default: |
2612 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "can't close file, unknown file close degree"); |
2613 | 6 | } /* end switch */ |
2614 | | |
2615 | | /* Mark this file as closing (prevents re-entering file shutdown code below) */ |
2616 | 6 | f->closing = true; |
2617 | | |
2618 | | /* If the file close degree is "strong", close all the open objects in this file */ |
2619 | 6 | if (f->shared->fc_degree == H5F_CLOSE_STRONG) { |
2620 | 0 | assert(nopen_files == 0); |
2621 | | |
2622 | | /* Forced close of all opened objects in this file */ |
2623 | 0 | if (f->nopen_objs > 0) { |
2624 | 0 | size_t obj_count; /* # of open objects */ |
2625 | 0 | hid_t objs[128]; /* Array of objects to close */ |
2626 | 0 | herr_t result; /* Local result from obj ID query */ |
2627 | 0 | size_t u; /* Local index variable */ |
2628 | | |
2629 | | /* Get the list of IDs of open dataset, group, & attribute objects */ |
2630 | 0 | while ((result = H5F_get_obj_ids( |
2631 | 0 | f, H5F_OBJ_LOCAL | H5F_OBJ_DATASET | H5F_OBJ_GROUP | H5F_OBJ_ATTR, |
2632 | 0 | (int)(sizeof(objs) / sizeof(objs[0])), objs, false, &obj_count)) <= 0 && |
2633 | 0 | obj_count != 0) { |
2634 | | |
2635 | | /* Try to close all the open objects in this file */ |
2636 | 0 | for (u = 0; u < obj_count; u++) |
2637 | 0 | if (H5I_dec_ref(objs[u]) < 0) |
2638 | 0 | HGOTO_ERROR(H5E_ID, H5E_CLOSEERROR, FAIL, "can't close object"); |
2639 | 0 | } |
2640 | 0 | if (result < 0) |
2641 | 0 | HGOTO_ERROR(H5E_FILE, H5E_BADITER, FAIL, "H5F_get_obj_ids failed(1)"); |
2642 | | |
2643 | | /* Get the list of IDs of open named datatype objects */ |
2644 | | /* (Do this separately from the dataset & attribute IDs, because |
2645 | | * they could be using one of the named datatypes and then the |
2646 | | * open named datatype ID will get closed twice) |
2647 | | */ |
2648 | 0 | while ((result = H5F_get_obj_ids(f, H5F_OBJ_LOCAL | H5F_OBJ_DATATYPE, |
2649 | 0 | (int)(sizeof(objs) / sizeof(objs[0])), objs, false, |
2650 | 0 | &obj_count)) <= 0 && |
2651 | 0 | obj_count != 0) { |
2652 | | |
2653 | | /* Try to close all the open objects in this file */ |
2654 | 0 | for (u = 0; u < obj_count; u++) |
2655 | 0 | if (H5I_dec_ref(objs[u]) < 0) |
2656 | 0 | HGOTO_ERROR(H5E_ID, H5E_CLOSEERROR, FAIL, "can't close object"); |
2657 | 0 | } |
2658 | 0 | if (result < 0) |
2659 | 0 | HGOTO_ERROR(H5E_INTERNAL, H5E_BADITER, FAIL, "H5F_get_obj_ids failed(2)"); |
2660 | 0 | } /* end if */ |
2661 | 0 | } /* end if */ |
2662 | | |
2663 | | /* Check if this is a child file in a mounting hierarchy & proceed up the |
2664 | | * hierarchy if so. |
2665 | | */ |
2666 | 6 | if (f->parent) |
2667 | 0 | if (H5F_try_close(f->parent, NULL) < 0) |
2668 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "can't close parent file"); |
2669 | | |
2670 | | /* Unmount and close each child before closing the current file. */ |
2671 | 6 | if (H5F__close_mounts(f) < 0) |
2672 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "can't unmount child files"); |
2673 | | |
2674 | | /* If there is more than one reference to the shared file struct and the |
2675 | | * file has an external file cache, we should see if it can be closed. This |
2676 | | * can happen if a cycle is formed with external file caches. |
2677 | | */ |
2678 | 6 | if (f->shared->efc && (f->shared->nrefs > 1)) |
2679 | 0 | if (H5F__efc_try_close(f) < 0) |
2680 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTRELEASE, FAIL, "can't attempt to close EFC"); |
2681 | | |
2682 | | /* Destroy the H5F_t struct and decrement the reference count for the |
2683 | | * shared H5F_shared_t struct. If the reference count for the H5F_shared_t |
2684 | | * struct reaches zero then destroy it also. |
2685 | | */ |
2686 | 6 | if (H5F__dest(f, true, false) < 0) |
2687 | 6 | HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "problems closing file"); |
2688 | | |
2689 | | /* Since we closed the file, this should be set to true */ |
2690 | 0 | if (was_closed) |
2691 | 0 | *was_closed = true; |
2692 | 6 | done: |
2693 | 6 | FUNC_LEAVE_NOAPI(ret_value) |
2694 | 6 | } /* end H5F_try_close() */ |
2695 | | |
2696 | | /*------------------------------------------------------------------------- |
2697 | | * Function: H5F__reopen |
2698 | | * |
2699 | | * Purpose: Reopen a file. The new file handle which is returned points |
2700 | | * to the same file as the specified file handle. Both handles |
2701 | | * share caches and other information. The only difference |
2702 | | * between the handles is that the new handle is not mounted |
2703 | | * anywhere and no files are mounted on it. |
2704 | | * |
2705 | | * Return: Success: A pointer to a file struct |
2706 | | * |
2707 | | * Failure: NULL |
2708 | | * |
2709 | | *------------------------------------------------------------------------- |
2710 | | */ |
2711 | | H5F_t * |
2712 | | H5F__reopen(H5F_t *f) |
2713 | 0 | { |
2714 | 0 | H5F_t *ret_value = NULL; /* Return value */ |
2715 | |
|
2716 | 0 | FUNC_ENTER_PACKAGE |
2717 | | |
2718 | | /* Get a new "top level" file struct, sharing the same "low level" file struct */ |
2719 | 0 | if (NULL == (ret_value = H5F__new(f->shared, 0, H5P_FILE_CREATE_DEFAULT, H5P_FILE_ACCESS_DEFAULT, NULL))) |
2720 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, NULL, "unable to reopen file"); |
2721 | | |
2722 | | /* Duplicate old file's names */ |
2723 | 0 | ret_value->open_name = H5MM_xstrdup(f->open_name); |
2724 | 0 | ret_value->actual_name = H5MM_xstrdup(f->actual_name); |
2725 | |
|
2726 | 0 | done: |
2727 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
2728 | 0 | } /* end H5F__reopen() */ |
2729 | | |
2730 | | /*------------------------------------------------------------------------- |
2731 | | * Function: H5F_get_id |
2732 | | * |
2733 | | * Purpose: Get the file ID, incrementing it, or "resurrecting" it as |
2734 | | * appropriate. |
2735 | | * |
2736 | | * Return: Success: An ID for a file |
2737 | | * |
2738 | | * Failure: H5I_INVALID_HID |
2739 | | * |
2740 | | *------------------------------------------------------------------------- |
2741 | | */ |
2742 | | hid_t |
2743 | | H5F_get_id(H5F_t *file) |
2744 | 0 | { |
2745 | 0 | hid_t ret_value = H5I_INVALID_HID; /* Return value */ |
2746 | |
|
2747 | 0 | FUNC_ENTER_NOAPI_NOINIT |
2748 | |
|
2749 | 0 | assert(file); |
2750 | |
|
2751 | 0 | if (H5I_find_id(file, H5I_FILE, &ret_value) < 0 || H5I_INVALID_HID == ret_value) { |
2752 | | /* resurrect the ID - Register an ID with the native connector */ |
2753 | 0 | if ((ret_value = H5VL_wrap_register(H5I_FILE, file, false)) < 0) |
2754 | 0 | HGOTO_ERROR(H5E_ID, H5E_CANTREGISTER, H5I_INVALID_HID, "unable to register group"); |
2755 | 0 | file->id_exists = true; |
2756 | 0 | } |
2757 | 0 | else { |
2758 | | /* Increment reference count on existing ID */ |
2759 | 0 | if (H5I_inc_ref(ret_value, false) < 0) |
2760 | 0 | HGOTO_ERROR(H5E_ID, H5E_CANTINC, H5I_INVALID_HID, "incrementing file ID failed"); |
2761 | 0 | } /* end else */ |
2762 | | |
2763 | 0 | done: |
2764 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
2765 | 0 | } /* end H5F_get_id() */ |
2766 | | |
2767 | | /*------------------------------------------------------------------------- |
2768 | | * Function: H5F_incr_nopen_objs |
2769 | | * |
2770 | | * Purpose: Increment the number of open objects for a file. |
2771 | | * |
2772 | | * Return: Success: The number of open objects, after the increment |
2773 | | * Failure: (can't happen) |
2774 | | *------------------------------------------------------------------------- |
2775 | | */ |
2776 | | unsigned |
2777 | | H5F_incr_nopen_objs(H5F_t *f) |
2778 | 6 | { |
2779 | | /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */ |
2780 | 6 | FUNC_ENTER_NOAPI_NOINIT_NOERR |
2781 | | |
2782 | 6 | assert(f); |
2783 | | |
2784 | 6 | FUNC_LEAVE_NOAPI(++f->nopen_objs) |
2785 | 6 | } /* end H5F_incr_nopen_objs() */ |
2786 | | |
2787 | | /*------------------------------------------------------------------------- |
2788 | | * Function: H5F_decr_nopen_objs |
2789 | | * |
2790 | | * Purpose: Decrement the number of open objects for a file. |
2791 | | * |
2792 | | * Return: Success: The number of open objects, after the decrement |
2793 | | * Failure: (can't happen) |
2794 | | *------------------------------------------------------------------------- |
2795 | | */ |
2796 | | unsigned |
2797 | | H5F_decr_nopen_objs(H5F_t *f) |
2798 | 0 | { |
2799 | | /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */ |
2800 | 0 | FUNC_ENTER_NOAPI_NOINIT_NOERR |
2801 | |
|
2802 | 0 | assert(f); |
2803 | |
|
2804 | 0 | FUNC_LEAVE_NOAPI(--f->nopen_objs) |
2805 | 0 | } /* end H5F_decr_nopen_objs() */ |
2806 | | |
2807 | | /*------------------------------------------------------------------------- |
2808 | | * Function: H5F__build_actual_name |
2809 | | * |
2810 | | * Purpose: Retrieve the name of a file, after following symlinks, etc. |
2811 | | * |
2812 | | * Note: Currently only working for "POSIX I/O compatible" VFDs |
2813 | | * |
2814 | | * Return: SUCCEED/FAIL |
2815 | | *------------------------------------------------------------------------- |
2816 | | */ |
2817 | | static herr_t |
2818 | | H5F__build_actual_name(const H5F_t *f, const H5P_genplist_t *fapl, const char *name, |
2819 | | char **actual_name /*out*/) |
2820 | 6 | { |
2821 | 6 | hid_t new_fapl_id = H5I_INVALID_HID; /* ID for duplicated FAPL */ |
2822 | 6 | #ifdef H5_HAVE_SYMLINK |
2823 | | /* This has to be declared here to avoid unfreed resources on errors */ |
2824 | 6 | char *realname = NULL; /* Fully resolved path name of file */ |
2825 | 6 | #endif /* H5_HAVE_SYMLINK */ |
2826 | 6 | herr_t ret_value = SUCCEED; /* Return value */ |
2827 | | |
2828 | 6 | FUNC_ENTER_PACKAGE |
2829 | | |
2830 | | /* Sanity check */ |
2831 | 6 | assert(f); |
2832 | 6 | assert(fapl); |
2833 | 6 | assert(name); |
2834 | 6 | assert(actual_name); |
2835 | | |
2836 | | /* Clear actual name pointer to begin with */ |
2837 | 6 | *actual_name = NULL; |
2838 | | |
2839 | | /* Assume that if the OS can't create symlinks, that we don't need to worry |
2840 | | * about resolving them either. -QAK |
2841 | | */ |
2842 | 6 | #ifdef H5_HAVE_SYMLINK |
2843 | | /* Check for POSIX I/O compatible file handle */ |
2844 | 6 | if (H5F_HAS_FEATURE(f, H5FD_FEAT_POSIX_COMPAT_HANDLE)) { |
2845 | 6 | h5_stat_t lst; /* Stat info from lstat() call */ |
2846 | | |
2847 | | /* Call lstat() on the file's name */ |
2848 | 6 | memset(&lst, 0, sizeof(h5_stat_t)); |
2849 | 6 | if (HDlstat(name, &lst) < 0) |
2850 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "can't retrieve stat info for file"); |
2851 | | |
2852 | | /* Check for symbolic link */ |
2853 | 6 | if (S_IFLNK == (lst.st_mode & S_IFMT)) { |
2854 | 0 | H5P_genplist_t *new_fapl; /* Duplicated FAPL */ |
2855 | 0 | int *fd; /* POSIX I/O file descriptor */ |
2856 | 0 | h5_stat_t st; /* Stat info from stat() call */ |
2857 | 0 | h5_stat_t fst; /* Stat info from fstat() call */ |
2858 | 0 | bool want_posix_fd; /* Flag for retrieving file descriptor from VFD */ |
2859 | | |
2860 | | /* Allocate realname buffer */ |
2861 | 0 | if (NULL == (realname = (char *)H5MM_calloc((size_t)PATH_MAX * sizeof(char)))) |
2862 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed"); |
2863 | | |
2864 | | /* Perform a sanity check that the file or link wasn't switched |
2865 | | * between when we opened it and when we called lstat(). This is |
2866 | | * according to the security best practices for lstat() documented |
2867 | | * here: |
2868 | | * https://www.securecoding.cert.org/confluence/display/seccode/POS35-C.+Avoid+race+conditions+while+checking+for+the+existence+of+a+symbolic+link |
2869 | | */ |
2870 | | |
2871 | | /* Copy the FAPL object to modify */ |
2872 | 0 | if ((new_fapl_id = H5P_copy_plist(fapl, false)) < 0) |
2873 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTCOPY, FAIL, "unable to copy file access property list"); |
2874 | 0 | if (NULL == (new_fapl = (H5P_genplist_t *)H5I_object(new_fapl_id))) |
2875 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTCREATE, FAIL, "can't get property list"); |
2876 | | |
2877 | | /* |
2878 | | * Set the private property for retrieving the backing store |
2879 | | * POSIX file descriptor from the Core VFD |
2880 | | */ |
2881 | 0 | want_posix_fd = true; |
2882 | 0 | if (H5P_set(new_fapl, H5F_ACS_WANT_POSIX_FD_NAME, &want_posix_fd) < 0) |
2883 | 0 | HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, |
2884 | 0 | "can't set property for retrieving file descriptor"); |
2885 | | |
2886 | | /* Retrieve the file handle */ |
2887 | 0 | if (H5F_get_vfd_handle(f, new_fapl_id, (void **)&fd) < 0) |
2888 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "can't retrieve POSIX file descriptor"); |
2889 | | |
2890 | | /* Stat the filename we're resolving */ |
2891 | 0 | memset(&st, 0, sizeof(h5_stat_t)); |
2892 | 0 | if (HDstat(name, &st) < 0) |
2893 | 0 | HSYS_GOTO_ERROR(H5E_FILE, H5E_BADFILE, FAIL, "unable to stat file"); |
2894 | | |
2895 | | /* Stat the file we opened */ |
2896 | 0 | memset(&fst, 0, sizeof(h5_stat_t)); |
2897 | 0 | if (HDfstat(*fd, &fst) < 0) |
2898 | 0 | HSYS_GOTO_ERROR(H5E_FILE, H5E_BADFILE, FAIL, "unable to fstat file"); |
2899 | | |
2900 | | /* Verify that the files are really the same */ |
2901 | 0 | if (st.st_mode != fst.st_mode || st.st_ino != fst.st_ino || st.st_dev != fst.st_dev) |
2902 | 0 | HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, FAIL, "files' st_ino or st_dev fields changed!"); |
2903 | | |
2904 | | /* Get the resolved path for the file name */ |
2905 | 0 | if (NULL == HDrealpath(name, realname)) |
2906 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "can't retrieve real path for file"); |
2907 | | |
2908 | | /* Duplicate the resolved path for the file name */ |
2909 | 0 | if (NULL == (*actual_name = (char *)H5MM_strdup(realname))) |
2910 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTALLOC, FAIL, "can't duplicate real path"); |
2911 | 0 | } /* end if */ |
2912 | 6 | } /* end if */ |
2913 | 6 | #endif /* H5_HAVE_SYMLINK */ |
2914 | | |
2915 | | /* Check if we've resolved the file's name */ |
2916 | 6 | if (NULL == *actual_name) { |
2917 | | /* Just duplicate the name used to open the file */ |
2918 | 6 | if (NULL == (*actual_name = (char *)H5MM_strdup(name))) |
2919 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTALLOC, FAIL, "can't duplicate open name"); |
2920 | 6 | } /* end else */ |
2921 | | |
2922 | 6 | done: |
2923 | | /* Close the property list */ |
2924 | 6 | if (new_fapl_id > 0) |
2925 | 0 | if (H5I_dec_app_ref(new_fapl_id) < 0) |
2926 | 0 | HDONE_ERROR(H5E_FILE, H5E_CANTCLOSEOBJ, FAIL, "can't close duplicated FAPL"); |
2927 | 6 | #ifdef H5_HAVE_SYMLINK |
2928 | 6 | if (realname) |
2929 | 0 | realname = (char *)H5MM_xfree(realname); |
2930 | 6 | #endif /* H5_HAVE_SYMLINK */ |
2931 | | |
2932 | 6 | FUNC_LEAVE_NOAPI(ret_value) |
2933 | 6 | } /* H5F__build_actual_name() */ |
2934 | | |
2935 | | /*------------------------------------------------------------------------- |
2936 | | * Function: H5F_addr_encode_len |
2937 | | * |
2938 | | * Purpose: Encodes an address into the buffer pointed to by *PP and |
2939 | | * then increments the pointer to the first byte after the |
2940 | | * address. An undefined value is stored as all 1's. |
2941 | | * |
2942 | | * Return: void |
2943 | | *------------------------------------------------------------------------- |
2944 | | */ |
2945 | | void |
2946 | | H5F_addr_encode_len(size_t addr_len, uint8_t **pp /*in,out*/, haddr_t addr) |
2947 | 30 | { |
2948 | 30 | unsigned u; /* Local index variable */ |
2949 | | |
2950 | | /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */ |
2951 | 30 | FUNC_ENTER_NOAPI_NOINIT_NOERR |
2952 | | |
2953 | 30 | assert(addr_len); |
2954 | 30 | assert(pp && *pp); |
2955 | | |
2956 | 30 | if (H5_addr_defined(addr)) { |
2957 | 72 | for (u = 0; u < addr_len; u++) { |
2958 | 48 | *(*pp)++ = (uint8_t)(addr & 0xff); |
2959 | 48 | addr >>= 8; |
2960 | 48 | } /* end for */ |
2961 | 24 | assert("overflow" && 0 == addr); |
2962 | 24 | } /* end if */ |
2963 | 6 | else { |
2964 | 18 | for (u = 0; u < addr_len; u++) |
2965 | 12 | *(*pp)++ = 0xff; |
2966 | 6 | } /* end else */ |
2967 | | |
2968 | 30 | FUNC_LEAVE_NOAPI_VOID |
2969 | 30 | } /* end H5F_addr_encode_len() */ |
2970 | | |
2971 | | /*------------------------------------------------------------------------- |
2972 | | * Function: H5F_addr_encode |
2973 | | * |
2974 | | * Purpose: Encodes an address into the buffer pointed to by *PP and |
2975 | | * then increments the pointer to the first byte after the |
2976 | | * address. An undefined value is stored as all 1's. |
2977 | | * |
2978 | | * Return: void |
2979 | | *------------------------------------------------------------------------- |
2980 | | */ |
2981 | | void |
2982 | | H5F_addr_encode(const H5F_t *f, uint8_t **pp /*in,out*/, haddr_t addr) |
2983 | 30 | { |
2984 | | /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */ |
2985 | 30 | FUNC_ENTER_NOAPI_NOINIT_NOERR |
2986 | | |
2987 | 30 | assert(f); |
2988 | | |
2989 | 30 | H5F_addr_encode_len(H5F_SIZEOF_ADDR(f), pp, addr); |
2990 | | |
2991 | 30 | FUNC_LEAVE_NOAPI_VOID |
2992 | 30 | } /* end H5F_addr_encode() */ |
2993 | | |
2994 | | /*------------------------------------------------------------------------- |
2995 | | * Function: H5F_addr_decode_len |
2996 | | * |
2997 | | * Purpose: Decodes an address from the buffer pointed to by *PP and |
2998 | | * updates the pointer to point to the next byte after the |
2999 | | * address. |
3000 | | * |
3001 | | * If the value read is all 1's then the address is returned |
3002 | | * with an undefined value. |
3003 | | * |
3004 | | * Return: void |
3005 | | *------------------------------------------------------------------------- |
3006 | | */ |
3007 | | void |
3008 | | H5F_addr_decode_len(size_t addr_len, const uint8_t **pp /*in,out*/, haddr_t *addr_p /*out*/) |
3009 | 42 | { |
3010 | 42 | bool all_zero = true; /* True if address was all zeroes */ |
3011 | 42 | unsigned u; /* Local index variable */ |
3012 | | |
3013 | | /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */ |
3014 | 42 | FUNC_ENTER_NOAPI_NOINIT_NOERR |
3015 | | |
3016 | 42 | assert(addr_len); |
3017 | 42 | assert(pp && *pp); |
3018 | 42 | assert(addr_p); |
3019 | | |
3020 | | /* Reset value in destination */ |
3021 | 42 | *addr_p = 0; |
3022 | | |
3023 | | /* Decode bytes from address */ |
3024 | 126 | for (u = 0; u < addr_len; u++) { |
3025 | 84 | uint8_t c; /* Local decoded byte */ |
3026 | | |
3027 | | /* Get decoded byte (and advance pointer) */ |
3028 | 84 | c = *(*pp)++; |
3029 | | |
3030 | | /* Check for non-undefined address byte value */ |
3031 | 84 | if (c != 0xff) |
3032 | 72 | all_zero = false; |
3033 | | |
3034 | 84 | if (u < sizeof(*addr_p)) { |
3035 | 84 | haddr_t tmp = c; /* Local copy of address, for casting */ |
3036 | | |
3037 | | /* Shift decoded byte to correct position */ |
3038 | 84 | tmp <<= (u * 8); /*use tmp to get casting right */ |
3039 | | |
3040 | | /* Merge into already decoded bytes */ |
3041 | 84 | *addr_p |= tmp; |
3042 | 84 | } /* end if */ |
3043 | 0 | else if (!all_zero) |
3044 | 0 | assert(0 == **pp); /*overflow */ |
3045 | 84 | } /* end for */ |
3046 | | |
3047 | | /* If 'all_zero' is still true, the address was entirely composed of '0xff' |
3048 | | * bytes, which is the encoded form of 'HADDR_UNDEF', so set the destination |
3049 | | * to that value */ |
3050 | 42 | if (all_zero) |
3051 | 6 | *addr_p = HADDR_UNDEF; |
3052 | | |
3053 | 42 | FUNC_LEAVE_NOAPI_VOID |
3054 | 42 | } /* end H5F_addr_decode_len() */ |
3055 | | |
3056 | | /*------------------------------------------------------------------------- |
3057 | | * Function: H5F_addr_decode |
3058 | | * |
3059 | | * Purpose: Decodes an address from the buffer pointed to by *PP and |
3060 | | * updates the pointer to point to the next byte after the |
3061 | | * address. |
3062 | | * |
3063 | | * If the value read is all 1's then the address is returned |
3064 | | * with an undefined value. |
3065 | | * |
3066 | | * Return: void |
3067 | | *------------------------------------------------------------------------- |
3068 | | */ |
3069 | | void |
3070 | | H5F_addr_decode(const H5F_t *f, const uint8_t **pp /*in,out*/, haddr_t *addr_p /*out*/) |
3071 | 42 | { |
3072 | | /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */ |
3073 | 42 | FUNC_ENTER_NOAPI_NOINIT_NOERR |
3074 | | |
3075 | 42 | assert(f); |
3076 | | |
3077 | 42 | H5F_addr_decode_len(H5F_SIZEOF_ADDR(f), pp, addr_p); |
3078 | | |
3079 | 42 | FUNC_LEAVE_NOAPI_VOID |
3080 | 42 | } /* end H5F_addr_decode() */ |
3081 | | |
3082 | | /*------------------------------------------------------------------------- |
3083 | | * Function: H5F_set_grp_btree_shared |
3084 | | * |
3085 | | * Purpose: Set the grp_btree_shared field with a valid ref-count pointer. |
3086 | | * |
3087 | | * Return: SUCCEED/FAIL |
3088 | | *------------------------------------------------------------------------- |
3089 | | */ |
3090 | | herr_t |
3091 | | H5F_set_grp_btree_shared(H5F_t *f, H5UC_t *rc) |
3092 | 6 | { |
3093 | | /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */ |
3094 | 6 | FUNC_ENTER_NOAPI_NOINIT_NOERR |
3095 | | |
3096 | | /* Sanity check */ |
3097 | 6 | assert(f); |
3098 | 6 | assert(f->shared); |
3099 | 6 | assert(rc); |
3100 | | |
3101 | 6 | f->shared->grp_btree_shared = rc; |
3102 | | |
3103 | 6 | FUNC_LEAVE_NOAPI(SUCCEED) |
3104 | 6 | } /* H5F_set_grp_btree_shared() */ |
3105 | | |
3106 | | /*------------------------------------------------------------------------- |
3107 | | * Function: H5F_set_sohm_addr |
3108 | | * |
3109 | | * Purpose: Set the sohm_addr field with a new value. |
3110 | | * |
3111 | | * Return: SUCCEED/FAIL |
3112 | | *------------------------------------------------------------------------- |
3113 | | */ |
3114 | | herr_t |
3115 | | H5F_set_sohm_addr(H5F_t *f, haddr_t addr) |
3116 | 0 | { |
3117 | | /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */ |
3118 | 0 | FUNC_ENTER_NOAPI_NOINIT_NOERR |
3119 | | |
3120 | | /* Sanity check */ |
3121 | 0 | assert(f); |
3122 | 0 | assert(f->shared); |
3123 | |
|
3124 | 0 | f->shared->sohm_addr = addr; |
3125 | |
|
3126 | 0 | FUNC_LEAVE_NOAPI(SUCCEED) |
3127 | 0 | } /* H5F_set_sohm_addr() */ |
3128 | | |
3129 | | /*------------------------------------------------------------------------- |
3130 | | * Function: H5F_set_sohm_vers |
3131 | | * |
3132 | | * Purpose: Set the sohm_vers field with a new value. |
3133 | | * |
3134 | | * Return: SUCCEED/FAIL |
3135 | | *------------------------------------------------------------------------- |
3136 | | */ |
3137 | | herr_t |
3138 | | H5F_set_sohm_vers(H5F_t *f, unsigned vers) |
3139 | 0 | { |
3140 | | /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */ |
3141 | 0 | FUNC_ENTER_NOAPI_NOINIT_NOERR |
3142 | | |
3143 | | /* Sanity check */ |
3144 | 0 | assert(f); |
3145 | 0 | assert(f->shared); |
3146 | |
|
3147 | 0 | f->shared->sohm_vers = vers; |
3148 | |
|
3149 | 0 | FUNC_LEAVE_NOAPI(SUCCEED) |
3150 | 0 | } /* H5F_set_sohm_vers() */ |
3151 | | |
3152 | | /*------------------------------------------------------------------------- |
3153 | | * Function: H5F_set_sohm_nindexes |
3154 | | * |
3155 | | * Purpose: Set the sohm_nindexes field with a new value. |
3156 | | * |
3157 | | * Return: SUCCEED/FAIL |
3158 | | *------------------------------------------------------------------------- |
3159 | | */ |
3160 | | herr_t |
3161 | | H5F_set_sohm_nindexes(H5F_t *f, unsigned nindexes) |
3162 | 0 | { |
3163 | | /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */ |
3164 | 0 | FUNC_ENTER_NOAPI_NOINIT_NOERR |
3165 | | |
3166 | | /* Sanity check */ |
3167 | 0 | assert(f); |
3168 | 0 | assert(f->shared); |
3169 | |
|
3170 | 0 | f->shared->sohm_nindexes = nindexes; |
3171 | |
|
3172 | 0 | FUNC_LEAVE_NOAPI(SUCCEED) |
3173 | 0 | } /* H5F_set_sohm_nindexes() */ |
3174 | | |
3175 | | /*------------------------------------------------------------------------- |
3176 | | * Function: H5F_set_store_msg_crt_idx |
3177 | | * |
3178 | | * Purpose: Set the store_msg_crt_idx field with a new value. |
3179 | | * |
3180 | | * Return: SUCCEED/FAIL |
3181 | | *------------------------------------------------------------------------- |
3182 | | */ |
3183 | | herr_t |
3184 | | H5F_set_store_msg_crt_idx(H5F_t *f, bool flag) |
3185 | 0 | { |
3186 | | /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */ |
3187 | 0 | FUNC_ENTER_NOAPI_NOINIT_NOERR |
3188 | | |
3189 | | /* Sanity check */ |
3190 | 0 | assert(f); |
3191 | 0 | assert(f->shared); |
3192 | |
|
3193 | 0 | f->shared->store_msg_crt_idx = flag; |
3194 | |
|
3195 | 0 | FUNC_LEAVE_NOAPI(SUCCEED) |
3196 | 0 | } /* H5F_set_store_msg_crt_idx() */ |
3197 | | |
3198 | | /*------------------------------------------------------------------------- |
3199 | | * Function: H5F__set_libver_bounds() |
3200 | | * |
3201 | | * Purpose: Set the file's low and high bound to the input parameters |
3202 | | * 'low' and 'high' respectively. |
3203 | | * This is done only if the existing setting is different |
3204 | | * from the inputs. |
3205 | | * |
3206 | | * Return: SUCCEED/FAIL |
3207 | | * |
3208 | | *------------------------------------------------------------------------- |
3209 | | */ |
3210 | | herr_t |
3211 | | H5F__set_libver_bounds(H5F_t *f, H5F_libver_t low, H5F_libver_t high) |
3212 | 0 | { |
3213 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
3214 | |
|
3215 | 0 | FUNC_ENTER_PACKAGE |
3216 | | |
3217 | | /* Sanity checks */ |
3218 | 0 | assert(f); |
3219 | 0 | assert(f->shared); |
3220 | | |
3221 | | /* Set the bounds only if the existing setting is different from the inputs */ |
3222 | 0 | if ((f->shared->low_bound != low || f->shared->high_bound != high) && |
3223 | 0 | !(H5F_INTENT(f) & H5F_ACC_SWMR_WRITE)) { |
3224 | | /* Call the flush routine, for this file */ |
3225 | | /* Note: This is done in case the binary format for representing a |
3226 | | * metadata entry class changes when the file format low / high |
3227 | | * bounds are changed and an unwritten entry of that class is |
3228 | | * sitting in the metadata cache. |
3229 | | * |
3230 | | * If that happens, it's possible that the entry's size could |
3231 | | * become larger, potentially corrupting the file (if the larger |
3232 | | * entry is fully written, overwriting data outside its allocated |
3233 | | * space), or corrupting the entry (if the entry is truncated to |
3234 | | * fit into the allocated space). |
3235 | | * |
3236 | | * Although I'm not aware of any metadata with this behavior |
3237 | | * currently, it would be very difficult to guard against and / or |
3238 | | * detect, but if we flush everything here, the format version |
3239 | | * for metadata entries in the cache will be finalized and these |
3240 | | * sorts of problems can be avoided. |
3241 | | * |
3242 | | * QAK - April, 2018 |
3243 | | */ |
3244 | 0 | if (H5F__flush(f) < 0) |
3245 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTFLUSH, FAIL, "unable to flush file's cached information"); |
3246 | | |
3247 | | /* Set the new bounds */ |
3248 | 0 | f->shared->low_bound = low; |
3249 | 0 | f->shared->high_bound = high; |
3250 | 0 | } |
3251 | | |
3252 | 0 | done: |
3253 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
3254 | 0 | } /* H5F__set_libver_bounds() */ |
3255 | | |
3256 | | /*------------------------------------------------------------------------- |
3257 | | * Function: H5F__get_file_image |
3258 | | * |
3259 | | * Purpose: Private version of H5Fget_file_image, returns bytes copied/ |
3260 | | * number of bytes needed in *image_len. |
3261 | | * |
3262 | | * Return: SUCCEED/FAIL |
3263 | | * |
3264 | | *------------------------------------------------------------------------- |
3265 | | */ |
3266 | | herr_t |
3267 | | H5F__get_file_image(H5F_t *file, void *buf_ptr, size_t buf_len, size_t *image_len) |
3268 | 0 | { |
3269 | 0 | H5FD_t *fd_ptr; /* file driver */ |
3270 | 0 | haddr_t eoa; /* End of file address */ |
3271 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
3272 | |
|
3273 | 0 | FUNC_ENTER_PACKAGE |
3274 | | |
3275 | | /* Check args */ |
3276 | 0 | if (!file || !file->shared || !file->shared->lf) |
3277 | 0 | HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, FAIL, "file_id yields invalid file pointer"); |
3278 | 0 | fd_ptr = file->shared->lf; |
3279 | 0 | if (!fd_ptr->cls) |
3280 | 0 | HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, FAIL, "fd_ptr yields invalid class pointer"); |
3281 | | |
3282 | | /* the address space used by the split and multi file drivers is not |
3283 | | * a good fit for this call. Since the plan is to depreciate these |
3284 | | * drivers anyway, don't bother to do a "force fit". |
3285 | | * |
3286 | | * The following clause tests for the multi file driver, and fails |
3287 | | * if the supplied file has the multi file driver as its top level |
3288 | | * file driver. However, this test will not work if there is some |
3289 | | * other file driver sitting on top of the multi file driver. |
3290 | | * |
3291 | | * I'm not sure if this is possible at present, but in all likelihood, |
3292 | | * it will become possible in the future. On the other hand, we may |
3293 | | * remove the split/multi file drivers before then. |
3294 | | * |
3295 | | * I am leaving this solution in for now, but we should review it, |
3296 | | * and improve the solution if necessary. |
3297 | | * |
3298 | | * JRM -- 11/11/22 |
3299 | | */ |
3300 | 0 | if (strcmp(fd_ptr->cls->name, "multi") == 0) |
3301 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "Not supported for multi file driver."); |
3302 | | |
3303 | | /* While the family file driver is conceptually fully compatible |
3304 | | * with the get file image operation, it sets a file driver message |
3305 | | * in the super block that prevents the image being opened with any |
3306 | | * driver other than the family file driver. Needless to say, this |
3307 | | * rather defeats the purpose of the get file image operation. |
3308 | | * |
3309 | | * While this problem is quite solvable, the required time and |
3310 | | * resources are lacking at present. Hence, for now, we don't |
3311 | | * allow the get file image operation to be performed on files |
3312 | | * opened with the family file driver. |
3313 | | * |
3314 | | * Observe that the following test only looks at the top level |
3315 | | * driver, and fails if there is some other driver sitting on to |
3316 | | * of the family file driver. |
3317 | | * |
3318 | | * I don't think this can happen at present, but that may change |
3319 | | * in the future. |
3320 | | * JRM -- 12/21/11 |
3321 | | */ |
3322 | 0 | if (strcmp(fd_ptr->cls->name, "family") == 0) |
3323 | 0 | HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, FAIL, "Not supported for family file driver."); |
3324 | | |
3325 | | /* Go get the actual file size */ |
3326 | 0 | if (HADDR_UNDEF == (eoa = H5FD_get_eoa(file->shared->lf, H5FD_MEM_DEFAULT))) |
3327 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "unable to get file size"); |
3328 | | |
3329 | | /* Test to see if a buffer was provided */ |
3330 | 0 | if (buf_ptr != NULL) { |
3331 | 0 | size_t tmp, tmp_size; |
3332 | | |
3333 | | /* Check for buffer too small */ |
3334 | 0 | if ((haddr_t)buf_len < eoa) |
3335 | 0 | HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, FAIL, "supplied buffer too small"); |
3336 | 0 | assert(buf_len >= (size_t)H5F_SUPERBLOCK_SIZE(file->shared->sblock)); |
3337 | | |
3338 | | /* Read in the file image */ |
3339 | | /* (Note compensation for base address addition in internal routine) */ |
3340 | 0 | if (H5FD_read(fd_ptr, H5FD_MEM_DEFAULT, 0, (size_t)eoa, buf_ptr) < 0) |
3341 | 0 | HGOTO_ERROR(H5E_FILE, H5E_READERROR, FAIL, "file image read request failed"); |
3342 | | |
3343 | | /* Offset to "status_flags" in the superblock */ |
3344 | 0 | tmp = H5F_SUPER_STATUS_FLAGS_OFF(file->shared->sblock->super_vers); |
3345 | | |
3346 | | /* Size of "status_flags" depends on the superblock version */ |
3347 | 0 | tmp_size = H5F_SUPER_STATUS_FLAGS_SIZE(file->shared->sblock->super_vers); |
3348 | | |
3349 | | /* Clear "status_flags" */ |
3350 | 0 | memset((uint8_t *)buf_ptr + tmp, 0, tmp_size); |
3351 | | |
3352 | | /* Check if the version is 2 or greater, if so we need to recalculate the checksum */ |
3353 | 0 | if (file->shared->sblock->super_vers >= HDF5_SUPERBLOCK_VERSION_2) { |
3354 | 0 | uint32_t chksum; /* Checksum temporary variable */ |
3355 | 0 | uint8_t *chksum_image_ptr; |
3356 | | |
3357 | | /* When we add new superblock versions make sure this code still works, then modify this assert |
3358 | | * appropriately */ |
3359 | 0 | assert(file->shared->sblock->super_vers <= HDF5_SUPERBLOCK_VERSION_3); |
3360 | | |
3361 | | /* Offset to checksum */ |
3362 | 0 | tmp = (size_t)H5F_SUPERBLOCK_SIZE(file->shared->sblock) - H5F_SIZEOF_CHKSUM; |
3363 | | |
3364 | | /* Recompute superblock checksum */ |
3365 | 0 | chksum = H5_checksum_metadata(buf_ptr, tmp, 0); |
3366 | | |
3367 | | /* Encode checksum into image */ |
3368 | 0 | chksum_image_ptr = (uint8_t *)buf_ptr + tmp; |
3369 | 0 | UINT32ENCODE(chksum_image_ptr, chksum); |
3370 | 0 | } |
3371 | 0 | } |
3372 | | |
3373 | | /* Set *image_len = to EOA */ |
3374 | 0 | *image_len = (size_t)eoa; |
3375 | |
|
3376 | 0 | done: |
3377 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
3378 | 0 | } /* H5F__get_file_image() */ |
3379 | | |
3380 | | /*------------------------------------------------------------------------- |
3381 | | * Function: H5F__get_info |
3382 | | * |
3383 | | * Purpose: Private version of H5Fget_info |
3384 | | * |
3385 | | * Return: Success: SUCCEED |
3386 | | * Failure: FAIL |
3387 | | *------------------------------------------------------------------------- |
3388 | | */ |
3389 | | herr_t |
3390 | | H5F__get_info(H5F_t *f, H5F_info2_t *finfo) |
3391 | 0 | { |
3392 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
3393 | |
|
3394 | 0 | FUNC_ENTER_PACKAGE |
3395 | | |
3396 | | /* Sanity check */ |
3397 | 0 | assert(f); |
3398 | 0 | assert(f->shared); |
3399 | 0 | assert(finfo); |
3400 | | |
3401 | | /* Reset file info struct */ |
3402 | 0 | memset(finfo, 0, sizeof(*finfo)); |
3403 | | |
3404 | | /* Get the size of the superblock and any superblock extensions */ |
3405 | 0 | if (H5F__super_size(f, &finfo->super.super_size, &finfo->super.super_ext_size) < 0) |
3406 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "unable to retrieve superblock sizes"); |
3407 | | |
3408 | | /* Get the size of any persistent free space */ |
3409 | 0 | if (H5MF_get_freespace(f, &finfo->free.tot_space, &finfo->free.meta_size) < 0) |
3410 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "unable to retrieve free space information"); |
3411 | | |
3412 | | /* Check for SOHM info */ |
3413 | 0 | if (H5_addr_defined(f->shared->sohm_addr)) |
3414 | 0 | if (H5SM_ih_size(f, &finfo->sohm.hdr_size, &finfo->sohm.msgs_info) < 0) |
3415 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "unable to retrieve SOHM index & heap storage info"); |
3416 | | |
3417 | | /* Set version # fields */ |
3418 | 0 | finfo->super.version = f->shared->sblock->super_vers; |
3419 | 0 | finfo->sohm.version = f->shared->sohm_vers; |
3420 | 0 | finfo->free.version = HDF5_FREESPACE_VERSION; |
3421 | |
|
3422 | 0 | done: |
3423 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
3424 | 0 | } /* H5F__get_info() */ |
3425 | | |
3426 | | /*------------------------------------------------------------------------- |
3427 | | * Function: H5F_track_metadata_read_retries |
3428 | | * |
3429 | | * Purpose: To track the # of a "retries" (log10) for a metadata item. |
3430 | | * This routine should be used only when: |
3431 | | * "retries" > 0 |
3432 | | * f->shared->read_attempts > 1 (does not have retry when 1) |
3433 | | * f->shared->retries_nbins > 0 (calculated based on f->shared->read_attempts) |
3434 | | * |
3435 | | * Return: SUCCEED/FAIL |
3436 | | *------------------------------------------------------------------------- |
3437 | | */ |
3438 | | herr_t |
3439 | | H5F_track_metadata_read_retries(H5F_t *f, unsigned actype, unsigned retries) |
3440 | 0 | { |
3441 | 0 | unsigned log_ind; /* Index to the array of retries based on log10 of retries */ |
3442 | 0 | double tmp; /* Temporary value, to keep compiler quiet */ |
3443 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
3444 | |
|
3445 | 0 | FUNC_ENTER_NOAPI(FAIL) |
3446 | | |
3447 | | /* Sanity check */ |
3448 | 0 | assert(f); |
3449 | 0 | assert(f->shared->read_attempts > 1); |
3450 | 0 | assert(f->shared->retries_nbins > 0); |
3451 | 0 | assert(retries > 0); |
3452 | 0 | assert(retries < f->shared->read_attempts); |
3453 | 0 | assert(actype < H5AC_NTYPES); |
3454 | | |
3455 | | /* Allocate memory for retries */ |
3456 | 0 | if (NULL == f->shared->retries[actype]) |
3457 | 0 | if (NULL == (f->shared->retries[actype] = |
3458 | 0 | (uint32_t *)H5MM_calloc((size_t)f->shared->retries_nbins * sizeof(uint32_t)))) |
3459 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed"); |
3460 | | |
3461 | | /* Index to retries based on log10 */ |
3462 | 0 | tmp = log10((double)retries); |
3463 | 0 | log_ind = (unsigned)tmp; |
3464 | 0 | assert(log_ind < f->shared->retries_nbins); |
3465 | | |
3466 | | /* Increment the # of the "retries" */ |
3467 | 0 | f->shared->retries[actype][log_ind]++; |
3468 | |
|
3469 | 0 | done: |
3470 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
3471 | 0 | } /* H5F_track_metadata_read_retries() */ |
3472 | | |
3473 | | /*------------------------------------------------------------------------- |
3474 | | * Function: H5F_set_retries |
3475 | | * |
3476 | | * Purpose: To initialize data structures for read retries: |
3477 | | * --zero out "retries" |
3478 | | * --set up "retries_nbins" based on read_attempts |
3479 | | * |
3480 | | * Return: SUCCEED/FAIL |
3481 | | *------------------------------------------------------------------------- |
3482 | | */ |
3483 | | herr_t |
3484 | | H5F_set_retries(H5F_t *f) |
3485 | 15 | { |
3486 | 15 | double tmp; /* Temporary variable */ |
3487 | | |
3488 | | /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */ |
3489 | 15 | FUNC_ENTER_NOAPI_NOINIT_NOERR |
3490 | | |
3491 | | /* Sanity check */ |
3492 | 15 | assert(f); |
3493 | | |
3494 | | /* Initialize the tracking for metadata read retries */ |
3495 | 15 | memset(f->shared->retries, 0, sizeof(f->shared->retries)); |
3496 | | |
3497 | | /* Initialize the # of bins for retries */ |
3498 | 15 | f->shared->retries_nbins = 0; |
3499 | 15 | if (f->shared->read_attempts > 1) { |
3500 | | /* Use ceil to ensure that the log10 value is rounded up to the |
3501 | | nearest integer before casting to unsigned */ |
3502 | 0 | tmp = ceil(log10((double)f->shared->read_attempts)); |
3503 | 0 | f->shared->retries_nbins = (unsigned)tmp; |
3504 | 0 | } |
3505 | | |
3506 | 15 | FUNC_LEAVE_NOAPI(SUCCEED) |
3507 | 15 | } /* H5F_set_retries() */ |
3508 | | |
3509 | | /*------------------------------------------------------------------------- |
3510 | | * Function: H5F_object_flush_cb |
3511 | | * |
3512 | | * Purpose: To invoke the callback function for object flush that is set |
3513 | | * in the file's access property list. |
3514 | | * |
3515 | | * Return: Success: SUCCEED |
3516 | | * Failure: FAIL |
3517 | | *------------------------------------------------------------------------- |
3518 | | */ |
3519 | | herr_t |
3520 | | H5F_object_flush_cb(H5F_t *f, hid_t obj_id) |
3521 | 0 | { |
3522 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
3523 | |
|
3524 | 0 | FUNC_ENTER_NOAPI(FAIL) |
3525 | | |
3526 | | /* Sanity check */ |
3527 | 0 | assert(f); |
3528 | 0 | assert(f->shared); |
3529 | | |
3530 | | /* Invoke object flush callback if there is one */ |
3531 | 0 | if (f->shared->object_flush.func) { |
3532 | | /* Prepare & restore library for user callback */ |
3533 | 0 | H5_BEFORE_USER_CB(FAIL) |
3534 | 0 | { |
3535 | 0 | ret_value = f->shared->object_flush.func(obj_id, f->shared->object_flush.udata); |
3536 | 0 | } |
3537 | 0 | H5_AFTER_USER_CB(FAIL) |
3538 | 0 | if (ret_value < 0) |
3539 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "object flush callback returns error"); |
3540 | 0 | } |
3541 | | |
3542 | 0 | done: |
3543 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
3544 | 0 | } /* H5F_object_flush_cb() */ |
3545 | | |
3546 | | /*------------------------------------------------------------------------- |
3547 | | * Function: H5F__set_base_addr |
3548 | | * |
3549 | | * Purpose: Quick and dirty routine to set the file's 'base_addr' value |
3550 | | * |
3551 | | * Return: Non-negative on success/Negative on failure |
3552 | | *------------------------------------------------------------------------- |
3553 | | */ |
3554 | | herr_t |
3555 | | H5F__set_base_addr(const H5F_t *f, haddr_t addr) |
3556 | 6 | { |
3557 | 6 | herr_t ret_value = SUCCEED; /* Return value */ |
3558 | | |
3559 | 6 | FUNC_ENTER_PACKAGE |
3560 | | |
3561 | 6 | assert(f); |
3562 | 6 | assert(f->shared); |
3563 | | |
3564 | | /* Dispatch to driver */ |
3565 | 6 | if (H5FD_set_base_addr(f->shared->lf, addr) < 0) |
3566 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTSET, FAIL, "driver set_base_addr request failed"); |
3567 | | |
3568 | 6 | done: |
3569 | 6 | FUNC_LEAVE_NOAPI(ret_value) |
3570 | 6 | } /* end H5F__set_base_addr() */ |
3571 | | |
3572 | | /*------------------------------------------------------------------------- |
3573 | | * Function: H5F__set_eoa |
3574 | | * |
3575 | | * Purpose: Quick and dirty routine to set the file's 'eoa' value |
3576 | | * |
3577 | | * Return: Non-negative on success/Negative on failure |
3578 | | *------------------------------------------------------------------------- |
3579 | | */ |
3580 | | herr_t |
3581 | | H5F__set_eoa(const H5F_t *f, H5F_mem_t type, haddr_t addr) |
3582 | 18 | { |
3583 | 18 | herr_t ret_value = SUCCEED; /* Return value */ |
3584 | | |
3585 | 18 | FUNC_ENTER_PACKAGE |
3586 | | |
3587 | 18 | assert(f); |
3588 | 18 | assert(f->shared); |
3589 | | |
3590 | | /* Dispatch to driver */ |
3591 | | /* (H5FD_set_eoa() will add base_addr to addr) */ |
3592 | 18 | if (H5FD_set_eoa(f->shared->lf, type, addr) < 0) |
3593 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTSET, FAIL, "driver set_eoa request failed"); |
3594 | | |
3595 | 18 | done: |
3596 | 18 | FUNC_LEAVE_NOAPI(ret_value) |
3597 | 18 | } /* end H5F__set_eoa() */ |
3598 | | |
3599 | | /*------------------------------------------------------------------------- |
3600 | | * Function: H5F__set_paged_aggr |
3601 | | * |
3602 | | * Purpose: Quick and dirty routine to set the file's paged_aggr mode |
3603 | | * |
3604 | | * Return: Non-negative on success/Negative on failure |
3605 | | *------------------------------------------------------------------------- |
3606 | | */ |
3607 | | herr_t |
3608 | | H5F__set_paged_aggr(const H5F_t *f, bool paged) |
3609 | 6 | { |
3610 | 6 | herr_t ret_value = SUCCEED; /* Return value */ |
3611 | | |
3612 | 6 | FUNC_ENTER_PACKAGE |
3613 | | |
3614 | | /* Sanity check */ |
3615 | 6 | assert(f); |
3616 | 6 | assert(f->shared); |
3617 | | |
3618 | | /* Dispatch to driver */ |
3619 | 6 | if (H5FD_set_paged_aggr(f->shared->lf, paged) < 0) |
3620 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTSET, FAIL, "driver set paged aggr mode failed"); |
3621 | | |
3622 | 6 | done: |
3623 | 6 | FUNC_LEAVE_NOAPI(ret_value) |
3624 | 6 | } /* end H5F__set_paged_aggr() */ |
3625 | | |
3626 | | /*------------------------------------------------------------------------- |
3627 | | * Function: H5F__get_max_eof_eoa |
3628 | | * |
3629 | | * Purpose: Determine the maximum of (EOA, EOF) for the file |
3630 | | * |
3631 | | * Return: SUCCEED/FAIL |
3632 | | *------------------------------------------------------------------------- |
3633 | | */ |
3634 | | herr_t |
3635 | | H5F__get_max_eof_eoa(const H5F_t *f, haddr_t *max_eof_eoa) |
3636 | 0 | { |
3637 | 0 | haddr_t eof; /* Relative address for EOF */ |
3638 | 0 | haddr_t eoa; /* Relative address for EOA */ |
3639 | 0 | haddr_t tmp_max; |
3640 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
3641 | |
|
3642 | 0 | FUNC_ENTER_PACKAGE |
3643 | | |
3644 | | /* Sanity checks */ |
3645 | 0 | assert(f); |
3646 | 0 | assert(f->shared); |
3647 | | |
3648 | | /* Get the relative EOA and EOF */ |
3649 | 0 | eoa = H5FD_get_eoa(f->shared->lf, H5FD_MEM_DEFAULT); |
3650 | 0 | eof = H5FD_get_eof(f->shared->lf, H5FD_MEM_DEFAULT); |
3651 | | |
3652 | | /* Determine the maximum */ |
3653 | 0 | tmp_max = MAX(eof, eoa); |
3654 | 0 | if (HADDR_UNDEF == tmp_max) |
3655 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "file get eof/eoa requests failed"); |
3656 | | |
3657 | 0 | *max_eof_eoa = tmp_max; |
3658 | |
|
3659 | 0 | done: |
3660 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
3661 | 0 | } /* end H5F__get_max_eof_eoa() */ |
3662 | | |
3663 | | /*------------------------------------------------------------------------- |
3664 | | * Function: H5F_get_metadata_read_retry_info |
3665 | | * |
3666 | | * Purpose: Private function to retrieve the collection of read retries |
3667 | | * for metadata items with checksum. |
3668 | | * |
3669 | | * Return: SUCCEED/FAIL |
3670 | | * |
3671 | | *------------------------------------------------------------------------- |
3672 | | */ |
3673 | | herr_t |
3674 | | H5F_get_metadata_read_retry_info(H5F_t *file, H5F_retry_info_t *info) |
3675 | 0 | { |
3676 | 0 | unsigned i, j; /* Local index variable */ |
3677 | 0 | size_t tot_size; /* Size of each retries[i] */ |
3678 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
3679 | |
|
3680 | 0 | FUNC_ENTER_NOAPI(FAIL) |
3681 | | |
3682 | | /* Check args */ |
3683 | 0 | assert(file); |
3684 | 0 | assert(info); |
3685 | | |
3686 | | /* Copy the # of bins for "retries" array */ |
3687 | 0 | info->nbins = file->shared->retries_nbins; |
3688 | | |
3689 | | /* Initialize the array of "retries" */ |
3690 | 0 | memset(info->retries, 0, sizeof(info->retries)); |
3691 | | |
3692 | | /* Return if there are no bins -- no retries */ |
3693 | 0 | if (!info->nbins) |
3694 | 0 | HGOTO_DONE(SUCCEED); |
3695 | | |
3696 | | /* Calculate size for each retries[i] */ |
3697 | 0 | tot_size = info->nbins * sizeof(uint32_t); |
3698 | | |
3699 | | /* Map and copy information to info's retries for metadata items with tracking for read retries */ |
3700 | 0 | j = 0; |
3701 | 0 | for (i = 0; i < H5AC_NTYPES; i++) { |
3702 | 0 | switch (i) { |
3703 | 0 | case H5AC_OHDR_ID: |
3704 | 0 | case H5AC_OHDR_CHK_ID: |
3705 | 0 | case H5AC_BT2_HDR_ID: |
3706 | 0 | case H5AC_BT2_INT_ID: |
3707 | 0 | case H5AC_BT2_LEAF_ID: |
3708 | 0 | case H5AC_FHEAP_HDR_ID: |
3709 | 0 | case H5AC_FHEAP_DBLOCK_ID: |
3710 | 0 | case H5AC_FHEAP_IBLOCK_ID: |
3711 | 0 | case H5AC_FSPACE_HDR_ID: |
3712 | 0 | case H5AC_FSPACE_SINFO_ID: |
3713 | 0 | case H5AC_SOHM_TABLE_ID: |
3714 | 0 | case H5AC_SOHM_LIST_ID: |
3715 | 0 | case H5AC_EARRAY_HDR_ID: |
3716 | 0 | case H5AC_EARRAY_IBLOCK_ID: |
3717 | 0 | case H5AC_EARRAY_SBLOCK_ID: |
3718 | 0 | case H5AC_EARRAY_DBLOCK_ID: |
3719 | 0 | case H5AC_EARRAY_DBLK_PAGE_ID: |
3720 | 0 | case H5AC_FARRAY_HDR_ID: |
3721 | 0 | case H5AC_FARRAY_DBLOCK_ID: |
3722 | 0 | case H5AC_FARRAY_DBLK_PAGE_ID: |
3723 | 0 | case H5AC_SUPERBLOCK_ID: |
3724 | 0 | assert(j < H5F_NUM_METADATA_READ_RETRY_TYPES); |
3725 | 0 | if (file->shared->retries[i] != NULL) { |
3726 | | /* Allocate memory for retries[i] |
3727 | | * |
3728 | | * This memory should be released by the user with |
3729 | | * the H5free_memory() call. |
3730 | | */ |
3731 | 0 | if (NULL == (info->retries[j] = (uint32_t *)H5MM_malloc(tot_size))) |
3732 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed"); |
3733 | | |
3734 | | /* Copy the information */ |
3735 | 0 | H5MM_memcpy(info->retries[j], file->shared->retries[i], tot_size); |
3736 | 0 | } |
3737 | | |
3738 | | /* Increment location in info->retries[] array */ |
3739 | 0 | j++; |
3740 | 0 | break; |
3741 | | |
3742 | 0 | default: |
3743 | 0 | break; |
3744 | 0 | } |
3745 | 0 | } |
3746 | | |
3747 | 0 | done: |
3748 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
3749 | 0 | } /* end H5F_get_metadata_read_retry_info() */ |
3750 | | |
3751 | | /*------------------------------------------------------------------------- |
3752 | | * Function: H5F__start_swmr_write |
3753 | | * |
3754 | | * Purpose: Private version of H5Fstart_swmr_write |
3755 | | * |
3756 | | * 1) Refresh opened objects: part 1 |
3757 | | * 2) Flush & reset accumulator |
3758 | | * 3) Mark the file in SWMR writing mode |
3759 | | * 4) Set metadata read attempts and retries info |
3760 | | * 5) Disable accumulator |
3761 | | * 6) Evict all cache entries except the superblock |
3762 | | * 7) Refresh opened objects (part 2) |
3763 | | * 8) Unlock the file |
3764 | | * |
3765 | | * Pre-conditions: |
3766 | | * |
3767 | | * 1) The file being opened has v3 superblock |
3768 | | * 2) The file is opened with H5F_ACC_RDWR |
3769 | | * 3) The file is not already marked for SWMR writing |
3770 | | * 4) Current implementation for opened objects: |
3771 | | * --only allow datasets and groups without attributes |
3772 | | * --disallow named datatype with/without attributes |
3773 | | * --disallow opened attributes attached to objects |
3774 | | * --disallow opened objects below 1.10 |
3775 | | * |
3776 | | * NOTE: Currently, only opened groups and datasets are allowed |
3777 | | * when enabling SWMR via H5Fstart_swmr_write(). |
3778 | | * Will later implement a different approach-- |
3779 | | * set up flush dependency/proxy even for file opened without |
3780 | | * SWMR to resolve issues with opened objects. |
3781 | | * |
3782 | | * Return: SUCCEED/FAIL |
3783 | | * |
3784 | | *------------------------------------------------------------------------- |
3785 | | */ |
3786 | | herr_t |
3787 | | H5F__start_swmr_write(H5F_t *f) |
3788 | 0 | { |
3789 | 0 | bool ci_load = false; /* whether MDC ci load requested */ |
3790 | 0 | bool ci_write = false; /* whether MDC CI write requested */ |
3791 | 0 | size_t grp_dset_count = 0; /* # of open objects: groups & datasets */ |
3792 | 0 | size_t nt_attr_count = 0; /* # of opened named datatypes + opened attributes */ |
3793 | 0 | hid_t *obj_ids = NULL; /* List of ids */ |
3794 | 0 | hid_t *obj_apl_ids = NULL; /* List of access property lists */ |
3795 | 0 | H5G_loc_t *obj_glocs = NULL; /* Group location of the object */ |
3796 | 0 | H5O_loc_t *obj_olocs = NULL; /* Object location */ |
3797 | 0 | H5G_name_t *obj_paths = NULL; /* Group hierarchy path */ |
3798 | 0 | size_t u; /* Local index variable */ |
3799 | 0 | bool setup = false; /* Boolean flag to indicate whether SWMR setting is enabled */ |
3800 | 0 | H5VL_connector_t *vol_connector = NULL; /* VOL connector for the file */ |
3801 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
3802 | |
|
3803 | 0 | FUNC_ENTER_PACKAGE |
3804 | | |
3805 | | /* Sanity check */ |
3806 | 0 | assert(f); |
3807 | 0 | assert(f->shared); |
3808 | | |
3809 | | /* Should have write permission */ |
3810 | 0 | if ((H5F_INTENT(f) & H5F_ACC_RDWR) == 0) |
3811 | 0 | HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, FAIL, "no write intent on file"); |
3812 | | |
3813 | | /* Check superblock version */ |
3814 | 0 | if (f->shared->sblock->super_vers < HDF5_SUPERBLOCK_VERSION_3) |
3815 | 0 | HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, FAIL, "file superblock version - should be at least 3"); |
3816 | | |
3817 | | /* Check for correct file format version to start SWMR writing */ |
3818 | 0 | if ((f->shared->low_bound < H5F_LIBVER_V110) || (f->shared->high_bound < H5F_LIBVER_V110)) |
3819 | 0 | HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, FAIL, |
3820 | 0 | "file format version does not support SWMR - needs to be 1.10 or greater"); |
3821 | | |
3822 | | /* Should not be marked for SWMR writing mode already */ |
3823 | 0 | if (f->shared->sblock->status_flags & H5F_SUPER_SWMR_WRITE_ACCESS) |
3824 | 0 | HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, FAIL, "file already in SWMR writing mode"); |
3825 | | |
3826 | | /* Check to see if cache image is enabled. Fail if so */ |
3827 | 0 | if (H5C_cache_image_status(f, &ci_load, &ci_write) < 0) |
3828 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "can't get MDC cache image status"); |
3829 | 0 | if (ci_load || ci_write) |
3830 | 0 | HGOTO_ERROR(H5E_FILE, H5E_UNSUPPORTED, FAIL, "can't have both SWMR and MDC cache image"); |
3831 | | |
3832 | | /* Flush the superblock extension */ |
3833 | 0 | if (H5F_flush_tagged_metadata(f, f->shared->sblock->ext_addr) < 0) |
3834 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTFLUSH, FAIL, "unable to flush superblock extension"); |
3835 | | |
3836 | | /* Flush data buffers */ |
3837 | 0 | if (H5F__flush(f) < 0) |
3838 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTFLUSH, FAIL, "unable to flush file's cached information"); |
3839 | | |
3840 | | /* Get the # of opened named datatypes and attributes */ |
3841 | 0 | if (H5F_get_obj_count(f, H5F_OBJ_DATATYPE | H5F_OBJ_ATTR, false, &nt_attr_count) < 0) |
3842 | 0 | HGOTO_ERROR(H5E_FILE, H5E_BADITER, FAIL, "H5F_get_obj_count failed"); |
3843 | 0 | if (nt_attr_count > 0) |
3844 | 0 | HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, FAIL, "named datatypes and/or attributes opened in the file"); |
3845 | | |
3846 | | /* Get the # of opened datasets and groups */ |
3847 | 0 | if (H5F_get_obj_count(f, H5F_OBJ_GROUP | H5F_OBJ_DATASET, false, &grp_dset_count) < 0) |
3848 | 0 | HGOTO_ERROR(H5E_FILE, H5E_BADITER, FAIL, "H5F_get_obj_count failed"); |
3849 | | |
3850 | 0 | if (grp_dset_count > 0) { |
3851 | | /* Allocate space for group and object locations */ |
3852 | 0 | if ((obj_ids = (hid_t *)H5MM_malloc(grp_dset_count * sizeof(hid_t))) == NULL) |
3853 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTALLOC, FAIL, "can't allocate buffer for hid_t"); |
3854 | | |
3855 | | /* Get the list of opened object ids (groups & datasets) */ |
3856 | 0 | if (H5F_get_obj_ids(f, H5F_OBJ_GROUP | H5F_OBJ_DATASET, grp_dset_count, obj_ids, false, |
3857 | 0 | &grp_dset_count) < 0) |
3858 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "H5F_get_obj_ids failed"); |
3859 | | |
3860 | | /* Ensure that there's no old-style opened objects */ |
3861 | 0 | for (u = 0; u < grp_dset_count; u++) { |
3862 | 0 | H5O_native_info_t ninfo; |
3863 | 0 | H5O_loc_t *oloc; |
3864 | 0 | uint8_t version; |
3865 | |
|
3866 | 0 | if (NULL == (oloc = H5O_get_loc(obj_ids[u]))) |
3867 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "H5O_get_loc() failed"); |
3868 | | |
3869 | 0 | if (H5O_get_native_info(oloc, &ninfo, H5O_NATIVE_INFO_HDR) < 0) |
3870 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "H5O_get_native_info() failed"); |
3871 | | |
3872 | 0 | if (H5O_get_version_bound(f->shared->low_bound, &version) < 0) |
3873 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "H5O_get_version_bound() failed"); |
3874 | | |
3875 | 0 | if (ninfo.hdr.version < version) |
3876 | 0 | HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, FAIL, "disallow opened objects below 1.10"); |
3877 | 0 | } |
3878 | | |
3879 | 0 | if ((obj_glocs = (H5G_loc_t *)H5MM_malloc(grp_dset_count * sizeof(H5G_loc_t))) == NULL) |
3880 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTALLOC, FAIL, "can't allocate buffer for object group locations"); |
3881 | 0 | if ((obj_olocs = (H5O_loc_t *)H5MM_malloc(grp_dset_count * sizeof(H5O_loc_t))) == NULL) |
3882 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTALLOC, FAIL, "can't allocate buffer for object locations"); |
3883 | 0 | if ((obj_paths = (H5G_name_t *)H5MM_malloc(grp_dset_count * sizeof(H5G_name_t))) == NULL) |
3884 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTALLOC, FAIL, "can't allocate buffer for object paths"); |
3885 | | |
3886 | | /* Taking a shortcut here to use calloc to initialize obj_apl_ids to all H5P_DEFAULT. If |
3887 | | * this changes in the future we'll need to either initialize this array to all H5P_DEFAULT |
3888 | | * or ensure 0 cannot be a valid value and check for 0 at cleanup. */ |
3889 | 0 | if ((obj_apl_ids = (hid_t *)H5MM_calloc(grp_dset_count * sizeof(hid_t))) == NULL) |
3890 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTALLOC, FAIL, "can't allocate buffer for hid_t"); |
3891 | 0 | assert(obj_apl_ids[0] == H5P_DEFAULT); |
3892 | | |
3893 | | /* Save the VOL connector and the object wrapping context for the refresh step */ |
3894 | 0 | if (grp_dset_count > 0) { |
3895 | 0 | H5VL_object_t *vol_obj; |
3896 | | |
3897 | | /* Get the VOL object for one of the IDs */ |
3898 | 0 | if (NULL == (vol_obj = H5VL_vol_object(obj_ids[0]))) |
3899 | 0 | HGOTO_ERROR(H5E_FILE, H5E_BADTYPE, FAIL, "invalid object identifier"); |
3900 | | |
3901 | | /* Get the (top) connector for the ID */ |
3902 | 0 | vol_connector = H5VL_OBJ_CONNECTOR(vol_obj); |
3903 | 0 | } /* end if */ |
3904 | | |
3905 | | /* Gather information about opened objects (groups, datasets) in the file */ |
3906 | | /* (For refresh later on) */ |
3907 | 0 | for (u = 0; u < grp_dset_count; u++) { |
3908 | 0 | void *obj = NULL; /* VOL object */ |
3909 | 0 | H5I_type_t type; /* Type of object for the ID */ |
3910 | 0 | H5G_loc_t tmp_loc; |
3911 | | |
3912 | | /* Get object's type */ |
3913 | 0 | type = H5I_get_type(obj_ids[u]); |
3914 | | |
3915 | | /* Get the object from the VOL */ |
3916 | 0 | if (NULL == (obj = H5VL_object(obj_ids[u]))) |
3917 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_BADTYPE, FAIL, "invalid location identifier"); |
3918 | | |
3919 | | /* Get the object's access property list, if it is a dataset (access |
3920 | | * properties are not needed to reopen other object types currently) |
3921 | | */ |
3922 | 0 | switch (type) { |
3923 | 0 | case H5I_GROUP: |
3924 | | /* Access properties not needed currently */ |
3925 | 0 | break; |
3926 | | |
3927 | 0 | case H5I_DATATYPE: |
3928 | | /* Access properties not needed currently */ |
3929 | 0 | break; |
3930 | | |
3931 | 0 | case H5I_DATASET: |
3932 | | |
3933 | | /* Get dataset access properties */ |
3934 | 0 | if ((obj_apl_ids[u] = H5D_get_access_plist(obj)) < 0) |
3935 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, |
3936 | 0 | "unable to get dataset access property list"); |
3937 | 0 | break; |
3938 | | |
3939 | 0 | case H5I_MAP: |
3940 | 0 | HGOTO_ERROR(H5E_FILE, H5E_BADTYPE, FAIL, "maps not supported in native VOL connector"); |
3941 | | |
3942 | 0 | case H5I_UNINIT: |
3943 | 0 | case H5I_BADID: |
3944 | 0 | case H5I_FILE: |
3945 | 0 | case H5I_DATASPACE: |
3946 | 0 | case H5I_ATTR: |
3947 | 0 | case H5I_VFL: |
3948 | 0 | case H5I_VOL: |
3949 | 0 | case H5I_GENPROP_CLS: |
3950 | 0 | case H5I_GENPROP_LST: |
3951 | 0 | case H5I_ERROR_CLASS: |
3952 | 0 | case H5I_ERROR_MSG: |
3953 | 0 | case H5I_ERROR_STACK: |
3954 | 0 | case H5I_SPACE_SEL_ITER: |
3955 | 0 | case H5I_EVENTSET: |
3956 | 0 | case H5I_NTYPES: |
3957 | 0 | default: |
3958 | 0 | HGOTO_ERROR(H5E_FILE, H5E_BADTYPE, FAIL, |
3959 | 0 | "not a valid file object ID (dataset, group, or datatype)"); |
3960 | 0 | break; |
3961 | 0 | } /* end switch */ |
3962 | | |
3963 | | /* Set up the id's group location */ |
3964 | 0 | obj_glocs[u].oloc = &obj_olocs[u]; |
3965 | 0 | obj_glocs[u].path = &obj_paths[u]; |
3966 | 0 | H5G_loc_reset(&obj_glocs[u]); |
3967 | | |
3968 | | /* Make deep local copy of object's location information */ |
3969 | 0 | H5G_loc_real(obj, type, &tmp_loc); |
3970 | 0 | H5G_loc_copy(&obj_glocs[u], &tmp_loc, H5_COPY_DEEP); |
3971 | | |
3972 | | /* Close the object */ |
3973 | 0 | if (H5I_dec_ref(obj_ids[u]) < 0) |
3974 | 0 | HGOTO_ERROR(H5E_ID, H5E_CANTCLOSEOBJ, FAIL, "decrementing object ID failed"); |
3975 | 0 | } /* end for */ |
3976 | 0 | } /* end if */ |
3977 | | |
3978 | | /* Flush and reset the accumulator */ |
3979 | 0 | if (H5F__accum_reset(f->shared, true, false) < 0) |
3980 | 0 | HGOTO_ERROR(H5E_IO, H5E_CANTRESET, FAIL, "can't reset accumulator"); |
3981 | | |
3982 | | /* Turn on SWMR write in shared file open flags */ |
3983 | 0 | f->shared->flags |= H5F_ACC_SWMR_WRITE; |
3984 | | |
3985 | | /* Mark the file in SWMR writing mode */ |
3986 | 0 | f->shared->sblock->status_flags |= H5F_SUPER_SWMR_WRITE_ACCESS; |
3987 | | |
3988 | | /* Set up metadata read attempts */ |
3989 | 0 | f->shared->read_attempts = H5F_SWMR_METADATA_READ_ATTEMPTS; |
3990 | | |
3991 | | /* Initialize "retries" and "retries_nbins" */ |
3992 | 0 | if (H5F_set_retries(f) < 0) |
3993 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "can't set retries and retries_nbins"); |
3994 | | |
3995 | | /* Turn off usage of accumulator */ |
3996 | 0 | f->shared->feature_flags &= ~(unsigned)H5FD_FEAT_ACCUMULATE_METADATA; |
3997 | 0 | if (H5FD_set_feature_flags(f->shared->lf, f->shared->feature_flags) < 0) |
3998 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTSET, FAIL, "can't set feature_flags in VFD"); |
3999 | | |
4000 | 0 | setup = true; |
4001 | | |
4002 | | /* Place an advisory lock on the file */ |
4003 | 0 | if (H5F_USE_FILE_LOCKING(f)) { |
4004 | | /* Have to unlock on Windows as Win32 doesn't support changing the lock |
4005 | | * type (exclusive vs shared) with a second call. |
4006 | | */ |
4007 | 0 | if (H5FD_unlock(f->shared->lf) < 0) { |
4008 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTUNLOCKFILE, FAIL, "unable to unlock the file"); |
4009 | 0 | } |
4010 | 0 | if (H5FD_lock(f->shared->lf, true) < 0) { |
4011 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTLOCKFILE, FAIL, "unable to lock the file"); |
4012 | 0 | } |
4013 | 0 | } |
4014 | | |
4015 | | /* Mark superblock as dirty */ |
4016 | 0 | if (H5F_super_dirty(f) < 0) |
4017 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTMARKDIRTY, FAIL, "unable to mark superblock as dirty"); |
4018 | | |
4019 | | /* Flush the superblock */ |
4020 | 0 | if (H5F_flush_tagged_metadata(f, H5AC__SUPERBLOCK_TAG) < 0) |
4021 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTFLUSH, FAIL, "unable to flush superblock"); |
4022 | | |
4023 | | /* Evict all flushed entries in the cache except the pinned superblock */ |
4024 | 0 | if (H5F__evict_cache_entries(f) < 0) |
4025 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTFLUSH, FAIL, "unable to evict file's cached information"); |
4026 | | |
4027 | | /* Refresh (reopen) the objects (groups & datasets) in the file */ |
4028 | 0 | for (u = 0; u < grp_dset_count; u++) |
4029 | 0 | if (H5O_refresh_metadata_reopen(obj_ids[u], obj_apl_ids[u], &obj_glocs[u], vol_connector, true) < 0) |
4030 | 0 | HGOTO_ERROR(H5E_ID, H5E_CLOSEERROR, FAIL, "can't refresh-close object"); |
4031 | | |
4032 | 0 | done: |
4033 | 0 | if (ret_value < 0 && setup) { |
4034 | | /* Re-enable accumulator */ |
4035 | 0 | f->shared->feature_flags |= (unsigned)H5FD_FEAT_ACCUMULATE_METADATA; |
4036 | 0 | if (H5FD_set_feature_flags(f->shared->lf, f->shared->feature_flags) < 0) |
4037 | 0 | HDONE_ERROR(H5E_FILE, H5E_CANTSET, FAIL, "can't set feature_flags in VFD"); |
4038 | | |
4039 | | /* Reset the # of read attempts */ |
4040 | 0 | f->shared->read_attempts = H5F_METADATA_READ_ATTEMPTS; |
4041 | 0 | if (H5F_set_retries(f) < 0) |
4042 | 0 | HDONE_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "can't set retries and retries_nbins"); |
4043 | | |
4044 | | /* Un-set H5F_ACC_SWMR_WRITE in shared open flags */ |
4045 | 0 | f->shared->flags &= ~H5F_ACC_SWMR_WRITE; |
4046 | | |
4047 | | /* Unmark the file: not in SWMR writing mode */ |
4048 | 0 | f->shared->sblock->status_flags &= (uint8_t)(~H5F_SUPER_SWMR_WRITE_ACCESS); |
4049 | | |
4050 | | /* Mark superblock as dirty */ |
4051 | 0 | if (H5F_super_dirty(f) < 0) |
4052 | 0 | HDONE_ERROR(H5E_FILE, H5E_CANTMARKDIRTY, FAIL, "unable to mark superblock as dirty"); |
4053 | | |
4054 | | /* Flush the superblock */ |
4055 | 0 | if (H5F_flush_tagged_metadata(f, H5AC__SUPERBLOCK_TAG) < 0) |
4056 | 0 | HDONE_ERROR(H5E_FILE, H5E_CANTFLUSH, FAIL, "unable to flush superblock"); |
4057 | 0 | } /* end if */ |
4058 | | |
4059 | | /* Unlock the file */ |
4060 | 0 | if (H5F_USE_FILE_LOCKING(f)) |
4061 | 0 | if (H5FD_unlock(f->shared->lf) < 0) |
4062 | 0 | HDONE_ERROR(H5E_FILE, H5E_CANTUNLOCKFILE, FAIL, "unable to unlock the file"); |
4063 | | |
4064 | | /* Free memory */ |
4065 | 0 | if (obj_ids) |
4066 | 0 | H5MM_xfree(obj_ids); |
4067 | 0 | if (obj_glocs) |
4068 | 0 | H5MM_xfree(obj_glocs); |
4069 | 0 | if (obj_olocs) |
4070 | 0 | H5MM_xfree(obj_olocs); |
4071 | 0 | if (obj_paths) |
4072 | 0 | H5MM_xfree(obj_paths); |
4073 | | |
4074 | | /* Free access property lists */ |
4075 | 0 | if (obj_apl_ids) { |
4076 | 0 | for (u = 0; u < grp_dset_count; u++) |
4077 | 0 | if (obj_apl_ids[u] != H5P_DEFAULT && obj_apl_ids[u] >= 0 && H5I_dec_ref(obj_apl_ids[u]) < 0) |
4078 | 0 | HDONE_ERROR(H5E_ID, H5E_CANTDEC, FAIL, "decrementing property list ID failed"); |
4079 | 0 | H5MM_xfree(obj_apl_ids); |
4080 | 0 | } |
4081 | |
|
4082 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
4083 | 0 | } /* end H5F__start_swmr_write() */ |
4084 | | |
4085 | | /*------------------------------------------------------------------------- |
4086 | | * Function: H5F__format_convert |
4087 | | * |
4088 | | * Purpose: Private version of H5Fformat_convert |
4089 | | * |
4090 | | * Return: Success: SUCCEED |
4091 | | * Failure: FAIL |
4092 | | *------------------------------------------------------------------------- |
4093 | | */ |
4094 | | herr_t |
4095 | | H5F__format_convert(H5F_t *f) |
4096 | 0 | { |
4097 | 0 | bool mark_dirty = false; /* Whether to mark the file's superblock dirty */ |
4098 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
4099 | |
|
4100 | 0 | FUNC_ENTER_PACKAGE |
4101 | | |
4102 | | /* Sanity check */ |
4103 | 0 | assert(f); |
4104 | 0 | assert(f->shared); |
4105 | | |
4106 | | /* Check if the superblock should be downgraded */ |
4107 | 0 | if (f->shared->sblock->super_vers > HDF5_SUPERBLOCK_VERSION_V18_LATEST) { |
4108 | 0 | f->shared->sblock->super_vers = HDF5_SUPERBLOCK_VERSION_V18_LATEST; |
4109 | 0 | mark_dirty = true; |
4110 | 0 | } |
4111 | | |
4112 | | /* Check for persistent freespace manager, which needs to be downgraded */ |
4113 | 0 | if (!(f->shared->fs_strategy == H5F_FILE_SPACE_STRATEGY_DEF && |
4114 | 0 | f->shared->fs_persist == H5F_FREE_SPACE_PERSIST_DEF && |
4115 | 0 | f->shared->fs_threshold == H5F_FREE_SPACE_THRESHOLD_DEF && |
4116 | 0 | f->shared->fs_page_size == H5F_FILE_SPACE_PAGE_SIZE_DEF)) { |
4117 | | |
4118 | | /* Check to remove free-space manager info message from superblock extension */ |
4119 | 0 | if (H5_addr_defined(f->shared->sblock->ext_addr)) |
4120 | 0 | if (H5F__super_ext_remove_msg(f, H5O_FSINFO_ID) < 0) |
4121 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTRELEASE, FAIL, |
4122 | 0 | "error in removing message from superblock extension"); |
4123 | | |
4124 | | /* Close freespace manager */ |
4125 | 0 | if (H5MF_try_close(f) < 0) |
4126 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTRELEASE, FAIL, "unable to free free-space address"); |
4127 | | |
4128 | | /* Set non-persistent freespace manager */ |
4129 | 0 | f->shared->fs_strategy = H5F_FILE_SPACE_STRATEGY_DEF; |
4130 | 0 | f->shared->fs_persist = H5F_FREE_SPACE_PERSIST_DEF; |
4131 | 0 | f->shared->fs_threshold = H5F_FREE_SPACE_THRESHOLD_DEF; |
4132 | 0 | f->shared->fs_page_size = H5F_FILE_SPACE_PAGE_SIZE_DEF; |
4133 | | |
4134 | | /* Indicate that the superblock should be marked dirty */ |
4135 | 0 | mark_dirty = true; |
4136 | 0 | } /* end if */ |
4137 | | |
4138 | | /* Check if we should mark the superblock dirty */ |
4139 | 0 | if (mark_dirty) |
4140 | | /* Mark superblock as dirty */ |
4141 | 0 | if (H5F_super_dirty(f) < 0) |
4142 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTMARKDIRTY, FAIL, "unable to mark superblock as dirty"); |
4143 | | |
4144 | 0 | done: |
4145 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
4146 | 0 | } /* H5F__format_convert() */ |
4147 | | |
4148 | | /*------------------------------------------------------------------------- |
4149 | | * Function: H5F_get_file_id |
4150 | | * |
4151 | | * Purpose: The private version of H5Iget_file_id(), obtains the file |
4152 | | * ID given an object ID. |
4153 | | * |
4154 | | * Return: Success: The file ID associated with the object |
4155 | | * Failure: H5I_INVALID_HID |
4156 | | * |
4157 | | *------------------------------------------------------------------------- |
4158 | | */ |
4159 | | hid_t |
4160 | | H5F_get_file_id(H5VL_object_t *vol_obj, H5I_type_t obj_type, bool app_ref) |
4161 | 0 | { |
4162 | 0 | void *vol_obj_file = NULL; /* File object pointer */ |
4163 | 0 | H5VL_object_get_args_t vol_cb_args; /* Arguments to VOL callback */ |
4164 | 0 | H5VL_loc_params_t loc_params; /* Location parameters */ |
4165 | 0 | hid_t file_id = H5I_INVALID_HID; /* File ID for object */ |
4166 | 0 | bool vol_wrapper_set = false; /* Whether the VOL object wrapping context was set up */ |
4167 | 0 | hid_t ret_value = H5I_INVALID_HID; /* Return value */ |
4168 | |
|
4169 | 0 | FUNC_ENTER_NOAPI(H5I_INVALID_HID) |
4170 | | |
4171 | | /* Set location parameters */ |
4172 | 0 | loc_params.type = H5VL_OBJECT_BY_SELF; |
4173 | 0 | loc_params.obj_type = obj_type; |
4174 | | |
4175 | | /* Set up VOL callback arguments */ |
4176 | 0 | vol_cb_args.op_type = H5VL_OBJECT_GET_FILE; |
4177 | 0 | vol_cb_args.args.get_file.file = &vol_obj_file; |
4178 | | |
4179 | | /* Retrieve VOL file from object */ |
4180 | 0 | if (H5VL_object_get(vol_obj, &loc_params, &vol_cb_args, H5P_DATASET_XFER_DEFAULT, H5_REQUEST_NULL) < 0) |
4181 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTGET, H5I_INVALID_HID, "can't retrieve file from object"); |
4182 | | |
4183 | | /* Check if the file's ID already exists */ |
4184 | 0 | if (H5I_find_id(vol_obj_file, H5I_FILE, &file_id) < 0) |
4185 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTGET, H5I_INVALID_HID, "getting file ID failed"); |
4186 | | |
4187 | | /* If the ID does not exist, register it with the VOL connector */ |
4188 | 0 | if (H5I_INVALID_HID == file_id) { |
4189 | | /* Set wrapper info in API context */ |
4190 | 0 | if (H5VL_set_vol_wrapper(vol_obj) < 0) |
4191 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTSET, H5I_INVALID_HID, "can't set VOL wrapper info"); |
4192 | 0 | vol_wrapper_set = true; |
4193 | |
|
4194 | 0 | if ((file_id = H5VL_wrap_register(H5I_FILE, vol_obj_file, app_ref)) < 0) |
4195 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTREGISTER, H5I_INVALID_HID, "unable to register file handle"); |
4196 | 0 | } /* end if */ |
4197 | 0 | else { |
4198 | | /* Increment ref count on existing ID */ |
4199 | 0 | if (H5I_inc_ref(file_id, app_ref) < 0) |
4200 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTSET, H5I_INVALID_HID, "incrementing file ID failed"); |
4201 | 0 | } /* end else */ |
4202 | | |
4203 | | /* Set return value */ |
4204 | 0 | ret_value = file_id; |
4205 | |
|
4206 | 0 | done: |
4207 | | /* Reset object wrapping info in API context */ |
4208 | 0 | if (vol_wrapper_set && H5VL_reset_vol_wrapper() < 0) |
4209 | 0 | HDONE_ERROR(H5E_FILE, H5E_CANTRESET, H5I_INVALID_HID, "can't reset VOL wrapper info"); |
4210 | |
|
4211 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
4212 | 0 | } /* end H5F_get_file_id() */ |
4213 | | |
4214 | | /*------------------------------------------------------------------------- |
4215 | | * Function: H5F_set_min_dset_ohdr |
4216 | | * |
4217 | | * Purpose: Set the crt_dset_ohdr_flag field with a new value. |
4218 | | * |
4219 | | * Return: SUCCEED/FAIL |
4220 | | *------------------------------------------------------------------------- |
4221 | | */ |
4222 | | herr_t |
4223 | | H5F_set_min_dset_ohdr(H5F_t *f, bool minimize) |
4224 | 0 | { |
4225 | | /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */ |
4226 | 0 | FUNC_ENTER_NOAPI_NOINIT_NOERR |
4227 | | |
4228 | | /* Sanity check */ |
4229 | 0 | assert(f); |
4230 | 0 | assert(f->shared); |
4231 | |
|
4232 | 0 | f->shared->crt_dset_min_ohdr_flag = minimize; |
4233 | |
|
4234 | 0 | FUNC_LEAVE_NOAPI(SUCCEED) |
4235 | 0 | } /* H5F_set_min_dset_ohdr() */ |