Repository: Unidata/netcdf-c
Pull request #1825 (2020-09-01 19:45:48)

Fix nccopy -c dim/x to actually use the dim/x value.
re: https://github.com/Unidata/netcdf-c/issues/1817

As it was, nccopy -c dim/x was sometimes being ignored. So
modify nccopy to properly take into account. This also required
a change to the nczarr code because it was not applying default
chunking in the same way as libhdf5.

Modify ncdump/tst_nccopy4.sh to test this feature properly.
Also add a similar test to nczarr_test.

Additionally, fix some other things that were causing Visual
Studio builds with testing to not work.
* fix curl testing under CMake to properly handle case
  where DAP is disabled, but byterange support is enabled.
* properly test and/or define uintptr_t
* Convert _O_XXX to O_XXX flags used by open();


Patch:
diff --git a/NUG/nczarr.md b/NUG/nczarr.md
index 296306034..326d2987f 100755
--- a/NUG/nczarr.md
+++ b/NUG/nczarr.md
@@ -41,6 +41,13 @@ currently unsupported.
 - String type
 - User-defined types (enum, opaque, VLEN, and Compound)
 - Unlimited dimensions
+- Contiguous or compact storage
+
+Note that contiguous and compact are not actually supported  because they are HDF5 specific.
+When specified, they are treated as chunked where the file consists of only one chunk.
+This means that testing for contiguous or compact is not possible, the _nc_inq_var_chunking_
+function will always return NC_CHUNKED and the chunksizes will be the same as the dimension sizes
+of the variable's dimensions.
 
 # Enabling NCZarr Support {#nczarr_enable}
 
diff --git a/config.h.cmake.in b/config.h.cmake.in
index 70ef3be24..7f75a0855 100644
--- a/config.h.cmake.in
+++ b/config.h.cmake.in
@@ -305,6 +305,12 @@ are set when opening a binary file on Windows. */
 /* Define to 1 if the system has the type `ssize_t'. */
 #cmakedefine HAVE_SSIZE_T 1
 
+/* Define to 1 if the system has the type `ptrdiff_t'. */
+#cmakedefine HAVE_PTRDIFF_T 1
+
+/* Define to 1 if the system has the type `uintptr_t'. */
+#cmakedefine HAVE_UINTPTR_T 1
+
 /* Define to 1 if you have the <stdarg.h> header file. */
 #cmakedefine HAVE_STDARG_H 1
 
@@ -608,6 +614,9 @@ with zip */
 /* Define to `int' if <sys/types.h> does not define. */
 #cmakedefine ssize_t int
 
+/* Define to `signed long if <sys/types.h> does not define. */
+#cmakedefine ptrdiff_t signed long
+
 /* Define to `unsigned long if <sys/types.h> does not define. */
 #cmakedefine uintptr_t unsigned long
 
diff --git a/configure.ac b/configure.ac
index 35212641e..05b9a8625 100644
--- a/configure.ac
+++ b/configure.ac
@@ -397,11 +397,104 @@ AC_MSG_RESULT($enable_set_log_level_func)
 
 # We need curl for DAP and byterange
 AC_CHECK_LIB([curl],[curl_easy_setopt],[found_curl=yes],[found_curl=no])
-if test "x$enable_dap" = "xyes" ; then
-   AC_SEARCH_LIBS([curl_easy_setopt],[curl curl.dll], [],
-      [AC_MSG_ERROR([curl required for remote access. Install curl or build with --disable-dap.])])
+if test "x$found_curl" = "xyes" ; then
+   AC_SEARCH_LIBS([curl_easy_setopt],[curl curl.dll cygcurl.dll], [],
+      [AC_MSG_ERROR([curl required for remote access. Install curl or disable relevant options.])])
 fi
 
+# CURLOPT_USERNAME is not defined until curl version 7.19.1
+# CURLOPT_PASSWORD is not defined until curl version 7.19.1
+# CURLOPT_KEYPASSWD is not defined until curl version 7.16.4
+# CURLINFO_RESPONSE_CODE is not defined until curl version 7.10.7
+# CURLOPT_CHUNK_BGN_FUNCTION is not defined until curl version 7.21.0
+# CURL_MAX_READ_SIZE is not defined until 7.59
+
+# Save/restore CFLAGS
+SAVECFLAGS="$CFLAGS"
+CFLAGS="${curl_cflags}"
+
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
+[#include "curl/curl.h"],
+[[int x = CURLOPT_USERNAME;]])],
+                   [haveusername=yes],
+                   [haveusername=no])
+AC_MSG_CHECKING([whether CURLOPT_USERNAME is defined])
+AC_MSG_RESULT([${haveusername}])
+if test $haveusername = yes; then
+  AC_DEFINE([HAVE_CURLOPT_USERNAME],[1],[Is CURLOPT_USERNAME defined])
+fi
+
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
+[#include "curl/curl.h"],
+[[int x = CURLOPT_PASSWORD;]])],
+                   [havepassword=yes],
+                   [havepassword=no])
+AC_MSG_CHECKING([whether CURLOPT_PASSWORD is defined])
+AC_MSG_RESULT([${havepassword}])
+if test $havepassword = yes; then
+  AC_DEFINE([HAVE_CURLOPT_PASSWORD],[1],[Is CURLOPT_PASSWORD defined])
+fi
+
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
+[#include "curl/curl.h"],
+[[int x = CURLOPT_KEYPASSWD;]])],
+                   [havekeypassword=yes],
+                   [havekeypassword=no])
+AC_MSG_CHECKING([whether CURLOPT_KEYPASSWD is defined])
+AC_MSG_RESULT([${havekeypassword}])
+if test $havekeypassword = yes; then
+  AC_DEFINE([HAVE_CURLOPT_KEYPASSWD],[1],[Is CURLOPT_KEYPASSWD defined])
+fi
+
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
+[#include "curl/curl.h"],
+[[int x = CURLINFO_RESPONSE_CODE;]])],
+                   [haveresponsecode=yes],
+                   [haveresponsecode=no])
+AC_MSG_CHECKING([whether CURLINFO_RESPONSE_CODE is defined])
+AC_MSG_RESULT([${haveresponsecode}])
+if test $haveresponsecode = yes; then
+  AC_DEFINE([HAVE_CURLINFO_RESPONSE_CODE],[1],[Is CURLINFO_RESPONSE_CODE defined])
+fi
+
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
+[#include "curl/curl.h"],
+[[int x = CURLOPT_BUFFERSIZE;]])],
+                   [havecurloption=yes],
+                   [havecurloption=no])
+AC_MSG_CHECKING([whether CURLOPT_BUFFERSIZE is defined])
+AC_MSG_RESULT([${havecurloption}])
+if test $havecurloption = yes; then
+  AC_DEFINE([HAVE_CURLOPT_BUFFERSIZE],[1],[Is CURLOPT_BUFFERSIZE defined])
+fi
+
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
+[#include "curl/curl.h"],
+[[int x = CURLOPT_TCP_KEEPALIVE;]])],
+                   [havecurloption=yes],
+                   [havecurloption=no])
+AC_MSG_CHECKING([whether CURLOPT_TCP_KEEPALIVE is defined])
+AC_MSG_RESULT([${havecurloption}])
+if test $havecurloption = yes; then
+  AC_DEFINE([HAVE_CURLOPT_KEEPALIVE],[1],[Is CURLOPT_TCP_KEEPALIVE defined])
+fi
+# CURLOPT_VERIFYHOST semantics differ depending on version
+AC_MSG_CHECKING([whether libcurl is version 7.66 or later?])
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
+[#include "curl/curl.h"],
+[[
+#if LIBCURL_VERSION_NUM < 0x074200
+error "<7.66";
+#endif
+]])], [libcurl766=yes], [libcurl766=no])
+
+AC_MSG_RESULT([$libcurl766])
+if test x$libcurl66 = xno; then
+  AC_DEFINE([HAVE_LIBCURL_766],[1],[Is libcurl version 7.66 or later])
+fi
+
+CFLAGS="$SAVECFLAGS"
+
 # --enable-dap => enable-dap4
 enable_dap4=$enable_dap
 # Default is to do the short remote tests.
@@ -466,8 +559,6 @@ if test "x$enable_dap_remote_tests" = "xno" ; then
 fi
 AC_MSG_RESULT([$enable_dap_long_tests])
 
-AM_CONDITIONAL(INTERNAL_OCLIB,[test "x" = "x"])
-
 # Control zarr storage
 if test "x$enable_nczarr" = xyes ; then
 if test "x$enable_netcdf_4" = xno ; then
@@ -758,99 +849,6 @@ AC_PROG_CXX
 AM_PROG_CC_C_O
 AC_C_CONST
 
-# CURLOPT_USERNAME is not defined until curl version 7.19.1
-# CURLOPT_PASSWORD is not defined until curl version 7.19.1
-# CURLOPT_KEYPASSWD is not defined until curl version 7.16.4
-# CURLINFO_RESPONSE_CODE is not defined until curl version 7.10.7
-# CURLOPT_CHUNK_BGN_FUNCTION is not defined until curl version 7.21.0
-# CURL_MAX_READ_SIZE is not defined until 7.59
-
-# Save/restore CFLAGS
-SAVECFLAGS="$CFLAGS"
-CFLAGS="${curl_cflags}"
-
-AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
-[#include "curl/curl.h"],
-[[int x = CURLOPT_USERNAME;]])],
-                   [haveusername=yes],
-                   [haveusername=no])
-AC_MSG_CHECKING([whether CURLOPT_USERNAME is defined])
-AC_MSG_RESULT([${haveusername}])
-if test $haveusername = yes; then
-  AC_DEFINE([HAVE_CURLOPT_USERNAME],[1],[Is CURLOPT_USERNAME defined])
-fi
-
-AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
-[#include "curl/curl.h"],
-[[int x = CURLOPT_PASSWORD;]])],
-                   [havepassword=yes],
-                   [havepassword=no])
-AC_MSG_CHECKING([whether CURLOPT_PASSWORD is defined])
-AC_MSG_RESULT([${havepassword}])
-if test $havepassword = yes; then
-  AC_DEFINE([HAVE_CURLOPT_PASSWORD],[1],[Is CURLOPT_PASSWORD defined])
-fi
-
-AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
-[#include "curl/curl.h"],
-[[int x = CURLOPT_KEYPASSWD;]])],
-                   [havekeypassword=yes],
-                   [havekeypassword=no])
-AC_MSG_CHECKING([whether CURLOPT_KEYPASSWD is defined])
-AC_MSG_RESULT([${havekeypassword}])
-if test $havekeypassword = yes; then
-  AC_DEFINE([HAVE_CURLOPT_KEYPASSWD],[1],[Is CURLOPT_KEYPASSWD defined])
-fi
-
-AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
-[#include "curl/curl.h"],
-[[int x = CURLINFO_RESPONSE_CODE;]])],
-                   [haveresponsecode=yes],
-                   [haveresponsecode=no])
-AC_MSG_CHECKING([whether CURLINFO_RESPONSE_CODE is defined])
-AC_MSG_RESULT([${haveresponsecode}])
-if test $haveresponsecode = yes; then
-  AC_DEFINE([HAVE_CURLINFO_RESPONSE_CODE],[1],[Is CURLINFO_RESPONSE_CODE defined])
-fi
-
-AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
-[#include "curl/curl.h"],
-[[int x = CURLOPT_BUFFERSIZE;]])],
-                   [havecurloption=yes],
-                   [havecurloption=no])
-AC_MSG_CHECKING([whether CURLOPT_BUFFERSIZE is defined])
-AC_MSG_RESULT([${havecurloption}])
-if test $havecurloption = yes; then
-  AC_DEFINE([HAVE_CURLOPT_BUFFERSIZE],[1],[Is CURLOPT_BUFFERSIZE defined])
-fi
-
-AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
-[#include "curl/curl.h"],
-[[int x = CURLOPT_TCP_KEEPALIVE;]])],
-                   [havecurloption=yes],
-                   [havecurloption=no])
-AC_MSG_CHECKING([whether CURLOPT_TCP_KEEPALIVE is defined])
-AC_MSG_RESULT([${havecurloption}])
-if test $havecurloption = yes; then
-  AC_DEFINE([HAVE_CURLOPT_KEEPALIVE],[1],[Is CURLOPT_TCP_KEEPALIVE defined])
-fi
-# CURLOPT_VERIFYHOST semantics differ depending on version
-AC_MSG_CHECKING([whether libcurl is version 7.66 or later?])
-AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
-[#include "curl/curl.h"],
-[[
-#if LIBCURL_VERSION_NUM < 0x074200
-error "<7.66";
-#endif
-]])], [libcurl766=yes], [libcurl766=no])
-
-AC_MSG_RESULT([$libcurl766])
-if test x$libcurl66 = xno; then
-  AC_DEFINE([HAVE_LIBCURL_766],[1],[Is libcurl version 7.66 or later])
-fi
-
-CFLAGS="$SAVECFLAGS"
-
 # Set up libtool.
 AC_MSG_NOTICE([setting up libtool])
 LT_PREREQ([2.2])
diff --git a/include/ncconfigure.h b/include/ncconfigure.h
index 4678960ab..7f1ffc3e3 100644
--- a/include/ncconfigure.h
+++ b/include/ncconfigure.h
@@ -107,9 +107,9 @@ typedef unsigned int uint;
 #ifndef _WIN32
 #ifndef HAVE_UINTPTR_T
 #if SIZEOF_VOIDP == 8
-typedef unsigned long uintptr_t;
+#define uintptr_t unsigned long
 #else
-typedef unsigned int uintptr_t;
+#define uintptr_t unsigned int
 #endif
 #endif
 #endif
diff --git a/include/ncwinpath.h b/include/ncwinpath.h
index 9bf3a5e0b..664d94aa9 100644
--- a/include/ncwinpath.h
+++ b/include/ncwinpath.h
@@ -14,6 +14,9 @@
 #ifdef HAVE_DIRENT_H
 #include <dirent.h>
 #endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
 #include "ncexternl.h"
 
 #ifndef WINPATH
@@ -31,6 +34,14 @@
 #define ACCESS_MODE_R 4
 #define ACCESS_MODE_W 2
 #define ACCESS_MODE_RW 6
+#ifndef O_RDONLY
+#define O_RDONLY _O_RDONLY
+#define O_RDWR _O_RDWR
+#define O_APPEND _O_APPEND
+#define O_BINARY _O_BINARY
+#define O_CREAT _O_CREAT
+#define O_EXCL _O_EXCL
+#endif
 #else
 #define ACCESS_MODE_EXISTS (F_OK)
 #define ACCESS_MODE_R (R_OK)
diff --git a/libdap4/CMakeLists.txt b/libdap4/CMakeLists.txt
index fdc5c17a2..5bd0a034b 100644
--- a/libdap4/CMakeLists.txt
+++ b/libdap4/CMakeLists.txt
@@ -20,7 +20,7 @@ set(man_MANS netcdf.3)
 
 set(ARGS_MANPAGE -DAPI=C)
 
-IF (USE_HDf5)
+IF (USE_HDF5)
   SET(ARGS_MANPAGE ${ARGS_MANPAGE} -DNETCDF4=TRUE)
 ENDIF(USE_HDF5)
 
diff --git a/libnczarr/zvar.c b/libnczarr/zvar.c
index 0f1e3fb08..08cec8448 100644
--- a/libnczarr/zvar.c
+++ b/libnczarr/zvar.c
@@ -25,9 +25,9 @@ reportchunking(const char* title, NC_VAR_INFO_T* var)
     strlcat(buf,var->hdr.name,sizeof(buf));
     strlcat(buf,"sizes=",sizeof(buf));
     for(i=0;i<var->ndims;i++) {
-        char digits[64];
-        if(i > 0) strlcat(buf,",",sizeof(buf));
-        snprintf(digits,sizeof(digits),"%ld",(unsigned long)var->chunksizes[i]);
+	char digits[64];
+	if(i > 0) strlcat(buf,",",sizeof(buf));
+	snprintf(digits,sizeof(digits),"%ld",(unsigned long)var->chunksizes[i]);
 	strlcat(buf,digits,sizeof(buf));
     }
     LOG((3,"%s",buf));
@@ -70,16 +70,16 @@ check_chunksizes(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var, const size_t *chunksize
     int retval;
 
     if ((retval = nc4_get_typelen_mem(grp->nc4_info, var->type_info->hdr.id, &type_len)))
-        return THROW(retval);
+	return THROW(retval);
     if (var->type_info->nc_type_class == NC_VLEN)
-        dprod = (double)sizeof(nc_hvl_t);
+	dprod = (double)sizeof(nc_hvl_t);
     else
-        dprod = (double)type_len;
+	dprod = (double)type_len;
     for (d = 0; d < var->ndims; d++)
-        dprod *= (double)chunksizes[d];
+	dprod *= (double)chunksizes[d];
 
-    if (dprod > (double) NC_MAX_UINT || dprod == 0)
-        return NC_EBADCHUNK;
+    if (dprod > (double) NC_MAX_UINT)
+	return NC_EBADCHUNK;
 
     return NC_NOERR;
 }
@@ -108,9 +108,9 @@ ncz_find_default_chunksizes2(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var)
 #endif
 
     if (var->type_info->nc_type_class == NC_STRING)
-        type_size = sizeof(char *);
+	type_size = sizeof(char *);
     else
