Coverage Report

Created: 2026-06-08 06:14

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/hdf5/src/H5FDfamily.c
Line
Count
Source
1
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2
 * Copyright by The HDF Group.                                               *
3
 * All rights reserved.                                                      *
4
 *                                                                           *
5
 * This file is part of HDF5.  The full HDF5 copyright notice, including     *
6
 * terms governing use, modification, and redistribution, is contained in    *
7
 * the LICENSE file, which can be found at the root of the source code       *
8
 * distribution tree, or in https://www.hdfgroup.org/licenses.               *
9
 * If you do not have access to either file, you may request a copy from     *
10
 * help@hdfgroup.org.                                                        *
11
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
12
13
/*
14
 * Purpose:    Implements a family of files that acts as a single hdf5
15
 *        file.  The purpose is to be able to split a huge file on a
16
 *        64-bit platform, transfer all the <2GB members to a 32-bit
17
 *        platform, and then access the entire huge file on the 32-bit
18
 *        platform.
19
 *
20
 *        All family members are logically the same size although their
21
 *        physical sizes may vary.  The logical member size is
22
 *        determined by looking at the physical size of the first member
23
 *        when the file is opened.  When creating a file family, the
24
 *        first member is created with a predefined physical size
25
 *        (actually, this happens when the file family is flushed, and
26
 *        can be quite time consuming on file systems that don't
27
 *        implement holes, like nfs).
28
 *
29
 */
30
31
#include "H5FDmodule.h" /* This source code file is part of the H5FD module */
32
33
#include "H5private.h"   /* Generic Functions                       */
34
#include "H5Eprivate.h"  /* Error handling                          */
35
#include "H5Fprivate.h"  /* File access                             */
36
#include "H5FDfamily.h"  /* Family file driver                      */
37
#include "H5FDpkg.h"     /* File drivers                            */
38
#include "H5Iprivate.h"  /* IDs                                     */
39
#include "H5MMprivate.h" /* Memory management                       */
40
#include "H5Pprivate.h"  /* Property lists                          */
41
42
/* The size of the member name buffers */
43
0
#define H5FD_FAM_MEMB_NAME_BUF_SIZE 4096
44
45
/* Default member size - 100 MiB */
46
0
#define H5FD_FAM_DEF_MEM_SIZE ((hsize_t)(100 * H5_MB))
47
48
/* The driver identification number, initialized at runtime */
49
hid_t H5FD_FAMILY_id_g = H5I_INVALID_HID;
50
51
/* The description of a file belonging to this driver. */
52
typedef struct H5FD_family_t {
53
    H5FD_t   pub;          /*public stuff, must be first        */
54
    hid_t    memb_fapl_id; /*file access property list for members    */
55
    hsize_t  memb_size;    /*actual size of each member file    */
56
    hsize_t  pmem_size;    /*member size passed in from property    */
57
    unsigned nmembs;       /*number of family members        */
58
    unsigned amembs;       /*number of member slots allocated    */
59
    H5FD_t **memb;         /*dynamic array of member pointers    */
60
    haddr_t  eoa;          /*end of allocated addresses        */
61
    char    *name;         /*name generator printf format        */
62
    unsigned flags;        /*flags for opening additional members    */
63
64
    /* Information from properties set by 'h5repart' tool */
65
    hsize_t mem_newsize; /*new member size passed in as private
66
                          * property. It's used only by h5repart */
67
    bool repart_members; /* Whether to mark the superblock dirty
68
                          * when it is loaded, so that the family
69
                          * member sizes can be re-encoded       */
70
} H5FD_family_t;
71
72
/* Driver-specific file access properties */
73
typedef struct H5FD_family_fapl_t {
74
    hsize_t memb_size;    /*size of each member            */
75
    hid_t   memb_fapl_id; /*file access property list of each memb*/
76
} H5FD_family_fapl_t;
77
78
/* Private routines */
79
static herr_t H5FD__family_get_default_config(H5FD_family_fapl_t *fa_out);
80
static char  *H5FD__family_get_default_printf_filename(const char *old_filename);
81
82
/* Callback prototypes */
83
static void   *H5FD__family_fapl_get(H5FD_t *_file);
84
static void   *H5FD__family_fapl_copy(const void *_old_fa);
85
static herr_t  H5FD__family_fapl_free(void *_fa);
86
static hsize_t H5FD__family_sb_size(H5FD_t *_file);
87
static herr_t  H5FD__family_sb_encode(H5FD_t *_file, char *name /*out*/, unsigned char *buf /*out*/);
88
static herr_t  H5FD__family_sb_decode(H5FD_t *_file, const char *name, const unsigned char *buf);
89
static H5FD_t *H5FD__family_open(const char *name, unsigned flags, hid_t fapl_id, haddr_t maxaddr);
90
static herr_t  H5FD__family_close(H5FD_t *_file);
91
static int     H5FD__family_cmp(const H5FD_t *_f1, const H5FD_t *_f2);
92
static herr_t  H5FD__family_query(const H5FD_t *_f1, unsigned long *flags);
93
static haddr_t H5FD__family_get_eoa(const H5FD_t *_file, H5FD_mem_t type);
94
static herr_t  H5FD__family_set_eoa(H5FD_t *_file, H5FD_mem_t type, haddr_t eoa);
95
static haddr_t H5FD__family_get_eof(const H5FD_t *_file, H5FD_mem_t type);
96
static herr_t  H5FD__family_get_handle(H5FD_t *_file, hid_t fapl, void **file_handle);
97
static herr_t  H5FD__family_read(H5FD_t *_file, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr, size_t size,
98
                                 void *_buf /*out*/);
99
static herr_t  H5FD__family_write(H5FD_t *_file, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr, size_t size,
100
                                  const void *_buf);
101
static herr_t  H5FD__family_flush(H5FD_t *_file, hid_t dxpl_id, bool closing);
102
static herr_t  H5FD__family_truncate(H5FD_t *_file, hid_t dxpl_id, bool closing);
103
static herr_t  H5FD__family_lock(H5FD_t *_file, bool rw);
104
static herr_t  H5FD__family_unlock(H5FD_t *_file);
105
static herr_t  H5FD__family_delete(const char *filename, hid_t fapl_id);
106
107
/* The class struct */
108
static const H5FD_class_t H5FD_family_g = {
109
    H5FD_CLASS_VERSION,         /* struct version       */
110
    H5FD_FAMILY_VALUE,          /* value                */
111
    "family",                   /* name                 */
112
    HADDR_MAX,                  /* maxaddr              */
113
    H5F_CLOSE_WEAK,             /* fc_degree            */
114
    NULL,                       /* terminate            */
115
    H5FD__family_sb_size,       /* sb_size              */
116
    H5FD__family_sb_encode,     /* sb_encode            */
117
    H5FD__family_sb_decode,     /* sb_decode            */
118
    sizeof(H5FD_family_fapl_t), /* fapl_size            */
119
    H5FD__family_fapl_get,      /* fapl_get             */
120
    H5FD__family_fapl_copy,     /* fapl_copy            */
121
    H5FD__family_fapl_free,     /* fapl_free            */
122
    0,                          /* dxpl_size            */
123
    NULL,                       /* dxpl_copy            */
124
    NULL,                       /* dxpl_free            */
125
    H5FD__family_open,          /* open                 */
126
    H5FD__family_close,         /* close                */
127
    H5FD__family_cmp,           /* cmp                  */
128
    H5FD__family_query,         /* query                */
129
    NULL,                       /* get_type_map         */
130
    NULL,                       /* alloc                */
131
    NULL,                       /* free                 */
132
    H5FD__family_get_eoa,       /* get_eoa              */
133
    H5FD__family_set_eoa,       /* set_eoa              */
134
    H5FD__family_get_eof,       /* get_eof              */
135
    H5FD__family_get_handle,    /* get_handle           */
136
    H5FD__family_read,          /* read                 */
137
    H5FD__family_write,         /* write                */
138
    NULL,                       /* read_vector          */
139
    NULL,                       /* write_vector         */
140
    NULL,                       /* read_selection       */
141
    NULL,                       /* write_selection      */
142
    H5FD__family_flush,         /* flush                */
143
    H5FD__family_truncate,      /* truncate             */
144
    H5FD__family_lock,          /* lock                 */
145
    H5FD__family_unlock,        /* unlock               */
146
    H5FD__family_delete,        /* del                  */
147
    NULL,                       /* ctl                  */
148
    H5FD_FLMAP_DICHOTOMY        /* fl_map               */
149
};
150
151
/*-------------------------------------------------------------------------
152
 * Function:    H5FD__family_get_default_config
153
 *
154
 * Purpose:     Populates a H5FD_family_fapl_t structure with default
155
 *              values.
156
 *
157
 * Return:      Non-negative on Success/Negative on Failure
158
 *
159
 *-------------------------------------------------------------------------
160
 */
