diff --git a/.github/workflows/netcdf.yml b/.github/workflows/netcdf.yml index 30b37bf8e65..0c396588cb0 100644 --- a/.github/workflows/netcdf.yml +++ b/.github/workflows/netcdf.yml @@ -74,6 +74,7 @@ jobs: repository: unidata/netcdf-c path: netcdf-c + - name: Test netCDF run: | cd netcdf-c diff --git a/doxygen/dox/H5.format.2.0.dox b/doxygen/dox/H5.format.2.0.dox index ab6d48b6aa8..bd2c1fecd78 100644 --- a/doxygen/dox/H5.format.2.0.dox +++ b/doxygen/dox/H5.format.2.0.dox @@ -143,7 +143,7 @@ Values for all fields in this document should be treated as unsigned integers, u the description of a field. Additionally, all metadata fields are stored in little-endian byte order. All checksums used in the format are computed with the -Jenkins’ lookup3 algorithm. +Jenkins’ lookup3 algorithm. Whenever a bit flag or field is mentioned for an entry, bits are numbered from the lowest bit position in the entry. diff --git a/doxygen/dox/H5.format.3.0.dox b/doxygen/dox/H5.format.3.0.dox index 36b37fff16a..353b0b4f64a 100644 --- a/doxygen/dox/H5.format.3.0.dox +++ b/doxygen/dox/H5.format.3.0.dox @@ -170,7 +170,7 @@ Values for all fields in this document should be treated as unsigned integers, u the description of a field. Additionally, all metadata fields are stored in little-endian byte order. All checksums used in the format are computed with the -Jenkins’ lookup3 algorithm. +Jenkins’ lookup3 algorithm. Whenever a bit flag or field is mentioned for an entry, bits are numbered from the lowest bit position in the entry. diff --git a/doxygen/examples/tables/volAPIs.dox b/doxygen/examples/tables/volAPIs.dox index 88299960ea6..b4167988ea0 100644 --- a/doxygen/examples/tables/volAPIs.dox +++ b/doxygen/examples/tables/volAPIs.dox @@ -52,7 +52,11 @@ -#H5Dread_chunk +#H5Dread_chunk1 + + + +#H5Dread_chunk2 @@ -461,7 +465,7 @@ #H5VL_NATIVE_DATASET_GET_CHUNK_INFO_BY_COORD -#H5Dread_chunk +#H5Dread_chunk1 / #H5Dread_chunk2 #H5VL_NATIVE_DATASET_CHUNK_READ diff --git a/fortran/src/H5Dff.F90 b/fortran/src/H5Dff.F90 index da7efd7a98e..34529824086 100644 --- a/fortran/src/H5Dff.F90 +++ b/fortran/src/H5Dff.F90 @@ -203,6 +203,12 @@ MODULE H5D INTEGER(HID_T) :: mem_type_id END FUNCTION h5dfill_c END INTERFACE + + INTERFACE h5dread_chunk_f + MODULE PROCEDURE h5dread_chunk1_f + MODULE PROCEDURE h5dread_chunk2_f + END INTERFACE + #endif CONTAINS @@ -1780,6 +1786,62 @@ CONTAINS INTEGER(HID_T), INTENT(IN) :: space_id END SUBROUTINE h5dfill_f +!> +!! \ingroup FH5D +!! +!! \brief Reads a raw data chunk directly from a dataset in a file into a buffer. +!! +!! \param dset_id Identifier of the dataset to read from +!! \param offset Logical position of the chunk's first element in the dataspace, \Bold{0-based indices} +!! \param filters Mask for identifying the filters in use +!! \param buf Buffer containing data to be read from the chunk, if passed \p C_NULL_PTR then returns the +!! needed size of \p buf in \p buf_size +!! \param buf_size Size of \p buf in bytes +!! \param hdferr \fortran_error +!! \param dxpl_id Dataset transfer property list identifier +!! +!! See C API: @ref H5Dread_chunk2() +!! + SUBROUTINE h5dread_chunk_f(dset_id, offset, filters, buf, buf_size, hdferr, dxpl_id) + IMPLICIT NONE + + INTEGER(HID_T) , INTENT(IN) :: dset_id + INTEGER(HSIZE_T) , INTENT(IN), DIMENSION(:) :: offset + INTEGER , INTENT(INOUT) :: filters + TYPE(C_PTR) :: buf + INTEGER(SIZE_T) , INTENT(INOUT) :: buf_size + INTEGER , INTENT(OUT) :: hdferr + INTEGER(HID_T) , INTENT(IN), OPTIONAL :: dxpl_id + END SUBROUTINE h5dread_chunk_f + +!> +!! \ingroup FH5D +!! +!! \important If HDF5 was built without deprecated symbols, the API \p h5dread_chunk_f will return an error +!! since there is no equivalent C API to call. +!! +!! \brief Reads a raw data chunk directly from a dataset in a file into a buffer. +!! +!! \param dset_id Identifier of the dataset to read from +!! \param offset Logical position of the chunk's first element in the dataspace, \Bold{0-based indices} +!! \param filters Mask for identifying the filters in use +!! \param buf Buffer containing data to be read from the chunk +!! \param hdferr \fortran_error +!! \param dxpl_id Dataset transfer property list identifier +!! +!! See C API: Deprecated @ref H5Dread_chunk1() +!! + SUBROUTINE h5dread_chunk_f(dset_id, offset, filters, buf, hdferr, dxpl_id) + IMPLICIT NONE + + INTEGER(HID_T) , INTENT(IN) :: dset_id + INTEGER(HSIZE_T) , INTENT(IN), DIMENSION(:) :: offset + INTEGER , INTENT(INOUT) :: filters + TYPE(C_PTR) :: buf + INTEGER , INTENT(OUT) :: hdferr + INTEGER(HID_T) , INTENT(IN), OPTIONAL :: dxpl_id + END SUBROUTINE h5dread_chunk_f + #else SUBROUTINE h5dwrite_reference_obj(dset_id, mem_type_id, buf, dims, hdferr, & @@ -2266,6 +2328,138 @@ CONTAINS END SUBROUTINE h5dfill_char + SUBROUTINE h5dread_chunk2_f(dset_id, offset, filters, buf, buf_size, hdferr, dxpl_id) + IMPLICIT NONE + + INTEGER(HID_T) , INTENT(IN) :: dset_id + INTEGER(HSIZE_T) , INTENT(IN), DIMENSION(:) :: offset + INTEGER , INTENT(INOUT) :: filters + TYPE(C_PTR) :: buf + INTEGER(SIZE_T) , INTENT(INOUT) :: buf_size + INTEGER , INTENT(OUT) :: hdferr + INTEGER(HID_T) , INTENT(IN), OPTIONAL :: dxpl_id + + INTEGER(HID_T) :: dxpl_id_default + INTEGER(HSIZE_T), DIMENSION(:), ALLOCATABLE :: c_offset + INTEGER(HSIZE_T) :: i, rank + INTEGER(C_INT32_T) :: c_filters + INTEGER(C_SIZE_T) :: cbuf_size + + INTERFACE + INTEGER(C_INT) FUNCTION H5Dread_chunk2(dset_id, dxpl_id, offset, filters, buf, buf_size) & + BIND(C, NAME='H5Dread_chunk2') + IMPORT :: SIZE_T, HSIZE_T, HID_T + IMPORT :: C_PTR, C_INT32_T, C_INT, C_SIZE_T + IMPLICIT NONE + INTEGER(HID_T) , VALUE :: dset_id + INTEGER(HID_T) , VALUE :: dxpl_id + INTEGER(HSIZE_T) , DIMENSION(*) :: offset + INTEGER(C_INT32_T) :: filters + TYPE(C_PTR) , VALUE :: buf + INTEGER(C_SIZE_T) :: buf_size + END FUNCTION H5Dread_chunk2 + END INTERFACE + + dxpl_id_default = H5P_DEFAULT_F + IF (PRESENT(dxpl_id)) dxpl_id_default = dxpl_id + + c_filters = INT(filters, KIND=C_INT32_T) + + rank = SIZE(offset, KIND=HSIZE_T) + + ALLOCATE(c_offset(rank), STAT=hdferr) + IF (hdferr .NE. 0 ) THEN + hdferr = -1 + RETURN + ENDIF + + ! + ! Reverse dimensions due to C-FORTRAN storage order + ! + DO i = 1, rank + c_offset(i) = offset(rank - i + 1) + ENDDO + + IF(.NOT. C_ASSOCIATED(buf) )THEN + cbuf_size = 0_C_SIZE_T + hdferr = INT(H5Dread_chunk2(dset_id, dxpl_id_default, c_offset, c_filters, C_NULL_PTR, cbuf_size)) + buf_size = INT(cbuf_size, SIZE_T) + RETURN + ELSE + cbuf_size = INT(buf_size, C_SIZE_T) + ENDIF + + hdferr = INT(H5Dread_chunk2(dset_id, dxpl_id_default, c_offset, c_filters, buf, cbuf_size)) + + filters = INT(c_filters) + buf_size = INT(cbuf_size, SIZE_T) + + DEALLOCATE(c_offset) + + END SUBROUTINE h5dread_chunk2_f + + SUBROUTINE h5dread_chunk1_f(dset_id, offset, filters, buf, hdferr, dxpl_id) + IMPLICIT NONE + + INTEGER(HID_T) , INTENT(IN) :: dset_id + INTEGER(HSIZE_T) , INTENT(IN), DIMENSION(:) :: offset + INTEGER , INTENT(INOUT) :: filters + TYPE(C_PTR) :: buf + INTEGER , INTENT(OUT) :: hdferr + INTEGER(HID_T) , INTENT(IN), OPTIONAL :: dxpl_id + +#ifdef H5_NO_DEPRECATED_SYMBOLS + buf = C_NULL_PTR + hdferr = -1 + RETURN +#else + INTEGER(HID_T) :: dxpl_id_default + INTEGER(HSIZE_T), DIMENSION(:), ALLOCATABLE :: c_offset + INTEGER(HSIZE_T) :: i, rank + INTEGER(C_INT32_T) :: c_filters + + INTERFACE + INTEGER(C_INT) FUNCTION H5Dread_chunk1(dset_id, dxpl_id, offset, filters, buf) & + BIND(C, NAME='H5Dread_chunk1') + IMPORT :: SIZE_T, HSIZE_T, HID_T + IMPORT :: C_PTR, C_INT32_T, C_INT + IMPLICIT NONE + INTEGER(HID_T) , VALUE :: dset_id + INTEGER(HID_T) , VALUE :: dxpl_id + INTEGER(HSIZE_T) , DIMENSION(*) :: offset + INTEGER(C_INT32_T) :: filters + TYPE(C_PTR) , VALUE :: buf + END FUNCTION H5Dread_chunk1 + END INTERFACE + + dxpl_id_default = H5P_DEFAULT_F + IF (PRESENT(dxpl_id)) dxpl_id_default = dxpl_id + + c_filters = INT(filters, KIND=C_INT32_T) + + rank = SIZE(offset, KIND=HSIZE_T) + + ALLOCATE(c_offset(rank), STAT=hdferr) + IF (hdferr .NE. 0 ) THEN + hdferr = -1 + RETURN + ENDIF + + ! + ! Reverse dimensions due to C-FORTRAN storage order + ! + DO i = 1, rank + c_offset(i) = offset(rank - i + 1) + ENDDO + + hdferr = INT(H5Dread_chunk1(dset_id, dxpl_id_default, c_offset, c_filters, buf)) + + filters = INT(c_filters) + + DEALLOCATE(c_offset) +#endif + END SUBROUTINE h5dread_chunk1_f + #endif !> @@ -2376,77 +2570,6 @@ CONTAINS END SUBROUTINE h5dwrite_multi_f -!> -!! \ingroup FH5D -!! -!! \brief Reads a raw data chunk directly from a dataset in a file into a buffer. -!! -!! \param dset_id Identifier of the dataset to read from -!! \param offset Logical position of the chunk's first element in the dataspace, \Bold{0-based indices} -!! \param filters Mask for identifying the filters in use -!! \param buf Buffer containing data to be read from the chunk -!! \param hdferr \fortran_error -!! \param dxpl_id Dataset transfer property list identifier -!! -!! See C API: @ref H5Dread_chunk() -!! - SUBROUTINE h5dread_chunk_f(dset_id, offset, filters, buf, hdferr, dxpl_id) - IMPLICIT NONE - - INTEGER(HID_T) , INTENT(IN) :: dset_id - INTEGER(HSIZE_T) , INTENT(IN), DIMENSION(:) :: offset - INTEGER , INTENT(INOUT) :: filters - TYPE(C_PTR) :: buf - INTEGER , INTENT(OUT) :: hdferr - INTEGER(HID_T) , INTENT(IN), OPTIONAL :: dxpl_id - - INTEGER(HID_T) :: dxpl_id_default - INTEGER(HSIZE_T), DIMENSION(:), ALLOCATABLE :: c_offset - INTEGER(HSIZE_T) :: i, rank - INTEGER(C_INT32_T) :: c_filters - - INTERFACE - INTEGER(C_INT) FUNCTION H5Dread_chunk(dset_id, dxpl_id, offset, filters, buf) & - BIND(C, NAME='H5Dread_chunk') - IMPORT :: SIZE_T, HSIZE_T, HID_T - IMPORT :: C_PTR, C_INT32_T, C_INT - IMPLICIT NONE - INTEGER(HID_T) , VALUE :: dset_id - INTEGER(HID_T) , VALUE :: dxpl_id - INTEGER(HSIZE_T) , DIMENSION(*) :: offset - INTEGER(C_INT32_T) :: filters - TYPE(C_PTR) , VALUE :: buf - END FUNCTION H5Dread_chunk - END INTERFACE - - dxpl_id_default = H5P_DEFAULT_F - IF (PRESENT(dxpl_id)) dxpl_id_default = dxpl_id - - c_filters = INT(filters, KIND=C_INT32_T) - - rank = SIZE(offset, KIND=HSIZE_T) - - ALLOCATE(c_offset(rank), STAT=hdferr) - IF (hdferr .NE. 0 ) THEN - hdferr = -1 - RETURN - ENDIF - - ! - ! Reverse dimensions due to C-FORTRAN storage order - ! - DO i = 1, rank - c_offset(i) = offset(rank - i + 1) - ENDDO - - hdferr = INT(H5Dread_chunk(dset_id, dxpl_id_default, c_offset, c_filters, buf)) - - filters = INT(c_filters) - - DEALLOCATE(c_offset) - - END SUBROUTINE h5dread_chunk_f - !> !! \ingroup FH5D !! diff --git a/fortran/src/hdf5_fortrandll.def.in b/fortran/src/hdf5_fortrandll.def.in index 5bc4a274c42..8a51a15928f 100644 --- a/fortran/src/hdf5_fortrandll.def.in +++ b/fortran/src/hdf5_fortrandll.def.in @@ -103,7 +103,8 @@ H5D_mp_H5DWRITE_MULTI_F H5D_mp_H5DWRITE_ASYNC_F H5D_mp_H5DREAD_ASYNC_F H5D_mp_H5DWRITE_CHUNK_F -H5D_mp_H5DREAD_CHUNK_F +H5D_mp_H5DREAD_CHUNK1_F +H5D_mp_H5DREAD_CHUNK2_F ; H5E H5E_mp_H5ECLEAR_F H5E_mp_H5EPRINT1_F diff --git a/fortran/test/tH5D.F90 b/fortran/test/tH5D.F90 index 59b69db7e7f..d5c5355c5d3 100644 --- a/fortran/test/tH5D.F90 +++ b/fortran/test/tH5D.F90 @@ -32,7 +32,6 @@ #include -! MODULE TH5D USE HDF5 ! This module contains all necessary modules @@ -1013,6 +1012,7 @@ CONTAINS INTEGER(HSIZE_T), DIMENSION(2) :: offset INTEGER(HSIZE_T), DIMENSION(2) :: dims = (/DIM0,DIM1/) INTEGER, DIMENSION(CHUNK0,CHUNK1), TARGET :: wdata1, rdata1, wdata2, rdata2 + INTEGER, DIMENSION(:), ALLOCATABLE, TARGET :: buf_alloc INTEGER(HSIZE_T), DIMENSION(2) :: chunk = (/CHUNK0, CHUNK1/) INTEGER :: i, j, n INTEGER :: error @@ -1020,6 +1020,7 @@ CONTAINS INTEGER :: filters INTEGER(SIZE_T) :: sizeINT INTEGER(HID_T) :: dxpl + INTEGER(SIZE_T) :: buf_size ! !Create a new file using default properties. @@ -1107,6 +1108,9 @@ CONTAINS filters = 99 offset(1:2) = (/0, 0/) CALL H5Dread_chunk_f(dset_id, offset, filters, f_ptr, error) +#ifdef H5_NO_DEPRECATED_SYMBOLS + CALL VERIFY("H5Dread_chunk_f",error,-1,total_error) +#else CALL check("H5Dread_chunk_f",error,total_error) ! Verify that the data read was correct. @@ -1118,10 +1122,14 @@ CONTAINS ENDDO CALL VERIFY("H5Dread_chunk_f",filters, 0, total_error) +#endif f_ptr = C_LOC(rdata2) offset(1:2) = (/0, 16/) CALL H5Dread_chunk_f(dset_id, offset, filters, f_ptr, error, dxpl) +#ifdef H5_NO_DEPRECATED_SYMBOLS + CALL VERIFY("H5Dread_chunk_f",error,-1,total_error) +#else CALL check("H5Dread_chunk_f",error,total_error) ! Verify that the data read was correct. @@ -1133,6 +1141,33 @@ CONTAINS ENDDO CALL VERIFY("H5Dread_chunk_f",filters, 0, total_error) +#endif + + ! + ! check version of H5Dread_chunk_f with buf_size parameter + ! + offset(1:2) = (/0, 16/) + + CALL H5Dread_chunk_f(dset_id, offset, filters, C_NULL_PTR, buf_size, error, dxpl) + CALL check("H5Dread_chunk_f",error,total_error) + CALL VERIFY("H5Dread_chunk_f", buf_size, 256_SIZE_T, total_error) + + ALLOCATE(buf_alloc(1:buf_size/sizeINT)) + f_ptr = C_LOC(buf_alloc(1)) + + CALL H5Dread_chunk_f(dset_id, offset, filters, f_ptr, buf_size, error, dxpl) + CALL check("H5Dread_chunk_f",error,total_error) + CALL VERIFY("H5Dread_chunk_f", buf_size, 256_SIZE_T, total_error) + + rdata2 = RESHAPE(buf_alloc,(/CHUNK0, CHUNK1/)) + DO i = 1, CHUNK0 + DO j = 1, CHUNK1 + CALL VERIFY("H5Dread_chunk_f", rdata2(i,j), wdata2(i,j), total_error) + IF(total_error.NE.0) EXIT + ENDDO + ENDDO + + DEALLOCATE(buf_alloc) CALL h5dclose_f(dset_id, error) CALL check("h5dclose_f",error,total_error) diff --git a/hl/src/H5DO.c b/hl/src/H5DO.c index 5e72b2b2645..cf827181870 100644 --- a/hl/src/H5DO.c +++ b/hl/src/H5DO.c @@ -60,7 +60,7 @@ herr_t H5DOread_chunk(hid_t dset_id, hid_t dxpl_id, const hsize_t *offset, uint32_t *filters, void *buf) { /* Call underlying H5D function */ - if (H5Dread_chunk(dset_id, dxpl_id, offset, filters, buf) < 0) + if (H5Dread_chunk1(dset_id, dxpl_id, offset, filters, buf) < 0) return FAIL; else return SUCCEED; diff --git a/release_docs/RELEASE.txt b/release_docs/RELEASE.txt index 60748b42e0b..910f647c74c 100644 --- a/release_docs/RELEASE.txt +++ b/release_docs/RELEASE.txt @@ -200,6 +200,32 @@ New Features Library: -------- + + - The H5Dread_chunk() signature has changed + + A new parameter, nalloc, has been added to H5Dread_chunk(). This parameter + contains a pointer to a variable that holds the size of the buffer buf. If + *nalloc is not large enough to hold the entire chunk being read, no data + is read. On exit, the value of this variable is set to the buffer size + needed to read the chunk. + + The old signature has been renamed to H5Dread_chunk1() and is considered + deprecated: + + herr_t H5Dread_chunk1(hid_t dset_id, hid_t dxpl_id, + const hsize_t *offset, uint32_t *filters, + void *buf); + + The new signature is H5Dread_chunk2(). All code should be updated to use + this version: + + herr_t H5Dread_chunk2(hid_t dset_id, hid_t dxpl_id, + const hsize_t *offset, uint32_t *filters, + void *buf, size_t *nalloc); + + H5Dread_chunk() will map to the new signature unless the library is + explicitly configured to use an older version of the API. + - Replaced the ROS3 VFD's S3 backend based on libcurl with a new backend based on the aws-c-s3 library (https://github.com/awslabs/aws-c-s3) @@ -282,6 +308,7 @@ New Features H5_FCTESTDLL(VAR) --> H5FC_TEST_DLL(VAR) HDF5_HL_F90CSTUBDLL(VAR) --> H5FC_HL_DLL(VAR) + - The H5Iregister_type() signature has changed The hash_size parameter has not been used since early versions of HDF5 diff --git a/src/H5D.c b/src/H5D.c index 711a257712a..394d9a3f569 100644 --- a/src/H5D.c +++ b/src/H5D.c @@ -1169,7 +1169,7 @@ done: } /* end H5Dread_multi_async() */ /*------------------------------------------------------------------------- - * Function: H5Dread_chunk + * Function: H5Dread_chunk2 * * Purpose: Reads an entire chunk from the file directly. * @@ -1178,7 +1178,8 @@ done: *--------------------------------------------------------------------------- */ herr_t -H5Dread_chunk(hid_t dset_id, hid_t dxpl_id, const hsize_t *offset, uint32_t *filters, void *buf /*out*/) +H5Dread_chunk2(hid_t dset_id, hid_t dxpl_id, const hsize_t *offset, uint32_t *filters /*out*/, + void *buf /*out*/, size_t *buf_size) { H5VL_object_t *vol_obj; /* Dataset for this operation */ H5VL_optional_args_t vol_cb_args; /* Arguments to VOL callback */ @@ -1190,12 +1191,12 @@ H5Dread_chunk(hid_t dset_id, hid_t dxpl_id, const hsize_t *offset, uint32_t *fil /* Check arguments */ if (NULL == (vol_obj = H5VL_vol_object_verify(dset_id, H5I_DATASET))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "dset_id is not a dataset ID"); - if (!buf) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "buf cannot be NULL"); if (!offset) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "offset cannot be NULL"); if (!filters) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "filters cannot be NULL"); + if (!buf_size) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "buf_size cannot be NULL"); /* Get the default dataset transfer property list if the user didn't provide one */ if (H5P_DEFAULT == dxpl_id) @@ -1204,11 +1205,12 @@ H5Dread_chunk(hid_t dset_id, hid_t dxpl_id, const hsize_t *offset, uint32_t *fil HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "dxpl_id is not a dataset transfer property list ID"); /* Set up VOL callback arguments */ - dset_opt_args.chunk_read.offset = offset; - dset_opt_args.chunk_read.filters = 0; - dset_opt_args.chunk_read.buf = buf; - vol_cb_args.op_type = H5VL_NATIVE_DATASET_CHUNK_READ; - vol_cb_args.args = &dset_opt_args; + dset_opt_args.chunk_read.offset = offset; + dset_opt_args.chunk_read.filters = 0; + dset_opt_args.chunk_read.buf = buf; + dset_opt_args.chunk_read.buf_size = buf_size; + vol_cb_args.op_type = H5VL_NATIVE_DATASET_CHUNK_READ; + vol_cb_args.args = &dset_opt_args; /* Read the raw chunk */ if (H5VL_dataset_optional(vol_obj, &vol_cb_args, dxpl_id, H5_REQUEST_NULL) < 0) @@ -1219,7 +1221,7 @@ H5Dread_chunk(hid_t dset_id, hid_t dxpl_id, const hsize_t *offset, uint32_t *fil done: FUNC_LEAVE_API(ret_value) -} /* end H5Dread_chunk() */ +} /* end H5Dread_chunk2() */ /*------------------------------------------------------------------------- * Function: H5D__write_api_common diff --git a/src/H5Dchunk.c b/src/H5Dchunk.c index 23e0cf11ba9..4c2dfc2fa2a 100644 --- a/src/H5Dchunk.c +++ b/src/H5Dchunk.c @@ -483,7 +483,7 @@ done: *------------------------------------------------------------------------- */ herr_t -H5D__chunk_direct_read(const H5D_t *dset, hsize_t *offset, uint32_t *filters, void *buf) +H5D__chunk_direct_read(const H5D_t *dset, hsize_t *offset, uint32_t *filters, void *buf, size_t *nalloc) { const H5O_layout_t *layout = &(dset->shared->layout); /* Dataset layout */ const H5D_rdcc_t *rdcc = &(dset->shared->cache.chunk); /* raw data chunk cache */ @@ -497,7 +497,7 @@ H5D__chunk_direct_read(const H5D_t *dset, hsize_t *offset, uint32_t *filters, vo assert(dset && H5D_CHUNKED == layout->type); assert(offset); assert(filters); - assert(buf); + assert(buf || nalloc); *filters = 0; @@ -553,10 +553,18 @@ H5D__chunk_direct_read(const H5D_t *dset, hsize_t *offset, uint32_t *filters, vo if (!H5_addr_defined(udata.chunk_block.offset)) HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "chunk address isn't defined"); - /* Read the chunk data into the supplied buffer */ - if (H5F_shared_block_read(H5F_SHARED(dset->oloc.file), H5FD_MEM_DRAW, udata.chunk_block.offset, - udata.chunk_block.length, buf) < 0) - HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "unable to read raw data chunk"); + /* If nalloc is provided, check if *nalloc is large enough. If not provided, assume it is large enough + * (this is the insecure older behaviour that is disallowed by H5Dread_chunk2(), but we must support it + * here for the deprecated H5Dreach_chunk1()). */ + if (udata.chunk_block.length > 0 && buf && (!nalloc || *nalloc >= udata.chunk_block.length)) + /* Read the chunk data into the supplied buffer */ + if (H5F_shared_block_read(H5F_SHARED(dset->oloc.file), H5FD_MEM_DRAW, udata.chunk_block.offset, + udata.chunk_block.length, buf) < 0) + HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "unable to read raw data chunk"); + + /* Return the size of the chunk block in *nalloc if nalloc is provided */ + if (nalloc) + *nalloc = udata.chunk_block.length; /* Return the filter mask */ *filters = udata.filter_mask; diff --git a/src/H5Ddeprec.c b/src/H5Ddeprec.c index 0b98a5e726a..dff60e3110a 100644 --- a/src/H5Ddeprec.c +++ b/src/H5Ddeprec.c @@ -335,4 +335,61 @@ done: FUNC_LEAVE_API(ret_value) } /* end H5Dvlen_reclaim() */ +/*------------------------------------------------------------------------- + * Function: H5Dread_chunk1 + * + * Purpose: Reads an entire chunk from the file directly. + * + * Note: Deprecated in favor of H5Dread_chunk2 + * + * Return: Non-negative on success/Negative on failure + * + *--------------------------------------------------------------------------- + */ +herr_t +H5Dread_chunk1(hid_t dset_id, hid_t dxpl_id, const hsize_t *offset, uint32_t *filters /*out*/, + void *buf /*out*/) +{ + H5VL_object_t *vol_obj; /* Dataset for this operation */ + H5VL_optional_args_t vol_cb_args; /* Arguments to VOL callback */ + H5VL_native_dataset_optional_args_t dset_opt_args; /* Arguments for optional operation */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_API(FAIL) + + /* Check arguments */ + if (NULL == (vol_obj = H5VL_vol_object_verify(dset_id, H5I_DATASET))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "dset_id is not a dataset ID"); + if (!buf) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "buf cannot be NULL"); + if (!offset) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "offset cannot be NULL"); + if (!filters) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "filters cannot be NULL"); + + /* Get the default dataset transfer property list if the user didn't provide one */ + if (H5P_DEFAULT == dxpl_id) + dxpl_id = H5P_DATASET_XFER_DEFAULT; + else if (true != H5P_isa_class(dxpl_id, H5P_DATASET_XFER)) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "dxpl_id is not a dataset transfer property list ID"); + + /* Set up VOL callback arguments */ + dset_opt_args.chunk_read.offset = offset; + dset_opt_args.chunk_read.filters = 0; + dset_opt_args.chunk_read.buf = buf; + dset_opt_args.chunk_read.buf_size = NULL; + vol_cb_args.op_type = H5VL_NATIVE_DATASET_CHUNK_READ; + vol_cb_args.args = &dset_opt_args; + + /* Read the raw chunk */ + if (H5VL_dataset_optional(vol_obj, &vol_cb_args, dxpl_id, H5_REQUEST_NULL) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "can't read unprocessed chunk data"); + + /* Set return value */ + *filters = dset_opt_args.chunk_read.filters; + +done: + FUNC_LEAVE_API(ret_value) +} /* end H5Dread_chunk1() */ + #endif /* H5_NO_DEPRECATED_SYMBOLS */ diff --git a/src/H5Dpkg.h b/src/H5Dpkg.h index d7dbf23ce1a..a7adbc4f2e5 100644 --- a/src/H5Dpkg.h +++ b/src/H5Dpkg.h @@ -750,7 +750,8 @@ H5_DLL herr_t H5D__chunk_delete(H5F_t *f, H5O_t *oh, H5O_storage_t *store); H5_DLL herr_t H5D__chunk_get_offset_copy(const H5D_t *dset, const hsize_t *offset, hsize_t *offset_copy); H5_DLL herr_t H5D__chunk_direct_write(H5D_t *dset, uint32_t filters, hsize_t *offset, uint32_t data_size, const void *buf); -H5_DLL herr_t H5D__chunk_direct_read(const H5D_t *dset, hsize_t *offset, uint32_t *filters, void *buf); +H5_DLL herr_t H5D__chunk_direct_read(const H5D_t *dset, hsize_t *offset, uint32_t *filters, void *buf, + size_t *nalloc); #ifdef H5D_CHUNK_DEBUG H5_DLL herr_t H5D__chunk_stats(const H5D_t *dset, bool headers); #endif /* H5D_CHUNK_DEBUG */ diff --git a/src/H5Dpublic.h b/src/H5Dpublic.h index f307be7f176..da69d5153ae 100644 --- a/src/H5Dpublic.h +++ b/src/H5Dpublic.h @@ -1221,14 +1221,14 @@ H5_DLL herr_t H5Dwrite_multi_async(size_t count, hid_t dset_id[], hid_t mem_type * \p buf is the memory buffer containing data to be written to * the chunk in the file. * - * \attention Exercise caution when using H5Dread_chunk() and + * \attention Exercise caution when using H5Dread_chunk2() and * H5Dwrite_chunk(), as they read and write data chunks directly * in a file. H5Dwrite_chunk() bypasses hyperslab selection, the * conversion of data from one datatype to another, and the filter * pipeline to write the chunk. Developers should have experience * with these processes before using this function. * - * \note H5Dread_chunk() and H5Dwrite_chunk() are currently not supported + * \note H5Dread_chunk2() and H5Dwrite_chunk() are currently not supported * with parallel HDF5 and do not support variable-length types. * * \since 1.10.2 @@ -1250,10 +1250,11 @@ H5_DLL herr_t H5Dwrite_chunk(hid_t dset_id, hid_t dxpl_id, uint32_t filters, con * dataspace * \param[in,out] filters Mask for identifying the filters in use * \param[out] buf Buffer containing data to be read from the chunk + * \param[in,out] buf_size Size of buf in bytes * * \return \herr_t * - * \details H5Dread_chunk() reads a raw data chunk as specified by + * \details H5Dread_chunk2() reads a raw data chunk as specified by * its logical offset \p offset in a chunked dataset \p dset_id * from the dataset in the file into the application memory * buffer \p buf. The data in \p buf is read directly from the @@ -1276,7 +1277,16 @@ H5_DLL herr_t H5Dwrite_chunk(hid_t dset_id, hid_t dxpl_id, uint32_t filters, con * \p buf is the memory buffer containing the chunk read from * the dataset in the file. * - * \attention Exercise caution when using H5Dread_chunk() and + * \p buf_size must be passed as a pointer to a variable holding the + * allocated size, in bytes, of the memory buffer \p buf. On exit, + * \p *buf_size is set to the buffer size needed to read the chunk, which + * is the same as the size of the chunk on disk. If the value of + * \p *buf_size passed in was insufficient to read the entire, chunk, no + * data is read. \p buf may be passed as NULL as long as \p *buf_size + * is 0. \p filters is always set by this function even if the chunk + * was not read. + * + * \attention Exercise caution when using H5Dread_chunk2() and * H5Dwrite_chunk(), as they read and write data chunks directly * in a file. H5Dwrite_chunk() bypasses hyperslab selection, the * conversion of data from one datatype to another, and the filter @@ -1284,14 +1294,14 @@ H5_DLL herr_t H5Dwrite_chunk(hid_t dset_id, hid_t dxpl_id, uint32_t filters, con * with these processes before using this function. Please see * \ref subsec_hldo_direct_chunk_using for more information. * - * \note H5Dread_chunk() and H5Dwrite_chunk() are currently not supported + * \note H5Dread_chunk2() and H5Dwrite_chunk() are currently not supported * with parallel HDF5 and do not support variable-length datatypes. * - * \since 1.10.2 + * \since 2.0.0 * */ -H5_DLL herr_t H5Dread_chunk(hid_t dset_id, hid_t dxpl_id, const hsize_t *offset, uint32_t *filters, - void *buf); +H5_DLL herr_t H5Dread_chunk2(hid_t dset_id, hid_t dxpl_id, const hsize_t *offset, uint32_t *filters, + void *buf, size_t *buf_size); /** * -------------------------------------------------------------------------- @@ -1890,6 +1900,75 @@ H5_DLL herr_t H5Dextend(hid_t dset_id, const hsize_t size[]); * */ H5_DLL herr_t H5Dvlen_reclaim(hid_t type_id, hid_t space_id, hid_t dxpl_id, void *buf); +/** + * -------------------------------------------------------------------------- + * \ingroup H5D + * + * \brief Reads a raw data chunk directly from a dataset in a file into + * a buffer + * + * \dset_id + * \dxpl_id + * \param[in] offset Logical position of the chunk's first element in the + * dataspace + * \param[in,out] filters Mask for identifying the filters in use + * \param[out] buf Buffer containing data to be read from the chunk + * + * \return \herr_t + * + * \deprecation_note{H5Dread_chunk2() or the macro H5Dread_chunk()} + * + * \details H5Dread_chunk1() reads a raw data chunk as specified by + * its logical offset \p offset in a chunked dataset \p dset_id + * from the dataset in the file into the application memory + * buffer \p buf. The data in \p buf is read directly from the + * file bypassing the library's internal data transfer pipeline, + * including filters. + * + * \p offset is an array specifying the logical position of the + * first element of the chunk in the dataset's dataspace. The + * length of the \p offset array must equal the number of dimensions, + * or rank, of the dataspace. The values in \p offset must not exceed + * the dimension limits and must specify a point that falls on + * a dataset chunk boundary. + * + * The mask \p filters indicates which filters were used when the + * chunk was written. A zero value (all bits 0) indicates that all + * enabled filters are applied on the chunk. A filter is skipped if + * the bit corresponding to the filter's position in the pipeline + * (0 ≤ position < 32) is turned on. + * + * \p buf is the memory buffer containing the chunk read from + * the dataset in the file. + * + * \attention It is strongly recommended to use H5Dread_chunk2() instead of this + * function due to the potential for memory corruption. During the + * typical usage pattern of this function, the application has no way + * of knowing the size of the chunk on disk, or even a maximum size + * (filters can increase the size of a chunk). The library also has no + * way of knowing the size of \p buf, so there is a potential for the + * library to write past the end of the buffer. The only general way to + * avoid this problem, besides upgrading to H5Dread_chunk2(), is to + * query the chunk size beforehand, which can be expensive. + * + * \attention Exercise caution when using H5Dread_chunk1() and + * H5Dwrite_chunk(), as they read and write data chunks directly + * in a file. H5Dwrite_chunk() bypasses hyperslab selection, the + * conversion of data from one datatype to another, and the filter + * pipeline to write the chunk. Developers should have experience + * with these processes before using this function. Please see + * \ref subsec_hldo_direct_chunk_using for more information. + * + * \note H5Dread_chunk1() and H5Dwrite_chunk() are currently not supported + * with parallel HDF5 and do not support variable-length datatypes. + * + * \version 2.0.0 Function was deprecated + * + * \since 1.10.2 + * + */ +H5_DLL herr_t H5Dread_chunk1(hid_t dset_id, hid_t dxpl_id, const hsize_t *offset, uint32_t *filters, + void *buf); #endif /* H5_NO_DEPRECATED_SYMBOLS */ diff --git a/src/H5VLnative.h b/src/H5VLnative.h index 6b1cc5652ec..c6ec4d5118c 100644 --- a/src/H5VLnative.h +++ b/src/H5VLnative.h @@ -84,6 +84,7 @@ typedef struct H5VL_native_dataset_chunk_read_t { const hsize_t *offset; uint32_t filters; void *buf; + size_t *buf_size; } H5VL_native_dataset_chunk_read_t; /* Parameters for native connector's dataset 'chunk write' operation */ diff --git a/src/H5VLnative_dataset.c b/src/H5VLnative_dataset.c index 415a67a7ead..db0e974fca2 100644 --- a/src/H5VLnative_dataset.c +++ b/src/H5VLnative_dataset.c @@ -732,8 +732,8 @@ H5VL__native_dataset_optional(void *obj, H5VL_optional_args_t *args, hid_t dxpl_ HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "failure to copy offset array"); /* Read the raw chunk */ - if (H5D__chunk_direct_read(dset, offset_copy, &chunk_read_args->filters, chunk_read_args->buf) < - 0) + if (H5D__chunk_direct_read(dset, offset_copy, &chunk_read_args->filters, chunk_read_args->buf, + chunk_read_args->buf_size) < 0) HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "can't read unprocessed chunk data"); break; diff --git a/src/H5vers.txt b/src/H5vers.txt index de65f1298c1..e11c10c42d6 100644 --- a/src/H5vers.txt +++ b/src/H5vers.txt @@ -44,6 +44,7 @@ FUNCTION: H5Acreate; ; v10, v18 FUNCTION: H5Aiterate; H5A_operator; v10, v18 FUNCTION: H5Dcreate; ; v10, v18 FUNCTION: H5Dopen; ; v10, v18 +FUNCTION: H5Dread_chunk; ; v110, v200 FUNCTION: H5Eclear; ; v10, v18 FUNCTION: H5Eget_auto; ; v10, v18 FUNCTION: H5Eprint; ; v10, v18 diff --git a/src/H5version.h b/src/H5version.h index 55b2e22ff55..92206293022 100644 --- a/src/H5version.h +++ b/src/H5version.h @@ -368,6 +368,10 @@ #define H5Dopen_vers 2 #endif /* !defined(H5Dopen_vers) */ +#if !defined(H5Dread_chunk_vers) + #define H5Dread_chunk_vers 1 +#endif /* !defined(H5Dread_chunk_vers) */ + #if !defined(H5Eclear_vers) #define H5Eclear_vers 2 #endif /* !defined(H5Eclear_vers) */ @@ -548,6 +552,10 @@ #define H5Dopen_vers 2 #endif /* !defined(H5Dopen_vers) */ +#if !defined(H5Dread_chunk_vers) + #define H5Dread_chunk_vers 1 +#endif /* !defined(H5Dread_chunk_vers) */ + #if !defined(H5Eclear_vers) #define H5Eclear_vers 2 #endif /* !defined(H5Eclear_vers) */ @@ -728,6 +736,10 @@ #define H5Dopen_vers 2 #endif /* !defined(H5Dopen_vers) */ +#if !defined(H5Dread_chunk_vers) + #define H5Dread_chunk_vers 1 +#endif /* !defined(H5Dread_chunk_vers) */ + #if !defined(H5Eclear_vers) #define H5Eclear_vers 2 #endif /* !defined(H5Eclear_vers) */ @@ -908,6 +920,10 @@ #define H5Dopen_vers 2 #endif /* !defined(H5Dopen_vers) */ +#if !defined(H5Dread_chunk_vers) + #define H5Dread_chunk_vers 2 +#endif /* !defined(H5Dread_chunk_vers) */ + #if !defined(H5Eclear_vers) #define H5Eclear_vers 2 #endif /* !defined(H5Eclear_vers) */ @@ -1123,6 +1139,17 @@ #error "H5Dopen_vers set to invalid value" #endif /* H5Dopen_vers */ +#if !defined(H5Dread_chunk_vers) || H5Dread_chunk_vers == 2 + #ifndef H5Dread_chunk_vers + #define H5Dread_chunk_vers 2 + #endif /* H5Dread_chunk_vers */ + #define H5Dread_chunk H5Dread_chunk2 +#elif H5Dread_chunk_vers == 1 + #define H5Dread_chunk H5Dread_chunk1 +#else /* H5Dread_chunk_vers */ + #error "H5Dread_chunk_vers set to invalid value" +#endif /* H5Dread_chunk_vers */ + #if !defined(H5Eclear_vers) || H5Eclear_vers == 2 #ifndef H5Eclear_vers #define H5Eclear_vers 2 diff --git a/test/chunk_info.c b/test/chunk_info.c index 6fd3b9ba09e..3c05d9234ed 100644 --- a/test/chunk_info.c +++ b/test/chunk_info.c @@ -325,11 +325,18 @@ verify_selected_chunks(hid_t dset, hid_t plist, const hsize_t *start, const hsiz chk_index = 0; for (ii = start[0]; ii < end[0]; ii++) for (jj = start[1]; jj < end[1]; jj++, chk_index++) { + size_t tmp_buf_size; + offset[0] = ii * CHUNK_NX; offset[1] = jj * CHUNK_NY; /* Read the current chunk */ - if (H5Dread_chunk(dset, plist, offset, &read_flt_msk, read_buf) < 0) + tmp_buf_size = sizeof(read_buf); + if (H5Dread_chunk2(dset, plist, offset, &read_flt_msk, read_buf, &tmp_buf_size) < 0) + TEST_ERROR; + + /* Check if buffer wasn't big enough */ + if (tmp_buf_size > sizeof(read_buf)) TEST_ERROR; /* Verify that read chunk is the same as the corresponding written one */ @@ -2060,12 +2067,18 @@ test_flt_msk_with_skip_compress(hid_t fapl) if (read_buf_size != CHK_SIZE) TEST_ERROR; - /* Read the raw chunk back with H5Dread_chunk */ - memset(&read_direct_buf, 0, sizeof(read_direct_buf)); - if (H5Dread_chunk(dset, H5P_DEFAULT, offset, &read_flt_msk, read_direct_buf) < 0) - TEST_ERROR; - if (read_flt_msk != flt_msk) - TEST_ERROR; + /* Read the raw chunk back with H5Dread_chunk2 */ + { + size_t tmp_buf_size = sizeof(read_direct_buf); + + memset(&read_direct_buf, 0, sizeof(read_direct_buf)); + if (H5Dread_chunk2(dset, H5P_DEFAULT, offset, &read_flt_msk, read_direct_buf, &tmp_buf_size) < 0) + TEST_ERROR; + if (tmp_buf_size > sizeof(read_direct_buf)) + TEST_ERROR; + if (read_flt_msk != flt_msk) + TEST_ERROR; + } /* Check that the direct chunk read is the same as the chunk written */ for (ii = 0; ii < CHUNK_NX; ii++) diff --git a/test/direct_chunk.c b/test/direct_chunk.c index 9afdb47e95b..9aa18ada1dc 100644 --- a/test/direct_chunk.c +++ b/test/direct_chunk.c @@ -41,6 +41,10 @@ #endif #define DATASETNAME11 "unallocated_chunk" #define DATASETNAME12 "unfiltered_data" +#define DATASETNAME13 "buf_size" +#ifndef H5_NO_DEPRECATED_SYMBOLS +#define DATASETNAME14 "deprec" +#endif /* H5_NO_DEPRECATED_SYMBOLS */ #define RANK 2 #define NX 16 @@ -525,7 +529,7 @@ test_skip_compress_write1(hid_t file) hsize_t count[2]; /* Block count */ hsize_t block[2]; /* Block sizes */ - TESTING("skipping compression filter for H5Dwrite_chunk/H5Dread_chunk"); + TESTING("skipping compression filter for H5Dwrite_chunk/H5Dread_chunk2"); /* * Create the data space with unlimited dimensions. @@ -622,10 +626,17 @@ test_skip_compress_write1(hid_t file) /* Read the raw chunk back */ memset(&read_direct_buf, 0, sizeof(read_direct_buf)); - if ((status = H5Dread_chunk(dataset, H5P_DEFAULT, offset, &read_filter_mask, read_direct_buf)) < 0) + if ((status = + H5Dread_chunk2(dataset, H5P_DEFAULT, offset, &read_filter_mask, read_direct_buf, &buf_size)) < 0) goto error; - if (read_filter_mask != filter_mask) + if (buf_size > read_buf_size) { + fprintf(stderr, "insufficient buffer size\n"); goto error; + } + if (read_filter_mask != filter_mask) { + fprintf(stderr, "incorrect filter mask returned\n"); + goto error; + } /* Check that the direct chunk read is the same as the chunk written */ for (i = 0; i < CHUNK_NX; i++) { @@ -888,12 +899,101 @@ test_skip_compress_write2(hid_t file) if (read_buf_size != buf_size) goto error; + /* Zero out read buffer and filter mask */ + memset(read_direct_buf, 0, sizeof(read_direct_buf)); + read_filter_mask = 0; + + /* Try reading with no buffer */ + buf_size = 0; + if ((status = H5Dread_chunk2(dataset, H5P_DEFAULT, offset, &read_filter_mask, NULL, &buf_size)) < 0) + goto error; + if (buf_size != read_buf_size) { + fprintf(stderr, "insufficient buffer size\n"); + goto error; + } + if (read_filter_mask != filter_mask) { + fprintf(stderr, "incorrect filter mask returned\n"); + goto error; + } + + /* Verify no data was read */ + for (i = 0; i < CHUNK_NX; i++) { + for (j = 0; j < CHUNK_NY; j++) { + if (read_direct_buf[i][j] != 0) { + printf(" 1. Values read when buffer too small."); + printf(" At index %d,%d\n", i, j); + printf(" read_direct_buf=%d\n", read_direct_buf[i][j]); + goto error; + } + } + } + + /* Try reading with buffer but 0 buf_size */ + buf_size = 0; + read_filter_mask = 0; + if ((status = + H5Dread_chunk2(dataset, H5P_DEFAULT, offset, &read_filter_mask, read_direct_buf, &buf_size)) < 0) + goto error; + if (buf_size != read_buf_size) { + fprintf(stderr, "insufficient buffer size\n"); + goto error; + } + if (read_filter_mask != filter_mask) { + fprintf(stderr, "incorrect filter mask returned\n"); + goto error; + } + + /* Verify no data was read */ + for (i = 0; i < CHUNK_NX; i++) { + for (j = 0; j < CHUNK_NY; j++) { + if (read_direct_buf[i][j] != 0) { + printf(" 1. Values read when buffer too small."); + printf(" At index %d,%d\n", i, j); + printf(" read_direct_buf=%d\n", read_direct_buf[i][j]); + goto error; + } + } + } + + /* Try reading with buffer but insufficient buf_size */ + buf_size = read_buf_size - 1; + read_filter_mask = 0; + if ((status = + H5Dread_chunk2(dataset, H5P_DEFAULT, offset, &read_filter_mask, read_direct_buf, &buf_size)) < 0) + goto error; + if (buf_size != read_buf_size) { + fprintf(stderr, "insufficient buffer size\n"); + goto error; + } + if (read_filter_mask != filter_mask) { + fprintf(stderr, "incorrect filter mask returned\n"); + goto error; + } + + /* Verify no data was read */ + for (i = 0; i < CHUNK_NX; i++) { + for (j = 0; j < CHUNK_NY; j++) { + if (read_direct_buf[i][j] != 0) { + printf(" 1. Values read when buffer too small."); + printf(" At index %d,%d\n", i, j); + printf(" read_direct_buf=%d\n", read_direct_buf[i][j]); + goto error; + } + } + } + /* Read the raw chunk back */ - memset(&read_direct_buf, 0, sizeof(read_direct_buf)); - if ((status = H5Dread_chunk(dataset, H5P_DEFAULT, offset, &read_filter_mask, read_direct_buf)) < 0) + if ((status = + H5Dread_chunk2(dataset, H5P_DEFAULT, offset, &read_filter_mask, read_direct_buf, &buf_size)) < 0) goto error; - if (read_filter_mask != filter_mask) + if (buf_size > read_buf_size) { + fprintf(stderr, "insufficient buffer size\n"); goto error; + } + if (read_filter_mask != filter_mask) { + fprintf(stderr, "incorrect filter mask returned\n"); + goto error; + } /* Check that the direct chunk read is the same as the chunk written */ for (i = 0; i < CHUNK_NX; i++) { @@ -969,7 +1069,7 @@ test_data_conv(hid_t file) uint32_t filter_mask = 0; src_type_t direct_buf[CHUNK_NX][CHUNK_NY]; dst_type_t check_chunk[CHUNK_NX][CHUNK_NY]; - src_type_t read_chunk[CHUNK_NX][CHUNK_NY]; /* For H5Dread_chunk */ + src_type_t read_chunk[CHUNK_NX][CHUNK_NY]; /* For H5Dread_chunk2 */ hsize_t offset[2] = {0, 0}; size_t buf_size = CHUNK_NX * CHUNK_NY * sizeof(src_type_t); @@ -979,7 +1079,7 @@ test_data_conv(hid_t file) hsize_t count[2]; /* Block count */ hsize_t block[2]; /* Block sizes */ - TESTING("data conversion for H5Dwrite_chunk/H5Dread_chunk"); + TESTING("data conversion for H5Dwrite_chunk/H5Dread_chunk2"); /* * Create the data space with unlimited dimensions. @@ -1063,9 +1163,17 @@ test_data_conv(hid_t file) if ((dataset = H5Dopen2(file, DATASETNAME4, H5P_DEFAULT)) < 0) goto error; - /* Use H5Dread_chunk() to read the uncompressed data */ - if ((status = H5Dread_chunk(dataset, dxpl, offset, &filter_mask, read_chunk)) < 0) - goto error; + /* Use H5Dread_chunk2() to read the uncompressed data */ + { + size_t tmp_buf_size = buf_size; + + if ((status = H5Dread_chunk2(dataset, dxpl, offset, &filter_mask, read_chunk, &tmp_buf_size)) < 0) + goto error; + if (tmp_buf_size > buf_size) { + fprintf(stderr, "insufficient buffer size\n"); + goto error; + } + } /* Check that the values read are the same as the values written */ for (i = 0; i < CHUNK_NX; i++) { @@ -1170,7 +1278,7 @@ error: /*------------------------------------------------------------------------- * Function: test_invalid_parameters * - * Purpose: Test invalid parameters for H5Dwrite_chunk and H5Dread_chunk + * Purpose: Test invalid parameters for H5Dwrite_chunk and H5Dread_chunk2 * * Return: Success: 0 * Failure: 1 @@ -1190,13 +1298,12 @@ test_invalid_parameters(hid_t file) uint32_t filter_mask = 0; int direct_buf[CHUNK_NX][CHUNK_NY]; - hsize_t offset[2] = {0, 0}; - size_t buf_size = CHUNK_NX * CHUNK_NY * sizeof(int); - int aggression = 9; /* Compression aggression setting */ + hsize_t offset[2] = {0, 0}; + size_t buf_size = CHUNK_NX * CHUNK_NY * sizeof(int); hsize_t chunk_nbytes; /* Chunk size */ - TESTING("invalid parameters for H5Dwrite_chunk/H5Dread_chunk"); + TESTING("invalid parameters for H5Dwrite_chunk/H5Dread_chunk2"); /* * Create the data space with unlimited dimensions. @@ -1213,8 +1320,12 @@ test_invalid_parameters(hid_t file) if ((cparms = H5Pcreate(H5P_DATASET_CREATE)) < 0) goto error; + /* Set early allocation time so unallocated data doesn't cause failures that mask an unexpected success */ + if (H5Pset_alloc_time(cparms, H5D_ALLOC_TIME_EARLY) < 0) + goto error; + /* - * Create a new contiguous dataset to verify H5Dwrite_chunk/H5Dread_chunk doesn't work + * Create a new contiguous dataset to verify H5Dwrite_chunk/H5Dread_chunk2 doesn't work */ if ((dataset = H5Dcreate2(file, DATASETNAME5, H5T_NATIVE_INT, dataspace, H5P_DEFAULT, cparms, H5P_DEFAULT)) < 0) @@ -1248,10 +1359,12 @@ test_invalid_parameters(hid_t file) } H5E_END_TRY - /* Try to H5Dread_chunk from the contiguous dataset. It should fail */ + /* Try to H5Dread_chunk2 from the contiguous dataset. It should fail */ H5E_BEGIN_TRY { - if ((status = H5Dread_chunk(dataset, dxpl, offset, &filter_mask, direct_buf)) != FAIL) + size_t tmp_buf_size = buf_size; + + if ((status = H5Dread_chunk2(dataset, dxpl, offset, &filter_mask, direct_buf, &tmp_buf_size)) != FAIL) goto error; } H5E_END_TRY @@ -1259,12 +1372,17 @@ test_invalid_parameters(hid_t file) if (H5Dclose(dataset) < 0) goto error; - /* Create a chunked dataset with compression filter */ + /* Create a chunked dataset with compression filter (if available) */ if ((status = H5Pset_chunk(cparms, RANK, chunk_dims)) < 0) goto error; - if ((status = H5Pset_deflate(cparms, (unsigned)aggression)) < 0) - goto error; +#ifdef H5_HAVE_FILTER_DEFLATE + { + unsigned aggression = 9; /* Compression aggression setting */ + if ((status = H5Pset_deflate(cparms, aggression)) < 0) + goto error; + } +#endif /* H5_HAVE_FILTER_DEFLATE */ /* * Create a new dataset within the file using cparms @@ -1274,7 +1392,7 @@ test_invalid_parameters(hid_t file) H5Dcreate2(file, DATASETNAME6, H5T_NATIVE_INT, dataspace, H5P_DEFAULT, cparms, H5P_DEFAULT)) < 0) goto error; - /* Check invalid dataset ID for H5Dwrite_chunk and H5Dread_chunk */ + /* Check invalid dataset ID for H5Dwrite_chunk and H5Dread_chunk2 */ H5E_BEGIN_TRY { if ((status = H5Dwrite_chunk((hid_t)H5I_INVALID_HID, dxpl, filter_mask, offset, buf_size, @@ -1285,12 +1403,15 @@ test_invalid_parameters(hid_t file) H5E_BEGIN_TRY { - if ((status = H5Dread_chunk((hid_t)H5I_INVALID_HID, dxpl, offset, &filter_mask, direct_buf)) != FAIL) + size_t tmp_buf_size = buf_size; + + if ((status = H5Dread_chunk2((hid_t)H5I_INVALID_HID, dxpl, offset, &filter_mask, direct_buf, + &tmp_buf_size)) != FAIL) goto error; } H5E_END_TRY - /* Check invalid DXPL ID for H5Dwrite_chunk and H5Dread_chunk */ + /* Check invalid DXPL ID for H5Dwrite_chunk and H5Dread_chunk2 */ H5E_BEGIN_TRY { if ((status = H5Dwrite_chunk(dataset, (hid_t)H5I_INVALID_HID, filter_mask, offset, buf_size, @@ -1301,13 +1422,15 @@ test_invalid_parameters(hid_t file) H5E_BEGIN_TRY { - if ((status = H5Dread_chunk(dataset, (hid_t)H5I_INVALID_HID, offset, &filter_mask, direct_buf)) != - FAIL) + size_t tmp_buf_size = buf_size; + + if ((status = H5Dread_chunk2(dataset, (hid_t)H5I_INVALID_HID, offset, &filter_mask, direct_buf, + &tmp_buf_size)) != FAIL) goto error; } H5E_END_TRY - /* Check invalid OFFSET for H5Dwrite_chunk and H5Dread_chunk */ + /* Check invalid OFFSET for H5Dwrite_chunk and H5Dread_chunk2 */ H5E_BEGIN_TRY { if ((status = H5Dwrite_chunk(dataset, dxpl, filter_mask, NULL, buf_size, direct_buf)) != FAIL) @@ -1317,12 +1440,14 @@ test_invalid_parameters(hid_t file) H5E_BEGIN_TRY { - if ((status = H5Dread_chunk(dataset, dxpl, NULL, &filter_mask, direct_buf)) != FAIL) + size_t tmp_buf_size = buf_size; + + if ((status = H5Dread_chunk2(dataset, dxpl, NULL, &filter_mask, direct_buf, &tmp_buf_size)) != FAIL) goto error; } H5E_END_TRY - /* Check when OFFSET is out of dataset range for H5Dwrite_chunk and H5Dread_chunk */ + /* Check when OFFSET is out of dataset range for H5Dwrite_chunk and H5Dread_chunk2 */ offset[0] = NX + 1; offset[1] = NY; H5E_BEGIN_TRY @@ -1334,12 +1459,14 @@ test_invalid_parameters(hid_t file) H5E_BEGIN_TRY { - if ((status = H5Dread_chunk(dataset, dxpl, offset, &filter_mask, direct_buf)) != FAIL) + size_t tmp_buf_size = buf_size; + + if ((status = H5Dread_chunk2(dataset, dxpl, offset, &filter_mask, direct_buf, &tmp_buf_size)) != FAIL) goto error; } H5E_END_TRY - /* Check when OFFSET is not on chunk boundary for H5Dwrite_chunk and H5Dread_chunk */ + /* Check when OFFSET is not on chunk boundary for H5Dwrite_chunk and H5Dread_chunk2 */ offset[0] = CHUNK_NX; offset[1] = CHUNK_NY + 1; H5E_BEGIN_TRY @@ -1351,7 +1478,9 @@ test_invalid_parameters(hid_t file) H5E_BEGIN_TRY { - if ((status = H5Dread_chunk(dataset, dxpl, offset, &filter_mask, direct_buf)) != FAIL) + size_t tmp_buf_size = buf_size; + + if ((status = H5Dread_chunk2(dataset, dxpl, offset, &filter_mask, direct_buf, &tmp_buf_size)) != FAIL) goto error; } H5E_END_TRY @@ -1367,7 +1496,7 @@ test_invalid_parameters(hid_t file) } H5E_END_TRY - /* Check invalid data buffer for H5Dwrite_chunk and H5Dread_chunk */ + /* Check invalid data buffer for H5Dwrite_chunk only */ buf_size = CHUNK_NX * CHUNK_NY * sizeof(int); H5E_BEGIN_TRY { @@ -1376,9 +1505,17 @@ test_invalid_parameters(hid_t file) } H5E_END_TRY + /* Check invalid buffer size pointer for H5Dread_chunk2, with and without data buffer */ H5E_BEGIN_TRY { - if ((status = H5Dread_chunk(dataset, dxpl, offset, &filter_mask, NULL)) != FAIL) + if ((status = H5Dread_chunk2(dataset, dxpl, offset, &filter_mask, direct_buf, NULL)) != FAIL) + goto error; + } + H5E_END_TRY + + H5E_BEGIN_TRY + { + if ((status = H5Dread_chunk2(dataset, dxpl, offset, &filter_mask, NULL, NULL)) != FAIL) goto error; } H5E_END_TRY @@ -1389,10 +1526,14 @@ test_invalid_parameters(hid_t file) /* * Close/release resources. */ - H5Sclose(mem_space); - H5Sclose(dataspace); - H5Pclose(cparms); - H5Pclose(dxpl); + if (H5Sclose(mem_space) < 0) + goto error; + if (H5Sclose(dataspace) < 0) + goto error; + if (H5Pclose(cparms) < 0) + goto error; + if (H5Pclose(dxpl) < 0) + goto error; PASSED(); return 0; @@ -1415,7 +1556,7 @@ error: /*------------------------------------------------------------------------- * Function: test_direct_chunk_read_no_cache * - * Purpose: Test the basic functionality of H5Dread_chunk with the + * Purpose: Test the basic functionality of H5Dread_chunk2 with the * chunk cache disabled. * * Return: Success: 0 @@ -1438,10 +1579,10 @@ test_direct_chunk_read_no_cache(hid_t file) int data[NX][NY]; int i, j, k, l, n; /* local index variables */ - uint32_t filter_mask = 0; /* filter mask returned from H5Dread_chunk */ + uint32_t filter_mask = 0; /* filter mask returned from H5Dread_chunk2 */ int direct_buf[CHUNK_NX][CHUNK_NY]; /* chunk read with H5Dread and manually decompressed */ int check_chunk[CHUNK_NX][CHUNK_NY]; /* chunk read with H5Dread */ - hsize_t offset[2]; /* chunk offset used for H5Dread_chunk */ + hsize_t offset[2]; /* chunk offset used for H5Dread_chunk2 */ size_t buf_size = CHUNK_NX * CHUNK_NY * sizeof(int); Bytef *z_src = NULL; /* source buffer */ @@ -1456,7 +1597,7 @@ test_direct_chunk_read_no_cache(hid_t file) hsize_t count[2]; /* Block count */ hsize_t block[2]; /* Block sizes */ - TESTING("basic functionality of H5Dread_chunk (chunk cache disabled)"); + TESTING("basic functionality of H5Dread_chunk2 (chunk cache disabled)"); /* Create the data space with unlimited dimensions. */ if ((dataspace = H5Screate_simple(RANK, dims, maxdims)) < 0) @@ -1500,9 +1641,11 @@ test_direct_chunk_read_no_cache(hid_t file) outbuf = malloc(z_src_nbytes); z_src = (Bytef *)outbuf; - /* For each chunk in the dataset, compare the result of H5Dread and H5Dread_chunk. */ + /* For each chunk in the dataset, compare the result of H5Dread and H5Dread_chunk2. */ for (i = 0; i < NX / CHUNK_NX; i++) { for (j = 0; j < NY / CHUNK_NY; j++) { + size_t tmp_buf_size; + /* Select hyperslab for one chunk in the file */ start[0] = (hsize_t)i * CHUNK_NX; start[1] = (hsize_t)j * CHUNK_NY; @@ -1525,14 +1668,23 @@ test_direct_chunk_read_no_cache(hid_t file) offset[0] = (hsize_t)i * CHUNK_NX; offset[1] = (hsize_t)j * CHUNK_NY; /* Read the compressed chunk back using the direct read function. */ - if ((status = H5Dread_chunk(dataset, dxpl, offset, &filter_mask, outbuf)) < 0) + tmp_buf_size = buf_size; + if ((status = H5Dread_chunk2(dataset, dxpl, offset, &filter_mask, outbuf, &tmp_buf_size)) < 0) goto error; + /* Check if buffer wasn't big enough */ + if (tmp_buf_size > buf_size) { + fprintf(stderr, "insufficient buffer size\n"); + goto error; + } + /* Check filter mask return value */ - if (filter_mask != 0) + if (filter_mask != 0) { + fprintf(stderr, "incorrect filter mask returned\n"); goto error; + } - /* Perform decompression from the source to the destination buffer */ + /* Perform decompression from the source to the destination buffer */ #if defined(H5_HAVE_ZLIBNG_H) ret = zng_uncompress(z_dst, &z_dst_nbytes, z_src, z_src_nbytes); #else @@ -1620,10 +1772,10 @@ test_direct_chunk_read_cache(hid_t file, bool flush) int data[NX][NY]; int i, j, k, l, n; /* local index variables */ - uint32_t filter_mask = 0; /* filter mask returned from H5Dread_chunk */ + uint32_t filter_mask = 0; /* filter mask returned from H5Dread_chunk2 */ int direct_buf[CHUNK_NX][CHUNK_NY]; /* chunk read with H5Dread and manually decompressed */ int check_chunk[CHUNK_NX][CHUNK_NY]; /* chunk read with H5Dread */ - hsize_t offset[2]; /* chunk offset used for H5Dread_chunk */ + hsize_t offset[2]; /* chunk offset used for H5Dread_chunk2 */ size_t buf_size = CHUNK_NX * CHUNK_NY * sizeof(int); Bytef *z_src = NULL; /* source buffer */ @@ -1640,10 +1792,10 @@ test_direct_chunk_read_cache(hid_t file, bool flush) hsize_t block[2]; /* Block sizes */ if (flush) { - TESTING("basic functionality of H5Dread_chunk (flush chunk cache)"); + TESTING("basic functionality of H5Dread_chunk2 (flush chunk cache)"); } else { - TESTING("basic functionality of H5Dread_chunk (does not flush chunk cache)"); + TESTING("basic functionality of H5Dread_chunk2 (does not flush chunk cache)"); } /* Create the data space with unlimited dimensions. */ @@ -1688,9 +1840,11 @@ test_direct_chunk_read_cache(hid_t file, bool flush) outbuf = malloc(z_src_nbytes); z_src = (Bytef *)outbuf; - /* For each chunk in the dataset, compare the result of H5Dread and H5Dread_chunk. */ + /* For each chunk in the dataset, compare the result of H5Dread and H5Dread_chunk2. */ for (i = 0; i < NX / CHUNK_NX; i++) { for (j = 0; j < NY / CHUNK_NY; j++) { + size_t tmp_buf_size; + /* Select hyperslab for one chunk in the file */ start[0] = (hsize_t)i * CHUNK_NX; start[1] = (hsize_t)j * CHUNK_NY; @@ -1720,14 +1874,23 @@ test_direct_chunk_read_cache(hid_t file, bool flush) goto error; /* Read the compressed chunk back using the direct read function. */ - if ((status = H5Dread_chunk(dataset, dxpl, offset, &filter_mask, outbuf)) < 0) + tmp_buf_size = buf_size; + if ((status = H5Dread_chunk2(dataset, dxpl, offset, &filter_mask, outbuf, &tmp_buf_size)) < 0) goto error; + /* Check if buffer wasn't big enough */ + if (tmp_buf_size > buf_size) { + fprintf(stderr, "insufficient buffer size\n"); + goto error; + } + /* Check filter mask return value */ - if (filter_mask != 0) + if (filter_mask != 0) { + fprintf(stderr, "incorrect filter mask returned\n"); goto error; + } - /* Perform decompression from the source to the destination buffer */ + /* Perform decompression from the source to the destination buffer */ #if defined(H5_HAVE_ZLIBNG_H) ret = zng_uncompress(z_dst, &z_dst_nbytes, z_src, z_src_nbytes); #else @@ -1801,7 +1964,7 @@ error: /*------------------------------------------------------------------------- * Function: test_read_unfiltered_dset * - * Purpose: Test the basic functionality of H5Dread_chunk on a dataset + * Purpose: Test the basic functionality of H5Dread_chunk2 on a dataset * without no filters applied. * * Return: Success: 0 @@ -1834,7 +1997,7 @@ test_read_unfiltered_dset(hid_t file) hsize_t count[2]; /* Block count */ hsize_t block[2]; /* Block sizes */ - TESTING("basic functionality of H5Dread_chunk on unfiltered datasets"); + TESTING("basic functionality of H5Dread_chunk2 on unfiltered datasets"); /* Create the data space with unlimited dimensions. */ if ((dataspace = H5Screate_simple(RANK, dims, maxdims)) < 0) @@ -1863,16 +2026,18 @@ test_read_unfiltered_dset(hid_t file) /* Write the data for the dataset. * It should stay in the chunk cache and will be evicted/flushed by - * the H5Dread_chunk function call. */ + * the H5Dread_chunk2 function call. */ if ((status = H5Dwrite(dataset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, dxpl, data)) < 0) goto error; if (H5Fflush(dataset, H5F_SCOPE_LOCAL) < 0) goto error; - /* For each chunk in the dataset, compare the result of H5Dread and H5Dread_chunk. */ + /* For each chunk in the dataset, compare the result of H5Dread and H5Dread_chunk2. */ for (i = 0; i < NX / CHUNK_NX; i++) { for (j = 0; j < NY / CHUNK_NY; j++) { + size_t tmp_buf_size; + /* Select hyperslab for one chunk in the file */ start[0] = (hsize_t)i * CHUNK_NX; start[1] = (hsize_t)j * CHUNK_NY; @@ -1903,13 +2068,22 @@ test_read_unfiltered_dset(hid_t file) offset[1] = (hsize_t)j * CHUNK_NY; /* Read the raw chunk back */ memset(&direct_buf, 0, sizeof(direct_buf)); - filter_mask = UINT_MAX; - if ((status = H5Dread_chunk(dataset, dxpl, offset, &filter_mask, direct_buf)) < 0) + filter_mask = UINT_MAX; + tmp_buf_size = buf_size; + if ((status = H5Dread_chunk2(dataset, dxpl, offset, &filter_mask, direct_buf, &tmp_buf_size)) < 0) goto error; - /* Check filter mask return value */ - if (filter_mask != 0) + /* Check if buffer wasn't big enough */ + if (tmp_buf_size > buf_size) { + fprintf(stderr, "insufficient buffer size\n"); goto error; + } + + /* Check filter mask return value */ + if (filter_mask != 0) { + fprintf(stderr, "incorrect filter mask returned\n"); + goto error; + } /* Check that the decompressed values match those read from H5Dread */ for (k = 0; k < CHUNK_NX; k++) { @@ -1953,7 +2127,7 @@ error: /*------------------------------------------------------------------------- * Function: test_read_unallocated_chunk * - * Purpose: Tests the H5Dread_chunk and H5Dget_chunk_storage_size with valid + * Purpose: Tests the H5Dread_chunk2 and H5Dget_chunk_storage_size with valid * offsets to chunks that have not been written to the dataset and are * not allocated in the chunk storage on disk. * @@ -1976,11 +2150,11 @@ test_read_unallocated_chunk(hid_t file) herr_t status; /* status from H5 function calls */ hsize_t i, j; /* local index variables */ - uint32_t filter_mask = 0; /* filter mask returned from H5Dread_chunk */ + uint32_t filter_mask = 0; /* filter mask returned from H5Dread_chunk2 */ int direct_buf[CHUNK_NX][CHUNK_NY]; /* chunk read with H5Dread and manually decompressed */ - hsize_t offset[2]; /* chunk offset used for H5Dread_chunk */ + hsize_t offset[2]; /* chunk offset used for H5Dread_chunk2 */ - TESTING("H5Dread_chunk with unallocated chunks"); + TESTING("H5Dread_chunk2 with unallocated chunks"); /* Create the data space with unlimited dimensions. */ if ((dataspace = H5Screate_simple(RANK, dims, maxdims)) < 0) @@ -2011,8 +2185,8 @@ test_read_unallocated_chunk(hid_t file) FAIL_STACK_ERROR; /* Attempt to read each chunk in the dataset. Chunks are not allocated, - * therefore we expect the result of H5Dread_chunk to fail. Chunk idx starts - * at 1, since one chunk was written to init the chunk storage. */ + * therefore we expect the result of H5Dread_chunk2 to fail. Chunk idx + * starts at 1, since one chunk was written to init the chunk storage. */ for (i = 1; i < NX / CHUNK_NX; i++) { for (j = 0; j < NY / CHUNK_NY; j++) { @@ -2022,7 +2196,9 @@ test_read_unallocated_chunk(hid_t file) /* Read a non-existent chunk using the direct read function. */ H5E_BEGIN_TRY { - status = H5Dread_chunk(dataset, dxpl, offset, &filter_mask, &direct_buf); + size_t tmp_buf_size = sizeof(direct_buf); + + status = H5Dread_chunk2(dataset, dxpl, offset, &filter_mask, &direct_buf, &tmp_buf_size); } H5E_END_TRY @@ -2076,6 +2252,283 @@ error: return 1; } /* test_read_unallocated_chunk() */ +/*------------------------------------------------------------------------- + * Function: test_direct_chunk_read_buf_size + * + * Purpose: Test buffer size parameter/query for H5Dread_chunk2 + * + * Return: Success: 0 + * Failure: 1 + * + *------------------------------------------------------------------------- + */ +static int +test_direct_chunk_read_buf_size(hid_t fid) +{ + hid_t sid = H5I_INVALID_HID; /* Dataspace ID */ + hid_t did = H5I_INVALID_HID; /* Dataset ID */ + hid_t dcpl = H5I_INVALID_HID; /* Dataset creation property list */ + hsize_t dims[2] = {DIM0, DIM1}; /* Dimension sizes */ + hsize_t chunk[2] = {CHUNK0, CHUNK1}; /* Chunk dimension sizes */ + hsize_t offset[2] = {0, 0}; /* Offset for writing */ + uint32_t filters; /* Filter mask out */ + size_t tmp_buf_size; /* Size of buffer as passed to H5Dread_chunk2 */ + int wdata[DIM0][DIM1]; /* Write buffer */ + int rdata[DIM0][DIM1]; /* Read buffer */ + int i, j; /* Local index variable */ + + TESTING("Read buffer size parameter"); + + /* Initialize data */ + for (i = 0; i < DIM0; i++) + for (j = 0; j < DIM1; j++) + wdata[i][j] = j / CHUNK0; + + /* Create dataspace */ + if ((sid = H5Screate_simple(2, dims, NULL)) < 0) + TEST_ERROR; + + /* Create the dataset creation property list and set the chunk size */ + if ((dcpl = H5Pcreate(H5P_DATASET_CREATE)) < 0) + TEST_ERROR; + if (H5Pset_chunk(dcpl, 2, chunk) < 0) + TEST_ERROR; + + /* Create the dataset */ + if ((did = H5Dcreate2(fid, DATASETNAME13, H5T_NATIVE_INT, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT)) < 0) + TEST_ERROR; + + /* Write the data directly to the dataset */ + if (H5Dwrite_chunk(did, H5P_DEFAULT, 0, offset, CHUNK0 * CHUNK1 * sizeof(int), (void *)wdata) < 0) + TEST_ERROR; + + /* Zero out read buffer */ + memset(rdata, 0, sizeof(rdata)); + + /* Test with no buffer and 0 tmp_buf_size */ + tmp_buf_size = 0; + if (H5Dread_chunk2(did, H5P_DEFAULT, offset, &filters, NULL, &tmp_buf_size) < 0) + TEST_ERROR; + + /* Verify correct buffer size returned */ + if (tmp_buf_size != sizeof(rdata)) + TEST_ERROR; + + /* Verify returned filter mask */ + if (filters != 0) + TEST_ERROR; + + /* Verify no data was read */ + for (i = 0; i < DIM0; i++) + for (j = 0; j < DIM1; j++) + if (rdata[i][j] != 0) + TEST_ERROR; + + /* Test with no buffer and nonzero tmp_buf_size */ + tmp_buf_size = 2112; + if (H5Dread_chunk2(did, H5P_DEFAULT, offset, &filters, NULL, &tmp_buf_size) < 0) + TEST_ERROR; + + /* Verify correct buffer size returned */ + if (tmp_buf_size != sizeof(rdata)) + TEST_ERROR; + + /* Verify returned filter mask */ + if (filters != 0) + TEST_ERROR; + + /* Verify no data was read */ + for (i = 0; i < DIM0; i++) + for (j = 0; j < DIM1; j++) + if (rdata[i][j] != 0) + TEST_ERROR; + + /* Test with buffer but 0 tmp_buf_size */ + tmp_buf_size = 0; + if (H5Dread_chunk2(did, H5P_DEFAULT, offset, &filters, rdata, &tmp_buf_size) < 0) + TEST_ERROR; + + /* Verify correct buffer size returned */ + if (tmp_buf_size != sizeof(rdata)) + TEST_ERROR; + + /* Verify returned filter mask */ + if (filters != 0) + TEST_ERROR; + + /* Verify no data was read */ + for (i = 0; i < DIM0; i++) + for (j = 0; j < DIM1; j++) + if (rdata[i][j] != 0) + TEST_ERROR; + + /* Test with buffer but insufficient tmp_buf_size */ + tmp_buf_size = sizeof(rdata) - 1; + if (H5Dread_chunk2(did, H5P_DEFAULT, offset, &filters, rdata, &tmp_buf_size) < 0) + TEST_ERROR; + + /* Verify correct buffer size returned */ + if (tmp_buf_size != sizeof(rdata)) + TEST_ERROR; + + /* Verify returned filter mask */ + if (filters != 0) + TEST_ERROR; + + /* Verify no data was read */ + for (i = 0; i < DIM0; i++) + for (j = 0; j < DIM1; j++) + if (rdata[i][j] != 0) + TEST_ERROR; + + /* Read the data directly */ + if (H5Dread_chunk2(did, H5P_DEFAULT, offset, &filters, rdata, &tmp_buf_size) < 0) + TEST_ERROR; + + /* Check if buffer wasn't big enough */ + if (tmp_buf_size > sizeof(rdata)) + TEST_ERROR; + + /* Verify returned filter mask */ + if (filters != 0) + TEST_ERROR; + + /* Verify that the data read was correct. */ + for (i = 0; i < DIM0; i++) + for (j = 0; j < DIM1; j++) + if (rdata[i][j] != wdata[i][j]) + TEST_ERROR; + + /* + * Close and release resources + */ + if (H5Pclose(dcpl) < 0) + TEST_ERROR; + if (H5Sclose(sid) < 0) + TEST_ERROR; + if (H5Dclose(did) < 0) + TEST_ERROR; + + PASSED(); + return 0; + +error: + H5E_BEGIN_TRY + { + H5Dclose(did); + H5Sclose(sid); + H5Pclose(dcpl); + } + H5E_END_TRY + + H5_FAILED(); + return 1; +} /* end test_direct_chunk_read_buf_size() */ + +#ifndef H5_NO_DEPRECATED_SYMBOLS +/*------------------------------------------------------------------------- + * Function: test_deprec + * + * Purpose: Test deprecated symbols + * + * Return: Success: 0 + * Failure: 1 + * + *------------------------------------------------------------------------- + */ +static int +test_deprec(hid_t fid) +{ + hid_t sid = H5I_INVALID_HID; /* Dataspace ID */ + hid_t did = H5I_INVALID_HID; /* Dataset ID */ + hid_t dcpl = H5I_INVALID_HID; /* Dataset creation property list */ + hsize_t dims[2] = {DIM0, DIM1}; /* Dimension sizes */ + hsize_t chunk[2] = {CHUNK0, CHUNK1}; /* Chunk dimension sizes */ + hsize_t offset[2] = {0, 0}; /* Offset for writing */ + uint32_t filters; /* Filter mask out */ + int wdata[DIM0][DIM1]; /* Write buffer */ + int rdata[DIM0][DIM1]; /* Read buffer */ + int i, j; /* Local index variable */ + + TESTING("Deprecated symbols"); + + /* Initialize data */ + for (i = 0; i < DIM0; i++) + for (j = 0; j < DIM1; j++) + wdata[i][j] = j / CHUNK0; + + /* Create dataspace */ + if ((sid = H5Screate_simple(2, dims, NULL)) < 0) + TEST_ERROR; + + /* Create the dataset creation property list and set the chunk size */ + if ((dcpl = H5Pcreate(H5P_DATASET_CREATE)) < 0) + TEST_ERROR; + if (H5Pset_chunk(dcpl, 2, chunk) < 0) + TEST_ERROR; + + /* Create the dataset */ + if ((did = H5Dcreate2(fid, DATASETNAME14, H5T_NATIVE_INT, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT)) < 0) + TEST_ERROR; + + /* Write the data directly to the dataset */ + if (H5Dwrite_chunk(did, H5P_DEFAULT, 0, offset, CHUNK0 * CHUNK1 * sizeof(int), (void *)wdata) < 0) + TEST_ERROR; + + /* Zero out read buffer */ + memset(rdata, 0, sizeof(rdata)); + + /* Try reading with no buffer */ + H5E_BEGIN_TRY + { + herr_t ret; + ret = H5Dread_chunk1(did, H5P_DEFAULT, offset, &filters, NULL); + if (ret >= 0) + TEST_ERROR; + } + H5E_END_TRY + + /* Read the data directly */ + if (H5Dread_chunk1(did, H5P_DEFAULT, offset, &filters, rdata) < 0) + TEST_ERROR; + + /* Verify returned filter mask */ + if (filters != 0) + TEST_ERROR; + + /* Verify that the data read was correct. */ + for (i = 0; i < DIM0; i++) + for (j = 0; j < DIM1; j++) + if (rdata[i][j] != wdata[i][j]) + TEST_ERROR; + + /* + * Close and release resources + */ + if (H5Pclose(dcpl) < 0) + TEST_ERROR; + if (H5Sclose(sid) < 0) + TEST_ERROR; + if (H5Dclose(did) < 0) + TEST_ERROR; + + PASSED(); + return 0; + +error: + H5E_BEGIN_TRY + { + H5Dclose(did); + H5Sclose(sid); + H5Pclose(dcpl); + } + H5E_END_TRY + + H5_FAILED(); + return 1; +} /* end test_deprec() */ +#endif /* H5_NO_DEPRECATED_SYMBOLS */ + /*------------------------------------------------------------------------- * Function: test_single_chunk * @@ -2149,7 +2602,7 @@ test_single_chunk(unsigned config) if (config & CONFIG_DIRECT_WRITE) { /* Write the data directly to the dataset */ - if (H5Dwrite_chunk(did, H5P_DEFAULT, 0, offset, CHUNK0 * CHUNK1 * 4, (void *)wdata) < 0) + if (H5Dwrite_chunk(did, H5P_DEFAULT, 0, offset, CHUNK0 * CHUNK1 * sizeof(int), (void *)wdata) < 0) FAIL_STACK_ERROR; } /* end if */ else @@ -2186,9 +2639,15 @@ test_single_chunk(unsigned config) FAIL_STACK_ERROR; if (config & CONFIG_DIRECT_READ) { + size_t tmp_buf_size = sizeof(rdata); + /* Read the data directly */ - if (H5Dread_chunk(did, H5P_DEFAULT, offset, &filters, rdata) < 0) - FAIL_STACK_ERROR; + if (H5Dread_chunk2(did, H5P_DEFAULT, offset, &filters, rdata, &tmp_buf_size) < 0) + TEST_ERROR; + + /* Check if buffer wasn't big enough */ + if (tmp_buf_size > sizeof(rdata)) + TEST_ERROR; /* Verify returned filter mask */ if (filters != 0) @@ -2231,13 +2690,13 @@ error: H5_FAILED(); return 1; -} /* test_single_chunk_latest() */ +} /* test_single_chunk() */ /*------------------------------------------------------------------------- * Function: Main function * * Purpose: Test direct chunk write function H5Dwrite_chunk and - * chunk direct read function H5Dread_chunk + * chunk direct read function H5Dread_chunk2 * * Return: Success: 0 * Failure: 1 @@ -2275,6 +2734,10 @@ main(void) #endif /* H5_HAVE_FILTER_DEFLATE */ nerrors += test_read_unfiltered_dset(file_id); nerrors += test_read_unallocated_chunk(file_id); + nerrors += test_direct_chunk_read_buf_size(file_id); +#ifndef H5_NO_DEPRECATED_SYMBOLS + nerrors += test_deprec(file_id); +#endif /* H5_NO_DEPRECATED_SYMBOLS */ /* Loop over test configurations */ for (config = 0; config < CONFIG_END; config++) {