-        type_size = var->type_info->size;
+	type_size = var->type_info->size;
 
 #ifdef LOGGING
     /* Later this will become the total number of bytes in the default
@@ -127,14 +127,14 @@ ncz_find_default_chunksizes2(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var)
      * unlimited dimensions). */
     for (d = 0; d < var->ndims; d++)
     {
-        assert(var->dim[d]);
-        if (! var->dim[d]->unlimited)
-            num_values *= (float)var->dim[d]->len;
+	assert(var->dim[d]);
+	if (! var->dim[d]->unlimited)
+	    num_values *= (float)var->dim[d]->len;
 #ifdef UNLIMITED
-        else {
-            num_unlim++;
-            var->chunksizes[d] = 1; /* overwritten below, if all dims are unlimited */
-        }
+	else {
+	    num_unlim++;
+	    var->chunksizes[d] = 1; /* overwritten below, if all dims are unlimited */
+	}
 #endif
     }
 #ifdef UNLIMITED
@@ -142,45 +142,45 @@ ncz_find_default_chunksizes2(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var)
        of space (DEFAULT_CHUNK_SIZE bytes). Instead we limit to about
        4KB */
     if (var->ndims == 1 && num_unlim == 1) {
-        if (DEFAULT_CHUNK_SIZE / type_size <= 0)
-            suggested_size = 1;
-        else if (DEFAULT_CHUNK_SIZE / type_size > DEFAULT_1D_UNLIM_SIZE)
-            suggested_size = DEFAULT_1D_UNLIM_SIZE;
-        else
-            suggested_size = DEFAULT_CHUNK_SIZE / type_size;
-        var->chunksizes[0] = suggested_size / type_size;
-        LOG((4, "%s: name %s dim %d DEFAULT_CHUNK_SIZE %d num_values %f type_size %d "
-             "chunksize %ld", __func__, var->hdr.name, d, DEFAULT_CHUNK_SIZE, num_values, type_size, var->chunksizes[0]));
+	if (DEFAULT_CHUNK_SIZE / type_size <= 0)
+	    suggested_size = 1;
+	else if (DEFAULT_CHUNK_SIZE / type_size > DEFAULT_1D_UNLIM_SIZE)
+	    suggested_size = DEFAULT_1D_UNLIM_SIZE;
+	else
+	    suggested_size = DEFAULT_CHUNK_SIZE / type_size;
+	var->chunksizes[0] = suggested_size / type_size;
+	LOG((4, "%s: name %s dim %d DEFAULT_CHUNK_SIZE %d num_values %f type_size %d "
+	     "chunksize %ld", __func__, var->hdr.name, d, DEFAULT_CHUNK_SIZE, num_values, type_size, var->chunksizes[0]));
     }
     if (var->ndims > 1 && var->ndims == num_unlim) { /* all dims unlimited */
-        suggested_size = pow((double)DEFAULT_CHUNK_SIZE/type_size, 1.0/(double)(var->ndims));
-        for (d = 0; d < var->ndims; d++)
-        {
-            var->chunksizes[d] = suggested_size ? suggested_size : 1;
-            LOG((4, "%s: name %s dim %d DEFAULT_CHUNK_SIZE %d num_values %f type_size %d "
-                 "chunksize %ld", __func__, var->hdr.name, d, DEFAULT_CHUNK_SIZE, num_values, type_size, var->chunksizes[d]));
-        }
+	suggested_size = pow((double)DEFAULT_CHUNK_SIZE/type_size, 1.0/(double)(var->ndims));
+	for (d = 0; d < var->ndims; d++)
+	{
+	    var->chunksizes[d] = suggested_size ? suggested_size : 1;
+	    LOG((4, "%s: name %s dim %d DEFAULT_CHUNK_SIZE %d num_values %f type_size %d "
+		 "chunksize %ld", __func__, var->hdr.name, d, DEFAULT_CHUNK_SIZE, num_values, type_size, var->chunksizes[d]));
+	}
     }
 #endif
 
     /* Pick a chunk length for each dimension, if one has not already
      * been picked above. */
     for (d = 0; d < var->ndims; d++)
-        if (!var->chunksizes[d])
-        {
-            suggested_size = (pow((double)DEFAULT_CHUNK_SIZE/(num_values * type_size),
-                                  1.0/(double)(var->ndims - num_unlim)) * var->dim[d]->len - .5);
-            if (suggested_size > var->dim[d]->len)
-                suggested_size = var->dim[d]->len;
-            var->chunksizes[d] = suggested_size ? suggested_size : 1;
-            LOG((4, "%s: name %s dim %d DEFAULT_CHUNK_SIZE %d num_values %f type_size %d "
-                 "chunksize %ld", __func__, var->hdr.name, d, DEFAULT_CHUNK_SIZE, num_values, type_size, var->chunksizes[d]));
-        }
+	if (!var->chunksizes[d])
+	{
+	    suggested_size = (pow((double)DEFAULT_CHUNK_SIZE/(num_values * type_size),
+				  1.0/(double)(var->ndims - num_unlim)) * var->dim[d]->len - .5);
+	    if (suggested_size > var->dim[d]->len)
+		suggested_size = var->dim[d]->len;
+	    var->chunksizes[d] = suggested_size ? suggested_size : 1;
+	    LOG((4, "%s: name %s dim %d DEFAULT_CHUNK_SIZE %d num_values %f type_size %d "
+		 "chunksize %ld", __func__, var->hdr.name, d, DEFAULT_CHUNK_SIZE, num_values, type_size, var->chunksizes[d]));
+	}
 
 #ifdef LOGGING
     /* Find total chunk size. */
     for (d = 0; d < var->ndims; d++)
-        total_chunk_size *= (double) var->chunksizes[d];
+	total_chunk_size *= (double) var->chunksizes[d];
     LOG((4, "total_chunk_size %f", total_chunk_size));
 #endif
 
@@ -188,14 +188,14 @@ ncz_find_default_chunksizes2(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var)
     retval = check_chunksizes(grp, var, var->chunksizes);
     if (retval)
     {
-        /* Other error? */
-        if (retval != NC_EBADCHUNK)
-            return THROW(retval);
-
-        /* Chunk is too big! Reduce each dimension by half and try again. */
-        for ( ; retval == NC_EBADCHUNK; retval = check_chunksizes(grp, var, var->chunksizes))
-            for (d = 0; d < var->ndims; d++)
-                var->chunksizes[d] = var->chunksizes[d]/2 ? var->chunksizes[d]/2 : 1;
+	/* Other error? */
+	if (retval != NC_EBADCHUNK)
+	    return THROW(retval);
+
+	/* Chunk is too big! Reduce each dimension by half and try again. */
+	for ( ; retval == NC_EBADCHUNK; retval = check_chunksizes(grp, var, var->chunksizes))
+	    for (d = 0; d < var->ndims; d++)
+		var->chunksizes[d] = var->chunksizes[d]/2 ? var->chunksizes[d]/2 : 1;
     }
 
     /* Do we have any big data overhangs? They can be dangerous to
@@ -203,14 +203,14 @@ ncz_find_default_chunksizes2(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var)
      * beer. */
     for (d = 0; d < var->ndims; d++)
     {
-        size_t num_chunks;
-        size_t overhang;
-        assert(var->chunksizes[d] > 0);
-        num_chunks = (var->dim[d]->len + var->chunksizes[d] - 1) / var->chunksizes[d];
-        if(num_chunks > 0) {
-            overhang = (num_chunks * var->chunksizes[d]) - var->dim[d]->len;
-            var->chunksizes[d] -= overhang / num_chunks;
-        }
+	size_t num_chunks;
+	size_t overhang;
+	assert(var->chunksizes[d] > 0);
+	num_chunks = (var->dim[d]->len + var->chunksizes[d] - 1) / var->chunksizes[d];
+	if(num_chunks > 0) {
+	    overhang = (num_chunks * var->chunksizes[d]) - var->dim[d]->len;
+	    var->chunksizes[d] -= overhang / num_chunks;
+	}
     }
 
 #ifdef LOGGING
@@ -240,10 +240,10 @@ give_var_secret_name(NC_VAR_INFO_T *var, const char *name)
     /* Set a different ncz name for this variable to avoid name
      * clash. */
     if (strlen(name) + strlen(NON_COORD_PREPEND) > NC_MAX_NAME)
-        return NC_EMAXNAME;
+	return NC_EMAXNAME;
     if (!(var->ncz_name = malloc((strlen(NON_COORD_PREPEND) +
-                                   strlen(name) + 1) * sizeof(char))))
-        return NC_ENOMEM;
+				   strlen(name) + 1) * sizeof(char))))
+	return NC_ENOMEM;
 
     sprintf(var->ncz_name, "%s%s", NON_COORD_PREPEND, name);
 
@@ -284,7 +284,7 @@ give_var_secret_name(NC_VAR_INFO_T *var, const char *name)
  */
 int
 NCZ_def_var(int ncid, const char *name, nc_type xtype, int ndims,
-            const int *dimidsp, int *varidp)
+	    const int *dimidsp, int *varidp)
 {
     NC_GRP_INFO_T *grp;
     NC_VAR_INFO_T *var;
@@ -298,13 +298,13 @@ NCZ_def_var(int ncid, const char *name, nc_type xtype, int ndims,
 
     /* Find info for this file and group, and set pointer to each. */
     if ((retval = nc4_find_grp_h5(ncid, &grp, &h5)))
-        BAIL(retval);
+	BAIL(retval);
     assert(grp && grp->format_grp_info && h5);
 
 #ifdef LOOK
     /* HDF5 allows maximum of 32 dimensions. */
     if (ndims > H5S_MAX_RANK)
-        BAIL(NC_EMAXDIMS);
+	BAIL(NC_EMAXDIMS);
 #endif
 
     /* If it's not in define mode, strict nc3 files error out,
@@ -312,53 +312,53 @@ NCZ_def_var(int ncid, const char *name, nc_type xtype, int ndims,
      * file is writable. */
     if (!(h5->flags & NC_INDEF))
     {
-        if (h5->cmode & NC_CLASSIC_MODEL)
-            BAIL(NC_ENOTINDEFINE);
-        if ((retval = NCZ_redef(ncid)))
-            BAIL(retval);
+	if (h5->cmode & NC_CLASSIC_MODEL)
+	    BAIL(NC_ENOTINDEFINE);
+	if ((retval = NCZ_redef(ncid)))
+	    BAIL(retval);
     }
     assert(!h5->no_write);
 
     /* Check and normalize the name. */
     if ((retval = nc4_check_name(name, norm_name)))
-        BAIL(retval);
+	BAIL(retval);
 
     /* Not a Type is, well, not a type.*/
     if (xtype == NC_NAT)
-        BAIL(NC_EBADTYPE);
+	BAIL(NC_EBADTYPE);
 
     /* For classic files, only classic types are allowed. */
     if (h5->cmode & NC_CLASSIC_MODEL && xtype > NC_DOUBLE)
-        BAIL(NC_ESTRICTNC3);
+	BAIL(NC_ESTRICTNC3);
 
     /* For classic files limit number of dims. */
     if (h5->cmode & NC_CLASSIC_MODEL && ndims > NC_MAX_VAR_DIMS)
-        BAIL(NC_EMAXDIMS);
+	BAIL(NC_EMAXDIMS);
 
     /* cast needed for braindead systems with signed size_t */
     if ((unsigned long) ndims > X_INT_MAX) /* Backward compat */
-        BAIL(NC_EINVAL);
+	BAIL(NC_EINVAL);
 
     /* Check that this name is not in use as a var, grp, or type. */
     if ((retval = nc4_check_dup_name(grp, norm_name)))
-        BAIL(retval);
+	BAIL(retval);
 
     /* For non-scalar vars, dim IDs must be provided. */
     if (ndims && !dimidsp)
-        BAIL(NC_EINVAL);
+	BAIL(NC_EINVAL);
 
     /* Check all the dimids to make sure they exist. */
     for (d = 0; d < ndims; d++)
-        if ((retval = nc4_find_dim(grp, dimidsp[d], &dim, NULL)))
-            BAIL(retval);
+	if ((retval = nc4_find_dim(grp, dimidsp[d], &dim, NULL)))
+	    BAIL(retval);
 
     /* These degrubbing messages sure are handy! */
     LOG((2, "%s: name %s type %d ndims %d", __func__, norm_name, xtype, ndims));
 #ifdef LOGGING
     {
-        int dd;
-        for (dd = 0; dd < ndims; dd++)
-            LOG((4, "dimid[%d] %d", dd, dimidsp[dd]));
+	int dd;
+	for (dd = 0; dd < ndims; dd++)
+	    LOG((4, "dimid[%d] %d", dd, dimidsp[dd]));
     }
 #endif
 
@@ -370,11 +370,11 @@ NCZ_def_var(int ncid, const char *name, nc_type xtype, int ndims,
 
     /* Create a new var and fill in some ZARR cache setting values. */
     if ((retval = nc4_var_list_add(grp, norm_name, ndims, &var)))
-        BAIL(retval);
+	BAIL(retval);
 
     /* Add storage for NCZ-specific var info. */
     if (!(var->format_var_info = calloc(1, sizeof(NCZ_VAR_INFO_T))))
-        BAIL(NC_ENOMEM);
+	BAIL(NC_ENOMEM);
     zvar = var->format_var_info;
     zvar->common.file = h5;
 
@@ -397,7 +397,7 @@ var->type_info->rc++;
      * variable type is variable length (NC_STRING or NC_VLEN) or is
      * user-defined type. */
     if (var->type_info->nc_type_class < NC_STRING)
-        var->no_fill = (h5->fill_mode == NC_NOFILL);
+	var->no_fill = (h5->fill_mode == NC_NOFILL);
 
     /* Assign dimensions to the variable. At the same time, check to
      * see if this is a coordinate variable. If so, it will have the
@@ -407,34 +407,34 @@ var->type_info->rc++;
     var->storage = NC_CHUNKED;
     for (d = 0; d < ndims; d++)
     {
-        NC_GRP_INFO_T *dim_grp;
-        /* Look up each dimension */
-        if ((retval = nc4_find_dim(grp, dimidsp[d], &dim, &dim_grp)))
-            BAIL(retval);
-        assert(dim && dim->format_dim_info);
+	NC_GRP_INFO_T *dim_grp;
+	/* Look up each dimension */
+	if ((retval = nc4_find_dim(grp, dimidsp[d], &dim, &dim_grp)))
+	    BAIL(retval);
+	assert(dim && dim->format_dim_info);
 #ifdef UNLIMITED
-        /* Check for unlimited dimension and turn off contiguous storage. */
-        if (dim->unlimited)
-            var->contiguous = NC_FALSE;
+	/* Check for unlimited dimension and turn off contiguous storage. */
+	if (dim->unlimited)
+	    var->contiguous = NC_FALSE;
 #endif
-        /* Track dimensions for variable */
-        var->dimids[d] = dimidsp[d];
-        var->dim[d] = dim;
+	/* Track dimensions for variable */
+	var->dimids[d] = dimidsp[d];
+	var->dim[d] = dim;
     }
 
     /* Determine default chunksizes for this variable. (Even for
      * variables which may be contiguous.) */
     LOG((4, "allocating array of %d size_t to hold chunksizes for var %s",
-         var->ndims, var->hdr.name));
+	 var->ndims, var->hdr.name));
     if (var->ndims) {
-        if (!(var->chunksizes = calloc(var->ndims, sizeof(size_t))))
-            BAIL(NC_ENOMEM);
-        if ((retval = ncz_find_default_chunksizes2(grp, var)))
-            BAIL(retval);
+	if (!(var->chunksizes = calloc(var->ndims, sizeof(size_t))))
+	    BAIL(NC_ENOMEM);
+	if ((retval = ncz_find_default_chunksizes2(grp, var)))
+	    BAIL(retval);
     } else {
 	/* Pretend that scalars are like var[1] */
-        if (!(var->chunksizes = calloc(1, sizeof(size_t))))
-            BAIL(NC_ENOMEM);
+	if (!(var->chunksizes = calloc(1, sizeof(size_t))))
+	    BAIL(NC_ENOMEM);
 	var->chunksizes[0] = 1;
     }
     
@@ -447,21 +447,21 @@ var->type_info->rc++;
 
     /* Create the cache */
     if((retval=NCZ_create_chunk_cache(var,zvar->chunkproduct*var->type_info->size,&zvar->cache)))
-        BAIL(retval);
+	BAIL(retval);
 
     /* Is this a variable with a chunksize greater than the current cache size? */
     if ((retval = NCZ_adjust_var_cache(grp, var)))
-        BAIL(retval);
+	BAIL(retval);
 
     /* Return the varid. */
     if (varidp)
-        *varidp = var->hdr.id;
+	*varidp = var->hdr.id;
     LOG((4, "new varid %d", var->hdr.id));
 
 exit:
     if (type)
-        if ((retval = nc4_type_free(type)))
-            BAIL2(retval);
+	if ((retval = nc4_type_free(type)))
+	    BAIL2(retval);
 
     return THROW(retval);
 }
