Coverage Report

Created: 2026-10-28 18:12

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/hdf5/src/H5FDcore.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:     A driver which stores the HDF5 data in main memory  using
15
 *              only the HDF5 public API. This driver is useful for fast
16
 *              access to small, temporary hdf5 files.
17
 */
18
19
#include "H5FDmodule.h" /* This source code file is part of the H5FD module */
20
21
#include "H5private.h"   /* Generic Functions            */
22
#include "H5Eprivate.h"  /* Error handling               */
23
#include "H5Fprivate.h"  /* File access                  */
24
#include "H5FDcore.h"    /* Core file driver             */
25
#include "H5FDpkg.h"     /* File drivers                 */
26
#include "H5FLprivate.h" /* Free lists                   */
27
#include "H5Iprivate.h"  /* IDs                          */
28
#include "H5MMprivate.h" /* Memory management            */
29
#include "H5Pprivate.h"  /* Property lists               */
30
#include "H5SLprivate.h" /* Skip lists                   */
31
32
/* The driver identification number, initialized at runtime */
33
hid_t H5FD_CORE_id_g = H5I_INVALID_HID;
34
35
/* The skip list node type.  Represents a region in the file. */
36
typedef struct H5FD_core_region_t {
37
    haddr_t start; /* Start address of the region          */
38
    haddr_t end;   /* End address of the region            */
39
} H5FD_core_region_t;
40
41
/* The description of a file belonging to this driver. The 'eoa' and 'eof'
42
 * determine the amount of hdf5 address space in use and the high-water mark
43
 * of the file (the current size of the underlying memory).
44
 */
45
typedef struct H5FD_core_t {
46
    H5FD_t         pub;              /* public stuff, must be first          */
47
    char          *name;             /* for equivalence testing              */
48
    unsigned char *mem;              /* the underlying memory                */
49
    haddr_t        eoa;              /* end of allocated region              */
50
    haddr_t        eof;              /* current allocated size               */
51
    size_t         increment;        /* multiples for mem allocation         */
52
    bool           backing_store;    /* write to file name on flush          */
53
    bool           write_tracking;   /* Whether to track writes              */
54
    size_t         bstore_page_size; /* backing store page size              */
55
    bool           ignore_disabled_file_locks;
56
    int            fd; /* backing store file descriptor        */
57
    /* Information for determining uniqueness of a file with a backing store */
58
#ifndef H5_HAVE_WIN32_API
59
    /* On most systems the combination of device and i-node number uniquely
60
     * identify a file.
61
     */
62
    dev_t device; /*file device number            */
63
    ino_t inode;  /*file i-node number            */
64
#else
65
    /* Files in windows are uniquely identified by the volume serial
66
     * number and the file index (both low and high parts).
67
     *
68
     * There are caveats where these numbers can change, especially
69
     * on FAT file systems.  On NTFS, however, a file should keep
70
     * those numbers the same until renamed or deleted (though you
71
     * can use ReplaceFile() on NTFS to keep the numbers the same
72
     * while renaming).
73
     *
74
     * See the MSDN "BY_HANDLE_FILE_INFORMATION Structure" entry for
75
     * more information.
76
     *
77
     * http://msdn.microsoft.com/en-us/library/aa363788(v=VS.85).aspx
78
     */
79
    DWORD nFileIndexLow;
80
    DWORD nFileIndexHigh;
81
    DWORD dwVolumeSerialNumber;
82
83
    HANDLE hFile; /* Native windows file handle */
84
#endif                                        /* H5_HAVE_WIN32_API */
85
    bool                        dirty;        /* changes not saved?       */
86
    H5FD_file_image_callbacks_t fi_callbacks; /* file image callbacks     */
87
    H5SL_t                     *dirty_list;   /* dirty parts of the file  */
88
} H5FD_core_t;
89
90
/* Driver-specific file access properties */
91
typedef struct H5FD_core_fapl_t {
92
    size_t increment;      /* how much to grow memory */
93
    bool   backing_store;  /* write to file name on flush */
94
    bool   write_tracking; /* Whether to track writes */
95
    size_t page_size;      /* Page size for tracked writes */
96
} H5FD_core_fapl_t;
97
98
/* Allocate memory in multiples of this size by default */
99
0
#define H5FD_CORE_INCREMENT                8192
100
0
#define H5FD_CORE_WRITE_TRACKING_FLAG      false
101
0
#define H5FD_CORE_WRITE_TRACKING_PAGE_SIZE 524288
102
103
/* These macros check for overflow of various quantities.  These macros
104
 * assume that file_offset_t is signed and haddr_t and size_t are unsigned.
105
 *
106
 * CORE_ADDR_OVERFLOW:   Checks whether a file address of type `haddr_t'
107
 *                       is too large to be represented by the second argument
108
 *                       of the file seek function.
109
 *
110
 * CORE_SIZE_OVERFLOW:   Checks whether a buffer size of type `hsize_t' is too
111
 *                       large to be represented by the `size_t' type.
112
 *
113
 * CORE_REGION_OVERFLOW: Checks whether an address and size pair describe data
114
 *                       which can be addressed entirely in memory.
115
 */
116
0
#define CORE_MAXADDR          ((haddr_t)((~(size_t)0) - 1))
117
0
#define CORE_ADDR_OVERFLOW(A) (HADDR_UNDEF == (A) || (A) > (haddr_t)CORE_MAXADDR)
118
0
#define CORE_SIZE_OVERFLOW(Z) ((Z) > (hsize_t)CORE_MAXADDR)
119
#define CORE_REGION_OVERFLOW(A, Z)                                                                           \
120
0
    (CORE_ADDR_OVERFLOW(A) || CORE_SIZE_OVERFLOW(Z) || HADDR_UNDEF == (A) + (Z) ||                           \
121
0
     (size_t)((A) + (Z)) < (size_t)(A))
122
123
/* Prototypes */
124
static herr_t  H5FD__core_add_dirty_region(H5FD_core_t *file, haddr_t start, haddr_t end);
125
static herr_t  H5FD__core_destroy_dirty_list(H5FD_core_t *file);
126
static herr_t  H5FD__core_write_to_bstore(H5FD_core_t *file, haddr_t addr, size_t size);
127
static void   *H5FD__core_fapl_get(H5FD_t *_file);
128
static H5FD_t *H5FD__core_open(const char *name, unsigned flags, hid_t fapl_id, haddr_t maxaddr);
129
static herr_t  H5FD__core_close(H5FD_t *_file);
130
static int     H5FD__core_cmp(const H5FD_t *_f1, const H5FD_t *_f2);
131
static herr_t  H5FD__core_query(const H5FD_t *_f1, unsigned long *flags);
132
static haddr_t H5FD__core_get_eoa(const H5FD_t *_file, H5FD_mem_t type);
133
static herr_t  H5FD__core_set_eoa(H5FD_t *_file, H5FD_mem_t type, haddr_t addr);
134
static haddr_t H5FD__core_get_eof(const H5FD_t *_file, H5FD_mem_t type);
135
static herr_t  H5FD__core_get_handle(H5FD_t *_file, hid_t fapl, void **file_handle);
136
static herr_t  H5FD__core_read(H5FD_t *_file, H5FD_mem_t type, hid_t fapl_id, haddr_t addr, size_t size,
137
                               void *buf);
138
static herr_t  H5FD__core_write(H5FD_t *_file, H5FD_mem_t type, hid_t fapl_id, haddr_t addr, size_t size,
139
                                const void *buf);
140
static herr_t  H5FD__core_flush(H5FD_t *_file, hid_t dxpl_id, bool closing);
141
static herr_t  H5FD__core_truncate(H5FD_t *_file, hid_t dxpl_id, bool closing);
142
static herr_t  H5FD__core_lock(H5FD_t *_file, bool rw);
143
static herr_t  H5FD__core_unlock(H5FD_t *_file);
144
static herr_t  H5FD__core_delete(const char *filename, hid_t fapl_id);
145
static inline const H5FD_core_fapl_t *H5FD__core_get_default_config(void);
146
147
static const H5FD_class_t H5FD_core_g = {
148
    H5FD_CLASS_VERSION,       /* struct version       */
149
    H5FD_CORE_VALUE,          /* value                */
150
    "core",                   /* name                 */
151
    CORE_MAXADDR,             /* maxaddr              */
152
    H5F_CLOSE_WEAK,           /* fc_degree            */
153
    NULL,                     /* terminate            */
154
    NULL,                     /* sb_size              */
155
    NULL,                     /* sb_encode            */
156
    NULL,                     /* sb_decode            */
157
    sizeof(H5FD_core_fapl_t), /* fapl_size            */
158
    H5FD__core_fapl_get,      /* fapl_get             */
159
    NULL,                     /* fapl_copy            */
160
    NULL,                     /* fapl_free            */
161
    0,                        /* dxpl_size            */
162
    NULL,                     /* dxpl_copy            */
163
    NULL,                     /* dxpl_free            */
164
    H5FD__core_open,          /* open                 */
165
    H5FD__core_close,         /* close                */
166
    H5FD__core_cmp,           /* cmp                  */
167
    H5FD__core_query,         /* query                */
168
    NULL,                     /* get_type_map         */
169
    NULL,                     /* alloc                */
170
    NULL,                     /* free                 */
171
    H5FD__core_get_eoa,       /* get_eoa              */
172
    H5FD__core_set_eoa,       /* set_eoa              */
173
    H5FD__core_get_eof,       /* get_eof              */
174
    H5FD__core_get_handle,    /* get_handle           */
175
    H5FD__core_read,          /* read                 */
176
    H5FD__core_write,         /* write                */
177
    NULL,                     /* read_vector          */
178
    NULL,                     /* write_vector         */
179
    NULL,                     /* read_selection       */
180
    NULL,                     /* write_selection      */
181
    H5FD__core_flush,         /* flush                */
182
    H5FD__core_truncate,      /* truncate             */
183
    H5FD__core_lock,          /* lock                 */
184
    H5FD__core_unlock,        /* unlock               */
185
    H5FD__core_delete,        /* del                  */
186
    NULL,                     /* ctl                  */
187
    H5FD_FLMAP_DICHOTOMY      /* fl_map               */
188
};
189
190
/* Default configurations, if none provided */
191
static const H5FD_core_fapl_t H5FD_core_default_config_g = {
192
    (size_t)H5_MB, true, H5FD_CORE_WRITE_TRACKING_FLAG, H5FD_CORE_WRITE_TRACKING_PAGE_SIZE};
