/* 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 * . */ #include #include #include #include #include /*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 #include /* for P_CACHE_ENABLED, among other definitions. */ #include /* 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); }