@@ -499,9 +499,9 @@ exit:
  */
 static int
 ncz_def_var_extra(int ncid, int varid, int *shuffle, int *unused1,
-                 int *unused2, int *fletcher32, int *storagep,
-                 const size_t *chunksizes, int *no_fill,
-                 const void *fill_value, int *endianness)
+		 int *unused2, int *fletcher32, int *storagep,
+		 const size_t *chunksizes, int *no_fill,
+		 const void *fill_value, int *endianness)
 {
     NC_GRP_INFO_T *grp;
     NC_FILE_INFO_T *h5;
@@ -515,211 +515,216 @@ ncz_def_var_extra(int ncid, int varid, int *shuffle, int *unused1,
 
     /* Find info for this file and group, and set pointer to each. */
     if ((retval = nc4_find_nc_grp_h5(ncid, NULL, &grp, &h5)))
-        return THROW(retval);
+	return THROW(retval);
     assert(grp && h5);
 
     /* Trying to write to a read-only file? No way, Jose! */
     if (h5->no_write)
-        return NC_EPERM;
+	return NC_EPERM;
 
     /* Find the var. */
     if (!(var = (NC_VAR_INFO_T *)ncindexith(grp->vars, varid)))
-        return NC_ENOTVAR;
+	return NC_ENOTVAR;
     assert(var && var->hdr.id == varid);
 
     /* Can't turn on parallel and deflate/fletcher32/szip/shuffle
      * before HDF5 1.10.3. */
 #ifndef HDF5_SUPPORTS_PAR_FILTERS
     if (h5->parallel == NC_TRUE)
-        if (nclistlength(var->filters) > 0  || fletcher32 || shuffle)
-            return NC_EINVAL;
+	if (nclistlength(var->filters) > 0  || fletcher32 || shuffle)
+	    return NC_EINVAL;
 #endif
 
     /* If the HDF5 dataset has already been created, then it is too
      * late to set all the extra stuff. */
     if (var->created)
-        return NC_ELATEDEF;
+	return NC_ELATEDEF;
 
 #if 0
     /* Check compression options. */
     if (deflate && !deflate_level)
-        return NC_EINVAL;
+	return NC_EINVAL;
 
     /* Valid deflate level? */
     if (deflate)
     {
-        if (*deflate)
-            if (*deflate_level < NC_MIN_DEFLATE_LEVEL ||
-                *deflate_level > NC_MAX_DEFLATE_LEVEL)
-                return NC_EINVAL;
-
-        /* For scalars, just ignore attempt to deflate. */
-        if (!var->ndims)
-            return NC_NOERR;
-
-        /* If szip is in use, return an error. */
-        if ((retval = nc_inq_var_szip(ncid, varid, &option_mask, NULL)))
-            return THROW(retval);
-        if (option_mask)
-            return NC_EINVAL;
-
-        /* Set the deflate settings. */
-        var->contiguous = NC_FALSE;
-        var->deflate = *deflate;
-        if (*deflate)
-            var->deflate_level = *deflate_level;
-        LOG((3, "%s: *deflate_level %d", __func__, *deflate_level));
+	if (*deflate)
+	    if (*deflate_level < NC_MIN_DEFLATE_LEVEL ||
+		*deflate_level > NC_MAX_DEFLATE_LEVEL)
+		return NC_EINVAL;
+
+	/* For scalars, just ignore attempt to deflate. */
+	if (!var->ndims)
+	    return NC_NOERR;
+
+	/* If szip is in use, return an error. */
+	if ((retval = nc_inq_var_szip(ncid, varid, &option_mask, NULL)))
+	    return THROW(retval);
+	if (option_mask)
+	    return NC_EINVAL;
+
+	/* Set the deflate settings. */
+	var->contiguous = NC_FALSE;
+	var->deflate = *deflate;
+	if (*deflate)
+	    var->deflate_level = *deflate_level;
+	LOG((3, "%s: *deflate_level %d", __func__, *deflate_level));
     }
 #endif
 
     /* Shuffle filter? */
     if (shuffle)
     {
-        var->shuffle = *shuffle;
-        var->storage = NC_CHUNKED;
+	var->shuffle = *shuffle;
+	var->storage = NC_CHUNKED;
     }
 
     /* Fletcher32 checksum error protection? */
     if (fletcher32)
     {
-        var->fletcher32 = *fletcher32;
-        var->storage = NC_CHUNKED;
+	var->fletcher32 = *fletcher32;
+	var->storage = NC_CHUNKED;
     }
 
     /* Handle storage settings. */
     if (storagep)
     {
 	storage = *storagep;
-        /* Does the user want a contiguous or compact dataset? Not so
-         * fast! Make sure that there are no unlimited dimensions, and
-         * no filters in use for this data. */
-        if (storage != NC_CHUNKED)
-        {
-            if (nclistlength(var->filters) > 0 || var->fletcher32 || var->shuffle)
-                return NC_EINVAL;
-            for (d = 0; d < var->ndims; d++)
-                if (var->dim[d]->unlimited)
-                    return NC_EINVAL;
+	/* Does the user want a contiguous or compact dataset? Not so
+	 * fast! Make sure that there are no unlimited dimensions, and
+	 * no filters in use for this data. */
+	if (storage != NC_CHUNKED)
+	{
+	    if (nclistlength(var->filters) > 0 || var->fletcher32 || var->shuffle)
+		return NC_EINVAL;
+	    for (d = 0; d < var->ndims; d++)
+		if (var->dim[d]->unlimited)
+		    return NC_EINVAL;
 	    storage = NC_CHUNKED; /*only chunked supported */
-        }
+	}
 
-        /* Handle chunked storage settings. */
-        if (storage == NC_CHUNKED && var->ndims == 0) {
+	/* Handle chunked storage settings. */
+	if (storage == NC_CHUNKED && var->ndims == 0) {
 	    return THROW(NC_EINVAL);
-        } else if (storage == NC_CHUNKED && var->ndims > 0) {
-            var->storage = NC_CHUNKED;
-
-            /* If the user provided chunksizes, check that they are valid
-             * and that their total size of chunk is less than 4 GB. */
-            if (chunksizes)
-            {
-                /* Check the chunksizes for validity. */
-                if ((retval = check_chunksizes(grp, var, chunksizes)))
-                    return THROW(retval);
-
-                /* Ensure chunksize is smaller than dimension size */
-                for (d = 0; d < var->ndims; d++)
-                    if (!var->dim[d]->unlimited && var->dim[d]->len > 0 &&
-                        chunksizes[d] > var->dim[d]->len)
-                        return NC_EBADCHUNK;
-            }
-        }
-        else if (storage == NC_CONTIGUOUS || storage == NC_COMPACT)
-        {
-            var->storage = NC_CHUNKED;
-        }
-    }
-
-    /* Is this a variable with a chunksize greater than the current
-     * cache size? */
-    if (var->storage == NC_CHUNKED)
-    {
-        zvar = var->format_var_info;
-        assert(zvar->cache != NULL);
-	if(chunksizes) {
-            for (d = 0; d < var->ndims; d++)
-                var->chunksizes[d] = chunksizes[d];
- 	} else { /* Use default chunking */
-            if ((retval = ncz_find_default_chunksizes2(grp, var)))
-		return THROW(retval);
-        }
-        assert(var->chunksizes != NULL);
-        /* Set the chunksize product for this variable. */
-        zvar->chunkproduct = 1;
-        for (d = 0; d < var->ndims; d++)
-	    zvar->chunkproduct *= var->chunksizes[d];
+	} else if (storage == NC_CHUNKED && var->ndims > 0) {
+	    var->storage = NC_CHUNKED;
+
+	    /* If the user provided chunksizes, check that they are valid
+	     * and that their total size of chunk is less than 4 GB. */
+	    if (chunksizes)
+	    {
+		/* Check the chunksizes for validity. */
+		if ((retval = check_chunksizes(grp, var, chunksizes)))
+		    return THROW(retval);
+
+		/* Ensure chunksize is smaller than dimension size */
+		for (d = 0; d < var->ndims; d++)
+		    if (!var->dim[d]->unlimited && var->dim[d]->len > 0 &&
+			chunksizes[d] > var->dim[d]->len)
+			return NC_EBADCHUNK;
+	    }
+	}
+	else if (storage == NC_CONTIGUOUS || storage == NC_COMPACT)
+	{
+	    var->storage = NC_CHUNKED;
+	}
+
+	/* Is this a variable with a chunksize greater than the current
+	 * cache size? */
+	if (var->storage == NC_CHUNKED)
+	{
+	    int anyzero = 0; /* check for any zero length chunksizes */
+	    zvar = var->format_var_info;
+	    assert(zvar->cache != NULL);
+	    if(chunksizes) {
+		for (d = 0; d < var->ndims; d++) {
+		    var->chunksizes[d] = chunksizes[d];
+		    if(chunksizes[d] == 0) anyzero = 1;
+		}
+	    }
+	    /* If chunksizes == NULL or anyzero then use defaults */
+	    if(chunksizes == NULL || anyzero) { /* Use default chunking */
+		if ((retval = ncz_find_default_chunksizes2(grp, var)))
+		    return THROW(retval);
+	    }
+	    assert(var->chunksizes != NULL);
+	    /* Set the chunksize product for this variable. */
+	    zvar->chunkproduct = 1;
+	    for (d = 0; d < var->ndims; d++)
+		zvar->chunkproduct *= var->chunksizes[d];
 #ifdef LOOK
-        /* Adjust the cache. */
-        if ((retval = ncz_adjust_var_cache(grp, var)))
-            return THROW(retval);
+	    /* Adjust the cache. */
+	    if ((retval = ncz_adjust_var_cache(grp, var)))
+		return THROW(retval);
 #endif
-    }
-
+	}
+    
 #ifdef LOGGING
-    {
-        int dfalt = (chunksizes == NULL);
-        reportchunking(dfalt ? "extra: default: " : "extra: user: ", var);
-    }
+	{
+	    int dfalt = (chunksizes == NULL);
+	    reportchunking(dfalt ? "extra: default: " : "extra: user: ", var);
+	}
 #endif
-
+    }
+    
     /* Are we setting a fill modes? */
     if (no_fill)
     {
-        if (*no_fill)
-        {
-            /* NC_STRING types may not turn off fill mode. It's disallowed
-             * by HDF5 and will cause a HDF5 error later. */
-            if (*no_fill)
-                if (var->type_info->hdr.id == NC_STRING)
-                    return NC_EINVAL;
-
-            /* Set the no-fill mode. */
-            var->no_fill = NC_TRUE;
-        }
-        else
-            var->no_fill = NC_FALSE;
+	if (*no_fill)
+	{
+	    /* NC_STRING types may not turn off fill mode. It's disallowed
+	     * by HDF5 and will cause a HDF5 error later. */
+	    if (*no_fill)
+		if (var->type_info->hdr.id == NC_STRING)
+		    return NC_EINVAL;
+
+	    /* Set the no-fill mode. */
+	    var->no_fill = NC_TRUE;
+	}
+	else
+	    var->no_fill = NC_FALSE;
     }
 
     /* Are we setting a fill value? */
     if (fill_value && !var->no_fill)
     {
-        /* Copy the fill_value. */
-        LOG((4, "Copying fill value into metadata for variable %s",
-             var->hdr.name));
-
-        /* If there's a _FillValue attribute, delete it. */
-        retval = NCZ_del_att(ncid, varid, _FillValue);
-        if (retval && retval != NC_ENOTATT)
-            return THROW(retval);
-
-        /* Create a _FillValue attribute. */
-        if ((retval = nc_put_att(ncid, varid, _FillValue, var->type_info->hdr.id,
-                                 1, fill_value)))
-            return THROW(retval);
+	/* Copy the fill_value. */
+	LOG((4, "Copying fill value into metadata for variable %s",
+	     var->hdr.name));
+
+	/* If there's a _FillValue attribute, delete it. */
+	retval = NCZ_del_att(ncid, varid, _FillValue);
+	if (retval && retval != NC_ENOTATT)
+	    return THROW(retval);
+
+	/* Create a _FillValue attribute. */
+	if ((retval = nc_put_att(ncid, varid, _FillValue, var->type_info->hdr.id,
+				 1, fill_value)))
+	    return THROW(retval);
     }
 
     /* Is the user setting the endianness? */
     if (endianness)
     {
-        /* Setting endianness is only premitted on atomic integer and
-         * atomic float types. */
-        switch (var->type_info->hdr.id)
-        {
-        case NC_BYTE:
-        case NC_SHORT:
-        case NC_INT:
-        case NC_FLOAT:
-        case NC_DOUBLE:
-        case NC_UBYTE:
-        case NC_USHORT:
-        case NC_UINT:
-        case NC_INT64:
-        case NC_UINT64:
-            break;
-        default:
-            return NC_EINVAL;
-        }
-        var->type_info->endianness = *endianness;
+	/* Setting endianness is only premitted on atomic integer and
+	 * atomic float types. */
+	switch (var->type_info->hdr.id)
+	{
+	case NC_BYTE:
+	case NC_SHORT:
+	case NC_INT:
+	case NC_FLOAT:
+	case NC_DOUBLE:
+	case NC_UBYTE:
+	case NC_USHORT:
+	case NC_UINT:
+	case NC_INT64:
+	case NC_UINT64:
+	    break;
+	default:
+	    return NC_EINVAL;
+	}
+	var->type_info->endianness = *endianness;
 	/* Propagate */
 	var->endianness = *endianness;
     }
@@ -750,16 +755,16 @@ ncz_def_var_extra(int ncid, int varid, int *shuffle, int *unused1,
  */
 int
 NCZ_def_var_deflate(int ncid, int varid, int shuffle, int deflate,
-                    int deflate_level)
+		    int deflate_level)
 {
     int stat = NC_NOERR;
     unsigned int level = (unsigned int)deflate_level;
     /* Set shuffle first */
     if((stat = ncz_def_var_extra(ncid, varid, &shuffle, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL))) goto done;
     if(deflate)
-        stat = nc_def_var_filter(ncid, varid, H5Z_FILTER_DEFLATE,1,&level);
+	stat = nc_def_var_filter(ncid, varid, H5Z_FILTER_DEFLATE,1,&level);
     else
-        stat = nc_var_filter_remove(ncid, varid, H5Z_FILTER_DEFLATE);
+	stat = nc_var_filter_remove(ncid, varid, H5Z_FILTER_DEFLATE);
     if(stat) goto done;
 done:
     return stat;
@@ -787,7 +792,7 @@ int
 NCZ_def_var_fletcher32(int ncid, int varid, int fletcher32)
 {
     return ncz_def_var_extra(ncid, varid, NULL, NULL, NULL, &fletcher32,
-                            NULL, NULL, NULL, NULL, NULL);
+			    NULL, NULL, NULL, NULL, NULL);
 }
 
 /**
@@ -816,7 +821,7 @@ int
 NCZ_def_var_chunking(int ncid, int varid, int contiguous, const size_t *chunksizesp)
 {
     return ncz_def_var_extra(ncid, varid, NULL, NULL, NULL, NULL,
-                            &contiguous, chunksizesp, NULL, NULL, NULL);
+			    &contiguous, chunksizesp, NULL, NULL, NULL);
 }
 
 /**
@@ -848,23 +853,23 @@ ncz_def_var_chunking_ints(int ncid, int varid, int contiguous, int *chunksizesp)
 
     /* Get pointer to the var. */
     if ((retval = nc4_find_grp_h5_var(ncid, varid, NULL, NULL, &var)))
-        return THROW(retval);
+	return THROW(retval);
     assert(var);
 
     /* Allocate space for the size_t copy of the chunksizes array. */
     if (var->ndims)
-        if (!(cs = malloc(var->ndims * sizeof(size_t))))
-            return NC_ENOMEM;
+	if (!(cs = malloc(var->ndims * sizeof(size_t))))
+	    return NC_ENOMEM;
 
     /* Copy to size_t array. */
     for (i = 0; i < var->ndims; i++)
-        cs[i] = chunksizesp[i];
+	cs[i] = chunksizesp[i];
 
     retval = ncz_def_var_extra(ncid, varid, NULL, NULL, NULL, NULL,
-                              &contiguous, cs, NULL, NULL, NULL);
+			      &contiguous, cs, NULL, NULL, NULL);
 
     if (var->ndims)
-        free(cs);
+	free(cs);
     return THROW(retval);
 }
 
@@ -895,7 +900,7 @@ int
 NCZ_def_var_fill(int ncid, int varid, int no_fill, const void *fill_value)
 {
     return ncz_def_var_extra(ncid, varid, NULL, NULL, NULL, NULL, NULL,
-                            NULL, &no_fill, fill_value, NULL);
+			    NULL, &no_fill, fill_value, NULL);
 }
 
 /**
@@ -924,7 +929,7 @@ int
 NCZ_def_var_endian(int ncid, int varid, int endianness)
 {
     return ncz_def_var_extra(ncid, varid, NULL, NULL, NULL, NULL, NULL,
-                            NULL, NULL, NULL, &endianness);
+			    NULL, NULL, NULL, &endianness);
 }
 
 /**
@@ -948,7 +953,7 @@ NCZ_def_var_endian(int ncid, int varid, int endianness)
  */
 int
 NCZ_def_var_filter(int ncid, int varid, unsigned int id, size_t nparams,
-                   const unsigned int* params)
+		   const unsigned int* params)
 {
     return NC_ENCZARR;
 }
@@ -994,167 +999,167 @@ NCZ_rename_var(int ncid, int varid, const char *name)
     int retval = NC_NOERR;
 
     if (!name)
-        return NC_EINVAL;
+	return NC_EINVAL;
 
     LOG((2, "%s: ncid 0x%x varid %d name %s", __func__, ncid, varid, name));
 
     /* Find info for this file and group, and set pointer to each. */
     if ((retval = nc4_find_grp_h5(ncid, &grp, &h5)))
-        return THROW(retval);
+	return THROW(retval);
     assert(h5 && grp && grp->format_grp_info);
 
     /* Is the new name too long? */
     if (strlen(name) > NC_MAX_NAME)
-        return NC_EMAXNAME;
+	return NC_EMAXNAME;
 
     /* Trying to write to a read-only file? No way, Jose! */
     if (h5->no_write)
-        return NC_EPERM;
+	return NC_EPERM;
 
     /* Check name validity, if strict nc3 rules are in effect for this
      * file. */
     if ((retval = NC_check_name(name)))
