(FILECREATED "11-Mar-85 21:19:46" {ERIS}<LISP>INTERMEZZO>SOURCES>LOCALFILE.;5 42568 changes to: (FNS \LFEventFn) (VARS LOCALFILECOMS) previous date: " 6-Mar-85 22:42:00" {ERIS}<LISP>INTERMEZZO>SOURCES>LOCALFILE.;3) (* Copyright (c) 1985 by Xerox Corporation. All rights reserved.) (PRETTYCOMPRINT LOCALFILECOMS) (RPAQQ LOCALFILECOMS ((DECLARE: EVAL@COMPILE DONTCOPY (FILES (LOADCOMP) LFPILOTFILE) (FILES DECL) (* * File system datatypes) (CONSTANTS (lispFileVersion 2) (leaderPageSeal 54321)) (RECORDS LFDEV DLIONSTREAM LeaderPage) (* * Error mechanism) (MACROS DiskError)) (DECLARE: (LOCALVARS . T) (IGNOREDECL . T)) (* * Public entry) (FNS CREATEDSKDIRECTORY PURGEDSKDIRECTORY LISPDIRECTORYP VOLUMES VOLUMESIZE) (FNS \DFSCurrentVolume \DFSFreeDiskPages) (FNS \LFEntryPoint \LFNormalizeVolumeName) (* * Device management) (FNS \LFCreateDevice \LFOpenDevice \LFCloseDevice) (GLOBALVARS \LFdevice \LFtopMonitor \LFrunSize) (P (\LFCreateDevice)) (INITVARS (\LFtopMonitor (CREATE.MONITORLOCK (QUOTE topMonitor))) (\LFrunSize 20)) (* * Device methods) (FNS \LFOpenFile \LFGetStreamForFile \LFOpenOldFile \LFGenFileID \LFCreateFile \LFMakeLeaderPage \LFUpdateLeaderPage \LFWriteLeaderPage) (FNS \LFCloseFile) (FNS \LFDeleteFile) (FNS \LFReadPages \LFReadOnePage) (FNS \LFWritePages \LFWriteOnePage \LFExtendFile) (FNS \LFGetFileInfo) (FNS \LFGetFileName) (FNS \LFEventFn) (FNS \LFDirectoryNameP) (FNS \LFTruncateFile) (* * Load other file system modules) (FILES LFDIRECTORY LFPILOTFILE))) (DECLARE: EVAL@COMPILE DONTCOPY (FILESLOAD (LOADCOMP) LFPILOTFILE) (FILESLOAD DECL) (DECLARE: EVAL@COMPILE (RPAQQ lispFileVersion 2) (RPAQQ leaderPageSeal 54321) (CONSTANTS (lispFileVersion 2) (leaderPageSeal 54321)) ) [DECLARE: EVAL@COMPILE (RECORD LFDEV FDEV (SUBRECORD FDEV) [TYPE? (AND (type? FDEV DATUM) (EQ (fetch (FDEV CLOSEFILE) of DATUM) (FUNCTION \LFCloseFile)) (EQ (fetch (FDEV HOSTNAMEP) of DATUM) (FUNCTION NILL]) (RECORD DLIONSTREAM STREAM (SUBRECORD STREAM) [ACCESSFNS ((FILEDESC (fetch F1 of DATUM) (replace F1 of DATUM with NEWVALUE)) (LEADERPAGE (fetch F2 of DATUM) (replace F2 of DATUM with NEWVALUE)) (DIRINFO (fetch F4 of DATUM) (replace F4 of DATUM with NEWVALUE)) (DIRHOLEPTR (fetch F5 of DATUM) (replace F5 of DATUM with NEWVALUE)) (VOLUME (\PFGetVol (fetch (FileDescriptor volNum) of (fetch (DLIONSTREAM FILEDESC) of DATUM] [TYPE? (AND (type? STREAM DATUM) (type? FileDescriptor (fetch (DLIONSTREAM FILEDESC) of DATUM]) (MESARECORD LeaderPage ((seal WORD) (version WORD) (TimeCreate FIXP) (TimeWrite FIXP) (TimeRead FIXP) (FileID FIXP) (AllocatedPages FIXP) (EofPage FIXP) (EOffSet WORD) (NameLength WORD) (FileName 256 BYTE) (AuthorLength WORD) (AuthorName 64 BYTE) (typeHolder WORD)) (ACCESSFNS (TYPE (SELECTQ (fetch (LeaderPage typeHolder) of DATUM) (0 (QUOTE TEXT)) (QUOTE BINARY)) (PROGN (replace (LeaderPage typeHolder) of DATUM with (SELECTQ NEWVALUE (TEXT 0) 1)) NEWVALUE))) (ACCESSFNS (fileName (\PFFetchString (LOCF (fetch (LeaderPage FileName) of DATUM)) (LOCF (fetch (LeaderPage NameLength) of DATUM)) 256) (\PFReplaceString (LOCF (fetch (LeaderPage FileName) of DATUM)) (LOCF (fetch (LeaderPage NameLength) of DATUM)) 256 NEWVALUE))) (ACCESSFNS (author (\PFFetchString (LOCF (fetch (LeaderPage AuthorName) of DATUM)) (LOCF (fetch (LeaderPage AuthorLength) of DATUM)) 64) (\PFReplaceString (LOCF (fetch (LeaderPage AuthorName) of DATUM)) (LOCF (fetch (LeaderPage AuthorLength) of DATUM)) 64 NEWVALUE))) (CREATE (PROG ((leader (create Page))) (replace (LeaderPage seal) of leader with leaderPageSeal) (RETURN leader))) (TYPE? (AND (type? Page DATUM) (EQ (fetch (LeaderPage seal) of DATUM) leaderPageSeal)))) ] (DECLARE: EVAL@COMPILE (PUTPROPS DiskError MACRO ((errorType fileName CONTINUEOKFLG) (PROG ((\INTERRUPTABLE T)) (* * Gross hack to allow the error to show up as a break rather than a 9318) (if CONTINUEOKFLG then (RELEASE.MONITORLOCK \LFtopMonitor)) (LISPERROR errorType fileName CONTINUEOKFLG)))) ) ) (DECLARE: (DECLARE: DOEVAL@COMPILE DONTCOPY (LOCALVARS . T) ) (DECLARE: DOEVAL@COMPILE DONTEVAL@LOAD DONTCOPY (RESETSAVE COMPILEIGNOREDECL (QUOTE T)) ) ) (* * Public entry) (DEFINEQ (CREATEDSKDIRECTORY [DLAMBDA ((volName (ONEOF ATOM STRINGP)) (smashDirectory BOOL) (RETURNS STRINGP)) (* hts: "13-Feb-85 22:37") (* * Creates a directory on the specified volume, if possible. If this constitutes the first Lisp directory on the disk, creates the local disk device to run this directory (and any subsequent ones). If smashDirectory, it will smash any old Lisp directory on the volume. If smashVFM, it will smash the old volume file map for the volume; otherwise (normally) it will reuse it.) (WITH.MONITOR \LFtopMonitor [PROG ((vol (\LFEntryPoint volName NIL T)) markerPage) (if (NOT (\PFPilotVolumeP vol)) then (ERROR "Non-pilot volume")) (if smashDirectory then (\LFPurgeDirectory vol)) (if (\LFDirectoryP vol) then (ERROR "Directory already created")) (UNINTERRUPTABLY (if [NOT (type? LFDEV (\GETDEVICEFROMNAME (QUOTE DSK] then (\LFCreateDevice)) (if (type? LFDEV (\GETDEVICEFROMNAME (QUOTE DSK))) then (\LFMakeVolumeDirectory vol) else (\LFMakeVolumeDirectory vol T) (\LFOpenDevice)))] (PACKFILENAME.STRING (QUOTE HOST) (QUOTE DSK) (QUOTE DIRECTORY) (U-CASE volName)))]) (PURGEDSKDIRECTORY [DLAMBDA ((volName (ONEOF ATOM STRINGP)) (dontDeleteFiles BOOL) (RETURNS NIL)) (* hts: "16-Feb-85 20:01") (* * Purges the Lisp directory on the specified volume. If this is the last valid Lisp directory on the disk, shuts down the local disk device.) [WITH.MONITOR \LFtopMonitor (PROG ((vol (\LFEntryPoint volName NIL T)) device) (if (NOT (\PFPilotVolumeP vol)) then (ERROR "Non-pilot volume")) (UNINTERRUPTABLY (* * CLose all files open on that directory) (for S in \OPENFILES when (AND (type? DLIONSTREAM S) (EQ (fetch (DLIONSTREAM VOLUME) of S) vol)) do (printout PROMPTWINDOW T "Closing " (CLOSEF S))) (* * Delete all files on that directory.) [if (NOT dontDeleteFiles) then (for F in (FILDIR (PACKFILENAME (QUOTE HOST) (QUOTE DSK) (QUOTE DIRECTORY) (fetch (LogicalVolumeDescriptor LVlabel) of vol))) do (printout PROMPTWINDOW T "Deleting " (DELFILE F] (* * Remove the directory) (\LFPurgeDirectory vol) (* * If this was the last Lisp directory, replace the dandelion disk device with a coredevice. Actually, all you need to do is kill the dlion disk device and VANILLADISK will take care of the rest) (OR (\LFFindDirectoryVol) (\LFCloseDevice)))]]) (LISPDIRECTORYP [DLAMBDA ((volumeName (ONEOF ATOM STRINGP)) (RETURNS BOOL)) (* hts: "13-Feb-85 22:43") (* * Returns T if volumeName has a valid Lisp directory on it, NIL otherwise.) (WITH.MONITOR \LFtopMonitor (SELECTQ (MACHINETYPE) [(DANDELION DOVE) (PROG ((vol (\LFEntryPoint volumeName NIL T))) (RETURN (NOT (NOT (AND vol (\LFDirectoryP vol] NIL))]) (VOLUMES [DLAMBDA ((RETURNS (LISTP OF ATOM))) (* hts: "13-Feb-85 22:44") (* * Returns a list of the names of the logical volumes on this machine.) (SELECTQ (MACHINETYPE) [(DANDELION DOVE) (\LFEntryPoint NIL T) (for vol in (\PFGetVols) collect (MKATOM (U-CASE (fetch (LogicalVolumeDescriptor LVlabel) of vol] NIL)]) (VOLUMESIZE [DLAMBDA ((volName (ONEOF NIL ATOM STRINGP)) (recompute BOOL) (RETURNS FIXP)) (* hts: "13-Feb-85 22:51") (* * Returns the size of the specified volume.) (PROG ((vol (\LFEntryPoint volName))) (RETURN (fetch (LogicalVolumeDescriptor volumeSize) of vol)))]) ) (DEFINEQ (\DFSCurrentVolume [LAMBDA NIL (* hts: "13-Feb-85 22:47") (* * Returns as an atom the name of the volume which contains the currently running virtual memory. Called by DISKPARTITION.) (\LFEntryPoint NIL T) (MKATOM (U-CASE (fetch (LogicalVolumeDescriptor LVlabel) of (\PFCurrentVol]) (\DFSFreeDiskPages [DLAMBDA ((volName (ONEOF NIL ATOM STRINGP)) (recompute BOOL) (RETURNS FIXP)) (* hts: "13-Feb-85 22:48") (* * Returns the number of free pages left on the specified volume. Called by DISKFREEPAGES.) [WITH.MONITOR \LFtopMonitor (PROG ((vol (\LFEntryPoint volName))) (RETURN (\PFFreeDiskPages vol recompute]]) ) (DEFINEQ (\LFEntryPoint [DLAMBDA ((volName (ONEOF ATOM STRINGP)) (noVolName BOOL) (dontDefault BOOL) (RETURNS (ONEOF NIL LogicalVolumeDescriptor))) (* hts: "13-Feb-85 22:36") (* * Run at every entry point to the file system. Makes sure everything is set up ok, and makes all entry points share some common code.) (SELECTQ (MACHINETYPE) ((DANDELION DOVE) NIL) (ERROR "Wrong machinetype")) (\PFEnsureInitialized) (if (NOT (\PFVersionOK)) then (ERROR "Wrong Pilot version on disk")) (if (NOT noVolName) then (PROG [(vol (OR (\PFGetLVPage (\LFNormalizeVolumeName volName)) (AND (NOT dontDefault) (\LFFindDirectoryVol NIL] (if (NULL vol) then (ERROR "Volume not on local disk")) (RETURN vol)))]) (\LFNormalizeVolumeName [DLAMBDA ((volName (ONEOF NIL ATOM STRINGP)) (RETURNS (ONEOF NIL ATOM STRINGP))) (* hts: "16-Jan-85 16:35") (* * If the volume name given is a valid one, returns that; else assumes it is a full file name of some sort, and extracts the volume name from it.) (if (STRPOS "{" volName) then (fetch (PARSEDFILENAME VOL) of (the PARSEDFILENAME (\LFParseFileName volName))) else volName)]) ) (* * Device management) (DEFINEQ (\LFCreateDevice [DLAMBDA ((RETURNS LFDEV)) (* hts: "25-Jan-85 16:33") (* * Creates and remembers the local hard disk file device, but does not open the device or any of its associated directories.) [if (AND (BOUNDP (QUOTE \LFdevice)) (type? LFDEV \LFdevice)) then \LFdevice else (SETQ \LFdevice (\MAKE.PMAP.DEVICE (create FDEV NODIRECTORIES ← T DEVICENAME ←(QUOTE DSK) CLOSEFILE ←(FUNCTION \LFCloseFile) DELETEFILE ←(FUNCTION \LFDeleteFile) TRUNCATEFILE ←(FUNCTION \LFTruncateFile) GETFILEINFO ←(FUNCTION \LFGetFileInfo) GETFILENAME ←(FUNCTION \LFGetFileName) OPENFILE ←(FUNCTION \LFOpenFile) READPAGES ←(FUNCTION \LFReadPages) SETFILEINFO ←(FUNCTION NILL) WRITEPAGES ←(FUNCTION \LFWritePages) REOPENFILE ←(FUNCTION \LFOpenFile) GENERATEFILES ←(FUNCTION \LFGenerateFiles) EVENTFN ←(FUNCTION \LFEventFn) DIRECTORYNAMEP ←(FUNCTION \LFDirectoryNameP) HOSTNAMEP ←(FUNCTION NILL]]) (\LFOpenDevice [DLAMBDA ((RETURNS (ONEOF NIL LFDEV))) (* hts: "29-Jan-85 20:42") (* * Opens the local hard disk file system device and returns it if it can be opened; otherwise returns NIL. Device can be opened iff Pilot version is OK and there is at least one valid Lisp directory of the appropriate version on the disk.) (WITH.MONITOR \LFtopMonitor (SELECTQ (MACHINETYPE) [(DANDELION DOVE) (\PFEnsureInitialized T) (AND (\PFVersionOK) (for VOL in (\PFGetVols) thereis (\LFCloseDirectory VOL) (AND (\LFDirectoryP VOL))) (\GETDEVICEFROMNAME (\DEFINEDEVICE (QUOTE DSK) (the LFDEV \LFdevice] NIL))]) (\LFCloseDevice [LAMBDA NIL (* hts: " 7-Jan-85 15:17") (* * comment) (WITH.MONITOR \LFtopMonitor (\PFEnsureInitialized T) (\REMOVEDEVICE (the LFDEV \LFdevice)) (AND (\PFVersionOK) (for VOL in (\PFGetVols) do (\LFCloseDirectory VOL))) NIL]) ) (DECLARE: DOEVAL@COMPILE DONTCOPY (GLOBALVARS \LFdevice \LFtopMonitor \LFrunSize) ) (\LFCreateDevice) (RPAQ? \LFtopMonitor (CREATE.MONITORLOCK (QUOTE topMonitor))) (RPAQ? \LFrunSize 20) (* * Device methods) (DEFINEQ (\LFOpenFile [LAMBDA (FILE ACCESS RECOG OTHERINFO FDEV OLDSTREAM) (* hts: " 8-Jan-85 14:47") (* * Open a Model44 file. Gets the physical end of file and sets up ofd) (WITH.MONITOR \LFtopMonitor (PROG ((DATE (FASSOC (QUOTE CREATIONDATE) OTHERINFO))) (* * Normalize creationdate. User can supply a bad creationdate. If normalization is done at a lower level in uninterruptable code, and if IDATE signals an error, the result will be a 9318 crash rather than an error break.) [if DATE then (RPLACA (CDR DATE) (IDATE (CADR DATE] (* * Force everything through GetStreamForFile to (even if it was already a stream) to force the file system to check the directory and rebuild the stream and all info cached in it.) (if (type? DLIONSTREAM FILE) then (SETQ FILE (fetch (DLIONSTREAM FULLFILENAME) of FILE))) (SETQ FILE (\LFGetStreamForFile FILE RECOG ACCESS (NEQ ACCESS (QUOTE INPUT)) OTHERINFO)) (* * If GetStreamForFile returned NIL, then the file didn't exist; return NIL instead of a stream.) (if (NOT FILE) then (RETURN NIL)) (* * Output stream is empty even if it is old.) (if (EQ ACCESS (QUOTE OUTPUT)) then (* File is EMPTY even if it is old) (replace EPAGE of FILE with (replace EOFFSET of FILE with 0))) (* * Update access dates. For REOPENFILE op, don't change dates) (\LFUpdateLeaderPage FILE (if (AND (NOT OLDSTREAM) (NOT (FMEMB (QUOTE DON'T.CHANGE.DATE) OTHERINFO))) then ACCESS else NIL)) (* * Return the stream you've just built.) (RETURN FILE]) (\LFGetStreamForFile [DLAMBDA ((NAME (ONEOF ATOM STRINGP)) (RECOG LITATOM) (ACCESS LITATOM) (CREATEFLG BOOL) (OTHERINFO LST) (RETURNS (ONEOF NIL DLIONSTREAM))) (* hts: "16-Feb-85 17:04") (* * Creates a STREAM for dsk file NAME, creating it if necessary when CREATEFLG is true.) (DPROG ((FILESPEC (\LFFileSpec NAME RECOG) (ONEOF NIL DFSFileSpec)) (volNum NIL (ONEOF NIL SMALLP)) (DIRPTR NIL (ONEOF NIL FIXP))) [RETURN (COND ((NULL FILESPEC) (* * If the file does not have a valid file specification, don't create a stream; just return NIL.) NIL) ((SETQ DIRPTR (fetch (DFSFileSpec FSDIRPTR) of FILESPEC)) (* * If the directory code found a pointer into the directory, then the file already exists; just open it up) (\LFOpenOldFile (create FileDescriptor fileID ←(\LFReadFileID [\LFGetDirectory (SETQ volNum (fetch (ExpandedName VOLNUM) of (fetch (DFSFileSpec EXPANDEDNAME) of FILESPEC] DIRPTR) volNum ← volNum type ← tLispFile) (\LFFullFileName (fetch (DFSFileSpec EXPANDEDNAME) of FILESPEC)) DIRPTR)) ((NULL (fetch (ExpandedName VERSION) of (fetch (DFSFileSpec EXPANDEDNAME) of FILESPEC))) NIL) ((IGREATERP (fetch (ExpandedName VERSION) of (fetch (DFSFileSpec EXPANDEDNAME) of FILESPEC)) MAX.SMALLP) (printout PROMPTWINDOW T "Version number too high") (DiskError "FILE SYSTEM RESOURCES EXCEEDED" NAME)) (CREATEFLG (\LFCreateFile (fetch (DFSFileSpec EXPANDEDNAME) of FILESPEC) OTHERINFO])]) (\LFOpenOldFile [DLAMBDA ((fileDesc FileDescriptor) (fullFileName LITATOM) (directoryPointer (ONEOF NIL FIXP)) (RETURNS DLIONSTREAM)) (* hts: "25-Jan-85 17:16") (* * Open an old (existing) file and return the resultant stream) (DPROG ((leaderPage (create LeaderPage) LeaderPage) THEN (STREAM (create DLIONSTREAM FULLFILENAME ← fullFileName FILEDESC ← fileDesc DIRINFO ← directoryPointer DEVICE ← \LFdevice LEADERPAGE ← leaderPage) DLIONSTREAM) (SIZE NIL (ONEOF NIL FIXP)) (LASTPAGE NIL (ONEOF NIL FIXP)) (OFFSET NIL (ONEOF NIL SMALLP))) (* * Use the volume file map to find out what size the file is; record this in the stream you are building.) (SETQ SIZE (\PFFindFileSize fileDesc)) (replace (FileDescriptor size) of fileDesc with SIZE) (* * Read in the leader page for the file. The leader page has stream-level eof information on it. It also has backing file length info on it. If this latter matches the length found from the vfm, then believe the leader page and use its eof info for the stream; else, the leader page is probably screwed up, so just make the stream's eof be the entire backing file. (This means you won't lose any info, but might gain about half a page of nulls.)) (\PFGetPage fileDesc 0 (\PFFindPageAddr fileDesc 0) leaderPage) (if (EQP (fetch (LeaderPage AllocatedPages) of leaderPage) SIZE) then (SETQ LASTPAGE (fetch EofPage of leaderPage)) (SETQ OFFSET (fetch EOffSet of leaderPage)) else (SETQ LASTPAGE (SUB1 SIZE)) (SETQ OFFSET BYTESPERPAGE)) (replace (DLIONSTREAM EPAGE) of STREAM with LASTPAGE) (replace (DLIONSTREAM EOFFSET) of STREAM with OFFSET) (* * Finally return the stream you've just built) (RETURN STREAM))]) (\LFGenFileID [DLAMBDA ((vol LogicalVolumeDescriptor) (RETURNS FIXP)) (* hts: " 8-Jan-85 14:50") (* * Generates and returns a new file ID and updates the ID count for the logical volume) (add (fetch (LogicalVolumeDescriptor lastIDAllocated) of vol) 1)]) (\LFCreateFile [LAMBDA (fileName info) (* hts: "13-Feb-85 16:30") (* * fileName: UNAME, pages: FIXP (estimated length of file; currently not taken advantage of), info: PLIST) (* * Creates a file by allocating the pages for it and returning a stream to it.) (UNINTERRUPTABLY (PROG ((vol (\PFGetVol (fetch (ExpandedName VOLNUM) of fileName))) stream) (SETQ stream (create DLIONSTREAM FULLFILENAME ←(\LFFullFileName fileName) FILEDESC ←(create FileDescriptor fileID ←(\LFGenFileID vol) volNum ←(\PFVolumeNumber vol) type ← tLispFile) DEVICE ← \LFdevice)) (* * Allocate pages for file; this will update size field of FileDescriptor) (\PFNewPages vol (fetch (DLIONSTREAM FILEDESC) of stream) (create PageGroup filePage ← 0 volumePage ← 0 nextFilePage ← \LFrunSize)) (* * Create leader page for the new file and put it and cache it) (replace (DLIONSTREAM LEADERPAGE) of stream with (\LFMakeLeaderPage (fetch (DLIONSTREAM FILEDESC) of stream) (\LFFileName fileName) info)) (* * Enter the new file in the directory) (\LFMakeDirEntry stream fileName (\LFGetDirectory vol)) (RETURN stream)))]) (\LFMakeLeaderPage [DLAMBDA ((file FileDescriptor) (fileName (ONEOF ATOM STRINGP)) (Info LST) (RETURNS LeaderPage)) (* hts: " 8-Jan-85 16:12") (* * Make, put, and return leader page for file) (DECLARE (GLOBALVARS DEFAULTFILETYPE)) (PROG ((TYPE (OR (CADR (FASSOC (QUOTE TYPE) Info)) DEFAULTFILETYPE)) (CurrentTime (OR (FIXP (CADR (FASSOC (QUOTE CREATIONDATE) Info))) (IDATE))) (Author (OR (CADR (FASSOC (QUOTE AUTHOR) Info)) (USERNAME))) (LeaderPage (create LeaderPage))) (replace (LeaderPage TYPE) of LeaderPage with TYPE) (replace (LeaderPage TimeCreate) of LeaderPage with CurrentTime) (replace (LeaderPage TimeWrite) of LeaderPage with CurrentTime) (replace (LeaderPage FileID) of LeaderPage with (fetch (FileDescriptor fileID) of file)) (replace (LeaderPage AllocatedPages) of LeaderPage with (fetch (FileDescriptor size) of file)) (replace (LeaderPage EofPage) of LeaderPage with 0) (replace (LeaderPage EOffSet) of LeaderPage with 0) (replace (LeaderPage fileName) of LeaderPage with fileName) (replace (LeaderPage author) of LeaderPage with Author) (replace (LeaderPage version) of LeaderPage with lispFileVersion) (\PFPutPage file 0 (\PFFindPageAddr file 0) LeaderPage) (RETURN LeaderPage))]) (\LFUpdateLeaderPage [LAMBDA (stream access) (* hts: " 9-Jan-85 16:52") (UNINTERRUPTABLY (PROG ((leaderPage (fetch (DLIONSTREAM LEADERPAGE) of stream)) (time (DAYTIME))) (* * Update end of file info) (replace (LeaderPage EofPage) of leaderPage with (fetch (STREAM EPAGE) of stream)) (replace (LeaderPage EOffSet) of leaderPage with (fetch (STREAM EOFFSET) of stream)) (replace (LeaderPage AllocatedPages) of leaderPage with (fetch (FileDescriptor size) of (fetch (DLIONSTREAM FILEDESC) of stream))) (* * Update info saying how many pages have been allocated to the file) (replace (LeaderPage AllocatedPages) of leaderPage with (fetch (FileDescriptor size) of (fetch (DLIONSTREAM FILEDESC) of stream))) (* * Update access times) (SELECTQ access ((OUTPUT BOTH APPEND) (replace (LeaderPage TimeWrite) of leaderPage with time)) NIL) (SELECTQ access ((INPUT BOTH) (replace (LeaderPage TimeRead) of leaderPage with time)) NIL) (* * and write out the refreshed leader page) (\LFWriteLeaderPage stream)))]) (\LFWriteLeaderPage [LAMBDA (stream) (* hts: " 5-Jan-85 16:15") (PROG ((vol (fetch (DLIONSTREAM VOLUME) of stream)) (fileDesc (fetch (DLIONSTREAM FILEDESC) of stream))) (\PFPutPage fileDesc 0 (\PFFindPageAddr fileDesc 0) (fetch (DLIONSTREAM LEADERPAGE) of stream]) ) (DEFINEQ (\LFCloseFile [LAMBDA (STREAM) (* mjs " 6-Mar-85 22:41") (* * Closes the specified stream.) (WITH.MONITOR \LFtopMonitor (* * Write out and dispense with buffers for this stream.) (\CLEARMAP STREAM) (if (NEQ (fetch ACCESS of STREAM) (QUOTE INPUT)) then (* * Update the stream eof info, trim the backing file so that it is just big enough to hold the stream, and record all the eof info on the stream's leader page. Minimum backing file length for the stream is computed as follows: 1 page for leader page; 1 page because stream pages (in particular EPAGE) are numbered from 0, not 1; EPAGE of stream pages; less 1 page if the EOFFSET is 0) (UNINTERRUPTABLY (\LFTruncateFile STREAM) (\PFTrimHelper (fetch (DLIONSTREAM VOLUME) of STREAM) (fetch (DLIONSTREAM FILEDESC) of STREAM) (PLUS 1 1 (fetch EPAGE of STREAM) (if (EQ (fetch EOFFSET of STREAM) 0) then -1 else 0))) (\LFUpdateLeaderPage STREAM))) (\PFSaveBuffers (fetch (DLIONSTREAM VOLUME) of STREAM)) STREAM]) ) (DEFINEQ (\LFDeleteFile [LAMBDA (fileName dev) (* mjs "20-Feb-85 21:03") (WITH.MONITOR \LFtopMonitor (PROG ((stream (\LFGetStreamForFile fileName (QUOTE OLDEST) (QUOTE BOTH) NIL NIL))) (DECLARE (GLOBALVARS \OPENFILES)) (if (OR (NOT stream) (bind (NAME ←(fetch FULLFILENAME of stream)) thereis stream in \OPENFILES suchthat (EQ (fetch FULLFILENAME of stream) NAME))) then (RETURN)) (UNINTERRUPTABLY (\LFRemoveDirEntry stream (\LFGetDirectory (fetch (DLIONSTREAM VOLUME) of stream))) (* * Take the entire file out of the BTree and out of the allocation map) (\PFTrimHelper (fetch (DLIONSTREAM VOLUME) of stream) (fetch (DLIONSTREAM FILEDESC) of stream) 0) (* * save buffers) (\PFSaveBuffers (fetch (DLIONSTREAM VOLUME) of stream))) (RETURN (fetch (DLIONSTREAM FULLFILENAME) of stream]) ) (DEFINEQ (\LFReadPages [DLAMBDA ((stream DLIONSTREAM) (firstPage FIXP) (buffers (ONEOF Page RandomPage (LISTP OF (ONEOF Page RandomPage)))) (RETURNS FIXP)) (* hts: "26-Jan-85 16:19") (* * Reads a bunch of pages from stream, starting at firstPage. Returns number of bytes read.) (\UPDATEOF stream) [PROG [(lastStreamPage (PLUS (fetch (DLIONSTREAM EPAGE) of stream) (if (EQ (fetch (DLIONSTREAM EOFFSET) of stream) 0) then -1 else 0] (RETURN (for buffer inside buffers as streamPageNumber from firstPage sum (\LFReadOnePage stream streamPageNumber buffer lastStreamPage]]) (\LFReadOnePage [LAMBDA (stream streamPageNumber buffer lastStreamPage offset) (* hts: "25-Jan-85 17:37") (* * Reads a single page from stream. Returns the number of bytes read.) (* * If asked to read a page which is off the end of the stream, it will zero the page. Odd though it may seem, reading off the end of the file is reasonable behavior for copybytes: buffer pages must come from somewhere, and copybytes may not have to write the whole page, and in general copybytes does not know whether a page is actually in a file or off the end of it. Seems inefficient, but since reading past eof does not actually require disk access, its not that bad.) (* * Pilot level numbers pages starting from 0; so does stream, but stream does not count the leader page.) (PROG ((vol (fetch (DLIONSTREAM VOLUME) of stream)) (file (fetch (DLIONSTREAM FILEDESC) of stream)) (filePageNumber (ADD1 streamPageNumber)) offset) (RETURN (if (LEQ streamPageNumber lastStreamPage) then (* * If page inside stream, then it has presumably already been written; read it in.) (\PFGetPage file filePageNumber (\PFFindPageAddr file filePageNumber) buffer) (if (EQ streamPageNumber lastStreamPage) then (* * If this was the last page in the file, then fill in the trailing bytes with nulls.) (SETQ offset (fetch (DLIONSTREAM EOFFSET) of stream)) (if (EQ offset 0) then (SETQ offset BYTESPERPAGE) else (for byte from offset to (SUB1 BYTESPERPAGE) do (\PUTBASEBYTE buffer byte 0))) offset else BYTESPERPAGE) else (* * If this was outside the stream, clear the buffer.) (\ZEROPAGE (fetch (POINTER PAGE#) of buffer)) 0]) ) (DEFINEQ (\LFWritePages [LAMBDA (stream firstPage buffers) (* hts: "25-Jan-85 17:19") (* * Writes a bunch of pages to stream, starting at firstPage) (for buffer inside buffers as streamPageNumber from firstPage do (\LFWriteOnePage stream streamPageNumber buffer]) (\LFWriteOnePage [LAMBDA (stream streamPageNumber buffer) (* hts: "25-Jan-85 17:19") (* add1 is because Pilot enumeration of file pages starts with the leader page and stream enumeration starts with the first real page of the file) (PROG ((vol (fetch (DLIONSTREAM VOLUME) of stream)) (file (fetch (DLIONSTREAM FILEDESC) of stream)) (filePageNumber (ADD1 streamPageNumber))) (* * If this page is beyond the last allocated page of the file, extend the file another chunk) (if (IGEQ filePageNumber (fetch (FileDescriptor size) of file)) then (\LFExtendFile stream (ADD1 filePageNumber))) (* * Write the page and check the label) (\PFPutPage file filePageNumber (\PFFindPageAddr file filePageNumber) buffer]) (\LFExtendFile [LAMBDA (stream page) (* hts: " 9-Jan-85 21:24") (* * Extends the backing file for stream so that its last page is at least page.) (PROG ((vol (fetch (DLIONSTREAM VOLUME) of stream)) (fileDesc (fetch (DLIONSTREAM FILEDESC) of stream))) (UNINTERRUPTABLY [\PFNewPages vol fileDesc (create PageGroup filePage ←(fetch (FileDescriptor size) of fileDesc) volumePage ← 0 nextFilePage ←(MAX page (IPLUS (fetch (FileDescriptor size) of fileDesc) \LFrunSize] (\UPDATEOF stream) (\LFUpdateLeaderPage stream))]) ) (DEFINEQ (\LFGetFileInfo [DLAMBDA ((stream (ONEOF ATOM STRINGP DLIONSTREAM)) (attribute (ONEOF ATOM STRINGP)) (device (ONEOF NIL LFDEV)) (RETURNS (ONEOF ATOM STRINGP))) (* hts: "14-Feb-85 23:17") (* * Get the value of the attribute for a file. If stream is a filename, then the file is not open. If stream is a STREAM, then it is open and has valid information in it.) [WITH.MONITOR \LFtopMonitor (AND [OR (type? DLIONSTREAM stream) (type? DLIONSTREAM (SETQ stream (\LFGetStreamForFile stream (QUOTE OLD) (QUOTE INPUT) NIL NIL] (PROG ((infoPage (fetch (DLIONSTREAM LEADERPAGE) of stream))) (RETURN (SELECTQ (MKATOM (U-CASE attribute)) (LENGTH (\UPDATEOF stream) (IPLUS (ITIMES (fetch (STREAM EPAGE) of stream) BYTESPERPAGE) (fetch (STREAM EOFFSET) of stream))) (SIZE (\UPDATEOF stream) (IPLUS (fetch (STREAM EPAGE) of stream) (FOLDHI (fetch (STREAM EOFFSET) of stream) BYTESPERPAGE))) (TYPE (fetch (LeaderPage TYPE) of infoPage)) (WRITEDATE (GDATE (fetch (LeaderPage TimeWrite) of infoPage))) (READDATE (GDATE (fetch (LeaderPage TimeRead) of infoPage))) (CREATIONDATE (GDATE (fetch (LeaderPage TimeCreate) of infoPage))) (IWRITEDATE (fetch (LeaderPage TimeWrite) of infoPage)) (IREADDATE (fetch (LeaderPage TimeRead) of infoPage)) (ICREATIONDATE (fetch (LeaderPage TimeCreate) of infoPage)) (AUTHOR (fetch (LeaderPage author) of infoPage)) NIL]]) ) (DEFINEQ (\LFGetFileName [DLAMBDA ((FileName (ONEOF ATOM STRINGP)) (Recog LITATOM) (Dev LFDEV) (RETURNS (ONEOF NIL LITATOM))) (* hts: "13-Feb-85 16:50") (* * Maps a filename onto a fully specified filename if it exists, or onto NIL if it doesn't exist.) [WITH.MONITOR \LFtopMonitor (DPROG ((fileSpec (\LFFileSpec FileName Recog) (ONEOF NIL DFSFileSpec))) [RETURN (AND fileSpec (\LFFullFileName (fetch (DFSFileSpec EXPANDEDNAME) of fileSpec])]]) ) (DEFINEQ (\LFEventFn [DLAMBDA ((Dev LFDEV) (Event ATOM)) (* edited: "11-Mar-85 21:18") (* * Determines dliondisk fdev behaviour across major system events. Must make the file system wake up properly on different machines, or even on the same machine with a different disk partitioning.) (WITH.MONITOR \LFtopMonitor (SELECTQ Event [(AFTERLOGOUT AFTERSYSOUT AFTERMAKESYS AFTERSAVEVM) (* * Close down the device) (\LFCloseDevice) (* * Force Pilot reinitialization) (\PFEnsureInitialized T) (* * Reopen the device if possible.) (\LFOpenDevice) (* * take down and replace the DSKDISPLAY window, if you have one open. This reshapes the window if you move to a DLion with a different number of volumes, and flushes the window if you move from a Dlion to a Dorado) (DSKDISPLAY (DSKDISPLAY (QUOTE CLOSED))) (* * If on an alien machine, make sure you won't attempt to reopen files. Note that if you're still on a dlion or dove, the reopenfile method will not break, but will simply return NIL if the file isn't there (say if someone deleted it since this Lisp image was last run, or if the disk changed).) (SELECTQ (MACHINETYPE) ((DANDELION DOVE) NIL) (replace (FDEV REOPENFILE) of Dev with (FUNCTION NILL] ((BEFORELOGOUT BEFORESYSOUT BEFOREMAKESYS BEFORESAVEVM) (* * BVM claims you should flush open streams associated with this device only before logout) (if (EQ Event (QUOTE BEFORELOGOUT)) then (\FLUSH.OPEN.STREAMS Dev)) (* * Save out buffers.) (for vol in (\PFGetVols) when (\LFDirectoryP vol) do (\PFSaveBuffers vol))) NIL))]) ) (DEFINEQ (\LFDirectoryNameP [DLAMBDA ((DirSpec (ONEOF ATOM STRINGP)) (RETURNS (ONEOF NIL STRINGP))) (* hts: "16-Jan-85 17:27") (* * Implements the DIRECTORYNAMEP method for the dlionfs. If DirSpec is a reasonable directory specification, returns the canonical form of that directory; otherwise returns NIL) (* * DirSpec (a) must parse correctly, (b) must have a proper directory associated with it, and (c) might have a subdirectory nestled in it.) [WITH.MONITOR \LFtopMonitor (DPROG ((PARSED NIL (ONEOF NIL PARSEDFILENAME)) (DIR NIL (ONEOF NIL LogicalVolumeDescriptor)) (SUBDIREND NIL (ONEOF NIL FIXP))) [RETURN (AND (SETQ PARSED (\LFParseFileName DirSpec)) (SETQ DIR (\LFFindDirectoryVol (fetch (PARSEDFILENAME VOL) of PARSED))) (PACKFILENAME.STRING (QUOTE HOST) (QUOTE DSK) (QUOTE DIRECTORY) (U-CASE (fetch (LogicalVolumeDescriptor LVlabel) of DIR)) (QUOTE NAME) (AND (SETQ SUBDIREND (FIXP (LASTCHPOS (CHARCODE >) (fetch ( PARSEDFILENAME NAME) of PARSED) 1))) (U-CASE (SUBSTRING (fetch ( PARSEDFILENAME NAME) of PARSED) 1 (SUB1 SUBDIREND])]]) ) (DEFINEQ (\LFTruncateFile [DLAMBDA ((STREAM DLIONSTREAM) (PAGE# (ONEOF NIL FIXP)) (OFFSET (ONEOF NIL SMALLP)) (RETURNS NIL)) (* hts: "16-Feb-85 18:20") (* * Used to shorten or lengthen STREAM. If lengthening, pad the file with nulls. Used by SETEOFPTR and FORCEOUTPUT.) (* * Normalize arguments) (\UPDATEOF STREAM) (OR (FIXP PAGE#) (SETQ PAGE# (fetch (DLIONSTREAM EPAGE) of STREAM))) (OR (FIXP OFFSET) (SETQ OFFSET (fetch (DLIONSTREAM EOFFSET) of STREAM))) (* * If lengthening stream, pad it with nulls.) (UNINTERRUPTABLY (PROG ((FILEPTR (\GETFILEPTR STREAM))) (to (DIFFERENCE (PLUS (TIMES PAGE# BYTESPERPAGE) OFFSET) (PLUS (TIMES (fetch (DLIONSTREAM EPAGE) of STREAM) BYTESPERPAGE) (fetch (DLIONSTREAM EOFFSET) of STREAM))) do (\BOUT STREAM 0)) (\SETFILEPTR STREAM FILEPTR))) (* * Record the new file length) (replace (DLIONSTREAM EPAGE) of STREAM with PAGE#) (replace (DLIONSTREAM EOFFSET) of STREAM with OFFSET) (\LFUpdateLeaderPage STREAM) (\PFSaveBuffers (fetch (DLIONSTREAM VOLUME) of STREAM)) NIL]) ) (* * Load other file system modules) (FILESLOAD LFDIRECTORY LFPILOTFILE) (PUTPROPS LOCALFILE COPYRIGHT ("Xerox Corporation" 1985)) (DECLARE: DONTCOPY (FILEMAP (NIL (5423 10202 (CREATEDSKDIRECTORY 5433 . 6997) (PURGEDSKDIRECTORY 6999 . 8753) ( LISPDIRECTORYP 8755 . 9281) (VOLUMES 9283 . 9786) (VOLUMESIZE 9788 . 10200)) (10203 11080 ( \DFSCurrentVolume 10213 . 10608) (\DFSFreeDiskPages 10610 . 11078)) (11081 12646 (\LFEntryPoint 11091 . 12085) (\LFNormalizeVolumeName 12087 . 12644)) (12677 15205 (\LFCreateDevice 12687 . 13969) ( \LFOpenDevice 13971 . 14823) (\LFCloseDevice 14825 . 15203)) (15430 27089 (\LFOpenFile 15440 . 17491) (\LFGetStreamForFile 17493 . 19466) (\LFOpenOldFile 19468 . 21616) (\LFGenFileID 21618 . 21989) ( \LFCreateFile 21991 . 23475) (\LFMakeLeaderPage 23477 . 25243) (\LFUpdateLeaderPage 25245 . 26707) ( \LFWriteLeaderPage 26709 . 27087)) (27090 28447 (\LFCloseFile 27100 . 28445)) (28448 29663 ( \LFDeleteFile 28458 . 29661)) (29664 32561 (\LFReadPages 29674 . 30486) (\LFReadOnePage 30488 . 32559) ) (32562 34579 (\LFWritePages 32572 . 32934) (\LFWriteOnePage 32936 . 33834) (\LFExtendFile 33836 . 34577)) (34580 36755 (\LFGetFileInfo 34590 . 36753)) (36756 37423 (\LFGetFileName 36766 . 37421)) ( 37424 39446 (\LFEventFn 37434 . 39444)) (39447 40981 (\LFDirectoryNameP 39457 . 40979)) (40982 42409 ( \LFTruncateFile 40992 . 42407))))) STOP