161
static herr_t
162
H5FD__family_get_default_config(H5FD_family_fapl_t *fa_out)
163
0
{
164
0
    H5P_genplist_t *def_plist;
165
0
    H5P_genplist_t *plist;
166
0
    herr_t          ret_value = SUCCEED;
167
168
0
    FUNC_ENTER_PACKAGE
169
170
0
    assert(fa_out);
171
172
0
    fa_out->memb_size = H5FD_FAM_DEF_MEM_SIZE;
173
174
    /* Use copy of default file access property list for member FAPL ID.
175
     * The Sec2 driver is explicitly set on the member FAPL ID, as the
176
     * default driver might have been replaced with the Family VFD, which
177
     * would cause recursion badness in the child members.
178
     */
179
0
    if (NULL == (def_plist = (H5P_genplist_t *)H5I_object(H5P_FILE_ACCESS_DEFAULT)))
180
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file access property list");
181
0
    if ((fa_out->memb_fapl_id = H5P_copy_plist(def_plist, false)) < 0)
182
0
        HGOTO_ERROR(H5E_VFL, H5E_CANTCOPY, FAIL, "can't copy property list");
183
0
    if (NULL == (plist = (H5P_genplist_t *)H5I_object(fa_out->memb_fapl_id)))
184
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file access property list");
185
0
    if (H5P_set_driver_by_value(plist, H5_VFD_SEC2, NULL, true) < 0)
186
0
        HGOTO_ERROR(H5E_VFL, H5E_CANTSET, FAIL, "can't set default driver on member FAPL");
187
188
0
done:
189
0
    if (ret_value < 0 && fa_out->memb_fapl_id >= 0)
190
0
        if (H5I_dec_ref(fa_out->memb_fapl_id) < 0)
191
0
            HDONE_ERROR(H5E_VFL, H5E_CANTDEC, FAIL, "can't decrement ref. count on member FAPL ID");
192
193
0
    FUNC_LEAVE_NOAPI(ret_value)
194
0
} /* end H5FD__family_get_default_config() */
195
196
/*-------------------------------------------------------------------------
197
 * Function:    H5FD__family_get_default_printf_filename
198
 *
199
 * Purpose:     Given a filename, allocates and returns a new filename
200
 *              buffer that contains the given filename modified into this
201
 *              VFD's printf-style format. For example, the filename
202
 *              "file1.h5" would be modified to "file1-%06d.h5". This would
203
 *              allow for member filenames such as "file1-000000.h5",
204
 *              "file1-000001.h5", etc. The caller is responsible for
205
 *              freeing the returned buffer.
206
 *
207
 * Return:      Non-negative on Success/Negative on Failure
208
 *
209
 *-------------------------------------------------------------------------
210
 */
211
static char *
212
H5FD__family_get_default_printf_filename(const char *old_filename)
213
0
{
214
0
    const char *suffix           = "-%06d";
215
0
    size_t      old_filename_len = 0;
216
0
    size_t      new_filename_len = 0;
217
0
    char       *file_extension   = NULL;
218
0
    char       *tmp_buffer       = NULL;
219
0
    char       *ret_value        = NULL;
220
221
0
    FUNC_ENTER_PACKAGE
222
223
0
    assert(old_filename);
224
225
0
    old_filename_len = strlen(old_filename);
226
0
    if (0 == old_filename_len)
227
0
        HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, NULL, "invalid filename");
228
229
0
    new_filename_len = old_filename_len + strlen(suffix) + 1;
230
0
    if (NULL == (tmp_buffer = H5MM_malloc(new_filename_len)))
231
0
        HGOTO_ERROR(H5E_VFL, H5E_CANTALLOC, NULL, "can't allocate new filename buffer");
232
233
    /* Determine if filename contains a ".h5" extension. */
234
0
    file_extension = strstr(old_filename, ".h5");
235
0
    if (file_extension) {
236
        /* Insert the printf format between the filename and ".h5" extension. */
237
0
        intptr_t beginningLength = file_extension - old_filename;
238
239
0
        snprintf(tmp_buffer, new_filename_len, "%.*s%s%s", (int)beginningLength, old_filename, suffix, ".h5");
240
0
    }
241
0
    else {
242
        /* If the filename doesn't contain a ".h5" extension, but contains
243
         * AN extension, just insert the printf format before that extension.
244
         */
245
0
        file_extension = strrchr(old_filename, '.');
246
0
        if (file_extension) {
247
0
            intptr_t beginningLength = file_extension - old_filename;
248
249
0
            snprintf(tmp_buffer, new_filename_len, "%.*s%s%s", (int)beginningLength, old_filename, suffix,
250
0
                     file_extension);
251
0
        }
252
0
        else
253
            /* If the filename doesn't contain an extension at all, just insert
254
             * the printf format at the end of the filename.
255
             */
256
0
            snprintf(tmp_buffer, new_filename_len, "%s%s", old_filename, suffix);
257
0
    }
258
259
0
    ret_value = tmp_buffer;
260
261
0
done:
262
0
    if (!ret_value)
263
0
        H5MM_xfree(tmp_buffer);
264
265
0
    FUNC_LEAVE_NOAPI(ret_value)
266
0
} /* end H5FD__family_get_default_printf_filename() */
267
268
/*-------------------------------------------------------------------------
269
 * Function:    H5FD__family_register
270
 *
271
 * Purpose:     Register the driver with the library.
272
 *
273
 * Return:      SUCCEED/FAIL
274
 *
275
 *-------------------------------------------------------------------------
276
 */
277
herr_t
278
H5FD__family_register(void)
279
1
{
280
1
    herr_t ret_value = SUCCEED; /* Return value */
281
282
1
    FUNC_ENTER_PACKAGE
283
284
1
    if (H5I_VFL != H5I_get_type(H5FD_FAMILY_id_g))
285
1
        if ((H5FD_FAMILY_id_g = H5FD_register(&H5FD_family_g, sizeof(H5FD_class_t), false)) < 0)
286
0
            HGOTO_ERROR(H5E_VFL, H5E_CANTREGISTER, FAIL, "unable to register family driver");
287
288
1
done:
289
1
    FUNC_LEAVE_NOAPI(ret_value)
290
1
} /* H5FD__family_register() */
291
292
/*---------------------------------------------------------------------------
293
 * Function:    H5FD__family_unregister
294
 *
295
 * Purpose:     Reset library driver info.
296
 *
297
 * Returns:     Non-negative on success or negative on failure
298
 *
299
 *---------------------------------------------------------------------------
300
 */
301
herr_t
302
H5FD__family_unregister(void)
303
1
{
304
1
    FUNC_ENTER_PACKAGE_NOERR
305
306
    /* Reset VFL ID */
307
1
    H5FD_FAMILY_id_g = H5I_INVALID_HID;
308
309
1
    FUNC_LEAVE_NOAPI(SUCCEED)
310
1
} /* end H5FD__family_unregister() */
311
312
/*-------------------------------------------------------------------------
313
 * Function:    H5Pset_fapl_family
314
 *
315
 * Purpose:    Sets the file access property list FAPL_ID to use the family
316
 *        driver. The MEMB_SIZE is the size in bytes of each file
317
 *        member (used only when creating a new file) and the
318
 *        MEMB_FAPL_ID is a file access property list to be used for
319
 *        each family member.
320
 *
321
 * Return:    Success:    Non-negative
322
 *
323
 *            Failure:    Negative
324
 *
325
 *-------------------------------------------------------------------------
326
 */
327
herr_t
328
H5Pset_fapl_family(hid_t fapl_id, hsize_t msize, hid_t memb_fapl_id)
329
0
{
330
0
    herr_t             ret_value;
331
0
    H5FD_family_fapl_t fa = {0, H5I_INVALID_HID};
332
0
    H5P_genplist_t    *plist; /* Property list pointer */
333
334
0
    FUNC_ENTER_API(FAIL)
335
336
    /* Check arguments */
337
0
    if (true != H5P_isa_class(fapl_id, H5P_FILE_ACCESS))
338
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file access property list");
339
0
    if (H5P_DEFAULT == memb_fapl_id) {
340
        /* Get default configuration for member FAPL */
341
0
        if (H5FD__family_get_default_config(&fa) < 0)
342
0
            HGOTO_ERROR(H5E_VFL, H5E_CANTGET, FAIL, "can't get default driver configuration info");
343
0
    }
344
0
    else if (true != H5P_isa_class(memb_fapl_id, H5P_FILE_ACCESS))
345
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file access list");
346
347
    /* Initialize driver specific information. */
348
0
    fa.memb_size = msize;
349
0
    if (H5P_DEFAULT != memb_fapl_id)
350
0
        fa.memb_fapl_id = memb_fapl_id;
351
352
0
    if (NULL == (plist = (H5P_genplist_t *)H5I_object(fapl_id)))
353
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file access property list");
354
0
    ret_value = H5P_set_driver(plist, H5FD_FAMILY, &fa, NULL);
355
356
0
done:
357
0
    FUNC_LEAVE_API(ret_value)
358
0
}
359
360
/*-------------------------------------------------------------------------
361
 * Function:    H5Pget_fapl_family
362
 *
363
 * Purpose:    Returns information about the family file access property
364
 *             list though the function arguments.
365
 *
366
 * Return:    Success:    Non-negative
367
 *
368
 *            Failure:    Negative
369
 *
370
 *-------------------------------------------------------------------------
371
 */
