-- File: MFileOnNSFileImpl.mesa Edited by -- Breisacher.es 31-Jan-86 15:04:17 -- Wagner.pa 23-May-86 11:57:30 -- Saxe.pa 19-May-86 17:53:41 -- Copyright (C) 1985, 1986 by Xerox Corporation. All rights reserved. DIRECTORY Containee, Environment USING [Block, bytesPerPage], File, Heap, MFile, MFileOnNSFile, MFileOnNSFileOps, MFileOps, NSAssignedTypes, NSFile, NSSegment, NSSegmentInternal, NSString, SpecialDesktop, StarDesktop, String, SpecialMFile, System USING [gmtEpoch], Time USING [Packed], Volume USING [ID, InsufficientSpace, nullID], XString; MFileOnNSFileImpl: MONITOR IMPORTS Containee, File, Heap, MFileOps, NSFile, NSSegment, NSSegmentInternal, NSString, SpecialDesktop, StarDesktop, String, Volume, XString EXPORTS MFile, MFileOnNSFile, MFileOnNSFileOps, MFileOps, SpecialMFile = BEGIN OPEN MFile; Handle: TYPE = LONG POINTER TO Object; Object: PUBLIC TYPE = RECORD [ ref: NSFile.Reference, nsfh: NSFile.Handle, length: ByteCount, lengthChanged: BOOLEAN, access: Access]; zone: UNCOUNTED ZONE ¬ Heap.Create [initial: 1]; NotImplemented: ERROR = CODE; << MFileOnNSFileOps EXPORTS >> NSRefFromMFHandle: PUBLIC PROCEDURE [mfh: Handle] RETURNS [NSFile.Reference] = {RETURN [mfh.ref]}; NSHandleFromMFHandle: PUBLIC PROCEDURE [mfh: Handle] RETURNS [NSFile.Handle] = {RETURN [mfh.nsfh]}; FirstPageAfterLeader: PUBLIC PROCEDURE [mfh: Handle] RETURNS [File.PageNumber] = { RETURN[NSSegmentInternal.GetID[NSHandleFromMFHandle[mfh]].firstPage] }; << MFile EXPORTS >> Error: PUBLIC ERROR [file: MFile.Handle, code: ErrorCode] = CODE; NameForError: PUBLIC SIGNAL RETURNS [errorName: LONG STRING] = CODE; AppendErrorMessage: PUBLIC PROCEDURE [msg: LONG STRING, code: ErrorCode, file: Handle] = {}; -- getting and releasing files Acquire: PUBLIC PROCEDURE [ name: LONG STRING, access: Access, release: ReleaseData, mightWrite: BOOLEAN ¬ FALSE, initialLength: InitialLength ¬ dontCare, type: Type ¬ unknown] RETURNS [mfh: Handle ¬ NIL] = { SELECT access FROM anchor, readOnly, delete, rename => { mfh ¬ GetFile[name, access]; IF mfh = NIL THEN ERROR Error[NIL, noSuchFile] }; writeOnly, readWrite, log => { mfh ¬ GetFile[name, access]; IF mfh = NIL THEN mfh ¬ CreateFile[name, initialLength, access, type] }; ENDCASE; }; AcquireTemp: PUBLIC PROCEDURE [ type: Type, initialLength: InitialLength ¬ dontCare, volume: Volume.ID ¬ Volume.nullID] RETURNS [mfh: Handle ¬ NIL] = { RETURN [CreateFile ["temp$"L, initialLength, readWrite, unknown, TRUE]]; }; Log: PUBLIC PROCEDURE [ name: LONG STRING, release: ReleaseData, initialLength: InitialLength ¬ dontCare] RETURNS [Handle] = {ERROR NotImplemented}; ReadOnly: PUBLIC PROCEDURE [name: LONG STRING, release: ReleaseData, mightWrite: BOOLEAN ¬ FALSE] RETURNS [mfh: Handle ¬ NIL] = { mfh ¬ GetFile[name, readOnly]; IF mfh = NIL THEN ERROR Error[NIL, noSuchFile]; }; ReadWrite: PUBLIC PROCEDURE [ name: LONG STRING, release: ReleaseData, type: Type, initialLength: InitialLength ¬ dontCare] RETURNS [mfh: Handle ¬ NIL] = { mfh ¬ GetFile[name, readWrite]; IF mfh = NIL THEN mfh ¬ CreateFile [name, initialLength, readWrite, type]; }; WriteOnly: PUBLIC PROCEDURE [ name: LONG STRING, release: ReleaseData, type: Type, initialLength: InitialLength ¬ dontCare] RETURNS [mfh: Handle ¬ NIL] = { mfh ¬ GetFile[name, writeOnly]; IF mfh = NIL THEN mfh ¬ CreateFile [name, initialLength, writeOnly, type]; }; DeleteWhenReleased: PUBLIC PROCEDURE [file: Handle] = {ERROR NotImplemented}; Delete: PUBLIC PROCEDURE [file: Handle] = { IF file.lengthChanged THEN ReallySetLength[file]; NSFile.Delete [file.nsfh !NSFile.Error => Error[file, conflictingAccess]]; IF StarDesktop.SelectReference[file.ref] THEN SpecialDesktop.RemoveReferenceFromDesktop[file.ref]; zone.FREE [@file]; }; Release: PUBLIC PROCEDURE [file: Handle] = { IF file.lengthChanged THEN ReallySetLength[file]; NSFile.Close [file.nsfh]; zone.FREE [@file]; }; CopyFileHandle: PUBLIC PROCEDURE [ file: Handle, release: ReleaseData, access: Access ¬ null] RETURNS [mfh: Handle] = { fh: NSFile.Handle ¬ NSFile.OpenByReference[NSRefFromMFHandle[file]]; mfh ¬ zone.NEW [Object ¬ [ref: NSRefFromMFHandle[file], nsfh: fh, access: IF access = null THEN file.access ELSE access, lengthChanged: FALSE, length: file.length]];}; SameFile: PUBLIC PROCEDURE [file1, file2: Handle] RETURNS [BOOLEAN] = {ERROR NotImplemented}; GetAccess: PUBLIC PROCEDURE [file: Handle] RETURNS [access: Access] = { RETURN[file.access]}; GetReleaseData: PUBLIC PROCEDURE [file: Handle] RETURNS [release: ReleaseData] = {ERROR NotImplemented}; SetAccess: PUBLIC PROCEDURE [file: Handle, access: Access] = { file.access ¬ access}; SetReleaseData: PUBLIC PROCEDURE [file: Handle, release: ReleaseData] = {}; Copy: PUBLIC PROCEDURE [file: Handle, newName: LONG STRING] = {ERROR NotImplemented}; CreateDirectory: PUBLIC PROCEDURE [dir: LONG STRING] = {ERROR NotImplemented}; EnumerateDirectory: PUBLIC PROCEDURE [name: LONG STRING, proc: EnumerateProc, which: EnumerationType] = {ERROR NotImplemented}; FreeSearchPath: PUBLIC PROCEDURE [SearchPath] = {ERROR NotImplemented}; GetNextHandleForReading: PUBLIC PROCEDURE [ filter, name: LONG STRING, release: ReleaseData, lastState: EnumerateState, stopNow: BOOLEAN ¬ FALSE] RETURNS [file: Handle, state: EnumerateState] = {ERROR NotImplemented}; -- make sure that you call in with stopNow = TRUE to release resources if quitting enumeration early GetSearchPath: PUBLIC PROCEDURE RETURNS [SearchPath] = {ERROR NotImplemented}; GetFullName: PUBLIC PROCEDURE [file: Handle, name: LONG STRING] = { attrRec: NSFile.AttributesRecord; NSFile.GetAttributes [file.nsfh, [[name: TRUE]], @attrRec]; NSString.AppendToMesaString [name, attrRec.name ! String.StringBoundsFault => RESUME[NIL] ]; NSFile.ClearAttributes [@attrRec]; }; Rename: PUBLIC PROCEDURE [file: Handle, newName: LONG STRING] = { attrib: ARRAY [0..1) OF NSFile.Attribute ¬ [ [name[nsname]] ]; rb: XString.ReaderBody; data: Containee.Data; nsname: NSString.String ¬ NSString.StringFromMesaString[newName]; attrib ¬ [ [name[nsname]] ]; NSFile.ChangeAttributes[ file: file.nsfh, attributes: DESCRIPTOR[attrib] ! NSFile.Error => {Error[file, insufficientAccess]}]; data.reference ¬ file.ref; rb ¬ XString.FromSTRING[newName, TRUE]; Containee.SetCachedName[@data, @rb];}; SetSearchPath: PUBLIC PROCEDURE [SearchPath] RETURNS [succeeded: BOOLEAN ¬ TRUE] = {ERROR NotImplemented}; SwapNames: PUBLIC PROCEDURE [f1, f2: Handle] = { attrRec1, attrRec2: NSFile.AttributesRecord; attrs1, attrs2: ARRAY [0..1) OF NSFile.Attribute; NSFile.GetAttributes [f1.nsfh, [[name: TRUE]], @attrRec1]; NSFile.GetAttributes [f2.nsfh, [[name: TRUE]], @attrRec2]; attrs1[0] ¬ [name[attrRec1.name]]; attrs2[0] ¬ [name[attrRec2.name]]; NSFile.ChangeAttributes [f1.nsfh, DESCRIPTOR[attrs2]]; NSFile.ChangeAttributes [f2.nsfh, DESCRIPTOR[attrs1]]; NSFile.ClearAttributes [@attrRec1]; NSFile.ClearAttributes [@attrRec2]; }; ValidFilename: PUBLIC PROCEDURE [name: LONG STRING] RETURNS [ok: BOOLEAN] = {ERROR NotImplemented}; CompleteFilename: PUBLIC PROCEDURE [name, addedPart: LONG STRING] RETURNS [exactMatch: BOOLEAN, matches: CARDINAL] = {ERROR NotImplemented}; ComputeFileType: PUBLIC PROCEDURE [file: Handle] RETURNS [type: Type] = {ERROR NotImplemented}; AddNotifyProc: PUBLIC PROCEDURE [ proc: NotifyProc, filter: Filter, clientInstanceData: LONG POINTER] = {}; RemoveNotifyProc: PUBLIC PROCEDURE [ proc: NotifyProc, filter: Filter, clientInstanceData: LONG POINTER] = {}; -- file properties PropertyError: PUBLIC ERROR [code: PropertyErrorCode] = CODE; GetVolume: PUBLIC PROCEDURE [file: Handle] RETURNS [Volume.ID] = {ERROR NotImplemented}; GetDirectoryName: PUBLIC PROCEDURE [file: Handle, name: LONG STRING] = {ERROR NotImplemented}; GetProperties: PUBLIC PROCEDURE [file: Handle, name: LONG STRING ¬ NIL] RETURNS [ create, write, read: Time.Packed, length: ByteCount, type: Type, deleteProtected, writeProtected, readProtected: BOOLEAN] = { attrs: NSFile.AttributesRecord; NSFile.GetAttributes [NSHandleFromMFHandle [file], [[name: TRUE, createdOn: TRUE, modifiedOn: TRUE, readOn: TRUE]], @attrs]; IF name # NIL THEN NSString.AppendToMesaString [name, attrs.name]; NSFile.ClearAttributes [@attrs]; RETURN [ create: attrs.createdOn, write: attrs.modifiedOn, read: attrs.readOn, length: file.length, type: unknown, deleteProtected: FALSE, writeProtected: FALSE, readProtected: FALSE]; }; GetCreateDate: PUBLIC PROCEDURE [file: Handle] RETURNS [create: Time.Packed] = {RETURN[GetTimes[file].create]}; GetTimes: PUBLIC PROCEDURE [file: Handle] RETURNS [create, write, read: Time.Packed] = { attrs: NSFile.AttributesRecord; NSFile.GetAttributes [NSHandleFromMFHandle [file], [[createdOn: TRUE, modifiedOn: TRUE, readOn: TRUE]], @attrs]; RETURN [ create: attrs.createdOn, write: attrs.modifiedOn, read: attrs.readOn]; }; GetType: PUBLIC PROCEDURE [file: Handle] RETURNS [type: Type] = {ERROR NotImplemented}; GetLength: PUBLIC PROCEDURE [file: Handle] RETURNS [ByteCount] = { RETURN[file.length]; }; GetProtection: PUBLIC PROCEDURE [file: Handle] RETURNS [deleteProtected, writeProtected, readProtected: BOOLEAN] = {ERROR NotImplemented}; SetProperties: PUBLIC PROCEDURE [ file: Handle, create, write, read: Time.Packed ¬ System.gmtEpoch, length: ByteCount, type: Type, deleteProtected, writeProtected, readProtected: BOOLEAN ¬ FALSE] = {ERROR NotImplemented}; SetTimes: PUBLIC PROCEDURE [file: Handle, create, read, write: Time.Packed ¬ System.gmtEpoch] = {}; SetType: PUBLIC PROCEDURE [file: Handle, type: Type] = {ERROR NotImplemented}; SetLength: PUBLIC PROCEDURE [file: Handle, length: ByteCount] = { SetMinimumFileDataPages[file, MFileOps.PageForBytes[length]]; file.lengthChanged ¬ TRUE; file.length ¬ length}; SetDeleteProtect: PUBLIC PROCEDURE [file: Handle, deleteProtected: BOOLEAN] = {ERROR NotImplemented}; SetWriteProtect: PUBLIC PROCEDURE [file: Handle, writeProtected: BOOLEAN] = {ERROR NotImplemented}; SetReadProtect: PUBLIC PROCEDURE [file: Handle, readProtected: BOOLEAN] = {}; SetProtection: PUBLIC PROCEDURE [ file: Handle, deleteProtected, writeProtected, readProtected: BOOLEAN ¬ FALSE] = {ERROR NotImplemented}; AddProperty: PUBLIC PROCEDURE [file: Handle, property: Property, maxLength: CARDINAL] = {ERROR NotImplemented}; CopyProperties: PUBLIC PROCEDURE [from, to: Handle] = {ERROR NotImplemented}; GetProperty: PUBLIC PROCEDURE [file: Handle, property: Property, block: Environment.Block] RETURNS [length: CARDINAL] = {ERROR NotImplemented}; RemoveProperty: PUBLIC PROCEDURE [file: Handle, property: Property] = {ERROR NotImplemented}; RemoveProperties: PUBLIC PROCEDURE [file: Handle] = {ERROR NotImplemented}; SetProperty: PUBLIC PROCEDURE [file: Handle, property: Property, block: Environment.Block] = {ERROR NotImplemented}; InitializeFileSystem: PUBLIC PROCEDURE = {}; << SpecialMFile >> AcquireID: PUBLIC PROCEDURE[ id: File.File, access: MFile.Access, release: MFile.ReleaseData] RETURNS [MFile.Handle] = {ERROR NotImplemented}; EscapeMatch: PUBLIC PROCEDURE [string, pattern: LONG STRING, pos: CARDINAL] RETURNS [correspondingingPos: CARDINAL] = {ERROR NotImplemented}; GetCapaWithAccess: PUBLIC PROCEDURE [file: Handle] RETURNS [File.File] = {RETURN [NSSegmentInternal.GetID [file.nsfh].pilotFile]}; LeaderPages: PUBLIC PROCEDURE RETURNS [CARDINAL] = { RETURN[MFileOps.leaderPages]}; RegisterWithSupervisor: PUBLIC PROCEDURE = {ERROR NotImplemented}; << MFileOps >> SetMinimumFileDataPages: PUBLIC PROCEDURE [ file: Handle, pages: File.PageCount] = { f: File.File = GetCapaWithAccess[file]; IF File.GetSize[f] < pages + MFileOps.leaderPages THEN SetFileDataSize[f, pages ! Volume.InsufficientSpace => Error[file, noRoomOnVolume]] }; SetFileDataSize: PUBLIC PROCEDURE [id: File.File, dataPages: File.PageCount] = { pages: File.PageCount ¬ MFileOps.IncrementCeiling[dataPages]; File.SetSize[file: id, size: pages]}; << MFile on NSFile impls >> defaultInitialLength: InitialLength = 512; -- from MPM CreateFile: PROCEDURE [name: LONG STRING, initialLength: InitialLength, access: Access, type: Type ¬ unknown, temp: BOOLEAN ¬ FALSE] RETURNS [mfh: Handle] = { << Creates an NSFile on the desktop >> nssName: NSString.String ¬ NSString.StringFromMesaString [name]; attrs: ARRAY [0..4) OF NSFile.Attribute ¬ [ [name[nssName]], [sizeInBytes[IF initialLength = dontCare THEN defaultInitialLength ELSE initialLength]], [isTemporary[temp]], [type[SELECT type FROM text => NSAssignedTypes.tText, ENDCASE => NSAssignedTypes.tUnspecified]]]; fh: NSFile.Handle; ref: NSFile.Reference; FirstDirectory: MFileOnNSFile.EachElementProc = { dfh: NSFile.Handle ¬ NSFile.OpenByReference [element]; fh ¬ NSFile.Create[ directory: dfh, attributes: DESCRIPTOR[attrs] ! NSFile.Error => CONTINUE]; NSFile.Close [dfh]; IF fh # NSFile.nullHandle AND element = StarDesktop.GetCurrentDesktopFile[] THEN { ref ¬ NSFile.GetReference [fh]; StarDesktop.AddReferenceToDesktop [ref] }; RETURN[done: TRUE]; }; EnumeratePath [FirstDirectory]; ref ¬ NSFile.GetReference [fh]; mfh ¬ zone.NEW [Object ¬ [ref: ref, nsfh: fh, access: access, lengthChanged: FALSE, length: IF initialLength = dontCare THEN defaultInitialLength ELSE initialLength]]; }; GetFile: PROCEDURE [name: LONG STRING, access: Access] RETURNS [mfh: Handle ¬ NIL] = { nssName: NSString.String ¬ NSString.StringFromMesaString [name]; attrs: NSFile.AttributesRecord; EachDirectory: MFileOnNSFile.EachElementProc = { fh: NSFile.Handle ¬ NSFile.nullHandle; dfh: NSFile.Handle ¬ NSFile.OpenByReference [element]; fh ¬ NSFile.OpenByName[directory: dfh, path: nssName ! NSFile.Error => {CONTINUE} ]; IF fh # NSFile.nullHandle THEN { mfh ¬ zone.NEW [Object ¬ [ ref: TRASH, nsfh: fh, access: access, lengthChanged: FALSE, length: NSSegment.GetSizeInBytes[fh]]]; NSFile.GetAttributes[fh, [[fileID: TRUE, service: TRUE]], @attrs]; mfh.ref ¬ [attrs.fileID, attrs.service] }; NSFile.Close [dfh]; RETURN [done: mfh#NIL]; }; EnumeratePath [EachDirectory]; }; ReallySetLength: PROCEDURE [file: Handle] = { NSSegment.SetSizeInBytes[file.nsfh, file.length] }; << Search path stuff - EXPORTed to MFileOnNSFile >> Path: TYPE = LONG POINTER TO PathSeq; PathSeq: TYPE = RECORD [SEQUENCE l: CARDINAL OF NSFile.Reference]; BadPath: PUBLIC ERROR = CODE; searchPath: Path ¬ NIL; SetPath: PUBLIC ENTRY PROCEDURE [ path: LONG DESCRIPTOR FOR ARRAY OF NSFile.Reference] = { ENABLE UNWIND => NULL; CheckPath[path]; zone.FREE [@searchPath]; searchPath ¬ zone.NEW [PathSeq [path.LENGTH]]; FOR i: CARDINAL IN [0..path.LENGTH) DO searchPath[i] ¬ path[i]; ENDLOOP; }; EnumeratePath: PUBLIC ENTRY PROCEDURE [ proc: MFileOnNSFile.EachElementProc] = { ENABLE UNWIND => NULL; IF searchPath = NIL THEN RETURN; FOR i: CARDINAL IN [0..searchPath.l) DO IF proc[searchPath[i]] THEN EXIT; ENDLOOP; }; CheckPath: PROCEDURE[ path: LONG DESCRIPTOR FOR ARRAY OF NSFile.Reference] = { -- Checks that all files are directories. attributes: NSFile.AttributesRecord; FOR i:CARDINAL IN [0..path.LENGTH) DO file: NSFile.Handle; file ¬ NSFile.OpenByReference[path[i] !NSFile.Error => ERROR BadPath]; NSFile.GetAttributes[file, [[isDirectory: TRUE]], @attributes]; IF ~attributes.isDirectory THEN ERROR BadPath; ENDLOOP; }; END. LOG NFS 19-May-86 17:56:47 Added check to setting search path that all files are directories.