Coverage Report

Created: 2025-08-28 06:37

/src/hdf5/src/H5FDmulti.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 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
 * Purpose:    Implements a file driver which dispatches I/O requests to
15
 *        other file drivers depending on the purpose of the address
16
 *        region being accessed. For instance, all meta-data could be
17
 *        place in one file while all raw data goes to some other file.
18
 *        This also serves as an example of coding a complex file driver,
19
 *        therefore, it should not use any non-public definitions.
20
 */
21
#include <assert.h>
22
#include <stdlib.h>
23
#include <string.h>
24
25
#include "hdf5.h"
26
27
#include "H5warnings.h"
28
29
#ifndef false
30
#define false 0
31
#endif
32
#ifndef true
33
#define true 1
34
#endif
35
36
/* Windows doesn't like some POSIX names and redefines them with an
37
 * underscore
38
 */
39
#ifdef _WIN32
40
#define my_strdup _strdup
41
#else
42
0
#define my_strdup strdup
43
#endif
44
45
/* Loop through all mapped files */
46
#define UNIQUE_MEMBERS_CORE(MAP, ITER, SEEN, LOOPVAR)                                                        \
47
0
    {                                                                                                        \
48
0
        H5FD_mem_t ITER, LOOPVAR;                                                                            \
49
0
        unsigned   SEEN[H5FD_MEM_NTYPES];                                                                    \
50
0
                                                                                                             \
51
0
        memset(SEEN, 0, sizeof SEEN);                                                                        \
52
0
        for (ITER = H5FD_MEM_SUPER; ITER < H5FD_MEM_NTYPES; ITER = (H5FD_mem_t)(ITER + 1)) {                 \
53
0
            LOOPVAR = MAP[ITER];                                                                             \
54
0
            if (H5FD_MEM_DEFAULT == LOOPVAR)                                                                 \
55
0
                LOOPVAR = ITER;                                                                              \
56
0
            assert(LOOPVAR > 0 && LOOPVAR < H5FD_MEM_NTYPES);                                                \
57
0
            if (SEEN[LOOPVAR]++)                                                                             \
58
0
                continue;
59
60
/* Need two front-ends, since they are nested sometimes */
61
0
#define UNIQUE_MEMBERS(MAP, LOOPVAR)  UNIQUE_MEMBERS_CORE(MAP, _unmapped, _seen, LOOPVAR)
62
0
#define UNIQUE_MEMBERS2(MAP, LOOPVAR) UNIQUE_MEMBERS_CORE(MAP, _unmapped2, _seen2, LOOPVAR)
63
64
#define ALL_MEMBERS(LOOPVAR)                                                                                 \
65
0
    {                                                                                                        \
66
0
        H5FD_mem_t LOOPVAR;                                                                                  \
67
0
        for (LOOPVAR = H5FD_MEM_DEFAULT; LOOPVAR < H5FD_MEM_NTYPES; LOOPVAR = (H5FD_mem_t)(LOOPVAR + 1)) {
68
69
#define END_MEMBERS                                                                                          \
70
0
    }                                                                                                        \
71
0
    }
72
73
#define H5FD_MULT_MAX_FILE_NAME_LEN 1024
74
75
/* Driver-specific file access properties */
76
typedef struct H5FD_multi_fapl_t {
77
    H5FD_mem_t memb_map[H5FD_MEM_NTYPES];  /*memory usage map              */
78
    hid_t      memb_fapl[H5FD_MEM_NTYPES]; /*member access properties      */
79
    char      *memb_name[H5FD_MEM_NTYPES]; /*name generators               */
80
    haddr_t    memb_addr[H5FD_MEM_NTYPES]; /*starting addr per member      */
81
    bool       relax;                      /*less stringent error checking */
82
} H5FD_multi_fapl_t;
83
84
/*
85
 * The description of a file belonging to this driver. The file access
86
 * properties and member names do not have to be copied into this struct
87
 * since they will be held open by the file access property list which is
88
 * copied into the parent file struct in H5F_open().
89
 */
90
typedef struct H5FD_multi_t {
91
    H5FD_t            pub;                        /*public stuff, must be first               */
92
    H5FD_multi_fapl_t fa;                         /*driver-specific file access properties    */
93
    haddr_t           memb_next[H5FD_MEM_NTYPES]; /*addr of next member                       */
94
    H5FD_t           *memb[H5FD_MEM_NTYPES];      /*member pointers                           */
95
    haddr_t           memb_eoa[H5FD_MEM_NTYPES];  /*EOA for individual files,
96
                                                   *end of allocated addresses.  v1.6 library
97
                                                   *have the EOA for the entire file. But it's
98
                                                   *meaningless for MULTI file.  We replaced it
99
                                                   *with the EOAs for individual files        */
100
    unsigned flags;                               /*file open flags saved for debugging       */
101
    char    *name;                                /*name passed to H5Fopen or H5Fcreate       */
102
} H5FD_multi_t;
103
104
/* Driver specific data transfer properties */
105
typedef struct H5FD_multi_dxpl_t {
106
    hid_t memb_dxpl[H5FD_MEM_NTYPES]; /*member data xfer properties*/
107
} H5FD_multi_dxpl_t;
108
109
/* Private functions */
110
static herr_t H5FD_split_populate_config(const char *meta_ext, hid_t meta_plist_id, const char *raw_ext,
111
                                         hid_t raw_plist_id, bool relax, H5FD_multi_fapl_t *fa_out);
112
static herr_t H5FD_multi_populate_config(const H5FD_mem_t *memb_map, const hid_t *memb_fapl,
113
                                         const char *const *memb_name, const haddr_t *memb_addr, bool relax,
114
                                         H5FD_multi_fapl_t *fa_out);
115
static int    compute_next(H5FD_multi_t *file);
116
static int    open_members(H5FD_multi_t *file);
117
118
/* Callback prototypes */
119
static hsize_t H5FD_multi_sb_size(H5FD_t *file);
120
static herr_t  H5FD_multi_sb_encode(H5FD_t *file, char *name /*out*/, unsigned char *buf /*out*/);
121
static herr_t  H5FD_multi_sb_decode(H5FD_t *file, const char *name, const unsigned char *buf);
122
static void   *H5FD_multi_fapl_get(H5FD_t *file);
123
static void   *H5FD_multi_fapl_copy(const void *_old_fa);
124
static herr_t  H5FD_multi_fapl_free(void *_fa);
125
static H5FD_t *H5FD_multi_open(const char *name, unsigned flags, hid_t fapl_id, haddr_t maxaddr);
126
static herr_t  H5FD_multi_close(H5FD_t *_file);
127
static int     H5FD_multi_cmp(const H5FD_t *_f1, const H5FD_t *_f2);
128
static herr_t  H5FD_multi_query(const H5FD_t *_f1, unsigned long *flags);
129
static herr_t  H5FD_multi_get_type_map(const H5FD_t *file, H5FD_mem_t *type_map);
130
static haddr_t H5FD_multi_get_eoa(const H5FD_t *_file, H5FD_mem_t type);
131
static herr_t  H5FD_multi_set_eoa(H5FD_t *_file, H5FD_mem_t type, haddr_t eoa);
132
static haddr_t H5FD_multi_get_eof(const H5FD_t *_file, H5FD_mem_t type);
133
static herr_t  H5FD_multi_get_handle(H5FD_t *_file, hid_t fapl, void **file_handle);
134
static haddr_t H5FD_multi_alloc(H5FD_t *_file, H5FD_mem_t type, hid_t dxpl_id, hsize_t size);
135
static herr_t  H5FD_multi_free(H5FD_t *_file, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr, hsize_t size);
136
static herr_t  H5FD_multi_read(H5FD_t *_file, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr, size_t size,
137
                               void *_buf /*out*/);
138
static herr_t  H5FD_multi_write(H5FD_t *_file, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr, size_t size,
139
                                const void *_buf);
140
static herr_t  H5FD_multi_flush(H5FD_t *_file, hid_t dxpl_id, bool closing);
141
static herr_t  H5FD_multi_truncate(H5FD_t *_file, hid_t dxpl_id, bool closing);
142
static herr_t  H5FD_multi_lock(H5FD_t *_file, bool rw);
143
static herr_t  H5FD_multi_unlock(H5FD_t *_file);
144
static herr_t  H5FD_multi_delete(const char *filename, hid_t fapl_id);
145
static herr_t  H5FD_multi_ctl(H5FD_t *_file, uint64_t op_code, uint64_t flags, const void *input,
146
                              void **output);
147
148
/* The class struct */
149
const H5FD_class_t H5FD_multi_g = {
150
    H5FD_CLASS_VERSION,        /* struct version    */
151
    H5_VFD_MULTI,              /* value             */
152
    "multi",                   /* name              */
153
    HADDR_MAX,                 /* maxaddr           */
154
    H5F_CLOSE_WEAK,            /* fc_degree         */
155
    NULL,                      /* terminate         */
156
    H5FD_multi_sb_size,        /* sb_size           */
157
    H5FD_multi_sb_encode,      /* sb_encode         */
158
    H5FD_multi_sb_decode,      /* sb_decode         */
159
    sizeof(H5FD_multi_fapl_t), /* fapl_size         */
160
    H5FD_multi_fapl_get,       /* fapl_get          */
161
    H5FD_multi_fapl_copy,      /* fapl_copy         */
162
    H5FD_multi_fapl_free,      /* fapl_free         */
163
    0,                         /* dxpl_size         */
164
    NULL,                      /* dxpl_copy         */
165
    NULL,                      /* dxpl_free         */
166
    H5FD_multi_open,           /* open              */
167
    H5FD_multi_close,          /* close             */
168
    H5FD_multi_cmp,            /* cmp               */
169
    H5FD_multi_query,          /* query             */
170
    H5FD_multi_get_type_map,   /* get_type_map      */
171
    H5FD_multi_alloc,          /* alloc             */
172
    H5FD_multi_free,           /* free              */
173
    H5FD_multi_get_eoa,        /* get_eoa           */
174
    H5FD_multi_set_eoa,        /* set_eoa           */
175
    H5FD_multi_get_eof,        /* get_eof           */
176
    H5FD_multi_get_handle,     /* get_handle        */
177
    H5FD_multi_read,           /* read              */
178
    H5FD_multi_write,          /* write             */
179
    NULL,                      /*read_vector        */
180
    NULL,                      /*write_vector       */
181
    NULL,                      /* read_selection    */
182
    NULL,                      /* write_selection   */
183
    H5FD_multi_flush,          /* flush             */
184
    H5FD_multi_truncate,       /* truncate          */
185
    H5FD_multi_lock,           /* lock              */
186
    H5FD_multi_unlock,         /* unlock            */
187
    H5FD_multi_delete,         /* del               */
188
    H5FD_multi_ctl,            /* ctl               */
189
    H5FD_FLMAP_DEFAULT         /* fl_map            */
190
};
191
192
/*-------------------------------------------------------------------------
193
 * Function:    H5Pset_fapl_split
194
 *
195
 * Purpose:    Compatibility function. Makes the multi driver act like the
196
 *        old split driver which stored meta data in one file and raw
197
 *        data in another file.
198
 *
199
 * Return:    Success:    0
200
 *
201
 *            Failure:    -1
202
 *
203
 *-------------------------------------------------------------------------
204
 */
205
herr_t
206
H5Pset_fapl_split(hid_t fapl, const char *meta_ext, hid_t meta_plist_id, const char *raw_ext,
207
                  hid_t raw_plist_id)
208
0
{
209
0
    H5FD_multi_fapl_t fa;
210
211
    /* Clear the error stack */
212
0
    H5Eclear2(H5E_DEFAULT);
213
214
0
    if (H5FD_split_populate_config(meta_ext, meta_plist_id, raw_ext, raw_plist_id, true, &fa) < 0)
215
0
        H5Epush_ret(__func__, H5E_ERR_CLS, H5E_INTERNAL, H5E_CANTSET,
216
0
                    "can't setup split driver configuration", -1);
217
218
0
    return H5Pset_driver(fapl, H5FD_MULTI, &fa);
219
0
}
220
221
/*-------------------------------------------------------------------------
222
 * Function:    H5Pset_fapl_multi
223
 *
224
 * Purpose:    Sets the file access property list FAPL_ID to use the multi
225
 *        driver. The MEMB_MAP array maps memory usage types to other
226
 *        memory usage types and is the mechanism which allows the
227
 *        caller to specify how many files are created. The array
228
 *        contains H5FD_MEM_NTYPES entries which are either the value
229
 *        H5FD_MEM_DEFAULT or a memory usage type and the number of
230
 *        unique values determines the number of files which are
231
 *        opened.  For each memory usage type which will be associated
232
 *        with a file the MEMB_FAPL array should have a property list
233
 *        and the MEMB_NAME array should be a name generator (a
234
 *        printf-style format with a %s which will be replaced with the
235
 *        name passed to H5FDopen(), usually from H5Fcreate() or
236
 *        H5Fopen()).
237
 *
238
 *        If RELAX is set then opening an existing file for read-only
239
 *        access will not fail if some file members are missing.  This
240
 *        allows a file to be accessed in a limited sense if just the
241
 *        meta data is available.
242
 *
243
 * Defaults:    Default values for each of the optional arguments are:
244
 *
245
 *        memb_map:    The default member map has the value
246
 *                H5FD_MEM_DEFAULT for each element.
247
 *
248
 *        memb_fapl:    The value H5P_DEFAULT for each element.
249
 *
250
 *        memb_name:    The string `%s-X.h5' where `X' is one of the
251
 *                letters `s' (H5FD_MEM_SUPER),
252
 *                `b' (H5FD_MEM_BTREE), `r' (H5FD_MEM_DRAW),
253
 *                 `g' (H5FD_MEM_GHEAP), 'l' (H5FD_MEM_LHEAP),
254
 *                 `o' (H5FD_MEM_OHDR).
255
 *
256
 *        memb_addr:    The value HADDR_UNDEF for each element.
257
 *
258
 *
259
 * Example:    To set up a multi file access property list which partitions
260
 *        data into meta and raw files each being 1/2 of the address
261
 *        space one would say:
262
 *
263
 *            H5FD_mem_t mt, memb_map[H5FD_MEM_NTYPES];
264
 *            hid_t memb_fapl[H5FD_MEM_NTYPES];
265
 *            const char *memb[H5FD_MEM_NTYPES];
266
 *            haddr_t memb_addr[H5FD_MEM_NTYPES];
267
 *
268
 *            // The mapping...
269
 *            for (mt=0; mt<H5FD_MEM_NTYPES; mt++) {
270
 *                memb_map[mt] = H5FD_MEM_SUPER;
271
 *            }
272
 *            memb_map[H5FD_MEM_DRAW] = H5FD_MEM_DRAW;
273
 *
274
 *            // Member information
275
 *            memb_fapl[H5FD_MEM_SUPER] = H5P_DEFAULT;
276
 *            memb_name[H5FD_MEM_SUPER] = "%s.meta";
277
 *            memb_addr[H5FD_MEM_SUPER] = 0;
278
 *
279
 *            memb_fapl[H5FD_MEM_DRAW] = H5P_DEFAULT;
280
 *            memb_name[H5FD_MEM_DRAW] = "%s.raw";
281
 *            memb_addr[H5FD_MEM_DRAW] = HADDR_MAX/2;
282
 *
283
 *            hid_t fapl = H5Pcreate(H5P_FILE_ACCESS);
284
 *            H5Pset_fapl_multi(fapl, memb_map, memb_fapl,
285
 *                              memb_name, memb_addr, true);
286
 *
287
 *
288
 * Return:    Success:    Non-negative
289
 *
290
 *            Failure:    Negative
291
 *
292
 *-------------------------------------------------------------------------
293
 */
294
herr_t
295
H5Pset_fapl_multi(hid_t fapl_id, const H5FD_mem_t *memb_map, const hid_t *memb_fapl,
296
                  const char *const *memb_name, const haddr_t *memb_addr, hbool_t relax)
297
0
{
298
0
    H5FD_multi_fapl_t fa;
299
300
    /* Clear the error stack */
301
0
    H5Eclear2(H5E_DEFAULT);
302
303
    /* Check arguments and supply default values */
304
0
    if (H5I_GENPROP_LST != H5Iget_type(fapl_id) || true != H5Pisa_class(fapl_id, H5P_FILE_ACCESS))
305
0
        H5Epush_ret(__func__, H5E_ERR_CLS, H5E_PLIST, H5E_BADVALUE, "not an access list", -1);
306
0
    if (H5FD_multi_populate_config(memb_map, memb_fapl, memb_name, memb_addr, relax, &fa) < 0)
307
0
        H5Epush_ret(__func__, H5E_ERR_CLS, H5E_INTERNAL, H5E_CANTSET, "can't setup driver configuration", -1);
308
309
0
    return H5Pset_driver(fapl_id, H5FD_MULTI, &fa);
310
0
}
311
312
/*-------------------------------------------------------------------------
313
 * Function:    H5Pget_fapl_multi
314
 *
315
 * Purpose:    Returns information about the multi file access property
316
 *        list though the function arguments which are the same as for
317
 *        H5Pset_fapl_multi() above.
318
 *
319
 * Return:    Success:    Non-negative
320
 *
321
 *            Failure:    Negative
322
 *
323
 *-------------------------------------------------------------------------
324
 */
325
herr_t
326
H5Pget_fapl_multi(hid_t fapl_id, H5FD_mem_t *memb_map /*out*/, hid_t *memb_fapl /*out*/,
327
                  char **memb_name /*out*/, haddr_t *memb_addr /*out*/, hbool_t *relax)
328
0
{
329
0
    const H5FD_multi_fapl_t *fa;
330
0
    H5FD_multi_fapl_t        default_fa;
331
0
    H5FD_mem_t               mt;
332
333
    /* Clear the error stack */
334
0
    H5Eclear2(H5E_DEFAULT);
335
336
0
    if (H5I_GENPROP_LST != H5Iget_type(fapl_id) || true != H5Pisa_class(fapl_id, H5P_FILE_ACCESS))
337
0
        H5Epush_ret(__func__, H5E_ERR_CLS, H5E_PLIST, H5E_BADTYPE, "not an access list", -1);
338
0
    if (H5FD_MULTI != H5Pget_driver(fapl_id))
339
0
        H5Epush_ret(__func__, H5E_ERR_CLS, H5E_PLIST, H5E_BADVALUE, "incorrect VFL driver", -1);
340
0
    H5E_BEGIN_TRY
341
0
    {
342
0
        fa = (const H5FD_multi_fapl_t *)H5Pget_driver_info(fapl_id);
343
0
    }
344
0
    H5E_END_TRY
345
0
    if (!fa || (H5P_FILE_ACCESS_DEFAULT == fapl_id)) {
346
0
        if (H5FD_multi_populate_config(NULL, NULL, NULL, NULL, true, &default_fa) < 0)
347
0
            H5Epush_ret(__func__, H5E_ERR_CLS, H5E_VFL, H5E_CANTSET,
348
0
                        "can't setup default driver configuration", -1);
349
0
        fa = &default_fa;
350
0
    }
351
352
0
    if (memb_map)
353
0
        memcpy(memb_map, fa->memb_map, H5FD_MEM_NTYPES * sizeof(H5FD_mem_t));
354
0
    if (memb_fapl) {
355
0
        for (mt = H5FD_MEM_DEFAULT; mt < H5FD_MEM_NTYPES; mt = (H5FD_mem_t)(mt + 1)) {
356
0
            if (fa->memb_fapl[mt] >= 0)
357
0
                memb_fapl[mt] = H5Pcopy(fa->memb_fapl[mt]);
358
0
            else
359
0
                memb_fapl[mt] = fa->memb_fapl[mt]; /*default or bad ID*/
360
0
        }
361
0
    }
362
0
    if (memb_name) {
363
0
        for (mt = H5FD_MEM_DEFAULT; mt < H5FD_MEM_NTYPES; mt = (H5FD_mem_t)(mt + 1)) {
364
0
            if (fa->memb_name[mt])
365
0
                memb_name[mt] = my_strdup(fa->memb_name[mt]);
366
0
            else
367
0
                memb_name[mt] = NULL;
368
0
        }
369
0
    }
370
0
    if (memb_addr)
371
0
        memcpy(memb_addr, fa->memb_addr, H5FD_MEM_NTYPES * sizeof(haddr_t));
372
0
    if (relax)
373
0
        *relax = fa->relax;
374
375
0
    return 0;
376
0
}
377
378
/*-------------------------------------------------------------------------
379
 * Function:    H5FD_split_populate_config
380
 *
381
 * Purpose:    Populates a H5FD_multi_fapl_t structure with the provided
382
 *             split driver values, supplying defaults where values are not
383
 *             provided.
384
 *
385
 * Return:    Non-negative on success/Negative on failure
386
 *
387
 *-------------------------------------------------------------------------
388
 */
389
static herr_t
390
H5FD_split_populate_config(const char *meta_ext, hid_t meta_plist_id, const char *raw_ext, hid_t raw_plist_id,
391
                           bool relax, H5FD_multi_fapl_t *fa_out)
392
0
{
393
0
    static char
394
0
        meta_name_g[H5FD_MULT_MAX_FILE_NAME_LEN]; /* Static scratch buffer to store metadata member name */
395
0
    static char
396
0
        raw_name_g[H5FD_MULT_MAX_FILE_NAME_LEN]; /* Static scratch buffer to store raw data member name */
397
0
    const char *_memb_name[H5FD_MEM_NTYPES];
398
0
    H5FD_mem_t  _memb_map[H5FD_MEM_NTYPES];
399
0
    hid_t       _memb_fapl[H5FD_MEM_NTYPES];
400
0
    haddr_t     _memb_addr[H5FD_MEM_NTYPES];
401
0
    herr_t      ret_value = 0;
402
403
0
    assert(fa_out);
404
405
    /* Initialize */
406
0
    ALL_MEMBERS (mt) {
407
        /* Treat global heap as raw data, not metadata */
408
0
        _memb_map[mt]  = ((mt == H5FD_MEM_DRAW || mt == H5FD_MEM_GHEAP) ? H5FD_MEM_DRAW : H5FD_MEM_SUPER);
409
0
        _memb_fapl[mt] = H5P_DEFAULT;
410
0
        _memb_name[mt] = NULL;
411
0
        _memb_addr[mt] = HADDR_UNDEF;
412
0
    }
413
0
    END_MEMBERS
414
415
    /* The file access properties */
416
0
    _memb_fapl[H5FD_MEM_SUPER] = meta_plist_id;
417
0
    _memb_fapl[H5FD_MEM_DRAW]  = raw_plist_id;
418
419
    /* The names */
420
    /* process meta filename */
421
0
    if (meta_ext) {
422
0
        if (strstr(meta_ext, "%s")) {
423
            /* Note: this doesn't accommodate for when the '%s' in the user's
424
             *  string is at a position >sizeof(meta_name) - QK & JK - 2013/01/17
425
             */
426
0
            strncpy(meta_name_g, meta_ext, sizeof(meta_name_g));
427
0
            meta_name_g[sizeof(meta_name_g) - 1] = '\0';
428
0
        }
429
0
        else
430
0
            snprintf(meta_name_g, sizeof(meta_name_g), "%%s%s", meta_ext);
431
0
    }
432
0
    else {
433
0
        strncpy(meta_name_g, "%s.meta", sizeof(meta_name_g));
434
0
        meta_name_g[sizeof(meta_name_g) - 1] = '\0';
435
0
    }
436
0
    _memb_name[H5FD_MEM_SUPER] = meta_name_g;
437
438
    /* process raw filename */
439
0
    if (raw_ext) {
440
0
        if (strstr(raw_ext, "%s")) {
441
            /* Note: this doesn't accommodate for when the '%s' in the user's
442
             *  string is at a position >sizeof(raw_name) - QK & JK - 2013/01/17
443
             */
444
0
            strncpy(raw_name_g, raw_ext, sizeof(raw_name_g));
445
0
            raw_name_g[sizeof(raw_name_g) - 1] = '\0';
446
0
        }
447
0
        else
448
0
            snprintf(raw_name_g, sizeof(raw_name_g), "%%s%s", raw_ext);
449
0
    }
450
0
    else {
451
0
        strncpy(raw_name_g, "%s.raw", sizeof(raw_name_g));
452
0
        raw_name_g[sizeof(raw_name_g) - 1] = '\0';
453
0
    }
454
0
    _memb_name[H5FD_MEM_DRAW] = raw_name_g;
455
456
    /* The sizes */
457
0
    _memb_addr[H5FD_MEM_SUPER] = 0;
458
0
    _memb_addr[H5FD_MEM_DRAW]  = HADDR_MAX / 2;
459
460
0
    ALL_MEMBERS (mt) {
461
        /* Map usage type */
462
0
        H5FD_mem_t mmt = _memb_map[mt];
463
0
        if (mmt < 0 || mmt >= H5FD_MEM_NTYPES)
464
0
            H5Epush_ret(__func__, H5E_ERR_CLS, H5E_INTERNAL, H5E_BADRANGE, "file resource type out of range",
465
0
                        -1);
466
467
        /*
468
         * All members of MEMB_FAPL must be either defaults or actual file
469
         * access property lists.
470
         */
471
0
        if (H5P_DEFAULT != _memb_fapl[mmt] && true != H5Pisa_class(_memb_fapl[mmt], H5P_FILE_ACCESS))
472
0
            H5Epush_ret(__func__, H5E_ERR_CLS, H5E_INTERNAL, H5E_BADVALUE, "file resource type incorrect",
473
0
                        -1);
474
475
        /* All names must be defined */
476
0
        if (!_memb_name[mmt] || !_memb_name[mmt][0])
477
0
            H5Epush_ret(__func__, H5E_ERR_CLS, H5E_INTERNAL, H5E_BADVALUE, "file resource type not set", -1);
478
0
    }
479
0
    END_MEMBERS
480
481
    /*
482
     * Initialize driver specific information. No need to copy it into the FA
483
     * struct since all members will be copied by H5Pset_driver().
484
     */
485
0
    memset(fa_out, 0, sizeof(H5FD_multi_fapl_t));
486
0
    memcpy(fa_out->memb_map, _memb_map, H5FD_MEM_NTYPES * sizeof(H5FD_mem_t));
487
0
    memcpy(fa_out->memb_fapl, _memb_fapl, H5FD_MEM_NTYPES * sizeof(hid_t));
488
0
    memcpy(fa_out->memb_name, _memb_name, H5FD_MEM_NTYPES * sizeof(char *));
489
0
    memcpy(fa_out->memb_addr, _memb_addr, H5FD_MEM_NTYPES * sizeof(haddr_t));
490
0
    fa_out->relax = relax;
491
492
    /* Patch up H5P_DEFAULT property lists for members */
493
0
    ALL_MEMBERS (mt) {
494
0
        if (fa_out->memb_fapl[mt] == H5P_DEFAULT) {
495
0
            fa_out->memb_fapl[mt] = H5Pcreate(H5P_FILE_ACCESS);
496
0
            if (H5Pset_fapl_sec2(fa_out->memb_fapl[mt]) < 0)
497
0
                H5Epush_ret(__func__, H5E_ERR_CLS, H5E_INTERNAL, H5E_CANTSET,
498
0
                            "can't set sec2 driver on member FAPL", -1);
499
0
        }
500
0
    }
501
0
    END_MEMBERS
502
503
0
    return ret_value;
504
0
}
505
506
/*-------------------------------------------------------------------------
507
 * Function:    H5FD_multi_populate_config
508
 *
509
 * Purpose:    Populates a H5FD_multi_fapl_t structure with the provided
510
 *             values, supplying defaults where values are not provided.
511
 *
512
 * Return:    Non-negative on success/Negative on failure
513
 *
514
 *-------------------------------------------------------------------------
515
 */
516
static herr_t
517
H5FD_multi_populate_config(const H5FD_mem_t *memb_map, const hid_t *memb_fapl, const char *const *memb_name,
518
                           const haddr_t *memb_addr, bool relax, H5FD_multi_fapl_t *fa_out)
519
0
{
520
0
    static const char *letters = "Xsbrglo";
521
0
    static char        _memb_name_g[H5FD_MEM_NTYPES][16]; /* Static scratch buffer to store member names */
522
0
    H5FD_mem_t         mt, mmt;
523
0
    H5FD_mem_t         _memb_map[H5FD_MEM_NTYPES];
524
0
    hid_t              _memb_fapl[H5FD_MEM_NTYPES];
525
0
    const char        *_memb_name_ptrs[H5FD_MEM_NTYPES];
526
0
    haddr_t            _memb_addr[H5FD_MEM_NTYPES];
527
0
    herr_t             ret_value = 0;
528
529
0
    assert(fa_out);
530
531
0
    if (!memb_map) {
532
0
        for (mt = H5FD_MEM_DEFAULT; mt < H5FD_MEM_NTYPES; mt = (H5FD_mem_t)(mt + 1))
533
0
            _memb_map[mt] = H5FD_MEM_DEFAULT;
534
0
        memb_map = _memb_map;
535
0
    }
536
0
    if (!memb_fapl) {
537
0
        for (mt = H5FD_MEM_DEFAULT; mt < H5FD_MEM_NTYPES; mt = (H5FD_mem_t)(mt + 1)) {
538
0
            _memb_fapl[mt] = H5Pcreate(H5P_FILE_ACCESS);
539
0
            if (H5Pset_fapl_sec2(_memb_fapl[mt]) < 0)
540
0
                H5Epush_ret(__func__, H5E_ERR_CLS, H5E_INTERNAL, H5E_CANTSET,
541
0
                            "can't set sec2 driver on member FAPL", -1);
542
0
        }
543
0
        memb_fapl = _memb_fapl;
544
0
    }
545
0
    if (!memb_name) {
546
0
        assert(strlen(letters) == H5FD_MEM_NTYPES);
547
0
        for (mt = H5FD_MEM_DEFAULT; mt < H5FD_MEM_NTYPES; mt = (H5FD_mem_t)(mt + 1)) {
548
0
            snprintf(_memb_name_g[mt], 16, "%%s-%c.h5", letters[mt]);
549
0
            _memb_name_ptrs[mt] = _memb_name_g[mt];
550
0
        }
551
0
        memb_name = _memb_name_ptrs;
552
0
    }
553
0
    if (!memb_addr) {
554
0
        for (mt = H5FD_MEM_DEFAULT; mt < H5FD_MEM_NTYPES; mt = (H5FD_mem_t)(mt + 1))
555
0
            _memb_addr[mt] = (hsize_t)(mt ? (mt - 1) : 0) * (HADDR_MAX / (H5FD_MEM_NTYPES - 1));
556
0
        memb_addr = _memb_addr;
557
0
    }
558
559
0
    for (mt = H5FD_MEM_DEFAULT; mt < H5FD_MEM_NTYPES; mt = (H5FD_mem_t)(mt + 1)) {
560
        /* Map usage type */
561
0
        mmt = memb_map[mt];
562
0
        if (mmt < 0 || mmt >= H5FD_MEM_NTYPES)
563
0
            H5Epush_ret(__func__, H5E_ERR_CLS, H5E_INTERNAL, H5E_BADRANGE, "file resource type out of range",
564
0
                        -1);
565
0
        if (H5FD_MEM_DEFAULT == mmt)
566
0
            mmt = mt;
567
568
        /*
569
         * All members of MEMB_FAPL must be either defaults or actual file
570
         * access property lists.
571
         */
572
0
        if (H5P_DEFAULT != memb_fapl[mmt] && true != H5Pisa_class(memb_fapl[mmt], H5P_FILE_ACCESS))
573
0
            H5Epush_ret(__func__, H5E_ERR_CLS, H5E_INTERNAL, H5E_BADVALUE, "file resource type incorrect",
574
0
                        -1);
575
576
        /* All names must be defined */
577
0
        if (!memb_name[mmt] || !memb_name[mmt][0])
578
0
            H5Epush_ret(__func__, H5E_ERR_CLS, H5E_INTERNAL, H5E_BADVALUE, "file resource type not set", -1);
579
0
    }
580
581
    /*
582
     * Initialize driver specific information. No need to copy it into the FA
583
     * struct since all members will be copied by H5Pset_driver().
584
     */
585
0
    memset(fa_out, 0, sizeof(H5FD_multi_fapl_t));
586
0
    memcpy(fa_out->memb_map, memb_map, H5FD_MEM_NTYPES * sizeof(H5FD_mem_t));
587
0
    memcpy(fa_out->memb_fapl, memb_fapl, H5FD_MEM_NTYPES * sizeof(hid_t));
588
0
    memcpy(fa_out->memb_name, memb_name, H5FD_MEM_NTYPES * sizeof(char *));
589
0
    memcpy(fa_out->memb_addr, memb_addr, H5FD_MEM_NTYPES * sizeof(haddr_t));
590
0
    fa_out->relax = relax;
591
592
    /* Patch up H5P_DEFAULT property lists for members */
593
0
    for (mt = H5FD_MEM_DEFAULT; mt < H5FD_MEM_NTYPES; mt = (H5FD_mem_t)(mt + 1)) {
594
0
        if (fa_out->memb_fapl[mt] == H5P_DEFAULT) {
595
0
            fa_out->memb_fapl[mt] = H5Pcreate(H5P_FILE_ACCESS);
596
0
            if (H5Pset_fapl_sec2(fa_out->memb_fapl[mt]) < 0)
597
0
                H5Epush_ret(__func__, H5E_ERR_CLS, H5E_INTERNAL, H5E_CANTSET,
598
0
                            "can't set sec2 driver on member FAPL", -1);
599
0
        }
600
0
    }
601
602
0
    return ret_value;
603
0
} /* end H5FD_multi_populate_config() */
604
605
/*-------------------------------------------------------------------------
606
 * Function:    H5FD_multi_sb_size
607
 *
608
 * Purpose:    Returns the size of the private information to be stored in
609
 *             the superblock.
610
 *
611
 * Return:    Success:    The super block driver data size.
612
 *
613
 *            Failure:    never fails
614
 *
615
 *-------------------------------------------------------------------------
616
 */
617
static hsize_t
618
H5FD_multi_sb_size(H5FD_t *_file)
619
0
{
620
0
    H5FD_multi_t *file   = (H5FD_multi_t *)_file;
621
0
    unsigned      nseen  = 0;
622
0
    hsize_t       nbytes = 8; /*size of header*/
623
624
    /* Clear the error stack */
625
0
    H5Eclear2(H5E_DEFAULT);
626
627
    /* How many unique files? */
628
0
    UNIQUE_MEMBERS (file->fa.memb_map, mt) {
629
0
        nseen++;
630
0
    }
631
0
    END_MEMBERS
632
633
    /* Addresses and EOA markers */
634
0
    nbytes += nseen * 2 * 8;
635
636
    /* Name templates */
637
0
    UNIQUE_MEMBERS (file->fa.memb_map, mt) {
638
0
        size_t n = strlen(file->fa.memb_name[mt]) + 1;
639
0
        nbytes += (n + 7) & ~((size_t)0x0007);
640
0
    }
641
0
    END_MEMBERS
642
643
0
    return nbytes;
644
0
}
645
646
/*-------------------------------------------------------------------------
647
 * Function:    H5FD_multi_sb_encode
648
 *
649
 * Purpose:    Encode driver information for the superblock. The NAME
650
 *        argument is a nine-byte buffer which will be initialized with
651
 *        an eight-character name/version number and null termination.
652
 *
653
 *        The encoding is a six-byte member mapping followed two bytes
654
 *        which are unused. For each unique file in usage-type order
655
 *        encode all the starting addresses as unsigned 64-bit integers,
656
 *        then all the EOA values as unsigned 64-bit integers, then all
657
 *        the template names as null terminated strings which are
658
 *        multiples of 8 characters.
659
 *
660
 * Return:    Success:    0
661
 *
662
 *            Failure:    -1
663
 *
664
 *-------------------------------------------------------------------------
665
 */
666
static herr_t
667
H5FD_multi_sb_encode(H5FD_t *_file, char *name /*out*/, unsigned char *buf /*out*/)
668
0
{
669
0
    H5FD_multi_t  *file = (H5FD_multi_t *)_file;
670
0
    haddr_t        memb_eoa;
671
0
    unsigned char *p;
672
0
    size_t         nseen;
673
0
    size_t         i;
674
0
    H5FD_mem_t     m;
675
676
    /* Clear the error stack */
677
0
    H5Eclear2(H5E_DEFAULT);
678
679
    /* Name and version number */
680
0
    strncpy(name, "NCSAmult", (size_t)9);
681
0
    name[8] = '\0';
682
683
0
    assert(7 == H5FD_MEM_NTYPES);
684
685
0
    for (m = H5FD_MEM_SUPER; m < H5FD_MEM_NTYPES; m = (H5FD_mem_t)(m + 1)) {
686
0
        buf[m - 1] = (unsigned char)file->fa.memb_map[m];
687
0
    }
688
0
    buf[6] = 0;
689
0
    buf[7] = 0;
690
691
    /*
692
     * Copy the starting addresses and EOA values into the buffer in order of
693
     * usage type but only for types which map to something unique.
694
     */
695
696
    /* Encode all starting addresses and EOA values */
697
0
    nseen = 0;
698
0
    p     = buf + 8;
699
0
    assert(sizeof(haddr_t) <= 8);
700
0
    UNIQUE_MEMBERS (file->fa.memb_map, mt) {
701
0
        memcpy(p, &(file->fa.memb_addr[mt]), sizeof(haddr_t));
702
0
        p += sizeof(haddr_t);
703
0
        memb_eoa = H5FDget_eoa(file->memb[mt], mt);
704
0
        memcpy(p, &memb_eoa, sizeof(haddr_t));
705
0
        p += sizeof(haddr_t);
706
0
        nseen++;
707
0
    }
708
0
    END_MEMBERS
709
0
    if (H5Tconvert(H5T_NATIVE_HADDR, H5T_STD_U64LE, nseen * 2, buf + 8, NULL, H5P_DEFAULT) < 0)
710
0
        H5Epush_ret(__func__, H5E_ERR_CLS, H5E_DATATYPE, H5E_CANTCONVERT, "can't convert superblock info",
711
0
                    -1);
712
713
    /* Encode all name templates */
714
0
    p = buf + 8 + nseen * 2 * 8;
715
0
    UNIQUE_MEMBERS (file->fa.memb_map, mt) {
716
0
        size_t n = strlen(file->fa.memb_name[mt]) + 1;
717
0
        strcpy((char *)p, file->fa.memb_name[mt]);
718
0
        p += n;
719
0
        for (i = n; i % 8; i++)
720
0
            *p++ = '\0';
721
0
    }
722
0
    END_MEMBERS
723
724
0
    return 0;
725
0
} /* end H5FD_multi_sb_encode() */
726
727
/*-------------------------------------------------------------------------
728
 * Function:    H5FD_multi_sb_decode
729
 *
730
 * Purpose:    Decodes the superblock information for this driver. The NAME
731
 *        argument is the eight-character (plus null termination) name
732
 *        stored in the file.
733
 *
734
 *        The FILE argument is updated according to the information in
735
 *        the superblock. This may mean that some member files are
736
 *        closed and others are opened.
737
 *
738
 * Return:    Success:    0
739
 *
740
 *            Failure:    -1
741
 *
742
 *-------------------------------------------------------------------------
743
 */
744
static herr_t
745
H5FD_multi_sb_decode(H5FD_t *_file, const char *name, const unsigned char *buf)
746
0
{
747
0
    H5FD_multi_t *file = (H5FD_multi_t *)_file;
748
0
    char          x[2 * H5FD_MEM_NTYPES * 8];
749
0
    H5FD_mem_t    map[H5FD_MEM_NTYPES];
750
0
    int           i;
751
0
    size_t        nseen       = 0;
752
0
    bool          map_changed = false;
753
0
    bool          in_use[H5FD_MEM_NTYPES];
754
0
    const char   *memb_name[H5FD_MEM_NTYPES];
755
0
    haddr_t       memb_addr[H5FD_MEM_NTYPES];
756
0
    haddr_t       memb_eoa[H5FD_MEM_NTYPES];
757
0
    haddr_t      *ap;
758
759
    /* Clear the error stack */
760
0
    H5Eclear2(H5E_DEFAULT);
761
762
    /* Make sure the name/version number is correct */
763
0
    if (strcmp(name, "NCSAmult") != 0)
764
0
        H5Epush_ret(__func__, H5E_ERR_CLS, H5E_FILE, H5E_BADVALUE, "invalid multi superblock", -1);
765
766
    /* Set default values */
767
0
    ALL_MEMBERS (mt) {
768
0
        memb_addr[mt] = HADDR_UNDEF;
769
0
        memb_eoa[mt]  = HADDR_UNDEF;
770
0
        memb_name[mt] = NULL;
771
0
    }
772
0
    END_MEMBERS
773
774
    /*
775
     * Read the map and count the unique members.
776
     */
777
0
    memset(map, 0, sizeof map);
778
779
0
    for (i = 0; i < 6; i++) {
780
0
        map[i + 1] = (H5FD_mem_t)buf[i];
781
0
        if (file->fa.memb_map[i + 1] != map[i + 1])
782
0
            map_changed = true;
783
0
    }
784
785
0
    UNIQUE_MEMBERS (map, mt) {
786
0
        nseen++;
787
0
    }
788
0
    END_MEMBERS
789
0
    buf += 8;
790
791
    /* Decode Address and EOA values */
792
0
    assert(sizeof(haddr_t) <= 8);
793
0
    memcpy(x, buf, (nseen * 2 * 8));
794
0
    buf += nseen * 2 * 8;
795
0
    if (H5Tconvert(H5T_STD_U64LE, H5T_NATIVE_HADDR, nseen * 2, x, NULL, H5P_DEFAULT) < 0)
796
0
        H5Epush_ret(__func__, H5E_ERR_CLS, H5E_DATATYPE, H5E_CANTCONVERT, "can't convert superblock info",
797
0
                    -1);
798
0
    ap = (haddr_t *)((void *)x); /* Extra (void *) cast to quiet "cast to create alignment" warning -
799
                                    2019/07/05, QAK */
800
0
    UNIQUE_MEMBERS (map, mt) {
801
0
        memb_addr[_unmapped] = *ap++;
802
0
        memb_eoa[_unmapped]  = *ap++;
803
0
    }
804
0
    END_MEMBERS
805
806
    /* Decode name templates */
807
0
    UNIQUE_MEMBERS (map, mt) {
808
0
        size_t n             = strlen((const char *)buf) + 1;
809
0
        memb_name[_unmapped] = (const char *)buf;
810
0
        buf += (n + 7) & ~((unsigned)0x0007);
811
0
    }
812
0
    END_MEMBERS
813
814
    /*
815
     * Use the mapping saved in the superblock in preference to the one
816
     * already set for the file. Since we may have opened files which are no
817
     * longer needed we should close all those files. We'll open the new
818
     * files at the end.
819
     */
820
0
    if (map_changed) {
821
        /* Commit map */
822
0
        ALL_MEMBERS (mt) {
823
0
            file->fa.memb_map[mt] = map[mt];
824
0
        }
825
0
        END_MEMBERS
826
827
        /* Close files which are unused now */
828
0
        memset(in_use, 0, sizeof in_use);
829
0
        UNIQUE_MEMBERS (map, mt) {
830
0
            in_use[mt] = true;
831
0
        }
832
0
        END_MEMBERS
833
0
        ALL_MEMBERS (mt) {
834
0
            if (!in_use[mt] && file->memb[mt]) {
835
0
                (void)H5FDclose(file->memb[mt]);
836
0
                file->memb[mt] = NULL;
837
0
            }
838
0
            file->fa.memb_map[mt] = map[mt];
839
0
        }
840
0
        END_MEMBERS
841
0
    }
842
843
    /* Commit member starting addresses and name templates */
844
0
    ALL_MEMBERS (mt) {
845
0
        file->fa.memb_addr[mt] = memb_addr[mt];
846
0
        if (memb_name[mt]) {
847
0
            if (file->fa.memb_name[mt])
848
0
                free(file->fa.memb_name[mt]);
849
0
            file->fa.memb_name[mt] = my_strdup(memb_name[mt]);
850
0
        }
851
0
    }
852
0
    END_MEMBERS
853
0
    if (compute_next(file) < 0)
854
0
        H5Epush_ret(__func__, H5E_ERR_CLS, H5E_INTERNAL, H5E_BADVALUE, "compute_next() failed", -1);
855
856
    /* Open all necessary files */
857
0
    if (open_members(file) < 0)
858
0
        H5Epush_ret(__func__, H5E_ERR_CLS, H5E_INTERNAL, H5E_BADVALUE, "open_members() failed", -1);
859
860
    /* Set the EOA marker for all open files */
861
0
    UNIQUE_MEMBERS (file->fa.memb_map, mt) {
862
0
        if (file->memb[mt])
863
0
            if (H5FDset_eoa(file->memb[mt], mt, memb_eoa[mt]) < 0)
864
0
                H5Epush_ret(__func__, H5E_ERR_CLS, H5E_INTERNAL, H5E_CANTSET, "set_eoa() failed", -1);
865
866
        /* Save the individual EOAs in one place for later comparison (in H5FD_multi_set_eoa)
867
         */
868
0
        file->memb_eoa[mt] = memb_eoa[mt];
869
0
    }
870
0
    END_MEMBERS
871
872
0
    return 0;
873
0
} /* end H5FD_multi_sb_decode() */
874
875
/*-------------------------------------------------------------------------
876
 * Function:    H5FD_multi_fapl_get
877
 *
878
 * Purpose:    Returns a file access property list which indicates how the
879
 *        specified file is being accessed. The return list could be
880
 *        used to access another file the same way.
881
 *
882
 * Return:    Success:    Ptr to new file access property list with all
883
 *                members copied from the file struct.
884
 *
885
 *            Failure:    NULL
886
 *
887
 *-------------------------------------------------------------------------
888
 */
889
static void *
890
H5FD_multi_fapl_get(H5FD_t *_file)
891
0
{
892
0
    H5FD_multi_t *file = (H5FD_multi_t *)_file;
893
894
    /* Clear the error stack */
895
0
    H5Eclear2(H5E_DEFAULT);
896
897
0
    return H5FD_multi_fapl_copy(&(file->fa));
898
0
}
899
900
/*-------------------------------------------------------------------------
901
 * Function:    H5FD_multi_fapl_copy
902
 *
903
 * Purpose:    Copies the multi-specific file access properties.
904
 *
905
 * Return:    Success:    Ptr to a new property list
906
 *
907
 *            Failure:    NULL
908
 *
909
 *-------------------------------------------------------------------------
910
 */
911
static void *
912
H5FD_multi_fapl_copy(const void *_old_fa)
913
0
{
914
0
    const H5FD_multi_fapl_t *old_fa  = (const H5FD_multi_fapl_t *)_old_fa;
915
0
    H5FD_multi_fapl_t       *new_fa  = (H5FD_multi_fapl_t *)calloc(1, sizeof(H5FD_multi_fapl_t));
916
0
    int                      nerrors = 0;
917
918
0
    assert(new_fa);
919
920
    /* Clear the error stack */
921
0
    H5Eclear2(H5E_DEFAULT);
922
923
0
    memcpy(new_fa, old_fa, sizeof(H5FD_multi_fapl_t));
924
0
    ALL_MEMBERS (mt) {
925
0
        if (old_fa->memb_fapl[mt] >= 0) {
926
0
            if (H5Iinc_ref(old_fa->memb_fapl[mt]) < 0) {
927
0
                nerrors++;
928
0
                break;
929
0
            }
930
0
            new_fa->memb_fapl[mt] = old_fa->memb_fapl[mt];
931
0
        }
932
0
        if (old_fa->memb_name[mt]) {
933
0
            new_fa->memb_name[mt] = my_strdup(old_fa->memb_name[mt]);
934
0
            if (NULL == new_fa->memb_name[mt]) {
935
0
                nerrors++;
936
0
                break;
937
0
            }
938
0
        }
939
0
    }
940
0
    END_MEMBERS
941
942
0
    if (nerrors) {
943
0
        ALL_MEMBERS (mt) {
944
0
            if (new_fa->memb_fapl[mt] >= 0)
945
0
                (void)H5Idec_ref(new_fa->memb_fapl[mt]);
946
0
            if (new_fa->memb_name[mt])
947
0
                free(new_fa->memb_name[mt]);
948
0
        }
949
0
        END_MEMBERS
950
0
        free(new_fa);
951
0
        H5Epush_ret(__func__, H5E_ERR_CLS, H5E_INTERNAL, H5E_BADVALUE, "can't release object on error", NULL);
952
0
    }
953
0
    return new_fa;
954
0
}
955
956
/*-------------------------------------------------------------------------
957
 * Function:    H5FD_multi_fapl_free
958
 *
959
 * Purpose:    Frees the multi-specific file access properties.
960
 *
961
 * Return:    Success:    0
962
 *
963
 *            Failure:    -1
964
 *
965
 *-------------------------------------------------------------------------
966
 */
967
static herr_t
968
H5FD_multi_fapl_free(void *_fa)
969
0
{
970
0
    H5FD_multi_fapl_t *fa = (H5FD_multi_fapl_t *)_fa;
971
972
    /* Clear the error stack */
973
0
    H5Eclear2(H5E_DEFAULT);
974
975
0
    ALL_MEMBERS (mt) {
976
0
        if (fa->memb_fapl[mt] >= 0)
977
0
            if (H5Idec_ref(fa->memb_fapl[mt]) < 0)
978
0
                H5Epush_ret(__func__, H5E_ERR_CLS, H5E_FILE, H5E_CANTCLOSEOBJ, "can't close property list",
979
0
                            -1);
980
0
        if (fa->memb_name[mt])
981
0
            free(fa->memb_name[mt]);
982
0
    }
983
0
    END_MEMBERS
984
0
    free(fa);
985
986
0
    return 0;
987
0
}
988
989
/*-------------------------------------------------------------------------
990
 * Function:    H5FD_multi_open
991
 *
992
 * Purpose:    Creates and/or opens a multi HDF5 file.
993
 *
994
 * Return:    Success:    A pointer to a new file data structure. The
995
 *                public fields will be initialized by the
996
 *                caller, which is always H5FD_open().
997
 *
998
 *            Failure:    NULL
999
 *
1000
 *-------------------------------------------------------------------------
1001
 */
1002
static H5FD_t *
1003
H5FD_multi_open(const char *name, unsigned flags, hid_t fapl_id, haddr_t maxaddr)
1004
0
{
1005
0
    H5FD_multi_t            *file       = NULL;
1006
0
    hid_t                    close_fapl = -1;
1007
0
    const H5FD_multi_fapl_t *fa;
1008
0
    H5FD_mem_t               m;
1009
1010
    /* Clear the error stack */
1011
0
    H5Eclear2(H5E_DEFAULT);
1012
1013
    /* Check arguments */
1014
0
    if (!name || !*name)
1015
0
        H5Epush_ret(__func__, H5E_ERR_CLS, H5E_ARGS, H5E_BADVALUE, "invalid file name", NULL);
1016
0
    if (0 == maxaddr || HADDR_UNDEF == maxaddr)
1017
0
        H5Epush_ret(__func__, H5E_ERR_CLS, H5E_ARGS, H5E_BADRANGE, "bogus maxaddr", NULL);
1018
1019
    /*
1020
     * Initialize the file from the file access properties, using default
1021
     * values if necessary.  Make sure to use CALLOC here because the code
1022
     * in H5FD_multi_set_eoa depends on the proper initialization of memb_eoa
1023
     * in H5FD_multi_t.
1024
     */
1025
0
    if (NULL == (file = (H5FD_multi_t *)calloc((size_t)1, sizeof(H5FD_multi_t))))
1026
0
        H5Epush_ret(__func__, H5E_ERR_CLS, H5E_RESOURCE, H5E_NOSPACE, "memory allocation failed", NULL);
1027
0
    H5E_BEGIN_TRY
1028
0
    {
1029
0
        fa = (const H5FD_multi_fapl_t *)H5Pget_driver_info(fapl_id);
1030
0
    }
1031
0
    H5E_END_TRY
1032
0
    if (!fa || (H5P_FILE_ACCESS_DEFAULT == fapl_id) || (H5FD_MULTI != H5Pget_driver(fapl_id))) {
1033
0
        char *env = getenv(HDF5_DRIVER);
1034
1035
0
        close_fapl = fapl_id = H5Pcreate(H5P_FILE_ACCESS);
1036
0
        if (env && !strcmp(env, "split")) {
1037
0
            if (H5Pset_fapl_split(fapl_id, NULL, H5P_DEFAULT, NULL, H5P_DEFAULT) < 0)
1038
0
                H5Epush_goto(__func__, H5E_ERR_CLS, H5E_FILE, H5E_CANTSET, "can't set property value", error);
1039
0
        }
1040
0
        else {
1041
0
            if (H5Pset_fapl_multi(fapl_id, NULL, NULL, NULL, NULL, true) < 0)
1042
0
                H5Epush_goto(__func__, H5E_ERR_CLS, H5E_FILE, H5E_CANTSET, "can't set property value", error);
1043
0
        }
1044
1045
0
        fa = (const H5FD_multi_fapl_t *)H5Pget_driver_info(fapl_id);
1046
0
    }
1047
0
    assert(fa);
1048
0
    ALL_MEMBERS (mt) {
1049
0
        file->fa.memb_map[mt]  = fa->memb_map[mt];
1050
0
        file->fa.memb_addr[mt] = fa->memb_addr[mt];
1051
0
        if (fa->memb_fapl[mt] >= 0)
1052
0
            H5Iinc_ref(fa->memb_fapl[mt]);
1053
0
        file->fa.memb_fapl[mt] = fa->memb_fapl[mt];
1054
0
        if (fa->memb_name[mt])
1055
0
            file->fa.memb_name[mt] = my_strdup(fa->memb_name[mt]);
1056
0
        else
1057
0
            file->fa.memb_name[mt] = NULL;
1058
0
    }
1059
0
    END_MEMBERS
1060
0
    file->fa.relax = fa->relax;
1061
0
    file->flags    = flags;
1062
0
    file->name     = my_strdup(name);
1063
0
    if (close_fapl >= 0)
1064
0
        if (H5Pclose(close_fapl) < 0)
1065
0
            H5Epush_goto(__func__, H5E_ERR_CLS, H5E_FILE, H5E_CANTCLOSEOBJ, "can't close property list",
1066
0
                         error);
1067
1068
    /* Compute derived properties and open member files */
1069
0
    if (compute_next(file) < 0)
1070
0
        H5Epush_goto(__func__, H5E_ERR_CLS, H5E_INTERNAL, H5E_BADVALUE, "compute_next() failed", error);
1071
0
    if (open_members(file) < 0)
1072
0
        H5Epush_goto(__func__, H5E_ERR_CLS, H5E_INTERNAL, H5E_BADVALUE, "open_members() failed", error);
1073
1074
    /* We must have opened at least the superblock file */
1075
0
    if (H5FD_MEM_DEFAULT == (m = file->fa.memb_map[H5FD_MEM_SUPER]))
1076
0
        m = H5FD_MEM_SUPER;
1077
0
    if (NULL == file->memb[m])
1078
0
        goto error;
1079
1080
0
    return (H5FD_t *)file;
1081
1082
0
error:
1083
    /* Cleanup and fail */
1084
0
    if (file) {
1085
0
        ALL_MEMBERS (mt) {
1086
0
            if (file->memb[mt])
1087
0
                (void)H5FDclose(file->memb[mt]);
1088
0
            if (file->fa.memb_fapl[mt] >= 0)
1089
0
                (void)H5Idec_ref(file->fa.memb_fapl[mt]);
1090
0
            if (file->fa.memb_name[mt])
1091
0
                free(file->fa.memb_name[mt]);
1092
0
        }
1093
0
        END_MEMBERS
1094
0
        if (file->name)
1095
0
            free(file->name);
1096
0
        free(file);
1097
0
    }
1098
0
    return NULL;
1099
0
}
1100
1101
/*-------------------------------------------------------------------------
1102
 * Function:    H5FD_multi_close
1103
 *
1104
 * Purpose:    Closes a multi file.
1105
 *
1106
 * Return:    Success:    Non-negative
1107
 *
1108
 *            Failure:    Negative with as many members closed as
1109
 *                possible. The only subsequent operation
1110
 *                permitted on the file is a close operation.
1111
 *
1112
 *-------------------------------------------------------------------------
1113
 */
1114
static herr_t
1115
H5FD_multi_close(H5FD_t *_file)
1116
0
{
1117
0
    H5FD_multi_t *file    = (H5FD_multi_t *)_file;
1118
0
    int           nerrors = 0;
1119
1120
    /* Clear the error stack */
1121
0
    H5Eclear2(H5E_DEFAULT);
1122
1123
    /* Close as many members as possible */
1124
0
    ALL_MEMBERS (mt) {
1125
0
        if (file->memb[mt]) {
1126
0
            if (H5FDclose(file->memb[mt]) < 0) {
1127
0
                nerrors++;
1128
0
            }
1129
0
            else {
1130
0
                file->memb[mt] = NULL;
1131
0
            }
1132
0
        }
1133
0
    }
1134
0
    END_MEMBERS
1135
0
    if (nerrors)
1136
0
        H5Epush_ret(__func__, H5E_ERR_CLS, H5E_INTERNAL, H5E_BADVALUE, "error closing member files", -1);
1137
1138
    /* Clean up other stuff */
1139
0
    ALL_MEMBERS (mt) {
1140
0
        if (file->fa.memb_fapl[mt] >= 0)
1141
0
            (void)H5Idec_ref(file->fa.memb_fapl[mt]);
1142
0
        if (file->fa.memb_name[mt])
1143
0
            free(file->fa.memb_name[mt]);
1144
0
    }
1145
0
    END_MEMBERS
1146
1147
0
    free(file->name);
1148
0
    free(file);
1149
0
    return 0;
1150
0
}
1151
1152
/*-------------------------------------------------------------------------
1153
 * Function:    H5FD_multi_cmp
1154
 *
1155
 * Purpose:    Compares two file families to see if they are the same. It
1156
 *        does this by comparing the first common member of the two
1157
 *        families.  If the families have no members in common then the
1158
 *        file with the earliest member is smaller than the other file.
1159
 *        We abort if neither file has any members.
1160
 *
1161
 * Return:    Success:    like strcmp()
1162
 *
1163
 *            Failure:    never fails (arguments were checked by th caller).
1164
 *
1165
 *-------------------------------------------------------------------------
1166
 */
1167
static int
1168
H5FD_multi_cmp(const H5FD_t *_f1, const H5FD_t *_f2)
1169
0
{
1170
0
    const H5FD_multi_t *f1     = (const H5FD_multi_t *)_f1;
1171
0
    const H5FD_multi_t *f2     = (const H5FD_multi_t *)_f2;
1172
0
    H5FD_mem_t          out_mt = H5FD_MEM_DEFAULT;
1173
0
    int                 cmp    = 0;
1174
1175
    /* Clear the error stack */
1176
0
    H5Eclear2(H5E_DEFAULT);
1177
1178
0
    ALL_MEMBERS (mt) {
1179
0
        out_mt = mt;
1180
0
        if (f1->memb[mt] && f2->memb[mt])
1181
0
            break;
1182
0
        if (!cmp) {
1183
0
            if (f1->memb[mt])
1184
0
                cmp = -1;
1185
0
            else if (f2->memb[mt])
1186
0
                cmp = 1;
1187
0
        }
1188
0
    }
1189
0
    END_MEMBERS
1190
0
    assert(cmp || out_mt < H5FD_MEM_NTYPES);
1191
0
    if (out_mt >= H5FD_MEM_NTYPES)
1192
0
        return cmp;
1193
1194
0
    return H5FDcmp(f1->memb[out_mt], f2->memb[out_mt]);
1195
0
}
1196
1197
/*-------------------------------------------------------------------------
1198
 * Function:    H5FD_multi_query
1199
 *
1200
 * Purpose:    Set the flags that this VFL driver is capable of supporting.
1201
 *              (listed in H5FDpublic.h)
1202
 *
1203
 * Return:    Success:    non-negative
1204
 *
1205
 *            Failure:    negative
1206
 *
1207
 *-------------------------------------------------------------------------
1208
 */
1209
static herr_t
1210
H5FD_multi_query(const H5FD_t *_f, unsigned long *flags /* out */)
1211
0
{
1212
    /* Shut compiler up */
1213
0
    (void)_f;
1214
1215
    /* Set the VFL feature flags that this driver supports */
1216
0
    if (flags) {
1217
0
        *flags = 0;
1218
0
        *flags |= H5FD_FEAT_DATA_SIEVE; /* OK to perform data sieving for faster raw data reads & writes */
1219
0
        *flags |= H5FD_FEAT_AGGREGATE_SMALLDATA; /* OK to aggregate "small" raw data allocations */
1220
0
        *flags |= H5FD_FEAT_USE_ALLOC_SIZE;      /* OK just pass the allocation size to the alloc callback */
1221
0
        *flags |= H5FD_FEAT_PAGED_AGGR;          /* OK special file space mapping for paged aggregation */
1222
0
    }                                            /* end if */
1223
1224
0
    return (0);
1225
0
} /* end H5FD_multi_query() */
1226
1227
/*-------------------------------------------------------------------------
1228
 * Function:    H5FD_multi_get_type_map
1229
 *
1230
 * Purpose:    Retrieve the memory type mapping for this file
1231
 *
1232
 * Return:    Success:    non-negative
1233
 *            Failure:    negative
1234
 *
1235
 *-------------------------------------------------------------------------
1236
 */
1237
static herr_t
1238
H5FD_multi_get_type_map(const H5FD_t *_file, H5FD_mem_t *type_map)
1239
0
{
1240
0
    const H5FD_multi_t *file = (const H5FD_multi_t *)_file;
1241
1242
    /* Copy file's free space type mapping */
1243
0
    memcpy(type_map, file->fa.memb_map, sizeof(file->fa.memb_map));
1244
1245
0
    return (0);
1246
0
} /* end H5FD_multi_get_type_map() */
1247
1248
/*-------------------------------------------------------------------------
1249
 * Function:    H5FD_multi_get_eoa
1250
 *
1251
 * Purpose:    Returns the end-of-address marker for the file. The EOA
1252
 *        marker is the first address past the last byte allocated in
1253
 *        the format address space.
1254
 *
1255
 * Return:    Success:    The end-of-address-marker
1256
 *
1257
 *            Failure:    HADDR_UNDEF
1258
 *
1259
 *-------------------------------------------------------------------------
1260
 */
1261
static haddr_t
1262
H5FD_multi_get_eoa(const H5FD_t *_file, H5FD_mem_t type)
1263
0
{
1264
0
    const H5FD_multi_t *file = (const H5FD_multi_t *)_file;
1265
0
    haddr_t             eoa  = 0;
1266
1267
    /* Clear the error stack */
1268
0
    H5Eclear2(H5E_DEFAULT);
1269
1270
    /* The library used to have EOA for the whole file.  But it's
1271
     * taken out because it makes little sense for MULTI files.
1272
     * However, the library sometimes queries it through H5F_get_eoa.
1273
     * Here the code finds the biggest EOA for individual file if
1274
     * the query is for TYPE == H5FD_MEM_DEFAULT.
1275
     */
1276
0
    if (H5FD_MEM_DEFAULT == type) {
1277
0
        UNIQUE_MEMBERS (file->fa.memb_map, mt) {
1278
0
            haddr_t memb_eoa;
1279
1280
0
            if (file->memb[mt]) {
1281
                /* Retrieve EOA */
1282
0
                H5E_BEGIN_TRY
1283
0
                {
1284
0
                    memb_eoa = H5FDget_eoa(file->memb[mt], mt);
1285
0
                }
1286
0
                H5E_END_TRY
1287
1288
0
                if (HADDR_UNDEF == memb_eoa)
1289
0
                    H5Epush_ret(__func__, H5E_ERR_CLS, H5E_INTERNAL, H5E_BADVALUE,
1290
0
                                "member file has unknown eoa", HADDR_UNDEF);
1291
0
                if (memb_eoa > 0)
1292
0
                    memb_eoa += file->fa.memb_addr[mt];
1293
0
            }
1294
0
            else if (file->fa.relax) {
1295
                /*
1296
                 * The member is not open yet (maybe it doesn't exist). Make the
1297
                 * best guess about the end-of-file.
1298
                 */
1299
0
                memb_eoa = file->memb_next[mt];
1300
0
                assert(HADDR_UNDEF != memb_eoa);
1301
0
            }
1302
0
            else {
1303
0
                H5Epush_ret(__func__, H5E_ERR_CLS, H5E_INTERNAL, H5E_BADVALUE, "bad eoa", HADDR_UNDEF);
1304
0
            }
1305
1306
0
            if (memb_eoa > eoa)
1307
0
                eoa = memb_eoa;
1308
0
        }
1309
0
        END_MEMBERS
1310
0
    }
1311
0
    else {
1312
0
        H5FD_mem_t mmt = file->fa.memb_map[type];
1313
1314
0
        if (H5FD_MEM_DEFAULT == mmt)
1315
0
            mmt = type;
1316
1317
0
        if (file->memb[mmt]) {
1318
0
            H5E_BEGIN_TRY
1319
0
            {
1320
0
                eoa = H5FDget_eoa(file->memb[mmt], mmt);
1321
0
            }
1322
0
            H5E_END_TRY
1323
1324
0
            if (HADDR_UNDEF == eoa)
1325
0
                H5Epush_ret(__func__, H5E_ERR_CLS, H5E_INTERNAL, H5E_BADVALUE, "member file has unknown eoa",
1326
0
                            HADDR_UNDEF);
1327
0
            if (eoa > 0)
1328
0
                eoa += file->fa.memb_addr[mmt];
1329
0
        }
1330
0
        else if (file->fa.relax) {
1331
            /*
1332
             * The member is not open yet (maybe it doesn't exist). Make the
1333
             * best guess about the end-of-file.
1334
             */
1335
0
            eoa = file->memb_next[mmt];
1336
0
            assert(HADDR_UNDEF != eoa);
1337
0
        }
1338
0
        else {
1339
0
            H5Epush_ret(__func__, H5E_ERR_CLS, H5E_INTERNAL, H5E_BADVALUE, "bad eoa", HADDR_UNDEF);
1340
0
        }
1341
0
    }
1342
1343
0
    return eoa;
1344
0
} /* end H5FD_multi_get_eoa() */
1345
1346
/*-------------------------------------------------------------------------
1347
 * Function:    H5FD_multi_set_eoa
1348
 *
1349
 * Purpose:    Set the end-of-address marker for the file by savig the new
1350
 *        EOA value in the file struct. Also set the EOA marker for the
1351
 *        subfile in which the new EOA value falls. We don't set the
1352
 *        EOA values of any other subfiles.
1353
 *
1354
 * Return:    Success:    0
1355
 *
1356
 *            Failure:    -1
1357
 *
1358
 *-------------------------------------------------------------------------
1359
 */
1360
static herr_t
1361
H5FD_multi_set_eoa(H5FD_t *_file, H5FD_mem_t type, haddr_t eoa)
1362
0
{
1363
0
    H5FD_multi_t *file = (H5FD_multi_t *)_file;
1364
0
    H5FD_mem_t    mmt;
1365
0
    herr_t        status;
1366
1367
    /* Clear the error stack */
1368
0
    H5Eclear2(H5E_DEFAULT);
1369
1370
0
    mmt = file->fa.memb_map[type];
1371
0
    if (H5FD_MEM_DEFAULT == mmt) {
1372
0
        if (H5FD_MEM_DEFAULT == type)
1373
0
            mmt = H5FD_MEM_SUPER;
1374
0
        else
1375
0
            mmt = type;
1376
0
    } /* end if */
1377
1378
    /* Handle backward compatibility in a quick and simple way.  v1.6 library
1379
     * had EOA for the entire virtual file.  But it wasn't meaningful.  So v1.8
1380
     * library doesn't have it anymore.  It saves the EOA for the metadata file,
1381
     * instead.  Here we try to figure out whether the EOA is from a v1.6 file
1382
     * by comparing its value.  If it is a big value, we assume it's from v1.6
1383
     * and simply discard it. This is the normal case when the metadata file
1384
     * has the smallest starting address.  If the metadata file has the biggest
1385
     * address, the EOAs of v1.6 and v1.8 files are the same.  It won't cause
1386
     * any trouble.  (Please see Issue 2598 in Jira) SLU - 2011/6/21
1387
     */
1388
0
    if (H5FD_MEM_SUPER == mmt && file->memb_eoa[H5FD_MEM_SUPER] > 0 &&
1389
0
        eoa > (file->memb_next[H5FD_MEM_SUPER] / 2))
1390
0
        return 0;
1391
1392
0
    assert(eoa >= file->fa.memb_addr[mmt]);
1393
0
    assert(eoa < file->memb_next[mmt]);
1394
1395
0
    H5E_BEGIN_TRY
1396
0
    {
1397
0
        status = H5FDset_eoa(file->memb[mmt], mmt, (eoa - file->fa.memb_addr[mmt]));
1398
0
    }
1399
0
    H5E_END_TRY
1400
0
    if (status < 0)
1401
0
        H5Epush_ret(__func__, H5E_ERR_CLS, H5E_FILE, H5E_BADVALUE, "member H5FDset_eoa failed", -1);
1402
1403
0
    return 0;
1404
0
} /* end H5FD_multi_set_eoa() */
1405
1406
/*-------------------------------------------------------------------------
1407
 * Function:    H5FD_multi_get_eof
1408
 *
1409
 * Purpose:    Returns the end-of-file marker, which is the greater of
1410
 *        either the total multi size or the current EOA marker.
1411
 *
1412
 * Return:    Success:    End of file address, the first address past
1413
 *                the end of the multi of files or the current
1414
 *                EOA, whichever is larger.
1415
 *
1416
 *            Failure:          HADDR_UNDEF
1417
 *
1418
 *-------------------------------------------------------------------------
1419
 */
1420
static haddr_t
1421
H5FD_multi_get_eof(const H5FD_t *_file, H5FD_mem_t type)
1422
0
{
1423
0
    const H5FD_multi_t *file = (const H5FD_multi_t *)_file;
1424
0
    haddr_t             eof  = 0;
1425
1426
    /* Clear the error stack */
1427
0
    H5Eclear2(H5E_DEFAULT);
1428
1429
0
    if (H5FD_MEM_DEFAULT == type) {
1430
0
        UNIQUE_MEMBERS (file->fa.memb_map, mt) {
1431
0
            haddr_t tmp_eof;
1432
1433
0
            if (file->memb[mt]) {
1434
                /* Retrieve EOF */
1435
0
                H5E_BEGIN_TRY
1436
0
                {
1437
0
                    tmp_eof = H5FDget_eof(file->memb[mt], type);
1438
0
                }
1439
0
                H5E_END_TRY
1440
1441
0
                if (HADDR_UNDEF == tmp_eof)
1442
0
                    H5Epush_ret(__func__, H5E_ERR_CLS, H5E_INTERNAL, H5E_BADVALUE,
1443
0
                                "member file has unknown eof", HADDR_UNDEF);
1444
0
                if (tmp_eof > 0)
1445
0
                    tmp_eof += file->fa.memb_addr[mt];
1446
0
            }
1447
0
            else if (file->fa.relax) {
1448
                /*
1449
                 * The member is not open yet (maybe it doesn't exist). Make the
1450
                 * best guess about the end-of-file.
1451
                 */
1452
0
                tmp_eof = file->memb_next[mt];
1453
0
                assert(HADDR_UNDEF != tmp_eof);
1454
0
            }
1455
0
            else {
1456
0
                H5Epush_ret(__func__, H5E_ERR_CLS, H5E_INTERNAL, H5E_BADVALUE, "bad eof", HADDR_UNDEF);
1457
0
            }
1458
0
            if (tmp_eof > eof)
1459
0
                eof = tmp_eof;
1460
0
        }
1461
0
        END_MEMBERS
1462
0
    }
1463
0
    else {
1464
0
        H5FD_mem_t mmt = file->fa.memb_map[type];
1465
1466
0
        if (H5FD_MEM_DEFAULT == mmt)
1467
0
            mmt = type;
1468
1469
0
        if (file->memb[mmt]) {
1470
            /* Retrieve EOF */
1471
0
            H5E_BEGIN_TRY
1472
0
            {
1473
0
                eof = H5FDget_eof(file->memb[mmt], mmt);
1474
0
            }
1475
0
            H5E_END_TRY
1476
1477
0
            if (HADDR_UNDEF == eof)
1478
0
                H5Epush_ret(__func__, H5E_ERR_CLS, H5E_INTERNAL, H5E_BADVALUE, "member file has unknown eof",
1479
0
                            HADDR_UNDEF);
1480
0
            if (eof > 0)
1481
0
                eof += file->fa.memb_addr[mmt];
1482
0
        }
1483
0
        else if (file->fa.relax) {
1484
            /*
1485
             * The member is not open yet (maybe it doesn't exist). Make the
1486
             * best guess about the end-of-file.
1487
             */
1488
0
            eof = file->memb_next[mmt];
1489
0
            assert(HADDR_UNDEF != eof);
1490
0
        }
1491
0
        else {
1492
0
            H5Epush_ret(__func__, H5E_ERR_CLS, H5E_INTERNAL, H5E_BADVALUE, "bad eof", HADDR_UNDEF);
1493
0
        }
1494
0
    }
1495
0
    return eof;
1496
0
}
1497
1498
/*-------------------------------------------------------------------------
1499
 * Function:       H5FD_multi_get_handle
1500
 *
1501
 * Purpose:        Returns the file handle of MULTI file driver.
1502
 *
1503
 * Returns:        Non-negative if succeed or negative if fails.
1504
 *
1505
 *-------------------------------------------------------------------------
1506
 */
1507
static herr_t
1508
H5FD_multi_get_handle(H5FD_t *_file, hid_t fapl, void **file_handle)
1509
0
{
1510
0
    H5FD_multi_t *file = (H5FD_multi_t *)_file;
1511
0
    H5FD_mem_t    type, mmt;
1512
1513
    /* Get data type for multi driver */
1514
0
    if (H5Pget_multi_type(fapl, &type) < 0)
1515
0
        H5Epush_ret(__func__, H5E_ERR_CLS, H5E_INTERNAL, H5E_BADVALUE, "can't get data type for multi driver",
1516
0
                    -1);
1517
0
    if (type < H5FD_MEM_DEFAULT || type >= H5FD_MEM_NTYPES)
1518
0
        H5Epush_ret(__func__, H5E_ERR_CLS, H5E_INTERNAL, H5E_BADVALUE, "data type is out of range", -1);
1519
0
    mmt = file->fa.memb_map[type];
1520
0
    if (H5FD_MEM_DEFAULT == mmt)
1521
0
        mmt = type;
1522
1523
0
    return (H5FDget_vfd_handle(file->memb[mmt], fapl, file_handle));
1524
0
}
1525
1526
/*-------------------------------------------------------------------------
1527
 * Function:    H5FD_multi_alloc
1528
 *
1529
 * Purpose:    Allocate file memory.
1530
 *
1531
 * Return:    Success:    Address of new memory
1532
 *
1533
 *            Failure:    HADDR_UNDEF
1534
 *
1535
 *-------------------------------------------------------------------------
1536
 */
1537
static haddr_t
1538
H5FD_multi_alloc(H5FD_t *_file, H5FD_mem_t type, hid_t dxpl_id, hsize_t size)
1539
0
{
1540
0
    H5FD_multi_t *file = (H5FD_multi_t *)_file;
1541
0
    H5FD_mem_t    mmt;
1542
0
    haddr_t       addr;
1543
1544
0
    mmt = file->fa.memb_map[type];
1545
0
    if (H5FD_MEM_DEFAULT == mmt)
1546
0
        mmt = type;
1547
1548
    /* XXX: NEED to work on this again */
1549
0
    if (file->pub.paged_aggr) {
1550
0
        ALL_MEMBERS (mt) {
1551
0
            if (file->memb[mt])
1552
0
                file->memb[mt]->paged_aggr = file->pub.paged_aggr;
1553
0
        }
1554
0
        END_MEMBERS
1555
0
    }
1556
1557
0
    if (HADDR_UNDEF == (addr = H5FDalloc(file->memb[mmt], mmt, dxpl_id, size)))
1558
0
        H5Epush_ret(__func__, H5E_ERR_CLS, H5E_INTERNAL, H5E_BADVALUE, "member file can't alloc",
1559
0
                    HADDR_UNDEF);
1560
0
    addr += file->fa.memb_addr[mmt];
1561
1562
0
    return addr;
1563
0
}
1564
1565
/*-------------------------------------------------------------------------
1566
 * Function:    H5FD_multi_free
1567
 *
1568
 * Purpose:    Frees memory
1569
 *
1570
 * Return:    Success:    0
1571
 *
1572
 *            Failure:    -1
1573
 *
1574
 *-------------------------------------------------------------------------
1575
 */
1576
static herr_t
1577
H5FD_multi_free(H5FD_t *_file, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr, hsize_t size)
1578
0
{
1579
0
    H5FD_multi_t *file = (H5FD_multi_t *)_file;
1580
0
    H5FD_mem_t    mmt;
1581
1582
    /* Clear the error stack */
1583
0
    H5Eclear2(H5E_DEFAULT);
1584
1585
0
    mmt = file->fa.memb_map[type];
1586
0
    if (H5FD_MEM_DEFAULT == mmt)
1587
0
        mmt = type;
1588
1589
0
    assert(addr >= file->fa.memb_addr[mmt]);
1590
0
    assert(addr + size <= file->memb_next[mmt]);
1591
0
    return H5FDfree(file->memb[mmt], mmt, dxpl_id, addr - file->fa.memb_addr[mmt], size);
1592
0
}
1593
1594
/*-------------------------------------------------------------------------
1595
 * Function:    H5FD_multi_read
1596
 *
1597
 * Purpose:    Reads SIZE bytes of data from FILE beginning at address ADDR
1598
 *        into buffer BUF according to data transfer properties in
1599
 *        DXPL_ID.
1600
 *
1601
 * Return:    Success:    Zero. Result is stored in caller-supplied
1602
 *                buffer BUF.
1603
 *
1604
 *            Failure:    -1, contents of buffer BUF are undefined.
1605
 *
1606
 *-------------------------------------------------------------------------
1607
 */
1608
static herr_t
1609
H5FD_multi_read(H5FD_t *_file, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr, size_t size, void *_buf /*out*/)
1610
0
{
1611
0
    H5FD_multi_t *file = (H5FD_multi_t *)_file;
1612
0
    H5FD_mem_t    mt, mmt, hi = H5FD_MEM_DEFAULT;
1613
0
    haddr_t       start_addr = 0;
1614
1615
    /* Clear the error stack */
1616
0
    H5Eclear2(H5E_DEFAULT);
1617
1618
    /* Find the file to which this address belongs */
1619
0
    for (mt = H5FD_MEM_SUPER; mt < H5FD_MEM_NTYPES; mt = (H5FD_mem_t)(mt + 1)) {
1620
0
        mmt = file->fa.memb_map[mt];
1621
0
        if (H5FD_MEM_DEFAULT == mmt)
1622
0
            mmt = mt;
1623
0
        assert(mmt > 0 && mmt < H5FD_MEM_NTYPES);
1624
1625
0
        if (file->fa.memb_addr[mmt] > addr)
1626
0
            continue;
1627
0
        if (file->fa.memb_addr[mmt] >= start_addr) {
1628
0
            start_addr = file->fa.memb_addr[mmt];
1629
0
            hi         = mmt;
1630
0
        } /* end if */
1631
0
    }     /* end for */
1632
0
    assert(hi > 0);
1633
1634
    /* Read from that member */
1635
0
    return H5FDread(file->memb[hi], type, dxpl_id, addr - start_addr, size, _buf);
1636
0
} /* end H5FD_multi_read() */
1637
1638
/*-------------------------------------------------------------------------
1639
 * Function:    H5FD_multi_write
1640
 *
1641
 * Purpose:    Writes SIZE bytes of data to FILE beginning at address ADDR
1642
 *        from buffer BUF according to data transfer properties in
1643
 *        DXPL_ID.
1644
 *
1645
 * Return:    Success:    Zero
1646
 *
1647
 *            Failure:    -1
1648
 *
1649
 *-------------------------------------------------------------------------
1650
 */
1651
static herr_t
1652
H5FD_multi_write(H5FD_t *_file, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr, size_t size, const void *_buf)
1653
0
{
1654
0
    H5FD_multi_t *file = (H5FD_multi_t *)_file;
1655
0
    H5FD_mem_t    mt, mmt, hi = H5FD_MEM_DEFAULT;
1656
0
    haddr_t       start_addr = 0;
1657
1658
    /* Clear the error stack */
1659
0
    H5Eclear2(H5E_DEFAULT);
1660
1661
    /* Find the file to which this address belongs */
1662
0
    for (mt = H5FD_MEM_SUPER; mt < H5FD_MEM_NTYPES; mt = (H5FD_mem_t)(mt + 1)) {
1663
0
        mmt = file->fa.memb_map[mt];
1664
0
        if (H5FD_MEM_DEFAULT == mmt)
1665
0
            mmt = mt;
1666
0
        assert(mmt > 0 && mmt < H5FD_MEM_NTYPES);
1667
1668
0
        if (file->fa.memb_addr[mmt] > addr)
1669
0
            continue;
1670
0
        if (file->fa.memb_addr[mmt] >= start_addr) {
1671
0
            start_addr = file->fa.memb_addr[mmt];
1672
0
            hi         = mmt;
1673
0
        } /* end if */
1674
0
    }     /* end for */
1675
0
    assert(hi > 0);
1676
1677
    /* Write to that member */
1678
0
    return H5FDwrite(file->memb[hi], type, dxpl_id, addr - start_addr, size, _buf);
1679
0
} /* end H5FD_multi_write() */
1680
1681
/*-------------------------------------------------------------------------
1682
 * Function:    H5FD_multi_flush
1683
 *
1684
 * Purpose:    Flushes all multi members.
1685
 *
1686
 * Return:    Success:    0
1687
 *
1688
 *            Failure:    -1, as many files flushed as possible.
1689
 *
1690
 *-------------------------------------------------------------------------
1691
 */
1692
static herr_t
1693
H5FD_multi_flush(H5FD_t *_file, hid_t dxpl_id, bool closing)
1694
0
{
1695
0
    H5FD_multi_t *file = (H5FD_multi_t *)_file;
1696
0
    H5FD_mem_t    mt;
1697
0
    int           nerrors = 0;
1698
1699
    /* Clear the error stack */
1700
0
    H5Eclear2(H5E_DEFAULT);
1701
1702
    /* Flush each file */
1703
0
    for (mt = H5FD_MEM_SUPER; mt < H5FD_MEM_NTYPES; mt = (H5FD_mem_t)(mt + 1)) {
1704
0
        if (file->memb[mt]) {
1705
0
            H5E_BEGIN_TRY
1706
0
            {
1707
0
                if (H5FDflush(file->memb[mt], dxpl_id, closing) < 0)
1708
0
                    nerrors++;
1709
0
            }
1710
0
            H5E_END_TRY
1711
0
        }
1712
0
    }
1713
0
    if (nerrors)
1714
0
        H5Epush_ret(__func__, H5E_ERR_CLS, H5E_INTERNAL, H5E_BADVALUE, "error flushing member files", -1);
1715
1716
0
    return 0;
1717
0
}
1718
1719
/*-------------------------------------------------------------------------
1720
 * Function:    H5FD_multi_truncate
1721
 *
1722
 * Purpose:    Truncates all multi members.
1723
 *
1724
 * Return:    Success:    0
1725
 *            Failure:    -1, as many files truncated as possible.
1726
 *
1727
 *-------------------------------------------------------------------------
1728
 */
1729
static herr_t
1730
H5FD_multi_truncate(H5FD_t *_file, hid_t dxpl_id, bool closing)
1731
0
{
1732
0
    H5FD_multi_t *file = (H5FD_multi_t *)_file;
1733
0
    H5FD_mem_t    mt;
1734
0
    int           nerrors = 0;
1735
1736
    /* Clear the error stack */
1737
0
    H5Eclear2(H5E_DEFAULT);
1738
1739
    /* Truncate each file */
1740
0
    for (mt = H5FD_MEM_SUPER; mt < H5FD_MEM_NTYPES; mt = (H5FD_mem_t)(mt + 1)) {
1741
0
        if (file->memb[mt]) {
1742
0
            H5E_BEGIN_TRY
1743
0
            {
1744
0
                if (H5FDtruncate(file->memb[mt], dxpl_id, closing) < 0)
1745
0
                    nerrors++;
1746
0
            }
1747
0
            H5E_END_TRY
1748
0
        }
1749
0
    }
1750
0
    if (nerrors)
1751
0
        H5Epush_ret(__func__, H5E_ERR_CLS, H5E_INTERNAL, H5E_BADVALUE, "error truncating member files", -1);
1752
1753
0
    return 0;
1754
0
} /* end H5FD_multi_truncate() */
1755
1756
/*-------------------------------------------------------------------------
1757
 * Function:    H5FD_multi_lock
1758
 *
1759
 * Purpose:    Place a lock on all multi members.
1760
 *        When there is error in locking a member file, it will not
1761
 *        proceed further and will try to remove the locks  of those
1762
 *        member files that are locked before error is encountered.
1763
 *
1764
 * Return:    Success:    0
1765
 *            Failure:    -1
1766
 *
1767
 *-------------------------------------------------------------------------
1768
 */
1769
static herr_t
1770
H5FD_multi_lock(H5FD_t *_file, bool rw)
1771
0
{
1772
0
    H5FD_multi_t *file    = (H5FD_multi_t *)_file;
1773
0
    int           nerrors = 0;
1774
0
    H5FD_mem_t    out_mt  = H5FD_MEM_DEFAULT;
1775
1776
    /* Clear the error stack */
1777
0
    H5Eclear2(H5E_DEFAULT);
1778
1779
    /* Lock all member files */
1780
0
    ALL_MEMBERS (mt) {
1781
0
        out_mt = mt;
1782
0
        if (file->memb[mt]) {
1783
0
            H5E_BEGIN_TRY
1784
0
            {
1785
0
                if (H5FDlock(file->memb[mt], rw) < 0) {
1786
0
                    nerrors++;
1787
0
                    break;
1788
0
                } /* end if */
1789
0
            }
1790
0
            H5E_END_TRY
1791
0
        } /* end if */
1792
0
    }
1793
0
    END_MEMBERS
1794
1795
    /* Try to unlock the member files that are locked before error is encountered */
1796
0
    if (nerrors) {
1797
0
        H5FD_mem_t k;
1798
1799
0
        for (k = H5FD_MEM_DEFAULT; k < out_mt; k = (H5FD_mem_t)(k + 1)) {
1800
0
            H5E_BEGIN_TRY
1801
0
            {
1802
0
                if (H5FDunlock(file->memb[k]) < 0)
1803
0
                    nerrors++;
1804
0
            }
1805
0
            H5E_END_TRY
1806
0
        } /* end for */
1807
0
    }     /* end if */
1808
1809
0
    if (nerrors)
1810
0
        H5Epush_ret(__func__, H5E_ERR_CLS, H5E_VFL, H5E_CANTLOCKFILE, "error locking member files", -1);
1811
0
    return 0;
1812
1813
0
} /* H5FD_multi_lock() */
1814
1815
/*-------------------------------------------------------------------------
1816
 * Function:    H5FD_multi_unlock
1817
 *
1818
 * Purpose:    Remove the lock on all multi members.
1819
 *        It will try to unlock all member files but will record error
1820
 *        encountered.
1821
 *
1822
 * Return:    Success:    0
1823
 *            Failure:    -1
1824
 *
1825
 *-------------------------------------------------------------------------
1826
 */
1827
static herr_t
1828
H5FD_multi_unlock(H5FD_t *_file)
1829
0
{
1830
0
    H5FD_multi_t *file    = (H5FD_multi_t *)_file;
1831
0
    int           nerrors = 0;
1832
1833
    /* Clear the error stack */
1834
0
    H5Eclear2(H5E_DEFAULT);
1835
1836
0
    ALL_MEMBERS (mt) {
1837
0
        if (file->memb[mt])
1838
0
            if (H5FDunlock(file->memb[mt]) < 0)
1839
0
                nerrors++;
1840
0
    }
1841
0
    END_MEMBERS
1842
1843
0
    if (nerrors)
1844
0
        H5Epush_ret(__func__, H5E_ERR_CLS, H5E_VFL, H5E_CANTUNLOCKFILE, "error unlocking member files", -1);
1845
1846
0
    return 0;
1847
0
} /* H5FD_multi_unlock() */
1848
1849
/*-------------------------------------------------------------------------
1850
 * Function:    compute_next
1851
 *
1852
 * Purpose:    Compute the memb_next[] values of the file based on the
1853
 *        file's member map and the member starting addresses.
1854
 *
1855
 * Return:    Success:    0
1856
 *
1857
 *            Failure:    -1
1858
 *
1859
 *-------------------------------------------------------------------------
1860
 */
1861
static int
1862
compute_next(H5FD_multi_t *file)
1863
0
{
1864
    /* Clear the error stack */
1865
0
    H5Eclear2(H5E_DEFAULT);
1866
1867
0
    ALL_MEMBERS (mt) {
1868
0
        file->memb_next[mt] = HADDR_UNDEF;
1869
0
    }
1870
0
    END_MEMBERS
1871
1872
0
    UNIQUE_MEMBERS (file->fa.memb_map, mt1) {
1873
0
        UNIQUE_MEMBERS2(file->fa.memb_map, mt2)
1874
0
        {
1875
0
            if (file->fa.memb_addr[mt1] < file->fa.memb_addr[mt2] &&
1876
0
                (HADDR_UNDEF == file->memb_next[mt1] || file->memb_next[mt1] > file->fa.memb_addr[mt2])) {
1877
0
                file->memb_next[mt1] = file->fa.memb_addr[mt2];
1878
0
            }
1879
0
        }
1880
0
        END_MEMBERS
1881
0
        if (HADDR_UNDEF == file->memb_next[mt1]) {
1882
0
            file->memb_next[mt1] = HADDR_MAX; /*last member*/
1883
0
        }
1884
0
    }
1885
0
    END_MEMBERS
1886
1887
0
    return 0;
1888
0
}
1889
1890
/*-------------------------------------------------------------------------
1891
 * Function:    open_members
1892
 *
1893
 * Purpose:    Opens all members which are not opened yet.
1894
 *
1895
 * Return:    Success:    0
1896
 *
1897
 *            Failure:    -1
1898
 *
1899
 *-------------------------------------------------------------------------
1900
 */
1901
static int
1902
open_members(H5FD_multi_t *file)
1903
0
{
1904
0
    char tmp[H5FD_MULT_MAX_FILE_NAME_LEN];
1905
0
    int  nerrors = 0;
1906
0
    int  nchars;
1907
1908
    /* Clear the error stack */
1909
0
    H5Eclear2(H5E_DEFAULT);
1910
1911
0
    UNIQUE_MEMBERS (file->fa.memb_map, mt) {
1912
0
        if (file->memb[mt])
1913
0
            continue; /*already open*/
1914
0
        assert(file->fa.memb_name[mt]);
1915
1916
0
        H5_WARN_FORMAT_NONLITERAL_OFF
1917
0
        nchars = snprintf(tmp, sizeof(tmp), file->fa.memb_name[mt], file->name);
1918
0
        H5_WARN_FORMAT_NONLITERAL_ON
1919
0
        if (nchars < 0 || nchars >= (int)sizeof(tmp))
1920
0
            H5Epush_ret(__func__, H5E_ERR_CLS, H5E_VFL, H5E_BADVALUE,
1921
0
                        "filename is too long and would be truncated", -1);
1922
1923
0
        H5E_BEGIN_TRY
1924
0
        {
1925
0
            file->memb[mt] = H5FDopen(tmp, file->flags, file->fa.memb_fapl[mt], HADDR_UNDEF);
1926
0
        }
1927
0
        H5E_END_TRY
1928
0
        if (!file->memb[mt]) {
1929
0
            if (!file->fa.relax || (file->flags & H5F_ACC_RDWR))
1930
0
                nerrors++;
1931
0
        }
1932
0
    }
1933
0
    END_MEMBERS
1934
0
    if (nerrors)
1935
0
        H5Epush_ret(__func__, H5E_ERR_CLS, H5E_INTERNAL, H5E_BADVALUE, "error opening member files", -1);
1936
1937
0
    return 0;
1938
0
}
1939
1940
/*-------------------------------------------------------------------------
1941
 * Function:    H5FD_multi_delete
1942
 *
1943
 * Purpose:     Delete a file
1944
 *
1945
 * Return:      SUCCEED/FAIL
1946
 *
1947
 *-------------------------------------------------------------------------
1948
 */
1949
static herr_t
1950
H5FD_multi_delete(const char *filename, hid_t fapl_id)
1951
0
{
1952
0
    char                     full_filename[H5FD_MULT_MAX_FILE_NAME_LEN];
1953
0
    int                      nchars;
1954
0
    const H5FD_multi_fapl_t *fa;
1955
0
    H5FD_multi_fapl_t        default_fa;
1956
1957
    /* Clear the error stack */
1958
0
    H5Eclear2(H5E_DEFAULT);
1959
1960
0
    assert(filename);
1961
1962
    /* Get the driver info */
1963
0
    H5E_BEGIN_TRY
1964
0
    {
1965
0
        fa = (const H5FD_multi_fapl_t *)H5Pget_driver_info(fapl_id);
1966
0
    }
1967
0
    H5E_END_TRY
1968
0
    if (!fa) {
1969
0
        char *env = getenv(HDF5_DRIVER);
1970
1971
0
        if (env && !strcmp(env, "split")) {
1972
0
            if (H5FD_split_populate_config(NULL, H5P_DEFAULT, NULL, H5P_DEFAULT, true, &default_fa) < 0)
1973
0
                H5Epush_ret(__func__, H5E_ERR_CLS, H5E_VFL, H5E_CANTSET, "can't setup driver configuration",
1974
0
                            -1);
1975
0
        }
1976
0
        else {
1977
0
            if (H5FD_multi_populate_config(NULL, NULL, NULL, NULL, true, &default_fa) < 0)
1978
0
                H5Epush_ret(__func__, H5E_ERR_CLS, H5E_VFL, H5E_CANTSET, "can't setup driver configuration",
1979
0
                            -1);
1980
0
        }
1981
1982
0
        fa = &default_fa;
1983
0
    }
1984
0
    assert(fa);
1985
1986
    /* Delete each member file using the underlying fapl */
1987
0
    UNIQUE_MEMBERS (fa->memb_map, mt) {
1988
0
        assert(fa->memb_name[mt]);
1989
0
        assert(fa->memb_fapl[mt] >= 0);
1990
1991
0
        H5_WARN_FORMAT_NONLITERAL_OFF
1992
0
        nchars = snprintf(full_filename, sizeof(full_filename), fa->memb_name[mt], filename);
1993
0
        H5_WARN_FORMAT_NONLITERAL_ON
1994
0
        if (nchars < 0 || nchars >= (int)sizeof(full_filename))
1995
0
            H5Epush_ret(__func__, H5E_ERR_CLS, H5E_VFL, H5E_BADVALUE,
1996
0
                        "filename is too long and would be truncated", -1);
1997
1998
0
        if (H5FDdelete(full_filename, fa->memb_fapl[mt]) < 0)
1999
0
            H5Epush_ret(__func__, H5E_ERR_CLS, H5E_VFL, H5E_BADVALUE, "error deleting member files", -1);
2000
0
    }
2001
0
    END_MEMBERS
2002
2003
0
    return 0;
2004
0
} /* end H5FD_multi_delete() */
2005
2006
/*-------------------------------------------------------------------------
2007
 * Function:    H5FD_multi_ctl
2008
 *
2009
 * Purpose:     Multi VFD version of the ctl callback.
2010
 *
2011
 *              The desired operation is specified by the op_code
2012
 *              parameter.
2013
 *
2014
 *              The flags parameter controls management of op_codes that
2015
 *              are unknown to the callback
2016
 *
2017
 *              The input and output parameters allow op_code specific
2018
 *              input and output
2019
 *
2020
 *              At present, this VFD supports no op codes of its own.
2021
 *
2022
 * Return:      Non-negative on success/Negative on failure
2023
 *
2024
 *-------------------------------------------------------------------------
2025
 */
2026
static herr_t
2027
H5FD_multi_ctl(H5FD_t *_file, uint64_t op_code, uint64_t flags, const void *input, void **output)
2028
0
{
2029
0
    H5FD_multi_t *file      = (H5FD_multi_t *)_file;
2030
0
    herr_t        ret_value = 0;
2031
2032
    /* Silence compiler */
2033
0
    (void)file;
2034
0
    (void)input;
2035
0
    (void)output;
2036
2037
    /* Clear the error stack */
2038
0
    H5Eclear2(H5E_DEFAULT);
2039
2040
0
    switch (op_code) {
2041
        /* Unknown op code */
2042
0
        default:
2043
0
            if (flags & H5FD_CTL_FAIL_IF_UNKNOWN_FLAG)
2044
0
                H5Epush_ret(__func__, H5E_ERR_CLS, H5E_VFL, H5E_FCNTL,
2045
0
                            "VFD ctl request failed (unknown op code and fail if unknown flag is set)", -1);
2046
2047
0
            break;
2048
0
    }
2049
2050
0
    return ret_value;
2051
0
} /* end H5FD_multi_ctl() */
2052
2053
#ifdef H5private_H
2054
/*
2055
 * This is not related to the functionality of the driver code.
2056
 * It is added here to trigger warning if HDF5 private definitions are included
2057
 * by mistake.  The code should use only HDF5 public API and definitions.
2058
 */
2059
#error "Do not use HDF5 private definitions"
2060
#endif