372
herr_t
373
H5Pget_fapl_family(hid_t fapl_id, hsize_t *msize /*out*/, hid_t *memb_fapl_id /*out*/)
374
0
{
375
0
    H5P_genplist_t           *plist; /* Property list pointer */
376
0
    const H5FD_family_fapl_t *fa;
377
0
    herr_t                    ret_value = SUCCEED; /* Return value */
378
379
0
    FUNC_ENTER_API(FAIL)
380
381
0
    if (NULL == (plist = H5P_object_verify(fapl_id, H5P_FILE_ACCESS, true)))
382
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file access list");
383
0
    if (H5FD_FAMILY != H5P_peek_driver(plist))
384
0
        HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "incorrect VFL driver");
385
0
    if (NULL == (fa = (const H5FD_family_fapl_t *)H5P_peek_driver_info(plist)))
386
0
        HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "bad VFL driver info");
387
0
    if (msize)
388
0
        *msize = fa->memb_size;
389
0
    if (memb_fapl_id) {
390
0
        if (NULL == (plist = (H5P_genplist_t *)H5I_object(fa->memb_fapl_id)))
391
0
            HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file access list");
392
0
        *memb_fapl_id = H5P_copy_plist(plist, true);
393
0
    } /* end if */
394
395
0
done:
396
0
    FUNC_LEAVE_API(ret_value)
397
0
}
398
399
/*-------------------------------------------------------------------------
400
 * Function:    H5FD__family_fapl_get
401
 *
402
 * Purpose:    Gets a file access property list which could be used to
403
 *             create an identical file.
404
 *
405
 * Return:    Success:    Ptr to new file access property list.
406
 *
407
 *            Failure:    NULL
408
 *
409
 *-------------------------------------------------------------------------
410
 */
411
static void *
412
H5FD__family_fapl_get(H5FD_t *_file)
413
0
{
414
0
    H5FD_family_t      *file = (H5FD_family_t *)_file;
415
0
    H5FD_family_fapl_t *fa   = NULL;
416
0
    H5P_genplist_t     *plist;            /* Property list pointer */
417
0
    void               *ret_value = NULL; /* Return value */
418
419
0
    FUNC_ENTER_PACKAGE
420
421
0
    if (NULL == (fa = (H5FD_family_fapl_t *)H5MM_calloc(sizeof(H5FD_family_fapl_t))))
422
0
        HGOTO_ERROR(H5E_VFL, H5E_CANTALLOC, NULL, "memory allocation failed");
423
424
0
    fa->memb_size = file->memb_size;
425
0
    if (NULL == (plist = (H5P_genplist_t *)H5I_object(file->memb_fapl_id)))
426
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "not a file access property list");
427
0
    fa->memb_fapl_id = H5P_copy_plist(plist, false);
428
429
    /* Set return value */
430
0
    ret_value = fa;
431
432
0
done:
433
0
    if (ret_value == NULL)
434
0
        if (fa != NULL)
435
0
            H5MM_xfree(fa);
436
437
0
    FUNC_LEAVE_NOAPI(ret_value)
438
0
}
439
440
/*-------------------------------------------------------------------------
441
 * Function:    H5FD__family_fapl_copy
442
 *
443
 * Purpose:    Copies the family-specific file access properties.
444
 *
445
 * Return:    Success:    Ptr to a new property list
446
 *
447
 *            Failure:    NULL
448
 *
449
 *-------------------------------------------------------------------------
450
 */
451
static void *
452
H5FD__family_fapl_copy(const void *_old_fa)
453
0
{
454
0
    const H5FD_family_fapl_t *old_fa = (const H5FD_family_fapl_t *)_old_fa;
455
0
    H5FD_family_fapl_t       *new_fa = NULL;
456
0
    H5P_genplist_t           *plist;            /* Property list pointer */
457
0
    void                     *ret_value = NULL; /* Return value */
458
459
0
    FUNC_ENTER_PACKAGE
460
461
0
    if (NULL == (new_fa = (H5FD_family_fapl_t *)H5MM_malloc(sizeof(H5FD_family_fapl_t))))
462
0
        HGOTO_ERROR(H5E_VFL, H5E_CANTALLOC, NULL, "memory allocation failed");
463
464
    /* Copy the fields of the structure */
465
0
    H5MM_memcpy(new_fa, old_fa, sizeof(H5FD_family_fapl_t));
466
467
    /* Deep copy the property list objects in the structure */
468
0
    if (old_fa->memb_fapl_id == H5P_FILE_ACCESS_DEFAULT) {
469
0
        if (H5I_inc_ref(new_fa->memb_fapl_id, false) < 0)
470
0
            HGOTO_ERROR(H5E_VFL, H5E_CANTINC, NULL, "unable to increment ref count on VFL driver");
471
0
    } /* end if */
472
0
    else {
473
0
        if (NULL == (plist = (H5P_genplist_t *)H5I_object(old_fa->memb_fapl_id)))
474
0
            HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "not a file access property list");
475
0
        new_fa->memb_fapl_id = H5P_copy_plist(plist, false);
476
0
    } /* end else */
477
478
    /* Set return value */
479
0
    ret_value = new_fa;
480
481
0
done:
482
0
    if (ret_value == NULL)
483
0
        if (new_fa != NULL)
484
0
            H5MM_xfree(new_fa);
485
486
0
    FUNC_LEAVE_NOAPI(ret_value)
487
0
}
488
489
/*-------------------------------------------------------------------------
490
 * Function:    H5FD__family_fapl_free
491
 *
492
 * Purpose:    Frees the family-specific file access properties.
493
 *
494
 * Return:    Success:    0
495
 *
496
 *            Failure:    -1
497
 *
498
 *-------------------------------------------------------------------------
499
 */
500
static herr_t
501
H5FD__family_fapl_free(void *_fa)
502
0
{
503
0
    H5FD_family_fapl_t *fa        = (H5FD_family_fapl_t *)_fa;
504
0
    herr_t              ret_value = SUCCEED; /* Return value */
505
506
0
    FUNC_ENTER_PACKAGE
507
508
0
    if (H5I_dec_ref(fa->memb_fapl_id) < 0)
509
0
        HGOTO_ERROR(H5E_VFL, H5E_CANTDEC, FAIL, "can't close driver ID");
510
0
    H5MM_xfree(fa);
511
512
0
done:
513
0
    FUNC_LEAVE_NOAPI(ret_value)
514
0
}
515
516
/*-------------------------------------------------------------------------
517
 * Function:    H5FD__family_sb_size
518
 *
519
 * Purpose:    Returns the size of the private information to be stored in
520
 *        the superblock.
521
 *
522
 * Return:    Success:    The super block driver data size.
523
 *
524
 *            Failure:    never fails
525
 *
526
 *-------------------------------------------------------------------------
527
 */
528
static hsize_t
529
H5FD__family_sb_size(H5FD_t H5_ATTR_UNUSED *_file)
530
0
{
531
0
    FUNC_ENTER_PACKAGE_NOERR
532
533
    /* 8 bytes field for the size of member file size field should be
534
     * enough for now. */
535
0
    FUNC_LEAVE_NOAPI(8)
536
0
}
537
538
/*-------------------------------------------------------------------------
539
 * Function:    H5FD__family_sb_encode
540
 *
541
 * Purpose:    Encode driver information for the superblock. The NAME
542
 *        argument is a nine-byte buffer which will be initialized with
543
 *        an eight-character name/version number and null termination.
544
 *
545
 *        The encoding is the member file size and name template.
546
 *
547
 * Return:    Success:    0
548
 *
549
 *            Failure:    -1
550
 *
551
 *-------------------------------------------------------------------------
552
 */