-        return THROW(retval);
+	return THROW(retval);
 
     /* Get the variable wrt varid */
     if (!(var = (NC_VAR_INFO_T *)ncindexith(grp->vars, varid)))
-        return NC_ENOTVAR;
+	return NC_ENOTVAR;
 
     /* Check if new name is in use; note that renaming to same name is
        still an error according to the nc_test/test_write.c
        code. Why?*/
     if (ncindexlookup(grp->vars, name))
-        return NC_ENAMEINUSE;
+	return NC_ENAMEINUSE;
 
     /* If we're not in define mode, new name must be of equal or
        less size, if strict nc3 rules are in effect for this . */
     if (!(h5->flags & NC_INDEF) && strlen(name) > strlen(var->hdr.name) &&
-        (h5->cmode & NC_CLASSIC_MODEL))
-        return NC_ENOTINDEFINE;
+	(h5->cmode & NC_CLASSIC_MODEL))
+	return NC_ENOTINDEFINE;
 
 #ifdef LOOK
     /* Is there another dim with this name, for which this var will not
      * be a coord var? If so, we have to create a dim without a
      * variable for the old name. */
     if ((other_dim = (NC_DIM_INFO_T *)ncindexlookup(grp->dim, name)) &&
-        strcmp(name, var->dim[0]->hdr.name))
+	strcmp(name, var->dim[0]->hdr.name))
     {
-        /* Create a dim without var dataset for old dim. */
-        if ((retval = ncz_create_dim_wo_var(other_dim)))
-            return THROW(retval);
-
-        /* Give this var a secret ZARR name so it can co-exist in file
-         * with dim wp var dataset. Base the secret name on the new var
-         * name. */
-        if ((retval = give_var_secret_name(var, name)))
-            return THROW(retval);
-        use_secret_name++;
+	/* Create a dim without var dataset for old dim. */
+	if ((retval = ncz_create_dim_wo_var(other_dim)))
+	    return THROW(retval);
+
+	/* Give this var a secret ZARR name so it can co-exist in file
+	 * with dim wp var dataset. Base the secret name on the new var
+	 * name. */
+	if ((retval = give_var_secret_name(var, name)))
+	    return THROW(retval);
+	use_secret_name++;
     }
 
     /* Change the ZARR file, if this var has already been created
        there. */
     if (var->created)
     {
-        int v;
-        char *ncz_name; /* Dataset will be renamed to this. */
-        ncz_name = use_secret_name ? var->ncz_name: (char *)name;
-
-        /* Do we need to read var metadata? */
-        if (!var->meta_read)
-            if ((retval = ncz_get_var_meta(var)))
-                return THROW(retval);
-
-        if (var->ndims)
-        {
-            NCZ_DIM_INFO_T *ncz_d0;
-            ncz_d0 = (NCZ_DIM_INFO_T *)var->dim[0]->format_dim_info;
-
-            /* Is there an existing dimscale-only dataset of this name? If
-             * so, it must be deleted. */
-            if (ncz_d0->hdf_dimscaleid)
-            {
-                if ((retval = delete_dimscale_dataset(grp, var->dim[0]->hdr.id,
-                                                      var->dim[0])))
-                    return THROW(retval);
-            }
-        }
-
-        LOG((3, "Moving dataset %s to %s", var->hdr.name, name));
-        if (H5Lmove(ncz_grp->hdf_grpid, var->hdr.name, ncz_grp->hdf_grpid,
-                    ncz_name, H5P_DEFAULT, H5P_DEFAULT) < 0)
-            return NC_EHDFERR;
-
-        /* Rename all the vars in this file with a varid greater than
-         * this var. Varids are assigned based on dataset creation time,
-         * and we have just changed that for this var. We must do the
-         * same for all vars with a > varid, so that the creation order
-         * will continue to be correct. */
-        for (v = var->hdr.id + 1; v < ncindexsize(grp->vars); v++)
-        {
-            NC_VAR_INFO_T *my_var;
-            my_var = (NC_VAR_INFO_T *)ncindexith(grp->vars, v);
-            assert(my_var);
-
-            LOG((3, "mandatory rename of %s to same name", my_var->hdr.name));
-
-            /* Rename to temp name. */
-            if (H5Lmove(ncz_grp->hdf_grpid, my_var->hdr.name, ncz_grp->hdf_grpid,
-                        NC_TEMP_NAME, H5P_DEFAULT, H5P_DEFAULT) < 0)
-                return NC_EHDFERR;
-
-            /* Rename to real name. */
-            if (H5Lmove(ncz_grp->hdf_grpid, NC_TEMP_NAME, ncz_grp->hdf_grpid,
-                        my_var->hdr.name, H5P_DEFAULT, H5P_DEFAULT) < 0)
-                return NC_EHDFERR;
-        }
+	int v;
+	char *ncz_name; /* Dataset will be renamed to this. */
+	ncz_name = use_secret_name ? var->ncz_name: (char *)name;
+
+	/* Do we need to read var metadata? */
+	if (!var->meta_read)
+	    if ((retval = ncz_get_var_meta(var)))
+		return THROW(retval);
+
+	if (var->ndims)
+	{
+	    NCZ_DIM_INFO_T *ncz_d0;
+	    ncz_d0 = (NCZ_DIM_INFO_T *)var->dim[0]->format_dim_info;
+
+	    /* Is there an existing dimscale-only dataset of this name? If
+	     * so, it must be deleted. */
+	    if (ncz_d0->hdf_dimscaleid)
+	    {
+		if ((retval = delete_dimscale_dataset(grp, var->dim[0]->hdr.id,
+						      var->dim[0])))
+		    return THROW(retval);
+	    }
+	}
+
+	LOG((3, "Moving dataset %s to %s", var->hdr.name, name));
+	if (H5Lmove(ncz_grp->hdf_grpid, var->hdr.name, ncz_grp->hdf_grpid,
+		    ncz_name, H5P_DEFAULT, H5P_DEFAULT) < 0)
+	    return NC_EHDFERR;
+
+	/* Rename all the vars in this file with a varid greater than
+	 * this var. Varids are assigned based on dataset creation time,
+	 * and we have just changed that for this var. We must do the
+	 * same for all vars with a > varid, so that the creation order
+	 * will continue to be correct. */
+	for (v = var->hdr.id + 1; v < ncindexsize(grp->vars); v++)
+	{
+	    NC_VAR_INFO_T *my_var;
+	    my_var = (NC_VAR_INFO_T *)ncindexith(grp->vars, v);
+	    assert(my_var);
+
+	    LOG((3, "mandatory rename of %s to same name", my_var->hdr.name));
+
+	    /* Rename to temp name. */
+	    if (H5Lmove(ncz_grp->hdf_grpid, my_var->hdr.name, ncz_grp->hdf_grpid,
+			NC_TEMP_NAME, H5P_DEFAULT, H5P_DEFAULT) < 0)
+		return NC_EHDFERR;
+
+	    /* Rename to real name. */
+	    if (H5Lmove(ncz_grp->hdf_grpid, NC_TEMP_NAME, ncz_grp->hdf_grpid,
+			my_var->hdr.name, H5P_DEFAULT, H5P_DEFAULT) < 0)
+		return NC_EHDFERR;
+	}
     }
 #endif
 
     /* Now change the name in our metadata. */
     free(var->hdr.name);
     if (!(var->hdr.name = strdup(name)))
-        return NC_ENOMEM;
+	return NC_ENOMEM;
     LOG((3, "var is now %s", var->hdr.name));
 
     /* Fix hash key and rebuild index. */
     var->hdr.hashkey = NC_hashmapkey(var->hdr.name, strlen(var->hdr.name));
     if (!ncindexrebuild(grp->vars))
-        return NC_EINTERNAL;
+	return NC_EINTERNAL;
 
 #ifdef LOOK
     /* Check if this was a coordinate variable previously, but names
      * are different now */
     if (var->dimscale && strcmp(var->hdr.name, var->dim[0]->hdr.name))
     {
-        /* Break up the coordinate variable */
-        if ((retval = ncz_break_coord_var(grp, var, var->dim[0])))
-            return THROW(retval);
+	/* Break up the coordinate variable */
+	if ((retval = ncz_break_coord_var(grp, var, var->dim[0])))
+	    return THROW(retval);
     }
 
     /* Check if this should become a coordinate variable. */
     if (!var->dimscale)
     {
-        /* Only variables with >0 dimensions can become coordinate
-         * variables. */
-        if (var->ndims)
-        {
-            NC_GRP_INFO_T *dim_grp;
-            NC_DIM_INFO_T *dim;
-
-            /* Check to see if this is became a coordinate variable.  If
-             * so, it will have the same name as dimension index 0. If it
-             * is a coordinate var, is it a coordinate var in the same
-             * group as the dim? */
-            if ((retval = ncz_find_dim(grp, var->dimids[0], &dim, &dim_grp)))
-                return THROW(retval);
-            if (!strcmp(dim->hdr.name, name) && dim_grp == grp)
-            {
-                /* Reform the coordinate variable. */
-                if ((retval = ncz_reform_coord_var(grp, var, dim)))
-                    return THROW(retval);
-                var->became_coord_var = NC_TRUE;
-            }
-        }
+	/* Only variables with >0 dimensions can become coordinate
+	 * variables. */
+	if (var->ndims)
+	{
+	    NC_GRP_INFO_T *dim_grp;
+	    NC_DIM_INFO_T *dim;
+
+	    /* Check to see if this is became a coordinate variable.  If
+	     * so, it will have the same name as dimension index 0. If it
+	     * is a coordinate var, is it a coordinate var in the same
+	     * group as the dim? */
+	    if ((retval = ncz_find_dim(grp, var->dimids[0], &dim, &dim_grp)))
+		return THROW(retval);
+	    if (!strcmp(dim->hdr.name, name) && dim_grp == grp)
+	    {
+		/* Reform the coordinate variable. */
+		if ((retval = ncz_reform_coord_var(grp, var, dim)))
+		    return THROW(retval);
+		var->became_coord_var = NC_TRUE;
+	    }
+	}
     }
 #endif
 
@@ -1178,7 +1183,7 @@ NCZ_rename_var(int ncid, int varid, const char *name)
  */
 int
 NCZ_put_vara(int ncid, int varid, const size_t *startp,
-             const size_t *countp, const void *op, int memtype)
+	     const size_t *countp, const void *op, int memtype)
 {
     return NCZ_put_vars(ncid, varid, startp, countp, NULL, op, memtype);
 }
@@ -1200,7 +1205,7 @@ NCZ_put_vara(int ncid, int varid, const size_t *startp,
  */
 int
 NCZ_get_vara(int ncid, int varid, const size_t *startp,
-             const size_t *countp, void *ip, int memtype)
+	     const size_t *countp, void *ip, int memtype)
 {
     return NCZ_get_vars(ncid, varid, startp, countp, NULL, ip, memtype);
 }
@@ -1226,21 +1231,21 @@ check_for_vara(nc_type *mem_nc_type, NC_VAR_INFO_T *var, NC_FILE_INFO_T *h5)
      * as the mem type as well. */
     assert(mem_nc_type);
     if (*mem_nc_type == NC_NAT)
-        *mem_nc_type = var->type_info->hdr.id;
+	*mem_nc_type = var->type_info->hdr.id;
     assert(*mem_nc_type);
 
     /* No NC_CHAR conversions, you pervert! */
     if (var->type_info->hdr.id != *mem_nc_type &&
-        (var->type_info->hdr.id == NC_CHAR || *mem_nc_type == NC_CHAR))
-        return NC_ECHAR;
+	(var->type_info->hdr.id == NC_CHAR || *mem_nc_type == NC_CHAR))
+	return NC_ECHAR;
 
     /* If we're in define mode, we can't read or write data. */
     if (h5->flags & NC_INDEF)
     {
-        if (h5->cmode & NC_CLASSIC_MODEL)
-            return NC_EINDEFINE;
-        if ((retval = ncz_enddef_netcdf4_file(h5)))
-            return THROW(retval);
+	if (h5->cmode & NC_CLASSIC_MODEL)
+	    return NC_EINDEFINE;
+	if ((retval = ncz_enddef_netcdf4_file(h5)))
+	    return THROW(retval);
     }
 
     return NC_NOERR;
