Coverage Report

Created: 2024-06-18 06:29

/src/hdf5/src/H5Fmount.c
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() */