Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ Release Notes {#RELEASE_NOTES}
\brief Release notes file for the netcdf-c package.

This file contains a high-level description of this package's evolution. Releases are in reverse chronological order (most recent first). Note that, as of netcdf 4.2, the `netcdf-c++` and `netcdf-fortran` libraries have been separated into their own libraries.

## 4.8.1 - TBD

* [Bug Fixes] The netcdf-c library was incorrectly determining the scope of types referred to by nc_inq_type_equal. See [Github #1959](https://github.com/Unidata/netcdf-c/pull/1959) for more information.
* [Bug Fix] Fix bug in use of XGetopt when building under Mingw. See [Github #2009](https://github.com/Unidata/netcdf-c/issues/2009).
* [Enhancement] Improve the error reporting when attempting to use a filter for which no implementation can be found in HDF5_PLUGIN_PATH. See [Github #2000](https://github.com/Unidata/netcdf-c/pull/2000) for more information.
* [Bug Fix] Fix `make distcheck` issue in `nczarr_test/` directory. See [Github #2007](https://github.com/Unidata/netcdf-c/issues/2007).
Expand Down
3 changes: 3 additions & 0 deletions include/ncconfigure.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
#ifdef HAVE_STDIO_H
#include <stdio.h>
#endif
#ifdef HAVE_STDINT_H
#include <stdint.h>
#endif

/*
This is included in bottom
Expand Down
3 changes: 3 additions & 0 deletions include/ncpathmgr.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,9 @@ EXTERNL int NChasdriveletter(const char* path);
/* Canonicalize and make absolute by prefixing the current working directory */
EXTERNL char* NCpathabsolute(const char* name);

/* Check if this path appears to start with a windows drive letter */
EXTERNL int NChasdriveletter(const char* path);

/* Convert from the local coding (e.g. ANSI) to utf-8;
note that this can produce unexpected results for Windows
because it first converts to wide character and then to utf8. */
Expand Down
187 changes: 127 additions & 60 deletions libdispatch/dcopy.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,13 @@
#include "config.h"
#include "ncdispatch.h"
#include "nc_logging.h"
#include "nclist.h"

#ifdef USE_NETCDF4

static int searchgroup(int ncid1, int tid1, int grp, int* tid2);
static int searchgrouptree(int ncid1, int tid1, int grp, int* tid2);

/**
* @internal Compare two netcdf types for equality. Must have the
* ncids as well, to find user-defined types.
Expand All @@ -27,8 +32,7 @@
* @author Ed Hartnett
*/
static int
NC_compare_nc_types(int ncid1, int typeid1, int ncid2, int typeid2,
int *equalp)
NC_compare_nc_types(int ncid1, int typeid1, int ncid2, int typeid2, int *equalp)
{
int ret = NC_NOERR;

Expand Down Expand Up @@ -152,77 +156,51 @@ NC_compare_nc_types(int ncid1, int typeid1, int ncid2, int typeid2,
}

/**
* @internal Recursively hunt for a netCDF type id. (Code from
* nc4internal.c); Return matching typeid or 0 if not found.
* @internal Recursively hunt for a netCDF type id, tid2, that is "equal" to tid1.
* Question is: what search order do we use? Ncgen uses root group tree in pre-order.
* But NC4_inq_typeid uses these rules:
* 1. ncid2
* 2. parents of ncid2 (up the tree to root)
* 3. root group tree in pre-order.
* We will leave ncgen for another day and use the nc_inq_typeid rule.
*
* Return matching typeid or 0 if not found.
*
* @param ncid1 File ID.
* @param tid1 Type ID.
* @param ncid2 File ID.
* @param tid2 Pointer that gets type ID of equal type.
*
* @return ::NC_NOERR No error.
* @author Ed Hartnett
* @author Ed Hartnett, Dennis Heimbigner
*/
static int
NC_rec_find_nc_type(int ncid1, nc_type tid1, int ncid2, nc_type* tid2)
{
int i,ret = NC_NOERR;
int nids;
int* ids = NULL;

/* Get all types in grp ncid2 */
if(tid2)
*tid2 = 0;
if ((ret = nc_inq_typeids(ncid2, &nids, NULL)))
return ret;
if (nids)
{
if (!(ids = (int *)malloc((size_t)nids * sizeof(int))))
return NC_ENOMEM;
if ((ret = nc_inq_typeids(ncid2, &nids, ids)))
return ret;
for(i = 0; i < nids; i++)
{
int equal = 0;
if ((ret = NC_compare_nc_types(ncid1, tid1, ncid2, ids[i], &equal)))
return ret;
if(equal)
{
if(tid2)
*tid2 = ids[i];
free(ids);
return NC_NOERR;
}
}
free(ids);
int ret = NC_NOERR;
int parent;

if((ret = searchgroup(ncid1,tid1,ncid2,tid2)))
goto done;
if(*tid2 != 0)
goto done; /* found */

/* Look in the parents of ncid2 upto the root */
switch (ret = nc_inq_grp_parent(ncid2,&parent)) {
case NC_NOERR:
/* Recurse up using parent grp */
ret = NC_rec_find_nc_type(ncid1, tid1, parent, tid2);
break;
case NC_ENOGRP:
/* do the breadth-first pre-order search of the whole tree */
/* ncid2 should be root group */
ret = searchgrouptree(ncid1,tid1,ncid2,tid2);
break;
default: break;
}

/* recurse */
if ((ret = nc_inq_grps(ncid1, &nids, NULL)))
return ret;
if (nids)
{
if (!(ids = (int *)malloc((size_t)nids * sizeof(int))))
return NC_ENOMEM;
if ((ret = nc_inq_grps(ncid1, &nids, ids)))
{
free(ids);
return ret;
}
for (i = 0; i < nids; i++)
{
ret = NC_rec_find_nc_type(ncid1, tid1, ids[i], tid2);
if (ret && ret != NC_EBADTYPE)
break;
if (tid2 && *tid2 != 0) /* found */
{
free(ids);
return NC_NOERR;
}
}
free(ids);
}
return NC_EBADTYPE; /* not found */
done:
return ret;
}

/**
Expand Down Expand Up @@ -711,3 +689,92 @@ nc_copy_att(int ncid_in, int varid_in, const char *name,

return NC_NOERR;
}

#ifdef USE_NETCDF4

/* Helper function for NC_rec_find_nc_type();
search a specified group for matching type.
*/
static int
searchgroup(int ncid1, int tid1, int grp, int* tid2)
{
int i,ret = NC_NOERR;
int nids;
int* ids = NULL;

/* Get all types in grp */
if(tid2)
*tid2 = 0;
if ((ret = nc_inq_typeids(grp, &nids, NULL)))
goto done;
if (nids)
{
if (!(ids = (int *)malloc((size_t)nids * sizeof(int))))
{ret = NC_ENOMEM; goto done;}
if ((ret = nc_inq_typeids(grp, &nids, ids)))
goto done;
for(i = 0; i < nids; i++)
{
int equal = 0;
if ((ret = NC_compare_nc_types(ncid1, tid1, grp, ids[i], &equal)))
goto done;
if(equal)
{
if(tid2)
*tid2 = ids[i];
goto done;
}
}
}

done:
nullfree(ids);
return ret;
}

/* Helper function for NC_rec_find_nc_type();
search a tree of groups for a matching type
using a breadth first queue
*/
static int
searchgrouptree(int ncid1, int tid1, int grp, int* tid2)
{
int i,ret = NC_NOERR;
int nids;
int* ids = NULL;
NClist* queue = nclistnew();
int gid;
uintptr_t id;

id = grp;
nclistpush(queue,(void*)id); /* prime the queue */
while(nclistlength(queue) > 0) {
id = (uintptr_t)nclistremove(queue,0);
gid = (int)id;
if((ret = searchgroup(ncid1,tid1,gid,tid2)))
goto done;
if(*tid2 != 0)
goto done; /*we found it*/
/* Get subgroups of gid and push onto front of the queue (for breadth first) */
if((ret = nc_inq_grps(gid,&nids,NULL)))
goto done;
if (!(ids = (int *)malloc((size_t)nids * sizeof(int))))
{ret = NC_ENOMEM; goto done;}
if ((ret = nc_inq_grps(gid, &nids, ids)))
goto done;
/* push onto the end of the queue */
for(i=0;i<nids;i++) {
id = ids[i];
nclistpush(queue,(void*)id);
}
}
/* Not found */
ret = NC_EBADTYPE;

done:
nclistfree(queue);
nullfree(ids);
return ret;
}

#endif
2 changes: 1 addition & 1 deletion libdispatch/dinfermodel.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ struct MagicFile {
struct NCURI* uri;
int omode;
NCmodel* model;
long long filelen;
size64_t filelen;
int use_parallel;
void* parameters; /* !NULL if inmemory && !diskless */
FILE* fp;
Expand Down
46 changes: 33 additions & 13 deletions libsrc4/nc4type.c
Original file line number Diff line number Diff line change
Expand Up @@ -554,36 +554,56 @@ NC4_inq_typeid(int ncid, const char *name, nc_type *typeidp)
NC_GRP_INFO_T *grptwo;
NC_FILE_INFO_T *h5;
NC_TYPE_INFO_T *type = NULL;
char *norm_name;
int i, retval;
char *norm_name = NULL;
int i, retval = NC_NOERR;

/* Handle atomic types. */
for (i = 0; i < NUM_ATOMIC_TYPES; i++)
if (!strcmp(name, nc4_atomic_name[i]))
{
if (typeidp)
*typeidp = i;
return NC_NOERR;
goto done;
}

/* Find info for this file and group, and set pointer to each. */
if ((retval = nc4_find_grp_h5(ncid, &grp, &h5)))
return retval;
goto done;
assert(h5 && grp);

/* If the first char is a /, this is a fully-qualified
* name. Otherwise, this had better be a local name (i.e. no / in
* the middle). */
if (name[0] != '/' && strstr(name, "/"))
return NC_EINVAL;
{retval = NC_EINVAL; goto done;}

/* Normalize name. */
if (!(norm_name = (char*)malloc(strlen(name) + 1)))
return NC_ENOMEM;
if ((retval = nc4_normalize_name(name, norm_name))) {
free(norm_name);
return retval;
{retval = NC_ENOMEM; goto done;}
if ((retval = nc4_normalize_name(name, norm_name)))
goto done;

/* If this is a fqn, then walk the sequence of parent groups to the last group
and see if that group has a type of the right name */
if(name[0] == '/') { /* FQN */
int rootncid = (grp->nc4_info->root_grp->hdr.id | grp->nc4_info->controller->ext_ncid);
int parent = 0;
char* lastname = strrchr(norm_name,'/'); /* break off the last segment: the type name */
if(lastname == norm_name)
{retval = NC_EINVAL; goto done;}
*lastname++ = '\0'; /* break off the lastsegment */
if((retval = NC4_inq_grp_full_ncid(rootncid,norm_name,&parent)))
goto done;
/* Get parent info */
if((retval=nc4_find_nc4_grp(parent,&grp)))
goto done;
/* See if type exists in this group */
type = (NC_TYPE_INFO_T*)ncindexlookup(grp->type,lastname);
if(type == NULL)
{retval = NC_EBADTYPE; goto done;}
goto done;
}

/* Is the type in this group? If not, search parents. */
for (grptwo = grp; grptwo; grptwo = grptwo->parent) {
type = (NC_TYPE_INFO_T*)ncindexlookup(grptwo->type,norm_name);
Expand All @@ -602,13 +622,13 @@ NC4_inq_typeid(int ncid, const char *name, nc_type *typeidp)
if (typeidp)
*typeidp = type->hdr.id;

free(norm_name);

/* OK, I give up already! */
if (!type)
return NC_EBADTYPE;
{retval = NC_EBADTYPE; goto done;}

return NC_NOERR;
done:
nullfree(norm_name);
return retval;
}

/**
Expand Down
Loading