@@ -1252,7 +1257,7 @@ check_for_vara(nc_type *mem_nc_type, NC_VAR_INFO_T *var, NC_FILE_INFO_T *h5)
  */
 static void
 log_dim_info(NC_VAR_INFO_T *var, size64_t *fdims, size64_t *fmaxdims,
-             size64_t *start, size64_t *count)
+	     size64_t *start, size64_t *count)
 {
     int d2;
 
@@ -1261,9 +1266,9 @@ log_dim_info(NC_VAR_INFO_T *var, size64_t *fdims, size64_t *fmaxdims,
     LOG((4, "File space, and requested:"));
     for (d2 = 0; d2 < var->ndims; d2++)
     {
-        LOG((4, "fdims[%d]=%Ld fmaxdims[%d]=%Ld", d2, fdims[d2], d2,
-             fmaxdims[d2]));
-        LOG((4, "start[%d]=%Ld  count[%d]=%Ld", d2, start[d2], d2, count[d2]));
+	LOG((4, "fdims[%d]=%Ld fmaxdims[%d]=%Ld", d2, fdims[d2], d2,
+	     fmaxdims[d2]));
+	LOG((4, "start[%d]=%Ld	count[%d]=%Ld", d2, start[d2], d2, count[d2]));
     }
 }
 #endif /* LOGGING */
@@ -1299,7 +1304,7 @@ log_dim_info(NC_VAR_INFO_T *var, size64_t *fdims, size64_t *fmaxdims,
  */
 int
 NCZ_put_vars(int ncid, int varid, const size_t *startp, const size_t *countp,
-             const ptrdiff_t *stridep, const void *data, nc_type mem_nc_type)
+	     const ptrdiff_t *stridep, const void *data, nc_type mem_nc_type)
 {
     NC_GRP_INFO_T *grp;
     NC_FILE_INFO_T *h5;
@@ -1326,11 +1331,11 @@ NCZ_put_vars(int ncid, int varid, const size_t *startp, const size_t *countp,
     
     /* Find info for this file, group, and var. */
     if ((retval = nc4_find_grp_h5_var(ncid, varid, &h5, &grp, &var)))
-        return THROW(retval);
+	return THROW(retval);
     assert(h5 && grp && var && var->hdr.id == varid && var->format_var_info);
 
     LOG((3, "%s: var->hdr.name %s mem_nc_type %d", __func__,
-         var->hdr.name, mem_nc_type));
+	 var->hdr.name, mem_nc_type));
 
     /* Cannot convert to user-defined types. */
     if (mem_nc_type >= NC_FIRSTUSERTYPEID)
@@ -1339,24 +1344,24 @@ NCZ_put_vars(int ncid, int varid, const size_t *startp, const size_t *countp,
     /* Check some stuff about the type and the file. If the file must
      * be switched from define mode, it happens here. */
     if ((retval = check_for_vara(&mem_nc_type, var, h5)))
-        return THROW(retval);
+	return THROW(retval);
     assert(!var->ndims || (startp && countp));
 
     /* Convert from size_t and ptrdiff_t to size64_t */
     /* Also do sanity checks */
     for (i = 0; i < var->ndims; i++)
     {
-        /* Check for non-positive stride. */
-        if (stridep && stridep[i] <= 0)
-            return NC_ESTRIDE;
+	/* Check for non-positive stride. */
+	if (stridep && stridep[i] <= 0)
+	    return NC_ESTRIDE;
 
-        start[i] = startp[i];
-        count[i] = countp ? countp[i] : var->dim[i]->len;
-        stride[i] = stridep ? stridep[i] : 1;
+	start[i] = startp[i];
+	count[i] = countp ? countp[i] : var->dim[i]->len;
+	stride[i] = stridep ? stridep[i] : 1;
 
-        /* Check to see if any counts are zero. */
-        if (!count[i])
-            zero_count++;
+	/* Check to see if any counts are zero. */
+	if (!count[i])
+	    zero_count++;
 	fdims[i] = var->dim[i]->len;
 
     }
@@ -1364,11 +1369,11 @@ NCZ_put_vars(int ncid, int varid, const size_t *startp, const size_t *countp,
 #ifdef LOOK
     /* Get file space of data. */
     if ((file_spaceid = H5Dget_space(ncz_var->hdf_datasetid)) < 0)
-        BAIL(NC_EHDFERR);
+	BAIL(NC_EHDFERR);
 
     /* Get the sizes of all the dims and put them in fdims. */
     if (H5Sget_simple_extent_dims(file_spaceid, fdims, fmaxdims) < 0)
-        BAIL(NC_EHDFERR);
+	BAIL(NC_EHDFERR);
 #endif
 
 #ifdef LOGGING
@@ -1379,20 +1384,20 @@ NCZ_put_vars(int ncid, int varid, const size_t *startp, const size_t *countp,
      * put data beyond their current length. */
     for (d2 = 0; d2 < var->ndims; d2++)
     {
-        size64_t endindex = start[d2] + stride[d2] * (count[d2] - 1); /* last index written */
-        dim = var->dim[d2];
-        assert(dim && dim->hdr.id == var->dimids[d2]);
-        if (count[d2] == 0)
-            endindex = start[d2]; /* fixup for zero read count */
-        if (!dim->unlimited)
-        {
-            /* Allow start to equal dim size if count is zero. */
-            if (start[d2] > fdims[d2] ||
-                (start[d2] == fdims[d2] && count[d2] > 0))
-                BAIL_QUIET(NC_EINVALCOORDS);
-            if (!zero_count && endindex >= fdims[d2])
-                BAIL_QUIET(NC_EEDGE);
-        }
+	size64_t endindex = start[d2] + stride[d2] * (count[d2] - 1); /* last index written */
+	dim = var->dim[d2];
+	assert(dim && dim->hdr.id == var->dimids[d2]);
+	if (count[d2] == 0)
+	    endindex = start[d2]; /* fixup for zero read count */
+	if (!dim->unlimited)
+	{
+	    /* Allow start to equal dim size if count is zero. */
+	    if (start[d2] > fdims[d2] ||
+		(start[d2] == fdims[d2] && count[d2] > 0))
+		BAIL_QUIET(NC_EINVALCOORDS);
+	    if (!zero_count && endindex >= fdims[d2])
+		BAIL_QUIET(NC_EEDGE);
+	}
     }
 
 #ifdef LOOK
@@ -1402,57 +1407,57 @@ NCZ_put_vars(int ncid, int varid, const size_t *startp, const size_t *countp,
        scalar. If it is, we won't try to set up a hyperslab. */
     if (H5Sget_simple_extent_type(file_spaceid) == H5S_SCALAR)
     {
-        if ((mem_spaceid = H5Screate(H5S_SCALAR)) < 0)
-            BAIL(NC_EHDFERR);
+	if ((mem_spaceid = H5Screate(H5S_SCALAR)) < 0)
+	    BAIL(NC_EHDFERR);
     }
     else
     {
-        if (H5Sselect_hyperslab(file_spaceid, H5S_SELECT_SET, start, stride,
-                                count, NULL) < 0)
-            BAIL(NC_EHDFERR);
-
-        /* Create a space for the memory, just big enough to hold the slab
-           we want. */
-        if ((mem_spaceid = H5Screate_simple(var->ndims, count, NULL)) < 0)
-            BAIL(NC_EHDFERR);
+	if (H5Sselect_hyperslab(file_spaceid, H5S_SELECT_SET, start, stride,
+				count, NULL) < 0)
+	    BAIL(NC_EHDFERR);
+
+	/* Create a space for the memory, just big enough to hold the slab
+	   we want. */
+	if ((mem_spaceid = H5Screate_simple(var->ndims, count, NULL)) < 0)
+	    BAIL(NC_EHDFERR);
     }
 #endif
 
     /* Are we going to convert any data? (No converting of user-defined types
        except enum). */
     if (mem_nc_type != var->type_info->hdr.id &&
-        mem_nc_type != NC_COMPOUND && mem_nc_type != NC_OPAQUE
-        && mem_nc_type != NC_VLEN)
+	mem_nc_type != NC_COMPOUND && mem_nc_type != NC_OPAQUE
+	&& mem_nc_type != NC_VLEN)
     {
-        size_t file_type_size;
-
-        /* We must convert - allocate a buffer. */
-        need_to_convert++;
-        if (var->ndims)
-            for (d2=0; d2<var->ndims; d2++)
-                len *= countp[d2];
-        LOG((4, "converting data for var %s type=%d len=%d", var->hdr.name,
-             var->type_info->hdr.id, len));
-
-        /* Later on, we will need to know the size of this type in the
-         * file. */
-        assert(var->type_info->size);
-        file_type_size = var->type_info->size;
-
-        /* If we're reading, we need bufr to have enough memory to store
-         * the data in the file. If we're writing, we need bufr to be
-         * big enough to hold all the data in the file's type. */
-        if (len > 0)
-            if (!(bufr = malloc(len * file_type_size)))
-                BAIL(NC_ENOMEM);
+	size_t file_type_size;
+
+	/* We must convert - allocate a buffer. */
+	need_to_convert++;
+	if (var->ndims)
+	    for (d2=0; d2<var->ndims; d2++)
+		len *= countp[d2];
+	LOG((4, "converting data for var %s type=%d len=%d", var->hdr.name,
+	     var->type_info->hdr.id, len));
+
+	/* Later on, we will need to know the size of this type in the
+	 * file. */
+	assert(var->type_info->size);
+	file_type_size = var->type_info->size;
+
+	/* If we're reading, we need bufr to have enough memory to store
+	 * the data in the file. If we're writing, we need bufr to be
+	 * big enough to hold all the data in the file's type. */
+	if (len > 0)
+	    if (!(bufr = malloc(len * file_type_size)))
+		BAIL(NC_ENOMEM);
     }
     else
-        bufr = (void *)data;
+	bufr = (void *)data;
 
 #ifdef LOOK
     /* Create the data transfer property list. */
     if ((xfer_plistid = H5Pcreate(H5P_DATASET_XFER)) < 0)
-        BAIL(NC_EHDFERR);
+	BAIL(NC_EHDFERR);
 
 #endif /*LOOK*/
 
@@ -1462,111 +1467,111 @@ NCZ_put_vars(int ncid, int varid, const size_t *startp, const size_t *countp,
     if (var->ndims)
     {
 #ifdef UNLIMITED
-        for (d2 = 0; d2 < var->ndims; d2++)
-        {
-            size64_t endindex = start[d2] + stride[d2] * (count[d2] - 1); /* last index written */
-            if (count[d2] == 0)
-                endindex = start[d2];
-            dim = var->dim[d2];
-            assert(dim && dim->hdr.id == var->dimids[d2]);
-            if (dim->unlimited)
-            {
-                if (!zero_count && endindex >= fdims[d2])
-                {
-                    xtend_size[d2] = (long long unsigned)(endindex+1);
-                    need_to_extend++;
-                }
-                else
-                    xtend_size[d2] = (long long unsigned)fdims[d2];
-
-                if (!zero_count && endindex >= dim->len)
-                {
-                    dim->len = endindex+1;
-                    dim->extended = NC_TRUE;
-                }
-            }
-            else
-            {
-                xtend_size[d2] = (size64_t)dim->len;
-            }
-        }
+	for (d2 = 0; d2 < var->ndims; d2++)
+	{
+	    size64_t endindex = start[d2] + stride[d2] * (count[d2] - 1); /* last index written */
+	    if (count[d2] == 0)
+		endindex = start[d2];
+	    dim = var->dim[d2];
+	    assert(dim && dim->hdr.id == var->dimids[d2]);
+	    if (dim->unlimited)
+	    {
+		if (!zero_count && endindex >= fdims[d2])
+		{
+		    xtend_size[d2] = (long long unsigned)(endindex+1);
+		    need_to_extend++;
+		}
+		else
+		    xtend_size[d2] = (long long unsigned)fdims[d2];
+
+		if (!zero_count && endindex >= dim->len)
+		{
+		    dim->len = endindex+1;
+		    dim->extended = NC_TRUE;
+		}
+	    }
+	    else
+	    {
+		xtend_size[d2] = (size64_t)dim->len;
+	    }
+	}
 #endif
 
 #ifdef LOOK
-        /* If we need to extend it, we also need a new file_spaceid
-           to reflect the new size of the space. */
-        if (need_to_extend)
-        {
-            LOG((4, "extending dataset"));
-            /* Convert xtend_size back to hsize_t for use with
-             * H5Dset_extent. */
-            for (d2 = 0; d2 < var->ndims; d2++)
-                fdims[d2] = (size64_t)xtend_size[d2];
-            if (H5Dset_extent(ncz_var->hdf_datasetid, fdims) < 0)
-                BAIL(NC_EHDFERR);
-            if (file_spaceid > 0 && H5Sclose(file_spaceid) < 0)
-                BAIL2(NC_EHDFERR);
-            if ((file_spaceid = H5Dget_space(ncz_var->hdf_datasetid)) < 0)
-                BAIL(NC_EHDFERR);
-            if (H5Sselect_hyperslab(file_spaceid, H5S_SELECT_SET,
-                                    start, stride, count, NULL) < 0)
-                BAIL(NC_EHDFERR);
-        }
+	/* If we need to extend it, we also need a new file_spaceid
+	   to reflect the new size of the space. */
+	if (need_to_extend)
+	{
+	    LOG((4, "extending dataset"));
+	    /* Convert xtend_size back to hsize_t for use with
+	     * H5Dset_extent. */
+	    for (d2 = 0; d2 < var->ndims; d2++)
+		fdims[d2] = (size64_t)xtend_size[d2];
+	    if (H5Dset_extent(ncz_var->hdf_datasetid, fdims) < 0)
+		BAIL(NC_EHDFERR);
+	    if (file_spaceid > 0 && H5Sclose(file_spaceid) < 0)
+		BAIL2(NC_EHDFERR);
+	    if ((file_spaceid = H5Dget_space(ncz_var->hdf_datasetid)) < 0)
+		BAIL(NC_EHDFERR);
+	    if (H5Sselect_hyperslab(file_spaceid, H5S_SELECT_SET,
+				    start, stride, count, NULL) < 0)
+		BAIL(NC_EHDFERR);
+	}
 #endif
     }
 
     /* Do we need to convert the data? */
     if (need_to_convert)
     {
-        if ((retval = nc4_convert_type(data, bufr, mem_nc_type, var->type_info->hdr.id,
-                                       len, &range_error, var->fill_value,
-                                       (h5->cmode & NC_CLASSIC_MODEL))))
-            BAIL(retval);
+	if ((retval = nc4_convert_type(data, bufr, mem_nc_type, var->type_info->hdr.id,
+				       len, &range_error, var->fill_value,
+				       (h5->cmode & NC_CLASSIC_MODEL))))
+	    BAIL(retval);
     }
 
 #ifdef LOOK
     /* Write the data. At last! */
     LOG((4, "about to write datasetid 0x%x mem_spaceid 0x%x "
-         "file_spaceid 0x%x", ncz_var->hdf_datasetid, mem_spaceid, file_spaceid));
+	 "file_spaceid 0x%x", ncz_var->hdf_datasetid, mem_spaceid, file_spaceid));
     if (H5Dwrite(ncz_var->hdf_datasetid,
-                 ((NCZ_TYPE_INFO_T *)var->type_info->format_type_info)->hdf_typeid,
-                 mem_spaceid, file_spaceid, xfer_plistid, bufr) < 0)
-        BAIL(NC_EHDFERR);
+		 ((NCZ_TYPE_INFO_T *)var->type_info->format_type_info)->hdf_typeid,
+		 mem_spaceid, file_spaceid, xfer_plistid, bufr) < 0)
+	BAIL(NC_EHDFERR);
 #endif /*LOOK*/
 
     if((retval = NCZ_transferslice(var, WRITING, start, count, stride, bufr, var->type_info->hdr.id)))
-        BAIL(retval);
+	BAIL(retval);
 
     /* Remember that we have written to this var so that Fill Value
      * can't be set for it. */
     if (!var->written_to)
-        var->written_to = NC_TRUE;
+	var->written_to = NC_TRUE;
 
     /* For strict netcdf-3 rules, ignore erange errors between UBYTE
      * and BYTE types. */
     if ((h5->cmode & NC_CLASSIC_MODEL) &&
-        (var->type_info->hdr.id == NC_UBYTE || var->type_info->hdr.id == NC_BYTE) &&
-        (mem_nc_type == NC_UBYTE || mem_nc_type == NC_BYTE) &&
-        range_error)
-        range_error = 0;
+	(var->type_info->hdr.id == NC_UBYTE || var->type_info->hdr.id == NC_BYTE) &&
+	(mem_nc_type == NC_UBYTE || mem_nc_type == NC_BYTE) &&
+	range_error)
+	range_error = 0;
 
 exit:
 #ifdef LOOK
     if (file_spaceid > 0 && H5Sclose(file_spaceid) < 0)
-        BAIL2(NC_EHDFERR);
+	BAIL2(NC_EHDFERR);
     if (mem_spaceid > 0 && H5Sclose(mem_spaceid) < 0)
-        BAIL2(NC_EHDFERR);
+	BAIL2(NC_EHDFERR);
     if (xfer_plistid && (H5Pclose(xfer_plistid) < 0))
-        BAIL2(NC_EPARINIT);
+	BAIL2(NC_EPARINIT);
 #endif
     if (need_to_convert && bufr) free(bufr);
 
     /* If there was an error return it, otherwise return any potential
        range error value. If none, return NC_NOERR as usual.*/
     if (retval)
-        return THROW(retval);
+	return THROW(retval);
     if (range_error)
-        return NC_ERANGE;
+	return NC_ERANGE;
     return NC_NOERR;
 }
 
@@ -1601,7 +1606,7 @@ exit:
  */
 int
 NCZ_get_vars(int ncid, int varid, const size_t *startp, const size_t *countp,
-             const ptrdiff_t *stridep, void *data, nc_type mem_nc_type)
+	     const ptrdiff_t *stridep, void *data, nc_type mem_nc_type)
 {
     NC_GRP_INFO_T *grp;
     NC_FILE_INFO_T *h5;
@@ -1625,33 +1630,33 @@ NCZ_get_vars(int ncid, int varid, const size_t *startp, const size_t *countp,
 
     /* Find info for this file, group, and var. */
     if ((retval = nc4_find_grp_h5_var(ncid, varid, &h5, &grp, &var)))
-        return THROW(retval);
+	return THROW(retval);
     assert(h5 && grp && var && var->hdr.id == varid && var->format_var_info &&
-           var->type_info && var->type_info->size &&
-           var->type_info->format_type_info);
+	   var->type_info && var->type_info->size &&
+	   var->type_info->format_type_info);
 
     LOG((3, "%s: var->hdr.name %s mem_nc_type %d", __func__,
-         var->hdr.name, mem_nc_type));
+	 var->hdr.name, mem_nc_type));
 
     /* Check some stuff about the type and the file. Also end define
      * mode, if needed. */
     if ((retval = check_for_vara(&mem_nc_type, var, h5)))