553
static herr_t
554
H5FD__family_sb_encode(H5FD_t *_file, char *name /*out*/, unsigned char *buf /*out*/)
555
0
{
556
0
    H5FD_family_t *file = (H5FD_family_t *)_file;
557
558
0
    FUNC_ENTER_PACKAGE_NOERR
559
560
    /* Name and version number */
561
0
    strncpy(name, "NCSAfami", (size_t)9);
562
0
    name[8] = '\0';
563
564
    /* Store member file size.  Use the member file size from the property here.
565
     * This is to guarantee backward compatibility.  If a file is created with
566
     * v1.6 library and the driver info isn't saved in the superblock.  We open
567
     * it with v1.8, the FILE->MEMB_SIZE will be the actual size of the first
568
     * member file (see H5FD__family_open).  So it isn't safe to use FILE->MEMB_SIZE.
569
     * If the file is created with v1.8, the correctness of FILE->PMEM_SIZE is
570
     * checked in H5FD__family_sb_decode. SLU - 2009/3/21
571
     */
572
0
    UINT64ENCODE(buf, (uint64_t)file->pmem_size);
573
574
0
    FUNC_LEAVE_NOAPI(SUCCEED)
575
0
} /* end H5FD__family_sb_encode() */
576
577
/*-------------------------------------------------------------------------
578
 * Function:    H5FD__family_sb_decode
579
 *
580
 * Purpose:     This function has 2 separate purpose.  One is to decodes the
581
 *              superblock information for this driver. The NAME argument is
582
 *              the eight-character (plus null termination) name stored in i
583
 *              the file.  The FILE argument is updated according to the
584
 *              information in the superblock.
585
 *
586
 * Return:    Success:    0
587
 *
588
 *            Failure:    -1
589
 *
590
 *-------------------------------------------------------------------------
591
 */
592
static herr_t
593
H5FD__family_sb_decode(H5FD_t *_file, const char H5_ATTR_UNUSED *name, const unsigned char *buf)
594
0
{
595
0
    H5FD_family_t *file = (H5FD_family_t *)_file;
596
0
    uint64_t       msize;
597
0
    herr_t         ret_value = SUCCEED; /* Return value */
598
599
0
    FUNC_ENTER_PACKAGE
600
601
    /* Read member file size. Skip name template for now although it's saved. */
602
0
    UINT64DECODE(buf, msize);
603
604
    /* For h5repart only. Private property of new member size is used to signal
605
     * h5repart is being used to change member file size.  h5repart will open
606
     * files for read and write.  When the files are closed, metadata will be
607
     * flushed to the files and updated to this new size */
608
0
    if (file->mem_newsize)
609
0
        file->memb_size = file->pmem_size = file->mem_newsize;
610
0
    else {
611
        /* Default - use the saved member size */
612
0
        if (file->pmem_size == H5F_FAMILY_DEFAULT)
613
0
            file->pmem_size = msize;
614
615
        /* Check if member size from file access property is correct */
616
0
        if (msize != file->pmem_size)
617
0
            HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL,
618
0
                        "Family member size should be %lu.  But the size from file access property is %lu",
619
0
                        (unsigned long)msize, (unsigned long)file->pmem_size);
620
621
        /* Update member file size to the size saved in the superblock.
622
         * That's the size intended to be. */
623
0
        file->memb_size = msize;
624
0
    } /* end else */
625
626
0
done:
627
0
    FUNC_LEAVE_NOAPI(ret_value)
628
0
} /* end H5FD__family_sb_decode() */
629
630
/*-------------------------------------------------------------------------
631
 * Function:    H5FD__family_open
632
 *
633
 * Purpose:    Creates and/or opens a family of files as an HDF5 file.
634
 *
635
 * Return:    Success:    A pointer to a new file dat structure. The
636
 *                public fields will be initialized by the
637
 *                caller, which is always H5FD_open().
638
 *
639
 *            Failure:    NULL
640
 *
641
 *-------------------------------------------------------------------------
642
 */
643
static H5FD_t *
644
H5FD__family_open(const char *name, unsigned flags, hid_t fapl_id, haddr_t maxaddr)
645
0
{
646
0
    H5FD_family_t *file      = NULL;
647
0
    char          *memb_name = NULL, *temp = NULL;
648
0
    hsize_t        eof            = HADDR_UNDEF;
649
0
    bool           default_config = false;
650
0
    unsigned       t_flags        = flags & ~H5F_ACC_CREAT;
651
0
    H5FD_t        *ret_value      = NULL;
652
653
0
    FUNC_ENTER_PACKAGE
654
655
    /* Check arguments */
656
0
    if (!name || !*name)
657
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "invalid file name");
658
0
    if (0 == maxaddr || HADDR_UNDEF == maxaddr)
659
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, NULL, "bogus maxaddr");
660
661
    /* Initialize file from file access properties */
662
0
    if (NULL == (file = (H5FD_family_t *)H5MM_calloc(sizeof(H5FD_family_t))))
663
0
        HGOTO_ERROR(H5E_VFL, H5E_CANTALLOC, NULL, "unable to allocate file struct");
664
0
    if (H5P_FILE_ACCESS_DEFAULT == fapl_id) {
665
0
        H5FD_family_fapl_t default_fa;
666
667
        /* Get default configuration */
668
0
        if (H5FD__family_get_default_config(&default_fa) < 0)
669
0
            HGOTO_ERROR(H5E_VFL, H5E_CANTGET, NULL, "can't get default driver configuration info");
670
671
0
        file->memb_fapl_id = default_fa.memb_fapl_id;
672
0
        file->memb_size    = H5FD_FAM_DEF_MEM_SIZE; /* Actual member size to be updated later */
673
0
        file->pmem_size    = H5FD_FAM_DEF_MEM_SIZE; /* Member size passed in through property */
674
0
        file->mem_newsize  = 0;                     /*New member size used by h5repart only       */
675
676
0
        default_config = true;
677
0
    } /* end if */
678
0
    else {
679
0
        H5P_genplist_t           *plist; /* Property list pointer */
680
0
        const H5FD_family_fapl_t *fa;
681
0
        H5FD_family_fapl_t        default_fa;
682
683
0
        if (NULL == (plist = (H5P_genplist_t *)H5I_object(fapl_id)))
684
0
            HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "not a file access property list");
685
0
        if (NULL == (fa = (const H5FD_family_fapl_t *)H5P_peek_driver_info(plist))) {
686
0
            if (H5FD__family_get_default_config(&default_fa) < 0)
687
0
                HGOTO_ERROR(H5E_VFL, H5E_CANTGET, NULL, "can't get default family VFD configuration");
688
0
            fa             = &default_fa;
689
0
            default_config = true;
690
0
        }
691
692
        /* Check for new family file size. It's used by h5repart only. */
693
0
        if (H5P_exist_plist(plist, H5F_ACS_FAMILY_NEWSIZE_NAME) > 0) {
694
            /* Get the new family file size */
695
0
            if (H5P_get(plist, H5F_ACS_FAMILY_NEWSIZE_NAME, &file->mem_newsize) < 0)
696
0
                HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get new family member size");
697
698
            /* Set flag for later */
699
0
            file->repart_members = true;
700
0
        } /* end if */
701
702
0
        if (fa->memb_fapl_id == H5P_FILE_ACCESS_DEFAULT) {
703
0
            if (H5I_inc_ref(fa->memb_fapl_id, false) < 0)
704
0
                HGOTO_ERROR(H5E_VFL, H5E_CANTINC, NULL, "unable to increment ref count on VFL driver");
705
0
            file->memb_fapl_id = fa->memb_fapl_id;
706
0
        } /* end if */
707
0
        else {
708
0
            if (NULL == (plist = (H5P_genplist_t *)H5I_object(fa->memb_fapl_id)))
709
0
                HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "not a file access property list");
710
0
            file->memb_fapl_id = H5P_copy_plist(plist, false);
711
0
        }                                /* end else */
712
0
        file->memb_size = fa->memb_size; /* Actual member size to be updated later */
713
0
        file->pmem_size = fa->memb_size; /* Member size passed in through property */
714
715
0
        if (default_config && H5I_dec_ref(fa->memb_fapl_id) < 0)
716
0
            HGOTO_ERROR(H5E_VFL, H5E_CANTDEC, NULL, "can't decrement ref. count on member FAPL");
717
0
    } /* end else */
718
0
    file->name  = H5MM_strdup(name);
719
0
    file->flags = flags;
720
721
    /* Allocate space for the string buffers */
722
0
    if (NULL == (memb_name = (char *)H5MM_malloc(H5FD_FAM_MEMB_NAME_BUF_SIZE)))
723
0
        HGOTO_ERROR(H5E_VFL, H5E_CANTALLOC, NULL, "unable to allocate member name");
724
0
    if (NULL == (temp = (char *)H5MM_malloc(H5FD_FAM_MEMB_NAME_BUF_SIZE)))
725
0
        HGOTO_ERROR(H5E_VFL, H5E_CANTALLOC, NULL, "unable to allocate temporary member name");
726
727
    /* Check that names are unique */
728
0
    H5_WARN_FORMAT_NONLITERAL_OFF
729
0
    snprintf(memb_name, H5FD_FAM_MEMB_NAME_BUF_SIZE, name, 0);
730
0
    snprintf(temp, H5FD_FAM_MEMB_NAME_BUF_SIZE, name, 1);
731
0
    H5_WARN_FORMAT_NONLITERAL_ON
