netcdf-c/oc2/ocrc.c
Dennis Heimbigner 715a6fe5eb The files libdispatch/dwinpath.c and include/ncwinpath.h
were added to provide a path name converter from e.g. cygwin
paths to e.g. windows paths. This is necessary because
the shell scripts may produce cygwin paths, but the code
may have been compiled with Visual Studio. Similar issues
arise with Mingw.

At appropriate places, and if using Visual Studio or Mingw,
I added calls to the path conversion code.
Apparently I forgot to find all the places where this
conversion was needed. So this pr does the following:
1. Push the calls to the converter to the various libXXX
   directories and out of libdispatch/dfile.c.
2. Add conversion calls to other parts of the code like oc2.

I also turns out that conversion code in dapcvt.c
had a bug when handling DAP Byte type under visual studio.

Notes:
1. there may still be places I missed that need to do path conversion.
2. need to make sure that calls to e.g. H5open also use converted path.
2017-07-13 10:40:07 -06:00

758 lines
22 KiB
C

/* Copyright 2009, UCAR/Unidata and OPeNDAP, Inc.
See the COPYRIGHT file for more information. */
#include "config.h"
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "netcdf.h"
#include "ocinternal.h"
#include "ocdebug.h"
#include "nclog.h"
#include "ncwinpath.h"
#define OCRCFILEENV "DAPRCFILE"
#define RTAG ']'
#define LTAG '['
#define TRIMCHARS " \t\r\n"
static OCerror rc_search(const char* prefix, const char* rcfile, char** pathp);
static int rcreadline(FILE* f, char* more, int morelen);
static void rctrim(char* text);
static char* combinecredentials(const char* user, const char* pwd);
static void storedump(char* msg, struct OCTriple*, int ntriples);
/* Define default rc files and aliases, also defines search order*/
static char* rcfilenames[] = {".daprc",".dodsrc",NULL};
/* The Username and password are in the URL if the URL is of the form:
* http://<name>:<passwd>@<host>/....
*/
static int
occredentials_in_url(const char *url)
{
char *pos = strstr(url, "http://");
if (!pos)
return 0;
pos += 7;
if (strchr(pos, '@') && strchr(pos, ':'))
return 1;
return 0;
}
static OCerror
ocextract_credentials(const char *url, char **userpwd, char **result_url)
{
NCURI* parsed = NULL;
if(ncuriparse(url,&parsed) != NCU_OK)
return OCTHROW(OC_EBADURL);
if(parsed->user != NULL || parsed->password == NULL) {
ncurifree(parsed);
return OCTHROW(OC_EBADURL);
}
if(userpwd) *userpwd = combinecredentials(parsed->user,parsed->password);
ncurifree(parsed);
return OC_NOERR;
}
char*
occombinehostport(const NCURI* uri)
{
char* hp;
int len = 0;
if(uri->host == NULL)
return NULL;
else
len += strlen(uri->host);
if(uri->port != NULL)
len += strlen(uri->port);
hp = (char*)malloc(len+1);
if(hp == NULL)
return NULL;
if(uri->port == NULL)
occopycat(hp,len+1,1,uri->host);
else
occopycat(hp,len+1,3,uri->host,":",uri->port);
return hp;
}
static char*
combinecredentials(const char* user, const char* pwd)
{
int userPassSize;
char *userPassword;
if(user == NULL) user = "";
if(pwd == NULL) pwd = "";
userPassSize = strlen(user) + strlen(pwd) + 2;
userPassword = malloc(sizeof(char) * userPassSize);
if (!userPassword) {
nclog(NCLOGERR,"Out of Memory\n");
return NULL;
}
occopycat(userPassword,userPassSize-1,3,user,":",pwd);
return userPassword;
}
static int
rcreadline(FILE* f, char* more, int morelen)
{
int i = 0;
int c = getc(f);
if(c < 0) return 0;
for(;;) {
if(i < morelen) /* ignore excess characters */
more[i++]=c;
c = getc(f);
if(c < 0) break; /* eof */
if(c == '\n') break; /* eol */
}
/* null terminate more */
more[i] = '\0';
return 1;
}
/* Trim TRIMCHARS from both ends of text; */
static void
rctrim(char* text)
{
char* p = text;
size_t len;
int i;
len = strlen(text);
/* locate first non-trimchar */
for(;*p;p++) {
if(strchr(TRIMCHARS,*p) == NULL) break; /* hit non-trim char */
}
memmove(text,p,strlen(p)+1);
len = strlen(text);
/* locate last non-trimchar */
if(len > 0) {
for(i=(len-1);i>=0;i--) {
if(strchr(TRIMCHARS,text[i]) == NULL) {
text[i+1] = '\0'; /* elide trailing trimchars */
break;
}
}
}
}
int
ocparseproxy(OCstate* state, char* v)
{
/* Do not free these; they are pointers into v; free v instead */
char *host_pos = NULL;
char *port_pos = NULL;
if(v == NULL || strlen(v) == 0)
return OC_NOERR; /* nothing there*/
if (occredentials_in_url(v)) {
char *result_url = NULL;
ocextract_credentials(v, &state->proxy.userpwd, &result_url);
v = result_url;
}
/* allocating a bit more than likely needed ... */
host_pos = strstr(v, "http://");
if (host_pos)
host_pos += strlen("http://");
else
host_pos = v;
port_pos = strchr(host_pos, ':');
if (port_pos) {
size_t host_len;
char *port_sep = port_pos;
port_pos++;
*port_sep = '\0';
host_len = strlen(host_pos);
state->proxy.host = malloc(sizeof(char) * host_len + 1);
if (state->proxy.host == NULL)
return OCTHROW(OC_ENOMEM);
strncpy(state->proxy.host, host_pos, host_len);
state->proxy.host[host_len] = '\0';
state->proxy.port = atoi(port_pos);
} else {
size_t host_len = strlen(host_pos);
state->proxy.host = malloc(sizeof(char) * host_len + 1);
if (state->proxy.host == NULL)
return OCTHROW(OC_ENOMEM);
strncpy(state->proxy.host, host_pos, host_len);
state->proxy.host[host_len] = '\0';
state->proxy.port = 80;
}
#if 0
state->proxy.host[v_len] = '\0';
state->proxy.port = atoi(v);
s_len = strlen(v);
state->proxy.user = malloc(sizeof(char) * s_len + 1);
if (state->proxy.user == NULL)
return OC_ENOMEM;
strncpy(state->proxy.user, v, s_len);
state->proxy.user[s_len] = '\0';
p_len = strlen(v);
state->proxy.password = malloc(sizeof(char) * p_len + 1);
if (state->proxy.password == NULL)
return OCTHROW(OC_ENOMEM);
strncpy(state->proxy.password, v, p_len);
state->proxy.password[p_len] = '\0';
#endif /*0*/
if (ocdebug > 1) {
nclog(NCLOGNOTE,"host name: %s", state->proxy.host);
#ifdef INSECURE
nclog(NCLOGNOTE,"user+pwd: %s", state->proxy.userpwd);
#endif
nclog(NCLOGNOTE,"port number: %d", state->proxy.port);
}
if(v) free(v);
return OC_NOERR;
}
/* insertion sort the triplestore based on url */
static void
sorttriplestore(struct OCTriplestore* store)
{
int i, nsorted;
struct OCTriple* sorted = NULL;
if(store == NULL) return; /* nothing to sort */
if(store->ntriples <= 1) return; /* nothing to sort */
if(ocdebug > 2)
storedump("initial:",store->triples,store->ntriples);
sorted = (struct OCTriple*)malloc(sizeof(struct OCTriple)*store->ntriples);
if(sorted == NULL) {
nclog(NCLOGERR,"sorttriplestore: out of memory");
return;
}
nsorted = 0;
while(nsorted < store->ntriples) {
int largest;
/* locate first non killed entry */
for(largest=0;largest<store->ntriples;largest++) {
if(store->triples[largest].key[0] != '\0') break;
}
OCASSERT(store->triples[largest].key[0] != '\0');
for(i=0;i<store->ntriples;i++) {
if(store->triples[i].key[0] != '\0') { /* avoid empty slots */
int lexorder = strcmp(store->triples[i].host,store->triples[largest].host);
int leni = strlen(store->triples[i].host);
int lenlarge = strlen(store->triples[largest].host);
/* this defines the ordering */
if(leni == 0 && lenlarge == 0) continue; /* if no urls, then leave in order */
if(leni != 0 && lenlarge == 0) largest = i;
else if(lexorder > 0) largest = i;
}
}
/* Move the largest entry */
OCASSERT(store->triples[largest].key[0] != 0);
sorted[nsorted] = store->triples[largest];
store->triples[largest].key[0] = '\0'; /* kill entry */
nsorted++;
if(ocdebug > 2)
storedump("pass:",sorted,nsorted);
}
memcpy((void*)store->triples,(void*)sorted,sizeof(struct OCTriple)*nsorted);
free(sorted);
if(ocdebug > 1)
storedump("final .rc order:",store->triples,store->ntriples);
}
/* Create a triple store from a file */
static int
ocrc_compile(const char* path)
{
char line0[MAXRCLINESIZE+1];
FILE *in_file = NULL;
int linecount = 0;
struct OCTriplestore* ocrc = &ocglobalstate.rc.daprc;
ocrc->ntriples = 0; /* reset; nothing to free */
in_file = NCfopen(path, "r"); /* Open the file to read it */
if (in_file == NULL) {
nclog(NCLOGERR, "Could not open configuration file: %s",path);
return OC_EPERM;
}
for(;;) {
char *line,*key,*value;
int c;
if(!rcreadline(in_file,line0,sizeof(line0))) break;
linecount++;
if(linecount >= MAXRCLINES) {
nclog(NCLOGERR, ".rc has too many lines");
return 0;
}
line = line0;
/* check for comment */
c = line[0];
if (c == '#') continue;
rctrim(line); /* trim leading and trailing blanks */
if(strlen(line) == 0) continue;
if(strlen(line) >= MAXRCLINESIZE) {
nclog(NCLOGERR, "%s line too long: %s",path,line0);
continue; /* ignore it */
}
/* setup */
ocrc->triples[ocrc->ntriples].host[0] = '\0';
ocrc->triples[ocrc->ntriples].key[0] = '\0';
ocrc->triples[ocrc->ntriples].value[0] = '\0';
if(line[0] == LTAG) {
NCURI* uri;
char* url = ++line;
char* rtag = strchr(line,RTAG);
if(rtag == NULL) {
nclog(NCLOGERR, "Malformed [url] in %s entry: %s",path,line);
continue;
}
line = rtag + 1;
*rtag = '\0';
/* compile the url and pull out the host */
if(ncuriparse(url,&uri) != NCU_OK) {
nclog(NCLOGERR, "Malformed [url] in %s entry: %s",path,line);
continue;
}
strncpy(ocrc->triples[ocrc->ntriples].host,uri->host,MAXRCLINESIZE-1);
if(uri->port != NULL) {
strncat(ocrc->triples[ocrc->ntriples].host,":",MAXRCLINESIZE-1);
strncat(ocrc->triples[ocrc->ntriples].host,uri->port,MAXRCLINESIZE-1);
}
ncurifree(uri);
}
/* split off key and value */
key=line;
value = strchr(line, '=');
if(value == NULL)
value = line + strlen(line);
else {
*value = '\0';
value++;
}
strncpy(ocrc->triples[ocrc->ntriples].key,key,MAXRCLINESIZE-1);
if(*value == '\0')
strcpy(ocrc->triples[ocrc->ntriples].value,"1");/*dfalt*/
else
strncpy(ocrc->triples[ocrc->ntriples].value,value,(MAXRCLINESIZE-1));
rctrim( ocrc->triples[ocrc->ntriples].key);
rctrim( ocrc->triples[ocrc->ntriples].value);
OCDBG2("rc: key=%s value=%s",
ocrc->triples[ocrc->ntriples].key,
ocrc->triples[ocrc->ntriples].value);
ocrc->ntriples++;
}
fclose(in_file);
sorttriplestore(&ocglobalstate.rc.daprc);
return 1;
}
/* read and compile the rc file, if any */
OCerror
ocrc_load(void)
{
OCerror stat = OC_NOERR;
char* path = NULL;
if(ocglobalstate.rc.ignore) {
nclog(NCLOGDBG,"No runtime configuration file specified; continuing");
return OC_NOERR;
}
if(ocglobalstate.rc.loaded) return OC_NOERR;
/* locate the configuration files in the following order:
1. specified by set_rcfile
2. set by DAPRCFILE env variable
3. '.'
4. $HOME
*/
if(ocglobalstate.rc.rcfile != NULL) { /* always use this */
path = strdup(ocglobalstate.rc.rcfile);
} else if(getenv(OCRCFILEENV) != NULL && strlen(getenv(OCRCFILEENV)) > 0) {
path = strdup(getenv(OCRCFILEENV));
} else {
char** rcname;
int found = 0;
for(rcname=rcfilenames;!found && *rcname;rcname++) {
stat = rc_search(".",*rcname,&path);
if(stat == OC_NOERR && path == NULL) /* try $HOME */
stat = rc_search(ocglobalstate.home,*rcname,&path);
if(stat != OC_NOERR)
goto done;
if(path != NULL)
found = 1;
}
}
if(path == NULL) {
nclog(NCLOGDBG,"Cannot find runtime configuration file; continuing");
} else {
if(ocdebug > 0)
fprintf(stderr, "RC file: %s\n", path);
if(ocrc_compile(path) == 0) {
nclog(NCLOGERR, "Error parsing %s\n",path);
stat = OC_ERCFILE;
}
}
done:
ocglobalstate.rc.loaded = 1; /* even if not exists */
if(path != NULL)
free(path);
return stat;
}
OCerror
ocrc_process(OCstate* state)
{
OCerror stat = OC_NOERR;
char* value = NULL;
NCURI* uri = state->uri;
char* url_userpwd = NULL;
char* url_hostport = NULL;
if(!ocglobalstate.initialized)
ocinternalinitialize();
if(!ocglobalstate.rc.loaded)
ocrc_load();
/* Note, we still must do this function even if
ocglobalstate.rc.ignore is set in order
to getinfo e.g. user:pwd from url
*/
url_userpwd = combinecredentials(uri->user,uri->password);
url_hostport = occombinehostport(uri);
if(url_hostport == NULL)
return OC_ENOMEM;
value = ocrc_lookup("HTTP.DEFLATE",url_hostport);
if(value != NULL) {
if(atoi(value)) state->curlflags.compress = 1;
if(ocdebug > 0)
nclog(NCLOGNOTE,"HTTP.DEFLATE: %ld", state->curlflags.compress);
}
if((value = ocrc_lookup("HTTP.VERBOSE",url_hostport)) != NULL) {
if(atoi(value)) state->curlflags.verbose = 1;
if(ocdebug > 0)
nclog(NCLOGNOTE,"HTTP.VERBOSE: %ld", state->curlflags.verbose);
}
if((value = ocrc_lookup("HTTP.TIMEOUT",url_hostport)) != NULL) {
if(atoi(value)) state->curlflags.timeout = atoi(value);
if(ocdebug > 0)
nclog(NCLOGNOTE,"HTTP.TIMEOUT: %ld", state->curlflags.timeout);
}
if((value = ocrc_lookup("HTTP.USERAGENT",url_hostport)) != NULL) {
if(atoi(value)) state->curlflags.useragent = strdup(value);
if(state->curlflags.useragent == NULL) {stat = OC_ENOMEM; goto done;}
if(ocdebug > 0)
nclog(NCLOGNOTE,"HTTP.USERAGENT: %s", state->curlflags.useragent);
}
if(
(value = ocrc_lookup("HTTP.COOKIEFILE",url_hostport))
|| (value = ocrc_lookup("HTTP.COOKIE_FILE",url_hostport))
|| (value = ocrc_lookup("HTTP.COOKIEJAR",url_hostport))
|| (value = ocrc_lookup("HTTP.COOKIE_JAR",url_hostport))
) {
state->curlflags.cookiejar = strdup(value);
if(state->curlflags.cookiejar == NULL) {stat = OC_ENOMEM; goto done;}
if(ocdebug > 0)
nclog(NCLOGNOTE,"HTTP.COOKIEJAR: %s", state->curlflags.cookiejar);
}
if((value = ocrc_lookup("HTTP.PROXY_SERVER",url_hostport)) != NULL) {
stat = ocparseproxy(state,value);
if(stat != OC_NOERR) goto done;
if(ocdebug > 0)
nclog(NCLOGNOTE,"HTTP.PROXY_SERVER: %s", value);
}
if((value = ocrc_lookup("HTTP.SSL.VALIDATE",url_hostport)) != NULL) {
if(atoi(value)) {
state->ssl.verifypeer = 1;
state->ssl.verifyhost = 1;
if(ocdebug > 0)
nclog(NCLOGNOTE,"HTTP.SSL.VALIDATE: %ld", 1);
}
}
if((value = ocrc_lookup("HTTP.SSL.CERTIFICATE",url_hostport)) != NULL) {
state->ssl.certificate = strdup(value);
if(state->ssl.certificate == NULL) {stat = OC_ENOMEM; goto done;}
if(ocdebug > 0)
nclog(NCLOGNOTE,"HTTP.SSL.CERTIFICATE: %s", state->ssl.certificate);
}
if((value = ocrc_lookup("HTTP.SSL.KEY",url_hostport)) != NULL) {
state->ssl.key = strdup(value);
if(state->ssl.key == NULL) {stat = OC_ENOMEM; goto done;}
if(ocdebug > 0)
nclog(NCLOGNOTE,"HTTP.SSL.KEY: %s", state->ssl.key);
}
if((value = ocrc_lookup("HTTP.SSL.KEYPASSWORD",url_hostport)) != NULL) {
state->ssl.keypasswd = strdup(value);
if(state->ssl.keypasswd == NULL) {stat = OC_ENOMEM; goto done;}
if(ocdebug > 0)
nclog(NCLOGNOTE,"HTTP.SSL.KEYPASSWORD: %s", state->ssl.keypasswd);
}
if((value = ocrc_lookup("HTTP.SSL.CAINFO",url_hostport)) != NULL) {
state->ssl.cainfo = strdup(value);
if(state->ssl.cainfo == NULL) {stat = OC_ENOMEM; goto done;}
if(ocdebug > 0)
nclog(NCLOGNOTE,"HTTP.SSL.CAINFO: %s", state->ssl.cainfo);
}
if((value = ocrc_lookup("HTTP.SSL.CAPATH",url_hostport)) != NULL) {
state->ssl.capath = strdup(value);
if(state->ssl.capath == NULL) {stat = OC_ENOMEM; goto done;}
if(ocdebug > 0)
nclog(NCLOGNOTE,"HTTP.SSL.CAPATH: %s", state->ssl.capath);
}
if((value = ocrc_lookup("HTTP.SSL.VERIFYPEER",url_hostport)) != NULL) {
char* s = strdup(value);
int tf = 0;
if(s == NULL || strcmp(s,"0")==0 || strcasecmp(s,"false")==0)
tf = 0;
else if(strcmp(s,"1")==0 || strcasecmp(s,"true")==0)
tf = 1;
else
tf = 1; /* default if not null */
state->ssl.verifypeer = tf;
if(ocdebug > 0)
nclog(NCLOGNOTE,"HTTP.SSL.VERIFYPEER: %d", state->ssl.verifypeer);
free(s);
}
if((value = ocrc_lookup("HTTP.NETRC",url_hostport)) != NULL) {
if(state->curlflags.netrc != NULL)
free(state->curlflags.netrc);
state->curlflags.netrc = strdup(value);
if(state->curlflags.netrc == NULL) {stat = OC_ENOMEM; goto done;}
if(ocdebug > 0)
nclog(NCLOGNOTE,"HTTP.NETRC: %s", state->curlflags.netrc);
}
{ /* Handle various cases for user + password */
/* First, see if the user+pwd was in the original url */
char* userpwd = NULL;
char* user = NULL;
char* pwd = NULL;
if(url_userpwd != NULL)
userpwd = url_userpwd;
else {
user = ocrc_lookup("HTTP.CREDENTIALS.USER",url_hostport);
pwd = ocrc_lookup("HTTP.CREDENTIALS.PASSWORD",url_hostport);
userpwd = ocrc_lookup("HTTP.CREDENTIALS.USERPASSWORD",url_hostport);
}
if(userpwd == NULL && user != NULL && pwd != NULL) {
userpwd = combinecredentials(user,pwd);
state->creds.userpwd = userpwd;
} else if(userpwd != NULL)
state->creds.userpwd = strdup(userpwd);
}
done:
if(url_hostport != NULL) free(url_hostport);
return stat;
}
static struct OCTriple*
ocrc_locate(char* key, char* hostport)
{
int i,found;
struct OCTriplestore* ocrc = &ocglobalstate.rc.daprc;
struct OCTriple* triple;
if(ocglobalstate.rc.ignore)
return NULL;
if(!ocglobalstate.rc.loaded)
ocrc_load();
triple = ocrc->triples;
if(key == NULL || ocrc == NULL) return NULL;
if(hostport == NULL) hostport = "";
/* Assume that the triple store has been properly sorted */
for(found=0,i=0;i<ocrc->ntriples;i++,triple++) {
size_t hplen = strlen(triple->host);
int t;
if(strcmp(key,triple->key) != 0) continue; /* keys do not match */
/* If the triple entry has no url, then use it
(because we have checked all other cases)*/
if(hplen == 0) {found=1;break;}
/* do hostport match */
t = strcmp(hostport,triple->host);
if(t == 0) {found=1; break;}
}
return (found?triple:NULL);
}
char*
ocrc_lookup(char* key, char* hostport)
{
struct OCTriple* triple = ocrc_locate(key,hostport);
if(triple != NULL && ocdebug > 2) {
fprintf(stderr,"lookup %s: [%s]%s = %s\n",hostport,triple->host,triple->key,triple->value);
}
return (triple == NULL ? NULL : triple->value);
}
static void
storedump(char* msg, struct OCTriple* triples, int ntriples)
{
int i;
struct OCTriplestore* ocrc = &ocglobalstate.rc.daprc;
if(msg != NULL) fprintf(stderr,"%s\n",msg);
if(ocrc == NULL) {
fprintf(stderr,"<EMPTY>\n");
return;
}
if(triples == NULL) triples= ocrc->triples;
if(ntriples < 0 ) ntriples= ocrc->ntriples;
for(i=0;i<ntriples;i++) {
fprintf(stderr,"\t%s\t%s\t%s\n",
(strlen(triples[i].host)==0?"--":triples[i].host),
triples[i].key,
triples[i].value);
}
}
#if 0
/*
Lookup against all prefixes
*/
static char*
ocrc_lookup(char* suffix, char* url)
{
char* value = NULL;
char key[MAXRCLINESIZE+1];
const char** p = prefixes;
for(;*p;p++) {
if(!occopycat(key,sizeof(key),2,*p,suffix))
return NULL;
value = ocrc_lookup(key,url);
if(value != NULL)
return value;
}
return value;
}
/* compile the rc file, if any */
static OCerror
ocreadrc(void)
{
OCerror stat = OC_NOERR;
char* path = NULL;
/* locate the configuration files: first if specified,
then '.', then $HOME */
if(ocglobalstate.rc.rcfile != NULL) { /* always use this */
path = ocglobalstate.rc.rcfile;
} else {
char** rcname;
int found = 0;
for(rcname=rcfilenames;!found && *rcname;rcname++) {
stat = rc_search(".",*rcname,&path);
if(stat == OC_NOERR && path == NULL) /* try $HOME */
stat = rc_search(ocglobalstate.home,*rcname,&path);
if(stat != OC_NOERR)
goto done;
if(path != NULL)
found = 1;
}
}
if(path == NULL) {
nclog(NCLOGDBG,"Cannot find runtime configuration file; continuing");
} else {
if(ocdebug > 0)
fprintf(stderr, "DODS RC file: %s\n", path);
if(ocdodsrc_read(path) == 0) {
nclog(NCLOGERR, "Error parsing %s\n",path);
stat = OC_ERCFILE;
}
}
done:
if(path != NULL)
free(path);
return stat;
}
#endif
/**
* Prefix must end in '/'
*/
static
OCerror
rc_search(const char* prefix, const char* rcname, char** pathp)
{
char* path = NULL;
FILE* f = NULL;
int plen = strlen(prefix);
int rclen = strlen(rcname);
OCerror stat = OC_NOERR;
size_t pathlen = plen+rclen+1+1; /*+1 for '/' +1 for nul*/
path = (char*)malloc(pathlen);
if(path == NULL) {
stat = OC_ENOMEM;
goto done;
}
if(!occopycat(path,pathlen,3,prefix,"/",rcname)) {
stat = OC_EOVERRUN;
goto done;
}
/* see if file is readable */
f = NCfopen(path,"r");
done:
if(f == NULL || stat != OC_NOERR) {
if(path != NULL)
free(path);
path = NULL;
}
if(f != NULL)
fclose(f);
if(pathp != NULL)
*pathp = path;
else {
free(path);
path = NULL;
}
return OCTHROW(stat);
}
struct OCTriple*
ocrc_triple_iterate(char* key, char* url, struct OCTriple* prev)
{
struct OCTriple* next;
if(prev == NULL)
next = ocrc_locate(key,url);
else
next = prev+1;
if(next == NULL)
return NULL;
for(; strlen(next->key) > 0; next++) {
/* See if key as prefix still matches */
int cmp = strcmp(key,next->key);
if(cmp != 0) {next = NULL; break;} /* key mismatch */
/* compare url */
cmp = ocstrncmp(url,next->host,strlen(next->host));
if(cmp == 0) break;
}
return next;
}