1 /* Copyright 2018, UCAR/Unidata and OPeNDAP, Inc.
2 See the COPYRIGHT file for more information. */
3
4 #include "config.h"
5 #include <errno.h>
6 #ifdef HAVE_UNISTD_H
7 #include <unistd.h>
8 #endif
9 #ifdef HAVE_SYS_STAT_H
10 #include <sys/stat.h>
11 #endif
12 #ifdef HAVE_FCNTL_H
13 #include <fcntl.h>
14 #endif
15
16 #ifdef _MSC_VER
17 #include <io.h>
18 #define mode_t int
19 #endif
20
21 #include "ocinternal.h"
22 #include "ocdebug.h"
23
24 /* Order is important: longest first */
25 static const char* DDSdatamarks[3] = {"Data:\r\n","Data:\n",(char*)NULL};
26
27 /* Not all systems have strndup, so provide one*/
28 char*
ocstrndup(const char * s,size_t len)29 ocstrndup(const char* s, size_t len)
30 {
31 char* dup;
32 if(s == NULL) return NULL;
33 dup = (char*)ocmalloc(len+1);
34 MEMCHECK(dup,NULL);
35 memcpy((void*)dup,s,len);
36 dup[len] = '\0';
37 return dup;
38 }
39
40 /* Do not trust strncmp semantics; this one
41 compares up to len chars or to null terminators */
42 int
ocstrncmp(const char * s1,const char * s2,size_t len)43 ocstrncmp(const char* s1, const char* s2, size_t len)
44 {
45 const char *p,*q;
46 if(s1 == s2) return 0;
47 if(s1 == NULL) return -1;
48 if(s2 == NULL) return +1;
49 for(p=s1,q=s2;len > 0;p++,q++,len--) {
50 if(*p == 0 && *q == 0) return 0; /* *p == *q == 0 */
51 if(*p != *q)
52 return (*p - *q);
53 }
54 /* 1st len chars are same */
55 return 0;
56 }
57
58
59 #if 0
60 void
61 makedimlist(Nclist* path, Nclist* dims)
62 {
63 unsigned int i,j;
64 for(i=0;i<nclistlength(path);i++) {
65 OCnode* node = (OCnode*)nclistget(path,i);
66 unsigned int rank = node->array.rank;
67 for(j=0;j<rank;j++) {
68 OCnode* dim = (OCnode*)nclistget(node->array.dimensions,j);
69 nclistpush(dims,(void*)dim);
70 }
71 }
72 }
73 #endif
74
75 void
ocfreeprojectionclause(OCprojectionclause * clause)76 ocfreeprojectionclause(OCprojectionclause* clause)
77 {
78 if(clause->target != NULL) free(clause->target);
79 while(nclistlength(clause->indexsets) > 0) {
80 NClist* slices = (NClist*)nclistpop(clause->indexsets);
81 while(nclistlength(slices) > 0) {
82 OCslice* slice = (OCslice*)nclistpop(slices);
83 if(slice != NULL) free(slice);
84 }
85 nclistfree(slices);
86 }
87 nclistfree(clause->indexsets);
88 free(clause);
89 }
90
91 #if 0
92 void
93 freeAttributes(NClist* attset)
94 {
95 unsigned int i,j;
96 for(i=0;i<nclistlength(attset);i++) {
97 OCattribute* att = (OCattribute*)nclistget(attset,i);
98 if(att->name != NULL) free(att->name);
99 if(att->etype == OC_String || att->etype == OC_URL) {
100 for(j=0;j<att->nvalues;j++) {
101 char* s = ((char**)att->values)[j];
102 if(s != NULL) free(s);
103 }
104 } else {
105 free(att->values);
106 }
107 }
108 }
109 #endif
110
111 #if 0
112 void
113 freeOCnode(OCnode* cdf, int deep)
114 {
115 unsigned int i;
116 if(cdf == NULL) return;
117 if(cdf->name != NULL) free(cdf->name);
118 if(cdf->fullname != NULL) free(cdf->fullname);
119 if(cdf->attributes != NULL) freeAttributes(cdf->attributes);
120 if(cdf->subnodes != NULL) {
121 if(deep) {
122 for(i=0;i<nclistlength(cdf->subnodes);i++) {
123 OCnode* node = (OCnode*)nclistget(cdf->subnodes,i);
124 freeOCnode(node,deep);
125 }
126 }
127 nclistfree(cdf->subnodes);
128 }
129 free(cdf);
130 }
131 #endif
132
133 int
ocfindbod(NCbytes * buffer,size_t * bodp,size_t * ddslenp)134 ocfindbod(NCbytes* buffer, size_t* bodp, size_t* ddslenp)
135 {
136 unsigned int i;
137 char* content;
138 size_t len = ncbyteslength(buffer);
139 const char** marks;
140
141 content = ncbytescontents(buffer);
142
143 for(marks = DDSdatamarks;*marks;marks++) {
144 const char* mark = *marks;
145 size_t tlen = strlen(mark);
146 for(i=0;i<len;i++) {
147 if((i+tlen) <= len
148 && (ocstrncmp(content+i,mark,tlen)==0)) {
149 *ddslenp = i;
150 i += tlen;
151 *bodp = i;
152 return 1;
153 }
154 }
155 }
156 *ddslenp = 0;
157 *bodp = 0;
158 return 0; /* tag not found; not necessarily an error*/
159 }
160
161 /* Compute total # of elements if dimensioned*/
162 size_t
octotaldimsize(size_t rank,size_t * sizes)163 octotaldimsize(size_t rank, size_t* sizes)
164 {
165 unsigned int i;
166 size_t count = 1;
167 for(i=0;i<rank;i++) {
168 count *= sizes[i];
169 }
170 return count;
171 }
172
173 size_t
octypesize(OCtype etype)174 octypesize(OCtype etype)
175 {
176 switch (etype) {
177 case OC_Char: return sizeof(char);
178 case OC_Byte: return sizeof(signed char);
179 case OC_UByte: return sizeof(unsigned char);
180 case OC_Int16: return sizeof(short);
181 case OC_UInt16: return sizeof(unsigned short);
182 case OC_Int32: return sizeof(int);
183 case OC_UInt32: return sizeof(unsigned int);
184 case OC_Float32: return sizeof(float);
185 case OC_Float64: return sizeof(double);
186 #ifdef HAVE_LONG_LONG_INT
187 case OC_Int64: return sizeof(long long);
188 case OC_UInt64: return sizeof(unsigned long long);
189 #endif
190 case OC_String: return sizeof(char*);
191 case OC_URL: return sizeof(char*);
192 default: break; /* Ignore all others */
193 }
194 return 0;
195 }
196
197 char*
octypetostring(OCtype octype)198 octypetostring(OCtype octype)
199 {
200 switch (octype) {
201 case OC_NAT: return "OC_NAT";
202 case OC_Char: return "OC_Char";
203 case OC_Byte: return "OC_Byte";
204 case OC_UByte: return "OC_UByte";
205 case OC_Int16: return "OC_Int16";
206 case OC_UInt16: return "OC_UInt16";
207 case OC_Int32: return "OC_Int32";
208 case OC_UInt32: return "OC_UInt32";
209 case OC_Int64: return "OC_Int64";
210 case OC_UInt64: return "OC_UInt64";
211 case OC_Float32: return "OC_Float32";
212 case OC_Float64: return "OC_Float64";
213 case OC_String: return "OC_String";
214 case OC_URL: return "OC_URL";
215 /* Non-primitives*/
216 case OC_Dataset: return "OC_Dataset";
217 case OC_Sequence: return "OC_Sequence";
218 case OC_Grid: return "OC_Grid";
219 case OC_Structure: return "OC_Structure";
220 case OC_Dimension: return "OC_Dimension";
221 case OC_Attribute: return "OC_Attribute";
222 case OC_Attributeset: return "OC_Attributeset";
223 case OC_Atomic: return "OC_Atomic";
224 default: break;
225 }
226 return NULL;
227 }
228
229 char*
octypetoddsstring(OCtype octype)230 octypetoddsstring(OCtype octype)
231 {
232 switch (octype) {
233 case OC_Byte: return "Byte";
234 case OC_Int16: return "Int16";
235 case OC_UInt16: return "UInt16";
236 case OC_Int32: return "Int32";
237 case OC_UInt32: return "UInt32";
238 case OC_Float32: return "Float32";
239 case OC_Float64: return "Float64";
240 case OC_String: return "String";
241 case OC_URL: return "Url";
242 /* Non-atomics*/
243 case OC_Dataset: return "Dataset";
244 case OC_Sequence: return "Sequence";
245 case OC_Grid: return "Grid";
246 case OC_Structure: return "Structure";
247 case OC_Dimension: return "Dimension";
248 case OC_Attribute: return "Attribute";
249 case OC_Attributeset: return "Attributeset";
250 case OC_Atomic: return "Atomic";
251 default: break;
252 }
253 return "<unknown>";
254 }
255
256
257 OCerror
octypeprint(OCtype etype,void * value,size_t bufsize,char * buf)258 octypeprint(OCtype etype, void* value, size_t bufsize, char* buf)
259 {
260 if(buf == NULL || bufsize == 0 || value == NULL) return OC_EINVAL;
261 buf[0] = '\0';
262 switch (etype) {
263 case OC_Char:
264 snprintf(buf,bufsize,"'%c'",*(char*)value);
265 break;
266 case OC_Byte:
267 snprintf(buf,bufsize,"%d",*(signed char*)value);
268 break;
269 case OC_UByte:
270 snprintf(buf,bufsize,"%u",*(unsigned char*)value);
271 break;
272 case OC_Int16:
273 snprintf(buf,bufsize,"%d",*(short*)value);
274 break;
275 case OC_UInt16:
276 snprintf(buf,bufsize,"%u",*(unsigned short*)value);
277 break;
278 case OC_Int32:
279 snprintf(buf,bufsize,"%d",*(int*)value);
280 break;
281 case OC_UInt32:
282 snprintf(buf,bufsize,"%u",*(unsigned int*)value);
283 break;
284 case OC_Float32:
285 snprintf(buf,bufsize,"%g",*(float*)value);
286 break;
287 case OC_Float64:
288 snprintf(buf,bufsize,"%g",*(double*)value);
289 break;
290 #ifdef HAVE_LONG_LONG_INT
291 case OC_Int64:
292 snprintf(buf,bufsize,"%lld",*(long long*)value);
293 break;
294 case OC_UInt64:
295 snprintf(buf,bufsize,"%llu",*(unsigned long long*)value);
296 break;
297 #endif
298 case OC_String:
299 case OC_URL: {
300 char* s = *(char**)value;
301 snprintf(buf,bufsize,"\"%s\"",s);
302 } break;
303 default: break;
304 }
305 return OC_NOERR;
306 }
307
308 size_t
xxdrsize(OCtype etype)309 xxdrsize(OCtype etype)
310 {
311 switch (etype) {
312 case OC_Char:
313 case OC_Byte:
314 case OC_UByte:
315 case OC_Int16:
316 case OC_UInt16:
317 case OC_Int32:
318 case OC_UInt32:
319 return XDRUNIT;
320 case OC_Int64:
321 case OC_UInt64:
322 return (2*XDRUNIT);
323 case OC_Float32:
324 return XDRUNIT;
325 case OC_Float64:
326 return (2*XDRUNIT);
327 case OC_String:
328 case OC_URL:
329 default: break;
330 }
331 return 0;
332 }
333
334 /**************************************/
335
336 char*
ocerrstring(int err)337 ocerrstring(int err)
338 {
339 if(err == 0) return "no error";
340 if(err > 0) return strerror(err);
341 switch (err) {
342 case OC_EBADID:
343 return "OC_EBADID: Not a valid ID";
344 case OC_EINVAL:
345 return "OC_EINVAL: Invalid argument";
346 case OC_EPERM:
347 return "OC_EPERM: Write to read only";
348 case OC_EINVALCOORDS:
349 return "OC_EINVALCOORDS: Index exceeds dimension bound";
350 case OC_ENOTVAR:
351 return "OC_ENOTVAR: Variable not found";
352 case OC_ECHAR:
353 return "OC_ECHAR: Attempt to convert between text & numbers";
354 case OC_EEDGE:
355 return "OC_EEDGE: Start+count exceeds dimension bound";
356 case OC_ESTRIDE:
357 return "OC_ESTRIDE: Illegal stride";
358 case OC_ENOMEM:
359 return "OC_ENOMEM: Memory allocation (malloc) failure";
360 case OC_EDIMSIZE:
361 return "OC_EDIMSIZE: Invalid dimension size";
362 case OC_EDAP:
363 return "OC_EDAP: unspecified DAP failure";
364 case OC_EXDR:
365 return "OC_EXDR: XDR failure";
366 case OC_ECURL:
367 return "OC_ECURL: unspecified libcurl failure";
368 case OC_EBADURL:
369 return "OC_EBADURL: malformed url";
370 case OC_EBADVAR:
371 return "OC_EBADVAR: no such variable";
372 case OC_EOPEN:
373 return "OC_EOPEN: temporary file open failed";
374 case OC_EIO:
375 return "OC_EIO: I/O failure";
376 case OC_ENODATA:
377 return "OC_ENODATA: Variable has no data in DAP request";
378 case OC_EDAPSVC:
379 return "OC_EDAPSVC: DAP Server error";
380 case OC_ENAMEINUSE:
381 return "OC_ENAMEINUSE: Duplicate name in DDS";
382 case OC_EDAS:
383 return "OC_EDAS: Malformed or unreadable DAS";
384 case OC_EDDS:
385 return "OC_EDDS: Malformed or unreadable DDS";
386 case OC_EDATADDS:
387 return "OC_EDATADDS: Malformed or unreadable DATADDS";
388 case OC_ERCFILE:
389 return "OC_ERCFILE: Malformed, unreadable, or bad value in the run-time configuration file";
390 case OC_ENOFILE:
391 return "OC_ENOFILE: cannot read content of URL";
392
393 /* oc_data related errors */
394 case OC_EINDEX:
395 return "OC_EINDEX: index argument too large";
396 case OC_EBADTYPE:
397 return "OC_EBADTYPE: argument of wrong OCtype";
398
399 /* String concatenation overrun */
400 case OC_EOVERRUN:
401 return "OC_EOVERRUN: internal concatenation failed";
402
403 /* Authorization Error */
404 case OC_EAUTH:
405 return "OC_EAUTH: authorization failure";
406
407 default: break;
408 }
409 return "<unknown error code>";
410 }
411
412 OCerror
ocsvcerrordata(OCstate * state,char ** codep,char ** msgp,long * httpp)413 ocsvcerrordata(OCstate* state, char** codep, char** msgp, long* httpp)
414 {
415 if(codep) *codep = state->error.code;
416 if(msgp) *msgp = state->error.message;
417 if(httpp) *httpp = state->error.httpcode;
418 return OC_NOERR;
419 }
420
421 /* if we get OC_EDATADDS error, then try to capture any
422 error message and log it; assumes that in this case,
423 the datadds is not big.
424 */
425 void
ocdataddsmsg(OCstate * state,OCtree * tree)426 ocdataddsmsg(OCstate* state, OCtree* tree)
427 {
428 #define ERRCHUNK 1024
429 #define ERRFILL ' '
430 #define ERRTAG "Error {"
431 int i,j;
432 size_t len;
433 XXDR* xdrs;
434 char* contents;
435 off_t ckp;
436
437 if(tree == NULL) return;
438 /* get available space */
439 xdrs = tree->data.xdrs;
440 len = xxdr_length(xdrs);
441 if(len < strlen(ERRTAG))
442 return; /* no room */
443 ckp = xxdr_getpos(xdrs);
444 xxdr_setpos(xdrs,(off_t)0);
445 /* read the whole thing */
446 contents = (char*)malloc(len+1);
447 (void)xxdr_getbytes(xdrs,contents,(off_t)len);
448 contents[len] = '\0';
449 /* Look for error tag */
450 for(i=0;i<len;i++) {
451 if(ocstrncmp(contents+i,ERRTAG,strlen(ERRTAG))==0) {
452 /* log the error message */
453 /* Do a quick and dirty escape */
454 for(j=i;j<len;j++) {
455 int c = contents[i+j];
456 if(c > 0 && (c < ' ' || c >= '\177'))
457 contents[i+j] = ERRFILL;
458 }
459 nclog(NCLOGERR,"DATADDS failure, possible message: '%s'\n",
460 contents+i);
461 goto done;
462 }
463 }
464 xxdr_setpos(xdrs,ckp);
465 done:
466 return;
467 }
468
469 /* Given some set of indices [i0][i1]...[in] (where n == rank-1)
470 and the maximum sizes, compute the linear offset
471 for set of dimension indices.
472 */
473 size_t
ocarrayoffset(size_t rank,size_t * sizes,const size_t * indices)474 ocarrayoffset(size_t rank, size_t* sizes, const size_t* indices)
475 {
476 unsigned int i;
477 size_t count = 0;
478 for(i=0;i<rank;i++) {
479 count *= sizes[i];
480 count += indices[i];
481 }
482 return count;
483 }
484
485 /* Inverse of ocarrayoffset: convert linear index to a set of indices */
486 void
ocarrayindices(size_t index,size_t rank,size_t * sizes,size_t * indices)487 ocarrayindices(size_t index, size_t rank, size_t* sizes, size_t* indices)
488 {
489 int i;
490 for(i=rank-1;i>=0;i--) {
491 indices[i] = index % sizes[i];
492 index = (index - indices[i]) / sizes[i];
493 }
494 }
495
496 /* Given some set of edge counts [i0][i1]...[in] (where n == rank-1)
497 and the maximum sizes, compute the linear offset
498 for the last edge position
499 */
500 size_t
ocedgeoffset(size_t rank,size_t * sizes,size_t * edges)501 ocedgeoffset(size_t rank, size_t* sizes, size_t* edges)
502 {
503 unsigned int i;
504 size_t count = 0;
505 for(i=0;i<rank;i++) {
506 count *= sizes[i];
507 count += (edges[i]-1);
508 }
509 return count;
510 }
511
512 int
ocvalidateindices(size_t rank,size_t * sizes,size_t * indices)513 ocvalidateindices(size_t rank, size_t* sizes, size_t* indices)
514 {
515 int i;
516 for(i=0;i<rank;i++) {
517 if(indices[i] >= sizes[i]) return 0;
518 }
519 return 1;
520 }
521
522 int
oc_ispacked(OCnode * node)523 oc_ispacked(OCnode* node)
524 {
525 OCtype octype = node->octype;
526 OCtype etype = node->etype;
527 int isscalar = (node->array.rank == 0);
528 int packed;
529
530 if(isscalar || octype != OC_Atomic)
531 return 0; /* is not packed */
532 packed = (etype == OC_Byte
533 || etype == OC_UByte
534 || etype == OC_Char) ? 1 : 0;
535 return packed;
536 }
537
538 /* Must be consistent with ocx.h.OCDT */
539 #define NMODES 6
540 #define MAXMODENAME 8 /*max (strlen(modestrings[i])) */
541 static const char* modestrings[NMODES+1] = {
542 "FIELD", /* ((OCDT)(1<<0)) field of a container */
543 "ELEMENT", /* ((OCDT)(1<<1)) element of a structure array */
544 "RECORD", /* ((OCDT)(1<<2)) record of a sequence */
545 "ARRAY", /* ((OCDT)(1<<3)) is structure array */
546 "SEQUENCE", /* ((OCDT)(1<<4)) is sequence */
547 "ATOMIC", /* ((OCDT)(1<<5)) is atomic leaf */
548 NULL,
549 };
550
551 char*
ocdtmodestring(OCDT mode,int compact)552 ocdtmodestring(OCDT mode,int compact)
553 {
554 char* result = NULL;
555 int i;
556 char* p = NULL;
557
558 result = malloc(1+(NMODES*(MAXMODENAME+1)));
559 if(result == NULL) return NULL;
560 p = result;
561 result[0] = '\0';
562 if(mode == 0) {
563 if(compact) *p++ = '-';
564 else if(!occoncat(result,sizeof(result),1,"NONE"))
565 return NULL;
566 } else for(i=0;;i++) {
567 const char* ms = modestrings[i];
568 if(ms == NULL) break;
569 if(!compact && i > 0)
570 if(!occoncat(result,sizeof(result),1,","))
571 return NULL;
572 if(fisset(mode,(1<<i))) {
573 if(compact) *p++ = ms[0];
574 else if(!occoncat(result,sizeof(result),1,ms))
575 return NULL;
576 }
577 }
578 /* pad compact list out to NMODES in length (+1 for null terminator) */
579 if(compact) {
580 while((p-result) < NMODES) *p++ = ' ';
581 *p = '\0';
582 }
583 return result;
584 }
585
586
587 /*
588 Instead of using snprintf to concatenate
589 multiple strings into a given target,
590 provide a direct concatenator.
591 So, this function concats the n argument strings
592 and overwrites the contents of dst.
593 Care is taken to never overrun the available
594 space (the size parameter).
595 Note that size is assumed to include the null
596 terminator and that in the event of overrun,
597 the string will have a null at dst[size-1].
598 Return 0 if overrun, 1 otherwise.
599 */
600 int
occopycat(char * dst,size_t size,size_t n,...)601 occopycat(char* dst, size_t size, size_t n, ...)
602 {
603 va_list args;
604 size_t avail = size - 1;
605 int i;
606 int status = 1; /* assume ok */
607 char* p = dst;
608
609 if(n == 0) {
610 if(size > 0)
611 dst[0] = '\0';
612 return (size > 0 ? 1: 0);
613 }
614
615 va_start(args,n);
616 for(i=0;i<n;i++) {
617 char* q = va_arg(args, char*);
618 for(;;) {
619 int c = *q++;
620 if(c == '\0') break;
621 if(avail == 0) {status = 0; goto done;}
622 *p++ = c;
623 avail--;
624 }
625 }
626 /* make sure we null terminate;
627 note that since avail was size-1, there
628 will always be room
629 */
630 *p = '\0';
631
632 done:
633 va_end(args);
634 return status;
635 }
636
637 /*
638 Similar to occopycat, but
639 the n strings are, in effect,
640 concatenated and appended to the
641 current contents of dst.
642 The size parameter is the total size of dst,
643 including room for null terminator.
644 Return 0 if overrun, 1 otherwise.
645 */
646 int
occoncat(char * dst,size_t size,size_t n,...)647 occoncat(char* dst, size_t size, size_t n, ...)
648 {
649 va_list args;
650 int status = 1; /* assume ok */
651 size_t avail = 0;
652 int i;
653 char* p;
654 size_t dstused;
655 dstused = strlen(dst);
656 if(dstused >= size)
657 return 0; /* There is no room to append */
658 /* move to the end of the current contents of dst
659 and act like we are doing copycat
660 */
661 p = dst + dstused;
662 size -= dstused;
663 avail = size - 1;
664 if(n == 0) {
665 if(size > 0)
666 p[0] = '\0';
667 return (size > 0 ? 1: 0);
668 }
669
670 va_start(args,n);
671 for(i=0;i<n;i++) {
672 char* q = va_arg(args, char*);
673 for(;;) {
674 int c = *q++;
675 if(c == '\0') break;
676 if(avail == 0) {status = 0; goto done;}
677 *p++ = c;
678 avail--;
679 }
680 }
681 /* make sure we null terminate;
682 note that since avail was size-1, there
683 will always be room
684 */
685 *p = '\0';
686
687 done:
688 va_end(args);
689 return status;
690 }
691
692 /* merge two envv style lists */
693 char**
ocmerge(const char ** list1,const char ** list2)694 ocmerge(const char** list1, const char** list2)
695 {
696 int l1, l2;
697 char** merge;
698 const char** p;
699 for(l1=0,p=list1;*p;p++) {l1++;}
700 for(l2=0,p=list2;*p;p++) {l2++;}
701 merge = (char**)malloc(sizeof(char*)*(l1+l2+1));
702 if(merge == NULL)
703 return NULL;
704 memcpy(merge,list1,sizeof(char*)*l1);
705 memcpy(merge+l1,list2,sizeof(char*)*l2);
706 merge[l1+l2] = NULL;
707 return merge;
708 }
709