193
static const H5FD_core_fapl_t H5FD_core_default_paged_config_g = {(size_t)H5_MB, true, true, (size_t)4096};
194
195
/* Define a free list to manage the region type */
196
H5FL_DEFINE(H5FD_core_region_t);
197
198
/*-------------------------------------------------------------------------
199
 * Function:    H5FD__core_add_dirty_region
200
 *
201
 * Purpose:     Add a new dirty region to the list for later flushing
202
 *              to the backing store.
203
 *
204
 * Return:      SUCCEED/FAIL
205
 *
206
 *-------------------------------------------------------------------------
207
 */
208
static herr_t
209
H5FD__core_add_dirty_region(H5FD_core_t *file, haddr_t start, haddr_t end)
210
0
{
211
0
    H5FD_core_region_t *b_item          = NULL;
212
0
    H5FD_core_region_t *a_item          = NULL;
213
0
    H5FD_core_region_t *item            = NULL;
214
0
    haddr_t             b_addr          = 0;
215
0
    haddr_t             a_addr          = 0;
216
0
    bool                create_new_node = true;
217
0
    herr_t              ret_value       = SUCCEED;
218
219
0
    FUNC_ENTER_PACKAGE
220
221
0
    assert(file);
222
0
    assert(file->dirty_list);
223
0
    assert(start <= end);
224
225
    /* Adjust the dirty region to the nearest block boundaries */
226
0
    if (start % file->bstore_page_size != 0)
227
0
        start = (start / file->bstore_page_size) * file->bstore_page_size;
228
229
0
    if (end % file->bstore_page_size != (file->bstore_page_size - 1)) {
230
0
        end = (((end / file->bstore_page_size) + 1) * file->bstore_page_size) - 1;
231
0
        if (end > file->eof)
232
0
            end = file->eof - 1;
233
0
    } /* end if */
234
235
    /* Get the regions before and after the intended insertion point */
236
0
    b_addr = start + 1;
237
0
    a_addr = end + 2;
238
0
    b_item = (H5FD_core_region_t *)H5SL_less(file->dirty_list, &b_addr);
239
0
    a_item = (H5FD_core_region_t *)H5SL_less(file->dirty_list, &a_addr);
240
241
    /* Check to see if we need to extend the upper end of the NEW region */
242
0
    if (a_item)
243
0
        if (start < a_item->start && end < a_item->end) {
244
            /* Extend the end of the NEW region to match the existing AFTER region */
245
0
            end = a_item->end;
246
0
        } /* end if */
247
    /* Attempt to extend the PREV region */
248
0
    if (b_item)
249
0
        if (start <= b_item->end + 1) {
250
251
            /* Need to set this for the delete algorithm */
252
0
            start = b_item->start;
253
254
            /* We won't need to insert a new node since we can
255
             * just update an existing one instead.
256
             */
257
0
            create_new_node = false;
258
0
        } /* end if */
259
260
    /* Remove any old nodes that are no longer needed */
261
0
    while (a_item && a_item->start > start) {
262
263
0
        H5FD_core_region_t *less;
264
0
        haddr_t             key = a_item->start - 1;
265
266
        /* Save the previous node before we trash this one */
267
0
        less = (H5FD_core_region_t *)H5SL_less(file->dirty_list, &key);
268
269
        /* Delete this node */
270
0
        a_item = (H5FD_core_region_t *)H5SL_remove(file->dirty_list, &a_item->start);
271
0
        a_item = H5FL_FREE(H5FD_core_region_t, a_item);
272
273
        /* Set up to check the next node */
274
0
        if (less)
275
0
            a_item = less;
276
0
    } /* end while */
277
278
    /* Insert the new node */
279
0
    if (create_new_node) {
280
0
        if (NULL == (item = (H5FD_core_region_t *)H5SL_search(file->dirty_list, &start))) {
281
            /* Ok to insert.  No pre-existing node with that key. */
282
0
            item        = (H5FD_core_region_t *)H5FL_CALLOC(H5FD_core_region_t);
283
0
            item->start = start;
284
0
            item->end   = end;
285
0
            if (H5SL_insert(file->dirty_list, item, &item->start) < 0)
286
0
                HGOTO_ERROR(H5E_SLIST, H5E_CANTINSERT, FAIL, "can't insert new dirty region: (%llu, %llu)\n",
287
0
                            (unsigned long long)start, (unsigned long long)end);
288
0
        } /* end if */
289
0
        else {
290
            /* Store the new item endpoint if it's bigger */
291
0
            item->end = (item->end < end) ? end : item->end;
292
0
        }
293
0
    }
294
0
    else {
295
        /* Update the size of the before region */
296
0
        if (b_item->end < end)
297
0
            b_item->end = end;
298
0
    }
299
300
0
done:
301
0
    FUNC_LEAVE_NOAPI(ret_value)
302
0
} /* end H5FD__core_add_dirty_region() */
303
304
/*-------------------------------------------------------------------------
305
 * Function:    H5FD__core_destroy_dirty_list
306
 *
307
 * Purpose:     Completely destroy the dirty list.
308
 *
309
 * Return:      SUCCEED/FAIL
310
 *
311
 *-------------------------------------------------------------------------
312
 */
313
static herr_t
314
H5FD__core_destroy_dirty_list(H5FD_core_t *file)
315
0
{
316
0
    herr_t ret_value = SUCCEED;
317
318
0
    FUNC_ENTER_PACKAGE
319
320
0
    assert(file);
321
322
    /* Destroy the list, including any remaining list elements */
323
0
    if (file->dirty_list) {
324
0
        H5FD_core_region_t *region = NULL;
325
326
0
        while (NULL != (region = (H5FD_core_region_t *)H5SL_remove_first(file->dirty_list)))
327
0
            region = H5FL_FREE(H5FD_core_region_t, region);
328
329
0
        if (H5SL_close(file->dirty_list) < 0)
330
0
            HGOTO_ERROR(H5E_SLIST, H5E_CLOSEERROR, FAIL, "can't close core vfd dirty list");
331
0
        file->dirty_list = NULL;
332
0
    } /* end if */
333
334
0
done:
335
0
    FUNC_LEAVE_NOAPI(ret_value)
336
0
} /* end H5FD__core_destroy_dirty_list() */
337
338
/*-------------------------------------------------------------------------
339
 * Function:    H5FD__core_write_to_bstore
340
 *
341
 * Purpose:     Write data to the backing store.
342
 *
343
 * Return:      SUCCEED/FAIL
344
 *
345
 *-------------------------------------------------------------------------
346
 */
347
static herr_t
348
H5FD__core_write_to_bstore(H5FD_core_t *file, haddr_t addr, size_t size)
349
0
{
350
0
    unsigned char *ptr = file->mem + addr; /* mutable pointer into the
351
                                            * buffer (can't change mem)
352
                                            */
353
0
    HDoff_t offset    = (HDoff_t)addr;     /* Offset to write at */
354
0
    herr_t  ret_value = SUCCEED;           /* Return value */
355
356
0
    FUNC_ENTER_PACKAGE
357
358
0
    assert(file);
359
360
0
#ifndef H5_HAVE_PREADWRITE
361
    /* Seek to the correct location (if we don't have pwrite) */
362
0
    if ((HDoff_t)addr != HDlseek(file->fd, (HDoff_t)addr, SEEK_SET))
363
0
        HGOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "error seeking in backing store");
364
0
#endif /* H5_HAVE_PREADWRITE */
365
366
0
    while (size > 0) {
367
368
0
        h5_posix_io_t     bytes_in    = 0;  /* # of bytes to write  */
369
0
        h5_posix_io_ret_t bytes_wrote = -1; /* # of bytes written   */
370
371
        /* Trying to write more bytes than the return type can handle is
372
         * undefined behavior in POSIX.
373
         */
374
0
        if (size > H5_POSIX_MAX_IO_BYTES)
375
0
            bytes_in = H5_POSIX_MAX_IO_BYTES;
376
0
        else
377
0
            bytes_in = (h5_posix_io_t)size;
378
379
0
        do {
380
#ifdef H5_HAVE_PREADWRITE
381
            bytes_wrote = HDpwrite(file->fd, ptr, bytes_in, offset);
382
            if (bytes_wrote > 0)
383
                offset += bytes_wrote;
384
#else
385
0
            bytes_wrote = HDwrite(file->fd, ptr, bytes_in);
386
0
#endif /* H5_HAVE_PREADWRITE */
387
0
        } while (-1 == bytes_wrote && EINTR == errno);
388
389
0
        if (-1 == bytes_wrote) { /* error */
390
0
            int  myerrno = errno;
391
0
            char time_str[32];
392
393
0
            H5_get_localtime_str(time_str, sizeof(time_str));
394
0
            offset = HDlseek(file->fd, 0, SEEK_CUR);
395
396
0
            HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL,
397
0
                        "write to backing store failed: time = %s, filename = '%s', file descriptor = %d, "
398
0
                        "errno = %d, error message = '%s', ptr = %p, total write size = %llu, bytes this "
399
0
                        "sub-write = %llu, bytes actually written = %llu, offset = %llu",
400
0
                        time_str, file->name, file->fd, myerrno, strerror(myerrno), (void *)ptr,
401
0
                        (unsigned long long)size, (unsigned long long)bytes_in,
402
0
                        (unsigned long long)bytes_wrote, (unsigned long long)offset);
403
0
        } /* end if */
404
405
0
        assert(bytes_wrote > 0);
406
0
        assert((size_t)bytes_wrote <= size);
407
408
0
        size -= (size_t)bytes_wrote;
