-- 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.