Coverage Report

Created: 2024-06-18 06:29

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