409
0
        ptr = (unsigned char *)ptr + bytes_wrote;
410
411
0
    } /* end while */
412
413
0
done:
414
0
    FUNC_LEAVE_NOAPI(ret_value)
415
0
} /* end H5FD__core_write_to_bstore() */
416
417
/*-------------------------------------------------------------------------
418
 * Function:    H5FD__core_get_default_config
419
 *
420
 * Purpose:     Retrieves a default configuration for this VFD when no
421
 *              configuration information has been provided.
422
 *
423
 * Return:      Valid Core VFD configuration information pointer (can't
424
 *                  fail)
425
 *
426
 *-------------------------------------------------------------------------
427
 */
428
static inline const H5FD_core_fapl_t *
429
H5FD__core_get_default_config(void)
430
0
{
431
0
    char *driver = getenv(HDF5_DRIVER);
432
433
0
    if (driver) {
434
0
        if (!strcmp(driver, "core"))
435
0
            return &H5FD_core_default_config_g;
436
0
        else if (!strcmp(driver, "core_paged"))
437
0
            return &H5FD_core_default_paged_config_g;
438
0
    }
439
440
0
    return &H5FD_core_default_config_g;
441
0
} /* end H5FD__core_get_default_config() */
442
443
/*-------------------------------------------------------------------------
444
 * Function:    H5FD__core_register
445
 *
446
 * Purpose:     Register the driver with the library.
447
 *
448
 * Return:      SUCCEED/FAIL
449
 *
450
 *-------------------------------------------------------------------------
451
 */
452
herr_t
453
H5FD__core_register(void)
454
6
{
455
6
    herr_t ret_value = SUCCEED; /* Return value */
456
457
6
    FUNC_ENTER_PACKAGE
458
459
6
    if (H5I_VFL != H5I_get_type(H5FD_CORE_id_g))
460
6
        if ((H5FD_CORE_id_g = H5FD_register(&H5FD_core_g, sizeof(H5FD_class_t), false)) < 0)
461
0
            HGOTO_ERROR(H5E_VFL, H5E_CANTREGISTER, FAIL, "unable to register core driver");
462
463
6
done:
464
6
    FUNC_LEAVE_NOAPI(ret_value)
465
6
} /* end H5FD__core_register() */
466
467
/*---------------------------------------------------------------------------
468
 * Function:    H5FD__core_unregister
469
 *
470
 * Purpose:     Reset library driver info.
471
 *
472
 * Returns:     SUCCEED (Can't fail)
473
 *
474
 *---------------------------------------------------------------------------
475
 */
476
herr_t
477
H5FD__core_unregister(void)
478
6
{
479
6
    FUNC_ENTER_PACKAGE_NOERR
480
481
    /* Reset VFL ID */
482
6
    H5FD_CORE_id_g = H5I_INVALID_HID;
483
484
6
    FUNC_LEAVE_NOAPI(SUCCEED)
485
6
} /* end H5FD__core_unregister() */
486
487
/*-------------------------------------------------------------------------
488
 * Function:    H5Pset_core_write_tracking
489
 *
490
 * Purpose:    Enables/disables core VFD write tracking and page
491
 *              aggregation size.
492
 *
493
 * Return:    Non-negative on success/Negative on failure
494
 *
495
 *-------------------------------------------------------------------------
496
 */
497
herr_t
498
H5Pset_core_write_tracking(hid_t plist_id, bool is_enabled, size_t page_size)
499
0
{
500
0
    H5P_genplist_t         *plist;               /* Property list pointer */
501
0
    H5FD_core_fapl_t        fa;                  /* Core VFD info */
502
0
    const H5FD_core_fapl_t *old_fa;              /* Old core VFD info */
503
0
    herr_t                  ret_value = SUCCEED; /* Return value */
504
505
0
    FUNC_ENTER_API(FAIL)
506
507
    /* The page size cannot be zero */
508
0
    if (page_size == 0)
509
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "page_size cannot be zero");
510
511
    /* Get the plist structure */
512
0
    if (NULL == (plist = H5P_object_verify(plist_id, H5P_FILE_ACCESS, false)))
513
0
        HGOTO_ERROR(H5E_PLIST, H5E_BADID, FAIL, "can't find object for ID");
514
0
    if (H5FD_CORE != H5P_peek_driver(plist))
515
0
        HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "incorrect VFL driver");
516
0
    if (NULL == (old_fa = (const H5FD_core_fapl_t *)H5P_peek_driver_info(plist)))
517
0
        old_fa = H5FD__core_get_default_config();
518
519
    /* Set VFD info values */
520
0
    memset(&fa, 0, sizeof(H5FD_core_fapl_t));
521
0
    fa.increment      = old_fa->increment;
522
0
    fa.backing_store  = old_fa->backing_store;
523
0
    fa.write_tracking = is_enabled;
524
0
    fa.page_size      = page_size;
525
526
    /* Set the property values & the driver for the FAPL */
527
0
    if (H5P_set_driver(plist, H5FD_CORE, &fa, NULL) < 0)
528
0
        HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set core VFD as driver");
529
530
0
done:
531
0
    FUNC_LEAVE_API(ret_value)
532
0
} /* end H5Pset_core_write_tracking() */
533
534
/*-------------------------------------------------------------------------
535
 * Function:    H5Pget_core_write_tracking
536
 *
537
 * Purpose:    Gets information about core VFD write tracking and page
538
 *              aggregation size.
539
 *
540
 * Return:    Non-negative on success/Negative on failure
541
 *
542
 *-------------------------------------------------------------------------
543
 */
544
herr_t
545
H5Pget_core_write_tracking(hid_t plist_id, bool *is_enabled /*out*/, size_t *page_size /*out*/)
546
0
{
547
0
    H5P_genplist_t         *plist;               /* Property list pointer */
548
0
    const H5FD_core_fapl_t *fa;                  /* Core VFD info */
549
0
    herr_t                  ret_value = SUCCEED; /* Return value */
550
551
0
    FUNC_ENTER_API(FAIL)
552
553
    /* Get the plist structure */
554
0
    if (NULL == (plist = H5P_object_verify(plist_id, H5P_FILE_ACCESS, true)))
555
0
        HGOTO_ERROR(H5E_PLIST, H5E_BADID, FAIL, "can't find object for ID");
556
0
    if (H5FD_CORE != H5P_peek_driver(plist))
557
0
        HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "incorrect VFL driver");
558
0
    if (NULL == (fa = (const H5FD_core_fapl_t *)H5P_peek_driver_info(plist)))
559
0
        HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "bad VFL driver info");
560
561
    /* Get values */
562
0
    if (is_enabled)
563
0
        *is_enabled = fa->write_tracking;
564
0
    if (page_size)
565
0
        *page_size = fa->page_size;
566
567
0
done:
568
0
    FUNC_LEAVE_API(ret_value)
569
0
} /* end H5Pget_core_write_tracking() */
570
571
/*-------------------------------------------------------------------------
572
 * Function:    H5Pset_fapl_core
573
 *
574
 * Purpose:     Modify the file access property list to use the H5FD_CORE
575
 *              driver defined in this source file.  The INCREMENT specifies
576
 *              how much to grow the memory each time we need more.
577
 *
578
 * Return:      SUCCEED/FAIL
579
 *
580
 *-------------------------------------------------------------------------
581
 */
582
herr_t
583
H5Pset_fapl_core(hid_t fapl_id, size_t increment, bool backing_store)
584
0
{
585
0
    H5P_genplist_t  *plist;               /* Property list pointer */
586
0
    H5FD_core_fapl_t fa;                  /* Core VFD info */
587
0
    herr_t           ret_value = SUCCEED; /* Return value */
588
589
0
    FUNC_ENTER_API(FAIL)
590
591
    /* Check argument */
592
0
    if (NULL == (plist = H5P_object_verify(fapl_id, H5P_FILE_ACCESS, false)))
593
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file access property list");
594
595
    /* Set VFD info values */
596
0
    memset(&fa, 0, sizeof(H5FD_core_fapl_t));
597
0
    fa.increment      = increment;
598
0
    fa.backing_store  = backing_store;
599
0
    fa.write_tracking = H5FD_CORE_WRITE_TRACKING_FLAG;
600
0
    fa.page_size      = H5FD_CORE_WRITE_TRACKING_PAGE_SIZE;
601
602
    /* Set the property values & the driver for the FAPL */
603
0
    if (H5P_set_driver(plist, H5FD_CORE, &fa, NULL) < 0)
604
0
        HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set core VFD as driver");
605
606
0
done:
607
0
    FUNC_LEAVE_API(ret_value)
608
0
} /* end H5Pset_fapl_core() */
609
610
/*-------------------------------------------------------------------------
611
 * Function:    H5Pget_fapl_core
612
 *
613
 * Purpose:     Queries properties set by the H5Pset_fapl_core() function.
614
 *
615
 * Return:      SUCCEED/FAIL
616
 *
617
 *-------------------------------------------------------------------------
618
 */
619
herr_t
620
H5Pget_fapl_core(hid_t fapl_id, size_t *increment /*out*/, bool *backing_store /*out*/)
621
0
{
622
0
    H5P_genplist_t         *plist;               /* Property list pointer */
623
0
    const H5FD_core_fapl_t *fa;                  /* Core VFD info */
624
0
    herr_t                  ret_value = SUCCEED; /* Return value */
625
626
0
    FUNC_ENTER_API(FAIL)
627
628
0
    if (NULL == (plist = H5P_object_verify(fapl_id, H5P_FILE_ACCESS, true)))
629
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file access property list");
630
0
    if (H5FD_CORE != H5P_peek_driver(plist))
631
0
        HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "incorrect VFL driver");
632
0
    if (NULL == (fa = (const H5FD_core_fapl_t *)H5P_peek_driver_info(plist)))
633
0
        HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "bad VFL driver info");
634
635
0
    if (increment)
636
0
        *increment = fa->increment;
637
0
    if (backing_store)
638
0
        *backing_store = fa->backing_store;