-        return THROW(retval);
+	return THROW(retval);
     assert((!var->ndims || (startp && countp)));
 
     /* Convert from size_t and ptrdiff_t to size64_t. Also do sanity
      * checks. */
     for (i = 0; i < var->ndims; i++)
     {
-        /* If any of the stride values are non-positive, fail. */
-        if (stridep && stridep[i] <= 0)
-            return NC_ESTRIDE;
-        start[i] = startp[i];
-        count[i] = countp[i];
-        stride[i] = stridep ? stridep[i] : 1;
-        /* if any of the count values are zero don't actually read. */
-        if (count[i] == 0)
-            no_read++;
+	/* If any of the stride values are non-positive, fail. */
+	if (stridep && stridep[i] <= 0)
+	    return NC_ESTRIDE;
+	start[i] = startp[i];
+	count[i] = countp[i];
+	stride[i] = stridep ? stridep[i] : 1;
+	/* if any of the count values are zero don't actually read. */
+	if (count[i] == 0)
+	    no_read++;
 	/* Get dimension sizes also */
 	fdims[i] = var->dim[i]->len;
 	fmaxdims[i] = fdims[i];
@@ -1660,13 +1665,13 @@ NCZ_get_vars(int ncid, int varid, const size_t *startp, const size_t *countp,
 #ifdef LOOK
     /* Get file space of data. */
     if ((file_spaceid = H5Dget_space(ncz_var->hdf_datasetid)) < 0)
-        BAIL(NC_EHDFERR);
+	BAIL(NC_EHDFERR);
 
     /* Check to ensure the user selection is
      * valid. H5Sget_simple_extent_dims gets the sizes of all the dims
      * and put them in fdims. */
     if (H5Sget_simple_extent_dims(file_spaceid, fdims, fmaxdims) < 0)
-        BAIL(NC_EHDFERR);
+	BAIL(NC_EHDFERR);
 #endif
 
 #ifdef LOGGING
@@ -1677,66 +1682,66 @@ NCZ_get_vars(int ncid, int varid, const size_t *startp, const size_t *countp,
      * put data beyond their current length. */
     for (d2 = 0; d2 < var->ndims; d2++)
     {
-        size64_t endindex = start[d2] + stride[d2] * (count[d2] - 1); /* last index read */
-        dim = var->dim[d2];
-        assert(dim && dim->hdr.id == var->dimids[d2]);
-        if (count[d2] == 0)
-            endindex = start[d2]; /* fixup for zero read count */
-        if (dim->unlimited)
-        {
-            size_t ulen;
-
-            /* We can't go beyond the largest current extent of
-               the unlimited dim. */
-            if ((retval = NCZ_inq_dim(ncid, dim->hdr.id, NULL, &ulen)))
-                BAIL(retval);
-
-            /* Check for out of bound requests. */
-            /* Allow start to equal dim size if count is zero. */
-            if (start[d2] > (size64_t)ulen ||
-                (start[d2] == (size64_t)ulen && count[d2] > 0))
-                BAIL_QUIET(NC_EINVALCOORDS);
-            if (count[d2] && endindex >= ulen)
-                BAIL_QUIET(NC_EEDGE);
-
-            /* Things get a little tricky here. If we're getting a GET
-               request beyond the end of this var's current length in
-               an unlimited dimension, we'll later need to return the
-               fill value for the variable. */
-            if (!no_read)
-            {
-                if (start[d2] >= (size64_t)fdims[d2])
-                    fill_value_size[d2] = count[d2];
-                else if (endindex >= fdims[d2])
-                    fill_value_size[d2] = count[d2] - ((fdims[d2] - start[d2])/stride[d2]);
-                else
-                    fill_value_size[d2] = 0;
-                count[d2] -= fill_value_size[d2];
-                if (count[d2] == 0)
-                    no_read++;
-                if (fill_value_size[d2])
-                    provide_fill++;
-            }
-            else
-                fill_value_size[d2] = count[d2];
-        }
-        else /* Dim is not unlimited. */
-        {
-            /* Check for out of bound requests. */
-            /* Allow start to equal dim size if count is zero. */
-            if (start[d2] > (size64_t)fdims[d2] ||
-                (start[d2] == (size64_t)fdims[d2] && count[d2] > 0))
-                BAIL_QUIET(NC_EINVALCOORDS);
-            if (count[d2] && endindex >= fdims[d2])
-                BAIL_QUIET(NC_EEDGE);
-            /* Set the fill value boundary */
-            fill_value_size[d2] = count[d2];
-        }
+	size64_t endindex = start[d2] + stride[d2] * (count[d2] - 1); /* last index read */
+	dim = var->dim[d2];
+	assert(dim && dim->hdr.id == var->dimids[d2]);
+	if (count[d2] == 0)
+	    endindex = start[d2]; /* fixup for zero read count */
+	if (dim->unlimited)
+	{
+	    size_t ulen;
+
+	    /* We can't go beyond the largest current extent of
+	       the unlimited dim. */
+	    if ((retval = NCZ_inq_dim(ncid, dim->hdr.id, NULL, &ulen)))
+		BAIL(retval);
+
+	    /* Check for out of bound requests. */
+	    /* Allow start to equal dim size if count is zero. */
+	    if (start[d2] > (size64_t)ulen ||
+		(start[d2] == (size64_t)ulen && count[d2] > 0))
+		BAIL_QUIET(NC_EINVALCOORDS);
+	    if (count[d2] && endindex >= ulen)
+		BAIL_QUIET(NC_EEDGE);
+
+	    /* Things get a little tricky here. If we're getting a GET
+	       request beyond the end of this var's current length in
+	       an unlimited dimension, we'll later need to return the
+	       fill value for the variable. */
+	    if (!no_read)
+	    {
+		if (start[d2] >= (size64_t)fdims[d2])
+		    fill_value_size[d2] = count[d2];
+		else if (endindex >= fdims[d2])
+		    fill_value_size[d2] = count[d2] - ((fdims[d2] - start[d2])/stride[d2]);
+		else
+		    fill_value_size[d2] = 0;
+		count[d2] -= fill_value_size[d2];
+		if (count[d2] == 0)
+		    no_read++;
+		if (fill_value_size[d2])
+		    provide_fill++;
+	    }
+	    else
+		fill_value_size[d2] = count[d2];
+	}
+	else /* Dim is not unlimited. */
+	{
+	    /* Check for out of bound requests. */
+	    /* Allow start to equal dim size if count is zero. */
+	    if (start[d2] > (size64_t)fdims[d2] ||
+		(start[d2] == (size64_t)fdims[d2] && count[d2] > 0))
+		BAIL_QUIET(NC_EINVALCOORDS);
+	    if (count[d2] && endindex >= fdims[d2])
+		BAIL_QUIET(NC_EEDGE);
+	    /* Set the fill value boundary */
+	    fill_value_size[d2] = count[d2];
+	}
     }
 
     /* Check the type_info fields. */
     assert(var->type_info && var->type_info->size &&
-           var->type_info->format_type_info);
+	   var->type_info->format_type_info);
 
     /* Later on, we will need to know the size of this type in the
      * file. */
@@ -1745,188 +1750,188 @@ NCZ_get_vars(int ncid, int varid, const size_t *startp, const size_t *countp,
     if (!no_read)
     {
 #ifdef LOOK
-        /* Now you would think that no one would be crazy enough to write
-           a scalar dataspace with one of the array function calls, but you
-           would be wrong. So let's check to see if the dataset is
-           scalar. If it is, we won't try to set up a hyperslab. */
-        if (H5Sget_simple_extent_type(file_spaceid) == H5S_SCALAR)
-        {
-            if ((mem_spaceid = H5Screate(H5S_SCALAR)) < 0)
-                BAIL(NC_EHDFERR);
-            scalar++;
-        }
-        else
-        {
-            if (H5Sselect_hyperslab(file_spaceid, H5S_SELECT_SET,
-                                    start, stride, count, NULL) < 0)
-                BAIL(NC_EHDFERR);
-            /* Create a space for the memory, just big enough to hold the slab
-               we want. */
-            if ((mem_spaceid = H5Screate_simple(var->ndims, count, NULL)) < 0)
-                BAIL(NC_EHDFERR);
-        }
+	/* Now you would think that no one would be crazy enough to write
+	   a scalar dataspace with one of the array function calls, but you
+	   would be wrong. So let's check to see if the dataset is
+	   scalar. If it is, we won't try to set up a hyperslab. */
+	if (H5Sget_simple_extent_type(file_spaceid) == H5S_SCALAR)
+	{
+	    if ((mem_spaceid = H5Screate(H5S_SCALAR)) < 0)
+		BAIL(NC_EHDFERR);
+	    scalar++;
+	}
+	else
+	{
+	    if (H5Sselect_hyperslab(file_spaceid, H5S_SELECT_SET,
+				    start, stride, count, NULL) < 0)
+		BAIL(NC_EHDFERR);
+	    /* Create a space for the memory, just big enough to hold the slab
+	       we want. */
+	    if ((mem_spaceid = H5Screate_simple(var->ndims, count, NULL)) < 0)
+		BAIL(NC_EHDFERR);
+	}
 #endif
 
 #ifdef LOOK
-        /* Fix bug when reading ZARR files with variable of type
-         * fixed-length string.  We need to make it look like a
-         * variable-length string, because that's all netCDF-4 data
-         * model supports, lacking anonymous dimensions.  So
-         * variable-length strings are in allocated memory that user has
-         * to free, which we allocate here. */
-        if (var->type_info->nc_type_class == NC_STRING &&
-            H5Tget_size(ncz_type->hdf_typeid) > 1 &&
-            !H5Tis_variable_str(ncz_type->hdf_typeid))
-        {
-            size64_t fstring_len;
-
-            if ((fstring_len = H5Tget_size(ncz_type->hdf_typeid)) == 0)
-                BAIL(NC_EHDFERR);
-            if (!(*(char **)data = malloc(1 + fstring_len)))
-                BAIL(NC_ENOMEM);
-            bufr = *(char **)data;
-        }
+	/* Fix bug when reading ZARR files with variable of type
+	 * fixed-length string.	 We need to make it look like a
+	 * variable-length string, because that's all netCDF-4 data
+	 * model supports, lacking anonymous dimensions.  So
+	 * variable-length strings are in allocated memory that user has
+	 * to free, which we allocate here. */
+	if (var->type_info->nc_type_class == NC_STRING &&
+	    H5Tget_size(ncz_type->hdf_typeid) > 1 &&
+	    !H5Tis_variable_str(ncz_type->hdf_typeid))
+	{
+	    size64_t fstring_len;
+
+	    if ((fstring_len = H5Tget_size(ncz_type->hdf_typeid)) == 0)
+		BAIL(NC_EHDFERR);
+	    if (!(*(char **)data = malloc(1 + fstring_len)))
+		BAIL(NC_ENOMEM);
+	    bufr = *(char **)data;
+	}
 #endif
-        /* Are we going to convert any data? (No converting of compound or
-         * opaque types.) */
-        if (mem_nc_type != var->type_info->hdr.id &&
-            mem_nc_type != NC_COMPOUND && mem_nc_type != NC_OPAQUE)
-        {
-            /* We must convert - allocate a buffer. */
-            need_to_convert++;
-            if (var->ndims)
-                for (d2 = 0; d2 < var->ndims; d2++)
-                    len *= countp[d2];
-            LOG((4, "converting data for var %s type=%d len=%d", var->hdr.name,
-                 var->type_info->hdr.id, len));
-
-            /* If we're reading, we need bufr to have enough memory to store
-             * the data in the file. If we're writing, we need bufr to be
-             * big enough to hold all the data in the file's type. */
-            if (len > 0)
-                if (!(bufr = malloc(len * file_type_size)))
-                    BAIL(NC_ENOMEM);
-        }
-        else
-            if (!bufr)
-                bufr = data;
+	/* Are we going to convert any data? (No converting of compound or
+	 * opaque types.) */
+	if (mem_nc_type != var->type_info->hdr.id &&
+	    mem_nc_type != NC_COMPOUND && mem_nc_type != NC_OPAQUE)
+	{
+	    /* We must convert - allocate a buffer. */
+	    need_to_convert++;
+	    if (var->ndims)
+		for (d2 = 0; d2 < var->ndims; d2++)
+		    len *= countp[d2];
+	    LOG((4, "converting data for var %s type=%d len=%d", var->hdr.name,
+		 var->type_info->hdr.id, len));
+
+	    /* If we're reading, we need bufr to have enough memory to store
+	     * the data in the file. If we're writing, we need bufr to be
+	     * big enough to hold all the data in the file's type. */
+	    if (len > 0)
+		if (!(bufr = malloc(len * file_type_size)))
+		    BAIL(NC_ENOMEM);
+	}
+	else
+	    if (!bufr)
+		bufr = data;
 
 #ifdef LOOK
-        /* Create the data transfer property list. */
-        if ((xfer_plistid = H5Pcreate(H5P_DATASET_XFER)) < 0)
-            BAIL(NC_EHDFERR);
-
-        /* Read this hyperslab into memory. */
-        LOG((5, "About to H5Dread some data..."));
-        if (H5Dread(ncz_var->hdf_datasetid,
-                    ((NCZ_TYPE_INFO_T *)var->type_info->format_type_info)->native_hdf_typeid,
-                    mem_spaceid, file_spaceid, xfer_plistid, bufr) < 0)
-            BAIL(NC_EHDFERR);
+	/* Create the data transfer property list. */
+	if ((xfer_plistid = H5Pcreate(H5P_DATASET_XFER)) < 0)
+	    BAIL(NC_EHDFERR);
+
+	/* Read this hyperslab into memory. */
+	LOG((5, "About to H5Dread some data..."));
+	if (H5Dread(ncz_var->hdf_datasetid,
+		    ((NCZ_TYPE_INFO_T *)var->type_info->format_type_info)->native_hdf_typeid,
+		    mem_spaceid, file_spaceid, xfer_plistid, bufr) < 0)
+	    BAIL(NC_EHDFERR);
 #endif /*LOOK*/
 
-        if((retval = NCZ_transferslice(var, READING, start, count, stride, bufr, var->type_info->hdr.id)))
+	if((retval = NCZ_transferslice(var, READING, start, count, stride, bufr, var->type_info->hdr.id)))
 	    BAIL(retval);
 
-        /* Convert data type if needed. */
-        if (need_to_convert)
-        {
-            if ((retval = nc4_convert_type(bufr, data, var->type_info->hdr.id, mem_nc_type,
-                                           len, &range_error, var->fill_value,
-                                           (h5->cmode & NC_CLASSIC_MODEL))))
-                BAIL(retval);
-
-            /* For strict netcdf-3 rules, ignore erange errors between UBYTE
-             * and BYTE types. */
-            if ((h5->cmode & NC_CLASSIC_MODEL) &&
-                (var->type_info->hdr.id == NC_UBYTE || var->type_info->hdr.id == NC_BYTE) &&
-                (mem_nc_type == NC_UBYTE || mem_nc_type == NC_BYTE) &&
-                range_error)
-                range_error = 0;
-        }
+	/* Convert data type if needed. */
+	if (need_to_convert)
+	{
+	    if ((retval = nc4_convert_type(bufr, data, var->type_info->hdr.id, mem_nc_type,
+					   len, &range_error, var->fill_value,
+					   (h5->cmode & NC_CLASSIC_MODEL))))
+		BAIL(retval);
+
+	    /* For strict netcdf-3 rules, ignore erange errors between UBYTE
+	     * and BYTE types. */
+	    if ((h5->cmode & NC_CLASSIC_MODEL) &&
+		(var->type_info->hdr.id == NC_UBYTE || var->type_info->hdr.id == NC_BYTE) &&
+		(mem_nc_type == NC_UBYTE || mem_nc_type == NC_BYTE) &&
+		range_error)
+		range_error = 0;
+	}
     } /* endif ! no_read */
     /* Now we need to fake up any further data that was asked for,
        using the fill values instead. First skip past the data we
        just read, if any. */
     if (!scalar && provide_fill)
     {
-        void *filldata;
-        size_t real_data_size = 0;
-        size_t fill_len;
-
-        /* Skip past the real data we've already read. */
-        if (!no_read)
-            for (real_data_size = file_type_size, d2 = 0; d2 < var->ndims; d2++)
-                real_data_size *= count[d2];
-
-        /* Get the fill value from the ZARR variable. Memory will be
-         * allocated. */
-        if (ncz_get_fill_value(h5, var, &fillvalue) < 0)
-            BAIL(NC_EHDFERR);
-
-        /* How many fill values do we need? */
-        for (fill_len = 1, d2 = 0; d2 < var->ndims; d2++)
-            fill_len *= (fill_value_size[d2] ? fill_value_size[d2] : 1);
-
-        /* Copy the fill value into the rest of the data buffer. */
-        filldata = (char *)data + real_data_size;
-        for (i = 0; i < fill_len; i++)
-        {
-
-            if (var->type_info->nc_type_class == NC_STRING)
-            {
-                if (*(char **)fillvalue)
-                {
-                    if (!(*(char **)filldata = strdup(*(char **)fillvalue)))
-                        BAIL(NC_ENOMEM);
-                }
-                else
-                    *(char **)filldata = NULL;
-            }
-            else if (var->type_info->nc_type_class == NC_VLEN)
-            {
-                if (fillvalue)
-                {
-                    memcpy(filldata,fillvalue,file_type_size);
-                } else {
-                    *(char **)filldata = NULL;
-                }
-            }
-            else
-                memcpy(filldata, fillvalue, file_type_size);
-            filldata = (char *)filldata + file_type_size;
-        }
+	void *filldata;
+	size_t real_data_size = 0;
+	size_t fill_len;
+
+	/* Skip past the real data we've already read. */
+	if (!no_read)
+	    for (real_data_size = file_type_size, d2 = 0; d2 < var->ndims; d2++)
+		real_data_size *= count[d2];
+
+	/* Get the fill value from the ZARR variable. Memory will be
+	 * allocated. */
+	if (ncz_get_fill_value(h5, var, &fillvalue) < 0)
+	    BAIL(NC_EHDFERR);
+
+	/* How many fill values do we need? */
+	for (fill_len = 1, d2 = 0; d2 < var->ndims; d2++)
+	    fill_len *= (fill_value_size[d2] ? fill_value_size[d2] : 1);
+
+	/* Copy the fill value into the rest of the data buffer. */
+	filldata = (char *)data + real_data_size;
+	for (i = 0; i < fill_len; i++)
+	{
+
+	    if (var->type_info->nc_type_class == NC_STRING)
+	    {
+		if (*(char **)fillvalue)
+		{
+		    if (!(*(char **)filldata = strdup(*(char **)fillvalue)))
+			BAIL(NC_ENOMEM);
+		}
+		else
+		    *(char **)filldata = NULL;
+	    }
+	    else if (var->type_info->nc_type_class == NC_VLEN)
+	    {
+		if (fillvalue)
+		{
+		    memcpy(filldata,fillvalue,file_type_size);
+		} else {
+		    *(char **)filldata = NULL;
+		}
+	    }
+	    else
+		memcpy(filldata, fillvalue, file_type_size);
+	    filldata = (char *)filldata + file_type_size;
+	}
     }
 
 exit:
 #ifdef LOOK
     if (file_spaceid > 0)
-        if (H5Sclose(file_spaceid) < 0)
-            BAIL2(NC_EHDFERR);
+	if (H5Sclose(file_spaceid) < 0)
+	    BAIL2(NC_EHDFERR);
     if (mem_spaceid > 0)
-        if (H5Sclose(mem_spaceid) < 0)
-            BAIL2(NC_EHDFERR);
+	if (H5Sclose(mem_spaceid) < 0)
+	    BAIL2(NC_EHDFERR);
     if (xfer_plistid > 0)
-        if (H5Pclose(xfer_plistid) < 0)
+	if (H5Pclose(xfer_plistid) < 0)
 
-            BAIL2(NC_EHDFERR);
+	    BAIL2(NC_EHDFERR);
 #endif
     if (need_to_convert && bufr)
-        free(bufr);
+	free(bufr);
     if (fillvalue)
     {
-        if (var->type_info->nc_type_class == NC_VLEN)
-            nc_free_vlen((nc_vlen_t *)fillvalue);
-        else if (var->type_info->nc_type_class == NC_STRING && *(char **)fillvalue)
-            free(*(char **)fillvalue);
-        free(fillvalue);
+	if (var->type_info->nc_type_class == NC_VLEN)
+	    nc_free_vlen((nc_vlen_t *)fillvalue);
+	else if (var->type_info->nc_type_class == NC_STRING && *(char **)fillvalue)
+	    free(*(char **)fillvalue);
+	free(fillvalue);
     }
 
     /* If there was an error return it, otherwise return any potential
        range error value. If none, return NC_NOERR as usual.*/
     if (retval)
-        return THROW(retval);
+	return THROW(retval);
     if (range_error)
-        return THROW(NC_ERANGE);
+	return THROW(NC_ERANGE);
     return NC_NOERR;
 }
 
@@ -1964,11 +1969,11 @@ exit:
  */
 int
 NCZ_inq_var_all(int ncid, int varid, char *name, nc_type *xtypep,
-                     int *ndimsp, int *dimidsp, int *nattsp,
-                     int *shufflep, int *unused4, int *unused5,
-                     int *fletcher32p, int *storagep, size_t *chunksizesp,
-                     int *no_fill, void *fill_valuep, int *endiannessp,
-                     unsigned int *unused1, size_t *unused2, unsigned int *unused3)
+		     int *ndimsp, int *dimidsp, int *nattsp,
+		     int *shufflep, int *unused4, int *unused5,
+		     int *fletcher32p, int *storagep, size_t *chunksizesp,
+		     int *no_fill, void *fill_valuep, int *endiannessp,
+		     unsigned int *unused1, size_t *unused2, unsigned int *unused3)
 {
     NC_FILE_INFO_T *h5;
     NC_GRP_INFO_T *grp;
@@ -1980,16 +1985,16 @@ NCZ_inq_var_all(int ncid, int varid, char *name, nc_type *xtypep,
     /* Find the file, group, and var info, and do lazy att read if
      * needed. */
     if ((retval = ncz_find_grp_var_att(ncid, varid, NULL, 0, 0, NULL,
-                                            &h5, &grp, &var, NULL)))
-        return THROW(retval);
+					    &h5, &grp, &var, NULL)))
+	return THROW(retval);
     assert(grp && h5);
 
     /* Now that lazy atts have been read, use the libsrc4 function to
      * get the answers. */
     return NC4_inq_var_all(ncid, varid, name, xtypep, ndimsp, dimidsp, nattsp,
-                           shufflep, unused4, unused5, fletcher32p,
-                           storagep, chunksizesp, no_fill, fill_valuep,
-                           endiannessp, unused1, unused2, unused3);
+			   shufflep, unused4, unused5, fletcher32p,
+			   storagep, chunksizesp, no_fill, fill_valuep,
+			   endiannessp, unused1, unused2, unused3);
 }
 
 #ifdef LOOK
