summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--MANIFEST4
-rw-r--r--src/H5FD.c2
-rw-r--r--src/H5FDsubfiling.c1314
-rw-r--r--src/H5FDsubfiling.h78
-rw-r--r--src/Makefile.am4
-rw-r--r--src/hdf5.h1
-rw-r--r--test/vfd.c159
7 files changed, 1559 insertions, 3 deletions
diff --git a/MANIFEST b/MANIFEST
index e3c3c50..eda21bb 100644
--- a/MANIFEST
+++ b/MANIFEST
@@ -710,8 +710,12 @@
./src/H5FDspace.c
./src/H5FDsplitter.c
./src/H5FDsplitter.h
+./src/H5FDsubfile.c
+./src/H5FDsubfile.h
./src/H5FDstdio.c
./src/H5FDstdio.h
+./src/H5FDsubfiling.c
+./src/H5FDsubfiling.h
./src/H5FDtest.c
./src/H5FDwindows.c
./src/H5FDwindows.h
diff --git a/src/H5FD.c b/src/H5FD.c
index 85ad025..39d30a0 100644
--- a/src/H5FD.c
+++ b/src/H5FD.c
@@ -1586,7 +1586,7 @@ H5FDwrite_vector(H5FD_t *file, hid_t dxpl_id, uint32_t count,
herr_t ret_value = SUCCEED; /* Return value */
FUNC_ENTER_API(FAIL)
- H5TRACE7("e", "*xiIu*Mt*a*z*x", file, dxpl_id, count, types, addrs, sizes, bufs);
+ H5TRACE7("e", "*xiIu*Mt*a*z**x", file, dxpl_id, count, types, addrs, sizes, bufs);
/* Check arguments */
if(!file)
diff --git a/src/H5FDsubfiling.c b/src/H5FDsubfiling.c
new file mode 100644
index 0000000..5626ed1
--- /dev/null
+++ b/src/H5FDsubfiling.c
@@ -0,0 +1,1314 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Robb Matzke <matzke@llnl.gov>
+ * Thursday, July 29, 1999
+ *
+ * Purpose: The POSIX unbuffered file driver using only the HDF5 public
+ * API and with a few optimizations: the lseek() call is made
+ * only when the current file position is unknown or needs to be
+ * changed based on previous I/O through this driver (don't mix
+ * I/O from this driver with I/O from other parts of the
+ * application to the same file).
+ */
+
+#include "H5FDdrvr_module.h" /* This source code file is part of the H5FD driver module */
+
+
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fprivate.h" /* File access */
+#include "H5FDprivate.h" /* File drivers */
+#include "H5FDsubfiling.h" /* Subfiling file driver */
+#include "H5FLprivate.h" /* Free Lists */
+#include "H5Iprivate.h" /* IDs */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5Pprivate.h" /* Property lists */
+
+/* The driver identification number, initialized at runtime */
+static hid_t H5FD_SUBFILING_g = 0;
+
+
+
+
+/* The description of a file belonging to this driver. The 'eoa' and 'eof'
+ * determine the amount of hdf5 address space in use and the high-water mark
+ * of the file (the current size of the underlying filesystem file). The
+ * 'pos' value is used to eliminate file position updates when they would be a
+ * no-op. Unfortunately we've found systems that use separate file position
+ * indicators for reading and writing so the lseek can only be eliminated if
+ * the current operation is the same as the previous operation. When opening
+ * a file the 'eof' will be set to the current file size, `eoa' will be set
+ * to zero, 'pos' will be set to H5F_ADDR_UNDEF (as it is when an error
+ * occurs), and 'op' will be set to H5F_OP_UNKNOWN.
+ */
+/***************************************************************************
+ *
+ * Structure: H5FD_subfiling_t
+ *
+ * Purpose:
+ *
+ * H5FD_subfiling_t is a structure used to store all information needed
+ * to setup, manage, and take down subfiling for a HDF5 file.
+ *
+ * This structure is created when such a file is "opened" and
+ * discarded when it is "closed".
+ *
+ * Presents a system of subfiles as a file to the HDF5 library.
+ *
+ *
+ *
+ * `pub` (H5FD_t)
+ *
+ * Instance of H5FD_t which contains all fields common to all VFDs.
+ * It must be the first item in this structure, since at higher levels,
+ * this structure will be treated as an instance of H5FD_t.
+ *
+ * `fa` (H5FD_subfiling_fapl_t)
+ *
+ * Instance of `H5FD_subfiling_fapl_t` containing the subfiling
+ * configuration data needed to "open" the HDF5 file.
+ *
+ *
+ * Document additional subfiling fields here.
+ *
+ * Recall that the existing fields are inherited from the sec2 driver
+ * and should be kept or not as appropriate for the sub-filing VFD.
+ *
+ *
+ * Programmer: Jacob Smith
+ *
+ ***************************************************************************/
+
+typedef struct H5FD_subfiling_t {
+ H5FD_t pub; /* public stuff, must be first */
+ H5FD_subfiling_fapl_t fa;
+
+ /* the following fields are inherrited from the sec2 VFD, and will
+ * likely be deleted.
+ */
+ int fd; /* the filesystem file descriptor */
+ haddr_t eoa; /* end of allocated region */
+ haddr_t eof; /* end of file; current file size */
+ haddr_t pos; /* current file I/O position */
+ H5FD_file_op_t op; /* last operation */
+ char filename[H5FD_MAX_FILENAME_LEN]; /* Copy of file name from open operation */
+#ifndef H5_HAVE_WIN32_API
+ /* On most systems the combination of device and i-node number uniquely
+ * identify a file. Note that Cygwin, MinGW and other Windows POSIX
+ * environments have the stat function (which fakes inodes)
+ * and will use the 'device + inodes' scheme as opposed to the
+ * Windows code further below.
+ */
+ dev_t device; /* file device number */
+ ino_t inode; /* file i-node number */
+#else
+ /* Files in windows are uniquely identified by the volume serial
+ * number and the file index (both low and high parts).
+ *
+ * There are caveats where these numbers can change, especially
+ * on FAT file systems. On NTFS, however, a file should keep
+ * those numbers the same until renamed or deleted (though you
+ * can use ReplaceFile() on NTFS to keep the numbers the same
+ * while renaming).
+ *
+ * See the MSDN "BY_HANDLE_FILE_INFORMATION Structure" entry for
+ * more information.
+ *
+ * http://msdn.microsoft.com/en-us/library/aa363788(v=VS.85).aspx
+ */
+ DWORD nFileIndexLow;
+ DWORD nFileIndexHigh;
+ DWORD dwVolumeSerialNumber;
+
+ HANDLE hFile; /* Native windows file handle */
+#endif /* H5_HAVE_WIN32_API */
+
+ /* Information from properties set by 'h5repart' tool
+ *
+ * Whether to eliminate the family driver info and convert this file to
+ * a single file.
+ */
+ hbool_t fam_to_single;
+
+} H5FD_subfiling_t;
+
+/*
+ * These macros check for overflow of various quantities. These macros
+ * assume that HDoff_t is signed and haddr_t and size_t are unsigned.
+ *
+ * ADDR_OVERFLOW: Checks whether a file address of type `haddr_t'
+ * is too large to be represented by the second argument
+ * of the file seek function.
+ *
+ * SIZE_OVERFLOW: Checks whether a buffer size of type `hsize_t' is too
+ * large to be represented by the `size_t' type.
+ *
+ * REGION_OVERFLOW: Checks whether an address and size pair describe data
+ * which can be addressed entirely by the second
+ * argument of the file seek function.
+ */
+#define MAXADDR (((haddr_t)1<<(8*sizeof(HDoff_t)-1))-1)
+#define ADDR_OVERFLOW(A) (HADDR_UNDEF==(A) || ((A) & ~(haddr_t)MAXADDR))
+#define SIZE_OVERFLOW(Z) ((Z) & ~(hsize_t)MAXADDR)
+#define REGION_OVERFLOW(A,Z) (ADDR_OVERFLOW(A) || SIZE_OVERFLOW(Z) || \
+ HADDR_UNDEF==(A)+(Z) || \
+ (HDoff_t)((A)+(Z))<(HDoff_t)(A))
+
+/* Prototypes */
+static herr_t H5FD_subfiling_term(void);
+static void *H5FD_subfiling_fapl_get(H5FD_t *_file);
+static void *H5FD_subfiling_fapl_copy(const void *_old_fa);
+static herr_t H5FD_subfiling_fapl_free(void *_fa);
+static H5FD_t *H5FD_subfiling_open(const char *name, unsigned flags,
+ hid_t fapl_id, haddr_t maxaddr);
+static herr_t H5FD_subfiling_close(H5FD_t *_file);
+static int H5FD_subfiling_cmp(const H5FD_t *_f1, const H5FD_t *_f2);
+static herr_t H5FD_subfiling_query(const H5FD_t *_f1, unsigned long *flags);
+static haddr_t H5FD_subfiling_get_eoa(const H5FD_t *_file, H5FD_mem_t type);
+static herr_t H5FD_subfiling_set_eoa(H5FD_t *_file, H5FD_mem_t type,
+ haddr_t addr);
+static haddr_t H5FD_subfiling_get_eof(const H5FD_t *_file, H5FD_mem_t type);
+static herr_t H5FD_subfiling_get_handle(H5FD_t *_file, hid_t fapl,
+ void** file_handle);
+static herr_t H5FD_subfiling_read(H5FD_t *_file, H5FD_mem_t type,
+ hid_t fapl_id, haddr_t addr, size_t size, void *buf);
+static herr_t H5FD_subfiling_write(H5FD_t *_file, H5FD_mem_t type,
+ hid_t fapl_id, haddr_t addr, size_t size, const void *buf);
+static herr_t H5FD_subfiling_truncate(H5FD_t *_file, hid_t dxpl_id,
+ hbool_t closing);
+static herr_t H5FD_subfiling_lock(H5FD_t *_file, hbool_t rw);
+static herr_t H5FD_subfiling_unlock(H5FD_t *_file);
+
+static herr_t H5FD_subfiling_validate_config(const H5FD_subfiling_fapl_t * fa);
+
+static const H5FD_class_t H5FD_subfiling_g = {
+ "subfiling", /* name */
+ MAXADDR, /* maxaddr */
+ H5F_CLOSE_WEAK, /* fc_degree */
+ H5FD_subfiling_term, /* terminate */
+ NULL, /* sb_size */
+ NULL, /* sb_encode */
+ NULL, /* sb_decode */
+ sizeof(H5FD_subfiling_fapl_t), /* fapl_size */
+ H5FD_subfiling_fapl_get, /* fapl_get */
+ H5FD_subfiling_fapl_copy, /* fapl_copy */
+ H5FD_subfiling_fapl_free, /* fapl_free */
+ 0, /* dxpl_size */
+ NULL, /* dxpl_copy */
+ NULL, /* dxpl_free */
+ H5FD_subfiling_open, /* open */
+ H5FD_subfiling_close, /* close */
+ H5FD_subfiling_cmp, /* cmp */
+ H5FD_subfiling_query, /* query */
+ NULL, /* get_type_map */
+ NULL, /* alloc */
+ NULL, /* free */
+ H5FD_subfiling_get_eoa, /* get_eoa */
+ H5FD_subfiling_set_eoa, /* set_eoa */
+ H5FD_subfiling_get_eof, /* get_eof */
+ H5FD_subfiling_get_handle, /* get_handle */
+ H5FD_subfiling_read, /* read */
+ H5FD_subfiling_write, /* write */
+ NULL, /* read_vector */
+ NULL, /* write_vector */
+ NULL, /* flush */
+ H5FD_subfiling_truncate, /* truncate */
+ H5FD_subfiling_lock, /* lock */
+ H5FD_subfiling_unlock, /* unlock */
+ H5FD_FLMAP_DICHOTOMY /* fl_map */
+};
+
+/* Declare a free list to manage the H5FD_subfiling_t struct */
+H5FL_DEFINE_STATIC(H5FD_subfiling_t);
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD__init_package
+ *
+ * Purpose: Initializes any interface-specific data or routines.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD__init_package(void)
+{
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_STATIC
+
+ if(H5FD_subfiling_init() < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "unable to initialize subfiling VFD")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5FD__init_package() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_subfiling_init
+ *
+ * Purpose: Initialize this driver by registering the driver with the
+ * library.
+ *
+ * Return: Success: The driver ID for the subfiling driver
+ * Failure: H5I_INVALID_HID
+ *
+ * Programmer: Robb Matzke
+ * Thursday, July 29, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5FD_subfiling_init(void)
+{
+ hid_t ret_value = H5I_INVALID_HID; /* Return value */
+
+ FUNC_ENTER_NOAPI(H5I_INVALID_HID)
+
+ if(H5I_VFL != H5I_get_type(H5FD_SUBFILING_g))
+ H5FD_SUBFILING_g = H5FD_register(&H5FD_subfiling_g, sizeof(H5FD_class_t), FALSE);
+
+ /* Set return value */
+ ret_value = H5FD_SUBFILING_g;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_subfiling_init() */
+
+
+/*---------------------------------------------------------------------------
+ * Function: H5FD_subfiling_term
+ *
+ * Purpose: Shut down the VFD
+ *
+ * Returns: SUCCEED (Can't fail)
+ *
+ * Programmer: Quincey Koziol
+ * Friday, Jan 30, 2004
+ *
+ *---------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_subfiling_term(void)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Reset VFL ID */
+ H5FD_SUBFILING_g = 0;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5FD_subfiling_term() */
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Function: H5Pset_fapl_subfiling
+ *
+ * Purpose: Modify the file access property list to use the
+ * H5FD_SUBFILING driver defined in this source file. All
+ * driver specfic properties are passed in as a pointer to
+ * a suitably initialized instance of H5FD_subfiling_fapl_t
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: John Mainzer
+ * 9/10/17
+ *
+ * Changes: None.
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_fapl_subfiling(hid_t fapl_id,
+ H5FD_subfiling_fapl_t *fa)
+{
+ H5P_genplist_t *plist = NULL; /* Property list pointer */
+ herr_t ret_value = FAIL;
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "i*x", fapl_id, fa);
+
+ HDassert(fa != NULL);
+
+ plist = H5P_object_verify(fapl_id, H5P_FILE_ACCESS);
+
+ if (plist == NULL) {
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, \
+ "not a file access property list")
+ }
+
+ if (FAIL == H5FD_subfiling_validate_config(fa)) {
+
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid subfiling config")
+ }
+
+ ret_value = H5P_set_driver(plist, H5FD_SUBFILING, (void *)fa);
+
+done:
+ FUNC_LEAVE_API(ret_value)
+
+} /* end H5Pset_fapl_subfiling() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_subfiling_validate_config()
+ *
+ * Purpose: Test to see if the supplied instance of
+ * H5FD_subfiling_fapl_t contains internally consistant data.
+ * Return SUCCEED if so, and FAIL otherwise.
+ *
+ * Note the difference between internally consistant and
+ * correct. As we will have to try to setup subfiling to
+ * determine whether the supplied data is correct,
+ * we will settle for internal consistancy at this point
+ *
+ * Return: SUCCEED if instance of H5FD_subfiling_fapl_t contains
+ * internally consistant data, FAIL otherwise.
+ *
+ * Programmer: Jacob Smith
+ * 9/10/17
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_subfiling_validate_config(const H5FD_subfiling_fapl_t * fa)
+{
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(fa != NULL);
+
+ if ( fa->version != H5FD_CURR_SUBFILING_FAPL_T_VERSION ) {
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL,
+ "Unknown H5FD_subfiling_fapl_t version");
+ }
+
+ /* add subfiling configuration validation code here */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+
+} /* end H5FD_subfiling_validate_config() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_fapl_subfiling
+ *
+ * Purpose: Returns information about the subfiling file access
+ * property list though the function arguments.
+ *
+ * Return: Success: Non-negative
+ *
+ * Failure: Negative
+ *
+ * Programmer: John Mainzer
+ * 9/10/17
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_fapl_subfiling(hid_t fapl_id,
+ H5FD_subfiling_fapl_t *fa_out)
+{
+ const H5FD_subfiling_fapl_t *fa = NULL;
+ H5P_genplist_t *plist = NULL;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "i*x", fapl_id, fa_out);
+
+ if (fa_out == NULL) {
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "fa_out is NULL")
+ }
+
+ plist = H5P_object_verify(fapl_id, H5P_FILE_ACCESS);
+
+ if (plist == NULL) {
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file access list")
+ }
+
+ if (H5FD_SUBFILING != H5P_peek_driver(plist)) {
+ HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "incorrect VFL driver")
+ }
+
+ fa = (const H5FD_subfiling_fapl_t *)H5P_peek_driver_info(plist);
+ if (fa == NULL) {
+ HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "bad VFL driver info")
+ }
+
+ /* Copy the subfiling fapl data out */
+ HDmemcpy(fa_out, fa, sizeof(H5FD_subfiling_fapl_t));
+
+done:
+ FUNC_LEAVE_API(ret_value)
+
+} /* end H5Pget_fapl_subfiling() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_subfiling_fapl_get
+ *
+ * Purpose: Gets a file access property list which could be used to
+ * create an identical file.
+ *
+ * Return: Success: Ptr to new file access property list value.
+ *
+ * Failure: NULL
+ *
+ * Programmer: John Mainzer
+ * 9/8/17
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5FD_subfiling_fapl_get(H5FD_t *_file)
+{
+ H5FD_subfiling_t *file = (H5FD_subfiling_t*)_file;
+ H5FD_subfiling_fapl_t *fa = NULL;
+ void *ret_value = NULL;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ fa = (H5FD_subfiling_fapl_t *)H5MM_calloc(sizeof(H5FD_subfiling_fapl_t));
+
+ if (fa == NULL) {
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL,
+ "memory allocation failed")
+ }
+
+ /* Copy the fields of the structure */
+ HDmemcpy(fa, &(file->fa), sizeof(H5FD_subfiling_fapl_t));
+
+ /* Set return value */
+ ret_value = fa;
+
+done:
+ if (ret_value == NULL) {
+
+ if (fa != NULL) {
+ H5MM_xfree(fa);
+ }
+ }
+ FUNC_LEAVE_NOAPI(ret_value)
+
+} /* end H5FD_subfiling_fapl_get() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_subfiling_fapl_copy
+ *
+ * Purpose: Copies the subfiling-specific file access properties.
+ *
+ * Return: Success: Ptr to a new property list
+ *
+ * Failure: NULL
+ *
+ * Programmer: John Mainzer
+ * 9/8/17
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5FD_subfiling_fapl_copy(const void *_old_fa)
+{
+ const H5FD_subfiling_fapl_t *old_fa = (const H5FD_subfiling_fapl_t*)_old_fa;
+ H5FD_subfiling_fapl_t *new_fa = NULL;
+ void *ret_value = NULL;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ new_fa = (H5FD_subfiling_fapl_t *)H5MM_malloc(sizeof(H5FD_subfiling_fapl_t));
+ if (new_fa == NULL) {
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL,
+ "memory allocation failed");
+ }
+
+ HDmemcpy(new_fa, old_fa, sizeof(H5FD_subfiling_fapl_t));
+ ret_value = new_fa;
+
+done:
+ if (ret_value == NULL) {
+
+ if (new_fa != NULL) {
+ H5MM_xfree(new_fa);
+ }
+ }
+ FUNC_LEAVE_NOAPI(ret_value)
+
+} /* end H5FD_subfiling_fapl_copy() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_subfiling_fapl_free
+ *
+ * Purpose: Frees the subfiling-specific file access properties.
+ *
+ * Return: SUCCEED (cannot fail)
+ *
+ * Programmer: John Mainzer
+ * 9/8/17
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_subfiling_fapl_free(void *_fa)
+{
+ H5FD_subfiling_fapl_t *fa = (H5FD_subfiling_fapl_t*)_fa;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(fa != NULL); /* sanity check */
+
+ H5MM_xfree(fa);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+
+} /* end H5FD_subfiling_fapl_free() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_subfiling_open
+ *
+ * Purpose: Create and/or opens a file as an HDF5 file.
+ *
+ * Return: Success: A pointer to a new file data structure. The
+ * public fields will be initialized by the
+ * caller, which is always H5FD_open().
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * Thursday, July 29, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5FD_t *
+H5FD_subfiling_open(const char *name, unsigned flags, hid_t fapl_id,
+ haddr_t maxaddr)
+{
+ H5FD_subfiling_t *file = NULL; /* subfiling VFD info */
+ int fd = -1; /* File descriptor */
+ int o_flags; /* Flags for open() call */
+#ifdef H5_HAVE_WIN32_API
+ struct _BY_HANDLE_FILE_INFORMATION fileinfo;
+#endif
+ h5_stat_t sb;
+ H5FD_subfiling_fapl_t fa;
+ H5FD_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check on file offsets */
+ HDcompile_assert(sizeof(HDoff_t) >= sizeof(size_t));
+
+ /* Check arguments */
+ if(!name || !*name)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "invalid file name")
+ if(0 == maxaddr || HADDR_UNDEF == maxaddr)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, NULL, "bogus maxaddr")
+ if(ADDR_OVERFLOW(maxaddr))
+ HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, NULL, "bogus maxaddr")
+
+ /* Build the open flags */
+ o_flags = (H5F_ACC_RDWR & flags) ? O_RDWR : O_RDONLY;
+ if(H5F_ACC_TRUNC & flags)
+ o_flags |= O_TRUNC;
+ if(H5F_ACC_CREAT & flags)
+ o_flags |= O_CREAT;
+ if(H5F_ACC_EXCL & flags)
+ o_flags |= O_EXCL;
+
+ if (FAIL == H5Pget_fapl_subfiling(fapl_id, &fa)) {
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "can't get property list")
+ }
+
+ /* Open the file */
+ if((fd = HDopen(name, o_flags, H5_POSIX_CREATE_MODE_RW)) < 0) {
+ int myerrno = errno;
+ HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to open file: name = '%s', errno = %d, error message = '%s', flags = %x, o_flags = %x", name, myerrno, HDstrerror(myerrno), flags, (unsigned)o_flags);
+ } /* end if */
+
+ if(HDfstat(fd, &sb) < 0)
+ HSYS_GOTO_ERROR(H5E_FILE, H5E_BADFILE, NULL, "unable to fstat file")
+
+ /* Create the new file struct */
+ if(NULL == (file = H5FL_CALLOC(H5FD_subfiling_t)))
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "unable to allocate file struct")
+
+ HDmemcpy(&(file->fa), &fa, sizeof(H5FD_subfiling_fapl_t));
+
+ file->fd = fd;
+ H5_CHECKED_ASSIGN(file->eof, haddr_t, sb.st_size, h5_stat_size_t);
+ file->pos = HADDR_UNDEF;
+ file->op = OP_UNKNOWN;
+#ifdef H5_HAVE_WIN32_API
+ file->hFile = (HANDLE)_get_osfhandle(fd);
+ if(INVALID_HANDLE_VALUE == file->hFile)
+ HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to get Windows file handle")
+
+ if(!GetFileInformationByHandle((HANDLE)file->hFile, &fileinfo))
+ HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to get Windows file information")
+
+ file->nFileIndexHigh = fileinfo.nFileIndexHigh;
+ file->nFileIndexLow = fileinfo.nFileIndexLow;
+ file->dwVolumeSerialNumber = fileinfo.dwVolumeSerialNumber;
+#else /* H5_HAVE_WIN32_API */
+ file->device = sb.st_dev;
+ file->inode = sb.st_ino;
+#endif /* H5_HAVE_WIN32_API */
+
+ /* Retain a copy of the name used to open the file, for possible error reporting */
+ HDstrncpy(file->filename, name, sizeof(file->filename));
+ file->filename[sizeof(file->filename) - 1] = '\0';
+
+ /* Check for non-default FAPL */
+ if(H5P_FILE_ACCESS_DEFAULT != fapl_id) {
+ H5P_genplist_t *plist; /* Property list pointer */
+
+ /* Get the FAPL */
+ if(NULL == (plist = (H5P_genplist_t *)H5I_object(fapl_id)))
+ HGOTO_ERROR(H5E_VFL, H5E_BADTYPE, NULL, "not a file access property list")
+
+ /* This step is for h5repart tool only. If user wants to change file driver from
+ * family to one that uses single files (sec2, etc.) while using h5repart, this
+ * private property should be set so that in the later step, the library can ignore
+ * the family driver information saved in the superblock.
+ */
+ if(H5P_exist_plist(plist, H5F_ACS_FAMILY_TO_SINGLE_NAME) > 0)
+ if(H5P_get(plist, H5F_ACS_FAMILY_TO_SINGLE_NAME, &file->fam_to_single) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_CANTGET, NULL, "can't get property of changing family to single")
+ } /* end if */
+
+ /* Set return value */
+ ret_value = (H5FD_t*)file;
+
+done:
+ if(NULL == ret_value) {
+ if(fd >= 0)
+ HDclose(fd);
+ if(file)
+ file = H5FL_FREE(H5FD_subfiling_t, file);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_subfiling_open() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_subfiling_close
+ *
+ * Purpose: Closes an HDF5 file.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL, file not closed.
+ *
+ * Programmer: Robb Matzke
+ * Thursday, July 29, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_subfiling_close(H5FD_t *_file)
+{
+ H5FD_subfiling_t *file = (H5FD_subfiling_t *)_file;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ /* Sanity check */
+ HDassert(file);
+
+ /* Close the underlying file */
+ if(HDclose(file->fd) < 0)
+ HSYS_GOTO_ERROR(H5E_IO, H5E_CANTCLOSEFILE, FAIL, "unable to close file")
+
+ /* Release the file info */
+ file = H5FL_FREE(H5FD_subfiling_t, file);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_subfiling_close() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_subfiling_cmp
+ *
+ * Purpose: Compares two files belonging to this driver using an
+ * arbitrary (but consistent) ordering.
+ *
+ * Return: Success: A value like strcmp()
+ * Failure: never fails (arguments were checked by the
+ * caller).
+ *
+ * Programmer: Robb Matzke
+ * Thursday, July 29, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5FD_subfiling_cmp(const H5FD_t *_f1, const H5FD_t *_f2)
+{
+ const H5FD_subfiling_t *f1 = (const H5FD_subfiling_t *)_f1;
+ const H5FD_subfiling_t *f2 = (const H5FD_subfiling_t *)_f2;
+ int ret_value = 0;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+#ifdef H5_HAVE_WIN32_API
+ if(f1->dwVolumeSerialNumber < f2->dwVolumeSerialNumber) HGOTO_DONE(-1)
+ if(f1->dwVolumeSerialNumber > f2->dwVolumeSerialNumber) HGOTO_DONE(1)
+
+ if(f1->nFileIndexHigh < f2->nFileIndexHigh) HGOTO_DONE(-1)
+ if(f1->nFileIndexHigh > f2->nFileIndexHigh) HGOTO_DONE(1)
+
+ if(f1->nFileIndexLow < f2->nFileIndexLow) HGOTO_DONE(-1)
+ if(f1->nFileIndexLow > f2->nFileIndexLow) HGOTO_DONE(1)
+#else /* H5_HAVE_WIN32_API */
+#ifdef H5_DEV_T_IS_SCALAR
+ if(f1->device < f2->device) HGOTO_DONE(-1)
+ if(f1->device > f2->device) HGOTO_DONE(1)
+#else /* H5_DEV_T_IS_SCALAR */
+ /* If dev_t isn't a scalar value on this system, just use memcmp to
+ * determine if the values are the same or not. The actual return value
+ * shouldn't really matter...
+ */
+ if(HDmemcmp(&(f1->device),&(f2->device),sizeof(dev_t)) < 0) HGOTO_DONE(-1)
+ if(HDmemcmp(&(f1->device),&(f2->device),sizeof(dev_t)) > 0) HGOTO_DONE(1)
+#endif /* H5_DEV_T_IS_SCALAR */
+ if(f1->inode < f2->inode) HGOTO_DONE(-1)
+ if(f1->inode > f2->inode) HGOTO_DONE(1)
+#endif /* H5_HAVE_WIN32_API */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_subfiling_cmp() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_subfiling_query
+ *
+ * Purpose: Set the flags that this VFL driver is capable of supporting.
+ * (listed in H5FDpublic.h)
+ *
+ * Return: SUCCEED (Can't fail)
+ *
+ * Programmer: Quincey Koziol
+ * Friday, August 25, 2000
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_subfiling_query(const H5FD_t *_file, unsigned long *flags /* out */)
+{
+ const H5FD_subfiling_t *file = (const H5FD_subfiling_t *)_file; /* subfiling VFD info */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Set the VFL feature flags that this driver supports */
+ /* Notice: the Mirror VFD Writer currently uses only the Sec2 driver as
+ * the underying driver -- as such, the Mirror VFD implementation copies
+ * these feature flags as its own. Any modifications made here must be
+ * reflected in H5FDmirror.c
+ * -- JOS 2020-01-13
+ */
+ if(flags) {
+ *flags = 0;
+ *flags |= H5FD_FEAT_AGGREGATE_METADATA; /* OK to aggregate metadata allocations */
+ *flags |= H5FD_FEAT_ACCUMULATE_METADATA; /* OK to accumulate metadata for faster writes */
+ *flags |= H5FD_FEAT_DATA_SIEVE; /* OK to perform data sieving for faster raw data reads & writes */
+ *flags |= H5FD_FEAT_AGGREGATE_SMALLDATA; /* OK to aggregate "small" raw data allocations */
+ *flags |= H5FD_FEAT_POSIX_COMPAT_HANDLE; /* get_handle callback returns a POSIX file descriptor */
+ *flags |= H5FD_FEAT_SUPPORTS_SWMR_IO; /* VFD supports the single-writer/multiple-readers (SWMR) pattern */
+ *flags |= H5FD_FEAT_DEFAULT_VFD_COMPATIBLE; /* VFD creates a file which can be opened with the default VFD */
+
+ /* Check for flags that are set by h5repart */
+ if(file && file->fam_to_single)
+ *flags |= H5FD_FEAT_IGNORE_DRVRINFO; /* Ignore the driver info when file is opened (which eliminates it) */
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5FD_subfiling_query() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_subfiling_get_eoa
+ *
+ * Purpose: Gets the end-of-address marker for the file. The EOA marker
+ * is the first address past the last byte allocated in the
+ * format address space.
+ *
+ * Return: The end-of-address marker.
+ *
+ * Programmer: Robb Matzke
+ * Monday, August 2, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static haddr_t
+H5FD_subfiling_get_eoa(const H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type)
+{
+ const H5FD_subfiling_t *file = (const H5FD_subfiling_t *)_file;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ FUNC_LEAVE_NOAPI(file->eoa)
+} /* end H5FD_subfiling_get_eoa() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_subfiling_set_eoa
+ *
+ * Purpose: Set the end-of-address marker for the file. This function is
+ * called shortly after an existing HDF5 file is opened in order
+ * to tell the driver where the end of the HDF5 data is located.
+ *
+ * Return: SUCCEED (Can't fail)
+ *
+ * Programmer: Robb Matzke
+ * Thursday, July 29, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_subfiling_set_eoa(H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type, haddr_t addr)
+{
+ H5FD_subfiling_t *file = (H5FD_subfiling_t *)_file;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ file->eoa = addr;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5FD_subfiling_set_eoa() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_subfiling_get_eof
+ *
+ * Purpose: Returns the end-of-file marker, which is the greater of
+ * either the filesystem end-of-file or the HDF5 end-of-address
+ * markers.
+ *
+ * Return: End of file address, the first address past the end of the
+ * "file", either the filesystem file or the HDF5 file.
+ *
+ * Programmer: Robb Matzke
+ * Thursday, July 29, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static haddr_t
+H5FD_subfiling_get_eof(const H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type)
+{
+ const H5FD_subfiling_t *file = (const H5FD_subfiling_t *)_file;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ FUNC_LEAVE_NOAPI(file->eof)
+} /* end H5FD_subfiling_get_eof() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_subfiling_get_handle
+ *
+ * Purpose: Returns the file handle of subfiling file driver.
+ *
+ * Returns: SUCCEED/FAIL
+ *
+ * Programmer: Raymond Lu
+ * Sept. 16, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_subfiling_get_handle(H5FD_t *_file, hid_t H5_ATTR_UNUSED fapl,
+ void **file_handle)
+{
+ H5FD_subfiling_t *file = (H5FD_subfiling_t *)_file;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ if(!file_handle)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "file handle not valid")
+
+ *file_handle = &(file->fd);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_subfiling_get_handle() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_subfiling_read
+ *
+ * Purpose: Reads SIZE bytes of data from FILE beginning at address ADDR
+ * into buffer BUF according to data transfer properties in
+ * DXPL_ID.
+ *
+ * Return: Success: SUCCEED. Result is stored in caller-supplied
+ * buffer BUF.
+ * Failure: FAIL, Contents of buffer BUF are undefined.
+ *
+ * Programmer: Robb Matzke
+ * Thursday, July 29, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_subfiling_read(H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type,
+ hid_t H5_ATTR_UNUSED dxpl_id, haddr_t addr, size_t size, void *buf /*out*/)
+{
+ H5FD_subfiling_t *file = (H5FD_subfiling_t *)_file;
+ HDoff_t offset = (HDoff_t)addr;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(file && file->pub.cls);
+ HDassert(buf);
+
+ /* Check for overflow conditions */
+ if(!H5F_addr_defined(addr))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "addr undefined, addr = %llu", (unsigned long long)addr)
+ if(REGION_OVERFLOW(addr, size))
+ HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, FAIL, "addr overflow, addr = %llu", (unsigned long long)addr)
+
+#ifndef H5_HAVE_PREADWRITE
+ /* Seek to the correct location (if we don't have pread) */
+ if(addr != file->pos || OP_READ != file->op) {
+ if(HDlseek(file->fd, (HDoff_t)addr, SEEK_SET) < 0)
+ HSYS_GOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to seek to proper position")
+ }
+#endif /* H5_HAVE_PREADWRITE */
+
+ /* Read data, being careful of interrupted system calls, partial results,
+ * and the end of the file.
+ */
+ while(size > 0) {
+
+ h5_posix_io_t bytes_in = 0; /* # of bytes to read */
+ h5_posix_io_ret_t bytes_read = -1; /* # of bytes actually read */
+
+ /* Trying to read more bytes than the return type can handle is
+ * undefined behavior in POSIX.
+ */
+ if(size > H5_POSIX_MAX_IO_BYTES)
+ bytes_in = H5_POSIX_MAX_IO_BYTES;
+ else
+ bytes_in = (h5_posix_io_t)size;
+
+ do {
+#ifdef H5_HAVE_PREADWRITE
+ bytes_read = HDpread(file->fd, buf, bytes_in, offset);
+ if(bytes_read > 0)
+ offset += bytes_read;
+#else
+ bytes_read = HDread(file->fd, buf, bytes_in);
+#endif /* H5_HAVE_PREADWRITE */
+ } while(-1 == bytes_read && EINTR == errno);
+
+ if(-1 == bytes_read) { /* error */
+ int myerrno = errno;
+ time_t mytime = HDtime(NULL);
+
+ offset = HDlseek(file->fd, (HDoff_t)0, SEEK_CUR);
+
+ HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "file read failed: time = %s, filename = '%s', file descriptor = %d, errno = %d, error message = '%s', buf = %p, total read size = %llu, bytes this sub-read = %llu, bytes actually read = %llu, offset = %llu", HDctime(&mytime), file->filename, file->fd, myerrno, HDstrerror(myerrno), buf, (unsigned long long)size, (unsigned long long)bytes_in, (unsigned long long)bytes_read, (unsigned long long)offset);
+ } /* end if */
+
+ if(0 == bytes_read) {
+ /* end of file but not end of format address space */
+ HDmemset(buf, 0, size);
+ break;
+ } /* end if */
+
+ HDassert(bytes_read >= 0);
+ HDassert((size_t)bytes_read <= size);
+
+ size -= (size_t)bytes_read;
+ addr += (haddr_t)bytes_read;
+ buf = (char *)buf + bytes_read;
+ } /* end while */
+
+ /* Update current position */
+ file->pos = addr;
+ file->op = OP_READ;
+
+done:
+ if(ret_value < 0) {
+ /* Reset last file I/O information */
+ file->pos = HADDR_UNDEF;
+ file->op = OP_UNKNOWN;
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_subfiling_read() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_subfiling_write
+ *
+ * Purpose: Writes SIZE bytes of data to FILE beginning at address ADDR
+ * from buffer BUF according to data transfer properties in
+ * DXPL_ID.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Robb Matzke
+ * Thursday, July 29, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_subfiling_write(H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type,
+ hid_t H5_ATTR_UNUSED dxpl_id, haddr_t addr, size_t size, const void *buf)
+{
+ H5FD_subfiling_t *file = (H5FD_subfiling_t *)_file;
+ HDoff_t offset = (HDoff_t)addr;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(file && file->pub.cls);
+ HDassert(buf);
+
+ /* Check for overflow conditions */
+ if(!H5F_addr_defined(addr))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "addr undefined, addr = %llu", (unsigned long long)addr)
+ if(REGION_OVERFLOW(addr, size))
+ HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, FAIL, "addr overflow, addr = %llu, size = %llu", (unsigned long long)addr, (unsigned long long)size)
+
+#ifndef H5_HAVE_PREADWRITE
+ /* Seek to the correct location (if we don't have pwrite) */
+ if(addr != file->pos || OP_WRITE != file->op) {
+ if(HDlseek(file->fd, (HDoff_t)addr, SEEK_SET) < 0)
+ HSYS_GOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to seek to proper position")
+ }
+#endif /* H5_HAVE_PREADWRITE */
+
+ /* Write the data, being careful of interrupted system calls and partial
+ * results
+ */
+ while(size > 0) {
+
+ h5_posix_io_t bytes_in = 0; /* # of bytes to write */
+ h5_posix_io_ret_t bytes_wrote = -1; /* # of bytes written */
+
+ /* Trying to write more bytes than the return type can handle is
+ * undefined behavior in POSIX.
+ */
+ if(size > H5_POSIX_MAX_IO_BYTES)
+ bytes_in = H5_POSIX_MAX_IO_BYTES;
+ else
+ bytes_in = (h5_posix_io_t)size;
+
+ do {
+#ifdef H5_HAVE_PREADWRITE
+ bytes_wrote = HDpwrite(file->fd, buf, bytes_in, offset);
+ if(bytes_wrote > 0)
+ offset += bytes_wrote;
+#else
+ bytes_wrote = HDwrite(file->fd, buf, bytes_in);
+#endif /* H5_HAVE_PREADWRITE */
+ } while(-1 == bytes_wrote && EINTR == errno);
+
+ if(-1 == bytes_wrote) { /* error */
+ int myerrno = errno;
+ time_t mytime = HDtime(NULL);
+
+ offset = HDlseek(file->fd, (HDoff_t)0, SEEK_CUR);
+
+ HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "file write failed: time = %s, filename = '%s', file descriptor = %d, errno = %d, error message = '%s', buf = %p, total write size = %llu, bytes this sub-write = %llu, bytes actually written = %llu, offset = %llu", HDctime(&mytime), file->filename, file->fd, myerrno, HDstrerror(myerrno), buf, (unsigned long long)size, (unsigned long long)bytes_in, (unsigned long long)bytes_wrote, (unsigned long long)offset);
+ } /* end if */
+
+ HDassert(bytes_wrote > 0);
+ HDassert((size_t)bytes_wrote <= size);
+
+ size -= (size_t)bytes_wrote;
+ addr += (haddr_t)bytes_wrote;
+ buf = (const char *)buf + bytes_wrote;
+ } /* end while */
+
+ /* Update current position and eof */
+ file->pos = addr;
+ file->op = OP_WRITE;
+ if(file->pos > file->eof)
+ file->eof = file->pos;
+
+done:
+ if(ret_value < 0) {
+ /* Reset last file I/O information */
+ file->pos = HADDR_UNDEF;
+ file->op = OP_UNKNOWN;
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_subfiling_write() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_subfiling_truncate
+ *
+ * Purpose: Makes sure that the true file size is the same (or larger)
+ * than the end-of-address.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, August 4, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_subfiling_truncate(H5FD_t *_file, hid_t H5_ATTR_UNUSED dxpl_id,
+ hbool_t H5_ATTR_UNUSED closing)
+{
+ H5FD_subfiling_t *file = (H5FD_subfiling_t *)_file;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(file);
+
+ /* Extend the file to make sure it's large enough */
+ if(!H5F_addr_eq(file->eoa, file->eof)) {
+#ifdef H5_HAVE_WIN32_API
+ LARGE_INTEGER li; /* 64-bit (union) integer for SetFilePointer() call */
+ DWORD dwPtrLow; /* Low-order pointer bits from SetFilePointer()
+ * Only used as an error code here.
+ */
+ DWORD dwError; /* DWORD error code from GetLastError() */
+ BOOL bError; /* Boolean error flag */
+
+ /* Windows uses this odd QuadPart union for 32/64-bit portability */
+ li.QuadPart = (__int64)file->eoa;
+
+ /* Extend the file to make sure it's large enough.
+ *
+ * Since INVALID_SET_FILE_POINTER can technically be a valid return value
+ * from SetFilePointer(), we also need to check GetLastError().
+ */
+ dwPtrLow = SetFilePointer(file->hFile, li.LowPart, &li.HighPart, FILE_BEGIN);
+ if(INVALID_SET_FILE_POINTER == dwPtrLow) {
+ dwError = GetLastError();
+ if(dwError != NO_ERROR )
+ HGOTO_ERROR(H5E_FILE, H5E_FILEOPEN, FAIL, "unable to set file pointer")
+ }
+
+ bError = SetEndOfFile(file->hFile);
+ if(0 == bError)
+ HGOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to extend file properly")
+#else /* H5_HAVE_WIN32_API */
+ if(-1 == HDftruncate(file->fd, (HDoff_t)file->eoa))
+ HSYS_GOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to extend file properly")
+#endif /* H5_HAVE_WIN32_API */
+
+ /* Update the eof value */
+ file->eof = file->eoa;
+
+ /* Reset last file I/O information */
+ file->pos = HADDR_UNDEF;
+ file->op = OP_UNKNOWN;
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_subfiling_truncate() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_subfiling_lock
+ *
+ * Purpose: To place an advisory lock on a file.
+ * The lock type to apply depends on the parameter "rw":
+ * TRUE--opens for write: an exclusive lock
+ * FALSE--opens for read: a shared lock
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Vailin Choi; May 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_subfiling_lock(H5FD_t *_file, hbool_t rw)
+{
+ H5FD_subfiling_t *file = (H5FD_subfiling_t *)_file; /* VFD file struct */
+ int lock_flags; /* file locking flags */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(file);
+
+ /* Set exclusive or shared lock based on rw status */
+ lock_flags = rw ? LOCK_EX : LOCK_SH;
+
+ /* Place a non-blocking lock on the file */
+ if(HDflock(file->fd, lock_flags | LOCK_NB) < 0) {
+ if(ENOSYS == errno)
+ HSYS_GOTO_ERROR(H5E_FILE, H5E_BADFILE, FAIL, "file locking disabled on this file system (use HDF5_USE_FILE_LOCKING environment variable to override)")
+ else
+ HSYS_GOTO_ERROR(H5E_FILE, H5E_BADFILE, FAIL, "unable to lock file")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_subfiling_lock() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_subfiling_unlock
+ *
+ * Purpose: To remove the existing lock on the file
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Vailin Choi; May 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_subfiling_unlock(H5FD_t *_file)
+{
+ H5FD_subfiling_t *file = (H5FD_subfiling_t *)_file; /* VFD file struct */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ HDassert(file);
+
+ if(HDflock(file->fd, LOCK_UN) < 0) {
+ if(ENOSYS == errno)
+ HSYS_GOTO_ERROR(H5E_FILE, H5E_BADFILE, FAIL, "file locking disabled on this file system (use HDF5_USE_FILE_LOCKING environment variable to override)")
+ else
+ HSYS_GOTO_ERROR(H5E_FILE, H5E_BADFILE, FAIL, "unable to unlock file")
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_subfiling_unlock() */
+
diff --git a/src/H5FDsubfiling.h b/src/H5FDsubfiling.h
new file mode 100644
index 0000000..b4b3f1c
--- /dev/null
+++ b/src/H5FDsubfiling.h
@@ -0,0 +1,78 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Robb Matzke <matzke@llnl.gov>
+ * Monday, August 2, 1999
+ *
+ * Purpose: The public header file for the subfiling driver.
+ */
+#ifndef H5FDsubfiling_H
+#define H5FDsubfiling_H
+
+#define H5FD_SUBFILING (H5FD_subfiling_init())
+
+/****************************************************************************
+ *
+ * Structure: H5FD_subfiling_fapl_t
+ *
+ * Purpose:
+ *
+ * H5FD_subfiling_fapl_t is a public structure that is used to pass
+ * subfiling configuration data to the appropriate subfiling VFD via
+ * the FAPL. A pointer to an instance of this structure is a parameter
+ * to H5Pset_fapl_subfiling() and H5Pget_fapl_subfiling().
+ *
+ * `version` (int32_t)
+ *
+ * Version number of the H5FD_subfiling_fapl_t structure. Any instance
+ * passed to the above calls must have a recognized version number, or
+ * an error will be flagged.
+ *
+ * This field should be set to H5FD_CURR_SUBFILING_FAPL_T_VERSION.
+ *
+ *
+ * Add fields needed to configure the subfiling VFD here.
+ *
+ * Note that we have to be able to copy FAPL entries -- thus use of
+ * variable size fields (i.e. pointers to strings, etc) will complicate
+ * matters.
+ *
+ ****************************************************************************/
+
+#define H5FD_CURR_SUBFILING_FAPL_T_VERSION 1
+
+typedef struct H5FD_subfiling_fapl_t {
+
+ int32_t version;
+
+ /* add configuration fields here */
+
+} H5FD_subfiling_fapl_t;
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+H5_DLL hid_t H5FD_subfiling_init(void);
+H5_DLL herr_t H5Pget_fapl_subfiling(hid_t fapl_id,
+ H5FD_subfiling_fapl_t *fa_out);
+H5_DLL herr_t H5Pset_fapl_subfiling(hid_t fapl_id, H5FD_subfiling_fapl_t *fa);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/src/Makefile.am b/src/Makefile.am
index 5fd9be0..04907a0 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -63,7 +63,7 @@ libhdf5_la_SOURCES= H5.c H5checksum.c H5dbg.c H5lib_settings.c H5system.c \
H5FAint.c H5FAstat.c H5FAtest.c \
H5FD.c H5FDcore.c H5FDfamily.c H5FDhdfs.c H5FDint.c H5FDlog.c \
H5FDmulti.c H5FDsec2.c H5FDspace.c \
- H5FDsplitter.c H5FDstdio.c H5FDtest.c \
+ H5FDsplitter.c H5FDstdio.c H5FDsubfiling.c H5FDtest.c \
H5FL.c H5FO.c H5FS.c H5FScache.c H5FSdbg.c H5FSint.c H5FSsection.c \
H5FSstat.c H5FStest.c \
H5G.c H5Gbtree2.c H5Gcache.c H5Gcompact.c H5Gdense.c H5Gdeprec.c \
@@ -144,7 +144,7 @@ include_HEADERS = hdf5.h H5api_adpt.h H5overflow.h H5pubconf.h H5public.h H5vers
H5Epubgen.h H5Epublic.h H5ESpublic.h H5Fpublic.h \
H5FDpublic.h H5FDcore.h H5FDdirect.h H5FDfamily.h H5FDhdfs.h \
H5FDlog.h H5FDmirror.h H5FDmpi.h H5FDmpio.h H5FDmulti.h H5FDros3.h \
- H5FDsec2.h H5FDsplitter.h H5FDstdio.h H5FDwindows.h \
+ H5FDsec2.h H5FDsplitter.h H5FDstdio.h H5FDsubfiling.h H5FDwindows.h \
H5Gpublic.h H5Ipublic.h H5Lpublic.h \
H5Mpublic.h H5MMpublic.h H5Opublic.h H5Ppublic.h \
H5PLextern.h H5PLpublic.h \
diff --git a/src/hdf5.h b/src/hdf5.h
index eaaf8ae..4c85fdc 100644
--- a/src/hdf5.h
+++ b/src/hdf5.h
@@ -51,6 +51,7 @@
#include "H5FDmulti.h" /* Usage-partitioned file family */
#include "H5FDros3.h" /* R/O S3 "file" I/O */
#include "H5FDsec2.h" /* POSIX unbuffered file I/O */
+#include "H5FDsubfiling.h" /* subfiling */
#include "H5FDsplitter.h" /* Twin-channel (R/W & R/O) I/O passthrough */
#include "H5FDstdio.h" /* Standard C buffered I/O */
#ifdef H5_HAVE_WINDOWS
diff --git a/test/vfd.c b/test/vfd.c
index bcc5bdb..bffc937 100644
--- a/test/vfd.c
+++ b/test/vfd.c
@@ -3998,6 +3998,164 @@ error:
return -1;
} /* end test_vector_io() */
+/*-------------------------------------------------------------------------
+ * Function: test_subfiling
+ *
+ * Purpose: Tests the file handle interface for subfiling driver
+ *
+ * Richard:
+ *
+ * This test is serial only -- I'm including it
+ * because I used the sec2 VFD as the base of the skeletal
+ * sub-filing VFD. Needless to say, sub-filing proper will
+ * be parallel only, which implies that the associated test
+ * code will be in testpar.
+ *
+ * That said, we will eventually need to be able to do
+ * sub-file I/O in serial. Also, it may be appropriate to
+ * test subfiling property lists in the serial code.
+ *
+ * Thus you may want to keep this function in stub form once
+ * modify the subfiling skeleton, and move the test code
+ * to testpar.
+ * -- John
+ *
+ * Return: Success: 0
+ * Failure: -1
+ *
+ * Programmer: <prgrammer>
+ * <date>
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+test_subfiling(void)
+{
+ hid_t fid = -1; /* file ID */
+ hid_t fapl_id = -1; /* file access property list ID */
+ hid_t fapl_id_out = -1; /* from H5Fget_access_plist */
+ hid_t driver_id = -1; /* ID for this VFD */
+ unsigned long driver_flags = 0; /* VFD feature flags */
+ char filename[1024]; /* filename */
+ void *os_file_handle = NULL; /* OS file handle */
+ hsize_t file_size; /* file size */
+ H5FD_subfiling_fapl_t fa_in = {H5FD_CURR_SUBFILING_FAPL_T_VERSION};
+ H5FD_subfiling_fapl_t fa_out;
+
+ TESTING("subfiling file driver");
+
+ /* Set property list and file name for subfiling driver. */
+ if((fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0)
+ TEST_ERROR;
+
+ if(H5Pset_fapl_subfiling(fapl_id, &fa_in) < 0)
+ TEST_ERROR;
+
+ /* get and verify the H5FD_subfiling_fapl_t */
+ if(H5Pget_fapl_subfiling(fapl_id, &fa_out) < 0)
+ TEST_ERROR;
+
+ if(fa_out.version != H5FD_CURR_SUBFILING_FAPL_T_VERSION)
+ TEST_ERROR;
+
+ h5_fixname(FILENAME[0], fapl_id, filename, sizeof(filename));
+
+ /* Check that the VFD feature flags are correct */
+ if ((driver_id = H5Pget_driver(fapl_id)) < 0)
+ TEST_ERROR
+
+ if (H5FDdriver_query(driver_id, &driver_flags) < 0)
+ TEST_ERROR
+
+ if(!(driver_flags & H5FD_FEAT_AGGREGATE_METADATA)) TEST_ERROR
+ if(!(driver_flags & H5FD_FEAT_ACCUMULATE_METADATA)) TEST_ERROR
+ if(!(driver_flags & H5FD_FEAT_DATA_SIEVE)) TEST_ERROR
+ if(!(driver_flags & H5FD_FEAT_AGGREGATE_SMALLDATA)) TEST_ERROR
+ if(!(driver_flags & H5FD_FEAT_POSIX_COMPAT_HANDLE)) TEST_ERROR
+ if(!(driver_flags & H5FD_FEAT_SUPPORTS_SWMR_IO)) TEST_ERROR
+ if(!(driver_flags & H5FD_FEAT_DEFAULT_VFD_COMPATIBLE)) TEST_ERROR
+
+ /* Check for extra flags not accounted for above */
+ if(driver_flags != (H5FD_FEAT_AGGREGATE_METADATA
+ | H5FD_FEAT_ACCUMULATE_METADATA
+ | H5FD_FEAT_DATA_SIEVE
+ | H5FD_FEAT_AGGREGATE_SMALLDATA
+ | H5FD_FEAT_POSIX_COMPAT_HANDLE
+ | H5FD_FEAT_SUPPORTS_SWMR_IO
+ | H5FD_FEAT_DEFAULT_VFD_COMPATIBLE))
+ TEST_ERROR
+
+ if((fid = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id)) < 0)
+ TEST_ERROR;
+
+ /* Retrieve the access property list... */
+ if((fapl_id_out = H5Fget_access_plist(fid)) < 0)
+ TEST_ERROR;
+
+ /* Check that the driver is correct */
+ if(H5FD_SUBFILING != H5Pget_driver(fapl_id_out))
+ TEST_ERROR;
+
+ /* get and verify the H5FD_subfiling_fapl_t again */
+ if(H5Pget_fapl_subfiling(fapl_id_out, &fa_out) < 0)
+ TEST_ERROR;
+
+ if(fa_out.version != H5FD_CURR_SUBFILING_FAPL_T_VERSION)
+ TEST_ERROR;
+
+ /* ...and close the property list */
+ if(H5Pclose(fapl_id_out) < 0)
+ TEST_ERROR;
+
+ /* Check that we can get an operating-system-specific handle from
+ * the library.
+ *
+ * Not sure that this will be meaningful in the subfiling case.
+ */
+ if(H5Fget_vfd_handle(fid, H5P_DEFAULT, &os_file_handle) < 0)
+ TEST_ERROR;
+
+ if(os_file_handle == NULL)
+ FAIL_PUTS_ERROR("NULL os-specific vfd/file handle was returned from H5Fget_vfd_handle");
+
+
+ /* There is no garantee the size of metadata in file is constant.
+ * Just try to check if it's reasonable.
+ *
+ * Currently it should be around 2 KB.
+ */
+ if(H5Fget_filesize(fid, &file_size) < 0)
+ TEST_ERROR;
+
+ if(file_size < 1 * KB || file_size > 4 * KB)
+ FAIL_PUTS_ERROR("suspicious file size obtained from H5Fget_filesize");
+
+ /* Close and delete the file */
+ if(H5Fclose(fid) < 0)
+ TEST_ERROR;
+
+ h5_delete_test_file(FILENAME[0], fapl_id);
+
+ /* Close the fapl */
+ if(H5Pclose(fapl_id) < 0)
+ TEST_ERROR;
+
+ PASSED();
+
+ return 0;
+
+error:
+ H5E_BEGIN_TRY {
+ H5Pclose(fapl_id);
+ H5Pclose(fapl_id_out);
+ H5Fclose(fid);
+ } H5E_END_TRY;
+
+ return -1;
+
+} /* end test_subfiling() */
+
+
/*-------------------------------------------------------------------------
* Function: main
@@ -4035,6 +4193,7 @@ main(void)
nerrors += test_splitter() < 0 ? 1 : 0;
nerrors += test_vector_io("sec2") < 0 ? 1 : 0;
nerrors += test_vector_io("stdio") < 0 ? 1 : 0;
+ nerrors += test_subfiling() < 0 ? 1 : 0;
if(nerrors) {