639
640
0
done:
641
0
    FUNC_LEAVE_API(ret_value)
642
0
} /* end H5Pget_fapl_core() */
643
644
/*-------------------------------------------------------------------------
645
 * Function:    H5FD__core_fapl_get
646
 *
647
 * Purpose:     Returns a copy of the file access properties.
648
 *
649
 * Return:      Success:    Ptr to new file access properties.
650
 *              Failure:    NULL
651
 *
652
 *-------------------------------------------------------------------------
653
 */
654
static void *
655
H5FD__core_fapl_get(H5FD_t *_file)
656
0
{
657
0
    H5FD_core_t      *file = (H5FD_core_t *)_file;
658
0
    H5FD_core_fapl_t *fa;               /* Core VFD info */
659
0
    void             *ret_value = NULL; /* Return value */
660
661
0
    FUNC_ENTER_PACKAGE
662
663
0
    if (NULL == (fa = (H5FD_core_fapl_t *)H5MM_calloc(sizeof(H5FD_core_fapl_t))))
664
0
        HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed");
665
666
0
    fa->increment      = file->increment;
667
0
    fa->backing_store  = (bool)(file->fd >= 0);
668
0
    fa->write_tracking = file->write_tracking;
669
0
    fa->page_size      = file->bstore_page_size;
670
671
    /* Set return value */
672
0
    ret_value = fa;
673
674
0
done:
675
0
    FUNC_LEAVE_NOAPI(ret_value)
676
0
} /* end H5FD__core_fapl_get() */
677
678
/*-------------------------------------------------------------------------
679
 * Function:    H5FD___core_open
680
 *
681
 * Purpose:     Create memory as an HDF5 file.
682
 *
683
 * Return:      Success:    A pointer to a new file data structure. The
684
 *                          public fields will be initialized by the
685
 *                          caller, which is always H5FD_open().
686
 *              Failure:    NULL
687
 *
688
 *-------------------------------------------------------------------------
689
 */
690
static H5FD_t *
691
H5FD__core_open(const char *name, unsigned flags, hid_t fapl_id, haddr_t maxaddr)
692
0
{
693
0
    int                     o_flags;
694
0
    H5FD_core_t            *file = NULL;
695
0
    const H5FD_core_fapl_t *fa   = NULL;
696
0
    H5P_genplist_t         *plist; /* Property list pointer */
697
#ifdef H5_HAVE_WIN32_API
698
    struct _BY_HANDLE_FILE_INFORMATION fileinfo;
699
#endif
700
0
    h5_stat_t              sb;
701
0
    int                    fd = -1;
702
0
    H5FD_file_image_info_t file_image_info;
703
0
    H5FD_t                *ret_value = NULL; /* Return value */
704
705
0
    FUNC_ENTER_PACKAGE
706
707
    /* Check arguments */
708
0
    if (!name || !*name)
709
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "invalid file name");
710
0
    if (0 == maxaddr || HADDR_UNDEF == maxaddr)
711
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, NULL, "bogus maxaddr");
712
0
    if (CORE_ADDR_OVERFLOW(maxaddr))
713
0
        HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, NULL, "maxaddr overflow");
714
0
    assert(H5P_DEFAULT != fapl_id);
715
0
    if (NULL == (plist = (H5P_genplist_t *)H5I_object(fapl_id)))
716
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "not a file access property list");
717
0
    if (NULL == (fa = (const H5FD_core_fapl_t *)H5P_peek_driver_info(plist)))
718
0
        fa = H5FD__core_get_default_config();
719
720
    /* Build the open flags */
721
0
    o_flags = (H5F_ACC_RDWR & flags) ? O_RDWR : O_RDONLY;
722
0
    if (H5F_ACC_TRUNC & flags)
723
0
        o_flags |= O_TRUNC;
724
0
    if (H5F_ACC_CREAT & flags)
725
0
        o_flags |= O_CREAT;
726
0
    if (H5F_ACC_EXCL & flags)
727
0
        o_flags |= O_EXCL;
728
729
    /* Retrieve initial file image info */
730
0
    if (H5P_peek(plist, H5F_ACS_FILE_IMAGE_INFO_NAME, &file_image_info) < 0)
731
0
        HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get initial file image info");
732
733
    /* If the file image exists and this is an open, make sure the file doesn't exist */
734
0
    assert(((file_image_info.buffer != NULL) && (file_image_info.size > 0)) ||
735
0
           ((file_image_info.buffer == NULL) && (file_image_info.size == 0)));
736
0
    memset(&sb, 0, sizeof(sb));
737
0
    if ((file_image_info.buffer != NULL) && !(H5F_ACC_CREAT & flags)) {
738
0
        if ((fd = HDopen(name, o_flags, H5_POSIX_CREATE_MODE_RW)) >= 0) {
739
0
            HDclose(fd);
740
0
            HGOTO_ERROR(H5E_FILE, H5E_FILEEXISTS, NULL, "file already exists");
741
0
        }
742
743
        /* If backing store is requested, create and stat the file
744
         * Note: We are forcing the O_CREAT flag here, even though this is
745
         * technically an open.
746
         */
747
0
        if (fa->backing_store) {
748
0
            if ((fd = HDopen(name, o_flags | O_CREAT, H5_POSIX_CREATE_MODE_RW)) < 0)
749
0
                HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to create file");
750
0
            memset(&sb, 0, sizeof(h5_stat_t));
751
0
            if (HDfstat(fd, &sb) < 0)
752
0
                HSYS_GOTO_ERROR(H5E_FILE, H5E_BADFILE, NULL, "unable to fstat file");
753
0
        } /* end if */
754
0
    }     /* end if */
755
    /* Open backing store, and get stat() from file.  The only case that backing
756
     * store is off is when  the backing_store flag is off and H5F_ACC_CREAT is
757
     * on. */
758
0
    else if (fa->backing_store || !(H5F_ACC_CREAT & flags)) {
759
0
        if ((fd = HDopen(name, o_flags, H5_POSIX_CREATE_MODE_RW)) < 0)
760
0
            HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to open file");
761
0
        memset(&sb, 0, sizeof(h5_stat_t));
762
0
        if (HDfstat(fd, &sb) < 0)
763
0
            HSYS_GOTO_ERROR(H5E_FILE, H5E_BADFILE, NULL, "unable to fstat file");
764
0
    } /* end if */
765
766
    /* Create the new file struct */
767
0
    if (NULL == (file = (H5FD_core_t *)H5MM_calloc(sizeof(H5FD_core_t))))
768
0
        HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "unable to allocate file struct");
769
0
    file->fd = fd;
770
0
    if (name && *name)
771
0
        file->name = H5MM_xstrdup(name);
772
773
    /* The increment comes from either the file access property list or the
774
     * default value. But if the file access property list was zero then use
775
     * the default value instead.
776
     */
777
0
    file->increment = (fa->increment > 0) ? fa->increment : H5FD_CORE_INCREMENT;
778
779
    /* If save data in backing store. */
780
0
    file->backing_store = fa->backing_store;
781
782
    /* Save file image callbacks */
783
0
    file->fi_callbacks = file_image_info.callbacks;
784
785
    /* Check the file locking flags in the fapl */
786
0
    if (H5FD_ignore_disabled_file_locks_p != FAIL)
787
        /* The environment variable was set, so use that preferentially */
788
0
        file->ignore_disabled_file_locks = H5FD_ignore_disabled_file_locks_p;
789
0
    else {
790
        /* Use the value in the property list */
791
0
        if (H5P_get(plist, H5F_ACS_IGNORE_DISABLED_FILE_LOCKS_NAME, &file->ignore_disabled_file_locks) < 0)
792
0
            HGOTO_ERROR(H5E_VFL, H5E_CANTGET, NULL, "can't get ignore disabled file locks property");
793
0
    }
794
795
0
    if (fd >= 0) {
796
        /* Retrieve information for determining uniqueness of file */
797
#ifdef H5_HAVE_WIN32_API
798
        file->hFile = (HANDLE)_get_osfhandle(fd);
799
        if (INVALID_HANDLE_VALUE == file->hFile)
800
            HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to get Windows file handle");
801
802
        if (!GetFileInformationByHandle((HANDLE)file->hFile, &fileinfo))
803
            HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to get Windows file information");
804
805
        file->nFileIndexHigh       = fileinfo.nFileIndexHigh;
806
        file->nFileIndexLow        = fileinfo.nFileIndexLow;
807
        file->dwVolumeSerialNumber = fileinfo.dwVolumeSerialNumber;
808
#else  /* H5_HAVE_WIN32_API */
809
0
        file->device = sb.st_dev;
810
0
        file->inode  = sb.st_ino;
811
0
#endif /* H5_HAVE_WIN32_API */
812
0
    }  /* end if */
813
814
    /* If an existing file is opened, load the whole file into memory. */
