summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorQuincey Koziol <koziol@koziol.gov>2020-04-19 15:00:15 (GMT)
committerQuincey Koziol <koziol@koziol.gov>2020-04-19 15:00:15 (GMT)
commit83c861f32793ea6aaefbeaac870f46fdb09a3412 (patch)
tree78368fab3b9a4b8a0d9680dfda884573ef623a7e
parent5c885f52335525cb218ad3620fd2ff1a008e4962 (diff)
parent7ba692badf9a1bafb9d3b2f72efbbdf773b5932a (diff)
downloadhdf5-83c861f32793ea6aaefbeaac870f46fdb09a3412.zip
hdf5-83c861f32793ea6aaefbeaac870f46fdb09a3412.tar.gz
hdf5-83c861f32793ea6aaefbeaac870f46fdb09a3412.tar.bz2
Merge remote-tracking branch 'origin/develop' into pio_update
-rw-r--r--CMakeInstallation.cmake7
-rw-r--r--CMakeLists.txt15
-rw-r--r--MANIFEST22
-rw-r--r--Makefile.am6
-rwxr-xr-xbin/trace2
-rw-r--r--config/cmake/ConfigureChecks.cmake17
-rw-r--r--config/cmake/H5pubconf.h.in12
-rw-r--r--config/cmake/HDFCXXCompilerFlags.cmake189
-rw-r--r--config/cmake/HDFCompilerFlags.cmake90
-rw-r--r--config/cmake/HDFFortranCompilerFlags.cmake89
-rw-r--r--config/cmake/libhdf5.settings.cmake.in1
-rw-r--r--config/cmake_ext_mod/ConfigureChecks.cmake3
-rw-r--r--config/gnu-cxxflags32
-rw-r--r--config/gnu-warnings/cxx-4.91
-rw-r--r--configure.ac48
-rw-r--r--hl/c++/test/ptableTest.cpp6
-rw-r--r--hl/src/H5LTanalyze.c894
-rw-r--r--hl/src/H5LTparse.c1276
-rw-r--r--hl/src/H5LTparse.h165
-rw-r--r--release_docs/RELEASE.txt14
-rw-r--r--src/CMakeLists.txt4
-rw-r--r--src/H5FDmirror.c2001
-rw-r--r--src/H5FDmirror.h371
-rw-r--r--src/H5FDpublic.h2
-rw-r--r--src/H5FDros3.c8
-rw-r--r--src/H5FDsec2.c6
-rw-r--r--src/H5FDsplitter.c1467
-rw-r--r--src/H5FDsplitter.h99
-rw-r--r--src/H5VL.c37
-rw-r--r--src/H5VLconnector.h18
-rw-r--r--src/H5VLpublic.h20
-rw-r--r--src/H5private.h63
-rw-r--r--src/Makefile.am14
-rw-r--r--src/hdf5.h2
-rw-r--r--src/libhdf5.settings.in1
-rw-r--r--test/CMakeLists.txt19
-rw-r--r--test/CMakeTests.cmake4
-rw-r--r--test/Makefile.am19
-rw-r--r--test/h5test.c75
-rw-r--r--test/h5test.h1
-rw-r--r--test/mirror_vfd.c2761
-rw-r--r--test/test_mirror.sh.in100
-rw-r--r--test/use.h52
-rw-r--r--test/use_append_chunk.c237
-rw-r--r--test/use_append_chunk_mirror.c403
-rw-r--r--test/use_append_mchunks.c180
-rw-r--r--test/use_common.c647
-rw-r--r--test/vfd.c1097
-rw-r--r--testpar/t_span_tree.c6
-rw-r--r--tools/lib/h5tools.c79
-rw-r--r--tools/lib/h5tools.h10
-rw-r--r--tools/lib/h5tools_dump.c15
-rw-r--r--tools/libtest/h5tools_test_utils.c2
-rw-r--r--tools/src/h5dump/h5dump.c10
-rw-r--r--tools/src/h5dump/h5dump_ddl.c8
-rw-r--r--tools/src/h5ls/h5ls.c17
-rw-r--r--tools/src/h5repack/h5repack_main.c24
-rw-r--r--tools/src/h5stat/h5stat.c10
-rw-r--r--tools/test/h5repack/testfiles/h5repack-help.txt8
-rw-r--r--utils/CMakeLists.txt4
-rw-r--r--utils/COPYING12
-rw-r--r--utils/Makefile.am26
-rw-r--r--utils/mirror_vfd/CMakeLists.txt64
-rw-r--r--utils/mirror_vfd/Makefile.am30
-rw-r--r--utils/mirror_vfd/mirror_remote.c225
-rw-r--r--utils/mirror_vfd/mirror_remote.h51
-rw-r--r--utils/mirror_vfd/mirror_server.c666
-rw-r--r--utils/mirror_vfd/mirror_server_stop.c214
-rw-r--r--utils/mirror_vfd/mirror_writer.c1103
69 files changed, 13145 insertions, 2036 deletions
diff --git a/CMakeInstallation.cmake b/CMakeInstallation.cmake
index 12d8273..94d3139 100644
--- a/CMakeInstallation.cmake
+++ b/CMakeInstallation.cmake
@@ -554,6 +554,13 @@ The HDF5 data model, file format, API, library, and tools are open and distribut
)
endif ()
+ cpack_add_component (utilsapplications
+ DISPLAY_NAME "HDF5 Utility Applications"
+ DEPENDS libraries
+ GROUP Applications
+ INSTALL_TYPES Full Developer User
+ )
+
if (HDF5_BUILD_TOOLS)
cpack_add_component (toolsapplications
DISPLAY_NAME "HDF5 Tools Applications"
diff --git a/CMakeLists.txt b/CMakeLists.txt
index b63d579..7d6e7a2 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -137,6 +137,7 @@ set (HDF5_CPP_LIB_CORENAME "hdf5_cpp")
set (HDF5_HL_LIB_CORENAME "hdf5_hl")
set (HDF5_HL_CPP_LIB_CORENAME "hdf5_hl_cpp")
set (HDF5_TOOLS_LIB_CORENAME "hdf5_tools")
+set (HDF5_UTILS_LIB_CORENAME "hdf5_utils")
set (HDF5_F90_LIB_CORENAME "hdf5_fortran")
set (HDF5_F90_C_LIB_CORENAME "hdf5_f90cstub")
set (HDF5_F90_TEST_LIB_CORENAME "hdf5_test_fortran")
@@ -156,6 +157,7 @@ set (HDF5_CPP_LIB_NAME "${HDF5_EXTERNAL_LIB_PREFIX}${HDF5_CPP_LIB_COREN
set (HDF5_HL_LIB_NAME "${HDF5_EXTERNAL_LIB_PREFIX}${HDF5_HL_LIB_CORENAME}")
set (HDF5_HL_CPP_LIB_NAME "${HDF5_EXTERNAL_LIB_PREFIX}${HDF5_HL_CPP_LIB_CORENAME}")
set (HDF5_TOOLS_LIB_NAME "${HDF5_EXTERNAL_LIB_PREFIX}${HDF5_TOOLS_LIB_CORENAME}")
+set (HDF5_UTILS_LIB_NAME "${HDF5_EXTERNAL_LIB_PREFIX}${HDF5_UTILS_LIB_CORENAME}")
set (HDF5_F90_LIB_NAME "${HDF5_EXTERNAL_LIB_PREFIX}${HDF5_F90_LIB_CORENAME}")
set (HDF5_F90_C_LIB_NAME "${HDF5_EXTERNAL_LIB_PREFIX}${HDF5_F90_C_LIB_CORENAME}")
set (HDF5_F90_TEST_LIB_NAME "${HDF5_EXTERNAL_LIB_PREFIX}${HDF5_F90_TEST_LIB_CORENAME}")
@@ -175,6 +177,7 @@ set (HDF5_CPP_LIB_TARGET "${HDF5_CPP_LIB_CORENAME}-static")
set (HDF5_HL_LIB_TARGET "${HDF5_HL_LIB_CORENAME}-static")
set (HDF5_HL_CPP_LIB_TARGET "${HDF5_HL_CPP_LIB_CORENAME}-static")
set (HDF5_TOOLS_LIB_TARGET "${HDF5_TOOLS_LIB_CORENAME}-static")
+set (HDF5_UTILS_LIB_TARGET "${HDF5_UTILS_LIB_CORENAME}-static")
set (HDF5_F90_LIB_TARGET "${HDF5_F90_LIB_CORENAME}-static")
set (HDF5_F90_C_LIB_TARGET "${HDF5_F90_C_LIB_CORENAME}-static")
set (HDF5_F90_TEST_LIB_TARGET "${HDF5_F90_TEST_LIB_CORENAME}-static")
@@ -190,6 +193,7 @@ set (HDF5_CPP_LIBSH_TARGET "${HDF5_CPP_LIB_CORENAME}-shared")
set (HDF5_HL_LIBSH_TARGET "${HDF5_HL_LIB_CORENAME}-shared")
set (HDF5_HL_CPP_LIBSH_TARGET "${HDF5_HL_CPP_LIB_CORENAME}-shared")
set (HDF5_TOOLS_LIBSH_TARGET "${HDF5_TOOLS_LIB_CORENAME}-shared")
+set (HDF5_UTILS_LIBSH_TARGET "${HDF5_UTILS_LIB_CORENAME}-shared")
set (HDF5_F90_LIBSH_TARGET "${HDF5_F90_LIB_CORENAME}-shared")
set (HDF5_F90_C_LIBSH_TARGET "${HDF5_F90_C_LIB_CORENAME}-shared")
set (HDF5_F90_TEST_LIBSH_TARGET "${HDF5_F90_TEST_LIB_CORENAME}-shared")
@@ -212,6 +216,7 @@ set (HDF5_HL_TOOLS_DIR ${HDF5_SOURCE_DIR}/hl/tools)
set (HDF5_TOOLS_DIR ${HDF5_SOURCE_DIR}/tools)
set (HDF5_TOOLS_SRC_DIR ${HDF5_SOURCE_DIR}/tools/src)
set (HDF5_PERFORM_SRC_DIR ${HDF5_SOURCE_DIR}/tools/src/perform)
+set (HDF5_UTILS_DIR ${HDF5_SOURCE_DIR}/utils)
set (HDF5_F90_SRC_DIR ${HDF5_SOURCE_DIR}/fortran)
set (HDF5_JAVA_JNI_SRC_DIR ${HDF5_SOURCE_DIR}/java/src/jni)
set (HDF5_JAVA_HDF5_SRC_DIR ${HDF5_SOURCE_DIR}/java/src/hdf)
@@ -920,6 +925,16 @@ if (BUILD_TESTING)
endif ()
#-----------------------------------------------------------------------------
+# Option to build HDF5 Utilities
+#-----------------------------------------------------------------------------
+if (EXISTS "${HDF5_SOURCE_DIR}/utils" AND IS_DIRECTORY "${HDF5_SOURCE_DIR}/utils")
+ option (HDF5_BUILD_UTILS "Build HDF5 Utils" ON)
+ if (HDF5_BUILD_UTILS)
+ add_subdirectory (utils)
+ endif ()
+endif ()
+
+#-----------------------------------------------------------------------------
# Option to build HDF5 Tools
#-----------------------------------------------------------------------------
if (EXISTS "${HDF5_SOURCE_DIR}/tools" AND IS_DIRECTORY "${HDF5_SOURCE_DIR}/tools")
diff --git a/MANIFEST b/MANIFEST
index b1be241..d03b527 100644
--- a/MANIFEST
+++ b/MANIFEST
@@ -165,6 +165,7 @@
./config/gnu-warnings/8
./config/gnu-warnings/9
./config/gnu-warnings/cxx-general
+./config/gnu-warnings/cxx-4.9
./config/gnu-warnings/developer-4.5
./config/gnu-warnings/developer-4.6
./config/gnu-warnings/developer-4.7
@@ -699,6 +700,8 @@
./src/H5FDint.c
./src/H5FDlog.c
./src/H5FDlog.h
+./src/H5FDmirror.c
+./src/H5FDmirror.h
./src/H5FDmodule.h
./src/H5FDmpi.c
./src/H5FDmpi.h
@@ -716,6 +719,8 @@
./src/H5FDsec2.c
./src/H5FDsec2.h
./src/H5FDspace.c
+./src/H5FDsplitter.c
+./src/H5FDsplitter.h
./src/H5FDstdio.c
./src/H5FDstdio.h
./src/H5FDtest.c
@@ -1158,6 +1163,7 @@
./test/memleak_H5O_dtype_decode_helper_H5Odtype.h5
./test/mergemsg.h5
./test/mf.c
+./test/mirror_vfd.c
./test/mount.c
./test/mtime.c
./test/multi_file_v16-r.h5
@@ -1218,6 +1224,7 @@
./test/testhdf5.c
./test/testhdf5.h
./test/testlibinfo.sh.in
+./test/test_mirror.sh.in
./test/test_usecases.sh.in
./test/test_vol_plugin.sh.in
./test/testmeta.c
@@ -1261,6 +1268,7 @@
./test/unlink.c
./test/unregister.c
./test/use_append_chunk.c
+./test/use_append_chunk_mirror.c
./test/use_append_mchunks.c
./test/use_common.c
./test/use_disable_mdc_flushes.c
@@ -2817,6 +2825,18 @@
./tools/test/perform/sio_standalone.h
./tools/test/perform/zip_perf.c
+# Utils directory
+./utils/COPYING
+./utils/Makefile.am
+
+# Mirror VFD utilities
+./utils/mirror_vfd/Makefile.am
+./utils/mirror_vfd/mirror_remote.c
+./utils/mirror_vfd/mirror_remote.h
+./utils/mirror_vfd/mirror_server.c
+./utils/mirror_vfd/mirror_server_stop.c
+./utils/mirror_vfd/mirror_writer.c
+
# high level libraries
./hl/COPYING
./hl/Makefile.am
@@ -3554,6 +3574,8 @@
./tools/test/misc/vds/CMakeLists.txt
./tools/test/perform/CMakeLists.txt
./tools/test/perform/CMakeTests.cmake
+./utils/CMakeLists.txt
+./utils/mirror_vfd/CMakeLists.txt
# CMake-specific User Scripts
./config/cmake/CTestScript.cmake
diff --git a/Makefile.am b/Makefile.am
index d96ffe3..9689b58 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -85,9 +85,9 @@ else
TOOLS_DIR=
endif
-SUBDIRS = src $(TESTSERIAL_DIR) $(TESTPARALLEL_DIR) bin $(TOOLS_DIR) . \
+SUBDIRS = src $(TESTSERIAL_DIR) $(TESTPARALLEL_DIR) bin utils $(TOOLS_DIR) . \
$(CXX_DIR) $(FORTRAN_DIR) $(JAVA_DIR) $(HDF5_HL_DIR)
-DIST_SUBDIRS = src test testpar tools . c++ fortran hl examples java
+DIST_SUBDIRS = src test testpar utils tools . c++ fortran hl examples java
# Some files generated during configure that should be cleaned
DISTCLEANFILES=config/stamp1 config/stamp2
@@ -190,7 +190,7 @@ trace:
# Run tests with different Virtual File Drivers.
# Currently, only invoke check-vfd in the test directory.
check-vfd:
- for d in src test; do \
+ for d in src utils test; do \
if test $$d != .; then \
(cd $$d && $(MAKE) $(AM_MAKEFLAGS) $@) || exit 1; \
fi; \
diff --git a/bin/trace b/bin/trace
index 15baa8a..fd0248e 100755
--- a/bin/trace
+++ b/bin/trace
@@ -43,6 +43,7 @@ $Source = "";
"H5D_space_status_t" => "Ds",
"H5D_vds_view_t" => "Dv",
"H5FD_mpio_xfer_t" => "Dt",
+ "H5FD_splitter_vfd_config_t" => "Dr",
"herr_t" => "e",
"H5E_direction_t" => "Ed",
"H5E_error_t" => "Ee",
@@ -159,6 +160,7 @@ $Source = "";
"H5FD_ros3_fapl_t" => "x",
"H5FD_hdfs_fapl_t" => "x",
"H5FD_file_image_callbacks_t" => "x",
+ "H5FD_mirror_fapl_t" => "x",
"H5G_iterate_t" => "x",
"H5G_info_t" => "x",
"H5I_free_t" => "x",
diff --git a/config/cmake/ConfigureChecks.cmake b/config/cmake/ConfigureChecks.cmake
index 11bf39c..5a401f7 100644
--- a/config/cmake/ConfigureChecks.cmake
+++ b/config/cmake/ConfigureChecks.cmake
@@ -171,6 +171,23 @@ option (HDF5_ENABLE_ROS3_VFD "Build the ROS3 Virtual File Driver" OFF)
endif ()
endif ()
+# ----------------------------------------------------------------------
+# Check whether we can build the Mirror VFD
+# Header-check flags set in config/cmake_ext_mod/ConfigureChecks.cmake
+# ----------------------------------------------------------------------
+option (HDF5_ENABLE_MIRROR_VFD "Build the Mirror Virtual File Driver" OFF)
+if (H5FD_ENABLE_MIRROR_VFD)
+ if ( ${HDF_PREFIX}_HAVE_NETINET_IN_H AND
+ ${HDF_PREFIX}_HAVE_NETDB_H AND
+ ${HDF_PREFIX}_HAVE_ARPA_INET_H AND
+ ${HDF_PREFIX}_HAVE_SYS_SOCKET_H AND
+ ${HDF_PREFIX}_HAVE_FORK)
+ set (${HDF_PREFIX}_HAVE_MIRROR_VFD 1)
+ else()
+ message(STATUS "The socket-based Mirror VFD was requested but cannot be built. System prerequisites are not met.")
+ endif()
+endif()
+
#-----------------------------------------------------------------------------
# Check if C has __float128 extension
#-----------------------------------------------------------------------------
diff --git a/config/cmake/H5pubconf.h.in b/config/cmake/H5pubconf.h.in
index 0836168..6edf6b4 100644
--- a/config/cmake/H5pubconf.h.in
+++ b/config/cmake/H5pubconf.h.in
@@ -104,6 +104,9 @@
/* Define if the compiler understands the __func__ keyword */
#cmakedefine H5_HAVE_C99_FUNC @H5_HAVE_C99_FUNC@
+/* Define to 1 if you have the <arpa/inet.h> header file. */
+#cmakedefine H5_HAVE_ARPA_INET_H @H5_HAVE_ARPA_INET_H@
+
/* Define to 1 if you have the `clock_gettime' function. */
#cmakedefine H5_HAVE_CLOCK_GETTIME @H5_HAVE_CLOCK_GETTIME@
@@ -273,6 +276,9 @@
/* Define to 1 if you have the <memory.h> header file. */
#cmakedefine H5_HAVE_MEMORY_H @H5_HAVE_MEMORY_H@
+/* Define if we can build the Mirror VFD */
+#cmakedefine H5_HAVE_MIRROR_VFD @H5_HAVE_MIRROR_VFD@
+
/* Define if we have MPE support */
#cmakedefine H5_HAVE_MPE @H5_HAVE_MPE@
@@ -285,6 +291,12 @@
/* Define if MPI_Info_c2f and MPI_Info_f2c exists */
#cmakedefine H5_HAVE_MPI_MULTI_LANG_Info @H5_HAVE_MPI_MULTI_LANG_Info@
+/* Define to 1 if you have the <netdb.h> header file. */
+#cmakedefine H5_HAVE_NETDB_H @H5_HAVE_NETDB_H@
+
+/* Define to 1 if you have the <netinet/in.h> header file. */
+#cmakedefine H5_HAVE_NETINET_IN_H @H5_HAVE_NETINET_IN_H@
+
/* Define to 1 if you have the <openssl/evp.h> header file. */
#cmakedefine H5_HAVE_OPENSSL_EVP_H @H5_HAVE_OPENSSL_EVP_H@
diff --git a/config/cmake/HDFCXXCompilerFlags.cmake b/config/cmake/HDFCXXCompilerFlags.cmake
index bf22886..6aa8784 100644
--- a/config/cmake/HDFCXXCompilerFlags.cmake
+++ b/config/cmake/HDFCXXCompilerFlags.cmake
@@ -104,6 +104,8 @@ if (NOT MSVC)
endif()
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
if (CMAKE_COMPILER_IS_GNUCXX AND CMAKE_CXX_COMPILER_LOADED)
+ # autotools always add the C flags with the CXX flags
+ ADD_H5_FLAGS (HDF5_CMAKE_CXX_FLAGS "${HDF5_SOURCE_DIR}/config/gnu-warnings/general")
ADD_H5_FLAGS (HDF5_CMAKE_CXX_FLAGS "${HDF5_SOURCE_DIR}/config/gnu-warnings/cxx-general")
endif ()
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
@@ -114,47 +116,160 @@ if (NOT MSVC)
message (STATUS "CMAKE_CXX_FLAGS_GENERAL=${HDF5_CMAKE_CXX_FLAGS}")
endif ()
- #-----------------------------------------------------------------------------
- # Option to allow the user to enable developer warnings
- # Developer warnings (suggestions from gcc, not code problems)
- #-----------------------------------------------------------------------------
- #if (HDF5_ENABLE_DEV_WARNINGS)
- # message (STATUS "....HDF5 developer group warnings are enabled")
- # if (CMAKE_CXX_COMPILER_ID STREQUAL "Intel")
- # list (APPEND H5_CXXFLAGS0 "-Winline -Wreorder -Wport -Wstrict-aliasing")
- # elseif (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
- # ADD_H5_FLAGS (H5_CXXFLAGS0 "${HDF5_SOURCE_DIR}/config/gnu-warnings/developer-general")
- # elseif (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
- # ADD_H5_FLAGS (H5_CXXFLAGS0 "${HDF5_SOURCE_DIR}/config/clang-warnings/developer-general")
- # endif ()
- #else ()
- # if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
- # ADD_H5_FLAGS (H5_CXXFLAGS0 "${HDF5_SOURCE_DIR}/config/gnu-warnings/no-developer-general")
- # elseif (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
- # ADD_H5_FLAGS (H5_CXXFLAGS0 "${HDF5_SOURCE_DIR}/config/clang-warnings/no-developer-general")
- # endif ()
- #endif ()
-
+ #-----------------------------------------------------------------------------
+ # Option to allow the user to enable developer warnings
+ # Developer warnings (suggestions from gcc, not code problems)
+ #-----------------------------------------------------------------------------
+ if (HDF5_ENABLE_DEV_WARNINGS)
+ message (STATUS "....HDF5 developer group warnings are enabled")
+ # if (CMAKE_CXX_COMPILER_ID STREQUAL "Intel")
+ # list (APPEND H5_CXXFLAGS0 "-Winline -Wreorder -Wport -Wstrict-aliasing")
+ # elseif (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
+ if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
+ # autotools always add the C flags with the CXX flags
+ ADD_H5_FLAGS (H5_CXXFLAGS0 "${HDF5_SOURCE_DIR}/config/gnu-warnings/developer-general")
+ # elseif (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
+ # ADD_H5_FLAGS (H5_CXXFLAGS0 "${HDF5_SOURCE_DIR}/config/clang-warnings/developer-general")
+ endif ()
+ else ()
+ if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
+ # autotools always add the C flags with the CXX flags
+ ADD_H5_FLAGS (H5_CXXFLAGS0 "${HDF5_SOURCE_DIR}/config/gnu-warnings/no-developer-general")
+ # elseif (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
+ # ADD_H5_FLAGS (H5_CXXFLAGS0 "${HDF5_SOURCE_DIR}/config/clang-warnings/no-developer-general")
+ endif ()
+ endif ()
- #if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
- # # Append warning flags that only gcc 4.3+ knows about
- # ADD_H5_FLAGS (H5_CXXFLAGS1 "${HDF5_SOURCE_DIR}/config/gnu-warnings/4.3")
+ if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
+ # Append warning flags that only gcc 4.3+ knows about
+ # autotools always add the C flags with the CXX flags
+ ADD_H5_FLAGS (H5_CXXFLAGS1 "${HDF5_SOURCE_DIR}/config/gnu-warnings/4.3")
+ #
+ # Technically, variable-length arrays are part of the C99 standard, but
+ # we should approach them a bit cautiously... Only needed for gcc 4.X
+ if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0)
+ # autotools always add the C flags with the CXX flags
+ ADD_H5_FLAGS (H5_CXXFLAGS1 "${HDF5_SOURCE_DIR}/config/gnu-warnings/4.2-4.last")
+ endif ()
- # # Append more extra warning flags that only gcc 4.4+ know about
- # if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.4)
- # ADD_H5_FLAGS (H5_CXXFLAGS1 "${HDF5_SOURCE_DIR}/config/gnu-warnings/4.4")
- # endif ()
- #endif ()
+ # Append more extra warning flags that only gcc 4.4+ know about
+ if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.4)
+ # autotools always add the C flags with the CXX flags
+ ADD_H5_FLAGS (H5_CXXFLAGS1 "${HDF5_SOURCE_DIR}/config/gnu-warnings/4.4")
+ endif ()
# Append more extra warning flags that only gcc 4.5+ know about
- #if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.5)
- # ADD_H5_FLAGS (H5_CXXFLAGS1 "${HDF5_SOURCE_DIR}/config/gnu-warnings/4.5")
- # if (HDF5_ENABLE_DEV_WARNINGS)
- # ADD_H5_FLAGS (H5_CXXFLAGS1 "${HDF5_SOURCE_DIR}/config/gnu-warnings/developer-4.5")
- # else ()
- # ADD_H5_FLAGS (H5_CXXFLAGS1 "${HDF5_SOURCE_DIR}/config/gnu-warnings/no-developer-4.5")
- # endif ()
- #endif ()
+ if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.5)
+ # autotools always add the C flags with the CXX flags
+ ADD_H5_FLAGS (H5_CXXFLAGS1 "${HDF5_SOURCE_DIR}/config/gnu-warnings/4.5")
+ if (HDF5_ENABLE_DEV_WARNINGS)
+ # autotools always add the C flags with the CXX flags
+ ADD_H5_FLAGS (H5_CXXFLAGS1 "${HDF5_SOURCE_DIR}/config/gnu-warnings/developer-4.5")
+ else ()
+ # autotools always add the C flags with the CXX flags
+ ADD_H5_FLAGS (H5_CXXFLAGS1 "${HDF5_SOURCE_DIR}/config/gnu-warnings/no-developer-4.5")
+ endif ()
+ endif ()
+
+ # Append more extra warning flags that only gcc 4.6 and less know about
+ if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.7)
+ # autotools always add the C flags with the CXX flags
+ ADD_H5_FLAGS (H5_CXXFLAGS1 "${HDF5_SOURCE_DIR}/config/gnu-warnings/4.2-4.6")
+ endif ()
+
+ # Append more extra warning flags that only gcc 4.5-4.6 know about
+ if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.5 AND CMAKE_C_COMPILER_VERSION VERSION_LESS 4.7)
+ # autotools always add the C flags with the CXX flags
+ ADD_H5_FLAGS (H5_CXXFLAGS1 "${HDF5_SOURCE_DIR}/config/gnu-warnings/4.5-4.6")
+ endif ()
+
+ # Append more extra warning flags that only gcc 4.6+ know about
+ if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.6)
+ # autotools always add the C flags with the CXX flags
+ ADD_H5_FLAGS (H5_CXXFLAGS1 "${HDF5_SOURCE_DIR}/config/gnu-warnings/4.6")
+ if (HDF5_ENABLE_DEV_WARNINGS)
+ # autotools always add the C flags with the CXX flags
+ ADD_H5_FLAGS (H5_CXXFLAGS1 "${HDF5_SOURCE_DIR}/config/gnu-warnings/developer-4.6")
+ else ()
+ # autotools always add the C flags with the CXX flags
+ ADD_H5_FLAGS (H5_CXXFLAGS1 "${HDF5_SOURCE_DIR}/config/gnu-warnings/no-developer-4.6")
+ endif ()
+ endif ()
+
+ # Append more extra warning flags that only gcc 4.7+ know about
+ if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.7)
+ # autotools always add the C flags with the CXX flags
+ ADD_H5_FLAGS (H5_CXXFLAGS1 "${HDF5_SOURCE_DIR}/config/gnu-warnings/4.7")
+ if (HDF5_ENABLE_DEV_WARNINGS)
+ # autotools always add the C flags with the CXX flags
+ ADD_H5_FLAGS (H5_CXXFLAGS1 "${HDF5_SOURCE_DIR}/config/gnu-warnings/developer-4.7")
+ else ()
+ # autotools always add the C flags with the CXX flags
+ ADD_H5_FLAGS (H5_CXXFLAGS1 "${HDF5_SOURCE_DIR}/config/gnu-warnings/no-developer-4.7")
+ endif ()
+ endif ()
+
+ # Append more extra warning flags that only gcc 4.8+ know about
+ if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.8)
+ ADD_H5_FLAGS (H5_CXXFLAGS1 "${HDF5_SOURCE_DIR}/config/gnu-warnings/4.8")
+ if (HDF5_ENABLE_DEV_WARNINGS)
+ ADD_H5_FLAGS (H5_CXXFLAGS1 "${HDF5_SOURCE_DIR}/config/gnu-warnings/developer-4.8")
+ else ()
+ ADD_H5_FLAGS (H5_CXXFLAGS1 "${HDF5_SOURCE_DIR}/config/gnu-warnings/no-developer-4.8")
+ endif ()
+ endif ()
+
+ # Append more extra warning flags that only gcc 4.9+ know about
+ if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.9)
+ # autotools always add the C flags with the CXX flags
+ ADD_H5_FLAGS (H5_CXXFLAGS1 "${HDF5_SOURCE_DIR}/config/gnu-warnings/4.9")
+ ADD_H5_FLAGS (H5_CXXFLAGS1 "${HDF5_SOURCE_DIR}/config/gnu-warnings/cxx-4.9")
+ endif ()
+
+ # Append more extra warning flags that only gcc 5.1+ know about
+ if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0)
+ # autotools always add the C flags with the CXX flags
+ ADD_H5_FLAGS (H5_CXXFLAGS1 "${HDF5_SOURCE_DIR}/config/gnu-warnings/5")
+ ADD_H5_FLAGS (H5_CXXFLAGS1 "${HDF5_SOURCE_DIR}/config/gnu-warnings/error-5")
+ endif ()
+
+ # Append more extra warning flags that only gcc 6.x+ know about
+ if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 6.0)
+ # autotools always add the C flags with the CXX flags
+ ADD_H5_FLAGS (H5_CXXFLAGS1 "${HDF5_SOURCE_DIR}/config/gnu-warnings/6")
+ endif ()
+
+ # Append more extra warning flags that only gcc 7.x+ know about
+ if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 7.0)
+ # autotools always add the C flags with the CXX flags
+ ADD_H5_FLAGS (H5_CXxFLAGS2 "${HDF5_SOURCE_DIR}/config/gnu-warnings/7")
+ if (HDF5_ENABLE_DEV_WARNINGS)
+ # autotools always add the C flags with the CXX flags
+ ADD_H5_FLAGS (H5_CXXFLAGS2 "${HDF5_SOURCE_DIR}/config/gnu-warnings/developer-7")
+ #else ()
+ # ADD_H5_FLAGS (H5_CXXFLAGS2 "${HDF5_SOURCE_DIR}/config/gnu-warnings/no-developer-7")
+ endif ()
+ endif ()
+
+ # Append more extra warning flags that only gcc 8.x+ know about
+ if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 8.0)
+ # autotools always add the C flags with the CXX flags
+ ADD_H5_FLAGS (H5_CXXFLAGS3 "${HDF5_SOURCE_DIR}/config/gnu-warnings/8")
+ if (HDF5_ENABLE_DEV_WARNINGS)
+ # autotools always add the C flags with the CXX flags
+ ADD_H5_FLAGS (H5_CXXFLAGS3 "${HDF5_SOURCE_DIR}/config/gnu-warnings/developer-8")
+ else ()
+ # autotools always add the C flags with the CXX flags
+ ADD_H5_FLAGS (H5_CXXFLAGS3 "${HDF5_SOURCE_DIR}/config/gnu-warnings/no-developer-8")
+ endif ()
+ endif ()
+
+ # Append more extra warning flags that only gcc 9.x+ know about
+ if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9.0)
+ # autotools always add the C flags with the CXX flags
+ ADD_H5_FLAGS (H5_CXXFLAGS4 "${HDF5_SOURCE_DIR}/config/gnu-warnings/9")
+ endif ()
+ endif ()
else ()
list (APPEND HDF5_CMAKE_CXX_FLAGS "/EHsc")
endif ()
diff --git a/config/cmake/HDFCompilerFlags.cmake b/config/cmake/HDFCompilerFlags.cmake
index b255e22..72141c0 100644
--- a/config/cmake/HDFCompilerFlags.cmake
+++ b/config/cmake/HDFCompilerFlags.cmake
@@ -125,47 +125,46 @@ if (NOT MSVC)
message (STATUS "CMAKE_C_FLAGS_GENERAL=${HDF5_CMAKE_C_FLAGS}")
endif ()
- #-----------------------------------------------------------------------------
- # Option to allow the user to enable developer warnings
- # Developer warnings (suggestions from gcc, not code problems)
- #-----------------------------------------------------------------------------
- option (HDF5_ENABLE_DEV_WARNINGS "Enable HDF5 developer group warnings" OFF)
- if (HDF5_ENABLE_DEV_WARNINGS)
- message (STATUS "....HDF5 developer group warnings are enabled")
- if (CMAKE_C_COMPILER_ID STREQUAL "Intel")
- list (APPEND H5_CFLAGS0 "-Winline -Wreorder -Wport -Wstrict-aliasing")
- elseif (CMAKE_C_COMPILER_ID STREQUAL "GNU")
- ADD_H5_FLAGS (H5_CFLAGS0 "${HDF5_SOURCE_DIR}/config/gnu-warnings/developer-general")
- elseif (CMAKE_C_COMPILER_ID STREQUAL "Clang")
- ADD_H5_FLAGS (H5_CFLAGS0 "${HDF5_SOURCE_DIR}/config/clang-warnings/developer-general")
- endif ()
- else ()
- if (CMAKE_C_COMPILER_ID STREQUAL "GNU")
- ADD_H5_FLAGS (H5_CFLAGS0 "${HDF5_SOURCE_DIR}/config/gnu-warnings/no-developer-general")
- elseif (CMAKE_C_COMPILER_ID STREQUAL "Clang")
- ADD_H5_FLAGS (H5_CFLAGS0 "${HDF5_SOURCE_DIR}/config/clang-warnings/no-developer-general")
- endif ()
+ #-----------------------------------------------------------------------------
+ # Option to allow the user to enable developer warnings
+ # Developer warnings (suggestions from gcc, not code problems)
+ #-----------------------------------------------------------------------------
+ option (HDF5_ENABLE_DEV_WARNINGS "Enable HDF5 developer group warnings" OFF)
+ if (HDF5_ENABLE_DEV_WARNINGS)
+ message (STATUS "....HDF5 developer group warnings are enabled")
+ if (CMAKE_C_COMPILER_ID STREQUAL "Intel")
+ list (APPEND H5_CFLAGS0 "-Winline -Wreorder -Wport -Wstrict-aliasing")
+ elseif (CMAKE_C_COMPILER_ID STREQUAL "GNU")
+ ADD_H5_FLAGS (H5_CFLAGS0 "${HDF5_SOURCE_DIR}/config/gnu-warnings/developer-general")
+ elseif (CMAKE_C_COMPILER_ID STREQUAL "Clang")
+ ADD_H5_FLAGS (H5_CFLAGS0 "${HDF5_SOURCE_DIR}/config/clang-warnings/developer-general")
+ endif ()
+ else ()
+ if (CMAKE_C_COMPILER_ID STREQUAL "GNU")
+ ADD_H5_FLAGS (H5_CFLAGS0 "${HDF5_SOURCE_DIR}/config/gnu-warnings/no-developer-general")
+ elseif (CMAKE_C_COMPILER_ID STREQUAL "Clang")
+ ADD_H5_FLAGS (H5_CFLAGS0 "${HDF5_SOURCE_DIR}/config/clang-warnings/no-developer-general")
endif ()
+ endif ()
- if (CMAKE_C_COMPILER_ID STREQUAL "GNU")
- # Append warning flags that only gcc 4.3+ knows about
- ADD_H5_FLAGS (H5_CFLAGS1 "${HDF5_SOURCE_DIR}/config/gnu-warnings/4.3")
- #
- # Technically, variable-length arrays are part of the C99 standard, but
- # we should approach them a bit cautiously... Only needed for gcc 4.X
- if (CMAKE_C_COMPILER_VERSION VERSION_LESS 5.0)
- ADD_H5_FLAGS (H5_CFLAGS1 "${HDF5_SOURCE_DIR}/config/gnu-warnings/4.2-4.last")
- endif ()
+ if (CMAKE_C_COMPILER_ID STREQUAL "GNU")
+ # Append warning flags that only gcc 4.3+ knows about
+ ADD_H5_FLAGS (H5_CFLAGS1 "${HDF5_SOURCE_DIR}/config/gnu-warnings/4.3")
+ #
+ # Technically, variable-length arrays are part of the C99 standard, but
+ # we should approach them a bit cautiously... Only needed for gcc 4.X
+ if (CMAKE_C_COMPILER_VERSION VERSION_LESS 5.0)
+ ADD_H5_FLAGS (H5_CFLAGS1 "${HDF5_SOURCE_DIR}/config/gnu-warnings/4.2-4.last")
+ endif ()
- # Append more extra warning flags that only gcc 4.4+ know about
- if (NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.4)
- ADD_H5_FLAGS (H5_CFLAGS1 "${HDF5_SOURCE_DIR}/config/gnu-warnings/4.4")
- endif ()
+ # Append more extra warning flags that only gcc 4.4+ know about
+ if (NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.4)
+ ADD_H5_FLAGS (H5_CFLAGS1 "${HDF5_SOURCE_DIR}/config/gnu-warnings/4.4")
endif ()
# Append more extra warning flags that only gcc 4.5+ know about
- if (CMAKE_C_COMPILER_ID STREQUAL "GNU" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.5)
+ if (NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.5)
ADD_H5_FLAGS (H5_CFLAGS1 "${HDF5_SOURCE_DIR}/config/gnu-warnings/4.5")
if (HDF5_ENABLE_DEV_WARNINGS)
ADD_H5_FLAGS (H5_CFLAGS1 "${HDF5_SOURCE_DIR}/config/gnu-warnings/developer-4.5")
@@ -175,17 +174,17 @@ if (NOT MSVC)
endif ()
# Append more extra warning flags that only gcc 4.6 and less know about
- if (CMAKE_C_COMPILER_ID STREQUAL "GNU" AND CMAKE_C_COMPILER_VERSION VERSION_LESS 4.7)
+ if (CMAKE_C_COMPILER_VERSION VERSION_LESS 4.7)
ADD_H5_FLAGS (H5_CFLAGS1 "${HDF5_SOURCE_DIR}/config/gnu-warnings/4.2-4.6")
endif ()
# Append more extra warning flags that only gcc 4.5-4.6 know about
- if (CMAKE_C_COMPILER_ID STREQUAL "GNU" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.5 AND CMAKE_C_COMPILER_VERSION VERSION_LESS 4.7)
+ if (NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.5 AND CMAKE_C_COMPILER_VERSION VERSION_LESS 4.7)
ADD_H5_FLAGS (H5_CFLAGS1 "${HDF5_SOURCE_DIR}/config/gnu-warnings/4.5-4.6")
endif ()
# Append more extra warning flags that only gcc 4.6+ know about
- if (CMAKE_C_COMPILER_ID STREQUAL "GNU" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.6)
+ if (NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.6)
ADD_H5_FLAGS (H5_CFLAGS1 "${HDF5_SOURCE_DIR}/config/gnu-warnings/4.6")
if (HDF5_ENABLE_DEV_WARNINGS)
ADD_H5_FLAGS (H5_CFLAGS1 "${HDF5_SOURCE_DIR}/config/gnu-warnings/developer-4.6")
@@ -195,7 +194,7 @@ if (NOT MSVC)
endif ()
# Append more extra warning flags that only gcc 4.7+ know about
- if (CMAKE_C_COMPILER_ID STREQUAL "GNU" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.7)
+ if (NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.7)
ADD_H5_FLAGS (H5_CFLAGS1 "${HDF5_SOURCE_DIR}/config/gnu-warnings/4.7")
if (HDF5_ENABLE_DEV_WARNINGS)
ADD_H5_FLAGS (H5_CFLAGS1 "${HDF5_SOURCE_DIR}/config/gnu-warnings/developer-4.7")
@@ -205,7 +204,7 @@ if (NOT MSVC)
endif ()
# Append more extra warning flags that only gcc 4.8+ know about
- if (CMAKE_C_COMPILER_ID STREQUAL "GNU" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.8)
+ if (NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.8)
ADD_H5_FLAGS (H5_CFLAGS1 "${HDF5_SOURCE_DIR}/config/gnu-warnings/4.8")
if (HDF5_ENABLE_DEV_WARNINGS)
ADD_H5_FLAGS (H5_CFLAGS1 "${HDF5_SOURCE_DIR}/config/gnu-warnings/developer-4.8")
@@ -215,23 +214,23 @@ if (NOT MSVC)
endif ()
# Append more extra warning flags that only gcc 4.9+ know about
- if (CMAKE_C_COMPILER_ID STREQUAL "GNU" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.9)
+ if (NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.9)
ADD_H5_FLAGS (H5_CFLAGS1 "${HDF5_SOURCE_DIR}/config/gnu-warnings/4.9")
endif ()
# Append more extra warning flags that only gcc 5.1+ know about
- if (CMAKE_C_COMPILER_ID STREQUAL "GNU" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 5.0)
+ if (NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 5.0)
ADD_H5_FLAGS (H5_CFLAGS1 "${HDF5_SOURCE_DIR}/config/gnu-warnings/5")
ADD_H5_FLAGS (H5_CFLAGS1 "${HDF5_SOURCE_DIR}/config/gnu-warnings/error-5")
endif ()
# Append more extra warning flags that only gcc 6.x+ know about
- if (CMAKE_C_COMPILER_ID STREQUAL "GNU" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 6.0)
+ if (NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 6.0)
ADD_H5_FLAGS (H5_CFLAGS1 "${HDF5_SOURCE_DIR}/config/gnu-warnings/6")
endif ()
# Append more extra warning flags that only gcc 7.x+ know about
- if (CMAKE_C_COMPILER_ID STREQUAL "GNU" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 7.0)
+ if (NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 7.0)
ADD_H5_FLAGS (H5_CFLAGS2 "${HDF5_SOURCE_DIR}/config/gnu-warnings/7")
if (HDF5_ENABLE_DEV_WARNINGS)
ADD_H5_FLAGS (H5_CFLAGS2 "${HDF5_SOURCE_DIR}/config/gnu-warnings/developer-7")
@@ -241,7 +240,7 @@ if (NOT MSVC)
endif ()
# Append more extra warning flags that only gcc 8.x+ know about
- if (CMAKE_C_COMPILER_ID STREQUAL "GNU" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 8.0)
+ if (NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 8.0)
ADD_H5_FLAGS (H5_CFLAGS3 "${HDF5_SOURCE_DIR}/config/gnu-warnings/8")
if (HDF5_ENABLE_DEV_WARNINGS)
ADD_H5_FLAGS (H5_CFLAGS3 "${HDF5_SOURCE_DIR}/config/gnu-warnings/developer-8")
@@ -251,9 +250,10 @@ if (NOT MSVC)
endif ()
# Append more extra warning flags that only gcc 9.x+ know about
- if (CMAKE_C_COMPILER_ID STREQUAL "GNU" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 9.0)
+ if (NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 9.0)
ADD_H5_FLAGS (H5_CFLAGS4 "${HDF5_SOURCE_DIR}/config/gnu-warnings/9")
endif ()
+ endif ()
endif ()
#-----------------------------------------------------------------------------
diff --git a/config/cmake/HDFFortranCompilerFlags.cmake b/config/cmake/HDFFortranCompilerFlags.cmake
index f31eba5..a56ef28 100644
--- a/config/cmake/HDFFortranCompilerFlags.cmake
+++ b/config/cmake/HDFFortranCompilerFlags.cmake
@@ -73,7 +73,12 @@ if (NOT MSVC)
list (APPEND HDF5_CMAKE_Fortran_FLAGS "-stand:f03" "-free")
elseif (CMAKE_Fortran_COMPILER_ID STREQUAL "GNU")
ADD_H5_FLAGS (HDF5_CMAKE_Fortran_FLAGS "${HDF5_SOURCE_DIR}/config/gnu-warnings/gfort-general")
- list (APPEND HDF5_CMAKE_Fortran_FLAGS "-ffree-form" "-std=f2008" "-fimplicit-none")
+ list (APPEND HDF5_CMAKE_Fortran_FLAGS "-ffree-form" "-fimplicit-none")
+ if (CMAKE_Fortran_COMPILER_VERSION VERSION_LESS 8.0 AND NOT CMAKE_Fortran_COMPILER_VERSION VERSION_LESS 4.6)
+ list (APPEND HDF5_CMAKE_Fortran_FLAGS "-std=f2008ts")
+ else ()
+ list (APPEND HDF5_CMAKE_Fortran_FLAGS "-std=f2008")
+ endif ()
elseif (CMAKE_Fortran_COMPILER_ID STREQUAL "PGI")
list (APPEND HDF5_CMAKE_Fortran_FLAGS "-Mfreeform" "-Mdclchk" "-Mstandard" "-Mallocatable=03")
endif ()
@@ -82,57 +87,57 @@ if (NOT MSVC)
if (CMAKE_Fortran_COMPILER_ID STREQUAL "GNU")
# Append warning flags that only gcc 4.4+ knows about
ADD_H5_FLAGS (HDF5_CMAKE_Fortran_FLAGS "${HDF5_SOURCE_DIR}/config/gnu-warnings/gfort-4.4")
- endif ()
- # Append more extra warning flags that only gcc 4.5+ know about
- if (CMAKE_Fortran_COMPILER_ID STREQUAL "GNU" AND NOT CMAKE_Fortran_COMPILER_VERSION VERSION_LESS 4.5)
- ADD_H5_FLAGS (HDF5_CMAKE_Fortran_FLAGS "${HDF5_SOURCE_DIR}/config/gnu-warnings/gfort-4.5")
- endif ()
+ # Append more extra warning flags that only gcc 4.5+ know about
+ if (NOT CMAKE_Fortran_COMPILER_VERSION VERSION_LESS 4.5)
+ ADD_H5_FLAGS (HDF5_CMAKE_Fortran_FLAGS "${HDF5_SOURCE_DIR}/config/gnu-warnings/gfort-4.5")
+ endif ()
- # Append more extra warning flags that only gcc 4.6+ know about
- #if (CMAKE_Fortran_COMPILER_ID STREQUAL "GNU" AND NOT CMAKE_Fortran_COMPILER_VERSION VERSION_LESS 4.6)
- # ADD_H5_FLAGS (HDF5_CMAKE_Fortran_FLAGS "${HDF5_SOURCE_DIR}/config/gnu-warnings/gfort-4.6")
- #endif ()
+ # Append more extra warning flags that only gcc 4.6+ know about
+ #if (NOT CMAKE_Fortran_COMPILER_VERSION VERSION_LESS 4.6)
+ # ADD_H5_FLAGS (HDF5_CMAKE_Fortran_FLAGS "${HDF5_SOURCE_DIR}/config/gnu-warnings/gfort-4.6")
+ #endif ()
- # Append more extra warning flags that only gcc 4.7+ know about
- if (CMAKE_Fortran_COMPILER_ID STREQUAL "GNU" AND NOT CMAKE_Fortran_COMPILER_VERSION VERSION_LESS 4.7)
- ADD_H5_FLAGS (HDF5_CMAKE_Fortran_FLAGS "${HDF5_SOURCE_DIR}/config/gnu-warnings/gfort-4.7")
- endif ()
+ # Append more extra warning flags that only gcc 4.7+ know about
+ if (NOT CMAKE_Fortran_COMPILER_VERSION VERSION_LESS 4.7)
+ ADD_H5_FLAGS (HDF5_CMAKE_Fortran_FLAGS "${HDF5_SOURCE_DIR}/config/gnu-warnings/gfort-4.7")
+ endif ()
- # Append more extra warning flags that only gcc 4.8+ know about
- if (CMAKE_Fortran_COMPILER_ID STREQUAL "GNU" AND NOT CMAKE_Fortran_COMPILER_VERSION VERSION_LESS 4.8)
- ADD_H5_FLAGS (HDF5_CMAKE_Fortran_FLAGS "${HDF5_SOURCE_DIR}/config/gnu-warnings/gfort-4.8")
- endif ()
+ # Append more extra warning flags that only gcc 4.8+ know about
+ if (NOT CMAKE_Fortran_COMPILER_VERSION VERSION_LESS 4.8)
+ ADD_H5_FLAGS (HDF5_CMAKE_Fortran_FLAGS "${HDF5_SOURCE_DIR}/config/gnu-warnings/gfort-4.8")
+ endif ()
- # Append more extra warning flags that only gcc 4.9+ know about
- #if (CMAKE_Fortran_COMPILER_ID STREQUAL "GNU" AND NOT CMAKE_Fortran_COMPILER_VERSION VERSION_LESS 4.9)
- # ADD_H5_FLAGS (HDF5_CMAKE_Fortran_FLAGS "${HDF5_SOURCE_DIR}/config/gnu-warnings/gfort-4.9")
- #endif ()
+ # Append more extra warning flags that only gcc 4.9+ know about
+ #if (NOT CMAKE_Fortran_COMPILER_VERSION VERSION_LESS 4.9)
+ # ADD_H5_FLAGS (HDF5_CMAKE_Fortran_FLAGS "${HDF5_SOURCE_DIR}/config/gnu-warnings/gfort-4.9")
+ #endif ()
- # Append more extra warning flags that only gcc 5.1+ know about
- if (CMAKE_Fortran_COMPILER_ID STREQUAL "GNU" AND NOT CMAKE_Fortran_COMPILER_VERSION VERSION_LESS 5.0)
- ADD_H5_FLAGS (HDF5_CMAKE_Fortran_FLAGS "${HDF5_SOURCE_DIR}/config/gnu-warnings/gfort-5")
- endif ()
+ # Append more extra warning flags that only gcc 5.1+ know about
+ if (NOT CMAKE_Fortran_COMPILER_VERSION VERSION_LESS 5.0)
+ ADD_H5_FLAGS (HDF5_CMAKE_Fortran_FLAGS "${HDF5_SOURCE_DIR}/config/gnu-warnings/gfort-5")
+ endif ()
- # Append more extra warning flags that only gcc 6.x+ know about
- if (CMAKE_Fortran_COMPILER_ID STREQUAL "GNU" AND NOT CMAKE_Fortran_COMPILER_VERSION VERSION_LESS 6.0)
- ADD_H5_FLAGS (HDF5_CMAKE_Fortran_FLAGS "${HDF5_SOURCE_DIR}/config/gnu-warnings/gfort-6")
- endif ()
+ # Append more extra warning flags that only gcc 6.x+ know about
+ if (NOT CMAKE_Fortran_COMPILER_VERSION VERSION_LESS 6.0)
+ ADD_H5_FLAGS (HDF5_CMAKE_Fortran_FLAGS "${HDF5_SOURCE_DIR}/config/gnu-warnings/gfort-6")
+ endif ()
- # Append more extra warning flags that only gcc 7.x+ know about
- #if (CMAKE_Fortran_COMPILER_ID STREQUAL "GNU" AND NOT CMAKE_Fortran_COMPILER_VERSION VERSION_LESS 7.0)
- # ADD_H5_FLAGS (HDF5_CMAKE_Fortran_FLAGS "${HDF5_SOURCE_DIR}/config/gnu-warnings/gfort-7")
- #endif ()
+ # Append more extra warning flags that only gcc 7.x+ know about
+ #if (NOT CMAKE_Fortran_COMPILER_VERSION VERSION_LESS 7.0)
+ # ADD_H5_FLAGS (HDF5_CMAKE_Fortran_FLAGS "${HDF5_SOURCE_DIR}/config/gnu-warnings/gfort-7")
+ #endif ()
- # Append more extra warning flags that only gcc 8.x+ know about
- if (CMAKE_Fortran_COMPILER_ID STREQUAL "GNU" AND NOT CMAKE_Fortran_COMPILER_VERSION VERSION_LESS 8.0)
- ADD_H5_FLAGS (HDF5_CMAKE_Fortran_FLAGS "${HDF5_SOURCE_DIR}/config/gnu-warnings/gfort-8")
- endif ()
+ # Append more extra warning flags that only gcc 8.x+ know about
+ if (NOT CMAKE_Fortran_COMPILER_VERSION VERSION_LESS 8.0)
+ ADD_H5_FLAGS (HDF5_CMAKE_Fortran_FLAGS "${HDF5_SOURCE_DIR}/config/gnu-warnings/gfort-8")
+ endif ()
- # Append more extra warning flags that only gcc 9.x+ know about
- #if (CMAKE_Fortran_COMPILER_ID STREQUAL "GNU" AND NOT CMAKE_Fortran_COMPILER_VERSION VERSION_LESS 9.0)
- # ADD_H5_FLAGS (HDF5_CMAKE_Fortran_FLAGS "${HDF5_SOURCE_DIR}/config/gnu-warnings/gfort-9")
- #endif ()
+ # Append more extra warning flags that only gcc 9.x+ know about
+ #if (NOT CMAKE_Fortran_COMPILER_VERSION VERSION_LESS 9.0)
+ # ADD_H5_FLAGS (HDF5_CMAKE_Fortran_FLAGS "${HDF5_SOURCE_DIR}/config/gnu-warnings/gfort-9")
+ #endif ()
+ endif ()
else ()
if (CMAKE_Fortran_COMPILER_ID STREQUAL "Intel")
#ADD_H5_FLAGS (HDF5_CMAKE_Fortran_FLAGS "${HDF5_SOURCE_DIR}/config/intel-warnings/win-ifort-general")
diff --git a/config/cmake/libhdf5.settings.cmake.in b/config/cmake/libhdf5.settings.cmake.in
index e9a8395..b745765 100644
--- a/config/cmake/libhdf5.settings.cmake.in
+++ b/config/cmake/libhdf5.settings.cmake.in
@@ -76,6 +76,7 @@ Parallel Filtered Dataset Writes: @PARALLEL_FILTERED_WRITES@
I/O filters (external): @EXTERNAL_FILTERS@
MPE: @H5_HAVE_LIBLMPE@
Direct VFD: @H5_HAVE_DIRECT@
+ Mirror VFD: @H5_HAVE_MIRROR_VFD@
(Read-Only) S3 VFD: @H5_HAVE_ROS3_VFD@
(Read-Only) HDFS VFD: @H5_HAVE_LIBHDFS@
dmalloc: @H5_HAVE_LIBDMALLOC@
diff --git a/config/cmake_ext_mod/ConfigureChecks.cmake b/config/cmake_ext_mod/ConfigureChecks.cmake
index 93b977e..0875aad 100644
--- a/config/cmake_ext_mod/ConfigureChecks.cmake
+++ b/config/cmake_ext_mod/ConfigureChecks.cmake
@@ -166,6 +166,8 @@ CHECK_INCLUDE_FILE_CONCAT ("memory.h" ${HDF_PREFIX}_HAVE_MEMORY_H)
CHECK_INCLUDE_FILE_CONCAT ("dlfcn.h" ${HDF_PREFIX}_HAVE_DLFCN_H)
CHECK_INCLUDE_FILE_CONCAT ("inttypes.h" ${HDF_PREFIX}_HAVE_INTTYPES_H)
CHECK_INCLUDE_FILE_CONCAT ("netinet/in.h" ${HDF_PREFIX}_HAVE_NETINET_IN_H)
+CHECK_INCLUDE_FILE_CONCAT ("netdb.h" ${HDF_PREFIX}_HAVE_NETDB_H)
+CHECK_INCLUDE_FILE_CONCAT ("arpa/inet.h" ${HDF_PREFIX}_HAVE_ARPA_INET_H)
# _Bool type support
CHECK_INCLUDE_FILE_CONCAT (stdbool.h ${HDF_PREFIX}_HAVE_STDBOOL_H)
@@ -681,3 +683,4 @@ endif ()
# the cache value is set in it's config file)
#
set (${HDF_PREFIX}_CONVERT_DENORMAL_FLOAT 1)
+
diff --git a/config/gnu-cxxflags b/config/gnu-cxxflags
index 73f49ba..e177aef 100644
--- a/config/gnu-cxxflags
+++ b/config/gnu-cxxflags
@@ -119,7 +119,7 @@ if test "X-g++" = "X-$cxx_vendor"; then
esac
# C++-specific
- H5_CXXFLAGS="$H5_CXXFLAGS $arch
+ H5_CXXFLAGS="$H5_CXXFLAGS $arch"
##############
# Production #
@@ -238,34 +238,35 @@ if test "X-g++" = "X-$cxx_vendor"; then
# gcc >= 4.5
if test $cc_vers_major -ge 5 -o $cc_vers_major -eq 4 -a $cc_vers_minor -ge 5; then
H5_CXXFLAGS="$H5_CXXFLAGS $(load_gnu_arguments 4.5)"
- DEVELOPER_WARNING_CXXFLAGS="$DEVELOPER_WARNING_CXXFLAGS $(load_gcc_arguments developer-4.5)"
- NO_DEVELOPER_WARNING_CXXFLAGS="$NO_DEVELOPER_WARNING_CXXFLAGS $(load_gcc_arguments no-developer-4.5)"
+ DEVELOPER_WARNING_CXXFLAGS="$DEVELOPER_WARNING_CXXFLAGS $(load_gnu_arguments developer-4.5)"
+ NO_DEVELOPER_WARNING_CXXFLAGS="$NO_DEVELOPER_WARNING_CXXFLAGS $(load_gnu_arguments no-developer-4.5)"
fi
# gcc >= 4.6
if test $cc_vers_major -ge 5 -o $cc_vers_major -eq 4 -a $cc_vers_minor -ge 6; then
H5_CXXFLAGS="$H5_CXXFLAGS $(load_gnu_arguments 4.6)"
- DEVELOPER_WARNING_CXXFLAGS="$DEVELOPER_WARNING_CXXFLAGS $(load_gcc_arguments developer-4.6)"
- NO_DEVELOPER_WARNING_CXXFLAGS="$NO_DEVELOPER_WARNING_CXXFLAGS $(load_gcc_arguments no-developer-4.6)"
+ DEVELOPER_WARNING_CXXFLAGS="$DEVELOPER_WARNING_CXXFLAGS $(load_gnu_arguments developer-4.6)"
+ NO_DEVELOPER_WARNING_CXXFLAGS="$NO_DEVELOPER_WARNING_CXXFLAGS $(load_gnu_arguments no-developer-4.6)"
fi
# gcc >= 4.7
if test $cc_vers_major -ge 5 -o $cc_vers_major -eq 4 -a $cc_vers_minor -ge 7; then
H5_CXXFLAGS="$H5_CXXFLAGS $(load_gnu_arguments 4.7)"
- DEVELOPER_WARNING_CXXFLAGS="$DEVELOPER_WARNING_CXXFLAGS $(load_gcc_arguments developer-4.7)"
- NO_DEVELOPER_WARNING_CXXFLAGS="$NO_DEVELOPER_WARNING_CXXFLAGS $(load_gcc_arguments no-developer-4.7)"
+ DEVELOPER_WARNING_CXXFLAGS="$DEVELOPER_WARNING_CXXFLAGS $(load_gnu_arguments developer-4.7)"
+ NO_DEVELOPER_WARNING_CXXFLAGS="$NO_DEVELOPER_WARNING_CXXFLAGS $(load_gnu_arguments no-developer-4.7)"
fi
# gcc >= 4.8
if test $cc_vers_major -ge 5 -o $cc_vers_major -eq 4 -a $cc_vers_minor -ge 8; then
H5_CXXFLAGS="$H5_CXXFLAGS $(load_gnu_arguments 4.8)"
- DEVELOPER_WARNING_CXXFLAGS="$DEVELOPER_WARNING_CXXFLAGS $(load_gcc_arguments developer-4.8)"
- NO_DEVELOPER_WARNING_CXXFLAGS="$NO_DEVELOPER_WARNING_CXXFLAGS $(load_gcc_arguments no-developer-4.8)"
+ DEVELOPER_WARNING_CXXFLAGS="$DEVELOPER_WARNING_CXXFLAGS $(load_gnu_arguments developer-4.8)"
+ NO_DEVELOPER_WARNING_CXXFLAGS="$NO_DEVELOPER_WARNING_CXXFLAGS $(load_gnu_arguments no-developer-4.8)"
fi
# gcc >= 4.9
if test $cc_vers_major -ge 5 -o $cc_vers_major -eq 4 -a $cc_vers_minor -ge 9; then
H5_CXXFLAGS="$H5_CXXFLAGS $(load_gnu_arguments 4.9)"
+ H5_CXXFLAGS="$H5_CXXFLAGS $(load_gnu_arguments cxx-4.9)"
fi
# gcc >= 5
@@ -282,15 +283,15 @@ if test "X-g++" = "X-$cxx_vendor"; then
# gcc >= 7
if test $cc_vers_major -ge 7; then
H5_CXXFLAGS="$H5_CXXFLAGS $(load_gnu_arguments 7)"
- DEVELOPER_WARNING_CXXFLAGS="$DEVELOPER_WARNING_CXXFLAGS $(load_gcc_arguments developer-7)"
+ DEVELOPER_WARNING_CXXFLAGS="$DEVELOPER_WARNING_CXXFLAGS $(load_gnu_arguments developer-7)"
fi
# gcc 8
if test $cc_vers_major -ge 8; then
H5_CXXFLAGS="$H5_CXXFLAGS $(load_gnu_arguments 8)"
H5_ECXXFLAGS="$H5_ECXXFLAGS $(load_gnu_arguments error-8)"
- DEVELOPER_WARNING_CXXFLAGS="$DEVELOPER_WARNING_CXXFLAGS $(load_gcc_arguments developer-8)"
- NO_DEVELOPER_WARNING_CXXFLAGS="$NO_DEVELOPER_WARNING_CXXFLAGS $(load_gcc_arguments no-developer-8)"
+ DEVELOPER_WARNING_CXXFLAGS="$DEVELOPER_WARNING_CXXFLAGS $(load_gnu_arguments developer-8)"
+ NO_DEVELOPER_WARNING_CXXFLAGS="$NO_DEVELOPER_WARNING_CXXFLAGS $(load_gnu_arguments no-developer-8)"
fi
# gcc 9
@@ -304,13 +305,6 @@ if test "X-g++" = "X-$cxx_vendor"; then
cxx_flags_set=yes
fi
-# Version-specific g++ flags
-
-# This flag was left behind when moving warnings flags to common files for
-# both autotools and CMake.
-# # Append more extra warning flags that only gcc 4.9+ know about
-# -Wopenmp-simd"
-
# Clear cxx info if no flags set
if test "X$cxx_flags_set" = "X"; then
cxx_vendor=
diff --git a/config/gnu-warnings/cxx-4.9 b/config/gnu-warnings/cxx-4.9
new file mode 100644
index 0000000..046d6db
--- /dev/null
+++ b/config/gnu-warnings/cxx-4.9
@@ -0,0 +1 @@
+-Wopenmp-simd
diff --git a/configure.ac b/configure.ac
index 5851b32..81e985e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1090,6 +1090,7 @@ AC_CHECK_HEADERS([stddef.h setjmp.h features.h])
AC_CHECK_HEADERS([dirent.h])
AC_CHECK_HEADERS([stdint.h], [C9x=yes])
AC_CHECK_HEADERS([stdbool.h])
+AC_CHECK_HEADERS([netdb.h netinet/in.h arpa/inet.h])
## Darwin
AC_CHECK_HEADERS([mach/mach_time.h])
@@ -2842,6 +2843,50 @@ fi
AM_CONDITIONAL([DIRECT_VFD_CONDITIONAL], [test "X$DIRECT_VFD" = "Xyes"])
## ----------------------------------------------------------------------
+## Check whether the Mirror VFD can be built.
+## Auto-enabled if the required libraries are present.
+##
+AC_SUBST([MIRROR_VFD])
+
+## Default is no Mirror VFD
+MIRROR_VFD=no
+
+AC_ARG_ENABLE([mirror-vfd],
+ [AS_HELP_STRING([--enable-mirror-vfd],
+ [Build the socket-based Mirror virtual file driver (VFD).
+ [default=no]])],
+ [MIRROR_VFD=$enableval], [MIRROR_VFD=no])
+
+if test "X$MIRROR_VFD" = "Xyes"; then
+
+ AC_CHECK_HEADERS([arpa/inet.h],, [unset MIRROR_VFD])
+ AC_CHECK_HEADERS([netinet/in.h],, [unset MIRROR_VFD])
+ AC_CHECK_HEADERS([netdb.h],, [unset MIRROR_VFD])
+ AC_CHECK_HEADERS([sys/socket.h],, [unset MIRROR_VFD])
+ AC_CHECK_FUNC([fork], [], [unset MIRROR_VFD])
+
+ AC_MSG_CHECKING([if the Mirror virtual file driver (VFD) can be built])
+ if test "X$MIRROR_VFD" = "Xyes"; then
+ AC_DEFINE([HAVE_MIRROR_VFD], [1],
+ [Define whether the Mirror virtual file driver (VFD) will be compiled])
+ AC_MSG_RESULT([yes])
+ else
+ AC_MSG_RESULT([no])
+ MIRROR_VFD=no
+ AC_MSG_ERROR([The Mirror VFD cannot be built.
+ Missing one or more of: arpa/inet.h, netinet/in.h,
+ netdb.h, sys/socket.h, fork().])
+ fi
+else
+ AC_MSG_CHECKING([if the Mirror virtual file driver (VFD) is enabled])
+ AC_MSG_RESULT([no])
+ MIRROR_VFD=no
+fi
+
+## Mirror VFD files built only if able.
+AM_CONDITIONAL([MIRROR_VFD_CONDITIONAL], [test "X$MIRROR_VFD" = "Xyes"])
+
+## ----------------------------------------------------------------------
## Check if Read-Only S3 virtual file driver is enabled by --enable-ros3-vfd
##
AC_SUBST([ROS3_VFD])
@@ -3720,10 +3765,13 @@ AC_CONFIG_FILES([src/libhdf5.settings
test/testvds_env.sh
test/testvdsswmr.sh
test/test_filter_plugin.sh
+ test/test_mirror.sh
test/test_usecases.sh
test/test_vol_plugin.sh
testpar/Makefile
testpar/testpflush.sh
+ utils/Makefile
+ utils/mirror_vfd/Makefile
tools/Makefile
tools/lib/Makefile
tools/libtest/Makefile
diff --git a/hl/c++/test/ptableTest.cpp b/hl/c++/test/ptableTest.cpp
index e873503..fd85828 100644
--- a/hl/c++/test/ptableTest.cpp
+++ b/hl/c++/test/ptableTest.cpp
@@ -142,7 +142,7 @@ int TestCompoundDatatype()
HDfflush(stdout);
/* Create compound datatype */
- typedef struct compoundType
+ typedef struct
{
short a, b, c;
int e;
@@ -479,7 +479,7 @@ int SystemTest()
/* Creating two inter-related datatypes. Create two datasets and put
* one datatype in each. */
- typedef struct compoundType
+ typedef struct
{
short a, b, c;
int e;
@@ -492,7 +492,7 @@ int SystemTest()
H5Tinsert(dtypeID1, "charlie", HOFFSET( compoundType, c ), H5T_NATIVE_SHORT);
H5Tinsert(dtypeID1, "ebert", HOFFSET( compoundType, e ), H5T_NATIVE_INT);
- typedef struct cType2
+ typedef struct
{
char f;
compoundType g;
diff --git a/hl/src/H5LTanalyze.c b/hl/src/H5LTanalyze.c
index 4094cd8..7288498 100644
--- a/hl/src/H5LTanalyze.c
+++ b/hl/src/H5LTanalyze.c
@@ -30,17 +30,11 @@
#define yy_create_buffer H5LTyy_create_buffer
#define yy_delete_buffer H5LTyy_delete_buffer
-#define yy_scan_buffer H5LTyy_scan_buffer
-#define yy_scan_string H5LTyy_scan_string
-#define yy_scan_bytes H5LTyy_scan_bytes
+#define yy_flex_debug H5LTyy_flex_debug
#define yy_init_buffer H5LTyy_init_buffer
#define yy_flush_buffer H5LTyy_flush_buffer
#define yy_load_buffer_state H5LTyy_load_buffer_state
#define yy_switch_to_buffer H5LTyy_switch_to_buffer
-#define yypush_buffer_state H5LTyypush_buffer_state
-#define yypop_buffer_state H5LTyypop_buffer_state
-#define yyensure_buffer_stack H5LTyyensure_buffer_stack
-#define yy_flex_debug H5LTyy_flex_debug
#define yyin H5LTyyin
#define yyleng H5LTyyleng
#define yylex H5LTyylex
@@ -55,246 +49,12 @@
#define FLEX_SCANNER
#define YY_FLEX_MAJOR_VERSION 2
-#define YY_FLEX_MINOR_VERSION 6
-#define YY_FLEX_SUBMINOR_VERSION 4
+#define YY_FLEX_MINOR_VERSION 5
+#define YY_FLEX_SUBMINOR_VERSION 37
#if YY_FLEX_SUBMINOR_VERSION > 0
#define FLEX_BETA
#endif
-#ifdef yy_create_buffer
-#define H5LTyy_create_buffer_ALREADY_DEFINED
-#else
-#define yy_create_buffer H5LTyy_create_buffer
-#endif
-
-#ifdef yy_delete_buffer
-#define H5LTyy_delete_buffer_ALREADY_DEFINED
-#else
-#define yy_delete_buffer H5LTyy_delete_buffer
-#endif
-
-#ifdef yy_scan_buffer
-#define H5LTyy_scan_buffer_ALREADY_DEFINED
-#else
-#define yy_scan_buffer H5LTyy_scan_buffer
-#endif
-
-#ifdef yy_scan_string
-#define H5LTyy_scan_string_ALREADY_DEFINED
-#else
-#define yy_scan_string H5LTyy_scan_string
-#endif
-
-#ifdef yy_scan_bytes
-#define H5LTyy_scan_bytes_ALREADY_DEFINED
-#else
-#define yy_scan_bytes H5LTyy_scan_bytes
-#endif
-
-#ifdef yy_init_buffer
-#define H5LTyy_init_buffer_ALREADY_DEFINED
-#else
-#define yy_init_buffer H5LTyy_init_buffer
-#endif
-
-#ifdef yy_flush_buffer
-#define H5LTyy_flush_buffer_ALREADY_DEFINED
-#else
-#define yy_flush_buffer H5LTyy_flush_buffer
-#endif
-
-#ifdef yy_load_buffer_state
-#define H5LTyy_load_buffer_state_ALREADY_DEFINED
-#else
-#define yy_load_buffer_state H5LTyy_load_buffer_state
-#endif
-
-#ifdef yy_switch_to_buffer
-#define H5LTyy_switch_to_buffer_ALREADY_DEFINED
-#else
-#define yy_switch_to_buffer H5LTyy_switch_to_buffer
-#endif
-
-#ifdef yypush_buffer_state
-#define H5LTyypush_buffer_state_ALREADY_DEFINED
-#else
-#define yypush_buffer_state H5LTyypush_buffer_state
-#endif
-
-#ifdef yypop_buffer_state
-#define H5LTyypop_buffer_state_ALREADY_DEFINED
-#else
-#define yypop_buffer_state H5LTyypop_buffer_state
-#endif
-
-#ifdef yyensure_buffer_stack
-#define H5LTyyensure_buffer_stack_ALREADY_DEFINED
-#else
-#define yyensure_buffer_stack H5LTyyensure_buffer_stack
-#endif
-
-#ifdef yylex
-#define H5LTyylex_ALREADY_DEFINED
-#else
-#define yylex H5LTyylex
-#endif
-
-#ifdef yyrestart
-#define H5LTyyrestart_ALREADY_DEFINED
-#else
-#define yyrestart H5LTyyrestart
-#endif
-
-#ifdef yylex_init
-#define H5LTyylex_init_ALREADY_DEFINED
-#else
-#define yylex_init H5LTyylex_init
-#endif
-
-#ifdef yylex_init_extra
-#define H5LTyylex_init_extra_ALREADY_DEFINED
-#else
-#define yylex_init_extra H5LTyylex_init_extra
-#endif
-
-#ifdef yylex_destroy
-#define H5LTyylex_destroy_ALREADY_DEFINED
-#else
-#define yylex_destroy H5LTyylex_destroy
-#endif
-
-#ifdef yyget_debug
-#define H5LTyyget_debug_ALREADY_DEFINED
-#else
-#define yyget_debug H5LTyyget_debug
-#endif
-
-#ifdef yyset_debug
-#define H5LTyyset_debug_ALREADY_DEFINED
-#else
-#define yyset_debug H5LTyyset_debug
-#endif
-
-#ifdef yyget_extra
-#define H5LTyyget_extra_ALREADY_DEFINED
-#else
-#define yyget_extra H5LTyyget_extra
-#endif
-
-#ifdef yyset_extra
-#define H5LTyyset_extra_ALREADY_DEFINED
-#else
-#define yyset_extra H5LTyyset_extra
-#endif
-
-#ifdef yyget_in
-#define H5LTyyget_in_ALREADY_DEFINED
-#else
-#define yyget_in H5LTyyget_in
-#endif
-
-#ifdef yyset_in
-#define H5LTyyset_in_ALREADY_DEFINED
-#else
-#define yyset_in H5LTyyset_in
-#endif
-
-#ifdef yyget_out
-#define H5LTyyget_out_ALREADY_DEFINED
-#else
-#define yyget_out H5LTyyget_out
-#endif
-
-#ifdef yyset_out
-#define H5LTyyset_out_ALREADY_DEFINED
-#else
-#define yyset_out H5LTyyset_out
-#endif
-
-#ifdef yyget_leng
-#define H5LTyyget_leng_ALREADY_DEFINED
-#else
-#define yyget_leng H5LTyyget_leng
-#endif
-
-#ifdef yyget_text
-#define H5LTyyget_text_ALREADY_DEFINED
-#else
-#define yyget_text H5LTyyget_text
-#endif
-
-#ifdef yyget_lineno
-#define H5LTyyget_lineno_ALREADY_DEFINED
-#else
-#define yyget_lineno H5LTyyget_lineno
-#endif
-
-#ifdef yyset_lineno
-#define H5LTyyset_lineno_ALREADY_DEFINED
-#else
-#define yyset_lineno H5LTyyset_lineno
-#endif
-
-#ifdef yywrap
-#define H5LTyywrap_ALREADY_DEFINED
-#else
-#define yywrap H5LTyywrap
-#endif
-
-#ifdef yyalloc
-#define H5LTyyalloc_ALREADY_DEFINED
-#else
-#define yyalloc H5LTyyalloc
-#endif
-
-#ifdef yyrealloc
-#define H5LTyyrealloc_ALREADY_DEFINED
-#else
-#define yyrealloc H5LTyyrealloc
-#endif
-
-#ifdef yyfree
-#define H5LTyyfree_ALREADY_DEFINED
-#else
-#define yyfree H5LTyyfree
-#endif
-
-#ifdef yytext
-#define H5LTyytext_ALREADY_DEFINED
-#else
-#define yytext H5LTyytext
-#endif
-
-#ifdef yyleng
-#define H5LTyyleng_ALREADY_DEFINED
-#else
-#define yyleng H5LTyyleng
-#endif
-
-#ifdef yyin
-#define H5LTyyin_ALREADY_DEFINED
-#else
-#define yyin H5LTyyin
-#endif
-
-#ifdef yyout
-#define H5LTyyout_ALREADY_DEFINED
-#else
-#define yyout H5LTyyout
-#endif
-
-#ifdef yy_flex_debug
-#define H5LTyy_flex_debug_ALREADY_DEFINED
-#else
-#define yy_flex_debug H5LTyy_flex_debug
-#endif
-
-#ifdef yylineno
-#define H5LTyylineno_ALREADY_DEFINED
-#else
-#define yylineno H5LTyylineno
-#endif
-
/* First, we deal with platform-specific or compiler-specific issues. */
/* begin standard C headers. */
@@ -365,61 +125,65 @@ typedef unsigned int flex_uint32_t;
#define UINT32_MAX (4294967295U)
#endif
-#ifndef SIZE_MAX
-#define SIZE_MAX (~(size_t)0)
-#endif
-
#endif /* ! C99 */
#endif /* ! FLEXINT_H */
-/* begin standard C++ headers. */
+#ifdef __cplusplus
-/* TODO: this is always defined, so inline it */
-#define yyconst const
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else /* ! __cplusplus */
+
+/* C99 requires __STDC__ to be defined as 1. */
+#if defined (__STDC__)
+
+#define YY_USE_CONST
-#if defined(__GNUC__) && __GNUC__ >= 3
-#define yynoreturn __attribute__((__noreturn__))
+#endif /* defined (__STDC__) */
+#endif /* ! __cplusplus */
+
+#ifdef YY_USE_CONST
+#define yyconst const
#else
-#define yynoreturn
+#define yyconst
#endif
/* Returned upon end-of-file. */
#define YY_NULL 0
-/* Promotes a possibly negative, possibly signed char to an
- * integer in range [0..255] for use as an array index.
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index. If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
*/
-#define YY_SC_TO_UI(c) ((YY_CHAR) (c))
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
/* Enter a start condition. This macro really ought to take a parameter,
* but we do it the disgusting crufty way forced on us by the ()-less
* definition of BEGIN.
*/
#define BEGIN (yy_start) = 1 + 2 *
+
/* Translate the current start state into a value that can be later handed
* to BEGIN to return to the state. The YYSTATE alias is for lex
* compatibility.
*/
#define YY_START (((yy_start) - 1) / 2)
#define YYSTATE YY_START
+
/* Action number for EOF rule of a given start state. */
#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
/* Special action meaning "start processing a new file". */
-#define YY_NEW_FILE yyrestart( yyin )
+#define YY_NEW_FILE H5LTyyrestart(H5LTyyin )
+
#define YY_END_OF_BUFFER_CHAR 0
/* Size of default input buffer. */
#ifndef YY_BUF_SIZE
-#ifdef __ia64__
-/* On IA-64, the buffer size is 16k, not 8k.
- * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case.
- * Ditto for the __ia64__ case accordingly.
- */
-#define YY_BUF_SIZE 32768
-#else
#define YY_BUF_SIZE 16384
-#endif /* __ia64__ */
#endif
/* The state buf must be large enough to hold one state per character in the main buffer.
@@ -436,30 +200,30 @@ typedef struct yy_buffer_state *YY_BUFFER_STATE;
typedef size_t yy_size_t;
#endif
-extern int yyleng;
+extern yy_size_t H5LTyyleng;
-extern FILE *yyin, *yyout;
+extern FILE *H5LTyyin, *H5LTyyout;
#define EOB_ACT_CONTINUE_SCAN 0
#define EOB_ACT_END_OF_FILE 1
#define EOB_ACT_LAST_MATCH 2
-
+
#define YY_LESS_LINENO(n)
- #define YY_LINENO_REWIND_TO(ptr)
/* Return all but the first "n" matched characters back to the input stream. */
#define yyless(n) \
do \
{ \
- /* Undo effects of setting up yytext. */ \
+ /* Undo effects of setting up H5LTyytext. */ \
int yyless_macro_arg = (n); \
YY_LESS_LINENO(yyless_macro_arg);\
*yy_cp = (yy_hold_char); \
YY_RESTORE_YY_MORE_OFFSET \
(yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
- YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+ YY_DO_BEFORE_ACTION; /* set up H5LTyytext again */ \
} \
while ( 0 )
+
#define unput(c) yyunput( c, (yytext_ptr) )
#ifndef YY_STRUCT_YY_BUFFER_STATE
@@ -474,12 +238,12 @@ struct yy_buffer_state
/* Size of input buffer in bytes, not including room for EOB
* characters.
*/
- int yy_buf_size;
+ yy_size_t yy_buf_size;
/* Number of characters read into yy_ch_buf, not including EOB
* characters.
*/
- int yy_n_chars;
+ yy_size_t yy_n_chars;
/* Whether we "own" the buffer - i.e., we know we created it,
* and can realloc() it to grow it, and should free() it to
@@ -502,7 +266,7 @@ struct yy_buffer_state
int yy_bs_lineno; /**< The line count. */
int yy_bs_column; /**< The column count. */
-
+
/* Whether to try to fill the input buffer when we reach the
* end of it.
*/
@@ -519,8 +283,8 @@ struct yy_buffer_state
* possible backing-up.
*
* When we actually see the EOF, we change the status to "new"
- * (via yyrestart()), so that the user can continue scanning by
- * just pointing yyin at a new input file.
+ * (via H5LTyyrestart()), so that the user can continue scanning by
+ * just pointing H5LTyyin at a new input file.
*/
#define YY_BUFFER_EOF_PENDING 2
@@ -530,7 +294,7 @@ struct yy_buffer_state
/* Stack of input buffers. */
static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */
static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */
-static YY_BUFFER_STATE * yy_buffer_stack = NULL; /**< Stack as an array. */
+static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */
/* We provide macros for accessing buffer states in case in the
* future we want to put the buffer states in a more general
@@ -541,98 +305,103 @@ static YY_BUFFER_STATE * yy_buffer_stack = NULL; /**< Stack as an array. */
#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \
? (yy_buffer_stack)[(yy_buffer_stack_top)] \
: NULL)
+
/* Same as previous macro, but useful when we know that the buffer stack is not
* NULL or when we need an lvalue. For internal use only.
*/
#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)]
-/* yy_hold_char holds the character lost when yytext is formed. */
+/* yy_hold_char holds the character lost when H5LTyytext is formed. */
static char yy_hold_char;
-static int yy_n_chars; /* number of characters read into yy_ch_buf */
-int yyleng;
+static yy_size_t yy_n_chars; /* number of characters read into yy_ch_buf */
+yy_size_t H5LTyyleng;
/* Points to current character in buffer. */
-static char *yy_c_buf_p = NULL;
+static char *yy_c_buf_p = (char *) 0;
static int yy_init = 0; /* whether we need to initialize */
static int yy_start = 0; /* start state number */
-/* Flag which is used to allow yywrap()'s to do buffer switches
- * instead of setting up a fresh yyin. A bit of a hack ...
+/* Flag which is used to allow H5LTyywrap()'s to do buffer switches
+ * instead of setting up a fresh H5LTyyin. A bit of a hack ...
*/
static int yy_did_buffer_switch_on_eof;
-void yyrestart ( FILE *input_file );
-void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer );
-YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size );
-void yy_delete_buffer ( YY_BUFFER_STATE b );
-void yy_flush_buffer ( YY_BUFFER_STATE b );
-void yypush_buffer_state ( YY_BUFFER_STATE new_buffer );
-void yypop_buffer_state ( void );
+void H5LTyyrestart (FILE *input_file );
+void H5LTyy_switch_to_buffer (YY_BUFFER_STATE new_buffer );
+YY_BUFFER_STATE H5LTyy_create_buffer (FILE *file,int size );
+void H5LTyy_delete_buffer (YY_BUFFER_STATE b );
+void H5LTyy_flush_buffer (YY_BUFFER_STATE b );
+void H5LTyypush_buffer_state (YY_BUFFER_STATE new_buffer );
+void H5LTyypop_buffer_state (void );
+
+static void H5LTyyensure_buffer_stack (void );
+static void H5LTyy_load_buffer_state (void );
+static void H5LTyy_init_buffer (YY_BUFFER_STATE b,FILE *file );
-static void yyensure_buffer_stack ( void );
-static void yy_load_buffer_state ( void );
-static void yy_init_buffer ( YY_BUFFER_STATE b, FILE *file );
-#define YY_FLUSH_BUFFER yy_flush_buffer( YY_CURRENT_BUFFER )
+#define YY_FLUSH_BUFFER H5LTyy_flush_buffer(YY_CURRENT_BUFFER )
-YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size );
-YY_BUFFER_STATE yy_scan_string ( const char *yy_str );
-YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len );
+YY_BUFFER_STATE H5LTyy_scan_buffer (char *base,yy_size_t size );
+YY_BUFFER_STATE H5LTyy_scan_string (yyconst char *yy_str );
+YY_BUFFER_STATE H5LTyy_scan_bytes (yyconst char *bytes,yy_size_t len );
-void *yyalloc ( yy_size_t );
-void *yyrealloc ( void *, yy_size_t );
-void yyfree ( void * );
+void *H5LTyyalloc (yy_size_t );
+void *H5LTyyrealloc (void *,yy_size_t );
+void H5LTyyfree (void * );
+
+#define yy_new_buffer H5LTyy_create_buffer
-#define yy_new_buffer yy_create_buffer
#define yy_set_interactive(is_interactive) \
{ \
if ( ! YY_CURRENT_BUFFER ){ \
- yyensure_buffer_stack (); \
+ H5LTyyensure_buffer_stack (); \
YY_CURRENT_BUFFER_LVALUE = \
- yy_create_buffer( yyin, YY_BUF_SIZE ); \
+ H5LTyy_create_buffer(H5LTyyin,YY_BUF_SIZE ); \
} \
YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
}
+
#define yy_set_bol(at_bol) \
{ \
if ( ! YY_CURRENT_BUFFER ){\
- yyensure_buffer_stack (); \
+ H5LTyyensure_buffer_stack (); \
YY_CURRENT_BUFFER_LVALUE = \
- yy_create_buffer( yyin, YY_BUF_SIZE ); \
+ H5LTyy_create_buffer(H5LTyyin,YY_BUF_SIZE ); \
} \
YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
}
+
#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
/* Begin user sect3 */
-typedef flex_uint8_t YY_CHAR;
-FILE *yyin = NULL, *yyout = NULL;
+typedef unsigned char YY_CHAR;
+
+FILE *H5LTyyin = (FILE *) 0, *H5LTyyout = (FILE *) 0;
typedef int yy_state_type;
-extern int yylineno;
-int yylineno = 1;
+extern int H5LTyylineno;
-extern char *yytext;
-#ifdef yytext_ptr
-#undef yytext_ptr
-#endif
-#define yytext_ptr yytext
+int H5LTyylineno = 1;
+
+extern char *H5LTyytext;
+#define yytext_ptr H5LTyytext
-static yy_state_type yy_get_previous_state ( void );
-static yy_state_type yy_try_NUL_trans ( yy_state_type current_state );
-static int yy_get_next_buffer ( void );
-static void yynoreturn yy_fatal_error ( const char* msg );
+static yy_state_type yy_get_previous_state (void );
+static yy_state_type yy_try_NUL_trans (yy_state_type current_state );
+static int yy_get_next_buffer (void );
+static void yy_fatal_error (yyconst char msg[] );
/* Done after the current pattern has been matched and before the
- * corresponding action - sets up yytext.
+ * corresponding action - sets up H5LTyytext.
*/
#define YY_DO_BEFORE_ACTION \
(yytext_ptr) = yy_bp; \
- yyleng = (int) (yy_cp - yy_bp); \
+ H5LTyyleng = (size_t) (yy_cp - yy_bp); \
(yy_hold_char) = *yy_cp; \
*yy_cp = '\0'; \
(yy_c_buf_p) = yy_cp;
+
#define YY_NUM_RULES 66
#define YY_END_OF_BUFFER 67
/* This struct is not used in this scanner,
@@ -642,7 +411,7 @@ struct yy_trans_info
flex_int32_t yy_verify;
flex_int32_t yy_nxt;
};
-static const flex_int16_t yy_acclist[437] =
+static yyconst flex_int16_t yy_acclist[437] =
{ 0,
64, 64, 64, 64, 67, 66, 64, 66, 64, 65,
66, 56, 66, 55, 66, 62, 66, 63, 66, 66,
@@ -694,7 +463,7 @@ static const flex_int16_t yy_acclist[437] =
57, 21, 57, 34, 34, 57
} ;
-static const flex_int16_t yy_accept[546] =
+static yyconst flex_int16_t yy_accept[546] =
{ 0,
1, 2, 3, 4, 5, 6, 7, 9, 12, 14,
16, 18, 20, 21, 22, 23, 24, 26, 28, 30,
@@ -758,7 +527,7 @@ static const flex_int16_t yy_accept[546] =
432, 434, 435, 437, 437
} ;
-static const YY_CHAR yy_ec[256] =
+static yyconst flex_int32_t yy_ec[256] =
{ 0,
1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
@@ -790,7 +559,7 @@ static const YY_CHAR yy_ec[256] =
1, 1, 1, 1, 1
} ;
-static const YY_CHAR yy_meta[42] =
+static yyconst flex_int32_t yy_meta[42] =
{ 0,
1, 1, 1, 2, 3, 3, 3, 3, 3, 3,
3, 3, 1, 1, 1, 1, 1, 1, 1, 1,
@@ -799,7 +568,7 @@ static const YY_CHAR yy_meta[42] =
1
} ;
-static const flex_int16_t yy_base[547] =
+static yyconst flex_int16_t yy_base[547] =
{ 0,
0, 0, 41, 0, 610, 611, 81, 83, 611, 0,
611, 611, 56, 599, 580, 575, 611, 611, 611, 611,
@@ -863,7 +632,7 @@ static const flex_int16_t yy_base[547] =
0, 611, 0, 611, 106, 275
} ;
-static const flex_int16_t yy_def[547] =
+static yyconst flex_int16_t yy_def[547] =
{ 0,
544, 1, 544, 3, 544, 544, 544, 544, 544, 545,
544, 544, 544, 544, 544, 544, 544, 544, 544, 544,
@@ -927,7 +696,7 @@ static const flex_int16_t yy_def[547] =
546, 544, 546, 0, 544, 544
} ;
-static const flex_int16_t yy_nxt[653] =
+static yyconst flex_int16_t yy_nxt[653] =
{ 0,
6, 7, 8, 9, 10, 10, 10, 10, 10, 10,
10, 10, 11, 12, 6, 6, 13, 6, 6, 6,
@@ -1003,7 +772,7 @@ static const flex_int16_t yy_nxt[653] =
544, 544
} ;
-static const flex_int16_t yy_chk[653] =
+static yyconst flex_int16_t yy_chk[653] =
{ 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
@@ -1079,15 +848,15 @@ static const flex_int16_t yy_chk[653] =
544, 544
} ;
-extern int yy_flex_debug;
-int yy_flex_debug = 0;
+extern int H5LTyy_flex_debug;
+int H5LTyy_flex_debug = 0;
static yy_state_type *yy_state_buf=0, *yy_state_ptr=0;
static char *yy_full_match;
static int yy_lp;
#define REJECT \
{ \
-*yy_cp = (yy_hold_char); /* undo effects of setting up yytext */ \
+*yy_cp = (yy_hold_char); /* undo effects of setting up H5LTyytext */ \
yy_cp = (yy_full_match); /* restore poss. backed-over text */ \
++(yy_lp); \
goto find_rule; \
@@ -1096,7 +865,7 @@ goto find_rule; \
#define yymore() yymore_used_but_not_detected
#define YY_MORE_ADJ 0
#define YY_RESTORE_YY_MORE_OFFSET
-char *yytext;
+char *H5LTyytext;
#line 1 "hl/src/H5LTanalyze.l"
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Copyright by The HDF Group. *
@@ -1173,9 +942,8 @@ extern hbool_t is_opq_tag;
hbool_t first_quote = 1;
-#line 1155 "hl/src/H5LTanalyze.c"
-#line 1157 "hl/src/H5LTanalyze.c"
+#line 925 "hl/src/H5LTanalyze.c"
#define INITIAL 0
#define TAG_STRING 1
@@ -1184,36 +952,36 @@ hbool_t first_quote = 1;
#define YY_EXTRA_TYPE void *
#endif
-static int yy_init_globals ( void );
+static int yy_init_globals (void );
/* Accessor methods to globals.
These are made visible to non-reentrant scanners for convenience. */
-int yylex_destroy ( void );
+int H5LTyylex_destroy (void );
-int yyget_debug ( void );
+int H5LTyyget_debug (void );
-void yyset_debug ( int debug_flag );
+void H5LTyyset_debug (int debug_flag );
-YY_EXTRA_TYPE yyget_extra ( void );
+YY_EXTRA_TYPE H5LTyyget_extra (void );
-void yyset_extra ( YY_EXTRA_TYPE user_defined );
+void H5LTyyset_extra (YY_EXTRA_TYPE user_defined );
-FILE *yyget_in ( void );
+FILE *H5LTyyget_in (void );
-void yyset_in ( FILE * _in_str );
+void H5LTyyset_in (FILE * in_str );
-FILE *yyget_out ( void );
+FILE *H5LTyyget_out (void );
-void yyset_out ( FILE * _out_str );
+void H5LTyyset_out (FILE * out_str );
- int yyget_leng ( void );
+yy_size_t H5LTyyget_leng (void );
-char *yyget_text ( void );
+char *H5LTyyget_text (void );
-int yyget_lineno ( void );
+int H5LTyyget_lineno (void );
-void yyset_lineno ( int _line_number );
+void H5LTyyset_lineno (int line_number );
/* Macros after this point can all be overridden by user definitions in
* section 1.
@@ -1221,43 +989,35 @@ void yyset_lineno ( int _line_number );
#ifndef YY_SKIP_YYWRAP
#ifdef __cplusplus
-extern "C" int yywrap ( void );
+extern "C" int H5LTyywrap (void );
#else
-extern int yywrap ( void );
+extern int H5LTyywrap (void );
#endif
#endif
-#ifndef YY_NO_UNPUT
-
- static void yyunput ( int c, char *buf_ptr );
+ static void yyunput (int c,char *buf_ptr );
-#endif
-
#ifndef yytext_ptr
-static void yy_flex_strncpy ( char *, const char *, int );
+static void yy_flex_strncpy (char *,yyconst char *,int );
#endif
#ifdef YY_NEED_STRLEN
-static int yy_flex_strlen ( const char * );
+static int yy_flex_strlen (yyconst char * );
#endif
#ifndef YY_NO_INPUT
+
#ifdef __cplusplus
-static int yyinput ( void );
+static int yyinput (void );
#else
-static int input ( void );
+static int input (void );
#endif
#endif
/* Amount of stuff to slurp up with each read. */
#ifndef YY_READ_BUF_SIZE
-#ifdef __ia64__
-/* On IA-64, the buffer size is 16k, not 8k */
-#define YY_READ_BUF_SIZE 16384
-#else
#define YY_READ_BUF_SIZE 8192
-#endif /* __ia64__ */
#endif
/* Copy whatever the last rule matched to the standard output. */
@@ -1265,7 +1025,7 @@ static int input ( void );
/* This used to be an fputs(), but since the string might contain NUL's,
* we now use fwrite().
*/
-#define ECHO do { if (fwrite( yytext, (size_t) yyleng, 1, yyout )) {} } while (0)
+#define ECHO do { if (fwrite( H5LTyytext, H5LTyyleng, 1, H5LTyyout )) {} } while (0)
#endif
/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL,
@@ -1276,20 +1036,20 @@ static int input ( void );
if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
{ \
int c = '*'; \
- int n; \
+ size_t n; \
for ( n = 0; n < max_size && \
- (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
+ (c = getc( H5LTyyin )) != EOF && c != '\n'; ++n ) \
buf[n] = (char) c; \
if ( c == '\n' ) \
buf[n++] = (char) c; \
- if ( c == EOF && ferror( yyin ) ) \
+ if ( c == EOF && ferror( H5LTyyin ) ) \
YY_FATAL_ERROR( "input in flex scanner failed" ); \
result = n; \
} \
else \
{ \
errno=0; \
- while ( (result = (int) fread(buf, 1, (yy_size_t) max_size, yyin)) == 0 && ferror(yyin)) \
+ while ( (result = fread(buf, 1, max_size, H5LTyyin))==0 && ferror(H5LTyyin)) \
{ \
if( errno != EINTR) \
{ \
@@ -1297,7 +1057,7 @@ static int input ( void );
break; \
} \
errno=0; \
- clearerr(yyin); \
+ clearerr(H5LTyyin); \
} \
}\
\
@@ -1330,12 +1090,12 @@ static int input ( void );
#ifndef YY_DECL
#define YY_DECL_IS_OURS 1
-extern int yylex (void);
+extern int H5LTyylex (void);
-#define YY_DECL int yylex (void)
+#define YY_DECL int H5LTyylex (void)
#endif /* !YY_DECL */
-/* Code executed at the beginning of each rule, after yytext and yyleng
+/* Code executed at the beginning of each rule, after H5LTyytext and H5LTyyleng
* have been set up.
*/
#ifndef YY_USER_ACTION
@@ -1344,7 +1104,7 @@ extern int yylex (void);
/* Code executed at the end of each rule. */
#ifndef YY_BREAK
-#define YY_BREAK /*LINTED*/break;
+#define YY_BREAK break;
#endif
#define YY_RULE_SETUP \
@@ -1354,10 +1114,15 @@ extern int yylex (void);
*/
YY_DECL
{
- yy_state_type yy_current_state;
- char *yy_cp, *yy_bp;
- int yy_act;
+ register yy_state_type yy_current_state;
+ register char *yy_cp, *yy_bp;
+ register int yy_act;
+#line 82 "hl/src/H5LTanalyze.l"
+
+
+#line 1103 "hl/src/H5LTanalyze.c"
+
if ( !(yy_init) )
{
(yy_init) = 1;
@@ -1368,39 +1133,33 @@ YY_DECL
/* Create the reject buffer large enough to save one state per allowed character. */
if ( ! (yy_state_buf) )
- (yy_state_buf) = (yy_state_type *)yyalloc(YY_STATE_BUF_SIZE );
+ (yy_state_buf) = (yy_state_type *)H5LTyyalloc(YY_STATE_BUF_SIZE );
if ( ! (yy_state_buf) )
- YY_FATAL_ERROR( "out of dynamic memory in yylex()" );
+ YY_FATAL_ERROR( "out of dynamic memory in H5LTyylex()" );
if ( ! (yy_start) )
(yy_start) = 1; /* first start state */
- if ( ! yyin )
- yyin = stdin;
+ if ( ! H5LTyyin )
+ H5LTyyin = stdin;
- if ( ! yyout )
- yyout = stdout;
+ if ( ! H5LTyyout )
+ H5LTyyout = stdout;
if ( ! YY_CURRENT_BUFFER ) {
- yyensure_buffer_stack ();
+ H5LTyyensure_buffer_stack ();
YY_CURRENT_BUFFER_LVALUE =
- yy_create_buffer( yyin, YY_BUF_SIZE );
+ H5LTyy_create_buffer(H5LTyyin,YY_BUF_SIZE );
}
- yy_load_buffer_state( );
+ H5LTyy_load_buffer_state( );
}
- {
-#line 82 "hl/src/H5LTanalyze.l"
-
-
-#line 1376 "hl/src/H5LTanalyze.c"
-
- while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */
+ while ( 1 ) /* loops until end-of-file is reached */
{
yy_cp = (yy_c_buf_p);
- /* Support of yytext. */
+ /* Support of H5LTyytext. */
*yy_cp = (yy_hold_char);
/* yy_bp points to the position in yy_ch_buf of the start of
@@ -1416,14 +1175,14 @@ YY_DECL
yy_match:
do
{
- YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ;
+ register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
{
yy_current_state = (int) yy_def[yy_current_state];
if ( yy_current_state >= 545 )
- yy_c = yy_meta[yy_c];
+ yy_c = yy_meta[(unsigned int) yy_c];
}
- yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
*(yy_state_ptr)++ = yy_current_state;
++yy_cp;
}
@@ -1432,9 +1191,7 @@ yy_match:
yy_find_action:
yy_current_state = *--(yy_state_ptr);
(yy_lp) = yy_accept[yy_current_state];
-
find_rule: /* we branch to this label when backing up */
-
for ( ; ; ) /* until we find what rule we matched */
{
if ( (yy_lp) && (yy_lp) < yy_accept[yy_current_state + 1] )
@@ -1733,7 +1490,7 @@ YY_RULE_SETUP
if( is_str_size || (is_enum && is_enum_memb) ||
is_opq_size || (asindex>-1 && arr_stack[asindex].is_dim) ||
(csindex>-1 && cmpd_stack[csindex].is_field) ) {
- H5LTyylval.ival = atoi(yytext);
+ H5LTyylval.ival = atoi(H5LTyytext);
return NUMBER;
} else
REJECT;
@@ -1759,9 +1516,9 @@ YY_RULE_SETUP
#line 165 "hl/src/H5LTanalyze.l"
{
#ifdef H5_HAVE_WIN32_API
- H5LTyylval.sval = _strdup(yytext);
+ H5LTyylval.sval = _strdup(H5LTyytext);
#else /* H5_HAVE_WIN32_API */
- H5LTyylval.sval = strdup(yytext);
+ H5LTyylval.sval = strdup(H5LTyytext);
#endif /* H5_HAVE_WIN32_API */
BEGIN INITIAL;
return STRING;
@@ -1814,7 +1571,7 @@ YY_RULE_SETUP
#line 184 "hl/src/H5LTanalyze.l"
ECHO;
YY_BREAK
-#line 1796 "hl/src/H5LTanalyze.c"
+#line 1553 "hl/src/H5LTanalyze.c"
case YY_STATE_EOF(INITIAL):
case YY_STATE_EOF(TAG_STRING):
yyterminate();
@@ -1832,15 +1589,15 @@ ECHO;
{
/* We're scanning a new file or input source. It's
* possible that this happened because the user
- * just pointed yyin at a new source and called
- * yylex(). If so, then we have to assure
+ * just pointed H5LTyyin at a new source and called
+ * H5LTyylex(). If so, then we have to assure
* consistency between YY_CURRENT_BUFFER and our
* globals. Here is the right place to do so, because
* this is the first action (other than possibly a
* back-up) that will match for the new input source.
*/
(yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
- YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin;
+ YY_CURRENT_BUFFER_LVALUE->yy_input_file = H5LTyyin;
YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
}
@@ -1893,11 +1650,11 @@ ECHO;
{
(yy_did_buffer_switch_on_eof) = 0;
- if ( yywrap( ) )
+ if ( H5LTyywrap( ) )
{
/* Note: because we've taken care in
* yy_get_next_buffer() to have set up
- * yytext, we can now set up
+ * H5LTyytext, we can now set up
* yy_c_buf_p so that if some total
* hoser (like flex itself) wants to
* call the scanner after we return the
@@ -1946,8 +1703,7 @@ ECHO;
"fatal flex scanner internal error--no action found" );
} /* end of action switch */
} /* end of scanning one token */
- } /* end of user's declarations */
-} /* end of yylex */
+} /* end of H5LTyylex */
/* yy_get_next_buffer - try to read in a new buffer
*
@@ -1958,9 +1714,9 @@ ECHO;
*/
static int yy_get_next_buffer (void)
{
- char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
- char *source = (yytext_ptr);
- int number_to_move, i;
+ register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+ register char *source = (yytext_ptr);
+ register int number_to_move, i;
int ret_val;
if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] )
@@ -1989,7 +1745,7 @@ static int yy_get_next_buffer (void)
/* Try to read more data. */
/* First move last chars to start of buffer. */
- number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr) - 1);
+ number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1;
for ( i = 0; i < number_to_move; ++i )
*(dest++) = *(source++);
@@ -2002,7 +1758,7 @@ static int yy_get_next_buffer (void)
else
{
- int num_to_read =
+ yy_size_t num_to_read =
YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
while ( num_to_read <= 0 )
@@ -2028,7 +1784,7 @@ static int yy_get_next_buffer (void)
if ( number_to_move == YY_MORE_ADJ )
{
ret_val = EOB_ACT_END_OF_FILE;
- yyrestart( yyin );
+ H5LTyyrestart(H5LTyyin );
}
else
@@ -2042,15 +1798,12 @@ static int yy_get_next_buffer (void)
else
ret_val = EOB_ACT_CONTINUE_SCAN;
- if (((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
+ if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
/* Extend the array by 50%, plus the number we really need. */
- int new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1);
- YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc(
- (void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf, (yy_size_t) new_size );
+ yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1);
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) H5LTyyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size );
if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
- /* "- 2" to take care of EOB's */
- YY_CURRENT_BUFFER_LVALUE->yy_buf_size = (int) (new_size - 2);
}
(yy_n_chars) += number_to_move;
@@ -2066,8 +1819,8 @@ static int yy_get_next_buffer (void)
static yy_state_type yy_get_previous_state (void)
{
- yy_state_type yy_current_state;
- char *yy_cp;
+ register yy_state_type yy_current_state;
+ register char *yy_cp;
yy_current_state = (yy_start);
@@ -2076,14 +1829,14 @@ static int yy_get_next_buffer (void)
for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp )
{
- YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+ register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
{
yy_current_state = (int) yy_def[yy_current_state];
if ( yy_current_state >= 545 )
- yy_c = yy_meta[yy_c];
+ yy_c = yy_meta[(unsigned int) yy_c];
}
- yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
*(yy_state_ptr)++ = yy_current_state;
}
@@ -2097,16 +1850,16 @@ static int yy_get_next_buffer (void)
*/
static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state )
{
- int yy_is_jam;
+ register int yy_is_jam;
- YY_CHAR yy_c = 1;
+ register YY_CHAR yy_c = 1;
while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
{
yy_current_state = (int) yy_def[yy_current_state];
if ( yy_current_state >= 545 )
- yy_c = yy_meta[yy_c];
+ yy_c = yy_meta[(unsigned int) yy_c];
}
- yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
yy_is_jam = (yy_current_state == 544);
if ( ! yy_is_jam )
*(yy_state_ptr)++ = yy_current_state;
@@ -2114,24 +1867,22 @@ static int yy_get_next_buffer (void)
return yy_is_jam ? 0 : yy_current_state;
}
-#ifndef YY_NO_UNPUT
-
- static void yyunput (int c, char * yy_bp )
+ static void yyunput (int c, register char * yy_bp )
{
- char *yy_cp;
+ register char *yy_cp;
yy_cp = (yy_c_buf_p);
- /* undo effects of setting up yytext */
+ /* undo effects of setting up H5LTyytext */
*yy_cp = (yy_hold_char);
if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
{ /* need to shift things up to make room */
/* +2 for EOB chars. */
- int number_to_move = (yy_n_chars) + 2;
- char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[
+ register yy_size_t number_to_move = (yy_n_chars) + 2;
+ register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[
YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2];
- char *source =
+ register char *source =
&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move];
while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
@@ -2140,7 +1891,7 @@ static int yy_get_next_buffer (void)
yy_cp += (int) (dest - source);
yy_bp += (int) (dest - source);
YY_CURRENT_BUFFER_LVALUE->yy_n_chars =
- (yy_n_chars) = (int) YY_CURRENT_BUFFER_LVALUE->yy_buf_size;
+ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_buf_size;
if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
YY_FATAL_ERROR( "flex scanner push-back overflow" );
@@ -2153,8 +1904,6 @@ static int yy_get_next_buffer (void)
(yy_c_buf_p) = yy_cp;
}
-#endif
-
#ifndef YY_NO_INPUT
#ifdef __cplusplus
static int yyinput (void)
@@ -2179,7 +1928,7 @@ static int yy_get_next_buffer (void)
else
{ /* need more input */
- int offset = (int) ((yy_c_buf_p) - (yytext_ptr));
+ yy_size_t offset = (yy_c_buf_p) - (yytext_ptr);
++(yy_c_buf_p);
switch ( yy_get_next_buffer( ) )
@@ -2196,14 +1945,14 @@ static int yy_get_next_buffer (void)
*/
/* Reset buffer status. */
- yyrestart( yyin );
+ H5LTyyrestart(H5LTyyin );
/*FALLTHROUGH*/
case EOB_ACT_END_OF_FILE:
{
- if ( yywrap( ) )
- return 0;
+ if ( H5LTyywrap( ) )
+ return EOF;
if ( ! (yy_did_buffer_switch_on_eof) )
YY_NEW_FILE;
@@ -2222,7 +1971,7 @@ static int yy_get_next_buffer (void)
}
c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */
- *(yy_c_buf_p) = '\0'; /* preserve yytext */
+ *(yy_c_buf_p) = '\0'; /* preserve H5LTyytext */
(yy_hold_char) = *++(yy_c_buf_p);
return c;
@@ -2234,32 +1983,32 @@ static int yy_get_next_buffer (void)
*
* @note This function does not reset the start condition to @c INITIAL .
*/
- void yyrestart (FILE * input_file )
+ void H5LTyyrestart (FILE * input_file )
{
if ( ! YY_CURRENT_BUFFER ){
- yyensure_buffer_stack ();
+ H5LTyyensure_buffer_stack ();
YY_CURRENT_BUFFER_LVALUE =
- yy_create_buffer( yyin, YY_BUF_SIZE );
+ H5LTyy_create_buffer(H5LTyyin,YY_BUF_SIZE );
}
- yy_init_buffer( YY_CURRENT_BUFFER, input_file );
- yy_load_buffer_state( );
+ H5LTyy_init_buffer(YY_CURRENT_BUFFER,input_file );
+ H5LTyy_load_buffer_state( );
}
/** Switch to a different input buffer.
* @param new_buffer The new input buffer.
*
*/
- void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer )
+ void H5LTyy_switch_to_buffer (YY_BUFFER_STATE new_buffer )
{
/* TODO. We should be able to replace this entire function body
* with
- * yypop_buffer_state();
- * yypush_buffer_state(new_buffer);
+ * H5LTyypop_buffer_state();
+ * H5LTyypush_buffer_state(new_buffer);
*/
- yyensure_buffer_stack ();
+ H5LTyyensure_buffer_stack ();
if ( YY_CURRENT_BUFFER == new_buffer )
return;
@@ -2272,21 +2021,21 @@ static int yy_get_next_buffer (void)
}
YY_CURRENT_BUFFER_LVALUE = new_buffer;
- yy_load_buffer_state( );
+ H5LTyy_load_buffer_state( );
/* We don't actually know whether we did this switch during
- * EOF (yywrap()) processing, but the only time this flag
- * is looked at is after yywrap() is called, so it's safe
+ * EOF (H5LTyywrap()) processing, but the only time this flag
+ * is looked at is after H5LTyywrap() is called, so it's safe
* to go ahead and always set it.
*/
(yy_did_buffer_switch_on_eof) = 1;
}
-static void yy_load_buffer_state (void)
+static void H5LTyy_load_buffer_state (void)
{
(yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
(yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
- yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
+ H5LTyyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
(yy_hold_char) = *(yy_c_buf_p);
}
@@ -2296,35 +2045,35 @@ static void yy_load_buffer_state (void)
*
* @return the allocated buffer state.
*/
- YY_BUFFER_STATE yy_create_buffer (FILE * file, int size )
+ YY_BUFFER_STATE H5LTyy_create_buffer (FILE * file, int size )
{
YY_BUFFER_STATE b;
- b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) );
+ b = (YY_BUFFER_STATE) H5LTyyalloc(sizeof( struct yy_buffer_state ) );
if ( ! b )
- YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+ YY_FATAL_ERROR( "out of dynamic memory in H5LTyy_create_buffer()" );
b->yy_buf_size = size;
/* yy_ch_buf has to be 2 characters longer than the size given because
* we need to put in 2 end-of-buffer characters.
*/
- b->yy_ch_buf = (char *) yyalloc( (yy_size_t) (b->yy_buf_size + 2) );
+ b->yy_ch_buf = (char *) H5LTyyalloc(b->yy_buf_size + 2 );
if ( ! b->yy_ch_buf )
- YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+ YY_FATAL_ERROR( "out of dynamic memory in H5LTyy_create_buffer()" );
b->yy_is_our_buffer = 1;
- yy_init_buffer( b, file );
+ H5LTyy_init_buffer(b,file );
return b;
}
/** Destroy the buffer.
- * @param b a buffer created with yy_create_buffer()
+ * @param b a buffer created with H5LTyy_create_buffer()
*
*/
- void yy_delete_buffer (YY_BUFFER_STATE b )
+ void H5LTyy_delete_buffer (YY_BUFFER_STATE b )
{
if ( ! b )
@@ -2334,27 +2083,27 @@ static void yy_load_buffer_state (void)
YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
if ( b->yy_is_our_buffer )
- yyfree( (void *) b->yy_ch_buf );
+ H5LTyyfree((void *) b->yy_ch_buf );
- yyfree( (void *) b );
+ H5LTyyfree((void *) b );
}
/* Initializes or reinitializes a buffer.
* This function is sometimes called more than once on the same buffer,
- * such as during a yyrestart() or at EOF.
+ * such as during a H5LTyyrestart() or at EOF.
*/
- static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file )
+ static void H5LTyy_init_buffer (YY_BUFFER_STATE b, FILE * file )
{
int oerrno = errno;
- yy_flush_buffer( b );
+ H5LTyy_flush_buffer(b );
b->yy_input_file = file;
b->yy_fill_buffer = 1;
- /* If b is the current buffer, then yy_init_buffer was _probably_
- * called from yyrestart() or through yy_get_next_buffer.
+ /* If b is the current buffer, then H5LTyy_init_buffer was _probably_
+ * called from H5LTyyrestart() or through yy_get_next_buffer.
* In that case, we don't want to reset the lineno or column.
*/
if (b != YY_CURRENT_BUFFER){
@@ -2371,7 +2120,7 @@ static void yy_load_buffer_state (void)
* @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
*
*/
- void yy_flush_buffer (YY_BUFFER_STATE b )
+ void H5LTyy_flush_buffer (YY_BUFFER_STATE b )
{
if ( ! b )
return;
@@ -2391,7 +2140,7 @@ static void yy_load_buffer_state (void)
b->yy_buffer_status = YY_BUFFER_NEW;
if ( b == YY_CURRENT_BUFFER )
- yy_load_buffer_state( );
+ H5LTyy_load_buffer_state( );
}
/** Pushes the new state onto the stack. The new state becomes
@@ -2400,14 +2149,14 @@ static void yy_load_buffer_state (void)
* @param new_buffer The new state.
*
*/
-void yypush_buffer_state (YY_BUFFER_STATE new_buffer )
+void H5LTyypush_buffer_state (YY_BUFFER_STATE new_buffer )
{
if (new_buffer == NULL)
return;
- yyensure_buffer_stack();
+ H5LTyyensure_buffer_stack();
- /* This block is copied from yy_switch_to_buffer. */
+ /* This block is copied from H5LTyy_switch_to_buffer. */
if ( YY_CURRENT_BUFFER )
{
/* Flush out information for old buffer. */
@@ -2421,8 +2170,8 @@ void yypush_buffer_state (YY_BUFFER_STATE new_buffer )
(yy_buffer_stack_top)++;
YY_CURRENT_BUFFER_LVALUE = new_buffer;
- /* copied from yy_switch_to_buffer. */
- yy_load_buffer_state( );
+ /* copied from H5LTyy_switch_to_buffer. */
+ H5LTyy_load_buffer_state( );
(yy_did_buffer_switch_on_eof) = 1;
}
@@ -2430,18 +2179,18 @@ void yypush_buffer_state (YY_BUFFER_STATE new_buffer )
* The next element becomes the new top.
*
*/
-void yypop_buffer_state (void)
+void H5LTyypop_buffer_state (void)
{
if (!YY_CURRENT_BUFFER)
return;
- yy_delete_buffer(YY_CURRENT_BUFFER );
+ H5LTyy_delete_buffer(YY_CURRENT_BUFFER );
YY_CURRENT_BUFFER_LVALUE = NULL;
if ((yy_buffer_stack_top) > 0)
--(yy_buffer_stack_top);
if (YY_CURRENT_BUFFER) {
- yy_load_buffer_state( );
+ H5LTyy_load_buffer_state( );
(yy_did_buffer_switch_on_eof) = 1;
}
}
@@ -2449,7 +2198,7 @@ void yypop_buffer_state (void)
/* Allocates the stack if it does not exist.
* Guarantees space for at least one push.
*/
-static void yyensure_buffer_stack (void)
+static void H5LTyyensure_buffer_stack (void)
{
yy_size_t num_to_alloc;
@@ -2459,15 +2208,15 @@ static void yyensure_buffer_stack (void)
* scanner will even need a stack. We use 2 instead of 1 to avoid an
* immediate realloc on the next call.
*/
- num_to_alloc = 1; /* After all that talk, this was set to 1 anyways... */
- (yy_buffer_stack) = (struct yy_buffer_state**)yyalloc
+ num_to_alloc = 1;
+ (yy_buffer_stack) = (struct yy_buffer_state**)H5LTyyalloc
(num_to_alloc * sizeof(struct yy_buffer_state*)
);
if ( ! (yy_buffer_stack) )
- YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
-
+ YY_FATAL_ERROR( "out of dynamic memory in H5LTyyensure_buffer_stack()" );
+
memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*));
-
+
(yy_buffer_stack_max) = num_to_alloc;
(yy_buffer_stack_top) = 0;
return;
@@ -2476,15 +2225,15 @@ static void yyensure_buffer_stack (void)
if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){
/* Increase the buffer to prepare for a possible push. */
- yy_size_t grow_size = 8 /* arbitrary grow size */;
+ int grow_size = 8 /* arbitrary grow size */;
num_to_alloc = (yy_buffer_stack_max) + grow_size;
- (yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc
+ (yy_buffer_stack) = (struct yy_buffer_state**)H5LTyyrealloc
((yy_buffer_stack),
num_to_alloc * sizeof(struct yy_buffer_state*)
);
if ( ! (yy_buffer_stack) )
- YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
+ YY_FATAL_ERROR( "out of dynamic memory in H5LTyyensure_buffer_stack()" );
/* zero only the new slots.*/
memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*));
@@ -2496,9 +2245,9 @@ static void yyensure_buffer_stack (void)
* @param base the character buffer
* @param size the size in bytes of the character buffer
*
- * @return the newly allocated buffer state object.
+ * @return the newly allocated buffer state object.
*/
-YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size )
+YY_BUFFER_STATE H5LTyy_scan_buffer (char * base, yy_size_t size )
{
YY_BUFFER_STATE b;
@@ -2506,49 +2255,49 @@ YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size )
base[size-2] != YY_END_OF_BUFFER_CHAR ||
base[size-1] != YY_END_OF_BUFFER_CHAR )
/* They forgot to leave room for the EOB's. */
- return NULL;
+ return 0;
- b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) );
+ b = (YY_BUFFER_STATE) H5LTyyalloc(sizeof( struct yy_buffer_state ) );
if ( ! b )
- YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" );
+ YY_FATAL_ERROR( "out of dynamic memory in H5LTyy_scan_buffer()" );
- b->yy_buf_size = (int) (size - 2); /* "- 2" to take care of EOB's */
+ b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */
b->yy_buf_pos = b->yy_ch_buf = base;
b->yy_is_our_buffer = 0;
- b->yy_input_file = NULL;
+ b->yy_input_file = 0;
b->yy_n_chars = b->yy_buf_size;
b->yy_is_interactive = 0;
b->yy_at_bol = 1;
b->yy_fill_buffer = 0;
b->yy_buffer_status = YY_BUFFER_NEW;
- yy_switch_to_buffer( b );
+ H5LTyy_switch_to_buffer(b );
return b;
}
-/** Setup the input buffer state to scan a string. The next call to yylex() will
+/** Setup the input buffer state to scan a string. The next call to H5LTyylex() will
* scan from a @e copy of @a str.
* @param yystr a NUL-terminated string to scan
*
* @return the newly allocated buffer state object.
* @note If you want to scan bytes that may contain NUL values, then use
- * yy_scan_bytes() instead.
+ * H5LTyy_scan_bytes() instead.
*/
-YY_BUFFER_STATE yy_scan_string (const char * yystr )
+YY_BUFFER_STATE H5LTyy_scan_string (yyconst char * yystr )
{
- return yy_scan_bytes( yystr, (int) strlen(yystr) );
+ return H5LTyy_scan_bytes(yystr,strlen(yystr) );
}
-/** Setup the input buffer state to scan the given bytes. The next call to yylex() will
+/** Setup the input buffer state to scan the given bytes. The next call to H5LTyylex() will
* scan from a @e copy of @a bytes.
* @param yybytes the byte buffer to scan
* @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes.
*
* @return the newly allocated buffer state object.
*/
-YY_BUFFER_STATE yy_scan_bytes (const char * yybytes, int _yybytes_len )
+YY_BUFFER_STATE H5LTyy_scan_bytes (yyconst char * yybytes, yy_size_t _yybytes_len )
{
YY_BUFFER_STATE b;
char *buf;
@@ -2556,19 +2305,19 @@ YY_BUFFER_STATE yy_scan_bytes (const char * yybytes, int _yybytes_len )
int i;
/* Get memory for full buffer, including space for trailing EOB's. */
- n = (yy_size_t) (_yybytes_len + 2);
- buf = (char *) yyalloc( n );
+ n = _yybytes_len + 2;
+ buf = (char *) H5LTyyalloc(n );
if ( ! buf )
- YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
+ YY_FATAL_ERROR( "out of dynamic memory in H5LTyy_scan_bytes()" );
for ( i = 0; i < _yybytes_len; ++i )
buf[i] = yybytes[i];
buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
- b = yy_scan_buffer( buf, n );
+ b = H5LTyy_scan_buffer(buf,n );
if ( ! b )
- YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" );
+ YY_FATAL_ERROR( "bad buffer in H5LTyy_scan_bytes()" );
/* It's okay to grow etc. this buffer, and we should throw it
* away when we're done.
@@ -2582,9 +2331,9 @@ YY_BUFFER_STATE yy_scan_bytes (const char * yybytes, int _yybytes_len )
#define YY_EXIT_FAILURE 2
#endif
-static void yynoreturn yy_fatal_error (const char* msg )
+static void yy_fatal_error (yyconst char* msg )
{
- fprintf( stderr, "%s\n", msg );
+ (void) fprintf( stderr, "%s\n", msg );
exit( YY_EXIT_FAILURE );
}
@@ -2594,14 +2343,14 @@ static void yynoreturn yy_fatal_error (const char* msg )
#define yyless(n) \
do \
{ \
- /* Undo effects of setting up yytext. */ \
+ /* Undo effects of setting up H5LTyytext. */ \
int yyless_macro_arg = (n); \
YY_LESS_LINENO(yyless_macro_arg);\
- yytext[yyleng] = (yy_hold_char); \
- (yy_c_buf_p) = yytext + yyless_macro_arg; \
+ H5LTyytext[H5LTyyleng] = (yy_hold_char); \
+ (yy_c_buf_p) = H5LTyytext + yyless_macro_arg; \
(yy_hold_char) = *(yy_c_buf_p); \
*(yy_c_buf_p) = '\0'; \
- yyleng = yyless_macro_arg; \
+ H5LTyyleng = yyless_macro_arg; \
} \
while ( 0 )
@@ -2610,91 +2359,91 @@ static void yynoreturn yy_fatal_error (const char* msg )
/** Get the current line number.
*
*/
-int yyget_lineno (void)
+int H5LTyyget_lineno (void)
{
-
- return yylineno;
+
+ return H5LTyylineno;
}
/** Get the input stream.
*
*/
-FILE *yyget_in (void)
+FILE *H5LTyyget_in (void)
{
- return yyin;
+ return H5LTyyin;
}
/** Get the output stream.
*
*/
-FILE *yyget_out (void)
+FILE *H5LTyyget_out (void)
{
- return yyout;
+ return H5LTyyout;
}
/** Get the length of the current token.
*
*/
-int yyget_leng (void)
+yy_size_t H5LTyyget_leng (void)
{
- return yyleng;
+ return H5LTyyleng;
}
/** Get the current token.
*
*/
-char *yyget_text (void)
+char *H5LTyyget_text (void)
{
- return yytext;
+ return H5LTyytext;
}
/** Set the current line number.
- * @param _line_number line number
+ * @param line_number
*
*/
-void yyset_lineno (int _line_number )
+void H5LTyyset_lineno (int line_number )
{
- yylineno = _line_number;
+ H5LTyylineno = line_number;
}
/** Set the input stream. This does not discard the current
* input buffer.
- * @param _in_str A readable stream.
+ * @param in_str A readable stream.
*
- * @see yy_switch_to_buffer
+ * @see H5LTyy_switch_to_buffer
*/
-void yyset_in (FILE * _in_str )
+void H5LTyyset_in (FILE * in_str )
{
- yyin = _in_str ;
+ H5LTyyin = in_str ;
}
-void yyset_out (FILE * _out_str )
+void H5LTyyset_out (FILE * out_str )
{
- yyout = _out_str ;
+ H5LTyyout = out_str ;
}
-int yyget_debug (void)
+int H5LTyyget_debug (void)
{
- return yy_flex_debug;
+ return H5LTyy_flex_debug;
}
-void yyset_debug (int _bdebug )
+void H5LTyyset_debug (int bdebug )
{
- yy_flex_debug = _bdebug ;
+ H5LTyy_flex_debug = bdebug ;
}
static int yy_init_globals (void)
{
/* Initialization is the same as for the non-reentrant scanner.
- * This function is called from yylex_destroy(), so don't allocate here.
+ * This function is called from H5LTyylex_destroy(), so don't allocate here.
*/
- (yy_buffer_stack) = NULL;
+ (yy_buffer_stack) = 0;
(yy_buffer_stack_top) = 0;
(yy_buffer_stack_max) = 0;
- (yy_c_buf_p) = NULL;
+ (yy_c_buf_p) = (char *) 0;
(yy_init) = 0;
(yy_start) = 0;
@@ -2705,39 +2454,39 @@ static int yy_init_globals (void)
/* Defined in main.c */
#ifdef YY_STDINIT
- yyin = stdin;
- yyout = stdout;
+ H5LTyyin = stdin;
+ H5LTyyout = stdout;
#else
- yyin = NULL;
- yyout = NULL;
+ H5LTyyin = (FILE *) 0;
+ H5LTyyout = (FILE *) 0;
#endif
/* For future reference: Set errno on error, since we are called by
- * yylex_init()
+ * H5LTyylex_init()
*/
return 0;
}
-/* yylex_destroy is for both reentrant and non-reentrant scanners. */
-int yylex_destroy (void)
+/* H5LTyylex_destroy is for both reentrant and non-reentrant scanners. */
+int H5LTyylex_destroy (void)
{
/* Pop the buffer stack, destroying each element. */
while(YY_CURRENT_BUFFER){
- yy_delete_buffer( YY_CURRENT_BUFFER );
+ H5LTyy_delete_buffer(YY_CURRENT_BUFFER );
YY_CURRENT_BUFFER_LVALUE = NULL;
- yypop_buffer_state();
+ H5LTyypop_buffer_state();
}
/* Destroy the stack itself. */
- yyfree((yy_buffer_stack) );
+ H5LTyyfree((yy_buffer_stack) );
(yy_buffer_stack) = NULL;
- yyfree ( (yy_state_buf) );
+ H5LTyyfree ( (yy_state_buf) );
(yy_state_buf) = NULL;
/* Reset the globals. This is important in a non-reentrant scanner so the next time
- * yylex() is called, initialization will occur. */
+ * H5LTyylex() is called, initialization will occur. */
yy_init_globals( );
return 0;
@@ -2748,19 +2497,18 @@ int yylex_destroy (void)
*/
#ifndef yytext_ptr
-static void yy_flex_strncpy (char* s1, const char * s2, int n )
+static void yy_flex_strncpy (char* s1, yyconst char * s2, int n )
{
-
- int i;
+ register int i;
for ( i = 0; i < n; ++i )
s1[i] = s2[i];
}
#endif
#ifdef YY_NEED_STRLEN
-static int yy_flex_strlen (const char * s )
+static int yy_flex_strlen (yyconst char * s )
{
- int n;
+ register int n;
for ( n = 0; s[n]; ++n )
;
@@ -2768,14 +2516,13 @@ static int yy_flex_strlen (const char * s )
}
#endif
-void *yyalloc (yy_size_t size )
+void *H5LTyyalloc (yy_size_t size )
{
- return malloc(size);
+ return (void *) malloc( size );
}
-void *yyrealloc (void * ptr, yy_size_t size )
+void *H5LTyyrealloc (void * ptr, yy_size_t size )
{
-
/* The cast to (char *) in the following accommodates both
* implementations that use char* generic pointers, and those
* that use void* generic pointers. It works with the latter
@@ -2783,18 +2530,19 @@ void *yyrealloc (void * ptr, yy_size_t size )
* any pointer type to void*, and deal with argument conversions
* as though doing an assignment.
*/
- return realloc(ptr, size);
+ return (void *) realloc( (char *) ptr, size );
}
-void yyfree (void * ptr )
+void H5LTyyfree (void * ptr )
{
- free( (char *) ptr ); /* see yyrealloc() for (char *) cast */
+ free( (char *) ptr ); /* see H5LTyyrealloc() for (char *) cast */
}
#define YYTABLES_NAME "yytables"
#line 184 "hl/src/H5LTanalyze.l"
+
int my_yyinput(char *buf, int max_size)
{
int ret;
@@ -2806,11 +2554,11 @@ int my_yyinput(char *buf, int max_size)
int H5LTyyerror(const char *msg)
{
- printf("ERROR: %s before \"%s\".\n", msg, yytext);
+ printf("ERROR: %s before \"%s\".\n", msg, H5LTyytext);
return 0;
}
-int yywrap()
+int H5LTyywrap()
{
return(1);
}
diff --git a/hl/src/H5LTparse.c b/hl/src/H5LTparse.c
index a9b3dc3..0275917 100644
--- a/hl/src/H5LTparse.c
+++ b/hl/src/H5LTparse.c
@@ -20,22 +20,22 @@
#elif defined _MSC_VER
#pragma warning(push, 1)
#endif
-/* A Bison parser, made by GNU Bison 3.0.4. */
+/* A Bison parser, made by GNU Bison 2.7. */
/* Bison implementation for Yacc-like parsers in C
-
- Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc.
-
+
+ Copyright (C) 1984, 1989-1990, 2000-2012 Free Software Foundation, Inc.
+
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
-
+
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
-
+
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
@@ -48,7 +48,7 @@
special exception, which will cause the skeleton and the resulting
Bison output files to be licensed under the GNU General Public
License without this special exception.
-
+
This special exception was added by the Free Software Foundation in
version 2.2 of Bison. */
@@ -66,7 +66,7 @@
#define YYBISON 1
/* Bison version. */
-#define YYBISON_VERSION "3.0.4"
+#define YYBISON_VERSION "2.7"
/* Skeleton name. */
#define YYSKELETON_NAME "yacc.c"
@@ -85,14 +85,14 @@
#define yyparse H5LTyyparse
#define yylex H5LTyylex
#define yyerror H5LTyyerror
-#define yydebug H5LTyydebug
-#define yynerrs H5LTyynerrs
-
#define yylval H5LTyylval
#define yychar H5LTyychar
+#define yydebug H5LTyydebug
+#define yynerrs H5LTyynerrs
/* Copy the first part of user declarations. */
-#line 20 "hl/src/H5LTparse.y" /* yacc.c:339 */
+/* Line 371 of yacc.c */
+#line 20 "hl/src/H5LTparse.y"
#include <stdio.h>
#include <string.h>
@@ -145,13 +145,14 @@ hbool_t is_opq_size = 0; /*flag to lexer for opaque type size*/
hbool_t is_opq_tag = 0; /*flag to lexer for opaque type tag*/
-#line 127 "hl/src/H5LTparse.c" /* yacc.c:339 */
+/* Line 371 of yacc.c */
+#line 128 "hl/src/H5LTparse.c"
-# ifndef YY_NULLPTR
+# ifndef YY_NULL
# if defined __cplusplus && 201103L <= __cplusplus
-# define YY_NULLPTR nullptr
+# define YY_NULL nullptr
# else
-# define YY_NULLPTR 0
+# define YY_NULL 0
# endif
# endif
@@ -167,7 +168,7 @@ hbool_t is_opq_tag = 0; /*flag to lexer for opaque type tag*/
by #include "H5LTparse.h". */
#ifndef YY_H5LTYY_HL_SRC_H5LTPARSE_H_INCLUDED
# define YY_H5LTYY_HL_SRC_H5LTPARSE_H_INCLUDED
-/* Debug traces. */
+/* Enabling traces. */
#ifndef YYDEBUG
# define YYDEBUG 0
#endif
@@ -175,99 +176,113 @@ hbool_t is_opq_tag = 0; /*flag to lexer for opaque type tag*/
extern int H5LTyydebug;
#endif
-/* Token type. */
+/* Tokens. */
#ifndef YYTOKENTYPE
# define YYTOKENTYPE
- enum yytokentype
- {
- H5T_STD_I8BE_TOKEN = 258,
- H5T_STD_I8LE_TOKEN = 259,
- H5T_STD_I16BE_TOKEN = 260,
- H5T_STD_I16LE_TOKEN = 261,
- H5T_STD_I32BE_TOKEN = 262,
- H5T_STD_I32LE_TOKEN = 263,
- H5T_STD_I64BE_TOKEN = 264,
- H5T_STD_I64LE_TOKEN = 265,
- H5T_STD_U8BE_TOKEN = 266,
- H5T_STD_U8LE_TOKEN = 267,
- H5T_STD_U16BE_TOKEN = 268,
- H5T_STD_U16LE_TOKEN = 269,
- H5T_STD_U32BE_TOKEN = 270,
- H5T_STD_U32LE_TOKEN = 271,
- H5T_STD_U64BE_TOKEN = 272,
- H5T_STD_U64LE_TOKEN = 273,
- H5T_NATIVE_CHAR_TOKEN = 274,
- H5T_NATIVE_SCHAR_TOKEN = 275,
- H5T_NATIVE_UCHAR_TOKEN = 276,
- H5T_NATIVE_SHORT_TOKEN = 277,
- H5T_NATIVE_USHORT_TOKEN = 278,
- H5T_NATIVE_INT_TOKEN = 279,
- H5T_NATIVE_UINT_TOKEN = 280,
- H5T_NATIVE_LONG_TOKEN = 281,
- H5T_NATIVE_ULONG_TOKEN = 282,
- H5T_NATIVE_LLONG_TOKEN = 283,
- H5T_NATIVE_ULLONG_TOKEN = 284,
- H5T_IEEE_F32BE_TOKEN = 285,
- H5T_IEEE_F32LE_TOKEN = 286,
- H5T_IEEE_F64BE_TOKEN = 287,
- H5T_IEEE_F64LE_TOKEN = 288,
- H5T_NATIVE_FLOAT_TOKEN = 289,
- H5T_NATIVE_DOUBLE_TOKEN = 290,
- H5T_NATIVE_LDOUBLE_TOKEN = 291,
- H5T_STRING_TOKEN = 292,
- STRSIZE_TOKEN = 293,
- STRPAD_TOKEN = 294,
- CSET_TOKEN = 295,
- CTYPE_TOKEN = 296,
- H5T_VARIABLE_TOKEN = 297,
- H5T_STR_NULLTERM_TOKEN = 298,
- H5T_STR_NULLPAD_TOKEN = 299,
- H5T_STR_SPACEPAD_TOKEN = 300,
- H5T_CSET_ASCII_TOKEN = 301,
- H5T_CSET_UTF8_TOKEN = 302,
- H5T_C_S1_TOKEN = 303,
- H5T_FORTRAN_S1_TOKEN = 304,
- H5T_OPAQUE_TOKEN = 305,
- OPQ_SIZE_TOKEN = 306,
- OPQ_TAG_TOKEN = 307,
- H5T_COMPOUND_TOKEN = 308,
- H5T_ENUM_TOKEN = 309,
- H5T_ARRAY_TOKEN = 310,
- H5T_VLEN_TOKEN = 311,
- STRING = 312,
- NUMBER = 313
- };
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ H5T_STD_I8BE_TOKEN = 258,
+ H5T_STD_I8LE_TOKEN = 259,
+ H5T_STD_I16BE_TOKEN = 260,
+ H5T_STD_I16LE_TOKEN = 261,
+ H5T_STD_I32BE_TOKEN = 262,
+ H5T_STD_I32LE_TOKEN = 263,
+ H5T_STD_I64BE_TOKEN = 264,
+ H5T_STD_I64LE_TOKEN = 265,
+ H5T_STD_U8BE_TOKEN = 266,
+ H5T_STD_U8LE_TOKEN = 267,
+ H5T_STD_U16BE_TOKEN = 268,
+ H5T_STD_U16LE_TOKEN = 269,
+ H5T_STD_U32BE_TOKEN = 270,
+ H5T_STD_U32LE_TOKEN = 271,
+ H5T_STD_U64BE_TOKEN = 272,
+ H5T_STD_U64LE_TOKEN = 273,
+ H5T_NATIVE_CHAR_TOKEN = 274,
+ H5T_NATIVE_SCHAR_TOKEN = 275,
+ H5T_NATIVE_UCHAR_TOKEN = 276,
+ H5T_NATIVE_SHORT_TOKEN = 277,
+ H5T_NATIVE_USHORT_TOKEN = 278,
+ H5T_NATIVE_INT_TOKEN = 279,
+ H5T_NATIVE_UINT_TOKEN = 280,
+ H5T_NATIVE_LONG_TOKEN = 281,
+ H5T_NATIVE_ULONG_TOKEN = 282,
+ H5T_NATIVE_LLONG_TOKEN = 283,
+ H5T_NATIVE_ULLONG_TOKEN = 284,
+ H5T_IEEE_F32BE_TOKEN = 285,
+ H5T_IEEE_F32LE_TOKEN = 286,
+ H5T_IEEE_F64BE_TOKEN = 287,
+ H5T_IEEE_F64LE_TOKEN = 288,
+ H5T_NATIVE_FLOAT_TOKEN = 289,
+ H5T_NATIVE_DOUBLE_TOKEN = 290,
+ H5T_NATIVE_LDOUBLE_TOKEN = 291,
+ H5T_STRING_TOKEN = 292,
+ STRSIZE_TOKEN = 293,
+ STRPAD_TOKEN = 294,
+ CSET_TOKEN = 295,
+ CTYPE_TOKEN = 296,
+ H5T_VARIABLE_TOKEN = 297,
+ H5T_STR_NULLTERM_TOKEN = 298,
+ H5T_STR_NULLPAD_TOKEN = 299,
+ H5T_STR_SPACEPAD_TOKEN = 300,
+ H5T_CSET_ASCII_TOKEN = 301,
+ H5T_CSET_UTF8_TOKEN = 302,
+ H5T_C_S1_TOKEN = 303,
+ H5T_FORTRAN_S1_TOKEN = 304,
+ H5T_OPAQUE_TOKEN = 305,
+ OPQ_SIZE_TOKEN = 306,
+ OPQ_TAG_TOKEN = 307,
+ H5T_COMPOUND_TOKEN = 308,
+ H5T_ENUM_TOKEN = 309,
+ H5T_ARRAY_TOKEN = 310,
+ H5T_VLEN_TOKEN = 311,
+ STRING = 312,
+ NUMBER = 313
+ };
#endif
-/* Value type. */
-#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
-union YYSTYPE
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
{
-#line 72 "hl/src/H5LTparse.y" /* yacc.c:355 */
+/* Line 387 of yacc.c */
+#line 72 "hl/src/H5LTparse.y"
int ival; /*for integer token*/
char *sval; /*for name string*/
hid_t hid; /*for hid_t token*/
-#line 232 "hl/src/H5LTparse.c" /* yacc.c:355 */
-};
-typedef union YYSTYPE YYSTYPE;
+/* Line 387 of yacc.c */
+#line 236 "hl/src/H5LTparse.c"
+} YYSTYPE;
# define YYSTYPE_IS_TRIVIAL 1
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
# define YYSTYPE_IS_DECLARED 1
#endif
-
extern YYSTYPE H5LTyylval;
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+hid_t H5LTyyparse (void *YYPARSE_PARAM);
+#else
+hid_t H5LTyyparse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
hid_t H5LTyyparse (void);
+#else
+hid_t H5LTyyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
#endif /* !YY_H5LTYY_HL_SRC_H5LTPARSE_H_INCLUDED */
/* Copy the second part of user declarations. */
-#line 249 "hl/src/H5LTparse.c" /* yacc.c:358 */
+/* Line 390 of yacc.c */
+#line 264 "hl/src/H5LTparse.c"
#ifdef short
# undef short
@@ -281,8 +296,11 @@ typedef unsigned char yytype_uint8;
#ifdef YYTYPE_INT8
typedef YYTYPE_INT8 yytype_int8;
-#else
+#elif (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
typedef signed char yytype_int8;
+#else
+typedef short int yytype_int8;
#endif
#ifdef YYTYPE_UINT16
@@ -302,7 +320,8 @@ typedef short int yytype_int16;
# define YYSIZE_T __SIZE_TYPE__
# elif defined size_t
# define YYSIZE_T size_t
-# elif ! defined YYSIZE_T
+# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
# define YYSIZE_T size_t
# else
@@ -324,33 +343,6 @@ typedef short int yytype_int16;
# endif
#endif
-#ifndef YY_ATTRIBUTE
-# if (defined __GNUC__ \
- && (2 < __GNUC__ || (__GNUC__ == 2 && 96 <= __GNUC_MINOR__))) \
- || defined __SUNPRO_C && 0x5110 <= __SUNPRO_C
-# define YY_ATTRIBUTE(Spec) __attribute__(Spec)
-# else
-# define YY_ATTRIBUTE(Spec) /* empty */
-# endif
-#endif
-
-#ifndef YY_ATTRIBUTE_PURE
-# define YY_ATTRIBUTE_PURE YY_ATTRIBUTE ((__pure__))
-#endif
-
-#ifndef YY_ATTRIBUTE_UNUSED
-# define YY_ATTRIBUTE_UNUSED YY_ATTRIBUTE ((__unused__))
-#endif
-
-#if !defined _Noreturn \
- && (!defined __STDC_VERSION__ || __STDC_VERSION__ < 201112)
-# if defined _MSC_VER && 1200 <= _MSC_VER
-# define _Noreturn __declspec (noreturn)
-# else
-# define _Noreturn YY_ATTRIBUTE ((__noreturn__))
-# endif
-#endif
-
/* Suppress unused-variable warnings by "using" E. */
#if ! defined lint || defined __GNUC__
# define YYUSE(E) ((void) (E))
@@ -358,26 +350,24 @@ typedef short int yytype_int16;
# define YYUSE(E) /* empty */
#endif
-#if defined __GNUC__ && 407 <= __GNUC__ * 100 + __GNUC_MINOR__
-/* Suppress an incorrect diagnostic about yylval being uninitialized. */
-# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \
- _Pragma ("GCC diagnostic push") \
- _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")\
- _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"")
-# define YY_IGNORE_MAYBE_UNINITIALIZED_END \
- _Pragma ("GCC diagnostic pop")
+/* Identity function, used to suppress warnings about constant conditions. */
+#ifndef lint
+# define YYID(N) (N)
#else
-# define YY_INITIAL_VALUE(Value) Value
-#endif
-#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
-# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
-# define YY_IGNORE_MAYBE_UNINITIALIZED_END
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static int
+YYID (int yyi)
+#else
+static int
+YYID (yyi)
+ int yyi;
#endif
-#ifndef YY_INITIAL_VALUE
-# define YY_INITIAL_VALUE(Value) /* Nothing. */
+{
+ return yyi;
+}
#endif
-
#if ! defined yyoverflow || YYERROR_VERBOSE
/* The parser invokes alloca or malloc; define the necessary symbols. */
@@ -395,7 +385,8 @@ typedef short int yytype_int16;
# define alloca _alloca
# else
# define YYSTACK_ALLOC alloca
-# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS
+# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
/* Use EXIT_SUCCESS as a witness for stdlib.h. */
# ifndef EXIT_SUCCESS
@@ -407,8 +398,8 @@ typedef short int yytype_int16;
# endif
# ifdef YYSTACK_ALLOC
- /* Pacify GCC's 'empty if-body' warning. */
-# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0)
+ /* Pacify GCC's `empty if-body' warning. */
+# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
# ifndef YYSTACK_ALLOC_MAXIMUM
/* The OS might guarantee only one guard page at the bottom of the stack,
and a page size can be as small as 4096 bytes. So we cannot safely
@@ -424,7 +415,7 @@ typedef short int yytype_int16;
# endif
# if (defined __cplusplus && ! defined EXIT_SUCCESS \
&& ! ((defined YYMALLOC || defined malloc) \
- && (defined YYFREE || defined free)))
+ && (defined YYFREE || defined free)))
# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
# ifndef EXIT_SUCCESS
# define EXIT_SUCCESS 0
@@ -432,13 +423,15 @@ typedef short int yytype_int16;
# endif
# ifndef YYMALLOC
# define YYMALLOC malloc
-# if ! defined malloc && ! defined EXIT_SUCCESS
+# if ! defined malloc && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
# endif
# endif
# ifndef YYFREE
# define YYFREE free
-# if ! defined free && ! defined EXIT_SUCCESS
+# if ! defined free && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
void free (void *); /* INFRINGES ON USER NAME SPACE */
# endif
# endif
@@ -448,7 +441,7 @@ void free (void *); /* INFRINGES ON USER NAME SPACE */
#if (! defined yyoverflow \
&& (! defined __cplusplus \
- || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+ || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
/* A type that is properly aligned for any stack member. */
union yyalloc
@@ -473,16 +466,16 @@ union yyalloc
elements in the stack, and YYPTR gives the new location of the
stack. Advance YYPTR to a properly aligned location for the next
stack. */
-# define YYSTACK_RELOCATE(Stack_alloc, Stack) \
- do \
- { \
- YYSIZE_T yynewbytes; \
- YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \
- Stack = &yyptr->Stack_alloc; \
- yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
- yyptr += yynewbytes / sizeof (*yyptr); \
- } \
- while (0)
+# define YYSTACK_RELOCATE(Stack_alloc, Stack) \
+ do \
+ { \
+ YYSIZE_T yynewbytes; \
+ YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \
+ Stack = &yyptr->Stack_alloc; \
+ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+ yyptr += yynewbytes / sizeof (*yyptr); \
+ } \
+ while (YYID (0))
#endif
@@ -501,7 +494,7 @@ union yyalloc
for (yyi = 0; yyi < (Count); yyi++) \
(Dst)[yyi] = (Src)[yyi]; \
} \
- while (0)
+ while (YYID (0))
# endif
# endif
#endif /* !YYCOPY_NEEDED */
@@ -517,19 +510,17 @@ union yyalloc
#define YYNNTS 46
/* YYNRULES -- Number of rules. */
#define YYNRULES 95
-/* YYNSTATES -- Number of states. */
+/* YYNRULES -- Number of states. */
#define YYNSTATES 143
-/* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned
- by yylex, with out-of-bounds checking. */
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
#define YYUNDEFTOK 2
#define YYMAXUTOK 313
-#define YYTRANSLATE(YYX) \
+#define YYTRANSLATE(YYX) \
((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
-/* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM
- as returned by yylex, without out-of-bounds checking. */
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
static const yytype_uint8 yytranslate[] =
{
0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
@@ -567,7 +558,52 @@ static const yytype_uint8 yytranslate[] =
};
#if YYDEBUG
- /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+ YYRHS. */
+static const yytype_uint8 yyprhs[] =
+{
+ 0, 0, 3, 4, 6, 8, 10, 12, 14, 16,
+ 18, 20, 22, 24, 26, 28, 30, 32, 34, 36,
+ 38, 40, 42, 44, 46, 48, 50, 52, 54, 56,
+ 58, 60, 62, 64, 66, 68, 70, 72, 74, 76,
+ 78, 80, 82, 84, 86, 88, 90, 92, 93, 99,
+ 100, 103, 104, 112, 114, 115, 118, 120, 121, 128,
+ 129, 132, 133, 134, 140, 142, 147, 148, 149, 150,
+ 151, 167, 169, 171, 172, 173, 174, 175, 176, 197,
+ 199, 201, 203, 205, 207, 209, 211, 213, 215, 216,
+ 224, 225, 228, 229, 236, 238
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS. */
+static const yytype_int8 yyrhs[] =
+{
+ 67, 0, -1, -1, 68, -1, 69, -1, 72, -1,
+ 80, -1, 87, -1, 70, -1, 71, -1, 95, -1,
+ 105, -1, 88, -1, 3, -1, 4, -1, 5, -1,
+ 6, -1, 7, -1, 8, -1, 9, -1, 10, -1,
+ 11, -1, 12, -1, 13, -1, 14, -1, 15, -1,
+ 16, -1, 17, -1, 18, -1, 19, -1, 20, -1,
+ 21, -1, 22, -1, 23, -1, 24, -1, 25, -1,
+ 26, -1, 27, -1, 28, -1, 29, -1, 30, -1,
+ 31, -1, 32, -1, 33, -1, 34, -1, 35, -1,
+ 36, -1, -1, 53, 73, 59, 74, 60, -1, -1,
+ 74, 75, -1, -1, 68, 76, 63, 77, 63, 78,
+ 65, -1, 57, -1, -1, 64, 79, -1, 58, -1,
+ -1, 55, 81, 59, 82, 68, 60, -1, -1, 82,
+ 83, -1, -1, -1, 61, 84, 86, 85, 62, -1,
+ 58, -1, 56, 59, 68, 60, -1, -1, -1, -1,
+ -1, 50, 59, 51, 89, 93, 65, 90, 52, 91,
+ 63, 94, 63, 65, 92, 60, -1, 58, -1, 57,
+ -1, -1, -1, -1, -1, -1, 37, 59, 38, 96,
+ 101, 65, 97, 39, 102, 65, 98, 40, 103, 65,
+ 99, 41, 104, 65, 100, 60, -1, 42, -1, 58,
+ -1, 43, -1, 44, -1, 45, -1, 46, -1, 47,
+ -1, 48, -1, 49, -1, -1, 54, 59, 70, 65,
+ 106, 107, 60, -1, -1, 107, 108, -1, -1, 63,
+ 110, 63, 109, 111, 65, -1, 57, -1, 58, -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
static const yytype_uint16 yyrline[] =
{
0, 105, 105, 106, 108, 109, 110, 111, 113, 114,
@@ -616,13 +652,13 @@ static const char *const yytname[] =
"$@5", "dimsize", "vlen_type", "opaque_type", "$@6", "@7", "$@8", "$@9",
"opaque_size", "opaque_tag", "string_type", "$@10", "$@11", "$@12",
"$@13", "@14", "strsize", "strpad", "cset", "ctype", "enum_type", "$@15",
- "enum_list", "enum_def", "$@16", "enum_symbol", "enum_val", YY_NULLPTR
+ "enum_list", "enum_def", "$@16", "enum_symbol", "enum_val", YY_NULL
};
#endif
# ifdef YYPRINT
-/* YYTOKNUM[NUM] -- (External) token number corresponding to the
- (internal) symbol number NUM (which must be that of a token). */
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+ token YYLEX-NUM. */
static const yytype_uint16 yytoknum[] =
{
0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
@@ -635,40 +671,39 @@ static const yytype_uint16 yytoknum[] =
};
# endif
-#define YYPACT_NINF -25
-
-#define yypact_value_is_default(Yystate) \
- (!!((Yystate) == (-25)))
-
-#define YYTABLE_NINF -1
-
-#define yytable_value_is_error(Yytable_value) \
- 0
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
+static const yytype_uint8 yyr1[] =
+{
+ 0, 66, 67, 67, 68, 68, 68, 68, 69, 69,
+ 69, 69, 69, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 71, 71, 71, 71, 71, 71, 71, 73, 72, 74,
+ 74, 76, 75, 77, 78, 78, 79, 81, 80, 82,
+ 82, 84, 85, 83, 86, 87, 89, 90, 91, 92,
+ 88, 93, 94, 96, 97, 98, 99, 100, 95, 101,
+ 101, 102, 102, 102, 103, 103, 104, 104, 106, 105,
+ 107, 107, 109, 108, 110, 111
+};
- /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
- STATE-NUM. */
-static const yytype_int16 yypact[] =
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
+static const yytype_uint8 yyr2[] =
{
- 114, -25, -25, -25, -25, -25, -25, -25, -25, -25,
- -25, -25, -25, -25, -25, -25, -25, -25, -25, -25,
- -25, -25, -25, -25, -25, -25, -25, -25, -25, -25,
- -25, -25, -25, -25, -25, -24, -20, -25, -15, -25,
- -14, 49, -25, -25, -25, -25, -25, -25, -25, -25,
- -25, -25, 19, 45, 38, 168, 39, 114, -25, -25,
- -25, -25, 34, -25, 40, -4, 43, 56, -25, -3,
- -25, -25, -25, 37, -25, 42, -25, -25, -25, -25,
- -25, 44, -25, -25, -25, 50, -23, 47, -25, 64,
- 62, 51, -25, 58, -25, -25, -25, -2, -25, -25,
- 89, -25, 90, 92, -25, -25, -25, 91, 94, 95,
- -25, -25, -25, 98, 100, 96, 102, 122, -25, 103,
- -25, -25, -25, -25, 133, 9, 134, -25, -25, -25,
- 135, -25, -25, 105, 160, -25, 46, -25, -25, 137,
- -25, 143, -25
+ 0, 2, 0, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 0, 5, 0,
+ 2, 0, 7, 1, 0, 2, 1, 0, 6, 0,
+ 2, 0, 0, 5, 1, 4, 0, 0, 0, 0,
+ 15, 1, 1, 0, 0, 0, 0, 0, 20, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 0, 7,
+ 0, 2, 0, 6, 1, 1
};
- /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM.
- Performed when YYTABLE does not specify something else to do. Zero
- means the default is an error. */
+/* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM.
+ Performed when YYTABLE doesn't specify something else to do. Zero
+ means the default is an error. */
static const yytype_uint8 yydefact[] =
{
2, 13, 14, 15, 16, 17, 18, 19, 20, 21,
@@ -688,17 +723,7 @@ static const yytype_uint8 yydefact[] =
77, 0, 78
};
- /* YYPGOTO[NTERM-NUM]. */
-static const yytype_int8 yypgoto[] =
-{
- -25, -25, -21, -25, 108, -25, -25, -25, -25, -25,
- -25, -25, -25, -25, -25, -25, -25, -25, -25, -25,
- -25, -25, -25, -25, -25, -25, -25, -25, -25, -25,
- -25, -25, -25, -25, -25, -25, -25, -25, -25, -25,
- -25, -25, -25, -25, -25, -25
-};
-
- /* YYDEFGOTO[NTERM-NUM]. */
+/* YYDEFGOTO[NTERM-NUM]. */
static const yytype_int16 yydefgoto[] =
{
-1, 41, 42, 43, 44, 45, 46, 54, 67, 78,
@@ -708,9 +733,42 @@ static const yytype_int16 yydefgoto[] =
79, 86, 94, 116, 102, 124
};
- /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If
- positive, shift that token. If negative, reduce the rule whose
- number is the opposite. If YYTABLE_NINF, syntax error. */
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+ STATE-NUM. */
+#define YYPACT_NINF -25
+static const yytype_int16 yypact[] =
+{
+ 114, -25, -25, -25, -25, -25, -25, -25, -25, -25,
+ -25, -25, -25, -25, -25, -25, -25, -25, -25, -25,
+ -25, -25, -25, -25, -25, -25, -25, -25, -25, -25,
+ -25, -25, -25, -25, -25, -24, -20, -25, -15, -25,
+ -14, 49, -25, -25, -25, -25, -25, -25, -25, -25,
+ -25, -25, 19, 45, 38, 168, 39, 114, -25, -25,
+ -25, -25, 34, -25, 40, -4, 43, 56, -25, -3,
+ -25, -25, -25, 37, -25, 42, -25, -25, -25, -25,
+ -25, 44, -25, -25, -25, 50, -23, 47, -25, 64,
+ 62, 51, -25, 58, -25, -25, -25, -2, -25, -25,
+ 89, -25, 90, 92, -25, -25, -25, 91, 94, 95,
+ -25, -25, -25, 98, 100, 96, 102, 122, -25, 103,
+ -25, -25, -25, -25, 133, 9, 134, -25, -25, -25,
+ 135, -25, -25, 105, 160, -25, 46, -25, -25, 137,
+ -25, 143, -25
+};
+
+/* YYPGOTO[NTERM-NUM]. */
+static const yytype_int8 yypgoto[] =
+{
+ -25, -25, -21, -25, 108, -25, -25, -25, -25, -25,
+ -25, -25, -25, -25, -25, -25, -25, -25, -25, -25,
+ -25, -25, -25, -25, -25, -25, -25, -25, -25, -25,
+ -25, -25, -25, -25, -25, -25, -25, -25, -25, -25,
+ -25, -25, -25, -25, -25, -25
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
+ positive, shift that token. If negative, reduce the rule which
+ number is the opposite. If YYTABLE_NINF, syntax error. */
+#define YYTABLE_NINF -1
static const yytype_uint8 yytable[] =
{
1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
@@ -736,6 +794,12 @@ static const yytype_uint8 yytable[] =
132, 136, 140, 142
};
+#define yypact_value_is_default(Yystate) \
+ (!!((Yystate) == (-25)))
+
+#define yytable_value_is_error(Yytable_value) \
+ YYID (0)
+
static const yytype_uint8 yycheck[] =
{
3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
@@ -761,8 +825,8 @@ static const yytype_uint8 yycheck[] =
65, 41, 65, 60
};
- /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
- symbol of state STATE-NUM. */
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+ symbol of state STATE-NUM. */
static const yytype_uint8 yystos[] =
{
0, 3, 4, 5, 6, 7, 8, 9, 10, 11,
@@ -782,46 +846,30 @@ static const yytype_uint8 yystos[] =
65, 100, 60
};
- /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
-static const yytype_uint8 yyr1[] =
-{
- 0, 66, 67, 67, 68, 68, 68, 68, 69, 69,
- 69, 69, 69, 70, 70, 70, 70, 70, 70, 70,
- 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
- 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
- 71, 71, 71, 71, 71, 71, 71, 73, 72, 74,
- 74, 76, 75, 77, 78, 78, 79, 81, 80, 82,
- 82, 84, 85, 83, 86, 87, 89, 90, 91, 92,
- 88, 93, 94, 96, 97, 98, 99, 100, 95, 101,
- 101, 102, 102, 102, 103, 103, 104, 104, 106, 105,
- 107, 107, 109, 108, 110, 111
-};
-
- /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */
-static const yytype_uint8 yyr2[] =
-{
- 0, 2, 0, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 0, 5, 0,
- 2, 0, 7, 1, 0, 2, 1, 0, 6, 0,
- 2, 0, 0, 5, 1, 4, 0, 0, 0, 0,
- 15, 1, 1, 0, 0, 0, 0, 0, 20, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 0, 7,
- 0, 2, 0, 6, 1, 1
-};
-
-
-#define yyerrok (yyerrstatus = 0)
-#define yyclearin (yychar = YYEMPTY)
-#define YYEMPTY (-2)
-#define YYEOF 0
-
-#define YYACCEPT goto yyacceptlab
-#define YYABORT goto yyabortlab
-#define YYERROR goto yyerrorlab
-
+#define yyerrok (yyerrstatus = 0)
+#define yyclearin (yychar = YYEMPTY)
+#define YYEMPTY (-2)
+#define YYEOF 0
+
+#define YYACCEPT goto yyacceptlab
+#define YYABORT goto yyabortlab
+#define YYERROR goto yyerrorlab
+
+
+/* Like YYERROR except do call yyerror. This remains here temporarily
+ to ease the transition to the new meaning of YYERROR, for GCC.
+ Once GCC version 2 has supplanted version 1, this can go. However,
+ YYFAIL appears to be in use. Nevertheless, it is formally deprecated
+ in Bison 2.4.2's NEWS entry, where a plan to phase it out is
+ discussed. */
+
+#define YYFAIL goto yyerrlab
+#if defined YYFAIL
+ /* This is here to suppress warnings from the GCC cpp's
+ -Wunused-macros. Normally we don't worry about that warning, but
+ some users do, and we want to make it easy for users to remove
+ YYFAIL uses, which will produce warnings from Bison 2.5. */
+#endif
#define YYRECOVERING() (!!yyerrstatus)
@@ -838,15 +886,27 @@ do \
else \
{ \
yyerror (YY_("syntax error: cannot back up")); \
- YYERROR; \
- } \
-while (0)
+ YYERROR; \
+ } \
+while (YYID (0))
/* Error token number */
-#define YYTERROR 1
-#define YYERRCODE 256
+#define YYTERROR 1
+#define YYERRCODE 256
+/* This macro is provided for backward compatibility. */
+#ifndef YY_LOCATION_PRINT
+# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+#endif
+
+
+/* YYLEX -- calling `yylex' with the right arguments. */
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (YYLEX_PARAM)
+#else
+# define YYLEX yylex ()
+#endif
/* Enable debugging if requested. */
#if YYDEBUG
@@ -856,36 +916,40 @@ while (0)
# define YYFPRINTF fprintf
# endif
-# define YYDPRINTF(Args) \
-do { \
- if (yydebug) \
- YYFPRINTF Args; \
-} while (0)
-
-/* This macro is provided for backward compatibility. */
-#ifndef YY_LOCATION_PRINT
-# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
-#endif
+# define YYDPRINTF(Args) \
+do { \
+ if (yydebug) \
+ YYFPRINTF Args; \
+} while (YYID (0))
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \
+do { \
+ if (yydebug) \
+ { \
+ YYFPRINTF (stderr, "%s ", Title); \
+ yy_symbol_print (stderr, \
+ Type, Value); \
+ YYFPRINTF (stderr, "\n"); \
+ } \
+} while (YYID (0))
-# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \
-do { \
- if (yydebug) \
- { \
- YYFPRINTF (stderr, "%s ", Title); \
- yy_symbol_print (stderr, \
- Type, Value); \
- YYFPRINTF (stderr, "\n"); \
- } \
-} while (0)
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
-/*----------------------------------------.
-| Print this symbol's value on YYOUTPUT. |
-`----------------------------------------*/
-
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
static void
yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_value_print (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE const * const yyvaluep;
+#endif
{
FILE *yyo = yyoutput;
YYUSE (yyo);
@@ -894,8 +958,14 @@ yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvalue
# ifdef YYPRINT
if (yytype < YYNTOKENS)
YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# else
+ YYUSE (yyoutput);
# endif
- YYUSE (yytype);
+ switch (yytype)
+ {
+ default:
+ break;
+ }
}
@@ -903,11 +973,22 @@ yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvalue
| Print this symbol on YYOUTPUT. |
`--------------------------------*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
static void
yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_print (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE const * const yyvaluep;
+#endif
{
- YYFPRINTF (yyoutput, "%s %s (",
- yytype < YYNTOKENS ? "token" : "nterm", yytname[yytype]);
+ if (yytype < YYNTOKENS)
+ YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+ else
+ YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
yy_symbol_value_print (yyoutput, yytype, yyvaluep);
YYFPRINTF (yyoutput, ")");
@@ -918,8 +999,16 @@ yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
| TOP (included). |
`------------------------------------------------------------------*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
static void
yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop)
+#else
+static void
+yy_stack_print (yybottom, yytop)
+ yytype_int16 *yybottom;
+ yytype_int16 *yytop;
+#endif
{
YYFPRINTF (stderr, "Stack now");
for (; yybottom <= yytop; yybottom++)
@@ -930,42 +1019,49 @@ yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop)
YYFPRINTF (stderr, "\n");
}
-# define YY_STACK_PRINT(Bottom, Top) \
-do { \
- if (yydebug) \
- yy_stack_print ((Bottom), (Top)); \
-} while (0)
+# define YY_STACK_PRINT(Bottom, Top) \
+do { \
+ if (yydebug) \
+ yy_stack_print ((Bottom), (Top)); \
+} while (YYID (0))
/*------------------------------------------------.
| Report that the YYRULE is going to be reduced. |
`------------------------------------------------*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_reduce_print (YYSTYPE *yyvsp, int yyrule)
+#else
static void
-yy_reduce_print (yytype_int16 *yyssp, YYSTYPE *yyvsp, int yyrule)
+yy_reduce_print (yyvsp, yyrule)
+ YYSTYPE *yyvsp;
+ int yyrule;
+#endif
{
- unsigned long int yylno = yyrline[yyrule];
int yynrhs = yyr2[yyrule];
int yyi;
+ unsigned long int yylno = yyrline[yyrule];
YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
- yyrule - 1, yylno);
+ yyrule - 1, yylno);
/* The symbols being reduced. */
for (yyi = 0; yyi < yynrhs; yyi++)
{
YYFPRINTF (stderr, " $%d = ", yyi + 1);
- yy_symbol_print (stderr,
- yystos[yyssp[yyi + 1 - yynrhs]],
- &(yyvsp[(yyi + 1) - (yynrhs)])
- );
+ yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
+ &(yyvsp[(yyi + 1) - (yynrhs)])
+ );
YYFPRINTF (stderr, "\n");
}
}
-# define YY_REDUCE_PRINT(Rule) \
-do { \
- if (yydebug) \
- yy_reduce_print (yyssp, yyvsp, Rule); \
-} while (0)
+# define YY_REDUCE_PRINT(Rule) \
+do { \
+ if (yydebug) \
+ yy_reduce_print (yyvsp, Rule); \
+} while (YYID (0))
/* Nonzero means print parse trace. It is left uninitialized so that
multiple parsers can coexist. */
@@ -979,7 +1075,7 @@ int yydebug;
/* YYINITDEPTH -- initial size of the parser's stacks. */
-#ifndef YYINITDEPTH
+#ifndef YYINITDEPTH
# define YYINITDEPTH 200
#endif
@@ -1002,8 +1098,15 @@ int yydebug;
# define yystrlen strlen
# else
/* Return the length of YYSTR. */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
static YYSIZE_T
yystrlen (const char *yystr)
+#else
+static YYSIZE_T
+yystrlen (yystr)
+ const char *yystr;
+#endif
{
YYSIZE_T yylen;
for (yylen = 0; yystr[yylen]; yylen++)
@@ -1019,8 +1122,16 @@ yystrlen (const char *yystr)
# else
/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
YYDEST. */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
static char *
yystpcpy (char *yydest, const char *yysrc)
+#else
+static char *
+yystpcpy (yydest, yysrc)
+ char *yydest;
+ const char *yysrc;
+#endif
{
char *yyd = yydest;
const char *yys = yysrc;
@@ -1050,27 +1161,27 @@ yytnamerr (char *yyres, const char *yystr)
char const *yyp = yystr;
for (;;)
- switch (*++yyp)
- {
- case '\'':
- case ',':
- goto do_not_strip_quotes;
-
- case '\\':
- if (*++yyp != '\\')
- goto do_not_strip_quotes;
- /* Fall through. */
- default:
- if (yyres)
- yyres[yyn] = *yyp;
- yyn++;
- break;
-
- case '"':
- if (yyres)
- yyres[yyn] = '\0';
- return yyn;
- }
+ switch (*++yyp)
+ {
+ case '\'':
+ case ',':
+ goto do_not_strip_quotes;
+
+ case '\\':
+ if (*++yyp != '\\')
+ goto do_not_strip_quotes;
+ /* Fall through. */
+ default:
+ if (yyres)
+ yyres[yyn] = *yyp;
+ yyn++;
+ break;
+
+ case '"':
+ if (yyres)
+ yyres[yyn] = '\0';
+ return yyn;
+ }
do_not_strip_quotes: ;
}
@@ -1093,11 +1204,11 @@ static int
yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
yytype_int16 *yyssp, int yytoken)
{
- YYSIZE_T yysize0 = yytnamerr (YY_NULLPTR, yytname[yytoken]);
+ YYSIZE_T yysize0 = yytnamerr (YY_NULL, yytname[yytoken]);
YYSIZE_T yysize = yysize0;
enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
/* Internationalized format string. */
- const char *yyformat = YY_NULLPTR;
+ const char *yyformat = YY_NULL;
/* Arguments of yyformat. */
char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
/* Number of reported tokens (one for the "unexpected", one per
@@ -1105,6 +1216,10 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
int yycount = 0;
/* There are many possibilities here to consider:
+ - Assume YYFAIL is not used. It's too flawed to consider. See
+ <http://lists.gnu.org/archive/html/bison-patches/2009-12/msg00024.html>
+ for details. YYERROR is fine as it does not invoke this
+ function.
- If this state is a consistent state with a default action, then
the only way this function was invoked is if the default action
is an error action. In that case, don't check for expected
@@ -1154,7 +1269,7 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
}
yyarg[yycount++] = yytname[yyx];
{
- YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULLPTR, yytname[yyx]);
+ YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULL, yytname[yyx]);
if (! (yysize <= yysize1
&& yysize1 <= YYSTACK_ALLOC_MAXIMUM))
return 2;
@@ -1221,17 +1336,31 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
| Release the memory associated to this symbol. |
`-----------------------------------------------*/
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
static void
yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yydestruct (yymsg, yytype, yyvaluep)
+ const char *yymsg;
+ int yytype;
+ YYSTYPE *yyvaluep;
+#endif
{
YYUSE (yyvaluep);
+
if (!yymsg)
yymsg = "Deleting";
YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
- YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
- YYUSE (yytype);
- YY_IGNORE_MAYBE_UNINITIALIZED_END
+ switch (yytype)
+ {
+
+ default:
+ break;
+ }
}
@@ -1240,8 +1369,18 @@ yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
/* The lookahead symbol. */
int yychar;
+
+#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_END
+#endif
+#ifndef YY_INITIAL_VALUE
+# define YY_INITIAL_VALUE(Value) /* Nothing. */
+#endif
+
/* The semantic value of the lookahead symbol. */
-YYSTYPE yylval;
+YYSTYPE yylval YY_INITIAL_VALUE(yyval_default);
+
/* Number of syntax errors so far. */
int yynerrs;
@@ -1250,16 +1389,35 @@ int yynerrs;
| yyparse. |
`----------*/
+#ifdef YYPARSE_PARAM
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+hid_t
+yyparse (void *YYPARSE_PARAM)
+#else
+hid_t
+yyparse (YYPARSE_PARAM)
+ void *YYPARSE_PARAM;
+#endif
+#else /* ! YYPARSE_PARAM */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
hid_t
yyparse (void)
+#else
+hid_t
+yyparse ()
+
+#endif
+#endif
{
int yystate;
/* Number of tokens to shift before error messages enabled. */
int yyerrstatus;
/* The stacks and their tools:
- 'yyss': related to states.
- 'yyvs': related to semantic values.
+ `yyss': related to states.
+ `yyvs': related to semantic values.
Refer to the stacks through separate pointers, to allow yyoverflow
to reallocate them elsewhere. */
@@ -1327,23 +1485,23 @@ yyparse (void)
#ifdef yyoverflow
{
- /* Give user a chance to reallocate the stack. Use copies of
- these so that the &'s don't force the real ones into
- memory. */
- YYSTYPE *yyvs1 = yyvs;
- yytype_int16 *yyss1 = yyss;
-
- /* Each stack pointer address is followed by the size of the
- data in use in that stack, in bytes. This used to be a
- conditional around just the two extra args, but that might
- be undefined if yyoverflow is a macro. */
- yyoverflow (YY_("memory exhausted"),
- &yyss1, yysize * sizeof (*yyssp),
- &yyvs1, yysize * sizeof (*yyvsp),
- &yystacksize);
-
- yyss = yyss1;
- yyvs = yyvs1;
+ /* Give user a chance to reallocate the stack. Use copies of
+ these so that the &'s don't force the real ones into
+ memory. */
+ YYSTYPE *yyvs1 = yyvs;
+ yytype_int16 *yyss1 = yyss;
+
+ /* Each stack pointer address is followed by the size of the
+ data in use in that stack, in bytes. This used to be a
+ conditional around just the two extra args, but that might
+ be undefined if yyoverflow is a macro. */
+ yyoverflow (YY_("memory exhausted"),
+ &yyss1, yysize * sizeof (*yyssp),
+ &yyvs1, yysize * sizeof (*yyvsp),
+ &yystacksize);
+
+ yyss = yyss1;
+ yyvs = yyvs1;
}
#else /* no yyoverflow */
# ifndef YYSTACK_RELOCATE
@@ -1351,22 +1509,22 @@ yyparse (void)
# else
/* Extend the stack our own way. */
if (YYMAXDEPTH <= yystacksize)
- goto yyexhaustedlab;
+ goto yyexhaustedlab;
yystacksize *= 2;
if (YYMAXDEPTH < yystacksize)
- yystacksize = YYMAXDEPTH;
+ yystacksize = YYMAXDEPTH;
{
- yytype_int16 *yyss1 = yyss;
- union yyalloc *yyptr =
- (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
- if (! yyptr)
- goto yyexhaustedlab;
- YYSTACK_RELOCATE (yyss_alloc, yyss);
- YYSTACK_RELOCATE (yyvs_alloc, yyvs);
+ yytype_int16 *yyss1 = yyss;
+ union yyalloc *yyptr =
+ (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+ if (! yyptr)
+ goto yyexhaustedlab;
+ YYSTACK_RELOCATE (yyss_alloc, yyss);
+ YYSTACK_RELOCATE (yyvs_alloc, yyvs);
# undef YYSTACK_RELOCATE
- if (yyss1 != yyssa)
- YYSTACK_FREE (yyss1);
+ if (yyss1 != yyssa)
+ YYSTACK_FREE (yyss1);
}
# endif
#endif /* no yyoverflow */
@@ -1375,10 +1533,10 @@ yyparse (void)
yyvsp = yyvs + yysize - 1;
YYDPRINTF ((stderr, "Stack size increased to %lu\n",
- (unsigned long int) yystacksize));
+ (unsigned long int) yystacksize));
if (yyss + yystacksize - 1 <= yyssp)
- YYABORT;
+ YYABORT;
}
YYDPRINTF ((stderr, "Entering state %d\n", yystate));
@@ -1407,7 +1565,7 @@ yybackup:
if (yychar == YYEMPTY)
{
YYDPRINTF ((stderr, "Reading a token: "));
- yychar = yylex ();
+ yychar = YYLEX;
}
if (yychar <= YYEOF)
@@ -1472,7 +1630,7 @@ yyreduce:
yylen = yyr2[yyn];
/* If YYLEN is nonzero, implement the default value of the action:
- '$$ = $1'.
+ `$$ = $1'.
Otherwise, the following line sets YYVAL to garbage.
This behavior is undocumented and Bison
@@ -1486,439 +1644,440 @@ yyreduce:
switch (yyn)
{
case 2:
-#line 105 "hl/src/H5LTparse.y" /* yacc.c:1646 */
+/* Line 1792 of yacc.c */
+#line 105 "hl/src/H5LTparse.y"
{ memset(arr_stack, 0, STACK_SIZE*sizeof(struct arr_info)); /*initialize here?*/ }
-#line 1470 "hl/src/H5LTparse.c" /* yacc.c:1646 */
break;
case 3:
-#line 106 "hl/src/H5LTparse.y" /* yacc.c:1646 */
+/* Line 1792 of yacc.c */
+#line 106 "hl/src/H5LTparse.y"
{ return (yyval.hid);}
-#line 1476 "hl/src/H5LTparse.c" /* yacc.c:1646 */
break;
case 13:
-#line 120 "hl/src/H5LTparse.y" /* yacc.c:1646 */
+/* Line 1792 of yacc.c */
+#line 120 "hl/src/H5LTparse.y"
{ (yyval.hid) = H5Tcopy(H5T_STD_I8BE); }
-#line 1482 "hl/src/H5LTparse.c" /* yacc.c:1646 */
break;
case 14:
-#line 121 "hl/src/H5LTparse.y" /* yacc.c:1646 */
+/* Line 1792 of yacc.c */
+#line 121 "hl/src/H5LTparse.y"
{ (yyval.hid) = H5Tcopy(H5T_STD_I8LE); }
-#line 1488 "hl/src/H5LTparse.c" /* yacc.c:1646 */
break;
case 15:
-#line 122 "hl/src/H5LTparse.y" /* yacc.c:1646 */
+/* Line 1792 of yacc.c */
+#line 122 "hl/src/H5LTparse.y"
{ (yyval.hid) = H5Tcopy(H5T_STD_I16BE); }
-#line 1494 "hl/src/H5LTparse.c" /* yacc.c:1646 */
break;
case 16:
-#line 123 "hl/src/H5LTparse.y" /* yacc.c:1646 */
+/* Line 1792 of yacc.c */
+#line 123 "hl/src/H5LTparse.y"
{ (yyval.hid) = H5Tcopy(H5T_STD_I16LE); }
-#line 1500 "hl/src/H5LTparse.c" /* yacc.c:1646 */
break;
case 17:
-#line 124 "hl/src/H5LTparse.y" /* yacc.c:1646 */
+/* Line 1792 of yacc.c */
+#line 124 "hl/src/H5LTparse.y"
{ (yyval.hid) = H5Tcopy(H5T_STD_I32BE); }
-#line 1506 "hl/src/H5LTparse.c" /* yacc.c:1646 */
break;
case 18:
-#line 125 "hl/src/H5LTparse.y" /* yacc.c:1646 */
+/* Line 1792 of yacc.c */
+#line 125 "hl/src/H5LTparse.y"
{ (yyval.hid) = H5Tcopy(H5T_STD_I32LE); }
-#line 1512 "hl/src/H5LTparse.c" /* yacc.c:1646 */
break;
case 19:
-#line 126 "hl/src/H5LTparse.y" /* yacc.c:1646 */
+/* Line 1792 of yacc.c */
+#line 126 "hl/src/H5LTparse.y"
{ (yyval.hid) = H5Tcopy(H5T_STD_I64BE); }
-#line 1518 "hl/src/H5LTparse.c" /* yacc.c:1646 */
break;
case 20:
-#line 127 "hl/src/H5LTparse.y" /* yacc.c:1646 */
+/* Line 1792 of yacc.c */
+#line 127 "hl/src/H5LTparse.y"
{ (yyval.hid) = H5Tcopy(H5T_STD_I64LE); }
-#line 1524 "hl/src/H5LTparse.c" /* yacc.c:1646 */
break;
case 21:
-#line 128 "hl/src/H5LTparse.y" /* yacc.c:1646 */
+/* Line 1792 of yacc.c */
+#line 128 "hl/src/H5LTparse.y"
{ (yyval.hid) = H5Tcopy(H5T_STD_U8BE); }
-#line 1530 "hl/src/H5LTparse.c" /* yacc.c:1646 */
break;
case 22:
-#line 129 "hl/src/H5LTparse.y" /* yacc.c:1646 */
+/* Line 1792 of yacc.c */
+#line 129 "hl/src/H5LTparse.y"
{ (yyval.hid) = H5Tcopy(H5T_STD_U8LE); }
-#line 1536 "hl/src/H5LTparse.c" /* yacc.c:1646 */
break;
case 23:
-#line 130 "hl/src/H5LTparse.y" /* yacc.c:1646 */
+/* Line 1792 of yacc.c */
+#line 130 "hl/src/H5LTparse.y"
{ (yyval.hid) = H5Tcopy(H5T_STD_U16BE); }
-#line 1542 "hl/src/H5LTparse.c" /* yacc.c:1646 */
break;
case 24:
-#line 131 "hl/src/H5LTparse.y" /* yacc.c:1646 */
+/* Line 1792 of yacc.c */
+#line 131 "hl/src/H5LTparse.y"
{ (yyval.hid) = H5Tcopy(H5T_STD_U16LE); }
-#line 1548 "hl/src/H5LTparse.c" /* yacc.c:1646 */
break;
case 25:
-#line 132 "hl/src/H5LTparse.y" /* yacc.c:1646 */
+/* Line 1792 of yacc.c */
+#line 132 "hl/src/H5LTparse.y"
{ (yyval.hid) = H5Tcopy(H5T_STD_U32BE); }
-#line 1554 "hl/src/H5LTparse.c" /* yacc.c:1646 */
break;
case 26:
-#line 133 "hl/src/H5LTparse.y" /* yacc.c:1646 */
+/* Line 1792 of yacc.c */
+#line 133 "hl/src/H5LTparse.y"
{ (yyval.hid) = H5Tcopy(H5T_STD_U32LE); }
-#line 1560 "hl/src/H5LTparse.c" /* yacc.c:1646 */
break;
case 27:
-#line 134 "hl/src/H5LTparse.y" /* yacc.c:1646 */
+/* Line 1792 of yacc.c */
+#line 134 "hl/src/H5LTparse.y"
{ (yyval.hid) = H5Tcopy(H5T_STD_U64BE); }
-#line 1566 "hl/src/H5LTparse.c" /* yacc.c:1646 */
break;
case 28:
-#line 135 "hl/src/H5LTparse.y" /* yacc.c:1646 */
+/* Line 1792 of yacc.c */
+#line 135 "hl/src/H5LTparse.y"
{ (yyval.hid) = H5Tcopy(H5T_STD_U64LE); }
-#line 1572 "hl/src/H5LTparse.c" /* yacc.c:1646 */
break;
case 29:
-#line 136 "hl/src/H5LTparse.y" /* yacc.c:1646 */
+/* Line 1792 of yacc.c */
+#line 136 "hl/src/H5LTparse.y"
{ (yyval.hid) = H5Tcopy(H5T_NATIVE_CHAR); }
-#line 1578 "hl/src/H5LTparse.c" /* yacc.c:1646 */
break;
case 30:
-#line 137 "hl/src/H5LTparse.y" /* yacc.c:1646 */
+/* Line 1792 of yacc.c */
+#line 137 "hl/src/H5LTparse.y"
{ (yyval.hid) = H5Tcopy(H5T_NATIVE_SCHAR); }
-#line 1584 "hl/src/H5LTparse.c" /* yacc.c:1646 */
break;
case 31:
-#line 138 "hl/src/H5LTparse.y" /* yacc.c:1646 */
+/* Line 1792 of yacc.c */
+#line 138 "hl/src/H5LTparse.y"
{ (yyval.hid) = H5Tcopy(H5T_NATIVE_UCHAR); }
-#line 1590 "hl/src/H5LTparse.c" /* yacc.c:1646 */
break;
case 32:
-#line 139 "hl/src/H5LTparse.y" /* yacc.c:1646 */
+/* Line 1792 of yacc.c */
+#line 139 "hl/src/H5LTparse.y"
{ (yyval.hid) = H5Tcopy(H5T_NATIVE_SHORT); }
-#line 1596 "hl/src/H5LTparse.c" /* yacc.c:1646 */
break;
case 33:
-#line 140 "hl/src/H5LTparse.y" /* yacc.c:1646 */
+/* Line 1792 of yacc.c */
+#line 140 "hl/src/H5LTparse.y"
{ (yyval.hid) = H5Tcopy(H5T_NATIVE_USHORT); }
-#line 1602 "hl/src/H5LTparse.c" /* yacc.c:1646 */
break;
case 34:
-#line 141 "hl/src/H5LTparse.y" /* yacc.c:1646 */
+/* Line 1792 of yacc.c */
+#line 141 "hl/src/H5LTparse.y"
{ (yyval.hid) = H5Tcopy(H5T_NATIVE_INT); }
-#line 1608 "hl/src/H5LTparse.c" /* yacc.c:1646 */
break;
case 35:
-#line 142 "hl/src/H5LTparse.y" /* yacc.c:1646 */
+/* Line 1792 of yacc.c */
+#line 142 "hl/src/H5LTparse.y"
{ (yyval.hid) = H5Tcopy(H5T_NATIVE_UINT); }
-#line 1614 "hl/src/H5LTparse.c" /* yacc.c:1646 */
break;
case 36:
-#line 143 "hl/src/H5LTparse.y" /* yacc.c:1646 */
+/* Line 1792 of yacc.c */
+#line 143 "hl/src/H5LTparse.y"
{ (yyval.hid) = H5Tcopy(H5T_NATIVE_LONG); }
-#line 1620 "hl/src/H5LTparse.c" /* yacc.c:1646 */
break;
case 37:
-#line 144 "hl/src/H5LTparse.y" /* yacc.c:1646 */
+/* Line 1792 of yacc.c */
+#line 144 "hl/src/H5LTparse.y"
{ (yyval.hid) = H5Tcopy(H5T_NATIVE_ULONG); }
-#line 1626 "hl/src/H5LTparse.c" /* yacc.c:1646 */
break;
case 38:
-#line 145 "hl/src/H5LTparse.y" /* yacc.c:1646 */
+/* Line 1792 of yacc.c */
+#line 145 "hl/src/H5LTparse.y"
{ (yyval.hid) = H5Tcopy(H5T_NATIVE_LLONG); }
-#line 1632 "hl/src/H5LTparse.c" /* yacc.c:1646 */
break;
case 39:
-#line 146 "hl/src/H5LTparse.y" /* yacc.c:1646 */
+/* Line 1792 of yacc.c */
+#line 146 "hl/src/H5LTparse.y"
{ (yyval.hid) = H5Tcopy(H5T_NATIVE_ULLONG); }
-#line 1638 "hl/src/H5LTparse.c" /* yacc.c:1646 */
break;
case 40:
-#line 149 "hl/src/H5LTparse.y" /* yacc.c:1646 */
+/* Line 1792 of yacc.c */
+#line 149 "hl/src/H5LTparse.y"
{ (yyval.hid) = H5Tcopy(H5T_IEEE_F32BE); }
-#line 1644 "hl/src/H5LTparse.c" /* yacc.c:1646 */
break;
case 41:
-#line 150 "hl/src/H5LTparse.y" /* yacc.c:1646 */
+/* Line 1792 of yacc.c */
+#line 150 "hl/src/H5LTparse.y"
{ (yyval.hid) = H5Tcopy(H5T_IEEE_F32LE); }
-#line 1650 "hl/src/H5LTparse.c" /* yacc.c:1646 */
break;
case 42:
-#line 151 "hl/src/H5LTparse.y" /* yacc.c:1646 */
+/* Line 1792 of yacc.c */
+#line 151 "hl/src/H5LTparse.y"
{ (yyval.hid) = H5Tcopy(H5T_IEEE_F64BE); }
-#line 1656 "hl/src/H5LTparse.c" /* yacc.c:1646 */
break;
case 43:
-#line 152 "hl/src/H5LTparse.y" /* yacc.c:1646 */
+/* Line 1792 of yacc.c */
+#line 152 "hl/src/H5LTparse.y"
{ (yyval.hid) = H5Tcopy(H5T_IEEE_F64LE); }
-#line 1662 "hl/src/H5LTparse.c" /* yacc.c:1646 */
break;
case 44:
-#line 153 "hl/src/H5LTparse.y" /* yacc.c:1646 */
+/* Line 1792 of yacc.c */
+#line 153 "hl/src/H5LTparse.y"
{ (yyval.hid) = H5Tcopy(H5T_NATIVE_FLOAT); }
-#line 1668 "hl/src/H5LTparse.c" /* yacc.c:1646 */
break;
case 45:
-#line 154 "hl/src/H5LTparse.y" /* yacc.c:1646 */
+/* Line 1792 of yacc.c */
+#line 154 "hl/src/H5LTparse.y"
{ (yyval.hid) = H5Tcopy(H5T_NATIVE_DOUBLE); }
-#line 1674 "hl/src/H5LTparse.c" /* yacc.c:1646 */
break;
case 46:
-#line 155 "hl/src/H5LTparse.y" /* yacc.c:1646 */
+/* Line 1792 of yacc.c */
+#line 155 "hl/src/H5LTparse.y"
{ (yyval.hid) = H5Tcopy(H5T_NATIVE_LDOUBLE); }
-#line 1680 "hl/src/H5LTparse.c" /* yacc.c:1646 */
break;
case 47:
-#line 159 "hl/src/H5LTparse.y" /* yacc.c:1646 */
+/* Line 1792 of yacc.c */
+#line 159 "hl/src/H5LTparse.y"
{ csindex++; cmpd_stack[csindex].id = H5Tcreate(H5T_COMPOUND, 1); /*temporarily set size to 1*/ }
-#line 1686 "hl/src/H5LTparse.c" /* yacc.c:1646 */
break;
case 48:
-#line 161 "hl/src/H5LTparse.y" /* yacc.c:1646 */
+/* Line 1792 of yacc.c */
+#line 161 "hl/src/H5LTparse.y"
{ (yyval.hid) = cmpd_stack[csindex].id;
cmpd_stack[csindex].id = 0;
cmpd_stack[csindex].first_memb = 1;
csindex--;
}
-#line 1696 "hl/src/H5LTparse.c" /* yacc.c:1646 */
break;
case 51:
-#line 170 "hl/src/H5LTparse.y" /* yacc.c:1646 */
+/* Line 1792 of yacc.c */
+#line 170 "hl/src/H5LTparse.y"
{ cmpd_stack[csindex].is_field = 1; /*notify lexer a compound member is parsed*/ }
-#line 1702 "hl/src/H5LTparse.c" /* yacc.c:1646 */
break;
case 52:
-#line 172 "hl/src/H5LTparse.y" /* yacc.c:1646 */
+/* Line 1792 of yacc.c */
+#line 172 "hl/src/H5LTparse.y"
{
size_t origin_size, new_size;
hid_t dtype_id = cmpd_stack[csindex].id;
/*Adjust size and insert member, consider both member size and offset.*/
if(cmpd_stack[csindex].first_memb) { /*reclaim the size 1 temporarily set*/
- new_size = H5Tget_size((yyvsp[-6].hid)) + (yyvsp[-1].ival);
+ new_size = H5Tget_size((yyvsp[(1) - (7)].hid)) + (yyvsp[(6) - (7)].ival);
H5Tset_size(dtype_id, new_size);
/*member name is saved in yylval.sval by lexer*/
- H5Tinsert(dtype_id, (yyvsp[-3].sval), (yyvsp[-1].ival), (yyvsp[-6].hid));
+ H5Tinsert(dtype_id, (yyvsp[(4) - (7)].sval), (yyvsp[(6) - (7)].ival), (yyvsp[(1) - (7)].hid));
cmpd_stack[csindex].first_memb = 0;
} else {
origin_size = H5Tget_size(dtype_id);
- if((yyvsp[-1].ival) == 0) {
- new_size = origin_size + H5Tget_size((yyvsp[-6].hid));
+ if((yyvsp[(6) - (7)].ival) == 0) {
+ new_size = origin_size + H5Tget_size((yyvsp[(1) - (7)].hid));
H5Tset_size(dtype_id, new_size);
- H5Tinsert(dtype_id, (yyvsp[-3].sval), origin_size, (yyvsp[-6].hid));
+ H5Tinsert(dtype_id, (yyvsp[(4) - (7)].sval), origin_size, (yyvsp[(1) - (7)].hid));
} else {
- new_size = (yyvsp[-1].ival) + H5Tget_size((yyvsp[-6].hid));
+ new_size = (yyvsp[(6) - (7)].ival) + H5Tget_size((yyvsp[(1) - (7)].hid));
H5Tset_size(dtype_id, new_size);
- H5Tinsert(dtype_id, (yyvsp[-3].sval), (yyvsp[-1].ival), (yyvsp[-6].hid));
+ H5Tinsert(dtype_id, (yyvsp[(4) - (7)].sval), (yyvsp[(6) - (7)].ival), (yyvsp[(1) - (7)].hid));
}
}
- if((yyvsp[-3].sval)) {
- free((yyvsp[-3].sval));
- (yyvsp[-3].sval) = NULL;
+ if((yyvsp[(4) - (7)].sval)) {
+ free((yyvsp[(4) - (7)].sval));
+ (yyvsp[(4) - (7)].sval) = NULL;
}
cmpd_stack[csindex].is_field = 0;
- H5Tclose((yyvsp[-6].hid));
+ H5Tclose((yyvsp[(1) - (7)].hid));
new_size = H5Tget_size(dtype_id);
}
-#line 1741 "hl/src/H5LTparse.c" /* yacc.c:1646 */
break;
case 53:
-#line 208 "hl/src/H5LTparse.y" /* yacc.c:1646 */
+/* Line 1792 of yacc.c */
+#line 208 "hl/src/H5LTparse.y"
{
(yyval.sval) = strdup(yylval.sval);
free(yylval.sval);
yylval.sval = NULL;
}
-#line 1751 "hl/src/H5LTparse.c" /* yacc.c:1646 */
break;
case 54:
-#line 215 "hl/src/H5LTparse.y" /* yacc.c:1646 */
+/* Line 1792 of yacc.c */
+#line 215 "hl/src/H5LTparse.y"
{ (yyval.ival) = 0; }
-#line 1757 "hl/src/H5LTparse.c" /* yacc.c:1646 */
break;
case 55:
-#line 217 "hl/src/H5LTparse.y" /* yacc.c:1646 */
+/* Line 1792 of yacc.c */
+#line 217 "hl/src/H5LTparse.y"
{ (yyval.ival) = yylval.ival; }
-#line 1763 "hl/src/H5LTparse.c" /* yacc.c:1646 */
break;
case 57:
-#line 221 "hl/src/H5LTparse.y" /* yacc.c:1646 */
+/* Line 1792 of yacc.c */
+#line 221 "hl/src/H5LTparse.y"
{ asindex++; /*pushd onto the stack*/ }
-#line 1769 "hl/src/H5LTparse.c" /* yacc.c:1646 */
break;
case 58:
-#line 223 "hl/src/H5LTparse.y" /* yacc.c:1646 */
+/* Line 1792 of yacc.c */
+#line 223 "hl/src/H5LTparse.y"
{
- (yyval.hid) = H5Tarray_create2((yyvsp[-1].hid), arr_stack[asindex].ndims, arr_stack[asindex].dims);
+ (yyval.hid) = H5Tarray_create2((yyvsp[(5) - (6)].hid), arr_stack[asindex].ndims, arr_stack[asindex].dims);
arr_stack[asindex].ndims = 0;
asindex--;
- H5Tclose((yyvsp[-1].hid));
+ H5Tclose((yyvsp[(5) - (6)].hid));
}
-#line 1780 "hl/src/H5LTparse.c" /* yacc.c:1646 */
break;
case 61:
-#line 233 "hl/src/H5LTparse.y" /* yacc.c:1646 */
+/* Line 1792 of yacc.c */
+#line 233 "hl/src/H5LTparse.y"
{ arr_stack[asindex].is_dim = 1; /*notice lexer of dimension size*/ }
-#line 1786 "hl/src/H5LTparse.c" /* yacc.c:1646 */
break;
case 62:
-#line 234 "hl/src/H5LTparse.y" /* yacc.c:1646 */
+/* Line 1792 of yacc.c */
+#line 234 "hl/src/H5LTparse.y"
{ unsigned ndims = arr_stack[asindex].ndims;
arr_stack[asindex].dims[ndims] = (hsize_t)yylval.ival;
arr_stack[asindex].ndims++;
arr_stack[asindex].is_dim = 0;
}
-#line 1796 "hl/src/H5LTparse.c" /* yacc.c:1646 */
break;
case 65:
-#line 245 "hl/src/H5LTparse.y" /* yacc.c:1646 */
- { (yyval.hid) = H5Tvlen_create((yyvsp[-1].hid)); H5Tclose((yyvsp[-1].hid)); }
-#line 1802 "hl/src/H5LTparse.c" /* yacc.c:1646 */
+/* Line 1792 of yacc.c */
+#line 245 "hl/src/H5LTparse.y"
+ { (yyval.hid) = H5Tvlen_create((yyvsp[(3) - (4)].hid)); H5Tclose((yyvsp[(3) - (4)].hid)); }
break;
case 66:
-#line 250 "hl/src/H5LTparse.y" /* yacc.c:1646 */
+/* Line 1792 of yacc.c */
+#line 250 "hl/src/H5LTparse.y"
{ is_opq_size = 1; }
-#line 1808 "hl/src/H5LTparse.c" /* yacc.c:1646 */
break;
case 67:
-#line 251 "hl/src/H5LTparse.y" /* yacc.c:1646 */
+/* Line 1792 of yacc.c */
+#line 251 "hl/src/H5LTparse.y"
{
size_t size = (size_t)yylval.ival;
(yyval.hid) = H5Tcreate(H5T_OPAQUE, size);
is_opq_size = 0;
}
-#line 1818 "hl/src/H5LTparse.c" /* yacc.c:1646 */
break;
case 68:
-#line 256 "hl/src/H5LTparse.y" /* yacc.c:1646 */
+/* Line 1792 of yacc.c */
+#line 256 "hl/src/H5LTparse.y"
{ is_opq_tag = 1; }
-#line 1824 "hl/src/H5LTparse.c" /* yacc.c:1646 */
break;
case 69:
-#line 257 "hl/src/H5LTparse.y" /* yacc.c:1646 */
+/* Line 1792 of yacc.c */
+#line 257 "hl/src/H5LTparse.y"
{
- H5Tset_tag((yyvsp[-6].hid), yylval.sval);
+ H5Tset_tag((yyvsp[(7) - (13)].hid), yylval.sval);
free(yylval.sval);
yylval.sval = NULL;
is_opq_tag = 0;
}
-#line 1835 "hl/src/H5LTparse.c" /* yacc.c:1646 */
break;
case 70:
-#line 263 "hl/src/H5LTparse.y" /* yacc.c:1646 */
- { (yyval.hid) = (yyvsp[-8].hid); }
-#line 1841 "hl/src/H5LTparse.c" /* yacc.c:1646 */
+/* Line 1792 of yacc.c */
+#line 263 "hl/src/H5LTparse.y"
+ { (yyval.hid) = (yyvsp[(7) - (15)].hid); }
break;
case 73:
-#line 271 "hl/src/H5LTparse.y" /* yacc.c:1646 */
+/* Line 1792 of yacc.c */
+#line 271 "hl/src/H5LTparse.y"
{ is_str_size = 1; }
-#line 1847 "hl/src/H5LTparse.c" /* yacc.c:1646 */
break;
case 74:
-#line 272 "hl/src/H5LTparse.y" /* yacc.c:1646 */
+/* Line 1792 of yacc.c */
+#line 272 "hl/src/H5LTparse.y"
{
- if((yyvsp[-1].ival) == H5T_VARIABLE_TOKEN)
+ if((yyvsp[(5) - (6)].ival) == H5T_VARIABLE_TOKEN)
is_variable = 1;
else
str_size = yylval.ival;
is_str_size = 0;
}
-#line 1859 "hl/src/H5LTparse.c" /* yacc.c:1646 */
break;
case 75:
-#line 280 "hl/src/H5LTparse.y" /* yacc.c:1646 */
+/* Line 1792 of yacc.c */
+#line 280 "hl/src/H5LTparse.y"
{
- if((yyvsp[-1].ival) == H5T_STR_NULLTERM_TOKEN)
+ if((yyvsp[(9) - (10)].ival) == H5T_STR_NULLTERM_TOKEN)
str_pad = H5T_STR_NULLTERM;
- else if((yyvsp[-1].ival) == H5T_STR_NULLPAD_TOKEN)
+ else if((yyvsp[(9) - (10)].ival) == H5T_STR_NULLPAD_TOKEN)
str_pad = H5T_STR_NULLPAD;
- else if((yyvsp[-1].ival) == H5T_STR_SPACEPAD_TOKEN)
+ else if((yyvsp[(9) - (10)].ival) == H5T_STR_SPACEPAD_TOKEN)
str_pad = H5T_STR_SPACEPAD;
}
-#line 1872 "hl/src/H5LTparse.c" /* yacc.c:1646 */
break;
case 76:
-#line 289 "hl/src/H5LTparse.y" /* yacc.c:1646 */
+/* Line 1792 of yacc.c */
+#line 289 "hl/src/H5LTparse.y"
{
- if((yyvsp[-1].ival) == H5T_CSET_ASCII_TOKEN)
+ if((yyvsp[(13) - (14)].ival) == H5T_CSET_ASCII_TOKEN)
str_cset = H5T_CSET_ASCII;
- else if((yyvsp[-1].ival) == H5T_CSET_UTF8_TOKEN)
+ else if((yyvsp[(13) - (14)].ival) == H5T_CSET_UTF8_TOKEN)
str_cset = H5T_CSET_UTF8;
}
-#line 1883 "hl/src/H5LTparse.c" /* yacc.c:1646 */
break;
case 77:
-#line 296 "hl/src/H5LTparse.y" /* yacc.c:1646 */
+/* Line 1792 of yacc.c */
+#line 296 "hl/src/H5LTparse.y"
{
- if((yyvsp[-1].hid) == H5T_C_S1_TOKEN)
+ if((yyvsp[(17) - (18)].hid) == H5T_C_S1_TOKEN)
(yyval.hid) = H5Tcopy(H5T_C_S1);
- else if((yyvsp[-1].hid) == H5T_FORTRAN_S1_TOKEN)
+ else if((yyvsp[(17) - (18)].hid) == H5T_FORTRAN_S1_TOKEN)
(yyval.hid) = H5Tcopy(H5T_FORTRAN_S1);
}
-#line 1894 "hl/src/H5LTparse.c" /* yacc.c:1646 */
break;
case 78:
-#line 303 "hl/src/H5LTparse.y" /* yacc.c:1646 */
+/* Line 1792 of yacc.c */
+#line 303 "hl/src/H5LTparse.y"
{
- hid_t str_id = (yyvsp[-1].hid);
+ hid_t str_id = (yyvsp[(19) - (20)].hid);
/*set string size*/
if(is_variable) {
@@ -1933,71 +2092,71 @@ yyreduce:
(yyval.hid) = str_id;
}
-#line 1915 "hl/src/H5LTparse.c" /* yacc.c:1646 */
break;
case 79:
-#line 320 "hl/src/H5LTparse.y" /* yacc.c:1646 */
+/* Line 1792 of yacc.c */
+#line 320 "hl/src/H5LTparse.y"
{(yyval.ival) = H5T_VARIABLE_TOKEN;}
-#line 1921 "hl/src/H5LTparse.c" /* yacc.c:1646 */
break;
case 81:
-#line 323 "hl/src/H5LTparse.y" /* yacc.c:1646 */
+/* Line 1792 of yacc.c */
+#line 323 "hl/src/H5LTparse.y"
{(yyval.ival) = H5T_STR_NULLTERM_TOKEN;}
-#line 1927 "hl/src/H5LTparse.c" /* yacc.c:1646 */
break;
case 82:
-#line 324 "hl/src/H5LTparse.y" /* yacc.c:1646 */
+/* Line 1792 of yacc.c */
+#line 324 "hl/src/H5LTparse.y"
{(yyval.ival) = H5T_STR_NULLPAD_TOKEN;}
-#line 1933 "hl/src/H5LTparse.c" /* yacc.c:1646 */
break;
case 83:
-#line 325 "hl/src/H5LTparse.y" /* yacc.c:1646 */
+/* Line 1792 of yacc.c */
+#line 325 "hl/src/H5LTparse.y"
{(yyval.ival) = H5T_STR_SPACEPAD_TOKEN;}
-#line 1939 "hl/src/H5LTparse.c" /* yacc.c:1646 */
break;
case 84:
-#line 327 "hl/src/H5LTparse.y" /* yacc.c:1646 */
+/* Line 1792 of yacc.c */
+#line 327 "hl/src/H5LTparse.y"
{(yyval.ival) = H5T_CSET_ASCII_TOKEN;}
-#line 1945 "hl/src/H5LTparse.c" /* yacc.c:1646 */
break;
case 85:
-#line 328 "hl/src/H5LTparse.y" /* yacc.c:1646 */
+/* Line 1792 of yacc.c */
+#line 328 "hl/src/H5LTparse.y"
{(yyval.ival) = H5T_CSET_UTF8_TOKEN;}
-#line 1951 "hl/src/H5LTparse.c" /* yacc.c:1646 */
break;
case 86:
-#line 330 "hl/src/H5LTparse.y" /* yacc.c:1646 */
+/* Line 1792 of yacc.c */
+#line 330 "hl/src/H5LTparse.y"
{(yyval.hid) = H5T_C_S1_TOKEN;}
-#line 1957 "hl/src/H5LTparse.c" /* yacc.c:1646 */
break;
case 87:
-#line 331 "hl/src/H5LTparse.y" /* yacc.c:1646 */
+/* Line 1792 of yacc.c */
+#line 331 "hl/src/H5LTparse.y"
{(yyval.hid) = H5T_FORTRAN_S1_TOKEN;}
-#line 1963 "hl/src/H5LTparse.c" /* yacc.c:1646 */
break;
case 88:
-#line 335 "hl/src/H5LTparse.y" /* yacc.c:1646 */
- { is_enum = 1; enum_id = H5Tenum_create((yyvsp[-1].hid)); H5Tclose((yyvsp[-1].hid)); }
-#line 1969 "hl/src/H5LTparse.c" /* yacc.c:1646 */
+/* Line 1792 of yacc.c */
+#line 335 "hl/src/H5LTparse.y"
+ { is_enum = 1; enum_id = H5Tenum_create((yyvsp[(3) - (4)].hid)); H5Tclose((yyvsp[(3) - (4)].hid)); }
break;
case 89:
-#line 337 "hl/src/H5LTparse.y" /* yacc.c:1646 */
+/* Line 1792 of yacc.c */
+#line 337 "hl/src/H5LTparse.y"
{ is_enum = 0; /*reset*/ (yyval.hid) = enum_id; }
-#line 1975 "hl/src/H5LTparse.c" /* yacc.c:1646 */
break;
case 92:
-#line 342 "hl/src/H5LTparse.y" /* yacc.c:1646 */
+/* Line 1792 of yacc.c */
+#line 342 "hl/src/H5LTparse.y"
{
is_enum_memb = 1; /*indicate member of enum*/
#ifdef H5_HAVE_WIN32_API
@@ -2008,11 +2167,11 @@ yyreduce:
free(yylval.sval);
yylval.sval = NULL;
}
-#line 1990 "hl/src/H5LTparse.c" /* yacc.c:1646 */
break;
case 93:
-#line 353 "hl/src/H5LTparse.y" /* yacc.c:1646 */
+/* Line 1792 of yacc.c */
+#line 353 "hl/src/H5LTparse.y"
{
char char_val=(char)yylval.ival;
short short_val=(short)yylval.ival;
@@ -2055,11 +2214,11 @@ yyreduce:
H5Tclose(super);
H5Tclose(native);
}
-#line 2037 "hl/src/H5LTparse.c" /* yacc.c:1646 */
break;
-#line 2041 "hl/src/H5LTparse.c" /* yacc.c:1646 */
+/* Line 1792 of yacc.c */
+#line 2200 "hl/src/H5LTparse.c"
default: break;
}
/* User semantic actions sometimes alter yychar, and that requires
@@ -2081,7 +2240,7 @@ yyreduce:
*++yyvsp = yyval;
- /* Now 'shift' the result of the reduction. Determine what state
+ /* Now `shift' the result of the reduction. Determine what state
that goes to, based on the state we popped back to and the rule
number reduced by. */
@@ -2096,9 +2255,9 @@ yyreduce:
goto yynewstate;
-/*--------------------------------------.
-| yyerrlab -- here on detecting error. |
-`--------------------------------------*/
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
yyerrlab:
/* Make sure we have latest lookahead translation. See comments at
user semantic actions for why this is necessary. */
@@ -2149,20 +2308,20 @@ yyerrlab:
if (yyerrstatus == 3)
{
/* If just tried and failed to reuse lookahead token after an
- error, discard it. */
+ error, discard it. */
if (yychar <= YYEOF)
- {
- /* Return failure if at end of input. */
- if (yychar == YYEOF)
- YYABORT;
- }
+ {
+ /* Return failure if at end of input. */
+ if (yychar == YYEOF)
+ YYABORT;
+ }
else
- {
- yydestruct ("Error: discarding",
- yytoken, &yylval);
- yychar = YYEMPTY;
- }
+ {
+ yydestruct ("Error: discarding",
+ yytoken, &yylval);
+ yychar = YYEMPTY;
+ }
}
/* Else will try to reuse lookahead token after shifting the error
@@ -2181,7 +2340,7 @@ yyerrorlab:
if (/*CONSTCOND*/ 0)
goto yyerrorlab;
- /* Do not reclaim the symbols of the rule whose action triggered
+ /* Do not reclaim the symbols of the rule which action triggered
this YYERROR. */
YYPOPSTACK (yylen);
yylen = 0;
@@ -2194,29 +2353,29 @@ yyerrorlab:
| yyerrlab1 -- common code for both syntax error and YYERROR. |
`-------------------------------------------------------------*/
yyerrlab1:
- yyerrstatus = 3; /* Each real token shifted decrements this. */
+ yyerrstatus = 3; /* Each real token shifted decrements this. */
for (;;)
{
yyn = yypact[yystate];
if (!yypact_value_is_default (yyn))
- {
- yyn += YYTERROR;
- if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
- {
- yyn = yytable[yyn];
- if (0 < yyn)
- break;
- }
- }
+ {
+ yyn += YYTERROR;
+ if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+ {
+ yyn = yytable[yyn];
+ if (0 < yyn)
+ break;
+ }
+ }
/* Pop the current state because it cannot handle the error token. */
if (yyssp == yyss)
- YYABORT;
+ YYABORT;
yydestruct ("Error: popping",
- yystos[yystate], yyvsp);
+ yystos[yystate], yyvsp);
YYPOPSTACK (1);
yystate = *yyssp;
YY_STACK_PRINT (yyss, yyssp);
@@ -2267,14 +2426,14 @@ yyreturn:
yydestruct ("Cleanup: discarding lookahead",
yytoken, &yylval);
}
- /* Do not reclaim the symbols of the rule whose action triggered
+ /* Do not reclaim the symbols of the rule which action triggered
this YYABORT or YYACCEPT. */
YYPOPSTACK (yylen);
YY_STACK_PRINT (yyss, yyssp);
while (yyssp != yyss)
{
yydestruct ("Cleanup: popping",
- yystos[*yyssp], yyvsp);
+ yystos[*yyssp], yyvsp);
YYPOPSTACK (1);
}
#ifndef yyoverflow
@@ -2285,5 +2444,8 @@ yyreturn:
if (yymsg != yymsgbuf)
YYSTACK_FREE (yymsg);
#endif
- return yyresult;
+ /* Make sure YYID is used. */
+ return YYID (yyresult);
}
+
+
diff --git a/hl/src/H5LTparse.h b/hl/src/H5LTparse.h
index e38116a..30c5ea8 100644
--- a/hl/src/H5LTparse.h
+++ b/hl/src/H5LTparse.h
@@ -1,19 +1,19 @@
-/* A Bison parser, made by GNU Bison 3.0.4. */
+/* A Bison parser, made by GNU Bison 2.7. */
/* Bison interface for Yacc-like parsers in C
-
- Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc.
-
+
+ Copyright (C) 1984, 1989-1990, 2000-2012 Free Software Foundation, Inc.
+
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
-
+
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
-
+
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
@@ -26,13 +26,13 @@
special exception, which will cause the skeleton and the resulting
Bison output files to be licensed under the GNU General Public
License without this special exception.
-
+
This special exception was added by the Free Software Foundation in
version 2.2 of Bison. */
#ifndef YY_H5LTYY_HL_SRC_H5LTPARSE_H_INCLUDED
# define YY_H5LTYY_HL_SRC_H5LTPARSE_H_INCLUDED
-/* Debug traces. */
+/* Enabling traces. */
#ifndef YYDEBUG
# define YYDEBUG 0
#endif
@@ -40,92 +40,105 @@
extern int H5LTyydebug;
#endif
-/* Token type. */
+/* Tokens. */
#ifndef YYTOKENTYPE
# define YYTOKENTYPE
- enum yytokentype
- {
- H5T_STD_I8BE_TOKEN = 258,
- H5T_STD_I8LE_TOKEN = 259,
- H5T_STD_I16BE_TOKEN = 260,
- H5T_STD_I16LE_TOKEN = 261,
- H5T_STD_I32BE_TOKEN = 262,
- H5T_STD_I32LE_TOKEN = 263,
- H5T_STD_I64BE_TOKEN = 264,
- H5T_STD_I64LE_TOKEN = 265,
- H5T_STD_U8BE_TOKEN = 266,
- H5T_STD_U8LE_TOKEN = 267,
- H5T_STD_U16BE_TOKEN = 268,
- H5T_STD_U16LE_TOKEN = 269,
- H5T_STD_U32BE_TOKEN = 270,
- H5T_STD_U32LE_TOKEN = 271,
- H5T_STD_U64BE_TOKEN = 272,
- H5T_STD_U64LE_TOKEN = 273,
- H5T_NATIVE_CHAR_TOKEN = 274,
- H5T_NATIVE_SCHAR_TOKEN = 275,
- H5T_NATIVE_UCHAR_TOKEN = 276,
- H5T_NATIVE_SHORT_TOKEN = 277,
- H5T_NATIVE_USHORT_TOKEN = 278,
- H5T_NATIVE_INT_TOKEN = 279,
- H5T_NATIVE_UINT_TOKEN = 280,
- H5T_NATIVE_LONG_TOKEN = 281,
- H5T_NATIVE_ULONG_TOKEN = 282,
- H5T_NATIVE_LLONG_TOKEN = 283,
- H5T_NATIVE_ULLONG_TOKEN = 284,
- H5T_IEEE_F32BE_TOKEN = 285,
- H5T_IEEE_F32LE_TOKEN = 286,
- H5T_IEEE_F64BE_TOKEN = 287,
- H5T_IEEE_F64LE_TOKEN = 288,
- H5T_NATIVE_FLOAT_TOKEN = 289,
- H5T_NATIVE_DOUBLE_TOKEN = 290,
- H5T_NATIVE_LDOUBLE_TOKEN = 291,
- H5T_STRING_TOKEN = 292,
- STRSIZE_TOKEN = 293,
- STRPAD_TOKEN = 294,
- CSET_TOKEN = 295,
- CTYPE_TOKEN = 296,
- H5T_VARIABLE_TOKEN = 297,
- H5T_STR_NULLTERM_TOKEN = 298,
- H5T_STR_NULLPAD_TOKEN = 299,
- H5T_STR_SPACEPAD_TOKEN = 300,
- H5T_CSET_ASCII_TOKEN = 301,
- H5T_CSET_UTF8_TOKEN = 302,
- H5T_C_S1_TOKEN = 303,
- H5T_FORTRAN_S1_TOKEN = 304,
- H5T_OPAQUE_TOKEN = 305,
- OPQ_SIZE_TOKEN = 306,
- OPQ_TAG_TOKEN = 307,
- H5T_COMPOUND_TOKEN = 308,
- H5T_ENUM_TOKEN = 309,
- H5T_ARRAY_TOKEN = 310,
- H5T_VLEN_TOKEN = 311,
- STRING = 312,
- NUMBER = 313
- };
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ H5T_STD_I8BE_TOKEN = 258,
+ H5T_STD_I8LE_TOKEN = 259,
+ H5T_STD_I16BE_TOKEN = 260,
+ H5T_STD_I16LE_TOKEN = 261,
+ H5T_STD_I32BE_TOKEN = 262,
+ H5T_STD_I32LE_TOKEN = 263,
+ H5T_STD_I64BE_TOKEN = 264,
+ H5T_STD_I64LE_TOKEN = 265,
+ H5T_STD_U8BE_TOKEN = 266,
+ H5T_STD_U8LE_TOKEN = 267,
+ H5T_STD_U16BE_TOKEN = 268,
+ H5T_STD_U16LE_TOKEN = 269,
+ H5T_STD_U32BE_TOKEN = 270,
+ H5T_STD_U32LE_TOKEN = 271,
+ H5T_STD_U64BE_TOKEN = 272,
+ H5T_STD_U64LE_TOKEN = 273,
+ H5T_NATIVE_CHAR_TOKEN = 274,
+ H5T_NATIVE_SCHAR_TOKEN = 275,
+ H5T_NATIVE_UCHAR_TOKEN = 276,
+ H5T_NATIVE_SHORT_TOKEN = 277,
+ H5T_NATIVE_USHORT_TOKEN = 278,
+ H5T_NATIVE_INT_TOKEN = 279,
+ H5T_NATIVE_UINT_TOKEN = 280,
+ H5T_NATIVE_LONG_TOKEN = 281,
+ H5T_NATIVE_ULONG_TOKEN = 282,
+ H5T_NATIVE_LLONG_TOKEN = 283,
+ H5T_NATIVE_ULLONG_TOKEN = 284,
+ H5T_IEEE_F32BE_TOKEN = 285,
+ H5T_IEEE_F32LE_TOKEN = 286,
+ H5T_IEEE_F64BE_TOKEN = 287,
+ H5T_IEEE_F64LE_TOKEN = 288,
+ H5T_NATIVE_FLOAT_TOKEN = 289,
+ H5T_NATIVE_DOUBLE_TOKEN = 290,
+ H5T_NATIVE_LDOUBLE_TOKEN = 291,
+ H5T_STRING_TOKEN = 292,
+ STRSIZE_TOKEN = 293,
+ STRPAD_TOKEN = 294,
+ CSET_TOKEN = 295,
+ CTYPE_TOKEN = 296,
+ H5T_VARIABLE_TOKEN = 297,
+ H5T_STR_NULLTERM_TOKEN = 298,
+ H5T_STR_NULLPAD_TOKEN = 299,
+ H5T_STR_SPACEPAD_TOKEN = 300,
+ H5T_CSET_ASCII_TOKEN = 301,
+ H5T_CSET_UTF8_TOKEN = 302,
+ H5T_C_S1_TOKEN = 303,
+ H5T_FORTRAN_S1_TOKEN = 304,
+ H5T_OPAQUE_TOKEN = 305,
+ OPQ_SIZE_TOKEN = 306,
+ OPQ_TAG_TOKEN = 307,
+ H5T_COMPOUND_TOKEN = 308,
+ H5T_ENUM_TOKEN = 309,
+ H5T_ARRAY_TOKEN = 310,
+ H5T_VLEN_TOKEN = 311,
+ STRING = 312,
+ NUMBER = 313
+ };
#endif
-/* Value type. */
-#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
-union YYSTYPE
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
{
-#line 72 "hl/src/H5LTparse.y" /* yacc.c:1909 */
+/* Line 2058 of yacc.c */
+#line 72 "hl/src/H5LTparse.y"
int ival; /*for integer token*/
char *sval; /*for name string*/
hid_t hid; /*for hid_t token*/
-#line 119 "hl/src/H5LTparse.h" /* yacc.c:1909 */
-};
-typedef union YYSTYPE YYSTYPE;
+/* Line 2058 of yacc.c */
+#line 122 "hl/src/H5LTparse.h"
+} YYSTYPE;
# define YYSTYPE_IS_TRIVIAL 1
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
# define YYSTYPE_IS_DECLARED 1
#endif
-
extern YYSTYPE H5LTyylval;
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int H5LTyyparse (void *YYPARSE_PARAM);
+#else
+int H5LTyyparse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
int H5LTyyparse (void);
+#else
+int H5LTyyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
#endif /* !YY_H5LTYY_HL_SRC_H5LTPARSE_H_INCLUDED */
diff --git a/release_docs/RELEASE.txt b/release_docs/RELEASE.txt
index 1f1ad60..6c43908 100644
--- a/release_docs/RELEASE.txt
+++ b/release_docs/RELEASE.txt
@@ -298,6 +298,20 @@ New Features
Library:
--------
+ - Add Mirror VFD
+
+ Use TCP/IP sockets to perform write-only (W/O) file I/O on a remote
+ machine. Must be used in conjunction with the Splitter VFD.
+
+ (JOS - 2020/03/13, TBD)
+
+ - Add Splitter VFD
+
+ Maintain separate R/W and W/O channels for "concurrent" file writes
+ to two files using a single HDF5 file handle.
+
+ (JOS - 2020/03/13, TBD)
+
- Refactored public exposure of haddr_t type in favor of "object tokens"
To better accommodate HDF5 VOL connectors where "object addresses in a file"
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 3682caa..c0915c8 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -231,6 +231,7 @@ set (H5FD_SOURCES
${HDF5_SRC_DIR}/H5FDhdfs.c
${HDF5_SRC_DIR}/H5FDint.c
${HDF5_SRC_DIR}/H5FDlog.c
+ ${HDF5_SRC_DIR}/H5FDmirror.c
${HDF5_SRC_DIR}/H5FDmpi.c
${HDF5_SRC_DIR}/H5FDmpio.c
${HDF5_SRC_DIR}/H5FDmulti.c
@@ -238,6 +239,7 @@ set (H5FD_SOURCES
${HDF5_SRC_DIR}/H5FDs3comms.c
${HDF5_SRC_DIR}/H5FDsec2.c
${HDF5_SRC_DIR}/H5FDspace.c
+ ${HDF5_SRC_DIR}/H5FDsplitter.c
${HDF5_SRC_DIR}/H5FDstdio.c
${HDF5_SRC_DIR}/H5FDtest.c
${HDF5_SRC_DIR}/H5FDwindows.c
@@ -249,6 +251,7 @@ set (H5FD_HDRS
${HDF5_SRC_DIR}/H5FDfamily.h
${HDF5_SRC_DIR}/H5FDhdfs.h
${HDF5_SRC_DIR}/H5FDlog.h
+ ${HDF5_SRC_DIR}/H5FDmirror.h
${HDF5_SRC_DIR}/H5FDmpi.h
${HDF5_SRC_DIR}/H5FDmpio.h
${HDF5_SRC_DIR}/H5FDmulti.h
@@ -256,6 +259,7 @@ set (H5FD_HDRS
${HDF5_SRC_DIR}/H5FDros3.h
${HDF5_SRC_DIR}/H5FDs3comms.h
${HDF5_SRC_DIR}/H5FDsec2.h
+ ${HDF5_SRC_DIR}/H5FDsplitter.h
${HDF5_SRC_DIR}/H5FDstdio.h
${HDF5_SRC_DIR}/H5FDwindows.h
)
diff --git a/src/H5FDmirror.c b/src/H5FDmirror.c
new file mode 100644
index 0000000..bcbac08
--- /dev/null
+++ b/src/H5FDmirror.c
@@ -0,0 +1,2001 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * 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. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Purpose: Transmit write-only operations to a receiver/writer process on
+ * a remote host.
+ */
+
+#include "H5FDdrvr_module.h" /* This source code file is part of the H5FD driver module */
+
+#include "H5private.h" /* Generic Functions */
+
+#ifdef H5_HAVE_MIRROR_VFD
+
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fprivate.h" /* File access */
+#include "H5FDprivate.h" /* File drivers */
+#include "H5FDmirror.h" /* "Mirror" definitions */
+#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_MIRROR_g = 0;
+
+/* Virtual file structure for a Mirror Driver */
+typedef struct H5FD_mirror_t {
+ H5FD_t pub; /* Public stuff, must be first */
+ H5FD_mirror_fapl_t fa; /* Configuration structure */
+ haddr_t eoa; /* End of allocated region */
+ haddr_t eof; /* End of file; current file size */
+ int sock_fd; /* Handle of socket to remote operator */
+ H5FD_mirror_xmit_t xmit; /* Primary communication header */
+ uint32_t xmit_i; /* Counter of transmission sent and rec'd */
+} H5FD_mirror_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))
+
+#ifndef BSWAP_64
+#define BSWAP_64(X) \
+ (uint64_t)( (((X) & 0x00000000000000FF) << 56) \
+ | (((X) & 0x000000000000FF00) << 40) \
+ | (((X) & 0x0000000000FF0000) << 24) \
+ | (((X) & 0x00000000FF000000) << 8) \
+ | (((X) & 0x000000FF00000000) >> 8) \
+ | (((X) & 0x0000FF0000000000) >> 24) \
+ | (((X) & 0x00FF000000000000) >> 40) \
+ | (((X) & 0xFF00000000000000) >> 56))
+#endif /* BSWAP_64 */
+
+/* Debugging flabs for verbose tracing -- nonzero to enable */
+#define MIRROR_DEBUG_OP_CALLS 0
+#define MIRROR_DEBUG_XMIT_BYTES 0
+
+#if MIRROR_DEBUG_XMIT_BYTES
+#define LOG_XMIT_BYTES(label, buf, len) do { \
+ ssize_t bytes_written = 0; \
+ const unsigned char *b = NULL; \
+ \
+ HDfprintf(stdout, "%s bytes:\n```\n", (label)); \
+ \
+ /* print whole lines */ \
+ while ((len - bytes_written) >= 32) { \
+ b = (const unsigned char *)(buf) + bytes_written; \
+ HDfprintf(stdout, \
+ "%04zX %02X%02X%02X%02X %02X%02X%02X%02X" \
+ " %02X%02X%02X%02X %02X%02X%02X%02X" \
+ " %02X%02X%02X%02X %02X%02X%02X%02X" \
+ " %02X%02X%02X%02X %02X%02X%02X%02X\n", \
+ bytes_written, \
+ b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7], \
+ b[8], b[9], b[10],b[11], b[12],b[13],b[14],b[15], \
+ b[16],b[17],b[18],b[19], b[20],b[21],b[22],b[23], \
+ b[24],b[25],b[26],b[27], b[28],b[29],b[30],b[31]); \
+ bytes_written += 32; \
+ } \
+ \
+ /* start partial line */ \
+ if (len > bytes_written) { \
+ HDfprintf(stdout, "%04zX ", bytes_written); \
+ } \
+ \
+ /* partial line blocks */ \
+ while ((len - bytes_written) >= 4) { \
+ HDfprintf(stdout, " %02X%02X%02X%02X", \
+ (buf)[bytes_written], (buf)[bytes_written+1], \
+ (buf)[bytes_written+2], (buf)[bytes_written+3]); \
+ bytes_written += 4; \
+ } \
+ \
+ /* block separator before partial block */ \
+ if (len > bytes_written) { \
+ HDfprintf(stdout, " "); \
+ } \
+ \
+ /* partial block individual bytes */ \
+ while (len > bytes_written) { \
+ HDfprintf(stdout, "%02X", (buf)[bytes_written++]); \
+ } \
+ \
+ /* end partial line */ \
+ HDfprintf(stdout, "\n"); \
+ HDfprintf(stdout, "```\n"); \
+ HDfflush(stdout); \
+} while (0)
+#else
+#define LOG_XMIT_BYTES(label, buf, len) /* no-op */
+#endif /* MIRROR_DEBUG_XMIT_BYTE */
+
+#if MIRROR_DEBUG_OP_CALLS
+#define LOG_OP_CALL(name) do { \
+ HDprintf("called %s()\n", (name)); \
+ fflush(stdout); \
+} while (0)
+#else
+#define LOG_OP_CALL(name) /* no-op */
+#endif /* MIRROR_DEBUG_OP_CALLS */
+
+/* Prototypes */
+static herr_t H5FD_mirror_term(void);
+static void *H5FD_mirror_fapl_get(H5FD_t *_file);
+static void *H5FD_mirror_fapl_copy(const void *_old_fa);
+static herr_t H5FD_mirror_fapl_free(void *_fa);
+static haddr_t H5FD_mirror_get_eoa(const H5FD_t *_file, H5FD_mem_t type);
+static herr_t H5FD_mirror_set_eoa(H5FD_t *_file, H5FD_mem_t type, haddr_t addr);
+static haddr_t H5FD_mirror_get_eof(const H5FD_t *_file, H5FD_mem_t type);
+static H5FD_t *H5FD_mirror_open(const char *name, unsigned flags, \
+ hid_t fapl_id, haddr_t maxaddr);
+static herr_t H5FD_mirror_close(H5FD_t *_file);
+static herr_t H5FD_mirror_query(const H5FD_t *_file, unsigned long *flags);
+static herr_t H5FD_mirror_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_mirror_read(H5FD_t *_file, H5FD_mem_t type, hid_t fapl_id,
+ haddr_t addr, size_t size, void *buf);
+static herr_t H5FD_mirror_truncate(H5FD_t *_file, hid_t dxpl_id, \
+ hbool_t closing);
+static herr_t H5FD_mirror_lock(H5FD_t *_file, hbool_t rw);
+static herr_t H5FD_mirror_unlock(H5FD_t *_file);
+
+static herr_t H5FD__mirror_verify_reply(H5FD_mirror_t *file);
+
+static const H5FD_class_t H5FD_mirror_g = {
+ "mirror", /* name */
+ MAXADDR, /* maxaddr */
+ H5F_CLOSE_WEAK, /* fc_degree */
+ H5FD_mirror_term, /* terminate */
+ NULL, /* sb_size */
+ NULL, /* sb_encode */
+ NULL, /* sb_decode */
+ 0, /* fapl_size */
+ H5FD_mirror_fapl_get, /* fapl_get */
+ H5FD_mirror_fapl_copy, /* fapl_copy */
+ H5FD_mirror_fapl_free, /* fapl_free */
+ 0, /* dxpl_size */
+ NULL, /* dxpl_copy */
+ NULL, /* dxpl_free */
+ H5FD_mirror_open, /* open */
+ H5FD_mirror_close, /* close */
+ NULL, /* cmp */
+ H5FD_mirror_query, /* query */
+ NULL, /* get_type_map */
+ NULL, /* alloc */
+ NULL, /* free */
+ H5FD_mirror_get_eoa, /* get_eoa */
+ H5FD_mirror_set_eoa, /* set_eoa */
+ H5FD_mirror_get_eof, /* get_eof */
+ NULL, /* get_handle */
+ H5FD_mirror_read, /* read */
+ H5FD_mirror_write, /* write */
+ NULL, /* flush */
+ H5FD_mirror_truncate, /* truncate */
+ H5FD_mirror_lock, /* lock */
+ H5FD_mirror_unlock, /* unlock */
+ H5FD_FLMAP_DICHOTOMY /* fl_map */
+};
+
+/* Declare a free list to manage the H5FD_mirror_t struct */
+H5FL_DEFINE_STATIC(H5FD_mirror_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
+
+ LOG_OP_CALL("H5FD__init_package");
+
+ if (H5FD_mirror_init() < 0) {
+ HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL,
+ "unable to initialize mirror VFD");
+ }
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5FD__init_package() */
+
+
+/* -------------------------------------------------------------------------
+ * Function: H5FD_mirror_init
+ *
+ * Purpose: Initialize this driver by registering the driver with the
+ * library.
+ *
+ * Return: Success: The driver ID for the mirror driver.
+ * Failure: Negative
+ * -------------------------------------------------------------------------
+ */
+hid_t
+H5FD_mirror_init(void)
+{
+ hid_t ret_value = H5I_INVALID_HID;
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ LOG_OP_CALL("H5FD_mirror_init");
+
+ if (H5I_VFL != H5I_get_type(H5FD_MIRROR_g)) {
+ H5FD_MIRROR_g = H5FD_register(&H5FD_mirror_g, sizeof(H5FD_class_t),
+ FALSE);
+ }
+
+ ret_value = H5FD_MIRROR_g;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_mirror_init() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: H5FD_mirror_term
+ *
+ * Purpose: Shut down the VFD
+ *
+ * Returns: SUCCEED (Can't fail)
+ * ---------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_mirror_term(void)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ /* Reset VFL ID */
+ H5FD_MIRROR_g = 0;
+
+ LOG_OP_CALL("H5FD_mirror_term");
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5FD_mirror_term() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: H5FD__mirror_xmit_decode_uint16
+ *
+ * Purpose: Extract a 16-bit integer in "network" (Big-Endian) word order
+ * from the byte-buffer and return it with the local word order at
+ * the destination pointer.
+ *
+ * The programmer must ensure that the received buffer holds
+ * at least the expected size of data.
+ *
+ * Return: The number of bytes read from the buffer (2).
+ * ---------------------------------------------------------------------------
+ */
+size_t
+H5FD__mirror_xmit_decode_uint16(uint16_t *out, const unsigned char *_buf)
+{
+ uint16_t n = 0;
+ LOG_OP_CALL("H5FD__mirror_xmit_decode_uint16");
+ HDassert(_buf && out);
+ HDmemcpy(&n, _buf, sizeof(n));
+ *out = (uint16_t)HDntohs(n);
+ return 2; /* number of bytes eaten */
+} /* end H5FD__mirror_xmit_decode_uint16() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: H5FD__mirror_xmit_decode_uint32
+ *
+ * Purpose: Extract a 32-bit integer in "network" (Big-Endian) word order
+ * from the byte-buffer and return it with the local word order at
+ * the destination pointer.
+ *
+ * The programmer must ensure that the received buffer holds
+ * at least the expected size of data.
+ *
+ * Return: The number of bytes read from the buffer (4).
+ * ---------------------------------------------------------------------------
+ */
+size_t
+H5FD__mirror_xmit_decode_uint32(uint32_t *out, const unsigned char *_buf)
+{
+ uint32_t n = 0;
+ LOG_OP_CALL("H5FD__mirror_xmit_decode_uint32");
+ HDassert(_buf && out);
+ HDmemcpy(&n, _buf, sizeof(n));
+ *out = (uint32_t)HDntohl(n);
+ return 4; /* number of bytes eaten */
+} /* end H5FD__mirror_xmit_decode_uint32() */
+
+
+
+/* ---------------------------------------------------------------------------
+ * Function: is_host_little_endian
+ *
+ * Purpose: Determine whether the host machine is is little-endian.
+ *
+ * Store an intger with a known value, re-map the memory to a
+ * character array, and inspect the array's contents.
+ *
+ * Return: The number of bytes written to the buffer (8).
+ *
+ * Programmer: Jacob Smith
+ * 2020-03-05
+ * ---------------------------------------------------------------------------
+ */
+static hbool_t
+is_host_little_endian(void)
+{
+ union {
+ uint32_t u32;
+ uint8_t u8[4];
+ } echeck;
+ echeck.u32 = 0xA1B2C3D4;
+ if (echeck.u8[0] == 0xD4) {
+ return TRUE;
+ }
+ else {
+ return FALSE;
+ }
+} /* end is_host_little_endian() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: H5FD__mirror_xmit_decode_uint64
+ *
+ * Purpose: Extract a 64-bit integer in "network" (Big-Endian) word order
+ * from the byte-buffer and return it with the local word order.
+ *
+ * The programmer must ensure that the received buffer holds
+ * at least the expected size of data.
+ *
+ * WARNING: Does not accommodate other forms of endianness,
+ * e.g. "middle-endian".
+ *
+ * Return: The number of bytes written to the buffer (8).
+ * ---------------------------------------------------------------------------
+ */
+size_t
+H5FD__mirror_xmit_decode_uint64(uint64_t *out, const unsigned char *_buf)
+{
+ uint64_t n = 0;
+ LOG_OP_CALL("H5FD__mirror_xmit_decode_uint64");
+ HDassert(_buf && out);
+ HDmemcpy(&n, _buf, sizeof(n));
+ if (TRUE == is_host_little_endian()) {
+ *out = BSWAP_64(n);
+ }
+ else {
+ *out = n;
+ }
+ return 8;
+} /* end H5FD__mirror_xmit_decode_uint64() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: H5FD__mirror_xmit_decode_uint8
+ *
+ * Purpose: Extract a 8-bit integer in "network" (Big-Endian) word order
+ * from the byte-buffer and return it with the local word order at
+ * the destination pointer.
+ * (yes, it's one byte).
+ *
+ * Return: The number of bytes read from the buffer (1).
+ * ---------------------------------------------------------------------------
+ */
+size_t
+H5FD__mirror_xmit_decode_uint8(uint8_t *out, const unsigned char *_buf)
+{
+ LOG_OP_CALL("H5FD__mirror_xmit_decode_uint8");
+ HDassert(_buf && out);
+ HDmemcpy(out, _buf, sizeof(uint8_t));
+ return 1; /* number of bytes eaten */
+} /* end H5FD__mirror_xmit_decode_uint8() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: H5FD__mirror_xmit_encode_uint16
+ *
+ * Purpose: Encode a 16-bit integer in "network" (Big-Endian) word order
+ * in place in the destination bytes-buffer.
+ *
+ * The programmer must ensure that the destination buffer is
+ * large enough to hold the expected data.
+ *
+ * Return: The number of bytes written to the buffer (2).
+ * ---------------------------------------------------------------------------
+ */
+size_t
+H5FD__mirror_xmit_encode_uint16(unsigned char *_dest, uint16_t v)
+{
+ uint16_t n = 0;
+ LOG_OP_CALL("H5FD__mirror_xmit_encode_uint16");
+ HDassert(_dest);
+ n = (uint16_t)HDhtons(v);
+ HDmemcpy(_dest, &n, sizeof(n));
+ return 2;
+} /* end H5FD__mirror_xmit_encode_uint16() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: H5FD__mirror_xmit_encode_uint32
+ *
+ * Purpose: Encode a 32-bit integer in "network" (Big-Endian) word order
+ * in place in the destination bytes-buffer.
+ *
+ * The programmer must ensure that the destination buffer is
+ * large enough to hold the expected data.
+ *
+ * Return: The number of bytes written to the buffer (4).
+ * ---------------------------------------------------------------------------
+ */
+size_t
+H5FD__mirror_xmit_encode_uint32(unsigned char *_dest, uint32_t v)
+{
+ uint32_t n = 0;
+ LOG_OP_CALL("H5FD__mirror_xmit_encode_uint32");
+ HDassert(_dest);
+ n = (uint32_t)HDhtonl(v);
+ HDmemcpy(_dest, &n, sizeof(n));
+ return 4;
+} /* end H5FD__mirror_xmit_encode_uint32() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: H5FD__mirror_xmit_encode_uint64
+ *
+ * Purpose: Encode a 64-bit integer in "network" (Big-Endian) word order
+ * in place in the destination bytes-buffer.
+ *
+ * The programmer must ensure that the destination buffer is
+ * large enough to hold the expected data.
+ *
+ * Return: The number of bytes written to the buffer (8).
+ * ---------------------------------------------------------------------------
+ */
+size_t
+H5FD__mirror_xmit_encode_uint64(unsigned char *_dest, uint64_t v)
+{
+ uint64_t n = v;
+ LOG_OP_CALL("H5FD__mirror_xmit_decode_uint64");
+ HDassert(_dest);
+ if (TRUE == is_host_little_endian()) {
+ n = BSWAP_64(v);
+ }
+ HDmemcpy(_dest, &n, sizeof(n));
+ return 8;
+} /* H5FD__mirror_xmit_encode_uint64() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: H5FD__mirror_xmit_encode_uint8
+ *
+ * Purpose: Encode a 8-bit integer in "network" (Big-Endian) word order
+ * in place in the destination bytes-buffer.
+ * (yes, it's one byte).
+ *
+ * The programmer must ensure that the destination buffer is
+ * large enough to hold the expected data.
+ *
+ * Return: The number of bytes read from the buffer (1).
+ * ---------------------------------------------------------------------------
+ */
+size_t
+H5FD__mirror_xmit_encode_uint8(unsigned char *dest, uint8_t v)
+{
+ LOG_OP_CALL("H5FD__mirror_xmit_encode_uint8");
+ HDassert(dest);
+ HDmemcpy(dest, &v, sizeof(v));
+ return 1;
+} /* end H5FD__mirror_xmit_encode_uint8() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: H5FD_mirror_xmit_decode_header
+ *
+ * Purpose: Extract a mirror_xmit_t "header" from the bytes-buffer.
+ *
+ * Fields will be lifted from the buffer and stored in the
+ * target structure, using in the correct location (different
+ * systems may insert different padding between components) and
+ * word order (Big- vs Little-Endian).
+ *
+ * The resulting structure should be sanity-checked with
+ * H5FD_mirror_xmit_is_xmit() before use.
+ *
+ * The programmer must ensure that the received buffer holds
+ * at least the expected size of data.
+ *
+ * Return: The number of bytes consumed from the buffer.
+ * ---------------------------------------------------------------------------
+ */
+size_t
+H5FD_mirror_xmit_decode_header(H5FD_mirror_xmit_t *out,
+ const unsigned char *buf)
+{
+ size_t n_eaten = 0;
+ LOG_OP_CALL("H5FD_mirror_xmit_decode_header");
+ HDassert(out && buf);
+ n_eaten += H5FD__mirror_xmit_decode_uint32(&(out->magic), &buf[n_eaten]);
+ n_eaten += H5FD__mirror_xmit_decode_uint8(&(out->version), &buf[n_eaten]);
+ n_eaten += H5FD__mirror_xmit_decode_uint32(&(out->session_token),
+ &buf[n_eaten]);
+ n_eaten += H5FD__mirror_xmit_decode_uint32(&(out->xmit_count),
+ &buf[n_eaten]);
+ n_eaten += H5FD__mirror_xmit_decode_uint8(&(out->op), &buf[n_eaten]);
+ HDassert(n_eaten == H5FD_MIRROR_XMIT_HEADER_SIZE);
+ return n_eaten;
+} /* end H5FD_mirror_xmit_decode_header() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: H5FD_mirror_xmit_decode_lock
+ *
+ * Purpose: Extract a mirror_xmit_lock_t from the bytes-buffer.
+ *
+ * Fields will be lifted from the buffer and stored in the
+ * target structure, using in the correct location (different
+ * systems may insert different padding between components) and
+ * word order (Big- vs Little-Endian).
+ *
+ * The programmer must ensure that the received buffer holds
+ * at least the expected size of data.
+ *
+ * The resulting structure should be sanity-checked with
+ * H5FD_mirror_xmit_is_lock() before use.
+ *
+ * Return: The number of bytes consumed from the buffer.
+ * ---------------------------------------------------------------------------
+ */
+size_t
+H5FD_mirror_xmit_decode_lock(H5FD_mirror_xmit_lock_t *out,
+ const unsigned char *buf)
+{
+ size_t n_eaten = 0;
+ LOG_OP_CALL("H5FD_mirror_xmit_decode_lock");
+ HDassert(out && buf);
+ n_eaten += H5FD_mirror_xmit_decode_header(&(out->pub), buf);
+ n_eaten += H5FD__mirror_xmit_decode_uint64(&(out->rw), &buf[n_eaten]);
+ HDassert(n_eaten == H5FD_MIRROR_XMIT_LOCK_SIZE);
+ return n_eaten;
+} /* end H5FD_mirror_xmit_decode_lock() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: H5FD_mirror_xmit_decode_open
+ *
+ * Purpose: Extract a mirror_xmit_open_t from the bytes-buffer.
+ *
+ * Fields will be lifted from the buffer and stored in the
+ * target structure, using in the correct location (different
+ * systems may insert different padding between components) and
+ * word order (Big- vs Little-Endian).
+ *
+ * The programmer must ensure that the received buffer holds
+ * at least the expected size of data.
+ *
+ * The resulting structure should be sanity-checked with
+ * H5FD_mirror_xmit_is_open() before use.
+ *
+ * Return: The maximum number of bytes that this decoding operation might
+ * have consumed from the buffer.
+ * ---------------------------------------------------------------------------
+ */
+size_t
+H5FD_mirror_xmit_decode_open(H5FD_mirror_xmit_open_t *out,
+ const unsigned char *buf)
+{
+ size_t n_eaten = 0;
+ LOG_OP_CALL("H5FD_mirror_xmit_decode_open");
+ HDassert(out && buf);
+ n_eaten += H5FD_mirror_xmit_decode_header(&(out->pub), buf);
+ n_eaten += H5FD__mirror_xmit_decode_uint32(&(out->flags), &buf[n_eaten]);
+ n_eaten += H5FD__mirror_xmit_decode_uint64(&(out->maxaddr), &buf[n_eaten]);
+ n_eaten += H5FD__mirror_xmit_decode_uint64(&(out->size_t_blob),
+ &buf[n_eaten]);
+ HDassert((H5FD_MIRROR_XMIT_OPEN_SIZE - H5FD_MIRROR_XMIT_FILEPATH_MAX)
+ == n_eaten);
+ HDstrncpy(out->filename, (const char *)&buf[n_eaten],
+ H5FD_MIRROR_XMIT_FILEPATH_MAX-1);
+ out->filename[H5FD_MIRROR_XMIT_FILEPATH_MAX-1] = 0; /* force final NULL */
+ return H5FD_MIRROR_XMIT_OPEN_SIZE;
+} /* end H5FD_mirror_xmit_decode_open() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: H5FD_mirror_xmit_decode_reply
+ *
+ * Purpose: Extract a mirror_xmit_reply_t from the bytes-buffer.
+ *
+ * Fields will be lifted from the buffer and stored in the
+ * target structure, using in the correct location (different
+ * systems may insert different padding between components) and
+ * word order (Big- vs Little-Endian).
+ *
+ * The programmer must ensure that the received buffer holds
+ * at least the expected size of data.
+ *
+ * The resulting structure should be sanity-checked with
+ * H5FD_mirror_xmit_is_reply() before use.
+ *
+ * Return: The maximum number of bytes that this decoding operation might
+ * have consumed from the buffer.
+ * ---------------------------------------------------------------------------
+ */
+size_t
+H5FD_mirror_xmit_decode_reply(H5FD_mirror_xmit_reply_t *out,
+ const unsigned char *buf)
+{
+ size_t n_eaten = 0;
+ LOG_OP_CALL("H5FD_mirror_xmit_decode_reply");
+ HDassert(out && buf);
+ n_eaten += H5FD_mirror_xmit_decode_header(&(out->pub), buf);
+ n_eaten += H5FD__mirror_xmit_decode_uint32(&(out->status), &buf[n_eaten]);
+ HDassert((H5FD_MIRROR_XMIT_REPLY_SIZE - H5FD_MIRROR_STATUS_MESSAGE_MAX)
+ == n_eaten);
+ HDstrncpy(out->message, (const char *)&buf[n_eaten],
+ H5FD_MIRROR_STATUS_MESSAGE_MAX-1);
+ out->message[H5FD_MIRROR_STATUS_MESSAGE_MAX-1] = 0; /* force NULL term */
+ return H5FD_MIRROR_XMIT_REPLY_SIZE;
+} /* end H5FD_mirror_xmit_decode_reply() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: H5FD_mirror_xmit_decode_set_eoa
+ *
+ * Purpose: Extract a mirror_xmit_eoa_t from the bytes-buffer.
+ *
+ * Fields will be lifted from the buffer and stored in the
+ * target structure, using in the correct location (different
+ * systems may insert different padding between components) and
+ * word order (Big- vs Little-Endian).
+ *
+ * The programmer must ensure that the received buffer holds
+ * at least the expected size of data.
+ *
+ * The resulting structure should be sanity-checked with
+ * H5FD_mirror_xmit_is_set_eoa() before use.
+ *
+ * Return: The number of bytes consumed from the buffer.
+ * ---------------------------------------------------------------------------
+ */
+size_t
+H5FD_mirror_xmit_decode_set_eoa(H5FD_mirror_xmit_eoa_t *out,
+ const unsigned char *buf)
+{
+ size_t n_eaten = 0;
+ LOG_OP_CALL("H5FD_mirror_xmit_decode_set_eoa");
+ HDassert(out && buf);
+ n_eaten += H5FD_mirror_xmit_decode_header(&(out->pub), buf);
+ n_eaten += H5FD__mirror_xmit_decode_uint8(&(out->type), &buf[n_eaten]);
+ n_eaten += H5FD__mirror_xmit_decode_uint64(&(out->eoa_addr), &buf[n_eaten]);
+ HDassert(n_eaten == H5FD_MIRROR_XMIT_EOA_SIZE);
+ return n_eaten;
+} /* end H5FD_mirror_xmit_decode_set_eoa() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: H5FD_mirror_xmit_decode_write
+ *
+ * Purpose: Extract a mirror_xmit_write_t from the bytes-buffer.
+ *
+ * Fields will be lifted from the buffer and stored in the
+ * target structure, using in the correct location (different
+ * systems may insert different padding between components) and
+ * word order (Big- vs Little-Endian).
+ *
+ * The programmer must ensure that the received buffer holds
+ * at least the expected size of data.
+ *
+ * The resulting structure should be sanity-checked with
+ * H5FD_mirror_xmit_is_write() before use.
+ *
+ * Return: The number of bytes consumed from the buffer.
+ * ---------------------------------------------------------------------------
+ */
+size_t
+H5FD_mirror_xmit_decode_write(H5FD_mirror_xmit_write_t *out,
+ const unsigned char *buf)
+{
+ size_t n_eaten = 0;
+ LOG_OP_CALL("H5FD_mirror_xmit_decode_write");
+ HDassert(out && buf);
+ n_eaten += H5FD_mirror_xmit_decode_header(&(out->pub), buf);
+ n_eaten += H5FD__mirror_xmit_decode_uint8(&(out->type), &buf[n_eaten]);
+ n_eaten += H5FD__mirror_xmit_decode_uint64(&(out->offset), &buf[n_eaten]);
+ n_eaten += H5FD__mirror_xmit_decode_uint64(&(out->size), &buf[n_eaten]);
+ HDassert(n_eaten == H5FD_MIRROR_XMIT_WRITE_SIZE);
+ return n_eaten;
+} /* end H5FD_mirror_xmit_decode_write() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: H5FD_mirror_xmit_encode_header
+ *
+ * Purpose: Encode a mirror_xmit_t "header" to the bytes-buffer.
+ *
+ * Fields will be packed into the buffer in a predictable manner,
+ * any numbers stored in "network" (Big-Endian) word order.
+ *
+ * The programmer must ensure that the destination buffer is
+ * large enough to hold the expected data.
+ *
+ * Return: The number of bytes written to the buffer.
+ * ---------------------------------------------------------------------------
+ */
+size_t
+H5FD_mirror_xmit_encode_header(unsigned char *dest,
+ const H5FD_mirror_xmit_t *x)
+{
+ size_t n_writ = 0;
+ LOG_OP_CALL("H5FD_mirror_xmit_encode_header");
+ HDassert(dest && x);
+ n_writ += H5FD__mirror_xmit_encode_uint32((dest+n_writ), x->magic);
+ n_writ += H5FD__mirror_xmit_encode_uint8((dest+n_writ), x->version);
+ n_writ += H5FD__mirror_xmit_encode_uint32((dest+n_writ), x->session_token);
+ n_writ += H5FD__mirror_xmit_encode_uint32((dest+n_writ), x->xmit_count);
+ n_writ += H5FD__mirror_xmit_encode_uint8((dest+n_writ), x->op);
+ HDassert(n_writ == H5FD_MIRROR_XMIT_HEADER_SIZE);
+ return n_writ;
+} /* end H5FD_mirror_xmit_encode_header() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: H5FD_mirror_xmit_encode_lock
+ *
+ * Purpose: Encode a mirror_xmit_lock_t to the bytes-buffer.
+ * Fields will be packed into the buffer in a predictable manner,
+ * any numbers stored in "network" (Big-Endian) word order.
+ *
+ * The programmer must ensure that the destination buffer is
+ * large enough to hold the expected data.
+ *
+ * Return: The number of bytes written to the buffer.
+ * ---------------------------------------------------------------------------
+ */
+size_t
+H5FD_mirror_xmit_encode_lock(unsigned char *dest,
+ const H5FD_mirror_xmit_lock_t *x)
+{
+ size_t n_writ = 0;
+ LOG_OP_CALL("H5FD_mirror_xmit_encode_lock");
+ HDassert(dest && x);
+ n_writ += H5FD_mirror_xmit_encode_header(dest,
+ (const H5FD_mirror_xmit_t *)&(x->pub));
+ n_writ += H5FD__mirror_xmit_encode_uint64(&dest[n_writ], x->rw);
+ HDassert(n_writ == H5FD_MIRROR_XMIT_LOCK_SIZE);
+ return n_writ;
+} /* end H5FD_mirror_xmit_encode_lock() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: H5FD_mirror_xmit_encode_open
+ *
+ * Purpose: Encode a mirror_xmit_open_t to the bytes-buffer.
+ * Fields will be packed into the buffer in a predictable manner,
+ * any numbers stored in "network" (Big-Endian) word order.
+ *
+ * The programmer must ensure that the destination buffer is
+ * large enough to hold the expected data.
+ *
+ * Return: The maximum number of bytes that this decoding operation might
+ * have written into the buffer.
+ * ---------------------------------------------------------------------------
+ */
+size_t
+H5FD_mirror_xmit_encode_open(unsigned char *dest,
+ const H5FD_mirror_xmit_open_t *x)
+{
+ size_t n_writ = 0;
+ LOG_OP_CALL("H5FD_mirror_xmit_encode_open");
+ HDassert(dest && x);
+ /* clear entire structure, but especially its filepath string area */
+ for (n_writ = 0; n_writ < H5FD_MIRROR_XMIT_OPEN_SIZE; n_writ++) {
+ *(dest+n_writ) = 0;
+ }
+ n_writ = 0;
+ n_writ += H5FD_mirror_xmit_encode_header(dest,
+ (const H5FD_mirror_xmit_t *)&(x->pub));
+ n_writ += H5FD__mirror_xmit_encode_uint32(&dest[n_writ], x->flags);
+ n_writ += H5FD__mirror_xmit_encode_uint64(&dest[n_writ], x->maxaddr);
+ n_writ += H5FD__mirror_xmit_encode_uint64(&dest[n_writ], x->size_t_blob);
+ HDassert((H5FD_MIRROR_XMIT_OPEN_SIZE - H5FD_MIRROR_XMIT_FILEPATH_MAX)
+ == n_writ);
+ HDstrncpy((char *)&dest[n_writ], x->filename,
+ H5FD_MIRROR_XMIT_FILEPATH_MAX);
+ return H5FD_MIRROR_XMIT_OPEN_SIZE;
+} /* end H5FD_mirror_xmit_encode_open() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: H5FD_mirror_xmit_encode_reply
+ *
+ * Purpose: Encode a mirror_xmit_reply_t to the bytes-buffer.
+ *
+ * Fields will be packed into the buffer in a predictable manner,
+ * any numbers stored in "network" (Big-Endian) word order.
+ *
+ * The programmer must ensure that the destination buffer is
+ * large enough to hold the expected data.
+ *
+ * Return: The maximum number of bytes that this decoding operation might
+ * have written into the buffer.
+ * ---------------------------------------------------------------------------
+ */
+size_t
+H5FD_mirror_xmit_encode_reply(unsigned char *dest,
+ const H5FD_mirror_xmit_reply_t *x)
+{
+ size_t n_writ = 0;
+ LOG_OP_CALL("H5FD_mirror_xmit_encode_reply");
+ HDassert(dest && x);
+ /* clear entire structure, but especially its message string area */
+ for (n_writ = 0; n_writ < H5FD_MIRROR_XMIT_REPLY_SIZE; n_writ++) {
+ *(dest+n_writ) = 0;
+ }
+ n_writ = 0;
+ n_writ += H5FD_mirror_xmit_encode_header(dest,
+ (const H5FD_mirror_xmit_t *)&(x->pub));
+ n_writ += H5FD__mirror_xmit_encode_uint32(&dest[n_writ], x->status);
+ HDassert((H5FD_MIRROR_XMIT_REPLY_SIZE - H5FD_MIRROR_STATUS_MESSAGE_MAX)
+ == n_writ);
+ HDstrncpy((char *)&dest[n_writ], x->message,
+ H5FD_MIRROR_STATUS_MESSAGE_MAX);
+ return H5FD_MIRROR_XMIT_REPLY_SIZE;
+} /* end H5FD_mirror_xmit_encode_reply() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: H5FD_mirror_xmit_encode_set_eoa
+ *
+ * Purpose: Encode a mirror_xmit_eoa_t to the bytes-buffer.
+ *
+ * Fields will be packed into the buffer in a predictable manner,
+ * any numbers stored in "network" (Big-Endian) word order.
+ *
+ * The programmer must ensure that the destination buffer is
+ * large enough to hold the expected data.
+ *
+ * Return: The number of bytes written to the buffer.
+ * ---------------------------------------------------------------------------
+ */
+size_t
+H5FD_mirror_xmit_encode_set_eoa(unsigned char *dest,
+ const H5FD_mirror_xmit_eoa_t *x)
+{
+ size_t n_writ = 0;
+ LOG_OP_CALL("H5FD_mirror_xmit_encode_set_eoa");
+ HDassert(dest && x);
+ n_writ += H5FD_mirror_xmit_encode_header(dest,
+ (const H5FD_mirror_xmit_t *)&(x->pub));
+ n_writ += H5FD__mirror_xmit_encode_uint8(&dest[n_writ], x->type);
+ n_writ += H5FD__mirror_xmit_encode_uint64(&dest[n_writ], x->eoa_addr);
+ HDassert(n_writ == H5FD_MIRROR_XMIT_EOA_SIZE);
+ return n_writ;
+} /* end H5FD_mirror_xmit_encode_set_eoa() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: H5FD_mirror_xmit_encode_write
+ *
+ * Purpose: Encode a mirror_xmit_write_t to the bytes-buffer.
+ *
+ * Fields will be packed into the buffer in a predictable manner,
+ * any numbers stored in "network" (Big-Endian) word order.
+ *
+ * The programmer must ensure that the destination buffer is
+ * large enough to hold the expected data.
+ *
+ * Return: The number of bytes written to the buffer.
+ * ---------------------------------------------------------------------------
+ */
+size_t
+H5FD_mirror_xmit_encode_write(unsigned char *dest,
+ const H5FD_mirror_xmit_write_t *x)
+{
+ size_t n_writ = 0;
+ LOG_OP_CALL("H5FD_mirror_xmit_encode_write");
+ HDassert(dest && x);
+ n_writ += H5FD_mirror_xmit_encode_header(dest,
+ (const H5FD_mirror_xmit_t *)&(x->pub));
+ n_writ += H5FD__mirror_xmit_encode_uint8(&dest[n_writ], x->type);
+ n_writ += H5FD__mirror_xmit_encode_uint64(&dest[n_writ], x->offset);
+ n_writ += H5FD__mirror_xmit_encode_uint64(&dest[n_writ], x->size);
+ HDassert(n_writ == H5FD_MIRROR_XMIT_WRITE_SIZE);
+ return n_writ;
+} /* end H5FD_mirror_xmit_encode_write() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: H5FD_mirror_xmit_is_close
+ *
+ * Purpose: Verify that a mirror_xmit_t is a valid CLOSE xmit.
+ *
+ * Checks header validity and op code.
+ *
+ * Return: TRUE if valid; else FALSE.
+ * ---------------------------------------------------------------------------
+ */
+hbool_t
+H5FD_mirror_xmit_is_close(const H5FD_mirror_xmit_t *xmit)
+{
+ LOG_OP_CALL("H5FD_mirror_xmit_is_close");
+ HDassert(xmit);
+ if ( (TRUE == H5FD_mirror_xmit_is_xmit(xmit)) &&
+ (H5FD_MIRROR_OP_CLOSE == xmit->op) )
+ {
+ return TRUE;
+ }
+ return FALSE;
+} /* end H5FD_mirror_xmit_is_close() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: H5FD_mirror_xmit_is_lock
+ *
+ * Purpose: Verify that a mirror_xmit_lock_t is a valid LOCK xmit.
+ *
+ * Checks header validity and op code.
+ *
+ * Return: TRUE if valid; else FALSE.
+ * ---------------------------------------------------------------------------
+ */
+hbool_t
+H5FD_mirror_xmit_is_lock(const H5FD_mirror_xmit_lock_t *xmit)
+{
+ LOG_OP_CALL("H5FD_mirror_xmit_is_lock");
+ HDassert(xmit);
+ if ( (TRUE == H5FD_mirror_xmit_is_xmit(&(xmit->pub))) &&
+ (H5FD_MIRROR_OP_LOCK == xmit->pub.op) )
+ {
+ return TRUE;
+ }
+ return FALSE;
+} /* end H5FD_mirror_xmit_is_lock() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: H5FD_mirror_xmit_is_open
+ *
+ * Purpose: Verify that a mirror_xmit_open_t is a valid OPEN xmit.
+ *
+ * Checks header validity and op code.
+ *
+ * Return: TRUE if valid; else FALSE.
+ * ---------------------------------------------------------------------------
+ */
+hbool_t
+H5FD_mirror_xmit_is_open(const H5FD_mirror_xmit_open_t *xmit)
+{
+ LOG_OP_CALL("H5FD_mirror_xmit_is_open");
+ HDassert(xmit);
+ if ( (TRUE == H5FD_mirror_xmit_is_xmit(&(xmit->pub))) &&
+ (H5FD_MIRROR_OP_OPEN == xmit->pub.op) )
+ {
+ return TRUE;
+ }
+ return FALSE;
+} /* end H5FD_mirror_xmit_is_open() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: H5FD_mirror_xmit_is_eoa
+ *
+ * Purpose: Verify that a mirror_xmit_eoa_t is a valid SET-EOA xmit.
+ *
+ * Checks header validity and op code.
+ *
+ * Return: TRUE if valid; else FALSE.
+ * ---------------------------------------------------------------------------
+ */
+hbool_t
+H5FD_mirror_xmit_is_set_eoa(const H5FD_mirror_xmit_eoa_t *xmit)
+{
+ LOG_OP_CALL("H5FD_mirror_xmit_is_set_eoa");
+ HDassert(xmit);
+ if ( (TRUE == H5FD_mirror_xmit_is_xmit(&(xmit->pub))) &&
+ (H5FD_MIRROR_OP_SET_EOA == xmit->pub.op) )
+ {
+ return TRUE;
+ }
+ return FALSE;
+} /* end H5FD_mirror_xmit_is_eoa() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: H5FD_mirror_xmit_is_reply
+ *
+ * Purpose: Verify that a mirror_xmit_reply_t is a valid REPLY xmit.
+ *
+ * Checks header validity and op code.
+ *
+ * Return: TRUE if valid; else FALSE.
+ * ---------------------------------------------------------------------------
+ */
+hbool_t
+H5FD_mirror_xmit_is_reply(const H5FD_mirror_xmit_reply_t *xmit)
+{
+ LOG_OP_CALL("H5FD_mirror_xmit_is_reply");
+ HDassert(xmit);
+ if ( (TRUE == H5FD_mirror_xmit_is_xmit(&(xmit->pub))) &&
+ (H5FD_MIRROR_OP_REPLY == xmit->pub.op) )
+ {
+ return TRUE;
+ }
+ return FALSE;
+} /* end H5FD_mirror_xmit_is_reply() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: H5FD_mirror_xmit_is_write
+ *
+ * Purpose: Verify that a mirror_xmit_write_t is a valid WRITE xmit.
+ *
+ * Checks header validity and op code.
+ *
+ * Return: TRUE if valid; else FALSE.
+ * ---------------------------------------------------------------------------
+ */
+hbool_t
+H5FD_mirror_xmit_is_write(const H5FD_mirror_xmit_write_t *xmit)
+{
+ LOG_OP_CALL("H5FD_mirror_xmit_is_write");
+ HDassert(xmit);
+ if ( (TRUE == H5FD_mirror_xmit_is_xmit(&(xmit->pub))) &&
+ (H5FD_MIRROR_OP_WRITE == xmit->pub.op) )
+ {
+ return TRUE;
+ }
+ return FALSE;
+} /* end H5FD_mirror_xmit_is_write() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: H5FD_mirror_xmit_is_xmit
+ *
+ * Purpose: Verify that a mirror_xmit_t is well-formed.
+ *
+ * Checks magic number and structure version.
+ *
+ * Return: TRUE if valid; else FALSE.
+ * ---------------------------------------------------------------------------
+ */
+hbool_t
+H5FD_mirror_xmit_is_xmit(const H5FD_mirror_xmit_t *xmit)
+{
+ LOG_OP_CALL("H5FD_mirror_xmit_is_xmit");
+ HDassert(xmit);
+ if ( (H5FD_MIRROR_XMIT_MAGIC != xmit->magic) ||
+ (H5FD_MIRROR_XMIT_CURR_VERSION != xmit->version) )
+ {
+ return FALSE;
+ }
+ return TRUE;
+} /* end H5FD_mirror_xmit_is_xmit() */
+
+
+/* ----------------------------------------------------------------------------
+ * Function: H5FD__mirror_verify_reply
+ *
+ * Purpose: Wait for and read reply data from remote processes.
+ * Sanity-check that a reply is well-formed and valid.
+ * If all checks pass, inspect the reply contents and handle
+ * reported error, if not an OK reply.
+ *
+ * Return: SUCCEED if ok, else FAIL.
+ * ----------------------------------------------------------------------------
+ */
+herr_t
+H5FD__mirror_verify_reply(H5FD_mirror_t *file)
+{
+ char xmit_buf[H5FD_MIRROR_XMIT_REPLY_SIZE];
+ struct H5FD_mirror_xmit_reply_t reply;
+ ssize_t read_ret = 0;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI_NOINIT;
+
+ LOG_OP_CALL("H5FD__mirror_verify_reply");
+
+ HDassert(file && file->sock_fd);
+
+ read_ret = HDread(file->sock_fd, xmit_buf, H5FD_MIRROR_XMIT_REPLY_SIZE);
+ if (read_ret < 0) {
+ HGOTO_ERROR(H5E_VFL, H5E_READERROR, FAIL, "unable to read reply");
+ }
+ if (read_ret != H5FD_MIRROR_XMIT_REPLY_SIZE) {
+ HGOTO_ERROR(H5E_VFL, H5E_READERROR, FAIL, "unexpected read size");
+ }
+
+ LOG_XMIT_BYTES("reply", xmit_buf, read_ret);
+
+ if (H5FD_mirror_xmit_decode_reply(&reply, (const unsigned char *)xmit_buf)
+ != H5FD_MIRROR_XMIT_REPLY_SIZE)
+ {
+ HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "unable to decode reply xmit");
+ }
+
+ if (H5FD_mirror_xmit_is_reply(&reply) != TRUE) {
+ HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "xmit op code was not REPLY");
+ }
+
+ if (reply.pub.session_token != file->xmit.session_token) {
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "wrong session");
+ }
+
+ if (reply.pub.xmit_count != (file->xmit_i)++) {
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "xmit out of sync");
+ }
+
+ if (reply.status != H5FD_MIRROR_STATUS_OK) {
+ HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL,
+ "%s", (const char *)(reply.message));
+ }
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value);
+} /* end H5FD__mirror_verify_reply() */
+
+
+/* -------------------------------------------------------------------------
+ * Function: H5FD_mirror_fapl_get
+ *
+ * Purpose: Get the file access propety list which could be used to create
+ * an identical file.
+ *
+ * Return: Success: pointer to the new file access property list value.
+ * Failure: NULL
+ * -------------------------------------------------------------------------
+ */
+static void *
+H5FD_mirror_fapl_get(H5FD_t *_file)
+{
+ H5FD_mirror_t *file = (H5FD_mirror_t *)_file;
+ H5FD_mirror_fapl_t *fa = NULL;
+ void *ret_value = NULL;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ LOG_OP_CALL("H5FD_mirror_fapl_get");
+
+ fa = (H5FD_mirror_fapl_t *)H5MM_calloc(sizeof(H5FD_mirror_fapl_t));
+ if (NULL == fa) {
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "calloc failed");
+ }
+
+ HDmemcpy(fa, &(file->fa), sizeof(H5FD_mirror_fapl_t));
+
+ ret_value = fa;
+
+done:
+ if (ret_value == NULL) {
+ if (fa != NULL) {
+ H5MM_xfree(fa);
+ }
+ }
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_mirror_fapl_get() */
+
+
+/* -------------------------------------------------------------------------
+ * Function: H5FD_mirror_fapl_copy
+ *
+ * Purpose: Copies the mirror vfd-specific file access properties.
+ *
+ * Return: Success: Pointer to a new property list
+ * Failure: NULL
+ * -------------------------------------------------------------------------
+ */
+static void *
+H5FD_mirror_fapl_copy(const void *_old_fa)
+{
+ const H5FD_mirror_fapl_t *old_fa = (const H5FD_mirror_fapl_t *)_old_fa;
+ H5FD_mirror_fapl_t *new_fa = NULL;
+ void *ret_value = NULL;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ LOG_OP_CALL("H5FD_mirror_fapl_copy");
+
+ new_fa = (H5FD_mirror_fapl_t *)H5MM_malloc(sizeof(H5FD_mirror_fapl_t));
+ if (new_fa == NULL) {
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL,
+ "memory allocation failed");
+ }
+
+ HDmemcpy(new_fa, old_fa, sizeof(H5FD_mirror_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_mirror_fapl_copy() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_mirror_fapl_free
+ *
+ * Purpose: Frees the mirror VFD-specific file access properties.
+ *
+ * Return: SUCCEED (cannot fail)
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_mirror_fapl_free(void *_fa)
+{
+ H5FD_mirror_fapl_t *fa = (H5FD_mirror_fapl_t*)_fa;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ LOG_OP_CALL("H5FD_mirror_fapl_free");
+
+ /* sanity check */
+ HDassert(fa != NULL);
+ HDassert(fa->magic == H5FD_MIRROR_FAPL_MAGIC);
+
+ fa->magic += 1; /* invalidate */
+ H5MM_xfree(fa);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5FD_mirror_fapl_free() */
+
+
+/* -------------------------------------------------------------------------
+ * Function: H5Pget_fapl_mirror
+ *
+ * Purpose: Get the configuration information for this fapl.
+ * Data is memcopied into the fa_out pointer.
+ *
+ * Return: SUCCEED/FAIL
+ * -------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_fapl_mirror(hid_t fapl_id, H5FD_mirror_fapl_t *fa_out)
+{
+ const H5FD_mirror_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);
+
+ LOG_OP_CALL("H5Pget_fapl_mirror");
+
+ if (NULL == fa_out) {
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "fa_out is NULL");
+ }
+
+ plist = H5P_object_verify(fapl_id, H5P_FILE_ACCESS);
+ if (NULL == plist) {
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL,
+ "not a file access property list");
+ }
+
+ if (H5P_peek_driver(plist) != H5FD_MIRROR) {
+ HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "incorrect VFL driver");
+ }
+
+ fa = (const H5FD_mirror_fapl_t *)H5P_peek_driver_info(plist);
+ if (NULL == fa) {
+ HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "bad VFL driver info");
+ }
+
+ HDassert(fa->magic == H5FD_MIRROR_FAPL_MAGIC); /* sanity check */
+
+ HDmemcpy(fa_out, fa, sizeof(H5FD_mirror_fapl_t));
+
+done:
+ FUNC_LEAVE_API(ret_value);
+} /* end H5Pget_fapl_mirror() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_fapl_mirror
+ *
+ * Purpose: Modify the file access property list to use the mirror
+ * driver (H5FD_MIRROR) defined in this source file.
+ *
+ * Return: SUCCEED/FAIL
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_fapl_mirror(hid_t fapl_id, H5FD_mirror_fapl_t *fa)
+{
+ H5P_genplist_t *plist = NULL;
+ herr_t ret_value = FAIL;
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "i*x", fapl_id, fa);
+
+ LOG_OP_CALL("H5Pset_fapl_mirror");
+
+ plist = H5P_object_verify(fapl_id, H5P_FILE_ACCESS);
+ if (NULL == plist) {
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL,
+ "not a file access property list");
+ }
+ if (NULL == fa) {
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "null fapl_t pointer");
+ }
+ if (H5FD_MIRROR_FAPL_MAGIC != fa->magic) {
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid fapl_t magic");
+ }
+ if (H5FD_MIRROR_CURR_FAPL_T_VERSION != fa->version) {
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unknown fapl_t version");
+ }
+
+ ret_value = H5P_set_driver(plist, H5FD_MIRROR, (const void *)fa);
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_fapl_mirror() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_mirror_open
+ *
+ * Purpose: Create and/or opens a file as an HDF5 file.
+ *
+ * Initiate connection with remote Server/Writer.
+ * If successful, the remote file is open.
+ *
+ * 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
+ *-------------------------------------------------------------------------
+ */
+static H5FD_t *
+H5FD_mirror_open(const char *name,
+ unsigned flags,
+ hid_t fapl_id,
+ haddr_t maxaddr)
+{
+#define MIRR_OPEN_MAXBUF 16 /* local symbol to give meaning to magic number */
+ /* #defined because it is needed at compile time */
+ /* Large enough to hold a port number string */
+ int live_socket = -1;
+ struct sockaddr_in target_addr;
+ socklen_t addr_size;
+ char xmit_buf[H5FD_MIRROR_XMIT_OPEN_SIZE];
+ H5FD_mirror_fapl_t fa;
+ H5FD_mirror_t *file = NULL;
+ H5FD_mirror_xmit_open_t open_xmit;
+ H5FD_t *ret_value = NULL;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ LOG_OP_CALL("H5FD_mirror_open");
+
+ /* --------------- */
+ /* Check arguments */
+ /* --------------- */
+
+ if (!name || !*name) {
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "invalid file name");
+ }
+ if (HDstrlen(name) >= H5FD_MIRROR_XMIT_FILEPATH_MAX) {
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "filename is too long");
+ }
+ 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");
+ }
+
+ if (H5Pget_fapl_mirror(fapl_id, &fa) == FAIL) {
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "can't get config info");
+ }
+
+ if (H5FD_MIRROR_FAPL_MAGIC != fa.magic) {
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "invalid fapl magic");
+ }
+
+ if (H5FD_MIRROR_CURR_FAPL_T_VERSION != fa.version) {
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "invalid fapl version");
+ }
+
+ /* --------------------- */
+ /* Handshake with remote */
+ /* --------------------- */
+
+ live_socket = HDsocket(AF_INET, SOCK_STREAM, 0);
+ if (live_socket < 0) {
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "can't create socket");
+ }
+
+ target_addr.sin_family = AF_INET;
+ target_addr.sin_port = HDhtons((uint16_t)fa.handshake_port);
+ target_addr.sin_addr.s_addr = HDinet_addr(fa.remote_ip);
+ HDmemset(target_addr.sin_zero, '\0', sizeof target_addr.sin_zero);
+
+ addr_size = sizeof(target_addr);
+ if (HDconnect(live_socket, (struct sockaddr *)&target_addr, addr_size) < 0)
+ {
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL,
+ "can't connect to remote server");
+ }
+
+ /* ------------- */
+ /* Open the file */
+ /* ------------- */
+
+ file = (H5FD_mirror_t *)H5FL_CALLOC(H5FD_mirror_t);
+ if (NULL == file) {
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL,
+ "unable to allocate file struct");
+ }
+
+ file->sock_fd = live_socket;
+ file->xmit_i = 0;
+
+ file->xmit.magic = H5FD_MIRROR_XMIT_MAGIC;
+ file->xmit.version = H5FD_MIRROR_XMIT_CURR_VERSION;
+ file->xmit.xmit_count = file->xmit_i++;
+ file->xmit.session_token = (uint32_t)(0x01020304 ^ file->sock_fd); /* TODO: hashing? */
+ /* int --> uint32_t may truncate on some systems... shouldn't matter? */
+
+ file->xmit.op = H5FD_MIRROR_OP_OPEN;
+ open_xmit.pub = file->xmit;
+ open_xmit.flags = (uint32_t)flags;
+ open_xmit.maxaddr = (uint64_t)maxaddr;
+ open_xmit.size_t_blob = (uint64_t)((size_t)(-1));
+ HDsnprintf(open_xmit.filename, H5FD_MIRROR_XMIT_FILEPATH_MAX-1, "%s", name);
+
+ if (H5FD_mirror_xmit_encode_open((unsigned char *)xmit_buf,
+ (const H5FD_mirror_xmit_open_t *)&open_xmit)
+ != H5FD_MIRROR_XMIT_OPEN_SIZE)
+ {
+ HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, NULL, "unable to encode open");
+ }
+
+ LOG_XMIT_BYTES("open", xmit_buf, H5FD_MIRROR_XMIT_OPEN_SIZE);
+
+ if (HDwrite(file->sock_fd, xmit_buf, H5FD_MIRROR_XMIT_OPEN_SIZE) < 0) {
+ HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, NULL, "unable to transmit open");
+ }
+
+ if (H5FD__mirror_verify_reply(file) == FAIL) {
+ HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, NULL, "invalid reply");
+ }
+
+ ret_value = (H5FD_t *)file;
+
+done:
+ if (NULL == ret_value) {
+ if (file) {
+ file = H5FL_FREE(H5FD_mirror_t, file);
+ }
+ if (live_socket >= 0 && HDclose(live_socket) < 0) {
+ HDONE_ERROR(H5E_VFL, H5E_CANTCLOSEFILE, NULL,
+ "can't close socket");
+ }
+ }
+ FUNC_LEAVE_NOAPI(ret_value)
+#undef MIRR_OPEN_MAXBUF
+} /* end H5FD_mirror_open() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_mirror_close
+ *
+ * Purpose: Closes the HDF5 file.
+ *
+ * Tries to send a CLOSE op to the remote Writer and expects
+ * a valid reply, then closes the socket.
+ * In error, attempts to send a deliberately invalid xmit to the
+ * Writer to get it to close/abort, then attempts to close the
+ * socket.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL, file possibly not closed but resources freed.
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_mirror_close(H5FD_t *_file)
+{
+ H5FD_mirror_t *file = (H5FD_mirror_t *)_file;
+ unsigned char xmit_buf[H5FD_MIRROR_XMIT_HEADER_SIZE];
+ int xmit_encoded = 0; /* monitor point of failure */
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ LOG_OP_CALL("H5FD_mirror_close");
+
+ /* Sanity check */
+ HDassert(file);
+ HDassert(file->sock_fd >= 0);
+
+ file->xmit.xmit_count = (file->xmit_i)++;
+ file->xmit.op = H5FD_MIRROR_OP_CLOSE;
+
+ if (H5FD_mirror_xmit_encode_header(xmit_buf,
+ (const H5FD_mirror_xmit_t *)&(file->xmit))
+ != H5FD_MIRROR_XMIT_HEADER_SIZE)
+ {
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to encode close");
+ }
+ xmit_encoded = 1;
+
+ LOG_XMIT_BYTES("close", xmit_buf, H5FD_MIRROR_XMIT_HEADER_SIZE);
+
+ if (HDwrite(file->sock_fd, xmit_buf, H5FD_MIRROR_XMIT_HEADER_SIZE) < 0) {
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to transmit close");
+ }
+
+ if (H5FD__mirror_verify_reply(file) == FAIL) {
+ HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "invalid reply");
+ }
+
+ if (HDclose(file->sock_fd) < 0) {
+ HGOTO_ERROR(H5E_VFL, H5E_CANTCLOSEFILE, FAIL, "can't close socket");
+ }
+
+done:
+ if (ret_value == FAIL) {
+ if (xmit_encoded == 0) {
+ /* Encode failed; send GOODBYE to force writer halt.
+ * We can ignore any response from the writer, if we receive
+ * any reply at all.
+ */
+ if (HDwrite(file->sock_fd, "GOODBYE", HDstrlen("GOODBYE")) < 0) {
+ HDONE_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL,
+ "unable to transmit close");
+ if (HDclose(file->sock_fd) < 0) {
+ HDONE_ERROR(H5E_VFL, H5E_CANTCLOSEFILE, FAIL,
+ "can't close socket");
+ }
+ file->sock_fd = -1; /* invalidate for later */
+ } /* end if problem writing goodbye; go down hard */
+ else
+ if (HDshutdown(file->sock_fd, SHUT_WR) < 0) {
+ HDONE_ERROR(H5E_VFL, H5E_BADVALUE, FAIL,
+ "can't shutdown socket write: %s",
+ HDstrerror(errno));
+ } /* end else-if problem shutting down socket */
+ } /* end if xmit encode failed */
+
+ if (file->sock_fd >= 0) {
+ if (HDclose(file->sock_fd) < 0) {
+ HDONE_ERROR(H5E_VFL, H5E_CANTCLOSEFILE, FAIL,
+ "can't close socket");
+ }
+ } /* end if socket not closed by going down hard */
+ } /* end if error */
+
+ file = H5FL_FREE(H5FD_mirror_t, file); /* always release resources */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_mirror_close() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_mirror_query
+ *
+ * Purpose: Get the driver feature flags implemented by the driver.
+ *
+ * Return: SUCCEED (non-negative) (can't fail)
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_mirror_query(const H5FD_t H5_ATTR_UNUSED *_file, unsigned long *flags)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR;
+
+ LOG_OP_CALL("H5FD_mirror_query");
+
+ /* Notice: the Mirror VFD Writer currently uses only the Sec2 driver as
+ * the underying driver -- as such, the Mirror VFD implementation copies
+ * the Sec2 feature flags as its own.
+ *
+ * File pointer is always NULL/unused -- the H5FD_FEAT_IGNORE_DRVRINFO flag
+ * is never included.
+ * -- JOS 2020-01-13
+ */
+ if (flags) {
+ *flags = 0 \
+ | 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;
+ }
+
+ FUNC_LEAVE_NOAPI(SUCCEED);
+} /* end H5FD_mirror_query() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_mirror_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.
+ *
+ * Required to register the driver.
+ *
+ * Return: The end-of-address marker.
+ *-------------------------------------------------------------------------
+ */
+static haddr_t
+H5FD_mirror_get_eoa(const H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type)
+{
+ const H5FD_mirror_t *file = (const H5FD_mirror_t *)_file;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ LOG_OP_CALL("H5FD_mirror_get_eoa");
+
+ HDassert(file);
+
+ FUNC_LEAVE_NOAPI(file->eoa)
+} /* end H5FD_mirror_get_eoa() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_mirror_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 / FAIL
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_mirror_set_eoa(H5FD_t *_file, H5FD_mem_t type, haddr_t addr)
+{
+ H5FD_mirror_xmit_eoa_t xmit_eoa;
+ unsigned char xmit_buf[H5FD_MIRROR_XMIT_EOA_SIZE];
+ H5FD_mirror_t *file = (H5FD_mirror_t *)_file;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ LOG_OP_CALL("H5FD_mirror_set_eoa");
+
+ HDassert(file);
+
+ file->eoa = addr; /* local copy */
+
+ file->xmit.xmit_count = (file->xmit_i)++;
+ file->xmit.op = H5FD_MIRROR_OP_SET_EOA;
+
+ xmit_eoa.pub = file->xmit;
+ xmit_eoa.type = (uint8_t)type;
+ xmit_eoa.eoa_addr = (uint64_t)addr;
+
+ if (H5FD_mirror_xmit_encode_set_eoa(xmit_buf,
+ (const H5FD_mirror_xmit_eoa_t *)&xmit_eoa)
+ != H5FD_MIRROR_XMIT_EOA_SIZE)
+ {
+ HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "unable to encode set-eoa");
+ }
+
+ LOG_XMIT_BYTES("set-eoa", xmit_buf, H5FD_MIRROR_XMIT_EOA_SIZE);
+
+ if (HDwrite(file->sock_fd, xmit_buf, H5FD_MIRROR_XMIT_EOA_SIZE) < 0) {
+ HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL,
+ "unable to transmit set-eoa");
+ }
+
+ if (H5FD__mirror_verify_reply(file) == FAIL) {
+ HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "invalid reply");
+ }
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_mirror_set_eoa() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_mirror_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.
+ *
+ * Required to register the driver.
+ *
+ * Return: End of file address, the first address past the end of the
+ * "file", either the filesystem file or the HDF5 file.
+ *-------------------------------------------------------------------------
+ */
+static haddr_t
+H5FD_mirror_get_eof(const H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type)
+{
+ const H5FD_mirror_t *file = (const H5FD_mirror_t *)_file;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ LOG_OP_CALL("H5FD_mirror_get_eof");
+
+ HDassert(file);
+
+ FUNC_LEAVE_NOAPI(file->eof)
+} /* end H5FD_mirror_get_eof() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_mirror_read
+ *
+ * Purpose: Required to register the driver.
+ * If called, MUST fail.
+ *
+ * Return: FAIL
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_mirror_read(H5FD_t H5_ATTR_UNUSED *_file,
+ H5FD_mem_t H5_ATTR_UNUSED type,
+ hid_t H5_ATTR_UNUSED fapl_id,
+ haddr_t H5_ATTR_UNUSED addr,
+ size_t H5_ATTR_UNUSED size,
+ void H5_ATTR_UNUSED *buf)
+{
+ herr_t ret_value = FAIL;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ LOG_OP_CALL("H5FD_mirror_read");
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_mirror_read() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_mirror_write
+ *
+ * Purpose: Writes SIZE bytes of data to FILE beginning at address ADDR
+ * from buffer BUF according to data transfer properties in
+ * DXPL_ID.
+ *
+ * Send metadata regarding the write (location, size) to the
+ * remote Writer, then separately transmits the data.
+ * Both transmission expect an OK reply from the Writer.
+ * This two-exchange approach incurs significant overhead,
+ * but is a simple and modular approach.
+ * Start optimizations here.
+ *
+ * Return: SUCCEED/FAIL
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_mirror_write(H5FD_t *_file,
+ H5FD_mem_t type,
+ hid_t H5_ATTR_UNUSED dxpl_id,
+ haddr_t addr,
+ size_t size,
+ const void *buf)
+{
+ H5FD_mirror_xmit_write_t xmit_write;
+ unsigned char xmit_buf[H5FD_MIRROR_XMIT_WRITE_SIZE];
+ H5FD_mirror_t *file = (H5FD_mirror_t *)_file;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ LOG_OP_CALL("H5FD_mirror_write");
+
+ HDassert(file);
+ HDassert(buf);
+
+ file->xmit.xmit_count = (file->xmit_i)++;
+ file->xmit.op = H5FD_MIRROR_OP_WRITE;
+
+ xmit_write.pub = file->xmit;
+ xmit_write.size = (uint64_t)size;
+ xmit_write.offset = (uint64_t)addr;
+ xmit_write.type = (uint8_t)type;
+
+
+ /* Notify Writer of incoming data to write. */
+ if (H5FD_mirror_xmit_encode_write(xmit_buf,
+ (const H5FD_mirror_xmit_write_t *)&xmit_write)
+ != H5FD_MIRROR_XMIT_WRITE_SIZE)
+ {
+ HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "unable to encode write");
+ }
+
+ LOG_XMIT_BYTES("write", xmit_buf, H5FD_MIRROR_XMIT_WRITE_SIZE);
+
+ if (HDwrite(file->sock_fd, xmit_buf, H5FD_MIRROR_XMIT_WRITE_SIZE) < 0) {
+ HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "unable to transmit write");
+ }
+
+ /* Check that our write xmission was received */
+ if (H5FD__mirror_verify_reply(file) == FAIL) {
+ HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "invalid reply");
+ }
+
+ /* Send the data to be written */
+ if (HDwrite(file->sock_fd, buf, size) < 0) {
+ HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "unable to transmit data");
+ }
+
+ /* Writer should reply that it got the data and is still okay/ready */
+ if (H5FD__mirror_verify_reply(file) == FAIL) {
+ HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "invalid reply");
+ }
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_mirror_write() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_mirror_truncate
+ *
+ * Purpose: Makes sure that the true file size is the same (or larger)
+ * than the end-of-address.
+ *
+ * Return: SUCCEED/FAIL
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_mirror_truncate(H5FD_t *_file,
+ hid_t H5_ATTR_UNUSED dxpl_id,
+ hbool_t H5_ATTR_UNUSED closing)
+{
+ unsigned char xmit_buf[H5FD_MIRROR_XMIT_HEADER_SIZE];
+ H5FD_mirror_t *file = (H5FD_mirror_t *)_file;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ LOG_OP_CALL("H5FD_mirror_truncate");
+
+ file->xmit.xmit_count = (file->xmit_i)++;
+ file->xmit.op = H5FD_MIRROR_OP_TRUNCATE;
+
+ if (H5FD_mirror_xmit_encode_header(xmit_buf, &(file->xmit))
+ != H5FD_MIRROR_XMIT_HEADER_SIZE)
+ {
+ HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "unable to encode truncate");
+ }
+
+ LOG_XMIT_BYTES("truncate", xmit_buf, H5FD_MIRROR_XMIT_HEADER_SIZE);
+
+ if (HDwrite(file->sock_fd, xmit_buf, H5FD_MIRROR_XMIT_HEADER_SIZE) < 0) {
+ HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL,
+ "unable to transmit truncate");
+ }
+
+ if (H5FD__mirror_verify_reply(file) == FAIL) {
+ HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "invalid reply");
+ }
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_mirror_truncate() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_mirror_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
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_mirror_lock(H5FD_t *_file, hbool_t rw)
+{
+ H5FD_mirror_xmit_lock_t xmit_lock;
+ unsigned char xmit_buf[H5FD_MIRROR_XMIT_LOCK_SIZE];
+ H5FD_mirror_t *file = (H5FD_mirror_t *)_file;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI_NOINIT;
+
+ LOG_OP_CALL("H5FD_mirror_lock");
+
+ file->xmit.xmit_count = (file->xmit_i)++;
+ file->xmit.op = H5FD_MIRROR_OP_LOCK;
+
+ xmit_lock.pub = file->xmit;
+ xmit_lock.rw = (uint64_t)rw;
+
+ if (H5FD_mirror_xmit_encode_lock(xmit_buf,
+ (const H5FD_mirror_xmit_lock_t *)&xmit_lock)
+ != H5FD_MIRROR_XMIT_LOCK_SIZE)
+ {
+ HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "unable to encode lock");
+ }
+
+ LOG_XMIT_BYTES("lock", xmit_buf, H5FD_MIRROR_XMIT_LOCK_SIZE);
+
+ if (HDwrite(file->sock_fd, xmit_buf, H5FD_MIRROR_XMIT_LOCK_SIZE) < 0) {
+ HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "unable to transmit lock");
+ }
+
+ if (H5FD__mirror_verify_reply(file) == FAIL) {
+ HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "invalid reply");
+ }
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value);
+} /* end H5FD_mirror_lock */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_mirror_unlock
+ *
+ * Purpose: Remove the existing lock on the file.
+ *
+ * Return: SUCCEED/FAIL
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_mirror_unlock(H5FD_t *_file)
+{
+ unsigned char xmit_buf[H5FD_MIRROR_XMIT_HEADER_SIZE];
+ H5FD_mirror_t *file = (H5FD_mirror_t *)_file;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI_NOINIT;
+
+ LOG_OP_CALL("H5FD_mirror_unlock");
+
+ file->xmit.xmit_count = (file->xmit_i)++;
+ file->xmit.op = H5FD_MIRROR_OP_UNLOCK;
+
+ if (H5FD_mirror_xmit_encode_header(xmit_buf, &(file->xmit))
+ != H5FD_MIRROR_XMIT_HEADER_SIZE)
+ {
+ HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "unable to encode unlock");
+ }
+
+ LOG_XMIT_BYTES("unlock", xmit_buf, H5FD_MIRROR_XMIT_HEADER_SIZE);
+
+ if (HDwrite(file->sock_fd, xmit_buf, H5FD_MIRROR_XMIT_HEADER_SIZE) < 0) {
+ HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "unable to transmit unlock");
+ }
+
+ if (H5FD__mirror_verify_reply(file) == FAIL) {
+ HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "invalid reply");
+ }
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value);
+} /* end H5FD_mirror_unlock */
+
+#endif /* H5_HAVE_MIRROR_VFD */
+
diff --git a/src/H5FDmirror.h b/src/H5FDmirror.h
new file mode 100644
index 0000000..fb66b7b
--- /dev/null
+++ b/src/H5FDmirror.h
@@ -0,0 +1,371 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * 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. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Purpose: Public, shared definitions for Mirror VFD & remote Writer.
+ */
+
+#ifndef H5FDmirror_H
+#define H5FDmirror_H
+
+#ifdef H5_HAVE_MIRROR_VFD
+
+#define H5FD_MIRROR (H5FD_mirror_init())
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* ============================================================================
+ * Mirror VFD use and operation.
+ * ============================================================================
+ */
+
+/* ---------------------------------------------------------------------------
+ * Structure: H5FD_mirror_fapl_t
+ *
+ * Used to pass configuraiton information to the Mirror VFD.
+ * Populate components as appropriate and pass structure pointer to
+ * `H5Pset_fapl_mirror()`.
+ *
+ * `magic` (uint32_t)
+ * Semi-unique number to sanity-check pointers to this structure type.
+ * MUST equal H5FD_MIRROR_FAPL_MAGIC to be considered valid.
+ *
+ * `version` (uint32_t)
+ * Indicates expected components of the structure.
+ *
+ * `handshake_port (int)
+ * Port number to expect to reach the "Mirror Server" on the remote host.
+ *
+ * `remote_ip` (char[])
+ * IP address string of "Mirror Server" remote host.
+ * ---------------------------------------------------------------------------
+ */
+#define H5FD_MIRROR_FAPL_MAGIC 0xF8DD514C
+#define H5FD_MIRROR_CURR_FAPL_T_VERSION 1
+#define H5FD_MIRROR_MAX_IP_LEN 32
+typedef struct H5FD_mirror_fapl_t {
+ uint32_t magic;
+ uint32_t version;
+ int handshake_port;
+ char remote_ip[H5FD_MIRROR_MAX_IP_LEN + 1];
+} H5FD_mirror_fapl_t;
+
+H5_DLL hid_t H5FD_mirror_init(void);
+H5_DLL herr_t H5Pget_fapl_mirror(hid_t fapl_id, H5FD_mirror_fapl_t *fa_out);
+H5_DLL herr_t H5Pset_fapl_mirror(hid_t fapl_id, H5FD_mirror_fapl_t *fa);
+
+/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
+ * IPC - Mirror VFD and Remote Worker application.
+ * = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
+ */
+
+
+/* The maximum allowed size for a receiving buffer when accepting bytes to
+ * write. Writes larger than this size are performed by multiple accept-write
+ * steps by the Writer. */
+#define H5FD_MIRROR_DATA_BUFFER_MAX H5_GB /* 1 Gigabyte */
+
+#define H5FD_MIRROR_XMIT_CURR_VERSION 1
+#define H5FD_MIRROR_XMIT_MAGIC 0x87F8005B
+
+#define H5FD_MIRROR_OP_OPEN 1
+#define H5FD_MIRROR_OP_CLOSE 2
+#define H5FD_MIRROR_OP_WRITE 3
+#define H5FD_MIRROR_OP_TRUNCATE 4
+#define H5FD_MIRROR_OP_REPLY 5
+#define H5FD_MIRROR_OP_SET_EOA 6
+#define H5FD_MIRROR_OP_LOCK 7
+#define H5FD_MIRROR_OP_UNLOCK 8
+
+#define H5FD_MIRROR_STATUS_OK 0
+#define H5FD_MIRROR_STATUS_ERROR 1
+#define H5FD_MIRROR_STATUS_MESSAGE_MAX 256 /* Dedicated error message size */
+
+/* Maximum length of a path/filename string, including the NULL-terminator.
+ * Must not be smaller than H5FD_SPLITTER_PATH_MAX. */
+#define H5FD_MIRROR_XMIT_FILEPATH_MAX 4097
+
+/* Define the exact sizes of the various xmit blobs as sent over the wire.
+ * This is used to minimize the number of bytes transmitted as well as to
+ * sanity-check received bytes.
+ * Any modifications to the xmit structures and/or the encode/decode functions
+ * must be reflected here.
+ * */
+#define H5FD_MIRROR_XMIT_HEADER_SIZE 14
+#define H5FD_MIRROR_XMIT_EOA_SIZE (H5FD_MIRROR_XMIT_HEADER_SIZE + 9)
+#define H5FD_MIRROR_XMIT_LOCK_SIZE (H5FD_MIRROR_XMIT_HEADER_SIZE + 8)
+#define H5FD_MIRROR_XMIT_OPEN_SIZE (H5FD_MIRROR_XMIT_HEADER_SIZE + 20 + H5FD_MIRROR_XMIT_FILEPATH_MAX)
+#define H5FD_MIRROR_XMIT_REPLY_SIZE (H5FD_MIRROR_XMIT_HEADER_SIZE + 4 + H5FD_MIRROR_STATUS_MESSAGE_MAX)
+#define H5FD_MIRROR_XMIT_WRITE_SIZE (H5FD_MIRROR_XMIT_HEADER_SIZE + 17)
+
+/* Maximum length of any xmit. */
+#define H5FD_MIRROR_XMIT_BUFFER_MAX MAX2( MAX3(H5FD_MIRROR_XMIT_HEADER_SIZE, \
+ H5FD_MIRROR_XMIT_EOA_SIZE, \
+ H5FD_MIRROR_XMIT_LOCK_SIZE), \
+ MAX3(H5FD_MIRROR_XMIT_OPEN_SIZE, \
+ H5FD_MIRROR_XMIT_REPLY_SIZE, \
+ H5FD_MIRROR_XMIT_WRITE_SIZE) ) \
+
+/* ---------------------------------------------------------------------------
+ * Structure: H5FD_mirror_xmit_t
+ *
+ * Common structure 'header' for all mirror VFD/worker IPC.
+ * Must be the first component of a derived operation xmit structure,
+ * such as file-open or write command.
+ *
+ * `magic` (uint32_t)
+ * A "unique" number identifying the structure and endianness of
+ * transmitting maching.
+ * Must be set to H5FD_MIRROR_XMIT_MAGIC native to the VFD "sender".
+ *
+ * `version` (uint8_t)
+ * Number used to identify the structure membership.
+ * Allows sane modifications to this structure in the future.
+ * Must be set to H5FD_MIRROR_XMIT_CURR_VERSION.
+ *
+ * `session_token` (uint32_t)
+ * A "unique" number identifying the session between VFD sender and
+ * remote receiver/worker/writer. Exists to help sanity-check.
+ *
+ * `xmit_count` (uint32_t)
+ * Which transmission this is since the session began.
+ * Used to sanity-check transmission errors.
+ * First xmit (file-open) must be 0.
+ *
+ * `op` (uint8_t)
+ * Number identifying which operation to perform.
+ * Corresponds with the extended structure outside of this xmit header.
+ * Possible values are all defined H5FD_MIRROR_OP_* constants.
+ *
+ * ---------------------------------------------------------------------------
+ */
+typedef struct H5FD_mirror_xmit_t {
+ uint32_t magic;
+ uint8_t version;
+ uint32_t session_token;
+ uint32_t xmit_count;
+ uint8_t op;
+} H5FD_mirror_xmit_t;
+
+/* ---------------------------------------------------------------------------
+ * Structure: H5FD_mirror_xmit_eoa_t
+ *
+ * Structure containing eoa-set information from VFD sender.
+ *
+ * `pub` (H5FD_mirror_xmit_t)
+ * Common transmission header, containing session information.
+ * Must be first.
+ *
+ * `type` (uint8_t)
+ * System-independent alias for H5F[D]_mem_t.
+ * Specifies datatype to be written.
+ *
+ * `eoa_addr` (uint64_t)
+ * New address for eoa.
+ * (Natively 'haddr_t', always a 64-bit field)
+ *
+ * ---------------------------------------------------------------------------
+ */
+typedef struct H5FD_mirror_xmit_eoa_t {
+ H5FD_mirror_xmit_t pub;
+ uint8_t type;
+ uint64_t eoa_addr;
+} H5FD_mirror_xmit_eoa_t;
+
+/* ---------------------------------------------------------------------------
+ * Structure: H5FD_mirror_xmit_lock_t
+ *
+ * Structure containing eoa-set information from VFD sender.
+ *
+ * `pub` (H5FD_mirror_xmit_t)
+ * Common transmission header, containing session information.
+ * Must be first.
+ *
+ * `rw` (uint64_t)
+ * The Read/Write mode flag passed into H5FDlock().
+ * (Natively `hbool_t`, an 'int') TODO: native int may be 64-bit?
+ *
+ * ---------------------------------------------------------------------------
+ */
+typedef struct H5FD_mirror_xmit_lock_t {
+ H5FD_mirror_xmit_t pub;
+ uint64_t rw;
+} H5FD_mirror_xmit_lock_t;
+
+/* ---------------------------------------------------------------------------
+ * Structure: H5FD_mirror_xmit_open_t
+ *
+ * Structure containing file-open information from the VFD sender.
+ *
+ * `pub` (H5FD_mirror_xmit_t)
+ * Common transmission header, containing session information.
+ * Must be first.
+ *
+ * `flags` (uint32_t)
+ * VFL-layer file-open flags passed directly to H5FDopen().
+ * (Natively 'unsigned [int]') TODO: native int may be 64-bit?
+ *
+ * `maxaddr` (uint64_t)
+ * VFL-layer maximum allowed address space for the file to open passed
+ * directly to H5FDopen().
+ * (Natively 'haddr_t', always a 64-bit field)
+ *
+ * `size_t_blob` (uint64_t)
+ * A number indicating how large a size_t is on the sending system.
+ * Must be set to (uint64_t)((size_t)(-1))
+ * (maximum possible value of size_t, cast to uint64_t).
+ * The receiving system inspects this value -- if the local (remote)
+ * size_t is smaller than that of the Sender, issues a warning.
+ * Not an error, as:
+ * 1. It is assumed that underlying file systems/drivers have become
+ * smart enough to handle file sizes that otherwise might be
+ * constrained.
+ * 2. The Mirror Writer ingests bytes to write multiple 'slices' if the
+ * size is greater than H5FD_MIRROR_DATA_BUFFER_MAX, regardless of
+ * any size_t storage size disparity.
+ *
+ * `filename` (char[])
+ * String giving the filename and path of file to open.
+ *
+ * ---------------------------------------------------------------------------
+ */
+typedef struct H5FD_mirror_xmit_open_t {
+ H5FD_mirror_xmit_t pub;
+ uint32_t flags;
+ uint64_t maxaddr;
+ uint64_t size_t_blob;
+ char filename[H5FD_MIRROR_XMIT_FILEPATH_MAX];
+} H5FD_mirror_xmit_open_t;
+
+/* ---------------------------------------------------------------------------
+ * Structure: H5FD_mirror_xmit_reply_t
+ *
+ * Structure used by the remote receiver/worker/writer to respond to
+ * a command from the VFD sender.
+ *
+ * `pub` (H5FD_mirror_xmit_t)
+ * Common transmission header, containing session information.
+ * Must be first.
+ *
+ * `status` (uint32_t)
+ * Number indicating whether the command was successful or if an
+ * occured.
+ * Allowed values are H5FD_MIRROR_STATUS_OK and
+ * H5FD_MIRROR_STATUS_ERROR.
+ *
+ * `message` (char[])
+ * Error message. Populated if and only if there was a problem.
+ * It is possible that a message may reach the end of the alloted
+ * space without a NULL terminator -- the onus is on the programmer to
+ * handle this situation.
+ *
+ * ---------------------------------------------------------------------------
+ */
+typedef struct H5FD_mirror_xmit_reply_t {
+ H5FD_mirror_xmit_t pub;
+ uint32_t status;
+ char message[H5FD_MIRROR_STATUS_MESSAGE_MAX];
+} H5FD_mirror_xmit_reply_t;
+
+/* ---------------------------------------------------------------------------
+ * Structure: H5FD_mirror_xmit_write_t
+ *
+ * Structure containing data-write information from VFD sender.
+ *
+ * The data to be written is transmitted in subsequent, packets
+ * and may be broken up into more than one transmission buffer.
+ * The VFD sender and remote receiver/worker/writer must coordinate
+ * the receipt of data.
+ *
+ * `pub` (H5FD_mirror_xmit_t)
+ * Common transmission header, containing session information.
+ * Must be first.
+ *
+ * `type` (uint8_t)
+ * Specifies datatype to be written.
+ * (Natively 'H5FD_mem_t', an enumerated type in H5Fpublic.h)
+ *
+ * `offset` (uint64_t)
+ * Start location of write in file.
+ * (Natively 'haddr_t', always a 64-bit field)
+ *
+ * `size` (uint64_t)
+ * Size of the data to be written, in bytes.
+ * (Natively 'size_t', accommodate the largest possible as 64-bits)
+ *
+ * ---------------------------------------------------------------------------
+ */
+typedef struct H5FD_mirror_xmit_write_t {
+ H5FD_mirror_xmit_t pub;
+ uint8_t type;
+ uint64_t offset;
+ uint64_t size;
+} H5FD_mirror_xmit_write_t;
+
+
+
+/* Encode/decode routines are required to "pack" the xmit data into a known
+ * byte format for transmission over the wire.
+ *
+ * All component numbers must be stored in "network" word order (Big-Endian).
+ *
+ * All components must be packed in the order given in the structure definition.
+ *
+ * All components must be packed with zero padding between.
+ */
+
+H5_DLL size_t H5FD__mirror_xmit_decode_uint16(uint16_t *out, const unsigned char *buf);
+H5_DLL size_t H5FD__mirror_xmit_decode_uint32(uint32_t *out, const unsigned char *buf);
+H5_DLL size_t H5FD__mirror_xmit_decode_uint64(uint64_t *out, const unsigned char *buf);
+H5_DLL size_t H5FD__mirror_xmit_decode_uint8(uint8_t *out, const unsigned char *buf);
+H5_DLL size_t H5FD__mirror_xmit_encode_uint16(unsigned char *dest, uint16_t v);
+H5_DLL size_t H5FD__mirror_xmit_encode_uint32(unsigned char *dest, uint32_t v);
+H5_DLL size_t H5FD__mirror_xmit_encode_uint64(unsigned char *dest, uint64_t v);
+H5_DLL size_t H5FD__mirror_xmit_encode_uint8(unsigned char *dest, uint8_t v);
+
+H5_DLL size_t H5FD_mirror_xmit_decode_header(H5FD_mirror_xmit_t *out, const unsigned char *buf);
+H5_DLL size_t H5FD_mirror_xmit_decode_lock(H5FD_mirror_xmit_lock_t *out, const unsigned char *buf);
+H5_DLL size_t H5FD_mirror_xmit_decode_open(H5FD_mirror_xmit_open_t *out, const unsigned char *buf);
+H5_DLL size_t H5FD_mirror_xmit_decode_reply(H5FD_mirror_xmit_reply_t *out, const unsigned char *buf);
+H5_DLL size_t H5FD_mirror_xmit_decode_set_eoa(H5FD_mirror_xmit_eoa_t *out, const unsigned char *buf);
+H5_DLL size_t H5FD_mirror_xmit_decode_write(H5FD_mirror_xmit_write_t *out, const unsigned char *buf);
+
+H5_DLL size_t H5FD_mirror_xmit_encode_header(unsigned char *dest, const H5FD_mirror_xmit_t *x);
+H5_DLL size_t H5FD_mirror_xmit_encode_lock(unsigned char *dest, const H5FD_mirror_xmit_lock_t *x);
+H5_DLL size_t H5FD_mirror_xmit_encode_open(unsigned char *dest, const H5FD_mirror_xmit_open_t *x);
+H5_DLL size_t H5FD_mirror_xmit_encode_reply(unsigned char *dest, const H5FD_mirror_xmit_reply_t *x);
+H5_DLL size_t H5FD_mirror_xmit_encode_set_eoa(unsigned char *dest, const H5FD_mirror_xmit_eoa_t *x);
+H5_DLL size_t H5FD_mirror_xmit_encode_write(unsigned char *dest, const H5FD_mirror_xmit_write_t *x);
+
+H5_DLL hbool_t H5FD_mirror_xmit_is_close(const H5FD_mirror_xmit_t *xmit);
+H5_DLL hbool_t H5FD_mirror_xmit_is_lock(const H5FD_mirror_xmit_lock_t *xmit);
+H5_DLL hbool_t H5FD_mirror_xmit_is_open(const H5FD_mirror_xmit_open_t *xmit);
+H5_DLL hbool_t H5FD_mirror_xmit_is_reply(const H5FD_mirror_xmit_reply_t *xmit);
+H5_DLL hbool_t H5FD_mirror_xmit_is_set_eoa(const H5FD_mirror_xmit_eoa_t *xmit);
+H5_DLL hbool_t H5FD_mirror_xmit_is_write(const H5FD_mirror_xmit_write_t *xmit);
+H5_DLL hbool_t H5FD_mirror_xmit_is_xmit(const H5FD_mirror_xmit_t *xmit);
+
+#ifdef __cplusplus
+}
+#endif
+
+#else /* H5_HAVE_MIRROR_VFD */
+
+#define H5FD_MIRROR (H5I_INAVLID_HID)
+
+#endif /* H5_HAVE_MIRROR_VFD */
+
+#endif /* H5FDmirror_H */
+
+
diff --git a/src/H5FDpublic.h b/src/H5FDpublic.h
index 514d1bf..124bac6 100644
--- a/src/H5FDpublic.h
+++ b/src/H5FDpublic.h
@@ -255,6 +255,8 @@ typedef enum H5F_mem_t H5FD_mem_t;
* that creates a file which is compatible with the default VFD.
* Generally, this means that the VFD creates a single file that follows
* the canonical HDF5 file format.
+ * Regarding the Splitter VFD specifically, only drivers with this flag
+ * enabled may be used as the Write-Only (W/O) channel driver.
*/
#define H5FD_FEAT_DEFAULT_VFD_COMPATIBLE 0x00008000
diff --git a/src/H5FDros3.c b/src/H5FDros3.c
index 75fcfd7..d99272c 100644
--- a/src/H5FDros3.c
+++ b/src/H5FDros3.c
@@ -325,7 +325,9 @@ hid_t
H5FD_ros3_init(void)
{
hid_t ret_value = H5I_INVALID_HID;
+#if ROS3_STATS
unsigned int bin_i;
+#endif
FUNC_ENTER_NOAPI(FAIL)
@@ -1347,7 +1349,7 @@ H5FD_ros3_cmp(
}
/* FAPL: AWS_REGION */
- if (f1->fa.aws_region[0] != '\0' && f1->fa.aws_region[0] != '\0') {
+ if (f1->fa.aws_region[0] != '\0' && f2->fa.aws_region[0] != '\0') {
if (HDstrcmp(f1->fa.aws_region, f2->fa.aws_region)) {
HGOTO_DONE(-1);
}
@@ -1362,7 +1364,7 @@ H5FD_ros3_cmp(
}
/* FAPL: SECRET_ID */
- if (f1->fa.secret_id[0] != '\0' && f1->fa.secret_id[0] != '\0') {
+ if (f1->fa.secret_id[0] != '\0' && f2->fa.secret_id[0] != '\0') {
if (HDstrcmp(f1->fa.secret_id, f2->fa.secret_id)) {
HGOTO_DONE(-1);
}
@@ -1377,7 +1379,7 @@ H5FD_ros3_cmp(
}
/* FAPL: SECRET_KEY */
- if (f1->fa.secret_key[0] != '\0' && f1->fa.secret_key[0] != '\0') {
+ if (f1->fa.secret_key[0] != '\0' && f2->fa.secret_key[0] != '\0') {
if (HDstrcmp(f1->fa.secret_key, f2->fa.secret_key)) {
HGOTO_DONE(-1);
}
diff --git a/src/H5FDsec2.c b/src/H5FDsec2.c
index 98021ca..70347fa 100644
--- a/src/H5FDsec2.c
+++ b/src/H5FDsec2.c
@@ -525,6 +525,12 @@ H5FD_sec2_query(const H5FD_t *_file, unsigned long *flags /* out */)
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 */
diff --git a/src/H5FDsplitter.c b/src/H5FDsplitter.c
new file mode 100644
index 0000000..13816a5
--- /dev/null
+++ b/src/H5FDsplitter.c
@@ -0,0 +1,1467 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * 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. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Purpose: The Splitter VFD implements a file driver which relays all the
+ * VFD calls to an underlying VFD, and send all the write calls to
+ * another underlying VFD. Maintains two files simultaneously.
+ */
+
+/* This source code file is part of the H5FD driver module */
+#include "H5FDdrvr_module.h"
+
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5Fprivate.h" /* File access */
+#include "H5FDprivate.h" /* File drivers */
+#include "H5FDsplitter.h" /* Splitter file driver */
+#include "H5FLprivate.h" /* Free Lists */
+#include "H5Iprivate.h" /* IDs */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5FDsec2.h" /* Generic Functions */
+#include "H5FDstdio.h" /* Generic Functions */
+#include "H5Pprivate.h" /* Property lists */
+
+/* The driver identification number, initialized at runtime */
+static hid_t H5FD_SPLITTER_g = 0;
+
+/* Driver-specific file access properties */
+typedef struct H5FD_splitter_fapl_t {
+ hid_t rw_fapl_id; /* fapl for the R/W channel */
+ hid_t wo_fapl_id; /* fapl for the W/O channel */
+ char wo_path[H5FD_SPLITTER_PATH_MAX + 1]; /* file name for the W/O channel */
+ char log_file_path[H5FD_SPLITTER_PATH_MAX + 1]; /* file to record errors reported by the W/O channel */
+ hbool_t ignore_wo_errs; /* TRUE to ignore errors on the W/O channel */
+} H5FD_splitter_fapl_t;
+
+/* The information of this splitter */
+typedef struct H5FD_splitter_t {
+ H5FD_t pub; /* public stuff, must be first */
+ unsigned version; /* version of the H5FD_splitter_vfd_config_t structure used */
+ H5FD_splitter_fapl_t fa; /* driver-specific file access properties */
+ H5FD_t *rw_file; /* pointer of R/W channel */
+ H5FD_t *wo_file; /* pointer of W/O channel */
+ FILE *logfp; /* Log file pointer */
+} H5FD_splitter_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))
+
+/* This macro provides a wrapper for shared fail-log-ignore behavior
+ * for errors arising in the splitter's W/O channel.
+ * Logs an error entry in a log file, if the file exists.
+ * If not set to ignore errors, registers an error with the library.
+ */
+#define H5FD_SPLITTER_WO_ERROR(file, funcname, errmajor, errminor, ret, mesg) \
+{ \
+ H5FD__splitter_log_error((file), (funcname), (mesg)); \
+ if (FALSE == (file)->fa.ignore_wo_errs) { \
+ HGOTO_ERROR((errmajor), (errminor), (ret), (mesg)) \
+ } \
+}
+
+#define H5FD_SPLITTER_DEBUG_OP_CALLS 0 /* debugging print toggle; 0 disables */
+
+#if H5FD_SPLITTER_DEBUG_OP_CALLS
+#define H5FD_SPLITTER_LOG_CALL(name) do { \
+ HDprintf("called %s()\n", (name)); \
+ fflush(stdout); \
+} while (0)
+#else
+#define H5FD_SPLITTER_LOG_CALL(name) /* no-op */
+#endif /* H5FD_SPLITTER_DEBUG_OP_CALLS */
+
+/* Private functions */
+
+/* Print error messages from W/O channel to log file */
+static herr_t H5FD__splitter_log_error(const H5FD_splitter_t *file, const char *atfunc, const char *msg);
+
+static int H5FD__copy_plist(hid_t fapl_id, hid_t *id_out_ptr);
+
+/* Prototypes */
+static herr_t H5FD_splitter_term(void);
+static hsize_t H5FD_splitter_sb_size(H5FD_t *_file);
+static herr_t H5FD_splitter_sb_encode(H5FD_t *_file, char *name/*out*/, unsigned char *buf/*out*/);
+static herr_t H5FD_splitter_sb_decode(H5FD_t *_file, const char *name, const unsigned char *buf);
+static void *H5FD_splitter_fapl_get(H5FD_t *_file);
+static void *H5FD_splitter_fapl_copy(const void *_old_fa);
+static herr_t H5FD_splitter_fapl_free(void *_fapl);
+static H5FD_t *H5FD_splitter_open(const char *name, unsigned flags, hid_t fapl_id, haddr_t maxaddr);
+static herr_t H5FD_splitter_close(H5FD_t *_file);
+static int H5FD_splitter_cmp(const H5FD_t *_f1, const H5FD_t *_f2);
+static herr_t H5FD_splitter_query(const H5FD_t *_file, unsigned long *flags /* out */);
+static herr_t H5FD_splitter_get_type_map(const H5FD_t *_file, H5FD_mem_t *type_map);
+static haddr_t H5FD_splitter_alloc(H5FD_t *file, H5FD_mem_t type, hid_t dxpl_id, hsize_t size);
+static herr_t H5FD_splitter_free(H5FD_t *_file, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr, hsize_t size);
+static haddr_t H5FD_splitter_get_eoa(const H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type);
+static herr_t H5FD_splitter_set_eoa(H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type, haddr_t addr);
+static haddr_t H5FD_splitter_get_eof(const H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type);
+static herr_t H5FD_splitter_get_handle(H5FD_t *_file, hid_t H5_ATTR_UNUSED fapl, void** file_handle);
+static herr_t H5FD_splitter_read(H5FD_t *_file, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr, size_t size, void *buf);
+static herr_t H5FD_splitter_write(H5FD_t *_file, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr, size_t size, const void *buf);
+static herr_t H5FD_splitter_flush(H5FD_t *_file, hid_t dxpl_id, hbool_t closing);
+static herr_t H5FD_splitter_truncate(H5FD_t *_file, hid_t dxpl_id, hbool_t closing);
+static herr_t H5FD_splitter_lock(H5FD_t *_file, hbool_t rw);
+static herr_t H5FD_splitter_unlock(H5FD_t *_file);
+
+static const H5FD_class_t H5FD_splitter_g = {
+ "splitter", /* name */
+ MAXADDR, /* maxaddr */
+ H5F_CLOSE_WEAK, /* fc_degree */
+ H5FD_splitter_term, /* terminate */
+ H5FD_splitter_sb_size, /* sb_size */
+ H5FD_splitter_sb_encode, /* sb_encode */
+ H5FD_splitter_sb_decode, /* sb_decode */
+ sizeof(H5FD_splitter_fapl_t), /* fapl_size */
+ H5FD_splitter_fapl_get, /* fapl_get */
+ H5FD_splitter_fapl_copy, /* fapl_copy */
+ H5FD_splitter_fapl_free, /* fapl_free */
+ 0, /* dxpl_size */
+ NULL, /* dxpl_copy */
+ NULL, /* dxpl_free */
+ H5FD_splitter_open, /* open */
+ H5FD_splitter_close, /* close */
+ H5FD_splitter_cmp, /* cmp */
+ H5FD_splitter_query, /* query */
+ H5FD_splitter_get_type_map, /* get_type_map */
+ H5FD_splitter_alloc, /* alloc */
+ H5FD_splitter_free, /* free */
+ H5FD_splitter_get_eoa, /* get_eoa */
+ H5FD_splitter_set_eoa, /* set_eoa */
+ H5FD_splitter_get_eof, /* get_eof */
+ H5FD_splitter_get_handle, /* get_handle */
+ H5FD_splitter_read, /* read */
+ H5FD_splitter_write, /* write */
+ H5FD_splitter_flush, /* flush */
+ H5FD_splitter_truncate, /* truncate */
+ H5FD_splitter_lock, /* lock */
+ H5FD_splitter_unlock, /* unlock */
+ H5FD_FLMAP_DICHOTOMY /* fl_map */
+};
+
+/* Declare a free list to manage the H5FD_splitter_t struct */
+H5FL_DEFINE_STATIC(H5FD_splitter_t);
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD__init_package
+ *
+ * Purpose: Initializes any interface-specific data or routines.
+ *
+ * Return: SUCCEED/FAIL
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD__init_package(void)
+{
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_STATIC
+
+ H5FD_SPLITTER_LOG_CALL("H5FD__init_package");
+
+ if (H5FD_splitter_init() < 0) {
+ HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "unable to initialize splitter VFD")
+ }
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5FD__init_package() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_splitter_init
+ *
+ * Purpose: Initialize the splitter driver by registering it with the
+ * library.
+ *
+ * Return: Success: The driver ID for the splitter driver.
+ * Failure: Negative
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5FD_splitter_init(void)
+{
+ hid_t ret_value = H5I_INVALID_HID;
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ H5FD_SPLITTER_LOG_CALL("H5FD_splitter_init");
+
+ if (H5I_VFL != H5I_get_type(H5FD_SPLITTER_g)) {
+ H5FD_SPLITTER_g = H5FDregister(&H5FD_splitter_g);
+ }
+
+ ret_value = H5FD_SPLITTER_g;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_splitter_init() */
+
+
+/*---------------------------------------------------------------------------
+ * Function: H5FD_splitter_term
+ *
+ * Purpose: Shut down the splitter VFD.
+ *
+ * Returns: SUCCEED (Can't fail)
+ *---------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_splitter_term(void)
+{
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ H5FD_SPLITTER_LOG_CALL("H5FD_splitter_term");
+
+ /* Reset VFL ID */
+ H5FD_SPLITTER_g = 0;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5FD_splitter_term() */
+
+
+ /*-------------------------------------------------------------------------
+ * Function: H5FD__copy_plist
+ *
+ * Purpose: Sanity-wrapped H5P_copy_plist() for each channel.
+ * Utility function for operation in multiple locations.
+ *
+ * Return: 0 on success, -1 on error.
+ *-------------------------------------------------------------------------
+ */
+static int
+H5FD__copy_plist(hid_t fapl_id,
+ hid_t *id_out_ptr)
+{
+ int ret_value = 0;
+ H5P_genplist_t *plist_ptr = NULL;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ H5FD_SPLITTER_LOG_CALL("H5FD__copy_plist");
+
+ HDassert(id_out_ptr != NULL);
+
+ if (FALSE == H5P_isa_class(fapl_id, H5P_FILE_ACCESS)) {
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, -1, "not a file access property list");
+ }
+
+ plist_ptr = (H5P_genplist_t *)H5I_object(fapl_id);
+ if (NULL == plist_ptr) {
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, -1, "unable to get property list");
+ }
+
+ *id_out_ptr = H5P_copy_plist(plist_ptr, FALSE);
+ if (H5I_INVALID_HID == *id_out_ptr) {
+ HGOTO_ERROR(H5E_VFL, H5E_BADTYPE, -1, "unable to copy file access property list");
+ }
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value);
+} /* end H5FD__copy_plist() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pset_fapl_splitter
+ *
+ * Purpose: Sets the file access property list to use the
+ * splitter driver.
+ *
+ * Return: SUCCEED/FAIL
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pset_fapl_splitter(hid_t fapl_id, H5FD_splitter_vfd_config_t *vfd_config)
+{
+ H5FD_splitter_fapl_t info;
+ H5P_genplist_t *plist_ptr = NULL;
+ herr_t ret_value = SUCCEED;
+
+ H5Eclear2(H5E_DEFAULT);
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "i*Dr", fapl_id, vfd_config);
+
+ H5FD_SPLITTER_LOG_CALL("H5Pset_fapl_splitter");
+
+ if (H5FD_SPLITTER_MAGIC != vfd_config->magic) {
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid configuration (magic number mismatch)")
+ }
+ if (H5FD_CURR_SPLITTER_VFD_CONFIG_VERSION != vfd_config->version) {
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invlaid config (version number mismatch)")
+ }
+
+ if (NULL == (plist_ptr = (H5P_genplist_t *)H5I_object(fapl_id))) {
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a valid property list")
+ }
+
+
+ /* Make sure that the W/O channel supports write-only capability.
+ * Some drivers (e.g. family or multi) do revision of the superblock
+ * in-memory, causing problems in that channel.
+ * Uses the feature flag H5FD_FEAT_DEFAULT_VFD_COMPATIBLE as the
+ * determining attribute.
+ */
+ if (H5P_DEFAULT != vfd_config->wo_fapl_id) {
+ H5FD_class_t *wo_driver = NULL;
+ H5FD_driver_prop_t wo_driver_prop;
+ H5P_genplist_t *wo_plist_ptr = NULL;
+ unsigned long wo_driver_flags = 0;
+
+ wo_plist_ptr = (H5P_genplist_t *)H5I_object(vfd_config->wo_fapl_id);
+ if (NULL == wo_plist_ptr) {
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file access property list")
+ }
+ if (H5P_peek(wo_plist_ptr, H5F_ACS_FILE_DRV_NAME, &wo_driver_prop) < 0) {
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get driver ID & info")
+ }
+ wo_driver = (H5FD_class_t *)H5I_object(wo_driver_prop.driver_id);
+ if (NULL == wo_driver) {
+ HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "invalid driver ID in file access property list")
+ }
+ if (H5FD_driver_query(wo_driver, &wo_driver_flags) < 0) {
+ HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "can't query VFD flags")
+ }
+ if (0 == (H5FD_FEAT_DEFAULT_VFD_COMPATIBLE & wo_driver_flags)) {
+ HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "unsuitable W/O driver")
+ }
+ } /* end if W/O VFD is non-default */
+
+
+ info.ignore_wo_errs = vfd_config->ignore_wo_errs;
+ HDstrncpy(info.wo_path, vfd_config->wo_path, H5FD_SPLITTER_PATH_MAX);
+ HDstrncpy(info.log_file_path, vfd_config->log_file_path, H5FD_SPLITTER_PATH_MAX);
+ info.rw_fapl_id = H5P_FILE_ACCESS_DEFAULT; /* pre-set value */
+ info.wo_fapl_id = H5P_FILE_ACCESS_DEFAULT; /* pre-set value */
+
+ /* Set non-default channel FAPL IDs in splitter configuration info */
+ if (H5P_DEFAULT != vfd_config->rw_fapl_id) {
+ if (FALSE == H5P_isa_class(vfd_config->rw_fapl_id, H5P_FILE_ACCESS)) {
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file access list")
+ }
+ info.rw_fapl_id = vfd_config->rw_fapl_id;
+ }
+ if (H5P_DEFAULT != vfd_config->wo_fapl_id) {
+ if (FALSE == H5P_isa_class(vfd_config->wo_fapl_id, H5P_FILE_ACCESS)) {
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file access list")
+ }
+ info.wo_fapl_id = vfd_config->wo_fapl_id;
+ }
+
+ ret_value = H5P_set_driver(plist_ptr, H5FD_SPLITTER, &info);
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pset_fapl_splitter() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5Pget_fapl_splitter
+ *
+ * Purpose: Returns information about the splitter file access property
+ * list through the structure config_out.
+ *
+ * Will fail if config_out is received without pre-set valid
+ * magic and version information.
+ *
+ * Return: SUCCEED/FAIL
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Pget_fapl_splitter(hid_t fapl_id, H5FD_splitter_vfd_config_t *config_out)
+{
+ const H5FD_splitter_fapl_t *fapl_ptr = NULL;
+ H5P_genplist_t *plist_ptr = NULL;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE2("e", "i*Dr", fapl_id, config_out);
+
+ H5FD_SPLITTER_LOG_CALL("H5Pget_fapl_splitter");
+
+ /* Check arguments */
+ if (TRUE != H5P_isa_class(fapl_id, H5P_FILE_ACCESS)) {
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file access property list")
+ }
+ if (config_out == NULL) {
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "config_out pointer is null")
+ }
+ if (H5FD_SPLITTER_MAGIC != config_out->magic) {
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "info-out pointer invalid (magic number mismatch)")
+ }
+ if (H5FD_CURR_SPLITTER_VFD_CONFIG_VERSION != config_out->version) {
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "info-out pointer invalid (version unsafe)")
+ }
+
+ /* Pre-set out FAPL IDs with intent to replace these values */
+ config_out->rw_fapl_id = H5I_INVALID_HID;
+ config_out->wo_fapl_id = H5I_INVALID_HID;
+
+ /* Check and get the splitter fapl */
+ if (NULL == (plist_ptr = H5P_object_verify(fapl_id, H5P_FILE_ACCESS))) {
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file access property list")
+ }
+ if (H5FD_SPLITTER != H5P_peek_driver(plist_ptr)) {
+ HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "incorrect VFL driver")
+ }
+ if (NULL == (fapl_ptr = (const H5FD_splitter_fapl_t *)H5P_peek_driver_info(plist_ptr))) {
+ HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "unable to get specific-driver info")
+ }
+
+ HDstrncpy(config_out->wo_path, fapl_ptr->wo_path, H5FD_SPLITTER_PATH_MAX);
+ HDstrncpy(config_out->log_file_path, fapl_ptr->log_file_path, H5FD_SPLITTER_PATH_MAX);
+ config_out->ignore_wo_errs = fapl_ptr->ignore_wo_errs;
+
+ /* Copy R/W and W/O FAPLs */
+ if (H5FD__copy_plist(fapl_ptr->rw_fapl_id, &(config_out->rw_fapl_id)) < 0) {
+ HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "can't copy R/W FAPL");
+ }
+ if (H5FD__copy_plist(fapl_ptr->wo_fapl_id, &(config_out->wo_fapl_id)) < 0) {
+ HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "can't copy W/O FAPL");
+ }
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* end H5Pget_fapl_splitter() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_splitter_flush
+ *
+ * Purpose: Flushes all data to disk for both channels.
+ *
+ * Return: SUCCEED/FAIL
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_splitter_flush(H5FD_t *_file, hid_t H5_ATTR_UNUSED dxpl_id, hbool_t closing)
+{
+ H5FD_splitter_t *file = (H5FD_splitter_t *)_file;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ H5FD_SPLITTER_LOG_CALL("H5FD_splitter_flush");
+
+ /* Public API for dxpl "context" */
+ if (H5FDflush(file->rw_file, dxpl_id, closing) < 0) {
+ HGOTO_ERROR(H5E_VFL, H5E_CANTFLUSH, FAIL, "unable to flush R/W file")
+ }
+ if (H5FDflush(file->wo_file, dxpl_id, closing) < 0) {
+ H5FD_SPLITTER_WO_ERROR(file, "H5FD_splitter_flush",
+ H5E_VFL, H5E_CANTFLUSH, FAIL,
+ "unable to flush W/O file")
+ }
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_splitter_flush() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_splitter_read
+ *
+ * Purpose: Reads SIZE bytes of data from the R/W channel, beginning at
+ * address ADDR into buffer BUF according to data transfer
+ * properties in DXPL_ID.
+ *
+ * Return: Success: SUCCEED
+ * The read result is written into the BUF buffer
+ * which should be allocated by the caller.
+ * Failure: FAIL
+ * The contents of BUF are undefined.
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_splitter_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_splitter_t *file = (H5FD_splitter_t *)_file;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ H5FD_SPLITTER_LOG_CALL("H5FD_splitter_read");
+
+ 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)
+ }
+
+ /* Only read from R/W channel */
+ /* Public API for dxpl "context" */
+ if (H5FDread(file->rw_file, type, dxpl_id, addr, size, buf) < 0) {
+ HGOTO_ERROR(H5E_VFL, H5E_READERROR, FAIL, "Reading from R/W channel failed")
+ }
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_splitter_read() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_splitter_write
+ *
+ * Purpose: Writes SIZE bytes of data to R/W and W/O channels, beginning
+ * at address ADDR from buffer BUF according to data transfer
+ * properties in DXPL_ID.
+ *
+ * Return: SUCCEED/FAIL
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_splitter_write(H5FD_t *_file, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr, size_t size, const void *buf)
+{
+ H5FD_splitter_t *file = (H5FD_splitter_t *)_file;
+ H5P_genplist_t *plist_ptr = NULL;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ H5FD_SPLITTER_LOG_CALL("H5FD_splitter_write");
+
+ if (NULL == (plist_ptr = (H5P_genplist_t *)H5I_object(dxpl_id))) {
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a property list")
+ }
+
+ /* Write to each file */
+ /* Public API for dxpl "context" */
+ if (H5FDwrite(file->rw_file, type, dxpl_id, addr, size, buf) < 0) {
+ HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "R/W file write failed")
+ }
+ if (H5FDwrite(file->wo_file, type, dxpl_id, addr, size, buf) < 0) {
+ H5FD_SPLITTER_WO_ERROR(file, "H5FD_splitter_write",
+ H5E_VFL, H5E_WRITEERROR, FAIL,
+ "unable to write W/O file")
+ }
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_splitter_write() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_splitter_fapl_get
+ *
+ * Purpose: Returns a file access property list which indicates how the
+ * specified file is being accessed. The return list could be
+ * used to access another file the same way.
+ *
+ * Return: Success: Ptr to new file access property list with all
+ * members copied from the file struct.
+ * Failure: NULL
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5FD_splitter_fapl_get(H5FD_t *_file)
+{
+ H5FD_splitter_t *file = (H5FD_splitter_t *)_file;
+ void *ret_value = NULL;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ H5FD_SPLITTER_LOG_CALL("H5FD_splitter_fapl_get");
+
+ ret_value = H5FD_splitter_fapl_copy(&(file->fa));
+
+ FUNC_LEAVE_NOAPI(ret_value)
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_splitter_fapl_copy
+ *
+ * Purpose: Copies the file access properties.
+ *
+ * Return: Success: Pointer to a new property list info structure.
+ * Failure: NULL
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5FD_splitter_fapl_copy(const void *_old_fa)
+{
+ const H5FD_splitter_fapl_t *old_fa_ptr = (const H5FD_splitter_fapl_t *)_old_fa;
+ H5FD_splitter_fapl_t *new_fa_ptr = NULL;
+ void *ret_value = NULL;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ H5FD_SPLITTER_LOG_CALL("H5FD_splitter_fapl_copy");
+
+ HDassert(old_fa_ptr);
+
+ new_fa_ptr = (H5FD_splitter_fapl_t *)H5MM_calloc(sizeof(H5FD_splitter_fapl_t));
+ if (NULL == new_fa_ptr) {
+ HGOTO_ERROR(H5E_VFL, H5E_CANTALLOC, NULL, "unable to allocate log file FAPL")
+ }
+
+ if (HDmemcpy(new_fa_ptr, old_fa_ptr, sizeof(H5FD_splitter_fapl_t)) == NULL) {
+ HGOTO_ERROR(H5E_ARGS, H5E_CANTCOPY, NULL, "unable to shallow-copy info")
+ }
+ if (HDstrncpy(new_fa_ptr->wo_path, old_fa_ptr->wo_path, H5FD_SPLITTER_PATH_MAX) == NULL) {
+ HGOTO_ERROR(H5E_ARGS, H5E_CANTCOPY, NULL, "unable to copy write-only channel file path")
+ }
+ if (HDstrncpy(new_fa_ptr->log_file_path, old_fa_ptr->log_file_path, H5FD_SPLITTER_PATH_MAX) == NULL) {
+ HGOTO_ERROR(H5E_ARGS, H5E_CANTCOPY, NULL, "unable to copy log file path")
+ }
+
+ /* Copy R/W and W/O FAPLs */
+ if (H5FD__copy_plist(old_fa_ptr->rw_fapl_id, &(new_fa_ptr->rw_fapl_id)) < 0) {
+ HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, NULL, "can't copy R/W FAPL");
+ }
+ if (H5FD__copy_plist(old_fa_ptr->wo_fapl_id, &(new_fa_ptr->wo_fapl_id)) < 0) {
+ HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, NULL, "can't copy W/O FAPL");
+ }
+
+ ret_value = (void *)new_fa_ptr;
+
+done:
+ if (NULL == ret_value) {
+ if (new_fa_ptr) {
+ H5MM_free(new_fa_ptr);
+ }
+ }
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_splitter_fapl_copy() */
+
+
+/*--------------------------------------------------------------------------
+ * Function: H5FD_splitter_fapl_free
+ *
+ * Purpose: Releases the file access lists
+ *
+ * Return: SUCCEED/FAIL
+ *--------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_splitter_fapl_free(void *_fapl)
+{
+ H5FD_splitter_fapl_t *fapl = (H5FD_splitter_fapl_t*)_fapl;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ H5FD_SPLITTER_LOG_CALL("H5FD_splitter_fapl_free");
+
+ /* Check arguments */
+ HDassert(fapl);
+
+ if (H5I_dec_ref(fapl->rw_fapl_id) < 0) {
+ HGOTO_ERROR(H5E_VFL, H5E_CANTDEC, FAIL, "can't close R/W FAPL ID")
+ }
+ if (H5I_dec_ref(fapl->wo_fapl_id) < 0) {
+ HGOTO_ERROR(H5E_VFL, H5E_CANTDEC, FAIL, "can't close W/O FAPL ID")
+ }
+
+ /* Free the property list */
+ H5MM_free(fapl);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_splitter_fapl_free() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_splitter_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
+ *-------------------------------------------------------------------------
+ */
+static H5FD_t *
+H5FD_splitter_open(const char *name, unsigned flags, hid_t splitter_fapl_id, haddr_t maxaddr)
+{
+ H5FD_splitter_t *file_ptr = NULL; /* Splitter VFD info */
+ const H5FD_splitter_fapl_t *fapl_ptr = NULL; /* Driver-specific property list */
+ H5P_genplist_t *plist_ptr = NULL;
+ H5FD_t *ret_value = NULL;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ H5FD_SPLITTER_LOG_CALL("H5FD_splitter_open");
+
+ /* 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")
+ }
+ if ( (H5P_FILE_ACCESS_DEFAULT == splitter_fapl_id) ||
+ (H5FD_SPLITTER != H5Pget_driver(splitter_fapl_id)) )
+ {
+ /* presupposes that H5P_FILE_ACCESS_DEFAULT is not a splitter */
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "driver is not splitter")
+ }
+
+ file_ptr = (H5FD_splitter_t *)H5FL_CALLOC(H5FD_splitter_t);
+ if (NULL == file_ptr) {
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "unable to allocate file struct")
+ }
+ file_ptr->fa.rw_fapl_id = H5I_INVALID_HID;
+ file_ptr->fa.wo_fapl_id = H5I_INVALID_HID;
+
+ /* Get the driver-specific file access properties */
+ plist_ptr = (H5P_genplist_t *)H5I_object(splitter_fapl_id);
+ if (NULL == plist_ptr) {
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "not a file access property list")
+ }
+ fapl_ptr = (const H5FD_splitter_fapl_t *)H5P_peek_driver_info(plist_ptr);
+ if (NULL == fapl_ptr) {
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "unable to get VFL driver info")
+ }
+
+ /* Copy simpler info */
+ if (HDstrncpy(file_ptr->fa.wo_path, fapl_ptr->wo_path, H5FD_SPLITTER_PATH_MAX) == NULL) {
+ HGOTO_ERROR(H5E_VFL, H5E_CANTCOPY, NULL, "unable to copy write-only path")
+ }
+ if (HDstrncpy(file_ptr->fa.log_file_path, fapl_ptr->log_file_path, H5FD_SPLITTER_PATH_MAX) == NULL) {
+ HGOTO_ERROR(H5E_VFL, H5E_CANTCOPY, NULL, "unable to copy logfile path")
+ }
+ file_ptr->fa.ignore_wo_errs = fapl_ptr->ignore_wo_errs;
+
+ /* Copy R/W and W/O channel FAPLs. */
+ if (H5FD__copy_plist(fapl_ptr->rw_fapl_id, &(file_ptr->fa.rw_fapl_id)) < 0) {
+ HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, NULL, "can't copy R/W FAPL");
+ }
+ if (H5FD__copy_plist(fapl_ptr->wo_fapl_id, &(file_ptr->fa.wo_fapl_id)) < 0) {
+ HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, NULL, "can't copy W/O FAPL");
+ }
+
+ /* Prepare log file if necessary.
+ * If application wants to ignore the errors from W/O channel and
+ * provided a name for the log file, then open it
+ */
+ if (!file_ptr->logfp) {
+ if (file_ptr->fa.log_file_path[0] != '\0') {
+ file_ptr->logfp = HDfopen(file_ptr->fa.log_file_path, "w");
+ if (file_ptr->logfp == NULL) {
+ HGOTO_ERROR(H5E_VFL, H5E_CANTOPENFILE, NULL, "unable to open log file")
+ }
+ } /* end if logfile path given */
+ } /* end if logfile pointer/handle does not exist */
+
+ file_ptr->rw_file = H5FD_open(name, flags, fapl_ptr->rw_fapl_id, HADDR_UNDEF);
+ if (!file_ptr->rw_file) {
+ HGOTO_ERROR(H5E_VFL, H5E_CANTOPENFILE, NULL, "unable to open R/W file")
+ }
+
+ file_ptr->wo_file = H5FD_open(fapl_ptr->wo_path, flags, fapl_ptr->wo_fapl_id, HADDR_UNDEF);
+ if (!file_ptr->wo_file) {
+ H5FD_SPLITTER_WO_ERROR(file_ptr, "H5FD_splitter_open",
+ H5E_VFL, H5E_CANTOPENFILE, NULL,
+ "unable to open W/O file")
+ }
+
+ ret_value = (H5FD_t*)file_ptr;
+
+done:
+ if (NULL == ret_value) {
+ if (file_ptr) {
+ if (H5I_INVALID_HID != file_ptr->fa.rw_fapl_id) {
+ H5I_dec_ref(file_ptr->fa.rw_fapl_id);
+ }
+ if (H5I_INVALID_HID != file_ptr->fa.wo_fapl_id) {
+ H5I_dec_ref(file_ptr->fa.wo_fapl_id);
+ }
+ if (file_ptr->rw_file) {
+ H5FD_close(file_ptr->rw_file);
+ }
+ if (file_ptr->wo_file) {
+ H5FD_close(file_ptr->wo_file);
+ }
+ H5FL_FREE(H5FD_splitter_t, file_ptr);
+ }
+ } /* end if error */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_splitter_open() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_splitter_close
+ *
+ * Purpose: Closes files on both read-write and write-only channels.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL, file not closed.
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_splitter_close(H5FD_t *_file)
+{
+ H5FD_splitter_t *file = (H5FD_splitter_t *)_file;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ H5FD_SPLITTER_LOG_CALL("H5FD_splitter_close");
+
+ /* Sanity check */
+ HDassert(file);
+
+ if (H5I_dec_ref(file->fa.rw_fapl_id) < 0) {
+ HGOTO_ERROR(H5E_VFL, H5E_ARGS, FAIL, "can't close R/W FAPL")
+ }
+ if (H5I_dec_ref(file->fa.wo_fapl_id) < 0) {
+ HGOTO_ERROR(H5E_VFL, H5E_ARGS, FAIL, "can't close W/O FAPL")
+ }
+
+ if (file->rw_file) {
+ if (H5FD_close(file->rw_file) == FAIL) {
+ HGOTO_ERROR(H5E_VFL, H5E_CANTCLOSEFILE, FAIL, "unable to close R/W file")
+ }
+ }
+ if (file->wo_file) {
+ if (H5FD_close(file->wo_file) == FAIL) {
+ H5FD_SPLITTER_WO_ERROR(file, "H5FD_splitter_close",
+ H5E_VFL, H5E_CANTCLOSEFILE, FAIL,
+ "unable to close W/O file")
+ }
+ }
+
+ if (file->logfp) {
+ HDfclose(file->logfp);
+ file->logfp = NULL;
+ }
+
+ /* Release the file info */
+ file = H5FL_FREE(H5FD_splitter_t, file);
+ file = NULL;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_splitter_close() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_splitter_get_eoa
+ *
+ * Purpose: Returns 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: Success: The end-of-address-marker
+ *
+ * Failure: HADDR_UNDEF
+ *-------------------------------------------------------------------------
+ */
+static haddr_t
+H5FD_splitter_get_eoa(const H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type)
+{
+ const H5FD_splitter_t *file = (const H5FD_splitter_t *)_file;
+ haddr_t ret_value = HADDR_UNDEF;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ H5FD_SPLITTER_LOG_CALL("H5FD_splitter_get_eoa");
+
+ /* Sanity check */
+ HDassert(file);
+ HDassert(file->rw_file);
+
+ if ((ret_value = H5FD_get_eoa(file->rw_file, type)) == HADDR_UNDEF) {
+ HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, HADDR_UNDEF, "unable to get eoa")
+ }
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_splitter_get_eoa */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_splitter_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/FAIL
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_splitter_set_eoa(H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type, haddr_t addr)
+{
+ H5FD_splitter_t *file = (H5FD_splitter_t *)_file;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ H5FD_SPLITTER_LOG_CALL("H5FD_splitter_set_eoa";)
+
+ /* Sanity check */
+ HDassert(file);
+ HDassert(file->rw_file);
+ HDassert(file->wo_file);
+
+ if (H5FD_set_eoa(file->rw_file, type, addr) < 0) {
+ HGOTO_ERROR(H5E_VFL, H5E_CANTSET, FAIL, "H5FDset_eoa failed for R/W file")
+ }
+
+ if (H5FD_set_eoa(file->wo_file, type, addr) < 0) {
+ H5FD_SPLITTER_WO_ERROR(file, "H5FD_splitter_set_eoa",
+ H5E_VFL, H5E_CANTSET, FAIL,
+ "unable to set EOA for W/O file")
+ }
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_splitter_set_eoa() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_splitter_get_eof
+ *
+ * Purpose: Returns 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: Success: The end-of-address-marker
+ *
+ * Failure: HADDR_UNDEF
+ *-------------------------------------------------------------------------
+ */
+static haddr_t
+H5FD_splitter_get_eof(const H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type)
+{
+ const H5FD_splitter_t *file = (const H5FD_splitter_t *)_file;
+ haddr_t ret_value = HADDR_UNDEF; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ H5FD_SPLITTER_LOG_CALL("H5FD_splitter_get_eof");
+
+ /* Sanity check */
+ HDassert(file);
+ HDassert(file->rw_file);
+
+ if (HADDR_UNDEF == (ret_value = H5FD_get_eof(file->rw_file, type))) {
+ HGOTO_ERROR(H5E_VFL, H5E_CANTGET, HADDR_UNDEF, "unable to get eof")
+ }
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_splitter_get_eof */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_splitter_truncate
+ *
+ * Purpose: Notify driver to truncate the file back to the allocated size.
+ *
+ * Return: SUCCEED/FAIL
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_splitter_truncate(H5FD_t *_file, hid_t dxpl_id, hbool_t closing)
+{
+ H5FD_splitter_t *file = (H5FD_splitter_t *)_file;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ H5FD_SPLITTER_LOG_CALL("H5FD_splitter_truncate");
+
+ HDassert(file);
+ HDassert(file->rw_file);
+ HDassert(file->wo_file);
+
+ if (H5FDtruncate(file->rw_file, dxpl_id, closing) < 0) {
+ HGOTO_ERROR(H5E_VFL, H5E_CANTUPDATE, FAIL, "unable to truncate R/W file")
+ }
+
+ if (H5FDtruncate(file->wo_file, dxpl_id, closing) < 0) {
+ H5FD_SPLITTER_WO_ERROR(file, "H5FD_splitter_truncate",
+ H5E_VFL, H5E_CANTUPDATE, FAIL,
+ "unable to truncate W/O file")
+ }
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_splitter_truncate */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_splitter_sb_size
+ *
+ * Purpose: Obtains the number of bytes required to store the driver file
+ * access data in the HDF5 superblock.
+ *
+ * Return: Success: Number of bytes required.
+ *
+ * Failure: 0 if an error occurs or if the driver has no
+ * data to store in the superblock.
+ *
+ * NOTE: no public API for H5FD_sb_size, it needs to be added
+ *-------------------------------------------------------------------------
+ */
+static hsize_t
+H5FD_splitter_sb_size(H5FD_t *_file)
+{
+ H5FD_splitter_t *file = (H5FD_splitter_t *)_file;
+ hsize_t ret_value = 0;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ H5FD_SPLITTER_LOG_CALL("H5FD_splitter_sb_size");
+
+ /* Sanity check */
+ HDassert(file);
+ HDassert(file->rw_file);
+
+ if (file->rw_file) {
+ ret_value = H5FD_sb_size(file->rw_file);
+ }
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_splitter_sb_size */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_splitter_sb_encode
+ *
+ * Purpose: Encode driver-specific data into the output arguments.
+ *
+ * Return: SUCCEED/FAIL
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_splitter_sb_encode(H5FD_t *_file, char *name/*out*/, unsigned char *buf/*out*/)
+{
+ H5FD_splitter_t *file = (H5FD_splitter_t *)_file;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ H5FD_SPLITTER_LOG_CALL("H5FD_splitter_sb_encode");
+
+ /* Sanity check */
+ HDassert(file);
+ HDassert(file->rw_file);
+
+ if (file->rw_file && H5FD_sb_encode(file->rw_file, name, buf) < 0) {
+ HGOTO_ERROR(H5E_VFL, H5E_CANTENCODE, FAIL, "unable to encode the superblock in R/W file")
+ }
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_splitter_sb_encode */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_splitter_sb_decode
+ *
+ * Purpose: Decodes the driver information block.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * NOTE: no public API for H5FD_sb_size, need to add
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_splitter_sb_decode(H5FD_t *_file, const char *name, const unsigned char *buf)
+{
+ H5FD_splitter_t *file = (H5FD_splitter_t *)_file;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ H5FD_SPLITTER_LOG_CALL("H5FD_splitter_sb_decode");
+
+ /* Sanity check */
+ HDassert(file);
+ HDassert(file->rw_file);
+
+ if (H5FD_sb_load(file->rw_file, name, buf) < 0) {
+ HGOTO_ERROR(H5E_VFL, H5E_CANTDECODE, FAIL, "unable to decode the superblock in R/W file")
+ }
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_splitter_sb_decode */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_splitter_cmp
+ *
+ * Purpose: Compare the keys of two files.
+ *
+ * Return: Success: A value like strcmp()
+ * Failure: Must never fail
+ *-------------------------------------------------------------------------
+ */
+static int
+H5FD_splitter_cmp(const H5FD_t *_f1, const H5FD_t *_f2)
+{
+ const H5FD_splitter_t *f1 = (const H5FD_splitter_t *)_f1;
+ const H5FD_splitter_t *f2 = (const H5FD_splitter_t *)_f2;
+ herr_t ret_value = 0; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ H5FD_SPLITTER_LOG_CALL("H5FD_splitter_cmp");
+
+ HDassert(f1);
+ HDassert(f2);
+
+ ret_value = H5FD_cmp(f1->rw_file, f2->rw_file);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_splitter_cmp */
+
+
+/*--------------------------------------------------------------------------
+ * Function: H5FD_splitter_get_handle
+ *
+ * Purpose: Returns a pointer to the file handle of low-level virtual
+ * file driver.
+ *
+ * Return: SUCCEED/FAIL
+ *--------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_splitter_get_handle(
+ H5FD_t *_file,
+ hid_t H5_ATTR_UNUSED fapl,
+ void **file_handle)
+{
+ H5FD_splitter_t *file = (H5FD_splitter_t*)_file;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ H5FD_SPLITTER_LOG_CALL("H5FD_splitter_get_handle");
+
+ /* Check arguments */
+ HDassert(file);
+ HDassert(file->rw_file);
+ HDassert(file_handle);
+
+ /* Only do for R/W channel */
+ if (H5FD_get_vfd_handle(file->rw_file, file->fa.rw_fapl_id, file_handle) < 0)
+ {
+ HGOTO_ERROR(H5E_VFL, H5E_CANTGET, FAIL, "unable to get handle of R/W file")
+ }
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_splitter_get_handle */
+
+
+/*--------------------------------------------------------------------------
+ * Function: H5FD_splitter_lock
+ *
+ * Purpose: Sets a file lock.
+ *
+ * Return: SUCCEED/FAIL
+ *--------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_splitter_lock(H5FD_t *_file, hbool_t rw)
+{
+ H5FD_splitter_t *file = (H5FD_splitter_t *)_file; /* VFD file struct */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ H5FD_SPLITTER_LOG_CALL("H5FD_splitter_lock");
+
+ HDassert(file);
+ HDassert(file->rw_file);
+
+ /* Place the lock on each file */
+ if (H5FD_lock(file->rw_file, rw) < 0) {
+ HGOTO_ERROR(H5E_VFL, H5E_CANTLOCK, FAIL, "unable to lock R/W file")
+ }
+ if (file->wo_file != NULL) {
+ if (H5FD_lock(file->wo_file, rw) < 0) {
+ H5FD_SPLITTER_WO_ERROR(file, "H5FD_splitter_lock",
+ H5E_VFL, H5E_CANTLOCK, FAIL,
+ "unable to lock W/O file")
+ }
+ }
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_splitter_lock */
+
+
+/*--------------------------------------------------------------------------
+ * Function: H5FD_splitter_unlock
+ *
+ * Purpose: Removes a file lock.
+ *
+ * Return: SUCCEED/FAIL
+ *--------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_splitter_unlock(H5FD_t *_file)
+{
+ H5FD_splitter_t *file = (H5FD_splitter_t *)_file; /* VFD file struct */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ H5FD_SPLITTER_LOG_CALL("H5FD_splitter_unlock");
+
+ /* Check arguments */
+ HDassert(file);
+ HDassert(file->rw_file);
+
+ /* Remove the lock on each file */
+ if (H5FD_unlock(file->rw_file) < 0) {
+ HGOTO_ERROR(H5E_VFL, H5E_CANTUNLOCK, FAIL, "unable to unlock R/W file")
+ }
+ if (file->wo_file != NULL) {
+ if (H5FD_unlock(file->wo_file) < 0) {
+ HGOTO_ERROR(H5E_VFL, H5E_CANTUNLOCK, FAIL,
+ "unable to unlock W/O file")
+ }
+ }
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_splitter_unlock */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_splitter_query
+ *
+ * Purpose: Set the flags that this VFL driver is capable of supporting.
+ * (listed in H5FDpublic.h)
+ *
+ * Return: SUCCEED/FAIL
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_splitter_query(const H5FD_t *_file, unsigned long *flags /* out */)
+{
+ const H5FD_splitter_t *file = (const H5FD_splitter_t *)_file;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ H5FD_SPLITTER_LOG_CALL("H5FD_splitter_query");
+
+ if (file) {
+ HDassert(file);
+ HDassert(file->rw_file);
+
+ if (H5FDquery(file->rw_file, flags) < 0) {
+ HGOTO_ERROR(H5E_VFL, H5E_CANTLOCK, FAIL,
+ "unable to query R/W file");
+ }
+ }
+ else {
+ /* There is no file. Because this is a pure passthrough VFD,
+ * it has no features of its own.
+ */
+ if (flags) {
+ *flags = 0;
+ }
+ }
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_splitter_query() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_splitter_alloc
+ *
+ * Purpose: Allocate file memory.
+ *
+ * Return: Address of allocated space (HADDR_UNDEF if error).
+ *-------------------------------------------------------------------------
+ */
+static haddr_t
+H5FD_splitter_alloc(H5FD_t *_file, H5FD_mem_t type, hid_t dxpl_id, hsize_t size)
+{
+ H5FD_splitter_t *file = (H5FD_splitter_t *)_file; /* VFD file struct */
+ haddr_t ret_value = HADDR_UNDEF; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ H5FD_SPLITTER_LOG_CALL("H5FD_splitter_alloc");
+
+ /* Check arguments */
+ HDassert(file);
+ HDassert(file->rw_file);
+
+ /* Allocate memory for each file, only return the return value for R/W file. */
+ if ((ret_value = H5FDalloc(file->rw_file, type, dxpl_id, size)) == HADDR_UNDEF) {
+ HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, HADDR_UNDEF, "unable to allocate for R/W file")
+ }
+
+ if (H5FDalloc(file->wo_file, type, dxpl_id, size) == HADDR_UNDEF) {
+ H5FD_SPLITTER_WO_ERROR(file, "H5FD_splitter_alloc",
+ H5E_VFL, H5E_CANTINIT, HADDR_UNDEF,
+ "unable to alloc for W/O file")
+ }
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_splitter_alloc() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_splitter_get_type_map
+ *
+ * Purpose: Retrieve the memory type mapping for this file
+ *
+ * Return: SUCCEED/FAIL
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_splitter_get_type_map(const H5FD_t *_file, H5FD_mem_t *type_map)
+{
+ const H5FD_splitter_t *file = (const H5FD_splitter_t *)_file;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ H5FD_SPLITTER_LOG_CALL("H5FD_splitter_get_type_map");
+
+ /* Check arguments */
+ HDassert(file);
+ HDassert(file->rw_file);
+
+ /* Retrieve memory type mapping for R/W channel only */
+ if (H5FD_get_fs_type_map(file->rw_file, type_map) < 0) {
+ HGOTO_ERROR(H5E_VFL, H5E_CANTGET, FAIL, "unable to allocate for R/W file")
+ }
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_splitter_get_type_map() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD_splitter_free
+ *
+ * Purpose: Free the resources for the splitter VFD.
+ *
+ * Return: SUCCEED/FAIL
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD_splitter_free(H5FD_t *_file, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr, hsize_t size)
+{
+ H5FD_splitter_t *file = (H5FD_splitter_t *)_file; /* VFD file struct */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT
+
+ H5FD_SPLITTER_LOG_CALL("H5FD_splitter_free");
+
+ /* Check arguments */
+ HDassert(file);
+ HDassert(file->rw_file);
+
+ if (H5FDfree(file->rw_file, type, dxpl_id, addr, size) < 0) {
+ HGOTO_ERROR(H5E_VFL, H5E_CANTFREE, FAIL, "unable to free for R/W file")
+ }
+
+ if (H5FDfree(file->wo_file, type, dxpl_id, addr, size) < 0) {
+ H5FD_SPLITTER_WO_ERROR(file, "H5FD_splitter_free",
+ H5E_VFL, H5E_CANTINIT, FAIL,
+ "unable to free for W/O file")
+ }
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD_splitter_free() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FD__splitter_log_error
+ *
+ * Purpose: Log an error from the W/O channel appropriately.
+ *
+ * Return: SUCCEED/FAIL
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FD__splitter_log_error(const H5FD_splitter_t *file, const char *atfunc, const char *msg)
+{
+ size_t size = 0;
+ char *s = NULL;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ H5FD_SPLITTER_LOG_CALL("H5FD__splitter_log_error");
+
+ /* Check arguments */
+ HDassert(file);
+ HDassert(atfunc && *atfunc);
+ HDassert(msg && *msg);
+
+ if (file->logfp != NULL) {
+ size = strlen(atfunc) + strlen(msg) + 3; /* ':', ' ', '\n' */
+ s = (char *)malloc(sizeof(char) * (size+1));
+ if (NULL == s) {
+ ret_value = FAIL;
+ }
+ else
+ if (size < (size_t)HDsnprintf(s, size+1, "%s: %s\n", atfunc, msg)) {
+ ret_value = FAIL;
+ }
+ else
+ if (size != HDfwrite(s, 1, size, file->logfp)) {
+ ret_value = FAIL;
+ }
+ HDfree(s);
+ }
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5FD__splitter_log_error() */
+
diff --git a/src/H5FDsplitter.h b/src/H5FDsplitter.h
new file mode 100644
index 0000000..5a5ef29
--- /dev/null
+++ b/src/H5FDsplitter.h
@@ -0,0 +1,99 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * 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. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Purpose: The public header file for the "splitter" driver.
+ */
+
+#ifndef H5FDsplitter_H
+#define H5FDsplitter_H
+
+#define H5FD_SPLITTER (H5FD_splitter_init())
+
+/* The version of the H5FD_splitter_vfd_config_t structure used */
+#define H5FD_CURR_SPLITTER_VFD_CONFIG_VERSION 1
+
+/* Maximum length of a filename/path string in the Write-Only channel,
+ * including the NULL-terminator.
+ */
+#define H5FD_SPLITTER_PATH_MAX 4096
+
+/* Semi-unique constant used to help identify structure pointers */
+#define H5FD_SPLITTER_MAGIC 0x2B916880
+
+/* ----------------------------------------------------------------------------
+ * Structure: H5FD_spliiter_vfd_config_t
+ *
+ * One-stop shopping for configuring a Splitter VFD (rather than many
+ * paramaters passed into H5Pset/get functions).
+ *
+ * magic (int32_t)
+ * Semi-unique number, used to sanity-check that a given pointer is
+ * likely (or not) to be this structure type. MUST be first.
+ * If magic is not H5FD_SPLITTER_MAGIC, the structure (and/or pointer to)
+ * must be considered invalid.
+ *
+ * version (unsigned int)
+ * Version number of this structure -- informs component membership.
+ * If not H5FD_CURR_SPLITTER_VFD_CONFIG_VERSION, the structure (and/or
+ * pointer to) must be considered invalid.
+ *
+ * rw_fapl_id (hid_t)
+ * Library-given identification number of the Read/Write channel driver
+ * File Access Property List.
+ * The driver must support read/write access.
+ * Must be set to H5P_DEFAULT or a valid FAPL ID.
+ *
+ * wo_fapl_id (hid_t)
+ * Library-given identification number of the Read/Write channel driver
+ * File Access Property List.
+ * The driver feature flags must include H5FD_FEAT_DEFAULT_VFD_COMPAITBLE.
+ * Must be set to H5P_DEFAULT or a valid FAPL ID.
+ *
+ * wo_file_path (char[H5FD_SPLITTER_PATH_MAX + 1])
+ * String buffer for the Write-Only channel target file.
+ * Must be null-terminated, cannot be empty.
+ *
+ * log_file_path (char[H5FD_SPLITTER_PATH_MAX + 1])
+ * String buffer for the Splitter VFD logging output.
+ * Must be null-terminated.
+ * If null, no logfile is created.
+ *
+ * ignore_wo_errors (hbool_t)
+ * Toggle flag for how judiciously to respond to errors on the Write-Only
+ * channel.
+ *
+ * ----------------------------------------------------------------------------
+ */
+typedef struct H5FD_splitter_vfd_config_t {
+ int32_t magic;
+ unsigned int version;
+ hid_t rw_fapl_id;
+ hid_t wo_fapl_id;
+ char wo_path[H5FD_SPLITTER_PATH_MAX + 1];
+ char log_file_path[H5FD_SPLITTER_PATH_MAX + 1];
+ hbool_t ignore_wo_errs;
+} H5FD_splitter_vfd_config_t;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+H5_DLL hid_t H5FD_splitter_init(void);
+H5_DLL herr_t H5Pset_fapl_splitter(hid_t fapl_id, H5FD_splitter_vfd_config_t *config_ptr);
+H5_DLL herr_t H5Pget_fapl_splitter(hid_t fapl_id, H5FD_splitter_vfd_config_t *config_ptr);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/src/H5VL.c b/src/H5VL.c
index f83baf2..c4f38dd 100644
--- a/src/H5VL.c
+++ b/src/H5VL.c
@@ -903,7 +903,7 @@ H5VLfree_lib_state(void *state)
/* Check args */
if(NULL == state)
- HGOTO_ERROR(H5E_VOL, H5E_BADVALUE, FAIL, "invalid state pointer")
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid state pointer")
/* Free the library state */
if(H5VL_free_lib_state(state) < 0)
@@ -913,3 +913,38 @@ done:
FUNC_LEAVE_API(ret_value)
} /* H5VLfree_lib_state() */
+
+/*---------------------------------------------------------------------------
+ * Function: H5VLquery_optional
+ *
+ * Purpose: Determine if a VOL connector supports a particular optional
+ * callback operation.
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ *---------------------------------------------------------------------------
+ */
+herr_t
+H5VLquery_optional(hid_t obj_id, H5VL_subclass_t subcls, int opt_type, hbool_t *supported)
+{
+ H5VL_object_t *vol_obj = NULL;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_API(FAIL)
+ H5TRACE4("e", "iVSIs*b", obj_id, subcls, opt_type, supported);
+
+ /* Check args */
+ if(NULL == supported)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid supported pointer")
+ if(NULL == (vol_obj = (H5VL_object_t *)H5I_object(obj_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid object identifier")
+
+ /* Query the connector */
+ if(H5VL_introspect_opt_query(vol_obj, subcls, opt_type, supported) < 0)
+ HGOTO_ERROR(H5E_VOL, H5E_CANTGET, FAIL, "unable to query VOL connector support")
+
+done:
+ FUNC_LEAVE_API(ret_value)
+} /* H5VLquery_optional() */
+
diff --git a/src/H5VLconnector.h b/src/H5VLconnector.h
index 7951a32..4a35f22 100644
--- a/src/H5VLconnector.h
+++ b/src/H5VLconnector.h
@@ -48,24 +48,6 @@
/* Public Typedefs */
/*******************/
-/* Enum type for each VOL subclass */
-/* (Used for various queries, etc) */
-typedef enum H5VL_subclass_t {
- H5VL_SUBCLS_NONE, /* Operations outside of a subclass */
- H5VL_SUBCLS_INFO, /* 'Info' subclass */
- H5VL_SUBCLS_WRAP, /* 'Wrap' subclass */
- H5VL_SUBCLS_ATTR, /* 'Attribute' subclass */
- H5VL_SUBCLS_DATASET, /* 'Dataset' subclass */
- H5VL_SUBCLS_DATATYPE, /* 'Named datatype' subclass */
- H5VL_SUBCLS_FILE, /* 'File' subclass */
- H5VL_SUBCLS_GROUP, /* 'Group' subclass */
- H5VL_SUBCLS_LINK, /* 'Link' subclass */
- H5VL_SUBCLS_OBJECT, /* 'Object' subclass */
- H5VL_SUBCLS_REQUEST, /* 'Request' subclass */
- H5VL_SUBCLS_BLOB, /* 'Blob' subclass */
- H5VL_SUBCLS_TOKEN /* 'Token' subclass */
-} H5VL_subclass_t;
-
/* types for attribute GET callback */
typedef enum H5VL_attr_get_t {
H5VL_ATTR_GET_ACPL, /* creation property list */
diff --git a/src/H5VLpublic.h b/src/H5VLpublic.h
index 006c3ea..8f79adc 100644
--- a/src/H5VLpublic.h
+++ b/src/H5VLpublic.h
@@ -48,6 +48,24 @@
typedef int H5VL_class_value_t;
+/* Enum type for each VOL subclass */
+/* (Used for various queries, etc) */
+typedef enum H5VL_subclass_t {
+ H5VL_SUBCLS_NONE, /* Operations outside of a subclass */
+ H5VL_SUBCLS_INFO, /* 'Info' subclass */
+ H5VL_SUBCLS_WRAP, /* 'Wrap' subclass */
+ H5VL_SUBCLS_ATTR, /* 'Attribute' subclass */
+ H5VL_SUBCLS_DATASET, /* 'Dataset' subclass */
+ H5VL_SUBCLS_DATATYPE, /* 'Named datatype' subclass */
+ H5VL_SUBCLS_FILE, /* 'File' subclass */
+ H5VL_SUBCLS_GROUP, /* 'Group' subclass */
+ H5VL_SUBCLS_LINK, /* 'Link' subclass */
+ H5VL_SUBCLS_OBJECT, /* 'Object' subclass */
+ H5VL_SUBCLS_REQUEST, /* 'Request' subclass */
+ H5VL_SUBCLS_BLOB, /* 'Blob' subclass */
+ H5VL_SUBCLS_TOKEN /* 'Token' subclass */
+} H5VL_subclass_t;
+
/********************/
/* Public Variables */
/********************/
@@ -70,7 +88,7 @@ H5_DLL hid_t H5VLget_connector_id_by_value(H5VL_class_value_t connector_value);
H5_DLL ssize_t H5VLget_connector_name(hid_t id, char *name/*out*/, size_t size);
H5_DLL herr_t H5VLclose(hid_t connector_id);
H5_DLL herr_t H5VLunregister_connector(hid_t connector_id);
-
+H5_DLL herr_t H5VLquery_optional(hid_t obj_id, H5VL_subclass_t subcls, int opt_type, hbool_t *supported);
#ifdef __cplusplus
}
diff --git a/src/H5private.h b/src/H5private.h
index f570723..95d4885 100644
--- a/src/H5private.h
+++ b/src/H5private.h
@@ -365,6 +365,22 @@
#endif /* __cplusplus */
/*
+ * Networking headers used by the mirror VFD and related tests and utilities.
+ */
+#ifdef H5_HAVE_ARPA_INET_H
+# include <arpa/inet.h>
+#endif
+#ifdef H5_HAVE_NETDB_H
+# include <netdb.h>
+#endif
+#ifdef H5_HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
+#ifdef H5_HAVE_SYS_SOCKET_H
+# include <sys/socket.h>
+#endif
+
+/*
* Status return values for the `herr_t' type.
* Since some unix/c routines use 0 and -1 (or more precisely, non-negative
* vs. negative) as their return code, and some assumption had been made in
@@ -646,6 +662,9 @@ typedef struct {
#ifndef HDabs
#define HDabs(X) abs(X)
#endif /* HDabs */
+#ifndef HDaccept
+ #define HDaccept(A,B,C) accept((A),(B),(C)) /* mirror VFD */
+#endif /* HDaccept */
#ifndef HDaccess
#define HDaccess(F,M) access(F, M)
#endif /* HDaccess */
@@ -692,6 +711,9 @@ typedef struct {
#ifndef HDatoll
#define HDatoll(S) atoll(S)
#endif /* HDatol */
+#ifndef HDbind
+ #define HDbind(A,B,C) bind((A),(B),(C)) /* mirror VFD */
+#endif /* HDbind */
#ifndef HDbsearch
#define HDbsearch(K,B,N,Z,F) bsearch(K,B,N,Z,F)
#endif /* HDbsearch */
@@ -734,6 +756,9 @@ typedef struct {
#ifndef HDclosedir
#define HDclosedir(D) closedir(D)
#endif /* HDclosedir */
+#ifndef HDconnect
+ #define HDconnect(A,B,C) connect((A),(B),(C)) /* mirror VFD */
+#endif /* HDconnect */
#ifndef HDcos
#define HDcos(X) cos(X)
#endif /* HDcos */
@@ -978,9 +1003,12 @@ typedef off_t h5_stat_size_t;
#ifndef HDgetgroups
#define HDgetgroups(Z,G) getgroups(Z,G)
#endif /* HDgetgroups */
+#ifndef HDgethostbyaddr
+ #define HDgethostbyaddr(A,B,C) gethostbyaddr((A),(B),(C)) /* mirror VFD */
+#endif /* HDgethostbyaddr */
#ifndef HDgethostname
#define HDgethostname(N,L) gethostname(N,L)
-#endif /* HDgetlogin */
+#endif /* HDgethostname */
#ifndef HDgetlogin
#define HDgetlogin() getlogin()
#endif /* HDgetlogin */
@@ -1014,6 +1042,18 @@ typedef off_t h5_stat_size_t;
#ifndef HDgmtime
#define HDgmtime(T) gmtime(T)
#endif /* HDgmtime */
+#ifndef HDhtonl
+ #define HDhtonl(X) htonl((X)) /* mirror VFD */
+#endif /* HDhtonl */
+#ifndef HDhtons
+ #define HDhtons(X) htons((X)) /* mirror VFD */
+#endif /* HDhtons */
+#ifndef HDinet_addr
+ #define HDinet_addr(C) inet_addr((C)) /* mirror VFD */
+#endif /* HDinet_addr */
+#ifndef HDinet_ntoa
+ #define HDinet_ntoa(C) inet_ntoa((C)) /* mirror VFD */
+#endif /* HDinet_ntoa */
#ifndef HDisalnum
#define HDisalnum(C) isalnum((int)(C)) /*cast for solaris warning*/
#endif /* HDisalnum */
@@ -1068,6 +1108,9 @@ typedef off_t h5_stat_size_t;
#ifndef HDlink
#define HDlink(OLD,NEW) link(OLD,NEW)
#endif /* HDlink */
+#ifndef HDlisten
+ #define HDlisten(A,B) listen((A),(B)) /* mirror VFD */
+#endif /* HDlisten */
#ifndef HDllround
#define HDllround(V) llround(V)
#endif /* HDround */
@@ -1149,6 +1192,12 @@ typedef off_t h5_stat_size_t;
#ifndef HDnanosleep
#define HDnanosleep(N, O) nanosleep(N, O)
#endif /* HDnanosleep */
+#ifndef HDntohl
+ #define HDntohl(A) ntohl((A)) /* mirror VFD */
+#endif /* HDntohl */
+#ifndef HDntohs
+ #define HDntohs(A) ntohs((A)) /* mirror VFD */
+#endif /* HDntohs */
#ifndef HDopen
#define HDopen(F,...) open(F,__VA_ARGS__)
#endif /* HDopen */
@@ -1296,12 +1345,21 @@ typedef off_t h5_stat_size_t;
#ifndef HDsetsid
#define HDsetsid() setsid()
#endif /* HDsetsid */
+#ifndef HDsetsockopt
+ #define HDsetsockopt(A,B,C,D,E) setsockopt((A),(B),(C),(D),(E)) /* mirror VFD */
+#endif /* HDsetsockopt */
#ifndef HDsetuid
#define HDsetuid(U) setuid(U)
#endif /* HDsetuid */
#ifndef HDsetvbuf
#define HDsetvbuf(F,S,M,Z) setvbuf(F,S,M,Z)
#endif /* HDsetvbuf */
+#ifndef HDshutdown
+ #define HDshutdown(A, B) shutdown((A),(B)) /* mirror VFD */
+#endif /* HDshutdown */
+#ifndef HDsigaction
+ #define HDsigaction(S,A,O) sigaction((S),(A),(O))
+#endif /* HDsigaction */
#ifndef HDsigaddset
#define HDsigaddset(S,N) sigaddset(S,N)
#endif /* HDsigaddset */
@@ -1347,6 +1405,9 @@ typedef off_t h5_stat_size_t;
#ifndef HDsnprintf
#define HDsnprintf snprintf /*varargs*/
#endif /* HDsnprintf */
+#ifndef HDsocket
+ #define HDsocket(A,B,C) socket((A),(B),(C)) /* mirror VFD */
+#endif /* HDsocket */
#ifndef HDsprintf
#define HDsprintf sprintf /*varargs*/
#endif /* HDsprintf */
diff --git a/src/Makefile.am b/src/Makefile.am
index 0c07c1b..787b502 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -62,7 +62,8 @@ libhdf5_la_SOURCES= H5.c H5checksum.c H5dbg.c H5lib_settings.c H5system.c \
H5FA.c H5FAcache.c H5FAdbg.c H5FAdblock.c H5FAdblkpage.c H5FAhdr.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 H5FDstdio.c H5FDtest.c \
+ H5FDmulti.c H5FDsec2.c H5FDspace.c \
+ H5FDsplitter.c H5FDstdio.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 \
@@ -125,6 +126,11 @@ if DIRECT_VFD_CONDITIONAL
libhdf5_la_SOURCES += H5FDdirect.c
endif
+# Only compile the mirror VFD if necessary
+if MIRROR_VFD_CONDITIONAL
+ libhdf5_la_SOURCES += H5FDmirror.c
+endif
+
# Only compile the read-only S3 VFD if necessary
if ROS3_VFD_CONDITIONAL
libhdf5_la_SOURCES += H5FDros3.c H5FDs3comms.c
@@ -135,9 +141,9 @@ include_HEADERS = hdf5.h H5api_adpt.h H5overflow.h H5pubconf.h H5public.h H5vers
H5Apublic.h H5ACpublic.h \
H5Cpublic.h H5Dpublic.h \
H5Epubgen.h H5Epublic.h H5ESpublic.h H5Fpublic.h \
- H5FDpublic.h H5FDcore.h H5FDdirect.h \
- H5FDfamily.h H5FDhdfs.h H5FDlog.h H5FDmpi.h H5FDmpio.h \
- H5FDmulti.h H5FDros3.h H5FDsec2.h H5FDstdio.h H5FDwindows.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 \
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 8367122..eaaf8ae 100644
--- a/src/hdf5.h
+++ b/src/hdf5.h
@@ -46,10 +46,12 @@
#include "H5FDfamily.h" /* File families */
#include "H5FDhdfs.h" /* Hadoop HDFS */
#include "H5FDlog.h" /* sec2 driver with I/O logging (for debugging) */
+#include "H5FDmirror.h" /* Mirror VFD and IPC definitions */
#include "H5FDmpi.h" /* MPI-based file drivers */
#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 "H5FDsplitter.h" /* Twin-channel (R/W & R/O) I/O passthrough */
#include "H5FDstdio.h" /* Standard C buffered I/O */
#ifdef H5_HAVE_WINDOWS
#include "H5FDwindows.h" /* Win32 I/O */
diff --git a/src/libhdf5.settings.in b/src/libhdf5.settings.in
index 0c2be75..192fc6f 100644
--- a/src/libhdf5.settings.in
+++ b/src/libhdf5.settings.in
@@ -80,6 +80,7 @@ Parallel Filtered Dataset Writes: @PARALLEL_FILTERED_WRITES@
MPE: @MPE@
Map (H5M) API: @MAP_API@
Direct VFD: @DIRECT_VFD@
+ Mirror VFD: @MIRROR_VFD@
(Read-Only) S3 VFD: @ROS3_VFD@
(Read-Only) HDFS VFD: @HAVE_LIBHDFS@
dmalloc: @HAVE_DMALLOC@
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 7a0b2dd..e3bfeb3 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -211,6 +211,11 @@ set (cache_image_SOURCES
${HDF5_TEST_SOURCE_DIR}/genall5.c
)
+set(mirror_vfd_SOURCES
+ ${HDF5_TEST_SOURCE_DIR}/mirror_vfd.c
+ ${HDF5_TEST_SOURCE_DIR}/genall5.c
+)
+
set (ttsafe_SOURCES
${HDF5_TEST_SOURCE_DIR}/ttsafe.c
${HDF5_TEST_SOURCE_DIR}/ttsafe_dcreate.c
@@ -273,6 +278,7 @@ set (H5_TESTS
ros3
s3comms
hdfs
+ mirror_vfd
ntypes
dangle
dtransform
@@ -312,6 +318,7 @@ set (H5_TESTS_MULTIPLE
cache_image
ttsafe
thread_id # special link
+ mirror_vfd
)
# Only build single source tests here
foreach (h5_test ${H5_TESTS})
@@ -415,6 +422,18 @@ else ()
endif ()
set_target_properties (thread_id PROPERTIES FOLDER test)
+#-- Adding test for mirror_vfd
+add_executable (mirror_vfd ${mirror_vfd_SOURCES})
+target_include_directories (mirror_vfd PRIVATE "${HDF5_SRC_DIR};${HDF5_BINARY_DIR};$<$<BOOL:${HDF5_ENABLE_PARALLEL}>:${MPI_C_INCLUDE_DIRS}>")
+if (NOT BUILD_SHARED_LIBS)
+ TARGET_C_PROPERTIES (mirror_vfd STATIC)
+ target_link_libraries (mirror_vfd PRIVATE ${HDF5_TEST_LIB_TARGET})
+else ()
+ TARGET_C_PROPERTIES (mirror_vfd SHARED)
+ target_link_libraries (mirror_vfd PRIVATE ${HDF5_TEST_LIBSH_TARGET})
+endif ()
+set_target_properties (mirror_vfd PROPERTIES FOLDER test)
+
##############################################################################
### A D D I T I O N A L T E S T S ###
##############################################################################
diff --git a/test/CMakeTests.cmake b/test/CMakeTests.cmake
index b7eaa56..c73aeda 100644
--- a/test/CMakeTests.cmake
+++ b/test/CMakeTests.cmake
@@ -446,6 +446,10 @@ set (test_CLEANFILES
vds_swmr_src_*.h5
tmp_vds_env/vds_src_2.h5
direct_chunk.h5
+ splitter*.h5
+ splitter.log
+ mirror_rw/*
+ mirror_wo/*
native_vol_test.h5
)
diff --git a/test/Makefile.am b/test/Makefile.am
index dd0a579..6bea16a 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -33,9 +33,11 @@ AM_CPPFLAGS+=-I$(top_srcdir)/src -I$(top_builddir)/src
# testvdsswmr.sh: vds_swmr*
# testabort_fail.sh: filenotclosed.c and del_many_dense_attrs.c
# test_filter_plugin.sh: filter_plugin.c
+# test_mirror.sh: mirror_vfd ../utils/mirror_vfd/*
# test_usecases.sh: use_append_chunk, use_append_mchunks, use_disable_mdc_flushes
TEST_SCRIPT = testerror.sh testlibinfo.sh testcheck_version.sh testlinks_env.sh testexternal_env.sh \
- testswmr.sh testvds_env.sh testvdsswmr.sh testflushrefresh.sh test_usecases.sh testabort_fail.sh
+ testswmr.sh testvds_env.sh testvdsswmr.sh testflushrefresh.sh test_usecases.sh testabort_fail.sh \
+ test_mirror.sh
SCRIPT_DEPEND = error_test$(EXEEXT) err_compat$(EXEEXT) links_env$(EXEEXT) \
external_env$(EXEEXT) filenotclosed$(EXEEXT) del_many_dense_attrs$(EXEEXT) \
flushrefresh$(EXEEXT) use_append_chunk$(EXEEXT) use_append_mchunks$(EXEEXT) use_disable_mdc_flushes$(EXEEXT) \
@@ -78,16 +80,18 @@ TEST_PROG= testhdf5 \
# swmr_* files (besides swmr.c) are used by testswmr.sh.
# vds_swmr_* files are used by testvdsswmr.sh
# vds_env is used by testvds_env.sh
+# mirror_vfd is used by test_mirror.sh
# 'make check' doesn't run them directly, so they are not included in TEST_PROG.
# Also build testmeta, which is used for timings test. It builds quickly,
# and this lets automake keep all its test programs in one place.
check_PROGRAMS=$(TEST_PROG) error_test err_compat tcheck_version \
testmeta accum_swmr_reader atomic_writer atomic_reader external_env \
links_env filenotclosed del_many_dense_attrs flushrefresh \
- use_append_chunk use_append_mchunks use_disable_mdc_flushes \
+ use_append_chunk use_append_chunk_mirror use_append_mchunks use_disable_mdc_flushes \
swmr_generator swmr_start_write swmr_reader swmr_writer swmr_remove_reader \
swmr_remove_writer swmr_addrem_writer swmr_sparse_reader swmr_sparse_writer \
- swmr_check_compat_vfd vds_env vds_swmr_gen vds_swmr_reader vds_swmr_writer
+ swmr_check_compat_vfd vds_env vds_swmr_gen vds_swmr_reader vds_swmr_writer \
+ mirror_vfd
if HAVE_SHARED_CONDITIONAL
check_PROGRAMS+= filter_plugin vol_plugin
endif
@@ -144,6 +148,7 @@ LDADD=libh5test.la $(LIBHDF5)
ttsafe_SOURCES=ttsafe.c ttsafe_dcreate.c ttsafe_error.c ttsafe_cancel.c \
ttsafe_acreate.c
cache_image_SOURCES=cache_image.c genall5.c
+mirror_vfd_SOURCES=mirror_vfd.c genall5.c
VFD_LIST = sec2 stdio core core_paged split multi family
if DIRECT_VFD_CONDITIONAL
@@ -213,7 +218,8 @@ CHECK_CLEANFILES+=accum.h5 cmpd_dset.h5 compact_dataset.h5 dataset.h5 dset_offse
flushrefresh_VERIFICATION_DONE atomic_data accum_swmr_big.h5 ohdr_swmr.h5 \
test_swmr*.h5 cache_logging.h5 cache_logging.out vds_swmr.h5 vds_swmr_src_*.h5 \
swmr[0-2].h5 swmr_writer.out swmr_writer.log.* swmr_reader.out.* swmr_reader.log.* \
- tbogus.h5.copy cache_image_test.h5 direct_chunk.h5 native_vol_test.h5
+ tbogus.h5.copy cache_image_test.h5 direct_chunk.h5 native_vol_test.h5 \
+ splitter*.h5 splitter.log
# Sources for testhdf5 executable
testhdf5_SOURCES=testhdf5.c tarray.c tattr.c tchecksum.c tconfig.c tfile.c \
@@ -223,12 +229,13 @@ testhdf5_SOURCES=testhdf5.c tarray.c tattr.c tchecksum.c tconfig.c tfile.c \
# Sources for Use Cases
use_append_chunk_SOURCES=use_append_chunk.c use_common.c
+use_append_chunk_mirror_SOURCES=use_append_chunk_mirror.c use_common.c
use_append_mchunks_SOURCES=use_append_mchunks.c use_common.c
use_disable_mdc_flushes_SOURCES=use_disable_mdc_flushes.c
# Temporary files.
DISTCLEANFILES=testerror.sh testlibinfo.sh testcheck_version.sh testlinks_env.sh test_filter_plugin.sh \
- testexternal_env.sh testswmr.sh testvds_env.sh testvdsswmr.sh test_usecases.sh testflushrefresh.sh testabort_fail.sh \
- test_vol_plugin.sh
+ testexternal_env.sh testswmr.sh testvds_env.sh testvdsswmr.sh test_usecases.sh testflushrefresh.sh \
+ testabort_fail.sh test_vol_plugin.sh test_mirror.sh
include $(top_srcdir)/config/conclude.am
diff --git a/test/h5test.c b/test/h5test.c
index 03731c6..e7d91b6 100644
--- a/test/h5test.c
+++ b/test/h5test.c
@@ -2043,6 +2043,80 @@ h5_get_version_string(H5F_libver_t libver)
} /* end of h5_get_version_string */
/*-------------------------------------------------------------------------
+ * Function: h5_compare_file_bytes()
+ *
+ * Purpose: Helper function to compare two files byte-for-byte.
+ *
+ * Return: Success: 0, if files are identical
+ * Failure: -1, if files differ
+ *
+ * Programmer: Binh-Minh Ribler
+ * October, 2018
+ *-------------------------------------------------------------------------
+ */
+int
+h5_compare_file_bytes(char *f1name, char *f2name)
+{
+ FILE *f1ptr = NULL; /* two file pointers */
+ FILE *f2ptr = NULL;
+ hsize_t f1size = 0; /* size of the files */
+ hsize_t f2size = 0;
+ char f1char = 0; /* one char from each file */
+ char f2char = 0;
+ hsize_t ii = 0;
+ int ret_value = 0; /* for error handling */
+
+ /* Open files for reading */
+ f1ptr = fopen(f1name, "r");
+ if (f1ptr == NULL) {
+ HDfprintf(stderr, "Unable to fopen() %s\n", f1name);
+ ret_value = -1;
+ goto done;
+ }
+ f2ptr = fopen(f2name, "r");
+ if (f2ptr == NULL) {
+ HDfprintf(stderr, "Unable to fopen() %s\n", f2name);
+ ret_value = -1;
+ goto done;
+ }
+
+ /* Get the file sizes and verify that they equal */
+ fseek(f1ptr , 0 , SEEK_END);
+ f1size = ftell(f1ptr);
+
+ fseek(f2ptr , 0 , SEEK_END);
+ f2size = ftell(f2ptr);
+
+ if (f1size != f2size) {
+ HDfprintf(stderr, "Files differ in size, %llu vs. %llu\n", f1size, f2size);
+ ret_value = -1;
+ goto done;
+ }
+
+ /* Compare each byte and fail if a difference is found */
+ rewind(f1ptr);
+ rewind(f2ptr);
+ for (ii = 0; ii < f1size; ii++) {
+ fread(&f1char, 1, 1, f1ptr);
+ fread(&f2char, 1, 1, f2ptr);
+ if (f1char != f2char) {
+ HDfprintf(stderr, "Mismatch @ 0x%llX: 0x%X != 0x%X\n", ii, f1char, f2char);
+ ret_value = -1;
+ goto done;
+ }
+ }
+
+done:
+ if (f1ptr) {
+ fclose(f1ptr);
+ }
+ if (f2ptr) {
+ fclose(f2ptr);
+ }
+ return(ret_value);
+} /* end h5_compare_file_bytes() */
+
+/*-------------------------------------------------------------------------
* Function: H5_get_srcdir_filename
*
* Purpose: Append the test file name to the srcdir path and return the whole string
@@ -2094,3 +2168,4 @@ const char *H5_get_srcdir(void)
else
return(NULL);
} /* end H5_get_srcdir() */
+
diff --git a/test/h5test.h b/test/h5test.h
index e67e559..39ec9d7 100644
--- a/test/h5test.h
+++ b/test/h5test.h
@@ -150,6 +150,7 @@ H5TEST_DLL herr_t h5_verify_cached_stabs(const char *base_name[], hid_t fapl);
H5TEST_DLL H5FD_class_t *h5_get_dummy_vfd_class(void);
H5TEST_DLL H5VL_class_t *h5_get_dummy_vol_class(void);
H5TEST_DLL const char *h5_get_version_string(H5F_libver_t libver);
+H5TEST_DLL int h5_compare_file_bytes(char *fname1, char *fname2);
/* Functions that will replace components of a FAPL */
H5TEST_DLL herr_t h5_get_vfd_fapl(hid_t fapl_id);
diff --git a/test/mirror_vfd.c b/test/mirror_vfd.c
new file mode 100644
index 0000000..112d67a
--- /dev/null
+++ b/test/mirror_vfd.c
@@ -0,0 +1,2761 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * 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. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Purpose: Test the Mirror VFD functionality.
+ */
+
+/* WARNING: The use of realpath() is probably system-dependent, as are
+ * other things here such as the socket calls.
+ * Notable to realpath() in particular is the use of "PATH_MAX", which
+ * apparently has some major potential issues if paths are abused.
+ * http://insanecoding.blogspot.com/2007/11/pathmax-simply-isnt.html
+ * so BE CAREFUL about the paths we throw around?
+ */
+
+#include "h5test.h"
+#include "cache_common.h"
+#include "genall5.h"
+
+#ifdef H5_HAVE_MIRROR_VFD
+
+/* For future consideration, IP address and port number might be
+ * environment variables?
+ */
+#define SERVER_IP_ADDRESS "127.0.0.1"
+
+/* Primary listening port on server. */
+#define SERVER_HANDSHAKE_PORT 3000
+
+#define DATABUFFER_SIZE 128
+#define DSET_NAME_LEN 16
+
+/* Parameters for the "large chunked dataset" writing */
+#define MAX_DSET_COUNT 255
+#define DSET_DIM 32
+#define CHUNK_DIM 8
+
+#define CONCURRENT_COUNT 3 /* Number of files in concurrent test */
+
+/* Macro: LOGPRINT()
+ * Prints logging and debugging messages to the output stream based
+ * on the level of verbosity.
+ * 0 : no logging
+ * 1 : errors only
+ * 2 : details
+ * 3 : all
+ */
+#define DEFAULT_VERBOSITY 1
+static unsigned int g_verbosity = DEFAULT_VERBOSITY;
+
+/* Macro for selective debug printing / logging */
+#define LOGPRINT(lvl, ...) \
+do { \
+ if ((lvl) <= g_verbosity) { \
+ fprintf(g_log_stream, __VA_ARGS__); \
+ fflush(g_log_stream); \
+ } \
+} while (0)
+
+#define MIRROR_RW_DIR "mirror_rw/"
+#define MIRROR_WO_DIR "mirror_wo/"
+
+/* String buffer for error messages */
+#define MIRR_MESG_SIZE 128
+static char mesg[MIRR_MESG_SIZE + 1];
+
+/* Convenience structure for passing file names via helper functions.
+ */
+struct mirrortest_filenames {
+ char rw[H5FD_SPLITTER_PATH_MAX+1];
+ char wo[H5FD_SPLITTER_PATH_MAX+1];
+ char log[H5FD_SPLITTER_PATH_MAX+1];
+};
+
+static FILE *g_log_stream = NULL; /* initialized at runtime */
+
+static herr_t _verify_datasets(unsigned min_dset, unsigned max_dset,
+ hid_t *filespace_id, hid_t *dataset_id, hid_t memspace_id);
+
+static herr_t _create_chunking_ids(hid_t file_id, unsigned min_dset,
+ unsigned max_dset, hsize_t *chunk_dims, hsize_t *dset_dims,
+ hid_t *dataspace_ids, hid_t *filespace_ids, hid_t *dataset_ids,
+ hid_t *memspace_id);
+
+static herr_t _close_chunking_ids(unsigned min_dset, unsigned max_dset,
+ hid_t *dataspace_ids, hid_t *filespace_ids, hid_t *dataset_ids,
+ hid_t *memspace_id);
+
+static herr_t _populate_filepath(const char *dirname, const char *_basename,
+ hid_t fapl_id, char *path_out, hbool_t h5suffix);
+
+static hid_t create_mirroring_split_fapl(const char *_basename,
+ struct mirrortest_filenames *names);
+
+static void mybzero(void *dest, size_t size);
+
+
+/* ----------------------------------------------------------------------------
+ * Function: mybzero
+ *
+ * Purpose: Have bzero simplicity and abstraction in (possible) absence of
+ * it being available.
+ *
+ * Programmer: Jacob Smith
+ * 2020-03-30
+ * ----------------------------------------------------------------------------
+ */
+static void
+mybzero(void *dest, size_t size)
+{
+ size_t i = 0;
+ char *s = NULL;
+ HDassert(dest != NULL);
+ s = (char *)dest;
+ for (i = 0; i < size; i++) {
+ *(s+i) = 0;
+ }
+} /* end mybzero() */
+
+
+/* ----------------------------------------------------------------------------
+ * Function: _populate_filepath
+ *
+ * Purpose: Given a directory name and a base name, concatenate the two and
+ * run h5fixname() to get the "actual" path to the intented target.
+ * `h5suffix' should be FALSE to keep the base name unaltered;
+ * TRUE will append the '.h5' h5suffix to the basename...
+ * FALSE -> h5fixname_no_suffix(), TRUE -> h5fixname()
+ * <h5fixname_prefix> / <dirname> / <_basename> <h5prefix?>
+ *
+ * Programmer: Jacob Smith
+ * 2019-08-16
+ * ----------------------------------------------------------------------------
+ */
+static herr_t
+_populate_filepath(const char *dirname, const char *_basename, hid_t fapl_id,
+ char *path_out, hbool_t h5suffix)
+{
+ char _path[H5FD_SPLITTER_PATH_MAX];
+
+ if ((_basename == NULL) ||
+ (*_basename == 0) ||
+ (dirname == NULL) ||
+ (*dirname == 0) ||
+ (path_out == NULL))
+ {
+ TEST_ERROR;
+ }
+
+ if (HDsnprintf(_path, H5FD_SPLITTER_PATH_MAX, "%s%s%s", dirname,
+ (dirname[strlen(dirname)] == '/') ? "" : "/", /* slash iff needed */
+ _basename)
+ > H5FD_SPLITTER_PATH_MAX)
+ {
+ TEST_ERROR;
+ }
+
+ if (h5suffix == TRUE) {
+ if (h5_fixname(_path, fapl_id, path_out,
+ H5FD_SPLITTER_PATH_MAX)
+ == NULL)
+ {
+ TEST_ERROR;
+ }
+ }
+ else {
+ if (h5_fixname_no_suffix(_path, fapl_id, path_out,
+ H5FD_SPLITTER_PATH_MAX)
+ == NULL)
+ {
+ TEST_ERROR;
+ }
+ }
+
+ return SUCCEED;
+
+error:
+ return FAIL;
+} /* end _populate_filepath() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: build_paths
+ *
+ * Purpose: Convenience function to create the three file paths used in
+ * most mirror tests.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Jacob Smith
+ * 2019-08-16
+ * ---------------------------------------------------------------------------
+ */
+static herr_t
+build_paths(
+ const char *_basename,
+ H5FD_splitter_vfd_config_t *splitter_config,
+ struct mirrortest_filenames *names)
+{
+ char baselogname[H5FD_SPLITTER_PATH_MAX];
+
+ if (_populate_filepath(MIRROR_RW_DIR, _basename,
+ splitter_config->rw_fapl_id, names->rw, TRUE)
+ == FAIL)
+ {
+ TEST_ERROR;
+ }
+
+ if (_populate_filepath(MIRROR_WO_DIR, _basename,
+ splitter_config->wo_fapl_id, names->wo, TRUE)
+ == FAIL)
+ {
+ TEST_ERROR;
+ }
+
+ if (_basename == NULL || *_basename == 0)
+ return FAIL;
+ if (HDsnprintf(baselogname, H5FD_SPLITTER_PATH_MAX, "%s_err.log",
+ _basename)
+ > H5FD_SPLITTER_PATH_MAX)
+ {
+ TEST_ERROR;
+ }
+
+ if (_populate_filepath(MIRROR_WO_DIR, baselogname,
+ splitter_config->wo_fapl_id, names->log, FALSE)
+ == FAIL)
+ {
+ TEST_ERROR;
+ }
+
+ return SUCCEED;
+
+error:
+ return FAIL;
+} /* end build_paths() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: test_fapl_configuration
+ *
+ * Purpose: Test FAPL configuration and examination.
+ *
+ * Return: Success: 0
+ * Failure: -1
+ *
+ * Programmer: Jacob Smith
+ * 2019-03-12
+ * ---------------------------------------------------------------------------
+ */
+static int
+test_fapl_configuration(void)
+{
+ hid_t fapl_id;
+ H5FD_mirror_fapl_t mirror_conf = {
+ H5FD_MIRROR_FAPL_MAGIC, /* magic */
+ H5FD_MIRROR_CURR_FAPL_T_VERSION, /* version */
+ SERVER_HANDSHAKE_PORT, /* handhake_port */
+ SERVER_IP_ADDRESS, /* remote_ip "IP address" */
+ };
+ H5FD_mirror_fapl_t fa_out = {0, 0, 0, ""};
+
+ TESTING("Mirror fapl configuration (set/get)");
+
+ fapl_id = H5Pcreate(H5P_FILE_ACCESS);
+ if (H5I_INVALID_HID == fapl_id) {
+ TEST_ERROR;
+ }
+
+ if (H5Pset_fapl_mirror(fapl_id, &mirror_conf) == FAIL) {
+ TEST_ERROR;
+ }
+
+ if (H5Pget_fapl_mirror(fapl_id, &fa_out) == FAIL) {
+ TEST_ERROR;
+ }
+ if (H5FD_MIRROR_FAPL_MAGIC != fa_out.magic) {
+ TEST_ERROR;
+ }
+ if (H5FD_MIRROR_CURR_FAPL_T_VERSION != fa_out.version) {
+ TEST_ERROR;
+ }
+ if (SERVER_HANDSHAKE_PORT != fa_out.handshake_port) {
+ TEST_ERROR;
+ }
+ if (HDstrncmp(SERVER_IP_ADDRESS, (const char *)fa_out.remote_ip,
+ H5FD_MIRROR_MAX_IP_LEN))
+ {
+ TEST_ERROR;
+ }
+
+ if (H5Pclose(fapl_id) == FAIL) {
+ TEST_ERROR;
+ }
+
+ PASSED();
+ return 0;
+
+error:
+ if (H5I_INVALID_HID != fapl_id) {
+ (void)H5Pclose(fapl_id);
+ }
+ return -1;
+} /* end test_fapl_configuration() */
+
+
+
+#define PRINT_BUFFER_DIFF(act, exp, len) do { \
+ size_t _x = 0; \
+ while ((act)[_x] == (exp)[_x]) { \
+ _x++; \
+ } \
+ if (_x != (len)) { \
+ size_t _y = 0; \
+ HDprintf("First bytes differ at %zu\n", _x); \
+ HDprintf("exp "); \
+ for (_y = _x; _y < (len); _y++) { \
+ HDprintf("%02X", (unsigned char)(exp)[_y]); \
+ } \
+ HDprintf("\nact "); \
+ for (_y = _x; _y < (len); _y++) { \
+ HDprintf("%02X", (unsigned char)(act)[_y]); \
+ } \
+ HDprintf("\n"); \
+ } \
+} while (0); /* end PRINT_BUFFER_DIFF */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: test_xmit_encode_decode
+ *
+ * Purpose: Test byte-encoding operations for network transport.
+ *
+ * Return: Success: 0
+ * Failure: -1
+ *
+ * Programmer: Jacob Smith
+ * 2020-02-02
+ * ---------------------------------------------------------------------------
+ */
+static int
+test_xmit_encode_decode(void)
+{
+ H5FD_mirror_xmit_t xmit_mock; /* re-used header in various xmit tests */
+
+ TESTING("Mirror encode/decode of xmit elements");
+
+ /* Set bogus values matching expected; encoding doesn't care
+ * Use sequential values to easily generate the expected buffer with a
+ * for loop.
+ */
+ xmit_mock.magic = 0x00010203;
+ xmit_mock.version = 0x04;
+ xmit_mock.session_token = 0x05060708;
+ xmit_mock.xmit_count = 0x090A0B0C;
+ xmit_mock.op = 0x0D;
+
+ /* Test uint8_t encode/decode
+ */
+ do {
+ unsigned char buf[8];
+ unsigned char expected[8];
+ const uint8_t v = 200;
+ unsigned char out = 0;
+
+ /* Start of buffer uint8_t
+ */
+ mybzero(buf, 8);
+ mybzero(expected, 8);
+ expected[0] = 200;
+ out = 0;
+ if (H5FD__mirror_xmit_encode_uint8(buf, v) != 1) {
+ TEST_ERROR;
+ }
+ if (HDmemcmp(buf, expected, 8) != 0) {
+ PRINT_BUFFER_DIFF(buf, expected, 8);
+ TEST_ERROR;
+ }
+ if (H5FD__mirror_xmit_decode_uint8(&out, buf) != 1) {
+ TEST_ERROR;
+ }
+ if (v != out) {
+ TEST_ERROR;
+ }
+
+ /* Middle of buffer uint8_t
+ */
+ mybzero(buf, 8);
+ mybzero(expected, 8);
+ expected[3] = v;
+ out = 0;
+ if (H5FD__mirror_xmit_encode_uint8((buf+3), v) != 1) {
+ TEST_ERROR;
+ }
+ if (HDmemcmp(buf, expected, 8) != 0) {
+ PRINT_BUFFER_DIFF(buf, expected, 8);
+ TEST_ERROR;
+ }
+ if (H5FD__mirror_xmit_decode_uint8(&out, (buf+3)) != 1) {
+ TEST_ERROR;
+ }
+ if (v != out) {
+ TEST_ERROR;
+ }
+
+ /* End of buffer uint8_t
+ */
+ mybzero(buf, 8);
+ mybzero(expected, 8);
+ expected[7] = v;
+ out = 0;
+ if (H5FD__mirror_xmit_encode_uint8((buf+7), v) != 1) {
+ TEST_ERROR;
+ }
+ if (HDmemcmp(buf, expected, 8) != 0) {
+ PRINT_BUFFER_DIFF(buf, expected, 8);
+ TEST_ERROR;
+ }
+ if (H5FD__mirror_xmit_decode_uint8(&out, (buf+7)) != 1) {
+ TEST_ERROR;
+ }
+ if (v != out) {
+ TEST_ERROR;
+ }
+
+ } while (0); /* end uint8_t en/decode */
+
+ /* Test uint16_t encode/decode
+ */
+ do {
+ unsigned char buf[8];
+ unsigned char expected[8];
+ const uint16_t v = 0x8F02;
+ uint16_t out = 0;
+
+ /* Start of buffer uint16_t
+ */
+ mybzero(buf, 8);
+ mybzero(expected, 8);
+ expected[0] = 0x8F;
+ expected[1] = 0x02;
+ out = 0;
+ if (H5FD__mirror_xmit_encode_uint16(buf, v) != 2) {
+ TEST_ERROR;
+ }
+ if (HDmemcmp(buf, expected, 8) != 0) {
+ PRINT_BUFFER_DIFF(buf, expected, 8);
+ TEST_ERROR;
+ }
+ if (H5FD__mirror_xmit_decode_uint16(&out, buf) != 2) {
+ TEST_ERROR;
+ }
+ if (out != v) {
+ TEST_ERROR;
+ }
+
+ /* Middle of buffer uint16_t
+ */
+ mybzero(buf, 8);
+ mybzero(expected, 8);
+ expected[3] = 0x8F;
+ expected[4] = 0x02;
+ out = 0;
+ if (H5FD__mirror_xmit_encode_uint16((buf+3), v) != 2) {
+ TEST_ERROR;
+ }
+ if (HDmemcmp(buf, expected, 8) != 0) {
+ PRINT_BUFFER_DIFF(buf, expected, 8);
+ TEST_ERROR;
+ }
+ if (H5FD__mirror_xmit_decode_uint16(&out, (buf+3)) != 2) {
+ TEST_ERROR;
+ }
+ if (out != v) {
+ TEST_ERROR;
+ }
+ /* slice */
+ if (H5FD__mirror_xmit_decode_uint16(&out, (buf+4)) != 2) {
+ TEST_ERROR;
+ }
+ if (out != 0x0200) {
+ TEST_ERROR;
+ }
+
+ /* End of buffer uint16_t
+ */
+ mybzero(buf, 8);
+ mybzero(expected, 8);
+ expected[6] = 0x8F;
+ expected[7] = 0x02;
+ out = 0;
+ if (H5FD__mirror_xmit_encode_uint16((buf+6), v) != 2) {
+ TEST_ERROR;
+ }
+ if (HDmemcmp(buf, expected, 8) != 0) {
+ PRINT_BUFFER_DIFF(buf, expected, 8);
+ TEST_ERROR;
+ }
+ if (H5FD__mirror_xmit_decode_uint16(&out, (buf+6)) != 2) {
+ TEST_ERROR;
+ }
+ if (out != v) {
+ TEST_ERROR;
+ }
+
+ } while (0); /* end uint16_t en/decode */
+
+ /* Test uint32_t encode/decode
+ */
+ do {
+ unsigned char buf[8];
+ unsigned char expected[8];
+ const uint32_t v = 0x8F020048;
+ uint32_t out = 0;
+
+ /* Start of buffer uint32_t
+ */
+ mybzero(buf, 8);
+ mybzero(expected, 8);
+ expected[0] = 0x8F;
+ expected[1] = 0x02;
+ expected[2] = 0x00;
+ expected[3] = 0x48;
+ out = 0;
+ if (H5FD__mirror_xmit_encode_uint32(buf, v) != 4) {
+ TEST_ERROR;
+ }
+ if (HDmemcmp(buf, expected, 8) != 0) {
+ PRINT_BUFFER_DIFF(buf, expected, 8);
+ TEST_ERROR;
+ }
+ if (H5FD__mirror_xmit_decode_uint32(&out, buf) != 4) {
+ TEST_ERROR;
+ }
+ if (out != v) {
+ TEST_ERROR;
+ }
+
+ /* Middle of buffer uint32_t
+ */
+ mybzero(buf, 8);
+ mybzero(expected, 8);
+ expected[3] = 0x8F;
+ expected[4] = 0x02;
+ expected[5] = 0x00;
+ expected[6] = 0x48;
+ out = 0;
+ if (H5FD__mirror_xmit_encode_uint32((buf+3), v) != 4) {
+ TEST_ERROR;
+ }
+ if (HDmemcmp(buf, expected, 8) != 0) {
+ PRINT_BUFFER_DIFF(buf, expected, 8);
+ TEST_ERROR;
+ }
+ if (H5FD__mirror_xmit_decode_uint32(&out, (buf+3)) != 4) {
+ TEST_ERROR;
+ }
+ if (out != v) {
+ TEST_ERROR;
+ }
+ /* slice */
+ if (H5FD__mirror_xmit_decode_uint32(&out, (buf+4)) != 4) {
+ TEST_ERROR;
+ }
+ if (out != 0x02004800) {
+ TEST_ERROR;
+ }
+
+ /* End of buffer uint32_t
+ */
+ mybzero(buf, 8);
+ mybzero(expected, 8);
+ expected[4] = 0x8F;
+ expected[5] = 0x02;
+ expected[6] = 0x00;
+ expected[7] = 0x48;
+ out = 0;
+ if (H5FD__mirror_xmit_encode_uint32((buf+4), v) != 4) {
+ TEST_ERROR;
+ }
+ if (HDmemcmp(buf, expected, 8) != 0) {
+ PRINT_BUFFER_DIFF(buf, expected, 8);
+ TEST_ERROR;
+ }
+ if (H5FD__mirror_xmit_decode_uint32(&out, (buf+4)) != 4) {
+ TEST_ERROR;
+ }
+ if (out != v) {
+ TEST_ERROR;
+ }
+
+ } while (0); /* end uint32_t en/decode */
+
+ /* Test uint64_t encode/decode
+ */
+ do {
+ unsigned char buf[16];
+ unsigned char expected[16];
+ const uint64_t v = 0x90DCBE17939CE4BB;
+ uint64_t out = 0;
+
+ /* Start of buffer uint64_t
+ */
+ mybzero(buf, 16);
+ mybzero(expected, 16);
+ expected[0] = 0x90;
+ expected[1] = 0xDC;
+ expected[2] = 0xBE;
+ expected[3] = 0x17;
+ expected[4] = 0x93;
+ expected[5] = 0x9C;
+ expected[6] = 0xE4;
+ expected[7] = 0xBB;
+ out = 0;
+ if (H5FD__mirror_xmit_encode_uint64(buf, v) != 8) {
+ TEST_ERROR;
+ }
+ if (HDmemcmp(buf, expected, 16) != 0) {
+ PRINT_BUFFER_DIFF(buf, expected, 16);
+ TEST_ERROR;
+ }
+ if (H5FD__mirror_xmit_decode_uint64(&out, buf) != 8) {
+ TEST_ERROR;
+ }
+ if (out != v) {
+ TEST_ERROR;
+ }
+
+ /* Middle of buffer uint64_t
+ */
+ mybzero(buf, 16);
+ mybzero(expected, 16);
+ expected[3] = 0x90;
+ expected[4] = 0xDC;
+ expected[5] = 0xBE;
+ expected[6] = 0x17;
+ expected[7] = 0x93;
+ expected[8] = 0x9C;
+ expected[9] = 0xE4;
+ expected[10] = 0xBB;
+ out = 0;
+ if (H5FD__mirror_xmit_encode_uint64((buf+3), v) != 8) {
+ TEST_ERROR;
+ }
+ if (HDmemcmp(buf, expected, 16) != 0) {
+ PRINT_BUFFER_DIFF(buf, expected, 16);
+ TEST_ERROR;
+ }
+ if (H5FD__mirror_xmit_decode_uint64(&out, (buf+3)) != 8) {
+ TEST_ERROR;
+ }
+ if (out != v) {
+ TEST_ERROR;
+ }
+ /* slice */
+ if (H5FD__mirror_xmit_decode_uint64(&out, (buf+6)) != 8) {
+ TEST_ERROR;
+ }
+ if (out != 0x17939CE4BB000000) {
+ TEST_ERROR;
+ }
+
+ /* End of buffer uint64_t
+ */
+ mybzero(buf, 16);
+ mybzero(expected, 16);
+ expected[8] = 0x90;
+ expected[9] = 0xDC;
+ expected[10] = 0xBE;
+ expected[11] = 0x17;
+ expected[12] = 0x93;
+ expected[13] = 0x9C;
+ expected[14] = 0xE4;
+ expected[15] = 0xBB;
+ out = 0;
+ if (H5FD__mirror_xmit_encode_uint64((buf+8), v) != 8) {
+ TEST_ERROR;
+ }
+ if (HDmemcmp(buf, expected, 16) != 0) {
+ PRINT_BUFFER_DIFF(buf, expected, 16);
+ TEST_ERROR;
+ }
+ if (H5FD__mirror_xmit_decode_uint64(&out, (buf+8)) != 8) {
+ TEST_ERROR;
+ }
+ if (out != v) {
+ TEST_ERROR;
+ }
+
+ } while (0); /* end uint64_t en/decode */
+
+ /* Test xmit header structure encode/decode
+ * Write bogus but easily verifiable data to inside a buffer, and compare.
+ * Then decode the buffer and compare the structure contents.
+ * Then repeat from a different offset in the buffer and compare.
+ */
+ do {
+ unsigned char buf[H5FD_MIRROR_XMIT_HEADER_SIZE+8];
+ unsigned char expected[H5FD_MIRROR_XMIT_HEADER_SIZE+8];
+ H5FD_mirror_xmit_t xmit_out;
+ size_t i = 0;
+
+ /* sanity check */
+ if (14 != H5FD_MIRROR_XMIT_HEADER_SIZE) {
+ FAIL_PUTS_ERROR("Header size definition does not match test\n");
+ }
+
+ /* Populate the expected buffer; expect end padding of 0xFF
+ */
+ HDmemset(expected, 0xFF, H5FD_MIRROR_XMIT_HEADER_SIZE+8);
+ for (i=0; i < H5FD_MIRROR_XMIT_HEADER_SIZE; i++) {
+ expected[i+2] = (unsigned char)i;
+ }
+
+ /* Encode, and compare buffer contents
+ * Initial buffer is filled with 0xFF to match expected padding
+ */
+ HDmemset(buf, 0xFF, H5FD_MIRROR_XMIT_HEADER_SIZE+8);
+ if (H5FD_mirror_xmit_encode_header((buf+2), &xmit_mock)
+ != H5FD_MIRROR_XMIT_HEADER_SIZE)
+ {
+ TEST_ERROR;
+ }
+ if (HDmemcmp(buf, expected, H5FD_MIRROR_XMIT_HEADER_SIZE+8) != 0) {
+ PRINT_BUFFER_DIFF(buf, expected, H5FD_MIRROR_XMIT_HEADER_SIZE+8);
+ TEST_ERROR;
+ }
+
+ /* Decode from buffer
+ */
+ if (H5FD_mirror_xmit_decode_header(&xmit_out, (buf+2))
+ != H5FD_MIRROR_XMIT_HEADER_SIZE)
+ {
+ TEST_ERROR;
+ }
+ if (xmit_out.magic != xmit_mock.magic) TEST_ERROR;
+ if (xmit_out.version != xmit_mock.version) TEST_ERROR;
+ if (xmit_out.session_token != xmit_mock.session_token) TEST_ERROR;
+ if (xmit_out.xmit_count != xmit_mock.xmit_count) TEST_ERROR;
+ if (xmit_out.op != xmit_mock.op) TEST_ERROR;
+
+ /* Decode from different offset in buffer
+ * Observe changes when ingesting the padding
+ */
+ if (H5FD_mirror_xmit_decode_header(&xmit_out, (buf))
+ != H5FD_MIRROR_XMIT_HEADER_SIZE)
+ {
+ TEST_ERROR;
+ }
+ if (xmit_out.magic != 0xFFFF0001) TEST_ERROR;
+ if (xmit_out.version != 0x02) TEST_ERROR;
+ if (xmit_out.session_token != 0x03040506) TEST_ERROR;
+ if (xmit_out.xmit_count != 0x0708090A) TEST_ERROR;
+ if (xmit_out.op != 0x0B) TEST_ERROR;
+
+ } while (0); /* end xmit header en/decode */
+
+ /* Test xmit set-eoa structure encode/decode
+ * Write bogus but easily verifiable data to inside a buffer, and compare.
+ * Then decode the buffer and compare the structure contents.
+ * Then repeat from a different offset in the buffer and compare.
+ */
+ do {
+ unsigned char buf[H5FD_MIRROR_XMIT_EOA_SIZE+8];
+ unsigned char expected[H5FD_MIRROR_XMIT_EOA_SIZE+8];
+ H5FD_mirror_xmit_eoa_t xmit_in;
+ H5FD_mirror_xmit_eoa_t xmit_out;
+ size_t i = 0;
+
+ /* sanity check */
+ if ((14+9) != H5FD_MIRROR_XMIT_EOA_SIZE) {
+ FAIL_PUTS_ERROR("Header size definition does not match test\n");
+ }
+ if (xmit_mock.op != 0x0D) {
+ FAIL_PUTS_ERROR("shared header structure is not in expected state");
+ }
+
+ /* Populate the expected buffer; expect end padding of 0xFF
+ */
+ HDmemset(expected, 0xFF, H5FD_MIRROR_XMIT_EOA_SIZE+8);
+ for (i=0; i < H5FD_MIRROR_XMIT_EOA_SIZE; i++) {
+ expected[i+2] = (unsigned char)i;
+ }
+
+ /* Set xmit_in
+ */
+ xmit_in.pub = xmit_mock; /* shared/common */
+ xmit_in.type = 0x0E;
+ xmit_in.eoa_addr = 0x0F10111213141516;
+
+ /* Encode, and compare buffer contents
+ * Initial buffer is filled with 0xFF to match expected padding
+ */
+ HDmemset(buf, 0xFF, H5FD_MIRROR_XMIT_EOA_SIZE+8);
+ if (H5FD_mirror_xmit_encode_set_eoa((buf+2), &xmit_in)
+ != H5FD_MIRROR_XMIT_EOA_SIZE)
+ {
+ TEST_ERROR;
+ }
+ if (HDmemcmp(buf, expected, H5FD_MIRROR_XMIT_EOA_SIZE+8) != 0) {
+ PRINT_BUFFER_DIFF(buf, expected, H5FD_MIRROR_XMIT_EOA_SIZE+8);
+ TEST_ERROR;
+ }
+
+ /* Decode from buffer
+ */
+ if (H5FD_mirror_xmit_decode_set_eoa(&xmit_out, (buf+2))
+ != H5FD_MIRROR_XMIT_EOA_SIZE)
+ {
+ TEST_ERROR;
+ }
+ if (xmit_out.pub.magic != xmit_mock.magic) TEST_ERROR;
+ if (xmit_out.pub.version != xmit_mock.version) TEST_ERROR;
+ if (xmit_out.pub.session_token != xmit_mock.session_token) TEST_ERROR;
+ if (xmit_out.pub.xmit_count != xmit_mock.xmit_count) TEST_ERROR;
+ if (xmit_out.pub.op != xmit_mock.op) TEST_ERROR;
+ if (xmit_out.type != 0x0E) TEST_ERROR;
+ if (xmit_out.eoa_addr != 0x0F10111213141516) TEST_ERROR;
+
+ /* Decode from different offset in buffer
+ * Observe changes when ingesting the padding
+ */
+ if (H5FD_mirror_xmit_decode_set_eoa(&xmit_out, (buf))
+ != H5FD_MIRROR_XMIT_EOA_SIZE)
+ {
+ TEST_ERROR;
+ }
+ if (xmit_out.pub.magic != 0xFFFF0001) TEST_ERROR;
+ if (xmit_out.pub.version != 0x02) TEST_ERROR;
+ if (xmit_out.pub.session_token != 0x03040506) TEST_ERROR;
+ if (xmit_out.pub.xmit_count != 0x0708090A) TEST_ERROR;
+ if (xmit_out.pub.op != 0x0B) TEST_ERROR;
+ if (xmit_out.type != 0x0C) TEST_ERROR;
+ if (xmit_out.eoa_addr != 0x0D0E0F1011121314) TEST_ERROR;
+
+ } while (0); /* end xmit set-eoa en/decode */
+
+ /* Test xmit lock structure encode/decode
+ * Write bogus but easily verifiable data to inside a buffer, and compare.
+ * Then decode the buffer and compare the structure contents.
+ * Then repeat from a different offset in the buffer and compare.
+ */
+ do {
+ unsigned char buf[H5FD_MIRROR_XMIT_LOCK_SIZE+8];
+ unsigned char expected[H5FD_MIRROR_XMIT_LOCK_SIZE+8];
+ H5FD_mirror_xmit_lock_t xmit_in;
+ H5FD_mirror_xmit_lock_t xmit_out;
+ size_t i = 0;
+
+ /* sanity check */
+ if ((14+8) != H5FD_MIRROR_XMIT_LOCK_SIZE) {
+ FAIL_PUTS_ERROR("Header size definition does not match test\n");
+ }
+ if (xmit_mock.op != 0x0D) {
+ FAIL_PUTS_ERROR("shared header structure is not in expected state");
+ }
+
+ /* Populate the expected buffer; expect end padding of 0xFF
+ */
+ HDmemset(expected, 0xFF, H5FD_MIRROR_XMIT_LOCK_SIZE+8);
+ for (i=0; i < H5FD_MIRROR_XMIT_LOCK_SIZE; i++) {
+ expected[i+2] = (unsigned char)i;
+ }
+
+ /* Set xmit_in
+ */
+ xmit_in.pub = xmit_mock; /* shared/common */
+ xmit_in.rw = 0x0E0F101112131415;
+
+ /* Encode, and compare buffer contents
+ * Initial buffer is filled with 0xFF to match expected padding
+ */
+ HDmemset(buf, 0xFF, H5FD_MIRROR_XMIT_LOCK_SIZE+8);
+ if (H5FD_mirror_xmit_encode_lock((buf+2), &xmit_in)
+ != H5FD_MIRROR_XMIT_LOCK_SIZE)
+ {
+ TEST_ERROR;
+ }
+ if (HDmemcmp(buf, expected, H5FD_MIRROR_XMIT_LOCK_SIZE+8) != 0) {
+ PRINT_BUFFER_DIFF(buf, expected, H5FD_MIRROR_XMIT_LOCK_SIZE+8);
+ TEST_ERROR;
+ }
+
+ /* Decode from buffer
+ */
+ if (H5FD_mirror_xmit_decode_lock(&xmit_out, (buf+2))
+ != H5FD_MIRROR_XMIT_LOCK_SIZE)
+ {
+ TEST_ERROR;
+ }
+ if (xmit_out.pub.magic != xmit_mock.magic) TEST_ERROR;
+ if (xmit_out.pub.version != xmit_mock.version) TEST_ERROR;
+ if (xmit_out.pub.session_token != xmit_mock.session_token) TEST_ERROR;
+ if (xmit_out.pub.xmit_count != xmit_mock.xmit_count) TEST_ERROR;
+ if (xmit_out.pub.op != xmit_mock.op) TEST_ERROR;
+ if (xmit_out.rw != 0x0E0F101112131415) TEST_ERROR;
+
+ /* Decode from different offset in buffer
+ * Observe changes when ingesting the padding
+ */
+ if (H5FD_mirror_xmit_decode_lock(&xmit_out, (buf))
+ != H5FD_MIRROR_XMIT_LOCK_SIZE)
+ {
+ TEST_ERROR;
+ }
+ if (xmit_out.pub.magic != 0xFFFF0001) TEST_ERROR;
+ if (xmit_out.pub.version != 0x02) TEST_ERROR;
+ if (xmit_out.pub.session_token != 0x03040506) TEST_ERROR;
+ if (xmit_out.pub.xmit_count != 0x0708090A) TEST_ERROR;
+ if (xmit_out.pub.op != 0x0B) TEST_ERROR;
+ if (xmit_out.rw != 0x0C0D0E0F10111213) TEST_ERROR;
+
+ } while (0); /* end xmit lock en/decode */
+
+ /* Test xmit open structure encode/decode
+ * Write bogus but easily verifiable data to inside a buffer, and compare.
+ * Then decode the buffer and compare the structure contents.
+ * Then repeat from a different offset in the buffer and compare.
+ *
+ * Verifies that the first zero character in the filepath will end the
+ * string, with all following bytes in the encoded buffer being zeroed.
+ */
+ do {
+ unsigned char buf[H5FD_MIRROR_XMIT_OPEN_SIZE+8];
+ unsigned char expected[H5FD_MIRROR_XMIT_OPEN_SIZE+8];
+ H5FD_mirror_xmit_open_t xmit_in;
+ H5FD_mirror_xmit_open_t xmit_out;
+ size_t i = 0;
+
+ /* sanity check */
+ if ((14+20+4097) != H5FD_MIRROR_XMIT_OPEN_SIZE) {
+ FAIL_PUTS_ERROR("Header size definition does not match test\n");
+ }
+ if (xmit_mock.op != 0x0D) {
+ FAIL_PUTS_ERROR("shared header structure is not in expected state");
+ }
+
+ /* Populate the expected buffer; expect end padding of 0xFF
+ */
+ HDmemset(expected, 0xFF, H5FD_MIRROR_XMIT_OPEN_SIZE+8);
+ for (i=0; i < H5FD_MIRROR_XMIT_OPEN_SIZE; i++) {
+ /* 0x100 is "zero" in a byte, so encode will treat it as a NULL-
+ * terminator in the filepath string. Expect all zeroes following.
+ */
+ expected[i+2] = (i > 0xFF) ? 0 : (unsigned char)i;
+ }
+
+ /* Set xmit_in
+ */
+ xmit_in.pub = xmit_mock; /* shared/common */
+ xmit_in.flags = 0x0E0F1011;
+ xmit_in.maxaddr = 0x1213141516171819;
+ xmit_in.size_t_blob = 0x1A1B1C1D1E1F2021;
+ for (i=0x22; i < H5FD_MIRROR_XMIT_FILEPATH_MAX+0x22; i++) {
+ /* nonzero values repeat after 0x100, but will not be encoded */
+ xmit_in.filename[i-0x22] = (char)(i % 0x100);
+ }
+ xmit_in.filename[H5FD_MIRROR_XMIT_FILEPATH_MAX-1] = 0;
+
+ /* Encode, and compare buffer contents
+ * Initial buffer is filled with 0xFF to match expected padding
+ */
+ HDmemset(buf, 0xFF, H5FD_MIRROR_XMIT_OPEN_SIZE+8);
+ if (H5FD_mirror_xmit_encode_open((buf+2), &xmit_in)
+ != H5FD_MIRROR_XMIT_OPEN_SIZE)
+ {
+ TEST_ERROR;
+ }
+ if (HDmemcmp(buf, expected, H5FD_MIRROR_XMIT_OPEN_SIZE+8) != 0) {
+ PRINT_BUFFER_DIFF(buf, expected, H5FD_MIRROR_XMIT_OPEN_SIZE+8);
+ TEST_ERROR;
+ }
+
+ /* Decode from buffer
+ */
+ if (H5FD_mirror_xmit_decode_open(&xmit_out, (buf+2))
+ != H5FD_MIRROR_XMIT_OPEN_SIZE)
+ {
+ TEST_ERROR;
+ }
+ if (xmit_out.pub.magic != xmit_mock.magic) TEST_ERROR;
+ if (xmit_out.pub.version != xmit_mock.version) TEST_ERROR;
+ if (xmit_out.pub.session_token != xmit_mock.session_token) TEST_ERROR;
+ if (xmit_out.pub.xmit_count != xmit_mock.xmit_count) TEST_ERROR;
+ if (xmit_out.pub.op != xmit_mock.op) TEST_ERROR;
+ if (xmit_out.flags != xmit_in.flags) TEST_ERROR;
+ if (xmit_out.maxaddr != xmit_in.maxaddr) TEST_ERROR;
+ if (xmit_out.size_t_blob != xmit_in.size_t_blob) TEST_ERROR;
+ if (HDstrncmp(xmit_out.filename, xmit_in.filename,
+ H5FD_MIRROR_XMIT_FILEPATH_MAX)
+ != 0)
+ {
+ PRINT_BUFFER_DIFF(xmit_out.filename, xmit_in.filename,
+ H5FD_MIRROR_XMIT_FILEPATH_MAX);
+ TEST_ERROR;
+ }
+
+ /* Decode from different offset in buffer
+ * Observe changes when ingesting the padding
+ */
+ if (H5FD_mirror_xmit_decode_open(&xmit_out, (buf))
+ != H5FD_MIRROR_XMIT_OPEN_SIZE)
+ {
+ TEST_ERROR;
+ }
+ if (xmit_out.pub.magic != 0xFFFF0001) TEST_ERROR;
+ if (xmit_out.pub.version != 0x02) TEST_ERROR;
+ if (xmit_out.pub.session_token != 0x03040506) TEST_ERROR;
+ if (xmit_out.pub.xmit_count != 0x0708090A) TEST_ERROR;
+ if (xmit_out.pub.op != 0x0B) TEST_ERROR;
+ if (xmit_out.flags != 0x0C0D0E0F) TEST_ERROR;
+ if (xmit_out.maxaddr != 0x1011121314151617) TEST_ERROR;
+ if (xmit_out.size_t_blob != 0x18191A1B1C1D1E1F) TEST_ERROR;
+ /* update expected "filepath" in structure */
+ for (i=0x20; i < H5FD_MIRROR_XMIT_FILEPATH_MAX+0x20; i++) {
+ xmit_in.filename[i-0x20] = (i > 0xFF) ? 0 : (char)i;
+ }
+ if (HDstrncmp(xmit_out.filename, xmit_in.filename,
+ H5FD_MIRROR_XMIT_FILEPATH_MAX)
+ != 0)
+ {
+ PRINT_BUFFER_DIFF(xmit_out.filename, xmit_in.filename,
+ H5FD_MIRROR_XMIT_FILEPATH_MAX);
+ TEST_ERROR;
+ }
+
+ } while (0); /* end xmit open en/decode */
+
+ /* Test xmit reply structure encode/decode
+ * Write bogus but easily verifiable data to inside a buffer, and compare.
+ * Then decode the buffer and compare the structure contents.
+ * Then repeat from a different offset in the buffer and compare.
+ *
+ * Verifies that the first zero character in the filepath will end the
+ * string, with all following bytes in the encoded buffer being zeroed.
+ */
+ do {
+ unsigned char buf[H5FD_MIRROR_XMIT_REPLY_SIZE+8];
+ unsigned char expected[H5FD_MIRROR_XMIT_REPLY_SIZE+8];
+ H5FD_mirror_xmit_reply_t xmit_in;
+ H5FD_mirror_xmit_reply_t xmit_out;
+ size_t i = 0;
+
+ /* sanity check */
+ if ((14+4+256) != H5FD_MIRROR_XMIT_REPLY_SIZE) {
+ FAIL_PUTS_ERROR("Header size definition does not match test\n");
+ }
+ if (xmit_mock.op != 0x0D) {
+ FAIL_PUTS_ERROR("shared header structure is not in expected state");
+ }
+
+ /* Populate the expected buffer; expect end padding of 0xFF
+ */
+ HDmemset(expected, 0xFF, H5FD_MIRROR_XMIT_REPLY_SIZE+8);
+ for (i=0; i < H5FD_MIRROR_XMIT_REPLY_SIZE; i++) {
+ /* 0x100 is "zero" in a byte, so encode will treat it as a NULL-
+ * terminator in the filepath string. Expect all zeroes following.
+ */
+ expected[i+2] = (i > 0xFF) ? 0 : (unsigned char)i;
+ }
+
+ /* Set xmit_in
+ */
+ xmit_in.pub = xmit_mock; /* shared/common */
+ xmit_in.status = 0x0E0F1011;
+ for (i=0x12; i < H5FD_MIRROR_STATUS_MESSAGE_MAX+0x12; i++) {
+ /* nonzero values repeat after 0x100, but will not be encoded */
+ xmit_in.message[i-0x12] = (char)(i % 0x100);
+ }
+ xmit_in.message[H5FD_MIRROR_STATUS_MESSAGE_MAX-1] = 0;
+
+ /* Encode, and compare buffer contents
+ * Initial buffer is filled with 0xFF to match expected padding
+ */
+ HDmemset(buf, 0xFF, H5FD_MIRROR_XMIT_REPLY_SIZE+8);
+ if (H5FD_mirror_xmit_encode_reply((buf+2), &xmit_in)
+ != H5FD_MIRROR_XMIT_REPLY_SIZE)
+ {
+ TEST_ERROR;
+ }
+ if (HDmemcmp(buf, expected, H5FD_MIRROR_XMIT_REPLY_SIZE+8) != 0) {
+ PRINT_BUFFER_DIFF(buf, expected, H5FD_MIRROR_XMIT_REPLY_SIZE+8);
+ TEST_ERROR;
+ }
+
+ /* Decode from buffer
+ */
+ if (H5FD_mirror_xmit_decode_reply(&xmit_out, (buf+2))
+ != H5FD_MIRROR_XMIT_REPLY_SIZE)
+ {
+ TEST_ERROR;
+ }
+ if (xmit_out.pub.magic != xmit_mock.magic) TEST_ERROR;
+ if (xmit_out.pub.version != xmit_mock.version) TEST_ERROR;
+ if (xmit_out.pub.session_token != xmit_mock.session_token) TEST_ERROR;
+ if (xmit_out.pub.xmit_count != xmit_mock.xmit_count) TEST_ERROR;
+ if (xmit_out.pub.op != xmit_mock.op) TEST_ERROR;
+ if (xmit_out.status != xmit_in.status) TEST_ERROR;
+ if (HDstrncmp(xmit_out.message, xmit_in.message,
+ H5FD_MIRROR_STATUS_MESSAGE_MAX)
+ != 0)
+ {
+ PRINT_BUFFER_DIFF(xmit_out.message, xmit_in.message,
+ H5FD_MIRROR_STATUS_MESSAGE_MAX);
+ TEST_ERROR;
+ }
+
+ /* Decode from different offset in buffer
+ * Observe changes when ingesting the padding
+ */
+ if (H5FD_mirror_xmit_decode_reply(&xmit_out, (buf))
+ != H5FD_MIRROR_XMIT_REPLY_SIZE)
+ {
+ TEST_ERROR;
+ }
+ if (xmit_out.pub.magic != 0xFFFF0001) TEST_ERROR;
+ if (xmit_out.pub.version != 0x02) TEST_ERROR;
+ if (xmit_out.pub.session_token != 0x03040506) TEST_ERROR;
+ if (xmit_out.pub.xmit_count != 0x0708090A) TEST_ERROR;
+ if (xmit_out.pub.op != 0x0B) TEST_ERROR;
+ if (xmit_out.status != 0x0C0D0E0F) TEST_ERROR;
+ /* update expected "message" in structure */
+ for (i=0x10; i < H5FD_MIRROR_STATUS_MESSAGE_MAX+0x10; i++) {
+ xmit_in.message[i-0x10] = (i > 0xFF) ? 0 : (char)i;
+ }
+ if (HDstrncmp(xmit_out.message, xmit_in.message,
+ H5FD_MIRROR_STATUS_MESSAGE_MAX)
+ != 0)
+ {
+ PRINT_BUFFER_DIFF(xmit_out.message, xmit_in.message,
+ H5FD_MIRROR_STATUS_MESSAGE_MAX);
+ TEST_ERROR;
+ }
+
+ } while (0); /* end xmit reply en/decode */
+
+ /* Test xmit write structure encode/decode
+ * Write bogus but easily verifiable data to inside a buffer, and compare.
+ * Then decode the buffer and compare the structure contents.
+ * Then repeat from a different offset in the buffer and compare.
+ */
+ do {
+ unsigned char buf[H5FD_MIRROR_XMIT_WRITE_SIZE+8];
+ unsigned char expected[H5FD_MIRROR_XMIT_WRITE_SIZE+8];
+ H5FD_mirror_xmit_write_t xmit_in;
+ H5FD_mirror_xmit_write_t xmit_out;
+ size_t i = 0;
+
+ /* sanity check */
+ if ((14+17) != H5FD_MIRROR_XMIT_WRITE_SIZE) {
+ FAIL_PUTS_ERROR("Header size definition does not match test\n");
+ }
+ if (xmit_mock.op != 0x0D) {
+ FAIL_PUTS_ERROR("shared header structure is not in expected state");
+ }
+
+ /* Populate the expected buffer; expect end padding of 0xFF
+ */
+ HDmemset(expected, 0xFF, H5FD_MIRROR_XMIT_WRITE_SIZE+8);
+ for (i=0; i < H5FD_MIRROR_XMIT_WRITE_SIZE; i++) {
+ expected[i+2] = (unsigned char)i;
+ }
+
+ /* Set xmit_in
+ */
+ xmit_in.pub = xmit_mock; /* shared/common */
+ xmit_in.type = 0x0E;
+ xmit_in.offset = 0x0F10111213141516;
+ xmit_in.size = 0x1718191A1B1C1D1E;
+
+ /* Encode, and compare buffer contents
+ * Initial buffer is filled with 0xFF to match expected padding
+ */
+ HDmemset(buf, 0xFF, H5FD_MIRROR_XMIT_WRITE_SIZE+8);
+ if (H5FD_mirror_xmit_encode_write((buf+2), &xmit_in)
+ != H5FD_MIRROR_XMIT_WRITE_SIZE)
+ {
+ TEST_ERROR;
+ }
+ if (HDmemcmp(buf, expected, H5FD_MIRROR_XMIT_WRITE_SIZE+8) != 0) {
+ PRINT_BUFFER_DIFF(buf, expected, H5FD_MIRROR_XMIT_WRITE_SIZE+8);
+ TEST_ERROR;
+ }
+
+ /* Decode from buffer
+ */
+ if (H5FD_mirror_xmit_decode_write(&xmit_out, (buf+2))
+ != H5FD_MIRROR_XMIT_WRITE_SIZE)
+ {
+ TEST_ERROR;
+ }
+ if (xmit_out.pub.magic != xmit_mock.magic) TEST_ERROR;
+ if (xmit_out.pub.version != xmit_mock.version) TEST_ERROR;
+ if (xmit_out.pub.session_token != xmit_mock.session_token) TEST_ERROR;
+ if (xmit_out.pub.xmit_count != xmit_mock.xmit_count) TEST_ERROR;
+ if (xmit_out.pub.op != xmit_mock.op) TEST_ERROR;
+ if (xmit_out.type != 0x0E) TEST_ERROR;
+ if (xmit_out.offset != 0x0F10111213141516) TEST_ERROR;
+ if (xmit_out.size != 0x1718191A1B1C1D1E) TEST_ERROR;
+
+ /* Decode from different offset in buffer
+ * Observe changes when ingesting the padding
+ */
+ if (H5FD_mirror_xmit_decode_write(&xmit_out, (buf))
+ != H5FD_MIRROR_XMIT_WRITE_SIZE)
+ {
+ TEST_ERROR;
+ }
+ if (xmit_out.pub.magic != 0xFFFF0001) TEST_ERROR;
+ if (xmit_out.pub.version != 0x02) TEST_ERROR;
+ if (xmit_out.pub.session_token != 0x03040506) TEST_ERROR;
+ if (xmit_out.pub.xmit_count != 0x0708090A) TEST_ERROR;
+ if (xmit_out.pub.op != 0x0B) TEST_ERROR;
+ if (xmit_out.type != 0x0C) TEST_ERROR;
+ if (xmit_out.offset != 0x0D0E0F1011121314) TEST_ERROR;
+ if (xmit_out.size != 0x15161718191A1B1C) TEST_ERROR;
+
+ } while (0); /* end xmit write en/decode */
+
+ PASSED();
+ return 0;
+
+error:
+ return -1;
+} /* end test_xmit_encode_decode */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: create_mirroring_split_fapl
+ *
+ * Purpose: Create and populate a mirroring FAPL ID.
+ * Creates target files with the given base name -- ideally the
+ * test name -- and creates mirroring/split FAPL set to use the
+ * global mirroring info and a sec2 R/W channel driver.
+ *
+ * TODO: receive target IP from caller?
+ *
+ * Return: Success: HID of the top-level (splitter) FAPL, a non-negative
+ * value.
+ * Failure: H5I_INVALID_HID, a negative value.
+ *
+ * Programmer: Jacob Smith
+ * 2019
+ * ---------------------------------------------------------------------------
+ */
+static hid_t
+create_mirroring_split_fapl(const char *_basename,
+ struct mirrortest_filenames *names)
+{
+ H5FD_splitter_vfd_config_t splitter_config;
+ H5FD_mirror_fapl_t mirror_conf;
+ hid_t ret_value = H5I_INVALID_HID;
+
+ if (_basename == NULL || *_basename == '\0') {
+ TEST_ERROR;
+ }
+
+ splitter_config.magic = H5FD_SPLITTER_MAGIC;
+ splitter_config.version = H5FD_CURR_SPLITTER_VFD_CONFIG_VERSION;
+ splitter_config.ignore_wo_errs = FALSE;
+
+ /* Create Splitter R/W channel driver (sec2)
+ */
+ splitter_config.rw_fapl_id = H5Pcreate(H5P_FILE_ACCESS);
+ if (H5I_INVALID_HID == splitter_config.rw_fapl_id) {
+ TEST_ERROR;
+ }
+ if (H5Pset_fapl_sec2(splitter_config.rw_fapl_id) == FAIL) {
+ TEST_ERROR;
+ }
+
+ /* Create Splitter W/O channel driver (mirror)
+ */
+ mirror_conf.magic = H5FD_MIRROR_FAPL_MAGIC;
+ mirror_conf.version = H5FD_MIRROR_CURR_FAPL_T_VERSION;
+ mirror_conf.handshake_port = SERVER_HANDSHAKE_PORT;
+ if (HDstrncpy(mirror_conf.remote_ip, SERVER_IP_ADDRESS,
+ H5FD_MIRROR_MAX_IP_LEN)
+ == NULL)
+ {
+ TEST_ERROR;
+ }
+ splitter_config.wo_fapl_id = H5Pcreate(H5P_FILE_ACCESS);
+ if (H5I_INVALID_HID == splitter_config.wo_fapl_id) {
+ TEST_ERROR;
+ }
+ if (H5Pset_fapl_mirror(splitter_config.wo_fapl_id, &mirror_conf) == FAIL) {
+ TEST_ERROR;
+ }
+
+ /* Build r/w, w/o, and log file paths
+ */
+ if (build_paths(_basename, &splitter_config, names) < 0) {
+ TEST_ERROR;
+ }
+
+ /* Set file paths for w/o and logfile
+ */
+ if (HDstrncpy(splitter_config.wo_path, (const char *)names->wo,
+ H5FD_SPLITTER_PATH_MAX)
+ == NULL)
+ {
+ TEST_ERROR;
+ }
+ if (HDstrncpy(splitter_config.log_file_path, (const char *)names->log,
+ H5FD_SPLITTER_PATH_MAX)
+ == NULL)
+ {
+ TEST_ERROR;
+ }
+
+ /* Create Splitter FAPL
+ */
+ ret_value = H5Pcreate(H5P_FILE_ACCESS);
+ if (H5I_INVALID_HID == ret_value) {
+ TEST_ERROR;
+ }
+ if (H5Pset_fapl_splitter(ret_value, &splitter_config) == FAIL) {
+ TEST_ERROR;
+ }
+
+ /* Close FAPLs created for child channels
+ */
+ if (H5Pclose(splitter_config.rw_fapl_id) < 0) {
+ TEST_ERROR;
+ }
+ splitter_config.rw_fapl_id = H5I_INVALID_HID;
+ if (H5Pclose(splitter_config.wo_fapl_id) < 0) {
+ TEST_ERROR;
+ }
+ splitter_config.wo_fapl_id = H5I_INVALID_HID;
+
+ return ret_value;
+
+error:
+ if (splitter_config.wo_fapl_id >= 0) {
+ (void)H5Pclose(splitter_config.wo_fapl_id);
+ }
+ if (splitter_config.rw_fapl_id >= 0) {
+ (void)H5Pclose(splitter_config.rw_fapl_id);
+ }
+ if (ret_value >= 0) {
+ (void)H5Pclose(ret_value);
+ }
+ return H5I_INVALID_HID;
+} /* end create_mirroring_split_fapl() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: test_create_and_close
+ *
+ * Purpose: Test/demonstrate a do-nothing file open and close.
+ *
+ * Verifying file existence and contents is part of other tests.
+ *
+ * TODO: receive target IP from caller?
+ *
+ * Return: Success: 0
+ * Failure: -1
+ *
+ * Programmer: Jacob Smith
+ * 2019-12-17
+ * ---------------------------------------------------------------------------
+ */
+static int
+test_create_and_close(void)
+{
+ struct mirrortest_filenames names;
+ hid_t file_id = H5I_INVALID_HID;
+ hid_t fapl_id = H5P_DEFAULT;
+
+ TESTING("File creation and immediate close");
+
+ /* Create FAPL for Splitter[sec2|mirror]
+ */
+ fapl_id = create_mirroring_split_fapl("basic_create", &names);
+ if (H5I_INVALID_HID == fapl_id) {
+ TEST_ERROR;
+ }
+
+ /* -------------------- */
+ /* TEST: Create and Close */
+
+ file_id = H5Fcreate(names.rw, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id);
+ if (H5I_INVALID_HID == file_id) {
+ TEST_ERROR;
+ }
+
+ /* -------------------- */
+ /* Standard cleanup */
+
+ if (H5Fclose(file_id) == FAIL) {
+ TEST_ERROR;
+ }
+ if (fapl_id != H5P_DEFAULT && fapl_id >= 0) {
+ if (H5Pclose(fapl_id) == FAIL) {
+ TEST_ERROR;
+ }
+ }
+
+ PASSED();
+ return 0;
+
+error:
+ H5E_BEGIN_TRY{
+ (void)H5Fclose(file_id);
+ (void)H5Pclose(fapl_id);
+ } H5E_END_TRY;
+ return -1;
+} /* end test_create_and_close() */
+
+
+/* ----------------------------------------------------------------------------
+ * Function: create_datasets
+ *
+ * Purpose: Given a file ID and least and greateset dataset indices, create
+ * populated chunked datasets in the target file from min_dset to
+ * (and including) max_dset.
+ * Uses #defined constants to determine chunk and dataset sizes
+ * and values.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Jacob Smith
+ * 2019-08-14
+ * ----------------------------------------------------------------------------
+ */
+static herr_t
+create_datasets(hid_t file_id,
+ unsigned min_dset,
+ unsigned max_dset)
+{
+ hid_t dataspace_ids[MAX_DSET_COUNT + 1];
+ hid_t dataset_ids[MAX_DSET_COUNT + 1];
+ hid_t filespace_ids[MAX_DSET_COUNT + 1];
+ int data_chunk[CHUNK_DIM][CHUNK_DIM];
+ unsigned int i, j, k, l, m;
+ hsize_t offset[2];
+ hid_t memspace_id = H5I_INVALID_HID;
+ hsize_t a_size[2] = {CHUNK_DIM, CHUNK_DIM};
+ hsize_t chunk_dims[2] = {CHUNK_DIM, CHUNK_DIM};
+ hsize_t dset_dims[2] = {DSET_DIM, DSET_DIM};
+
+ HDassert(file_id >= 0);
+ HDassert(min_dset <= max_dset);
+ HDassert(max_dset <= MAX_DSET_COUNT);
+
+ LOGPRINT(2, "create_dataset()\n");
+
+ /* ---------------------------------
+ * "Clear" ID arrays
+ */
+
+ for (i = 0; i < MAX_DSET_COUNT; i++) {
+ LOGPRINT(3, "clearing IDs [%d]\n", i);
+ dataspace_ids[i] = H5I_INVALID_HID;
+ dataset_ids[i] = H5I_INVALID_HID;
+ filespace_ids[i] = H5I_INVALID_HID;
+ }
+
+ /* ---------------------------------
+ * Generate dataspace, dataset, and 'filespace' IDs
+ */
+
+ if (_create_chunking_ids(file_id, min_dset, max_dset, chunk_dims,
+ dset_dims, dataspace_ids, filespace_ids, dataset_ids, &memspace_id)
+ == FAIL)
+ {
+ TEST_ERROR;
+ }
+
+ /* ---------------------------------
+ * Initialize (write) all datasets in a "round robin"...
+ * for a given chunk 'location', write chunk data to each dataset.
+ */
+
+ for (i = 0; i < DSET_DIM; i += CHUNK_DIM)
+ {
+ LOGPRINT(3, "i: %d\n", i);
+ for (j = 0; j < DSET_DIM; j += CHUNK_DIM)
+ {
+ LOGPRINT(3, " j: %d\n", j);
+ for (m = min_dset; m <= max_dset; m++)
+ {
+ LOGPRINT(3, " m: %d\n", m);
+ for (k = 0; k < CHUNK_DIM; k++)
+ {
+ for (l = 0; l < CHUNK_DIM; l++)
+ {
+ data_chunk[k][l] = (int)((DSET_DIM * DSET_DIM * m) +
+ (DSET_DIM * (i + k)) + j + l);
+ LOGPRINT(3, " data_chunk[%d][%d]: %d\n",
+ k, l, data_chunk[k][l]);
+ }
+ }
+
+ /* select on disk hyperslab */
+ offset[0] = (hsize_t)i;
+ offset[1] = (hsize_t)j;
+ LOGPRINT(3, " H5Sselect_hyperslab()\n");
+ if (H5Sselect_hyperslab(filespace_ids[m], H5S_SELECT_SET,
+ offset, NULL, a_size, NULL)
+ < 0)
+ {
+ TEST_ERROR;
+ }
+
+ LOGPRINT(3, " H5Dwrite()\n");
+ if (H5Dwrite(dataset_ids[m], H5T_NATIVE_INT, memspace_id,
+ filespace_ids[m], H5P_DEFAULT, data_chunk)
+ < 0)
+ {
+ TEST_ERROR;
+ }
+
+ }
+ }
+ }
+
+ /* ---------------------------------
+ * Read and verify data from datasets
+ */
+
+ if (_verify_datasets(min_dset, max_dset, filespace_ids, dataset_ids,
+ memspace_id)
+ == FAIL)
+ {
+ TEST_ERROR;
+ }
+
+ /* ---------------------------------
+ * Cleanup
+ */
+
+ if (_close_chunking_ids(min_dset, max_dset, dataspace_ids, filespace_ids,
+ dataset_ids, &memspace_id)
+ == FAIL)
+ {
+ TEST_ERROR;
+ }
+
+ return SUCCEED;
+
+error:
+ (void)_close_chunking_ids(min_dset, max_dset, dataspace_ids,
+ filespace_ids, dataset_ids, &memspace_id);
+ LOGPRINT(1, "create_datasets() FAILED\n");
+ return FAIL;
+} /* end create_datasets() */
+
+
+/* ----------------------------------------------------------------------------
+ * Function: _create_chunking_ids
+ *
+ * Purpose: Create new IDs to be used with the associated file.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programer: Jacob Smith
+ * 2019
+ * ----------------------------------------------------------------------------
+ */
+static herr_t
+_create_chunking_ids(hid_t file_id,
+ unsigned min_dset,
+ unsigned max_dset,
+ hsize_t *chunk_dims,
+ hsize_t *dset_dims,
+ hid_t *dataspace_ids,
+ hid_t *filespace_ids,
+ hid_t *dataset_ids,
+ hid_t *memspace_id)
+{
+ char dset_name[DSET_NAME_LEN + 1];
+ unsigned m = 0;
+ hid_t dcpl_id = H5I_INVALID_HID;
+
+ LOGPRINT(2, "_create_chunking_ids()\n");
+
+ /* --------------------
+ * Create chunking DCPL
+ */
+
+ dcpl_id = H5Pcreate(H5P_DATASET_CREATE);
+ if (dcpl_id < 0) {
+ TEST_ERROR;
+ }
+ if (H5Pset_chunk(dcpl_id, 2, chunk_dims) == FAIL) {
+ TEST_ERROR;
+ }
+
+ /* --------------------
+ * Create dataspace IDs
+ */
+
+ for (m = min_dset; m <= max_dset; m++) {
+ dataspace_ids[m] = H5Screate_simple(2, dset_dims, NULL);
+ if (dataspace_ids[m] < 0) {
+ HDsnprintf(mesg, MIRR_MESG_SIZE,
+ "unable to create dataspace ID %d\n", m);
+ FAIL_PUTS_ERROR(mesg);
+ }
+ }
+
+ /* --------------------
+ * Create dataset IDs
+ */
+
+ for (m = min_dset; m <= max_dset; m++) {
+ if (HDsnprintf(dset_name, DSET_NAME_LEN, "/dset%03d", m)
+ > DSET_NAME_LEN)
+ {
+ HDsnprintf(mesg, MIRR_MESG_SIZE,
+ "unable to compose dset name %d\n", m);
+ FAIL_PUTS_ERROR(mesg);
+ }
+
+ dataset_ids[m] = H5Dcreate(file_id, dset_name, H5T_STD_I32BE,
+ dataspace_ids[m], H5P_DEFAULT, dcpl_id, H5P_DEFAULT);
+ if (dataset_ids[m] < 0) {
+ HDsnprintf(mesg, MIRR_MESG_SIZE,
+ "unable to create dset ID %d\n", m);
+ FAIL_PUTS_ERROR(mesg);
+ }
+ }
+
+ /* --------------------
+ * Get file space IDs
+ */
+
+ for (m = min_dset; m <= max_dset; m++) {
+ filespace_ids[m] = H5Dget_space(dataset_ids[m]);
+ if (filespace_ids[m] < 0) {
+ HDsnprintf(mesg, MIRR_MESG_SIZE,
+ "unable to create filespace ID %d\n", m);
+ FAIL_PUTS_ERROR(mesg);
+ }
+ }
+
+ /* --------------------
+ * Create mem space to be used to read and write chunks
+ */
+
+ *memspace_id = H5Screate_simple(2, chunk_dims, NULL);
+ if (*memspace_id < 0) {
+ TEST_ERROR;
+ }
+
+ /* --------------------
+ * Clean up the DCPL, even if there were errors before
+ */
+
+ if (dcpl_id != H5P_DEFAULT && dcpl_id != H5I_INVALID_HID) {
+ if (H5Pclose(dcpl_id) == FAIL) {
+ TEST_ERROR;
+ }
+ }
+
+ return SUCCEED;
+
+error:
+ if (dcpl_id != H5P_DEFAULT && dcpl_id != H5I_INVALID_HID) {
+ (void)H5Pclose(dcpl_id);
+ }
+ LOGPRINT(1, "_create_chunking_ids() FAILED\n");
+ return FAIL;
+} /* end _create_chunking_ids() */
+
+
+/* ----------------------------------------------------------------------------
+ * Function: _open_chunking_ids
+ *
+ * Purpose: Open/access IDs from the given file.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Jacob Smith
+ * 2019
+ * ----------------------------------------------------------------------------
+ */
+static herr_t
+_open_chunking_ids(
+ hid_t file_id,
+ unsigned min_dset,
+ unsigned max_dset,
+ hsize_t *chunk_dims,
+ hid_t *filespace_ids,
+ hid_t *dataset_ids,
+ hid_t *memspace_id)
+{
+ char dset_name[DSET_NAME_LEN+1];
+ unsigned m = 0;
+
+ LOGPRINT(2, "_open_chunking_ids()\n");
+
+ /* --------------------
+ * Open dataset IDs
+ */
+
+ for (m = min_dset; m <= max_dset; m++) {
+ if (HDsnprintf(dset_name, DSET_NAME_LEN, "/dset%03d", m)
+ > DSET_NAME_LEN)
+ {
+ HDsnprintf(mesg, MIRR_MESG_SIZE,
+ "unable to compose dset name %d\n", m);
+ FAIL_PUTS_ERROR(mesg);
+ }
+
+ dataset_ids[m] = H5Dopen2(file_id, dset_name, H5P_DEFAULT);
+ if (dataset_ids[m] < 0) {
+ HDsnprintf(mesg, MIRR_MESG_SIZE, "unable to open dset ID %d\n", m);
+ FAIL_PUTS_ERROR(mesg);
+ }
+ }
+
+ /* --------------------
+ * Open filespace IDs
+ */
+
+ for (m = min_dset; m <= max_dset; m++) {
+ filespace_ids[m] = H5Dget_space(dataset_ids[m]);
+ if (filespace_ids[m] < 0) {
+ HDsnprintf(mesg, MIRR_MESG_SIZE,
+ "unable to get filespace ID %d\n", m);
+ FAIL_PUTS_ERROR(mesg);
+ }
+ }
+
+ /* --------------------
+ * Create mem space to be used to read and write chunks
+ */
+
+ *memspace_id = H5Screate_simple(2, chunk_dims, NULL);
+ if (*memspace_id < 0) {
+ TEST_ERROR;
+ }
+
+ return SUCCEED;
+
+error:
+ LOGPRINT(1, "_open_chunking_ids() FAILED\n");
+ return FAIL;
+} /* end _open_chunking_ids() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: _close_chunking_ids
+ *
+ * Purpose: Close IDs that were created or opened.
+ * Pass NULL into `dataspace_ids` when closing items opened with
+ * _open_chunking_ids(). (as opposed to created IDs)
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Jacob Smith
+ * 2019
+ * ---------------------------------------------------------------------------
+ */
+static herr_t
+_close_chunking_ids(unsigned min_dset,
+ unsigned max_dset,
+ hid_t *dataspace_ids,
+ hid_t *filespace_ids,
+ hid_t *dataset_ids,
+ hid_t *memspace_id)
+{
+ unsigned m;
+
+ LOGPRINT(2, "_close_chunking_ids()\n");
+
+ for (m = min_dset; m <= max_dset; m++) {
+ LOGPRINT(3, "closing ids[%d]\n", m);
+ if (dataspace_ids) {
+ if (H5Sclose(dataspace_ids[m]) < 0) {
+ HDsnprintf(mesg, MIRR_MESG_SIZE,
+ "unable to close dataspace_id[%d]\n", m);
+ FAIL_PUTS_ERROR(mesg);
+ }
+ }
+ if (H5Dclose(dataset_ids[m]) < 0) {
+ HDsnprintf(mesg, MIRR_MESG_SIZE,
+ "unable to close dataset_id[%d]\n", m);
+ FAIL_PUTS_ERROR(mesg);
+ }
+ if (H5Sclose(filespace_ids[m]) < 0) {
+ HDsnprintf(mesg, MIRR_MESG_SIZE,
+ "unable to close filespace_id[%d]\n", m);
+ FAIL_PUTS_ERROR(mesg);
+ }
+ }
+
+ if ( (*memspace_id != H5I_INVALID_HID) &&
+ (H5Sclose(*memspace_id) < 0) )
+ {
+ TEST_ERROR;
+ }
+
+ return SUCCEED;
+
+error:
+ LOGPRINT(1, "_close_chunking_ids() FAILED\n");
+ return FAIL;
+} /* end _close_chunking_ids() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: _verify_datasets
+ *
+ * Purpose: Check that each chunk's contents are as expected, as pertaining
+ * to create_datasets().
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Jacob Smith
+ * 2019
+ * ---------------------------------------------------------------------------
+ */
+static herr_t
+_verify_datasets(unsigned min_dset,
+ unsigned max_dset,
+ hid_t *filespace_ids,
+ hid_t *dataset_ids,
+ hid_t memspace_id)
+{
+ unsigned i, j, k, l, m;
+ int data_chunk[CHUNK_DIM][CHUNK_DIM];
+ hsize_t offset[2];
+ hsize_t a_size[2] = {CHUNK_DIM, CHUNK_DIM};
+
+ LOGPRINT(2, "_verify_datasets()\n");
+
+ for (i = 0; i < DSET_DIM; i += CHUNK_DIM)
+ {
+ LOGPRINT(3, "i: %d\n", i);
+ for (j = 0; j < DSET_DIM; j += CHUNK_DIM)
+ {
+ LOGPRINT(3, " j: %d\n", j);
+ for (m = min_dset; m <= max_dset; m++)
+ {
+ LOGPRINT(3, " m: %d\n", m);
+
+ /* select on disk hyperslab */
+ offset[0] = (hsize_t)i;
+ offset[1] = (hsize_t)j;
+ if (H5Sselect_hyperslab(filespace_ids[m], H5S_SELECT_SET,
+ offset, NULL, a_size, NULL)
+ < 0)
+ {
+ TEST_ERROR;
+ }
+
+ if (H5Dread(dataset_ids[m], H5T_NATIVE_INT, memspace_id,
+ filespace_ids[m], H5P_DEFAULT, data_chunk)
+ < 0)
+ {
+ HDsnprintf(mesg, MIRR_MESG_SIZE,
+ " H5Dread() [%d][%d][%d]\n",
+ i, j, m);
+ FAIL_PUTS_ERROR(mesg);
+ }
+
+ for (k = 0; k < CHUNK_DIM; k++) {
+ for (l = 0; l < CHUNK_DIM; l++) {
+ if ((unsigned)data_chunk[k][l]
+ !=
+ ((DSET_DIM * DSET_DIM * m) +
+ (DSET_DIM * (i + k)) + j + l))
+ {
+ HDsnprintf(mesg, MIRR_MESG_SIZE,
+ " MISMATCH [%d][%d][%d][%d][%d]\n",
+ i, j, m, k, l);
+ FAIL_PUTS_ERROR(mesg);
+ }
+ }
+ }
+
+ }
+ }
+ }
+
+ return SUCCEED;
+
+error:
+ LOGPRINT(1, "_verify_datasets() FAILED\n");
+ return FAIL;
+} /* end _verify_datasets() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: verify_datasets
+ *
+ * Purpose: Inspect the datasets in the file created by create_datasets().
+ * Wrapper for _verify_datasets() -- this function sets up and
+ * tears down accessor information.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Jacob Smith
+ * 2019
+ * ---------------------------------------------------------------------------
+ */
+static herr_t
+verify_datasets(hid_t file_id,
+ unsigned min_dset,
+ unsigned max_dset)
+{
+ hid_t dataset_ids[MAX_DSET_COUNT + 1];
+ hid_t filespace_ids[MAX_DSET_COUNT + 1];
+ unsigned i;
+ hid_t memspace_id = H5I_INVALID_HID;
+ hsize_t chunk_dims[2] = {CHUNK_DIM, CHUNK_DIM};
+
+ HDassert(file_id >= 0);
+ HDassert(min_dset <= max_dset);
+ HDassert(max_dset <= MAX_DSET_COUNT);
+
+ LOGPRINT(2, "verify_datasets()\n");
+
+ /* ---------------------------------
+ * "Clear" ID arrays
+ */
+
+ for (i = 0; i < MAX_DSET_COUNT; i++) {
+ LOGPRINT(3, "clearing IDs [%d]\n", i);
+ dataset_ids[i] = H5I_INVALID_HID;
+ filespace_ids[i] = H5I_INVALID_HID;
+ }
+
+ /* ---------------------------------
+ * Generate dataspace, dataset, and 'filespace' IDs
+ */
+
+ if (_open_chunking_ids(file_id, min_dset, max_dset, chunk_dims,
+ filespace_ids, dataset_ids, &memspace_id)
+ == FAIL)
+ {
+ TEST_ERROR;
+ }
+
+ /* ---------------------------------
+ * Read and verify data from datasets
+ */
+
+ if (_verify_datasets(min_dset, max_dset, filespace_ids, dataset_ids,
+ memspace_id)
+ == FAIL)
+ {
+ TEST_ERROR;
+ }
+
+ /* ---------------------------------
+ * Cleanup
+ */
+
+ if (_close_chunking_ids(min_dset, max_dset, NULL, filespace_ids,
+ dataset_ids, &memspace_id)
+ == FAIL)
+ {
+ TEST_ERROR;
+ }
+
+ return SUCCEED;
+
+error:
+ LOGPRINT(1, "verify_datasets() FAILED\n");
+ (void)_close_chunking_ids(min_dset, max_dset, NULL, filespace_ids,
+ dataset_ids, &memspace_id);
+ return FAIL;
+
+} /* end verify_datasets() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: test_basic_dataset_write
+ *
+ * Purpose: Create and close files; repoen files and write a dataset,
+ * close; compare files.
+ *
+ * TODO: receive target IP from caller?
+ *
+ * Return: Success: 0
+ * Failure: -1
+ *
+ * Programmer: Jacob Smith
+ * 2019
+ * ---------------------------------------------------------------------------
+ */
+static int
+test_basic_dataset_write(void)
+{
+ struct mirrortest_filenames names;
+ hid_t file_id = H5I_INVALID_HID;
+ hid_t fapl_id = H5P_DEFAULT;
+ hid_t dset_id = H5I_INVALID_HID;
+ hid_t dspace_id = H5I_INVALID_HID;
+ hid_t dtype_id = H5T_NATIVE_INT;
+ hsize_t dims[2] = { DATABUFFER_SIZE, DATABUFFER_SIZE };
+ int *buf = NULL;
+ int i = 0;
+ int j = 0;
+
+ TESTING("Mirror open and dataset writing");
+
+ /* Create FAPL for Splitter[sec2|mirror]
+ */
+ fapl_id = create_mirroring_split_fapl("basic_write", &names);
+ if (H5I_INVALID_HID == fapl_id) {
+ TEST_ERROR;
+ }
+
+ /* Prepare data to be written
+ */
+ buf = (int *)HDmalloc(DATABUFFER_SIZE * DATABUFFER_SIZE * sizeof(int));
+ if (NULL == buf) {
+ TEST_ERROR;
+ }
+ for (i = 0; i < DATABUFFER_SIZE; i++) {
+ for (j = 0; j < DATABUFFER_SIZE; j++) {
+ int k = i * DATABUFFER_SIZE + j;
+ buf[k] = k;
+ }
+ }
+
+ /* -------------------- */
+ /* TEST: Create and Close */
+
+ file_id = H5Fcreate(names.rw, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id);
+ if (H5I_INVALID_HID == file_id) {
+ TEST_ERROR;
+ }
+ if (H5Fclose(file_id) == FAIL) {
+ TEST_ERROR;
+ }
+ file_id = H5I_INVALID_HID;
+
+
+ /* -------------------- */
+ /* TEST: Repoen and Write */
+
+ file_id = H5Fopen(names.rw, H5F_ACC_RDWR, fapl_id);
+ if (H5I_INVALID_HID == file_id) {
+ TEST_ERROR;
+ }
+
+ dspace_id = H5Screate_simple(2, dims, NULL);
+ if (H5I_INVALID_HID == dspace_id) {
+ TEST_ERROR;
+ }
+ dset_id = H5Dcreate2(file_id, "dataset", dtype_id, dspace_id, H5P_DEFAULT,
+ H5P_DEFAULT, H5P_DEFAULT);
+ if (H5I_INVALID_HID == dset_id) {
+ TEST_ERROR;
+ }
+
+ if (H5Dwrite(dset_id, dtype_id, H5S_ALL, H5S_ALL, H5P_DEFAULT, buf)
+ == FAIL)
+ {
+ TEST_ERROR;
+ }
+
+ /* -------------------- */
+ /* Standard cleanup */
+
+ HDfree(buf);
+ buf = NULL;
+ if (H5Dclose(dset_id) == FAIL) {
+ TEST_ERROR;
+ }
+ if (H5Sclose(dspace_id) == FAIL) {
+ TEST_ERROR;
+ }
+ if (H5Fclose(file_id) == FAIL) {
+ TEST_ERROR;
+ }
+ if (fapl_id != H5P_DEFAULT && fapl_id > 0) {
+ if (H5Pclose(fapl_id) == FAIL) {
+ TEST_ERROR;
+ }
+ }
+
+ /* -------------------- */
+ /* TEST: Verify that the R/W and W/O files are identical */
+
+ if (h5_compare_file_bytes(names.rw, names.wo) < 0) {
+ TEST_ERROR;
+ }
+
+ PASSED();
+ return 0;
+
+error:
+ H5E_BEGIN_TRY{
+ (void)H5Fclose(file_id);
+ if (buf) {
+ HDfree(buf);
+ }
+ (void)H5Dclose(dset_id);
+ (void)H5Sclose(dspace_id);
+ if (fapl_id != H5P_DEFAULT && fapl_id > 0) {
+ (void)H5Pclose(fapl_id);
+ }
+ } H5E_END_TRY;
+ return -1;
+} /* end test_basic_dataset_write() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: test_chunked_dataset_write
+ *
+ * Purpose: Create and close files; repoen files and write a dataset,
+ * close; compare files.
+ *
+ * TODO: receive target IP from caller?
+ *
+ * Return: Success: 0
+ * Failure: -1
+ *
+ * Programmer: Jacob Smith
+ * 2019
+ * ---------------------------------------------------------------------------
+ */
+static int
+test_chunked_dataset_write(void)
+{
+ struct mirrortest_filenames names;
+ hid_t file_id = H5I_INVALID_HID;
+ hid_t fapl_id = H5P_DEFAULT;
+
+ TESTING("Mirror open and dataset writing (chunked)");
+
+ /* Create FAPL for Splitter[sec2|mirror]
+ */
+ fapl_id = create_mirroring_split_fapl("chunked_write", &names);
+ if (H5I_INVALID_HID == fapl_id) {
+ TEST_ERROR;
+ }
+
+ /* -------------------- */
+ /* TEST: Create and Close */
+
+ file_id = H5Fcreate(names.rw, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id);
+ if (H5I_INVALID_HID == file_id) {
+ TEST_ERROR;
+ }
+ if (H5Fclose(file_id) == FAIL) {
+ TEST_ERROR;
+ }
+ file_id = H5I_INVALID_HID;
+
+ /* -------------------- */
+ /* TEST: Reopen and Write */
+
+ file_id = H5Fopen(names.rw, H5F_ACC_RDWR, fapl_id);
+ if (H5I_INVALID_HID == file_id) {
+ TEST_ERROR;
+ }
+
+ /* Write datasets to file
+ */
+ if (create_datasets(file_id, 0, MAX_DSET_COUNT) == FAIL) {
+ TEST_ERROR;
+ }
+
+ /* Close to 'flush to disk', and reopen file
+ */
+ if (H5Fclose(file_id) == FAIL) {
+ TEST_ERROR;
+ }
+ file_id = H5I_INVALID_HID;
+
+ /* Reopen file
+ */
+ file_id = H5Fopen(names.rw, H5F_ACC_RDWR, fapl_id);
+ if (H5I_INVALID_HID == file_id) {
+ TEST_ERROR;
+ }
+
+ /* Verify written data integrity
+ */
+ if (verify_datasets(file_id, 0, MAX_DSET_COUNT) == FAIL) {
+ TEST_ERROR;
+ }
+
+ /* -------------------- */
+ /* Standard cleanup */
+
+ if (H5Fclose(file_id) == FAIL) {
+ TEST_ERROR;
+ }
+ file_id = H5I_INVALID_HID;
+ if (fapl_id != H5P_DEFAULT && fapl_id > 0) {
+ if (H5Pclose(fapl_id) == FAIL) {
+ TEST_ERROR;
+ }
+ fapl_id = H5I_INVALID_HID;
+ }
+
+ /* -------------------- */
+ /* TEST: Verify that the R/W and W/O files are identical */
+
+ if (h5_compare_file_bytes(names.rw, names.wo) < 0) {
+ TEST_ERROR;
+ }
+
+ PASSED();
+ return 0;
+
+error:
+ H5E_BEGIN_TRY {
+ (void)H5Fclose(file_id);
+ if (fapl_id != H5P_DEFAULT && fapl_id > 0) {
+ (void)H5Pclose(fapl_id);
+ }
+ } H5E_END_TRY;
+ return -1;
+} /* end test_chunked_dataset_write() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: test_on_disk_zoo
+ *
+ * Purpose: Verify that the mirror can handle the passing of all the
+ * various on-disk data structures over the wire, as implemented
+ * in genall5.c:create_zoo().
+ *
+ * TODO: receive target IP from caller?
+ *
+ * Return: Success: 0
+ * Failure: -1
+ *
+ * Programmer: Jacob Smith
+ * 2019
+ * ---------------------------------------------------------------------------
+ */
+static int
+test_on_disk_zoo(void)
+{
+ const char grp_name[] = "/only";
+ struct mirrortest_filenames names;
+ hid_t file_id = H5I_INVALID_HID;
+ hid_t grp_id = H5I_INVALID_HID;
+ hid_t fapl_id = H5P_DEFAULT;
+
+ TESTING("'Zoo' of on-disk structures");
+
+ /* Create FAPL for Splitter[sec2|mirror]
+ */
+ fapl_id = create_mirroring_split_fapl("zoo", &names);
+ if (H5I_INVALID_HID == fapl_id) {
+ TEST_ERROR;
+ }
+
+ /* -------------------- */
+ /* TEST: Create file */
+ file_id = H5Fcreate(names.rw, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id);
+ if (H5I_INVALID_HID == file_id) {
+ TEST_ERROR;
+ }
+
+ grp_id = H5Gcreate2(file_id, grp_name, H5P_DEFAULT, H5P_DEFAULT,
+ H5P_DEFAULT);
+ if (grp_id == H5I_INVALID_HID) {
+ TEST_ERROR;
+ }
+
+ /* Create datasets in file, close (flush) and reopen, validate.
+ * Use of ( pass ) a conceit required for using create_ and validate_zoo()
+ * from cache_common and/or genall5.
+ */
+
+ if ( pass ) {
+ create_zoo(file_id, grp_name, 0);
+ }
+ if ( pass ) {
+ if (H5Fclose(file_id) == FAIL) {
+ TEST_ERROR;
+ }
+ file_id = H5Fopen(names.rw, H5F_ACC_RDWR, fapl_id);
+ if (H5I_INVALID_HID == file_id) {
+ TEST_ERROR;
+ }
+ }
+ if ( pass ) {
+ validate_zoo(file_id, grp_name, 0); /* sanity-check */
+ }
+ if ( !pass ) {
+ HDprintf(failure_mssg);
+ TEST_ERROR;
+ }
+
+ /* -------------------- */
+ /* Standard cleanup */
+
+ if (fapl_id != H5P_DEFAULT && fapl_id >= 0) {
+ if (H5Pclose(fapl_id) == FAIL) {
+ TEST_ERROR;
+ }
+ }
+ if (H5Gclose(grp_id) == FAIL) {
+ TEST_ERROR;
+ }
+ if (H5Fclose(file_id) == FAIL) {
+ TEST_ERROR;
+ }
+
+ /* -------------------- */
+ /* TEST: Verify that the R/W and W/O files are identical */
+
+ if (h5_compare_file_bytes(names.rw, names.wo) < 0) {
+ TEST_ERROR;
+ }
+
+ PASSED();
+ return 0;
+
+error:
+ H5E_BEGIN_TRY {
+ (void)H5Fclose(file_id);
+ (void)H5Gclose(grp_id);
+ if (fapl_id != H5P_DEFAULT && fapl_id > 0) {
+ (void)H5Pclose(fapl_id);
+ }
+ } H5E_END_TRY;
+ return -1;
+} /* end test_on_disk_zoo() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: test_vanishing_datasets
+ *
+ * Purpose: Verify behavior when writing to a file where data is deleted.
+ *
+ * Each dataset is populated with the value of its suffix
+ * (dset5 is all fives).
+ *
+ * Opens 0..15 create one new dataset each, '/dset[i]'.
+ * Opens 3..18 delete '/dset[1-3]'
+ *
+ * Should end with no data in file.
+ *
+ * Return: Success: 0
+ * Failure: -1
+ *
+ * Programmer: Jacob Smith
+ * 2019
+ * ---------------------------------------------------------------------------
+ */
+static int
+test_vanishing_datasets(void)
+{
+ struct mirrortest_filenames names;
+ hid_t file_id = H5I_INVALID_HID;
+ hid_t fapl_id = H5I_INVALID_HID;
+ hid_t dset_id = H5I_INVALID_HID;
+ hid_t dspace_id = H5I_INVALID_HID;
+ hid_t mirror_fapl_id = H5I_INVALID_HID;
+ hsize_t dims[2] = {DATABUFFER_SIZE, DATABUFFER_SIZE};
+ uint32_t buf[DATABUFFER_SIZE][DATABUFFER_SIZE]; /* consider malloc? */
+ H5G_info_t group_info;
+ unsigned int i, j, k;
+ const unsigned int max_loops = 20;
+ const unsigned int max_at_one_time = 3;
+
+ TESTING("Vanishing Datasets");
+
+ /* -------------------- */
+ /* Set up recurrent data (FAPL, dataspace) */
+
+ /* Create FAPL for Splitter[sec2|mirror]
+ */
+ fapl_id = create_mirroring_split_fapl("vanishing", &names);
+ if (H5I_INVALID_HID == fapl_id) {
+ TEST_ERROR;
+ }
+
+ dspace_id = H5Screate_simple(2, dims, NULL);
+ if (dspace_id < 0) {
+ TEST_ERROR;
+ }
+
+ /* create file */
+ file_id = H5Fcreate(names.rw, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id);
+ if (H5I_INVALID_HID == file_id) {
+ TEST_ERROR;
+ }
+
+ for (i=0; i < max_loops; i++) {
+ char namebuf[DSET_NAME_LEN + 1];
+
+ /* deleting datasets */
+ if (i >= max_at_one_time) {
+ if (HDsnprintf(namebuf, DSET_NAME_LEN, "/dset%02d",
+ (i - max_at_one_time) )
+ > DSET_NAME_LEN)
+ {
+ TEST_ERROR;
+ }
+ if (H5Ldelete(file_id, namebuf, H5P_DEFAULT) < 0) {
+ TEST_ERROR;
+ }
+ } /* end if deleting a dataset */
+
+ /* writing datasets */
+ if (i < (max_loops - max_at_one_time)) {
+ if (HDsnprintf(namebuf, DSET_NAME_LEN, "/dset%02d", i)
+ > DSET_NAME_LEN)
+ {
+ TEST_ERROR;
+ }
+ dset_id = H5Dcreate2(file_id, namebuf, H5T_STD_U32LE, dspace_id,
+ H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
+ if (H5I_INVALID_HID == dset_id) {
+ TEST_ERROR;
+ }
+
+ for (j=0; j < DATABUFFER_SIZE; j++) {
+ for (k=0; k < DATABUFFER_SIZE; k++) {
+ buf[j][k] = (uint32_t)i;
+ }
+ }
+
+ if (H5Dwrite(dset_id, H5T_STD_U32LE, H5S_ALL, H5S_ALL, H5P_DEFAULT,
+ buf)
+ < 0)
+ {
+ TEST_ERROR;
+ }
+
+ if (H5Dclose(dset_id) < 0) {
+ TEST_ERROR;
+ }
+ dset_id = H5I_INVALID_HID;
+ } /* end if writing a dataset */
+
+ } /* end for dataset create-destroy cycles */
+
+ if (H5Fclose(file_id) < 0) {
+ TEST_ERROR;
+ }
+ file_id = H5I_INVALID_HID;
+
+ /* verify there are no datasets in file */
+ file_id = H5Fopen(names.rw, H5F_ACC_RDONLY, H5P_DEFAULT);
+ if (file_id < 0) {
+ TEST_ERROR;
+ }
+ if (H5Gget_info(file_id, &group_info) < 0) {
+ TEST_ERROR;
+ }
+ if (group_info.nlinks > 0) {
+ HDfprintf(stderr, "links in rw file: %d\n", group_info.nlinks);
+ HDfflush(stderr);
+ TEST_ERROR;
+ }
+ if (H5Fclose(file_id) < 0) {
+ TEST_ERROR;
+ }
+ file_id = H5Fopen(names.wo, H5F_ACC_RDONLY, H5P_DEFAULT);
+ if (file_id < 0) {
+ TEST_ERROR;
+ }
+ if (H5Gget_info(file_id, &group_info) < 0) {
+ TEST_ERROR;
+ }
+ if (group_info.nlinks > 0) {
+ HDfprintf(stderr, "links in wo file: %d\n", group_info.nlinks);
+ HDfflush(stderr);
+ TEST_ERROR;
+ }
+ if (H5Fclose(file_id) < 0) {
+ TEST_ERROR;
+ }
+ file_id = H5I_INVALID_HID;
+
+ if (h5_compare_file_bytes(names.rw, names.wo) < 0)
+ TEST_ERROR;
+
+ /* -------------------- */
+ /* Teardown */
+
+ if (H5Sclose(dspace_id) < 0) {
+ TEST_ERROR;
+ }
+ if (H5Pclose(fapl_id) < 0) {
+ TEST_ERROR;
+ }
+
+ PASSED();
+ return 0;
+
+error:
+ H5E_BEGIN_TRY {
+ if (mirror_fapl_id != H5I_INVALID_HID) {
+ H5Pclose(mirror_fapl_id);
+ }
+ if (fapl_id != H5I_INVALID_HID) {
+ H5Pclose(fapl_id);
+ }
+ if (file_id != H5I_INVALID_HID) {
+ H5Fclose(file_id);
+ }
+ if (dset_id != H5I_INVALID_HID) {
+ H5Dclose(dset_id);
+ }
+ if (dspace_id != H5I_INVALID_HID) {
+ H5Sclose(dspace_id);
+ }
+ } H5E_END_TRY;
+ return -1;
+} /* test_vanishing_datasets() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: test_concurrent_access
+ *
+ * Purpose: Verify that more than one file may be opened at a time.
+ *
+ * TODO: receive target IP from caller?
+ *
+ * Return: Success: 0
+ * Failure: -1
+ *
+ * Programmer: Jacob Smith
+ * 2020-03-09
+ * ---------------------------------------------------------------------------
+ */
+static int
+test_concurrent_access(void)
+{
+ struct file_bundle {
+ struct mirrortest_filenames names;
+ hid_t dset_id;
+ hid_t fapl_id;
+ hid_t file_id;
+ } bundle[CONCURRENT_COUNT];
+ hid_t dspace_id = H5I_INVALID_HID;
+ hid_t dtype_id = H5T_NATIVE_INT;
+ hsize_t dims[2] = { DATABUFFER_SIZE, DATABUFFER_SIZE };
+ int *buf = NULL;
+ int i = 0;
+ int j = 0;
+
+ TESTING("Concurrent opened mirrored files");
+
+ /* blank bundle */
+ for (i = 0; i < CONCURRENT_COUNT; i++) {
+ bundle[i].dset_id = H5I_INVALID_HID;
+ bundle[i].fapl_id = H5I_INVALID_HID;
+ bundle[i].file_id = H5I_INVALID_HID;
+ *bundle[i].names.rw = '\0';
+ *bundle[i].names.wo = '\0';
+ *bundle[i].names.log = '\0';
+ }
+
+ /* Create FAPL for Splitter[sec2|mirror]
+ */
+ for (i = 0; i < CONCURRENT_COUNT; i++) {
+ char _name[16] = "";
+ hid_t _fapl_id = H5I_INVALID_HID;
+ HDsnprintf(_name, 15, "concurrent%d", i);
+ _fapl_id = create_mirroring_split_fapl(_name, &bundle[i].names);
+ if (H5I_INVALID_HID == _fapl_id) {
+ TEST_ERROR;
+ }
+ bundle[i].fapl_id = _fapl_id;
+ }
+
+ /* Prepare data to be written
+ */
+ buf = (int *)HDmalloc(DATABUFFER_SIZE * DATABUFFER_SIZE * sizeof(int));
+ if (NULL == buf) {
+ TEST_ERROR;
+ }
+ for (i = 0; i < DATABUFFER_SIZE; i++) {
+ for (j = 0; j < DATABUFFER_SIZE; j++) {
+ int k = i * DATABUFFER_SIZE + j;
+ buf[k] = k;
+ }
+ }
+
+ /* Prepare generic dataspace
+ */
+ dspace_id = H5Screate_simple(2, dims, NULL);
+ if (H5I_INVALID_HID == dspace_id) {
+ TEST_ERROR;
+ }
+
+ /* -------------------- */
+ /* TEST: Create file and open elements */
+
+ for (i = 0; i < CONCURRENT_COUNT; i++) {
+ hid_t _file_id = H5I_INVALID_HID;
+ hid_t _dset_id = H5I_INVALID_HID;
+
+ _file_id = H5Fcreate(bundle[i].names.rw, H5F_ACC_TRUNC, H5P_DEFAULT,
+ bundle[i].fapl_id);
+ if (H5I_INVALID_HID == _file_id) {
+ TEST_ERROR;
+ }
+
+ bundle[i].file_id = _file_id;
+
+ _dset_id = H5Dcreate2(_file_id, "dataset", dtype_id, dspace_id,
+ H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
+ if (H5I_INVALID_HID == _dset_id) {
+ TEST_ERROR;
+ }
+ bundle[i].dset_id = _dset_id;
+ }
+
+ /* -------------------- */
+ /* TEST: Write to files */
+
+ for (i = 0; i < CONCURRENT_COUNT; i++) {
+ if (H5Dwrite(bundle[i].dset_id, dtype_id, H5S_ALL, H5S_ALL,
+ H5P_DEFAULT, buf)
+ == FAIL)
+ {
+ TEST_ERROR;
+ }
+ }
+
+ /* -------------------- */
+ /* TEST: Close elements */
+
+ for (i = 0; i < CONCURRENT_COUNT; i++) {
+ if (H5Dclose(bundle[i].dset_id) == FAIL) {
+ TEST_ERROR;
+ }
+ if (H5Fclose(bundle[i].file_id) == FAIL) {
+ TEST_ERROR;
+ }
+ if (H5Pclose(bundle[i].fapl_id) == FAIL) {
+ TEST_ERROR;
+ }
+ }
+
+ /* -------------------- */
+ /* Standard cleanup */
+
+ HDfree(buf);
+ buf = NULL;
+ if (H5Sclose(dspace_id) == FAIL) {
+ TEST_ERROR;
+ }
+
+ /* -------------------- */
+ /* TEST: Verify that the R/W and W/O files are identical */
+
+ for (i = 0; i < CONCURRENT_COUNT; i++) {
+ if (h5_compare_file_bytes(bundle[i].names.rw, bundle[i].names.wo) < 0) {
+ TEST_ERROR;
+ }
+ }
+
+ PASSED();
+ return 0;
+
+error:
+ H5E_BEGIN_TRY{
+ if (buf) {
+ HDfree(buf);
+ }
+ (void)H5Sclose(dspace_id);
+ for (i = 0; i < CONCURRENT_COUNT; i++) {
+ (void)H5Dclose(bundle[i].dset_id);
+ (void)H5Fclose(bundle[i].file_id);
+ (void)H5Pclose(bundle[i].fapl_id);
+ }
+ } H5E_END_TRY;
+ return -1;
+} /* end test_concurrent_access() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: main
+ *
+ * Purpose: Run tests.
+ *
+ * Return: Success: 0
+ * Failure: 1
+ *
+ * Programmer: Jacob Smith
+ * 2019
+ * ---------------------------------------------------------------------------
+ */
+int
+main(void)
+{
+ int nerrors = 0;
+
+ h5_reset();
+
+ g_log_stream = stdout; /* default debug/logging output stream */
+
+ HDprintf("Testing Mirror VFD functionality.\n");
+
+ /* -------------------- */
+ /* SETUP */
+
+ /* Create directories for test-generated .h5 files
+ */
+ if (nerrors == 0) {
+ if ((HDmkdir(MIRROR_RW_DIR, (mode_t)0755) < 0) && (errno != EEXIST)) {
+ nerrors++;
+ }
+ }
+ if (nerrors == 0) {
+ if ((HDmkdir(MIRROR_WO_DIR, (mode_t)0755) < 0) && (errno != EEXIST)) {
+ nerrors++;
+ }
+ }
+
+ /* -------------------- */
+ /* TESTS */
+ /* Tests return negative values; `-=' increments nerrors count */
+
+ if (nerrors == 0) {
+ nerrors -= test_fapl_configuration();
+ nerrors -= test_xmit_encode_decode();
+ nerrors -= test_create_and_close();
+ nerrors -= test_basic_dataset_write();
+ nerrors -= test_chunked_dataset_write();
+ nerrors -= test_on_disk_zoo();
+ nerrors -= test_vanishing_datasets();
+ nerrors -= test_concurrent_access();
+ }
+
+ if (nerrors) {
+ HDprintf("***** %d Mirror VFD TEST%s FAILED! *****\n",
+ nerrors, nerrors > 1 ? "S" : "");
+ return EXIT_FAILURE;
+ }
+
+ HDprintf("All Mirror Virtual File Driver tests passed.\n");
+ return EXIT_SUCCESS;
+} /* end main() */
+
+#else /* H5_HAVE_MIRROR_VFD */
+
+int
+main(void)
+{
+ h5_reset();
+ HDprintf("Testing Mirror VFD functionality.\n");
+ HDprintf("SKIPPED - Mirror VFD not built.\n");
+ return EXIT_SUCCESS;
+}
+
+#endif /* H5_HAVE_MIRROR_VFD */
+
+
diff --git a/test/test_mirror.sh.in b/test/test_mirror.sh.in
new file mode 100644
index 0000000..9635c38
--- /dev/null
+++ b/test/test_mirror.sh.in
@@ -0,0 +1,100 @@
+#! /bin/bash
+#
+# Copyright by The HDF Group.
+# 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.
+#
+# Tests for the Mirror VFD feature.
+#
+# Created:
+# Jacob Smith, 2019-12-30
+
+###############################################################################
+## test parameters
+###############################################################################
+
+nerrors=0
+
+SERVER_VERBOSITY="--verbosity=1"
+SERVER_PORT="--port=3000"
+
+
+###############################################################################
+## Main
+###############################################################################
+
+## TODO: arguments for main port, port range, verbosity?
+# Parse options (none accepted at this time)
+while [ $# -gt 0 ]; do
+ case "$1" in
+ *) # unknown option
+ echo "$0: Unknown option ($1)"
+ exit 1
+ ;;
+ esac
+done
+
+
+
+RUN_DIR=mirror_vfd_test
+MIRROR_UTILS=../utils/mirror_vfd # TODO: presupposes from test/
+
+mkdir $RUN_DIR
+
+# Copy program files into dedicated test directory
+for FILE in $MIRROR_UTILS/mirror_* ; do
+ case "$FILE" in
+ *.o) continue ;; # Don't copy .o files
+ esac
+ cp $FILE $RUN_DIR
+done
+cp mirror_vfd $RUN_DIR
+
+# With the --disable-shared option, program files are built in their main
+# directories; otherwise they are built in dir/.libs with a corresponding
+# wrapper script. Copy these libs builds if appropriate.
+if [ -f $MIRROR_UTILS/.libs/mirror_server ] ; then
+ RUN_LIBS=$RUN_DIR/.libs
+ mkdir $RUN_LIBS
+ for FILE in $MIRROR_UTILS/.libs/mirror_* ; do
+ case "$FILE" in
+ *.o) continue ;; # Don't copy .o files
+ esac
+ cp $FILE $RUN_LIBS
+ done
+ cp .libs/mirror_vfd $RUN_LIBS
+fi
+
+cd $RUN_DIR
+
+echo "Launching Mirror Server"
+SERVER_ARGS="$SERVER_PORT $SERVER_VERBOSITY"
+./mirror_server $SERVER_ARGS &
+
+./mirror_vfd
+nerrors=$?
+
+echo "Stopping Mirror Server"
+./mirror_server_stop $SERVER_PORT
+
+###############################################################################
+## Report and exit
+###############################################################################
+cd ..
+if test $nerrors -eq 0 ; then
+ echo "Mirror VFD tests passed."
+ if test -z "$HDF5_NOCLEANUP" ; then
+ rm -rf $RUN_DIR
+ fi
+ exit 0
+else
+ echo "Mirror VFD tests FAILED."
+ exit 1
+fi
+
diff --git a/test/use.h b/test/use.h
index 54d9b26..e5eced2 100644
--- a/test/use.h
+++ b/test/use.h
@@ -16,48 +16,46 @@
#include "h5test.h"
/* Macro definitions */
-#define Hgoto_error(val) {ret_value=val; goto done;}
-#define Hgoto_done {goto done;}
-#define Chunksize_DFT 256 /* chunksize default */
-#define ErrorReportMax 10 /* max number of errors reported */
+#define Hgoto_error(val) {ret_value=val; goto done;}
+#define Hgoto_done {goto done;}
+#define Chunksize_DFT 256 /* chunksize default */
+#define ErrorReportMax 10 /* max number of errors reported */
/* these two definitions must match each other */
-#define UC_DATATYPE H5T_NATIVE_SHORT /* use case HDF5 data type */
-#define UC_CTYPE short /* use case C data type */
-#define UC_RANK 3 /* use case dataset rank */
+#define UC_DATATYPE H5T_NATIVE_SHORT /* use case HDF5 data type */
+#define UC_CTYPE short /* use case C data type */
+#define UC_RANK 3 /* use case dataset rank */
/* Name of message file that is sent by the writer */
#define WRITER_MESSAGE "USE_WRITER_MESSAGE"
/* type declarations */
typedef enum part_t {
- UC_READWRITE =0, /* both writer and reader */
- UC_WRITER, /* writer only */
- UC_READER /* reader only */
+ UC_READWRITE = 0, /* both writer and reader */
+ UC_WRITER, /* writer only */
+ UC_READER /* reader only */
} part_t;
typedef struct options_t {
- hsize_t chunksize; /* chunks are chunksize^2 planes */
- hsize_t chunkplanes; /* number of planes per chunk, default 1 */
+ hsize_t chunksize; /* chunks are chunksize^2 planes */
+ hsize_t chunkplanes; /* number of planes per chunk, default 1 */
hsize_t chunkdims[UC_RANK]; /* chunk dims is (chunkplan, chunksize, chunksize) */
hsize_t dims[UC_RANK]; /* dataset initial dims */
hsize_t max_dims[UC_RANK]; /* dataset max dims */
- hsize_t nplanes; /* number of planes to write, default proportional to chunksize */
- char *filename; /* use case data filename */
- part_t launch; /* launch writer, reader or both */
- hbool_t use_swmr; /* use swmr open (1) or not */
- int iterations; /* iterations, default 1 */
+ hsize_t nplanes; /* number of planes to write, default proportional to chunksize */
+ char *filename; /* use case data filename */
+ part_t launch; /* launch writer, reader or both */
+ hbool_t use_swmr; /* use swmr open (1) or not */
+ int iterations; /* iterations, default 1 */
+ hid_t fapl_id; /* instance-specific FAPL ID */
+ char *progname; /* Program name (used in usage and dset name) */
} options_t;
-/* global variables declarations */
-extern options_t UC_opts; /* Use Case Options */
-extern const char *progname_g; /* Program name */
-
/* prototype declarations */
-int parse_option(int argc, char * const argv[]);
-int setup_parameters(int argc, char * const argv[]);
-void show_parameters(void);
+int parse_option(int argc, char * const argv[], options_t * opts);
+int setup_parameters(int argc, char * const argv[], options_t * opts);
+void show_parameters(options_t * opts);
void usage(const char *prog);
-int create_uc_file(void);
-int write_uc_file(hbool_t tosend, hid_t fid);
-int read_uc_file(hbool_t towait);
+int create_uc_file(options_t * opts);
+int write_uc_file(hbool_t tosend, hid_t file_id, options_t * opts);
+int read_uc_file(hbool_t towait, options_t * opts);
diff --git a/test/use_append_chunk.c b/test/use_append_chunk.c
index 6b34f1e..35594cf 100644
--- a/test/use_append_chunk.c
+++ b/test/use_append_chunk.c
@@ -11,7 +11,7 @@
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * Use Case 1.7 Appending a single chunk
+ * Use Case 1.7 Appending a single chunk
* Description:
* Appending a single chunk of raw data to a dataset along an unlimited
* dimension within a pre-created file and reading the new data back.
@@ -24,35 +24,36 @@
* Level:
* User Level
* Guarantees:
- * o Readers will see the modified dimension sizes after the Writer
- * finishes HDF5 metadata updates and issues H5Fflush or H5Oflush calls.
- * o Readers will see newly appended data after the Writer finishes
- * the flush operation.
- *
+ * o Readers will see the modified dimension sizes after the Writer
+ * finishes HDF5 metadata updates and issues H5Fflush or H5Oflush calls.
+ * o Readers will see newly appended data after the Writer finishes
+ * the flush operation.
+ *
* Preconditions:
- * o Readers are not allowed to modify the file. o All datasets
- * that are modified by the Writer exist when the Writer opens the file.
- * o All datasets that are modified by the Writer exist when a Reader
- * opens the file. o Data is written by a hyperslab contained in
- * one chunk.
- *
+ * o Readers are not allowed to modify the file.
+ * o All datasets that are modified by the Writer exist when the Writer
+ * opens the file.
+ * o All datasets that are modified by the Writer exist when a Reader
+ * opens the file.
+ * o Data is written by a hyperslab contained in one chunk.
+ *
* Main Success Scenario:
- * 1. An application creates a file with required objects (groups,
- * datasets, and attributes).
- * 2. The Writer application opens the file and datasets in the file
- * and starts adding data along the unlimited dimension using a hyperslab
- * selection that corresponds to an HDF5 chunk.
- * 3. A Reader opens the file and a dataset in a file, and queries
- * the sizes of the dataset; if the extent of the dataset has changed,
- * reads the appended data back.
- *
+ * 1. An application creates a file with required objects (groups,
+ * datasets, and attributes).
+ * 2. The Writer application opens the file and datasets in the file
+ * and starts adding data along the unlimited dimension using a hyperslab
+ * selection that corresponds to an HDF5 chunk.
+ * 3. A Reader opens the file and a dataset in a file, and queries
+ * the sizes of the dataset; if the extent of the dataset has changed,
+ * reads the appended data back.
+ *
* Discussion points:
- * 1. Since the new data is written to the file, and metadata update
- * operation of adding pointer to the newly written chunk is atomic and
- * happens after the chunk is on the disk, only two things may happen
- * to the Reader:
- * o The Reader will not see new data.
- * o The Reader will see all new data written by Writer.
+ * 1. Since the new data is written to the file, and metadata update
+ * operation of adding pointer to the newly written chunk is atomic and
+ * happens after the chunk is on the disk, only two things may happen
+ * to the Reader:
+ * o The Reader will not see new data.
+ * o The Reader will see all new data written by Writer.
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* Created: Albert Cheng, 2013/5/28 */
@@ -68,46 +69,43 @@
#include "use.h"
-/* Global Variable definitions */
-options_t UC_opts; /* Use Case Options */
-const char *progname_g="use_append_chunk"; /* program name */
+#define USE_APPEND_CHUNK_PROGNAME "use_append_chunk"
+
+static options_t UC_opts; /* Use Case Options */
/* Setup parameters for the use case.
* Return: 0 succeed; -1 fail.
*/
-int setup_parameters(int argc, char * const argv[])
+int
+setup_parameters(int argc, char * const argv[], options_t * opts)
{
/* use case defaults */
- HDmemset(&UC_opts, 0, sizeof(options_t));
- UC_opts.chunksize = Chunksize_DFT;
- UC_opts.use_swmr = TRUE; /* use swmr open */
- UC_opts.iterations = 1;
- UC_opts.chunkplanes = 1;
-
- /* parse options */
- if (parse_option(argc, argv) < 0)
- return(-1);
-
- /* set chunk dims */
- UC_opts.chunkdims[0] = UC_opts.chunkplanes;
- UC_opts.chunkdims[1] = UC_opts.chunkdims[2] = UC_opts.chunksize;
-
- /* set dataset initial and max dims */
- UC_opts.dims[0] = 0;
- UC_opts.max_dims[0] = H5S_UNLIMITED;
- UC_opts.dims[1] = UC_opts.dims[2] = UC_opts.max_dims[1] = UC_opts.max_dims[2] = UC_opts.chunksize;
-
- /* set nplanes */
- if (UC_opts.nplanes == 0)
- UC_opts.nplanes = (hsize_t)UC_opts.chunksize;
-
- /* show parameters and return */
- show_parameters();
+ HDmemset(opts, 0, sizeof(options_t));
+ opts->chunksize = Chunksize_DFT;
+ opts->use_swmr = TRUE; /* use swmr open */
+ opts->iterations = 1;
+ opts->chunkplanes = 1;
+ opts->progname = USE_APPEND_CHUNK_PROGNAME;
+
+ if (parse_option(argc, argv, opts) < 0)
+ return(-1);
+
+ opts->chunkdims[0] = opts->chunkplanes;
+ opts->chunkdims[1] = opts->chunkdims[2] = opts->chunksize;
+
+ opts->dims[0] = 0;
+ opts->max_dims[0] = H5S_UNLIMITED;
+ opts->dims[1] = opts->dims[2] = opts->max_dims[1] = opts->max_dims[2] = opts->chunksize;
+
+ if (opts->nplanes == 0)
+ opts->nplanes = (hsize_t)opts->chunksize;
+
+ show_parameters(opts);
return(0);
-}
+} /* setup_parameters() */
-/* Overall Algorithm:
+/* Overall Algorithm:
* Parse options from user;
* Generate/pre-created test files needed and close it;
* fork: child process becomes the reader process;
@@ -119,22 +117,20 @@ main(int argc, char *argv[])
{
pid_t childpid=0;
pid_t mypid, tmppid;
- int child_status;
+ int child_status;
int child_wait_option=0;
int ret_value = 0;
int child_ret_value;
hbool_t send_wait = FALSE;
hid_t fapl = -1; /* File access property list */
hid_t fid = -1; /* File ID */
- char *name; /* Test file name */
- /* initialization */
- if (setup_parameters(argc, argv) < 0){
+ if (setup_parameters(argc, argv, &UC_opts) < 0) {
Hgoto_error(1);
}
/* Determine the need to send/wait message file*/
- if(UC_opts.launch == UC_READWRITE) {
+ if (UC_opts.launch == UC_READWRITE) {
HDunlink(WRITER_MESSAGE);
send_wait = TRUE;
}
@@ -144,38 +140,63 @@ main(int argc, char *argv[])
/* UC_WRITER: create datafile, skip reader, launch writer. */
/* UC_READER: skip create, launch reader, exit. */
/* ==============================================================*/
- /* ============*/
+ /* =========== */
/* Create file */
- /* ============*/
- if (UC_opts.launch != UC_READER){
+ /* =========== */
+ if (UC_opts.launch != UC_READER) {
HDprintf("Creating skeleton data file for test...\n");
- if (create_uc_file() < 0){
+ if ((UC_opts.fapl_id = h5_fileaccess()) < 0) {
+ HDfprintf(stderr, "can't create creation FAPL\n");
+ Hgoto_error(1);
+ }
+ if (H5Pset_libver_bounds(UC_opts.fapl_id, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST) < 0) {
+ HDfprintf(stderr, "can't set creation FAPL libver bounds\n");
+ Hgoto_error(1);
+ }
+ if (create_uc_file(&UC_opts) < 0) {
HDfprintf(stderr, "***encounter error\n");
Hgoto_error(1);
- }else
+ } else {
HDprintf("File created.\n");
+ }
+ /* Close FAPL to prevent issues with forking later */
+ if (H5Pclose(UC_opts.fapl_id) < 0) {
+ HDfprintf(stderr, "can't close creation FAPL\n");
+ Hgoto_error(1);
+ }
+ UC_opts.fapl_id = H5I_INVALID_HID;
}
- if (UC_opts.launch==UC_READWRITE){
- /* fork process */
- if((childpid = HDfork()) < 0) {
+ /* ============ */
+ /* Fork process */
+ /* ============ */
+ if (UC_opts.launch == UC_READWRITE) {
+ if ((childpid = HDfork()) < 0) {
HDperror("fork");
Hgoto_error(1);
- };
- };
+ }
+ }
mypid = HDgetpid();
/* ============= */
/* launch reader */
/* ============= */
- if (UC_opts.launch != UC_WRITER){
+ if (UC_opts.launch != UC_WRITER) {
/* child process launch the reader */
- if(0 == childpid) {
+ if (0 == childpid) {
HDprintf("%d: launch reader process\n", mypid);
- if (read_uc_file(send_wait) < 0){
+ if ((UC_opts.fapl_id = h5_fileaccess()) < 0) {
+ HDfprintf(stderr, "can't create read FAPL\n");
+ HDexit(EXIT_FAILURE);
+ }
+ if (read_uc_file(send_wait, &UC_opts) < 0) {
HDfprintf(stderr, "read_uc_file encountered error\n");
HDexit(EXIT_FAILURE);
}
+ if (H5Pclose(UC_opts.fapl_id) < 0) {
+ HDfprintf(stderr, "can't close read FAPL\n");
+ HDexit(EXIT_FAILURE);
+ }
HDexit(EXIT_SUCCESS);
}
}
@@ -186,65 +207,63 @@ main(int argc, char *argv[])
/* this process continues to launch the writer */
HDprintf("%d: continue as the writer process\n", mypid);
- name = UC_opts.filename;
-
- /* Set file access proeprty list */
- if((fapl = h5_fileaccess()) < 0)
+ if ((fapl = h5_fileaccess()) < 0) {
+ HDfprintf(stderr, "can't create write FAPL\n");
Hgoto_error(1);
+ }
- if(UC_opts.use_swmr)
- if(H5Pset_libver_bounds(fapl, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST) < 0)
+ if (UC_opts.use_swmr) {
+ if (H5Pset_libver_bounds(fapl, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST) < 0) {
+ HDfprintf(stderr, "can't set write FAPL libver bounds\n");
Hgoto_error(1);
+ }
+ }
- /* Open the file */
- if((fid = H5Fopen(name, H5F_ACC_RDWR | (UC_opts.use_swmr ? H5F_ACC_SWMR_WRITE : 0), fapl)) < 0) {
+ if ((fid = H5Fopen(UC_opts.filename, H5F_ACC_RDWR | (UC_opts.use_swmr ? H5F_ACC_SWMR_WRITE : 0), fapl)) < 0) {
HDfprintf(stderr, "H5Fopen failed\n");
Hgoto_error(1);
}
- if(write_uc_file(send_wait, fid) < 0) {
+ if (write_uc_file(send_wait, fid, &UC_opts) < 0) {
HDfprintf(stderr, "write_uc_file encountered error\n");
Hgoto_error(1);
}
+ if (H5Fclose(fid) < 0) {
+ HDfprintf(stderr, "Failed to close write\n");
+ Hgoto_error(1);
+ }
+
+ if (H5Pclose(fapl) < 0) {
+ HDfprintf(stderr, "can't close write FAPL\n");
+ Hgoto_error(1);
+ }
+
/* ================================================ */
/* If readwrite, collect exit code of child process */
/* ================================================ */
- if (UC_opts.launch == UC_READWRITE){
- if ((tmppid = HDwaitpid(childpid, &child_status, child_wait_option)) < 0){
+ if (UC_opts.launch == UC_READWRITE) {
+ if ((tmppid = HDwaitpid(childpid, &child_status, child_wait_option)) < 0) {
HDperror("waitpid");
Hgoto_error(1);
}
- /* Close the file */
- if(H5Fclose(fid) < 0) {
- HDfprintf(stderr, "Failed to close file id\n");
- Hgoto_error(1);
- }
-
- /* Close the property list */
- if(H5Pclose(fapl) < 0) {
- HDfprintf(stderr, "Failed to close the property list\n");
- Hgoto_error(1);
- }
-
- if (WIFEXITED(child_status)){
- if ((child_ret_value=WEXITSTATUS(child_status)) != 0){
+ if (WIFEXITED(child_status)) {
+ if ((child_ret_value = WEXITSTATUS(child_status)) != 0) {
HDprintf("%d: child process exited with non-zero code (%d)\n",
mypid, child_ret_value);
Hgoto_error(2);
}
- } else {
- HDprintf("%d: child process terminated abnormally\n", mypid);
- Hgoto_error(2);
- }
+ } else {
+ HDprintf("%d: child process terminated abnormally\n", mypid);
+ Hgoto_error(2);
+ }
}
-
+
done:
- /* Print result and exit */
- if (ret_value != 0){
+ if (ret_value != 0) {
HDprintf("Error(s) encountered\n");
- }else{
+ } else {
HDprintf("All passed\n");
}
diff --git a/test/use_append_chunk_mirror.c b/test/use_append_chunk_mirror.c
new file mode 100644
index 0000000..6ee01c0
--- /dev/null
+++ b/test/use_append_chunk_mirror.c
@@ -0,0 +1,403 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * 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. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/* HACKED VERSION
+ * Demonstrate SWMR with a mirrored file.
+ *
+ * Must be built with SERVER_IP as the IP address of the target system
+ * with a running mirror server, and SERVER_PORT as the primary server port.
+ *
+ * In addition to the local file, 'shinano.h5' will be created on the remote
+ * system, mirroring the local file. The file location will be local to
+ * Server's/Writer's invocation directory.
+ *
+ * Template for demonstration purposes:
+ *
+ * # Launch mirror server on remote machine (in foreground to easily stop)
+ * REMOTE(1)$ ./mirror_server /path/to/mirror_worker
+ *
+ * # Launch chunk writer with plenty of chunks.
+ * LOCAL(1)$ ./use_append_chunk_mirror -l w -n 10000
+ *
+ * # Wait one second for files to be created.
+ *
+ * # Launch chunk readers on both files.
+ * LOCAL(2)$ ./use_append_chunk_mirror -l r -n 10000
+ * REMOTE(2)$ ./use_append_chunk_mirror -l r -n 10000 -f shinano.h5
+ *
+ * # Hard-stop the server.
+ * REMOTE(1)$ ^C
+ * # alt, softer shutdown using echo and nc
+ * echo "SHUTDOWN" | nc localhost 3000
+ */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Use Case 1.7 Appending a single chunk
+ * Description:
+ * Appending a single chunk of raw data to a dataset along an unlimited
+ * dimension within a pre-created file and reading the new data back.
+ * Goal:
+ * Read data appended by the Writer to a pre-existing dataset in a
+ * file. The dataset has one or more unlimited dimensions. The data is
+ * appended by a hyperslab that is contained in one chunk (for example,
+ * appending 2-dim planes along the slowest changing dimension in the
+ * 3-dim dataset).
+ * Level:
+ * User Level
+ * Guarantees:
+ * o Readers will see the modified dimension sizes after the Writer
+ * finishes HDF5 metadata updates and issues H5Fflush or H5Oflush calls.
+ * o Readers will see newly appended data after the Writer finishes
+ * the flush operation.
+ *
+ * Preconditions:
+ * o Readers are not allowed to modify the file.
+ * o All datasets that are modified by the Writer exist when the Writer
+ * opens the file.
+ * o All datasets that are modified by the Writer exist when a Reader
+ * opens the file.
+ * o Data is written by a hyperslab contained in one chunk.
+ *
+ * Main Success Scenario:
+ * 1. An application creates a file with required objects (groups,
+ * datasets, and attributes).
+ * 2. The Writer application opens the file and datasets in the file
+ * and starts adding data along the unlimited dimension using a hyperslab
+ * selection that corresponds to an HDF5 chunk.
+ * 3. A Reader opens the file and a dataset in a file, and queries
+ * the sizes of the dataset; if the extent of the dataset has changed,
+ * reads the appended data back.
+ *
+ * Discussion points:
+ * 1. Since the new data is written to the file, and metadata update
+ * operation of adding pointer to the newly written chunk is atomic and
+ * happens after the chunk is on the disk, only two things may happen
+ * to the Reader:
+ * o The Reader will not see new data.
+ * o The Reader will see all new data written by Writer.
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/* Created: Jacob Smith, 2019 */
+
+#include "use.h"
+
+/* This test uses many POSIX things that are not available on
+ * Windows. We're using a check for fork(2) here as a proxy for
+ * all POSIX/Unix/Linux things until this test can be made
+ * more platform-independent.
+ */
+#ifdef H5_HAVE_FORK
+
+#ifdef H5_HAVE_MIRROR_VFD
+
+#define THIS_PROGNAME "use_append_chunk_mirror"
+
+#define CONNECT_WITH_JELLY 0
+
+#if CONNECT_WITH_JELLY
+#define SERVER_IP "10.10.10.248" /* hard-coded IP address */
+#else
+#define SERVER_IP "127.0.0.1" /* localhost */
+#endif /* CONNECT_WITH_JELLY */
+#define SERVER_PORT 3000 /* hard-coded port number */
+#define MIRROR_FILE_NAME "shinano.h5" /* hard-coded duplicate/mirror filename */
+
+static options_t UC_opts; /* Use Case Options */
+
+/* Setup parameters for the use case.
+ * Return: 0 succeed; -1 fail.
+ */
+int
+setup_parameters(int argc, char * const argv[], options_t * opts)
+{
+ /* use case defaults */
+ HDmemset(opts, 0, sizeof(options_t));
+ opts->chunksize = Chunksize_DFT;
+ opts->use_swmr = TRUE;
+ opts->iterations = 1;
+ opts->chunkplanes = 1;
+ opts->progname = THIS_PROGNAME;
+
+ if (parse_option(argc, argv, opts) < 0)
+ return(-1);
+
+ opts->chunkdims[0] = opts->chunkplanes;
+ opts->chunkdims[1] = opts->chunkdims[2] = opts->chunksize;
+
+ opts->dims[0] = 0;
+ opts->max_dims[0] = H5S_UNLIMITED;
+ opts->dims[1] = opts->dims[2] = opts->max_dims[1] = opts->max_dims[2] = opts->chunksize;
+
+ if (opts->nplanes == 0)
+ opts->nplanes = (hsize_t)opts->chunksize;
+
+ show_parameters(opts);
+ return(0);
+} /* setup_parameters() */
+
+
+/* Overall Algorithm:
+ * Parse options from user;
+ * Generate/pre-created test files needed and close it;
+ * fork: child process becomes the reader process;
+ * while parent process continues as the writer process;
+ * both run till ending conditions are met.
+ */
+int
+main(int argc, char *argv[])
+{
+ pid_t childpid=0;
+ pid_t mypid, tmppid;
+ int child_status;
+ int child_wait_option=0;
+ int ret_value = 0;
+ int child_ret_value;
+ hbool_t send_wait = FALSE;
+ hid_t fid = -1; /* File ID */
+ H5FD_mirror_fapl_t mirr_fa;
+ H5FD_splitter_vfd_config_t split_fa;
+ hid_t mirr_fapl_id = H5I_INVALID_HID;
+
+ if (setup_parameters(argc, argv, &UC_opts) < 0) {
+ Hgoto_error(1);
+ }
+
+ mirr_fa.magic = H5FD_MIRROR_FAPL_MAGIC;
+ mirr_fa.version = H5FD_MIRROR_CURR_FAPL_T_VERSION;
+ mirr_fa.handshake_port = SERVER_PORT;
+ HDstrncpy(mirr_fa.remote_ip, SERVER_IP, H5FD_MIRROR_MAX_IP_LEN);
+
+
+ split_fa.wo_fapl_id = H5I_INVALID_HID;
+ split_fa.rw_fapl_id = H5I_INVALID_HID;
+ split_fa.magic = H5FD_SPLITTER_MAGIC;
+ split_fa.version = H5FD_CURR_SPLITTER_VFD_CONFIG_VERSION;
+ split_fa.log_file_path[0] = '\0'; /* none */
+ split_fa.ignore_wo_errs = FALSE;
+ HDstrncpy(split_fa.wo_path, MIRROR_FILE_NAME, H5FD_SPLITTER_PATH_MAX);
+
+ /* Determine the need to send/wait message file*/
+ if (UC_opts.launch == UC_READWRITE) {
+ HDunlink(WRITER_MESSAGE);
+ send_wait = TRUE;
+ }
+
+ /* ==============================================================*/
+ /* UC_READWRITE: create datafile, launch both reader and writer. */
+ /* UC_WRITER: create datafile, skip reader, launch writer. */
+ /* UC_READER: skip create, launch reader, exit. */
+ /* ==============================================================*/
+ /* =========== */
+ /* Create file */
+ /* =========== */
+ if (UC_opts.launch != UC_READER) {
+ HDprintf("Creating skeleton data file for test...\n");
+
+ /* Prepare mirror child driver */
+ mirr_fapl_id = H5Pcreate(H5P_FILE_ACCESS);
+ if (mirr_fapl_id == H5I_INVALID_HID) {
+ HDfprintf(stderr, "can't create creation mirror FAPL\n");
+ Hgoto_error(1);
+ }
+ if (H5Pset_fapl_mirror(mirr_fapl_id, &mirr_fa) < 0) {
+ HDfprintf(stderr, "can't set creation mirror FAPL\n");
+ H5Eprint2(H5E_DEFAULT, stdout);
+ Hgoto_error(1);
+ }
+
+ /* Prepare parent "splitter" driver in UC_opts */
+ split_fa.wo_fapl_id = mirr_fapl_id;
+ split_fa.rw_fapl_id = H5P_DEFAULT;
+ UC_opts.fapl_id = H5Pcreate(H5P_FILE_ACCESS);
+ if (UC_opts.fapl_id == H5I_INVALID_HID) {
+ HDfprintf(stderr, "can't create creation FAPL\n");
+ Hgoto_error(1);
+ }
+ if (H5Pset_fapl_splitter(UC_opts.fapl_id, &split_fa) < 0) {
+ HDfprintf(stderr, "can't set creation FAPL\n");
+ H5Eprint2(H5E_DEFAULT, stdout);
+ Hgoto_error(1);
+ }
+
+ if (H5Pset_libver_bounds(UC_opts.fapl_id, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST) < 0) {
+ HDfprintf(stderr, "can't set creation FAPL libver bounds\n");
+ Hgoto_error(1);
+ }
+
+ /* Create file */
+ if (create_uc_file(&UC_opts) < 0) {
+ HDfprintf(stderr, "***encounter error\n");
+ Hgoto_error(1);
+ } else {
+ HDprintf("File created.\n");
+ }
+
+ /* Close FAPLs to prevent issues with forking later */
+ if (H5Pclose(UC_opts.fapl_id) < 0) {
+ HDfprintf(stderr, "can't close creation FAPL\n");
+ Hgoto_error(1);
+ }
+ UC_opts.fapl_id = H5I_INVALID_HID;
+ if (H5Pclose(mirr_fapl_id) < 0) {
+ HDfprintf(stderr, "can't close creation mirror FAPL\n");
+ Hgoto_error(1);
+ }
+ mirr_fapl_id = H5I_INVALID_HID;
+ }
+
+ /* ============ */
+ /* Fork process */
+ /* ============ */
+ if (UC_opts.launch == UC_READWRITE) {
+ if ((childpid = HDfork()) < 0) {
+ HDperror("fork");
+ Hgoto_error(1);
+ }
+ }
+ mypid = HDgetpid();
+
+ /* ============= */
+ /* launch reader */
+ /* ============= */
+ if (UC_opts.launch != UC_WRITER) {
+ /* child process -- launch the reader */
+ /* reader only opens the one file -- separate reader needed for mirrored file 'shinano.h5' */
+ if (0 == childpid) {
+ HDprintf("%d: launch reader process\n", mypid);
+
+ UC_opts.fapl_id = H5P_DEFAULT;
+ if (read_uc_file(send_wait, &UC_opts) < 0) {
+ HDfprintf(stderr, "read_uc_file encountered error (%d)\n", mypid);
+ HDexit(1);
+ }
+
+ HDexit(0);
+ }
+ }
+
+ /* ============= */
+ /* launch writer */
+ /* ============= */
+ /* this process continues to launch the writer */
+ HDprintf("%d: continue as the writer process\n", mypid);
+
+ /* Prepare mirror child driver */
+ mirr_fapl_id = H5Pcreate(H5P_FILE_ACCESS);
+ if (mirr_fapl_id == H5I_INVALID_HID) {
+ HDfprintf(stderr, "can't create creation mirror FAPL\n");
+ Hgoto_error(1);
+ }
+ if (H5Pset_fapl_mirror(mirr_fapl_id, &mirr_fa) < 0) {
+ HDfprintf(stderr, "can't set creation mirror FAPL\n");
+ H5Eprint2(H5E_DEFAULT, stdout);
+ Hgoto_error(1);
+ }
+
+ /* Prepare parent "splitter" driver in UC_opts */
+ split_fa.wo_fapl_id = mirr_fapl_id;
+ split_fa.rw_fapl_id = H5P_DEFAULT;
+ UC_opts.fapl_id = H5Pcreate(H5P_FILE_ACCESS);
+ if (UC_opts.fapl_id == H5I_INVALID_HID) {
+ HDfprintf(stderr, "can't create creation FAPL\n");
+ Hgoto_error(1);
+ }
+ if (H5Pset_fapl_splitter(UC_opts.fapl_id, &split_fa) < 0) {
+ HDfprintf(stderr, "can't set creation FAPL\n");
+ H5Eprint2(H5E_DEFAULT, stdout);
+ Hgoto_error(1);
+ }
+
+ if (UC_opts.use_swmr) {
+ if (H5Pset_libver_bounds(UC_opts.fapl_id, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST) < 0) {
+ HDfprintf(stderr, "can't set write FAPL libver bounds\n");
+ Hgoto_error(1);
+ }
+ }
+
+ if ((fid = H5Fopen(UC_opts.filename, H5F_ACC_RDWR | (UC_opts.use_swmr ? H5F_ACC_SWMR_WRITE : 0), UC_opts.fapl_id)) < 0) {
+ HDfprintf(stderr, "H5Fopen failed\n");
+ Hgoto_error(1);
+ }
+
+ if (write_uc_file(send_wait, fid, &UC_opts) < 0) {
+ HDfprintf(stderr, "write_uc_file encountered error\n");
+ Hgoto_error(1);
+ }
+
+ if (H5Fclose(fid) < 0) {
+ HDfprintf(stderr, "Failed to close write\n");
+ Hgoto_error(1);
+ }
+
+ if (H5Pclose(UC_opts.fapl_id) < 0) {
+ HDfprintf(stderr, "can't close write FAPL\n");
+ Hgoto_error(1);
+ }
+
+ if (H5Pclose(mirr_fapl_id) < 0) {
+ HDfprintf(stderr, "can't close write mirror FAPL\n");
+ Hgoto_error(1);
+ }
+
+ /* ================================================ */
+ /* If readwrite, collect exit code of child process */
+ /* ================================================ */
+ if (UC_opts.launch == UC_READWRITE) {
+ if ((tmppid = HDwaitpid(childpid, &child_status, child_wait_option)) < 0) {
+ HDperror("waitpid");
+ Hgoto_error(1);
+ }
+
+ if (WIFEXITED(child_status)) {
+ if ((child_ret_value = WEXITSTATUS(child_status)) != 0) {
+ HDprintf("%d: child process exited with non-zero code (%d)\n",
+ mypid, child_ret_value);
+ Hgoto_error(2);
+ }
+ } else {
+ HDprintf("%d: child process terminated abnormally\n", mypid);
+ Hgoto_error(2);
+ }
+ }
+
+done:
+ if (ret_value != 0) {
+ HDprintf("Error(s) encountered\n");
+ } else {
+ HDprintf("All passed\n");
+ }
+
+ return(ret_value);
+}
+
+#else /* H5_HAVE_MIRROR_VFD */
+
+int
+main(void)
+{
+ HDfprintf(stderr, "Mirror VFD is not built. Skipping.\n");
+ return EXIT_SUCCESS;
+} /* end main() */
+
+#endif /* H5_HAVE_MIRROR_VFD */
+
+#else /* H5_HAVE_FORK */
+
+int
+main(void)
+{
+ HDfprintf(stderr, "Non-POSIX platform. Skipping.\n");
+ return EXIT_SUCCESS;
+} /* end main() */
+
+#endif /* H5_HAVE_FORK */
+
diff --git a/test/use_append_mchunks.c b/test/use_append_mchunks.c
index b7d45a4..2eb5a1d 100644
--- a/test/use_append_mchunks.c
+++ b/test/use_append_mchunks.c
@@ -29,14 +29,14 @@
* finishes HDF5 metadata updates and issues H5Fflush or H5Oflush calls.
* o Readers will see newly appended data after the Writer finishes
* the flush operation.
- *
+ *
* Preconditions:
* o Readers are not allowed to modify the file.
* o All datasets that are modified by the Writer exist when the
* Writer opens the file.
* o All datasets that are modified by the Writer exist when a Reader
* opens the file.
- *
+ *
* Main Success Scenario:
* 1. An application creates a file with required objects (groups,
* datasets, and attributes).
@@ -45,7 +45,7 @@
* spans several chunks.
* 3. A Reader opens the file and a dataset in a file; if the size of
* the unlimited dimension has changed, reads the appended data back.
- *
+ *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* Created: Albert Cheng, 2013/6/1 */
@@ -61,46 +61,45 @@
#include "use.h"
-/* Global Variable definitions */
-options_t UC_opts; /* Use Case Options */
-const char *progname_g="use_append_mchunks"; /* program name */
+#define USE_APPEND_MCHUNKS_PROGNAME "use_append_mchunks"
+
+static options_t UC_opts; /* Use Case Options */
/* Setup parameters for the use case.
* Return: 0 succeed; -1 fail.
*/
-int setup_parameters(int argc, char * const argv[])
+int
+setup_parameters(int argc, char * const argv[], options_t * opts)
{
/* use case defaults */
- HDmemset(&UC_opts, 0, sizeof(options_t));
- UC_opts.chunksize = Chunksize_DFT;
- UC_opts.use_swmr = 1; /* use swmr open */
- UC_opts.iterations = 1;
- UC_opts.chunkplanes = 1;
-
- /* parse options */
- if (parse_option(argc, argv) < 0){
- return(-1);
+ HDmemset(opts, 0, sizeof(options_t));
+ opts->chunksize = Chunksize_DFT;
+ opts->use_swmr = 1; /* use swmr open */
+ opts->iterations = 1;
+ opts->chunkplanes = 1;
+ opts->progname = USE_APPEND_MCHUNKS_PROGNAME;
+ opts->fapl_id = H5I_INVALID_HID;
+
+ if (parse_option(argc, argv, opts) < 0) {
+ return(-1);
}
- /* set chunk dims */
- UC_opts.chunkdims[0] = (hsize_t)UC_opts.chunkplanes;
- UC_opts.chunkdims[1] = UC_opts.chunkdims[2] = (hsize_t)UC_opts.chunksize;
- /* set dataset initial and max dims */
- UC_opts.dims[0] = 0;
- UC_opts.max_dims[0] = H5S_UNLIMITED;
- UC_opts.dims[1] = UC_opts.dims[2] = UC_opts.max_dims[1] = UC_opts.max_dims[2] = 2 * (hsize_t)UC_opts.chunksize;
+ opts->chunkdims[0] = (hsize_t)opts->chunkplanes;
+ opts->chunkdims[1] = opts->chunkdims[2] = (hsize_t)opts->chunksize;
+
+ opts->dims[0] = 0;
+ opts->max_dims[0] = H5S_UNLIMITED;
+ opts->dims[1] = opts->dims[2] = opts->max_dims[1] = opts->max_dims[2] = 2 * (hsize_t)opts->chunksize;
- /* set nplanes */
- if (UC_opts.nplanes == 0)
- UC_opts.nplanes = 2 * (hsize_t)UC_opts.chunksize;
+ if (opts->nplanes == 0)
+ opts->nplanes = 2 * (hsize_t)opts->chunksize;
- /* show parameters and return */
- show_parameters();
+ show_parameters(opts);
return(0);
-}
+} /* end setup_parameters() */
-/* Overall Algorithm:
+/* Overall Algorithm:
* Parse options from user;
* Generate/pre-created test files needed and close it;
* fork: child process becomes the reader process;
@@ -112,22 +111,20 @@ main(int argc, char *argv[])
{
pid_t childpid=0;
pid_t mypid, tmppid;
- int child_status;
+ int child_status;
int child_wait_option=0;
int ret_value = 0;
int child_ret_value;
hbool_t send_wait = 0;
hid_t fapl = -1; /* File access property list */
hid_t fid = -1; /* File ID */
- char *name; /* Test file name */
- /* initialization */
- if (setup_parameters(argc, argv) < 0){
+ if (setup_parameters(argc, argv, &UC_opts) < 0) {
Hgoto_error(1);
}
/* Determine the need to send/wait message file*/
- if(UC_opts.launch == UC_READWRITE) {
+ if (UC_opts.launch == UC_READWRITE) {
HDunlink(WRITER_MESSAGE);
send_wait = 1;
}
@@ -137,38 +134,63 @@ main(int argc, char *argv[])
/* UC_WRITER: create datafile, skip reader, launch writer. */
/* UC_READER: skip create, launch reader, exit. */
/* ==============================================================*/
- /* ============*/
+ /* =========== */
/* Create file */
- /* ============*/
- if (UC_opts.launch != UC_READER){
+ /* =========== */
+ if (UC_opts.launch != UC_READER) {
HDprintf("Creating skeleton data file for test...\n");
- if (create_uc_file() < 0){
- HDfprintf(stderr, "***encounter error\n");
- Hgoto_error(1);
- }else
- HDprintf("File created.\n");
+ if ((UC_opts.fapl_id = h5_fileaccess()) < 0) {
+ HDfprintf(stderr, "can't create creation FAPL\n");
+ Hgoto_error(1);
+ }
+ if (H5Pset_libver_bounds(UC_opts.fapl_id, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST) < 0) {
+ HDfprintf(stderr, "can't set creation FAPL libver bounds\n");
+ Hgoto_error(1);
+ }
+ if (create_uc_file(&UC_opts) < 0) {
+ HDfprintf(stderr, "***encounter error\n");
+ Hgoto_error(1);
+ } else {
+ HDprintf("File created.\n");
+ }
+ /* Close FAPL to prevent issues with forking later */
+ if (H5Pclose(UC_opts.fapl_id) < 0) {
+ HDfprintf(stderr, "can't close creation FAPL\n");
+ Hgoto_error(1);
+ }
+ UC_opts.fapl_id = H5I_INVALID_HID;
}
- if (UC_opts.launch==UC_READWRITE){
- /* fork process */
- if((childpid = fork()) < 0) {
+ /* ============ */
+ /* Fork process */
+ /* ============ */
+ if (UC_opts.launch==UC_READWRITE) {
+ if ((childpid = fork()) < 0) {
perror("fork");
Hgoto_error(1);
- };
- };
+ }
+ }
mypid = getpid();
/* ============= */
/* launch reader */
/* ============= */
- if (UC_opts.launch != UC_WRITER){
+ if (UC_opts.launch != UC_WRITER) {
/* child process launch the reader */
- if(0 == childpid) {
+ if (0 == childpid) {
HDprintf("%d: launch reader process\n", mypid);
- if (read_uc_file(send_wait) < 0){
+ if ((UC_opts.fapl_id = h5_fileaccess()) < 0) {
+ HDfprintf(stderr, "can't create read FAPL\n");
+ HDexit(EXIT_FAILURE);
+ }
+ if (read_uc_file(send_wait, &UC_opts) < 0) {
HDfprintf(stderr, "read_uc_file encountered error\n");
HDexit(EXIT_FAILURE);
}
+ if (H5Pclose(UC_opts.fapl_id) < 0) {
+ HDfprintf(stderr, "can't close read FAPL\n");
+ HDexit(EXIT_FAILURE);
+ }
HDexit(EXIT_SUCCESS);
}
}
@@ -179,51 +201,50 @@ main(int argc, char *argv[])
/* this process continues to launch the writer */
HDprintf("%d: continue as the writer process\n", mypid);
- name = UC_opts.filename;
-
/* Set the file access property list */
- if((fapl = h5_fileaccess()) < 0)
+ if ((fapl = h5_fileaccess()) < 0) {
+ HDfprintf(stderr, "can't get write FAPL\n");
Hgoto_error(1);
+ }
- if(UC_opts.use_swmr)
- if(H5Pset_libver_bounds(fapl, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST) < 0)
+ if (UC_opts.use_swmr) {
+ if (H5Pset_libver_bounds(fapl, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST) < 0) {
+ HDfprintf(stderr, "can't set write FAPL libver bounds\n");
Hgoto_error(1);
+ }
+ }
- /* Open the file */
- if((fid = H5Fopen(name, H5F_ACC_RDWR | (UC_opts.use_swmr ? H5F_ACC_SWMR_WRITE : 0), fapl)) < 0) {
+ if ((fid = H5Fopen(UC_opts.filename, H5F_ACC_RDWR | (UC_opts.use_swmr ? H5F_ACC_SWMR_WRITE : 0), fapl)) < 0) {
HDfprintf(stderr, "H5Fopen failed\n");
Hgoto_error(1);
}
- if(write_uc_file(send_wait, fid) < 0) {
+ if (write_uc_file(send_wait, fid, &UC_opts) < 0) {
HDfprintf(stderr, "write_uc_file encountered error\n");
Hgoto_error(1);
}
+ if (H5Fclose(fid) < 0) {
+ HDfprintf(stderr, "Failed to close file id\n");
+ Hgoto_error(1);
+ }
+
+ if (H5Pclose(fapl) < 0) {
+ HDfprintf(stderr, "can't close write FAPL\n");
+ Hgoto_error(1);
+ }
/* ================================================ */
/* If readwrite, collect exit code of child process */
/* ================================================ */
- if (UC_opts.launch == UC_READWRITE){
- if ((tmppid = waitpid(childpid, &child_status, child_wait_option)) < 0){
+ if (UC_opts.launch == UC_READWRITE) {
+ if ((tmppid = waitpid(childpid, &child_status, child_wait_option)) < 0) {
perror("waitpid");
Hgoto_error(1);
}
- /* Close the file */
- if(H5Fclose(fid) < 0) {
- HDfprintf(stderr, "Failed to close file id\n");
- Hgoto_error(1);
- }
-
- /* Close the property list */
- if(H5Pclose(fapl) < 0) {
- HDfprintf(stderr, "Failed to close the property list\n");
- Hgoto_error(1);
- }
-
- if (WIFEXITED(child_status)){
- if ((child_ret_value=WEXITSTATUS(child_status)) != 0){
+ if (WIFEXITED(child_status)) {
+ if ((child_ret_value=WEXITSTATUS(child_status)) != 0) {
HDprintf("%d: child process exited with non-zero code (%d)\n",
mypid, child_ret_value);
Hgoto_error(1);
@@ -233,17 +254,16 @@ main(int argc, char *argv[])
Hgoto_error(2);
}
}
-
+
done:
- /* Print result and exit */
- if (ret_value != 0){
+ if (ret_value != 0) {
HDprintf("Error(s) encountered\n");
- }else{
+ } else {
HDprintf("All passed\n");
}
return(ret_value);
-}
+} /* end main() */
#else /* H5_HAVE_FORK */
diff --git a/test/use_common.c b/test/use_common.c
index 4111b24..bf29936 100644
--- a/test/use_common.c
+++ b/test/use_common.c
@@ -21,10 +21,11 @@
#include "use.h"
-#define H5D_FRIEND /*suppress error about including H5Dpkg */
-#define H5D_TESTING
-#include "H5Dpkg.h"
-
+/* ----------------------------------------------------------------------------
+ * Print a common/shared usage message.
+ * Receives program name to show default test file name (<program_name>.h5).
+ * ----------------------------------------------------------------------------
+ */
void
usage(const char *prog)
{
@@ -41,10 +42,13 @@ usage(const char *prog)
HDfprintf(stderr, "\n");
} /* end usage() */
-/* Setup Use Case parameters by parsing command line options.
-* Setup default values if not set by options. */
+/* ----------------------------------------------------------------------------
+ * Setup Use Case parameters by parsing command line options.
+ * Includes default values for unspecified options.
+ * ----------------------------------------------------------------------------
+ */
int
-parse_option(int argc, char * const argv[])
+parse_option(int argc, char * const argv[], options_t * opts)
{
int ret_value=0;
int c;
@@ -56,302 +60,307 @@ parse_option(int argc, char * const argv[])
/* suppress getopt from printing error */
opterr = 0;
- while (1){
- c = getopt (argc, argv, nagg_options);
- if (-1 == c)
- break;
- switch (c) {
- case 'h':
- usage(progname_g);
- HDexit(EXIT_SUCCESS);
- break;
- case 'f': /* usecase data file name */
- UC_opts.filename = optarg;
- break;
- case 'i': /* iterations */
- if ((UC_opts.iterations = HDatoi(optarg)) <= 0) {
- HDfprintf(stderr, "bad iterations number %s, must be a positive integer\n", optarg);
- usage(progname_g);
- Hgoto_error(-1);
- };
- break;
- case 'l': /* launch reader or writer only */
- switch (*optarg) {
- case 'r': /* reader only */
- UC_opts.launch = UC_READER;
- break;
- case 'w': /* writer only */
- UC_opts.launch = UC_WRITER;
- break;
+ while (1) {
+ c = getopt(argc, argv, nagg_options);
+ if (-1 == c)
+ break;
+ switch (c) {
+ case 'h':
+ usage(opts->progname);
+ exit(EXIT_SUCCESS);
+ break;
+ case 'f': /* usecase data file name */
+ opts->filename = optarg;
+ break;
+ case 'i': /* iterations */
+ if ((opts->iterations = HDatoi(optarg)) <= 0) {
+ HDfprintf(stderr, "bad iterations number %s, must be a positive integer\n", optarg);
+ usage(opts->progname);
+ Hgoto_error(-1);
+ }
+ break;
+ case 'l': /* launch reader or writer only */
+ switch (*optarg) {
+ case 'r': /* reader only */
+ opts->launch = UC_READER;
+ break;
+ case 'w': /* writer only */
+ opts->launch = UC_WRITER;
+ break;
+ default:
+ HDfprintf(stderr, "launch value(%c) should be w or r only.\n", *optarg);
+ usage(opts->progname);
+ Hgoto_error(-1);
+ break;
+ } /* end switch (reader/writer-only mode toggle) */
+ break;
+ case 'n': /* number of planes to write/read */
+ if ((opts->nplanes = HDstrtoul(optarg, NULL, 0)) <= 0) {
+ HDfprintf(stderr, "bad number of planes %s, must be a positive integer\n", optarg);
+ usage(opts->progname);
+ Hgoto_error(-1);
+ }
+ break;
+ case 's': /* use swmr file open mode */
+ use_swmr = HDatoi(optarg);
+ if (use_swmr != 0 && use_swmr != 1) {
+ HDfprintf(stderr, "swmr value should be 0(no) or 1(yes)\n");
+ usage(opts->progname);
+ Hgoto_error(-1);
+ }
+ opts->use_swmr = (hbool_t)use_swmr;
+ break;
+ case 'y': /* Number of planes per chunk */
+ if ((opts->chunkplanes = HDstrtoul(optarg, NULL, 0)) <= 0) {
+ HDfprintf(stderr, "bad number of planes per chunk %s, must be a positive integer\n", optarg);
+ usage(opts->progname);
+ Hgoto_error(-1);
+ }
+ break;
+ case 'z': /* size of chunk=(z,z) */
+ if ((opts->chunksize = HDstrtoull(optarg, NULL, 0)) <= 0) {
+ HDfprintf(stderr, "bad chunksize %s, must be a positive integer\n", optarg);
+ usage(opts->progname);
+ Hgoto_error(-1);
+ }
+ break;
+ case '?':
+ HDfprintf(stderr, "getopt returned '%c'.\n", c);
+ Hgoto_error(-1);
default:
- HDfprintf(stderr, "launch value(%c) should be w or r only.\n", *optarg);
- usage(progname_g);
- Hgoto_error(-1);
- break;
- }
- break;
- case 'n': /* number of planes to write/read */
- if ((UC_opts.nplanes = HDstrtoul(optarg, NULL, 0)) <= 0) {
- HDfprintf(stderr, "bad number of planes %s, must be a positive integer\n", optarg);
- usage(progname_g);
- Hgoto_error(-1);
- };
- break;
- case 's': /* use swmr file open mode */
- use_swmr = HDatoi(optarg);
- if (use_swmr != 0 && use_swmr != 1) {
- HDfprintf(stderr, "swmr value should be 0(no) or 1(yes)\n");
- usage(progname_g);
+ HDfprintf(stderr, "getopt returned unexpected value.\n");
+ HDfprintf(stderr, "Unexpected value is %d\n", c);
Hgoto_error(-1);
- }
- UC_opts.use_swmr = (hbool_t)use_swmr;
- break;
- case 'y': /* Number of planes per chunk */
- if ((UC_opts.chunkplanes = HDstrtoul(optarg, NULL, 0)) <= 0) {
- HDfprintf(stderr, "bad number of planes per chunk %s, must be a positive integer\n", optarg);
- usage(progname_g);
- Hgoto_error(-1);
- };
- break;
- case 'z': /* size of chunk=(z,z) */
- if ((UC_opts.chunksize = HDstrtoull(optarg, NULL, 0)) <= 0) {
- HDfprintf(stderr, "bad chunksize %s, must be a positive integer\n", optarg);
- usage(progname_g);
- Hgoto_error(-1);
- };
- break;
- case '?':
- HDfprintf(stderr, "getopt returned '%c'.\n", c);
- Hgoto_error(-1);
- default:
- HDfprintf(stderr, "getopt returned unexpected value.\n");
- HDfprintf(stderr, "Unexpected value is %d\n", c);
- Hgoto_error(-1);
- }
- }
+ } /* end switch (argument symbol) */
+ } /* end while (there are still arguments) */
/* set test file name if not given */
- if (!UC_opts.filename){
- /* default data file name is <progname>.h5 */
- if ((UC_opts.filename=(char*)HDmalloc(HDstrlen(progname_g)+4))==NULL) {
- HDfprintf(stderr, "malloc: failed\n");
- Hgoto_error(-1);
- };
- HDstrcpy(UC_opts.filename, progname_g);
- HDstrcat(UC_opts.filename, ".h5");
+ if (!opts->filename) {
+ /* default data file name is <progname>.h5 */
+ if ((opts->filename=(char*)HDmalloc(HDstrlen(opts->progname)+4))==NULL) {
+ HDfprintf(stderr, "malloc: failed\n");
+ Hgoto_error(-1);
+ }
+ HDstrcpy(opts->filename, opts->progname);
+ HDstrcat(opts->filename, ".h5");
}
done:
- /* All done. */
return(ret_value);
-}
+} /* end parse_option() */
-/* Show parameters used for this use case */
-void show_parameters(void){
+/* ----------------------------------------------------------------------------
+ * Show parameters used for this use case.
+ * ----------------------------------------------------------------------------
+ */
+void
+show_parameters(options_t * opts)
+{
HDprintf("===Parameters used:===\n");
- printf("chunk dims=(%llu, %llu, %llu)\n", (unsigned long long)UC_opts.chunkdims[0],
- (unsigned long long)UC_opts.chunkdims[1], (unsigned long long)UC_opts.chunkdims[2]);
- printf("dataset max dims=(%llu, %llu, %llu)\n", (unsigned long long)UC_opts.max_dims[0],
- (unsigned long long)UC_opts.max_dims[1], (unsigned long long)UC_opts.max_dims[2]);
- HDprintf("number of planes to write=%llu\n", (unsigned long long)UC_opts.nplanes);
- HDprintf("using SWMR mode=%s\n", UC_opts.use_swmr ? "yes(1)" : "no(0)");
- HDprintf("data filename=%s\n", UC_opts.filename);
+ HDprintf("chunk dims=(%llu, %llu, %llu)\n", (unsigned long long)opts->chunkdims[0],
+ (unsigned long long)opts->chunkdims[1], (unsigned long long)opts->chunkdims[2]);
+ HDprintf("dataset max dims=(%llu, %llu, %llu)\n", (unsigned long long)opts->max_dims[0],
+ (unsigned long long)opts->max_dims[1], (unsigned long long)opts->max_dims[2]);
+ HDprintf("number of planes to write=%llu\n", (unsigned long long)opts->nplanes);
+ HDprintf("using SWMR mode=%s\n", opts->use_swmr ? "yes(1)" : "no(0)");
+ HDprintf("data filename=%s\n", opts->filename);
HDprintf("launch part=");
- switch (UC_opts.launch){
- case UC_READWRITE:
- printf("Reader/Writer\n");
- break;
- case UC_WRITER:
- printf("Writer\n");
- break;
- case UC_READER:
- printf("Reader\n");
- break;
- default:
- /* should not happen */
- printf("Illegal part(%d)\n", UC_opts.launch);
- };
- HDprintf("number of iterations=%d (not used yet)\n", UC_opts.iterations);
+ switch (opts->launch) {
+ case UC_READWRITE:
+ HDprintf("Reader/Writer\n");
+ break;
+ case UC_WRITER:
+ HDprintf("Writer\n");
+ break;
+ case UC_READER:
+ HDprintf("Reader\n");
+ break;
+ default:
+ /* should not happen */
+ HDprintf("Illegal part(%d)\n", opts->launch);
+ }
+ HDprintf("number of iterations=%d (not used yet)\n", opts->iterations);
HDprintf("===Parameters shown===\n");
-}
+} /* end show_parameters() */
-/* Create the skeleton use case file for testing.
+/* ----------------------------------------------------------------------------
+ * Create the skeleton use case file for testing.
* It has one 3d dataset using chunked storage.
* The dataset is (unlimited, chunksize, chunksize).
* Dataset type is 2 bytes integer.
* It starts out "empty", i.e., first dimension is 0.
*
* Return: 0 succeed; -1 fail.
+ * ----------------------------------------------------------------------------
*/
-int create_uc_file(void)
+int
+create_uc_file(options_t * opts)
{
- hsize_t dims[3]; /* Dataset starting dimensions */
- hid_t fid; /* File ID for new HDF5 file */
- hid_t dcpl; /* Dataset creation property list */
- hid_t sid; /* Dataspace ID */
- hid_t dsid; /* Dataset ID */
- hid_t fapl; /* File access property list */
+ hsize_t dims[3]; /* Dataset starting dimensions */
+ hid_t fid; /* File ID for new HDF5 file */
+ hid_t dcpl; /* Dataset creation property list */
+ hid_t sid; /* Dataspace ID */
+ hid_t dsid; /* Dataset ID */
H5D_chunk_index_t idx_type; /* Chunk index type */
- /* Create the file */
- if((fapl = h5_fileaccess()) < 0)
- return -1;
- if(H5Pset_libver_bounds(fapl, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST) < 0)
- return -1;
- if((fid = H5Fcreate(UC_opts.filename, H5F_ACC_TRUNC, H5P_DEFAULT, fapl)) < 0)
+ if ((fid = H5Fcreate(opts->filename, H5F_ACC_TRUNC, H5P_DEFAULT, opts->fapl_id)) < 0)
return -1;
/* Set up dimension sizes */
dims[0] = 0;
- dims[1] = dims[2] = UC_opts.max_dims[1];
+ dims[1] = dims[2] = opts->max_dims[1];
/* Create dataspace for creating datasets */
- if((sid = H5Screate_simple(3, dims, UC_opts.max_dims)) < 0)
+ if ((sid = H5Screate_simple(3, dims, opts->max_dims)) < 0)
return -1;
/* Create dataset creation property list */
- if((dcpl = H5Pcreate(H5P_DATASET_CREATE)) < 0)
+ if ((dcpl = H5Pcreate(H5P_DATASET_CREATE)) < 0)
return -1;
- if(H5Pset_chunk(dcpl, 3, UC_opts.chunkdims) < 0)
+ if (H5Pset_chunk(dcpl, 3, opts->chunkdims) < 0)
return -1;
/* create dataset of progname */
- if((dsid = H5Dcreate2(fid, progname_g, UC_DATATYPE, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT)) < 0)
- return -1;
+ if ((dsid = H5Dcreate2(fid, opts->progname, UC_DATATYPE, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT)) < 0)
+ return -1;
/* Check that the chunk index type is not version 1 B-tree.
* Version 1 B-trees are not supported under SWMR.
*/
- if(H5D__layout_idx_type_test(dsid, &idx_type) < 0)
+ if (H5Dget_chunk_index_type(dsid, &idx_type) < 0)
return -1;
- if(idx_type == H5D_CHUNK_IDX_BTREE) {
+ if (idx_type == H5D_CHUNK_IDX_BTREE) {
HDfprintf(stderr, "ERROR: Chunk index is version 1 B-tree: aborting.\n");
return -1;
}
/* Close everything */
- if(H5Dclose(dsid) < 0)
- return -1;
- if(H5Pclose(fapl) < 0)
+ if (H5Dclose(dsid) < 0)
return -1;
- if(H5Pclose(dcpl) < 0)
+ if (H5Pclose(dcpl) < 0)
return -1;
- if(H5Sclose(sid) < 0)
+ if (H5Sclose(sid) < 0)
return -1;
- if(H5Fclose(fid) < 0)
+ if (H5Fclose(fid) < 0)
return -1;
return 0;
-}
+} /* end create_uc_file() */
-/* Append planes, each of (1,2*chunksize,2*chunksize) to the dataset.
+/* ----------------------------------------------------------------------------
+ * Append planes, each of (1,2*chunksize,2*chunksize) to the dataset.
* In other words, 4 chunks are appended to the dataset at a time.
* Fill each plan with the plane number and then write it at the nth plane.
* Increase the plane number and repeat till the end of dataset, when it
* reaches chunksize long. End product is a (2*chunksize)^3 cube.
*
* Return: 0 succeed; -1 fail.
+ * ----------------------------------------------------------------------------
*/
-int write_uc_file(hbool_t tosend, hid_t fid)
+int
+write_uc_file(hbool_t tosend, hid_t file_id, options_t * opts)
{
- hid_t dsid; /* dataset ID */
- hid_t dcpl; /* Dataset creation property list */
- UC_CTYPE *buffer, *bufptr; /* data buffer */
- hsize_t cz=UC_opts.chunksize; /* Chunk size */
- hid_t f_sid; /* dataset file space id */
- hid_t m_sid; /* memory space id */
- int rank; /* rank */
- hsize_t chunk_dims[3]; /* Chunk dimensions */
- hsize_t dims[3]; /* Dataspace dimensions */
- hsize_t memdims[3]; /* Memory space dimensions */
- hsize_t start[3] = {0,0,0}, count[3]; /* Hyperslab selection values */
- hsize_t i, j, k;
-
- if(tosend)
+ hid_t dsid; /* dataset ID */
+ hid_t dcpl; /* Dataset creation property list */
+ UC_CTYPE *buffer, *bufptr; /* data buffer */
+ hsize_t cz=opts->chunksize; /* Chunk size */
+ hid_t f_sid; /* dataset file space id */
+ hid_t m_sid; /* memory space id */
+ int rank; /* rank */
+ hsize_t chunk_dims[3]; /* Chunk dimensions */
+ hsize_t dims[3]; /* Dataspace dimensions */
+ hsize_t memdims[3]; /* Memory space dimensions */
+ hsize_t start[3] = {0,0,0}, count[3]; /* Hyperslab selection values */
+ hsize_t i, j, k;
+
+ if (TRUE == tosend) {
/* Send a message that H5Fopen is complete--releasing the file lock */
h5_send_message(WRITER_MESSAGE, NULL, NULL);
+ }
/* Open the dataset of the program name */
- if((dsid = H5Dopen2(fid, progname_g, H5P_DEFAULT)) < 0){
+ if ((dsid = H5Dopen2(file_id, opts->progname, H5P_DEFAULT)) < 0) {
HDfprintf(stderr, "H5Dopen2 failed\n");
return -1;
}
/* Find chunksize used */
- if ((dcpl = H5Dget_create_plist(dsid)) < 0){
+ if ((dcpl = H5Dget_create_plist(dsid)) < 0) {
HDfprintf(stderr, "H5Dget_create_plist failed\n");
return -1;
}
- if (H5D_CHUNKED != H5Pget_layout(dcpl)){
+ if (H5D_CHUNKED != H5Pget_layout(dcpl)) {
HDfprintf(stderr, "storage layout is not chunked\n");
return -1;
}
- if ((rank = H5Pget_chunk(dcpl, 3, chunk_dims)) != 3){
+ if ((rank = H5Pget_chunk(dcpl, 3, chunk_dims)) != 3) {
HDfprintf(stderr, "storage rank is not 3\n");
return -1;
}
/* verify chunk_dims against set paramenters */
- if (chunk_dims[0]!=UC_opts.chunkdims[0] || chunk_dims[1] != cz || chunk_dims[2] != cz){
+ if (chunk_dims[0]!=opts->chunkdims[0] || chunk_dims[1] != cz || chunk_dims[2] != cz) {
HDfprintf(stderr, "chunk size is not as expected. Got dims=(%llu,%llu,%llu)\n",
- (unsigned long long)chunk_dims[0], (unsigned long long)chunk_dims[1],
+ (unsigned long long)chunk_dims[0], (unsigned long long)chunk_dims[1],
(unsigned long long)chunk_dims[2]);
return -1;
}
/* allocate space for data buffer 1 X dims[1] X dims[2] of UC_CTYPE */
memdims[0]=1;
- memdims[1] = UC_opts.dims[1];
- memdims[2] = UC_opts.dims[2];
+ memdims[1] = opts->dims[1];
+ memdims[2] = opts->dims[2];
if ((buffer=(UC_CTYPE*)HDmalloc((size_t)memdims[1]*(size_t)memdims[2]*sizeof(UC_CTYPE)))==NULL) {
HDfprintf(stderr, "malloc: failed\n");
return -1;
- };
+ }
/*
* Get dataset rank and dimension.
*/
f_sid = H5Dget_space(dsid); /* Get filespace handle first. */
rank = H5Sget_simple_extent_ndims(f_sid);
- if (rank != UC_RANK){
+ if (rank != UC_RANK) {
HDfprintf(stderr, "rank(%d) of dataset does not match\n", rank);
return -1;
}
- if (H5Sget_simple_extent_dims(f_sid, dims, NULL) < 0){
+ if (H5Sget_simple_extent_dims(f_sid, dims, NULL) < 0) {
HDfprintf(stderr, "H5Sget_simple_extent_dims got error\n");
return -1;
}
HDprintf("dataset rank %d, dimensions %llu x %llu x %llu\n",
- rank, (unsigned long long)(dims[0]), (unsigned long long)(dims[1]),
+ rank, (unsigned long long)(dims[0]), (unsigned long long)(dims[1]),
(unsigned long long)(dims[2]));
/* verify that file space dims are as expected and are consistent with memory space dims */
- if (dims[0] != 0 || dims[1] != memdims[1] || dims[2] != memdims[2]){
+ if (dims[0] != 0 || dims[1] != memdims[1] || dims[2] != memdims[2]) {
HDfprintf(stderr, "dataset is not empty. Got dims=(%llu,%llu,%llu)\n",
- (unsigned long long)dims[0], (unsigned long long)dims[1],
+ (unsigned long long)dims[0], (unsigned long long)dims[1],
(unsigned long long)dims[2]);
return -1;
}
/* setup mem-space for buffer */
- if ((m_sid=H5Screate_simple(rank, memdims, NULL))<0){
+ if ((m_sid=H5Screate_simple(rank, memdims, NULL))<0) {
HDfprintf(stderr, "H5Screate_simple for memory failed\n");
return -1;
- };
+ }
/* write planes */
count[0]=1;
count[1]=dims[1];
count[2]=dims[2];
- for (i=0; i<UC_opts.nplanes; i++){
+ for (i=0; i < opts->nplanes; i++) {
/* fill buffer with value i+1 */
bufptr = buffer;
- for (j=0; j<dims[1]; j++)
- for (k=0; k<dims[2]; k++)
+ for (j=0; j < dims[1]; j++) {
+ for (k=0; k < dims[2]; k++) {
*bufptr++ = (UC_CTYPE)i;
+ }
+ }
/* Cork the dataset's metadata in the cache, if SWMR is enabled */
- if(UC_opts.use_swmr) {
- if(H5Odisable_mdc_flushes(dsid) < 0) {
+ if (opts->use_swmr) {
+ if (H5Odisable_mdc_flushes(dsid) < 0) {
HDfprintf(stderr, "H5Odisable_mdc_flushes failed\n");
return -1;
}
@@ -359,64 +368,65 @@ int write_uc_file(hbool_t tosend, hid_t fid)
/* extend the dataset by one for new plane */
dims[0]=i+1;
- if(H5Dset_extent(dsid, dims) < 0){
+ if (H5Dset_extent(dsid, dims) < 0) {
HDfprintf(stderr, "H5Dset_extent failed\n");
return -1;
}
/* Get the dataset's dataspace */
- if((f_sid = H5Dget_space(dsid)) < 0){
+ if ((f_sid = H5Dget_space(dsid)) < 0) {
HDfprintf(stderr, "H5Dset_extent failed\n");
return -1;
}
start[0]=i;
/* Choose the next plane to write */
- if(H5Sselect_hyperslab(f_sid, H5S_SELECT_SET, start, NULL, count, NULL) < 0){
+ if (H5Sselect_hyperslab(f_sid, H5S_SELECT_SET, start, NULL, count, NULL) < 0) {
HDfprintf(stderr, "Failed H5Sselect_hyperslab\n");
return -1;
}
/* Write plane to the dataset */
- if(H5Dwrite(dsid, UC_DATATYPE, m_sid, f_sid, H5P_DEFAULT, buffer) < 0){
+ if (H5Dwrite(dsid, UC_DATATYPE, m_sid, f_sid, H5P_DEFAULT, buffer) < 0) {
HDfprintf(stderr, "Failed H5Dwrite\n");
return -1;
}
/* Uncork the dataset's metadata from the cache, if SWMR is enabled */
- if(UC_opts.use_swmr)
- if(H5Oenable_mdc_flushes(dsid) < 0) {
+ if (opts->use_swmr) {
+ if (H5Oenable_mdc_flushes(dsid) < 0) {
HDfprintf(stderr, "H5Oenable_mdc_flushes failed\n");
return -1;
}
+ }
/* flush file to make the just written plane available. */
- if(H5Dflush(dsid) < 0) {
+ if (H5Dflush(dsid) < 0) {
HDfprintf(stderr, "Failed to H5Fflush file\n");
return -1;
}
- }
+ } /* end for each plane to write */
/* Done writing. Free/Close all resources including data file */
HDfree(buffer);
- if (H5Dclose(dsid) < 0){
+ if (H5Dclose(dsid) < 0) {
HDfprintf(stderr, "Failed to close datasete\n");
return -1;
}
- if (H5Sclose(m_sid) < 0){
+ if (H5Sclose(m_sid) < 0) {
HDfprintf(stderr, "Failed to close memory space\n");
return -1;
}
- if (H5Sclose(f_sid) < 0){
+ if (H5Sclose(f_sid) < 0) {
HDfprintf(stderr, "Failed to close file space\n");
return -1;
}
return 0;
-}
+} /* end write_uc_file() */
-
-/* Read planes from the dataset.
+/* ----------------------------------------------------------------------------
+ * Read planes from the dataset.
* It expects the dataset is being changed (growing).
* It checks the unlimited dimension (1st one). When it increases,
* it will read in the new planes, one by one, and verify the data correctness.
@@ -425,61 +435,51 @@ int write_uc_file(hbool_t tosend, hid_t fid)
* that is the expected end of data, the reader exits.
*
* Return: 0 succeed; -1 fail.
+ * ----------------------------------------------------------------------------
*/
-int read_uc_file(hbool_t towait)
+int
+read_uc_file(hbool_t towait, options_t * opts)
{
- hid_t fapl; /* file access property list ID */
- hid_t fid; /* File ID for new HDF5 file */
- hid_t dsid; /* dataset ID */
- char *name;
- UC_CTYPE *buffer, *bufptr; /* read data buffer */
- hid_t f_sid; /* dataset file space id */
- hid_t m_sid; /* memory space id */
- int rank; /* rank */
- hsize_t dims[3]; /* Dataspace dimensions */
- hsize_t memdims[3]; /* Memory space dimensions */
- hsize_t nplane=0, nplane_old=0; /* nth plane, last nth plane */
- hsize_t start[3] = {0,0,0}, count[3]; /* Hyperslab selection values */
- hsize_t j, k;
- int nreadererr=0;
- int nerrs;
- int nonewplane;
+ hid_t fid; /* File ID for new HDF5 file */
+ hid_t dsid; /* dataset ID */
+ UC_CTYPE *buffer, *bufptr; /* read data buffer */
+ hid_t f_sid; /* dataset file space id */
+ hid_t m_sid; /* memory space id */
+ int rank; /* rank */
+ hsize_t dims[3]; /* Dataspace dimensions */
+ hsize_t memdims[3]; /* Memory space dimensions */
+ hsize_t nplane=0, nplanes_seen=0; /* nth plane, last nth plane */
+ hsize_t start[3] = {0,0,0}, count[3]; /* Hyperslab selection values */
+ hsize_t j, k;
+ int nreadererr=0;
+ int nerrs;
+ int loops_waiting_for_plane;
/* Before reading, wait for the message that H5Fopen is complete--file lock is released */
- if(towait && h5_wait_message(WRITER_MESSAGE) < 0) {
+ if (towait && h5_wait_message(WRITER_MESSAGE) < 0) {
HDfprintf(stderr, "Cannot find writer message file...failed\n");
return -1;
}
- name = UC_opts.filename;
-
- /* Open the file */
- if((fapl = h5_fileaccess()) < 0)
- return -1;
- if((fid = H5Fopen(name, H5F_ACC_RDONLY | (UC_opts.use_swmr ? H5F_ACC_SWMR_READ : 0), fapl)) < 0){
+ HDfprintf(stderr, "Opening to read %s\n", opts->filename);
+ if ((fid = H5Fopen(opts->filename, H5F_ACC_RDONLY | (opts->use_swmr ? H5F_ACC_SWMR_READ : 0), opts->fapl_id)) < 0) {
HDfprintf(stderr, "H5Fopen failed\n");
return -1;
}
- if (H5Pclose(fapl) < 0){
- HDfprintf(stderr, "Failed to property list\n");
- return -1;
- }
-
- /* Open the dataset of the program name */
- if((dsid = H5Dopen2(fid, progname_g, H5P_DEFAULT)) < 0){
+ if ((dsid = H5Dopen2(fid, opts->progname, H5P_DEFAULT)) < 0) {
HDfprintf(stderr, "H5Dopen2 failed\n");
return -1;
}
- /* allocate space for data buffer 1 X dims[1] X dims[2] of UC_CTYPE */
- memdims[0]=1;
- memdims[1] = UC_opts.dims[1];
- memdims[2] = UC_opts.dims[2];
+ /* Allocate space for data buffer 1 X dims[1] X dims[2] of UC_CTYPE */
+ memdims[0] = 1;
+ memdims[1] = opts->dims[1];
+ memdims[2] = opts->dims[2];
if ((buffer=(UC_CTYPE*)HDmalloc((size_t)memdims[1]*(size_t)memdims[2]*sizeof(UC_CTYPE)))==NULL) {
HDfprintf(stderr, "malloc: failed\n");
return -1;
- };
+ }
/*
* Get dataset rank and dimension.
@@ -487,11 +487,11 @@ int read_uc_file(hbool_t towait)
*/
f_sid = H5Dget_space(dsid); /* Get filespace handle first. */
rank = H5Sget_simple_extent_ndims(f_sid);
- if (rank != UC_RANK){
+ if (rank != UC_RANK) {
HDfprintf(stderr, "rank(%d) of dataset does not match\n", rank);
return -1;
}
- if (H5Sget_simple_extent_dims(f_sid, dims, NULL) < 0){
+ if (H5Sget_simple_extent_dims(f_sid, dims, NULL) < 0) {
HDfprintf(stderr, "H5Sget_simple_extent_dims got error\n");
return -1;
}
@@ -499,7 +499,7 @@ int read_uc_file(hbool_t towait)
rank, (unsigned long long)(dims[0]), (unsigned long long)(dims[1]),
(unsigned long long)(dims[2]));
/* verify that file space dims are as expected and are consistent with memory space dims */
- if (dims[1] != memdims[1] || dims[2] != memdims[2]){
+ if (dims[1] != memdims[1] || dims[2] != memdims[2]) {
HDfprintf(stderr, "dataset dimension is not as expected. Got dims=(%llu,%llu,%llu)\n",
(unsigned long long)dims[0], (unsigned long long)dims[1],
(unsigned long long)dims[2]);
@@ -509,120 +509,101 @@ int read_uc_file(hbool_t towait)
return -1;
}
- /* setup mem-space for buffer */
- if ((m_sid=H5Screate_simple(rank, memdims, NULL))<0){
+ /* Setup mem-space for buffer */
+ if ((m_sid=H5Screate_simple(rank, memdims, NULL)) < 0) {
HDfprintf(stderr, "H5Screate_simple for memory failed\n");
return -1;
- };
+ }
- /* Read 1 plane at a time whenever the dataset grows larger
- * (along dim[0]) */
- count[0]=1;
- count[1]=dims[1];
- count[2]=dims[2];
+ /* Read 1 plane at a time whenever the dataset grows larger (along dim[0]) */
+ count[0] = 1;
+ count[1] = dims[1];
+ count[2] = dims[2];
/* quit when all nplanes have been read */
- nonewplane=0;
- while (nplane_old < UC_opts.nplanes ){
- /* print progress message according to if new planes are availalbe */
- if (nplane_old < dims[0]) {
- if (nonewplane){
- /* end the previous message */
- HDprintf("\n");
- nonewplane=0;
- }
- HDprintf("reading planes %llu to %llu\n", (unsigned long long)nplane_old,
+ loops_waiting_for_plane=0;
+ while (nplanes_seen < opts->nplanes) {
+ /* print progress message according to if new planes are availalbe */
+ if (nplanes_seen < dims[0]) {
+ if (loops_waiting_for_plane) {
+ /* end the previous message */
+ HDprintf("\n");
+ loops_waiting_for_plane=0;
+ }
+ HDprintf("reading planes %llu to %llu\n", (unsigned long long)nplanes_seen,
(unsigned long long)dims[0]);
- }else{
- if (nonewplane){
- HDprintf(".");
- if (nonewplane>=30){
- HDfprintf(stderr, "waited too long for new plane, quit.\n");
- return -1;
- }
- }else{
- /* print mesg only the first time; dots still no new plane */
- HDprintf("no new planes to read ");
}
- nonewplane++;
- /* pause for a second */
- HDsleep(1);
- }
- for (nplane=nplane_old; nplane < dims[0]; nplane++){
- /* read planes between last old nplanes and current extent */
- /* Get the dataset's dataspace */
- if((f_sid = H5Dget_space(dsid)) < 0){
- HDfprintf(stderr, "H5Dget_space failed\n");
- return -1;
+ else {
+ if (loops_waiting_for_plane) {
+ HDprintf(".");
+ if (loops_waiting_for_plane>=30) {
+ HDfprintf(stderr, "waited too long for new plane, quit.\n");
+ return -1;
+ }
+ }
+ else {
+ /* print mesg only the first time; dots still no new plane */
+ HDprintf("waiting for new planes to read ");
+ }
+ loops_waiting_for_plane++;
+ /* pause for a second */
+ HDsleep(1);
}
- start[0]=nplane;
- /* Choose the next plane to read */
- if(H5Sselect_hyperslab(f_sid, H5S_SELECT_SET, start, NULL, count, NULL) < 0){
- HDfprintf(stderr, "H5Sselect_hyperslab failed\n");
- return -1;
- }
+ for (nplane=nplanes_seen; nplane < dims[0]; nplane++) {
+ /* read planes between last old nplanes and current extent */
+ /* Get the dataset's dataspace */
+ if ((f_sid = H5Dget_space(dsid)) < 0) {
+ HDfprintf(stderr, "H5Dget_space failed\n");
+ return -1;
+ }
- /* Read the plane from the dataset */
- if(H5Dread(dsid, UC_DATATYPE, m_sid, f_sid, H5P_DEFAULT, buffer) < 0){
- HDfprintf(stderr, "H5Dread failed\n");
- return -1;
- }
+ start[0]=nplane;
+ /* Choose the next plane to read */
+ if (H5Sselect_hyperslab(f_sid, H5S_SELECT_SET, start, NULL, count, NULL) < 0) {
+ HDfprintf(stderr, "H5Sselect_hyperslab failed\n");
+ return -1;
+ }
- /* compare read data with expected data value which is nplane */
- bufptr = buffer;
- nerrs=0;
- for (j=0; j<dims[1]; j++){
- for (k=0; k<dims[2]; k++){
- if ((hsize_t)*bufptr++ != nplane){
- if (++nerrs < ErrorReportMax){
- HDfprintf(stderr,
- "found error %llu plane(%llu,%llu), expected %llu, got %d\n",
- (unsigned long long)nplane, (unsigned long long)j,
- (unsigned long long)k, (unsigned long long)nplane, (int)*(bufptr-1));
- }
- }
+ /* Read the plane from the dataset */
+ if (H5Dread(dsid, UC_DATATYPE, m_sid, f_sid, H5P_DEFAULT, buffer) < 0) {
+ HDfprintf(stderr, "H5Dread failed\n");
+ return -1;
}
- }
- if (nerrs){
- nreadererr++;
- HDfprintf(stderr, "found %d unexpected values in plane %llu\n", nerrs,
+
+ /* compare read data with expected data value which is nplane */
+ bufptr = buffer;
+ nerrs=0;
+ for (j=0; j < dims[1]; j++) {
+ for (k=0; k < dims[2]; k++) {
+ if ((hsize_t)*bufptr++ != nplane) {
+ if (++nerrs < ErrorReportMax) {
+ HDfprintf(stderr,
+ "found error %llu plane(%llu,%llu), expected %llu, got %d\n",
+ (unsigned long long)nplane, (unsigned long long)j,
+ (unsigned long long)k, (unsigned long long)nplane, (int)*(bufptr-1));
+ } /* end if should print error */
+ } /* end if value mismatch */
+ } /* end for plane second dimension */
+ } /* end for plane first dimension */
+ if (nerrs) {
+ nreadererr++;
+ HDfprintf(stderr, "found %d unexpected values in plane %llu\n", nerrs,
(unsigned long long)nplane);
- }
- }
- /* Have read all current planes */
- nplane_old=dims[0];
+ }
+ } /* end for each plane added since last read */
- /* check if dataset has grown since last time */
-#if 0
- /* close dsid and file, then reopen them */
- if (H5Dclose(dsid) < 0){
- HDfprintf(stderr, "H5Dclose failed\n");
- return -1;
- }
- if (H5Fclose(fid) < 0){
- HDfprintf(stderr, "H5Fclose failed\n");
- return -1;
- }
- if((fid = H5Fopen(name, H5F_ACC_RDONLY | (UC_opts.use_swmr ? H5F_ACC_SWMR_READ : 0), H5P_DEFAULT)) < 0){
- HDfprintf(stderr, "H5Fopen failed\n");
- return -1;
- }
- if((dsid = H5Dopen2(fid, progname_g, H5P_DEFAULT)) < 0){
- HDfprintf(stderr, "H5Dopen2 failed\n");
- return -1;
- }
-#else
- H5Drefresh(dsid);
-#endif
- f_sid = H5Dget_space(dsid); /* Get filespace handle first. */
- if (H5Sget_simple_extent_dims(f_sid, dims, NULL) < 0){
- HDfprintf(stderr, "H5Sget_simple_extent_dims got error\n");
- return -1;
- }
- }
+ nplanes_seen=dims[0];
+
+ /* check if dataset has grown since last time (update dims) */
+ H5Drefresh(dsid);
+ f_sid = H5Dget_space(dsid); /* Get filespace handle first. */
+ if (H5Sget_simple_extent_dims(f_sid, dims, NULL) < 0) {
+ HDfprintf(stderr, "H5Sget_simple_extent_dims got error\n");
+ return -1;
+ }
+ } /* end while (expecting more planes to read) */
- /* Close the file */
- if(H5Fclose(fid) < 0) {
+ if (H5Fclose(fid) < 0) {
HDfprintf(stderr, "H5Fclose failed\n");
return -1;
}
@@ -631,7 +612,7 @@ int read_uc_file(hbool_t towait)
return -1;
else
return 0;
-} /* read_uc_file() */
+} /* end read_uc_file() */
#endif /* H5_HAVE_FORK */
diff --git a/test/vfd.c b/test/vfd.c
index e88d9bb..97995d2 100644
--- a/test/vfd.c
+++ b/test/vfd.c
@@ -25,6 +25,7 @@
#define FAMILY_SIZE (1*KB)
#define FAMILY_SIZE2 (5*KB)
#define MULTI_SIZE 128
+#define SPLITTER_SIZE 8 /* dimensions of a dataset */
#define CORE_INCREMENT (4*KB)
#define CORE_PAGE_SIZE (1024*KB)
@@ -59,6 +60,9 @@ const char *FILENAME[] = {
"windows_file", /*8*/
"new_multi_file_v16",/*9*/
"ro_s3_file", /*10*/
+ "splitter_rw_file", /*11*/
+ "splitter_wo_file", /*12*/
+ "splitter.log", /*13*/
NULL
};
@@ -66,8 +70,47 @@ const char *FILENAME[] = {
#define COMPAT_BASENAME "family_v16_"
#define MULTI_COMPAT_BASENAME "multi_file_v16"
+#define SPLITTER_DATASET_NAME "dataset"
+
+/* Macro: HEXPRINT()
+ * Helper macro to pretty-print hexadecimal output of a buffer of known size.
+ * Each line has the address of the first printed byte, and four columns of
+ * four-byte data.
+ */
+static int __k;
+#define HEXPRINT(size, buf) \
+for (__k = 0; __k < (size); __k++) { \
+ if (__k % 16 == 0) { \
+ HDprintf("\n%04x", __k); \
+ } \
+ HDprintf((__k%4 == 0) ? " %02X" : " %02X", (unsigned char)(buf)[__k]); \
+} /* end #define HEXPRINT() */
+/* Helper structure to pass around dataset information.
+ */
+struct splitter_dataset_def {
+ void *buf; /* contents of dataset */
+ const char *dset_name; /* dataset name, always added to root group */
+ hid_t mem_type_id; /* datatype */
+ const hsize_t *dims; /* dimensions */
+ int n_dims; /* rank */
+};
+
+static int splitter_prepare_file_paths(H5FD_splitter_vfd_config_t *vfd_config,
+ char *filename_rw_out);
+static int splitter_create_single_file_at(const char *filename, hid_t fapl_id,
+ const struct splitter_dataset_def *data);
+static int splitter_compare_expected_data(hid_t file_id,
+ const struct splitter_dataset_def *data);
+static int run_splitter_test(const struct splitter_dataset_def *data,
+ hbool_t ignore_wo_errors, hbool_t provide_logfile_path,
+ hid_t sub_fapl_ids[2]);
+static int splitter_RO_test(const struct splitter_dataset_def *data,
+ hid_t child_fapl_id);
+static int splitter_tentative_open_test(hid_t child_fapl_id);
+static int file_exists(const char *filename, hid_t fapl_id);
+
/*-------------------------------------------------------------------------
* Function: test_sec2
*
@@ -859,7 +902,7 @@ test_family(void)
hid_t driver_id = -1; /* ID for this VFD */
unsigned long driver_flags = 0; /* VFD feature flags */
char filename[1024];
- char dname[]="dataset";
+ char dname[] = "dataset";
unsigned int i, j;
int *fhandle=NULL, *fhandle2=NULL;
int **buf = NULL;
@@ -1263,7 +1306,7 @@ error:
return FAIL;
} /* end test_family_member_fapl() */
-
+
/*-------------------------------------------------------------------------
* Function: test_multi_opens
*
@@ -2179,6 +2222,1052 @@ error:
#endif /* H5_HAVE_ROS3_VFD */
} /* end test_ros3() */
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * Macro: SPLITTER_TEST_FAULT()
+ *
+ * utility macro, helps create stack-like backtrace on error.
+ * requires defined in the calling function:
+ * * variable `int ret_value` (return -1 on error)`
+ * * label `done` for exit on fault
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ */
+#define SPLITTER_TEST_FAULT(mesg) { \
+ H5_FAILED(); \
+ AT(); \
+ HDfprintf(stderr, mesg); \
+ H5Eprint2(H5E_DEFAULT, stderr); \
+ fflush(stderr); \
+ ret_value = -1; \
+ goto done; \
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: compare_splitter_config_info
+ *
+ * Purpose: Helper function to compare configuration info found in a
+ * FAPL against a canonical structure.
+ *
+ * Return: Success: 0, if config info in FAPL matches info structure.
+ * Failure: -1, if difference detected.
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+compare_splitter_config_info(hid_t fapl_id, H5FD_splitter_vfd_config_t *info)
+{
+ int ret_value = 0;
+ H5FD_splitter_vfd_config_t fetched_info;
+
+ fetched_info.magic = H5FD_SPLITTER_MAGIC;
+ fetched_info.version = H5FD_CURR_SPLITTER_VFD_CONFIG_VERSION;
+ fetched_info.rw_fapl_id = H5I_INVALID_HID;
+ fetched_info.wo_fapl_id = H5I_INVALID_HID;
+
+ if (H5Pget_fapl_splitter(fapl_id, &fetched_info) < 0) {
+ SPLITTER_TEST_FAULT("can't get splitter info\n");
+ }
+ if (info->rw_fapl_id == H5P_DEFAULT) {
+ if (H5Pget_driver(fetched_info.rw_fapl_id) != H5Pget_driver(H5P_FILE_ACCESS_DEFAULT)) {
+ SPLITTER_TEST_FAULT("Read-Write driver mismatch (default)\n");
+ }
+ }
+ else {
+ if (H5Pget_driver(fetched_info.rw_fapl_id) != H5Pget_driver(info->rw_fapl_id)) {
+ SPLITTER_TEST_FAULT("Read-Write driver mismatch\n");
+ }
+ }
+ if (info->wo_fapl_id == H5P_DEFAULT) {
+ if (H5Pget_driver(fetched_info.wo_fapl_id) != H5Pget_driver(H5P_FILE_ACCESS_DEFAULT)) {
+ SPLITTER_TEST_FAULT("Write-Only driver mismatch (default)\n");
+ }
+ }
+ else {
+ if (H5Pget_driver(fetched_info.wo_fapl_id) != H5Pget_driver(info->wo_fapl_id)) {
+ SPLITTER_TEST_FAULT("Write-Only driver mismatch\n");
+ }
+ }
+ if ( (HDstrlen(info->wo_path) != HDstrlen(fetched_info.wo_path)) ||
+ HDstrncmp(info->wo_path, fetched_info.wo_path, H5FD_SPLITTER_PATH_MAX))
+ {
+ HDfprintf(stderr, "MISMATCH: '%s' :: '%s'\n", info->wo_path, fetched_info.wo_path);
+ HEXPRINT(H5FD_SPLITTER_PATH_MAX, info->wo_path);
+ HEXPRINT(H5FD_SPLITTER_PATH_MAX, fetched_info.wo_path);
+ SPLITTER_TEST_FAULT("Write-Only file path mismatch\n");
+ }
+
+done:
+ return ret_value;
+} /* end compare_splitter_config_info() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: run_splitter_test
+ *
+ * Purpose: Auxiliary function for test_splitter().
+ *
+ * Return: Success: 0
+ * Failure: -1
+ *
+ * Description:
+ * Perform basic open-write-close with the Splitter VFD.
+ * Prior to operations, removes files from a previous run,
+ * if they exist.
+ * After writing, compares read-write and write-only files.
+ * Includes FAPL sanity testing.
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+run_splitter_test(const struct splitter_dataset_def *data,
+ hbool_t ignore_wo_errors,
+ hbool_t provide_logfile_path,
+ hid_t sub_fapl_ids[2])
+{
+ hid_t file_id = H5I_INVALID_HID;
+ hid_t fapl_id = H5I_INVALID_HID;
+ hid_t dset_id = H5I_INVALID_HID;
+ hid_t space_id = H5I_INVALID_HID;
+ hid_t fapl_id_out = H5I_INVALID_HID;
+ hid_t fapl_id_cpy = H5I_INVALID_HID;
+ H5FD_splitter_vfd_config_t vfd_config;
+ char filename_rw[H5FD_SPLITTER_PATH_MAX + 1];
+ FILE *logfile = NULL;
+ int ret_value = 0;
+
+ vfd_config.magic = H5FD_SPLITTER_MAGIC;
+ vfd_config.version = H5FD_CURR_SPLITTER_VFD_CONFIG_VERSION;
+ vfd_config.ignore_wo_errs = ignore_wo_errors;
+ vfd_config.rw_fapl_id = sub_fapl_ids[0];
+ vfd_config.wo_fapl_id = sub_fapl_ids[1];
+
+ if (splitter_prepare_file_paths(&vfd_config, filename_rw) < 0) {
+ SPLITTER_TEST_FAULT("can't prepare file paths\n");
+ }
+
+ if (provide_logfile_path == FALSE) {
+ *vfd_config.log_file_path = '\0'; /* reset as empty string */
+ }
+
+ /* Create a new fapl to use the SPLITTER file driver */
+ if ((fapl_id = H5Pcreate(H5P_FILE_ACCESS)) == H5I_INVALID_HID) {
+ SPLITTER_TEST_FAULT("can't create FAPL ID\n");
+ }
+ if (H5Pset_fapl_splitter(fapl_id, &vfd_config) < 0) {
+ SPLITTER_TEST_FAULT("can't set splitter FAPL\n");
+ }
+ if (H5Pget_driver(fapl_id) != H5FD_SPLITTER) {
+ SPLITTER_TEST_FAULT("set FAPL not SPLITTER\n");
+ }
+
+ if (compare_splitter_config_info(fapl_id, &vfd_config) < 0) {
+ SPLITTER_TEST_FAULT("information mismatch\n");
+ }
+
+ /*
+ * Copy property list, light compare, and close the copy.
+ * Helps test driver-implemented FAPL-copying and library ID management.
+ */
+
+ fapl_id_cpy = H5Pcopy(fapl_id);
+ if (H5I_INVALID_HID == fapl_id_cpy) {
+ SPLITTER_TEST_FAULT("can't copy FAPL\n");
+ }
+ if (compare_splitter_config_info(fapl_id_cpy, &vfd_config) < 0) {
+ SPLITTER_TEST_FAULT("information mismatch\n");
+ }
+ if (H5Pclose(fapl_id_cpy) < 0) {
+ SPLITTER_TEST_FAULT("can't close fapl copy\n");
+ }
+
+ /*
+ * Proceed with test. Create file.
+ */
+ file_id = H5Fcreate(filename_rw, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id);
+ if (file_id < 0) {
+ SPLITTER_TEST_FAULT("can't create file\n");
+ }
+
+ /*
+ * Check driver from file
+ */
+
+ fapl_id_out = H5Fget_access_plist(file_id);
+ if (H5I_INVALID_HID == fapl_id_out) {
+ SPLITTER_TEST_FAULT("can't get file's FAPL\n");
+
+ }
+ if (H5Pget_driver(fapl_id_out) != H5FD_SPLITTER) {
+ SPLITTER_TEST_FAULT("wrong file FAPL driver\n");
+ }
+ if (compare_splitter_config_info(fapl_id_out, &vfd_config) < 0) {
+ SPLITTER_TEST_FAULT("information mismatch\n");
+ }
+ if (H5Pclose(fapl_id_out) < 0) {
+ SPLITTER_TEST_FAULT("can't close file's FAPL\n");
+ }
+
+ /*
+ * Create and write the dataset
+ */
+
+ space_id = H5Screate_simple(data->n_dims, data->dims, NULL);
+ if (space_id < 0) {
+ SPLITTER_TEST_FAULT("can't create dataspace\n");
+ }
+ dset_id = H5Dcreate2(file_id, data->dset_name, data->mem_type_id, space_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
+ if (dset_id < 0) {
+ SPLITTER_TEST_FAULT("can't create dataset\n");
+ }
+ if (H5Dwrite(dset_id, data->mem_type_id, H5S_ALL, H5S_ALL, H5P_DEFAULT, data->buf) < 0) {
+ SPLITTER_TEST_FAULT("can't write data to dataset\n");
+ }
+
+ /* Close everything */
+ if (H5Dclose(dset_id) < 0) {
+ SPLITTER_TEST_FAULT("can't close dset\n");
+ }
+ if (H5Sclose(space_id) < 0) {
+ SPLITTER_TEST_FAULT("can't close space\n");
+ }
+ if (H5Pclose(fapl_id) < 0) {
+ SPLITTER_TEST_FAULT("can't close fapl\n");
+ }
+ if (H5Fclose(file_id) < 0) {
+ SPLITTER_TEST_FAULT("can't close file\n");
+ }
+
+ /* Verify that the R/W and W/O files are identical */
+ if (h5_compare_file_bytes(filename_rw, vfd_config.wo_path) < 0) {
+ SPLITTER_TEST_FAULT("files are not byte-for-byte equivalent\n");
+ }
+
+ /* Verify existence of logfile iff appropriate */
+ logfile = fopen(vfd_config.log_file_path, "r");
+ if ( (TRUE == provide_logfile_path && NULL == logfile) ||
+ (FALSE == provide_logfile_path && NULL != logfile) )
+ {
+ SPLITTER_TEST_FAULT("no logfile when one was expected\n");
+ }
+
+done:
+ if (ret_value < 0) {
+ H5E_BEGIN_TRY {
+ (void)H5Dclose(dset_id);
+ (void)H5Sclose(space_id);
+ (void)H5Pclose(fapl_id_out);
+ (void)H5Pclose(fapl_id_cpy);
+ (void)H5Pclose(fapl_id);
+ (void)H5Fclose(file_id);
+ } H5E_END_TRY;
+ }
+ if (logfile != NULL) {
+ fclose(logfile);
+ }
+ return ret_value;
+
+} /* end run_splitter_test() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: driver_is_splitter_compatible
+ *
+ * Purpose: Determine whether the driver set in the FAPL ID is compatible
+ * with the Splitter VFD -- specificially, Write-Only channel.
+ *
+ * Return: Success: 0
+ * Failure: -1
+ *
+ * Description: Attempts to put the given FAPL ID as the W/O channel.
+ * Uses driver's own mechanisms to generate error, and catches
+ * error.
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+driver_is_splitter_compatible(hid_t fapl_id)
+{
+ H5FD_splitter_vfd_config_t vfd_config;
+ hid_t split_fapl_id = H5I_INVALID_HID;
+ herr_t ret;
+ int ret_value = 0;
+
+ split_fapl_id = H5Pcreate(H5P_FILE_ACCESS);
+ if (H5I_INVALID_HID == split_fapl_id) {
+ FAIL_PUTS_ERROR("Can't create contained FAPL");
+ }
+ vfd_config.magic = H5FD_SPLITTER_MAGIC;
+ vfd_config.version = H5FD_CURR_SPLITTER_VFD_CONFIG_VERSION;
+ vfd_config.ignore_wo_errs = FALSE;
+ vfd_config.rw_fapl_id = H5P_DEFAULT;
+ vfd_config.wo_fapl_id = fapl_id;
+ HDstrncpy(vfd_config.wo_path, "nonesuch", H5FD_SPLITTER_PATH_MAX);
+
+ H5E_BEGIN_TRY {
+ ret = H5Pset_fapl_splitter(split_fapl_id, &vfd_config);
+ } H5E_END_TRY;
+ if (SUCCEED == ret) {
+ ret_value = -1;
+ }
+
+ if (H5Pclose(split_fapl_id) < 0) {
+ FAIL_PUTS_ERROR("Can't close contained FAPL")
+ }
+ split_fapl_id = H5I_INVALID_HID;
+
+ return ret_value;
+
+error:
+ H5E_BEGIN_TRY {
+ (void)H5Pclose(split_fapl_id);
+ } H5E_END_TRY;
+ return -1;
+} /* end driver_is_splitter_compatible() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: splitter_RO_test
+ *
+ * Purpose: Verify Splitter VFD with the Read-Only access flag.
+ *
+ * Return: Success: 0
+ * Failure: -1
+ *
+ * Description: Attempt read-only opening of files with different
+ * permutations of files already existing on-disk.
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+splitter_RO_test(
+ const struct splitter_dataset_def *data,
+ hid_t child_fapl_id)
+{
+ char filename_rw[H5FD_SPLITTER_PATH_MAX + 1];
+ H5FD_splitter_vfd_config_t vfd_config;
+ hid_t fapl_id = H5I_INVALID_HID;
+ int ret_value = 0;
+ hid_t file_id = H5I_INVALID_HID;
+
+ vfd_config.magic = H5FD_SPLITTER_MAGIC;
+ vfd_config.version = H5FD_CURR_SPLITTER_VFD_CONFIG_VERSION;
+ vfd_config.ignore_wo_errs = FALSE;
+ vfd_config.rw_fapl_id = child_fapl_id;
+ vfd_config.wo_fapl_id = child_fapl_id;
+
+ if (splitter_prepare_file_paths(&vfd_config, filename_rw) < 0) {
+ SPLITTER_TEST_FAULT("can't prepare splitter file paths\n");
+ }
+
+ /* Create a new fapl to use the SPLITTER file driver */
+ fapl_id = H5Pcreate(H5P_FILE_ACCESS);
+ if (H5I_INVALID_HID == fapl_id) {
+ SPLITTER_TEST_FAULT("can't create FAPL ID\n");
+ }
+ if (H5Pset_fapl_splitter(fapl_id, &vfd_config) < 0) {
+ SPLITTER_TEST_FAULT("can't set splitter FAPL\n");
+ }
+ if (H5Pget_driver(fapl_id) != H5FD_SPLITTER) {
+ SPLITTER_TEST_FAULT("set FAPL not SPLITTER\n");
+ }
+
+ /* Attempt R/O open when both files are nonexistent
+ * Should fail.
+ */
+
+ H5E_BEGIN_TRY {
+ file_id = H5Fopen(filename_rw, H5F_ACC_RDONLY, fapl_id);
+ } H5E_END_TRY;
+ if (file_id >= 0) {
+ SPLITTER_TEST_FAULT("R/O open on nonexistent files unexpectedly successful\n");
+ }
+
+ /* Attempt R/O open when only W/O file exists
+ * Should fail.
+ */
+
+ if (splitter_create_single_file_at(vfd_config.wo_path, vfd_config.wo_fapl_id, data) < 0) {
+ SPLITTER_TEST_FAULT("can't write W/O file\n");
+ }
+ H5E_BEGIN_TRY {
+ file_id = H5Fopen(filename_rw, H5F_ACC_RDONLY, fapl_id);
+ } H5E_END_TRY;
+ if (file_id >= 0) {
+ SPLITTER_TEST_FAULT("R/O open with extant W/O file unexpectedly successful\n");
+ }
+ HDremove(vfd_config.wo_path);
+
+ /* Attempt R/O open when only R/W file exists
+ * Should fail.
+ */
+
+ if (splitter_create_single_file_at(filename_rw, vfd_config.rw_fapl_id, data) < 0) {
+ SPLITTER_TEST_FAULT("can't create R/W file\n");
+ }
+ H5E_BEGIN_TRY {
+ file_id = H5Fopen(filename_rw, H5F_ACC_RDONLY, fapl_id);
+ } H5E_END_TRY;
+ if (file_id >= 0) {
+ SPLITTER_TEST_FAULT("R/O open with extant R/W file unexpectedly successful\n");
+ }
+
+ /* Attempt R/O open when both R/W and W/O files exist
+ */
+
+ if (splitter_create_single_file_at(vfd_config.wo_path, vfd_config.wo_fapl_id, data) < 0) {
+ SPLITTER_TEST_FAULT("can't create W/O file\n");
+ }
+ file_id = H5Fopen(filename_rw, H5F_ACC_RDONLY, fapl_id);
+ if (file_id < 0) {
+ SPLITTER_TEST_FAULT("R/O open on two extant files failed\n");
+ }
+ if (splitter_compare_expected_data(file_id, data) < 0) {
+ SPLITTER_TEST_FAULT("data mismatch in R/W file\n");
+ }
+ if (H5Fclose(file_id) < 0) {
+ SPLITTER_TEST_FAULT("can't close file(s)\n");
+ }
+ file_id = H5I_INVALID_HID;
+
+ /* Cleanup
+ */
+
+ if (H5Pclose(fapl_id) < 0) {
+ SPLITTER_TEST_FAULT("can't close FAPL ID\n");
+ }
+ fapl_id = H5I_INVALID_HID;
+
+done:
+ if (ret_value < 0) {
+ H5E_BEGIN_TRY {
+ (void)H5Pclose(fapl_id);
+ (void)H5Fclose(file_id);
+ } H5E_END_TRY;
+ } /* end if error */
+ return ret_value;
+} /* end splitter_RO_test() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: splitter_prepare_file_paths
+ *
+ * Purpose: Get file paths ready for use by the Splitter VFD tests.
+ *
+ * Return: Success: 0
+ * Failure: -1
+ *
+ * Description:
+ * Use h5_fixname to adjust the splitter-relevant file paths
+ * from those given in FILENAMES.
+ *
+ * REMOVES EXISTING FILES AT THE PATH LOCATIONS PRIOR TO RETURN.
+ *
+ * The relevant file paths will be set in filename_rw_out and
+ * inside the config structure (wo_path, log_file_path).
+ *
+ * `filename_rw_out` must be at least H5FD_SPLITTER_PATH_MAX+1
+ * characters long.
+ *
+ * `vfd_config` must have its child FAPL IDs preset.
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+splitter_prepare_file_paths(H5FD_splitter_vfd_config_t *vfd_config, char *filename_rw_out)
+{
+ int ret_value = 0;
+
+ if (vfd_config == NULL || vfd_config->magic != H5FD_SPLITTER_MAGIC) {
+ SPLITTER_TEST_FAULT("invalid splitter config pointer\n");
+ }
+ if (filename_rw_out == NULL) {
+ SPLITTER_TEST_FAULT("NULL filename_rw pointer\n");
+ }
+
+ /* TODO: sanity-check fapl IDs? */
+
+ /* Build the r/w file, w/o file, and the log file paths.
+ * Output is stored in the associated string pointers.
+ */
+ h5_fixname(FILENAME[11], vfd_config->rw_fapl_id, filename_rw_out, H5FD_SPLITTER_PATH_MAX);
+ h5_fixname(FILENAME[12], vfd_config->wo_fapl_id, vfd_config->wo_path, H5FD_SPLITTER_PATH_MAX);
+ h5_fixname_no_suffix(FILENAME[13], vfd_config->wo_fapl_id, vfd_config->log_file_path, H5FD_SPLITTER_PATH_MAX);
+
+ /* Delete any existing files on disk.
+ */
+ HDremove(filename_rw_out);
+ HDremove(vfd_config->wo_path);
+ HDremove(vfd_config->log_file_path);
+
+done:
+ return ret_value;
+} /* end splitter_prepare_file_paths() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: splitter_crate_single_file_at
+ *
+ * Purpose: Create a file, optionally w/ dataset.
+ *
+ * Return: Success: 0
+ * Failure: -1
+ *
+ * Description:
+ * Create a file at the given location with the given FAPL,
+ * and write data as defined in `data` in a pre-determined location in the file.
+ *
+ * If the dataset definition pointer is NULL, no data is written
+ * to the file.
+ *
+ * Will always overwrite an existing file with the given name/path.
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+splitter_create_single_file_at(
+ const char *filename,
+ hid_t fapl_id,
+ const struct splitter_dataset_def *data)
+{
+ hid_t file_id = H5I_INVALID_HID;
+ hid_t space_id = H5I_INVALID_HID;
+ hid_t dset_id = H5I_INVALID_HID;
+ int ret_value = 0;
+
+ if (filename == NULL || *filename == '\0') {
+ SPLITTER_TEST_FAULT("filename is invalid\n");
+ }
+ /* TODO: sanity-check fapl id? */
+
+ file_id = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id);
+ if (file_id < 0) {
+ SPLITTER_TEST_FAULT("can't create file\n");
+ }
+
+ if (data) {
+ /* TODO: sanity-check data, if it exists? */
+ space_id = H5Screate_simple(data->n_dims, data->dims, NULL);
+ if (space_id < 0) {
+ SPLITTER_TEST_FAULT("can't create dataspace\n");
+ }
+
+ dset_id = H5Dcreate2(
+ file_id,
+ data->dset_name,
+ data->mem_type_id,
+ space_id,
+ H5P_DEFAULT,
+ H5P_DEFAULT,
+ H5P_DEFAULT);
+ if (dset_id < 0) {
+ SPLITTER_TEST_FAULT("can't create dataset\n");
+ }
+
+ if (H5Dwrite(dset_id, data->mem_type_id, H5S_ALL, H5S_ALL, H5P_DEFAULT, data->buf) < 0) {
+ SPLITTER_TEST_FAULT("can't write data to dataset\n");
+ }
+
+ if (H5Dclose(dset_id) < 0) {
+ SPLITTER_TEST_FAULT("can't close dset\n");
+ }
+ if (H5Sclose(space_id) < 0) {
+ SPLITTER_TEST_FAULT("can't close space\n");
+ }
+ } /* end if data definition is provided */
+
+ if (H5Fclose(file_id) < 0) {
+ SPLITTER_TEST_FAULT("can't close file\n");
+ }
+
+done:
+ if (ret_value < 0) {
+ H5E_BEGIN_TRY {
+ (void)H5Dclose(dset_id);
+ (void)H5Sclose(space_id);
+ (void)H5Fclose(file_id);
+ } H5E_END_TRY;
+ } /* end if error */
+ return ret_value;
+} /* end splitter_create_single_file_at() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: splitter_compare_expected_data
+ *
+ * Purpose: Compare data within a predermined dataset.
+ *
+ * Return: Success: 0
+ * Failure: -1
+ *
+ * Description: Read data from the file at a predetermined location, and
+ * compare its contents byte-for-byte with that expected in
+ * the `data` definition structure.
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+splitter_compare_expected_data(hid_t file_id,
+ const struct splitter_dataset_def *data)
+{
+ hid_t dset_id = H5I_INVALID_HID;
+ int buf[SPLITTER_SIZE][SPLITTER_SIZE];
+ int expected[SPLITTER_SIZE][SPLITTER_SIZE];
+ size_t i = 0;
+ size_t j = 0;
+ int ret_value = 0;
+
+ if (sizeof((void *)buf) != sizeof(data->buf)) {
+ SPLITTER_TEST_FAULT("invariant size of expected data does not match that received!\n");
+ }
+ HDmemcpy(expected, data->buf, sizeof(expected));
+
+ dset_id = H5Dopen2(file_id, data->dset_name, H5P_DEFAULT);
+ if (dset_id < 0) {
+ SPLITTER_TEST_FAULT("can't open dataset\n");
+ }
+
+ if (H5Dread(dset_id, data->mem_type_id, H5S_ALL, H5S_ALL, H5P_DEFAULT, (void *)buf) < 0) {
+ SPLITTER_TEST_FAULT("can't read dataset\n");
+ }
+
+ for (i=0; i < SPLITTER_SIZE; i++) {
+ for (j=0; j < SPLITTER_SIZE; j++) {
+ if (buf[i][j] != expected[i][j]) {
+ SPLITTER_TEST_FAULT("mismatch in expected data\n");
+ }
+ }
+ }
+
+ if (H5Dclose(dset_id) < 0) {
+ SPLITTER_TEST_FAULT("can't close dataset\n");
+ }
+
+done:
+ if (ret_value < 0) {
+ H5E_BEGIN_TRY {
+ (void)H5Dclose(dset_id);
+ } H5E_END_TRY;
+ }
+ return ret_value;
+} /* end splitter_compare_expected_data() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: splitter_tentative_open_test()
+ *
+ * Purpose: Verifies Splitter behavior with "tentative" H5F_open.
+ *
+ * Return: Success: 0
+ * Failure: -1
+ *
+ * Description:
+ * H5F_open() has a two-stage opening process when given a
+ * Read/Write access flag -- first it performs a "tentative
+ * open", where it checks to see whether files already exist
+ * on the system, done in such a way as to not "alter its state"
+ * (i.e., truncate).
+ * This can cause problems with the Splitter VFD, as the
+ * file on the R/W channel might exist already, but that on the
+ * W/O channel will not, and vice-versa.
+ *
+ * This test exists to verify that in any event, files will be
+ * created as required.
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+splitter_tentative_open_test(hid_t child_fapl_id)
+{
+ char filename_rw[H5FD_SPLITTER_PATH_MAX + 1];
+ H5FD_splitter_vfd_config_t vfd_config;
+ hid_t fapl_id = H5I_INVALID_HID;
+ hid_t file_id = H5I_INVALID_HID;
+ int buf[SPLITTER_SIZE][SPLITTER_SIZE]; /* for comparison */
+ hsize_t dims[2] = { SPLITTER_SIZE, SPLITTER_SIZE }; /* for comparison */
+ int i = 0; /* for comparison */
+ int j = 0; /* for comparison */
+ struct splitter_dataset_def data; /* for comparison */
+ int ret_value = 0;
+
+ /* pre-fill data buffer to write */
+ for (i=0; i < SPLITTER_SIZE; i++) {
+ for (j=0; j < SPLITTER_SIZE; j++) {
+ buf[i][j] = i*100+j;
+ }
+ }
+
+ /* Dataset info */
+ data.buf = (void *)buf;
+ data.mem_type_id = H5T_NATIVE_INT;
+ data.dims = dims;
+ data.n_dims = 2;
+ data.dset_name = SPLITTER_DATASET_NAME;
+
+ vfd_config.magic = H5FD_SPLITTER_MAGIC;
+ vfd_config.version = H5FD_CURR_SPLITTER_VFD_CONFIG_VERSION;
+ vfd_config.ignore_wo_errs = FALSE;
+ vfd_config.rw_fapl_id = child_fapl_id;
+ vfd_config.wo_fapl_id = child_fapl_id;
+
+ if (splitter_prepare_file_paths(&vfd_config, filename_rw) < 0) {
+ SPLITTER_TEST_FAULT("can't prepare splitter file paths\n");
+ }
+
+ /* Create a new fapl to use the SPLITTER file driver */
+ if ((fapl_id = H5Pcreate(H5P_FILE_ACCESS)) == H5I_INVALID_HID) {
+ SPLITTER_TEST_FAULT("can't create FAPL ID\n");
+ }
+ if (H5Pset_fapl_splitter(fapl_id, &vfd_config) < 0) {
+ SPLITTER_TEST_FAULT("can't set splitter FAPL\n");
+ }
+ if (H5Pget_driver(fapl_id) != H5FD_SPLITTER) {
+ SPLITTER_TEST_FAULT("set FAPL not SPLITTER\n");
+ }
+
+ /* H5Fopen() with RDWR access.
+ * Neither file exist already
+ * Should fail.
+ */
+
+ H5E_BEGIN_TRY {
+ file_id = H5Fopen(filename_rw, H5F_ACC_RDWR, fapl_id);
+ } H5E_END_TRY;
+ if (file_id != H5I_INVALID_HID) {
+ SPLITTER_TEST_FAULT("open with both nonexistent files unexpectedly succeeded\n");
+ }
+ if (file_exists(filename_rw, child_fapl_id)) {
+ SPLITTER_TEST_FAULT("R/W file unexpectedly created\n");
+ }
+ if (file_exists(vfd_config.wo_path, child_fapl_id)) {
+ SPLITTER_TEST_FAULT("W/O file unexpectedly created\n");
+ }
+
+ /* H5Fopen() with RDWR access.
+ * W/O file exists already.
+ * Should fail.
+ */
+
+ if (splitter_create_single_file_at(vfd_config.wo_path, child_fapl_id, &data) < 0) {
+ SPLITTER_TEST_FAULT("can't write W/O file\n");
+ }
+ H5E_BEGIN_TRY {
+ file_id = H5Fopen(filename_rw, H5F_ACC_RDWR, fapl_id);
+ } H5E_END_TRY;
+ if (file_id != H5I_INVALID_HID) {
+ SPLITTER_TEST_FAULT("open with nonexistent R/W file unexpectedly succeeded\n");
+ }
+ if (file_exists(filename_rw, child_fapl_id)) {
+ SPLITTER_TEST_FAULT("R/W file unexpectedly created\n");
+ }
+ if (!file_exists(vfd_config.wo_path, child_fapl_id)) {
+ SPLITTER_TEST_FAULT("W/O file mysteriously disappeared\n");
+ }
+ HDremove(vfd_config.wo_path);
+ if (file_exists(vfd_config.wo_path, child_fapl_id)) {
+ SPLITTER_TEST_FAULT("failed to remove W/O file\n");
+ }
+
+ /* H5Fopen() with RDWR access.
+ * R/W file exists already.
+ * Should fail.
+ */
+
+ if (splitter_create_single_file_at(filename_rw, child_fapl_id, &data) < 0) {
+ SPLITTER_TEST_FAULT("can't write R/W file\n");
+ }
+ H5E_BEGIN_TRY {
+ file_id = H5Fopen(filename_rw, H5F_ACC_RDWR, fapl_id);
+ } H5E_END_TRY;
+ if (file_id != H5I_INVALID_HID) {
+ SPLITTER_TEST_FAULT("open with nonexistent W/O unexpectedly succeeded\n");
+ }
+ if (!file_exists(filename_rw, child_fapl_id)) {
+ SPLITTER_TEST_FAULT("R/W file mysteriously disappeared\n");
+ }
+ if (file_exists(vfd_config.wo_path, child_fapl_id)) {
+ SPLITTER_TEST_FAULT("W/O file unexpectedly created\n");
+ }
+
+ /* H5Fopen() with RDWR access.
+ * Both files already exist.
+ */
+
+ if (splitter_create_single_file_at(vfd_config.wo_path, child_fapl_id, &data) < 0) {
+ SPLITTER_TEST_FAULT("can't write W/O file\n");
+ }
+ file_id = H5Fopen(filename_rw, H5F_ACC_RDWR, fapl_id);
+ if (file_id == H5I_INVALID_HID) {
+ SPLITTER_TEST_FAULT("file-open failed with both present\n");
+ }
+ /* Open successful; close file then inspect presence again */
+ if (H5Fclose(file_id) < 0) {
+ SPLITTER_TEST_FAULT("can't close file ID\n");
+ }
+ if (!file_exists(filename_rw, child_fapl_id)) {
+ SPLITTER_TEST_FAULT("R/W file mysteriously disappared\n");
+ }
+ if (!file_exists(vfd_config.wo_path, child_fapl_id)) {
+ SPLITTER_TEST_FAULT("W/O file mysteriously disappeared\n");
+ }
+ if (h5_compare_file_bytes(filename_rw, vfd_config.wo_path) < 0) {
+ SPLITTER_TEST_FAULT("files are not byte-for-byte equivalent\n");
+ }
+
+ /* H5Fcreate() with TRUNC access.
+ * Both files already exist.
+ */
+
+ file_id = H5Fcreate(filename_rw, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id);
+ if (file_id == H5I_INVALID_HID) {
+ SPLITTER_TEST_FAULT("file-open failed with both present\n");
+ }
+ /* Open successful; close file then inspect presence again */
+ if (H5Fclose(file_id) < 0) {
+ SPLITTER_TEST_FAULT("can't close file ID\n");
+ }
+ if (!file_exists(filename_rw, child_fapl_id)) {
+ SPLITTER_TEST_FAULT("R/W file mysteriously disappared\n");
+ }
+ if (!file_exists(vfd_config.wo_path, child_fapl_id)) {
+ SPLITTER_TEST_FAULT("W/O file mysteriously disappeared\n");
+ }
+ if (h5_compare_file_bytes(filename_rw, vfd_config.wo_path) < 0) {
+ SPLITTER_TEST_FAULT("files are not byte-for-byte equivalent\n");
+ }
+
+ /* H5Fcreate() with TRUNC access.
+ * R/W already exists.
+ */
+
+ HDremove(filename_rw);
+ HDremove(vfd_config.wo_path);
+ if (splitter_create_single_file_at(filename_rw, child_fapl_id, &data) < 0) {
+ SPLITTER_TEST_FAULT("can't write R/W file\n");
+ }
+
+ if (file_exists(vfd_config.wo_path, child_fapl_id)) {
+ SPLITTER_TEST_FAULT("failed to remove W/O file\n");
+ }
+ file_id = H5Fcreate(filename_rw, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id);
+ if (file_id == H5I_INVALID_HID) {
+ SPLITTER_TEST_FAULT("file-open failed with both present\n");
+ }
+ /* Open successful; close file then inspect presence again */
+ if (H5Fclose(file_id) < 0) {
+ SPLITTER_TEST_FAULT("can't close file ID\n");
+ }
+ if (!file_exists(filename_rw, child_fapl_id)) {
+ SPLITTER_TEST_FAULT("R/W file mysteriously disappared\n");
+ }
+ if (!file_exists(vfd_config.wo_path, child_fapl_id)) {
+ SPLITTER_TEST_FAULT("W/O file mysteriously disappeared\n");
+ }
+ if (h5_compare_file_bytes(filename_rw, vfd_config.wo_path) < 0) {
+ SPLITTER_TEST_FAULT("files are not byte-for-byte equivalent\n");
+ }
+
+ /* H5Fcreate() with TRUNC access.
+ * W/O already exists.
+ */
+
+ HDremove(filename_rw);
+ HDremove(vfd_config.wo_path);
+ if (splitter_create_single_file_at(vfd_config.wo_path, child_fapl_id, &data) < 0) {
+ SPLITTER_TEST_FAULT("can't write R/W file\n");
+ }
+
+ if (file_exists(filename_rw, child_fapl_id)) {
+ SPLITTER_TEST_FAULT("failed to remove R/W file\n");
+ }
+ file_id = H5Fcreate(filename_rw, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id);
+ if (file_id == H5I_INVALID_HID) {
+ SPLITTER_TEST_FAULT("file-open failed with both present\n");
+ }
+ /* Open successful; close file then inspect presence again */
+ if (H5Fclose(file_id) < 0) {
+ SPLITTER_TEST_FAULT("can't close file ID\n");
+ }
+ if (!file_exists(filename_rw, child_fapl_id)) {
+ SPLITTER_TEST_FAULT("R/W file mysteriously disappared\n");
+ }
+ if (!file_exists(vfd_config.wo_path, child_fapl_id)) {
+ SPLITTER_TEST_FAULT("W/O file mysteriously disappeared\n");
+ }
+ if (h5_compare_file_bytes(filename_rw, vfd_config.wo_path) < 0) {
+ SPLITTER_TEST_FAULT("files are not byte-for-byte equivalent\n");
+ }
+
+ /* H5Fcreate with both files absent is tested elsewhere */
+
+ /* Cleanup
+ */
+
+ if (H5Pclose(fapl_id) < 0) {
+ SPLITTER_TEST_FAULT("can't close splitter FAPL ID\n");
+ }
+
+done:
+ if (ret_value < 0) {
+ H5E_BEGIN_TRY {
+ (void)H5Pclose(fapl_id);
+ (void)H5Fclose(file_id);
+ } H5E_END_TRY;
+ } /* end if error */
+ return ret_value;
+} /* end splitter_tentative_open_test() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: file_exists()
+ *
+ * Purpose: Determine whether a file exists on-system
+ *
+ * Return: Non-zero (1) if it exists (H5Fopen successful),
+ * zero (0) if absent (cannot be opened).
+ *
+ * Description: Attempt H5Fopen with the given FAPL ID and RDONLY access flag.
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+file_exists(const char *filename, hid_t fapl_id)
+{
+ hid_t file_id = H5I_INVALID_HID;
+ int ret_value = 0;
+
+ H5E_BEGIN_TRY {
+ file_id = H5Fopen(filename, H5F_ACC_RDONLY, fapl_id);
+ } H5E_END_TRY;
+ if (file_id != H5I_INVALID_HID) {
+ ret_value = 1;
+ if (H5Fclose(file_id) < 0) {
+ FAIL_PUTS_ERROR("can't close file ID\n");
+ }
+ }
+
+ return ret_value;
+
+error:
+ H5E_BEGIN_TRY {
+ (void)H5Fclose(file_id);
+ } H5E_END_TRY;
+ return ret_value;
+} /* end file_exists() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: test_splitter
+ *
+ * Purpose: Tests the Splitter VFD
+ *
+ * Return: Success: 0
+ * Failure: -1
+ *
+ * Description:
+ * This test function uses the Splitter VFD to produce a r/w
+ * file and a w/o file. It will verify that the two files
+ * are identical.
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+test_splitter(void)
+{
+ int buf[SPLITTER_SIZE][SPLITTER_SIZE];
+ hsize_t dims[2] = { SPLITTER_SIZE, SPLITTER_SIZE };
+ hid_t child_fapl_id = H5I_INVALID_HID;
+ int i = 0;
+ int j = 0;
+ struct splitter_dataset_def data;
+
+ TESTING("SPLITTER file driver");
+
+ /* pre-fill data buffer to write */
+ for (i=0; i < SPLITTER_SIZE; i++) {
+ for (j=0; j < SPLITTER_SIZE; j++) {
+ buf[i][j] = i*100+j;
+ }
+ }
+
+ /* Dataset info */
+ data.buf = (void *)buf;
+ data.mem_type_id = H5T_NATIVE_INT;
+ data.dims = dims;
+ data.n_dims = 2;
+ data.dset_name = SPLITTER_DATASET_NAME;
+
+ /* Stand-in for manual FAPL creation
+ * Enables verification with arbitrary VFDs via `make check-vfd`
+ */
+ child_fapl_id = h5_fileaccess();
+ if (child_fapl_id < 0) {
+ TEST_ERROR;
+ }
+
+ if (!driver_is_splitter_compatible(child_fapl_id)) {
+ SKIPPED();
+ HDprintf(" given driver is not Splitter W/O compatible.\n");
+ return 0;
+ }
+
+ /* Test Read-Only access, including when a file on the W/O channel
+ * does not exist.
+ */
+ if (splitter_RO_test(&data, child_fapl_id) < 0) {
+ TEST_ERROR;
+ }
+
+ /* Test opening of files when the W/O channel does not exist.
+ */
+ if (splitter_tentative_open_test(child_fapl_id) < 0) {
+ TEST_ERROR;
+ }
+
+
+ /* Test file creation, utilizing different child FAPLs (default vs.
+ * specified), logfile, and Write Channel error ignoring behavior.
+ */
+ for (i=0; i < 4; i++) {
+ hbool_t ignore_wo_errors = (i & 1) ? TRUE : FALSE;
+ hbool_t provide_logfile_path = (i & 2) ? TRUE : FALSE;
+ hid_t child_fapl_ids[2] = { H5P_DEFAULT, H5P_DEFAULT };
+
+ /* Test child driver definition/default combination */
+ for (j=0; j < 4; j++) {
+
+ child_fapl_ids[0] = (j & 1) ? child_fapl_id : H5P_DEFAULT;
+ child_fapl_ids[1] = (j & 2) ? child_fapl_id : H5P_DEFAULT;
+
+ if (run_splitter_test(&data, ignore_wo_errors, provide_logfile_path, child_fapl_ids) < 0) {
+ TEST_ERROR;
+ }
+
+ } /* end for child fapl definition/pairing */
+
+ } /* end for behavior-flag loops */
+
+/* TODO: SWMR open? */
+/* Concurrent opens with both drivers using the Splitter */
+
+
+ if (H5Pclose(child_fapl_id) == FAIL) {
+ TEST_ERROR;
+ }
+
+ PASSED();
+ return 0;
+
+error:
+ if (child_fapl_id != H5I_INVALID_HID) {
+ (void)H5Pclose(child_fapl_id);
+ }
+ return -1;
+} /* end test_splitter() */
+
+#undef SPLITTER_TEST_FAULT
+
+
/*-------------------------------------------------------------------------
* Function: main
*
@@ -2187,9 +3276,6 @@ error:
* Return: Success: 0
* Failure: 1
*
- * Programmer: Raymond Lu
- * Tuesday, Sept 24, 2002
- *
*-------------------------------------------------------------------------
*/
int
@@ -2213,6 +3299,7 @@ main(void)
nerrors += test_stdio() < 0 ? 1 : 0;
nerrors += test_windows() < 0 ? 1 : 0;
nerrors += test_ros3() < 0 ? 1 : 0;
+ nerrors += test_splitter() < 0 ? 1 : 0;
if(nerrors) {
HDprintf("***** %d Virtual File Driver TEST%s FAILED! *****\n",
diff --git a/testpar/t_span_tree.c b/testpar/t_span_tree.c
index fe8a618..8d2b61c 100644
--- a/testpar/t_span_tree.c
+++ b/testpar/t_span_tree.c
@@ -867,6 +867,12 @@ coll_read_test(void)
VRFY((ret >= 0),"H5D contiguous irregular collective read succeed");
/*
+ * Free read buffers.
+ */
+ HDfree(matrix_out);
+ HDfree(matrix_out1);
+
+ /*
* Close memory file and memory dataspaces.
*/
ret = H5Sclose(mspaceid);
diff --git a/tools/lib/h5tools.c b/tools/lib/h5tools.c
index cd915f5..2f641d0 100644
--- a/tools/lib/h5tools.c
+++ b/tools/lib/h5tools.c
@@ -531,9 +531,9 @@ h5tools_set_vfd_fapl(hid_t fapl, h5tools_fapl_info_t *fapl_info)
}
else if (!HDstrcmp(fapl_info->u.name, drivernames[ROS3_VFD_IDX])) {
#ifdef H5_HAVE_ROS3_VFD
- if (!fapl_info->info)
+ if (!fapl_info->info_string)
H5TOOLS_GOTO_ERROR(FAIL, "Read-only S3 VFD info is invalid");
- if (H5Pset_fapl_ros3(fapl, (H5FD_ros3_fapl_t *)fapl_info->info) < 0)
+ if (H5Pset_fapl_ros3(fapl, (H5FD_ros3_fapl_t *)fapl_info->info_string) < 0)
H5TOOLS_GOTO_ERROR(FAIL, "H5Pset_fapl_ros3() failed");
#else
H5TOOLS_GOTO_ERROR(FAIL, "Read-only S3 VFD is not enabled");
@@ -541,9 +541,9 @@ h5tools_set_vfd_fapl(hid_t fapl, h5tools_fapl_info_t *fapl_info)
}
else if (!HDstrcmp(fapl_info->u.name, drivernames[HDFS_VFD_IDX])) {
#ifdef H5_HAVE_LIBHDFS
- if (!fapl_info->info)
+ if (!fapl_info->info_string)
H5TOOLS_GOTO_ERROR(FAIL, "HDFS VFD info is invalid");
- if (H5Pset_fapl_hdfs(fapl, (H5FD_hdfs_fapl_t *)fapl_info->info) < 0)
+ if (H5Pset_fapl_hdfs(fapl, (H5FD_hdfs_fapl_t *)fapl_info->info_string) < 0)
H5TOOLS_GOTO_ERROR(FAIL, "H5Pset_fapl_hdfs() failed");
#else
H5TOOLS_GOTO_ERROR(FAIL, "The HDFS VFD is not enabled");
@@ -555,7 +555,7 @@ h5tools_set_vfd_fapl(hid_t fapl, h5tools_fapl_info_t *fapl_info)
break;
case VOL_BY_NAME:
- case VOL_BY_ID:
+ case VOL_BY_VALUE:
default:
H5TOOLS_GOTO_ERROR(FAIL, "invalid VFD retrieval type");
}
@@ -575,10 +575,11 @@ done:
*-------------------------------------------------------------------------
*/
static herr_t
-h5tools_set_vol_fapl(hid_t fapl, h5tools_fapl_info_t *fapl_info)
+h5tools_set_vol_fapl(hid_t fapl_id, h5tools_fapl_info_t *fapl_info)
{
htri_t connector_is_registered;
hid_t connector_id = H5I_INVALID_HID;
+ void *vol_info = NULL;
herr_t ret_value = SUCCEED;
switch (fapl_info->type) {
@@ -604,30 +605,40 @@ h5tools_set_vol_fapl(hid_t fapl, h5tools_fapl_info_t *fapl_info)
}
}
+ /* Convert the info string */
+ if (fapl_info->info_string)
+ if (H5VLconnector_str_to_info(fapl_info->info_string, connector_id, &vol_info) < 0)
+ H5TOOLS_GOTO_ERROR(FAIL, "can't get VOL info from string");
+
break;
- case VOL_BY_ID:
+ case VOL_BY_VALUE:
/* Retrieve VOL connector by ID */
- if ((connector_is_registered = H5VLis_connector_registered_by_value((H5VL_class_value_t) fapl_info->u.id)) < 0)
+ if ((connector_is_registered = H5VLis_connector_registered_by_value(fapl_info->u.value)) < 0)
H5TOOLS_GOTO_ERROR(FAIL, "can't check if VOL connector is registered");
if (connector_is_registered) {
- if ((connector_id = H5VLget_connector_id_by_value((H5VL_class_value_t) fapl_info->u.id)) < 0)
+ if ((connector_id = H5VLget_connector_id_by_value(fapl_info->u.value)) < 0)
H5TOOLS_GOTO_ERROR(FAIL, "can't get VOL connector ID");
}
else {
/* Check for VOL connectors that ship with the library */
- if (fapl_info->u.id == H5VL_NATIVE_VALUE) {
+ if (fapl_info->u.value == H5VL_NATIVE_VALUE) {
connector_id = H5VL_NATIVE;
}
- else if (fapl_info->u.id == H5VL_PASSTHRU_VALUE) {
+ else if (fapl_info->u.value == H5VL_PASSTHRU_VALUE) {
connector_id = H5VL_PASSTHRU;
}
else {
- if ((connector_id = H5VLregister_connector_by_value((H5VL_class_value_t) fapl_info->u.id, H5P_DEFAULT)) < 0)
+ if ((connector_id = H5VLregister_connector_by_value(fapl_info->u.value, H5P_DEFAULT)) < 0)
H5TOOLS_GOTO_ERROR(FAIL, "can't register VOL connector");
}
}
+ /* Convert the info string */
+ if (fapl_info->info_string)
+ if (H5VLconnector_str_to_info(fapl_info->info_string, connector_id, &vol_info) < 0)
+ H5TOOLS_GOTO_ERROR(FAIL, "can't get VOL info from string");
+
break;
case VFD_BY_NAME:
@@ -635,10 +646,14 @@ h5tools_set_vol_fapl(hid_t fapl, h5tools_fapl_info_t *fapl_info)
H5TOOLS_GOTO_ERROR(FAIL, "invalid VOL retrieval type");
}
- if (H5Pset_vol(fapl, connector_id, fapl_info->info) < 0)
+ if (H5Pset_vol(fapl_id, connector_id, vol_info) < 0)
H5TOOLS_GOTO_ERROR(FAIL, "can't set VOL connector on FAPL");
done:
+ if (vol_info)
+ if (H5VLfree_connector_info(connector_id, vol_info))
+ H5TOOLS_ERROR(FAIL, "failed to free VOL connector-specific info");
+
if (ret_value < 0) {
if (connector_id >= 0 && H5Idec_ref(connector_id) < 0)
H5TOOLS_ERROR(FAIL, "failed to decrement refcount on VOL connector ID");
@@ -658,44 +673,44 @@ done:
*-------------------------------------------------------------------------
*/
hid_t
-h5tools_get_fapl(hid_t fapl, h5tools_fapl_info_t *fapl_info)
+h5tools_get_fapl(hid_t prev_fapl_id, h5tools_fapl_info_t *fapl_info)
{
- hid_t new_fapl = H5I_INVALID_HID;
+ hid_t new_fapl_id = H5I_INVALID_HID;
hid_t ret_value = H5I_INVALID_HID;
- if (fapl < 0)
+ if (prev_fapl_id < 0)
H5TOOLS_GOTO_ERROR(FAIL, "invalid FAPL");
if (!fapl_info)
H5TOOLS_GOTO_ERROR(FAIL, "invalid FAPL retrieval info");
/* Make a copy of the FAPL if necessary, or create a FAPL if
* H5P_DEFAULT is specified. */
- if (H5P_DEFAULT == fapl) {
- if ((new_fapl = H5Pcreate(H5P_FILE_ACCESS)) < 0)
+ if (H5P_DEFAULT == prev_fapl_id) {
+ if ((new_fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0)
H5TOOLS_GOTO_ERROR(H5I_INVALID_HID, "H5Pcreate failed");
} /* end if */
else {
- if ((new_fapl = H5Pcopy(fapl)) < 0)
+ if ((new_fapl_id = H5Pcopy(prev_fapl_id)) < 0)
H5TOOLS_GOTO_ERROR(H5I_INVALID_HID, "H5Pcopy failed");
}
if (VFD_BY_NAME == fapl_info->type) {
- if (h5tools_set_vfd_fapl(new_fapl, fapl_info) < 0)
+ if (h5tools_set_vfd_fapl(new_fapl_id, fapl_info) < 0)
H5TOOLS_GOTO_ERROR(H5I_INVALID_HID, "failed to set VFD on FAPL");
}
- else if (VOL_BY_NAME == fapl_info->type || VOL_BY_ID == fapl_info->type) {
- if (h5tools_set_vol_fapl(new_fapl, fapl_info) < 0)
+ else if (VOL_BY_NAME == fapl_info->type || VOL_BY_VALUE == fapl_info->type) {
+ if (h5tools_set_vol_fapl(new_fapl_id, fapl_info) < 0)
H5TOOLS_GOTO_ERROR(H5I_INVALID_HID, "failed to set VOL on FAPL");
}
else
H5TOOLS_GOTO_ERROR(H5I_INVALID_HID, "invalid FAPL retrieval type");
- ret_value = new_fapl;
+ ret_value = new_fapl_id;
done:
- if ((new_fapl >= 0) && (ret_value < 0)) {
- H5Pclose(new_fapl);
- new_fapl = H5I_INVALID_HID;
+ if ((new_fapl_id >= 0) && (ret_value < 0)) {
+ H5Pclose(new_fapl_id);
+ new_fapl_id = H5I_INVALID_HID;
}
return ret_value;
@@ -887,9 +902,9 @@ h5tools_fopen(const char *fname, unsigned flags, hid_t fapl, hbool_t use_specifi
for (volnum = 0; volnum < NUM_VOLS; volnum++) {
h5tools_fapl_info_t vol_info;
- vol_info.type = VOL_BY_NAME;
- vol_info.info = NULL;
- vol_info.u.name = volnames[volnum];
+ vol_info.type = VOL_BY_NAME;
+ vol_info.info_string = NULL;
+ vol_info.u.name = volnames[volnum];
/* Get a FAPL for the current VOL connector */
if ((tmp_vol_fapl = h5tools_get_fapl(fapl, &vol_info)) < 0)
@@ -912,9 +927,9 @@ h5tools_fopen(const char *fname, unsigned flags, hid_t fapl, hbool_t use_specifi
if (drivernum == LOG_VFD_IDX)
continue;
- vfd_info.type = VFD_BY_NAME;
- vfd_info.info = NULL;
- vfd_info.u.name = drivernames[drivernum];
+ vfd_info.type = VFD_BY_NAME;
+ vfd_info.info_string = NULL;
+ vfd_info.u.name = drivernames[drivernum];
/* Using the current VOL FAPL as a base, get the correct FAPL for the given VFL driver */
if ((tmp_vfd_fapl = h5tools_get_fapl(tmp_vol_fapl, &vfd_info)) < 0)
diff --git a/tools/lib/h5tools.h b/tools/lib/h5tools.h
index 5244f7be..b931dc8 100644
--- a/tools/lib/h5tools.h
+++ b/tools/lib/h5tools.h
@@ -542,19 +542,19 @@ typedef struct h5tools_context_t {
typedef enum {
VFD_BY_NAME,
VOL_BY_NAME,
- VOL_BY_ID
+ VOL_BY_VALUE
} h5tools_fapl_info_type_t;
typedef struct h5tools_fapl_info_t {
h5tools_fapl_info_type_t type;
/* Pointer to information to be passed to the driver/connector for its setup */
- const void *info;
+ const char *info_string;
/* Field specifying either the driver's/connector's name or ID */
union {
- const char *name;
- long id;
+ const char *name; /* VOL and VFD */
+ H5VL_class_value_t value; /* VOL only */
} u;
} h5tools_fapl_info_t;
@@ -637,7 +637,7 @@ H5TOOLS_DLL int h5tools_set_attr_output_file(const char *fname, int is_bin);
H5TOOLS_DLL int h5tools_set_input_file(const char *fname, int is_bin);
H5TOOLS_DLL int h5tools_set_output_file(const char *fname, int is_bin);
H5TOOLS_DLL int h5tools_set_error_file(const char *fname, int is_bin);
-H5TOOLS_DLL hid_t h5tools_get_fapl(hid_t fapl, h5tools_fapl_info_t *fapl_info);
+H5TOOLS_DLL hid_t h5tools_get_fapl(hid_t prev_fapl_id, h5tools_fapl_info_t *fapl_info);
H5TOOLS_DLL herr_t h5tools_get_vfd_name(hid_t fapl_id, char *drivername, size_t drivername_size);
H5TOOLS_DLL hid_t h5tools_fopen(const char *fname, unsigned flags, hid_t fapl,
hbool_t use_specific_driver, char *drivername, size_t drivername_size);
diff --git a/tools/lib/h5tools_dump.c b/tools/lib/h5tools_dump.c
index cd7c3d2..b59ae93 100644
--- a/tools/lib/h5tools_dump.c
+++ b/tools/lib/h5tools_dump.c
@@ -3283,8 +3283,6 @@ h5tools_dump_dcpl(FILE *stream, const h5tool_format_t *info,
}
else {
haddr_t ioffset;
- void *obj = NULL;
- hid_t connector_id = H5I_INVALID_HID;
hbool_t supported = FALSE;
/* NORMAL FILE */
@@ -3304,10 +3302,7 @@ h5tools_dump_dcpl(FILE *stream, const h5tool_format_t *info,
/* Only dump the offset if the VOL connector implements
* the functionality.
*/
- obj = H5VLobject(dset_id);
- connector_id = H5VLget_connector_id(dset_id);
- H5VLintrospect_opt_query(obj, connector_id, H5VL_SUBCLS_DATASET, H5VL_NATIVE_DATASET_GET_OFFSET, &supported);
- H5VLclose(connector_id);
+ H5VLquery_optional(dset_id, H5VL_SUBCLS_DATASET, H5VL_NATIVE_DATASET_GET_OFFSET, &supported);
if (supported) {
@@ -3732,15 +3727,11 @@ h5tools_dump_comment(FILE *stream, const h5tool_format_t *info, h5tools_context_
* instead of the current stripmine position i; this is necessary
* to print the array indices
*/
- void *obj = NULL;
- hid_t connector_id = H5I_INVALID_HID;
hbool_t supported = FALSE;
/* Check if comments are supported and return if not */
- obj = H5VLobject(obj_id);
- connector_id = H5VLget_connector_id(obj_id);
- H5VLintrospect_opt_query(obj, connector_id, H5VL_SUBCLS_OBJECT, H5VL_NATIVE_OBJECT_GET_COMMENT, &supported);
- H5VLclose(connector_id);
+ H5VLquery_optional(obj_id, H5VL_SUBCLS_OBJECT, H5VL_NATIVE_OBJECT_GET_COMMENT, &supported);
+
if (!supported)
return;
diff --git a/tools/libtest/h5tools_test_utils.c b/tools/libtest/h5tools_test_utils.c
index 8956bb5..aecd3f5 100644
--- a/tools/libtest/h5tools_test_utils.c
+++ b/tools/libtest/h5tools_test_utils.c
@@ -1172,7 +1172,7 @@ test_set_configured_fapl(void)
/* test */
fapl_info.type = VFD_BY_NAME;
- fapl_info.info = C.conf_fa;
+ fapl_info.info_string = C.conf_fa;
fapl_info.u.name = C.vfdname;
result = h5tools_get_fapl(H5P_DEFAULT, &fapl_info);
if (C.expected == 0)
diff --git a/tools/src/h5dump/h5dump.c b/tools/src/h5dump/h5dump.c
index e49141d..3de6454 100644
--- a/tools/src/h5dump/h5dump.c
+++ b/tools/src/h5dump/h5dump.c
@@ -1418,13 +1418,13 @@ main(int argc, const char *argv[])
h5tools_fapl_info_t fapl_info;
/* Currently, only retrieval of VFDs is supported. */
- fapl_info.type = VFD_BY_NAME;
- fapl_info.info = NULL;
- fapl_info.u.name = driver;
+ fapl_info.type = VFD_BY_NAME;
+ fapl_info.info_string = NULL;
+ fapl_info.u.name = driver;
if (!HDstrcmp(driver, drivernames[ROS3_VFD_IDX])) {
#ifdef H5_HAVE_ROS3_VFD
- fapl_info.info = (void *)&ros3_fa;
+ fapl_info.info_string = (void *)&ros3_fa;
#else
error_msg("Read-Only S3 VFD not enabled.\n");
h5tools_setstatus(EXIT_FAILURE);
@@ -1433,7 +1433,7 @@ main(int argc, const char *argv[])
}
else if (!HDstrcmp(driver, drivernames[HDFS_VFD_IDX])) {
#ifdef H5_HAVE_LIBHDFS
- fapl_info.info = (void *)&hdfs_fa;
+ fapl_info.info_string = (void *)&hdfs_fa;
#else
error_msg("The HDFS VFD is not enabled.\n");
h5tools_setstatus(EXIT_FAILURE);
diff --git a/tools/src/h5dump/h5dump_ddl.c b/tools/src/h5dump/h5dump_ddl.c
index e97ab7e..1df205c 100644
--- a/tools/src/h5dump/h5dump_ddl.c
+++ b/tools/src/h5dump/h5dump_ddl.c
@@ -1136,8 +1136,6 @@ dump_fcpl(hid_t fid)
unsigned sym_ik; /* symbol table B-tree internal 'K' value */
unsigned istore_ik; /* indexed storage B-tree internal 'K' value */
- void *obj = NULL;
- hid_t connector_id = H5I_INVALID_HID;
hbool_t supported = FALSE;
/* Dumping the information here only makes sense for the native
@@ -1145,10 +1143,8 @@ dump_fcpl(hid_t fid)
* use that as a proxy for "native-ness". If that isn't supported, we'll
* just return.
*/
- obj = H5VLobject(fid);
- connector_id = H5VLget_connector_id(fid);
- H5VLintrospect_opt_query(obj, connector_id, H5VL_SUBCLS_FILE, H5VL_NATIVE_FILE_GET_INFO, &supported);
- H5VLclose(connector_id);
+ H5VLquery_optional(fid, H5VL_SUBCLS_FILE, H5VL_NATIVE_FILE_GET_INFO, &supported);
+
if (!supported)
return;
diff --git a/tools/src/h5ls/h5ls.c b/tools/src/h5ls/h5ls.c
index f82827c..9fc91f1 100644
--- a/tools/src/h5ls/h5ls.c
+++ b/tools/src/h5ls/h5ls.c
@@ -2364,8 +2364,6 @@ list_obj(const char *name, const H5O_info2_t *oinfo, const char *first_seen, voi
char* comment = NULL;
char* obj_tok_str = NULL;
ssize_t cmt_bufsize = -1;
- void *obj = NULL;
- hid_t connector_id = H5I_INVALID_HID;
hbool_t supported = FALSE;
/* Display attributes */
@@ -2401,10 +2399,7 @@ list_obj(const char *name, const H5O_info2_t *oinfo, const char *first_seen, voi
} /* end if */
/* Only emit comments if the VOL connector supports that */
- obj = H5VLobject(obj_id);
- connector_id = H5VLget_connector_id(obj_id);
- H5VLintrospect_opt_query(obj, connector_id, H5VL_SUBCLS_OBJECT, H5VL_NATIVE_OBJECT_GET_COMMENT, &supported);
- H5VLclose(connector_id);
+ H5VLquery_optional(obj_id, H5VL_SUBCLS_OBJECT, H5VL_NATIVE_OBJECT_GET_COMMENT, &supported);
if (supported) {
@@ -3156,13 +3151,13 @@ main(int argc, const char *argv[])
h5tools_fapl_info_t fapl_info;
/* Currently, only retrieval of VFDs is supported. */
- fapl_info.type = VFD_BY_NAME;
- fapl_info.info = NULL;
- fapl_info.u.name = preferred_driver;
+ fapl_info.type = VFD_BY_NAME;
+ fapl_info.info_string = NULL;
+ fapl_info.u.name = preferred_driver;
if (!HDstrcmp(preferred_driver, drivernames[ROS3_VFD_IDX])) {
#ifdef H5_HAVE_ROS3_VFD
- fapl_info.info = (void *)&ros3_fa;
+ fapl_info.info_string = (void *)&ros3_fa;
#else
HDfprintf(rawerrorstream, "Error: Read-Only S3 VFD is not enabled\n\n");
leave(EXIT_FAILURE);
@@ -3170,7 +3165,7 @@ main(int argc, const char *argv[])
}
else if (!HDstrcmp(preferred_driver, drivernames[HDFS_VFD_IDX])) {
#ifdef H5_HAVE_LIBHDFS
- fapl_info.info = (void *)&hdfs_fa;
+ fapl_info.info_string = (void *)&hdfs_fa;
#else
HDfprintf(rawerrorstream, "Error: The HDFS VFD is not enabled\n\n");
leave(EXIT_FAILURE);
diff --git a/tools/src/h5repack/h5repack_main.c b/tools/src/h5repack/h5repack_main.c
index 1761fb4..03da8d9 100644
--- a/tools/src/h5repack/h5repack_main.c
+++ b/tools/src/h5repack/h5repack_main.c
@@ -62,10 +62,10 @@ static struct long_options l_opts[] = {
{ "sort_by", require_arg, 'q' },
{ "sort_order", require_arg, 'z' },
{ "enable-error-stack", no_arg, 'E' },
- { "src-vol-id", require_arg, '1' },
+ { "src-vol-value", require_arg, '1' },
{ "src-vol-name", require_arg, '2' },
{ "src-vol-info", require_arg, '3' },
- { "dst-vol-id", require_arg, '4' },
+ { "dst-vol-value", require_arg, '4' },
{ "dst-vol-name", require_arg, '5' },
{ "dst-vol-info", require_arg, '6' },
{ NULL, 0, '\0' }
@@ -92,14 +92,14 @@ static void usage(const char *prog) {
PRINTVALSTREAM(rawoutstream, " -n, --native Use a native HDF5 type when repacking\n");
PRINTVALSTREAM(rawoutstream, " --enable-error-stack Prints messages from the HDF5 error stack as they\n");
PRINTVALSTREAM(rawoutstream, " occur\n");
- PRINTVALSTREAM(rawoutstream, " --src-vol-id ID of the VOL connector to use for opening the input\n");
- PRINTVALSTREAM(rawoutstream, " HDF5 file specified\n");
+ PRINTVALSTREAM(rawoutstream, " --src-vol-value Value (ID) of the VOL connector to use for opening the\n");
+ PRINTVALSTREAM(rawoutstream, " input HDF5 file specified\n");
PRINTVALSTREAM(rawoutstream, " --src-vol-name Name of the VOL connector to use for opening the input\n");
PRINTVALSTREAM(rawoutstream, " HDF5 file specified\n");
PRINTVALSTREAM(rawoutstream, " --src-vol-info VOL-specific info to pass to the VOL connector used for\n");
PRINTVALSTREAM(rawoutstream, " opening the input HDF5 file specified\n");
- PRINTVALSTREAM(rawoutstream, " --dst-vol-id ID of the VOL connector to use for opening the output\n");
- PRINTVALSTREAM(rawoutstream, " HDF5 file specified\n");
+ PRINTVALSTREAM(rawoutstream, " --dst-vol-value Value (ID) of the VOL connector to use for opening the\n");
+ PRINTVALSTREAM(rawoutstream, " output HDF5 file specified\n");
PRINTVALSTREAM(rawoutstream, " --dst-vol-name Name of the VOL connector to use for opening the output\n");
PRINTVALSTREAM(rawoutstream, " HDF5 file specified\n");
PRINTVALSTREAM(rawoutstream, " --dst-vol-info VOL-specific info to pass to the VOL connector used for\n");
@@ -682,8 +682,8 @@ int parse_command_line(int argc, const char **argv, pack_opt_t* options)
break;
case '1':
- in_vol_info.type = VOL_BY_ID;
- in_vol_info.u.id = HDatol(opt_arg);
+ in_vol_info.type = VOL_BY_VALUE;
+ in_vol_info.u.value = (H5VL_class_value_t)HDatoi(opt_arg);
custom_in_fapl = TRUE;
break;
@@ -694,12 +694,12 @@ int parse_command_line(int argc, const char **argv, pack_opt_t* options)
break;
case '3':
- in_vol_info.info = opt_arg;
+ in_vol_info.info_string = opt_arg;
break;
case '4':
- out_vol_info.type = VOL_BY_ID;
- out_vol_info.u.id = HDatol(opt_arg);
+ out_vol_info.type = VOL_BY_VALUE;
+ out_vol_info.u.value = (H5VL_class_value_t)HDatoi(opt_arg);
custom_out_fapl = TRUE;
break;
@@ -710,7 +710,7 @@ int parse_command_line(int argc, const char **argv, pack_opt_t* options)
break;
case '6':
- out_vol_info.info = opt_arg;
+ out_vol_info.info_string = opt_arg;
break;
default:
diff --git a/tools/src/h5stat/h5stat.c b/tools/src/h5stat/h5stat.c
index fdf49cd..bebe443 100644
--- a/tools/src/h5stat/h5stat.c
+++ b/tools/src/h5stat/h5stat.c
@@ -1816,13 +1816,13 @@ main(int argc, const char *argv[])
h5tools_fapl_info_t fapl_info;
/* Currently, only retrieval of VFDs is supported. */
- fapl_info.type = VFD_BY_NAME;
- fapl_info.info = NULL;
- fapl_info.u.name = drivername;
+ fapl_info.type = VFD_BY_NAME;
+ fapl_info.info_string = NULL;
+ fapl_info.u.name = drivername;
if (!HDstrcmp(drivername, drivernames[ROS3_VFD_IDX])) {
#ifdef H5_HAVE_ROS3_VFD
- fapl_info.info = (void *)&ros3_fa;
+ fapl_info.info_string = (void *)&ros3_fa;
#else
error_msg("Read-Only S3 VFD not enabled.\n");
goto done;
@@ -1830,7 +1830,7 @@ main(int argc, const char *argv[])
}
else if (!HDstrcmp(drivername, drivernames[HDFS_VFD_IDX])) {
#ifdef H5_HAVE_LIBHDFS
- fapl_info.info = (void *)&hdfs_fa;
+ fapl_info.info_string = (void *)&hdfs_fa;
#else
error_msg("HDFS VFD not enabled.\n");
goto done;
diff --git a/tools/test/h5repack/testfiles/h5repack-help.txt b/tools/test/h5repack/testfiles/h5repack-help.txt
index fe02584..00fae24 100644
--- a/tools/test/h5repack/testfiles/h5repack-help.txt
+++ b/tools/test/h5repack/testfiles/h5repack-help.txt
@@ -8,14 +8,14 @@ usage: h5repack [OPTIONS] file1 file2
-n, --native Use a native HDF5 type when repacking
--enable-error-stack Prints messages from the HDF5 error stack as they
occur
- --src-vol-id ID of the VOL connector to use for opening the input
- HDF5 file specified
+ --src-vol-value Value (ID) of the VOL connector to use for opening the
+ input HDF5 file specified
--src-vol-name Name of the VOL connector to use for opening the input
HDF5 file specified
--src-vol-info VOL-specific info to pass to the VOL connector used for
opening the input HDF5 file specified
- --dst-vol-id ID of the VOL connector to use for opening the output
- HDF5 file specified
+ --dst-vol-value Value (ID) of the VOL connector to use for opening the
+ output HDF5 file specified
--dst-vol-name Name of the VOL connector to use for opening the output
HDF5 file specified
--dst-vol-info VOL-specific info to pass to the VOL connector used for
diff --git a/utils/CMakeLists.txt b/utils/CMakeLists.txt
new file mode 100644
index 0000000..2d5626e
--- /dev/null
+++ b/utils/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required (VERSION 3.10)
+project (HDF5_UTILS C)
+
+add_subdirectory (mirror_vfd)
diff --git a/utils/COPYING b/utils/COPYING
new file mode 100644
index 0000000..4a23112
--- /dev/null
+++ b/utils/COPYING
@@ -0,0 +1,12 @@
+
+ Copyright by The HDF Group.
+ All rights reserved.
+
+ The files and subdirectories in this directory are 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.
+
diff --git a/utils/Makefile.am b/utils/Makefile.am
new file mode 100644
index 0000000..b4409ac
--- /dev/null
+++ b/utils/Makefile.am
@@ -0,0 +1,26 @@
+#
+# Copyright by The HDF Group.
+# 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.
+##
+## Makefile.am
+## Run automake to generate a Makefile.in from this file.
+##
+#
+# Utils HDF5 Makefile(.in)
+#
+
+include $(top_srcdir)/config/commence.am
+
+CONFIG=ordered
+
+# All subdirectories
+SUBDIRS=mirror_vfd
+
+include $(top_srcdir)/config/conclude.am
diff --git a/utils/mirror_vfd/CMakeLists.txt b/utils/mirror_vfd/CMakeLists.txt
new file mode 100644
index 0000000..1926352
--- /dev/null
+++ b/utils/mirror_vfd/CMakeLists.txt
@@ -0,0 +1,64 @@
+cmake_minimum_required (VERSION 3.10)
+project (HDF5_UTILS_MIRRORVFD C)
+
+#-----------------------------------------------------------------------------
+# Add the mirror_server executable
+#-----------------------------------------------------------------------------
+
+set (mirror_server_SOURCES
+ ${HDF5_UTILS_MIRRORVFD_SOURCE_DIR}/mirror_remote.c
+ ${HDF5_UTILS_MIRRORVFD_SOURCE_DIR}/mirror_server.c
+ ${HDF5_UTILS_MIRRORVFD_SOURCE_DIR}/mirror_writer.c)
+add_executable (mirror_server ${mirror_server_SOURCES})
+target_include_directories (mirror_server PRIVATE "${HDF5_UITLS_DIR};${HDF5_SRC_DIR};${HDF5_BINARY_DIR};$<$<BOOL:${HDF5_ENABLE_PARALLEL}>:${MPI_C_INCLUDE_DIRS}>")
+if (NOT BUILD_SHARED_LIBS)
+ TARGET_C_PROPERTIES (mirror_server STATIC)
+ target_link_libraries (mirror_server PRIVATE ${HDF5_TOOLS_LIB_TARGET} ${HDF5_LIB_TARGET})
+else ()
+ TARGET_C_PROPERTIES (mirror_server SHARED)
+ target_link_libraries (mirror_server PRIVATE ${HDF5_TOOLS_LIBSH_TARGET} ${HDF5_LIBSH_TARGET})
+endif ()
+set_target_properties (mirror_server PROPERTIES FOLDER utils)
+set_global_variable (HDF5_UTILS_TO_EXPORT "${HDF5_UTILS_TO_EXPORT};mirror_server")
+set (H5_DEP_EXECUTABLES ${H5_DEP_EXECUTABLES} mirror_server)
+
+#-----------------------------------------------------------------------------
+# Add the mirror_server_stop executable
+#-----------------------------------------------------------------------------
+
+set (mirror_server_stop_SOURCES ${HDF5_UTILS_MIRRORVFD_SOURCE_DIR}/mirror_server_stop.c)
+add_executable (mirror_server_stop ${mirror_server_stop_SOURCES})
+target_include_directories (mirror_server_stop PRIVATE "${HDF5_UITLS_DIR};${HDF5_SRC_DIR};${HDF5_BINARY_DIR};$<$<BOOL:${HDF5_ENABLE_PARALLEL}>:${MPI_C_INCLUDE_DIRS}>")
+if (NOT BUILD_SHARED_LIBS)
+ TARGET_C_PROPERTIES (mirror_server_stop STATIC)
+ target_link_libraries (mirror_server_stop PRIVATE ${HDF5_TOOLS_LIB_TARGET} ${HDF5_LIB_TARGET})
+else ()
+ TARGET_C_PROPERTIES (mirror_server_stop SHARED)
+ target_link_libraries (mirror_server_stop PRIVATE ${HDF5_TOOLS_LIBSH_TARGET} ${HDF5_LIBSH_TARGET})
+endif ()
+set_target_properties (mirror_server_stop PROPERTIES FOLDER utils)
+set_global_variable (HDF5_UTILS_TO_EXPORT "${HDF5_UTILS_TO_EXPORT};mirror_server_stop")
+set (H5_DEP_EXECUTABLES ${H5_DEP_EXECUTABLES} mirror_server_stop)
+
+##############################################################################
+##############################################################################
+### I N S T A L L A T I O N ###
+##############################################################################
+##############################################################################
+
+#-----------------------------------------------------------------------------
+# Rules for Installation of tools using make Install target
+#-----------------------------------------------------------------------------
+if (HDF5_EXPORTED_TARGETS)
+ foreach (exec ${H5_DEP_EXECUTABLES})
+ INSTALL_PROGRAM_PDB (${exec} ${HDF5_INSTALL_BIN_DIR} utilsapplications)
+ endforeach ()
+
+ install (
+ TARGETS
+ ${H5_DEP_EXECUTABLES}
+ EXPORT
+ ${HDF5_EXPORTED_TARGETS}
+ RUNTIME DESTINATION ${HDF5_INSTALL_BIN_DIR} COMPONENT utilsapplications
+ )
+endif ()
diff --git a/utils/mirror_vfd/Makefile.am b/utils/mirror_vfd/Makefile.am
new file mode 100644
index 0000000..96d3104
--- /dev/null
+++ b/utils/mirror_vfd/Makefile.am
@@ -0,0 +1,30 @@
+#
+# Copyright by The HDF Group.
+# 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.
+##
+## Makefile.am
+## Run automake to generate a Makefile.in from this file.
+#
+# HDF5 Library Makefile(.in)
+#
+
+include $(top_srcdir)/config/commence.am
+
+AM_CPPFLAGS+=-I$(top_srcdir)/src
+
+bin_PROGRAMS = mirror_server mirror_server_stop
+
+mirror_server_SOURCES = mirror_server.c mirror_writer.c mirror_remote.c
+#mirror_writer_SOURCES = mirror_writer.c mirror_remote.c
+
+# All programs depend on the hdf5 library
+LDADD=$(LIBHDF5)
+
+include $(top_srcdir)/config/conclude.am
diff --git a/utils/mirror_vfd/mirror_remote.c b/utils/mirror_vfd/mirror_remote.c
new file mode 100644
index 0000000..81a3625
--- /dev/null
+++ b/utils/mirror_vfd/mirror_remote.c
@@ -0,0 +1,225 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * 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. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/* Common operations for "remote" processes for the Mirror VFD.
+ *
+ * Jacob Smith, 2020-03-06
+ */
+
+#include "mirror_remote.h"
+
+#ifdef H5_HAVE_MIRROR_VFD
+
+
+/* ---------------------------------------------------------------------------
+ * Function: mirror_log
+ *
+ * Purpose: Write message to the logging stream/file.
+ * If logging info pointer is NULL, uses logging defaults.
+ * ----------------------------------------------------------------------------
+ */
+void
+mirror_log(struct mirror_log_info *info,
+ unsigned int level,
+ const char *format,
+ ...)
+{
+ FILE *stream = MIRROR_LOG_DEFAULT_STREAM;
+ unsigned int verbosity = MIRROR_LOG_DEFAULT_VERBOSITY;
+ hbool_t custom = FALSE;
+
+ if (info != NULL && info->magic == MIRROR_LOG_INFO_MAGIC) {
+ stream = info->stream;
+ verbosity = info->verbosity;
+ custom = TRUE;
+ }
+
+ if (level == V_NONE) {
+ return;
+ }
+ else
+ if (level <= verbosity) {
+ if (custom == TRUE && info->prefix[0] != '\0') {
+ HDfprintf(stream, "%s", info->prefix);
+ }
+
+ switch (level) {
+ case (V_ERR) :
+ HDfprintf(stream, "ERROR ");
+ break;
+ case (V_WARN) :
+ HDfprintf(stream, "WARNING ");
+ break;
+ default:
+ break;
+ }
+
+ if (format != NULL) {
+ va_list args;
+ HDva_start(args, format);
+ HDvfprintf(stream, format, args);
+ HDva_end(args);
+ }
+
+ HDfprintf(stream, "\n");
+ HDfflush(stream);
+ } /* end if sufficiently verbose to print */
+} /* end mirror_log() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: session_log_bytes
+ *
+ * Purpose: "Pretty-print" raw binary data to logging stream/file.
+ * If info pointer is NULL, uses logging defaults.
+ * ----------------------------------------------------------------------------
+ */
+void
+mirror_log_bytes(struct mirror_log_info *info,
+ unsigned int level,
+ size_t n_bytes,
+ const unsigned char *buf)
+{
+ FILE *stream = MIRROR_LOG_DEFAULT_STREAM;
+ unsigned int verbosity = MIRROR_LOG_DEFAULT_VERBOSITY;
+
+ if (buf == NULL) {
+ return;
+ }
+
+ if (info != NULL && info->magic == MIRROR_LOG_INFO_MAGIC) {
+ stream = info->stream;
+ verbosity = info->verbosity;
+ }
+
+ if (level <= verbosity) {
+ size_t bytes_written = 0;
+ const unsigned char *b = NULL;
+
+ /* print whole lines */
+ while ((n_bytes - bytes_written) >= 32) {
+ b = buf + bytes_written; /* point to region in buffer */
+ HDfprintf(stream,
+ "%04zX %02X%02X%02X%02X %02X%02X%02X%02X" \
+ " %02X%02X%02X%02X %02X%02X%02X%02X" \
+ " %02X%02X%02X%02X %02X%02X%02X%02X" \
+ " %02X%02X%02X%02X %02X%02X%02X%02X\n",
+ bytes_written,
+ b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7],
+ b[8], b[9], b[10],b[11], b[12],b[13],b[14],b[15],
+ b[16],b[17],b[18],b[19], b[20],b[21],b[22],b[23],
+ b[24],b[25],b[26],b[27], b[28],b[29],b[30],b[31]);
+ bytes_written += 32;
+ }
+
+ /* start partial line */
+ if (n_bytes > bytes_written) {
+ HDfprintf(stream, "%04zX ", bytes_written);
+ }
+
+ /* partial line blocks */
+ while ((n_bytes - bytes_written) >= 4) {
+ HDfprintf(stream, " %02X%02X%02X%02X",
+ buf[bytes_written], buf[bytes_written+1],
+ buf[bytes_written+2], buf[bytes_written+3]);
+ bytes_written += 4;
+ }
+
+ /* block separator before partial block */
+ if (n_bytes > bytes_written) {
+ HDfprintf(stream, " ");
+ }
+
+ /* partial block individual bytes */
+ while (n_bytes > bytes_written) {
+ HDfprintf(stream, "%02X", buf[bytes_written++]);
+ }
+
+ /* end partial line */
+ HDfprintf(stream, "\n");
+ } /* end if suitably verbose to log */
+} /* end mirror_log_bytes() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: mirror_log_init
+ *
+ * Purpose: Prepare a loginfo_t structure for use.
+ *
+ * Return: Success: Pointer to newly-ceated info.
+ * Failure: NULL. Either unable to allocate or cannot open file.
+ * ----------------------------------------------------------------------------
+ */
+loginfo_t *
+mirror_log_init(char *path, char *prefix, unsigned int verbosity)
+{
+ loginfo_t *info = NULL;
+
+ info = (loginfo_t *)HDmalloc(sizeof(loginfo_t));
+ if (info != NULL) {
+ info->magic = MIRROR_LOG_INFO_MAGIC;
+ info->verbosity = verbosity;
+ info->stream = MIRROR_LOG_DEFAULT_STREAM;
+ info->prefix[0] = '\0';
+
+ if (prefix && *prefix) {
+ HDstrncpy(info->prefix, prefix, MIRROR_LOG_PREFIX_MAX);
+ }
+
+ if (path && *path) {
+ FILE *f = NULL;
+ f = HDfopen(path, "w");
+ if (NULL == f) {
+ HDfprintf(MIRROR_LOG_DEFAULT_STREAM,
+ "WARN custom logging path could not be opened: %s\n",
+ path);
+ info->magic += 1;
+ HDfree(info);
+ }
+ else {
+ info->stream = f;
+ }
+ }
+
+ } /* end if able to allocate */
+
+ return info;
+} /* end mirror_log_init() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: mirror_log_term
+ *
+ * Purpose: Shut down and clean up a loginfo_t structure.
+ *
+ * Return: Success: SUCCEED. Resources released.
+ * Failure: FAIL. Indeterminite state.
+ * ----------------------------------------------------------------------------
+ */
+herr_t
+mirror_log_term(loginfo_t *info)
+{
+ if (info == NULL || info->magic != MIRROR_LOG_INFO_MAGIC) {
+ return FAIL;
+ }
+ if (info->stream != stderr || info->stream != stdout) {
+ if (HDfclose(info->stream) < 0) {
+ return FAIL;
+ }
+ }
+ info->magic += 1;
+ HDfree(info);
+ return SUCCEED;
+} /* end mirror_log_term() */
+
+#endif /* H5_HAVE_MIRROR_VFD */
+
diff --git a/utils/mirror_vfd/mirror_remote.h b/utils/mirror_vfd/mirror_remote.h
new file mode 100644
index 0000000..9132d51
--- /dev/null
+++ b/utils/mirror_vfd/mirror_remote.h
@@ -0,0 +1,51 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * 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. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/* Common definitions for "remote" processes for the Mirror VFD.
+ *
+ * Jacob Smith, 2020-03-06
+ */
+
+#include "hdf5.h"
+#include "H5private.h"
+
+#ifdef H5_HAVE_MIRROR_VFD
+
+#define V_NONE 0
+#define V_ERR 1
+#define V_WARN 2
+#define V_INFO 3
+#define V_ALL 4
+
+#define MIRROR_LOG_DEFAULT_STREAM stdout
+#define MIRROR_LOG_DEFAULT_VERBOSITY V_WARN
+#define MIRROR_LOG_PREFIX_MAX 79
+#define MIRROR_LOG_INFO_MAGIC 0x569D589A
+
+typedef struct mirror_log_info {
+ uint32_t magic;
+ FILE *stream;
+ unsigned int verbosity;
+ char prefix[MIRROR_LOG_PREFIX_MAX+1];
+} loginfo_t;
+
+void mirror_log(loginfo_t *info, unsigned int level,
+ const char *format, ...);
+void mirror_log_bytes(loginfo_t *info, unsigned int level,
+ size_t n_bytes, const unsigned char *buf);
+loginfo_t *mirror_log_init(char *path, char *prefix, unsigned int verbosity);
+int mirror_log_term(loginfo_t *loginfo);
+
+herr_t run_writer(int socketfd, H5FD_mirror_xmit_open_t *xmit_open);
+
+#endif /* H5_HAVE_MIRROR_VFD */
+
diff --git a/utils/mirror_vfd/mirror_server.c b/utils/mirror_vfd/mirror_server.c
new file mode 100644
index 0000000..2583e60
--- /dev/null
+++ b/utils/mirror_vfd/mirror_server.c
@@ -0,0 +1,666 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * 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. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * "Server" application to associate a Mirror VFD Driver with a Writer.
+ *
+ * Server waits on a dedicated port for a Driver to attempt to connect.
+ * When connection is made, reads a message from the Driver.
+ * If message is "SHUTDOWN", Server closes connection and terminates.
+ * Else, if it receives an encoded OPEN xmit (from Driver), the Server forks
+ * itself; the child becomes a dedicated Writer and maintains connection with
+ * the Driver instance, and the parent process remains a Server and returns
+ * to listening for incoming requests.
+ * Else, the message is not recognized and is ignored.
+ *
+ *
+ *
+ * mirror_server [args]
+ *
+ * Primary server for coordinating mirror VFD connections with the remote
+ * process.
+ *
+ * args:
+ * --help, -h Print help message and exit.
+ * --port=N Positive integer for primary listening port.
+ * --verbosity=N Debugging verbosity
+ * 0: none
+ * 1: errors
+ * 2: details
+ * 3: all
+ * --logpath=S File path to direct debugging output, if any.
+ * Default of none prints output to stdout.
+ *
+ */
+
+#include "mirror_remote.h"
+
+#ifdef H5_HAVE_MIRROR_VFD
+
+#define MAXBUF 2048 /* max buffer length. */
+#define LISTENQ 80 /* max pending mirrorS requests */
+#define DEFAULT_PORT 3000 /* default listening port */
+#define MAX_PORT_LOOPS 20 /* max iteratations through port range */
+#define PORT_LOOP_RETRY_DELAY 1 /* seconds to wait between port scans */
+
+/* semi-unique "magic" numbers to sanity-check structure pointers */
+#define OP_ARGS_MAGIC 0xCF074379u
+#define SERVER_RUN_MAGIC 0x741B459Au
+
+
+/* ---------------------------------------------------------------------------
+ * Structure: struct op_args
+ *
+ * Purpose: Convenience structure for holding arguments from command-line.
+ *
+ * `magic` (uint32_t)
+ * Semi-unique number to help validate a pointer to this struct type.
+ * Must be OP_ARGS_MAGIC to be considered valid.
+ *
+ * `help` (int)
+ * Flag that the help argument was present in the command line.
+ *
+ * `main_port` (int)
+ * Flag that the help argument was present in the command line.
+ *
+ * `verbosity` (int)
+ * Number between 0 (none) and 4 (all) that controls how much detail
+ * the program prints as a course of logging.
+ *
+ * `log_prepend_serv` (int)
+ * Flag that the logging messages should have 'S- ' at the start of each
+ * line.
+ *
+ * `log_prepend_type` (int)
+ * Flag that the logging messages should have the assocaited verbosity
+ * level present in the line (e.g., "WARN", "ERROR", or "INFO").
+ *
+ * `log_path` (char *)
+ * Path string from the command line, giving the absolute path
+ * for the file for logging output. Can be empty.
+ *
+ * `writer_log_path` (char *)
+ * Path string from the command line, giving the absolute path
+ * for the file for writer's logging output. Can be empty.
+ *
+ * ---------------------------------------------------------------------------
+ */
+struct op_args {
+ uint32_t magic;
+ int help;
+ int main_port;
+ int verbosity;
+ int log_prepend_serv;
+ int log_prepend_type;
+ char log_path[PATH_MAX+1];
+ char writer_log_path[PATH_MAX+1];
+};
+
+
+/* ---------------------------------------------------------------------------
+ * Structure: struct server_run
+ *
+ * Purpose: Convenience structure for holding information about a server
+ * in operation.
+ *
+ * `magic` (uint32_t)
+ * Semi-unique number to help validate a pointer to this struct type.
+ * Must be SERVER_RUN_MAGIC to be considered valid.
+ *
+ * `log_stream` (FILE *)
+ * File handle where logging output is directed.
+ * By default, is stdout.
+ *
+ * `opts` (struct opt_args)
+ * Contained structure, holds the server's configuration.
+ *
+ * `listenfd` (int)
+ * File descriptor of the listening socket.
+ *
+ * ---------------------------------------------------------------------------
+ */
+struct server_run {
+ uint32_t magic;
+ struct op_args opts;
+ struct mirror_log_info *loginfo;
+ int listenfd;
+};
+
+
+/* ---------------------------------------------------------------------------
+ * Function: mybzero
+ *
+ * Purpose: Introduce bzero without neededing it on the system.
+ *
+ * Programmer: Jacob Smith
+ * 2020-03-30
+ * ---------------------------------------------------------------------------
+ */
+static void mybzero(void *dest, size_t size)
+{
+ size_t i = 0;
+ char *s = NULL;
+ HDassert(dest);
+ s = (char *)dest;
+ for (i = 0; i < size; i++) {
+ *(s+i) = 0;
+ }
+} /* end mybzero() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: usage
+ *
+ * Purpose: Print the usage message to stdout.
+ * ---------------------------------------------------------------------------
+ */
+static void
+usage(void)
+{
+ HDfprintf(stdout,
+ "mirror_server [options]\n" \
+ "\n" \
+ "Application for providing Mirror Writer process to " \
+ " Mirror VFD on file-open.\n" \
+ "Listens on a dedicated socket; forks as a Writer upon receipt" \
+ " of a valid OPEN xmit.\n" \
+ "\n" \
+ "Options:\n" \
+ "--help [-h] : Print this help message and quit.\n" \
+ "--logpath=PATH : File path for logging output " \
+ "(default none, to stdout).\n" \
+ "--port=PORT : Primary port (default %d).\n" \
+ "--verbosity=NUM : Debug printing level " \
+ "0..4, (default %d).\n",
+ DEFAULT_PORT,
+ MIRROR_LOG_DEFAULT_VERBOSITY);
+} /* end usage() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: parse_args
+ *
+ * Purpose: Read command line options and store results in args_out
+ * structure. Fails in event of unrecognized option.
+ *
+ * Return: 0 on success, -1 on failure.
+ * ---------------------------------------------------------------------------
+ */
+static int
+parse_args(int argc, char **argv, struct op_args *args_out)
+{
+ int i;
+
+ /* preset default values
+ */
+ args_out->main_port = DEFAULT_PORT;
+ args_out->help = 0;
+ args_out->log_prepend_serv = 1;
+ args_out->log_prepend_type = 1;
+ args_out->verbosity = MIRROR_LOG_DEFAULT_VERBOSITY;
+ /* preset empty strings */
+ mybzero(args_out->log_path, PATH_MAX+1);
+ mybzero(args_out->writer_log_path, PATH_MAX+1);
+
+ if (argv == NULL || *argv == NULL) {
+ mirror_log(NULL, V_ERR, "invalid argv pointer");
+ return -1;
+ }
+
+ /* Loop over arguments after program name and writer_path */
+ for (i=2; i < argc; i++) {
+ if (!HDstrncmp(argv[i], "-h", 3) || !HDstrncmp(argv[i], "--help", 7)) {
+ mirror_log(NULL, V_INFO, "found help argument");
+ args_out->help = 1;
+ return 0;
+ } /* end if help */
+ else
+ if (!HDstrncmp(argv[i], "--port=", 7)) {
+ mirror_log(NULL, V_INFO, "parsing 'main_port' (%s)", argv[i]+7);
+ args_out->main_port = HDatoi(argv[i]+7);
+ } /* end if port */
+ else
+ if (!HDstrncmp(argv[i], "--verbosity=", 12)) {
+ mirror_log(NULL, V_INFO, "parsing 'verbosity' (%s)", argv[i]+12);
+ args_out->verbosity = HDatoi(argv[i]+12);
+ } /* end if verbosity */
+ else
+ if (!HDstrncmp(argv[i], "--logpath=", 10)) {
+ mirror_log(NULL, V_INFO, "parsing 'logpath' (%s)", argv[i]+10);
+ HDstrncpy(args_out->log_path, argv[i]+10, PATH_MAX);
+ } /* end if logpath */
+ else {
+ mirror_log(NULL, V_ERR, "unrecognized argument: %s", argv[i]);
+ return -1;
+ } /* end if unrecognized argument */
+ } /* end for each arg after the path to writer "receiver process" */
+
+ mirror_log(NULL, V_INFO, "all args parsed");
+
+ return 0;
+} /* end parse_args() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: prepare_listening_socket
+ *
+ * Purpose: Configure and open a socket.
+ * In event of error, attempts to undo its processes.
+ *
+ * Return: Success: non-negative (the file descriptor of the socket)
+ * Failure: -1
+ * ---------------------------------------------------------------------------
+ */
+static int
+prepare_listening_socket(struct server_run *run)
+{
+ struct sockaddr_in server_addr;
+ int _true = 1; /* needed for setsockopt() */
+ int ret_value = -1;
+ int ret = 0; /* for checking return value of function calls */
+
+ if (run == NULL || run->magic != SERVER_RUN_MAGIC) {
+ mirror_log(NULL, V_ERR, "invalid server_run pointer");
+ return -1;
+ }
+
+ mirror_log(run->loginfo, V_INFO, "preparing socket");
+
+ server_addr.sin_family = AF_INET;
+ server_addr.sin_addr.s_addr = HDhtonl(INADDR_ANY);
+ server_addr.sin_port = HDhtons((uint16_t)run->opts.main_port);
+
+ mirror_log(run->loginfo, V_INFO, "socket()");
+ ret_value = HDsocket(AF_INET, SOCK_STREAM, 0);
+ if (ret_value < 0) {
+ mirror_log(run->loginfo, V_ERR, "listening socket:%d", ret_value);
+ goto error;
+ }
+
+ mirror_log(run->loginfo, V_ALL, "setsockopt()");
+ HDsetsockopt(ret_value, SOL_SOCKET, SO_REUSEADDR, &_true, sizeof(int));
+
+ mirror_log(run->loginfo, V_INFO, "bind()");
+ ret = HDbind(ret_value, (struct sockaddr *)&server_addr,
+ sizeof(server_addr));
+ if (ret < 0) {
+ mirror_log(run->loginfo, V_ERR, "bind() %s", HDstrerror(errno));
+ goto error;
+ }
+
+ mirror_log(run->loginfo, V_INFO, "listen()");
+ ret = HDlisten(ret_value, LISTENQ);
+ if (ret < 0) {
+ mirror_log(run->loginfo, V_ERR, "H5FD server listen:%d", ret);
+ goto error;
+ }
+
+ return ret_value;
+
+error:
+ if (ret_value >= 0) {
+ HDshutdown(ret_value, SHUT_RDWR);
+ HDclose(ret_value);
+ }
+ return -1;
+} /* end prepare_listening_socket() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: init_server_run
+ *
+ * Purpose: Set up server_run struct with default and specified values.
+ *
+ * Return: Zero (0) if successful, -1 if an error occurred.
+ * ---------------------------------------------------------------------------
+ */
+static struct server_run *
+init_server_run(int argc, char **argv)
+{
+ struct server_run *run;
+
+ run = (struct server_run *)HDmalloc(sizeof(struct server_run));
+ if (run == NULL) {
+ mirror_log(NULL, V_ERR, "can't allocate server_run struct");
+ return NULL;
+ }
+
+ run->magic = (uint32_t)SERVER_RUN_MAGIC;
+ run->opts.magic = (uint32_t)OP_ARGS_MAGIC;
+ run->listenfd = -1;
+
+ if (parse_args(argc, argv, &(run->opts)) < 0) {
+ mirror_log(NULL, V_ERR, "can't parse arguments");
+ usage();
+ goto error;
+ }
+
+ if (run->opts.help) {
+ usage();
+ return run; /* early exit */
+ }
+
+ run->loginfo = mirror_log_init(run->opts.log_path, "s- ",
+ run->opts.verbosity);
+
+ run->listenfd = prepare_listening_socket(run);
+ if (run->listenfd < 0) {
+ mirror_log(NULL, V_ERR, "can't prepare listening socket");
+ goto error;
+ }
+
+ return run;
+
+error:
+ if (run != NULL) {
+ HDfree(run);
+ }
+ return NULL;
+
+} /* end init_server_run() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: term_server_run
+ *
+ * Purpose: Close opened items in a sever_run and release the pointer.
+ *
+ * Return: Zero (0) if successful, -1 if an error occurred.
+ * ---------------------------------------------------------------------------
+ */
+static int
+term_server_run(struct server_run *run)
+{
+ if (run == NULL || run->magic != SERVER_RUN_MAGIC) {
+ mirror_log(NULL, V_ERR, "invalid server_run pointer");
+ return -1;
+ }
+
+ mirror_log(run->loginfo, V_INFO, "shutting down");
+
+ if (run->listenfd >= 0) {
+ HDshutdown(run->listenfd, SHUT_RDWR); /* TODO: error-checking? */
+ HDclose(run->listenfd); /* TODO: error-checking? */
+ run->listenfd = -1;
+ }
+
+ if (mirror_log_term(run->loginfo) < 0) {
+ mirror_log(NULL, V_ERR, "can't close logging stream");
+ return -1; /* doesn't solve the problem, but informs of error */
+ }
+ run->loginfo = NULL;
+
+ (run->magic)++;
+ (run->opts.magic)++;
+ HDfree(run);
+ return 0;
+} /* end term_server_run() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: accept_connection
+ *
+ * Purpose: Main working loop; process requests as they are received.
+ * Does nothing if the run option help is set.
+ *
+ * Return: -1 on error, else a non-negative file descriptor of the socket.
+ * ---------------------------------------------------------------------------
+ */
+static int
+accept_connection(struct server_run *run)
+{
+ struct sockaddr_in client_addr; /**/
+ socklen_t clilen; /**/
+ struct hostent *host_port = NULL; /**/
+ char *hostaddrp; /**/
+ int connfd = -1; /* connection file descriptor */
+
+ if (run == NULL || run->magic != SERVER_RUN_MAGIC) {
+ mirror_log(NULL, V_ERR, "invalid server_run pointer");
+ return -1;
+ }
+
+ /*------------------------------*/
+ /* accept a connection on a socket */
+ clilen = sizeof(client_addr);
+ connfd = HDaccept(run->listenfd, (struct sockaddr *)&client_addr, &clilen);
+ if (connfd < 0) {
+ mirror_log(run->loginfo, V_ERR, "accept:%d", connfd);
+ goto error;
+ }
+ mirror_log(run->loginfo, V_INFO, "connection achieved");
+
+ /*------------------------------*/
+ /* get client address information */
+ host_port = HDgethostbyaddr(
+ (const char *)&client_addr.sin_addr.s_addr,
+ sizeof(client_addr.sin_addr.s_addr),
+ AF_INET);
+ if (host_port == NULL) {
+ mirror_log(run->loginfo, V_ERR, "gethostbyaddr()");
+ goto error;
+ }
+
+ /* function has the string space statically scoped -- OK until next call */
+ hostaddrp = HDinet_ntoa(client_addr.sin_addr);
+ /* TODO? proper error-checking */
+
+ mirror_log(run->loginfo, V_INFO,
+ "server connected with %s (%s)",
+ host_port->h_name,
+ hostaddrp);
+
+ return connfd;
+
+error:
+ if (connfd >= 0) {
+ close(connfd);
+ }
+ return -1;
+} /* end accept_connection() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: wait_for_child
+ *
+ * Purpose: Signal handler to reap zombie processes.
+ * ---------------------------------------------------------------------------
+ */
+static void
+wait_for_child(int sig)
+{
+ while (HDwaitpid(-1, NULL, WNOHANG) > 0);
+} /* end wait_for_child() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: handle_requests
+ *
+ * Purpose: Main working loop; process requests as they are received.
+ * Does nothing if the run option `help` is set.
+ *
+ * Return: -1 on error, else 0 for successful operation.
+ * ---------------------------------------------------------------------------
+ */
+static int
+handle_requests(struct server_run *run)
+{
+ int connfd = -1; /**/
+ char mybuf[H5FD_MIRROR_XMIT_OPEN_SIZE]; /**/
+ int ret; /* general-purpose error-checking */
+ int pid; /* process ID of fork */
+ struct sigaction sa;
+ int ret_value = 0;
+
+ if (run == NULL || run->magic != SERVER_RUN_MAGIC) {
+ mirror_log(NULL, V_ERR, "invalid server_run pointer");
+ return -1;
+ }
+
+ if (run->opts.help) {
+ return 0;
+ }
+
+ if (run->listenfd < 0) {
+ mirror_log(NULL, V_ERR, "invalid listening socket");
+ return -1;
+ }
+
+ /* Set up the signal handler */
+ sa.sa_handler = wait_for_child;
+ HDsigemptyset(&sa.sa_mask);
+ sa.sa_flags = SA_RESTART;
+ if (HDsigaction(SIGCHLD, &sa, NULL) == -1) {
+ perror("sigaction");
+ return 1;
+ }
+
+ /* Keep listening for attempts to connect.
+ */
+
+ while (1) { /* infinite loop, exited via break or goto */
+ mirror_log(run->loginfo, V_INFO, "server waiting for connections...");
+
+ connfd = -1;
+
+ connfd = accept_connection(run);
+ if (connfd < 0) {
+ mirror_log(run->loginfo, V_ERR, "unable to receive connection");
+ goto error;
+ }
+
+ /* Read handshake from port connection.
+ */
+
+ ret = (int)HDread(connfd, &mybuf, H5FD_MIRROR_XMIT_OPEN_SIZE);
+ if (-1 == ret) {
+ mirror_log(run->loginfo, V_ERR, "read:%d", ret);
+ goto error;
+ }
+ mirror_log(run->loginfo, V_INFO, "received %d bytes", ret);
+ mirror_log(run->loginfo, V_ALL, "```");
+ mirror_log_bytes(run->loginfo, V_ALL, ret,
+ (const unsigned char *)mybuf);
+ mirror_log(run->loginfo, V_ALL, "```");
+
+ /* Respond to handshake message.
+ */
+
+ if (!HDstrncmp("SHUTDOWN", mybuf, 8)) {
+ /* Stop operation if told to stop */
+ mirror_log(run->loginfo, V_INFO, "received SHUTDOWN!", ret);
+ HDclose(connfd);
+ connfd = -1;
+ goto done;
+ } /* end if explicit "SHUTDOWN" directive */
+ else
+ if (H5FD_MIRROR_XMIT_OPEN_SIZE == ret) {
+ H5FD_mirror_xmit_open_t xopen;
+
+ mirror_log(run->loginfo, V_INFO,
+ "probable OPEN xmit received");
+
+ H5FD_mirror_xmit_decode_open(&xopen, (const unsigned char *)mybuf);
+ if (FALSE == H5FD_mirror_xmit_is_open(&xopen)) {
+ mirror_log(run->loginfo, V_WARN,
+ "expected OPEN xmit was malformed");
+ HDclose(connfd);
+ continue;
+ }
+
+ mirror_log(run->loginfo, V_INFO,
+ "probable OPEN xmit confirmed");
+
+ pid = HDfork();
+ if (pid < 0) { /* fork error */
+ mirror_log(run->loginfo, V_ERR, "cannot fork");
+ goto error;
+ } /* end if fork error */
+ else
+ if (pid == 0) { /* child process (writer side of fork) */
+ mirror_log(run->loginfo, V_INFO,
+ "executing writer");
+ if (run_writer(connfd, &xopen) < 0) {
+ HDprintf("can't run writer\n");
+ }
+ else {
+ HDprintf("writer OK\n");
+ }
+ HDclose(connfd);
+
+ HDexit(EXIT_SUCCESS);
+ } /* end if writer side of fork */
+ else { /* parent process (server side of fork) */
+ mirror_log(run->loginfo, V_INFO, "tidying up from handshake");
+ HDclose(connfd);
+ } /* end if server side of fork */
+
+ } /* end else-if valid request for service */
+ else {
+ /* Ignore unrecognized messages */
+ HDclose(connfd);
+ continue;
+ } /* end else (not a valid message, to be ignored) */
+
+ } /* end while listening for new connections */
+
+done:
+ if (connfd >= 0) {
+ mirror_log(run->loginfo, V_WARN, "connfd still open upon cleanup");
+ HDclose(connfd);
+ }
+
+ return ret_value;
+
+error:
+ if (connfd >= 0) {
+ HDclose(connfd);
+ }
+ return -1;
+} /* end handle_requests() */
+
+
+/* ------------------------------------------------------------------------- */
+int
+main(int argc, char **argv)
+{
+ struct server_run *run;
+
+ run = init_server_run(argc, argv);
+ if (NULL == run) {
+ mirror_log(NULL, V_ERR, "can't initialize run");
+ HDexit(EXIT_FAILURE);
+ }
+
+ if (handle_requests(run) < 0) {
+ mirror_log(run->loginfo, V_ERR, "problem handling requests");
+ }
+
+ if (term_server_run(run) < 0) {
+ mirror_log(NULL, V_ERR, "problem closing server run");
+ HDexit(EXIT_FAILURE);
+ }
+
+ HDexit(EXIT_SUCCESS);
+} /* end main() */
+
+#else /* H5_HAVE_MIRROR_VFD */
+
+int
+main(int argc, char **argv)
+{
+ HDprintf("Mirror VFD was not built -- cannot launch server.\n");
+ HDexit(EXIT_FAILURE);
+}
+
+#endif /* H5_HAVE_MIRROR_VFD */
+
diff --git a/utils/mirror_vfd/mirror_server_stop.c b/utils/mirror_vfd/mirror_server_stop.c
new file mode 100644
index 0000000..ccd5824
--- /dev/null
+++ b/utils/mirror_vfd/mirror_server_stop.c
@@ -0,0 +1,214 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * 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. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Purpose: Stop the mirror server
+ * Exists for cross-platform, optionally remote shutdown.
+ */
+
+#include "H5private.h" /* System compatability call-wrapper macros */
+
+#ifdef H5_HAVE_MIRROR_VFD
+
+#define MSHS_OPTS_MAGIC 0x613B1C15u /* sanity-checking constant */
+#define MSHS_IP_STR_SIZE 20
+#define MSHS_DEFAULT_IP "127.0.0.1"
+#define MSHS_DEFAULT_PORTNO 3000
+
+
+/* ----------------------------------------------------------------------------
+ * Structure: struct mshs_opts
+ *
+ * Purpose: Convenience structure to hold options as parsed from the
+ * command line.
+ *
+ * `magic` (uint32_t)
+ * Semi-unique constant to help verify pointer integrity.
+ *
+ * `help` (int)
+ * Flag that the help argument was present.
+ *
+ * `portno` (int)
+ * Port number, as received from arguments.
+ *
+ * `ip` (char *)
+ * IP address string as received from arguments.
+ *
+ * ----------------------------------------------------------------------------
+ */
+struct mshs_opts {
+ uint32_t magic;
+ int help;
+ int portno;
+ char ip[MSHS_IP_STR_SIZE + 1];
+};
+
+
+/* ----------------------------------------------------------------------------
+ * Function: usage
+ *
+ * Purpose: Print usage message to stdout.
+ * ----------------------------------------------------------------------------
+ */
+static void
+usage(void)
+{
+ HDprintf("mirror_server_halten_sie [options]\n" \
+ "System-independent Mirror Server shutdown program.\n" \
+ "Sends shutdown message to Mirror Server at given IP:port\n" \
+ "\n" \
+ "Options:\n" \
+ " -h | --help Print this usage message and exit.\n" \
+ " --ip=ADDR IP Address of remote server (defaut %s)\n" \
+ " --port=PORT Handshake port of remote server (default %d)\n",
+ MSHS_DEFAULT_IP,
+ MSHS_DEFAULT_PORTNO);
+} /* end usage() */
+
+
+/* ----------------------------------------------------------------------------
+ * Function: parse_args
+ *
+ * Purpose: Parse command-line arguments, populating the options struct
+ * pointer as appropriate.
+ * Default values will be set for unspecified options.
+ *
+ * Return: 0 on success, negative (-1) if error.
+ * ----------------------------------------------------------------------------
+ */
+static int
+parse_args(int argc, char **argv, struct mshs_opts *opts)
+{
+ int i = 0;
+
+ opts->magic = MSHS_OPTS_MAGIC;
+ opts->help = 0;
+ opts->portno = MSHS_DEFAULT_PORTNO;
+ HDstrncpy(opts->ip, MSHS_DEFAULT_IP, MSHS_IP_STR_SIZE);
+
+ for (i=1; i < argc; i++) { /* start with first possible option argument */
+ if (!HDstrncmp(argv[i], "-h", 3) || !HDstrncmp(argv[i], "--help", 7)) {
+ opts->help = 1;
+ }
+ else
+ if (!HDstrncmp(argv[i], "--ip=", 5)) {
+ HDstrncpy(opts->ip, argv[i]+5, MSHS_IP_STR_SIZE);
+ }
+ else
+ if (!HDstrncmp(argv[i], "--port=", 7)) {
+ opts->portno = HDatoi(argv[i]+7);
+ }
+ else {
+ HDprintf("Unrecognized option: '%s'\n", argv[i]);
+ usage();
+ opts->magic++; /* invalidate for sanity */
+ return -1;
+ }
+ } /* end for each argument from command line */
+
+ /* auto-replace 'localhost' with numeric IP */
+ if (!HDstrncmp(opts->ip, "localhost", 10)) { /* include null terminator */
+ HDstrncpy(opts->ip, "127.0.0.1", MSHS_IP_STR_SIZE);
+ }
+
+ return 0;
+} /* end parse_args() */
+
+
+/* ----------------------------------------------------------------------------
+ * Function: send_shutdown
+ *
+ * Purpose: Create socket and send shutdown signal to remote server.
+ *
+ * Return: 0 on success, negative (-1) if error.
+ * ----------------------------------------------------------------------------
+ */
+static int
+send_shutdown(struct mshs_opts *opts)
+{
+ int live_socket;
+ struct sockaddr_in target_addr;
+
+ if (opts->magic != MSHS_OPTS_MAGIC) {
+ HDprintf("invalid options structure\n");
+ return -1;
+ }
+
+ live_socket = HDsocket(AF_INET, SOCK_STREAM, 0);
+ if (live_socket < 0) {
+ HDprintf("ERROR socket()\n");
+ return -1;
+ }
+
+ target_addr.sin_family = AF_INET;
+ target_addr.sin_port = HDhtons((uint16_t)opts->portno);
+ target_addr.sin_addr.s_addr = HDinet_addr(opts->ip);
+ HDmemset(target_addr.sin_zero, '\0', sizeof(target_addr.sin_zero));
+
+ if (HDconnect(live_socket, (struct sockaddr *)&target_addr,
+ (socklen_t)sizeof(target_addr))
+ < 0)
+ {
+ HDprintf("ERROR connect() (%d)\n%s\n", errno, HDstrerror(errno));
+ return -1;
+ }
+
+ if (HDwrite(live_socket, "SHUTDOWN", 9) == -1) {
+ HDprintf("ERROR write() (%d)\n%s\n", errno, HDstrerror(errno));
+ return -1;
+ }
+
+ if (HDclose(live_socket) < 0) {
+ HDprintf("ERROR close() can't close socket\n");
+ return -1;
+ }
+
+ return 0;
+} /* end send_shutdown() */
+
+
+/* ------------------------------------------------------------------------- */
+int
+main(int argc, char **argv)
+{
+ struct mshs_opts opts;
+
+ if (parse_args(argc, argv, &opts) < 0) {
+ HDprintf("Unable to parse arguments\n");
+ return EXIT_FAILURE;
+ }
+
+ if (opts.help) {
+ usage();
+ return EXIT_SUCCESS;
+ }
+
+ if (send_shutdown(&opts) < 0) {
+ HDprintf("Unable to send shutdown command\n");
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+} /* end main() */
+
+#else /* H5_HAVE_MIRROR_VFD */
+
+
+/* ------------------------------------------------------------------------- */
+int
+main(int argc, char **argv)
+{
+ HDprintf("Mirror VFD not built -- unable to perform shutdown.\n");
+ return EXIT_FAILURE;
+}
+
+#endif /* H5_HAVE_MIRROR_VFD */
diff --git a/utils/mirror_vfd/mirror_writer.c b/utils/mirror_vfd/mirror_writer.c
new file mode 100644
index 0000000..e1ab1b2
--- /dev/null
+++ b/utils/mirror_vfd/mirror_writer.c
@@ -0,0 +1,1103 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * 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. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Remote writer process for the mirror (socket) VFD.
+ *
+ * Writer is started with arguments for slaved port.
+ * Awaits a connection on the socket.
+ * Handles instructions from the master 'Driver' process.
+ *
+ * Current implementation uses Sec2 as the underlying driver when opening a
+ * file. This is reflected in the source (H5FDmirror.c) of the Mirror driver.
+ */
+
+#include "mirror_remote.h"
+
+#ifdef H5_HAVE_MIRROR_VFD
+
+#define HEXDUMP_XMITS 1 /* Toggle whether to print xmit bytes-blob */
+ /* in detailed logging */
+#define HEXDUMP_WRITEDATA 0 /* Toggle whether to print bytes to write */
+ /* in detailed logging */
+#define LISTENQ 80 /* max pending Driver requests */
+
+#define MW_SESSION_MAGIC 0x88F36B32u
+#define MW_SOCK_COMM_MAGIC 0xDF10A157u
+#define MW_OPTS_MAGIC 0x3BA8B462u
+
+
+/* ---------------------------------------------------------------------------
+ * Structure: struct mirror_session
+ *
+ * Bundle of information used to manage the operation of this remote Writer
+ * in a "session" with the Driver process.
+ *
+ * magic (uint32_t)
+ * Semi-unique "magic" number used to sanity-check a structure for
+ * validity. MUST equal MW_SESSION_MAGIC to be valid.
+ *
+ * sockfd (int)
+ * File descriptor to the socket.
+ * Used for receiving bytes from and writing bytes to the Driver
+ * across the network.
+ * If not NULL, should be a valid descriptor.
+ *
+ * token (uint32t)
+ * Number used to help sanity-check received transmission from the Writer.
+ * Each Driver/Writer pairing should have a semi-unique "token" to help
+ * guard against commands from the wrong entity.
+ *
+ * xmit_count (uint32_t)
+ * Record of trasmissions received from the Driver. While the transmission
+ * protocol should be trustworthy, this serves as an additional guard.
+ * Starts a 0 and should be incremented for each one-way transmission.
+ *
+ * file (H5FD_t *)
+ * Virtual File handle for the hdf5 file.
+ * Set on file open if H5Fopen() is successful. If NULL, it is invalid.
+ *
+ * log_verbosity (unsigned int)
+ * The verbosity level for logging. Should be set to one of the values
+ * defined at the top of this file.
+ *
+ * log_stream (FILE *)
+ * File pointer to which logging output is written. Starts (and ends)
+ * with a default stream, such as stdout, but can be overridden at
+ * runtime.
+ *
+ * reply (H5FD_mirror_xmit_reply_t)
+ * Structure space for persistent reply data.
+ * Should be initialized with basic header info (magic, version, op),
+ * then with session info (token, xmit count), and finally with specific
+ * reply info (update xmit_count, status code, and message) before
+ * transmission.
+ *
+ * ----------------------------------------------------------------------------
+ */
+struct mirror_session {
+ uint32_t magic;
+ int sockfd;
+ uint32_t token;
+ uint32_t xmit_count;
+ H5FD_t *file;
+ loginfo_t *loginfo;
+ H5FD_mirror_xmit_reply_t reply;
+};
+
+
+/* ---------------------------------------------------------------------------
+ * Structure: struct sock_comm
+ *
+ * Structure for placing the data read and pre-processed from Driver in an
+ * organized fashion. Useful for pre-processing a received xmit.
+ *
+ * magic (uint32_t)
+ * Semi-unique number to sanity-check structure pointer and validity.
+ * Must equal MW_SOCK_COMM_MAGIC to be valid.
+ *
+ * recd_die (int)
+ * "Boolean" flag indicating that an explicit shutdown/kill/die command
+ * was received. Potentially useful for debugging and or "manual"
+ * operation of the program.
+ * 0 indicates normal operation, non-0 (1) indicates to die.
+ *
+ * xmit_recd (H5FD_mirror_xmit_t *)
+ * Structure pointer for the "xmit header" as decoded from the raw
+ * binary stream read from the socket.
+ *
+ * raw (char *)
+ * Pointer to a raw byte array, for storing data as read from the
+ * socket. Bytes buffer is decoded into xmit_t header and derivative
+ * structures.
+ *
+ * raw_size (size_t)
+ * Give the size of the `raw` buffer.
+ *
+ * ---------------------------------------------------------------------------
+ */
+struct sock_comm {
+ uint32_t magic;
+ int recd_die;
+ H5FD_mirror_xmit_t *xmit_recd;
+ char *raw;
+ size_t raw_size;
+};
+
+
+/* ---------------------------------------------------------------------------
+ * Structure: struct mirror_writer_opts
+ *
+ * Container for default values and options as parsed from the command line.
+ * Currently rather vestigal, but may be expanded and/or moved to be set by
+ * Server and passed around as an argument.
+ *
+ * magic (uint32_t)
+ * Semi-unique number to sanity-check structure pointer and validity.
+ * Must equal MW_OPTS_MAGIC to be valid.
+ *
+ * logpath (char *)
+ * String pointer. Allocated at runtime.
+ * Specifies file location for logging output.
+ * May be NULL -- uses default output (e.g., stdout).
+ *
+ * ----------------------------------------------------------------------------
+ */
+struct mirror_writer_opts {
+ uint32_t magic;
+ char *logpath;
+};
+
+static void mybzero(void *dest, size_t size);
+
+static int do_open(struct mirror_session *session,
+ const H5FD_mirror_xmit_open_t *xmit_open);
+
+
+/* ---------------------------------------------------------------------------
+ * Function: mybzero
+ *
+ * Purpose: Introduce bzero without neededing it on the system.
+ *
+ * Programmer: Jacob Smith
+ * 2020-03-30
+ * ---------------------------------------------------------------------------
+ */
+static void mybzero(void *dest, size_t size)
+{
+ size_t i = 0;
+ char *s = NULL;
+ HDassert(dest);
+ s = (char *)dest;
+ for (i = 0; i < size; i++) {
+ *(s+i) = 0;
+ }
+} /* end mybzero() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: session_init
+ *
+ * Purpose: Populate mirror_session structure with default and
+ * options-drived values.
+ *
+ * Return: An allocated mirror_session structure pointer on success,
+ * else NULL.
+ * ----------------------------------------------------------------------------
+ */
+static struct mirror_session *
+session_init(struct mirror_writer_opts *opts)
+{
+ struct mirror_session *session = NULL;
+
+ mirror_log(NULL, V_INFO, "session_init()");
+
+ if (NULL == opts || opts->magic != MW_OPTS_MAGIC) {
+ mirror_log(NULL, V_ERR, "invalid opts pointer");
+ goto error;
+ }
+
+ session = (struct mirror_session *)HDmalloc(sizeof(struct mirror_session));
+ if (session == NULL) {
+ mirror_log(NULL, V_ERR, "can't allocate session structure");
+ goto error;
+ }
+
+ session->magic = MW_SESSION_MAGIC;
+ session->sockfd = -1;
+ session->xmit_count = 0;
+ session->token = 0;
+ session->file = NULL;
+
+ session->reply.pub.magic = H5FD_MIRROR_XMIT_MAGIC;
+ session->reply.pub.version = H5FD_MIRROR_XMIT_CURR_VERSION;
+ session->reply.pub.op = H5FD_MIRROR_OP_REPLY;
+ session->reply.pub.session_token = 0;
+ mybzero(session->reply.message, H5FD_MIRROR_STATUS_MESSAGE_MAX);
+
+ /* Options-derived population
+ */
+
+ session->loginfo = mirror_log_init(opts->logpath, "W- ",
+ MIRROR_LOG_DEFAULT_VERBOSITY);
+
+ return session;
+
+error:
+ if (session) {
+ HDfree(session);
+ }
+ return NULL;
+} /* end session_init() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: session_stop
+ *
+ * Purpose: Stop and clean up a session.
+ * Only do this as part of program termination or aborting startup.
+ *
+ * Return: 0 on success, or negative sum of errors encountered.
+ * ----------------------------------------------------------------------------
+ */
+static int
+session_stop(struct mirror_session *session)
+{
+ int ret_value = 0;
+
+ HDassert(session && (session->magic == MW_SESSION_MAGIC));
+
+ mirror_log(session->loginfo, V_INFO, "session_stop()");
+
+ /* Close HDF5 file if it is still open (probably in error) */
+ if (session->file) {
+ mirror_log(session->loginfo, V_WARN, "HDF5 file still open at cleanup");
+ if (H5FDclose(session->file) < 0) {
+ mirror_log(session->loginfo, V_ERR, "H5FDclose() during cleanup!");
+ ret_value--;
+ }
+ }
+
+ /* Socket will be closed by parent side of server fork after exit */
+
+ /* Close custom logging stream */
+ if (mirror_log_term(session->loginfo) < 0) {
+ mirror_log(NULL, V_ERR, "Problem closing logging stream");
+ ret_value--;
+ }
+ session->loginfo = NULL;
+
+ /* Invalidate and release structure */
+ session->magic++;
+ HDfree(session);
+
+ return ret_value;
+} /* end session_stop() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: session_start
+ *
+ * Purpose: Initiate session, open files.
+ *
+ * Return: Success: A valid mirror_session pointer which must later be
+ * cleaned up with session_stop().
+ * Failure: NULL, after cleaning up after itself.
+ * ---------------------------------------------------------------------------
+ */
+static struct mirror_session *
+session_start(int socketfd, const H5FD_mirror_xmit_open_t *xmit_open)
+{
+ struct mirror_session *session = NULL;
+ struct mirror_writer_opts opts;
+#if 0 /* TODO: behaviro option */
+ char logpath[H5FD_MIRROR_XMIT_FILEPATH_MAX] = "";
+#endif
+
+ mirror_log(NULL, V_INFO, "session_start()");
+
+ if (FALSE == H5FD_mirror_xmit_is_open(xmit_open)) {
+ mirror_log(NULL, V_ERR, "invalid OPEN xmit");
+ return NULL;
+ }
+
+ opts.magic = MW_OPTS_MAGIC;
+#if 0 /* TODO: behavior option */
+ HDsnprintf(logpath, H5FD_MIRROR_XMIT_FILEPATH_MAX, "%s.log",
+ xmit_open->filename);
+ opts.logpath = logpath;
+#else
+ opts.logpath = NULL;
+#endif
+
+ session = session_init(&opts);
+ if (NULL == session) {
+ mirror_log(NULL, V_ERR, "can't instantiate session");
+ goto error;
+ }
+
+ session->sockfd = socketfd;
+
+ if (do_open(session, xmit_open) < 0) {
+ mirror_log(NULL, V_ERR, "unable to open file");
+ goto error;
+ }
+
+ return session;
+
+error:
+ if (session != NULL) {
+ if (session_stop(session) < 0) {
+ mirror_log(NULL, V_WARN, "Can't abort session init");
+ }
+ session = NULL;
+ }
+ return NULL;
+}
+
+
+/* ---------------------------------------------------------------------------
+ * Function: _xmit_reply
+ *
+ * Purpose: Common operations to send a reply xmit through the session.
+ *
+ * Return: 0 on success, -1 if error.
+ * ----------------------------------------------------------------------------
+ */
+static int
+_xmit_reply(struct mirror_session *session)
+{
+ unsigned char xmit_buf[H5FD_MIRROR_XMIT_REPLY_SIZE];
+ H5FD_mirror_xmit_reply_t *reply = &(session->reply);
+
+ HDassert(session && (session->magic == MW_SESSION_MAGIC));
+
+ mirror_log(session->loginfo, V_ALL, "_xmit_reply()");
+
+ reply->pub.xmit_count = session->xmit_count++;
+ if (H5FD_mirror_xmit_encode_reply(xmit_buf,
+ (const H5FD_mirror_xmit_reply_t *)reply)
+ != H5FD_MIRROR_XMIT_REPLY_SIZE)
+ {
+ mirror_log(session->loginfo, V_ERR, "can't encode reply");
+ return -1;
+ }
+
+ mirror_log(session->loginfo, V_ALL, "reply xmit data\n```");
+ mirror_log_bytes(session->loginfo, V_ALL, H5FD_MIRROR_XMIT_REPLY_SIZE,
+ (const unsigned char *)xmit_buf);
+ mirror_log(session->loginfo, V_ALL, "```");
+
+ if (HDwrite(session->sockfd, xmit_buf, H5FD_MIRROR_XMIT_REPLY_SIZE) < 0) {
+ mirror_log(session->loginfo, V_ERR, "can't write reply to Driver");
+ return -1;
+ }
+
+ return 0;
+} /* end _xmit_reply() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: reply_ok
+ *
+ * Purpose: Send an OK reply through the session.
+ *
+ * Return: 0 on success, -1 if error.
+ * ---------------------------------------------------------------------------
+ */
+static int
+reply_ok(struct mirror_session *session)
+{
+ H5FD_mirror_xmit_reply_t *reply = &(session->reply);
+
+ HDassert(session && (session->magic == MW_SESSION_MAGIC));
+
+ mirror_log(session->loginfo, V_ALL, "reply_ok()");
+
+ reply->status = H5FD_MIRROR_STATUS_OK;
+ mybzero(reply->message, H5FD_MIRROR_STATUS_MESSAGE_MAX);
+ return _xmit_reply(session);
+} /* end reply_ok() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: reply_error
+ *
+ * Purpose: Send an ERROR reply with message through the session.
+ * Message may be cut short if it would overflow the available
+ * buffer in the xmit.
+ *
+ * Return: 0 on success, -1 if error.
+ * ---------------------------------------------------------------------------
+ */
+static int
+reply_error(struct mirror_session *session,
+ const char *msg)
+{
+ H5FD_mirror_xmit_reply_t *reply = &(session->reply);
+
+ HDassert(session && (session->magic == MW_SESSION_MAGIC));
+
+ mirror_log(session->loginfo, V_ALL, "reply_error(%s)", msg);
+
+ reply->status = H5FD_MIRROR_STATUS_ERROR;
+ HDsnprintf(reply->message, H5FD_MIRROR_STATUS_MESSAGE_MAX-1, "%s", msg);
+ return _xmit_reply(session);
+} /* end reply_error() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: do_close
+ *
+ * Purpose: Handle an CLOSE operation.
+ *
+ * Return: 0 on success, -1 if error.
+ * ---------------------------------------------------------------------------
+ */
+static int
+do_close(struct mirror_session *session)
+{
+
+ HDassert(session && (session->magic == MW_SESSION_MAGIC));
+
+ mirror_log(session->loginfo, V_INFO, "do_close()");
+
+ if (NULL == session->file) {
+ mirror_log(session->loginfo, V_ERR, "no file to close!");
+ reply_error(session, "no file to close");
+ return -1;
+ }
+
+ if (H5FDclose(session->file) < 0) {
+ mirror_log(session->loginfo, V_ERR, "H5FDclose()");
+ reply_error(session, "H5FDclose()");
+ return -1;
+ }
+ session->file = NULL;
+
+ if (reply_ok(session) < 0) {
+ mirror_log(session->loginfo, V_ERR, "can't reply");
+ reply_error(session, "ok reply failed; session contaminated");
+ return -1;
+ }
+
+ return 0;
+} /* end do_close() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: do_lock
+ *
+ * Purpose: Handle a LOCK operation.
+ *
+ * Return: 0 on success, -1 if error.
+ * ---------------------------------------------------------------------------
+ */
+static int
+do_lock(struct mirror_session *session,
+ const unsigned char *xmit_buf)
+{
+ size_t decode_ret = 0;
+ H5FD_mirror_xmit_lock_t xmit_lock;
+
+ HDassert(session && (session->magic == MW_SESSION_MAGIC) && xmit_buf);
+
+ mirror_log(session->loginfo, V_INFO, "do_lock()");
+
+ decode_ret = H5FD_mirror_xmit_decode_lock(&xmit_lock, xmit_buf);
+ if (H5FD_MIRROR_XMIT_LOCK_SIZE != decode_ret) {
+ mirror_log(session->loginfo, V_ERR, "can't decode set-eoa xmit");
+ reply_error(session, "remote xmit_eoa_t decoding size failure");
+ return -1;
+ }
+
+ if (!H5FD_mirror_xmit_is_lock(&xmit_lock)) {
+ mirror_log(session->loginfo, V_ERR, "not a set-eoa xmit");
+ reply_error(session, "remote xmit_eoa_t decode failure");
+ return -1;
+ }
+ mirror_log(session->loginfo, V_INFO, "lock rw: (%d)", xmit_lock.rw);
+
+ if (H5FDlock(session->file, (hbool_t)xmit_lock.rw) < 0) {
+ mirror_log(session->loginfo, V_ERR, "H5FDlock()");
+ reply_error(session, "remote H5FDlock() failure");
+ return -1;
+ }
+
+ if (reply_ok(session) < 0) {
+ mirror_log(session->loginfo, V_ERR, "can't reply");
+ reply_error(session, "ok reply failed; session contaminated");
+ return -1;
+ }
+
+ return 0;
+} /* end do_lock() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: do_open
+ *
+ * Purpose: Handle an OPEN operation.
+ *
+ * Return: 0 on success, -1 if error.
+ * ---------------------------------------------------------------------------
+ */
+static int
+do_open(struct mirror_session *session,
+ const H5FD_mirror_xmit_open_t *xmit_open)
+{
+ hid_t fapl_id = H5I_INVALID_HID;
+ unsigned _flags = 0;
+ haddr_t _maxaddr = HADDR_UNDEF;
+
+ HDassert(session && (session->magic == MW_SESSION_MAGIC) && xmit_open &&
+ TRUE == H5FD_mirror_xmit_is_open(xmit_open));
+
+ mirror_log(session->loginfo, V_INFO, "do_open()");
+
+ if (0 != xmit_open->pub.xmit_count) {
+ mirror_log(session->loginfo, V_ERR, "open with xmit count not zero!");
+ reply_error(session, "initial transmission count not zero");
+ goto error;
+ }
+ if (0 != session->token) {
+ mirror_log(session->loginfo, V_ERR, "open with token already set!");
+ reply_error(session, "initial session token not zero");
+ goto error;
+ }
+
+ session->xmit_count = 1;
+ session->token = xmit_open->pub.session_token;
+ session->reply.pub.session_token = session->token;
+
+ _flags = (unsigned)xmit_open->flags;
+ _maxaddr = (haddr_t)xmit_open->maxaddr;
+
+ /* Check whether the native size_t on the remote machine (Driver) is larger
+ * than that on the local machine; if so, issue a warning.
+ * The blob is always an 8-byte bitfield -- check its contents.
+ */
+ if (xmit_open->size_t_blob > (uint64_t)((size_t)(-1))) {
+ mirror_log(session->loginfo, V_WARN,
+ "Driver size_t is larger than our own");
+ }
+
+ mirror_log(session->loginfo, V_INFO,
+ "to open file %s (flags %d) (maxaddr %d)",
+ xmit_open->filename, _flags, _maxaddr);
+
+ /* Explicitly use Sec2 as the underlying driver for now.
+ */
+ fapl_id = H5Pcreate(H5P_FILE_ACCESS);
+ if (fapl_id < 0) {
+ mirror_log(session->loginfo, V_ERR, "can't create FAPL");
+ reply_error(session, "H5Pcreate() failure");
+ goto error;
+ }
+ if (H5Pset_fapl_sec2(fapl_id) < 0) {
+ mirror_log(session->loginfo, V_ERR, "can't set FAPL as Sec2");
+ reply_error(session, "H5Pset_fapl_sec2() failure");
+ goto error;
+ }
+
+ session->file = H5FDopen(xmit_open->filename, _flags, fapl_id, _maxaddr);
+ if (NULL == session->file) {
+ mirror_log(session->loginfo, V_ERR, "H5FDopen()");
+ reply_error(session, "remote H5FDopen() failure");
+ goto error;
+ }
+
+ /* FAPL is set and in use; clean up */
+ if (H5Pclose(fapl_id) < 0) {
+ mirror_log(session->loginfo, V_ERR, "can't set FAPL as Sec2");
+ reply_error(session, "H5Pset_fapl_sec2() failure");
+ goto error;
+ }
+
+ if (reply_ok(session) < 0) {
+ mirror_log(session->loginfo, V_ERR, "can't reply");
+ reply_error(session, "ok reply failed; session contaminated");
+ return -1;
+ }
+
+ return 0;
+
+error:
+ if (fapl_id > 0) {
+ H5E_BEGIN_TRY {
+ (void)H5Pclose(fapl_id);
+ } H5E_END_TRY;
+ }
+ return -1;
+} /* end do_open() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: do_set_eoa
+ *
+ * Purpose: Handle a SET_EOA operation.
+ *
+ * Return: 0 on success, -1 if error.
+ * ---------------------------------------------------------------------------
+ */
+static int
+do_set_eoa(struct mirror_session *session,
+ const unsigned char *xmit_buf)
+{
+ size_t decode_ret = 0;
+ H5FD_mirror_xmit_eoa_t xmit_seoa;
+
+ HDassert(session && (session->magic == MW_SESSION_MAGIC) && xmit_buf);
+
+ mirror_log(session->loginfo, V_INFO, "do_set_eoa()");
+
+ decode_ret = H5FD_mirror_xmit_decode_set_eoa(&xmit_seoa, xmit_buf);
+ if (H5FD_MIRROR_XMIT_EOA_SIZE != decode_ret) {
+ mirror_log(session->loginfo, V_ERR, "can't decode set-eoa xmit");
+ reply_error(session, "remote xmit_eoa_t decoding size failure");
+ return -1;
+ }
+
+ if (!H5FD_mirror_xmit_is_set_eoa(&xmit_seoa)) {
+ mirror_log(session->loginfo, V_ERR, "not a set-eoa xmit");
+ reply_error(session, "remote xmit_eoa_t decode failure");
+ return -1;
+ }
+
+ mirror_log(session->loginfo, V_INFO, "set EOA addr %d",
+ xmit_seoa.eoa_addr);
+
+ if (H5FDset_eoa(session->file, (H5FD_mem_t)xmit_seoa.type,
+ (haddr_t)xmit_seoa.eoa_addr)
+ < 0)
+ {
+ mirror_log(session->loginfo, V_ERR, "H5FDset_eoa()");
+ reply_error(session, "remote H5FDset_eoa() failure");
+ return -1;
+ }
+
+ if (reply_ok(session) < 0) {
+ mirror_log(session->loginfo, V_ERR, "can't reply");
+ reply_error(session, "ok reply failed; session contaminated");
+ return -1;
+ }
+
+ return 0;
+} /* end do_set_eoa() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: do_truncate
+ *
+ * Purpose: Handle a TRUNCATE operation.
+ *
+ * Return: 0 on success, -1 if error.
+ * ---------------------------------------------------------------------------
+ */
+static int
+do_truncate(struct mirror_session *session)
+{
+
+ HDassert(session && (session->magic == MW_SESSION_MAGIC));
+
+ mirror_log(session->loginfo, V_INFO, "do_truncate()");
+
+ /* default DXPL ID (0), 0 for "FALSE" closing -- both probably unused */
+ if (H5FDtruncate(session->file, 0, 0) < 0) {
+ mirror_log(session->loginfo, V_ERR, "H5FDtruncate()");
+ reply_error(session, "remote H5FDtruncate() failure");
+ return -1;
+ }
+
+ if (reply_ok(session) < 0) {
+ mirror_log(session->loginfo, V_ERR, "can't reply");
+ reply_error(session, "ok reply failed; session contaminated");
+ return -1;
+ }
+
+ return 0;
+} /* end do_truncate() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: do_unlock
+ *
+ * Purpose: Handle an UNLOCK operation.
+ *
+ * Return: 0 on success, -1 if error.
+ * ---------------------------------------------------------------------------
+ */
+static int
+do_unlock(struct mirror_session *session)
+{
+ HDassert(session && (session->magic == MW_SESSION_MAGIC));
+
+ mirror_log(session->loginfo, V_INFO, "do_unlock()");
+
+ if (H5FDunlock(session->file) < 0) {
+ mirror_log(session->loginfo, V_ERR, "H5FDunlock()");
+ reply_error(session, "remote H5FDunlock() failure");
+ return -1;
+ }
+
+ if (reply_ok(session) < 0) {
+ mirror_log(session->loginfo, V_ERR, "can't reply");
+ reply_error(session, "ok reply failed; session contaminated");
+ return -1;
+ }
+
+ return 0;
+} /* end do_unlock() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: do_write
+ *
+ * Purpose: Handle a WRITE operation.
+ * Receives command, replies; receives & writes data, replies.
+ *
+ * It is known that this results in suboptimal performance,
+ * but handling both small and very, very large write buffers
+ * with a single "over the wire" exchange
+ * poses design challenges not worth tackling as of March 2020.
+ *
+ * Return: 0 on success, -1 if error.
+ * ---------------------------------------------------------------------------
+ */
+static int
+do_write(struct mirror_session *session,
+ const unsigned char *xmit_buf)
+{
+ size_t decode_ret = 0;
+ haddr_t addr = 0;
+ haddr_t sum_bytes_written = 0;
+ H5FD_mem_t type = 0;
+ char *buf = NULL;
+ ssize_t nbytes_in_packet = 0;
+ H5FD_mirror_xmit_write_t xmit_write;
+
+ HDassert(session && (session->magic == MW_SESSION_MAGIC) && xmit_buf);
+
+ mirror_log(session->loginfo, V_INFO, "do_write()");
+
+ if (NULL == session->file) {
+ mirror_log(session->loginfo, V_ERR, "no open file!");
+ reply_error(session, "no file open on remote");
+ return -1;
+ }
+
+ decode_ret = H5FD_mirror_xmit_decode_write(&xmit_write, xmit_buf);
+ if (H5FD_MIRROR_XMIT_WRITE_SIZE != decode_ret) {
+ mirror_log(session->loginfo, V_ERR, "can't decode write xmit");
+ reply_error(session, "remote xmit_write_t decoding size failure");
+ return -1;
+ }
+
+ if (!H5FD_mirror_xmit_is_write(&xmit_write)) {
+ mirror_log(session->loginfo, V_ERR, "not a write xmit");
+ reply_error(session, "remote xmit_write_t decode failure");
+ return -1;
+ }
+
+ addr = (haddr_t)xmit_write.offset;
+ type = (H5FD_mem_t)xmit_write.type;
+
+ /* Allocate the buffer once -- re-use between loops.
+ */
+ buf = (char *)HDmalloc(sizeof(char) * H5FD_MIRROR_DATA_BUFFER_MAX);
+ if (NULL == buf) {
+ mirror_log(session->loginfo, V_ERR, "can't allocate databuffer");
+ reply_error(session, "can't allocate buffer for receiving data");
+ return -1;
+ }
+
+ /* got write signal; ready for data */
+ if (reply_ok(session) < 0) {
+ mirror_log(session->loginfo, V_ERR, "can't reply");
+ reply_error(session, "ok reply failed; session contaminated");
+ return -1;
+ }
+
+ mirror_log(session->loginfo, V_INFO, "to write %zu bytes at %zu",
+ xmit_write.size,
+ addr);
+
+ /* The given write may be:
+ * 1. larger than the allowed single buffer size
+ * 2. larger than the native size_t of this system
+ *
+ * Handle all cases by looping, ingesting as much of the stream as possible
+ * and writing that part to the file.
+ */
+ sum_bytes_written = 0;
+ do {
+ nbytes_in_packet = HDread(session->sockfd, buf,
+ H5FD_MIRROR_DATA_BUFFER_MAX);
+ if (-1 == nbytes_in_packet) {
+ mirror_log(session->loginfo, V_ERR, "can't read into databuffer");
+ reply_error(session, "can't read data buffer");
+ return -1;
+ }
+
+ mirror_log(session->loginfo, V_INFO, "received %zd bytes",
+ nbytes_in_packet);
+ if (HEXDUMP_WRITEDATA) {
+ mirror_log(session->loginfo, V_ALL, "DATA:\n```");
+ mirror_log_bytes(session->loginfo, V_ALL, nbytes_in_packet,
+ (const unsigned char *)buf);
+ mirror_log(session->loginfo, V_ALL, "```");
+ }
+
+ mirror_log(session->loginfo, V_INFO, "writing %zd bytes at %zu",
+ nbytes_in_packet,
+ (addr + sum_bytes_written));
+
+ if (H5FDwrite(session->file, type, H5P_DEFAULT,
+ (addr + sum_bytes_written), (size_t)nbytes_in_packet, buf)
+ < 0)
+ {
+ mirror_log(session->loginfo, V_ERR, "H5FDwrite()");
+ reply_error(session, "remote H5FDwrite() failure");
+ return -1;
+ }
+
+ sum_bytes_written += (haddr_t)nbytes_in_packet;
+
+ } while (sum_bytes_written < xmit_write.size); /* end while ingesting */
+
+ HDfree(buf);
+
+ /* signal that we're done here and a-ok */
+ if (reply_ok(session) < 0) {
+ mirror_log(session->loginfo, V_ERR, "can't reply");
+ reply_error(session, "ok reply failed; session contaminated");
+ return -1;
+ }
+
+ return 0;
+} /* end do_write() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: receive_communique
+ *
+ * Purpose: Accept bytes from the socket, check for emergency shutdown, and
+ * sanity-check received bytes.
+ * The raw bytes read are stored in the sock_comm structure at
+ * comm->raw.
+ * The raw bytes are decoded and a xmit_t (header) struct pointer
+ * in comm is populated at comm->xmit_recd.
+ *
+ * Return: 0 on success, -1 if error.
+ * ---------------------------------------------------------------------------
+ */
+static int
+receive_communique(
+ struct mirror_session *session,
+ struct sock_comm *comm)
+{
+ ssize_t read_ret = 0;
+ size_t decode_ret;
+ H5FD_mirror_xmit_t *X = comm->xmit_recd;
+
+ HDassert((session != NULL) && \
+ (session->magic == MW_SESSION_MAGIC) && \
+ (comm != NULL) && \
+ (comm->magic == MW_SOCK_COMM_MAGIC) && \
+ (comm->xmit_recd != NULL) && \
+ (comm->raw != NULL) && \
+ (comm->raw_size >= H5FD_MIRROR_XMIT_BUFFER_MAX) );
+
+ mirror_log(session->loginfo, V_INFO, "receive_communique()");
+
+ mybzero(comm->raw, comm->raw_size);
+ comm->recd_die = 0;
+
+ mirror_log(session->loginfo, V_INFO, "ready to receive"); /* TODO */
+
+ read_ret = HDread(session->sockfd, comm->raw, H5FD_MIRROR_XMIT_BUFFER_MAX);
+ if (-1 == read_ret) {
+ mirror_log(session->loginfo, V_ERR, "read:%zd", read_ret);
+ goto error;
+ }
+
+ mirror_log(session->loginfo, V_INFO, "received %zd bytes", read_ret);
+ if (HEXDUMP_XMITS) {
+ mirror_log(session->loginfo, V_ALL, "```", read_ret);
+ mirror_log_bytes(session->loginfo, V_ALL, (size_t)read_ret,
+ (const unsigned char *)comm->raw);
+ mirror_log(session->loginfo, V_ALL, "```");
+ } /* end if hexdump transmissions received */
+
+ /* old-fashioned manual kill (for debugging) */
+ if (!HDstrncmp("GOODBYE", comm->raw, 7)) {
+ mirror_log(session->loginfo, V_INFO, "received GOODBYE");
+ comm->recd_die = 1;
+ goto done;
+ }
+
+ decode_ret = H5FD_mirror_xmit_decode_header(X,
+ (const unsigned char *)comm->raw);
+ if (H5FD_MIRROR_XMIT_HEADER_SIZE != decode_ret) {
+ mirror_log(session->loginfo, V_ERR,
+ "header decode size mismatch: expected (%z), got (%z)",
+ H5FD_MIRROR_XMIT_HEADER_SIZE, decode_ret);
+ /* Try to tell Driver that it should stop */
+ reply_error(session, "xmit size mismatch");
+ goto error;
+ }
+
+ if (!H5FD_mirror_xmit_is_xmit(X)) {
+ mirror_log(session->loginfo, V_ERR, "bad magic: 0x%X", X->magic);
+ /* Try to tell Driver that it should stop */
+ reply_error(session, "bad magic");
+ goto error;
+ }
+
+ if (session->xmit_count != X->xmit_count) {
+ mirror_log(session->loginfo, V_ERR,
+ "xmit_count mismatch exp:%d recd:%d",
+ session->xmit_count, X->xmit_count);
+ /* Try to tell Driver that it should stop */
+ reply_error(session, "xmit_count mismatch");
+ goto error;
+ }
+
+ if ( (session->token > 0) && (session->token != X->session_token) ) {
+ mirror_log(session->loginfo, V_ERR, "wrong session");
+ /* Try to tell Driver that it should stop */
+ reply_error(session, "wrong session");
+ goto error;
+ }
+
+ session->xmit_count++;
+
+done:
+ return 0;
+
+error:
+ return -1;
+} /* end receive_communique() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: process_instructions
+ *
+ * Purpose: Receive and handle all instructions from Driver.
+ *
+ * Return: 0 on success, -1 if error.
+ * ---------------------------------------------------------------------------
+ */
+static int
+process_instructions(struct mirror_session *session)
+{
+ struct sock_comm comm;
+ char xmit_buf[H5FD_MIRROR_XMIT_BUFFER_MAX]; /* raw bytes */
+ H5FD_mirror_xmit_t xmit_recd; /* for decoded xmit header */
+
+ HDassert(session && (session->magic == MW_SESSION_MAGIC));
+
+ mirror_log(session->loginfo, V_INFO, "process_instructions()");
+
+ comm.magic = MW_SOCK_COMM_MAGIC;
+ comm.recd_die = 0; /* Flag for program to terminate */
+ comm.xmit_recd = &xmit_recd;
+ comm.raw = xmit_buf;
+ comm.raw_size = sizeof(xmit_buf);
+
+ while (1) { /* sill-listening infinite loop */
+
+ /* Use convenience structure for raw/decoded info in/out */
+ if (receive_communique(session, &comm) < 0) {
+ mirror_log(session->loginfo, V_ERR, "problem reading socket");
+ return -1;
+ }
+
+ if (comm.recd_die) {
+ goto done;
+ }
+
+ switch(xmit_recd.op) {
+ case H5FD_MIRROR_OP_CLOSE:
+ if (do_close(session) < 0) {
+ return -1;
+ }
+ goto done;
+ case H5FD_MIRROR_OP_LOCK:
+ if (do_lock(session, (const unsigned char *)xmit_buf) < 0) {
+ return -1;
+ }
+ break;
+ case H5FD_MIRROR_OP_OPEN:
+ mirror_log(session->loginfo, V_ERR, "OPEN xmit during session");
+ reply_error(session, "illegal OPEN xmit during session");
+ return -1;
+ case H5FD_MIRROR_OP_SET_EOA:
+ if (do_set_eoa(session, (const unsigned char *)xmit_buf) < 0) {
+ return -1;
+ }
+ break;
+ case H5FD_MIRROR_OP_TRUNCATE:
+ if (do_truncate(session) < 0) {
+ return -1;
+ }
+ break;
+ case H5FD_MIRROR_OP_UNLOCK:
+ if (do_unlock(session) < 0) {
+ return -1;
+ }
+ break;
+ case H5FD_MIRROR_OP_WRITE:
+ if (do_write(session, (const unsigned char *)xmit_buf) < 0) {
+ return -1;
+ }
+ break;
+ default:
+ mirror_log(session->loginfo, V_ERR, "unrecognized transmission");
+ reply_error(session, "unrecognized transmission");
+ return -1;
+ } /* end switch (xmit_recd.op) */
+
+ } /* end while still listening */
+
+done:
+ comm.magic = 0; /* invalidate structure, on principle */
+ xmit_recd.magic = 0; /* invalidate structure, on principle */
+ return 0;
+} /* end process_instructions() */
+
+
+/* ---------------------------------------------------------------------------
+ * Function: run_writer
+ *
+ * Purpose: Initiate Writer operations.
+ *
+ * Receives as parameters a socket which has accepted the
+ * connection to the Driver and the OPEN xmit (which must be
+ * decoded into the structure and verified prior to being passed
+ * to this function).
+ *
+ * Is not responsible for closing or cleaning up any of the
+ * received parameters.
+ *
+ * Return: Success: SUCCEED
+ * Failure: FAIL
+ * ---------------------------------------------------------------------------
+ */
+herr_t
+run_writer(int socketfd, H5FD_mirror_xmit_open_t *xmit_open)
+{
+ struct mirror_session *session = NULL;
+ int ret_value = SUCCEED;
+
+ session = session_start(socketfd, xmit_open);
+ if (NULL == session) {
+ mirror_log(NULL, V_ERR, "Can't start session -- aborting");
+ ret_value = FAIL;
+ }
+ else {
+ if (process_instructions(session) < 0) {
+ mirror_log(session->loginfo, V_ERR,
+ "problem processing instructions");
+ ret_value = FAIL;
+ }
+ if (session_stop(session) < 0) {
+ mirror_log(NULL, V_ERR, "Can't stop session -- going down hard");
+ ret_value = FAIL;
+ }
+ }
+
+ return ret_value;
+} /* end run_writer */
+
+#endif /* H5_HAVE_MIRROR_VFD */
+