@@ -2008,23 +2013,23 @@ NCZ_inq_var_all(int ncid, int varid, char *name, nc_type *xtypep,
  */
 int
 ncz_set_var_chunk_cache_ints(int ncid, int varid, int size, int nelems,
-                            int preemption)
+			    int preemption)
 {
     size_t real_size = H5D_CHUNK_CACHE_NBYTES_DEFAULT;
     size_t real_nelems = H5D_CHUNK_CACHE_NSLOTS_DEFAULT;
     float real_preemption = CHUNK_CACHE_PREEMPTION;
 
     if (size >= 0)
-        real_size = ((size_t) size) * MEGABYTE;
+	real_size = ((size_t) size) * MEGABYTE;
 
     if (nelems >= 0)
-        real_nelems = nelems;
+	real_nelems = nelems;
 
     if (preemption >= 0)
-        real_preemption = preemption / 100.;
+	real_preemption = preemption / 100.;
 
     return NCZ_set_var_chunk_cache(ncid, varid, real_size, real_nelems,
-                                        real_preemption);
+					real_preemption);
 }
 #endif
 
@@ -2040,48 +2045,48 @@ ncz_gettype(NC_FILE_INFO_T* h5, NC_GRP_INFO_T* container, int xtype, NC_TYPE_INF
      * struct. */
     if (xtype <= NC_STRING)
     {
-        size_t len;
+	size_t len;
 	char name[NC_MAX_NAME];
 
-        /* Get type name and length. */
-        if((retval = NC4_inq_atomic_type(xtype,name,&len)))
-            BAIL(retval);
+	/* Get type name and length. */
+	if((retval = NC4_inq_atomic_type(xtype,name,&len)))
+	    BAIL(retval);
 
-        /* Create new NC_TYPE_INFO_T struct for this atomic type. */
-        if ((retval = nc4_type_new(len, name, xtype, &type)))
-            BAIL(retval);
+	/* Create new NC_TYPE_INFO_T struct for this atomic type. */
+	if ((retval = nc4_type_new(len, name, xtype, &type)))
+	    BAIL(retval);
 	assert(type->rc == 0);
 	type->container = container;
-        type->endianness = (NC_isLittleEndian()?NC_ENDIAN_LITTLE:NC_ENDIAN_BIG);
-        type->size = len;
+	type->endianness = (NC_isLittleEndian()?NC_ENDIAN_LITTLE:NC_ENDIAN_BIG);
+	type->size = len;
 
 	/* Allocate storage for NCZ-specific type info. */
 	if (!(ztype = calloc(1, sizeof(NCZ_TYPE_INFO_T))))
-            return NC_ENOMEM;
+	    return NC_ENOMEM;
 	type->format_type_info = ztype;
 	ztype->common.file = h5;
 	ztype = NULL;
 
-        /* Set the "class" of the type */
-        if (xtype == NC_CHAR)
-            type->nc_type_class = NC_CHAR;
-        else
-        {
+	/* Set the "class" of the type */
+	if (xtype == NC_CHAR)
+	    type->nc_type_class = NC_CHAR;
+	else
+	{
 	    if(xtype == NC_FLOAT || xtype == NC_DOUBLE)
 		type->nc_type_class = NC_FLOAT;
 	    else if(xtype < NC_STRING)
 		type->nc_type_class = NC_INT;
 	    else
 		type->nc_type_class = NC_STRING;
-        }
+	}
     }
     else
     {
 #ifdef LOOK
-        /* If this is a user defined type, find it. */
-        if (nc4_find_type(grp->nc4_info, xtype, &type))
+	/* If this is a user defined type, find it. */
+	if (nc4_find_type(grp->nc4_info, xtype, &type))
 #endif
-            BAIL(NC_EBADTYPE);
+	    BAIL(NC_EBADTYPE);
     }
 
     /* increment its ref. count */
@@ -2092,9 +2097,7 @@ ncz_gettype(NC_FILE_INFO_T* h5, NC_GRP_INFO_T* container, int xtype, NC_TYPE_INF
 
 exit:
     if (type)
-        retval = nc4_type_free(type);
+	retval = nc4_type_free(type);
     nullfree(ztype);
     return THROW(retval);
 }
-	
-    
diff --git a/ncdump/Makefile.am b/ncdump/Makefile.am
index c35cd6830..6cf1bf904 100644
--- a/ncdump/Makefile.am
+++ b/ncdump/Makefile.am
@@ -155,7 +155,7 @@ ref_null_byte_padding_test.nc ref_tst_irish_rover.nc			\
 ref_provenance_v1.nc ref_tst_radix.cdl tst_radix.cdl test_radix.sh	\
 ref_nccopy_w.cdl tst_nccopy_w3.sh tst_nccopy_w4.sh			\
 ref_no_ncproperty.nc test_unicode_directory.sh				\
-ref_roman_szip_simple.cdl ref_roman_szip_unlim.cdl
+ref_roman_szip_simple.cdl ref_roman_szip_unlim.cdl ref_tst_perdimspecs.cdl
 
 # The L512.bin file is file containing exactly 512 bytes each of value 0.
 # It is used for creating hdf5 files with varying offsets for testing.
@@ -191,4 +191,4 @@ tst_ncf199.cdl tst_tst_gattenum.cdl tst_tst_usuffix.cdl ctest.c		\
 ctest64.c nccopy3_subset_out.nc camrun.c tst_ncf213.cdl tst_ncf213.nc	\
 tst_radix.nc tmp_radix.cdl ctest_small_3.c ctest_small_4.c		\
 ctest_special_atts_4.c tst_roman_szip_simple.cdl			\
-tst_roman_szip_unlim.cdl
+tst_roman_szip_unlim.cdl tst_perdimpspecs.nc tmppds.*
diff --git a/ncdump/nccopy.c b/ncdump/nccopy.c
index 4bfde2714..37e9bdc4b 100644
--- a/ncdump/nccopy.c
+++ b/ncdump/nccopy.c
@@ -910,6 +910,7 @@ copy_chunking(int igrp, int i_varid, int ogrp, int o_varid, int ndims, int inkin
     size_t ichunkp[NC_MAX_VAR_DIMS];
     size_t ochunkp[NC_MAX_VAR_DIMS];
     size_t dimlens[NC_MAX_VAR_DIMS];
+    size_t perdimchunklen[NC_MAX_VAR_DIMS]; /* the values of relevant -c dim/n specifications */
     size_t dfaltchunkp[NC_MAX_VAR_DIMS]; /* default chunking for ovarid */
     int is_unlimited = 0;
 
@@ -920,6 +921,7 @@ copy_chunking(int igrp, int i_varid, int ogrp, int o_varid, int ndims, int inkin
     memset(ichunkp,0,sizeof(ichunkp));
     memset(ochunkp,0,sizeof(ochunkp));
     memset(dimlens,0,sizeof(dimlens));
+    memset(perdimchunklen,0,sizeof(perdimchunklen));
     memset(dfaltchunkp,0,sizeof(dfaltchunkp));
 
     /* Get the chunking, if any, on the current input variable */
@@ -959,7 +961,7 @@ copy_chunking(int igrp, int i_varid, int ogrp, int o_varid, int ndims, int inkin
     if(option_deflate_level >= 0 || hasfilteroptforvar(ofqn))
 	ocontig = NC_CHUNKED;
 
-    /* See about dim-specific chunking; does not override -c spec*/
+    /* See about dim-specific chunking; does not override specific variable chunk spec*/
     {
 	int idim;
 	/* size of a chunk: product of dimension chunksizes and size of value */
@@ -968,8 +970,10 @@ copy_chunking(int igrp, int i_varid, int ogrp, int o_varid, int ndims, int inkin
 	int dimids[NC_MAX_VAR_DIMS];
 
 	/* See if dim-specific chunking was suppressed */
-	if(dimchunkspec_omit()) /* use input chunksizes */
+	if(dimchunkspec_omit()) { /* no chunking at all on output, except as overridden by e.g. compression */
+	   ocontig = NC_CONTIGUOUS;
     	    goto next2;
+	}
 
 	/* Setup for possible output chunking */
 	typesize = val_size(igrp, i_varid);
@@ -979,8 +983,8 @@ copy_chunking(int igrp, int i_varid, int ogrp, int o_varid, int ndims, int inkin
 	/* Prepare to iterate over the dimids of this input variable */
 	NC_CHECK(nc_inq_vardimid(igrp, i_varid, dimids));
 
-        /* Capture dimension lengts for all dimensions of variable;
-	   even if we decide to not chunk */
+        /* Capture dimension lengths for all dimensions of variable */
+	/* Also, capture per-dimension -c specs even if we decide to not chunk */
         for(idim = 0; idim < ndims; idim++) {
             int idimid = dimids[idim];
             int odimid = dimmap_odimid(idimid);
@@ -995,8 +999,8 @@ copy_chunking(int igrp, int i_varid, int ogrp, int o_varid, int ndims, int inkin
 	    }
 
 	    if(dimchunkspec_exists(idimid)) {
-                /* If the -c set a chunk size for this dimension, use it */
-                dimlens[idim] = dimchunkspec_size(idimid); /* Save it */
+                /* If the -c set a chunk size for this dimension, capture it */
+                perdimchunklen[idim] = dimchunkspec_size(idimid); /* Save it */
 		ocontig = NC_CHUNKED; /* force chunking */
 	    }
 
@@ -1021,17 +1025,21 @@ copy_chunking(int igrp, int i_varid, int ogrp, int o_varid, int ndims, int inkin
 	    }
         }
 
-	/* compute the final ochunksizes: precedence is output, input, defaults, dimelen */
+	/* compute the final ochunksizes: precedence is output, per-dim-spec, input, defaults, dimlen */
         for(idim = 0; idim < ndims; idim++) {
-	    if(ochunkp[idim] == 0) {
+	    if(ochunkp[idim] == 0) { /* use -c dim/n if specified */
+	        if(perdimchunklen[idim] != 0)
+		    ochunkp[idim] = perdimchunklen[idim];
+	    }
+	    if(ochunkp[idim] == 0) { /* use input chunk size */
 	        if(ichunkp[idim] != 0)
 		    ochunkp[idim] = ichunkp[idim];
 	    }
-	    if(ochunkp[idim] == 0) {
+	    if(ochunkp[idim] == 0) { /* use chunk defaults */
 	        if(dfaltchunkp[idim] != 0)
 		    ochunkp[idim] = dfaltchunkp[idim];
 	    }
-	    if(ochunkp[idim] == 0) {
+	    if(ochunkp[idim] == 0) { /* last resort: use full dimension size */
 	        if(dimlens[idim] != 0)
 		    ochunkp[idim] = dimlens[idim];
 	    }
@@ -1104,7 +1112,6 @@ copy_var_specials(int igrp, int varid, int ogrp, int o_varid, int inkind, int ou
 	    NC_CHECK(copy_chunking(igrp, varid, ogrp, o_varid, ndims, inkind, outkind));
 	}
     }
-
     if(ndims > 0)
     { /* handle compression parameters, copying from input, overriding
        * with command-line options */
@@ -1136,7 +1143,6 @@ copy_var_specials(int igrp, int varid, int ogrp, int o_varid, int inkind, int ou
 	    deflated = deflate_out;
 	}
     }
-
     if(innc4 && outnc4 && ndims > 0)
     {				/* handle checksum parameters */
 	int fletcher32 = 0;
@@ -1145,7 +1151,6 @@ copy_var_specials(int igrp, int varid, int ogrp, int o_varid, int inkind, int ou
 	    NC_CHECK(nc_def_var_fletcher32(ogrp, o_varid, fletcher32));
 	}
     }
-
     if(innc4 && outnc4)
     {				/* handle endianness */
 	int endianness = 0;
@@ -1159,7 +1164,6 @@ copy_var_specials(int igrp, int varid, int ogrp, int o_varid, int inkind, int ou
         /* handle other general filters */
         NC_CHECK(copy_var_filter(igrp, varid, ogrp, o_varid, inkind, outkind));
     }
-
     return stat;
 }
 
@@ -2457,4 +2461,3 @@ freefilterlist(size_t nfilters, NC_Filterspec** filters)
 }
 
 #endif
-
diff --git a/ncdump/ref_tst_perdimspecs.cdl b/ncdump/ref_tst_perdimspecs.cdl
new file mode 100644
index 000000000..73f8b6cc9
--- /dev/null
+++ b/ncdump/ref_tst_perdimspecs.cdl
@@ -0,0 +1,11 @@
+netcdf ref_tst_perdimspecs {
+dimensions:
+	lon = 40 ;
+	lat = 40 ;
+	time = UNLIMITED ;
+variables:
+	float lon(lon) ;
+	float lat(lat) ;
+	double time(time) ;
+	float tas(time, lat, lon) ;
+}
diff --git a/ncdump/tst_nccopy4.sh b/ncdump/tst_nccopy4.sh
index 534bc1a02..5ad311ceb 100755
--- a/ncdump/tst_nccopy4.sh
+++ b/ncdump/tst_nccopy4.sh
@@ -85,16 +85,27 @@ diff tmp.cdl tmp-chunked.cdl
 ${NCCOPY} -c dim0/,dim1/,dim2/,dim3/,dim4/,dim5/,dim6/ tmp-chunked.nc tmp-unchunked.nc
 ${NCDUMP} -n tmp tmp-unchunked.nc > tmp-unchunked.cdl
 diff tmp.cdl tmp-unchunked.cdl
-${NCCOPY} -c // tmp-chunked.nc tmp-unchunked.nc
-${NCDUMP} -n tmp tmp-unchunked.nc > tmp-unchunked.cdl
-diff tmp.cdl tmp-unchunked.cdl
+${NCCOPY} -c // tmp-chunked.nc tmp-unchunked2.nc
+${NCDUMP} -n tmp tmp-unchunked.nc > tmp-unchunked2.cdl
+diff tmp.cdl tmp-unchunked2.cdl
 echo "*** Test that nccopy -c works as intended for record dimension default (1)"
 ${NCGEN} -b -o tst_bug321.nc $srcdir/tst_bug321.cdl
 ${NCCOPY} -k nc7 -c"lat/2,lon/2" tst_bug321.nc tmp.nc
 ${NCDUMP} -n tst_bug321 tmp.nc > tmp.cdl
 diff -b $srcdir/tst_bug321.cdl tmp.cdl
-# echo "*** Test that nccopy compression with chunking can improve compression"
-rm tst_chunking.nc tmp.nc tmp.cdl tmp-chunked.nc tmp-chunked.cdl tmp-unchunked.nc tmp-unchunked.cdl
+
+echo "*** Test that nccopy -c dim/n works as intended "
+${NCGEN} -4 -b -o tst_perdimspecs.nc $srcdir/ref_tst_perdimspecs.cdl
+${NCCOPY} -M0 -4 -c "time/10,lat/15,lon/20" tst_perdimspecs.nc tmppds.nc
+${NCDUMP} -hs tmppds.nc > tmppds.cdl
+STORAGE=`cat tmppds.cdl | sed -e '/tas:_Storage/p' -ed | tr -d '\t \r'`
+test "x$STORAGE" = 'xtas:_Storage="chunked";'
+CHUNKSIZES=`cat tmppds.cdl | sed -e '/tas:_ChunkSizes/p' -ed | tr -d '\t \r'`
+test "x$CHUNKSIZES" = 'xtas:_ChunkSizes=10,15,20;'
+
+rm -f tst_chunking.nc tmp.nc tmp.cdl tmp-chunked.nc tmp-chunked.* tmp-unchunked2.*
+rm -fr tst_perdimspecs.nc tmppds.cdl tmppds.nc
 
 echo "*** All nccopy tests passed!"
 exit 0
+


Test patch:
diff --git a/nc_test/tst_open_mem.c b/nc_test/tst_open_mem.c
index 94edfbb04..73e3e4bb3 100644
--- a/nc_test/tst_open_mem.c
+++ b/nc_test/tst_open_mem.c
@@ -19,6 +19,7 @@ See \ref copyright file for more info.
 #include "netcdf.h"
 #include "netcdf_mem.h"
 #include "ncbytes.h"
+#include "ncwinpath.h"
 #include "nc_tests.h"
 
 #ifdef USE_HDF5
@@ -30,40 +31,38 @@ static int
 readfile(const char* path, NC_memio* memio)
 {
     int status = NC_NOERR;
-    FILE* f = NULL;
-    size_t filesize = 0;
-    size_t count = 0;
+    int fd = -1;
+    off_t filesize = 0;
+    off_t count = 0;
     char* memory = NULL;
     char* p = NULL;
-
-    /* Open the file for reading */
-#ifdef _MSC_VER
-    f = fopen(path,"rb");
-#else
-    f = fopen(path,"r");
+    int oflags = O_RDONLY;
+#ifdef O_BINARY
+    oflags |= O_BINARY;
 #endif
-    if(f == NULL) {
+
+    /* Open the file to get its size*/
+    fd = NCopen2(path,oflags);
+    if(fd < 0) {
 	fprintf(stderr,"cannot open file: %s\n",path);
-	fflush(stderr);
 	status = errno;
 	goto done;
     }
     /* get current filesize */
-    if(fseek(f,0,SEEK_END) < 0)
+    filesize = lseek(fd,0,SEEK_END);
+    if(filesize < 0)
 	{status = errno; goto done;}
-    filesize = (size_t)ftell(f);
+    count = lseek(fd,0,SEEK_SET); /* rewind */
     /* allocate memory */
     memory = malloc((size_t)filesize);
     if(memory == NULL)
 	{status = NC_ENOMEM; goto done;}
-    /* move pointer back to beginning of file */
-    rewind(f);
     count = filesize;
     p = memory;
     while(count > 0) {
-        size_t actual;
-        actual = fread(p,1,count,f);
-	if(actual == 0 || ferror(f))
+        ssize_t actual;
+        actual = read(fd,p,count);
+	if(actual <= 0)
 	    {status = NC_EIO; goto done;}
 	count -= actual;
 	p += actual;
@@ -76,7 +75,7 @@ readfile(const char* path, NC_memio* memio)
 done:
     if(status != NC_NOERR && memory != NULL)
 	free(memory);
-    if(f != NULL) fclose(f);
+    if(fd  >= 0) close(fd);
     return status;
 }
 
@@ -90,10 +89,8 @@ main(int argc, char** argv)
 
     if(argc > 1)
 	path = argv[1];
-
     if((retval=readfile(path,&mem)))
 	goto exit;
-
     if((retval = nc_open_mem("mem", NC_INMEMORY|NC_NETCDF4, mem.size, mem.memory, &ncid)))
 	goto exit;
     if((retval = nc_close(ncid)))
diff --git a/nczarr_test/CMakeLists.txt b/nczarr_test/CMakeLists.txt
index fc2a00470..f9c336db7 100644
--- a/nczarr_test/CMakeLists.txt
+++ b/nczarr_test/CMakeLists.txt
@@ -34,6 +34,7 @@ IF(ENABLE_TESTS)
   BUILD_BIN_TEST(ut_chunking ${COMMONSRC})
   BUILD_BIN_TEST(tst_chunks ${COMMONSRC})
   BUILD_BIN_TEST(tst_chunks2 ${COMMONSRC})
+  BUILD_BIN_TEST(tst_chunks3 ${COMMONSRC})
 
   TARGET_INCLUDE_DIRECTORIES(ut_map PUBLIC ../libnczarr)
   TARGET_INCLUDE_DIRECTORIES(ut_mapapi PUBLIC ../libnczarr)
@@ -42,6 +43,7 @@ IF(ENABLE_TESTS)
   TARGET_INCLUDE_DIRECTORIES(ut_chunking PUBLIC ../libnczarr)
   TARGET_INCLUDE_DIRECTORIES(tst_chunks PUBLIC ../libnczarr)
   TARGET_INCLUDE_DIRECTORIES(tst_chunks2 PUBLIC ../libnczarr)
+  TARGET_INCLUDE_DIRECTORIES(tst_chunks3 PUBLIC ../libnczarr)
 
   # Helper programs for testing
   BUILD_BIN_TEST(zmapio ${COMMONSRC})
@@ -59,6 +61,7 @@ IF(ENABLE_TESTS)
     add_sh_test(nczarr_test run_ut_chunk)
     IF(USE_HDF5)
     add_sh_test(nczarr_test run_it_test1)
+    add_sh_test(nczarr_test tst_nccopyz)
     ENDIF()
     add_sh_test(nczarr_test run_it_test2)
   ENDIF(BUILD_UTILITIES)
diff --git a/nczarr_test/Makefile.am b/nczarr_test/Makefile.am
index e8b007570..a1994dca8 100644
--- a/nczarr_test/Makefile.am
+++ b/nczarr_test/Makefile.am
@@ -24,7 +24,7 @@ check_PROGRAMS =
 TESTS =
 
 # Unit Tests
-check_PROGRAMS += ut_map ut_mapapi ut_json ut_projections ut_chunking
+check_PROGRAMS += ut_map ut_mapapi ut_json ut_projections ut_chunking 
 
 commonsrc = ut_util.c ut_test.c ut_includes.h ut_test.h ut_util.h test_nczarr_utils.h
 
@@ -34,19 +34,20 @@ ut_json_SOURCES = ut_json.c ${commonsrc}
 ut_projections_SOURCES = ut_projections.c ${commonsrc}
 ut_chunking_SOURCES = ut_chunking.c ${commonsrc}
 
-# Integration Tests
-#check_PROGRAMS += it_meta
-
-check_PROGRAMS += tst_chunks tst_chunks2
+check_PROGRAMS += tst_chunks tst_chunks2 tst_chunks3
 
 TESTS += run_ut_map.sh
 TESTS += run_ut_mapapi.sh
 TESTS += run_ut_misc.sh
 TESTS += run_ut_chunk.sh
-TESTS += run_it_test2.sh
+
+if BUILD_UTILITIES
 if USE_HDF5
+TESTS += tst_nccopyz.sh
 TESTS += run_it_test1.sh
 endif
+TESTS += run_it_test2.sh
+endif
 
 ignorec = ut_allslices.c ut_transfer.c ut_vars.c ut_walk.c
 ignoresh = run_meta_tests.sh run_unittests.sh
@@ -65,7 +66,7 @@ zs3parse_SOURCES = zs3parse.c
 
 EXTRA_DIST = \
 run_ut_map.sh run_ut_mapapi.sh run_ut_misc.sh run_ut_chunk.sh run_it_test1.sh run_it_test2.sh \
-test_nczarr.sh \
+test_nczarr.sh tst_nccopyz.sh \
 ref_ut_map_readmeta_nzf.txt \
 ref_ut_map_writedata_nzf.cdl \
 ref_ut_map_writemeta_nzf.cdl \
@@ -96,11 +97,12 @@ ref_ut_mapapi_meta_nzf.cdl \
 ref_ut_mapapi_meta_s3.cdl \
 ref_ut_mapapi_search_nz4.txt \
 ref_ut_mapapi_search_nzf.txt \
-ref_ut_mapapi_search_s3.txt
+ref_ut_mapapi_search_s3.txt \
+ref_perdimspecs.cdl
 
 CLEANFILES = test.nzf test.nz4 test.nz4 tst_chunks.nc.nzf tst_chunks.nc.nz4 \
 testmap.nzf testmap.nz4 testmapapi.nzf testmapapi.nz4 \
 tst_chunks.nz4 tst_chunks.nzf tst_chunks2.nc.nz4 \
-ut_*.txt ut*.cdl
+ut_*.txt ut*.cdl tmp*.nc tmp*.cdl
 
 #tst_group_data.dmp tst_nans.dmp tst_solar_1.dmp tst_nul4.dmp dimscope.dmp
diff --git a/nczarr_test/ref_perdimspecs.cdl b/nczarr_test/ref_perdimspecs.cdl
new file mode 100644
index 000000000..e3149d3ae
--- /dev/null
+++ b/nczarr_test/ref_perdimspecs.cdl
@@ -0,0 +1,11 @@
+netcdf ref_tst_perdimspecs {
+dimensions:
+	lon = 40 ;
+	lat = 41 ;
+	time = 42;
+variables:
+	float lon(lon) ;
+	float lat(lat) ;
+	double time(time) ;
+	float tas(time, lat, lon) ;
+}
diff --git a/nczarr_test/test_nczarr_utils.h b/nczarr_test/test_nczarr_utils.h
index 57ee7c47b..b6a6589fc 100644
--- a/nczarr_test/test_nczarr_utils.h
+++ b/nczarr_test/test_nczarr_utils.h
@@ -117,7 +117,7 @@ buildpath(const char* target,NCZM_IMPL impl)
     ncbytesfree(buf);
 }
 
-static void
+void
 processoptions(int argc, char** argv, const char* base_file_name)
 {
     int c;
@@ -151,7 +151,7 @@ processoptions(int argc, char** argv, const char* base_file_name)
 
 }
 
-static void
+void
 clearoptions(void)
 {
     nullfree(itoptions.path);
diff --git a/nczarr_test/tst_chunks3.c b/nczarr_test/tst_chunks3.c
new file mode 100644
index 000000000..ae3886b11
--- /dev/null
+++ b/nczarr_test/tst_chunks3.c
@@ -0,0 +1,77 @@
+/* This is part of the netCDF package. Copyright 2018 University
+   Corporation for Atmospheric Research/Unidata.  See COPYRIGHT file for
+   conditions of use. See www.unidata.ucar.edu for more info.
+
+   Create a chunkable test file for nccopy to test chunking.
+*/
+
+#include "ut_includes.h"
+#include "test_nczarr_utils.h"
+
+#define DEBUG
+
+static int ret = NC_NOERR;
+#define FILE_NAME "tst_chunks3.nc"
+
+#define VAR_RANK 7
+#define IVAR_NAME "ivar"
+#define FVAR_NAME "fvar"
+#define NVALS 45360		/* 7 * 4 * 2 * 3 * 5 * 6 * 9 */
+
+/* Make trackable ERR macro replacement */
+static int lerr(int stat, const char* file, int lineno) {
+    fflush(stdout); /* Make sure our stdout is synced with stderr. */
+    err++;
+    fprintf(stderr, "Sorry! Unexpected result(%d), %s, line: %d\n",ret,file,lineno);
+    fflush(stderr);                                             \
+    return 2;                                                   \
+}
+#define LERR lerr(ret,__FILE__,__LINE__)
+
+static const char *dim_names[VAR_RANK] = {"dim0", "dim1", "dim2", "dim3", "dim4", "dim5", "dim6"};
+static const size_t dim_lens[VAR_RANK] = {7, 4, 2, 3, 5, 6, 9};
+
+int
+main(int argc, char** argv)
+{
+    /* file metadata */
+    int mode = NC_CLOBBER|NC_NETCDF4;
+    int ncid;
+    int ivarid, fvarid;
+    int ivar_dims[VAR_RANK];
+    int fvar_dims[VAR_RANK];
+    int ivar_data[NVALS];
+    float fvar_data[NVALS];
+    int r, i;
+    char* file_name = FILE_NAME;
+
+    printf("*** Creating chunkable test file %s...\n", file_name);
+
+    if ((ret=nc_create(FILE_NAME, mode, &ncid))) LERR;
+    for(r = 0; r < VAR_RANK; r++) {
+	if ((ret=nc_def_dim(ncid, dim_names[r], dim_lens[r], &ivar_dims[r]))) LERR;
+	fvar_dims[VAR_RANK - 1 - r] = ivar_dims[r];
+    }
+    if ((ret=nc_def_var(ncid, IVAR_NAME, NC_INT, VAR_RANK, ivar_dims, &ivarid))) LERR;
+
+    /* fvar is unchanged */
+    if ((ret=nc_def_var(ncid, FVAR_NAME, NC_FLOAT, VAR_RANK, fvar_dims, &fvarid))) LERR;
+    if ((ret=nc_enddef (ncid))) LERR;
+
+    /* Fill in the data */
+    for(i=0; i < NVALS; i++) {
+	ivar_data[i] = i;
+    }
+    if ((ret=nc_put_var(ncid, ivarid, ivar_data))) LERR;
+
+    /* fvar is unchanged */
+    for(i=0; i < NVALS; i++) {
+        fvar_data[i] = NVALS - i;
+    }
+    if ((ret=nc_put_var(ncid, fvarid, fvar_data))) LERR;
+
+    if ((ret=nc_close(ncid))) LERR;
+
+    SUMMARIZE_ERR;
+
+}
diff --git a/nczarr_test/tst_nccopyz.sh b/nczarr_test/tst_nccopyz.sh
new file mode 100755
index 000000000..6d15b49c5
--- /dev/null
+++ b/nczarr_test/tst_nccopyz.sh
@@ -0,0 +1,68 @@
+#!/bin/sh
+
+if test "x$srcdir" = x ; then srcdir=`pwd`; fi
+. ../test_common.sh
+
+set -e
+echo ""
+
+#chunkclean src dst
+chunkclean() {
+    rm -f ./$2
+    cat ./$1 | sed -e '/:_Storage/d' | sed -e '/:_ChunkSizes/d' > ./$2
+}
+
+#verifychunking cdl-file  <chunkspec>...
+verifychunking() {
+  f=$1
+  shift
+  for t in "$@" ; do
+    x=`cat $f | tr -d '\t \r' | sed -e "/$t/p" -ed`
+    if test "x$x" = x ; then echo "$f: $t not found"; exit 1; fi
+  done
+}
+
+./tst_chunks3 -e nzf
+echo "*** Test that nccopy -c can chunk files"
+${NCCOPY} -M0 tst_chunks3.nc 'file://tmp.nzf#mode=nczarr,nzf'
+${NCDUMP} -n tmp -sh 'file://tmp.nzf#mode=nczarr,nzf' > tmp.cdl
+verifychunking tmp.cdl 'ivar:_ChunkSizes=7,4,2,3,5,6,9;' 'fvar:_ChunkSizes=9,6,5,3,2,4,7;'
+
+${NCCOPY} -M0 -c dim0/,dim1/1,dim2/,dim3/1,dim4/,dim5/1,dim6/ tst_chunks3.nc 'file://tmp_chunked.nzf#mode=nczarr,nzf'
+${NCDUMP} -sh -n tmp 'file://tmp_chunked.nzf#mode=nczarr,nzf' > tmp_chunked.cdl
+verifychunking tmp_chunked.cdl 'ivar:_ChunkSizes=7,1,2,1,5,1,9;' 'fvar:_ChunkSizes=9,1,5,1,2,1,7;'
+chunkclean tmp.cdl tmpx.cdl
+chunkclean tmp_chunked.cdl tmp_chunkedx.cdl 
+diff tmpx.cdl tmp_chunkedx.cdl
+
+# Note that unchunked means that there is only one chunk
+${NCCOPY} -M0 -c dim0/,dim1/,dim2/,dim3/,dim4/,dim5/,dim6/ 'file://tmp_chunked.nzf#mode=nczarr,nzf' 'file://tmp_unchunked.nzf#mode=nczarr,nzf'
+${NCDUMP} -sh -n tmp 'file://tmp_unchunked.nzf#mode=nczarr,nzf' > tmp_unchunked.cdl
+verifychunking tmp_unchunked.cdl 'ivar:_ChunkSizes=7,4,2,3,5,6,9;' 'fvar:_ChunkSizes=9,6,5,3,2,4,7;'
+chunkclean tmp_unchunked.cdl tmp_unchunkedx.cdl 
+diff tmpx.cdl tmp_unchunkedx.cdl
+
+# Test -c /
+${NCCOPY} -M0 -c '/' 'file://tmp_chunked.nzf#mode=nczarr,nzf' 'file://tmp_unchunked2.nzf#mode=nczarr,nzf'
+${NCDUMP} -sh -n tmp 'file://tmp_unchunked2.nzf#mode=nczarr,nzf' > tmp_unchunked2.cdl
+verifychunking tmp_unchunked.cdl 'ivar:_ChunkSizes=7,4,2,3,5,6,9;' 'fvar:_ChunkSizes=9,6,5,3,2,4,7;'
+chunkclean tmp_unchunked.cdl tmp_unchunkedx.cdl 
+diff tmpx.cdl tmp_unchunkedx.cdl
+
+echo "*** Test that nccopy -c dim/n is used "
+${NCGEN} -4 -b -o 'file://tst_perdimspecs.nzf#mode=nczarr,nzf' $srcdir/ref_perdimspecs.cdl
+${NCDUMP} -n tmp_perdimspecs -hs 'file://tst_perdimspecs.nzf#mode=nczarr,nzf' > tmp_perdimspecs.cdl
+${NCCOPY} -M0 -4 -c "time/10,lat/15,lon/20" 'file://tst_perdimspecs.nzf#mode=nczarr,nzf' 'file://tmppds.nzf#mode=nczarr,nzf'
+${NCDUMP} -n tmppds -hs 'file://tmppds.nzf#mode=nczarr,nzf' > tmppds.cdl
+STORAGE=`cat tmppds.cdl | sed -e '/tas:_Storage/p' -ed | tr -d '\t \r'`
+test "x$STORAGE" = 'xtas:_Storage="chunked";'
+CHUNKSIZES=`cat tmppds.cdl | sed -e '/tas:_ChunkSizes/p' -ed | tr -d '\t \r'`
+test "x$CHUNKSIZES" = 'xtas:_ChunkSizes=10,15,20;'
+
+# Cleanup
+rm -f tmp*.nc tmp*.cdl
+rm -fr tmp*.nzf
+
+echo "*** All nccopy nczarr tests passed!"
+exit 0
+