815
0
    if (!(H5F_ACC_CREAT & flags)) {
816
0
        size_t size;
817
818
        /* Retrieve file size */
819
0
        if (file_image_info.buffer && file_image_info.size > 0)
820
0
            size = file_image_info.size;
821
0
        else
822
0
            size = (size_t)sb.st_size;
823
824
        /* Check if we should allocate the memory buffer and read in existing data */
825
0
        if (size) {
826
            /* Allocate memory for the file's data, using the file image callback if available. */
827
0
            if (file->fi_callbacks.image_malloc) {
828
                /* Prepare & restore library for user callback */
829
0
                H5_BEFORE_USER_CB(NULL)
830
0
                    {
831
0
                        file->mem = file->fi_callbacks.image_malloc(size, H5FD_FILE_IMAGE_OP_FILE_OPEN,
832
0
                                                                    file->fi_callbacks.udata);
833
0
                    }
834
0
                H5_AFTER_USER_CB(NULL)
835
0
                if (NULL == file->mem)
836
0
                    HGOTO_ERROR(H5E_VFL, H5E_CANTALLOC, NULL, "image malloc callback failed");
837
0
            } /* end if */
838
0
            else {
839
0
                if (NULL == (file->mem = H5MM_malloc(size)))
840
0
                    HGOTO_ERROR(H5E_VFL, H5E_CANTALLOC, NULL, "unable to allocate memory block");
841
0
            } /* end else */
842
843
            /* Set up data structures */
844
0
            file->eof = size;
845
846
            /* If there is an initial file image, copy it, using the callback if possible */
847
0
            if (file_image_info.buffer && file_image_info.size > 0) {
848
0
                if (file->fi_callbacks.image_memcpy) {
849
0
                    void *tmp;
850
851
                    /* Prepare & restore library for user callback */
852
0
                    H5_BEFORE_USER_CB(NULL)
853
0
                        {
854
0
                            tmp = file->fi_callbacks.image_memcpy(file->mem, file_image_info.buffer, size,
855
0
                                                                  H5FD_FILE_IMAGE_OP_FILE_OPEN,
856
0
                                                                  file->fi_callbacks.udata);
857
0
                        }
858
0
                    H5_AFTER_USER_CB(NULL)
859
0
                    if (file->mem != tmp)
860
0
                        HGOTO_ERROR(H5E_VFL, H5E_CANTCOPY, NULL, "image_memcpy callback failed");
861
0
                } /* end if */
862
0
                else
863
0
                    H5MM_memcpy(file->mem, file_image_info.buffer, size);
864
0
            } /* end if */
865
            /* Read in existing data from the file if there is no image */
866
0
            else {
867
                /* Read in existing data, being careful of interrupted system calls,
868
                 * partial results, and the end of the file.
869
                 */
870
871
0
                uint8_t *mem    = file->mem; /* memory pointer for writes */
872
0
                HDoff_t  offset = 0;         /* offset for reading */
873
874
0
                while (size > 0) {
875
0
                    h5_posix_io_t     bytes_in   = 0;  /* # of bytes to read       */
876
0
                    h5_posix_io_ret_t bytes_read = -1; /* # of bytes actually read */
877
878
                    /* Trying to read more bytes than the return type can handle is
879
                     * undefined behavior in POSIX.
880
                     */
881
0
                    if (size > H5_POSIX_MAX_IO_BYTES)
882
0
                        bytes_in = H5_POSIX_MAX_IO_BYTES;
883
0
                    else
884
0
                        bytes_in = (h5_posix_io_t)size;
885
886
0
                    do {
887
#ifdef H5_HAVE_PREADWRITE
888
                        bytes_read = HDpread(file->fd, mem, bytes_in, offset);
889
                        if (bytes_read > 0)
890
                            offset += bytes_read;
891
#else
892
0
                        bytes_read = HDread(file->fd, mem, bytes_in);
893
0
#endif /* H5_HAVE_PREADWRITE */
894
0
                    } while (-1 == bytes_read && EINTR == errno);
895
896
0
                    if (-1 == bytes_read) { /* error */
897
0
                        int  myerrno = errno;
898
0
                        char time_str[32];
899
900
0
                        H5_get_localtime_str(time_str, sizeof(time_str));
901
0
                        offset = HDlseek(file->fd, 0, SEEK_CUR);
902
903
0
                        HGOTO_ERROR(
904
0
                            H5E_IO, H5E_READERROR, NULL,
905
0
                            "file read failed: time = %s, filename = '%s', file descriptor = %d, errno = %d, "
906
0
                            "error message = '%s', file->mem = %p, total read size = %llu, bytes this "
907
0
                            "sub-read = %llu, bytes actually read = %llu, offset = %llu",
908
0
                            time_str, file->name, file->fd, myerrno, strerror(myerrno), (void *)file->mem,
909
0
                            (unsigned long long)size, (unsigned long long)bytes_in,
910
0
                            (unsigned long long)bytes_read, (unsigned long long)offset);
911
0
                    } /* end if */
912
913
0
                    assert(bytes_read >= 0);
914
0
                    assert((size_t)bytes_read <= size);
915
916
0
                    mem += bytes_read;
917
0
                    size -= (size_t)bytes_read;
918
0
                } /* end while */
919
0
            }     /* end else */
920
0
        }         /* end if */
921
0
    }             /* end if */
922
923
    /* Get the write tracking & page size */
924
0
    file->write_tracking   = fa->write_tracking;
925
0
    file->bstore_page_size = fa->page_size;
926
927
    /* Set up write tracking if the backing store is on */
928
0
    file->dirty_list = NULL;
929
0
    if (fa->backing_store) {
930
0
        bool use_write_tracking = false; /* what we're actually doing */
931
932
        /* default is to have write tracking OFF for create (hence the check to see
933
         * if the user explicitly set a page size) and ON with the default page size
934
         * on open (when not read-only).
935
         */
936
        /* Only use write tracking if the file is open for writing */
937
0
        use_write_tracking = (true == fa->write_tracking) /* user asked for write tracking */
938
0
                             && !(o_flags & O_RDONLY)     /* file is open for writing (i.e. not read-only) */
939
0
                             && (file->bstore_page_size != 0); /* page size is not zero */
940
941
        /* initialize the dirty list */
942
0
        if (use_write_tracking)
943
0
            if (NULL == (file->dirty_list = H5SL_create(H5SL_TYPE_HADDR, NULL)))
944
0
                HGOTO_ERROR(H5E_SLIST, H5E_CANTCREATE, NULL, "can't create core vfd dirty region list");
945
0
    } /* end if */
946
947
    /* Set return value */
948
0
    ret_value = (H5FD_t *)file;
949
950
0
done:
951
0
    if (!ret_value && file) {
952
0
        if (file->fd >= 0)
953
0
            HDclose(file->fd);
954
0
        H5MM_xfree(file->name);
955
0
        H5MM_xfree(file->mem);
956
0
        H5MM_xfree(file);
957
0
    } /* end if */
958
959
0
    FUNC_LEAVE_NOAPI(ret_value)
960
0
} /* end H5FD__core_open() */
961
962
/*-------------------------------------------------------------------------
963
 * Function:    H5FD__core_close
964
 *
965
 * Purpose:     Closes the file.
966
 *
967
 * Return:      SUCCEED/FAIL
968
 *
969
 *-------------------------------------------------------------------------
970
 */
971
static herr_t
972
H5FD__core_close(H5FD_t *_file)
973
0
{
974
0
    H5FD_core_t *file      = (H5FD_core_t *)_file;
975
0
    herr_t       ret_value = SUCCEED; /* Return value */
976
977
0
    FUNC_ENTER_PACKAGE
978
979
    /* Flush any changed buffers */
980
0
    if (H5FD__core_flush(_file, (hid_t)-1, true) < 0)
981
0
        HGOTO_ERROR(H5E_FILE, H5E_CANTFLUSH, FAIL, "unable to flush core vfd backing store");
982
983
    /* Destroy the dirty region list */
984
0
    if (file->dirty_list)
985
0
        if (H5FD__core_destroy_dirty_list(file) != SUCCEED)
986
0
            HGOTO_ERROR(H5E_VFL, H5E_CANTFREE, FAIL, "unable to free core vfd dirty region list");
987
988
    /* Release resources */
989
0
    if (file->fd >= 0)
990
0
        HDclose(file->fd);
991
0
    if (file->name)
992
0
        H5MM_xfree(file->name);
993
0
    if (file->mem) {
994
        /* Use image callback if available */
995
0
        if (file->fi_callbacks.image_free) {
996
            /* Prepare & restore library for user callback */
997
0
            H5_BEFORE_USER_CB(FAIL)
998
0
                {
999
0
                    ret_value = file->fi_callbacks.image_free(file->mem, H5FD_FILE_IMAGE_OP_FILE_CLOSE,
1000
0
                                                              file->fi_callbacks.udata);
1001
0
                }
1002
0
            H5_AFTER_USER_CB(FAIL)
1003
0
            if (ret_value < 0)
1004
0
                HGOTO_ERROR(H5E_VFL, H5E_CANTFREE, FAIL, "image_free callback failed");
1005
0
        } /* end if */
1006
0
        else
1007
0
            H5MM_xfree(file->mem);
1008
0
    } /* end if */
1009
0
    memset(file, 0, sizeof(H5FD_core_t));
1010
0
    H5MM_xfree(file);
1011
1012
0
done:
1013
0
    FUNC_LEAVE_NOAPI(ret_value)
1014
0
} /* end H5FD__core_close() */
1015
1016
/*-------------------------------------------------------------------------
1017
 * Function:    H5FD__core_cmp
1018
 *
1019
 * Purpose:     Compares two files belonging to this driver by name. If one
1020
 *              file doesn't have a name then it is less than the other file.
1021
 *              If neither file has a name then the comparison is by file
1022
 *              address.
1023
 *
1024
 * Return:      Success:    A value like strcmp()
1025
 *              Failure:    never fails (arguments were checked by the
1026
 *                          caller).
1027
 *
1028
 *-------------------------------------------------------------------------
1029
 */
