/src/netcdf-c/libnczarr/zinternal.c
| Line | Count | Source | 
| 1 |  | /* Copyright 2003-2018, University Corporation for Atmospheric | 
| 2 |  |  * Research. See the COPYRIGHT file for copying and redistribution | 
| 3 |  |  * conditions. | 
| 4 |  |  */ | 
| 5 |  |  | 
| 6 |  | /** | 
| 7 |  |  * @file @internal Internal netcdf-4 functions. | 
| 8 |  |  * | 
| 9 |  |  * This file contains functions internal to the netcdf4 library. None of | 
| 10 |  |  * the functions in this file are exposed in the exetnal API. These | 
| 11 |  |  * functions all relate to the manipulation of netcdf-4's in-memory | 
| 12 |  |  * buffer of metadata information, i.e. the linked list of NC | 
| 13 |  |  * structs. | 
| 14 |  |  * | 
| 15 |  |  * @author Dennis Heimbigner, Ed Hartnett | 
| 16 |  |  */ | 
| 17 |  |  | 
| 18 |  | #include "zincludes.h" | 
| 19 |  | #include "zfilter.h" | 
| 20 |  |  | 
| 21 |  | /* Forward */ | 
| 22 |  |  | 
| 23 |  | #ifdef LOGGING | 
| 24 |  | /* This is the severity level of messages which will be logged. Use | 
| 25 |  |    severity 0 for errors, 1 for important log messages, 2 for less | 
| 26 |  |    important, etc. */ | 
| 27 |  | extern int nc_log_level; | 
| 28 |  | #endif /* LOGGING */ | 
| 29 |  |  | 
| 30 |  | #ifdef LOOK | 
| 31 |  | /** | 
| 32 |  |  * @internal Provide a wrapper for H5Eset_auto | 
| 33 |  |  * @param func Pointer to func. | 
| 34 |  |  * @param client_data Client data. | 
| 35 |  |  * | 
| 36 |  |  * @return 0 for success | 
| 37 |  |  */ | 
| 38 |  | static herr_t | 
| 39 |  | set_auto(void* func, void *client_data) | 
| 40 |  | { | 
| 41 |  | #ifdef DEBUGH5 | 
| 42 |  |     return H5Eset_auto2(H5E_DEFAULT,(H5E_auto2_t)h5catch,client_data); | 
| 43 |  | #else | 
| 44 |  |     return H5Eset_auto2(H5E_DEFAULT,(H5E_auto2_t)func,client_data); | 
| 45 |  | #endif | 
| 46 |  | } | 
| 47 |  | #endif | 
| 48 |  |  | 
| 49 |  | /** | 
| 50 |  |  * @internal Provide a function to do any necessary initialization of | 
| 51 |  |  * the ZARR library. | 
| 52 |  |  */ | 
| 53 |  | int | 
| 54 |  | NCZ_initialize_internal(void) | 
| 55 | 1 | { | 
| 56 | 1 |     int stat = NC_NOERR; | 
| 57 | 1 |     char* dimsep = NULL; | 
| 58 | 1 |     NCglobalstate* ngs = NULL; | 
| 59 |  |  | 
| 60 | 1 |     ncz_initialized = 1; | 
| 61 | 1 |     ngs = NC_getglobalstate(); | 
| 62 | 1 |     if(ngs != NULL) { | 
| 63 |  |         /* Defaults */ | 
| 64 | 1 |   ngs->zarr.dimension_separator = DFALT_DIM_SEPARATOR; | 
| 65 | 1 |         dimsep = NC_rclookup("ZARR.DIMENSION_SEPARATOR",NULL,NULL); | 
| 66 | 1 |         if(dimsep != NULL) { | 
| 67 |  |             /* Verify its value */ | 
| 68 | 0 |       if(dimsep != NULL && strlen(dimsep) == 1 && islegaldimsep(dimsep[0])) | 
| 69 | 0 |     ngs->zarr.dimension_separator = dimsep[0]; | 
| 70 | 0 |         }     | 
| 71 | 1 |     } | 
| 72 |  |  | 
| 73 | 1 |     return stat; | 
| 74 | 1 | } | 
| 75 |  |  | 
| 76 |  | /** | 
| 77 |  |  * @internal Provide a function to do any necessary finalization of | 
| 78 |  |  * the ZARR library. | 
| 79 |  |  */ | 
| 80 |  | int | 
| 81 |  | NCZ_finalize_internal(void) | 
| 82 | 1 | { | 
| 83 |  |     /* Reclaim global resources */ | 
| 84 | 1 |     ncz_initialized = 0; | 
| 85 |  | #ifdef NETCDF_ENABLE_NCZARR_FILTERS | 
| 86 |  |     NCZ_filter_finalize(); | 
| 87 |  | #endif | 
| 88 |  | #ifdef NETCDF_ENABLE_S3 | 
| 89 |  |     NCZ_s3finalize(); | 
| 90 |  | #endif | 
| 91 | 1 |     return NC_NOERR; | 
| 92 | 1 | } | 
| 93 |  |  | 
| 94 |  | /** | 
| 95 |  |  * @internal Given a varid, return the maximum length of a dimension | 
| 96 |  |  * using dimid. | 
| 97 |  |  * | 
| 98 |  |  * @param grp Pointer to group info struct. | 
| 99 |  |  * @param varid Variable ID. | 
| 100 |  |  * @param dimid Dimension ID. | 
| 101 |  |  * @param maxlen Pointer that gets the max length. | 
| 102 |  |  * | 
| 103 |  |  * @return ::NC_NOERR No error. | 
| 104 |  |  * @author Dennis Heimbigner, Ed Hartnett | 
| 105 |  |  */ | 
| 106 |  | static int | 
| 107 |  | find_var_dim_max_length(NC_GRP_INFO_T *grp, int varid, int dimid, | 
| 108 |  |                         size_t *maxlen) | 
| 109 | 0 | { | 
| 110 | 0 |     NC_VAR_INFO_T *var; | 
| 111 | 0 |     int retval = NC_NOERR; | 
| 112 |  | 
 | 
| 113 | 0 |     *maxlen = 0; | 
| 114 |  |  | 
| 115 |  |     /* Find this var. */ | 
| 116 | 0 |     var = (NC_VAR_INFO_T*)ncindexith(grp->vars,(size_t)varid); | 
| 117 | 0 |     if (!var) return NC_ENOTVAR; | 
| 118 | 0 |     assert(var->hdr.id == varid); | 
| 119 |  |  | 
| 120 |  |     /* If the var hasn't been created yet, its size is 0. */ | 
| 121 | 0 |     if (!var->created) | 
| 122 | 0 |     { | 
| 123 | 0 |         *maxlen = 0; | 
| 124 | 0 |     } | 
| 125 | 0 |     else | 
| 126 | 0 |     { | 
| 127 |  |         /* Get the number of records in the dataset. */ | 
| 128 |  | #ifdef LOOK | 
| 129 |  | #if 0 | 
| 130 |  | not needed        if ((retval = ncz_open_var_grp2(grp, var->hdr.id, &datasetid))) | 
| 131 |  |             BAIL(retval); | 
| 132 |  | #endif | 
| 133 |  |         if ((spaceid = H5Dget_space(datasetid)) < 0) | 
| 134 |  |             BAIL(NC_EHDFERR); | 
| 135 |  |         /* If it's a scalar dataset, it has length one. */ | 
| 136 |  |         if (H5Sget_simple_extent_type(spaceid) == H5S_SCALAR) | 
| 137 |  |         { | 
| 138 |  |             *maxlen = (var->dimids && var->dimids[0] == dimid) ? 1 : 0; | 
| 139 |  |         } | 
| 140 |  |         else | 
| 141 |  |         { | 
| 142 |  |             /* Check to make sure ndims is right, then get the len of each | 
| 143 |  |                dim in the space. */ | 
| 144 |  |             if ((dataset_ndims = H5Sget_simple_extent_ndims(spaceid)) < 0) | 
| 145 |  |                 BAIL(NC_EHDFERR); | 
| 146 |  |             if (dataset_ndims != var->ndims) | 
| 147 |  |                 BAIL(NC_EHDFERR); | 
| 148 |  |             if (!(h5dimlen = malloc(dataset_ndims * sizeof(hsize_t)))) | 
| 149 |  |                 BAIL(NC_ENOMEM); | 
| 150 |  |             if (!(h5dimlenmax = malloc(dataset_ndims * sizeof(hsize_t)))) | 
| 151 |  |                 BAIL(NC_ENOMEM); | 
| 152 |  |             if ((dataset_ndims = H5Sget_simple_extent_dims(spaceid, | 
| 153 |  |                                                            h5dimlen, h5dimlenmax)) < 0) | 
| 154 |  |                 BAIL(NC_EHDFERR); | 
| 155 |  |             LOG((5, "find_var_dim_max_length: varid %d len %d max: %d", | 
| 156 |  |                  varid, (int)h5dimlen[0], (int)h5dimlenmax[0])); | 
| 157 |  |             for (d=0; d<dataset_ndims; d++) { | 
| 158 |  |                 if (var->dimids[d] == dimid) { | 
| 159 |  |                     *maxlen = *maxlen > h5dimlen[d] ? *maxlen : h5dimlen[d]; | 
| 160 |  |                 } | 
| 161 |  |             } | 
| 162 |  |         } | 
| 163 |  | #endif /*LOOK*/ | 
| 164 | 0 |     } | 
| 165 |  | 
 | 
| 166 |  | #ifdef LOOK | 
| 167 |  | exit: | 
| 168 |  |     if (spaceid > 0 && H5Sclose(spaceid) < 0) | 
| 169 |  |         BAIL2(NC_EHDFERR); | 
| 170 |  |     if (h5dimlen) free(h5dimlen); | 
| 171 |  |     if (h5dimlenmax) free(h5dimlenmax); | 
| 172 |  | #endif | 
| 173 | 0 |     return retval; | 
| 174 | 0 | } | 
| 175 |  |  | 
| 176 |  | #ifdef LOOK | 
| 177 |  | /** | 
| 178 |  |  * @internal Search for type with a given HDF type id. | 
| 179 |  |  * | 
| 180 |  |  * @param h5 File | 
| 181 |  |  * @param target_hdf_typeid ZARR type ID to find. | 
| 182 |  |  * | 
| 183 |  |  * @return Pointer to type info struct, or NULL if not found. | 
| 184 |  |  * @author Dennis Heimbigner, Ed Hartnett | 
| 185 |  |  */ | 
| 186 |  | NC_TYPE_INFO_T * | 
| 187 |  | ncz_rec_find_hdf_type(NC_FILE_INFO_T *h5, hid_t target_hdf_typeid) | 
| 188 |  | { | 
| 189 |  |     NC_TYPE_INFO_T *type; | 
| 190 |  |     int i; | 
| 191 |  |  | 
| 192 |  |     assert(h5); | 
| 193 |  |  | 
| 194 |  |     for (i = 0; i < nclistlength(h5->alltypes); i++) | 
| 195 |  |     { | 
| 196 |  |         type = (NC_TYPE_INFO_T*)nclistget(h5->alltypes, i); | 
| 197 |  |         if(type == NULL) continue; | 
| 198 |  |  | 
| 199 |  | #ifdef LOOK | 
| 200 |  |         /* Select the ZARR typeid to use. */ | 
| 201 |  |         hdf_typeid = ncz_type->native_hdf_typeid ? | 
| 202 |  |             ncz_type->native_hdf_typeid : ncz_type->hdf_typeid; | 
| 203 |  |  | 
| 204 |  |         /* Is this the type we are searching for? */ | 
| 205 |  |         if ((equal = H5Tequal(hdf_typeid, target_hdf_typeid)) < 0) | 
| 206 |  |             return NULL; | 
| 207 |  |         if (equal) | 
| 208 |  |             return type; | 
| 209 |  | #endif | 
| 210 |  |     } | 
| 211 |  |     /* Can't find it. Fate, why do you mock me? */ | 
| 212 |  |     return NULL; | 
| 213 |  | } | 
| 214 |  | #endif | 
| 215 |  |  | 
| 216 |  | /** | 
| 217 |  |  * @internal Find the actual length of a dim by checking the length of | 
| 218 |  |  * that dim in all variables that use it, in grp or children. **len | 
| 219 |  |  * must be initialized to zero before this function is called. | 
| 220 |  |  * | 
| 221 |  |  * @param grp Pointer to group info struct. | 
| 222 |  |  * @param dimid Dimension ID. | 
| 223 |  |  * @param len Pointer to pointer that gets length. | 
| 224 |  |  * | 
| 225 |  |  * @return ::NC_NOERR No error. | 
| 226 |  |  * @author Dennis Heimbigner, Ed Hartnett | 
| 227 |  |  */ | 
| 228 |  | int | 
| 229 |  | ncz_find_dim_len(NC_GRP_INFO_T *grp, int dimid, size_t **len) | 
| 230 | 0 | { | 
| 231 | 0 |     NC_VAR_INFO_T *var; | 
| 232 | 0 |     int retval; | 
| 233 | 0 |     size_t i; | 
| 234 |  | 
 | 
| 235 | 0 |     assert(grp && len); | 
| 236 | 0 |     LOG((3, "%s: grp->name %s dimid %d", __func__, grp->hdr.name, dimid)); | 
| 237 |  |  | 
| 238 |  |     /* If there are any groups, call this function recursively on | 
| 239 |  |      * them. */ | 
| 240 | 0 |     for (i = 0; i < ncindexsize(grp->children); i++) { | 
| 241 | 0 |         if ((retval = ncz_find_dim_len((NC_GRP_INFO_T*)ncindexith(grp->children, i), | 
| 242 | 0 |                                        dimid, len))) | 
| 243 | 0 |             return retval; | 
| 244 | 0 |     } | 
| 245 |  |     /* For all variables in this group, find the ones that use this | 
| 246 |  |      * dimension, and remember the max length. */ | 
| 247 | 0 |     for (i = 0; i < ncindexsize(grp->vars); i++) | 
| 248 | 0 |     { | 
| 249 | 0 |         size_t mylen; | 
| 250 | 0 |         var = (NC_VAR_INFO_T *)ncindexith(grp->vars, i); | 
| 251 | 0 |         assert(var); | 
| 252 |  |  | 
| 253 |  |         /* Find max length of dim in this variable... */ | 
| 254 | 0 |         if ((retval = find_var_dim_max_length(grp, var->hdr.id, dimid, &mylen))) | 
| 255 | 0 |             return retval; | 
| 256 |  |  | 
| 257 | 0 |         **len = **len > mylen ? **len : mylen; | 
| 258 | 0 |     } | 
| 259 |  |  | 
| 260 | 0 |     return NC_NOERR; | 
| 261 | 0 | } | 
| 262 |  |  | 
| 263 |  | #if 0 | 
| 264 |  | /** | 
| 265 |  |  * @internal Close ZARR resources for global atts in a group. | 
| 266 |  |  * | 
| 267 |  |  * @param grp Pointer to group info struct. | 
| 268 |  |  * | 
| 269 |  |  * @return ::NC_NOERR No error. | 
| 270 |  |  * @return ::NC_EHDFERR ZARR error. | 
| 271 |  |  * @author Dennis Heimbigner, Ed Hartnett | 
| 272 |  |  */ | 
| 273 |  |  | 
| 274 |  | static int | 
| 275 |  | close_gatts(NC_GRP_INFO_T *grp) | 
| 276 |  | { | 
| 277 |  |     NC_ATT_INFO_T *att; | 
| 278 |  |     int a; | 
| 279 |  |  | 
| 280 |  |     for (a = 0; a < ncindexsize(grp->att); a++) | 
| 281 |  |     { | 
| 282 |  |         att = (NC_ATT_INFO_T *)ncindexith(grp->att, a); | 
| 283 |  |         assert(att && att->format_att_info); | 
| 284 |  |  | 
| 285 |  | #ifdef LOOK | 
| 286 |  |         /* Close the ZARR typeid. */ | 
| 287 |  |         if (ncz_att->native_hdf_typeid && | 
| 288 |  |             H5Tclose(ncz_att->native_hdf_typeid) < 0) | 
| 289 |  |             return NC_EHDFERR; | 
| 290 |  | #endif | 
| 291 |  |     } | 
| 292 |  |     return NC_NOERR; | 
| 293 |  | } | 
| 294 |  | #endif /*0*/ | 
| 295 |  |  | 
| 296 |  | #if 0 | 
| 297 |  | /** | 
| 298 |  |  * @internal Close ZARR resources for vars in a group. | 
| 299 |  |  * | 
| 300 |  |  * @param grp Pointer to group info struct. | 
| 301 |  |  * | 
| 302 |  |  * @return ::NC_NOERR No error. | 
| 303 |  |  * @return ::NC_EHDFERR ZARR error. | 
| 304 |  |  * @author Dennis Heimbigner, Ed Hartnett | 
| 305 |  |  */ | 
| 306 |  | static int | 
| 307 |  | close_vars(NC_GRP_INFO_T *grp) | 
| 308 |  | { | 
| 309 |  |     NC_VAR_INFO_T *var; | 
| 310 |  |     NC_ATT_INFO_T *att; | 
| 311 |  |     int a, i; | 
| 312 |  |  | 
| 313 |  |     for (i = 0; i < ncindexsize(grp->vars); i++) | 
| 314 |  |     { | 
| 315 |  |         var = (NC_VAR_INFO_T *)ncindexith(grp->vars, i); | 
| 316 |  |         assert(var && var->format_var_info); | 
| 317 |  |  | 
| 318 |  |         /* Close the ZARR dataset associated with this var. */ | 
| 319 |  | #ifdef LOOK | 
| 320 |  |         if (ncz_var->hdf_datasetid) | 
| 321 |  | #endif | 
| 322 |  |         { | 
| 323 |  | #ifdef LOOK | 
| 324 |  |             LOG((3, "closing ZARR dataset %lld", ncz_var->hdf_datasetid)); | 
| 325 |  |             if (H5Dclose(ncz_var->hdf_datasetid) < 0) | 
| 326 |  |                 return NC_EHDFERR; | 
| 327 |  | #endif | 
| 328 |  |             if (var->fill_value) | 
| 329 |  |             { | 
| 330 |  |                 if (var->type_info) | 
| 331 |  |                 { | 
| 332 |  |         int stat = NC_NOERR; | 
| 333 |  |         if((stat = NC_reclaim_data(grp->nc4_info,var->type_info->hdr.id,var->fill_value,1))) | 
| 334 |  |             return stat; | 
| 335 |  |         nullfree(var->fill_value); | 
| 336 |  |                 } | 
| 337 |  |             } | 
| 338 |  |         } | 
| 339 |  |  | 
| 340 |  | #ifdef LOOK | 
| 341 |  |         /* Delete any ZARR dimscale objid information. */ | 
| 342 |  |         if (ncz_var->dimscale_ncz_objids) | 
| 343 |  |             free(ncz_var->dimscale_ncz_objids); | 
| 344 |  | #endif | 
| 345 |  |  | 
| 346 |  |         for (a = 0; a < ncindexsize(var->att); a++) | 
| 347 |  |         { | 
| 348 |  |             att = (NC_ATT_INFO_T *)ncindexith(var->att, a); | 
| 349 |  |             assert(att && att->format_att_info); | 
| 350 |  |  | 
| 351 |  | #ifdef LOOK | 
| 352 |  |             /* Close the ZARR typeid if one is open. */ | 
| 353 |  |             if (ncz_att->native_hdf_typeid && | 
| 354 |  |                 H5Tclose(ncz_att->native_hdf_typeid) < 0) | 
| 355 |  |                 return NC_EHDFERR; | 
| 356 |  | #endif | 
| 357 |  |         } | 
| 358 |  |  | 
| 359 |  |   /* Reclaim filters */ | 
| 360 |  |   if(var->filters != NULL) { | 
| 361 |  |       (void)NCZ_filter_freelists(var); | 
| 362 |  |   } | 
| 363 |  |   var->filters = NULL; | 
| 364 |  |  | 
| 365 |  |     } | 
| 366 |  |  | 
| 367 |  |     return NC_NOERR; | 
| 368 |  | } | 
| 369 |  | #endif /*0*/ | 
| 370 |  |  | 
| 371 |  | #if 0 | 
| 372 |  | /** | 
| 373 |  |  * @internal Close ZARR resources for dims in a group. | 
| 374 |  |  * | 
| 375 |  |  * @param grp Pointer to group info struct. | 
| 376 |  |  * | 
| 377 |  |  * @return ::NC_NOERR No error. | 
| 378 |  |  * @return ::NC_EHDFERR ZARR error. | 
| 379 |  |  * @author Dennis Heimbigner, Ed Hartnett | 
| 380 |  |  */ | 
| 381 |  | static int | 
| 382 |  | close_dims(NC_GRP_INFO_T *grp) | 
| 383 |  | { | 
| 384 |  |     NC_DIM_INFO_T *dim; | 
| 385 |  |     size_t i; | 
| 386 |  |  | 
| 387 |  |     for (i = 0; i < ncindexsize(grp->dim); i++) | 
| 388 |  |     { | 
| 389 |  |         dim = (NC_DIM_INFO_T *)ncindexith(grp->dim, i); | 
| 390 |  |         assert(dim && dim->format_dim_info); | 
| 391 |  |  | 
| 392 |  | #ifdef LOOK | 
| 393 |  |         /* If this is a dim without a coordinate variable, then close | 
| 394 |  |          * the ZARR DIM_WITHOUT_VARIABLE dataset associated with this | 
| 395 |  |          * dim. */ | 
| 396 |  |         if (ncz_dim->hdf_dimscaleid && H5Dclose(ncz_dim->hdf_dimscaleid) < 0) | 
| 397 |  |             return NC_EHDFERR; | 
| 398 |  | #endif | 
| 399 |  |     } | 
| 400 |  |  | 
| 401 |  |     return NC_NOERR; | 
| 402 |  | } | 
| 403 |  | #endif /*0*/ | 
| 404 |  |  | 
| 405 |  | #if 0 | 
| 406 |  | /** | 
| 407 |  |  * @internal Close ZARR resources for types in a group.  Set values to | 
| 408 |  |  * 0 after closing types. Because of type reference counters, these | 
| 409 |  |  * closes can be called multiple times. | 
| 410 |  |  * | 
| 411 |  |  * @param grp Pointer to group info struct. | 
| 412 |  |  * | 
| 413 |  |  * @return ::NC_NOERR No error. | 
| 414 |  |  * @return ::NC_EHDFERR ZARR error. | 
| 415 |  |  * @author Dennis Heimbigner, Ed Hartnett | 
| 416 |  |  */ | 
| 417 |  | static int | 
| 418 |  | close_types(NC_GRP_INFO_T *grp) | 
| 419 |  | { | 
| 420 |  |     size_t i; | 
| 421 |  |  | 
| 422 |  |     for (i = 0; i < ncindexsize(grp->type); i++) | 
| 423 |  |     { | 
| 424 |  |         NC_TYPE_INFO_T *type; | 
| 425 |  |  | 
| 426 |  |         type = (NC_TYPE_INFO_T *)ncindexith(grp->type, i); | 
| 427 |  |         assert(type && type->format_type_info); | 
| 428 |  |  | 
| 429 |  | #ifdef LOOK | 
| 430 |  |         /* Close any open user-defined ZARR typeids. */ | 
| 431 |  |         if (ncz_type->hdf_typeid && H5Tclose(ncz_type->hdf_typeid) < 0) | 
| 432 |  |             return NC_EHDFERR; | 
| 433 |  |         ncz_type->hdf_typeid = 0; | 
| 434 |  |         if (ncz_type->native_hdf_typeid && | 
| 435 |  |             H5Tclose(ncz_type->native_hdf_typeid) < 0) | 
| 436 |  |             return NC_EHDFERR; | 
| 437 |  |         ncz_type->native_hdf_typeid = 0; | 
| 438 |  | #endif | 
| 439 |  |     } | 
| 440 |  |  | 
| 441 |  |     return NC_NOERR; | 
| 442 |  | } | 
| 443 |  | #endif /*0*/ | 
| 444 |  |  | 
| 445 |  | #if 0 | 
| 446 |  | /** | 
| 447 |  |  * @internal Recursively free ZARR objects for a group (and everything | 
| 448 |  |  * it contains). | 
| 449 |  |  * | 
| 450 |  |  * @param grp Pointer to group info struct. | 
| 451 |  |  * | 
| 452 |  |  * @return ::NC_NOERR No error. | 
| 453 |  |  * @return ::NC_EHDFERR ZARR error. | 
| 454 |  |  * @author Dennis Heimbigner, Ed Hartnett | 
| 455 |  |  */ | 
| 456 |  | static int | 
| 457 |  | ncz_rec_grp_NCZ_del(NC_GRP_INFO_T *grp) | 
| 458 |  | { | 
| 459 |  |     size_t i; | 
| 460 |  |     int retval; | 
| 461 |  |  | 
| 462 |  |     assert(grp && grp->format_grp_info); | 
| 463 |  |     LOG((3, "%s: grp->name %s", __func__, grp->hdr.name)); | 
| 464 |  |  | 
| 465 |  |     /* Recursively call this function for each child, if any, stopping | 
| 466 |  |      * if there is an error. */ | 
| 467 |  |     for (i = 0; i < ncindexsize(grp->children); i++) | 
| 468 |  |         if ((retval = ncz_rec_grp_NCZ_del((NC_GRP_INFO_T *)ncindexith(grp->children, | 
| 469 |  |                                                                        i)))) | 
| 470 |  |             return retval; | 
| 471 |  |  | 
| 472 |  |     /* Close ZARR resources associated with global attributes. */ | 
| 473 |  |     if ((retval = close_gatts(grp))) | 
| 474 |  |         return retval; | 
| 475 |  |  | 
| 476 |  |     /* Close ZARR resources associated with vars. */ | 
| 477 |  |     if ((retval = close_vars(grp))) | 
| 478 |  |         return retval; | 
| 479 |  |  | 
| 480 |  |     /* Close ZARR resources associated with dims. */ | 
| 481 |  |     if ((retval = close_dims(grp))) | 
| 482 |  |         return retval; | 
| 483 |  |  | 
| 484 |  |     /* Close ZARR resources associated with types. */ | 
| 485 |  |     if ((retval = close_types(grp))) | 
| 486 |  |         return retval; | 
| 487 |  |  | 
| 488 |  |     /* Close the ZARR group. */ | 
| 489 |  |     LOG((4, "%s: closing group %s", __func__, grp->hdr.name)); | 
| 490 |  | #ifdef LOOK | 
| 491 |  |     if (ncz_grp->hdf_grpid && H5Gclose(ncz_grp->hdf_grpid) < 0) | 
| 492 |  |         return NC_EHDFERR; | 
| 493 |  | #endif | 
| 494 |  |  | 
| 495 |  |     return NC_NOERR; | 
| 496 |  | } | 
| 497 |  | #endif /*0*/ | 
| 498 |  |  | 
| 499 |  | /** | 
| 500 |  |  * @internal Given an ncid and varid, get pointers to the group and var | 
| 501 |  |  * metadata. Lazy var metadata reads are done as needed. | 
| 502 |  |  * | 
| 503 |  |  * @param ncid File ID. | 
| 504 |  |  * @param varid Variable ID. | 
| 505 |  |  * @param h5 Pointer that gets pointer to the NC_FILE_INFO_T struct | 
| 506 |  |  * for this file. Ignored if NULL. | 
| 507 |  |  * @param grp Pointer that gets pointer to group info. Ignored if | 
| 508 |  |  * NULL. | 
| 509 |  |  * @param var Pointer that gets pointer to var info. Ignored if NULL. | 
| 510 |  |  * | 
| 511 |  |  * @return ::NC_NOERR No error. | 
| 512 |  |  * @return ::NC_ENOTVAR Variable not found. | 
| 513 |  |  * @author Dennis Heimbigner, Ed Hartnett | 
| 514 |  |  */ | 
| 515 |  | int | 
| 516 |  | ncz_find_grp_file_var(int ncid, int varid, NC_FILE_INFO_T **h5, | 
| 517 |  |                          NC_GRP_INFO_T **grp, NC_VAR_INFO_T **var) | 
| 518 | 0 | { | 
| 519 | 0 |     NC_FILE_INFO_T *my_h5; | 
| 520 | 0 |     NC_VAR_INFO_T *my_var; | 
| 521 | 0 |     int retval; | 
| 522 |  |  | 
| 523 |  |     /* Delegate to libsrc4 */ | 
| 524 | 0 |     if((retval = nc4_find_grp_h5_var(ncid,varid,&my_h5,grp,&my_var))) return retval; | 
| 525 |  |  | 
| 526 |  |     /* Do we need to read var metadata? */ | 
| 527 | 0 |     if (!my_var->meta_read && my_var->created) | 
| 528 | 0 |         if ((retval = ncz_get_var_meta(my_h5, my_var))) | 
| 529 | 0 |             return retval; | 
| 530 | 0 |     if (var) *var = my_var; | 
| 531 | 0 |     if (h5) *h5 = my_h5; | 
| 532 | 0 |     return NC_NOERR; | 
| 533 | 0 | } | 
| 534 |  |  | 
| 535 |  | /** | 
| 536 |  |  * @internal Given an ncid, varid, and attribute name, return | 
| 537 |  |  * normalized name and (optionally) pointers to the file, group, | 
| 538 |  |  * var, and att info structs. | 
| 539 |  |  * Lazy reads of attributes and variable metadata are done as needed. | 
| 540 |  |  * | 
| 541 |  |  * @param ncid File/group ID. | 
| 542 |  |  * @param varid Variable ID. | 
| 543 |  |  * @param name Name to of attribute. | 
| 544 |  |  * @param attnum Number of attribute. | 
| 545 |  |  * @param use_name If true, use the name to get the | 
| 546 |  |  * attribute. Otherwise use the attnum. | 
| 547 |  |  * @param norm_name Pointer to storage of size NC_MAX_NAME + 1, | 
| 548 |  |  * which will get the normalized name, if use_name is true. Ignored if | 
| 549 |  |  * NULL. | 
| 550 |  |  * @param h5 Pointer to pointer that gets file info struct. Ignored if | 
| 551 |  |  * NULL. | 
| 552 |  |  * @param grp Pointer to pointer that gets group info struct. Ignored | 
| 553 |  |  * if NULL. | 
| 554 |  |  * @param h5 Pointer to pointer that gets variable info | 
| 555 |  |  * struct. Ignored if NULL. | 
| 556 |  |  * @param att Pointer to pointer that gets attribute info | 
| 557 |  |  * struct. Ignored if NULL. | 
| 558 |  |  * | 
| 559 |  |  * @return ::NC_NOERR No error. | 
| 560 |  |  * @return ::NC_EBADID Bad ncid. | 
| 561 |  |  * @return ::NC_ENOTVAR Variable not found. | 
| 562 |  |  * @return ::NC_ENOTATT Attribute not found. | 
| 563 |  |  * @author Dennis Heimbigner, Ed Hartnett | 
| 564 |  |  */ | 
| 565 |  | int | 
| 566 |  | ncz_find_grp_var_att(int ncid, int varid, const char *name, int attnum, | 
| 567 |  |                           int use_name, char *norm_name, NC_FILE_INFO_T **h5, | 
| 568 |  |                           NC_GRP_INFO_T **grp, NC_VAR_INFO_T **var, | 
| 569 |  |                           NC_ATT_INFO_T **att) | 
| 570 | 0 | { | 
| 571 | 0 |     NC_FILE_INFO_T *my_h5; | 
| 572 | 0 |     NC_GRP_INFO_T *my_grp; | 
| 573 | 0 |     NC_VAR_INFO_T *my_var = NULL; | 
| 574 | 0 |     NC_ATT_INFO_T *my_att; | 
| 575 | 0 |     char my_norm_name[NC_MAX_NAME + 1] = ""; | 
| 576 | 0 |     NCindex *attlist = NULL; | 
| 577 | 0 |     int retval; | 
| 578 |  | 
 | 
| 579 | 0 |     LOG((4, "%s: ncid %d varid %d attnum %d use_name %d", __func__, ncid, varid, | 
| 580 | 0 |          attnum, use_name)); | 
| 581 |  |  | 
| 582 |  |     /* Don't need to provide name unless getting att pointer and using | 
| 583 |  |      * use_name. */ | 
| 584 | 0 |     assert(!att || ((use_name && name) || !use_name)); | 
| 585 |  |  | 
| 586 |  |     /* Find info for this file, group, and h5 info. */ | 
| 587 | 0 |     if ((retval = nc4_find_nc_grp_h5(ncid, NULL, &my_grp, &my_h5))) | 
| 588 | 0 |         return retval; | 
| 589 | 0 |     assert(my_grp && my_h5); | 
| 590 |  |  | 
| 591 |  |     /* Read the attributes for this var, if any */ | 
| 592 | 0 |     switch (retval = ncz_getattlist(my_grp, varid, &my_var, &attlist)) { | 
| 593 | 0 |     case NC_NOERR: assert(attlist); break; | 
| 594 | 0 |     case NC_EEMPTY: retval = NC_NOERR; attlist = NULL; break; /* variable has no attributes */ | 
| 595 | 0 |     default: return retval; /* significant error */ | 
| 596 | 0 |     } | 
| 597 |  |  | 
| 598 |  |     /* Need a name if use_name is true. */ | 
| 599 | 0 |     if (use_name && !name) | 
| 600 | 0 |         return NC_EBADNAME; | 
| 601 |  |  | 
| 602 |  |     /* Normalize the name. */ | 
| 603 | 0 |     if (use_name) | 
| 604 | 0 |         if ((retval = nc4_normalize_name(name, my_norm_name))) | 
| 605 | 0 |             return retval; | 
| 606 |  |  | 
| 607 |  |     /* Now find the attribute by name or number. */ | 
| 608 | 0 |     if (att) | 
| 609 | 0 |     { | 
| 610 | 0 |         my_att = use_name ? (NC_ATT_INFO_T *)ncindexlookup(attlist, my_norm_name) : | 
| 611 | 0 |             (NC_ATT_INFO_T *)ncindexith(attlist, (size_t)attnum); | 
| 612 | 0 |         if (!my_att) | 
| 613 | 0 |             return NC_ENOTATT; | 
| 614 | 0 |     } | 
| 615 |  |  | 
| 616 |  |     /* Give the people what they want. */ | 
| 617 | 0 |     if (norm_name) | 
| 618 | 0 |         strncpy(norm_name, my_norm_name, NC_MAX_NAME); | 
| 619 | 0 |     if (h5) | 
| 620 | 0 |         *h5 = my_h5; | 
| 621 | 0 |     if (grp) | 
| 622 | 0 |         *grp = my_grp; | 
| 623 | 0 |     if (var) | 
| 624 | 0 |         *var = my_var; | 
| 625 | 0 |     if (att) | 
| 626 | 0 |         *att = my_att; | 
| 627 |  | 
 | 
| 628 | 0 |     return retval; | 
| 629 | 0 | } | 
| 630 |  |  | 
| 631 |  | /** | 
| 632 |  |  * @internal Ensure that either var->no_fill || var->fill_value != NULL. | 
| 633 |  |  * Side effects: set as default if necessary and build _FillValue attribute. | 
| 634 |  |  * | 
| 635 |  |  * @param h5 Pointer to file info struct. | 
| 636 |  |  * @param var Pointer to variable info struct. | 
| 637 |  |  * | 
| 638 |  |  * @returns NC_NOERR No error. | 
| 639 |  |  * @returns NC_ENOMEM Out of memory. | 
| 640 |  |  * @author Ed Hartnett, Dennis Heimbigner | 
| 641 |  |  */ | 
| 642 |  | int | 
| 643 |  | NCZ_ensure_fill_value(NC_VAR_INFO_T *var) | 
| 644 | 0 | { | 
| 645 | 0 |     size_t size; | 
| 646 | 0 |     int retval = NC_NOERR; | 
| 647 | 0 |     NC_FILE_INFO_T *h5 = var->container->nc4_info; | 
| 648 |  | 
 | 
| 649 | 0 |     if(var->no_fill) | 
| 650 | 0 |         return NC_NOERR; | 
| 651 |  |  | 
| 652 |  | #if 0 /*LOOK*/ | 
| 653 |  |     /* Find out how much space we need for this type's fill value. */ | 
| 654 |  |     if (var->type_info->nc_type_class == NC_VLEN) | 
| 655 |  |         size = sizeof(nc_vlen_t); | 
| 656 |  |     else if (var->type_info->nc_type_class == NC_STRING) | 
| 657 |  |         size = sizeof(char *); | 
| 658 |  |     else | 
| 659 |  | #endif | 
| 660 |  |  | 
| 661 | 0 |     if ((retval = nc4_get_typelen_mem(h5, var->type_info->hdr.id, &size))) goto done; | 
| 662 | 0 |     assert(size); | 
| 663 |  |  | 
| 664 |  |     /* If the user has set a fill_value for this var, use, otherwise find the default fill value. */ | 
| 665 |  | 
 | 
| 666 | 0 |     if (var->fill_value == NULL) { | 
| 667 |  |   /* initialize the fill_value to the default */ | 
| 668 |  |   /* Allocate the fill_value space. */ | 
| 669 | 0 |         if((var->fill_value = calloc(1, size))==NULL) | 
| 670 | 0 |       {retval = NC_ENOMEM; goto done;} | 
| 671 | 0 |         if((retval = nc4_get_default_fill_value(var->type_info, var->fill_value))) { | 
| 672 |  |             /* Note: release memory, but don't return error on failure */ | 
| 673 | 0 |       (void)NCZ_reclaim_fill_value(var); | 
| 674 | 0 |       retval = NC_NOERR; | 
| 675 | 0 |       goto done; | 
| 676 | 0 |         } | 
| 677 | 0 |     } | 
| 678 | 0 |     assert(var->fill_value != NULL); | 
| 679 |  | 
 | 
| 680 | 0 |     LOG((4, "Found a fill value for var %s", var->hdr.name)); | 
| 681 |  | #if 0 /*LOOK*/ | 
| 682 |  |   /* Need to copy both vlen and a single basetype */ | 
| 683 |  |         if (var->type_info->nc_type_class == NC_VLEN) | 
| 684 |  |         { | 
| 685 |  |             nc_vlen_t *in_vlen = (nc_vlen_t *)(var->fill_value); | 
| 686 |  |       nc_vlen-t *fv_vlen = (nc_vlen_t *)fill; | 
| 687 |  |             size_t basetypesize = 0; | 
| 688 |  |  | 
| 689 |  |             if((retval=nc4_get_typelen_mem(h5, var->type_info->u.v.base_nc_typeid, &basetypesize))) | 
| 690 |  |                 return retval; | 
| 691 |  |  | 
| 692 |  |             fv_vlen->len = in_vlen->len; | 
| 693 |  |             if (!(fv_vlen->p = malloc(basetypesize * in_vlen->len))) | 
| 694 |  |             { | 
| 695 |  |                 free(*fillp); | 
| 696 |  |                 *fillp = NULL; | 
| 697 |  |                 return NC_ENOMEM; | 
| 698 |  |             } | 
| 699 |  |             memcpy(fv_vlen->p, in_vlen->p, in_vlen->len * basetypesize); | 
| 700 |  |         } | 
| 701 |  |         else if (var->type_info->nc_type_class == NC_STRING) | 
| 702 |  |         { | 
| 703 |  |             if (*(char **)var->fill_value) | 
| 704 |  |                 if (!(**(char ***)fillp = strdup(*(char **)var->fill_value))) | 
| 705 |  |                 { | 
| 706 |  |                     free(*fillp); | 
| 707 |  |                     *fillp = NULL; | 
| 708 |  |                     return NC_ENOMEM; | 
| 709 |  |                 } | 
| 710 |  |         } | 
| 711 |  | #endif /*0*/ | 
| 712 | 0 | done: | 
| 713 | 0 |     return retval; | 
| 714 | 0 | } | 
| 715 |  |  | 
| 716 |  | #ifdef LOGGING | 
| 717 |  | /* We will need to check against nc log level from nc4internal.c. */ | 
| 718 |  | extern int nc_log_level; | 
| 719 |  |  | 
| 720 |  | /** | 
| 721 |  |  * @internal This is like nc_set_log_level(), but will also turn on | 
| 722 |  |  * ZARR internal logging, in addition to netCDF logging. This should | 
| 723 |  |  * never be called by the user. It is called in open/create when the | 
| 724 |  |  * nc logging level has changed. | 
| 725 |  |  * | 
| 726 |  |  * @return ::NC_NOERR No error. | 
| 727 |  |  * @author Dennis Heimbigner, Ed Hartnett | 
| 728 |  |  */ | 
| 729 |  | int | 
| 730 |  | NCZ_set_log_level() | 
| 731 |  | { | 
| 732 |  |     /* If the user wants to completely turn off logging, turn off NCZ | 
| 733 |  |        logging too. Now I truely can't think of what to do if this | 
| 734 |  |        fails, so just ignore the return code. */ | 
| 735 |  |     if (nc_log_level == NC_TURN_OFF_LOGGING) | 
| 736 |  |     { | 
| 737 |  | #ifdef LOOK | 
| 738 |  |         set_auto(NULL, NULL); | 
| 739 |  | #endif | 
| 740 |  |         LOG((1, "NCZ error messages turned off!")); | 
| 741 |  |     } | 
| 742 |  |     else | 
| 743 |  |     { | 
| 744 |  | #ifdef LOOK | 
| 745 |  |         if (set_auto((H5E_auto_t)&H5Eprint1, stderr) < 0) | 
| 746 |  |             LOG((0, "H5Eset_auto failed!")); | 
| 747 |  | #endif | 
| 748 |  |         LOG((1, "NCZ error messages turned on.")); | 
| 749 |  |     } | 
| 750 |  |  | 
| 751 |  |     return NC_NOERR; | 
| 752 |  | } | 
| 753 |  | #endif /* LOGGING */ | 
| 754 |  |  | 
| 755 |  | /** | 
| 756 |  |  * @internal Get the format (i.e. NC_FORMAT_NETCDF4 pr | 
| 757 |  |  * NC_FORMAT_NETCDF4_CLASSIC) of an open netCDF-4 file. | 
| 758 |  |  * | 
| 759 |  |  * @param ncid File ID (ignored). | 
| 760 |  |  * @param formatp Pointer that gets the constant indicating format. | 
| 761 |  |  | 
| 762 |  |  * @return ::NC_NOERR No error. | 
| 763 |  |  * @return ::NC_EBADID Bad ncid. | 
| 764 |  |  * @author Ed Hartnett | 
| 765 |  |  */ | 
| 766 |  | int | 
| 767 |  | NCZ_inq_format(int ncid, int *formatp) | 
| 768 | 0 | { | 
| 769 | 0 |     int stat = NC_NOERR; | 
| 770 |  | 
 | 
| 771 | 0 |     ZTRACE(0,"ncid=%d formatp=%p",ncid,formatp); | 
| 772 | 0 |     stat = NC4_inq_format(ncid,formatp); | 
| 773 | 0 |     return ZUNTRACEX(stat,"formatp=%d",(formatp?-1:*formatp)); | 
| 774 | 0 | } | 
| 775 |  |  | 
| 776 |  | /** | 
| 777 |  |  * @internal Return the extended format (i.e. the dispatch model), | 
| 778 |  |  * plus the mode associated with an open file. | 
| 779 |  |  * | 
| 780 |  |  * @param ncid File ID (ignored). | 
| 781 |  |  * @param formatp a pointer that gets the extended format. Note that | 
| 782 |  |  * this is not the same as the format provided by nc_inq_format(). The | 
| 783 |  |  * extended foramt indicates the dispatch layer model. NetCDF-4 files | 
| 784 |  |  * will always get NC_FORMATX_NC4. | 
| 785 |  |  * @param modep a pointer that gets the open/create mode associated with | 
| 786 |  |  * this file. Ignored if NULL. | 
| 787 |  |  | 
| 788 |  |  * @return ::NC_NOERR No error. | 
| 789 |  |  * @return ::NC_EBADID Bad ncid. | 
| 790 |  |  * @author Dennis Heimbigner | 
| 791 |  |  */ | 
| 792 |  | int | 
| 793 |  | NCZ_inq_format_extended(int ncid, int *formatp, int *modep) | 
| 794 | 0 | { | 
| 795 | 0 |     NC *nc; | 
| 796 | 0 |     int retval; | 
| 797 |  | 
 | 
| 798 | 0 |     LOG((2, "%s: ncid 0x%x", __func__, ncid)); | 
| 799 |  | 
 | 
| 800 | 0 |     if ((retval = nc4_find_nc_grp_h5(ncid, &nc, NULL, NULL))) | 
| 801 | 0 |         return NC_EBADID; | 
| 802 |  |  | 
| 803 | 0 |     if(modep) | 
| 804 | 0 |         *modep = nc->mode|NC_NETCDF4; | 
| 805 |  | 
 | 
| 806 | 0 |     if (formatp) | 
| 807 | 0 |         *formatp = NC_FORMATX_NCZARR; | 
| 808 |  | 
 | 
| 809 | 0 |     return NC_NOERR; | 
| 810 | 0 | } |