732
733
0
    if (!strcmp(memb_name, temp)) {
734
0
        if (default_config) {
735
0
            temp = H5MM_xfree(temp);
736
0
            if (NULL == (temp = H5FD__family_get_default_printf_filename(name)))
737
0
                HGOTO_ERROR(H5E_VFL, H5E_CANTGET, NULL, "can't get default printf-style filename");
738
0
            name = temp;
739
0
        }
740
0
        else
741
0
            HGOTO_ERROR(H5E_VFL, H5E_FILEEXISTS, NULL,
742
0
                        "differing member numbers do not produce unique member file names - try inserting "
743
0
                        "\"%%06d\" into the file name string");
744
0
    }
745
746
    /* Open all the family members */
747
0
    while (1) {
748
0
        H5_WARN_FORMAT_NONLITERAL_OFF
749
0
        snprintf(memb_name, H5FD_FAM_MEMB_NAME_BUF_SIZE, name, file->nmembs);
750
0
        H5_WARN_FORMAT_NONLITERAL_ON
751
752
        /* Enlarge member array */
753
0
        if (file->nmembs >= file->amembs) {
754
0
            unsigned n = MAX(64, 2 * file->amembs);
755
0
            H5FD_t **x;
756
757
0
            assert(n > 0);
758
0
            if (NULL == (x = (H5FD_t **)H5MM_realloc(file->memb, n * sizeof(H5FD_t *))))
759
0
                HGOTO_ERROR(H5E_VFL, H5E_CANTALLOC, NULL, "unable to reallocate members");
760
0
            file->amembs = n;
761
0
            file->memb   = x;
762
0
        } /* end if */
763
764
        /*
765
         * Attempt to open file. If the first file cannot be opened then fail;
766
         * otherwise an open failure means that we've reached the last member.
767
         * Allow H5F_ACC_CREAT only on the first family member.
768
         */
769
0
        if (0 == file->nmembs) {
770
0
            if (H5FD_open(false, &file->memb[file->nmembs], memb_name, (0 == file->nmembs ? flags : t_flags),
771
0
                          file->memb_fapl_id, HADDR_UNDEF) < 0)
772
0
                HGOTO_ERROR(H5E_VFL, H5E_CANTOPENFILE, NULL, "unable to open member file");
773
0
        }
774
0
        else {
775
0
            if (H5FD_open(true, &file->memb[file->nmembs], memb_name, (0 == file->nmembs ? flags : t_flags),
776
0
                          file->memb_fapl_id, HADDR_UNDEF) < 0)
777
0
                HGOTO_ERROR(H5E_VFL, H5E_CANTOPENFILE, NULL, "unable to open member file");
778
779
0
            if (!file->memb[file->nmembs])
780
0
                break;
781
0
        }
782
783
0
        file->nmembs++;
784
0
    }
785
786
    /* If the file is reopened and there's only one member file existing, this file may be
787
     * smaller than the size specified through H5Pset_fapl_family().  Update the actual
788
     * member size.
789
     */
790
0
    if ((eof = H5FD_get_eof(file->memb[0], H5FD_MEM_DEFAULT)))
791
0
        file->memb_size = eof;
792
793
0
    ret_value = (H5FD_t *)file;
794
795
0
done:
796
    /* Release resources */
797
0
    if (memb_name)
798
0
        H5MM_xfree(memb_name);
799
0
    if (temp)
800
0
        H5MM_xfree(temp);
801
802
    /* Cleanup and fail */
803
0
    if (ret_value == NULL && file != NULL) {
804
0
        unsigned nerrors = 0; /* Number of errors closing member files */
805
0
        unsigned u;           /* Local index variable */
806
807
        /* Close as many members as possible. Use private function here to avoid clearing
808
         * the error stack. We need the error message to indicate wrong member file size. */
809
0
        for (u = 0; u < file->nmembs; u++)
810
0
            if (file->memb[u])
811
0
                if (H5FD_close(file->memb[u]) < 0)
812
0
                    nerrors++;
813
0
        if (nerrors)
814
0
            HDONE_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, NULL, "unable to close member files");
815
816
0
        if (file->memb)
817
0
            H5MM_xfree(file->memb);
818
0
        if (H5I_dec_ref(file->memb_fapl_id) < 0)
819
0
            HDONE_ERROR(H5E_VFL, H5E_CANTDEC, NULL, "can't close driver ID");
820
0
        if (file->name)
821
0
            H5MM_xfree(file->name);
822
0
        H5MM_xfree(file);
823
0
    } /* end if */
824
825
0
    FUNC_LEAVE_NOAPI(ret_value)
826
0
} /* end H5FD__family_open() */
827
828
/*-------------------------------------------------------------------------
829
 * Function:    H5FD__family_close
830
 *
831
 * Purpose:    Closes a family of files.
832
 *
833
 * Return:    Success:    Non-negative
834
 *
835
 *            Failure:    Negative with as many members closed as
836
 *                possible. The only subsequent operation
837
 *                permitted on the file is a close operation.
838
 *
839
 *-------------------------------------------------------------------------
840
 */
841
static herr_t
842
H5FD__family_close(H5FD_t *_file)
843
0
{
844
0
    H5FD_family_t *file    = (H5FD_family_t *)_file;
845
0
    unsigned       nerrors = 0;         /* Number of errors while closing member files */
846
0
    unsigned       u;                   /* Local index variable */
847
0
    herr_t         ret_value = SUCCEED; /* Return value */
848
849
0
    FUNC_ENTER_PACKAGE
850
851
    /* Close as many members as possible. Use private function here to avoid clearing
852
     * the error stack. We need the error message to indicate wrong member file size. */
853
0
    for (u = 0; u < file->nmembs; u++) {
854
0
        if (file->memb[u]) {
855
0
            if (H5FD_close(file->memb[u]) < 0)
856
0
                nerrors++;
857
0
            else
858
0
                file->memb[u] = NULL;
859
0
        } /* end if */
860
0
    }     /* end for */
861
0
    if (nerrors)
862
        /* Push error, but keep going*/
863
0
        HDONE_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, FAIL, "unable to close member files");
864
865
    /* Clean up other stuff */
866
0
    if (H5I_dec_ref(file->memb_fapl_id) < 0)
867
        /* Push error, but keep going*/
868
0
        HDONE_ERROR(H5E_VFL, H5E_CANTDEC, FAIL, "can't close driver ID");
869
0
    H5MM_xfree(file->memb);
870
0
    H5MM_xfree(file->name);
871
0
    H5MM_xfree(file);
872
873
0
    FUNC_LEAVE_NOAPI(ret_value)
874
0
} /* end H5FD__family_close() */
875
876
/*-------------------------------------------------------------------------
877
 * Function:    H5FD__family_cmp
878
 *
879
 * Purpose:    Compares two file families to see if they are the same. It
880
 *        does this by comparing the first member of the two families.
881
 *
882
 * Return:    Success:    like strcmp()
883
 *
884
 *            Failure:    never fails (arguments were checked by the
885
 *                caller).
886
 *
887
 *-------------------------------------------------------------------------
888
 */
889
static int
890
H5FD__family_cmp(const H5FD_t *_f1, const H5FD_t *_f2)
891
0
{
892
0
    const H5FD_family_t *f1        = (const H5FD_family_t *)_f1;
893
0
    const H5FD_family_t *f2        = (const H5FD_family_t *)_f2;
894
0
    int                  ret_value = 0;
895
896
0
    FUNC_ENTER_PACKAGE_NOERR
897
898
0
    assert(f1->nmembs >= 1 && f1->memb[0]);
899
0
    assert(f2->nmembs >= 1 && f2->memb[0]);
900
901
0
    ret_value = H5FD_cmp(f1->memb[0], f2->memb[0]);
902
903
0
    FUNC_LEAVE_NOAPI(ret_value)
904
0
} /* end H5FD__family_cmp() */
905
906
/*-------------------------------------------------------------------------
907
 * Function:    H5FD__family_query
908
 *
909
 * Purpose:    Set the flags that this VFL driver is capable of supporting.
910
 *              (listed in H5FDpublic.h)
911
 *
912
 * Return:    Success:    non-negative
913
 *            Failure:    negative
914
 *
915
 *-------------------------------------------------------------------------
916
 */