1030
static int
1031
H5FD__core_cmp(const H5FD_t *_f1, const H5FD_t *_f2)
1032
0
{
1033
0
    const H5FD_core_t *f1        = (const H5FD_core_t *)_f1;
1034
0
    const H5FD_core_t *f2        = (const H5FD_core_t *)_f2;
1035
0
    int                ret_value = 0;
1036
1037
0
    FUNC_ENTER_PACKAGE_NOERR
1038
1039
0
    if (f1->fd >= 0 && f2->fd >= 0) {
1040
        /* Compare low level file information for backing store */
1041
#ifdef H5_HAVE_WIN32_API
1042
        if (f1->dwVolumeSerialNumber < f2->dwVolumeSerialNumber)
1043
            HGOTO_DONE(-1);
1044
        if (f1->dwVolumeSerialNumber > f2->dwVolumeSerialNumber)
1045
            HGOTO_DONE(1);
1046
1047
        if (f1->nFileIndexHigh < f2->nFileIndexHigh)
1048
            HGOTO_DONE(-1);
1049
        if (f1->nFileIndexHigh > f2->nFileIndexHigh)
1050
            HGOTO_DONE(1);
1051
1052
        if (f1->nFileIndexLow < f2->nFileIndexLow)
1053
            HGOTO_DONE(-1);
1054
        if (f1->nFileIndexLow > f2->nFileIndexLow)
1055
            HGOTO_DONE(1);
1056
1057
#else
1058
0
        if (f1->device < f2->device)
1059
0
            HGOTO_DONE(-1);
1060
0
        if (f1->device > f2->device)
1061
0
            HGOTO_DONE(1);
1062
1063
0
        if (f1->inode < f2->inode)
1064
0
            HGOTO_DONE(-1);
1065
0
        if (f1->inode > f2->inode)
1066
0
            HGOTO_DONE(1);
1067
1068
0
#endif /*H5_HAVE_WIN32_API*/
1069
0
    }  /* end if */
1070
0
    else {
1071
0
        if (NULL == f1->name && NULL == f2->name) {
1072
0
            if (f1 < f2)
1073
0
                HGOTO_DONE(-1);
1074
0
            if (f1 > f2)
1075
0
                HGOTO_DONE(1);
1076
0
            HGOTO_DONE(0);
1077
0
        } /* end if */
1078
1079
0
        if (NULL == f1->name)
1080
0
            HGOTO_DONE(-1);
1081
0
        if (NULL == f2->name)
1082
0
            HGOTO_DONE(1);
1083
1084
0
        ret_value = strcmp(f1->name, f2->name);
1085
0
    } /* end else */
1086
1087
0
done:
1088
0
    FUNC_LEAVE_NOAPI(ret_value)
1089
0
} /* end H5FD__core_cmp() */
1090
1091
/*-------------------------------------------------------------------------
1092
 * Function:    H5FD__core_query
1093
 *
1094
 * Purpose:     Set the flags that this VFL driver is capable of supporting.
1095
 *              (listed in H5FDpublic.h)
1096
 *
1097
 * Return:      SUCCEED (Can't fail)
1098
 *
1099
 *-------------------------------------------------------------------------
1100
 */
1101
static herr_t
1102
H5FD__core_query(const H5FD_t *_file, unsigned long *flags /* out */)
1103
0
{
1104
0
    const H5FD_core_t *file = (const H5FD_core_t *)_file;
1105
1106
0
    FUNC_ENTER_PACKAGE_NOERR
1107
1108
    /* clang-format off */
1109
    /* Set the VFL feature flags that this driver supports */
1110
0
    if(flags) {
1111
0
        *flags = 0;
1112
0
        *flags |= H5FD_FEAT_AGGREGATE_METADATA;             /* OK to aggregate metadata allocations                             */
1113
0
        *flags |= H5FD_FEAT_ACCUMULATE_METADATA;            /* OK to accumulate metadata for faster writes                      */
1114
0
        *flags |= H5FD_FEAT_DATA_SIEVE;                     /* OK to perform data sieving for faster raw data reads & writes    */
1115
0
        *flags |= H5FD_FEAT_AGGREGATE_SMALLDATA;            /* OK to aggregate "small" raw data allocations                     */
1116
0
        *flags |= H5FD_FEAT_ALLOW_FILE_IMAGE;               /* OK to use file image feature with this VFD                       */
1117
0
        *flags |= H5FD_FEAT_CAN_USE_FILE_IMAGE_CALLBACKS;   /* OK to use file image callbacks with this VFD                     */
1118
1119
        /* These feature flags are only applicable if the backing store is enabled */
1120
0
        if(file && file->fd >= 0 && file->backing_store) {
1121
0
            *flags |= H5FD_FEAT_POSIX_COMPAT_HANDLE;        /* get_handle callback returns a POSIX file descriptor              */
1122
0
            *flags |= H5FD_FEAT_DEFAULT_VFD_COMPATIBLE;     /* VFD creates a file which can be opened with the default VFD      */
1123
0
        }
1124
0
    } /* end if */
1125
    /* clang-format on */
1126
1127
0
    FUNC_LEAVE_NOAPI(SUCCEED)
1128
0
} /* end H5FD__core_query() */
1129
1130
/*-------------------------------------------------------------------------
1131
 * Function:    H5FD__core_get_eoa
1132
 *
1133
 * Purpose:     Gets the end-of-address marker for the file. The EOA marker
1134
 *              is the first address past the last byte allocated in the
1135
 *              format address space.
1136
 *
1137
 * Return:      The end-of-address marker. (Can't fail)
1138
 *
1139
 *-------------------------------------------------------------------------
1140
 */
1141
static haddr_t
1142
H5FD__core_get_eoa(const H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type)
1143
0
{
1144
0
    const H5FD_core_t *file = (const H5FD_core_t *)_file;
1145
1146
0
    FUNC_ENTER_PACKAGE_NOERR
1147
1148
0
    FUNC_LEAVE_NOAPI(file->eoa)
1149
0
} /* end H5FD__core_get_eoa() */
1150
1151
/*-------------------------------------------------------------------------
1152
 * Function:    H5FD__core_set_eoa
1153
 *
1154
 * Purpose:     Set the end-of-address marker for the file. This function is
1155
 *              called shortly after an existing HDF5 file is opened in order
1156
 *              to tell the driver where the end of the HDF5 data is located.
1157
 *
1158
 * Return:      SUCCEED/FAIL
1159
 *
1160
 *-------------------------------------------------------------------------
1161
 */
1162
static herr_t
1163
H5FD__core_set_eoa(H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type, haddr_t addr)
1164
0
{
1165
0
    H5FD_core_t *file      = (H5FD_core_t *)_file;
1166
0
    herr_t       ret_value = SUCCEED; /* Return value */
1167
1168
0
    FUNC_ENTER_PACKAGE
1169
1170
0
    if (CORE_ADDR_OVERFLOW(addr))
1171
0
        HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, FAIL, "address overflow");
1172
1173
0
    file->eoa = addr;
1174
1175
0
done:
1176
0
    FUNC_LEAVE_NOAPI(ret_value)
1177
0
} /* end H5FD__core_set_eoa() */
1178
1179
/*-------------------------------------------------------------------------
1180
 * Function:    H5FD__core_get_eof
1181
 *
1182
 * Purpose:     Returns the end-of-file marker, which is the greater of
1183
 *              either the size of the underlying memory or the HDF5
1184
 *              end-of-address markers.
1185
 *
1186
 * Return:      End of file address, the first address past
1187
 *              the end of the "file", either the memory
1188
 *              or the HDF5 file. (Can't fail)
1189
 *
1190
 *-------------------------------------------------------------------------
1191
 */
1192
static haddr_t
1193
H5FD__core_get_eof(const H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type)
1194
0
{
1195
0
    const H5FD_core_t *file = (const H5FD_core_t *)_file;
1196
1197
0
    FUNC_ENTER_PACKAGE_NOERR
1198
1199
0
    FUNC_LEAVE_NOAPI(file->eof)
1200
0
} /* end H5FD__core_get_eof() */
1201
1202
/*-------------------------------------------------------------------------
1203
 * Function:       H5FD__core_get_handle
1204
 *
1205
 * Purpose:        Gets the file handle of CORE file driver.
1206
 *
1207
 * Returns:        SUCCEED/FAIL
1208
 *
1209
 *-------------------------------------------------------------------------
1210
 */
1211
static herr_t
1212
H5FD__core_get_handle(H5FD_t *_file, hid_t fapl, void **file_handle)
1213
0
{
1214
0
    H5FD_core_t *file      = (H5FD_core_t *)_file; /* core VFD info */
1215
0
    herr_t       ret_value = SUCCEED;              /* Return value */
1216
1217
0
    FUNC_ENTER_PACKAGE
1218
1219
    /* Check args */
1220
0
    if (!file_handle)
1221
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "file handle not valid");
1222
1223
    /* Check for non-default FAPL */
1224
0
    if (H5P_FILE_ACCESS_DEFAULT != fapl && H5P_DEFAULT != fapl) {
1225
0
        H5P_genplist_t *plist; /* Property list pointer */
1226
1227
        /* Get the FAPL */
1228
0
        if (NULL == (plist = (H5P_genplist_t *)H5I_object(fapl)))
1229
0
            HGOTO_ERROR(H5E_VFL, H5E_BADTYPE, FAIL, "not a file access property list");
1230
1231
        /* Check if private property for retrieving the backing store POSIX
1232
         * file descriptor is set.  (This should not be set except within the
1233
         * library)  QAK - 2009/12/04
1234
         */
1235
0
        if (H5P_exist_plist(plist, H5F_ACS_WANT_POSIX_FD_NAME) > 0) {
1236
0
            bool want_posix_fd; /* Setting for retrieving file descriptor from core VFD */
1237
1238
            /* Get property */
1239
0
            if (H5P_get(plist, H5F_ACS_WANT_POSIX_FD_NAME, &want_posix_fd) < 0)
1240
0
                HGOTO_ERROR(H5E_VFL, H5E_CANTGET, FAIL, "can't get property of retrieving file descriptor");
1241
1242
            /* If property is set, pass back the file descriptor instead of the memory address */
1243
0
            if (want_posix_fd)
1244
0
                *file_handle = &(file->fd);
1245
0
            else
1246
0
                *file_handle = &(file->mem);
1247
0
        } /* end if */
1248
0
        else
1249
0
            *file_handle = &(file->mem);
1250
0
    } /* end if */
1251
0
    else
1252
0
        *file_handle = &(file->mem);
1253
1254
0
done:
1255
0
    FUNC_LEAVE_NOAPI(ret_value)
1256
0
} /* end H5FD__core_get_handle() */
1257
1258
/*-------------------------------------------------------------------------
1259
 * Function:    H5FD__core_read
1260
 *
1261
 * Purpose:     Reads SIZE bytes of data from FILE beginning at address ADDR
1262
 *              into buffer BUF according to data transfer properties in
1263
 *              DXPL_ID.
1264
 *
1265
 * Return:      Success:    SUCCEED. Result is stored in caller-supplied
1266
 *                          buffer BUF.
1267
 *              Failure:    FAIL, Contents of buffer BUF are undefined.
1268
 *
1269
 *-------------------------------------------------------------------------
1270
 */
