[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[netCDF #DOE-704686]: (No Subject)



ok, attached is the file named ocinternal.c.
Use it to replace the one in
    netcdf-4.1.1/libncdap3/oc
Rebuild and see if it works.

Let me add again that I owe you a big apology.
I was rude and did not take your problem
seriously enough.  I hope I learned a lesson
from this.

=Dennis Heimbigner
  Unidata


Ticket Details
===================
Ticket ID: DOE-704686
Department: Support netCDF
Priority: Normal
Status: Open
/* Copyright 2009, UCAR/Unidata and OPeNDAP, Inc.
   See the COPYRIGHT file for more information. */

#include <stdio.h>
#include <fcntl.h>
#include <errno.h>

#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif

#include "ocinternal.h"
#include "ocdebug.h"
#include "ocdata.h"
#include "occontent.h"
#include "occlientparams.h"
#include "rc.h"

#include "http.h"
#include "read.h"

/* Note: TMPPATH must end in '/' */
#ifdef __CYGWIN__
#define TMPPATH1 "c:/temp/"
#define TMPPATH2 "./"
#else
#define TMPPATH1 "/tmp/"
#define TMPPATH2 "./"
#endif

#define BUFSIZE 512
#define DODSRC_SIZE 9
#define DODSRC "/.dodsrc"

static int ocextractdds(OCstate*,OCtree*);
static char* constraintescape(const char* url);
#ifdef OC_DISK_STORAGE
static OCerror createtempfile(OCstate*,OCtree*);
static int createtempfile1(char*,char*);
#endif

extern OCnode* makeunlimiteddimension(void);

#ifdef WIN32
#include <fcntl.h>
#define _S_IREAD 256
#define _S_IWRITE 128
int mkstemp(char *tmpl)
{
   int ret=-1;

mktemp(tmpl); ret=open(tmpl,O_RDWR|O_BINARY|O_CREAT|O_EXCL|_O_SHORT_LIVED, 
_S_IREAD|_S_IWRITE);

   return ret;
}

#endif

/* Global flags*/
static int oc_big_endian;
int oc_network_order; /* network order is big endian */
int oc_invert_xdr_double;
int oc_curl_file_supported;

static int ocinitialized = 0;

static int
ocinitialize(void)
{
    int stat = OC_NOERR;
    char buf[BUFSIZE];
    char *env;
    int len;

    /* Compute if we are same as network order v-a-v xdr */
#ifdef XDRBYTEORDER
    {
        XDR xdrs;
        union {
            char tmp[sizeof(unsigned int)];
            unsigned int i;
        } u;
        int testint = 1;
        xrmem_create(&xdrs, (caddr_t)&u.tmp,sizeof(u.tmp), XDR_ENCODE);
        xdr_int(&xdrs, &testint);   
        oc_network_order = (udub.i == testint?1:0);
        oc_big_endian = oc_network_order;
    }
#else   
    {
        int testint = 0x00000001;
        char *byte = (char *)&testint;
        oc_big_endian = (byte[0] == 0 ? 1 : 0);
        oc_network_order = oc_big_endian;
    }
#endif /*XDRBYTEORDER*/
    {
        /* It turns out that various machines
           store double in different formats.
           This affects the conversion code ocdata.c
           when reconstructing; probably could deduce this
           from oc_big_endian, but not sure.
        */
        XDR xdrs;
        union {
            double dv;
            unsigned int i;
            unsigned int iv[2];
            char tmp[sizeof(double)];
        } udub;
        double testdub = 18000;
        /* verify double vs int size */
        if(sizeof(double) != (2 * sizeof(unsigned int)))
            ocpanic("|double| != 2*|int|");
        if(sizeof(udub) != sizeof(double))
            ocpanic("|double| != |udub|");
        memset((void*)&udub,0,sizeof(udub));
        xdrmem_create(&xdrs, (caddr_t)&udub.tmp,sizeof(udub.tmp), XDR_ENCODE);
        xdr_double(&xdrs, &testdub);
        udub.iv[0] = ocntoh(udub.iv[0]);
        udub.iv[1] = ocntoh(udub.iv[1]);
        if (udub.dv == testdub)
                oc_invert_xdr_double = 0;
        else { /* swap and try again */
            unsigned int temp = udub.iv[0];
            udub.iv[0] = udub.iv[1];
            udub.iv[1] = temp;
            if (udub.dv != testdub)
                ocpanic("cannot unpack xdr_double");
            oc_invert_xdr_double = 1;
        }
    }
    oc_loginit();

    /* read/write configuration file */
    env = getenv("HOME");
    if (env != NULL) {
            len = strlen(env);
            if (len >= BUFSIZE - DODSRC_SIZE) {
                    oc_log(LOGERR, "length of home directory is too long\n");
                    stat = OC_EIO;
                    goto end;
            }
            strncpy(buf, env, BUFSIZE - 1);
            buf[len] = '\0';
            strncat(buf, DODSRC, BUFSIZE - 1);
            buf[len + DODSRC_SIZE] = '\0';

            if (ocdebug > 1)
                    fprintf(stderr, "Your RC file: %s\n", buf);

            /* stat = OC_NOERR; */
            if (access(buf, R_OK) != 0) {
                    if (write_dodsrc(buf) != OC_NOERR) {
                            oc_log(LOGERR, "Error getting buffer\n");
                            stat = OC_EIO;
                    }
            }

            if (read_dodsrc(buf) != OC_NOERR) {
                    oc_log(LOGERR, "Error parsing buffer\n");
                    stat = OC_EIO;
            }
    }

    /* Determine if this version of curl supports "file://..." urls.*/
    {
        const char* const* proto; /*weird*/
        curl_version_info_data* curldata;
        curldata = curl_version_info(CURLVERSION_NOW);
        oc_curl_file_supported = 0;
        for(proto=curldata->protocols;*proto;proto++) {
            if(strcmp("file",*proto)==0) {oc_curl_file_supported=1;break;}
        }
        if(ocdebug > 0) {
            oc_log(LOGNOTE,"Curl file:// support = %d",oc_curl_file_supported);
        }
    }

    ocinitialized = 1;

end:
    return THROW(stat);
}

/**************************************************/
OCerror
ocopen(OCstate** statep, const char* url)
{
    int stat = OC_NOERR;
    OCstate * state = NULL;
    DAPURL tmpurl;
    CURL* curl = NULL; /* curl handle*/

    memset((void*)&tmpurl,0,sizeof(tmpurl));

    if(!ocinitialized) {
        stat=ocinitialize();
        if(stat) {THROWCHK(stat=OC_EBADURL); goto fail;}
    }

    if(!dapurlparse(url,&tmpurl)) {THROWCHK(stat=OC_EBADURL); goto fail;}
    
    stat = occurlopen(&curl);
    if(stat != OC_NOERR) {THROWCHK(stat); goto fail;}

    state = (OCstate*)ocmalloc(sizeof(OCstate)); /* ocmalloc zeros memory*/
    if(state == NULL) {THROWCHK(stat=OC_ENOMEM); goto fail;}

    /* Setup DAP state*/
    state->magic = OCMAGIC;
    state->curl = curl;
    state->trees = oclistnew();
    state->contentlist = NULL;
    state->url = tmpurl;
    state->clientparams = ocparamdecode(state->url.params);
    if(state->clientparams == NULL) {
        oc_log(LOGWARN,"Could not parse client parameters");
    }
    state->packet = ocbytesnew();
    ocbytessetalloc(state->packet,DFALTPACKETSIZE); /*initial reasonable size*/
    if(statep) *statep = state;
    return THROW(stat);   

fail:
    dapurlclear(&tmpurl);
    if(state != NULL) ocfree(state);
    if(curl != NULL) occurlclose(curl);
    return THROW(stat);
}

OCerror
ocfetch(OCstate* state, const char* constraint, OCdxd kind, OCnode** rootp)
{
    OCtree* tree = NULL;
    OCnode* root = NULL;
    OCerror stat = OC_NOERR;
    
    tree = (OCtree*)ocmalloc(sizeof(OCtree));
    MEMCHECK(tree,OC_ENOMEM);
    memset((void*)tree,0,sizeof(OCtree));
    tree->dxdclass = kind;
    tree->constraint = constraintescape(constraint);
    if(tree->constraint == NULL)
        tree->constraint = nulldup(constraint);

    ocbytesclear(state->packet);

    switch (kind) {
    case OCDAS:
        stat = readDAS(state,tree);
        if(stat == OC_NOERR) {
            tree->text = ocbytesdup(state->packet);
            if(tree->text == NULL) stat = OC_EDAS;
        }
        break;
    case OCDDS:
        stat = readDDS(state,tree);
        if(stat == OC_NOERR) {
            tree->text = ocbytesdup(state->packet);
            if(tree->text == NULL) stat = OC_EDDS;
        }
        break;
    case OCDATADDS:
#ifdef OC_DISK_STORAGE
       /* Create the datadds file immediately
           so that DRNO can reference it*/
        /* Make the tmp file*/
        stat = createtempfile(state,tree);
        if(stat) {THROWCHK(stat); goto unwind;}
        stat = readDATADDS(state,tree);
        if(stat == OC_NOERR) {
            /* Separate the DDS from data and return the dds;
               will modify packet */
            stat = ocextractdds(state,tree);
        }
#else
        stat = readDATADDS(state,tree);
        if(stat == OC_NOERR) {
            /* Separate the DDS from data*/
            stat = ocextractdds(state,tree);
            tree->data.xdrdata = ocbytesdup(state->packet);
        }
#endif
        break;
    }
    if(stat != OC_NOERR) {
        /* Obtain any http code */
        state->error.httpcode = ocfetchhttpcode(state->curl);
        if(state->error.httpcode >= 400) {
            oc_log(LOGWARN,"oc_open: Could not read url; http error = 
%l",state->error.httpcode);
        } else {
            oc_log(LOGWARN,"oc_open: Could not read url");
        }
        return THROW(stat);
    }

    tree->nodes = NULL;
    stat = DAPparse(state,tree,tree->text);
    /* Check and report on an error return from the server */
    if(stat == OC_EDAPSVC  && state->error.code != NULL) {
        oc_log(LOGERR,"oc_open: server error retrieving url: code=%s 
message=\"%s\"",
                  state->error.code,    
                  (state->error.message?state->error.message:""));
    }
    if(stat) {THROWCHK(stat); goto unwind;}
    root = tree->root;
    /* make sure */
    tree->root = root;
    root->tree = tree;

    /* Verify the parse */
    switch (kind) {
    case OCDAS:
        if(root->octype != OC_Attributeset)
            {THROWCHK(stat=OC_EDAS); goto unwind;}
        break;
    case OCDDS:
        if(root->octype != OC_Dataset)
            {THROWCHK(stat=OC_EDDS); goto unwind;}
        break;
    case OCDATADDS:
        if(root->octype != OC_Dataset)
            {THROWCHK(stat=OC_EDATADDS); goto unwind;}
        /* Modify the tree kind */
        tree->dxdclass = OCDATADDS;
        break;
    default: return OC_EINVAL;
    }

    if(kind != OCDAS) {
        /* Process ocnodes to fix various semantic issues*/
        computeocsemantics(tree->nodes);
    }

    /* Process ocnodes to compute name info*/
    computeocfullnames(tree->root);

    if(kind != OCDAS) {
        /* Process ocnodes to compute sizes when uniform in size*/
        ocsetsize(tree->root);
    }

    if(kind == OCDATADDS) {
        tree->data.xdrs = (XDR*)ocmalloc(sizeof(XDR));
        MEMCHECK(tree->data.xdrs,OC_ENOMEM);
#ifdef OC_DISK_STORAGE
        ocxdrstdio_create(tree->data.xdrs,tree->data.file,XDR_DECODE);
#else
        
xdrmem_create(tree->data.xdrs,tree->data.xdrdata,tree->data.datasize,XDR_DECODE);
#endif
        if(!xdr_setpos(tree->data.xdrs,tree->data.bod)) return xdrerror();
    }

#ifdef OC_DISK_STORAGE
    if(ocdebug == 0 && tree->data.filename != NULL) {
        unlink(tree->data.filename);
    }
#endif

    if(rootp) *rootp = root;
    return stat;

unwind:
    ocfreetree(tree);
    return THROW(stat);
}

void
occlose(OCstate* state)
{
    unsigned int i;
    if(state == NULL) return;

    for(i=0;i<oclistlength(state->trees);i++) {
        OCnode* root = (OCnode*)oclistpop(state->trees);
        ocfreeroot(root);
    }
    oclistfree(state->trees);
    dapurlclear(&state->url);
    ocbytesfree(state->packet);
    ocfree(state->error.code);
    ocfree(state->error.message);
    if(state->contentlist != NULL) {
        struct OCcontent* next;
        struct OCcontent* curr = state->contentlist;
        while(curr != NULL) {
            next = curr->next;
            ocfree(curr);
            curr = next;
        }
    }
    if(state->curl != NULL) occurlclose(state->curl);
    if(state->clientparams != NULL) ocparamfree(state->clientparams);
    ocfree(state);
}

static OCerror
ocextractdds(OCstate* state, OCtree* tree)
{
    OCerror stat = OC_NOERR;
    size_t ddslen, bod, bodfound;
#ifdef OC_DISK_STORAGE
    /* Read until we find the separator (or EOF)*/
    ocbytesclear(state->packet);
    rewind(tree->data.file);
    do {
        char chunk[128];
        size_t count;
        /* read chunks of the file until we find the separator*/
        count = fread(chunk,1,sizeof(chunk),tree->data.file);
        if(count <= 0) break; /* EOF;*/
        ocbytesappendn(state->packet,chunk,count);
        bodfound = findbod(state->packet,&bod,&ddslen);
    } while(!bodfound);
#else /*!OC_DISK_STORAGE*/
    /* Read until we find the separator (or EOF)*/
    bodfound = findbod(state->packet,&bod,&ddslen);
#endif
    if(bodfound) {
        tree->data.bod = bod;
        tree->data.ddslen = ddslen;
    } else { /* No BOD; pretend */
        tree->data.bod = tree->data.datasize;
        tree->data.ddslen = tree->data.bod;
    }
    /* copy out the dds */
    if(ddslen > 0) {
        tree->text = (char*)ocmalloc(ddslen+1);
        memcpy((void*)tree->text,(void*)ocbytescontents(state->packet),ddslen);
        tree->text[ddslen] = '\0';
    } else
        tree->text = NULL;
#ifdef OC_DISK_STORAGE
    /* reset the position of the tmp file*/
    fseek(tree->data.file,tree->data.bod,SEEK_SET);
#else
    /* If the data part is not on an 8 byte boundary, make it so */
    if(tree->data.bod % sizeof(unsigned long long) != 0) {
        unsigned long count = tree->data.datasize - tree->data.bod;
        char* dst = ocbytescontents(state->packet);
        char* src = dst + tree->data.bod;
        int i;
        /* memcpy((void*)dst,(void*)src,count); overlap*/
        for(i=0;i<count;i++) dst[i] = src[i]; /* avoid memcpy overlap */
        tree->data.datasize = count;
        tree->data.bod = 0;
        tree->data.ddslen = 0;
    }
#endif
    if(tree->text == NULL) stat = OC_EDATADDS;
    return THROW(stat);
}

#ifdef OC_DISK_STORAGE
static OCerror
createtempfile(OCstate* state, OCtree* tree)
{
    int fd,slen;
    char* name;
    slen = strlen(TMPPATH1);
    if(slen < strlen(TMPPATH2)) slen = strlen(TMPPATH2);
    slen += strlen("datadds") + strlen("XXXXXX");
    name = (char*)ocmalloc(slen+1);
    MEMCHECK(name,OC_ENOMEM);
    fd = createtempfile1(name, TMPPATH1);
    if(fd < 0)
        fd = createtempfile1(name, TMPPATH2);
    if(fd < 0) {
        oc_log(LOGERR,"oc_open: attempt to open tmp file %s failed",name);
        return errno;
    }
    oc_log(LOGNOTE,"oc_open: using tmp file: %s",name);
    tree->data.filename = name; /* remember our tmp file name */
    tree->data.file = fdopen(fd,"w+");
    if(tree->data.file == NULL) return OC_EOPEN;
    /* unlink the temp file so it will automatically be reclaimed */
    if(ocdebug == 0) unlink(tree->data.filename);
    return OC_NOERR;
}

int
createtempfile1(char* name, char* tmppath)
{
    char* p;
    int c,fd;
    strcpy(name,tmppath);
    strcat(name,"datadds");
    strcat(name,"XXXXXX");
    p = name + strlen("datadds");
    /* \', and '/' to '_' and '.' to '-'*/
    for(;(c=*p);p++) {
        if(c == '\\' || c == '/') {*p = '_';}
        else if(c == '.') {*p = '-';}
    }
    /* Note Potential problem: old versions of this function
       leave the file in mode 0666 instead of 0600 */
    fd = mkstemp(name);
    return fd;
}
#endif /*OC_DISK_STORAGE*/

/* Allow these (non-alpha-numerics) to pass thru */
static char okchars[] = "&/:;,.=?@'\"<>{}!|\\^[]`~";
static char hexdigits[] = "0123456789abcdef";


/* Modify constraint to use %XX escapes */
static char*
constraintescape(const char* url)
{
    size_t len;
    char* p;
    int c;
    char* eurl;

    if(url == NULL) return NULL;
    len = strlen(url);
    eurl = ocmalloc(1+3*len); /* worst case: c -> %xx */
    MEMCHECK(eurl,NULL);
    p = eurl;
    *p = '\0';
    while((c=*url++)) {
        if(c >= '0' && c <= '9') {*p++ = c;}
        else if(c >= 'a' && c <= 'z') {*p++ = c;}
        else if(c >= 'A' && c <= 'Z') {*p++ = c;}
        else if(strchr(okchars,c) != NULL) {*p++ = c;}
        else {
            *p++ = '%';
            *p++ = hexdigits[(c & 0xf0)>>4];
            *p++ = hexdigits[(c & 0xf)];
        }
    }
    *p = '\0';
    return eurl;
}

OCerror
ocupdatelastmodifieddata(OCstate* state)
{
    OCerror status = OC_NOERR;
    long lastmodified;
    status = ocfetchlastmodified(state->curl, state->url.base, &lastmodified);
    if(status == OC_NOERR) {
        state->datalastmodified = lastmodified;
    }
    return status;
}

NOTE: All email exchanges with Unidata User Support are recorded in the Unidata inquiry tracking system and then made publicly available through the web. If you do not want to have your interactions made available in this way, you must let us know in each email you send to us.