917
static herr_t
918
H5FD__family_query(const H5FD_t *_file, unsigned long *flags /* out */)
919
0
{
920
0
    const H5FD_family_t *file = (const H5FD_family_t *)_file; /* Family VFD info */
921
922
0
    FUNC_ENTER_PACKAGE_NOERR
923
924
    /* Set the VFL feature flags that this driver supports */
925
0
    if (flags) {
926
0
        *flags = 0;
927
0
        *flags |= H5FD_FEAT_AGGREGATE_METADATA;  /* OK to aggregate metadata allocations */
928
0
        *flags |= H5FD_FEAT_ACCUMULATE_METADATA; /* OK to accumulate metadata for faster writes. */
929
0
        *flags |= H5FD_FEAT_DATA_SIEVE; /* OK to perform data sieving for faster raw data reads & writes */
930
0
        *flags |= H5FD_FEAT_AGGREGATE_SMALLDATA; /* OK to aggregate "small" raw data allocations */
931
932
        /* Check for flags that are set by h5repart */
933
0
        if (file && file->repart_members)
934
0
            *flags |= H5FD_FEAT_DIRTY_DRVRINFO_LOAD; /* Mark the superblock dirty when it is loaded (so the
935
                                                        family member sizes are rewritten) */
936
0
    }                                                /* end if */
937
938
0
    FUNC_LEAVE_NOAPI(SUCCEED)
939
0
} /* end H5FD__family_query() */
940
941
/*-------------------------------------------------------------------------
942
 * Function:    H5FD__family_get_eoa
943
 *
944
 * Purpose:    Returns the end-of-address marker for the file. The EOA
945
 *        marker is the first address past the last byte allocated in
946
 *        the format address space.
947
 *
948
 * Return:    Success:    The end-of-address-marker
949
 *
950
 *            Failure:    HADDR_UNDEF
951
 *
952
 *-------------------------------------------------------------------------
953
 */
954
static haddr_t
955
H5FD__family_get_eoa(const H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type)
956
0
{
957
0
    const H5FD_family_t *file = (const H5FD_family_t *)_file;
958
959
0
    FUNC_ENTER_PACKAGE_NOERR
960
961
0
    FUNC_LEAVE_NOAPI(file->eoa)
962
0
}
963
964
/*-------------------------------------------------------------------------
965
 * Function:    H5FD__family_set_eoa
966
 *
967
 * Purpose:    Set the end-of-address marker for the file.
968
 *
969
 * Return:    Success:    0
970
 *
971
 *            Failure:    -1
972
 *
973
 *-------------------------------------------------------------------------
974
 */
975
static herr_t
976
H5FD__family_set_eoa(H5FD_t *_file, H5FD_mem_t type, haddr_t abs_eoa)
977
0
{
978
0
    H5FD_family_t *file      = (H5FD_family_t *)_file;
979
0
    haddr_t        addr      = abs_eoa;
980
0
    char          *memb_name = NULL;
981
0
    unsigned       u;                   /* Local index variable */
982
0
    herr_t         ret_value = SUCCEED; /* Return value */
983
984
0
    FUNC_ENTER_PACKAGE
985
986
    /* Allocate space for the member name buffer */
987
0
    if (NULL == (memb_name = (char *)H5MM_malloc(H5FD_FAM_MEMB_NAME_BUF_SIZE)))
988
0
        HGOTO_ERROR(H5E_VFL, H5E_CANTALLOC, FAIL, "unable to allocate member name");
989
990
0
    for (u = 0; addr || u < file->nmembs; u++) {
991
992
        /* Enlarge member array */
993
0
        if (u >= file->amembs) {
994
0
            unsigned n = MAX(64, 2 * file->amembs);
995
0
            H5FD_t **x = (H5FD_t **)H5MM_realloc(file->memb, n * sizeof(H5FD_t *));
996
997
0
            if (!x)
998
0
                HGOTO_ERROR(H5E_VFL, H5E_CANTALLOC, FAIL, "unable to allocate memory block");
999
0
            file->amembs = n;
1000
0
            file->memb   = x;
1001
0
            file->nmembs = u;
1002
0
        } /* end if */
1003
1004
        /* Create another file if necessary */
1005
0
        if (u >= file->nmembs || !file->memb[u]) {
1006
0
            file->nmembs = MAX(file->nmembs, u + 1);
1007
1008
0
            H5_WARN_FORMAT_NONLITERAL_OFF
1009
0
            snprintf(memb_name, H5FD_FAM_MEMB_NAME_BUF_SIZE, file->name, u);
1010
0
            H5_WARN_FORMAT_NONLITERAL_ON
1011
1012
0
            H5_CHECK_OVERFLOW(file->memb_size, hsize_t, haddr_t);
1013
0
            if (H5FD_open(false, &file->memb[u], memb_name, file->flags | H5F_ACC_CREAT, file->memb_fapl_id,
1014
0
                          (haddr_t)file->memb_size) < 0)
1015
0
                HGOTO_ERROR(H5E_VFL, H5E_CANTOPENFILE, FAIL, "unable to open member file");
1016
0
        } /* end if */
1017
1018
        /* Set the EOA marker for the member */
1019
0
        H5_CHECK_OVERFLOW(file->memb_size, hsize_t, haddr_t);
1020
0
        if (addr > (haddr_t)file->memb_size) {
1021
0
            if (H5FD_set_eoa(file->memb[u], type, (haddr_t)file->memb_size) < 0)
1022
0
                HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "unable to set file eoa");
1023
0
            addr -= file->memb_size;
1024
0
        } /* end if */
1025
0
        else {
1026
0
            if (H5FD_set_eoa(file->memb[u], type, addr) < 0)
1027
0
                HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "unable to set file eoa");
1028
0
            addr = 0;
1029
0
        } /* end else */
1030
0
    }     /* end for */
1031
1032
0
    file->eoa = abs_eoa;
1033
1034
0
done:
1035
    /* Release resources */
1036
0
    if (memb_name)
1037
0
        H5MM_xfree(memb_name);
1038
1039
0
    FUNC_LEAVE_NOAPI(ret_value)
1040
0
}
1041
1042
/*-------------------------------------------------------------------------
1043
 * Function:    H5FD__family_get_eof
1044
 *
1045
 * Purpose:    Returns the end-of-file marker, which is the greater of
1046
 *        either the total family size or the current EOA marker.
1047
 *
1048
 * Return:    Success:    End of file address, the first address past
1049
 *                the end of the family of files or the current
1050
 *                EOA, whichever is larger.
1051
 *
1052
 *            Failure:          HADDR_UNDEF
1053
 *
1054
 *-------------------------------------------------------------------------
1055
 */
1056
static haddr_t
1057
H5FD__family_get_eof(const H5FD_t *_file, H5FD_mem_t type)
1058
0
{
1059
0
    const H5FD_family_t *file = (const H5FD_family_t *)_file;
1060
0
    haddr_t              eof  = 0;
1061
0
    int                  i;                       /* Local index variable */
1062
0
    haddr_t              ret_value = HADDR_UNDEF; /* Return value */
1063
1064
0
    FUNC_ENTER_PACKAGE_NOERR
1065
1066
    /*
1067
     * Find the last member that has a non-zero EOF and break out of the loop
1068
     * with `i' equal to that member. If all members have zero EOF then exit
1069
     * loop with i==0.
1070
     */
1071
0
    assert(file->nmembs > 0);
1072
0
    for (i = (int)(file->nmembs - 1); i >= 0; --i) {
1073
0
        if ((eof = H5FD_get_eof(file->memb[i], type)) != 0)
1074
0
            break;
1075
0
        if (0 == i)
1076
0
            break;
1077
0
    } /* end for */
1078
1079
    /*
1080
     * The file size is the number of members before the i'th member plus the
1081
     * size of the i'th member.
1082
     */
1083
0
    eof += ((unsigned)i) * file->memb_size;
1084
1085
    /* Set return value */
1086
0
    ret_value = eof;
1087
1088
0
    FUNC_LEAVE_NOAPI(ret_value)
1089
0
}
1090
1091
/*-------------------------------------------------------------------------
1092
 * Function:       H5FD__family_get_handle
1093
 *
1094
 * Purpose:        Returns the file handle of FAMILY file driver.
1095
 *
1096
 * Returns:        Non-negative if succeed or negative if fails.
1097
 *
1098
 *-------------------------------------------------------------------------
1099
 */
1100
static herr_t
1101
H5FD__family_get_handle(H5FD_t *_file, hid_t fapl, void **file_handle)
1102
0
{
1103
0
    H5FD_family_t  *file = (H5FD_family_t *)_file;
1104
0
    H5P_genplist_t *plist;
1105
0
    hsize_t         offset;
1106
0
    int             memb;
1107
0
    herr_t          ret_value = FAIL; /* Return value */
1108
1109
0
    FUNC_ENTER_PACKAGE
1110
1111
    /* Get the plist structure and family offset */
1112
0
    if (NULL == (plist = H5P_object_verify(fapl, H5P_FILE_ACCESS, true)))
1113
0
        HGOTO_ERROR(H5E_VFL, H5E_BADID, FAIL, "can't find object for ID");
1114
0
    if (H5P_get(plist, H5F_ACS_FAMILY_OFFSET_NAME, &offset) < 0)
1115
0
        HGOTO_ERROR(H5E_VFL, H5E_CANTGET, FAIL, "can't get offset for family driver");
1116
1117
0
    if (offset > (file->memb_size * file->nmembs))
1118
0
        HGOTO_ERROR(H5E_VFL, H5E_BADID, FAIL, "offset is bigger than file size");
1119
0
    memb = (int)(offset / file->memb_size);
1120
1121
0
    ret_value = H5FD_get_vfd_handle(file->memb[memb], fapl, file_handle);
1122
1123
0
done:
1124
0
    FUNC_LEAVE_NOAPI(ret_value)
1125
0
}
1126
1127
/*-------------------------------------------------------------------------
1128
 * Function:    H5FD__family_read
1129
 *
1130
 * Purpose:    Reads SIZE bytes of data from FILE beginning at address ADDR
1131
 *        into buffer BUF according to data transfer properties in
1132
 *        DXPL_ID.
1133
 *
1134
 * Return:    Success:    Zero. Result is stored in caller-supplied
1135
 *                buffer BUF.
1136
 *
1137
 *            Failure:    -1, contents of buffer BUF are undefined.
1138
 *
1139
 *-------------------------------------------------------------------------
1140
 */