1271
static herr_t
1272
H5FD__core_read(H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type, hid_t H5_ATTR_UNUSED dxpl_id, haddr_t addr,
1273
                size_t size, void *buf /*out*/)
1274
0
{
1275
0
    H5FD_core_t *file      = (H5FD_core_t *)_file;
1276
0
    herr_t       ret_value = SUCCEED; /* Return value */
1277
1278
0
    FUNC_ENTER_PACKAGE
1279
1280
0
    assert(file && file->pub.cls);
1281
0
    assert(buf);
1282
1283
    /* Check for overflow conditions */
1284
0
    if (HADDR_UNDEF == addr)
1285
0
        HGOTO_ERROR(H5E_IO, H5E_OVERFLOW, FAIL, "file address overflowed");
1286
0
    if (CORE_REGION_OVERFLOW(addr, size))
1287
0
        HGOTO_ERROR(H5E_IO, H5E_OVERFLOW, FAIL, "file address overflowed");
1288
1289
    /* Read the part which is before the EOF marker */
1290
0
    if (addr < file->eof) {
1291
0
        size_t nbytes;
1292
#ifndef NDEBUG
1293
        hsize_t temp_nbytes;
1294
1295
        temp_nbytes = file->eof - addr;
1296
        H5_CHECK_OVERFLOW(temp_nbytes, hsize_t, size_t);
1297
        nbytes = MIN(size, (size_t)temp_nbytes);
1298
#else  /* NDEBUG */
1299
0
        nbytes = MIN(size, (size_t)(file->eof - addr));
1300
0
#endif /* NDEBUG */
1301
1302
0
        H5MM_memcpy(buf, file->mem + addr, nbytes);
1303
0
        size -= nbytes;
1304
0
        addr += nbytes;
1305
0
        buf = (char *)buf + nbytes;
1306
0
    }
1307
1308
    /* Read zeros for the part which is after the EOF markers */
1309
0
    if (size > 0)
1310
0
        memset(buf, 0, size);
1311
1312
0
done:
1313
0
    FUNC_LEAVE_NOAPI(ret_value)
1314
0
} /* end H5FD__core_read() */
1315
1316
/*-------------------------------------------------------------------------
1317
 * Function:    H5FD__core_write
1318
 *
1319
 * Purpose:     Writes SIZE bytes of data to FILE beginning at address ADDR
1320
 *              from buffer BUF according to data transfer properties in
1321
 *              DXPL_ID.
1322
 *
1323
 * Return:      SUCCEED/FAIL
1324
 *
1325
 *-------------------------------------------------------------------------
1326
 */
1327
static herr_t
1328
H5FD__core_write(H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type, hid_t H5_ATTR_UNUSED dxpl_id, haddr_t addr,
1329
                 size_t size, const void *buf)
1330
0
{
1331
0
    H5FD_core_t *file      = (H5FD_core_t *)_file;
1332
0
    herr_t       ret_value = SUCCEED; /* Return value */
1333
1334
0
    FUNC_ENTER_PACKAGE
1335
1336
0
    assert(file && file->pub.cls);
1337
0
    assert(buf);
1338
1339
    /* Check for overflow conditions */
1340
0
    if (CORE_REGION_OVERFLOW(addr, size))
1341
0
        HGOTO_ERROR(H5E_IO, H5E_OVERFLOW, FAIL, "file address overflowed");
1342
1343
    /*
1344
     * Allocate more memory if necessary, careful of overflow. Also, if the
1345
     * allocation fails then the file should remain in a usable state.  Be
1346
     * careful of non-Posix realloc() that doesn't understand what to do when
1347
     * the first argument is null.
1348
     */
1349
0
    if (addr + size > file->eof) {
1350
0
        unsigned char *x;
1351
0
        size_t         new_eof;
1352
1353
        /* Determine new size of memory buffer */
1354
0
        H5_CHECKED_ASSIGN(new_eof, size_t, file->increment * ((addr + size) / file->increment), hsize_t);
1355
0
        if ((addr + size) % file->increment)
1356
0
            new_eof += file->increment;
1357
1358
        /* (Re)allocate memory for the file buffer, using callbacks if available */
1359
0
        if (file->fi_callbacks.image_realloc) {
1360
            /* Prepare & restore library for user callback */
1361
0
            H5_BEFORE_USER_CB(FAIL)
1362
0
                {
1363
0
                    x = file->fi_callbacks.image_realloc(file->mem, new_eof, H5FD_FILE_IMAGE_OP_FILE_RESIZE,
1364
0
                                                         file->fi_callbacks.udata);
1365
0
                }
1366
0
            H5_AFTER_USER_CB(FAIL)
1367
0
            if (NULL == x)
1368
0
                HGOTO_ERROR(H5E_VFL, H5E_CANTALLOC, FAIL,
1369
0
                            "unable to allocate memory block of %llu bytes with callback",
1370
0
                            (unsigned long long)new_eof);
1371
0
        } /* end if */
1372
0
        else {
1373
0
            if (NULL == (x = H5MM_realloc(file->mem, new_eof)))
1374
0
                HGOTO_ERROR(H5E_VFL, H5E_CANTALLOC, FAIL, "unable to allocate memory block of %llu bytes",
1375
0
                            (unsigned long long)new_eof);
1376
0
        } /* end else */
1377
1378
0
        memset(x + file->eof, 0, (size_t)(new_eof - file->eof));
1379
0
        file->mem = x;
1380
1381
0
        file->eof = new_eof;
1382
0
    } /* end if */
1383
1384
    /* Add the buffer region to the dirty list if using that optimization */
1385
0
    if (file->dirty_list) {
1386
0
        haddr_t start = addr;
1387
0
        haddr_t end   = addr + (haddr_t)size - 1;
1388
1389
0
        if (H5FD__core_add_dirty_region(file, start, end) != SUCCEED)
1390
0
            HGOTO_ERROR(
1391
0
                H5E_VFL, H5E_CANTINSERT, FAIL,
1392
0
                "unable to add core VFD dirty region during write call - addresses: start=%llu end=%llu",
1393
0
                (unsigned long long)start, (unsigned long long)end);
1394
0
    }
1395
1396
    /* Write from BUF to memory */
1397
0
    H5MM_memcpy(file->mem + addr, buf, size);
1398
1399
    /* Mark memory buffer as modified */
1400
0
    file->dirty = true;
1401
1402
0
done:
1403
0
    FUNC_LEAVE_NOAPI(ret_value)
1404
0
} /* end H5FD__core_write() */
1405
1406
/*-------------------------------------------------------------------------
1407
 * Function:    H5FD__core_flush
1408
 *
1409
 * Purpose:     Flushes the file to backing store if there is any and if the
1410
 *              dirty flag is set.
1411
 *
1412
 * Return:      SUCCEED/FAIL
1413
 *
1414
 *-------------------------------------------------------------------------
1415
 */
1416
static herr_t
1417
H5FD__core_flush(H5FD_t *_file, hid_t H5_ATTR_UNUSED dxpl_id, bool H5_ATTR_UNUSED closing)
1418
0
{
1419
0
    H5FD_core_t *file      = (H5FD_core_t *)_file;
1420
0
    herr_t       ret_value = SUCCEED; /* Return value */
1421
1422
0
    FUNC_ENTER_PACKAGE
1423
1424
    /* Write to backing store */
1425
0
    if (file->dirty && file->fd >= 0 && file->backing_store) {
1426
1427
        /* Use the dirty list, if available */
1428
0
        if (file->dirty_list) {
1429
0
            H5FD_core_region_t *item = NULL;
1430
0
            size_t              size;
1431
1432
0
            while (NULL != (item = (H5FD_core_region_t *)H5SL_remove_first(file->dirty_list))) {
1433
1434
                /* The file may have been truncated, so check for that
1435
                 * and skip or adjust as necessary.
1436
                 */
1437
0
                if (item->start < file->eof) {
1438
0
                    if (item->end >= file->eof)
1439
0
                        item->end = file->eof - 1;
1440
1441
0
                    size = (size_t)((item->end - item->start) + 1);
1442
1443
0
                    if (H5FD__core_write_to_bstore(file, item->start, size) != SUCCEED)
1444
0
                        HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "unable to write to backing store");
1445
0
                } /* end if */
1446
1447
0
                item = H5FL_FREE(H5FD_core_region_t, item);
1448
0
            } /* end while */
1449
1450
0
        } /* end if */
1451
        /* Otherwise, write the entire file out at once */
1452
0
        else {
1453
0
            if (H5FD__core_write_to_bstore(file, (haddr_t)0, (size_t)file->eof) != SUCCEED)
1454
0
                HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "unable to write to backing store");
1455
0
        } /* end else */
1456
1457
0
        file->dirty = false;
1458
0
    }
1459
1460
0
done:
1461
0
    FUNC_LEAVE_NOAPI(ret_value)
1462
0
} /* end H5FD__core_flush() */
1463
1464
/*-------------------------------------------------------------------------
1465
 * Function:    H5FD__core_truncate
1466
 *
1467
 * Purpose:     Makes sure that the true file size is the same (or larger)
1468
 *              than the end-of-address.
1469
 *
1470
 *              Addendum -- 12/2/11
1471
 *              For file images opened with the core file driver, it is
1472
 *              necessary that we avoid reallocating the core file driver's
1473
 *              buffer unnecessarily.
1474
 *
1475
 *              To this end, I have made the following functional changes
1476
 *              to this function.
1477
 *
1478
 *              If we are closing, and there is no backing store, this
1479
 *              function becomes a no-op.
1480
 *
1481
 *              If we are closing, and there is backing store, we set the
1482
 *              eof to equal the eoa, and truncate the backing store to
1483
 *              the new eof
1484
 *
1485
 *              If we are not closing, we realloc the buffer to size equal
1486
 *              to the smallest multiple of the allocation increment that
1487
 *              equals or exceeds the eoa and set the eof accordingly.
1488
 *              Note that we no longer truncate    the backing store to the
1489
 *              new eof if applicable.
1490
 *                                                                  -- JRM
1491
 *
1492
 * Return:      SUCCEED/FAIL
1493
 *
1494
 *-------------------------------------------------------------------------
1495
 */
