NetCDF  4.6.0
nc4attr.c
Go to the documentation of this file.
1 
19 #include "nc4internal.h"
20 #include "nc.h"
21 #include "nc4dispatch.h"
22 #include "ncdispatch.h"
23 
24 int nc4typelen(nc_type type);
25 
43 static int
44 nc4_get_att_special(NC_HDF5_FILE_INFO_T* h5, const char* name,
45  nc_type* filetypep, nc_type mem_type, size_t* lenp,
46  int* attnump, int is_long, void* data)
47 {
48  /* Fail if asking for att id */
49  if(attnump)
50  return NC_EATTMETA;
51 
52  if(strcmp(name,NCPROPS)==0) {
53  char* propdata = NULL;
54  int stat = NC_NOERR;
55  int len;
56  if(h5->fileinfo->propattr.version == 0)
57  return NC_ENOTATT;
58  if(mem_type == NC_NAT) mem_type = NC_CHAR;
59  if(mem_type != NC_CHAR)
60  return NC_ECHAR;
61  if(filetypep) *filetypep = NC_CHAR;
62  stat = NC4_buildpropinfo(&h5->fileinfo->propattr, &propdata);
63  if(stat != NC_NOERR) return stat;
64  len = strlen(propdata);
65  if(lenp) *lenp = len;
66  if(data) strncpy((char*)data,propdata,len+1);
67  free(propdata);
68  } else if(strcmp(name,ISNETCDF4ATT)==0
69  || strcmp(name,SUPERBLOCKATT)==0) {
70  unsigned long long iv = 0;
71  if(filetypep) *filetypep = NC_INT;
72  if(lenp) *lenp = 1;
73  if(strcmp(name,SUPERBLOCKATT)==0)
74  iv = (unsigned long long)h5->fileinfo->superblockversion;
75  else /* strcmp(name,ISNETCDF4ATT)==0 */
76  iv = NC4_isnetcdf4(h5);
77  if(mem_type == NC_NAT) mem_type = NC_INT;
78  if(data)
79  switch (mem_type) {
80  case NC_BYTE: *((char*)data) = (char)iv; break;
81  case NC_SHORT: *((short*)data) = (short)iv; break;
82  case NC_INT: *((int*)data) = (int)iv; break;
83  case NC_UBYTE: *((unsigned char*)data) = (unsigned char)iv; break;
84  case NC_USHORT: *((unsigned short*)data) = (unsigned short)iv; break;
85  case NC_UINT: *((unsigned int*)data) = (unsigned int)iv; break;
86  case NC_INT64: *((long long*)data) = (long long)iv; break;
87  case NC_UINT64: *((unsigned long long*)data) = (unsigned long long)iv; break;
88  default:
89  return NC_ERANGE;
90  }
91  }
92  return NC_NOERR;
93 }
94 
115 int
116 nc4_get_att(int ncid, NC *nc, int varid, const char *name, nc_type *xtype,
117  nc_type mem_type, size_t *lenp, int *attnum, int is_long,
118  void *data)
119 {
120  NC_GRP_INFO_T *grp;
121  NC_HDF5_FILE_INFO_T *h5;
122  NC_ATT_INFO_T *att = NULL;
123  int my_attnum = -1;
124 
125  int need_to_convert = 0;
126  int range_error = NC_NOERR;
127  void *bufr = NULL;
128  size_t type_size;
129  char norm_name[NC_MAX_NAME + 1];
130  int i;
131  int retval = NC_NOERR;
132 
133  if (attnum) {
134  my_attnum = *attnum;
135  }
136 
137  LOG((3, "%s: ncid 0x%x varid %d name %s attnum %d mem_type %d",
138  __func__, ncid, varid, name, my_attnum, mem_type));
139 
140  /* Find info for this file and group, and set pointer to each. */
141  h5 = NC4_DATA(nc);
142  if (!(grp = nc4_rec_find_grp(h5->root_grp, (ncid & GRP_ID_MASK))))
143  BAIL(NC_EBADGRPID);
144 
145  /* Check varid */
146  if (varid != NC_GLOBAL) {
147  if (varid < 0 || varid >= grp->vars.nelems)
148  return NC_ENOTVAR;
149  if (grp->vars.value[varid] == NULL)
150  return NC_ENOTVAR;
151  assert(grp->vars.value[varid]->varid == varid);
152  }
153 
154  if (name == NULL)
155  BAIL(NC_EBADNAME);
156 
157  /* Normalize name. */
158  if ((retval = nc4_normalize_name(name, norm_name)))
159  BAIL(retval);
160 
161  if(nc->ext_ncid == ncid && varid == NC_GLOBAL) {
162  const char** sp;
163  for(sp = NC_RESERVED_SPECIAL_LIST;*sp;sp++) {
164  if(strcmp(name,*sp)==0) {
165  return nc4_get_att_special(h5, norm_name, xtype, mem_type, lenp, attnum, is_long, data);
166  }
167  }
168  }
169 
170  /* Find the attribute, if it exists.
171  <strike>If we don't find it, we are major failures.</strike>
172  */
173  if ((retval = nc4_find_grp_att(grp, varid, norm_name, my_attnum, &att))) {
174  if(retval == NC_ENOTATT)
175  return retval;
176  else
177  BAIL(retval);
178  }
179 
180  /* If mem_type is NC_NAT, it means we want to use the attribute's
181  * file type as the mem type as well. */
182  if (mem_type == NC_NAT)
183  mem_type = att->nc_typeid;
184 
185  /* If the attribute is NC_CHAR, and the mem_type isn't, or vice
186  * versa, that's a freakish attempt to convert text to
187  * numbers. Some pervert out there is trying to pull a fast one!
188  * Send him an NC_ECHAR error...*/
189  if (data && att->len &&
190  ((att->nc_typeid == NC_CHAR && mem_type != NC_CHAR) ||
191  (att->nc_typeid != NC_CHAR && mem_type == NC_CHAR)))
192  BAIL(NC_ECHAR); /* take that, you freak! */
193 
194  /* Copy the info. */
195  if (lenp)
196  *lenp = att->len;
197  if (xtype)
198  *xtype = att->nc_typeid;
199  if (attnum) {
200  *attnum = att->attnum;
201  }
202 
203  /* Zero len attributes are easy to read! */
204  if (!att->len)
205  BAIL(NC_NOERR);
206 
207  /* Later on, we will need to know the size of this type. */
208  if ((retval = nc4_get_typelen_mem(h5, mem_type, is_long, &type_size)))
209  BAIL(retval);
210 
211  /* We may have to convert data. Treat NC_CHAR the same as
212  * NC_UBYTE. If the mem_type is NAT, don't try any conversion - use
213  * the attribute's type. */
214  if (data && att->len && mem_type != att->nc_typeid &&
215  mem_type != NC_NAT &&
216  !(mem_type == NC_CHAR &&
217  (att->nc_typeid == NC_UBYTE || att->nc_typeid == NC_BYTE)))
218  {
219  if (!(bufr = malloc((size_t)(att->len * type_size))))
220  BAIL(NC_ENOMEM);
221  need_to_convert++;
222  if ((retval = nc4_convert_type(att->data, bufr, att->nc_typeid,
223  mem_type, (size_t)att->len, &range_error,
224  NULL, (h5->cmode & NC_CLASSIC_MODEL), 0, is_long)))
225  BAIL(retval);
226 
227  /* For strict netcdf-3 rules, ignore erange errors between UBYTE
228  * and BYTE types. */
229  if ((h5->cmode & NC_CLASSIC_MODEL) &&
230  (att->nc_typeid == NC_UBYTE || att->nc_typeid == NC_BYTE) &&
231  (mem_type == NC_UBYTE || mem_type == NC_BYTE) &&
232  range_error)
233  range_error = 0;
234  }
235  else
236  {
237  bufr = att->data;
238  }
239 
240  /* If the caller wants data, copy it for him. If he hasn't
241  allocated enough memory for it, he will burn in segmentation
242  fault hell, writhing with the agony of undiscovered memory
243  bugs! */
244  if (data)
245  {
246  if (att->vldata)
247  {
248  size_t base_typelen;
249  hvl_t *vldest = data;
250  NC_TYPE_INFO_T *type;
251 
252  /* Get the type object for the attribute's type */
253  if ((retval = nc4_find_type(h5, att->nc_typeid, &type)))
254  BAIL(retval);
255 
256  /* Retrieve the size of the base type */
257  if ((retval = nc4_get_typelen_mem(h5, type->u.v.base_nc_typeid, 0, &base_typelen)))
258  BAIL(retval);
259 
260  for (i = 0; i < att->len; i++)
261  {
262  vldest[i].len = att->vldata[i].len;
263  if (!(vldest[i].p = malloc(vldest[i].len * base_typelen)))
264  BAIL(NC_ENOMEM);
265  memcpy(vldest[i].p, att->vldata[i].p, vldest[i].len * base_typelen);
266  }
267  }
268  else if (att->stdata)
269  {
270  for (i = 0; i < att->len; i++)
271  {
272  /* Check for NULL pointer for string (valid in HDF5) */
273  if(att->stdata[i])
274  {
275  if (!(((char **)data)[i] = strdup(att->stdata[i])))
276  BAIL(NC_ENOMEM);
277  }
278  else
279  ((char **)data)[i] = att->stdata[i];
280  }
281  }
282  else
283  {
284  /* For long types, we need to handle this special... */
285  if (is_long && att->nc_typeid == NC_INT)
286  {
287  long *lp = data;
288  int *ip = bufr;
289 
290  for (i = 0; i < att->len; i++)
291  *lp++ = *ip++;
292  }
293  else
294  memcpy(data, bufr, (size_t)(att->len * type_size));
295  }
296  }
297 
298 exit:
299  if (need_to_convert)
300  free(bufr);
301  if (range_error)
302  retval = NC_ERANGE;
303  return retval;
304 }
305 
323 static int
324 nc4_put_att(int ncid, NC *nc, int varid, const char *name,
325  nc_type file_type, nc_type mem_type, size_t len, int is_long,
326  const void *data)
327 {
328  NC_GRP_INFO_T *grp;
329  NC_HDF5_FILE_INFO_T *h5;
330  NC_VAR_INFO_T *var = NULL;
331  NC_ATT_INFO_T *att, **attlist = NULL;
332  char norm_name[NC_MAX_NAME + 1];
333  nc_bool_t new_att = NC_FALSE;
334  int retval = NC_NOERR, range_error = 0;
335  size_t type_size;
336  int i;
337  int res;
338 
339  if (!name)
340  return NC_EBADNAME;
341  assert(nc && NC4_DATA(nc));
342 
343  LOG((1, "nc4_put_att: ncid 0x%x varid %d name %s "
344  "file_type %d mem_type %d len %d", ncid, varid,
345  name, file_type, mem_type, len));
346 
347  /* If len is not zero, then there must be some data. */
348  if (len && !data)
349  return NC_EINVAL;
350 
351  /* Find info for this file and group, and set pointer to each. */
352  h5 = NC4_DATA(nc);
353  if (!(grp = nc4_rec_find_grp(h5->root_grp, (ncid & GRP_ID_MASK))))
354  return NC_EBADGRPID;
355 
356  /* If the file is read-only, return an error. */
357  if (h5->no_write)
358  return NC_EPERM;
359 
360  /* Find att, if it exists. */
361  if (varid == NC_GLOBAL)
362  attlist = &grp->att;
363  else
364  {
365  if (varid < 0 || varid >= grp->vars.nelems)
366  return NC_ENOTVAR;
367  var = grp->vars.value[varid];
368  if (!var) return NC_ENOTVAR;
369  attlist = &var->att;
370  assert(var->varid == varid);
371  }
372 
373  if (!name)
374  return NC_EBADNAME;
375 
376  /* Check and normalize the name. */
377  if ((retval = nc4_check_name(name, norm_name)))
378  return retval;
379 
380  if(nc->ext_ncid == ncid && varid == NC_GLOBAL) {
381  const char** sp;
382  for(sp = NC_RESERVED_SPECIAL_LIST;*sp;sp++) {
383  if(strcmp(name,*sp)==0) {
384  return NC_ENOTATT; /* Not settable */
385  }
386  }
387  }
388 
389  for (att = *attlist; att; att = att->l.next)
390  if (!strcmp(att->name, norm_name))
391  break;
392 
393  /* If len is not zero, then there must be some data. */
394  if (len && !data)
395  return NC_EINVAL;
396 
397  LOG((1, "nc4_put_att: ncid 0x%x varid %d name %s "
398  "file_type %d mem_type %d len %d", ncid, varid,
399  name, file_type, mem_type, len));
400 
401  if (!att)
402  {
403  /* If this is a new att, require define mode. */
404  if (!(h5->flags & NC_INDEF))
405  {
406  if (h5->cmode & NC_CLASSIC_MODEL)
407  return NC_EINDEFINE;
408  if ((retval = NC4_redef(ncid)))
409  BAIL(retval);
410  }
411  new_att = NC_TRUE;
412  }
413  else
414  {
415  /* For an existing att, if we're not in define mode, the len
416  must not be greater than the existing len for classic model. */
417  if (!(h5->flags & NC_INDEF) &&
418  len * nc4typelen(file_type) > (size_t)att->len * nc4typelen(att->nc_typeid))
419  {
420  if (h5->cmode & NC_CLASSIC_MODEL)
421  return NC_EINDEFINE;
422  if ((retval = NC4_redef(ncid)))
423  BAIL(retval);
424  }
425  }
426 
427  /* We must have two valid types to continue. */
428  if (file_type == NC_NAT || mem_type == NC_NAT)
429  return NC_EBADTYPE;
430 
431  /* Get information about this type. */
432  if ((retval = nc4_get_typelen_mem(h5, file_type, is_long, &type_size)))
433  return retval;
434 
435  /* No character conversions are allowed. */
436  if (file_type != mem_type &&
437  (file_type == NC_CHAR || mem_type == NC_CHAR ||
438  file_type == NC_STRING || mem_type == NC_STRING))
439  return NC_ECHAR;
440 
441  /* For classic mode file, only allow atts with classic types to be
442  * created. */
443  if (h5->cmode & NC_CLASSIC_MODEL && file_type > NC_DOUBLE)
444  return NC_ESTRICTNC3;
445 
446  /* Add to the end of the attribute list, if this att doesn't
447  already exist. */
448  if (new_att)
449  {
450  LOG((3, "adding attribute %s to the list...", norm_name));
451  if ((res = nc4_att_list_add(attlist, &att)))
452  BAIL (res);
453  if (!(att->name = strdup(norm_name)))
454  return NC_ENOMEM;
455  }
456 
457  /* Now fill in the metadata. */
458  att->dirty = NC_TRUE;
459  att->nc_typeid = file_type;
460 
461  /* If this att has vlen or string data, release it before we lose the length value. */
462  if (att->stdata)
463  {
464  for (i = 0; i < att->len; i++)
465  if(att->stdata[i])
466  free(att->stdata[i]);
467  free(att->stdata);
468  att->stdata = NULL;
469  }
470  if (att->vldata)
471  {
472  for (i = 0; i < att->len; i++)
473  nc_free_vlen(&att->vldata[i]);
474  free(att->vldata);
475  att->vldata = NULL;
476  }
477 
478  att->len = len;
479  if (att->l.prev)
480  att->attnum = ((NC_ATT_INFO_T *)att->l.prev)->attnum + 1;
481  else
482  att->attnum = 0;
483 
484  /* If this is the _FillValue attribute, then we will also have to
485  * copy the value to the fill_vlue pointer of the NC_VAR_INFO_T
486  * struct for this var. (But ignore a global _FillValue
487  * attribute). */
488  if (!strcmp(att->name, _FillValue) && varid != NC_GLOBAL)
489  {
490  int size;
491 
492  /* Fill value must be same type and have exactly one value */
493  if (att->nc_typeid != var->type_info->nc_typeid)
494  return NC_EBADTYPE;
495  if (att->len != 1)
496  return NC_EINVAL;
497 
498  /* If we already wrote to the dataset, then return an error. */
499  if (var->written_to)
500  return NC_ELATEFILL;
501 
502  /* If fill value hasn't been set, allocate space. Of course,
503  * vlens have to be different... */
504  if ((retval = nc4_get_typelen_mem(grp->nc4_info, var->type_info->nc_typeid, 0,
505  &type_size)))
506  return retval;
507 
508  /* Already set a fill value? Now I'll have to free the old
509  * one. Make up your damn mind, would you? */
510  if (var->fill_value)
511  {
512  if (var->type_info->nc_type_class == NC_VLEN)
513  {
514  if ((retval = nc_free_vlen(var->fill_value)))
515  return retval;
516  }
517  else if (var->type_info->nc_type_class == NC_STRING)
518  {
519  if (*(char **)var->fill_value)
520  free(*(char **)var->fill_value);
521  }
522  free(var->fill_value);
523  }
524 
525  /* Allocate space for the fill value. */
526  if (var->type_info->nc_type_class == NC_VLEN)
527  size = sizeof(hvl_t);
528  else if (var->type_info->nc_type_class == NC_STRING)
529  size = sizeof(char *);
530  else
531  size = type_size;
532 
533  if (!(var->fill_value = calloc(1, size)))
534  return NC_ENOMEM;
535 
536  /* Copy the fill_value. */
537  LOG((4, "Copying fill value into metadata for variable %s", var->name));
538  if (var->type_info->nc_type_class == NC_VLEN)
539  {
540  nc_vlen_t *in_vlen = (nc_vlen_t *)data, *fv_vlen = (nc_vlen_t *)(var->fill_value);
541 
542  fv_vlen->len = in_vlen->len;
543  if (!(fv_vlen->p = malloc(size * in_vlen->len)))
544  return NC_ENOMEM;
545  memcpy(fv_vlen->p, in_vlen->p, in_vlen->len * size);
546  }
547  else if (var->type_info->nc_type_class == NC_STRING)
548  {
549  if(NULL != (*(char **)data))
550  {
551  if (!(*(char **)(var->fill_value) = malloc(strlen(*(char **)data) + 1)))
552  return NC_ENOMEM;
553  strcpy(*(char **)var->fill_value, *(char **)data);
554  }
555  else
556  *(char **)var->fill_value = NULL;
557  }
558  else
559  memcpy(var->fill_value, data, type_size);
560 
561  /* Indicate that the fill value was changed, if the variable has already
562  * been created in the file, so the dataset gets deleted and re-created. */
563  if (var->created)
564  var->fill_val_changed = NC_TRUE;
565  }
566 
567  /* Copy the attribute data, if there is any. VLENs and string
568  * arrays have to be handled specially. */
569  if(att->len)
570  {
571  nc_type type_class; /* Class of attribute's type */
572 
573  /* Get class for this type. */
574  if ((retval = nc4_get_typeclass(h5, file_type, &type_class)))
575  return retval;
576 
577  assert(data);
578  if (type_class == NC_VLEN)
579  {
580  const hvl_t *vldata1;
581  NC_TYPE_INFO_T *type;
582  size_t base_typelen;
583 
584  /* Get the type object for the attribute's type */
585  if ((retval = nc4_find_type(h5, file_type, &type)))
586  BAIL(retval);
587 
588  /* Retrieve the size of the base type */
589  if ((retval = nc4_get_typelen_mem(h5, type->u.v.base_nc_typeid, 0, &base_typelen)))
590  BAIL(retval);
591 
592  vldata1 = data;
593  if (!(att->vldata = (nc_vlen_t*)malloc(att->len * sizeof(hvl_t))))
594  BAIL(NC_ENOMEM);
595  for (i = 0; i < att->len; i++)
596  {
597  att->vldata[i].len = vldata1[i].len;
598  if (!(att->vldata[i].p = malloc(base_typelen * att->vldata[i].len)))
599  BAIL(NC_ENOMEM);
600  memcpy(att->vldata[i].p, vldata1[i].p, base_typelen * att->vldata[i].len);
601  }
602  }
603  else if (type_class == NC_STRING)
604  {
605  LOG((4, "copying array of NC_STRING"));
606  if (!(att->stdata = malloc(sizeof(char *) * att->len))) {
607  BAIL(NC_ENOMEM);
608  }
609 
610  /* If we are overwriting an existing attribute,
611  specifically an NC_CHAR, we need to clean up
612  the pre-existing att->data. */
613  if (!new_att && att->data) {
614  free(att->data);
615  att->data = NULL;
616  }
617 
618  for (i = 0; i < att->len; i++)
619  {
620  if(NULL != ((char **)data)[i]) {
621  LOG((5, "copying string %d of size %d", i, strlen(((char **)data)[i]) + 1));
622  if (!(att->stdata[i] = strdup(((char **)data)[i])))
623  BAIL(NC_ENOMEM);
624  }
625  else
626  att->stdata[i] = ((char **)data)[i];
627  }
628  }
629  else
630  {
631  /* [Re]allocate memory for the attribute data */
632  if (!new_att)
633  free (att->data);
634  if (!(att->data = malloc(att->len * type_size)))
635  BAIL(NC_ENOMEM);
636 
637  /* Just copy the data, for non-atomic types */
638  if (type_class == NC_OPAQUE || type_class == NC_COMPOUND || type_class == NC_ENUM)
639  memcpy(att->data, data, len * type_size);
640  else
641  {
642  /* Data types are like religions, in that one can convert. */
643  if ((retval = nc4_convert_type(data, att->data, mem_type, file_type,
644  len, &range_error, NULL,
645  (h5->cmode & NC_CLASSIC_MODEL), is_long, 0)))
646  BAIL(retval);
647  }
648  }
649  }
650  att->dirty = NC_TRUE;
651  att->created = NC_FALSE;
652 
653  /* Mark attributes on variable dirty, so they get written */
654  if(var)
655  var->attr_dirty = NC_TRUE;
656 
657 exit:
658  /* If there was an error return it, otherwise return any potential
659  range error value. If none, return NC_NOERR as usual.*/
660  if (retval)
661  return retval;
662  if (range_error)
663  return NC_ERANGE;
664  return NC_NOERR;
665 }
666 
681 int
682 NC4_inq_att(int ncid, int varid, const char *name, nc_type *xtypep, size_t *lenp)
683 {
684  NC *nc;
685  NC_HDF5_FILE_INFO_T *h5;
686 
687  LOG((2, "nc_inq_att: ncid 0x%x varid %d name %s", ncid, varid, name));
688 
689  /* Find metadata. */
690  if (!(nc = nc4_find_nc_file(ncid,NULL)))
691  return NC_EBADID;
692 
693  /* get netcdf-4 metadata */
694  h5 = NC4_DATA(nc);
695  assert(h5);
696 
697  /* Handle netcdf-4 files. */
698  return nc4_get_att(ncid, nc, varid, name, xtypep, NC_NAT, lenp, NULL, 0, NULL);
699 }
700 
712 int
713 NC4_inq_attid(int ncid, int varid, const char *name, int *attnump)
714 {
715  NC *nc;
716  NC_HDF5_FILE_INFO_T *h5;
717  int stat;
718 
719  LOG((2, "nc_inq_attid: ncid 0x%x varid %d name %s", ncid, varid, name));
720 
721  /* Find metadata. */
722  if (!(nc = nc4_find_nc_file(ncid,NULL)))
723  return NC_EBADID;
724 
725  /* get netcdf-4 metadata */
726  h5 = NC4_DATA(nc);
727  assert(h5);
728 
729  /* Handle netcdf-4 files. */
730  stat = nc4_get_att(ncid, nc, varid, name, NULL, NC_NAT,
731  NULL, attnump, 0, NULL);
732  return stat;
733 }
734 
735 
748 int
749 NC4_inq_attname(int ncid, int varid, int attnum, char *name)
750 {
751  NC *nc;
752  NC_ATT_INFO_T *att;
753  NC_HDF5_FILE_INFO_T *h5;
754  int retval = NC_NOERR;
755 
756  LOG((2, "nc_inq_attname: ncid 0x%x varid %d attnum %d",
757  ncid, varid, attnum));
758 
759  /* Find metadata. */
760  if (!(nc = nc4_find_nc_file(ncid,NULL)))
761  return NC_EBADID;
762 
763  /* get netcdf-4 metadata */
764  h5 = NC4_DATA(nc);
765  assert(h5);
766 
767  /* Handle netcdf-4 files. */
768  if ((retval = nc4_find_nc_att(ncid, varid, NULL, attnum, &att)))
769  return retval;
770 
771  /* Get the name. */
772  if (name)
773  strcpy(name, att->name);
774 
775  return NC_NOERR;
776 }
777 
791 int
792 NC4_rename_att(int ncid, int varid, const char *name, const char *newname)
793 {
794  NC *nc;
795  NC_GRP_INFO_T *grp;
796  NC_HDF5_FILE_INFO_T *h5;
797  NC_VAR_INFO_T *var = NULL;
798  NC_ATT_INFO_T *att, *list;
799  char norm_newname[NC_MAX_NAME + 1], norm_name[NC_MAX_NAME + 1];
800  hid_t datasetid = 0;
801  int retval = NC_NOERR;
802 
803  if (!name || !newname)
804  return NC_EINVAL;
805 
806  LOG((2, "nc_rename_att: ncid 0x%x varid %d name %s newname %s",
807  ncid, varid, name, newname));
808 
809  /* If the new name is too long, that's an error. */
810  if (strlen(newname) > NC_MAX_NAME)
811  return NC_EMAXNAME;
812 
813  /* Find metadata for this file. */
814  if ((retval = nc4_find_nc_grp_h5(ncid, &nc, &grp, &h5)))
815  return retval;
816 
817  assert(h5 && grp);
818 
819  /* If the file is read-only, return an error. */
820  if (h5->no_write)
821  return NC_EPERM;
822 
823  /* Check and normalize the name. */
824  if ((retval = nc4_check_name(newname, norm_newname)))
825  return retval;
826 
827  /* Is norm_newname in use? */
828  if (varid == NC_GLOBAL)
829  {
830  list = grp->att;
831  }
832  else
833  {
834  if (varid < 0 || varid >= grp->vars.nelems)
835  return NC_ENOTVAR;
836  var = grp->vars.value[varid];
837  if (!var) return NC_ENOTVAR;
838  assert(var->varid == varid);
839  list = var->att;
840  }
841  for (att = list; att; att = att->l.next)
842  if (!strncmp(att->name, norm_newname, NC_MAX_NAME))
843  return NC_ENAMEINUSE;
844 
845  /* Normalize name and find the attribute. */
846  if ((retval = nc4_normalize_name(name, norm_name)))
847  return retval;
848  for (att = list; att; att = att->l.next)
849  if (!strncmp(att->name, norm_name, NC_MAX_NAME))
850  break;
851  if (!att)
852  return NC_ENOTATT;
853 
854  /* If we're not in define mode, new name must be of equal or
855  less size, if complying with strict NC3 rules. */
856  if (!(h5->flags & NC_INDEF) && strlen(norm_newname) > strlen(att->name) &&
857  (h5->cmode & NC_CLASSIC_MODEL))
858  return NC_ENOTINDEFINE;
859 
860  /* Delete the original attribute, if it exists in the HDF5 file. */
861  if (att->created)
862  {
863  if (varid == NC_GLOBAL)
864  {
865  if (H5Adelete(grp->hdf_grpid, att->name) < 0)
866  return NC_EHDFERR;
867  }
868  else
869  {
870  if ((retval = nc4_open_var_grp2(grp, varid, &datasetid)))
871  return retval;
872  if (H5Adelete(datasetid, att->name) < 0)
873  return NC_EHDFERR;
874  }
875  att->created = NC_FALSE;
876  }
877 
878  /* Copy the new name into our metadata. */
879  free(att->name);
880  if (!(att->name = malloc((strlen(norm_newname) + 1) * sizeof(char))))
881  return NC_ENOMEM;
882  strcpy(att->name, norm_newname);
883  att->dirty = NC_TRUE;
884 
885  /* Mark attributes on variable dirty, so they get written */
886  if(var)
887  var->attr_dirty = NC_TRUE;
888 
889  return retval;
890 }
891 
905 int
906 NC4_del_att(int ncid, int varid, const char *name)
907 {
908  NC *nc;
909  NC_GRP_INFO_T *grp;
910  NC_HDF5_FILE_INFO_T *h5;
911  NC_ATT_INFO_T *att, *natt;
912  NC_VAR_INFO_T *var;
913  NC_ATT_INFO_T **attlist = NULL;
914  hid_t locid = 0, datasetid = 0;
915  int retval = NC_NOERR;
916 
917  if (!name)
918  return NC_EINVAL;
919 
920  LOG((2, "nc_del_att: ncid 0x%x varid %d name %s",
921  ncid, varid, name));
922 
923  /* Find metadata for this file. */
924  if ((retval = nc4_find_nc_grp_h5(ncid, &nc, &grp, &h5)))
925  return retval;
926 
927  assert(h5 && grp);
928 
929  /* If the file is read-only, return an error. */
930  if (h5->no_write)
931  return NC_EPERM;
932 
933  /* If it's not in define mode, forget it. */
934  if (!(h5->flags & NC_INDEF))
935  {
936  if (h5->cmode & NC_CLASSIC_MODEL)
937  return NC_ENOTINDEFINE;
938  if ((retval = NC4_redef(ncid)))
939  BAIL(retval);
940  }
941 
942  /* Get either the global or a variable attribute list. Also figure
943  out the HDF5 location it's attached to. */
944  if (varid == NC_GLOBAL)
945  {
946  attlist = &grp->att;
947  locid = grp->hdf_grpid;
948  }
949  else
950  {
951  if (varid < 0 || varid >= grp->vars.nelems)
952  return NC_ENOTVAR;
953  var = grp->vars.value[varid];
954  if (!var) return NC_ENOTVAR;
955  attlist = &var->att;
956  assert(var->varid == varid);
957  if (var->created)
958  locid = var->hdf_datasetid;
959  }
960 
961  /* Now find the attribute by name or number. */
962  for (att = *attlist; att; att = att->l.next)
963  if (!strcmp(att->name, name))
964  break;
965 
966  /* If att is NULL, we couldn't find the attribute. */
967  if (!att)
968  BAIL_QUIET(NC_ENOTATT);
969 
970  /* Delete it from the HDF5 file, if it's been created. */
971  if (att->created)
972  {
973  assert(locid);
974 
975  if(H5Adelete(locid, att->name) < 0)
976  BAIL(NC_EATTMETA);
977  }
978 
979  /* Renumber all following attributes. */
980  for (natt = att->l.next; natt; natt = natt->l.next)
981  natt->attnum--;
982 
983  /* Delete this attribute from this list. */
984  if ((retval = nc4_att_list_del(attlist, att)))
985  BAIL(retval);
986 
987 exit:
988  if (datasetid > 0) H5Dclose(datasetid);
989  return retval;
990 }
991 
1009 static int
1010 nc4_put_att_tc(int ncid, int varid, const char *name, nc_type file_type,
1011  nc_type mem_type, int mem_type_is_long, size_t len,
1012  const void *op)
1013 {
1014  NC *nc;
1015  NC_HDF5_FILE_INFO_T *h5;
1016 
1017  /* The length needs to be positive (cast needed for braindead
1018  systems with signed size_t). */
1019  if((unsigned long) len > X_INT_MAX)
1020  return NC_EINVAL;
1021 
1022  /* Find metadata. */
1023  if (!(nc = nc4_find_nc_file(ncid,NULL)))
1024  return NC_EBADID;
1025 
1026  /* get netcdf-4 metadata */
1027  h5 = NC4_DATA(nc);
1028  assert(h5);
1029 
1030  /* Check varid */
1031  if (varid != NC_GLOBAL) {
1032  /* Find info for this file and group, and set pointer to each. */
1033  NC_GRP_INFO_T *grp;
1034  if (!(grp = nc4_rec_find_grp(h5->root_grp, (ncid & GRP_ID_MASK))))
1035  return NC_EBADGRPID;
1036 
1037  if (varid < 0 || varid >= grp->vars.nelems)
1038  return NC_ENOTVAR;
1039  if (grp->vars.value[varid] == NULL)
1040  return NC_ENOTVAR;
1041  assert(grp->vars.value[varid]->varid == varid);
1042  }
1043 
1044  if (!name || strlen(name) > NC_MAX_NAME)
1045  return NC_EBADNAME;
1046 
1047  LOG((3, "nc4_put_att_tc: ncid 0x%x varid %d name %s file_type %d "
1048  "mem_type %d len %d", ncid, varid, name, file_type, mem_type, len));
1049 
1050  if(nc->ext_ncid == ncid && varid == NC_GLOBAL) {
1051  const char** reserved = NC_RESERVED_ATT_LIST;
1052  for(;*reserved;reserved++) {
1053  if(strcmp(name,*reserved)==0)
1054  return NC_ENAMEINUSE;
1055  }
1056  }
1057 
1058  if(varid != NC_GLOBAL) {
1059  const char** reserved = NC_RESERVED_VARATT_LIST;
1060  for(;*reserved;reserved++) {
1061  if(strcmp(name,*reserved)==0)
1062  return NC_ENAMEINUSE;
1063  }
1064  }
1065 
1066  /* Otherwise, handle things the netcdf-4 way. */
1067  return nc4_put_att(ncid, nc, varid, name, file_type, mem_type, len,
1068  mem_type_is_long, op);
1069 }
1070 
1087 int
1088 nc4_get_att_tc(int ncid, int varid, const char *name, nc_type mem_type,
1089  int mem_type_is_long, void *ip)
1090 {
1091  NC *nc;
1092  NC_HDF5_FILE_INFO_T *h5;
1093 
1094  LOG((3, "nc4_get_att_tc: ncid 0x%x varid %d name %s mem_type %d",
1095  ncid, varid, name, mem_type));
1096 
1097  /* Find metadata. */
1098  if (!(nc = nc4_find_nc_file(ncid,NULL)))
1099  return NC_EBADID;
1100 
1101  /* get netcdf-4 metadata */
1102  h5 = NC4_DATA(nc);
1103  assert(h5);
1104 
1105  return nc4_get_att(ncid, nc, varid, name, NULL, mem_type,
1106  NULL, NULL, mem_type_is_long, ip);
1107 }
1108 
1124 int
1125 NC4_put_att(int ncid, int varid, const char *name, nc_type xtype,
1126  size_t nelems, const void *value, nc_type memtype)
1127 {
1128  return nc4_put_att_tc(ncid, varid, name, xtype, memtype, 0, nelems, value);
1129 }
1130 
1144 int
1145 NC4_get_att(int ncid, int varid, const char *name, void *value, nc_type memtype)
1146 {
1147  return nc4_get_att_tc(ncid, varid, name, memtype, 0, value);
1148 }
#define _FillValue
Name of fill value attribute.
Definition: netcdf.h:112
#define NC_ENOMEM
Memory allocation (malloc) failure.
Definition: netcdf.h:395
#define NC_CHAR
ISO/ASCII character.
Definition: netcdf.h:35
#define NC_UBYTE
unsigned 1 byte int
Definition: netcdf.h:41
#define NC_CLASSIC_MODEL
Enforce classic model on netCDF-4.
Definition: netcdf.h:135
#define NC_ERANGE
Math result not representable.
Definition: netcdf.h:394
#define NC_UINT
unsigned 4-byte int
Definition: netcdf.h:43
#define NC_EHDFERR
Error at HDF5 layer.
Definition: netcdf.h:426
#define NC_OPAQUE
opaque types
Definition: netcdf.h:53
#define NC_ELATEFILL
Attempt to define fill value when data already exists.
Definition: netcdf.h:447
#define NC_INT64
signed 8-byte int
Definition: netcdf.h:44
#define NC_STRING
string
Definition: netcdf.h:46
#define NC_ENOTINDEFINE
Operation not allowed in data mode.
Definition: netcdf.h:331
#define NC_DOUBLE
double precision floating point number
Definition: netcdf.h:40
int nc_type
The nc_type type is just an int.
Definition: netcdf.h:24
#define NC_BYTE
signed 1 byte integer
Definition: netcdf.h:34
#define NC_EINDEFINE
Operation not allowed in define mode.
Definition: netcdf.h:340
size_t len
Length of VL data (in base type units)
Definition: netcdf.h:667
#define NC_ENAMEINUSE
String match to name in use.
Definition: netcdf.h:354
#define NC_EATTMETA
Problem with attribute metadata.
Definition: netcdf.h:432
#define NC_VLEN
vlen (variable-length) types
Definition: netcdf.h:52
#define NC_EBADTYPE
Not a netcdf data type.
Definition: netcdf.h:357
#define NC_EBADNAME
Attribute or variable name contains illegal characters.
Definition: netcdf.h:387
#define NC_EINVAL
Invalid Argument.
Definition: netcdf.h:325
#define NC_INT
signed 4 byte integer
Definition: netcdf.h:37
#define NC_ESTRICTNC3
Attempting netcdf-4 operation on strict nc3 netcdf-4 file.
Definition: netcdf.h:437
#define NC_EBADGRPID
Bad group ID.
Definition: netcdf.h:441
#define NC_MAX_NAME
Maximum for classic library.
Definition: netcdf.h:265
void * p
Pointer to VL data.
Definition: netcdf.h:668
#define NC_NAT
Not A Type.
Definition: netcdf.h:33
EXTERNL int nc_free_vlen(nc_vlen_t *vl)
Free memory in a VLEN object.
Definition: dvlen.c:31
#define NC_USHORT
unsigned 2-byte int
Definition: netcdf.h:42
#define NC_EBADID
Not a netcdf id.
Definition: netcdf.h:322
This is the type of arrays of vlens.
Definition: netcdf.h:666
#define NC_SHORT
signed 2 byte integer
Definition: netcdf.h:36
#define NC_ENOTVAR
Variable not found.
Definition: netcdf.h:369
#define NC_EMAXNAME
NC_MAX_NAME exceeded.
Definition: netcdf.h:373
#define NC_EPERM
Write to read only.
Definition: netcdf.h:326
#define NC_NOERR
No Error.
Definition: netcdf.h:315
#define NC_ENUM
enum types
Definition: netcdf.h:54
#define NC_ECHAR
Attempt to convert between text & numbers.
Definition: netcdf.h:376
#define NC_COMPOUND
compound types
Definition: netcdf.h:55
#define NC_GLOBAL
Attribute id to put/get a global attribute.
Definition: netcdf.h:238
#define NC_ENOTATT
Attribute not found.
Definition: netcdf.h:355
#define NC_UINT64
unsigned 8-byte int
Definition: netcdf.h:45

Return to the Main Unidata NetCDF page.
Generated on Thu Jan 25 2018 21:06:33 for NetCDF. NetCDF is a Unidata library.