1141
static herr_t
1142
H5FD__family_read(H5FD_t *_file, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr, size_t size,
1143
                  void *_buf /*out*/)
1144
0
{
1145
0
    H5FD_family_t  *file = (H5FD_family_t *)_file;
1146
0
    unsigned char  *buf  = (unsigned char *)_buf;
1147
0
    haddr_t         sub;
1148
0
    size_t          req;
1149
0
    hsize_t         tempreq;
1150
0
    unsigned        u;                   /* Local index variable */
1151
0
    H5P_genplist_t *plist;               /* Property list pointer */
1152
0
    herr_t          ret_value = SUCCEED; /* Return value */
1153
1154
0
    FUNC_ENTER_PACKAGE
1155
1156
    /*
1157
     * Get the member data transfer property list. If the transfer property
1158
     * list does not belong to this driver then assume defaults
1159
     */
1160
0
    if (NULL == (plist = (H5P_genplist_t *)H5I_object(dxpl_id)))
1161
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file access property list");
1162
1163
    /* Read from each member */
1164
0
    while (size > 0) {
1165
0
        H5_CHECKED_ASSIGN(u, unsigned, addr / file->memb_size, hsize_t);
1166
1167
0
        sub = addr % file->memb_size;
1168
1169
        /* This check is for mainly for IA32 architecture whose size_t's size
1170
         * is 4 bytes, to prevent overflow when user application is trying to
1171
         * write files bigger than 4GB. */
1172
0
        tempreq = file->memb_size - sub;
1173
0
        if (tempreq > SIZE_MAX)
1174
0
            tempreq = SIZE_MAX;
1175
0
        req = MIN(size, (size_t)tempreq);
1176
1177
0
        assert(u < file->nmembs);
1178
1179
0
        if (H5FD_read(file->memb[u], type, sub, req, buf) < 0)
1180
0
            HGOTO_ERROR(H5E_VFL, H5E_READERROR, FAIL, "member file read failed");
1181
1182
0
        addr += req;
1183
0
        buf += req;
1184
0
        size -= req;
1185
0
    }
1186
1187
0
done:
1188
0
    FUNC_LEAVE_NOAPI(ret_value)
1189
0
}
1190
1191
/*-------------------------------------------------------------------------
1192
 * Function:    H5FD__family_write
1193
 *
1194
 * Purpose:    Writes SIZE bytes of data to FILE beginning at address ADDR
1195
 *        from buffer BUF according to data transfer properties in
1196
 *        DXPL_ID.
1197
 *
1198
 * Return:    Success:    Zero
1199
 *
1200
 *            Failure:    -1
1201
 *
1202
 *-------------------------------------------------------------------------
1203
 */
1204
static herr_t
1205
H5FD__family_write(H5FD_t *_file, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr, size_t size, const void *_buf)
1206
0
{
1207
0
    H5FD_family_t       *file = (H5FD_family_t *)_file;
1208
0
    const unsigned char *buf  = (const unsigned char *)_buf;
1209
0
    haddr_t              sub;
1210
0
    size_t               req;
1211
0
    hsize_t              tempreq;
1212
0
    unsigned             u;                   /* Local index variable */
1213
0
    H5P_genplist_t      *plist;               /* Property list pointer */
1214
0
    herr_t               ret_value = SUCCEED; /* Return value */
1215
1216
0
    FUNC_ENTER_PACKAGE
1217
1218
    /*
1219
     * Get the member data transfer property list. If the transfer property
1220
     * list does not belong to this driver then assume defaults.
1221
     */
1222
0
    if (NULL == (plist = (H5P_genplist_t *)H5I_object(dxpl_id)))
1223
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file access property list");
1224
1225
    /* Write to each member */
1226
0
    while (size > 0) {
1227
0
        H5_CHECKED_ASSIGN(u, unsigned, addr / file->memb_size, hsize_t);
1228
1229
0
        sub = addr % file->memb_size;
1230
1231
        /* This check is for mainly for IA32 architecture whose size_t's size
1232
         * is 4 bytes, to prevent overflow when user application is trying to
1233
         * write files bigger than 4GB. */
1234
0
        tempreq = file->memb_size - sub;
1235
0
        if (tempreq > SIZE_MAX)
1236
0
            tempreq = SIZE_MAX;
1237
0
        req = MIN(size, (size_t)tempreq);
1238
1239
0
        assert(u < file->nmembs);
1240
1241
0
        if (H5FD_write(file->memb[u], type, sub, req, buf) < 0)
1242
0
            HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "member file write failed");
1243
1244
0
        addr += req;
1245
0
        buf += req;
1246
0
        size -= req;
1247
0
    }
1248
1249
0
done:
1250
0
    FUNC_LEAVE_NOAPI(ret_value)
1251
0
}
1252
1253
/*-------------------------------------------------------------------------
1254
 * Function:    H5FD__family_flush
1255
 *
1256
 * Purpose:    Flushes all family members.
1257
 *
1258
 * Return:    Success:    0
1259
 *            Failure:    -1, as many files flushed as possible.
1260
 *
1261
 *-------------------------------------------------------------------------
1262
 */
1263
static herr_t
1264
H5FD__family_flush(H5FD_t *_file, hid_t H5_ATTR_UNUSED dxpl_id, bool closing)
1265
0
{
1266
0
    H5FD_family_t *file = (H5FD_family_t *)_file;
1267
0
    unsigned       u, nerrors = 0;
1268
0
    herr_t         ret_value = SUCCEED; /* Return value */
1269
1270
0
    FUNC_ENTER_PACKAGE
1271
1272
0
    for (u = 0; u < file->nmembs; u++)
1273
0
        if (file->memb[u] && H5FD_flush(file->memb[u], closing) < 0)
1274
0
            nerrors++;
1275
1276
0
    if (nerrors)
1277
0
        HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "unable to flush member files");
1278
1279
0
done:
1280
0
    FUNC_LEAVE_NOAPI(ret_value)
1281
0
} /* end H5FD__family_flush() */
1282
1283
/*-------------------------------------------------------------------------
1284
 * Function:    H5FD__family_truncate
1285
 *
1286
 * Purpose:    Truncates all family members.
1287
 *
1288
 * Return:    Success:    0
1289
 *
1290
 *            Failure:    -1, as many files truncated as possible.
1291
 *
1292
 *-------------------------------------------------------------------------
1293
 */
1294
static herr_t
1295
H5FD__family_truncate(H5FD_t *_file, hid_t H5_ATTR_UNUSED dxpl_id, bool closing)
1296
0
{
1297
0
    H5FD_family_t *file = (H5FD_family_t *)_file;
1298
0
    unsigned       u, nerrors = 0;
1299
0
    herr_t         ret_value = SUCCEED; /* Return value */
1300
1301
0
    FUNC_ENTER_PACKAGE
1302
1303
0
    for (u = 0; u < file->nmembs; u++)
1304
0
        if (file->memb[u] && H5FD_truncate(file->memb[u], closing) < 0)
1305
0
            nerrors++;
1306
1307
0
    if (nerrors)
1308
0
        HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "unable to flush member files");
1309
1310
0
done:
1311
0
    FUNC_LEAVE_NOAPI(ret_value)
1312
0
} /* end H5FD__family_truncate() */
1313
1314
/*-------------------------------------------------------------------------
1315
 * Function:    H5FD__family_lock
1316
 *
1317
 * Purpose:     To place an advisory lock on a file.
1318
 *              The lock type to apply depends on the parameter "rw":
1319
 *                      true--opens for write: an exclusive lock
1320
 *                      false--opens for read: a shared lock
1321
 *
1322
 * Return:      SUCCEED/FAIL
1323
 *
1324
 *-------------------------------------------------------------------------
1325
 */
