rem: NsFastGet(void *arg, Ns_Conn *conn)
add: Ns_FastPathOp(void *arg, Ns_Conn *conn)
context: static Ns_Callback FreeEntry;static void DecrEntry(File *);static int UrlIs(char *server, char *url, int dir);static int FastStat(char *file, struct stat *stPtr);static int FastReturn(NsServer *servPtr, Ns_Conn *conn, int status,    char *type, char *file, struct stat *stPtr);/* *---------------------------------------------------------------------- * NsFastpathCache -- * *	Initialize the fastpath cache. * * Results: *	Pointer to Ns_Cache. * * Side effects: *	None. * *---------------------------------------------------------------------- */Ns_Cache *NsFastpathCache(char *server, int size){    Ns_DString ds;    Ns_Cache *fpCache;    int keys;#ifdef _WIN32    keys = TCL_STRING_KEYS;#else    keys = FILE_KEYS;#endif    Ns_DStringInit(&ds);    Ns_DStringVarAppend(&ds, "nsfp:", server, NULL);    fpCache = Ns_CacheCreateSz(ds.string, keys, (size_t) size, FreeEntry);    Ns_DStringFree(&ds);    return fpCache;}/* *---------------------------------------------------------------------- * * Ns_ConnReturnFile -- * *	Send the contents of a file out the conn.  * * Results: *	NS_OK/NS_ERROR  * * Side effects: *	See FastReturn. * *---------------------------------------------------------------------- */intNs_ConnReturnFile(Ns_Conn *conn, int status, char *type, char *file){    struct stat st;    char *server;    NsServer *servPtr;        if (!FastStat(file, &st)) {    	return Ns_ConnReturnNotFound(conn);    }    server = Ns_ConnServer(conn);    servPtr = NsGetServer(server);    return FastReturn(servPtr, conn, status, type, file, &st);}/* *---------------------------------------------------------------------- * Ns_PageRoot -- * *      Return path name of the server pages directory. * * Results: *      Server pageroot or NULL on invalid server. * * Side effects: *      None. * *---------------------------------------------------------------------- */char *Ns_PageRoot(char *server){    NsServer *servPtr = NsGetServer(server);        return servPtr->fastpath.pageroot;}/* *---------------------------------------------------------------------- * Ns_SetUrlToFileProc -- * *      Set pointer to custom routine that acts like Ns_UrlToFile(); * * Results: *      None. * * Side effects: *      None. * *---------------------------------------------------------------------- */voidNs_SetUrlToFileProc(char *server, Ns_UrlToFileProc *procPtr){    NsServer *servPtr = NsGetServer(server);    servPtr->fastpath.url2file = procPtr;}/* *---------------------------------------------------------------------- * Ns_UrlToFile -- * *      Construct the filename that corresponds to a URL. * * Results: *      Return NS_OK on success or NS_ERROR on failure. * * Side effects: *      None. * *---------------------------------------------------------------------- */intNs_UrlToFile(Ns_DString *dsPtr, char *server, char *url){    NsServer *servPtr = NsGetServer(server);        return NsUrlToFile(dsPtr, servPtr, url);}/* *---------------------------------------------------------------------- * Ns_UrlIsFile, Ns_UrlIsDir -- * *      Check if a file/directory that corresponds to a URL exists. * * Results: *      Return NS_TRUE if the file exists and NS_FALSE otherwise. * * Side effects: *      None. * *---------------------------------------------------------------------- */intNs_UrlIsFile(char *server, char *url){    return UrlIs(server, url, 0);}intNs_UrlIsDir(char *server, char *url){    return UrlIs(server, url, 1);}static intUrlIs(char *server, char *url, int dir){    Ns_DString ds;    int is = NS_FALSE;    struct stat st;    Ns_DStringInit(&ds);    if (Ns_UrlToFile(&ds, server, url) == NS_OK &&	(stat(ds.string, &st) == 0) &&	((dir && S_ISDIR(st.st_mode)) ||	    (dir == NS_FALSE && S_ISREG(st.st_mode)))) {	is = NS_TRUE;    }    Ns_DStringFree(&ds);    return is;}/* *---------------------------------------------------------------------- * FastGetRestart -- * *	Construct the full URL and redirect internally. * * Results: *      See Ns_ConnRedirect(). * * Side effects: *      See Ns_ConnRedirect(). * *---------------------------------------------------------------------- */static intFastGetRestart(Ns_Conn *conn, char *page){    int		    status;    Ns_DString      ds;    Ns_DStringInit(&ds);    Ns_MakePath(&ds, conn->request->url, page, NULL);    status = Ns_ConnRedirect(conn, ds.string);    Ns_DStringFree(&ds);    return status;}/* *---------------------------------------------------------------------- * NsFastGet -- * *      Return the contents of a URL. * * Results: *      Return NS_OK for success or NS_ERROR for failure. * * Side effects: *      Contents of file may be cached in file cache. * *---------------------------------------------------------------------- */intNsFastGet(void *arg, Ns_Conn *conn){    Conn	   *connPtr = (Conn *) conn;    NsServer  	   *servPtr = connPtr->servPtr;    char	   *url = conn->request->url;    Ns_DString      ds;    struct stat	    st;    int             result, i;    Ns_DStringInit(&ds);    if (NsUrlToFile(&ds, servPtr, url) != NS_OK    	    || !FastStat(ds.string, &st)) {	goto notfound;    }    if (S_ISREG(st.st_mode)) {	/*	 * Return ordinary files as with Ns_ConnReturnFile.	 */	result = FastReturn(servPtr, conn, 200, NULL, ds.string, &st);    } else if (S_ISDIR(st.st_mode)) {	/*	 * For directories, search for a matching directory file and 	 * restart the connection if found.	 */    	for (i = 0; i < servPtr->fastpath.dirc; ++i) {	    Ns_DStringTrunc(&ds, 0);	    if (NsUrlToFile(&ds, servPtr, url) != NS_OK) {		goto notfound;	    }	    Ns_DStringVarAppend(&ds, "/", servPtr->fastpath.dirv[i], NULL);            if ((stat(ds.string, &st) == 0) && S_ISREG(st.st_mode)) {                if (url[strlen(url) - 1] != '/') {                    Ns_DStringTrunc(&ds, 0);                    Ns_DStringVarAppend(&ds, url, "/", NULL);                    result = Ns_ConnReturnRedirect(conn, ds.string);                } else {                    result = FastGetRestart(conn, servPtr->fastpath.dirv[i]);                }                goto done;            }        }    	/*	 * If no index file was found, invoke a directory listing	 * ADP or Tcl proc if configured.	 */	 	if (servPtr->fastpath.diradp != NULL) {	    result = Ns_AdpRequest(conn, servPtr->fastpath.diradp);	} else if (servPtr->fastpath.dirproc != NULL) {	    result = Ns_TclRequest(conn, servPtr->fastpath.dirproc);	} else {	    goto notfound;	}    } else { notfound:	result = Ns_ConnReturnNotFound(conn);    } done:    Ns_DStringFree(&ds);    return result;}/* *---------------------------------------------------------------------- * FreeEntry -- * *      Logically remove a cached file from file cache. * * Results: *      None. * * Side effects: *      None. * *---------------------------------------------------------------------- */static voidFreeEntry(void *arg){    File *filePtr = (File *) arg;    DecrEntry(filePtr);}