[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;
}