301 lines
9.3 KiB
C
301 lines
9.3 KiB
C
|
/* This was the main function for the Prospero program vcache.
|
||
|
* return with status 0 if file retrieval was successful; nonzero if it was
|
||
|
* not. This is called only by p__map_cache(), in lib/pcompat/pmap_cache.c and
|
||
|
* by VGET in user/vget.c.
|
||
|
*
|
||
|
* The memory leaks have probably all been nailed by Mitra by now.
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
* Copyright (c) 1991-1994 by the University of Southern California
|
||
|
*
|
||
|
* For copying and distribution information, please see the file
|
||
|
* <usc-license.h>.
|
||
|
*/
|
||
|
|
||
|
#include <usc-license.h>
|
||
|
|
||
|
#include <stdio.h>
|
||
|
#include <sys/param.h>
|
||
|
#include <errno.h>
|
||
|
|
||
|
#include <pmachine.h> /*SCOUNIX needs sys/types.h*/
|
||
|
/* SOLARIS needs prototype for tempnam() */
|
||
|
|
||
|
/* #include "ftp_var.h" /* Nasty - doesnt declare these external */
|
||
|
extern int debug;
|
||
|
extern int trace;
|
||
|
extern int anonlogin;
|
||
|
|
||
|
#include "vcache.h"
|
||
|
#include <pfs.h>
|
||
|
#include <psite.h> /* for P_CACHE_ENABLED, among other
|
||
|
definitions. */
|
||
|
#include <perrno.h>
|
||
|
|
||
|
/* A lot of this code memory leaks - not a problem since it exits - but
|
||
|
a pain if going to incorporate inside anything else. */
|
||
|
|
||
|
/* Benjamin Britt wrote routines enabling VCACHE to retrieve files
|
||
|
using WAIS. These are not yet very useful, since modifications
|
||
|
need to be made to user/vget.c and lib/pfs/pget_am.c. Therefore, they are
|
||
|
commented out. #define WAIS and change the definitions of WAIS_LIBS and
|
||
|
WAIS_TARGETS in the Makefile in order to link them in, if you wish to
|
||
|
experiment with them and continue developing them. You will also need the
|
||
|
directory user/vcache/wais, which is not part of the standard distribution,
|
||
|
but will be sent on request.
|
||
|
|
||
|
#define WAIS
|
||
|
*/
|
||
|
|
||
|
#include "vcache_macros.h"
|
||
|
|
||
|
int cache_verbose = 0;
|
||
|
#define verbose cache_verbose
|
||
|
|
||
|
static int
|
||
|
prospero_contents_get(VLINK vl, char *local);
|
||
|
|
||
|
char *old_err_string = NULL;
|
||
|
|
||
|
void
|
||
|
vcache2_init()
|
||
|
{
|
||
|
debug = 0;
|
||
|
trace = 0;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* If called with the MANAGE argument set, will manage the cache (if compiled
|
||
|
* for cache management); otherwise won't. Also, won't
|
||
|
* This is an exported interface in Mitra's use of the Prospero library.
|
||
|
* Not an exported interface otherwise.
|
||
|
*
|
||
|
* Returns 0 on success, -1 on FAILURE.
|
||
|
*/
|
||
|
int
|
||
|
vcache2a(char *host, char *remote, char *local, char *method,
|
||
|
char *argv[], int manage_cache)
|
||
|
{
|
||
|
#ifndef P_CACHE_ENABLED
|
||
|
p__mkdirs(local, FALSE);
|
||
|
return vc_get_file_A(host,remote,local,method,argv);
|
||
|
#else
|
||
|
/* Add code here to manage the cache */
|
||
|
/* This code implements the algorithm ...
|
||
|
if (fetch to P_CACHE_TMP)
|
||
|
then mv from P_CACHE_TMP to local, overwriting
|
||
|
if local exists, then success, else failure
|
||
|
NOTE this means it wont default to return a file that exists already
|
||
|
but if the retrieval fails and the file exists then you'll get it
|
||
|
- If someone doesnt like this behaviour, then change it with options.
|
||
|
*/
|
||
|
|
||
|
char *tempfile = NULL;
|
||
|
int retval;
|
||
|
|
||
|
|
||
|
char *tempfile = NULL;
|
||
|
if (!manage_cache) {
|
||
|
p__mkdirs(local, FALSE);
|
||
|
return vc_get_file_A(host,remote,local,method,argv);
|
||
|
}
|
||
|
|
||
|
if (p__mkdirs(P_CACHE_TMP,TRUE)) {
|
||
|
/* p_err_string already set */
|
||
|
RETURN(-1);
|
||
|
}
|
||
|
tempfile = tempnam(P_CACHE_TMP,NULL);
|
||
|
|
||
|
if ((retval = vc_get_file_A(host,remote,tempfile,method,argv))
|
||
|
== 0) {
|
||
|
/* Succeeded in fetching file */
|
||
|
if (file_incache(local)) {
|
||
|
if (unlink(local)) {
|
||
|
ERRSYS("Cant unlink existing %s %s %s",local);
|
||
|
RETURN(-1);
|
||
|
}
|
||
|
}
|
||
|
if (p__mkdirs(local,FALSE)) {
|
||
|
/* p_err_string already set */
|
||
|
RETURN(-1);
|
||
|
}
|
||
|
if (renameOrCopyAndDelete(tempfile,local)) {
|
||
|
/* p_err_string set */
|
||
|
RETURN(-1);
|
||
|
}
|
||
|
RETURN(0);
|
||
|
} else {
|
||
|
/* Couldnt retrieve, maybe in the cache already */
|
||
|
if (file_incache(local))
|
||
|
RETURN(0);
|
||
|
RETURN(-1);
|
||
|
}
|
||
|
assert(0); /* Unreached */
|
||
|
cleanup:
|
||
|
free(tempfile);
|
||
|
return(retval);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Retrieve the file with the HSONAME REMOTE from the computer HOST.
|
||
|
* Retrieve it to the file LOCAL using access-method METHOD.
|
||
|
* Arguments to the access method in argv.
|
||
|
*/
|
||
|
int
|
||
|
vc_get_file_A(char *host, char *remote, char *local, char *method,
|
||
|
char *argv[])
|
||
|
{
|
||
|
int retval = 0;
|
||
|
char *slash;
|
||
|
int argc;
|
||
|
|
||
|
/* Set ARGC appropriately. */
|
||
|
for (argc = 0; argv[argc]; ++argc)
|
||
|
;
|
||
|
|
||
|
/* If no method provided, then we are done */
|
||
|
if(!method) return(0);
|
||
|
|
||
|
/* Make the directory to include the cached copy */
|
||
|
/* if it does not already exist */
|
||
|
if (p__mkdirs(local,FALSE)) {
|
||
|
/* p_err_string already set */
|
||
|
return(1);
|
||
|
}
|
||
|
|
||
|
anonlogin = strequal(method,"AFTP");
|
||
|
if(anonlogin || strcmp(method,"FTP") == 0) {
|
||
|
char *trans_mode;
|
||
|
if(argc != 1) {
|
||
|
ERR( "vcache: wrong number of arguments for %s%s", method);
|
||
|
return(1);
|
||
|
}
|
||
|
trans_mode = argv[0];
|
||
|
if(strcmp(trans_mode,"DIRECTORY") == 0) {
|
||
|
ERR("File is the directory %s on the host %s which may not be running Prospero%s",
|
||
|
remote,host);
|
||
|
return(1);
|
||
|
}
|
||
|
/* Note "aftpget" used to do a exit*/
|
||
|
return(aftpget(host,local,remote,trans_mode));
|
||
|
} else if (strequal(method, "PROSPERO-CONTENTS")) {
|
||
|
VLINK vl = vlalloc();
|
||
|
if(argc != 0) {
|
||
|
ERR("vcache: wrong number of arguments for %s%s", method);
|
||
|
vlfree(vl);
|
||
|
return(1);
|
||
|
}
|
||
|
vl->host = stcopyr(host, vl->host);
|
||
|
vl->hsoname = stcopyr(remote, vl->hsoname);
|
||
|
retval = prospero_contents_get(vl, local);
|
||
|
vlfree(vl);
|
||
|
if(retval) return(1);
|
||
|
else return(0);
|
||
|
} else if (strcmp(method, "GOPHER") == 0) {
|
||
|
extern char *strchr();
|
||
|
/* Remote file name is Gopher selector string. */
|
||
|
/* port # included in the hostname. */
|
||
|
/* Check validity of the argument. */
|
||
|
register char *cp = strchr(host, '(');
|
||
|
int gopherport;
|
||
|
int gophertype;
|
||
|
|
||
|
if (argc != 1) {
|
||
|
ERR("vcache: The GOPHER access method expects \
|
||
|
one additional argument. Got %d arguments.%s", argc);
|
||
|
return(1);
|
||
|
}
|
||
|
if (cp == NULL) {
|
||
|
ERR("vcache: The GOPHER access method requires \
|
||
|
that the specified hostname have a port number included. Got the hostname \
|
||
|
%s.%s", host);
|
||
|
return(1);
|
||
|
}
|
||
|
*cp++ = '\0'; /* terminate the hostname normally.
|
||
|
cp now points to the port start. */
|
||
|
gopherport = atoi(cp);
|
||
|
|
||
|
if (strlen(argv[0]) == 1) {
|
||
|
gophertype = *argv[0];
|
||
|
} else if (strequal(argv[0], "BINARY")) {
|
||
|
gophertype = '9'; /* generic binary type */
|
||
|
} else if (strequal(argv[0], "TEXT")) {
|
||
|
gophertype = '0'; /* generic text type */
|
||
|
} else {
|
||
|
ERR("Malformed argument to GOPHER access method.%s");
|
||
|
return(1);
|
||
|
}
|
||
|
if(retval = gopherget(host,local,remote,gopherport, gophertype))
|
||
|
return(1);
|
||
|
else
|
||
|
return(0);
|
||
|
} if (strcmp(method,"WAIS") == 0) {
|
||
|
|
||
|
/* Note that the remote file name is actually the docid */
|
||
|
retval = waisRetrieveFileByHsoname(local,remote);
|
||
|
return(retval ? 1 : 0 );
|
||
|
} else {
|
||
|
ERR("vcache: access method (%s) not supported.%s",method);
|
||
|
return(1);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static int
|
||
|
prospero_contents_get(VLINK vl, char *local)
|
||
|
{
|
||
|
PATTRIB at = NULL;
|
||
|
FILE *local_file = NULL; /* file pointer for local destination */
|
||
|
int retval = PSUCCESS; /* return from function */
|
||
|
int need_newline = 0; /* set to 1 if data didn't end with a newline
|
||
|
*/
|
||
|
/* Seek multiple instances of the attribute. */
|
||
|
|
||
|
for (at = pget_at(vl,"CONTENTS"); at; at = at->next) {
|
||
|
TOKEN seq = at->value.sequence;
|
||
|
if (strequal(at->aname, "CONTENTS") && at->avtype == ATR_SEQUENCE &&
|
||
|
((length(seq) >= 2
|
||
|
&& strequal(seq->token, "DATA"))
|
||
|
|| (length(seq) >= 3
|
||
|
&& strequal(seq->token, "TAGGED")))) {
|
||
|
/* Found one. Open the file */
|
||
|
if (!local_file) {
|
||
|
local_file = fopen(local, "w");
|
||
|
if (local_file == NULL) {
|
||
|
ERRSYS ( "vcache: Couldn't create the local file %s: %s",
|
||
|
local);
|
||
|
RETURN(PFAILURE);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
/* So, we now have a file open for output and something to put in it.
|
||
|
*/
|
||
|
if (need_newline) {
|
||
|
putc('\n', local_file);
|
||
|
need_newline = 0;
|
||
|
}
|
||
|
if (strequal(elt(seq, 0), "DATA")) {
|
||
|
p__fputbst(elt(seq, 1), local_file);
|
||
|
} else if (strequal(elt(seq, 0), "TAGGED")) {
|
||
|
char *s;
|
||
|
|
||
|
p__fputbst(elt(seq, 1), local_file);
|
||
|
fputs(": ", local_file);
|
||
|
need_newline = p__fputbst(elt(seq, 2), local_file);
|
||
|
} else
|
||
|
internal_error("Shouldn't get here with unrecognized attribute \
|
||
|
0th element.");
|
||
|
}
|
||
|
if (!local_file) {
|
||
|
ERR("vcache: Couldn't get remote object's CONTENTS attribute.%s");
|
||
|
RETURN(PFAILURE);
|
||
|
}
|
||
|
if (ferror(local_file)) retval = PFAILURE;
|
||
|
cleanup:
|
||
|
if (local_file) { if (fclose(local_file)) { retval = PFAILURE; } }
|
||
|
if (at) atfree(at);
|
||
|
return(retval);
|
||
|
}
|
||
|
|