1496
static herr_t
1497
H5FD__core_truncate(H5FD_t *_file, hid_t H5_ATTR_UNUSED dxpl_id, bool closing)
1498
0
{
1499
0
    H5FD_core_t *file = (H5FD_core_t *)_file;
1500
0
    size_t       new_eof;             /* New size of memory buffer */
1501
0
    herr_t       ret_value = SUCCEED; /* Return value */
1502
1503
0
    FUNC_ENTER_PACKAGE
1504
1505
0
    assert(file);
1506
1507
    /* if we are closing and not using backing store, do nothing */
1508
0
    if (!closing || file->backing_store) {
1509
0
        if (closing) /* set eof to eoa */
1510
0
            new_eof = file->eoa;
1511
0
        else { /* set eof to smallest multiple of increment that exceeds eoa */
1512
            /* Determine new size of memory buffer */
1513
0
            H5_CHECKED_ASSIGN(new_eof, size_t, file->increment * (file->eoa / file->increment), hsize_t);
1514
0
            if (file->eoa % file->increment)
1515
0
                new_eof += file->increment;
1516
0
        } /* end else */
1517
1518
        /* Extend the file to make sure it's large enough */
1519
0
        if (!H5_addr_eq(file->eof, (haddr_t)new_eof)) {
1520
0
            unsigned char *x; /* Pointer to new buffer for file data */
1521
1522
            /* (Re)allocate memory for the file buffer, using callback if available */
1523
0
            if (file->fi_callbacks.image_realloc) {
1524
                /* Prepare & restore library for user callback */
1525
0
                H5_BEFORE_USER_CB(FAIL)
1526
0
                    {
1527
0
                        x = file->fi_callbacks.image_realloc(
1528
0
                            file->mem, new_eof, H5FD_FILE_IMAGE_OP_FILE_RESIZE, file->fi_callbacks.udata);
1529
0
                    }
1530
0
                H5_AFTER_USER_CB(FAIL)
1531
0
                if (NULL == x)
1532
0
                    HGOTO_ERROR(H5E_VFL, H5E_CANTALLOC, FAIL,
1533
0
                                "unable to allocate memory block with callback");
1534
0
            } /* end if */
1535
0
            else {
1536
0
                if (NULL == (x = H5MM_realloc(file->mem, new_eof)))
1537
0
                    HGOTO_ERROR(H5E_VFL, H5E_CANTALLOC, FAIL, "unable to allocate memory block");
1538
0
            } /* end else */
1539
1540
0
            if (file->eof < new_eof)
1541
0
                memset(x + file->eof, 0, (size_t)(new_eof - file->eof));
1542
0
            file->mem = x;
1543
1544
            /* Update backing store, if using it and if closing */
1545
0
            if (closing && (file->fd >= 0) && file->backing_store) {
1546
#ifdef H5_HAVE_WIN32_API
1547
                LARGE_INTEGER li;       /* 64-bit (union) integer for SetFilePointer() call */
1548
                DWORD         dwPtrLow; /* Low-order pointer bits from SetFilePointer()
1549
                                         * Only used as an error code here.
1550
                                         */
1551
                DWORD dwError;          /* DWORD error code from GetLastError() */
1552
                BOOL  bError;           /* Boolean error flag */
1553
1554
                /* Windows uses this odd QuadPart union for 32/64-bit portability */
1555
                li.QuadPart = (LONGLONG)file->eoa;
1556
1557
                /* Extend the file to make sure it's large enough.
1558
                 *
1559
                 * Since INVALID_SET_FILE_POINTER can technically be a valid return value
1560
                 * from SetFilePointer(), we also need to check GetLastError().
1561
                 */
1562
                dwPtrLow = SetFilePointer(file->hFile, li.LowPart, &li.HighPart, FILE_BEGIN);
1563
                if (INVALID_SET_FILE_POINTER == dwPtrLow) {
1564
                    dwError = GetLastError();
1565
                    if (dwError != NO_ERROR)
1566
                        HGOTO_ERROR(H5E_FILE, H5E_FILEOPEN, FAIL, "unable to set file pointer");
1567
                }
1568
1569
                bError = SetEndOfFile(file->hFile);
1570
                if (0 == bError)
1571
                    HGOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to extend file properly");
1572
#else  /* H5_HAVE_WIN32_API */
1573
0
                if (-1 == HDftruncate(file->fd, (HDoff_t)new_eof))
1574
0
                    HSYS_GOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to extend file properly");
1575
0
#endif /* H5_HAVE_WIN32_API */
1576
1577
0
            } /* end if */
1578
1579
            /* Update the eof value */
1580
0
            file->eof = new_eof;
1581
0
        } /* end if */
1582
0
    }     /* end if(file->eof < file->eoa) */
1583
1584
0
done:
1585
0
    FUNC_LEAVE_NOAPI(ret_value)
1586
0
} /* end H5FD__core_truncate() */
1587
1588
/*-------------------------------------------------------------------------
1589
 * Function:    H5FD__core_lock
1590
 *
1591
 * Purpose:     To place an advisory lock on a file.
1592
 *        The lock type to apply depends on the parameter "rw":
1593
 *            true--opens for write: an exclusive lock
1594
 *            false--opens for read: a shared lock
1595
 *
1596
 * Return:      SUCCEED/FAIL
1597
 *
1598
 *-------------------------------------------------------------------------
1599
 */
1600
static herr_t
1601
H5FD__core_lock(H5FD_t *_file, bool rw)
1602
0
{
1603
0
    H5FD_core_t *file = (H5FD_core_t *)_file; /* VFD file struct          */
1604
0
    int          lock_flags;                  /* file locking flags       */
1605
0
    herr_t       ret_value = SUCCEED;         /* Return value             */
1606
1607
0
    FUNC_ENTER_PACKAGE
1608
1609
0
    assert(file);
1610
1611
    /* Only set the lock if there is a file descriptor. If no file
1612
     * descriptor, this is a no-op.
1613
     */
1614
0
    if (file->fd >= 0) {
1615
        /* Set exclusive or shared lock based on rw status */
1616
0
        lock_flags = rw ? LOCK_EX : LOCK_SH;
1617
1618
        /* Place a non-blocking lock on the file */
1619
0
        if (HDflock(file->fd, lock_flags | LOCK_NB) < 0) {
1620
0
            if (file->ignore_disabled_file_locks && ENOSYS == errno) {
1621
                /* When errno is set to ENOSYS, the file system does not support
1622
                 * locking, so ignore it.
1623
                 */
1624
0
                errno = 0;
1625
0
            }
1626
0
            else
1627
0
                HSYS_GOTO_ERROR(H5E_FILE, H5E_BADFILE, FAIL, "unable to lock file");
1628
0
        } /* end if */
1629
0
    }     /* end if */
1630
1631
0
done:
1632
0
    FUNC_LEAVE_NOAPI(ret_value)
1633
0
} /* end H5FD__core_lock() */
1634
1635
/*-------------------------------------------------------------------------
1636
 * Function:    H5FD__core_unlock
1637
 *
1638
 * Purpose:     To remove the existing lock on the file
1639
 *
1640
 * Return:      SUCCEED/FAIL
1641
 *
1642
 *-------------------------------------------------------------------------
1643
 */
1644
static herr_t
1645
H5FD__core_unlock(H5FD_t *_file)
1646
0
{
1647
0
    H5FD_core_t *file      = (H5FD_core_t *)_file; /* VFD file struct */
1648
0
    herr_t       ret_value = SUCCEED;              /* Return value */
1649
1650
0
    FUNC_ENTER_PACKAGE
1651
1652
0
    assert(file);
1653
1654
0
    if (file->fd >= 0)
1655
0
        if (HDflock(file->fd, LOCK_UN) < 0) {
1656
0
            if (file->ignore_disabled_file_locks && ENOSYS == errno) {
1657
                /* When errno is set to ENOSYS, the file system does not support
1658
                 * locking, so ignore it.
1659
                 */
1660
0
                errno = 0;
1661
0
            }
1662
0
            else
1663
0
                HSYS_GOTO_ERROR(H5E_FILE, H5E_BADFILE, FAIL, "unable to unlock file");
1664
0
        }
1665
1666
0
done:
1667
0
    FUNC_LEAVE_NOAPI(ret_value)
1668
0
} /* end H5FD__core_unlock() */
1669
1670
/*-------------------------------------------------------------------------
1671
 * Function:    H5FD__core_delete
1672
 *
1673
 * Purpose:     Delete a file
1674
 *
1675
 * Return:      SUCCEED/FAIL
1676
 *
1677
 *-------------------------------------------------------------------------
1678
 */
1679
static herr_t
1680
H5FD__core_delete(const char *filename, hid_t fapl_id)
1681
0
{
1682
0
    const H5FD_core_fapl_t *fa = NULL;
1683
0
    H5P_genplist_t         *plist;               /* Property list pointer */
1684
0
    herr_t                  ret_value = SUCCEED; /* Return value */
1685
1686
0
    FUNC_ENTER_PACKAGE
1687
1688
0
    assert(filename);
1689
1690
0
    if (NULL == (plist = (H5P_genplist_t *)H5I_object(fapl_id)))
1691
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file access property list");
1692
0
    if (NULL == (fa = (const H5FD_core_fapl_t *)H5P_peek_driver_info(plist)))
1693
0
        fa = H5FD__core_get_default_config();
1694
1695
0
    if (fa->backing_store)
1696
0
        if (HDremove(filename) < 0)
1697
0
            HSYS_GOTO_ERROR(H5E_VFL, H5E_CANTDELETEFILE, FAIL, "unable to delete file");
1698
1699
0
done:
1700
0
    FUNC_LEAVE_NOAPI(ret_value)
1701
0
} /* end H5FD__core_delete() */