archie/prospero/user/vcache/vcache.c
2024-05-27 16:13:40 +02:00

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