Line | Count | Source (jump to first uncovered line) |
1 | | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
2 | | * Copyright by The HDF Group. * |
3 | | * All rights reserved. * |
4 | | * * |
5 | | * This file is part of HDF5. The full HDF5 copyright notice, including * |
6 | | * terms governing use, modification, and redistribution, is contained in * |
7 | | * the COPYING file, which can be found at the root of the source code * |
8 | | * distribution tree, or in https://www.hdfgroup.org/licenses. * |
9 | | * If you do not have access to either file, you may request a copy from * |
10 | | * help@hdfgroup.org. * |
11 | | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
12 | | |
13 | | #include "H5Fmodule.h" /* This source code file is part of the H5F module */ |
14 | | |
15 | | /* Packages needed by this file... */ |
16 | | #include "H5private.h" /* Generic Functions */ |
17 | | #include "H5Eprivate.h" /* Error handling */ |
18 | | #include "H5Fpkg.h" /* File access */ |
19 | | #include "H5Gprivate.h" /* Groups */ |
20 | | #include "H5MMprivate.h" /* Memory management */ |
21 | | #include "H5Pprivate.h" /* Property lists */ |
22 | | |
23 | | /* PRIVATE PROTOTYPES */ |
24 | | static void H5F__mount_count_ids_recurse(H5F_t *f, unsigned *nopen_files, unsigned *nopen_objs); |
25 | | |
26 | | /*------------------------------------------------------------------------- |
27 | | * Function: H5F__close_mounts |
28 | | * |
29 | | * Purpose: Close all mounts for a given file |
30 | | * |
31 | | * Return: Non-negative on success/Negative on failure |
32 | | * |
33 | | *------------------------------------------------------------------------- |
34 | | */ |
35 | | herr_t |
36 | | H5F__close_mounts(H5F_t *f) |
37 | 7 | { |
38 | 7 | unsigned u; /* Local index */ |
39 | 7 | herr_t ret_value = SUCCEED; /* Return value */ |
40 | | |
41 | 7 | FUNC_ENTER_PACKAGE |
42 | | |
43 | 7 | assert(f); |
44 | | |
45 | | /* Unmount all child files. Loop backwards to avoid having to adjust u when |
46 | | * a file is unmounted. Note that we rely on unsigned u "wrapping around" |
47 | | * to terminate the loop. |
48 | | */ |
49 | 7 | for (u = f->shared->mtab.nmounts - 1; u < f->shared->mtab.nmounts; u--) { |
50 | | /* Only unmount children mounted to this top level file structure */ |
51 | 0 | if (f->shared->mtab.child[u].file->parent == f) { |
52 | | /* Detach the child file from the parent file */ |
53 | 0 | f->shared->mtab.child[u].file->parent = NULL; |
54 | | |
55 | | /* Close the internal group maintaining the mount point */ |
56 | 0 | if (H5G_close(f->shared->mtab.child[u].group) < 0) |
57 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEOBJ, FAIL, "can't close child group"); |
58 | | |
59 | | /* Close the child file */ |
60 | 0 | if (H5F_try_close(f->shared->mtab.child[u].file, NULL) < 0) |
61 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "can't close child file"); |
62 | | |
63 | | /* Eliminate the mount point from the table */ |
64 | 0 | memmove(f->shared->mtab.child + u, f->shared->mtab.child + u + 1, |
65 | 0 | (f->shared->mtab.nmounts - u - 1) * sizeof(f->shared->mtab.child[0])); |
66 | 0 | f->shared->mtab.nmounts--; |
67 | 0 | f->nmounts--; |
68 | 0 | } |
69 | 0 | } |
70 | | |
71 | 7 | assert(f->nmounts == 0); |
72 | | |
73 | 7 | done: |
74 | 7 | FUNC_LEAVE_NOAPI(ret_value) |
75 | 7 | } /* end H5F__close_mounts() */ |
76 | | |
77 | | /*------------------------------------------------------------------------- |
78 | | * Function: H5F_mount |
79 | | * |
80 | | * Purpose: Mount file CHILD onto the group specified by LOC and NAME, |
81 | | * using mount properties in PLIST. CHILD must not already be |
82 | | * mouted and must not be a mount ancestor of the mount-point. |
83 | | * |
84 | | * Return: Non-negative on success/Negative on failure |
85 | | * |
86 | | *------------------------------------------------------------------------- |
87 | | */ |
88 | | herr_t |
89 | | H5F_mount(const H5G_loc_t *loc, const char *name, H5F_t *child, hid_t H5_ATTR_UNUSED plist_id) |
90 | 0 | { |
91 | 0 | H5G_t *mount_point = NULL; /*mount point group */ |
92 | 0 | H5F_t *ancestor = NULL; /*ancestor files */ |
93 | 0 | H5F_t *parent = NULL; /*file containing mount point */ |
94 | 0 | unsigned lt, rt, md; /*binary search indices */ |
95 | 0 | int cmp; /*binary search comparison value*/ |
96 | 0 | H5G_loc_t mp_loc; /* entry of mount point to be opened */ |
97 | 0 | H5G_name_t mp_path; /* Mount point group hier. path */ |
98 | 0 | H5O_loc_t mp_oloc; /* Mount point object location */ |
99 | 0 | H5G_loc_t root_loc; /* Group location of root of file to mount */ |
100 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
101 | |
|
102 | 0 | FUNC_ENTER_NOAPI(FAIL) |
103 | |
|
104 | 0 | assert(loc); |
105 | 0 | assert(name && *name); |
106 | 0 | assert(child); |
107 | 0 | assert(true == H5P_isa_class(plist_id, H5P_FILE_MOUNT)); |
108 | | |
109 | | /* Set up group location to fill in */ |
110 | 0 | mp_loc.oloc = &mp_oloc; |
111 | 0 | mp_loc.path = &mp_path; |
112 | 0 | H5G_loc_reset(&mp_loc); |
113 | | |
114 | | /* |
115 | | * Check that the child isn't mounted, that the mount point exists, that |
116 | | * the mount point wasn't reached via external link, that |
117 | | * the parent & child files have the same file close degree, and |
118 | | * that the mount wouldn't introduce a cycle in the mount tree. |
119 | | */ |
120 | 0 | if (child->parent) |
121 | 0 | HGOTO_ERROR(H5E_FILE, H5E_MOUNT, FAIL, "file is already mounted"); |
122 | 0 | if (H5G_loc_find(loc, name, &mp_loc) < 0) |
123 | 0 | HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "group not found"); |
124 | | /* If the mount location is holding its file open, that file will close |
125 | | * and remove the mount as soon as we exit this function. Prevent the |
126 | | * user from doing this. |
127 | | */ |
128 | 0 | if (mp_loc.oloc->holding_file != false) |
129 | 0 | HGOTO_ERROR(H5E_FILE, H5E_MOUNT, FAIL, "mount path cannot contain links to external files"); |
130 | | |
131 | | /* Open the mount point group */ |
132 | 0 | if (NULL == (mount_point = H5G_open(&mp_loc))) |
133 | 0 | HGOTO_ERROR(H5E_FILE, H5E_MOUNT, FAIL, "mount point not found"); |
134 | | |
135 | | /* Check if the proposed mount point group is already a mount point */ |
136 | 0 | if (H5G_MOUNTED(mount_point)) |
137 | 0 | HGOTO_ERROR(H5E_FILE, H5E_MOUNT, FAIL, "mount point is already in use"); |
138 | | |
139 | | /* Retrieve information from the mount point group */ |
140 | | /* (Some of which we had before but was reset in mp_loc when the group |
141 | | * "took over" the group location - QAK) |
142 | | */ |
143 | 0 | parent = H5G_fileof(mount_point); |
144 | 0 | assert(parent); |
145 | 0 | mp_loc.oloc = H5G_oloc(mount_point); |
146 | 0 | assert(mp_loc.oloc); |
147 | 0 | mp_loc.path = H5G_nameof(mount_point); |
148 | 0 | assert(mp_loc.path); |
149 | 0 | for (ancestor = parent; ancestor; ancestor = ancestor->parent) |
150 | 0 | if (ancestor->shared == child->shared) |
151 | 0 | HGOTO_ERROR(H5E_FILE, H5E_MOUNT, FAIL, "mount would introduce a cycle"); |
152 | | |
153 | | /* Make certain that the parent & child files have the same "file close degree" */ |
154 | 0 | if (parent->shared->fc_degree != child->shared->fc_degree) |
155 | 0 | HGOTO_ERROR(H5E_FILE, H5E_MOUNT, FAIL, "mounted file has different file close degree than parent"); |
156 | | |
157 | | /* |
158 | | * Use a binary search to locate the position that the child should be |
159 | | * inserted into the parent mount table. At the end of this paragraph |
160 | | * `md' will be the index where the child should be inserted. |
161 | | */ |
162 | 0 | lt = md = 0; |
163 | 0 | rt = parent->shared->mtab.nmounts; |
164 | 0 | cmp = -1; |
165 | 0 | while (lt < rt && cmp) { |
166 | 0 | H5O_loc_t *oloc; /*temporary symbol table entry */ |
167 | |
|
168 | 0 | md = (lt + rt) / 2; |
169 | 0 | oloc = H5G_oloc(parent->shared->mtab.child[md].group); |
170 | 0 | cmp = H5_addr_cmp(mp_loc.oloc->addr, oloc->addr); |
171 | 0 | if (cmp < 0) |
172 | 0 | rt = md; |
173 | 0 | else if (cmp > 0) |
174 | 0 | lt = md + 1; |
175 | 0 | } |
176 | 0 | if (cmp > 0) |
177 | 0 | md++; |
178 | 0 | if (!cmp) |
179 | 0 | HGOTO_ERROR(H5E_FILE, H5E_MOUNT, FAIL, "mount point is already in use"); |
180 | | |
181 | | /* Make room in the table */ |
182 | 0 | if (parent->shared->mtab.nmounts >= parent->shared->mtab.nalloc) { |
183 | 0 | unsigned n = MAX(16, 2 * parent->shared->mtab.nalloc); |
184 | 0 | H5F_mount_t *x = (H5F_mount_t *)H5MM_realloc(parent->shared->mtab.child, |
185 | 0 | n * sizeof(parent->shared->mtab.child[0])); |
186 | |
|
187 | 0 | if (!x) |
188 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for mount table"); |
189 | 0 | parent->shared->mtab.child = x; |
190 | 0 | parent->shared->mtab.nalloc = n; |
191 | 0 | } |
192 | | |
193 | | /* Insert into table */ |
194 | 0 | memmove(parent->shared->mtab.child + md + 1, parent->shared->mtab.child + md, |
195 | 0 | (parent->shared->mtab.nmounts - md) * sizeof(parent->shared->mtab.child[0])); |
196 | 0 | parent->shared->mtab.nmounts++; |
197 | 0 | parent->nmounts++; |
198 | 0 | parent->shared->mtab.child[md].group = mount_point; |
199 | 0 | parent->shared->mtab.child[md].file = child; |
200 | 0 | child->parent = parent; |
201 | | |
202 | | /* Set the group's mountpoint flag */ |
203 | 0 | if (H5G_mount(parent->shared->mtab.child[md].group) < 0) |
204 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEOBJ, FAIL, "unable to set group mounted flag"); |
205 | | |
206 | | /* Get the group location for the root group in the file to unmount */ |
207 | 0 | if (NULL == (root_loc.oloc = H5G_oloc(child->shared->root_grp))) |
208 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get object location for root group"); |
209 | 0 | if (NULL == (root_loc.path = H5G_nameof(child->shared->root_grp))) |
210 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get path for root group"); |
211 | | |
212 | | /* Search the open IDs and replace names for mount operation */ |
213 | | /* We pass H5G_UNKNOWN as object type; search all IDs */ |
214 | 0 | if (H5G_name_replace(NULL, H5G_NAME_MOUNT, mp_loc.oloc->file, mp_loc.path->full_path_r, |
215 | 0 | root_loc.oloc->file, root_loc.path->full_path_r) < 0) |
216 | 0 | HGOTO_ERROR(H5E_FILE, H5E_MOUNT, FAIL, "unable to replace name"); |
217 | | |
218 | 0 | done: |
219 | 0 | if (ret_value < 0) { |
220 | 0 | if (mount_point) { |
221 | 0 | if (H5G_close(mount_point) < 0) |
222 | 0 | HDONE_ERROR(H5E_FILE, H5E_CANTCLOSEOBJ, FAIL, "unable to close mounted group"); |
223 | 0 | } |
224 | 0 | else { |
225 | 0 | if (H5G_loc_free(&mp_loc) < 0) |
226 | 0 | HDONE_ERROR(H5E_SYM, H5E_CANTRELEASE, FAIL, "unable to free mount location"); |
227 | 0 | } |
228 | 0 | } |
229 | |
|
230 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
231 | 0 | } /* end H5F_mount() */ |
232 | | |
233 | | /*------------------------------------------------------------------------- |
234 | | * Function: H5F_unmount |
235 | | * |
236 | | * Purpose: Unmount the child which is mounted at the group specified by |
237 | | * LOC and NAME or fail if nothing is mounted there. Neither |
238 | | * file is closed. |
239 | | * |
240 | | * Because the mount point is specified by name and opened as a |
241 | | * group, the H5G_namei() will resolve it to the root of the |
242 | | * mounted file, not the group where the file is mounted. |
243 | | * |
244 | | * Return: Non-negative on success/Negative on failure |
245 | | * |
246 | | *------------------------------------------------------------------------- |
247 | | */ |
248 | | herr_t |
249 | | H5F_unmount(const H5G_loc_t *loc, const char *name) |
250 | 0 | { |
251 | 0 | H5G_t *child_group = NULL; /* Child's group in parent mtab */ |
252 | 0 | H5F_t *child = NULL; /*mounted file */ |
253 | 0 | H5F_t *parent = NULL; /*file where mounted */ |
254 | 0 | H5O_loc_t *mnt_oloc; /* symbol table entry for root of mounted file */ |
255 | 0 | H5G_name_t mp_path; /* Mount point group hier. path */ |
256 | 0 | H5O_loc_t mp_oloc; /* Mount point object location */ |
257 | 0 | H5G_loc_t mp_loc; /* entry used to open mount point*/ |
258 | 0 | bool mp_loc_setup = false; /* Whether mount point location is set up */ |
259 | 0 | H5G_loc_t root_loc; /* Group location of root of file to unmount */ |
260 | 0 | int child_idx; /* Index of child in parent's mtab */ |
261 | 0 | herr_t ret_value = SUCCEED; /*return value */ |
262 | |
|
263 | 0 | FUNC_ENTER_NOAPI(FAIL) |
264 | |
|
265 | 0 | assert(loc); |
266 | 0 | assert(name && *name); |
267 | | |
268 | | /* Set up mount point location to fill in */ |
269 | 0 | mp_loc.oloc = &mp_oloc; |
270 | 0 | mp_loc.path = &mp_path; |
271 | 0 | H5G_loc_reset(&mp_loc); |
272 | | |
273 | | /* |
274 | | * Get the mount point, or more precisely the root of the mounted file. |
275 | | * If we get the root group and the file has a parent in the mount tree, |
276 | | * then we must have found the mount point. |
277 | | */ |
278 | 0 | if (H5G_loc_find(loc, name, &mp_loc /*out*/) < 0) |
279 | 0 | HGOTO_ERROR(H5E_FILE, H5E_NOTFOUND, FAIL, "group not found"); |
280 | 0 | mp_loc_setup = true; |
281 | 0 | child = mp_loc.oloc->file; |
282 | 0 | mnt_oloc = H5G_oloc(child->shared->root_grp); |
283 | 0 | child_idx = -1; |
284 | |
|
285 | 0 | if (child->parent && H5_addr_eq(mp_oloc.addr, mnt_oloc->addr)) { |
286 | 0 | unsigned u; /*counters */ |
287 | | |
288 | | /* |
289 | | * We've been given the root group of the child. We do a reverse |
290 | | * lookup in the parent's mount table to find the correct entry. |
291 | | */ |
292 | 0 | parent = child->parent; |
293 | 0 | for (u = 0; u < parent->shared->mtab.nmounts; u++) { |
294 | 0 | if (parent->shared->mtab.child[u].file->shared == child->shared) { |
295 | | /* Found the correct index */ |
296 | 0 | child_idx = (int)u; |
297 | 0 | break; |
298 | 0 | } |
299 | 0 | } |
300 | 0 | } |
301 | 0 | else { |
302 | 0 | unsigned lt, rt, md = 0; /*binary search indices */ |
303 | 0 | int cmp; /*binary search comparison value*/ |
304 | | |
305 | | /* We've been given the mount point in the parent. We use a binary |
306 | | * search in the parent to locate the mounted file, if any. |
307 | | */ |
308 | 0 | parent = child; /*we guessed wrong*/ |
309 | 0 | lt = 0; |
310 | 0 | rt = parent->shared->mtab.nmounts; |
311 | 0 | cmp = -1; |
312 | |
|
313 | 0 | while (lt < rt && cmp) { |
314 | 0 | md = (lt + rt) / 2; |
315 | 0 | mnt_oloc = H5G_oloc(parent->shared->mtab.child[md].group); |
316 | 0 | cmp = H5_addr_cmp(mp_oloc.addr, mnt_oloc->addr); |
317 | 0 | if (cmp < 0) |
318 | 0 | rt = md; |
319 | 0 | else |
320 | 0 | lt = md + 1; |
321 | 0 | } |
322 | |
|
323 | 0 | if (cmp) |
324 | 0 | HGOTO_ERROR(H5E_FILE, H5E_MOUNT, FAIL, "not a mount point"); |
325 | | |
326 | | /* Found the correct index, set the info about the child */ |
327 | 0 | child_idx = (int)md; |
328 | 0 | H5G_loc_free(&mp_loc); |
329 | 0 | mp_loc_setup = false; |
330 | 0 | mp_loc.oloc = mnt_oloc; |
331 | 0 | mp_loc.path = H5G_nameof(parent->shared->mtab.child[md].group); |
332 | 0 | child = parent->shared->mtab.child[child_idx].file; |
333 | | |
334 | | /* Set the parent to be the actual parent of the discovered child. |
335 | | * Could be different due to the shared mount table. */ |
336 | 0 | parent = child->parent; |
337 | 0 | } /* end else */ |
338 | 0 | assert(child_idx >= 0); |
339 | | |
340 | | /* Save the information about the child from the mount table */ |
341 | 0 | child_group = parent->shared->mtab.child[child_idx].group; |
342 | | |
343 | | /* Get the group location for the root group in the file to unmount */ |
344 | 0 | if (NULL == (root_loc.oloc = H5G_oloc(child->shared->root_grp))) |
345 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get object location for root group"); |
346 | 0 | if (NULL == (root_loc.path = H5G_nameof(child->shared->root_grp))) |
347 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get path for root group"); |
348 | | |
349 | | /* Search the open IDs replace names to reflect unmount operation */ |
350 | 0 | if (H5G_name_replace(NULL, H5G_NAME_UNMOUNT, mp_loc.oloc->file, mp_loc.path->full_path_r, |
351 | 0 | root_loc.oloc->file, root_loc.path->full_path_r) < 0) |
352 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "unable to replace name"); |
353 | | |
354 | | /* Eliminate the mount point from the table */ |
355 | 0 | memmove(parent->shared->mtab.child + (unsigned)child_idx, |
356 | 0 | (parent->shared->mtab.child + (unsigned)child_idx) + 1, |
357 | 0 | ((parent->shared->mtab.nmounts - (unsigned)child_idx) - 1) * |
358 | 0 | sizeof(parent->shared->mtab.child[0])); |
359 | 0 | parent->shared->mtab.nmounts -= 1; |
360 | 0 | parent->nmounts -= 1; |
361 | | |
362 | | /* Unmount the child file from the parent file */ |
363 | 0 | if (H5G_unmount(child_group) < 0) |
364 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTRELEASE, FAIL, "unable to reset group mounted flag"); |
365 | 0 | if (H5G_close(child_group) < 0) |
366 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEOBJ, FAIL, "unable to close unmounted group"); |
367 | | |
368 | | /* Detach child file from parent & see if it should close */ |
369 | 0 | child->parent = NULL; |
370 | 0 | if (H5F_try_close(child, NULL) < 0) |
371 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "unable to close unmounted file"); |
372 | | |
373 | 0 | done: |
374 | | /* Free the mount point location's information, if it's been set up */ |
375 | 0 | if (mp_loc_setup) |
376 | 0 | H5G_loc_free(&mp_loc); |
377 | |
|
378 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
379 | 0 | } /* end H5F_unmount() */ |
380 | | |
381 | | /*------------------------------------------------------------------------- |
382 | | * Function: H5F_is_mount |
383 | | * |
384 | | * Purpose: Check if a file is mounted within another file. |
385 | | * |
386 | | * Return: Success: true/false |
387 | | * Failure: (can't happen) |
388 | | * |
389 | | *------------------------------------------------------------------------- |
390 | | */ |
391 | | bool |
392 | | H5F_is_mount(const H5F_t *file) |
393 | 221 | { |
394 | 221 | bool ret_value = false; /* Return value */ |
395 | | |
396 | 221 | FUNC_ENTER_NOAPI_NOINIT_NOERR |
397 | | |
398 | 221 | assert(file); |
399 | | |
400 | 221 | if (file->parent != NULL) |
401 | 0 | ret_value = true; |
402 | 221 | else |
403 | 221 | ret_value = false; |
404 | | |
405 | 221 | FUNC_LEAVE_NOAPI(ret_value) |
406 | 221 | } /* end H5F_is_mount() */ |
407 | | |
408 | | /*------------------------------------------------------------------------- |
409 | | * Function: H5F__mount_count_ids_recurse |
410 | | * |
411 | | * Purpose: Helper routine for counting number of open IDs in mount |
412 | | * hierarchy. |
413 | | * |
414 | | * Return: void |
415 | | * |
416 | | *------------------------------------------------------------------------- |
417 | | */ |
418 | | static void |
419 | | H5F__mount_count_ids_recurse(H5F_t *f, unsigned *nopen_files, unsigned *nopen_objs) |
420 | 90 | { |
421 | 90 | unsigned u; /* Local index value */ |
422 | | |
423 | 90 | FUNC_ENTER_PACKAGE_NOERR |
424 | | |
425 | | /* Sanity check */ |
426 | 90 | assert(f); |
427 | 90 | assert(nopen_files); |
428 | 90 | assert(nopen_objs); |
429 | | |
430 | | /* If this file is still open, increment number of file IDs open */ |
431 | 90 | if (H5F_ID_EXISTS(f)) |
432 | 83 | *nopen_files += 1; |
433 | | |
434 | | /* Increment number of open objects in file |
435 | | * (Reduced by number of mounted files, we'll add back in the mount point's |
436 | | * groups later, if they are open) |
437 | | */ |
438 | 90 | *nopen_objs += (f->nopen_objs - f->nmounts); |
439 | | |
440 | | /* Iterate over files mounted in this file and add in their open ID counts also */ |
441 | 90 | for (u = 0; u < f->shared->mtab.nmounts; u++) { |
442 | | /* Only recurse on children mounted to this top level file structure */ |
443 | 0 | if (f->shared->mtab.child[u].file->parent == f) { |
444 | | /* Increment the open object count if the mount point group has an open ID */ |
445 | 0 | if (H5G_get_shared_count(f->shared->mtab.child[u].group) > 1) |
446 | 0 | *nopen_objs += 1; |
447 | |
|
448 | 0 | H5F__mount_count_ids_recurse(f->shared->mtab.child[u].file, nopen_files, nopen_objs); |
449 | 0 | } |
450 | 0 | } |
451 | | |
452 | 90 | FUNC_LEAVE_NOAPI_VOID |
453 | 90 | } /* end H5F__mount_count_ids_recurse() */ |
454 | | |
455 | | /*------------------------------------------------------------------------- |
456 | | * Function: H5F__mount_count_ids |
457 | | * |
458 | | * Purpose: Count the number of open file & object IDs in a mount hierarchy |
459 | | * |
460 | | * Return: SUCCEED/FAIL |
461 | | * |
462 | | *------------------------------------------------------------------------- |
463 | | */ |
464 | | herr_t |
465 | | H5F__mount_count_ids(H5F_t *f, unsigned *nopen_files, unsigned *nopen_objs) |
466 | 90 | { |
467 | 90 | FUNC_ENTER_PACKAGE_NOERR |
468 | | |
469 | | /* Sanity check */ |
470 | 90 | assert(f); |
471 | 90 | assert(nopen_files); |
472 | 90 | assert(nopen_objs); |
473 | | |
474 | | /* Find the top file in the mounting hierarchy */ |
475 | 90 | while (f->parent) |
476 | 0 | f = f->parent; |
477 | | |
478 | | /* Count open IDs in the hierarchy */ |
479 | 90 | H5F__mount_count_ids_recurse(f, nopen_files, nopen_objs); |
480 | | |
481 | 90 | FUNC_LEAVE_NOAPI(SUCCEED) |
482 | 90 | } /* end H5F__mount_count_ids() */ |
483 | | |
484 | | /*------------------------------------------------------------------------- |
485 | | * Function: H5F__flush_mounts_recurse |
486 | | * |
487 | | * Purpose: Flush a mount hierarchy, recursively |
488 | | * |
489 | | * Return: SUCCEED/FAIL |
490 | | * |
491 | | *------------------------------------------------------------------------- |
492 | | */ |
493 | | static herr_t |
494 | | H5F__flush_mounts_recurse(H5F_t *f) |
495 | 0 | { |
496 | 0 | unsigned nerrors = 0; /* Errors from recursive flushes */ |
497 | 0 | unsigned u; /* Index variable */ |
498 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
499 | |
|
500 | 0 | FUNC_ENTER_PACKAGE |
501 | | |
502 | | /* Sanity check */ |
503 | 0 | assert(f); |
504 | | |
505 | | /* Flush all child files, not stopping for errors */ |
506 | 0 | for (u = 0; u < f->shared->mtab.nmounts; u++) |
507 | 0 | if (H5F__flush_mounts_recurse(f->shared->mtab.child[u].file) < 0) |
508 | 0 | nerrors++; |
509 | | |
510 | | /* Call the "real" flush routine, for this file */ |
511 | 0 | if (H5F__flush(f) < 0) |
512 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTFLUSH, FAIL, "unable to flush file's cached information"); |
513 | | |
514 | | /* Check flush errors for children - errors are already on the stack */ |
515 | 0 | if (nerrors) |
516 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTFLUSH, FAIL, "unable to flush file's child mounts"); |
517 | | |
518 | 0 | done: |
519 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
520 | 0 | } /* end H5F__flush_mounts_recurse() */ |
521 | | |
522 | | /*------------------------------------------------------------------------- |
523 | | * Function: H5F_flush_mounts |
524 | | * |
525 | | * Purpose: Flush a mount hierarchy |
526 | | * |
527 | | * Return: SUCCEED/FAIL |
528 | | * |
529 | | *------------------------------------------------------------------------- |
530 | | */ |
531 | | herr_t |
532 | | H5F_flush_mounts(H5F_t *f) |
533 | 0 | { |
534 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
535 | |
|
536 | 0 | FUNC_ENTER_NOAPI(FAIL) |
537 | | |
538 | | /* Sanity check */ |
539 | 0 | assert(f); |
540 | | |
541 | | /* Find the top file in the mount hierarchy */ |
542 | 0 | while (f->parent) |
543 | 0 | f = f->parent; |
544 | | |
545 | | /* Flush the mounted file hierarchy */ |
546 | 0 | if (H5F__flush_mounts_recurse(f) < 0) |
547 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTFLUSH, FAIL, "unable to flush mounted file hierarchy"); |
548 | | |
549 | 0 | done: |
550 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
551 | 0 | } /* end H5F_flush_mounts() */ |
552 | | |
553 | | /*------------------------------------------------------------------------- |
554 | | * Function: H5F_traverse_mount |
555 | | * |
556 | | * Purpose: If LNK is a mount point then copy the entry for the root |
557 | | * group of the mounted file into LNK. |
558 | | * |
559 | | * Return: Non-negative on success/Negative on failure |
560 | | * |
561 | | *------------------------------------------------------------------------- |
562 | | */ |
563 | | herr_t |
564 | | H5F_traverse_mount(H5O_loc_t *oloc /*in,out*/) |
565 | 140 | { |
566 | 140 | H5F_t *parent = oloc->file, /* File of object */ |
567 | 140 | *child = NULL; /* Child file */ |
568 | 140 | unsigned lt, rt, md = 0; /* Binary search indices */ |
569 | 140 | int cmp; |
570 | 140 | H5O_loc_t *mnt_oloc = NULL; /* Object location for mount points */ |
571 | 140 | herr_t ret_value = SUCCEED; /* Return value */ |
572 | | |
573 | 140 | FUNC_ENTER_NOAPI(FAIL) |
574 | | |
575 | | /* Sanity check */ |
576 | 140 | assert(oloc); |
577 | | |
578 | | /* |
579 | | * The loop is necessary because we might have file1 mounted at the root |
580 | | * of file2, which is mounted somewhere in file3. |
581 | | */ |
582 | 140 | do { |
583 | | /* |
584 | | * Use a binary search to find the potential mount point in the mount |
585 | | * table for the parent |
586 | | */ |
587 | 140 | lt = 0; |
588 | 140 | rt = parent->shared->mtab.nmounts; |
589 | 140 | cmp = -1; |
590 | 140 | while (lt < rt && cmp) { |
591 | 0 | md = (lt + rt) / 2; |
592 | 0 | mnt_oloc = H5G_oloc(parent->shared->mtab.child[md].group); |
593 | 0 | cmp = H5_addr_cmp(oloc->addr, mnt_oloc->addr); |
594 | 0 | if (cmp < 0) |
595 | 0 | rt = md; |
596 | 0 | else |
597 | 0 | lt = md + 1; |
598 | 0 | } |
599 | | |
600 | | /* Copy root info over to ENT */ |
601 | 140 | if (0 == cmp) { |
602 | | /* Get the child file */ |
603 | 0 | child = parent->shared->mtab.child[md].file; |
604 | | |
605 | | /* Get the location for the root group in the child's file */ |
606 | 0 | mnt_oloc = H5G_oloc(child->shared->root_grp); |
607 | | |
608 | | /* Release the mount point */ |
609 | 0 | if (H5O_loc_free(oloc) < 0) |
610 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTFREE, FAIL, "unable to free object location"); |
611 | | |
612 | | /* Copy the entry for the root group */ |
613 | 0 | if (H5O_loc_copy_deep(oloc, mnt_oloc) < 0) |
614 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTCOPY, FAIL, "unable to copy object location"); |
615 | | |
616 | | /* In case the shared root group info points to a different file handle |
617 | | * than the child, modify oloc */ |
618 | 0 | oloc->file = child; |
619 | | |
620 | | /* Switch to child's file */ |
621 | 0 | parent = child; |
622 | 0 | } /* end if */ |
623 | 140 | } while (!cmp); |
624 | | |
625 | 140 | done: |
626 | 140 | FUNC_LEAVE_NOAPI(ret_value) |
627 | 140 | } /* end H5F_traverse_mount() */ |