(FILECREATED "13-Mar-86 15:27:02" {PHYLUM}<LANNING>FILECACHE>FILECACHE.;21 191070 changes to: (MACROS \FCACHE.LOCALDEVICE MatchFileName KLUDGE WITH.FCACHE.ABORT.WINDOW) (VARS FILECACHECOMS) (FNS \FCACHE.CREATE.MSG.WINDOW \FCACHE.BUILD.DEVICE \FCACHE.BEFORELOGIN \FCACHE.\INTERNAL/SETPASSWORD \FCACHE.CLOSEFILE \FCACHE.GETFILENAME \FCACHE.OPENFILE \FCACHE.RENAMEFILE \FCACHE.REOPENFILE \FCACHE.SETFILEINFO \FCACHE.ENTRYINFO \FCACHE.RESOURCES.ERROR \FCACHE.WRITEOUT \FCACHE.RESTORE \FCACHE.LOOKUP \FCACHE.VERIFY FCACHE.DUMP \FCACHE.LOAD \FCACHE.MAKEROOM \FCACHE.DEVICE.EVENTFN \FCACHE.INITIALIZE.PROPS \FCACHE.USECACHE? \FCACHE.INITIALIZE FCACHE.VANQUISH \FCACHE.DIRECTORYNAMEP \FCACHE.IGNOREDATECHECK? \FCACHE.USELOCALDIRECTORY? \FCACHE.ADDENTRY \FCACHE.DUMP.ENTRY \FCACHE.RESTORE.ENTRY FCACHE.START \FCACHE.WRITEOUT.READNEWFILENAME \FCACHE.WRITEOUT.NEWFILENAME \FCACHE.BROWSE.CACHE \FCACHE.BROWSE.WHENSELECTEDFN CACHE.FILE FCACHE.DELETE.CACHE.ENTRY FCACHE.DIRTY? FCACHE.DUMP.FILE \FCACHE.DONE.OR.ABORTED.MSG \FCACHE.DELETE.ENTRY \FCACHE.AROUNDEXIT \FCACHE.DELETEFILE \FCACHE.GETFILEINFO FCACHE.DUMP.ALL \FCACHE.EVENTFN \FCACHE.CANONICAL.HOSTNAME \FCACHE.PRINT.PROMPT \FCACHE.INSPECT.PROPCOMMANDFN \FCACHE.GENERATE.LOCAL.FILES FILES.IN.ORDER? \FCACHE.GENERIC.DEVICE.TYPE \FCACHE.PRINT.MESSAGE? \FCACHE.HOSTUP? \FCACHE.FLUSH.INFOHOOK \FCACHE.WRITEOUT.WHENSELECTEDFN \FCACHE.GENERATE.FILES.DEPTH \FCACHE.NEXT.LOCAL.FILE MERGED.NEXTFILEFN \MERGED.NEXTFILEFN1 \FCACHE.REPAIR.FINDFILE \FCACHE.REPAIR.VERIFY \FCACHE.HOSTDEAD.WHENSELECTEDFN FCACHE.GENERIC.START \GETCACHEDEVICEFROMHOSTNAME \FCACHE.GENERATE.FILEINFO \FCACHE.BROWSE.COPYFN FCACHE.PUTPROP \FCACHE.BROWSE.REPAINTFN \FCACHE.INSPECT.TITLEFN \FCACHE.BROWSE.RECOMPUTE \FCACHE.BROWSER.SCAVENGE) (RECORDS MERGEDFILEGENSTATE LocalFileGenerator CACHENTRY) previous date: " 3-Feb-86 17:49:02" {PHYLUM}<LANNING>FILECACHE>FILECACHE.;3) (* Copyright (c) 1983, 1985, 1986 by Xerox Corporation. All rights reserved.) (PRETTYCOMPRINT FILECACHECOMS) (RPAQQ FILECACHECOMS ((* * The FileCache package, here before your eyes! * *) (COMS (* * Public functions for manipulating the cache) (FNS ADD.FILE.TO.CACHE? CACHE.FILE FCACHE.DELETE.CACHE.ENTRY FCACHE.DUMP.ALL FCACHE.GENERIC.START FCACHE.GENERIC.STOP FCACHE.GETPROP FCACHE.PRIVATE.FILE? FCACHE.PUTPROP FCACHE.START FCACHE.STOP FCACHE.CACHELIST FCACHE.DIRTY? FCACHE.DUMP.FILE FCACHE.DUMP) (PROP SETFN FCACHE.GETPROP) (TEMPLATES FCACHE.GETPROP FCACHE.PUTPROP) (INITVARS (FCACHE.GENERIC.DEVICE.TYPES (QUOTE (LEAF NSFILING))) (DON'T.CACHE.FILES NIL) (PRIVATE.FILES NIL)) (GLOBALVARS DON'T.CACHE.FILES PRIVATE.FILES FCACHE.GENERIC.DEVICE.TYPES)) (COMS (* * Used to be public, but now aren't advertised) (MACROS WITHOUT.FCACHE) (PROP ARGNAMES WITHOUT.FCACHE)) (COMS (* * Status messages to the user) (FNS \FCACHE.DONE.OR.ABORTED.MSG \FCACHE.PRINT.MESSAGE?) (INITVARS (*FILE-CACHE-MESSAGE-STREAM* PROMPTWINDOW)) (GLOBALVARS *FILE-CACHE-MESSAGE-STREAM* \FCACHE.MESSAGE.WINDOW.LOCK)) (COMS (* * Unscheduled user interaction stuff) (FNS \FCACHE.PRINT.PROMPT \FCACHE.CREATE.MSG.WINDOW) (DECLARE: DONTCOPY (MACROS WITH.FCACHE.ABORT.WINDOW)) (INITVARS (\ABORT.WINDOW.LOCK (CREATE.MONITORLOCK (QUOTE \ABORT.WINDOW.LOCK))) (\ABORT.WINDOW.LEFT 350) (\ABORT.WINDOW.BOTTOM 200) (\ABORT.WINDOW.WIDTH 425) (\ABORT.WINDOW.HEIGHT 150) (\FREE.ABORT.WINDOWS NIL)) (GLOBALVARS \ABORT.WINDOW.LOCK \ABORT.WINDOW.LEFT \ABORT.WINDOW.BOTTOM \ABORT.WINDOW.WIDTH \ABORT.WINDOW.HEIGHT \FREE.ABORT.WINDOWS)) (COMS (* * Functions for producing the device given the name) (FNS \GETUSERDEVICEFROMNAME \GETCACHEDEVICEFROMHOSTNAME \GETREALDEVICEFROMHOSTNAME \FCACHE.CANONICAL.HOSTNAME \FCACHE.GENERIC.DEVICE.TYPE)) (COMS (* * Functions for loading or removing a file into the cache) (FNS \FCACHE.DELETE.ENTRY \FCACHE.INVENTNAME \FCACHE.KEEPVERSIONS \FCACHE.LOAD \FCACHE.MAKE.LEGAL.FILENAME \FCACHE.MAKEROOM \FCACHE.MAKEROOM.DELETEABLE?) (INITVARS (\FCACHE.CACHELOCK (CREATE.MONITORLOCK (QUOTE \FCACHE.CACHELOCK))) (\FCACHE.CACHE.CHANGED.EVENT (CREATE.EVENT (QUOTE FCACHE.CHANGED))) (\FCACHE.CACHING.FILES NIL) (\FCACHE.LIST NIL) (\FCACHE.LIST.CHANGED? NIL) (\FCACHE.LOGFILE NIL)) (GLOBALVARS \FCACHE.CACHELOCK \FCACHE.CACHE.CHANGED.EVENT \FCACHE.CACHING.FILES \FCACHE.LIST \FCACHE.LIST.CHANGED? \FCACHE.LOGFILE)) (COMS (* * Scavenging functions) (FNS FCACHE.SCAVENGE) (FNS \FCACHE.REPAIR \FCACHE.REPAIR.FINDFILE \FCACHE.REPAIR.VERIFY) [INITVARS (FCACHE.SCAVENGE.IGNORE (QUOTE ((DANDELION FCACHE.POINTER FCACHE.LISTING FCACHE.LOG) (DOVE FCACHE.POINTER FCACHE.LISTING FCACHE.LOG) (DORADO FCACHE.POINTER FCACHE.LISTING FCACHE.LOG COM.CM DISKDESCRIPTOR. DMT.BOOT DUMPER.BOOT EXECUTIVE.RUN FTP.LOG FTP.RUN REM.CM SWAT. SWATEE. SYS.BOOT SYS.ERRORS SYSDIR. SYSFONT.AL USER.CM] (GLOBALVARS FCACHE.SCAVENGE.IGNORE)) (COMS (* * Functions for creating or destroying a cache device) (FNS \FCACHE.BUILD.DEVICE \FCACHE.OFF)) (COMS (* * Functions for dealing with device events, like LOGOUT) (FNS \FCACHE.DEVICE.EVENTFN \FCACHE.INITIALIZE.PROPS) (GLOBALVARS \FCACHE.DEVICE) (* Make sure the cache devices are at the top of the list of known devices before we do any device event -- in other words, a big HACK) (FNS \FCACHE.GLOBAL.EVENT) (APPENDVARS (AROUNDEXITFNS \FCACHE.GLOBAL.EVENT)) (* Before revalidating files, load the LOG file, if any -- in other words, a big HACK) (FNS \FCACHE.AROUNDEXIT)) (COMS (* * Catch changes to the current user / password) (* This is a HACK) (FNS \FCACHE.BEFORELOGIN \FCACHE.\INTERNAL/SETPASSWORD) (ADDVARS (\BEFORELOGINFNS \FCACHE.BEFORELOGIN)) (GLOBALVARS \BEFORELOGINFNS)) (COMS (* * Methods for the {FCACHE} file device. Note that methods that are not defined are not really needed since {FCACHE} is a specialization of the local device that holds the cache, and inherits all bin/bout like methods) (FNS \FCACHE.CLOSEFILE \FCACHE.DELETEFILE \FCACHE.DIRECTORYNAMEP \FCACHE.EVENTFN \FCACHE.GENERATEFILES \FCACHE.GETFILEINFO \FCACHE.GETFILENAME \FCACHE.HOSTNAMEP \FCACHE.OPENFILE \FCACHE.RENAMEFILE \FCACHE.REOPENFILE \FCACHE.SETFILEINFO) (* Helper fns) (FNS \FCACHE.ENTRYINFO)) (COMS (* * Directory enumeration functions) (FNS \FCACHE.GENERATE.FILEINFO \FCACHE.GENERATE.FILES.DEPTH \FCACHE.GENERATE.LOCAL.FILES \FCACHE.NEXT.LOCAL.FILE) (* Merging together two file generators) (FNS MERGE.FILEGENERATORS MERGED.FILEINFOFN MERGED.NEXTFILEFN \MERGED.NEXTFILEFN1 FILES.IN.ORDER?) (DECLARE: DONTCOPY (RECORDS MERGEDFILEGENSTATE LocalFileGenerator))) (COMS (* * Functions for finding a file in the cache) (FNS \FCACHE.LOOKUP \FCACHE.PROMOTE \FCACHE.USECACHE? \FCACHE.VERIFY) (MACROS MatchFileName)) (COMS (* * Try to figure out if a host is up) (FNS \FCACHE.HOSTUP? \NSFILING.ADDRESS \FCACHE.IGNOREDATECHECK? \FCACHE.USELOCALDIRECTORY? \FCACHE.HOSTDEAD.WHENSELECTEDFN) (INITVARS (FCACHE.DEAD.HOSTS NIL)) (GLOBALVARS FCACHE.DEAD.HOSTS)) (COMS (* * Functions for dealing with overflow of the cache) (FNS \FCACHE.RESOURCES.ERROR)) (COMS (* * Functions for writing out dirty files from the cache) (FNS \FCACHE.ENTRYOPEN? \FCACHE.FLUSH \FCACHE.WRITEOUT \FCACHE.WRITEOUT.NEWFILENAME \FCACHE.WRITEOUT.READNEWFILENAME \FCACHE.WRITEOUT.WHENSELECTEDFN) (VARS (\FCACHE.DUMPLOCK (CREATE.MONITORLOCK "File cache writout"))) (GLOBALVARS \FCACHE.DUMPLOCK)) (COMS (* * Functions for dumping and restoring information about the contents of the cache) (FNS \FCACHE.ADDENTRY \FCACHE.DUMP.ENTRY \FCACHE.FILEMATCH? \FCACHE.LOGENTRY \FCACHE.RESTORE \FCACHE.RESTORE.ENTRY) (VARS (\FCACHE.LISTING.VERSION.NUMBER NIL)) (GLOBALVARS \FCACHE.LISTING.VERSION.NUMBER)) (COMS (* * Functions for inspecting the cache) (FNS \FCACHE.FLUSH.INFOHOOK) (* Browsing thru the cache) (FNS \FCACHE.BROWSE.CACHE \FCACHE.BROWSE.COPYFN \FCACHE.BROWSE.PRINTFN \FCACHE.BROWSE.RECOMPUTE \FCACHE.BROWSE.WHENSELECTEDFN) (FILES READNUMBER TABLEBROWSER) (DECLARE: EVAL@COMPILE DONTCOPY DONTEVAL@LOAD (FILES TABLEBROWSERDECLS)) (INITVARS (\FCACHE.BROWSER NIL)) (BITMAPS \FCACHE.ICON) (GLOBALVARS \FCACHE.BROWSER \FCACHE.ICON) (* Inspecting the cache properties) (FNS \FCACHE.INSPECT.PROPCOMMANDFN \FCACHE.INSPECT.TITLEFN \FCACHE.INSPECT.VALUES \FCACHE.PROPERTY.NAMES)) (COMS (* * Data access functions) (DECLARE: DONTCOPY (MACROS \FCACHE.PROPERTY \FCACHE.PROPERTY.PUT \FCACHE.LOCALDEVICE)) (RECORDS CACHEDEVINFO CACHENTRY CACHEDEVICE) (FNS \FCACHE.DEVINFO \FCACHE.PUT.DEVINFO) (ADDVARS (\SYSTEMCACHEVARS \FCACHE.LOCALDEVICE)) (INITVARS (\FCACHE.LOCALDEVICE NIL) (\FCACHE.PROPERTIES (QUOTE (USECACHE T DEVICES NIL PREFIX NIL SIZE 0 MAXSIZE 10000 MAXFILEPAGES 600 UNSAFE ASK UNSAFE.TIMEOUT 30 UNSAFE.DEFAULT NIL SILENT NIL DUMPSLEEP 10000 DUMPIDLE 20 FASTDIR NIL KEEPVERSIONS 2 TIMETOVERIFY 5 BADDEVICES NIL))) (\FCACHE.PROMPT.WINDOW (CREATEW (CREATEREGION 200 200 500 100) "File cache prompt window" 15 T)) (\FCACHE.GENERIC.DEVICES NIL)) (GLOBALVARS \FCACHE.LOCALDEVICE \FCACHE.PROMPT.WINDOW \FCACHE.PROMPT.WINDOW.MONITORLOCK \FCACHE.PROPERTIES \FCACHE.GENERIC.DEVICES)) (* * Initialize things) (FNS \FCACHE.INITIALIZE FCACHE.VANQUISH) (DECLARE: DONTEVAL@LOAD DOCOPY (P (\FCACHE.INITIALIZE))) [COMS * (BQUOTE ((VARS (FCACHE.VERSION.DATE , (DATE)) (FCACHE.VERSION.NUMBER 5.1)) (GLOBALVARS FCACHE.VERSION.DATE FCACHE.VERSION.NUMBER] (* * Compile time magic) (DECLARE: EVAL@COMPILE DONTCOPY (MACROS REALDEVOP VersionlessFileName KLUDGE) (I.S.OPRS INUNSORTEDFILES) DONTEVAL@LOAD (* * This all depends on record defns from the system) (FILES NSFILING LLNS)))) (* * The FileCache package, here before your eyes! * *) (* * Public functions for manipulating the cache) (DEFINEQ (ADD.FILE.TO.CACHE? [LAMBDA (fileName) (* smL "30-Jan-86 17:06") (* * Should the file be added to the cache?) (NOT (for fileSpec in DON'T.CACHE.FILES thereis (\FCACHE.FILEMATCH? fileName ( DIRECTORY.FILL.PATTERN fileSpec "" "*"]) (CACHE.FILE [LAMBDA (fileName) (* smL "11-Feb-86 18:58") (* * Load the file into the cache) (RESETLST (LET ((fullName (INFILEP fileName))) (if (NULL fullName) then NIL elseif (\FCACHE.LOAD fullName) then fullName else NIL]) (FCACHE.DELETE.CACHE.ENTRY [LAMBDA (fileName) (* smL "11-Feb-86 18:54") (* * Delete the cache entry for the given file) (LET ((fullName (FINDFILE fileName))) (if fullName then (RESETLST (LET ((entry (\FCACHE.LOOKUP (\GETUSERDEVICEFROMNAME fullName) fullName))) (if entry then (\FCACHE.DELETE.ENTRY entry) else NIL))) else NIL]) (FCACHE.DUMP.ALL [LAMBDA NIL (* smL "11-Feb-86 16:11") (* * Cause an immediate flush of all dirty files) (ALLOW.BUTTON.EVENTS) (FCACHE.DUMP T) (printout *FILE-CACHE-MESSAGE-STREAM* T "Done writing out cache"]) (FCACHE.GENERIC.START [LAMBDA (deviceType) (* smL " 4-Feb-86 12:58") (* * remember that cache devices for this device are to be created on the fly) (DECLARE (GLOBALVARS \FILEDEVICES)) (LET [(genericDevice (for dev in \FILEDEVICES thereis (EQ (fetch DEVICENAME of dev) (U-CASE deviceType] (if (NULL genericDevice) then NIL else (* Make this undoable) (UNDOSAVE (LIST (FUNCTION FCACHE.GENERIC.STOP) deviceType)) (pushnew \FCACHE.GENERIC.DEVICES genericDevice) (for dev in \FILEDEVICES when (EQ (U-CASE deviceType) (\FCACHE.GENERIC.DEVICE.TYPE dev)) do (FCACHE.START (fetch DEVICENAME of dev))) genericDevice]) (FCACHE.GENERIC.STOP [LAMBDA (deviceType) (* smL "12-Aug-85 11:48") (* * undo the effect of an FCACHE.GENERIC.START) (DECLARE (GLOBALVARS \FILEDEVICES)) (LET [(device (for dev in \FILEDEVICES thereis (EQ (fetch DEVICENAME of dev) (U-CASE deviceType] (if (NULL device) then NIL else (SETQ \FCACHE.GENERIC.DEVICES (DREMOVE device \FCACHE.GENERIC.DEVICES)) device]) (FCACHE.GETPROP [LAMBDA (name) (* smL " 5-Aug-85 17:04") (* * Public function for getting file cache properties) (SELECTQ name (ENTRIES (LENGTH \FCACHE.LIST)) (DEVICES (for info in (\FCACHE.PROPERTY (QUOTE DEVICES)) collect (fetch REALDEVICENAME of info))) (DUMPSLEEP (QUOTIENT (\FCACHE.PROPERTY name) 1000)) (\FCACHE.PROPERTY name]) (FCACHE.PRIVATE.FILE? [LAMBDA (fullName) (* smL " 9-Aug-85 14:06") (* * Is this a private file) (for fileSpec in PRIVATE.FILES thereis (\FCACHE.FILEMATCH? fullName (DIRECTORY.FILL.PATTERN fileSpec "" "*"]) (FCACHE.PUTPROP [LAMBDA (name value) (* smL " 4-Feb-86 09:48") (* * Public function for setting file cache properties) (SELECTQ name ((DEVICES ENTRIES) (ERROR "Can't set that cache property " name)) [PREFIX (SETQ value (MKATOM value)) (if (for entry in \FCACHE.LIST thereis (NOT (\FCACHE.WRITEOUT entry))) then (ERROR "Can't flush a file, so can't switch cache prefix") else (FCACHE.DUMP T) (if (\FCACHE.RESTORE value) then (* update the cache devices) (for devInfo in (\FCACHE.PROPERTY (QUOTE DEVICES)) do (\FCACHE.EVENTFN (fetch CACHEDEV of devInfo) (QUOTE AFTERLOGOUT))) (* update the pointer file) (LET [(file (OPENFILE (QUOTE {DSK}FCache.pointer;1) (QUOTE OUTPUT) (QUOTE OLD/NEW] (PRINT value file) (CLOSEF file)) else (ERROR "Bad prefix " value] ((MAXSIZE MAXFILEPAGES UNSAFE.TIMEOUT TIMETOVERIFY) (if (NUMBERP value) then (SETQ \FCACHE.LIST.CHANGED? T) (\FCACHE.PROPERTY.PUT name value) else (ERROR "Value not a number" value))) (DUMPSLEEP (\FCACHE.PROPERTY.PUT name (TIMES value 1000))) [BADDEVICES (\FCACHE.PROPERTY.PUT name (for devName in value join (MKLIST ( \FCACHE.CANONICAL.HOSTNAME devName] (\FCACHE.PROPERTY.PUT name value)) value]) (FCACHE.START [LAMBDA (devname) (* smL "24-Feb-86 13:58") (* * Turn on caching for the given device) (if (NULL (\FCACHE.PROPERTY (QUOTE PREFIX))) then (printout *FILE-CACHE-MESSAGE-STREAM* T "No cache prefix, so can't start cache for " devname) NIL else (LET ((canonicalName (\FCACHE.CANONICAL.HOSTNAME devname))) (if (NULL canonicalName) then (printout *FILE-CACHE-MESSAGE-STREAM* T "No such host " devname) NIL elseif (for info in (\FCACHE.PROPERTY (QUOTE DEVICES)) thereis (EQ (fetch (CACHEDEVINFO REALDEVICENAME) of info) canonicalName)) elseif (MEMB (GETHOSTINFO canonicalName (QUOTE OS)) (QUOTE (UNIX))) then (* can't work with UNIX hosts. Sorry.) NIL else (LET ((cacheDevice (\FCACHE.BUILD.DEVICE canonicalName))) (if (\FCACHE.PRINT.MESSAGE?) then (printout *FILE-CACHE-MESSAGE-STREAM* T "Creating cache device for host " canonicalName)) (replace CACHEDEVINFO of cacheDevice with (create CACHEDEVINFO CACHEDEV ← cacheDevice REALDEVICENAME ← canonicalName)) (\DEFINEDEVICE (PACK* canonicalName (QUOTE -CACHE)) cacheDevice) (* Make this UNDOable) (if (NOT (FIND.PROCESS (QUOTE DUMP-FCACHE))) then (ADD.PROCESS (QUOTE (\FCACHE.FLUSH)) (QUOTE NAME) (QUOTE DUMP-FCACHE) (QUOTE RESTARTABLE) (QUOTE SYSTEM) (QUOTE INFOHOOK) (QUOTE \FCACHE.FLUSH.INFOHOOK))) (UNDOSAVE (LIST (FUNCTION FCACHE.STOP) canonicalName)) [FCACHE.PUTPROP (QUOTE BADDEVICES) (DREMOVE canonicalName (FCACHE.GETPROP (QUOTE BADDEVICES] cacheDevice]) (FCACHE.STOP [LAMBDA (devname) (* smL "14-Aug-85 14:01") (* * Turn off caching for the given device) (DECLARE (GLOBALVARS \OPENFILES)) (LET ((dev (\GETCACHEDEVICEFROMHOSTNAME devname T T)) stream entry) (if (NULL dev) then (* not turned on) NIL elseif [SETQ stream (for stream in \OPENFILES thereis (AND (EQ dev (fetch DEVICE of stream)) (STREAMPROP stream (QUOTE cacheEntry] then (* there is an open stream on the cache, so you can't turn off that device) (ERROR "Can't turn off cache -- file is open " (fetch FULLFILENAME of stream)) elseif [SETQ entry (for entry in \FCACHE.LIST thereis (AND (EQ dev (\GETCACHEDEVICEFROMHOSTNAME (FILENAMEFIELD (fetch REMOTEFILENAME of entry) (QUOTE HOST)) T T)) (NOT (\FCACHE.WRITEOUT entry] then (* can't flush a file on that device) (ERROR "Can't turn off cache because I can't write out the file " (fetch REMOTEFILENAME of entry)) else (* really can turn off caching) (pushnew (FCACHE.GETPROP (QUOTE BADDEVICES)) devname) (\FCACHE.OFF dev]) (FCACHE.CACHELIST [LAMBDA NIL (* smL "26-Apr-85 14:58") (* * What files are cached for this device) (for entry in \FCACHE.LIST collect (fetch REMOTEFILENAME of entry]) (FCACHE.DIRTY? [LAMBDA (fileName) (* smL "11-Feb-86 18:54") (* * Is the entry for this file dirty?) (RESETLST (LET ((entry (\FCACHE.LOOKUP (\GETCACHEDEVICEFROMHOSTNAME (FILENAMEFIELD fileName (QUOTE HOST))) fileName T))) (if entry then (fetch CACHEISDIRTY of entry) else NIL]) (FCACHE.DUMP.FILE [LAMBDA (fileName) (* smL "11-Feb-86 18:55") (* * Flush a single file to the server) (RESETLST (LET ((entry (\FCACHE.LOOKUP (\GETCACHEDEVICEFROMHOSTNAME (FILENAMEFIELD fileName (QUOTE HOST))) fileName T))) (if (AND entry (fetch CACHEISDIRTY of entry) (NOT (\FCACHE.ENTRYOPEN? entry))) then (\FCACHE.WRITEOUT entry) fileName else NIL]) (FCACHE.DUMP [LAMBDA (onlyIfChanged) (* smL "12-Mar-86 13:31") (* * Dump out the cache info) (* always dump out dirty files) (WITH.MONITOR \FCACHE.DUMPLOCK [if (\FCACHE.PROPERTY (QUOTE PREFIX)) then (for entry in \FCACHE.LIST do (if (NOT (\FCACHE.WRITEOUT entry)) then (* could not dump the file, so warn the user) (if (\FCACHE.PRINT.MESSAGE?) then (printout *FILE-CACHE-MESSAGE-STREAM* T "Could not dump the file " (fetch REMOTEFILENAME of entry] (if (AND onlyIfChanged (NOT \FCACHE.LIST.CHANGED?)) then (* nothing changed, so don't bother to dump) NIL elseif (\FCACHE.PROPERTY (QUOTE PREFIX)) then (RESETLST (\FCACHE.DONE.OR.ABORTED.MSG "Dumping cache listing") (LET [(stream (OPENSTREAM (PACK* (\FCACHE.PROPERTY (QUOTE PREFIX) ) "FCache.Listing;1") (QUOTE OUTPUT) (QUOTE OLD/NEW] (RESETSAVE NIL (LIST (QUOTE CLOSEF?) stream)) (* Put a warning message at the head of the info file) (PRINT [BQUOTE (ERROR "This file cannot be LOADed. Do not delete or alter this file!" (QUOTE (FCacheVersion , FCACHE.VERSION.NUMBER MaxSize , (\FCACHE.PROPERTY (QUOTE MAXSIZE)) MaxFilePages , (\FCACHE.PROPERTY (QUOTE MAXFILEPAGES] stream) (for f in \FCACHE.LIST do (\FCACHE.DUMP.ENTRY f stream) (if (\FCACHE.PRINT.MESSAGE?) then (printout *FILE-CACHE-MESSAGE-STREAM* ".") (FORCEOUTPUT *FILE-CACHE-MESSAGE-STREAM*))) (* Print out a little msg so we can tell if the whole file got written out.) (PRINT (QUOTE STOP) stream) (CLOSEF? stream)) (if (AND (STREAMP \FCACHE.LOGFILE) (OPENP \FCACHE.LOGFILE)) then (replace USERCLOSEABLE of \FCACHE.LOGFILE with T) (DELFILE (CLOSEF \FCACHE.LOGFILE)) (SETQ \FCACHE.LOGFILE NIL)) (SETQ \FCACHE.LIST.CHANGED? NIL]) ) (PUTPROPS FCACHE.GETPROP SETFN FCACHE.PUTPROP) (SETTEMPLATE (QUOTE FCACHE.GETPROP) (QUOTE (EVAL PROP . PPE))) (SETTEMPLATE (QUOTE FCACHE.PUTPROP) (QUOTE (EVAL PROP EVAL . PPE))) (RPAQ? FCACHE.GENERIC.DEVICE.TYPES (QUOTE (LEAF NSFILING))) (RPAQ? DON'T.CACHE.FILES NIL) (RPAQ? PRIVATE.FILES NIL) (DECLARE: DOEVAL@COMPILE DONTCOPY (GLOBALVARS DON'T.CACHE.FILES PRIVATE.FILES FCACHE.GENERIC.DEVICE.TYPES) ) (* * Used to be public, but now aren't advertised) (DECLARE: EVAL@COMPILE [PUTPROPS WITHOUT.FCACHE MACRO (...forms (BQUOTE (RESETLST [RESETSAVE (FCACHE.PUTPROP (QUOTE USECACHE) NIL) (LIST (QUOTE FCACHE.PUTPROP) (QUOTE USECACHE) (FCACHE.GETPROP (QUOTE USECACHE] ,@ ...forms] ) (PUTPROPS WITHOUT.FCACHE ARGNAMES (form1 ... formN)) (* * Status messages to the user) (DEFINEQ (\FCACHE.DONE.OR.ABORTED.MSG [LAMBDA (entermsg) (* smL "11-Feb-86 18:21") (* * Printout the entermsg when starting, then printout a "done" or "aborted" message in the FCache message window, depending how we are unwinding. Assumes we are inside of a RESETLST) (if (\FCACHE.PRINT.MESSAGE?) then (RESETSAVE (printout *FILE-CACHE-MESSAGE-STREAM* T "[" entermsg "]") (LIST (FUNCTION [LAMBDA (msg) (printout *FILE-CACHE-MESSAGE-STREAM* T "[" (if RESETSTATE then "Aborted" else "Done") ": " msg "]"]) entermsg]) (\FCACHE.PRINT.MESSAGE? [LAMBDA NIL (* smL " 6-Feb-86 16:26") (* * Is printing to the file cache message stream enabled?) (AND *FILE-CACHE-MESSAGE-STREAM* (NOT (\FCACHE.PROPERTY (QUOTE SILENT))) (if (WINDOWP *FILE-CACHE-MESSAGE-STREAM*) then (OPENWP *FILE-CACHE-MESSAGE-STREAM*) elseif (STREAMP *FILE-CACHE-MESSAGE-STREAM*) then (OPENP *FILE-CACHE-MESSAGE-STREAM* (QUOTE OUTPUT)) else NIL]) ) (RPAQ? *FILE-CACHE-MESSAGE-STREAM* PROMPTWINDOW) (DECLARE: DOEVAL@COMPILE DONTCOPY (GLOBALVARS *FILE-CACHE-MESSAGE-STREAM* \FCACHE.MESSAGE.WINDOW.LOCK) ) (* * Unscheduled user interaction stuff) (DEFINEQ (\FCACHE.PRINT.PROMPT [LAMBDA (window msgsLines) (* smL "10-Feb-86 18:07") (* * Clears the windows promptwindow and prints the msgs to it. If the promptwindow isn't big enough, makes it grow grow. Return the prompt window.) (LET* [(pwindow (GETPROMPTWINDOW (MAINWINDOW window T))) (font (DSPFONT NIL pwindow)) (width (WINDOWPROP pwindow (QUOTE WIDTH] [SETQ pwindow (GETPROMPTWINDOW (MAINWINDOW window T) (for line in msgsLines sum (FIX (PLUS .9 (FQUOTIENT (STRINGWIDTH line font) width] (CLEARW pwindow) (for line in msgsLines do (printout pwindow T line)) pwindow]) (\FCACHE.CREATE.MSG.WINDOW [LAMBDA NIL (* smL "13-Mar-86 14:16") (* * Create a new window to display an error msg from the cacher) (CREATEW (CREATEREGION 550 100 450 300) "FileCache ERROR" 10]) ) (DECLARE: DONTCOPY (DECLARE: EVAL@COMPILE (DEFMACRO WITH.FCACHE.ABORT.WINDOW (windowVar &REST forms) (* * Evaluate the forms with the windowVar bound to an unused abort window - Note that this assumes it is operating within a RESETLST) (BQUOTE (LET [(, windowVar (WITH.MONITOR \ABORT.WINDOW.LOCK (OR (pop \FREE.ABORT.WINDOWS) (PROGN (SETQ \ABORT.WINDOW.LEFT (MAX 0 (DIFFERENCE \ABORT.WINDOW.LEFT 20)) ) (SETQ \ABORT.WINDOW.BOTTOM (MAX 0 (DIFFERENCE \ABORT.WINDOW.BOTTOM 20)) ) (CREATEW (CREATEREGION \ABORT.WINDOW.LEFT \ABORT.WINDOW.BOTTOM \ABORT.WINDOW.WIDTH \ABORT.WINDOW.HEIGHT) NIL NIL T] (RESETSAVE NIL (LIST (FUNCTION [LAMBDA (abortWindow) (WINDOWPROP abortWindow (QUOTE TITLE) NIL) (for menu in (WINDOWPROP abortWindow (QUOTE MENU)) do (DELETEMENU menu NIL abortWindow)) (CLEARW abortWindow) (CLOSEW abortWindow) (push \FREE.ABORT.WINDOWS abortWindow]) , windowVar)) ,@ forms))) ) ) (RPAQ? \ABORT.WINDOW.LOCK (CREATE.MONITORLOCK (QUOTE \ABORT.WINDOW.LOCK))) (RPAQ? \ABORT.WINDOW.LEFT 350) (RPAQ? \ABORT.WINDOW.BOTTOM 200) (RPAQ? \ABORT.WINDOW.WIDTH 425) (RPAQ? \ABORT.WINDOW.HEIGHT 150) (RPAQ? \FREE.ABORT.WINDOWS NIL) (DECLARE: DOEVAL@COMPILE DONTCOPY (GLOBALVARS \ABORT.WINDOW.LOCK \ABORT.WINDOW.LEFT \ABORT.WINDOW.BOTTOM \ABORT.WINDOW.WIDTH \ABORT.WINDOW.HEIGHT \FREE.ABORT.WINDOWS) ) (* * Functions for producing the device given the name) (DEFINEQ (\GETUSERDEVICEFROMNAME [LAMBDA (name noError? dontCreate?) (* smL "16-Aug-85 16:04") (* * Replaces the function \GETDEVICEFROMNAME so that generic file system code will go thru the cache) (OR [if (AND (OR (LITATOM name) (STRINGP name)) (\FCACHE.PROPERTY (QUOTE USECACHE)) (\FCACHE.PROPERTY (QUOTE PREFIX))) then (LET ((hostName (OR (FILENAMEFIELD name (QUOTE HOST)) name))) (OR (\GETCACHEDEVICEFROMHOSTNAME hostName T dontCreate?) (\GETREALDEVICEFROMHOSTNAME hostName dontCreate? (\GETCACHEDEVICEFROMHOSTNAME hostName T T] (\GETDEVICEFROMNAME name noError? dontCreate?]) (\GETCACHEDEVICEFROMHOSTNAME [LAMBDA (devname noError? dontCreate?) (* smL " 4-Feb-86 12:59") (* * Return the cache device, if it exists, otherwise the real device) (PROG (devInfo canonicalName realDevice) (* * Works like this - if there is already a cache device by the given name, use it - if the canonical name is different, see if there is a cache device by that name - if there is already a real device, use it - it we are told to create a device and this is a genericly started cache device, start up the cache on it - finally just create and return the real device) (* If there is already a cache device, use it) (SETQ devInfo (for info in (\FCACHE.PROPERTY (QUOTE DEVICES)) thereis (EQ (fetch (CACHEDEVINFO REALDEVICENAME) of info) devname))) [COND (devInfo (RETURN (fetch (CACHEDEVINFO CACHEDEV) of devInfo] (* See if there is a cache device for this host under a different name) (SETQ canonicalName (OR (\FCACHE.CANONICAL.HOSTNAME devname) devname)) [COND ((AND canonicalName (NEQ devname canonicalName)) (SETQ devInfo (for info in (\FCACHE.PROPERTY (QUOTE DEVICES)) thereis (EQ (fetch (CACHEDEVINFO REALDEVICENAME) of info) canonicalName))) (COND (devInfo (RETURN (fetch (CACHEDEVINFO CACHEDEV) of devInfo] (* If we should generically start it, go ahead and make a new cache devcie) (SETQ realDevice (\GETDEVICEFROMNAME canonicalName T T)) [COND ([AND (NOT dontCreate?) (NOT (for name in (\FCACHE.PROPERTY (QUOTE BADDEVICES)) thereis (EQ canonicalName name))) (if realDevice then (for dev in \FCACHE.GENERIC.DEVICES thereis (EQ (\FCACHE.GENERIC.DEVICE.TYPE realDevice) (fetch DEVICENAME of dev))) else (for dev in \FCACHE.GENERIC.DEVICES thereis (FDEVOP (QUOTE HOSTNAMEP) dev canonicalName] (* we should create the device on the fly) (RETURN (OR (FCACHE.START canonicalName) (\GETDEVICEFROMNAME canonicalName noError? dontCreate?] (* nope, so just go with the generic system code) (RETURN (OR realDevice (\GETDEVICEFROMNAME canonicalName noError? dontCreate?]) (\GETREALDEVICEFROMHOSTNAME [LAMBDA (name dontCreate? ignoreDevice) (* smL " 7-Aug-85 17:06") (* * Used by the cacher to get the REAL device for this name. This is a clone of the function \GETDEVICEFROMHOSTNAME, except that this excludes the given device from consideration.) (DECLARE (GLOBALVARS \DEVICENAMETODEVICE \FILEDEVICES)) (OR [CDR (for devNamePair in \DEVICENAMETODEVICE when (NEQ ignoreDevice (CDR devNamePair)) thereis (EQ name (CAR devNamePair] [PROGN (SETQ name (U-CASE name)) (CDR (for devNamePair in \DEVICENAMETODEVICE when (NOT (EQ ignoreDevice (CDR devNamePair))) thereis (EQ name (CAR devNamePair] (AND (NOT dontCreate?) (for dev in \FILEDEVICES bind temp when (AND (NEQ ignoreDevice dev) (SETQ temp (FDEVOP (QUOTE HOSTNAMEP) dev name dev))) do (if (type? FDEV temp) then (SETQ dev temp)) (\DEFINEDEVICE name dev) (RETURN dev]) (\FCACHE.CANONICAL.HOSTNAME [LAMBDA (name) (* smL "11-Feb-86 16:25") (* * Get the "canonical" hostname for the device) (* * This is more or less what the standard CANONICAL.HOSTNAME function should be doing, but doesn't. In fact, this is the same as CANONICAL.HOSTNAME except for the first test in the COND) (* * NOTE that for "internal" predefined device, this will NOT talk on the net) (U-CASE (MKATOM (LET ((dev (\GETDEVICEFROMNAME name T T))) (if [AND dev (NOT (MEMB (fetch DEVICENAME of dev) (QUOTE (DPUPFTP] then (* It's a good bet that the device is an internal one) (fetch DEVICENAME of dev) elseif (STRPOS ":" (OR (FILENAMEFIELD name (QUOTE HOST)) name)) then (\CANONICAL.NSHOSTNAME (OR (FILENAMEFIELD name (QUOTE HOST)) name)) else (\CANONICAL.HOSTNAME (OR (FILENAMEFIELD name (QUOTE HOST)) name]) (\FCACHE.GENERIC.DEVICE.TYPE [LAMBDA (device) (* smL " 6-Feb-86 14:09") (* * HACK: This tries to figure out what the "generic" type of a device is, either LEAF or NSFILING. Should be a field in the device or something.) (KLUDGE (SELECTQ (fetch OPENFILE of device) (\LEAF.OPENFILE (QUOTE LEAF)) (\NSFILING.OPENFILE (QUOTE NSFILING)) NIL]) ) (* * Functions for loading or removing a file into the cache) (DEFINEQ (\FCACHE.DELETE.ENTRY [LAMBDA (entry) (* smL "12-Feb-86 09:43") (* * Delete a cache entry) (WITH.MONITOR \FCACHE.CACHELOCK (OBTAIN.MONITORLOCK (fetch CACHELOCK of entry) NIL T) (LET ((size (fetch CACHEFILELENGTH of entry))) (* Flush the entry if it is dirty) (if (\FCACHE.ENTRYOPEN? entry) then (ERROR "Cached file is open, so can't delete entry for file " (fetch REMOTEFILENAME of entry))) (* Get rid of the file) (\FCACHE.DONE.OR.ABORTED.MSG (CONCAT "Deleting entry " (fetch REMOTEFILENAME of entry))) (* A hack to make sure that the server is really ready) (CLEAR.LEAF.CACHE (FILENAMEFIELD (fetch REMOTEFILENAME of entry) (QUOTE HOST))) (DELFILE (fetch LOCALFILENAME of entry)) (* Now forget about the entry) (change \FCACHE.LIST (DREMOVE entry DATUM)) (\FCACHE.PROPERTY.PUT (QUOTE SIZE) (DIFFERENCE (\FCACHE.PROPERTY (QUOTE SIZE)) size]) (\FCACHE.INVENTNAME [LAMBDA (REMOTENAME) (* smL "22-Jul-85 10:35") (* * Remote files are cached in a file with the same name) (LET ((FIELDS (UNPACKFILENAME REMOTENAME))) (PACK* (\FCACHE.PROPERTY (QUOTE PREFIX)) (OR (\FCACHE.MAKE.LEGAL.FILENAME (LISTGET FIELDS (QUOTE NAME))) "") (QUOTE ".") (OR (\FCACHE.MAKE.LEGAL.FILENAME (LISTGET FIELDS (QUOTE EXTENSION))) ""]) (\FCACHE.KEEPVERSIONS [LAMBDA (fullFileName keepVersions) (* smL "14-Aug-85 10:26") (* * Take older versions of the file and put them at the end of the cache list) (if [OR (NOT (NUMBERP keepVersions)) (LESSP keepVersions 1) (NOT (NUMBERP (FILENAMEFIELD fullFileName (QUOTE VERSION] then (* don't bother) NIL else (for e in (for entry in \FCACHE.LIST bind (versionlessName ←(U-CASE (VersionlessFileName fullFileName))) (oldestVersion ←(ADD1 (DIFFERENCE (FILENAMEFIELD fullFileName (QUOTE VERSION)) keepVersions))) when (AND (EQ versionlessName (VersionlessFileName (fetch MATCHFILENAME of entry))) (LESSP (OR (FILENAMEFIELD (fetch MATCHFILENAME of entry) (QUOTE VERSION)) oldestVersion) oldestVersion)) collect entry) do (* move the entry to the end) (SETQ \FCACHE.LIST (NCONC1 (DREMOVE e \FCACHE.LIST) e]) (\FCACHE.LOAD [LAMBDA (fullName) (* smL "13-Mar-86 10:04") (* * Load up a global file into the cache, returning the entry, or NIL if the load fails - NOTE: This fn returns holding the entry's CACHELOCK. It should only be called within a RESETLST!) (PROG (inStream remoteDevice outStream localFileName length idate entry inProgress?) (* This first loop takes care of the possibility that another process is already busy caching the file) CheckCache [WITH.MONITOR \FCACHE.CACHELOCK (SETQ entry (\FCACHE.LOOKUP (\GETUSERDEVICEFROMNAME fullName) fullName T)) (if (NULL entry) then (SETQ inProgress? (MEMBER fullName \FCACHE.CACHING.FILES] (if entry then (GO Exit) elseif inProgress? then (AWAIT.EVENT \FCACHE.CACHE.CHANGED.EVENT) (GO CheckCache) else (RESETSAVE (push \FCACHE.CACHING.FILES fullName) (LIST (FUNCTION [LAMBDA (file) (SETQ \FCACHE.CACHING.FILES (DREMOVE file \FCACHE.CACHING.FILES)) (NOTIFY.EVENT \FCACHE.CACHE.CHANGED.EVENT]) fullName))) (* Try to open the remote file) [SETQ inStream (OPENSTREAM fullName (QUOTE INPUT) (QUOTE OLD) (QUOTE (FCACHE.INTERNAL SEQUENTIAL] (if (NULL inStream) then (GO Exit) else (push \FCACHE.CACHING.FILES fullName)) (RESETSAVE NIL (LIST (FUNCTION CLOSEF?) inStream)) (replace USERVISIBLE of inStream with NIL) (SETQ fullName (fetch FULLFILENAME of inStream)) (SETQ remoteDevice (fetch DEVICE of inStream)) (SETQ length (OR (GETFILEINFO inStream (QUOTE SIZE)) 0)) (* See if the file is too big to cache) (if (LET [(maxLength (\FCACHE.PROPERTY (QUOTE MAXFILEPAGES] (AND maxLength (IGREATERP length maxLength))) then (CLOSEF? inStream) (GO Exit)) (* Make sure there is enough room for the file) (\FCACHE.KEEPVERSIONS fullName (\FCACHE.PROPERTY (QUOTE KEEPVERSIONS))) (if (OR (NOT (ADD.FILE.TO.CACHE? fullName)) (NOT (\FCACHE.MAKEROOM length))) then (CLOSEF? inStream) (GO Exit)) (SETQ idate (FDEVOP (QUOTE GETFILEINFO) remoteDevice inStream (QUOTE ICREATIONDATE) remoteDevice)) (\FCACHE.DONE.OR.ABORTED.MSG (CONCAT "Caching " fullName)) [SETQ outStream (OPENSTREAM (\FCACHE.INVENTNAME fullName) (QUOTE OUTPUT) (QUOTE NEW) NIL (BQUOTE (FCACHE.INTERNAL SEQUENTIAL (TYPE , (FDEVOP (QUOTE GETFILEINFO) remoteDevice inStream (QUOTE TYPE) remoteDevice)) (ICREATIONDATE , idate) (LENGTH , (OR (FDEVOP (QUOTE GETFILEINFO) remoteDevice inStream (QUOTE LENGTH) remoteDevice) 0] (if outStream then (RESETSAVE NIL (LIST (FUNCTION CLOSEF?) outStream)) (replace USERVISIBLE of outStream with NIL) (SETQ localFileName (fetch FULLFILENAME of outStream)) (COPYCHARS inStream outStream) (CLOSEF inStream) (CLOSEF outStream) (* this SETFILEINFO is needed in case the local device does not do the right thing with the ICREATIONDATE in the OPENSTREAM above. This ensures that the date of the local file matches the remote file) (SETFILEINFO outStream (QUOTE ICREATIONDATE) idate) (SETQ entry (\FCACHE.ADDENTRY localFileName fullName idate (GETFILEINFO inStream (QUOTE PLIST)) length)) (replace TIMELASTVERIFIED of entry with (OR (IDATE) 0))) Exit(SETQ \FCACHE.CACHING.FILES (DREMOVE fullName \FCACHE.CACHING.FILES)) (if entry then (OBTAIN.MONITORLOCK (fetch CACHELOCK of entry) NIL T)) (RETURN entry]) (\FCACHE.MAKE.LEGAL.FILENAME [LAMBDA (file) (* smL "19-Feb-85 09:19") (* * Convert a potential file name into something that the local file system will accept) (PACK (for c inchars file collect (SELCHARQ c ((A B C D E F G H I J K L M N O P Q R S T U V W X Y Z a b c d e f g h i j k l m n o p q r s t u v w x y z 1 2 3 4 5 6 7 8 9 0 + - $ < >) (CHARACTER c)) "$"]) (\FCACHE.MAKEROOM [LAMBDA (length) (* smL "12-Mar-86 17:11") (* * Make sure that there is enough room in the cache to hold this file) (SETQ length (OR length 0)) (LET [(cacheMaxTotal (\FCACHE.PROPERTY (QUOTE MAXSIZE))) (cacheSize (\FCACHE.PROPERTY (QUOTE SIZE))) (freePages (OR [CAR (NLSETQ (SELECTQ (MACHINETYPE) ((DORADO DOLPHIN) (* \GETDEVICEFROMNAME is a hack to program around bug) (DIFFERENCE [DISKFREEPAGES (\GETDEVICEFROMNAME (\FCACHE.PROPERTY (QUOTE PREFIX] 50)) (DIFFERENCE (DISKFREEPAGES (\FCACHE.PROPERTY (QUOTE PREFIX))) 100] (ADD1 length] (SETQ cacheMaxTotal (if (NUMBERP cacheMaxTotal) then (MIN cacheMaxTotal (PLUS freePages cacheSize)) else (PLUS freePages cacheSize))) (if (ILESSP cacheMaxTotal length) then (* the file wont ever fit, so dont even try) NIL elseif (ILESSP (PLUS length cacheSize) cacheMaxTotal) then (* the file will fit w/o having to get rid of any old cached files) T else (* delete some old files until it fits) (* NOTE: this is ugly -- perhaps I would be better off if I maintained the cache list in the other order? But then looking up files would be slowed. Oh well...) (RESETLST (\FCACHE.DONE.OR.ABORTED.MSG "Making some room in the cache") (for entry in (REVERSE \FCACHE.LIST) bind (desiredLength ←(IDIFFERENCE cacheMaxTotal length)) do (WITH.MONITOR (fetch CACHELOCK of entry) (if (AND (NOT (fetch CACHEISDIRTY of entry)) (NOT (\FCACHE.ENTRYOPEN? entry)) (\FCACHE.MAKEROOM.DELETEABLE? (fetch REMOTEFILENAME of entry))) then (\FCACHE.DELETE.ENTRY entry))) (if (ILESSP (\FCACHE.PROPERTY (QUOTE SIZE)) desiredLength) then (RETURN T)) finally (RETURN NIL]) (\FCACHE.MAKEROOM.DELETEABLE? [LAMBDA (fileName) (* smL "11-Sep-85 13:17") (* * Is this cache entry deleteable to make room for some new cache entry?) T]) ) (RPAQ? \FCACHE.CACHELOCK (CREATE.MONITORLOCK (QUOTE \FCACHE.CACHELOCK))) (RPAQ? \FCACHE.CACHE.CHANGED.EVENT (CREATE.EVENT (QUOTE FCACHE.CHANGED))) (RPAQ? \FCACHE.CACHING.FILES NIL) (RPAQ? \FCACHE.LIST NIL) (RPAQ? \FCACHE.LIST.CHANGED? NIL) (RPAQ? \FCACHE.LOGFILE NIL) (DECLARE: DOEVAL@COMPILE DONTCOPY (GLOBALVARS \FCACHE.CACHELOCK \FCACHE.CACHE.CHANGED.EVENT \FCACHE.CACHING.FILES \FCACHE.LIST \FCACHE.LIST.CHANGED? \FCACHE.LOGFILE) ) (* * Scavenging functions) (DEFINEQ (FCACHE.SCAVENGE [LAMBDA (options) (* smL "11-Sep-85 11:47") (* * Build a list of all files in the cache directory that are not known to the cacher, and not on the list FCACHE.SCAVENGE.IGNORE) (WITHOUT.FCACHE (WITH.MONITOR \FCACHE.CACHELOCK (LET ((options (MKLIST options)) badList) (* make sure the cache size is correct) (if (NOT (MEMB (QUOTE SILENT) options)) then (printout NIL "Recomputing cache size..." T)) (\FCACHE.PROPERTY.PUT (QUOTE SIZE) (for entry in \FCACHE.LIST sum (fetch CACHEFILELENGTH of entry))) (* get rid of all entries that don't have coresponding cached files) (if (MEMB (QUOTE EXISTS) options) then (if (MEMB (QUOTE SILENT) options) then (for entry in \FCACHE.LIST do (if (NOT (INFILEP (fetch LOCALFILENAME of entry))) then (\FCACHE.DELETE.ENTRY entry))) else (printout NIL "Verifying that cache files exist") (for entry in \FCACHE.LIST do (if (NOT (INFILEP (fetch LOCALFILENAME of entry))) then (printout NIL "?") (\FCACHE.DELETE.ENTRY entry) else (printout NIL "."))) (printout NIL T))) (* if we should, verify all files in the cache) [if (MEMB (QUOTE VERIFY) options) then (if (MEMB (QUOTE SILENT) options) then (for entry in \FCACHE.LIST do (if [NOT (WITH.MONITOR (fetch CACHELOCK of entry) (\FCACHE.REPAIR.VERIFY (fetch LOCALFILENAME of entry) (fetch REMOTEFILENAME of entry] then (\FCACHE.DELETE.ENTRY entry))) else (printout NIL "Verifying that cache files are valid copies" T) (for entry in \FCACHE.LIST do (if [NOT (WITH.MONITOR (fetch CACHELOCK of entry) (\FCACHE.REPAIR.VERIFY (fetch LOCALFILENAME of entry) (fetch REMOTEFILENAME of entry] then (printout NIL "?") (\FCACHE.DELETE.ENTRY entry) else (printout NIL "."] (* now collect the list of all files on the local disk that are not cached files) (if (NOT (MEMB (QUOTE SILENT) options)) then (printout NIL "Collecting unknown files from the cache..." T)) (SETQ badList (for file inunsortedfiles (CONCAT (FCACHE.GETPROP (QUOTE PREFIX) ) "*.*;*") eachtime (SETQ file (MKATOM (U-CASE file))) when [NOT (for entry in \FCACHE.LIST thereis (EQ file (fetch LOCALFILENAME of entry] collect file)) (* and then remove the files that match any on FCACHE.SCAVENGE.IGNORE) [for fileSpec in (CDR (ASSOC (MACHINETYPE) FCACHE.SCAVENGE.IGNORE)) bind (host ←(FILENAMEFIELD (\FCACHE.PROPERTY (QUOTE PREFIX)) (QUOTE HOST))) (dir ←(FILENAMEFIELD (\FCACHE.PROPERTY (QUOTE PREFIX)) (QUOTE DIRECTORY))) while (NOT (NULL badList)) do (for file in badList when (\FCACHE.FILEMATCH? file (PACKFILENAME (QUOTE BODY) fileSpec (QUOTE DIRECTORY) dir (QUOTE HOST) host (QUOTE VERSION) "*")) do (SETQ badList (DREMOVE file badList] (* try to repair files if we are told to.) [if (MEMB (QUOTE REPAIR) options) then (if (NOT (MEMB (QUOTE SILENT) options)) then (printout NIL "Trying to repair unknown files..." T)) (for file in badList bind remoteFile alreadyCached do [SETQ remoteFile (MKATOM (U-CASE (\FCACHE.REPAIR file] [SETQ alreadyCached (AND remoteFile (for entry in \FCACHE.LIST when (EQ remoteFile (fetch LOCALFILENAME of entry)) thereis (\FCACHE.VERIFY entry (FILENAMEFIELD (fetch REMOTEFILENAME of entry) (QUOTE HOST] (if (NOT (MEMB (QUOTE SILENT) options)) then (if alreadyCached then (printout NIL file " is a duplicate copy of " remoteFile T) elseif remoteFile then (printout NIL file " is a copy of " remoteFile T) else (printout NIL "Can't match the file " file T))) (if (AND (NOT alreadyCached) remoteFile) then (\FCACHE.ADDENTRY file remoteFile (GETFILEINFO file (QUOTE ICREATIONDATE)) (GETFILEINFO remoteFile (QUOTE PLIST)) (GETFILEINFO file (QUOTE SIZE))) (SETQ badList (DREMOVE file badList] badList]) ) (DEFINEQ (\FCACHE.REPAIR [LAMBDA (localFileName) (* lmm " 6-Nov-85 15:58") (* * Try to figure out what file this is a cached version of. RETURN the remote file name if you can) (DECLARE (GLOBALVARS COMPILE.EXT LAFITEMAIL.EXT LAFITETOC.EXT LAFITEFORM.EXT LAFITEFORMDIRECTORIES LAFITEDEFAULTHOST&DIR DISPLAYFONTDIRECTORIES FILERDTBL DISPLAYFONTDIRECTORIES INTERPRESSFONTDIRECTORIES PRESSFONTWIDTHSFILES LOGINHOST/DIR DIRECTORIES LISPUSERSDIRECTORIES)) (RESETLST (LET ((fileNameFields (U-CASE (UNPACKFILENAME localFileName))) name ext stream expr) (SETQ name (LISTGET fileNameFields (QUOTE NAME))) (SETQ ext (LISTGET fileNameFields (QUOTE EXTENSION))) (* * First try some magic based on the file name. If that doesn't work, try some generic method to find the remote file. * *) (OR (for lf in LOADEDFILELST when (STRPOS name lf) when (EQ (PACKFILENAME (QUOTE NAME) name (QUOTE EXTENSION) ext) (NAMEFIELD lf T)) do (AND (\FCACHE.REPAIR.VERIFY localFileName lf) (RETURN lf))) (if (LISPSOURCEFILEP localFileName) then (* possibly a LISP file -- see if the first expr in the file is a FILECREATED expression) [RESETSAVE NIL (LIST (FUNCTION CLOSEF?) (SETQ stream (OPENSTREAM localFileName (QUOTE INPUT] [SETQ expr (CAR (NLSETQ (READ stream FILERDTBL] (if (AND (EQ (CAR expr) (QUOTE FILECREATED)) (\FCACHE.REPAIR.VERIFY localFileName (CADDR expr))) then (CADDR expr) else NIL)) (if (EQ ext COMPILE.EXT) then [RESETSAVE NIL (LIST (FUNCTION CLOSEF?) (SETQ stream (OPENSTREAM localFileName (QUOTE INPUT] [SETQ expr (CAR (NLSETQ (READ stream FILERDTBL] (if (EQ (CAR expr) (QUOTE FILECREATED)) then (* now (CADR (CADDR expr)) is a pointer to the source file, so we need to figure out what DCOM file this is) [CAR (NLSETQ (for file inunsortedfiles (PACKFILENAME.STRING (QUOTE EXTENSION) COMPILE.EXT (QUOTE VERSION) (QUOTE *) (QUOTE BODY) (CADR (CADDR expr))) thereis ( \FCACHE.REPAIR.VERIFY localFileName file] else NIL)) (if (MEMB ext (LIST LAFITEMAIL.EXT (PACK* LAFITEMAIL.EXT LAFITETOC.EXT) LAFITEFORM.EXT)) then (* a LAFITE file, so look in the users mail directory) (\FCACHE.REPAIR.FINDFILE localFileName (OR LAFITEDEFAULTHOST&DIR LOGINHOST/DIR))) (if (AND (BOUNDP (QUOTE LAFITEFORMDIRECTORIES)) LAFITEFORMDIRECTORIES (EQ ext LAFITEFORM.EXT)) then (* a LAFITE form, so check the form directory) (\FCACHE.REPAIR.FINDFILE localFileName (MKLIST LAFITEFORMDIRECTORIES))) (if (MEMB ext (CONS (QUOTE WD) DISPLAYFONTEXTENSIONS)) then (* a font file, so check the font directories) (\FCACHE.REPAIR.FINDFILE localFileName (UNION DISPLAYFONTDIRECTORIES INTERPRESSFONTDIRECTORIES))) (if (AND (EQ name (QUOTE FONTS)) (EQ ext (QUOTE WIDTHS))) then (* a fonts widths file) (for file in PRESSFONTWIDTHSFILES when (NOT (EQ (U-CASE (FILENAMEFIELD file (QUOTE HOST))) (QUOTE DSK))) thereis (\FCACHE.REPAIR.VERIFY localFileName file))) (\FCACHE.REPAIR.FINDFILE localFileName (UNION (LIST LOGINHOST/DIR) DIRECTORIES LISPUSERSDIRECTORIES]) (\FCACHE.REPAIR.FINDFILE [LAMBDA (localFile dirList) (* smL " 5-Feb-86 14:13") (* * Kind of like FINDFILE, but keeps looking on the directories untill a file matches) (CAR (NLSETQ (OR (for dir inside dirList bind full when (AND (NOT (STRPOS "DSK" dir NIL NIL NIL NIL ( UPPERCASEARRAY))) (SETQ full (INFILEP (PACKFILENAME.STRING (QUOTE VERSION) NIL (QUOTE DIRECTORY) dir (QUOTE BODY) localFile))) (\FCACHE.REPAIR.VERIFY localFile full)) do (RETURN full)) (for dir inside dirList bind (name ←(FILENAMEFIELD localFile (QUOTE NAME))) (extension ←(FILENAMEFIELD localFile (QUOTE EXTENSION))) remoteFile when (NOT (STRPOS "DSK" dir NIL NIL NIL NIL (UPPERCASEARRAY))) do (SETQ remoteFile (for file inunsortedfiles (PACKFILENAME.STRING (QUOTE DIRECTORY) dir (QUOTE NAME) name (QUOTE EXTENSION) extension) thereis (\FCACHE.REPAIR.VERIFY localFile file))) (if remoteFile then (RETURN remoteFile]) (\FCACHE.REPAIR.VERIFY [LAMBDA (localFile remoteFile) (* smL " 5-Feb-86 14:11") (* * Is the local file a copy of the remote file?) (CAR (NLSETQ (AND (INFILEP localFile) (INFILEP remoteFile) (for prop in (QUOTE (ICREATIONDATE LENGTH)) bind info always (AND (SETQ info (GETFILEINFO localFile prop)) (EQUAL info (GETFILEINFO remoteFile prop]) ) (RPAQ? FCACHE.SCAVENGE.IGNORE (QUOTE ((DANDELION FCACHE.POINTER FCACHE.LISTING FCACHE.LOG) (DOVE FCACHE.POINTER FCACHE.LISTING FCACHE.LOG) (DORADO FCACHE.POINTER FCACHE.LISTING FCACHE.LOG COM.CM DISKDESCRIPTOR. DMT.BOOT DUMPER.BOOT EXECUTIVE.RUN FTP.LOG FTP.RUN REM.CM SWAT. SWATEE. SYS.BOOT SYS.ERRORS SYSDIR. SYSFONT.AL USER.CM)))) (DECLARE: DOEVAL@COMPILE DONTCOPY (GLOBALVARS FCACHE.SCAVENGE.IGNORE) ) (* * Functions for creating or destroying a cache device) (DEFINEQ (\FCACHE.BUILD.DEVICE [LAMBDA (devname) (* smL " 7-Aug-85 11:36") (* * Build a cache device trying to inherit as much as possible from the local device) (LET [(cacheDevice (create FDEV using (\FCACHE.LOCALDEVICE] (replace DEVICENAME of cacheDevice with devname) (replace NODIRECTORIES of cacheDevice with T) (* other methods are special for the cache device) (replace GENERATEFILES of cacheDevice with (QUOTE \FCACHE.GENERATEFILES)) (replace EVENTFN of cacheDevice with (QUOTE \FCACHE.EVENTFN)) (replace OPENFILE of cacheDevice with (QUOTE \FCACHE.OPENFILE)) (replace CLOSEFILE of cacheDevice with (QUOTE \FCACHE.CLOSEFILE)) (replace HOSTNAMEP of cacheDevice with (QUOTE \FCACHE.HOSTNAMEP)) (replace DIRECTORYNAMEP of cacheDevice with (QUOTE \FCACHE.DIRECTORYNAMEP)) (replace REOPENFILE of cacheDevice with (QUOTE \FCACHE.REOPENFILE)) (replace GETFILENAME of cacheDevice with (QUOTE \FCACHE.GETFILENAME)) (replace DELETEFILE of cacheDevice with (QUOTE \FCACHE.DELETEFILE)) (replace GETFILEINFO of cacheDevice with (QUOTE \FCACHE.GETFILEINFO)) (replace SETFILEINFO of cacheDevice with (QUOTE \FCACHE.SETFILEINFO)) (replace RENAMEFILE of cacheDevice with (QUOTE \FCACHE.RENAMEFILE)) cacheDevice]) (\FCACHE.OFF [LAMBDA (device) (* lmm "22-Oct-85 16:05") (* * Turn off the cache device) (OR [\FCACHE.PROPERTY.PUT (QUOTE DEVICES) (REMOVE (fetch (CACHEDEVICE CACHEDEVINFO) of device) (\FCACHE.PROPERTY (QUOTE DEVICES] (DEL.PROCESS (QUOTE DUMP-FCACHE))) (\REMOVEDEVICE device]) ) (* * Functions for dealing with device events, like LOGOUT) (DEFINEQ (\FCACHE.DEVICE.EVENTFN [LAMBDA (DEVICE EVENT) (* smL "13-Mar-86 10:33") (* * The event fn for the dummy FCACHE device) (SELECTQ EVENT ((AFTERSYSOUT AFTERMAKESYS AFTERLOGOUT AFTERSAVEVM) (if \FCACHE.LOGFILE then (* the logfile was left open, so we had better get rid of it quick - this can only happen AFTERSAVEVM) (SETQ \OPENFILES (DREMOVE \FCACHE.LOGFILE \OPENFILES)) (SETQ \FCACHE.LOGFILE NIL)) (* Restore the cache devices and info) (\FCACHE.INITIALIZE.PROPS)) ((AFTERDOMAKESYS AFTERDOSYSOUT AFTERDOSAVEVM) (* Don't need to do anything here) NIL) ((BEFORESYSOUT BEFOREMAKESYS BEFORESAVEVM) (* Dump out the cache listings) (FCACHE.DUMP T)) (BEFORELOGOUT (* Dump the cache info) [for entry in \FCACHE.LIST bind fileName when (fetch CACHEISDIRTY of entry) do (SETQ fileName (fetch REMOTEFILENAME of entry)) (if (\FCACHE.ENTRYOPEN? entry) then (OR (BREAK1 T T "Can't flush file" ((printout NIL "The cached version of the file " fileName , "needs to be dumped to the fileserver, " "but I can't because the file is open." T "If you continue with OK, I will continue with the LOGOUT." T "RETURN NIL will abort the LOGOUT." T))) (ERROR "Can't dump file " fileName)) elseif (\FCACHE.WRITEOUT entry) then (* ok, the file was written out) T else (* can't dump the file!) (OR (BREAK1 T T "Can't flush file" ((printout NIL "The cached version of the file " fileName , "needs to be dumped to the fileserver, " "but I can't do it." T "If you continue with OK, I will continue with the LOGOUT." T "RETURN NIL will abort the LOGOUT." T))) (ERROR "Can't dump file " fileName] (for entry in \FCACHE.LIST when (FCACHE.PRIVATE.FILE? (fetch REMOTEFILENAME of entry)) do (\FCACHE.DELETE.ENTRY entry)) (FCACHE.DUMP T)) (\ILLEGAL.ARG EVENT]) (\FCACHE.INITIALIZE.PROPS [LAMBDA NIL (* smL "12-Mar-86 13:47") (* * Reinitialize the cache properties.) (SETQ \FCACHE.LOGFILE NIL) (if (INFILEP (QUOTE {DSK}FCache.pointer;1)) then (LET [(f (OPENFILE (QUOTE {DSK}FCache.pointer;1) (QUOTE INPUT] [\FCACHE.PROPERTY.PUT (QUOTE PREFIX) (MKATOM (CAR (NLSETQ (READ f] (CLOSEF f)) (OR (\FCACHE.RESTORE (\FCACHE.PROPERTY (QUOTE PREFIX))) (\FCACHE.RESTORE NIL)) else (PROG ((f (OPENFILE (QUOTE {DSK}FCache.pointer;1) (QUOTE OUTPUT))) prefix) (CLEARW \FCACHE.PROMPT.WINDOW) TryAgain [SETQ prefix (MKATOM (RESETBUFS (PROMPTFORWORD "What should the file cache prefix be (NIL to disable)? " (SELECTQ (MACHINETYPE) ((DORADO DOLPHIN) "{DSK1}") (DANDELION "{DSK}<LispFiles>Cache>") NIL) NIL \FCACHE.PROMPT.WINDOW NIL T] (if (\FCACHE.RESTORE prefix) then (CLOSEW \FCACHE.PROMPT.WINDOW) (printout f .P2 (\FCACHE.PROPERTY (QUOTE PREFIX)) T) (CLOSEF f) else (printout \FCACHE.PROMPT.WINDOW T "Bad device specification: " prefix T) (GO TryAgain]) ) (DECLARE: DOEVAL@COMPILE DONTCOPY (GLOBALVARS \FCACHE.DEVICE) ) (* Make sure the cache devices are at the top of the list of known devices before we do any device event -- in other words, a big HACK) (DEFINEQ (\FCACHE.GLOBAL.EVENT [LAMBDA (EVENT) (* lmm "14-Sep-85 19:03") (* * Before doing a device event, make sure the cache devices are the last devices defined. The dummey one should be positioned so that it gets the event first after a logout.) (\REMOVEDEVICE \FCACHE.DEVICE) (\DEFINEDEVICE (QUOTE FCACHE) \FCACHE.DEVICE) (for x in (\FCACHE.PROPERTY (QUOTE DEVICES)) do (LET ((device (fetch CACHEDEV of x))) (\REMOVEDEVICE device) (\DEFINEDEVICE (PACK* (fetch REALDEVICENAME of x) (QUOTE -CACHE)) device))) (SELECTQ EVENT ((AFTERLOGOUT AFTERSYSOUT AFTERMAKESYS AFTERSAVEVM) (\FCACHE.AROUNDEXIT)) NIL]) ) (APPENDTOVAR AROUNDEXITFNS \FCACHE.GLOBAL.EVENT) (* Before revalidating files, load the LOG file, if any -- in other words, a big HACK) (DEFINEQ (\FCACHE.AROUNDEXIT [LAMBDA NIL (* smL "11-Feb-86 18:17") (* * Called before revalidating files after a logout -- make sure that the cache info is up to date. In other words, after an event, check for a log file) (RESETLST (PROG (prefix logfileName) (* forget it if there is no cache) (SETQ prefix (\FCACHE.PROPERTY (QUOTE PREFIX))) (if (NULL prefix) then (RETURN NIL)) (SETQ logfileName (PACK* prefix "FCache.Log;1")) (* close the log file if it is open) (if (OPENP logfileName) then (SETQ \FCACHE.LOGFILE (GETSTREAM logfileName)) (replace USERCLOSEABLE of \FCACHE.LOGFILE with T) (CLOSEF? \FCACHE.LOGFILE)) (* skip loading the entries it if there is no log file) (if (NOT (INFILEP logfileName)) then (RETURN T)) (* load the entries from the log file) (\FCACHE.DONE.OR.ABORTED.MSG "Restoring log entries") (SETQ \FCACHE.LOGFILE (OPENSTREAM logfileName (QUOTE INPUT))) [bind entrydef while (NOT (EOFP \FCACHE.LOGFILE)) do (SETQ entrydef (NLSETQ (READ \FCACHE.LOGFILE))) (if entrydef then (\FCACHE.RESTORE.ENTRY (CAR entrydef) T) else (LET ((errorWindow (CREATEW (create REGION LEFT ← 250 BOTTOM ← 250 WIDTH ← 425 HEIGHT ← 120) "File cache warning"))) (printout errorWindow "WARNING: The file cache log file was not completly dumped." "The cacher may have lost track of some files." "If there were any files that needed to be dumped, " "they may have been lost!" T T "You should run FCACHE.SCAVENGE soon to clean up your disk."] (FCACHE.DUMP) (RETURN T]) ) (* * Catch changes to the current user / password) (* This is a HACK) (DEFINEQ (\FCACHE.BEFORELOGIN [LAMBDA (HOST) (* smL "13-Mar-86 13:12") (* * The user is about to be changed. Make sure that all dirty files have been dumped.) (if (NULL HOST) then (for entry in \FCACHE.LIST bind fileName when (fetch CACHEISDIRTY of entry) do (SETQ fileName (fetch REMOTEFILENAME of entry)) (if (\FCACHE.ENTRYOPEN? entry) then (OR (BREAK1 T T "Can't flush file" ((printout NIL "The cached version of the file " fileName , "needs to be dumped to the fileserver, " "but I can't because the file is open." T "If you continue with OK, " "I will continue with changing the password." T "RETURN NIL will abort it." T))) (ERROR "Can't dump file " fileName)) elseif (\FCACHE.WRITEOUT entry) then (* ok, the file was written out) T else (* can't dump the file!) (OR (BREAK1 T T "Can't flush file" ((printout NIL "The cached version of the file " fileName , "needs to be dumped to the fileserver, " "but I can't do it." T "If you continue with OK, " "I will continue with changing the password." T "RETURN NIL will abort it." T))) (ERROR "Can't dump file " fileName]) (\FCACHE.\INTERNAL/SETPASSWORD [LAMBDA (HOST NEWNAME/PASS DIRECTORY ALWAYSASK MSG DEFAULTNAME OSTYPE) (* smL "13-Mar-86 13:13") (* * A replacement for \INTERNAL/SETPASSWORD) (for fn in \BEFORELOGINFNS do (APPLY* fn HOST NEWNAME/PASS DIRECTORY ALWAYSASK MSG DEFAULTNAME OSTYPE)) (\OLD\INTERNAL/SETPASSWORD HOST NEWNAME/PASS DIRECTORY ALWAYSASK MSG DEFAULTNAME OSTYPE]) ) (ADDTOVAR \BEFORELOGINFNS \FCACHE.BEFORELOGIN) (DECLARE: DOEVAL@COMPILE DONTCOPY (GLOBALVARS \BEFORELOGINFNS) ) (* * Methods for the {FCACHE} file device. Note that methods that are not defined are not really needed since {FCACHE} is a specialization of the local device that holds the cache, and inherits all bin/bout like methods) (DEFINEQ (\FCACHE.CLOSEFILE [LAMBDA (STREAM) (* smL "11-Feb-86 18:55") (* * Implements the CLOSEFILE method for the {FCACHE} device.) (RESETLST (PROG (cacheDevice localDevice entry result) (SETQ cacheDevice (fetch DEVICE of STREAM)) (SETQ localDevice (\FCACHE.LOCALDEVICE)) (if (NULL (SETQ entry (\FCACHE.LOOKUP cacheDevice STREAM NIL))) then (ERROR "Lost the cache entry for " STREAM)) (if (SETQ result (FDEVOP (QUOTE CLOSEFILE) localDevice STREAM)) then (* For some reason, if we don't do this OPENP thinks the local file is still open) (CLOSEF? (fetch LOCALFILENAME of entry)) (if (fetch CACHEISDIRTY of entry) then (* Update the file size, since it probably changed) (\FCACHE.PROPERTY.PUT (QUOTE SIZE) (DIFFERENCE (\FCACHE.PROPERTY (QUOTE SIZE)) (fetch CACHEFILELENGTH of entry))) (replace CACHEFILELENGTH of entry with (FDEVOP (QUOTE GETFILEINFO) localDevice (fetch LOCALFILENAME of entry) (QUOTE SIZE) localDevice)) (\FCACHE.PROPERTY.PUT (QUOTE SIZE) (PLUS (\FCACHE.PROPERTY (QUOTE SIZE)) (fetch CACHEFILELENGTH of entry))) (\FCACHE.MAKEROOM)) (replace CACHETIMECLOSED of entry with (IDATE)) (RETURN result) else (ERROR "Can't close the cache file " (fetch LOCALFILENAME of entry]) (\FCACHE.DELETEFILE [LAMBDA (NAME DEVICE) (* smL "11-Feb-86 18:56") (* * Implements the DELETEFILE method for the {FCACHE} device.) (RESETLST (LET ((fullName (\FCACHE.GETFILENAME NAME (QUOTE OLDEST) DEVICE)) entry) (SETQ entry (if fullName then (\FCACHE.LOOKUP DEVICE fullName T))) (if (OR (NULL fullName) (AND entry (\FCACHE.ENTRYOPEN? entry))) then NIL else (* delete the cache entry, then the remote file) (if entry then (\FCACHE.DELETE.ENTRY entry)) (if (AND entry (fetch CACHEISDIRTY of entry) (NOT (fetch FILEXISTED of entry))) then fullName else (REALDEVOP (QUOTE DELETEFILE) DEVICE fullName DEVICE]) (\FCACHE.DIRECTORYNAMEP [LAMBDA (HostAndDir DEVICE) (* smL "27-Feb-86 11:20") (* * Implements the DIRECTORYNAMEP method for the {FCACHE} device) (RESETLST (LET ((hostName (fetch (CACHEDEVICE REALDEVICENAME) of DEVICE))) (OR (AND (if (\FCACHE.HOSTUP? hostName) then NIL elseif (MEMB (U-CASE (MKATOM hostName)) FCACHE.DEAD.HOSTS) then T else (SELECTQ (\FCACHE.PROPERTY (QUOTE UNSAFE)) (T (* We are told to use the local cache) T) (NOTIFY (* Use the cache, but notify the user what is going on) (printout *FILE-CACHE-MESSAGE-STREAM* T (fetch (CACHEDEVICE REALDEVICENAME) of DEVICE) , "does not seem to be responding for directory name verification." T "Trusting that" , HostAndDir , "is OK.") T) [ASK (* Ask to find out what to do) (WITH.FCACHE.ABORT.WINDOW msgWindow (WINDOWPROP msgWindow (QUOTE TITLE) (CONCAT hostName " not responding...")) (CLEARW msgWindow) (printout msgWindow .FONT DEFAULTFONT "Can't verify if" T .FONT BOLDFONT .CENTER 0 HostAndDir .FONT DEFAULTFONT T "is a valid directory name" T T .CENTER 0 "I'll keep trying...") (WINDOWPROP msgWindow (QUOTE ItemPicked) NIL) (LET [(menu (create MENU CENTERFLG ← T ITEMS ←(QUOTE (("Trust the cache" Use) ("Don't trust the cache" Don'tUse) ("Add to DEAD.HOSTS" MakeDead))) WHENSELECTEDFN ←(FUNCTION \FCACHE.HOSTDEAD.WHENSELECTEDFN] (ADDMENU menu msgWindow (create POSITION XCOORD ←(IQUOTIENT (DIFFERENCE (WINDOWPROP msgWindow (QUOTE WIDTH)) (fetch IMAGEWIDTH of menu)) 2) YCOORD ← 10))) (during (\FCACHE.PROPERTY (QUOTE UNSAFE.TIMEOUT)) timerUnits (QUOTE SECONDS) do (BLOCK) (if (\FCACHE.HOSTUP? hostName) then (RETURN NIL) else (SELECTQ (WINDOWPROP msgWindow (QUOTE ItemPicked)) (Use (RETURN T)) (Don'tUse (RETURN NIL)) (MakeDead (pushnew FCACHE.DEAD.HOSTS hostName) (RETURN T)) NIL)) finally (RETURN (\FCACHE.PROPERTY (QUOTE UNSAFE.DEFAULT] (NIL (* We are running in cautious mode) NIL) NIL)) HostAndDir) (REALDEVOP (QUOTE DIRECTORYNAMEP) DEVICE HostAndDir DEVICE]) (\FCACHE.EVENTFN [LAMBDA (DEVICE EVENT) (* smL "11-Feb-86 16:13") (* * EVENT method for the cached device) (SELECTQ EVENT ((BEFORESYSOUT BEFOREMAKESYS BEFORELOGOUT BEFORESAVEVM) (* Don't need to do anything here) NIL) [(AFTERSYSOUT AFTERMAKESYS AFTERLOGOUT AFTERSAVEVM) (* Restore the device) (if (NULL (\FCACHE.PROPERTY (QUOTE PREFIX))) then (* no cache prefix, so delete this cache device) (if (\FCACHE.PRINT.MESSAGE?) then (printout *FILE-CACHE-MESSAGE-STREAM* T "No cache prefix, so turning off cache for " (fetch (CACHEDEVICE REALDEVICENAME) of DEVICE))) (\FCACHE.OFF DEVICE) elseif [NOT (for stream in \OPENFILES thereis (EQ DEVICE (fetch DEVICE of stream] then (* there is no open file on this device, so forget it) (\FCACHE.OFF DEVICE) else (LET [(newDevice (\FCACHE.BUILD.DEVICE (fetch (CACHEDEVICE REALDEVICENAME) of DEVICE] (if (type? FDEV newDevice) then (for descr in (GETDESCRIPTORS (QUOTE FDEV)) do (REPLACEFIELD descr DEVICE (FETCHFIELD descr newDevice))) else (if (\FCACHE.PRINT.MESSAGE?) then (printout *FILE-CACHE-MESSAGE-STREAM* T (fetch (CACHEDEVICE REALDEVICENAME) of DEVICE) " no longer a known host, do turning off its cache")) (\FCACHE.OFF DEVICE] ((AFTERDOMAKESYS AFTERDOSYSOUT AFTERDOSAVEVM) (* Don't need to do anything here) NIL) (\ILLEGAL.ARG EVENT]) (\FCACHE.GENERATEFILES [LAMBDA (DEVICE PATTERN DESIREDPROPS OPTIONS) (* smL " 7-Aug-85 18:09") (* * Implements the GENERATEFILES method for the {FCACHE} device.) (if (\FCACHE.USELOCALDIRECTORY? (fetch (CACHEDEVICE REALDEVICENAME) of DEVICE) PATTERN) then (\FCACHE.GENERATE.LOCAL.FILES DEVICE PATTERN DESIREDPROPS OPTIONS) elseif (\FCACHE.PROPERTY (QUOTE FASTDIR)) then (REALDEVOP (QUOTE GENERATEFILES) DEVICE DEVICE PATTERN DESIREDPROPS OPTIONS) else (MERGE.FILEGENERATORS (REALDEVOP (QUOTE GENERATEFILES) DEVICE DEVICE PATTERN DESIREDPROPS OPTIONS) (\FCACHE.GENERATE.LOCAL.FILES DEVICE PATTERN DESIREDPROPS OPTIONS T) (FMEMB (QUOTE SORT) OPTIONS]) (\FCACHE.GETFILEINFO [LAMBDA (NameOrStream Attribute Device) (* smL "12-Feb-86 11:33") (* * Implements the GETFILEINFO method for {FCACHE}. If the file is cached, try to fetch the property locally. Otherwise, pass on the the remote host.) (RESETLST (LET ((entry (\FCACHE.LOOKUP Device NameOrStream T))) (if entry then (\FCACHE.ENTRYINFO Device entry Attribute) else (REALDEVOP (QUOTE GETFILEINFO) Device (if (STREAMP NameOrStream) then (fetch FULLFILENAME of NameOrStream) else NameOrStream) Attribute Device]) (\FCACHE.GETFILENAME [LAMBDA (NAME RECOG DEVICE) (* smL "13-Mar-86 14:27") (* * Implements the GETFILENAME method for the {FCACHE} file device.) (DECLARE (GLOBALVARS \CONNECTED.DIRECTORY)) (for entry in \FCACHE.LIST bind (RECOG ←(OR RECOG (QUOTE OLD))) (givenVersion ←(FILENAMEFIELD NAME (QUOTE VERSION))) (hostName ←(fetch (CACHEDEVICE REALDEVICENAME) of DEVICE)) filter file fileVersion entryVersion first (* * Try to get the file from the remote host) (if [AND givenVersion (MEMB RECOG (QUOTE (NEW OLD/NEW] then (* we are given a full name, so return it) (RETURN NAME) elseif (NOT (\FCACHE.USELOCALDIRECTORY? hostName NAME)) then (SETQ file (REALDEVOP (QUOTE GETFILENAME) DEVICE NAME RECOG DEVICE)) (if [AND file givenVersion (MEMB RECOG (QUOTE (OLDEST OLD] then (* in this case, we don't need to check the local files at all) (RETURN file))) (* * Now we need to check the local files to see if that would change the answer from the remote host. Ugh.) [SETQ filter (if givenVersion then (MatchFileName (PACKFILENAME.STRING (QUOTE BODY) NAME (QUOTE HOST) hostName (QUOTE DIRECTORY) \CONNECTED.DIRECTORY)) else (DIRECTORY.MATCH.SETUP (PACKFILENAME.STRING (QUOTE VERSION) "*" (QUOTE BODY) NAME (QUOTE HOST) hostName (QUOTE DIRECTORY) \CONNECTED.DIRECTORY] when [if givenVersion then (EQ filter (fetch MATCHFILENAME of entry)) else (AND (DIRECTORY.MATCH filter (fetch MATCHFILENAME of entry)) (EQ hostName (\FCACHE.CANONICAL.HOSTNAME (FILENAMEFIELD (fetch MATCHFILENAME of entry) (QUOTE HOST] do (if (WITH.MONITOR (fetch CACHELOCK of entry) (if (NOT (\FCACHE.VERIFY entry DEVICE)) then (* oops, a bad entry!) (if (\FCACHE.PRINT.MESSAGE?) then (printout *FILE-CACHE-MESSAGE-STREAM* "[Invalid cache file!]" T)) (\FCACHE.DELETE.ENTRY entry) T else NIL)) then (GO $$ITERATE)) (SETQ fileVersion (FILENAMEFIELD file (QUOTE VERSION))) (SETQ entryVersion (FILENAMEFIELD (fetch REMOTEFILENAME of entry) (QUOTE VERSION))) (if (NULL givenVersion) then (SELECTQ RECOG [OLDEST (if (OR (NULL file) (AND (NUMBERP fileVersion) (NUMBERP entryVersion) (LESSP entryVersion fileVersion))) then (* this entry is an older one, so update the oldest) (SETQ file (fetch REMOTEFILENAME of entry] [(OLD/NEW OLD) (if (OR (NULL file) (AND (NUMBERP fileVersion) (NUMBERP entryVersion) (LESSP fileVersion entryVersion))) then (* this entry is newer than the current guess, so update the guess) (SETQ file (fetch REMOTEFILENAME of entry] [NEW (if (OR (NULL file) (AND (NUMBERP fileVersion) (NUMBERP entryVersion) (LEQ fileVersion entryVersion))) then (* this entry is at least as new as the current guess, so update the guess) (SETQ file (if (NUMBERP entryVersion) then (PACK* (VersionlessFileName (fetch REMOTEFILENAME of entry)) ";" (ADD1 entryVersion)) else (fetch REMOTEFILENAME of entry] (\ILLEGAL.ARG RECOG)) elseif (EQP entryVersion givenVersion) then (* we have a match, so go with it) (RETURN (fetch REMOTEFILENAME of entry)) else (* given an explicit version number, but this entry doesn't match it, so do nothing) NIL) finally (* * if we found no matching file, and RECOG is NEW or OLD/NEW, then create one with version = 1) [if [AND (NULL file) (MEMB RECOG (QUOTE (NEW OLD/NEW] then (* no old file, so create a new one) (SETQ file (if (STRPOS "." NAME) then (PACK* (VersionlessFileName NAME) ";1") else (PACK* (VersionlessFileName NAME) ".;1"] (RETURN file]) (\FCACHE.HOSTNAMEP [LAMBDA (hostName device) (* smL " 8-Aug-85 13:23") (* * The HOSTNAMEP method of a cached device) NIL]) (\FCACHE.OPENFILE [LAMBDA (NAME ACCESS RECOG PARAMETERS DEVICE) (* smL "12-Mar-86 16:55") (* * Implements the OPENFILE method for the {FCACHE-whatever} file device.) (* Why is this RESETLST here, you ask? So that the cache lookup can return us a cache entry with the lock on that entry in our possesion, knowing that the lock will be released in the enclosing RESETLST) (RESETLST (LET ((localDevice (\FCACHE.LOCALDEVICE)) fullName cacheStream cacheEntry fileExisted? filePages) (* * Set the default RECOG) [SETQ RECOG (OR RECOG (SELECTQ ACCESS (INPUT (QUOTE OLD)) (OUTPUT (QUOTE NEW)) ((BOTH APPEND) (QUOTE OLD/NEW)) (\ILLEGAL.ARG ACCESS] (* * Try to get a cache entry) (SETQ filePages (OR (CADR (ASSOC (QUOTE SIZE) PARAMETERS)) (FOLDHI (OR (CADR (ASSOC (QUOTE LENGTH) PARAMETERS)) 0) BYTESPERPAGE))) (SETQ fullName (\FCACHE.USECACHE? NAME ACCESS RECOG PARAMETERS DEVICE filePages)) (if (type? CACHENTRY fullName) then (* We already have the cache entry, go ahead and use it) (SETQ fileExisted? T) (SETQ cacheEntry fullName) (SETQ fullName (fetch REMOTEFILENAME of cacheEntry)) elseif fullName then (* We should use the cache, but there is no cache entry available) (SELECTQ ACCESS (INPUT (SETQ cacheEntry (\FCACHE.LOAD fullName))) [(OUTPUT BOTH APPEND) (SETQ fileExisted? (FDEVOP (QUOTE GETFILENAME) DEVICE fullName (QUOTE OLD) DEVICE)) (if fileExisted? then (SETQ cacheEntry (\FCACHE.LOAD fullName)) else (* We get to add a brand new file to the cache) (\FCACHE.KEEPVERSIONS fullName (\FCACHE.PROPERTY (QUOTE KEEPVERSIONS) )) (SETQ cacheEntry (\FCACHE.ADDENTRY (OUTFILEP (\FCACHE.INVENTNAME fullName)) fullName (IDATE) NIL filePages] (\ILLEGAL.ARG ACCESS))) (* * Now if we have a cache entry, try to open it) (if cacheEntry then (SETQ cacheStream (FDEVOP (QUOTE OPENFILE) localDevice (fetch LOCALFILENAME of cacheEntry) ACCESS RECOG PARAMETERS localDevice))) (* * If we are lucky and managed to cache, we have an open stream...) (if cacheStream then (* we succeeded in our attempts to cache the file. Patch up the FULLFILENAME and DEVICE fields to fool any consumers of this stream.) (replace FULLFILENAME of cacheStream with (fetch REMOTEFILENAME of cacheEntry)) (replace DEVICE of cacheStream with DEVICE) (* Store a pointer on the cache stream back to the cache entry) (STREAMPROP cacheStream (QUOTE cacheEntry) cacheEntry) (* Fill in appropriate fields in the cache entry) (if (MEMB ACCESS (QUOTE (OUTPUT BOTH APPEND))) then (replace CACHEISDIRTY of cacheEntry with T) (replace CACHETIMECLOSED of cacheEntry with NIL) (replace FILEXISTED of cacheEntry with (AND fileExisted? T)) (\FCACHE.LOGENTRY cacheEntry)) (* Advance this entry to the head of the list) (\FCACHE.PROMOTE cacheEntry DEVICE) (* Return the cache stream) cacheStream else (* For one reason or another, we don't cache this file) (REALDEVOP (QUOTE OPENFILE) DEVICE NAME ACCESS RECOG PARAMETERS DEVICE]) (\FCACHE.RENAMEFILE [LAMBDA (OLDNAME NEWNAME DEVICE) (* smL "27-Feb-86 13:14") (* * Impelments the RENAMEFILE method for the {FCACHE} file device.) (RESETLST (PROG ((OldRemoteName (\FCACHE.GETFILENAME OLDNAME (QUOTE OLD) DEVICE)) (fullNewName (FDEVOP (QUOTE GETFILENAME) DEVICE NEWNAME (QUOTE NEW) DEVICE)) (localDevice (\FCACHE.LOCALDEVICE)) entry newLocalName newRemoteName oldStream) (* can't rename open files) (if (SETQ oldStream (AND (OPENP OldRemoteName) (GETSTREAM OldRemoteName))) then (ERROR "File open, can't rename " OLDNAME)) (* flush the cache if it is dirty) (if (AND (SETQ entry (\FCACHE.LOOKUP DEVICE OldRemoteName T)) (NOT (\FCACHE.WRITEOUT entry))) then (ERROR "Can't flush file, so can't rename " OLDNAME)) (* Then do the rename on the remote host) [SETQ newRemoteName (INFILEP (LET ((realDevice (fetch (CACHEDEVICE REALDEVICE) of DEVICE))) (if (fetch RENAMEFILE of realDevice) then (REALDEVOP (QUOTE RENAMEFILE) DEVICE OldRemoteName fullNewName DEVICE) else (\GENERIC.RENAMEFILE OldRemoteName fullNewName] (* Now fix up the cache -- recompute the entry in case the rename of the file changed the cache -- like \GENERIC.RENAMEFILE does) (if (SETQ entry (\FCACHE.LOOKUP DEVICE OldRemoteName T)) then (SETQ newLocalName (\FCACHE.INVENTNAME newRemoteName)) (FDEVOP (QUOTE RENAMEFILE) localDevice (fetch LOCALFILENAME entry) newLocalName localDevice) (replace LOCALFILENAME of entry with (INFILEP newLocalName) ) (replace REMOTEFILENAME of entry with newRemoteName) (replace MATCHFILENAME of entry with (MatchFileName newRemoteName))) (RETURN newRemoteName]) (\FCACHE.REOPENFILE [LAMBDA (NAME ACCESS RECOG PARAMETERS DEVICE OLDSTREAM) (* smL "11-Feb-86 18:57") (* * Implements the REOPENFILE method for the {FCACHE} file device.) (if (NOT (STREAMPROP OLDSTREAM (QUOTE cacheEntry))) then (* it was not a cached file, so we shouldn't be here. But just to be safe...) NIL else (RESETLST (LET ((entry (\FCACHE.LOOKUP DEVICE (fetch FULLFILENAME of OLDSTREAM) T)) (localDevice (\FCACHE.LOCALDEVICE)) newStream) (if entry then (STREAMPROP OLDSTREAM (QUOTE cacheEntry) entry) (OR (RESETLST (RESETSAVE (replace DEVICE of OLDSTREAM with localDevice) (LIST (FUNCTION [LAMBDA (stream device) (replace DEVICE of stream with device] ) OLDSTREAM DEVICE)) (SETQ newStream (FDEVOP (QUOTE REOPENFILE) localDevice (fetch LOCALFILENAME of entry) ACCESS RECOG PARAMETERS localDevice OLDSTREAM)) (if newStream then (replace DEVICE of newStream with DEVICE) (STREAMPROP newStream (QUOTE cacheEntry) entry)) newStream) (\FCACHE.OPENFILE NAME ACCESS RECOG PARAMETERS DEVICE)) else (* it wasn't -- so punt!) NIL]) (\FCACHE.SETFILEINFO [LAMBDA (NameOrStream attribute value device) (* smL "12-Feb-86 11:33") (* * The SETFILEINFO method for a cached device) (RESETLST (LET ((localDevice (\FCACHE.LOCALDEVICE)) (entry (\FCACHE.LOOKUP device NameOrStream T)) result) (if (NULL entry) then (* no cached copy, so do it on the remote one) (SETQ result (REALDEVOP (QUOTE SETFILEINFO) device (if (STREAMP NameOrStream) then (fetch FULLFILENAME of NameOrStream) else NameOrStream) attribute value device)) elseif (AND (fetch CACHEISDIRTY of entry) (NOT (fetch FILEXISTED of entry))) then (* there is no remote file, so do it on the local one) (SETQ result (FDEVOP (QUOTE SETFILEINFO) localDevice (fetch LOCALFILENAME of entry) attribute value localDevice)) elseif (AND (fetch CACHEISDIRTY of entry) (EQ attribute (QUOTE LENGTH))) then (* we can get away with doing it on the local one only, as long as we are careful) (SETQ result (FDEVOP (QUOTE SETFILEINFO) localDevice (fetch LOCALFILENAME of entry) attribute value localDevice)) else (* we really need to do it on the remote file) (SETQ result (REALDEVOP (QUOTE SETFILEINFO) device (if (STREAMP NameOrStream) then (fetch FULLFILENAME of NameOrStream) else NameOrStream) attribute value device)) (if result then (FDEVOP (QUOTE SETFILEINFO) localDevice (fetch LOCALFILENAME of entry) attribute value localDevice))) (* patch up any fields in the cache entry) (if (AND result entry) then (SELECTQ attribute (LENGTH (replace CACHEFILELENGTH of entry with value)) (CREATIONDATE (replace CACHEFILEDATE of entry with (IDATE value))) (ICREATIONDATE (replace CACHEFILEDATE of entry with value)) (PLIST (replace CACHEFILEPROPS of entry with value)) NIL)) result]) ) (* Helper fns) (DEFINEQ (\FCACHE.ENTRYINFO [LAMBDA (cacheDevice entry attribute) (* smL " 7-Aug-85 18:25") (* * Get file information for a cache entry) (SELECTQ attribute (ICREATIONDATE (* this prop is stored in the entry) (fetch CACHEFILEDATE of entry)) (CREATIONDATE (* this prop is stored in the entry) (GDATE (fetch CACHEFILEDATE of entry))) (SIZE (* this prop is stored in the entry) (if (fetch CACHEISDIRTY of entry) then (LET ((localDevice (\FCACHE.LOCALDEVICE))) (FDEVOP (QUOTE GETFILEINFO) localDevice (fetch LOCALFILENAME of entry) attribute localDevice)) else (fetch CACHEFILELENGTH of entry))) (CACHEDIRTY (* Is the local cache dirty?) (fetch CACHEISDIRTY of entry)) (CACHEFILE (* We add a file attribute, the CACHEFILE property that tells where a given remote file is cached) (fetch LOCALFILENAME of entry)) ((TYPE LENGTH) (* For these file props, the local device holds the info) (LET ((localDevice (\FCACHE.LOCALDEVICE))) (FDEVOP (QUOTE GETFILEINFO) localDevice (fetch LOCALFILENAME of entry) attribute localDevice))) (AND (REALDEVOP (QUOTE GETFILENAME) cacheDevice (fetch REMOTEFILENAME of entry) (QUOTE OLD) cacheDevice) (REALDEVOP (QUOTE GETFILEINFO) cacheDevice (fetch REMOTEFILENAME of entry) attribute cacheDevice]) ) (* * Directory enumeration functions) (DEFINEQ (\FCACHE.GENERATE.FILEINFO [LAMBDA (genfilestate attribute) (* smL " 4-Feb-86 14:17") (* * FILEINFOFN for the local directory generator) (if (fetch (LocalFileGenerator FileGenPrevEntry) of genfilestate) then (GETFILEINFO (fetch LOCALFILENAME of (fetch (LocalFileGenerator FileGenPrevEntry) of genfilestate)) attribute]) (\FCACHE.GENERATE.FILES.DEPTH [LAMBDA (pattern) (* smL " 5-Feb-86 10:05") (* * How many subdirectories are specified in the file pattern?) (PROG ((count 0) (pos 0)) LOOP(SETQ pos (STRPOS ">" pattern (ADD1 pos))) (if (NULL pos) then (RETURN count) else (add count 1) (GO LOOP]) (\FCACHE.GENERATE.LOCAL.FILES [LAMBDA (device pattern desiredprops options dirtyOnly?) (* smL "10-Feb-86 19:15") (* * Use the currently cached files to look up files) (LET [(entries (for entry in \FCACHE.LIST bind (filter ←(DIRECTORY.MATCH.SETUP pattern)) (hostName ←(fetch (CACHEDEVICE REALDEVICENAME) of device)) collect entry when (AND (OR (NOT dirtyOnly?) (fetch CACHEISDIRTY of entry)) (DIRECTORY.MATCH filter (fetch REMOTEFILENAME of entry)) [EQ hostName (\FCACHE.CANONICAL.HOSTNAME (FILENAMEFIELD (fetch REMOTEFILENAME of entry) (QUOTE HOST] (if (NEQ (QUOTE NSFILING) (\FCACHE.GENERIC.DEVICE.TYPE (fetch (CACHEDEVICE REALDEVICE) of device))) then T elseif (EQ FILING.ENUMERATION.DEPTH T) then T else (LESSP (\FCACHE.GENERATE.FILES.DEPTH (fetch REMOTEFILENAME of entry)) (PLUS ( \FCACHE.GENERATE.FILES.DEPTH pattern) FILING.ENUMERATION.DEPTH] (create FILEGENOBJ NEXTFILEFN ←(FUNCTION \FCACHE.NEXT.LOCAL.FILE) FILEINFOFN ←(FUNCTION \FCACHE.GENERATE.FILEINFO) GENFILESTATE ←(create LocalFileGenerator FileGenEntryList ←(if (MEMB (QUOTE SORT) options) then [SORT entries (FUNCTION (LAMBDA (X Y) (FMEMB (FILES.IN.ORDER? (fetch MATCHFILENAME of X) (fetch MATCHFILENAME of Y)) (QUOTE (EQUAL LESSP] else entries) FileGenDirtyOnly? ← dirtyOnly?]) (\FCACHE.NEXT.LOCAL.FILE [LAMBDA (genfilestate nameonly) (* smL " 5-Feb-86 11:18") (* * The NEXTFILEFN for local file generation) (LET [(entry (pop (fetch (LocalFileGenerator FileGenEntryList) of genfilestate] (if (NULL entry) then (* at the end) (replace (LocalFileGenerator FileGenPrevEntry) of genfilestate with NIL) NIL elseif (AND (fetch (LocalFileGenerator FileGenDirtyOnly?) of genfilestate) (NOT (fetch CACHEISDIRTY of entry))) then (* skip this entry, it isn't dirty) (\FCACHE.NEXT.LOCAL.FILE genfilestate nameonly) else (* use this entry) (replace (LocalFileGenerator FileGenPrevEntry) of genfilestate with entry) (fetch REMOTEFILENAME of entry]) ) (* Merging together two file generators) (DEFINEQ (MERGE.FILEGENERATORS [LAMBDA (gen1 gen2 sorted?) (* smL "28-Jun-85 15:49") (* * Merge the two file generators into one) (create FILEGENOBJ NEXTFILEFN ←(FUNCTION MERGED.NEXTFILEFN) FILEINFOFN ←(FUNCTION MERGED.FILEINFOFN) GENFILESTATE ←(create MERGEDFILEGENSTATE gen1 ← gen1 gen2 ← gen2 sorted? ← sorted?]) (MERGED.FILEINFOFN [LAMBDA (genState attribute) (* smL "28-Jun-85 15:42") (* * The FILEINFOFN for a merged filegenerator) (with MERGEDFILEGENSTATE genState (if lastUsedGen then (\GENERATEFILEINFO lastUsedGen attribute) else (ERROR "No files generated yet!"]) (MERGED.NEXTFILEFN [LAMBDA (genState nameOnly) (* smL " 4-Feb-86 18:12") (* * The NEXTFILEFN for a merged filegenerator) (with MERGEDFILEGENSTATE genState (PROG (nextFile) TRYNEXTFILE (SETQ nextFile (\MERGED.NEXTFILEFN1 genState nameOnly)) (if (NULL nextFile) then (* no more files) (RETURN NIL) elseif (MEMB (MKATOM (U-CASE nextFile)) genedFiles) then (* don't include the file twice) (GO TRYNEXTFILE) else (push genedFiles (MKATOM (U-CASE nextFile))) (RETURN nextFile]) (\MERGED.NEXTFILEFN1 [LAMBDA (genState nameOnly) (* smL " 4-Feb-86 18:06") (* * Almost the NEXTFILEFN for a merged filegenerator, but doesn't worry about replications) (with MERGEDFILEGENSTATE genState (LET (file gen1File gen2File) (if (NOT sorted?) then (* easy -- just use the first one till it is done, then switch to the second one) (if (NOT gen1Empty?) then (SETQ file (\GENERATENEXTFILE gen1 nameOnly)) (SETQ lastUsedGen gen1) (if (NULL file) then (SETQ gen1Empty? T) (\MERGED.NEXTFILEFN1 genState nameOnly) else file) else (SETQ file (\GENERATENEXTFILE gen2 nameOnly)) (SETQ lastUsedGen gen2) (if (NULL file) then (SETQ gen2Empty? T) file else file)) else (* sorted is more difficult --) [SETQ gen1File (OR gen1Info (AND (NOT gen1Empty?) (\GENERATENEXTFILE gen1 nameOnly] [SETQ gen2File (OR gen2Info (AND (NOT gen2Empty?) (\GENERATENEXTFILE gen2 nameOnly] (if (AND (NOT gen1File) (NOT gen2File) gen1Empty? gen2Empty?) then (* bad boy, you shouldnt be doing this) (ERROR "File generator exhausted!") ) (if (NOT gen1File) then (SETQ gen1Empty? T)) (if (NOT gen2File) then (SETQ gen2Empty? T)) (* if either gen1File or gen2File is NIL, things are easy) (if (NOT gen1File) then (SETQ gen2Info NIL) (SETQ lastUsedGen gen2) gen2File elseif (NOT gen2File) then (SETQ gen1Info NIL) (SETQ lastUsedGen gen1) gen1File else (* use the one that occurs first in order, but remember the unused one) (SELECTQ (FILES.IN.ORDER? gen1File gen2File) ((EQUAL LESSP) (SETQ gen1Info NIL) (SETQ gen2Info gen2File) (SETQ lastUsedGen gen1) gen1File) (GREATERP (SETQ gen1Info gen1File) (SETQ gen2Info NIL) (SETQ lastUsedGen gen2) gen2File) (SHOULDNT]) (FILES.IN.ORDER? [LAMBDA (file1 file2) (* smL " 7-Feb-86 15:08") (* * Are the two files in correct order for a directory generation?) (LET ((testFile1 (U-CASE file1)) (testFile2 (U-CASE file2))) (if (EQ testFile1 testFile2) then (QUOTE EQUAL) else (OR [for field in (QUOTE (DIRECTORY NAME EXTENSION)) bind file1Field file2Field do (SETQ file1Field (UNPACKFILENAME.STRING testFile1 field)) (SETQ file2Field (UNPACKFILENAME.STRING testFile2 field)) (if (AND (NULL file1Field) (NULL file2Field)) then NIL elseif (NULL file1Field) then (RETURN (QUOTE LESSP)) elseif (NULL file2Field) then (RETURN (QUOTE GREATERP)) elseif (STRING-EQUAL file1Field file2Field) then NIL elseif (ALPHORDER file1Field file2Field) then (RETURN (QUOTE LESSP)) else (RETURN (QUOTE GREATERP] (LET [(version1 (FILENAMEFIELD testFile1 (QUOTE VERSION))) (version2 (FILENAMEFIELD testFile2 (QUOTE VERSION] (if (AND (NUMBERP version1) (NUMBERP version2)) then (if (LESSP version1 version2) then (QUOTE LESSP) else (QUOTE GREATERP)) elseif (ALPHORDER testFile1 testFile2) then (QUOTE LESSP) else (QUOTE GREATERP]) ) (DECLARE: DONTCOPY [DECLARE: EVAL@COMPILE (RECORD MERGEDFILEGENSTATE (gen1 gen2 lastUsedGen gen1Info gen2Info gen1Empty? gen2Empty? sorted? genedFiles) (SYSTEM)) (RECORD LocalFileGenerator (FileGenEntryList FileGenDirtyOnly? FileGenPrevEntry) (SYSTEM)) ] ) (* * Functions for finding a file in the cache) (DEFINEQ (\FCACHE.LOOKUP [LAMBDA (DEVICE NAME/STREAM Verify?) (* smL "13-Mar-86 14:45") (* * Find the matching entry in the cache) (* * NOTE: This fn returns holding the entries CACHELOCK. It should only be called from within a RESETLST!) (OR (AND (STREAMP NAME/STREAM) (STREAMPROP NAME/STREAM (QUOTE cacheEntry))) (PROG ((ListOfEntries \FCACHE.LIST) entry DAT verified?) (* First get the upper case file name) (if (LITATOM NAME/STREAM) then (SETQ NAME/STREAM (U-CASE NAME/STREAM)) elseif (STREAMP NAME/STREAM) then (SETQ NAME/STREAM (U-CASE (fetch FULLFILENAME of NAME/STREAM))) elseif (STRINGP NAME/STREAM) then (SETQ NAME/STREAM (MKATOM (U-CASE NAME/STREAM))) else (\ILLEGAL.ARG NAME/STREAM)) (* Now hunt for a cache entry that matches) TryNextEntry [SETQ entry (CAR (OR (LISTP ListOfEntries) (RETURN NIL] (if (EQ (fetch MATCHFILENAME of entry) NAME/STREAM) then (OBTAIN.MONITORLOCK (fetch CACHELOCK of entry) NIL T) (if (NOT (MEMB entry \FCACHE.LIST)) then (* The entry has been deleted by some other process!) NIL elseif (OR (NOT Verify?) (\FCACHE.VERIFY entry DEVICE)) then (* it matches!) (RETURN entry) else (* The cache is invalid, so get rid of it) (if (\FCACHE.PRINT.MESSAGE?) then (printout *FILE-CACHE-MESSAGE-STREAM* "[Invalid cache file!]" T)) (\FCACHE.DELETE.ENTRY entry))) (SETQ ListOfEntries (CDR ListOfEntries)) (GO TryNextEntry]) (\FCACHE.PROMOTE [LAMBDA (ENTRY DEVICE) (* smL "23-Sep-85 13:27") (* * Promote ENTRY to head of cache so that is will be found faster the next time -- and won't be deleted to make space for new files in the cache. It turns out that searching doing an \FCACHE.LOOKUP with about 200 entries in the cache takes less than .4 seconds on a DTiger, even if the file is not found. This is quick enough that there no need to try to speed up cache file lookup.) [if (NEQ ENTRY (CAR \FCACHE.LIST)) then (for TAIL on \FCACHE.LIST when (EQ (CADR TAIL) ENTRY) do (RETURN (UNINTERRUPTABLY (SETQ \FCACHE.LIST (CONS ENTRY \FCACHE.LIST)) (RPLACD TAIL (CDDR TAIL)))] ENTRY]) (\FCACHE.USECACHE? [LAMBDA (NAME ACCESS RECOG PARAMETERS DEVICE FILEPAGES) (* smL "13-Mar-86 10:02") (* * Used by \FCACHE.OPENFILE to determine if opening a file should go thru the cache. - Return NIL if the cache should be avoided - a CACHENTRY if it is the entry that should be used - the FULLNAME of the file if it is OK to cache it, but it isn't cached now) (if (MEMB (QUOTE FCACHE.INTERNAL) PARAMETERS) then (* A FILECACHE internal call to OPENSTREAM) NIL else (LET* [[Don'tCacheFlag? (OR (MEMB (QUOTE DON'TCACHE) PARAMETERS) (CADR (ASSOC (QUOTE DON'TCACHE) PARAMETERS] (fullName (FDEVOP (QUOTE GETFILENAME) DEVICE NAME RECOG DEVICE)) (cacheEntry (AND fullName (\FCACHE.LOOKUP DEVICE fullName T] (if (NOT fullName) then (* Can't even find the full file name) NIL elseif (AND cacheEntry (fetch CACHEISDIRTY of cacheEntry)) then (* The cache entry is the only valid copy of the file, so we have to use it) cacheEntry elseif cacheEntry then (SELECTQ ACCESS (INPUT (* Perfectly safe to use the cache as we are not going to be writing the file) cacheEntry) ((OUTPUT BOTH APPEND) (* Only use the cache entry if the cache is write enabled.) (if [AND (NOT Don'tCacheFlag?) (MEMB (\FCACHE.PROPERTY (QUOTE USECACHE)) (QUOTE (T Write] then cacheEntry else NIL)) (\ILLEGAL.ARG ACCESS)) elseif [NOT (MEMB (\FCACHE.PROPERTY (QUOTE USECACHE)) (SELECTQ ACCESS (INPUT (QUOTE (T Read))) ((OUTPUT BOTH APPEND) (QUOTE (T Write))) (\ILLEGAL.ARG ACCESS] then (* Cache not enabled for the access mode) NIL elseif Don'tCacheFlag? then (* We are told to not add the file to the cache) NIL elseif (NOT (ADD.FILE.TO.CACHE? fullName)) then (* The file is on the list of DONT.CACHE.FILES so don't add it to the cache) NIL elseif [AND FILEPAGES (\FCACHE.PROPERTY (QUOTE MAXFILEPAGES)) (GREATERP FILEPAGES (\FCACHE.PROPERTY (QUOTE MAXFILEPAGES] then (* File too big, don't bother) NIL else (* Go ahead and add it if you like) fullName]) (\FCACHE.VERIFY [LAMBDA (entry cacheDevice) (* smL "13-Mar-86 14:39") (* * Verify that the entry is valid) (* It is possible to pass in a name instead of a device) (if (OR (LITATOM cacheDevice) (STRINGP cacheDevice)) then (SETQ cacheDevice (\GETCACHEDEVICEFROMHOSTNAME cacheDevice T))) (AND (INFILEP (fetch LOCALFILENAME of entry)) (OR [ILESSP (IDATE) (PLUS (fetch TIMELASTVERIFIED of entry) (TIMES (CONSTANT (DIFFERENCE (IDATE "1-JAN-80 12:00:01") (IDATE "1-JAN-80 12:00:00"))) (\FCACHE.PROPERTY (QUOTE TIMETOVERIFY] (\FCACHE.IGNOREDATECHECK? entry cacheDevice) (WITH.MONITOR (fetch CACHELOCK of entry) (if (OR (NOT (fetch CACHEISDIRTY of entry)) (fetch FILEXISTED of entry)) then (* entry is valid iff it matches the one out there) (if [AND (REALDEVOP (QUOTE GETFILENAME) cacheDevice (fetch REMOTEFILENAME of entry) (QUOTE OLD) cacheDevice) (LET ((idate (REALDEVOP (QUOTE GETFILEINFO) cacheDevice (fetch REMOTEFILENAME of entry) (QUOTE ICREATIONDATE) cacheDevice))) (AND (NUMBERP idate) (IEQP idate (fetch CACHEFILEDATE of entry] then (replace TIMELASTVERIFIED of entry with (OR (IDATE) 0)) T) else (* it is the most recent, so it is up to date) T]) ) (DECLARE: EVAL@COMPILE [DEFMACRO MatchFileName (fileName) (* * Compute the match file name from a given filename) (BQUOTE (MKATOM (U-CASE , fileName] ) (* * Try to figure out if a host is up) (DEFINEQ (\FCACHE.HOSTUP? [LAMBDA (name) (* smL " 6-Feb-86 16:16") (* * Try to determine if the host if able to respond) (if (MEMB (U-CASE (MKATOM name)) FCACHE.DEAD.HOSTS) then NIL else (LET ((DEV (\GETDEVICEFROMNAME name T NIL))) (SELECTQ (COND (DEV (* use real DEV to determine the DEV type) (SELECTQ (fetch OPENFILE of DEV) ((\LEAF.OPENFILE \FTP.OPENFILE) (QUOTE LEAF)) (\NSFILING.OPENFILE (QUOTE NSFILING)) (fetch DEVICENAME of DEV))) (T (* the FDEV doesn't exist, and we can't create one for it, so it must be down) (QUOTE NOFDEV))) [LEAF (* We think its a LEAF server, so try PUP.ECHOUSER) (RESETLST (PROG ((i 1) (interval 1000) (PORT (BESTPUPADDRESS name *FILE-CACHE-MESSAGE-STREAM*)) (SOC (OPENPUPSOCKET)) echo OPUP IPUP ECHOPUPLENGTH I) (RESETSAVE NIL (LIST (QUOTE CLOSEPUPSOCKET) SOC)) (OR PORT (RETURN)) TryAgain (if (IGREATERP i 3) then (RETURN NIL)) (SETQ OPUP (ALLOCATE.PUP)) (SETUPPUP OPUP PORT \PUPSOCKET.ECHO \PT.ECHOME NIL SOC T) (PUTPUPWORD OPUP 0 (SETQ I 1)) (add (fetch PUPLENGTH of OPUP) BYTESPERWORD) (SETQ ECHOPUPLENGTH (fetch PUPLENGTH of OPUP)) (SENDPUP SOC OPUP) [COND ((SETQ IPUP (GETPUP SOC interval)) (COND ((PROG1 (AND (EQ (fetch PUPTYPE of IPUP) \PT.IAMECHO) (EQ (fetch PUPIDHI of IPUP) (fetch PUPIDHI of OPUP)) (EQ (fetch PUPIDLO of IPUP) (fetch PUPIDLO of OPUP)) (EQ (fetch PUPLENGTH of IPUP) ECHOPUPLENGTH) (IEQP (GETPUPWORD IPUP 0) I)) (RELEASE.PUP IPUP)) (RETURN T] (SETQ i (ADD1 i)) (SETQ interval (ITIMES interval 2)) (GO TryAgain] [NSFILING (* We think its an NSFILING server, so try NS.ECHOUSER) (RESETLST (PROG ((i 1) (interval 1000) (ECHOADDRESS (if DEV then (create NSADDRESS using ( \NSFILING.ADDRESS DEV) NSSOCKET ← \NS.WKS.Echo) else (\COERCE.TO.NSADDRESS name \NS.WKS.Echo))) (NSOC (OPENNSOCKET)) echo OXIP IXIP ECHOXIPLENGTH XIPBASE NSOC I) (RESETSAVE NIL (LIST (QUOTE CLOSENSOCKET) NSOC)) (OR ECHOADDRESS (RETURN)) TryAgain (if (IGREATERP i 3) then (RETURN NIL)) (SETQ OXIP (\FILLINXIP \XIPT.ECHO NSOC ECHOADDRESS)) (XIPAPPEND.WORD OXIP \XECHO.OP.REQUEST) (XIPAPPEND.WORD OXIP (SETQ I 1)) (SETQ ECHOXIPLENGTH (fetch XIPLENGTH of OXIP)) (SENDXIP NSOC OXIP) [COND ((SETQ IXIP (GETXIP NSOC interval)) (COND ((PROG1 (AND (EQ (fetch XIPTYPE of IXIP) \XIPT.ECHO) (EQ (fetch XIPLENGTH of IXIP) ECHOXIPLENGTH) (EQ (\GETBASE (SETQ XIPBASE (fetch XIPCONTENTS of IXIP)) 0) \XECHO.OP.REPLY)) (RELEASE.XIP IXIP)) (RETURN T] (SETQ i (ADD1 i)) (SETQ interval (ITIMES interval 2)) (GO TryAgain] (FLOPPY (* the FLOPPY disk) (* Should be (FLOPPY.CAN.READP) but this triggers a bug in the Floppy handler) T) (TCP (* A TCP device. Punt on them) T) (NOFDEV (* we can't create an FDEV for the device, so it can't be up) NIL) T]) (\NSFILING.ADDRESS [LAMBDA (DEV) (* lmm "14-Sep-85 16:27") (CAR (fetch NSFSADDRESSES of (fetch NSFILESERVER of (fetch DEVICEINFO of DEV]) (\FCACHE.IGNOREDATECHECK? [LAMBDA (entry cacheDevice) (* smL "27-Feb-86 11:20") (* * Should we ignore the date check, or not?) (RESETLST (LET ((hostName (fetch (CACHEDEVICE REALDEVICENAME) of cacheDevice))) (if (OR (fetch CACHEISDIRTY of entry) (\FCACHE.ENTRYOPEN? entry)) then T elseif (\FCACHE.HOSTUP? hostName) then NIL elseif (MEMB (U-CASE (MKATOM hostName)) FCACHE.DEAD.HOSTS) then T else (SELECTQ (\FCACHE.PROPERTY (QUOTE UNSAFE)) (T (* We are told to use the local cache) T) (NOTIFY (* Use the cache, but notify the user what is going on) (printout *FILE-CACHE-MESSAGE-STREAM* T "It doesn't look like I can check to see if" , (fetch LOCALFILENAME of entry) , "is a valid cache for" , (fetch REMOTEFILENAME of entry) ", but I'm using it anyway.") T) [ASK (* Ask to find out what to do) (WITH.FCACHE.ABORT.WINDOW msgWindow (WINDOWPROP msgWindow (QUOTE TITLE) (CONCAT hostName " not responding...")) (CLEARW msgWindow) (printout msgWindow .FONT DEFAULTFONT "Can't verify if" T .FONT BOLDFONT .CENTER 0 (fetch LOCALFILENAME of entry) .FONT DEFAULTFONT T "is a valid cache entry for" .FONT BOLDFONT T .CENTER 0 (fetch REMOTEFILENAME of entry) .FONT DEFAULTFONT T T .CENTER 0 "I'll keep trying...") (WINDOWPROP msgWindow (QUOTE ItemPicked) NIL) (LET [(menu (create MENU CENTERFLG ← T ITEMS ←(QUOTE (("Trust the cache" Use) ("Don't trust the cache" Don'tUse) ("Add to DEAD.HOSTS" MakeDead))) WHENSELECTEDFN ←(FUNCTION \FCACHE.HOSTDEAD.WHENSELECTEDFN] (ADDMENU menu msgWindow (create POSITION XCOORD ←(IQUOTIENT (DIFFERENCE (WINDOWPROP msgWindow (QUOTE WIDTH)) (fetch IMAGEWIDTH of menu)) 2) YCOORD ← 10))) (during (\FCACHE.PROPERTY (QUOTE UNSAFE.TIMEOUT)) timerUnits (QUOTE SECONDS) do (BLOCK) (if (\FCACHE.HOSTUP? hostName) then (RETURN NIL) else (SELECTQ (WINDOWPROP msgWindow (QUOTE ItemPicked)) (Use (RETURN T)) (Don'tUse (RETURN NIL)) (MakeDead (pushnew FCACHE.DEAD.HOSTS hostName) (RETURN T)) NIL)) finally (RETURN (\FCACHE.PROPERTY (QUOTE UNSAFE.DEFAULT] (NIL (* We are running in cautious mode) NIL) NIL]) (\FCACHE.USELOCALDIRECTORY? [LAMBDA (hostName filePattern) (* smL "27-Feb-86 11:21") (* * The hostName is down, should we use the cached files to generate a directory?) (RESETLST (if (\FCACHE.HOSTUP? hostName) then NIL elseif (MEMB (U-CASE (MKATOM hostName)) FCACHE.DEAD.HOSTS) then T else (SELECTQ (\FCACHE.PROPERTY (QUOTE UNSAFE)) (T (* We are told to use the local cache) T) (NOTIFY (* Use the cache, but notify the user what is going on) (printout *FILE-CACHE-MESSAGE-STREAM* T hostName , "does not seem to be responding for directory lookup " "for file pattern " filePattern T "Using local cache list instead.") T) [ASK (* Ask to find out what to do) (WITH.FCACHE.ABORT.WINDOW msgWindow (WINDOWPROP msgWindow (QUOTE TITLE) (CONCAT hostName " not responding...")) (CLEARW msgWindow) (printout msgWindow .FONT DEFAULTFONT "Can't use remote host for directory lookup for file" T .FONT BOLDFONT .CENTER 0 filePattern .FONT DEFAULTFONT T T .CENTER 0 "I'll keep trying...") (WINDOWPROP msgWindow (QUOTE ItemPicked) NIL) (LET [(menu (create MENU CENTERFLG ← T ITEMS ←(QUOTE (("Trust the cache" Use) ("Don't trust the cache" Don'tUse) ("Add to DEAD.HOSTS" MakeDead))) WHENSELECTEDFN ←(FUNCTION \FCACHE.HOSTDEAD.WHENSELECTEDFN] (ADDMENU menu msgWindow (create POSITION XCOORD ←(IQUOTIENT (DIFFERENCE (WINDOWPROP msgWindow (QUOTE WIDTH)) (fetch IMAGEWIDTH of menu)) 2) YCOORD ← 10))) (during (\FCACHE.PROPERTY (QUOTE UNSAFE.TIMEOUT)) timerUnits (QUOTE SECONDS) do (BLOCK) (if (\FCACHE.HOSTUP? hostName) then (RETURN NIL) else (SELECTQ (WINDOWPROP msgWindow (QUOTE ItemPicked)) (Use (RETURN T)) (Don'tUse (RETURN NIL)) (MakeDead (pushnew FCACHE.DEAD.HOSTS hostName) (RETURN T)) NIL)) finally (RETURN (\FCACHE.PROPERTY (QUOTE UNSAFE.DEFAULT] (NIL (* We are running in cautious mode) NIL) NIL]) (\FCACHE.HOSTDEAD.WHENSELECTEDFN [LAMBDA (item menu button) (* smL " 5-Feb-86 13:51") (* * The WHENSELECTEDFN for the abort windows used to prompt a user when a host is dead) (LET ((msgWindow (WFROMMENU menu))) (if [AND item (NOT (WINDOWPROP msgWindow (QUOTE ItemPicked] then (SHADEITEM item menu GRAYSHADE) (WINDOWPROP msgWindow (QUOTE ItemPicked) (if (LITATOM item) then item else (CADR item]) ) (RPAQ? FCACHE.DEAD.HOSTS NIL) (DECLARE: DOEVAL@COMPILE DONTCOPY (GLOBALVARS FCACHE.DEAD.HOSTS) ) (* * Functions for dealing with overflow of the cache) (DEFINEQ (\FCACHE.RESOURCES.ERROR [LAMBDA (file) (* smL "13-Mar-86 10:59") (* * Called when there is a "FILE SYSTEM RESOURCES EXCEEDED" error.) (* NOTE: this counts on the fact that there is only one stream per file name!) (LET [(stream (AND (OPENP file) (GETSTREAM file] (if (AND (STREAMP stream) (STREAMPROP stream (QUOTE cacheEntry))) then (* The error happened while trying to write to a cached file, so delete some old entry and try again.) (* the magic number 10 is just a convienient number. Nothing special) (\FCACHE.MAKEROOM 10) elseif (for fn in (QUOTE (\FCACHE.LOAD \FCACHE.LOGENTRY FCACHE.DUMP)) thereis (STKPOS fn)) then (* inside of a cacher operation, so try to make room) (\FCACHE.MAKEROOM 10) elseif (EQ (\FCACHE.LOCALDEVICE) (if stream then (fetch DEVICE of stream) else (\GETDEVICEFROMNAME file T))) then (* Got the error on the local device, so delete a couple of cache files and try again) (\FCACHE.MAKEROOM 10) else (* we can't do anything about it) NIL]) ) (* * Functions for writing out dirty files from the cache) (DEFINEQ (\FCACHE.ENTRYOPEN? [LAMBDA (entry) (* smL "14-Jun-85 11:37") (* * Is the file this entry describes open?) (DECLARE (GLOBALVARS \OPENFILES)) (for stream in \OPENFILES thereis (EQ entry (STREAMPROP stream (QUOTE cacheEntry]) (\FCACHE.FLUSH [LAMBDA NIL (* smL "31-Jul-85 17:44") (* * Background function that flushes dirty files out the the remote hosts) (PROG NIL WAIT(BLOCK (\FCACHE.PROPERTY (QUOTE DUMPSLEEP))) (for entry in \FCACHE.LIST do (if [AND (fetch CACHEISDIRTY of entry) (NOT (\FCACHE.ENTRYOPEN? entry)) (FIXP (fetch CACHETIMECLOSED of entry)) (GREATERP (IDATE) (PLUS (fetch CACHETIMECLOSED of entry) (\FCACHE.PROPERTY (QUOTE DUMPIDLE] then (\FCACHE.WRITEOUT entry))) (GO WAIT]) (\FCACHE.WRITEOUT [LAMBDA (entry) (* smL "13-Mar-86 10:07") (* * Write a cache entry out to the remote host) (RESETLST (OBTAIN.MONITORLOCK \FCACHE.DUMPLOCK NIL T) (OBTAIN.MONITORLOCK (fetch CACHELOCK of entry) NIL T) (PROG ((originalFileName (fetch REMOTEFILENAME of entry)) (fileName (fetch REMOTEFILENAME of entry)) (localDevice (\FCACHE.LOCALDEVICE)) newFileName remoteDevice inStream outStream errorN (errorCount 0) idate) (* * First make sure that we can and should write out the entry) StartAgain (if (NOT (fetch CACHEISDIRTY of entry)) then (* we don't need to flush it) (RETURN T) elseif (\FCACHE.ENTRYOPEN? entry) then (* can't flush files that are open) (RETURN NIL) elseif (NOT (INFILEP (fetch LOCALFILENAME of entry))) then (* Gad, the cached file has disappeared!) (\FCACHE.DELETE.ENTRY entry) (LET ((msgWindow (\FCACHE.CREATE.MSG.WINDOW))) (printout msgWindow "WARNING: the cached version of the file" T T .FONT BOLDFONT originalFileName .FONT DEFAULTFONT T T "was deleted from the cache before it " "be written to its host!" T T "The file has been lost forever!" T T "Some Interlisp-D utilities might get confused " "because the file no longer exists.")) (RETURN NIL) elseif [NOT (AND (\FCACHE.HOSTUP? (FILENAMEFIELD fileName (QUOTE HOST))) (type? FDEV (SETQ remoteDevice ( \GETDEVICEFROMNAME fileName T] then (* can't find the server) (RETURN NIL)) (* * verify that the state of this file on the server out there has not changed) (if (fetch FILEXISTED of entry) then (if (NOT (FDEVOP (QUOTE GETFILENAME) remoteDevice fileName (QUOTE OLD) remoteDevice)) then (WITH.FCACHE.ABORT.WINDOW msgWindow (WINDOWPROP msgWindow (QUOTE TITLE) "FileCache -- problem writing out file") (printout msgWindow .FONT DEFAULTFONT "When the cached file " T .FONT BOLDFONT .TAB 10 fileName T .FONT DEFAULTFONT "was created, a remote version of the file existed." T "It is now time to write out the cached version," T "but the remote file has disappeared!" T) (SELECTQ [CADR (\FCACHE.WRITEOUT.NEWFILENAME msgWindow (QUOTE (("Write it out anyway" Same) ( "Write it out somewhere else" Other) ( "Delete the cache file" Delete] (Same (CLOSEW msgWindow) (GO OpenFiles)) (Other (SETQ newFileName ( \FCACHE.WRITEOUT.READNEWFILENAME fileName msgWindow)) (CLOSEW msgWindow) (GO SetDumpFileName)) (Delete (CLOSEW msgWindow) (GO DeleteEntry)) NIL)) elseif (NOT (EQUAL (fetch CACHEFILEDATE of entry) (FDEVOP (QUOTE GETFILEINFO) remoteDevice fileName (QUOTE ICREATIONDATE) remoteDevice))) then (WITH.FCACHE.ABORT.WINDOW msgWindow (WINDOWPROP msgWindow (QUOTE TITLE) "FileCache -- problem writing out file") (printout msgWindow .FONT DEFAULTFONT "The remote version of " T .FONT BOLDFONT .TAB 10 fileName T .FONT DEFAULTFONT "has changed since you wrote the cached file." T) (SELECTQ [CADR (\FCACHE.WRITEOUT.NEWFILENAME msgWindow (QUOTE (("Write it out anyway" Same) ( "Write it out somewhere else" Other) ( "Delete the cache file" Delete] (Same (CLOSEW msgWindow) (GO OpenFiles)) (Other (SETQ newFileName ( \FCACHE.WRITEOUT.READNEWFILENAME fileName msgWindow)) (CLOSEW msgWindow) (GO SetDumpFileName)) (Delete (CLOSEW msgWindow) (GO DeleteEntry)) NIL)) else (GO OpenFiles)) else (if (FDEVOP (QUOTE GETFILENAME) remoteDevice fileName (QUOTE OLD) remoteDevice) then (WITH.FCACHE.ABORT.WINDOW msgWindow (WINDOWPROP msgWindow (QUOTE TITLE) "FileCache -- problem writing out file") (printout msgWindow .FONT DEFAULTFONT "When the cached file " T .FONT BOLDFONT .TAB 10 fileName T .FONT DEFAULTFONT "was created, no remote version of the file existed." T "It is now time to write out the cached version," T "but a remote version of the file has since appeared!") (SELECTQ [CADR (\FCACHE.WRITEOUT.NEWFILENAME msgWindow (QUOTE (("Write it out anyway" Same) ( "Write it out somewhere else" Other) ("Delete the cache file" Delete] (Same (CLOSEW msgWindow) (GO OpenFiles)) (Other (SETQ newFileName ( \FCACHE.WRITEOUT.READNEWFILENAME fileName msgWindow)) (CLOSEW msgWindow) (GO SetDumpFileName)) (Delete (CLOSEW msgWindow) (GO DeleteEntry)) NIL)) else (GO OpenFiles))) SetDumpFileName (if newFileName then (SETQ fileName (FULLNAME newFileName (QUOTE OLD/NEW))) (replace REMOTEFILENAME of entry with fileName) (replace MATCHFILENAME of entry with (MatchFileName fileName) ) (SETQ remoteDevice (\GETDEVICEFROMNAME fileName T))) (* * open the streams for the copy) OpenFiles (if (NULL inStream) then [SETQ inStream (OPENSTREAM (fetch LOCALFILENAME of entry) (QUOTE INPUT) (QUOTE OLD) NIL (QUOTE (SEQUENTIAL] (if inStream then (RESETSAVE NIL (LIST (FUNCTION CLOSEF?) inStream)) (replace USERVISIBLE of inStream with NIL) else (RETURN NIL))) (SETQ idate (OR (FDEVOP (QUOTE GETFILEINFO) localDevice inStream (QUOTE ICREATIONDATE) localDevice) (IDATE))) [SETQ outStream (CAR (NLSETQ (OPENSTREAM fileName (QUOTE OUTPUT) (QUOTE OLD/NEW) NIL (BQUOTE (FCACHE.INTERNAL SEQUENTIAL (TYPE , (FDEVOP (QUOTE GETFILEINFO) localDevice inStream (QUOTE TYPE) localDevice)) (ICREATIONDATE , idate) (LENGTH , (FDEVOP (QUOTE GETFILEINFO) localDevice inStream (QUOTE LENGTH) localDevice] [if outStream then (RESETSAVE NIL (LIST (FUNCTION CLOSEF?) outStream)) (replace USERVISIBLE of outStream with NIL) else (* ugh -- the remote file won't open!) (add errorCount 1) (SETQ errorN (ERRORN)) (SELECTQ (CAR errorN) (41 (* the current user does not have write access to the directory) (WITH.FCACHE.ABORT.WINDOW msgWindow (WINDOWPROP msgWindow (QUOTE TITLE) "FileCache -- problem writing out file") (printout msgWindow .FONT DEFAULTFONT "You do not have write privilege for the file " T .FONT BOLDFONT .TAB 10 fileName T .FONT DEFAULTFONT) (SELECTQ [CADR (\FCACHE.WRITEOUT.NEWFILENAME msgWindow (QUOTE (("Try to write it out again" TryAgain) ("Write it out somewhere else" Other) ("Delete the cache file" Delete] (TryAgain (CLOSEW msgWindow) (GO StartAgain)) (Other (SETQ newFileName ( \FCACHE.WRITEOUT.READNEWFILENAME fileName msgWindow)) (CLOSEW msgWindow) (GO SetDumpFileName)) (Delete (CLOSEW msgWindow) (GO DeleteEntry)) NIL))) (42 (* the file name was bad) (WITH.FCACHE.ABORT.WINDOW msgWindow (WINDOWPROP msgWindow (QUOTE TITLE) "FileCache -- problem writing out file") (printout msgWindow .FONT DEFAULTFONT "The cached file " T .FONT BOLDFONT .TAB 10 fileName T .FONT DEFAULTFONT "does not appear to have a legal file name." T) (SELECTQ [CADR (\FCACHE.WRITEOUT.NEWFILENAME msgWindow (QUOTE (("Try to write it out again" TryAgain) ("Write it out somewhere else" Other) ("Delete the cache file" Delete] (TryAgain (CLOSEW msgWindow) (GO StartAgain)) (Other (SETQ newFileName ( \FCACHE.WRITEOUT.READNEWFILENAME fileName msgWindow)) (CLOSEW msgWindow) (GO SetDumpFileName)) (Delete (CLOSEW msgWindow) (GO DeleteEntry)) NIL))) (22 (* there was no room for the file) (WITH.FCACHE.ABORT.WINDOW msgWindow (WINDOWPROP msgWindow (QUOTE TITLE) "FileCache -- problem writing out file") (printout msgWindow .FONT DEFAULTFONT "There is not enough space on the server to write out the cached file " T .FONT BOLDFONT .TAB 10 fileName T .FONT DEFAULTFONT T) (SELECTQ [CADR (\FCACHE.WRITEOUT.NEWFILENAME msgWindow (QUOTE (("Try to write it out again" TryAgain) ("Write it out somewhere else" Other) ("Delete the cache file" Delete] (TryAgain (CLOSEW msgWindow) (GO StartAgain)) (Other (SETQ newFileName ( \FCACHE.WRITEOUT.READNEWFILENAME fileName msgWindow)) (CLOSEW msgWindow) (GO SetDumpFileName)) (Delete (CLOSEW msgWindow) (GO DeleteEntry)) NIL))) [9 (* a generic "File Won't Open" error. Possibly caused by the LEAF cache not having closed the file yet. Try it again.) (if (LESSP errorCount 4) then (* try it again, after a delay to let the LEAF cache get dumped) (CLEAR.LEAF.CACHE (FILENAMEFIELD fileName (QUOTE HOST))) (BLOCK 1000) (GO OpenFiles) else (* we have already tried it 3 times, so give up) (WITH.FCACHE.ABORT.WINDOW msgWindow (WINDOWPROP msgWindow (QUOTE TITLE) "FileCache -- problem writing out file") (printout msgWindow .FONT DEFAULTFONT "The error '" (ERRORSTRING (CAR ERRORN)) "'" , "occured while trying to write out the cache file " T .FONT BOLDFONT .TAB 10 fileName T .FONT DEFAULTFONT T) (SELECTQ [CADR (\FCACHE.WRITEOUT.NEWFILENAME msgWindow (QUOTE (("Try to write it out again" TryAgain) ( "Write it out somewhere else" Other) ("Delete the cache file" Delete] (TryAgain (CLOSEW msgWindow) (GO StartAgain)) (Other (SETQ newFileName ( \FCACHE.WRITEOUT.READNEWFILENAME fileName msgWindow)) (CLOSEW msgWindow) (GO SetDumpFileName)) (Delete (CLOSEW msgWindow) (GO DeleteEntry)) NIL] (PROGN (* The default case -- an unknow error) (if (LESSP errorCount 4) then (CLEAR.LEAF.CACHE (FILENAMEFIELD fileName (QUOTE HOST))) (BLOCK 1000) (GO OpenFiles) else (* alter the user and then try again) (WITH.FCACHE.ABORT.WINDOW msgWindow (WINDOWPROP msgWindow (QUOTE TITLE) "FileCache -- problem writing out file") (printout msgWindow .FONT DEFAULTFONT "The error '" (ERRORSTRING (CAR ERRORN)) "'" , "occured while trying to write out the cache file " T .FONT BOLDFONT .TAB 10 fileName T .FONT DEFAULTFONT T) (SELECTQ [CADR (\FCACHE.WRITEOUT.NEWFILENAME msgWindow (QUOTE (( "Try to write it out again" TryAgain) ( "Write it out somewhere else" Other) ( "Delete the cache file" Delete] (TryAgain (CLOSEW msgWindow) (GO StartAgain)) (Other (SETQ newFileName ( \FCACHE.WRITEOUT.READNEWFILENAME fileName msgWindow)) (CLOSEW msgWindow) (GO SetDumpFileName)) (Delete (CLOSEW msgWindow) (GO DeleteEntry)) NIL] (* * Copy it out) (\FCACHE.DONE.OR.ABORTED.MSG (CONCAT "Writing out " fileName)) (COPYCHARS inStream outStream) (if (NLSETQ (CLOSEF outStream)) then (replace CACHEISDIRTY of entry with NIL) (replace FILEXISTED of entry with NIL) (* set the creationdate for the file - - this is needed because some hosts don't set the file creation date correctly as desired in the above OPENSTREAM. The following code ensures that, after the file has been written out, the cache entry and the local file have the correct dates.) (KLUDGE (* This call to CLEAR.LEAF.CACHE and the delay after is a hack. If we don't do it, we don't always read back the correct value after the SETFILEINFO above) (CLEAR.LEAF.CACHE (fetch DEVICENAME of remoteDevice)) (BLOCK 1000)) (FDEVOP (QUOTE SETFILEINFO) remoteDevice (fetch REMOTEFILENAME of entry) (QUOTE ICREATIONDATE) idate remoteDevice) (replace CACHEFILEDATE of entry with (OR (FDEVOP (QUOTE GETFILEINFO) remoteDevice (fetch REMOTEFILENAME of entry) (QUOTE ICREATIONDATE) remoteDevice) idate)) (SETFILEINFO inStream (QUOTE ICREATIONDATE) (fetch CACHEFILEDATE of entry)) (\FCACHE.LOGENTRY entry) (replace TIMELASTVERIFIED of entry with (IDATE)) (if (NEQ originalFileName fileName) then (LET ((msgWindow (\FCACHE.CREATE.MSG.WINDOW))) (printout msgWindow "WARNING: the file that was supposed to be " T .FONT BOLDFONT .TAB 10 originalFileName T .FONT DEFAULTFONT "was actually stored as " T .FONT BOLDFONT .TAB 10 fileName T .FONT DEFAULTFONT "Some Interlisp-D utilities might get " "confused by the rename, since Lisp thought it wrote out " originalFileName , "but it actually didn't. You should try to clean up " "before accessing the file again. " "Close TEdit windows and Get the files anew; " "close Lafite folders and Browse them again; " "or do an explicit LOADFROM again for Lisp source files."))) (RETURN T) else (RETURN NIL)) DeleteEntry (CLOSEF? inStream) (\FCACHE.DELETE.ENTRY entry) (RETURN NIL]) (\FCACHE.WRITEOUT.NEWFILENAME [LAMBDA (msgWindow items) (* smL "18-Feb-86 14:07") (* * Put up a menu in the window and wait for the user to pick one of the items. Return the selected item) (PROG [(event (CREATE.EVENT (QUOTE \FCACHE.WRITEOUT))) (menu (create MENU CENTERFLG ← T MENUCOLUMNS ← 1 ITEMS ← items WHENSELECTEDFN ←(FUNCTION \FCACHE.WRITEOUT.WHENSELECTEDFN] (PUTMENUPROP menu (QUOTE event) event) (ADDMENU menu msgWindow (create POSITION XCOORD ←(QUOTIENT (DIFFERENCE (WINDOWPROP msgWindow (QUOTE WIDTH)) (fetch IMAGEWIDTH of menu)) 2) YCOORD ← 5)) WAIT(AWAIT.EVENT event) (if (NULL (GETMENUPROP menu (QUOTE selected))) then (GO WAIT) else (RETURN (GETMENUPROP menu (QUOTE selected]) (\FCACHE.WRITEOUT.READNEWFILENAME [LAMBDA (file msgwindow) (* smL "24-Feb-86 13:45") (* * Prompt the user for a new file name) (LET [(pwindow (GETPROMPTWINDOW (MAINWINDOW msgWindow T) (for line in (LIST "Write it out where >" fileName) bind (font ←(DSPFONT NIL msgwindow)) (width ←(WINDOWPROP msgwindow (QUOTE WIDTH))) sum (FIX (PLUS .9 (FQUOTIENT (STRINGWIDTH line font) width] (CLEARW pwindow) (PROMPTFORWORD "Write it out where >" fileName NIL pwindow]) (\FCACHE.WRITEOUT.WHENSELECTEDFN [LAMBDA (item menu button) (* smL " 5-Feb-86 11:33") (* * An item has been chosen from a msg window during an \FCACHE.WRITEOUT) (SHADEITEM item menu GRAYSHADE) (PUTMENUPROP menu (QUOTE selected) item) (NOTIFY.EVENT (GETMENUPROP menu (QUOTE event]) ) (RPAQ \FCACHE.DUMPLOCK (CREATE.MONITORLOCK "File cache writout")) (DECLARE: DOEVAL@COMPILE DONTCOPY (GLOBALVARS \FCACHE.DUMPLOCK) ) (* * Functions for dumping and restoring information about the contents of the cache) (DEFINEQ (\FCACHE.ADDENTRY [LAMBDA (LOCALNAME REMOTENAME ICREATIONDATE PROPS PAGES) (* smL "27-Feb-86 13:15") (* * Add an entry to the cache directory. This goes on the front of the directory so it will be found quickly in the future.) (* * NOTE: This code assumes that it is called within a RESETLST that will release the entry's CACHELOCK) (LET ((ENTRY (create CACHENTRY REMOTEFILENAME ← REMOTENAME LOCALFILENAME ← LOCALNAME MATCHFILENAME ←(MatchFileName REMOTENAME) CACHEFILEPROPS ← PROPS CACHEFILEDATE ← ICREATIONDATE CACHEFILELENGTH ← PAGES))) (OBTAIN.MONITORLOCK (fetch CACHELOCK of ENTRY) NIL T) (push \FCACHE.LIST ENTRY) (\FCACHE.PROPERTY.PUT (QUOTE SIZE) (PLUS (\FCACHE.PROPERTY (QUOTE SIZE)) PAGES)) (\FCACHE.LOGENTRY ENTRY) ENTRY]) (\FCACHE.DUMP.ENTRY [LAMBDA (entry stream) (* smL "27-Feb-86 13:08") (* * Write out a single entry to the info file) (RESETLST (RESETSAVE (RADIX 10)) (with CACHENTRY entry (printout stream T "(" .P2 REMOTEFILENAME , .P2 LOCALFILENAME T .P2 CACHEISDIRTY , .P2 FILEXISTED , .P2 CACHEFILELENGTH , .P2 CACHEFILEPROPS , .P2 CACHEFILEDATE , .P2 CACHETIMECLOSED ")" T]) (\FCACHE.FILEMATCH? [LAMBDA (fullName fileSpec) (* smL " 9-Aug-85 14:10") (* * Does the file match the spec?) (AND (DIRECTORY.MATCH (DIRECTORY.MATCH.SETUP fileSpec) fullName) (LET [(fileSpecHost (FILENAMEFIELD fileSpec (QUOTE HOST] (OR (NOT fileSpecHost) (EQ (\FCACHE.CANONICAL.HOSTNAME (FILENAMEFIELD fileSpec (QUOTE HOST))) (\FCACHE.CANONICAL.HOSTNAME (FILENAMEFIELD fullName (QUOTE HOST]) (\FCACHE.LOGENTRY [LAMBDA (entry) (* smL " 9-Aug-85 10:18") (* * Dribble out a bit of into to the cache log file so we know the state of the cache if the system dies an ungraceful death) (SETQ \FCACHE.LIST.CHANGED? T) (if (\FCACHE.PROPERTY (QUOTE PREFIX)) then (if [NOT (AND (STREAMP \FCACHE.LOGFILE) (OPENP \FCACHE.LOGFILE (QUOTE OUTPUT] then (if (STREAMP \FCACHE.LOGFILE) then (CLOSEF? \FCACHE.LOGFILE)) (SETQ \FCACHE.LOGFILE (OPENSTREAM (PACK* (\FCACHE.PROPERTY (QUOTE PREFIX)) "FCache.Log;1") (QUOTE OUTPUT) (QUOTE OLD/NEW))) (replace USERCLOSEABLE of \FCACHE.LOGFILE with NIL) (replace USERVISIBLE of \FCACHE.LOGFILE with NIL)) (\FCACHE.DUMP.ENTRY entry \FCACHE.LOGFILE) (FORCEOUTPUT \FCACHE.LOGFILE T]) (\FCACHE.RESTORE [LAMBDA (prefix) (* smL "13-Mar-86 13:34") (* * Restore the cache info dumped out by a previous system -- return T if success, NIL if failure) (RESETLST (* Clear the cache of the local device) (SETQ \FCACHE.LOCALDEVICE NIL) (if (NULL prefix) then (* disable the cache) (if (\FCACHE.PRINT.MESSAGE?) then (printout *FILE-CACHE-MESSAGE-STREAM* T "Cache prefix is NIL, so disabling cache.")) (SETQ \FCACHE.LIST NIL) (\FCACHE.PROPERTY.PUT (QUOTE SIZE) 0) (\FCACHE.PROPERTY.PUT (QUOTE PREFIX) prefix) T elseif (NULL (\GETDEVICEFROMNAME prefix T)) then (* prefix is bad) NIL elseif (LET (testFile) (* can we access that directory?) [RESETSAVE NIL (LIST [FUNCTION (LAMBDA (s) (if (STREAMP s) then (CLOSEF? s) (DELFILE (fetch FULLFILENAME of s] (SETQ testFile (CAR (NLSETQ (OPENSTREAM (PACK* prefix "fcache.temp") (QUOTE OUTPUT) (QUOTE NEW] testFile) then (PROG (name stream entryDef) (SETQ \FCACHE.LIST NIL) (\FCACHE.PROPERTY.PUT (QUOTE SIZE) 0) (\FCACHE.PROPERTY.PUT (QUOTE PREFIX) prefix) (if [NULL (SETQ name (INFILEP (PACK* prefix "FCache.Listing;1"] then (* nothing to restore) (RETURN T)) [RESETSAVE NIL (LIST (QUOTE CLOSEF?) (SETQ stream (OPENSTREAM name (QUOTE INPUT) (QUOTE OLD] (\FCACHE.DONE.OR.ABORTED.MSG "Restoring cache") (* Read in the warning msg, and make sure that it is correct.) (if (NOT (LET [(header (CAR (NLSETQ (READ stream] (if (AND (EQ (CAR header) (QUOTE ERROR)) (EQUAL (CADR header) "This file cannot be LOADed. Do not delete or alter this file!")) then (* The file header matches, so parse the properties) [LET [(plist (EVAL (CADDR header] (SETQ \FCACHE.LISTING.VERSION.NUMBER (OR (NUMBERP (LISTGET plist (QUOTE FCacheVersion)) 0))) [if (GEQ \FCACHE.LISTING.VERSION.NUMBER 1) then (\FCACHE.PROPERTY.PUT (QUOTE MAXSIZE) (LISTGET plist (QUOTE MaxSize] (if (GEQ \FCACHE.LISTING.VERSION.NUMBER 1.6) then (\FCACHE.PROPERTY.PUT (QUOTE MAXFILEPAGES) (LISTGET plist (QUOTE MaxFilePages] T else NIL))) then (LET ((errorWindow (CREATEW (create REGION LEFT ← 300 BOTTOM ← 300 WIDTH ← 425 HEIGHT ← 120) "File cache warning"))) (printout errorWindow "WARNING: The file cache directory file was trashed!" "The cacher has lost track of all the files in the cache." "If there were any files that needed to be dumped, " "they have been lost!" T T "You should run FCACHE.SCAVENGE soon to clean up your disk.")) (GO BADINFOFILE)) NEXTENTRY (if (EOFP stream) then (LET ((errorWindow (CREATEW (create REGION LEFT ← 300 BOTTOM ← 300 WIDTH ← 425 HEIGHT ← 120) "File cache warning"))) (printout errorWindow "WARNING: The file cache directory file was not completly dumped." "The cacher may have lost track of some files." "If there were any files that needed to be dumped, " "they may have been lost!" T T "You should run FCACHE.SCAVENGE soon to clean up your disk.")) (GO BADINFOFILE) elseif (EQ [SETQ entryDef (CAR (NLSETQ (READ stream] (QUOTE STOP)) then (GO DONE) elseif (NLSETQ (\FCACHE.RESTORE.ENTRY entryDef)) then (* a good entry def) (if (\FCACHE.PRINT.MESSAGE?) then (printout *FILE-CACHE-MESSAGE-STREAM* ".")) else (* a bad entry def) (if (\FCACHE.PRINT.MESSAGE?) then (printout *FILE-CACHE-MESSAGE-STREAM* "?"))) (GO NEXTENTRY) BADINFOFILE (CLOSEF? stream) (DELFILE name) (GO CLEANUP) DONE(CLOSEF? stream) CLEANUP [if (LESSP \FCACHE.LISTING.VERSION.NUMBER 5.0) then (* At version 5.0 there was a change in the way that the listing file gets written. If an older version attempts to read a cache listing created after version 5.0, it will not see any MATCHFILENAME fields in the cache entries. It might then add a file to the cache that is already cached. Then, if you go back to a more recent version of the cacher, it would find two different cache enties for the same file. TROUBLE! The following is an attempt to take care of this odd situation.) (for entries on \FCACHE.LIST do (for e in (CDR entries) when (EQ (fetch MATCHFILENAME of e) (fetch MATCHFILENAME of (CAR entries))) do (if (\FCACHE.PRINT.MESSAGE?) then (printout *FILE-CACHE-MESSAGE-STREAM* "[Duplicate cache file!]" T)) (\FCACHE.DELETE.ENTRY e] (RETURN T)) else (* nope, can't access the directory at that prefix) (if (\FCACHE.PRINT.MESSAGE?) then (printout *FILE-CACHE-MESSAGE-STREAM* T "Cache can't write to " prefix "!"]) (\FCACHE.RESTORE.ENTRY [LAMBDA (entryList first?) (* smL "27-Feb-86 13:16") (* * Restore an entryList to the cache list. Put it at the end of the list because of the order they are read in.) (LET [[entry (create CACHENTRY REMOTEFILENAME ←(CAR entryList) LOCALFILENAME ←(CADR entryList) CACHEISDIRTY ←(CADDR entryList) FILEXISTED ←(CADDDR entryList) CACHEFILELENGTH ←(CAR (CDDDDR entryList)) CACHEFILEPROPS ←(CADR (CDDDDR entryList)) CACHEFILEDATE ←(CADDR (CDDDDR entryList)) CACHETIMECLOSED ←(CADDDR (CDDDDR entryList)) MATCHFILENAME ←(MatchFileName (CAR entryList] (oldEntry (for x in \FCACHE.LIST bind (name ←(CADR entryList)) thereis (EQ name (fetch LOCALFILENAME of x] [if oldEntry then (SETQ \FCACHE.LIST (DREMOVE oldEntry \FCACHE.LIST)) (\FCACHE.PROPERTY.PUT (QUOTE SIZE) (DIFFERENCE (\FCACHE.PROPERTY (QUOTE SIZE)) (fetch CACHEFILELENGTH of oldEntry] (SETQ \FCACHE.LIST (if first? then (CONS entry \FCACHE.LIST) else (NCONC1 \FCACHE.LIST entry))) (\FCACHE.PROPERTY.PUT (QUOTE SIZE) (PLUS (\FCACHE.PROPERTY (QUOTE SIZE)) (fetch CACHEFILELENGTH of entry]) ) (RPAQQ \FCACHE.LISTING.VERSION.NUMBER NIL) (DECLARE: DOEVAL@COMPILE DONTCOPY (GLOBALVARS \FCACHE.LISTING.VERSION.NUMBER) ) (* * Functions for inspecting the cache) (DEFINEQ (\FCACHE.FLUSH.INFOHOOK [LAMBDA NIL (* smL " 5-Feb-86 18:00") (* * The info hook function for the CACHE-FLUSH proc) (if (AND \FCACHE.BROWSER (type? TABLEBROWSER \FCACHE.BROWSER) (WINDOWP (TB.WINDOW \FCACHE.BROWSER))) then (OPENW (TB.WINDOW \FCACHE.BROWSER)) (\FCACHE.BROWSE.RECOMPUTE \FCACHE.BROWSER) else (SETQ \FCACHE.BROWSER (\FCACHE.BROWSE.CACHE]) ) (* Browsing thru the cache) (DEFINEQ (\FCACHE.BROWSE.CACHE [LAMBDA NIL (* smL "14-Feb-86 17:26") (* * Build a browser for the cache) (LET* [[menu (create MENU ITEMS ←(QUOTE (Delete Prune Undelete Inspect Filter Recompute Expunge)) CENTERFLG ← T MENUROWS ← 1 MENUOUTLINESIZE ← 1 WHENSELECTEDFN ←(FUNCTION \FCACHE.BROWSE.WHENSELECTEDFN) MENUFONT ←(FONTCREATE (QUOTE Helvetica) 10 (QUOTE BOLD] (inspectWindow (CREATEW (CREATEREGION SCREENWIDTH SCREENHEIGHT (TIMES 25 (STRINGWIDTH "A" DEFAULTFONT)) (HEIGHTIFWINDOW (TIMES (ADD1 (QUOTIENT (LENGTH \FCACHE.PROPERTIES) 2)) (FONTPROP DEFAULTFONT (QUOTE HEIGHT))) T)) "File cache props")) [cacheBrowserWindowRegion (GETREGION (fetch IMAGEWIDTH of menu) (PLUS (fetch IMAGEHEIGHT of menu) (MAX (HEIGHTIFWINDOW 0 T] (cacheBrowserWindow (CREATEW (CREATEREGION (fetch LEFT of cacheBrowserWindowRegion) (fetch BOTTOM of cacheBrowserWindowRegion) [DIFFERENCE (fetch WIDTH of cacheBrowserWindowRegion) (fetch WIDTH of (WINDOWPROP inspectWindow (QUOTE REGION] (DIFFERENCE (fetch HEIGHT of cacheBrowserWindowRegion) (fetch IMAGEHEIGHT of menu))) "File cache browser")) (cacheBrowser (TB.MAKE.BROWSER NIL cacheBrowserWindow (QUOTE (USERDATA "*.*" PRINTFN \FCACHE.BROWSE.PRINTFN COPYFN \FCACHE.BROWSE.COPYFN] (* Glue the inspect window to the right of the browser window) (ATTACHWINDOW inspectWindow cacheBrowserWindow (QUOTE RIGHT) (QUOTE TOP)) [WINDOWPROP inspectWindow (QUOTE MINSIZE) (CONS (fetch WIDTH of (WINDOWPROP inspectWindow (QUOTE REGION))) (fetch HEIGHT of (WINDOWPROP inspectWindow (QUOTE REGION] [WINDOWPROP inspectWindow (QUOTE MAXSIZE) (CONS (fetch WIDTH of (WINDOWPROP inspectWindow (QUOTE REGION))) (fetch HEIGHT of (WINDOWPROP inspectWindow (QUOTE REGION] (WINDOWPROP cacheBrowserWindow (QUOTE inspectWindow) inspectWindow) (INSPECTW.CREATE \FCACHE.PROPERTIES (FUNCTION \FCACHE.PROPERTY.NAMES) (FUNCTION \FCACHE.INSPECT.VALUES) (FUNCTION [LAMBDA (object property newvalue) (FCACHE.PUTPROP property newvalue]) (FUNCTION \FCACHE.INSPECT.PROPCOMMANDFN) (FUNCTION NILL) (FUNCTION \FCACHE.INSPECT.TITLEFN) "File cache props" NIL inspectWindow) (* Glue the menu window to the top of the browser window) (PUTMENUPROP menu (QUOTE CacheBrowser) cacheBrowser) (ATTACHMENU menu cacheBrowserWindow (QUOTE TOP)) (* Give the window set a cute icon) (WINDOWPROP cacheBrowserWindow (QUOTE ICON) \FCACHE.ICON) (* Update the display) (\FCACHE.BROWSE.RECOMPUTE cacheBrowser) cacheBrowser]) (\FCACHE.BROWSE.COPYFN [LAMBDA (cacheBrowser item) (* smL " 4-Feb-86 13:48") (* * The copybutton went down on the item) (COPYINSERT (fetch REMOTEFILENAME of (fetch TIDATA of item]) (\FCACHE.BROWSE.PRINTFN [LAMBDA (cacheBrowser item window) (* smL " 3-Feb-86 17:19") (* * The PRINTFN for the cache browser) (LET ((entry (fetch TIDATA of item))) (printout window (fetch REMOTEFILENAME of entry) .TAB0 (MAX (ADD1 (POSITION window)) 60) (if (\FCACHE.ENTRYOPEN? entry) then "Open" else " ") .TAB0 (MAX (ADD1 (POSITION window)) 65) (if (fetch CACHEISDIRTY of entry) then "Dirty" else " "]) (\FCACHE.BROWSE.RECOMPUTE [LAMBDA (cacheBrowser) (* smL " 4-Feb-86 10:42") (* * The REPAINT function for a cache browser) (LET ((cacheBrowserWindow (TB.WINDOW cacheBrowser))) (TB.REPLACE.ITEMS cacheBrowser) (WINDOWPROP cacheBrowserWindow (QUOTE TITLE) (CONCAT "File cache browser -- files matching " (TB.USERDATA cacheBrowser)) ) (for entry in \FCACHE.LIST do (TB.INSERT.ITEM cacheBrowser (create TABLEITEM TIDATA ← entry TIUNDELETABLE ← T)) when (\FCACHE.FILEMATCH? (fetch REMOTEFILENAME of entry) (TB.USERDATA cacheBrowser))) (INSPECTW.REDISPLAY (WINDOWPROP cacheBrowserWindow (QUOTE inspectWindow]) (\FCACHE.BROWSE.WHENSELECTEDFN [LAMBDA (item menu button) (* smL "14-Feb-86 17:30") (* * The WHENSELECTEDFN for the FileCache browser) (RESETLST (if item then (RESETSAVE (SHADEITEM item menu GRAYSHADE) (LIST (FUNCTION SHADEITEM) item menu WHITESHADE)) (LET [(cacheBrowser (GETMENUPROP menu (QUOTE CacheBrowser] (SELECTQ (if (LITATOM item) then item else (CADR item)) [Delete (TB.MAP.SELECTED.ITEMS cacheBrowser (FUNCTION (LAMBDA ( cacheBrowser item) (TB.DELETE.ITEM cacheBrowser item] [Prune (* Thanks to MikeDixon for this idea) (bind (old.date ←(DIFFERENCE (IDATE) (TIMES (RNUMBER "Delete files untouched in how many days?" NIL NIL NIL T) 86400))) (numberDeleted ← 0) for tableItem in (fetch TBITEMS of cacheBrowser) when (AND (NUMBERP (fetch CACHETIMECLOSED of (fetch TIDATA of tableItem))) (LESSP (fetch CACHETIMECLOSED of (fetch TIDATA of tableItem) ) old.date)) do (TB.DELETE.ITEM cacheBrowser tableItem) (add numberDeleted 1) finally (\FCACHE.PRINT.PROMPT (TB.WINDOW cacheBrowser) (LIST (CONCAT "Marked " numberDeleted " cache enties for deletion"] [Undelete (TB.MAP.SELECTED.ITEMS cacheBrowser (FUNCTION (LAMBDA ( cacheBrowser item) (TB.UNDELETE.ITEM cacheBrowser item] [Inspect (LET [(firstSelectedItem (for tableItem in (fetch TBITEMS of cacheBrowser) thereis (fetch TISELECTED of tableItem] (if firstSelectedItem then (INSPECT (fetch TIDATA of firstSelectedItem] (Filter (TB.USERDATA cacheBrowser (PACKFILENAME (QUOTE BODY) (PROMPTFORWORD ">" (TB.USERDATA cacheBrowser) NIL (\FCACHE.PRINT.PROMPT (TB.WINDOW cacheBrowser) (LIST "Browse entries matching what "))) (QUOTE BODY) "*.*")) (DOSELECTEDITEM menu (QUOTE Recompute) button) (\FCACHE.PRINT.PROMPT (TB.WINDOW cacheBrowser)) ) (Recompute (\FCACHE.BROWSE.RECOMPUTE cacheBrowser)) [Expunge (TB.MAP.DELETED.ITEMS cacheBrowser (FUNCTION (LAMBDA (cacheBrowser item) (if (\FCACHE.DELETE.ENTRY (fetch TIDATA of item)) then (TB.REMOVE.ITEM cacheBrowser item] NIL]) ) (FILESLOAD READNUMBER TABLEBROWSER) (DECLARE: EVAL@COMPILE DONTCOPY DONTEVAL@LOAD (FILESLOAD TABLEBROWSERDECLS) ) (RPAQ? \FCACHE.BROWSER NIL) (RPAQ \FCACHE.ICON (READBITMAP)) (102 76 "D@GF@D@@@@@@@AOLAB@HH@@@@@@@" "OOOOOOOOOOOOOOOOOOOOOOOOOL@@" "OOOOOOOOOOOOOOOOOOOOOOOOOL@@" "OOOOOOOOOOOOCKOOOOOOOONCND@@" "FMBCOOOOONCMGFNJOOOOOOJBJH@@" "BAAKOOOKBIGAGJNBMMOOOOKJNL@@" "OOOOOONJHLC@@@@JMLLOOOOOOL@@" "OOOOOMJCL@@@@@@@@NHEMOOOOL@@" "OOOOOMOH@@@@@@@@@@@MJKKOOD@@" "B@H@DM@@@@@@@@@@@@@AKHEMIH@@" "NLKNGH@@@@@@@@@@@@@@CIGOGL@@" "M@@@D@@@@@@@@@@@@@@@@@@@@@@@" "@@@@@@@@@@@@GL@@@@@@@@@@@@@@" "@@@@@@@@@@@GOOH@@@@@@@@@@@@@" "@D@H@@@@@@AOOON@@@@@@@@@@@@@" "@@@@@@@@@@GOOOOH@@@H@DD@DD@@" "B@BL@@@@@@OL@@CL@@@H@@@@D@@@" "@@@@@@@@@AN@@@CN@@@H@@@@@D@@" "@@@@@@@@@CHO@@GO@@@HB@@BD@@@" "@@@@@@@@@GHO@@FOH@@@@@@@@@@@" "@@@@@@@@@OHC@@FGL@@@@@@@@@@@" "D@@@@@@@@OKDF@CGN@@@@@@@@@@@" "OL@@@@@@ANCN@@@GN@@@@@@@@@@@" "OL@@@@@@COHL@@CCO@@@@@@@@@@@" "ON@@@@@@CONF@@@COH@@@@@@@@@@" "OOH@@@@@GONB@@@COH@@@BJ@H@@@" "AOH@@@@@GONB@@@@OL@@@@@@@@@@" "@OL@@@@@OOOB@JMHGL@@@@@@@@@@" "HGL@@@@@OOOJMNOHOL@@@@@@L@@@" "@CL@@@@@OOKCNNOHOL@@@@AMOH@@" "@CD@@@@@OOHDDBADON@@@@COOD@@" "@CL@@@@AOONN@B@EON@@@@GNC@@@" "BCL@@@@AOOON@C@GON@@@@KOO@@@" "BGL@@@@AOOOO@A@GON@@@AKFGH@@" "NGL@@@@AOOOO@GLGOO@@@AKGO@@@" "@OL@@@@AOOOOHGHGOO@@@ACFCD@@" "COH@@@@AOOOOH@@GOO@@@CKFCL@@" "OOH@@@@AOOOOLGHGOO@@@CGGOL@@" "ON@@@@@AOOOONC@GOO@@@CNGOL@@" "OL@@@@@COOOONCHOOO@@@CNNGL@@" "O@@@@@@COOOOO@AOOO@@@AKLCL@@" "D@@@@@@AOOOOOOGOOO@@@AKGOL@@" "@@@@@@@AOOOOOOOOON@@@AOKAL@@" "@@@@@@@AOOOOOOIOOO@@@@OOGL@@" "@@@@@@@AOOOOOOAOOO@@@@GOOL@@" "HHIHD@@AOOOOO@COON@@@@COOL@@" "@EE@D@@AOOOOL@COON@@@@AOKH@@" "@HLDD@@AOOOON@COON@@@@@CL@@@" "@@DDH@@@OOOON@COOL@@@@@@@@@@" "@@@@@@@@OOOON@EOOL@@@@@@@@@@" "@@@@@@@@OOOOO@AOOL@@@@@@@@@@" "@@@@@@@@GOOOO@AOOL@@@@@@@@@@" "@@@@@@@@GOOOOH@OOH@@@@@@@@@@" "@@@@@@@@COOOOL@OOH@@@@@@@@@@" "@@@DH@@@COOOON@GO@@@@@@@@@@@" "DCLH@K@@AOOOON@GO@@@@@@G@@@@" "@@@HAG@@AOOOON@GN@AO@@@@@@@@" "@@@@@B@@@OOOOO@CH@@C@@@@@@@@" "@@@@@L@@AKOOIOHCN@@E@@@@@@@@" "MFOCIH@@AKO@BJ@AD@@@@@@@@@@@" "@@@@@@@@@CH@CB@AH@@@@@@@@@@@" "@@@@@@BD@@@NEENAD@DMMLII@@@@" "@COEMJJLJGGNLDOMKOOOOOOOL@@@" "@MBOAOLLKEONIEGO@DLOOKOO@@@@" "@AHHHAEAI@D@@IL@BDIA@IECD@@@" "FKIHHCC@HLDLHHMBBFAC@HGCNH@@" "OOILICADHDHIH@EBEBAE@HEIN@@@" "NOINICEEJLNOJJOFOOOOOOOONL@@" "OOOOOOO@@@@A@A@@@@AOOOOOOH@@" "OOOOOOOOKHOADIBGAOMOOOOOOL@@" "OO@@@@B@CH@F@B@NANAL@BAKOL@@" "OO@BHHHBAHDDBAANAN@L@B@COL@@" "OOLCH@DBAHD@BAAJAB@D@F@AOL@@" "OOLCHLDBCHDDBBA@@AHD@BNCOL@@" "OONCMMONOOOOOOOOOOOOOOOOOL@@" "OOOLOOOOOLIN@@@@@@@@@@@@@@@@") (DECLARE: DOEVAL@COMPILE DONTCOPY (GLOBALVARS \FCACHE.BROWSER \FCACHE.ICON) ) (* Inspecting the cache properties) (DEFINEQ (\FCACHE.INSPECT.PROPCOMMANDFN [LAMBDA (property object inspectw) (* smL "10-Feb-86 18:09") (* * What to do when the user has selected a property from the cache inspect window) (LET [(set?menu (CONSTANT (create MENU ITEMS ←(QUOTE ((SET (QUOTE SET) "Set the value of the property"] (SELECTQ property (USECACHE (if (MENU set?menu) then (FCACHE.PUTPROP property (SELECTQ (MENU (CONSTANT (create MENU ITEMS ←(QUOTE ((T T "Use cache for Reading and Writing") (Read (QUOTE Read) "Use cache for Reading only") (Write (QUOTE Write) "Use cache for Writing only") (NIL (QUOTE OFF) "Don't use the cache at all"))) TITLE ← "Value for USECACHE"))) (T T) (Read (QUOTE Read)) (Write (QUOTE Write)) (OFF NIL) (NIL (FCACHE.GETPROP property)) NIL)) (INSPECTW.REDISPLAY inspectw))) ((DEVICES ENTRIES SIZE) (\FCACHE.PRINT.PROMPT inspectw (LIST "Can't set that field!"))) [PREFIX (if (MENU set?menu) then (LET [(pwindow (\FCACHE.PRINT.PROMPT inspectw (LIST "Enter the new cache prefix" "The expression read will NOT be EVALuated. "] (if [NLSETQ (FCACHE.PUTPROP (QUOTE PREFIX) (MKATOM (PROMPTFORWORD ">" (FCACHE.GETPROP (QUOTE PREFIX)) NIL pwindow] then (INSPECTW.REDISPLAY inspectw) else (printout pwindow T "Bad cache prefix"] ((MAXSIZE MAXFILEPAGES DUMPSLEEP DUMPIDLE KEEPVERSIONS UNSAFE.TIMEOUT TIMETOVERIFY) (if (MENU set?menu) then (FCACHE.PUTPROP property (RNUMBER (CONCAT "Value for " property))) (INSPECTW.REDISPLAY inspectw))) (FASTDIR (if (MENU set?menu) then (FCACHE.PUTPROP property (SELECTQ (MENU (CONSTANT (create MENU ITEMS ←[QUOTE (T (NIL (QUOTE OFF] TITLE ← "Value for FASTDIR"))) (T T) (OFF NIL) (NIL (FCACHE.GETPROP property)) NIL)) (INSPECTW.REDISPLAY inspectw))) (UNSAFE.DEFAULT (if (MENU set?menu) then (FCACHE.PUTPROP property (SELECTQ (MENU (CONSTANT (create MENU ITEMS ←(QUOTE ((T T "Go ahead and trust the cache") (NIL (QUOTE OFF) "Don't trust the cache"))) TITLE ← "Value for UNSAFE.DEFAULT") )) (T T) (OFF NIL) (NIL (FCACHE.GETPROP property)) NIL)) (INSPECTW.REDISPLAY inspectw))) (SILENT (if (MENU set?menu) then (FCACHE.PUTPROP property (SELECTQ (MENU (CONSTANT (create MENU ITEMS ←[QUOTE (T (NIL (QUOTE OFF] TITLE ← "Value for SILENT"))) (T T) (OFF NIL) (NIL (FCACHE.GETPROP property)) NIL)) (INSPECTW.REDISPLAY inspectw))) (UNSAFE (if (MENU set?menu) then (FCACHE.PUTPROP property (SELECTQ (MENU (CONSTANT (create MENU ITEMS ←(QUOTE ((T T "Silently use the cache if a server is down") (NOTIFY (QUOTE NOTIFY) "Tell the user when using the cache while a server is down") (ASK (QUOTE ASK) "Ask the user whether to use the cache if a server is down") (NIL (QUOTE OFF) "Don't use the cache if a server is down"))) TITLE ← "Value for UNSAFE"))) (T T) (ASK (QUOTE ASK)) (NOTIFY (QUOTE NOTIFY)) (OFF NIL) (NIL (FCACHE.GETPROP (QUOTE UNSAFE))) NIL)) (INSPECTW.REDISPLAY inspectw))) (NIL NIL) (if (MENU set?menu) then [FCACHE.PUTPROP property (MKATOM (PROMPTFORWORD ">" NIL NIL (\FCACHE.PRINT.PROMPT inspectw (LIST (CONCAT "Enter the new " property " cache property") "The expression read will be EVALuated. "] (INSPECTW.REDISPLAY inspectw]) (\FCACHE.INSPECT.TITLEFN [LAMBDA (inspectw object) (* smL " 3-Feb-86 19:10") (* * The title was bugged in the inspectw) (SELECTQ [MENU (CONSTANT (create MENU ITEMS ←(QUOTE ((ReFetch (QUOTE REFETCH) "Recompute the inspect window"] (REFETCH (INSPECTW.REDISPLAY inspectw)) (NIL NIL) (SHOULDNT]) (\FCACHE.INSPECT.VALUES [LAMBDA (cachePropList property) (* smL " 2-May-85 10:07") (* * What is the property value) (FCACHE.GETPROP property]) (\FCACHE.PROPERTY.NAMES [LAMBDA NIL (* smL "15-Jul-85 09:41") (* * Return a list of all current cache properties) (CONS (QUOTE ENTRIES) (for p on \FCACHE.PROPERTIES by (CDDR p) collect (CAR p]) ) (* * Data access functions) (DECLARE: DONTCOPY (DECLARE: EVAL@COMPILE (PUTPROPS \FCACHE.PROPERTY MACRO (OPENLAMBDA (X) (LISTGET \FCACHE.PROPERTIES X))) (PUTPROPS \FCACHE.PROPERTY.PUT MACRO (OPENLAMBDA (NAME VALUE) (LISTPUT \FCACHE.PROPERTIES NAME VALUE))) [PUTPROPS \FCACHE.LOCALDEVICE MACRO (OPENLAMBDA NIL (OR \FCACHE.LOCALDEVICE (SETQ \FCACHE.LOCALDEVICE (\GETDEVICEFROMNAME (\FCACHE.PROPERTY (QUOTE PREFIX)) T] ) ) [DECLARE: EVAL@COMPILE (RECORD CACHEDEVINFO (REALDEVICENAME (* The name of the real device) CACHEDEV (* The cache device for this remote device) ) [ACCESSFNS ((REALDEVICE (\GETREALDEVICEFROMHOSTNAME (fetch REALDEVICENAME of DATUM) NIL (fetch CACHEDEV of DATUM] (SYSTEM)) (DATATYPE CACHENTRY (REMOTEFILENAME LOCALFILENAME MATCHFILENAME (CACHEISDIRTY FLAG) (* True if OPENFILE specified version) (FILEXISTED FLAG) (* Did the file exist when we started to write it out?) (CACHEFILELENGTH INTEGER) (* in bytes. Not valid while open for write) CACHEFILEPROPS (* prop list of real file from opening) (CACHEFILEDATE INTEGER) (* ICREATIONDATE of remote file) (CACHEBEINGWRITTEN FLAG) (* True while writeout in progress) CACHETIMECLOSED (* The time the cache file was last closed) CACHELOCK (* A monitor lock for access to the cache) (TIMELASTVERIFIED INTEGER) (* When was this entry last verified?) ) CACHELOCK ←(CREATE.MONITORLOCK (QUOTE CACHELOCK)) TIMELASTVERIFIED ← 0 (SYSTEM)) (ACCESSFNS CACHEDEVICE ((CACHEDEVINFO (\FCACHE.DEVINFO DATUM) (\FCACHE.PUT.DEVINFO DATUM NEWVALUE))) (SUBRECORD CACHEDEVINFO) (SYSTEM)) ] (/DECLAREDATATYPE (QUOTE CACHENTRY) (QUOTE (POINTER POINTER POINTER FLAG FLAG FIXP POINTER FIXP FLAG POINTER POINTER FIXP)) (QUOTE ((CACHENTRY 0 POINTER) (CACHENTRY 2 POINTER) (CACHENTRY 4 POINTER) (CACHENTRY 4 (FLAGBITS . 0)) (CACHENTRY 4 (FLAGBITS . 16)) (CACHENTRY 6 FIXP) (CACHENTRY 8 POINTER) (CACHENTRY 10 FIXP) (CACHENTRY 8 (FLAGBITS . 0)) (CACHENTRY 12 POINTER) (CACHENTRY 14 POINTER) (CACHENTRY 16 FIXP))) (QUOTE 18)) (DEFINEQ (\FCACHE.DEVINFO [LAMBDA (dev) (* smL " 9-Apr-85 12:56") (* * Get the cache dev info for this cache device) (for devinfo in (\FCACHE.PROPERTY (QUOTE DEVICES)) thereis (EQ dev (fetch CACHEDEV of devinfo]) (\FCACHE.PUT.DEVINFO [LAMBDA (dev info) (* smL " 9-Apr-85 13:14") (* * Replace the device info record for this cache device) (\FCACHE.PROPERTY.PUT (QUOTE DEVICES) (CONS info (DREMOVE (\FCACHE.DEVINFO dev) (\FCACHE.PROPERTY (QUOTE DEVICES]) ) (ADDTOVAR \SYSTEMCACHEVARS \FCACHE.LOCALDEVICE) (RPAQ? \FCACHE.LOCALDEVICE NIL) (RPAQ? \FCACHE.PROPERTIES (QUOTE (USECACHE T DEVICES NIL PREFIX NIL SIZE 0 MAXSIZE 10000 MAXFILEPAGES 600 UNSAFE ASK UNSAFE.TIMEOUT 30 UNSAFE.DEFAULT NIL SILENT NIL DUMPSLEEP 10000 DUMPIDLE 20 FASTDIR NIL KEEPVERSIONS 2 TIMETOVERIFY 5 BADDEVICES NIL))) (RPAQ? \FCACHE.PROMPT.WINDOW (CREATEW (CREATEREGION 200 200 500 100) "File cache prompt window" 15 T)) (RPAQ? \FCACHE.GENERIC.DEVICES NIL) (DECLARE: DOEVAL@COMPILE DONTCOPY (GLOBALVARS \FCACHE.LOCALDEVICE \FCACHE.PROMPT.WINDOW \FCACHE.PROMPT.WINDOW.MONITORLOCK \FCACHE.PROPERTIES \FCACHE.GENERIC.DEVICES) ) (* * Initialize things) (DEFINEQ (\FCACHE.INITIALIZE [LAMBDA NIL (* smL "12-Mar-86 19:01") (* * Initialize the FileCache stuff, UNDOably) (DECLARE (GLOBALVARS BackgroundMenu BackgroundMenuCommands ERRORTYPELST)) (if (NOT (\GETDEVICEFROMHOSTNAME (QUOTE FCACHE) T)) then (* * Change the user level IO functions so that they go thru the cache) (* The lists of functions below is the result of (FINDCALLERS (QUOTE (\GETDEVICEFROMNAME)) (QUOTE ({Eris}<Lisp>Intermezzo>Sources>Fileio))) and (FINDCALLERS (QUOTE (\GETDEVICEFROMHOSTNAME)) (QUOTE ({Eris}<Lisp>Intermezzo>Sources>Fileio)))) (for fn in (QUOTE (\DELETEFILE \GENERATEFILES \GETFILENAME \GETFILENAME.OR.STREAM \OPENFILE \RENAMEFILE DIRECTORYNAMEP GETFILEINFO SETFILEINFO)) do (CHANGENAME fn (QUOTE \GETDEVICEFROMNAME) (QUOTE \GETUSERDEVICEFROMNAME))) (for fn in (QUOTE (DIRECTORYNAME)) do (CHANGENAME fn (QUOTE \GETDEVICEFROMHOSTNAME) (QUOTE \GETUSERDEVICEFROMNAME))) (* * The following device is used to catch events...) (SETQ \FCACHE.DEVICE (create FDEV EVENTFN ←(FUNCTION \FCACHE.DEVICE.EVENTFN) DEVICENAME ←(QUOTE FCACHE) NODIRECTORIES ← T HOSTNAMEP ←(FUNCTION NILL))) (\DEFINEDEVICE (QUOTE FCACHE) \FCACHE.DEVICE) (* * Catch changes in the user password) (MOVD? (QUOTE \INTERNAL/SETPASSWORD) (QUOTE \OLD\INTERNAL/SETPASSWORD)) [UNDOSAVE (QUOTE (MOVD (QUOTE \OLD\INTERNAL/SETPASSWORD) (QUOTE \INTERNAL/SETPASSWORD] (MOVD (QUOTE \FCACHE.\INTERNAL/SETPASSWORD) (QUOTE \INTERNAL/SETPASSWORD)) (* * Set up to catch "FILE SYSTEM RESOURCES EXCEEDED" erorrs) (PUTASSOC 22 [QUOTE ((\FCACHE.RESOURCES.ERROR (CADR ERRORMESS] ERRORTYPELST) (* * Put a flush-cache entry on the background menu) (if (NOT (ASSOC (QUOTE DumpCache) BackgroundMenuCommands)) then [push BackgroundMenuCommands (QUOTE (DumpCache (QUOTE (FCACHE.DUMP.ALL)) "Writes out all dirty files and updates the cache listing" (SUBITEMS (DumpCache (QUOTE (FCACHE.DUMP.ALL)) "Writes out all dirty files and updates the cache listing") (BrowseCache (QUOTE ( \FCACHE.FLUSH.INFOHOOK)) "Inspect the cache properties"] (SETQ BackgroundMenu NIL)) (* * Make it all undoable) (UNDOSAVE (QUOTE (FCACHE.VANQUISH))) (* * Now start it all up) (\FCACHE.INITIALIZE.PROPS) (for devName in FCACHE.GENERIC.DEVICE.TYPES do (FCACHE.GENERIC.START devName]) (FCACHE.VANQUISH [LAMBDA NIL (* smL "12-Mar-86 18:49") (* * Unload the cacher from the system, removing any and all traces that it ever existed) (DECLARE (GLOBALVARS BackgroundMenu BackgroundMenuCommands ERRORTYPELST)) (if (\GETDEVICEFROMNAME (QUOTE FCACHE) T) then [for entry in \FCACHE.LIST do (if (AND (fetch CACHEISDIRTY of entry) (\FCACHE.ENTRYOPEN? entry)) then (ERROR "Can't vanquish the file cacher -- a (cached) file is open and needs to be flushed!" (fetch REMOTEFILENAME of entry] (for dev in \FCACHE.GENERIC.DEVICES do (FCACHE.GENERIC.STOP dev)) (\FCACHE.DEVICE.EVENTFN \FCACHE.DEVICE (QUOTE BEFORELOGOUT)) (for dev in (\FCACHE.PROPERTY (QUOTE DEVICES)) do (FCACHE.STOP (CAR dev))) (if (GETD (QUOTE \OLD\INTERNAL/SETPASSWORD)) then (MOVD (QUOTE \OLD\INTERNAL/SETPASSWORD) (QUOTE \INTERNAL/SETPASSWORD))) (\REMOVEDEVICE (\GETDEVICEFROMNAME (QUOTE FCACHE) T]) ) (DECLARE: DONTEVAL@LOAD DOCOPY (\FCACHE.INITIALIZE) ) (RPAQ FCACHE.VERSION.DATE "13-Mar-86 15:28:16") (RPAQQ FCACHE.VERSION.NUMBER 5.1) (DECLARE: DOEVAL@COMPILE DONTCOPY (GLOBALVARS FCACHE.VERSION.DATE FCACHE.VERSION.NUMBER) ) (* * Compile time magic) (DECLARE: EVAL@COMPILE DONTCOPY (DECLARE: EVAL@COMPILE [PUTPROPS REALDEVOP MACRO (X (LET [(realDevice (GENSYM (QUOTE realDevice] (BQUOTE (LET [(, realDevice (fetch (CACHEDEVICE REALDEVICE) of , (CADR X] (if , realDevice then (FDEVOP ,@ (SUBST realDevice (CADR X) X)) else (ERROR "Host not up" (fetch (CACHEDEVICE REALDEVICENAME) of , (CADR X] [PUTPROPS VersionlessFileName MACRO (OPENLAMBDA (fileName) (SUBATOM fileName 1 (SUB1 (OR (STRPOS ";" fileName) (ADD1 (NCHARS fileName] (DEFMACRO KLUDGE (&REST FORMS) (* * Just like PROGN, but lets us use MASTERSCOPE to find this kludge) (BQUOTE (PROGN ., FORMS))) ) (DECLARE: EVAL@COMPILE (I.S.OPR (QUOTE INUNSORTEDFILES) NIL [QUOTE (SUBST (GENSYM) (QUOTE GENVAR) (QUOTE (BIND GENVAR ← (\GENERATEFILES BODY) EACHTIME (PROGN (OR (SETQ I.V. (\GENERATENEXTFILE GENVAR)) (GO $$OUT)) (IF (LISTP I.V.) THEN (SETQ I.V. (CONCATCODES I.V.] T) ) DONTEVAL@LOAD (FILESLOAD NSFILING LLNS) ) (PUTPROPS FILECACHE COPYRIGHT ("Xerox Corporation" 1983 1985 1986)) (DECLARE: DONTCOPY (FILEMAP (NIL (10472 23835 (ADD.FILE.TO.CACHE? 10482 . 10848) (CACHE.FILE 10850 . 11213) ( FCACHE.DELETE.CACHE.ENTRY 11215 . 11716) (FCACHE.DUMP.ALL 11718 . 12021) (FCACHE.GENERIC.START 12023 . 12945) (FCACHE.GENERIC.STOP 12947 . 13471) (FCACHE.GETPROP 13473 . 13958) (FCACHE.PRIVATE.FILE? 13960 . 14265) (FCACHE.PUTPROP 14267 . 16011) (FCACHE.START 16013 . 18180) (FCACHE.STOP 18182 . 19834) (FCACHE.CACHELIST 19836 . 20101) (FCACHE.DIRTY? 20103 . 20542) (FCACHE.DUMP.FILE 20544 . 21085) ( FCACHE.DUMP 21087 . 23833)) (24734 25977 (\FCACHE.DONE.OR.ABORTED.MSG 24744 . 25421) ( \FCACHE.PRINT.MESSAGE? 25423 . 25975)) (26185 27290 (\FCACHE.PRINT.PROMPT 26195 . 26999) ( \FCACHE.CREATE.MSG.WINDOW 27001 . 27288)) (29048 35522 (\GETUSERDEVICEFROMNAME 29058 . 29804) ( \GETCACHEDEVICEFROMHOSTNAME 29806 . 32687) (\GETREALDEVICEFROMHOSTNAME 32689 . 33854) ( \FCACHE.CANONICAL.HOSTNAME 33856 . 35046) (\FCACHE.GENERIC.DEVICE.TYPE 35048 . 35520)) (35591 46462 ( \FCACHE.DELETE.ENTRY 35601 . 37025) (\FCACHE.INVENTNAME 37027 . 37538) (\FCACHE.KEEPVERSIONS 37540 . 38783) (\FCACHE.LOAD 38785 . 43227) (\FCACHE.MAKE.LEGAL.FILENAME 43229 . 43737) (\FCACHE.MAKEROOM 43739 . 46233) (\FCACHE.MAKEROOM.DELETEABLE? 46235 . 46460)) (46969 52744 (FCACHE.SCAVENGE 46979 . 52742)) (52745 59128 (\FCACHE.REPAIR 52755 . 57184) (\FCACHE.REPAIR.FINDFILE 57186 . 58630) ( \FCACHE.REPAIR.VERIFY 58632 . 59126)) (59636 61738 (\FCACHE.BUILD.DEVICE 59646 . 61332) (\FCACHE.OFF 61334 . 61736)) (61805 65901 (\FCACHE.DEVICE.EVENTFN 61815 . 64416) (\FCACHE.INITIALIZE.PROPS 64418 . 65899)) (66112 66974 (\FCACHE.GLOBAL.EVENT 66122 . 66972)) (67124 69339 (\FCACHE.AROUNDEXIT 67134 . 69337)) (69424 71461 (\FCACHE.BEFORELOGIN 69434 . 70965) (\FCACHE.\INTERNAL/SETPASSWORD 70967 . 71459) ) (71809 97868 (\FCACHE.CLOSEFILE 71819 . 73659) (\FCACHE.DELETEFILE 73661 . 74593) ( \FCACHE.DIRECTORYNAMEP 74595 . 77590) (\FCACHE.EVENTFN 77592 . 79640) (\FCACHE.GENERATEFILES 79642 . 80447) (\FCACHE.GETFILEINFO 80449 . 81124) (\FCACHE.GETFILENAME 81126 . 86433) (\FCACHE.HOSTNAMEP 86435 . 86621) (\FCACHE.OPENFILE 86623 . 90977) (\FCACHE.RENAMEFILE 90979 . 93515) (\FCACHE.REOPENFILE 93517 . 95233) (\FCACHE.SETFILEINFO 95235 . 97866)) (97892 99777 (\FCACHE.ENTRYINFO 97902 . 99775)) ( 99822 103739 (\FCACHE.GENERATE.FILEINFO 99832 . 100278) (\FCACHE.GENERATE.FILES.DEPTH 100280 . 100704) (\FCACHE.GENERATE.LOCAL.FILES 100706 . 102727) (\FCACHE.NEXT.LOCAL.FILE 102729 . 103737)) (103789 110068 (MERGE.FILEGENERATORS 103799 . 104216) (MERGED.FILEINFOFN 104218 . 104573) (MERGED.NEXTFILEFN 104575 . 105449) (\MERGED.NEXTFILEFN1 105451 . 108415) (FILES.IN.ORDER? 108417 . 110066)) (110416 118229 (\FCACHE.LOOKUP 110426 . 112432) (\FCACHE.PROMOTE 112434 . 113293) (\FCACHE.USECACHE? 113295 . 116317) (\FCACHE.VERIFY 116319 . 118227)) (118435 130189 (\FCACHE.HOSTUP? 118445 . 123435) ( \NSFILING.ADDRESS 123437 . 123661) (\FCACHE.IGNOREDATECHECK? 123663 . 126868) ( \FCACHE.USELOCALDIRECTORY? 126870 . 129622) (\FCACHE.HOSTDEAD.WHENSELECTEDFN 129624 . 130187)) (130354 132010 (\FCACHE.RESOURCES.ERROR 130364 . 132008)) (132076 152022 (\FCACHE.ENTRYOPEN? 132086 . 132419) (\FCACHE.FLUSH 132421 . 133134) (\FCACHE.WRITEOUT 133136 . 149967) (\FCACHE.WRITEOUT.NEWFILENAME 149969 . 150973) (\FCACHE.WRITEOUT.READNEWFILENAME 150975 . 151638) (\FCACHE.WRITEOUT.WHENSELECTEDFN 151640 . 152020)) (152253 163249 (\FCACHE.ADDENTRY 152263 . 153198) (\FCACHE.DUMP.ENTRY 153200 . 153664) (\FCACHE.FILEMATCH? 153666 . 154199) (\FCACHE.LOGENTRY 154201 . 155190) (\FCACHE.RESTORE 155192 . 161804) (\FCACHE.RESTORE.ENTRY 161806 . 163247)) (163426 163933 (\FCACHE.FLUSH.INFOHOOK 163436 . 163931)) (163970 172614 (\FCACHE.BROWSE.CACHE 163980 . 167576) (\FCACHE.BROWSE.COPYFN 167578 . 167840) (\FCACHE.BROWSE.PRINTFN 167842 . 168463) (\FCACHE.BROWSE.RECOMPUTE 168465 . 169308) ( \FCACHE.BROWSE.WHENSELECTEDFN 169310 . 172612)) (175285 180991 (\FCACHE.INSPECT.PROPCOMMANDFN 175295 . 180038) (\FCACHE.INSPECT.TITLEFN 180040 . 180476) (\FCACHE.INSPECT.VALUES 180478 . 180681) ( \FCACHE.PROPERTY.NAMES 180683 . 180989)) (183804 184479 (\FCACHE.DEVINFO 183814 . 184121) ( \FCACHE.PUT.DEVINFO 184123 . 184477)) (185231 189556 (\FCACHE.INITIALIZE 185241 . 188319) ( FCACHE.VANQUISH 188321 . 189554))))) STOP