1326
static herr_t
1327
H5FD__family_lock(H5FD_t *_file, bool rw)
1328
0
{
1329
0
    H5FD_family_t *file = (H5FD_family_t *)_file; /* VFD file struct */
1330
0
    unsigned       u;                             /* Local index variable */
1331
0
    herr_t         ret_value = SUCCEED;           /* Return value */
1332
1333
0
    FUNC_ENTER_PACKAGE
1334
1335
    /* Place the lock on all the member files */
1336
0
    for (u = 0; u < file->nmembs; u++)
1337
0
        if (file->memb[u])
1338
0
            if (H5FD_lock(file->memb[u], rw) < 0)
1339
0
                break;
1340
1341
    /* If one of the locks failed, try to unlock the locked member files
1342
     * in an attempt to return to a fully unlocked state.
1343
     */
1344
0
    if (u < file->nmembs) {
1345
0
        unsigned v; /* Local index variable */
1346
1347
0
        for (v = 0; v < u; v++)
1348
0
            if (H5FD_unlock(file->memb[v]) < 0)
1349
                /* Push error, but keep going */
1350
0
                HDONE_ERROR(H5E_IO, H5E_CANTUNLOCKFILE, FAIL, "unable to unlock member files");
1351
1352
0
        HGOTO_ERROR(H5E_VFL, H5E_CANTLOCKFILE, FAIL, "unable to lock member files");
1353
0
    } /* end if */
1354
1355
0
done:
1356
0
    FUNC_LEAVE_NOAPI(ret_value)
1357
0
} /* end H5FD__family_lock() */
1358
1359
/*-------------------------------------------------------------------------
1360
 * Function:    H5FD__family_unlock
1361
 *
1362
 * Purpose:     To remove the existing lock on the file
1363
 *
1364
 * Return:      SUCCEED/FAIL
1365
 *
1366
 *-------------------------------------------------------------------------
1367
 */
1368
static herr_t
1369
H5FD__family_unlock(H5FD_t *_file)
1370
0
{
1371
0
    H5FD_family_t *file = (H5FD_family_t *)_file; /* VFD file struct */
1372
0
    unsigned       u;                             /* Local index variable */
1373
0
    herr_t         ret_value = SUCCEED;           /* Return value */
1374
1375
0
    FUNC_ENTER_PACKAGE
1376
1377
    /* Remove the lock on the member files */
1378
0
    for (u = 0; u < file->nmembs; u++)
1379
0
        if (file->memb[u])
1380
0
            if (H5FD_unlock(file->memb[u]) < 0)
1381
0
                HGOTO_ERROR(H5E_VFL, H5E_CANTUNLOCKFILE, FAIL, "unable to unlock member files");
1382
1383
0
done:
1384
0
    FUNC_LEAVE_NOAPI(ret_value)
1385
0
} /* end H5FD__family_unlock() */
1386
1387
/*-------------------------------------------------------------------------
1388
 * Function:    H5FD__family_delete
1389
 *
1390
 * Purpose:     Delete a file
1391
 *
1392
 * Return:      SUCCEED/FAIL
1393
 *
1394
 *-------------------------------------------------------------------------
1395
 */
1396
static herr_t
1397
H5FD__family_delete(const char *filename, hid_t fapl_id)
1398
0
{
1399
0
    H5P_genplist_t           *plist;
1400
0
    const H5FD_family_fapl_t *fa;
1401
0
    H5FD_family_fapl_t        default_fa     = {0, H5I_INVALID_HID};
1402
0
    bool                      default_config = false;
1403
0
    hid_t                     memb_fapl_id   = H5I_INVALID_HID;
1404
0
    unsigned                  current_member;
1405
0
    char                     *member_name = NULL;
1406
0
    char                     *temp        = NULL;
1407
0
    herr_t                    ret_value   = SUCCEED;
1408
1409
0
    FUNC_ENTER_PACKAGE
1410
1411
0
    if (!filename)
1412
0
        HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "invalid filename pointer");
1413
1414
    /* Get the driver info (for the member fapl)
1415
     * The family_open call accepts H5P_DEFAULT, so we'll accept that here, too.
1416
     */
1417
0
    if (H5P_FILE_ACCESS_DEFAULT == fapl_id) {
1418
0
        if (H5FD__family_get_default_config(&default_fa) < 0)
1419
0
            HGOTO_ERROR(H5E_VFL, H5E_CANTGET, FAIL, "can't get default family VFD configuration");
1420
0
        memb_fapl_id   = default_fa.memb_fapl_id;
1421
0
        default_config = true;
1422
0
    }
1423
0
    else {
1424
0
        if (NULL == (plist = (H5P_genplist_t *)H5I_object(fapl_id)))
1425
0
            HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file access property list");
1426
0
        if (NULL == (fa = (const H5FD_family_fapl_t *)H5P_peek_driver_info(plist))) {
1427
0
            if (H5FD__family_get_default_config(&default_fa) < 0)
1428
0
                HGOTO_ERROR(H5E_VFL, H5E_CANTGET, FAIL, "can't get default family VFD configuration");
1429
0
            fa             = &default_fa;
1430
0
            default_config = true;
1431
0
        }
1432
0
        memb_fapl_id = fa->memb_fapl_id;
1433
0
    }
1434
1435
    /* Allocate space for the string buffers */
1436
0
    if (NULL == (member_name = (char *)H5MM_malloc(H5FD_FAM_MEMB_NAME_BUF_SIZE)))
1437
0
        HGOTO_ERROR(H5E_VFL, H5E_CANTALLOC, FAIL, "unable to allocate member name");
1438
0
    if (NULL == (temp = (char *)H5MM_malloc(H5FD_FAM_MEMB_NAME_BUF_SIZE)))
1439
0
        HGOTO_ERROR(H5E_VFL, H5E_CANTALLOC, FAIL, "unable to allocate temporary member name");
1440
1441
    /* Sanity check to make sure that generated names are unique */
1442
1443
0
    H5_WARN_FORMAT_NONLITERAL_OFF
1444
0
    snprintf(member_name, H5FD_FAM_MEMB_NAME_BUF_SIZE, filename, 0);
1445
0
    snprintf(temp, H5FD_FAM_MEMB_NAME_BUF_SIZE, filename, 1);
1446
0
    H5_WARN_FORMAT_NONLITERAL_ON
1447
1448
0
    if (!strcmp(member_name, temp)) {
1449
0
        if (default_config) {
1450
0
            temp = H5MM_xfree(temp);
1451
0
            if (NULL == (temp = H5FD__family_get_default_printf_filename(filename)))
1452
0
                HGOTO_ERROR(H5E_VFL, H5E_CANTGET, FAIL, "can't get default printf-style filename");
1453
0
            filename = temp;
1454
0
        }
1455
0
        else
1456
0
            HGOTO_ERROR(H5E_VFL, H5E_CANTDELETEFILE, FAIL,
1457
0
                        "provided file name cannot generate unique sub-files");
1458
0
    }
1459
1460
    /* Delete all the family members */
1461
0
    current_member = 0;
1462
0
    while (1) {
1463
        /* Fix up the filename with the current member's number */
1464
0
        H5_WARN_FORMAT_NONLITERAL_OFF
1465
0
        snprintf(member_name, H5FD_FAM_MEMB_NAME_BUF_SIZE, filename, current_member);
1466
0
        H5_WARN_FORMAT_NONLITERAL_ON
1467
1468
        /* Attempt to delete the member files. If the first file throws an error
1469
         * we always consider this an error. With subsequent member files, however,
1470
         * errors usually mean that we hit the last member file so we ignore them.
1471
         *
1472
         * Note that this means that any missing files in the family will leave
1473
         * undeleted members behind.
1474
         */
1475
0
        if (0 == current_member) {
1476
0
            if (H5FD_delete(member_name, memb_fapl_id) < 0)
1477
0
                HGOTO_ERROR(H5E_VFL, H5E_CANTDELETEFILE, FAIL, "unable to delete member file");
1478
0
        }
1479
0
        else {
1480
0
            herr_t delete_error;
1481
1482
0
            H5E_PAUSE_ERRORS
1483
0
                {
1484
0
                    delete_error = H5FD_delete(member_name, memb_fapl_id);
1485
0
                }
1486
0
            H5E_RESUME_ERRORS
1487
0
            if (delete_error < 0)
1488
0
                break;
1489
0
        }
1490
1491
0
        current_member++;
1492
0
    } /* end while */
1493
1494
0
done:
1495
0
    if (member_name)
1496
0
        H5MM_xfree(member_name);
1497
0
    if (temp)
1498
0
        H5MM_xfree(temp);
1499
1500
    /* Only close memb_fapl_id if we created one from the default configuration */
1501
0
    if (default_fa.memb_fapl_id >= 0 && H5I_dec_ref(default_fa.memb_fapl_id) < 0)
1502
0
        HDONE_ERROR(H5E_VFL, H5E_CANTDEC, FAIL, "can't decrement ref. count on member FAPL ID");
1503
1504
0
    FUNC_LEAVE_NOAPI(ret_value)
1505
0
} /* end H5FD__family_delete() */