<<**** SECTION HEADINGS AND ALL MESA STATEMENTS ARE AT THE TOP LEVEL ****>> <<>> <<>> <> <> <<>> <> <> <> <> <> <> <> <> DIRECTORY BasicTime USING [ GMT, nullGMT ], IO USING [ STREAM ], Rope USING [ ROPE ]; FS: CEDAR DEFINITIONS = BEGIN ROPE: TYPE = Rope.ROPE; STREAM: TYPE = IO.STREAM; <<>> <<>> <<>> <> <> <<>> <> <<>> <> <<>> <> <<>> <> <<>> <> <<>> <> <<>> <> <<>> <> <<>> <> <<>> < IF error.group = user THEN { YourProcedureToShowRopeToUser[error.explanation]; CONTINUE }>> <<>> <> <<>> <> <<>> <> <<>> <<>> <<>> <> <<>> <> <> <> <<>> <<>> <<>> <<>> <> <> <<>> <> <<>> <> <<>> <<>> <> <> <<>> <> <<>> <> <<>> <> <<>> <> Error: ERROR [error: ErrorDesc]; ErrorDesc: TYPE = RECORD [group: ErrorGroup, code: ATOM, explanation: ROPE] _ [ok, NIL, NIL]; ErrorGroup: TYPE = { ok, -- initial group for a new FS.ErrorDesc bug, -- caused by an internal bug environment, -- something's wrong in the environment; human intervention required lock, -- conflict over locks client, -- illegal operation, probably due to bug in client program user -- illegal operation, probably due to user action }; <<>> <<>> <> <> maxFNameLength: CARDINAL = 126; <<>> <> <<>> <> <<>> <<[server]subDirectory>simpleName!version>> <> <<>> <", or "/". The non-structural characters are the same as for the server part with the exception of "#". The additional structural character "!" is used as the version part prefix. The rest of the version part can be a number in the range [1 .. 65534], or one of the letters "L" or "H". Case is not significant in FNames.>> <<>> <> <<>> <> <<>> <> <<>> <<[]<>FS.mesa!3>> <> <<[]Temp>DebugTool.bcd!12>> <> <<>> <> <<>> <> <<1. Certain remote servers, e.g., Gateways, Grapevine servers, do not have a directory structure or versions. Such servers require GNames of the form "[server]simpleName".>> <<2. The root directory in an LName may also be identified by its unique VolumeID. The syntax for the root directory part in this case is "#" followed by a 20-digit hexadecimal string.>> <<3. The Cedar debugger interface makes a remote debuggee's disk available to a debugger as if its disks were attached to the debugger's machine. This is essentially transparent to FS; volumes of the debuggee's disk will appear to be part of the local server, i.e., files will be LNames, not GNames. This is entirely different from the situation in which the remote machine is operating normally and is running, say, an FTP server.>> <<>> <> <> <<>> <> <<>> <<1) the "wDir" argument;>> <<2) the value of the $WorkingDirectory property of the process property list;>> <<3) the default working directory (set with FS.SetDefaultWDir).>> <<>> <" ("/") then a ">" ("/") is appended. The defualt working directory must be local. >> SetDefaultWDir: PROC [dir: ROPE _ NIL]; GetDefaultWDir: PROC RETURNS [ROPE]; <", meaning the system volume for this Cedar instance. "[]<>" also is the initial value for the default working directory. If "dir" does not end with ">" ("/") a ">" ("/") is appended.>> <<>> <> <> <<>> <<>> <> <<>> Position: TYPE = RECORD [start, length: CARDINAL]; ComponentPositions: TYPE = RECORD [server, dir, subDirs, base, ext, ver: Position]; ExpandName: PROC[name: ROPE, wDir: ROPE _ NIL] RETURNS [fullFName: ROPE, cp: ComponentPositions, dirOmitted: BOOLEAN]; <> <<>> < ... >". The "subDirs" is the all the subdirectory part without without surounding "> ... >" but including interior ">"s. The "base" is the portion of the simple name up to but not including the final "." The "ext" is the portion of the simple name following the final "." If there are no "."s in the simple name then it is all considered to be "base". The "ver" is everything after the "!".>> <<>> <"), then "dirOmitted" returns TRUE; otherwise it returns FALSE.>> <<>> <> <<>> <> <<>> <> <<>> <> <> <<>> ComponentRopes: TYPE = RECORD [server, dir, subDirs, base, ext, ver: ROPE _ NIL]; ConstructFName: PROC [cr: ComponentRopes, omitDir: BOOLEAN _ FALSE] RETURNS [ROPE]; <" within the subdirectory component.>> <<>> <> <> <" ];>> < 0 THEN name _ Rope.Cat[ name, cr.subDirs, ">" ];>> <> < 0 THEN name _ Rope.Cat[ name, ".", cr.ext ];>> < 0 THEN name _ Rope.Cat[ name, "!", cr.ver ];>> <> <<>> <> <> <<>> <<>> <> <<>> <<>> <> <<>> WordsForPages: PROC[pages: INT] RETURNS [words: INT]; BytesForPages: PROC[pages: INT] RETURNS [bytes: INT]; PagesForWords: PROC[words: INT] RETURNS [pages: INT]; PagesForBytes: PROC[bytes: INT] RETURNS [pages: INT]; <<>> <<>> <> <<>> <<>> <> <<>> <> <<>> <> <> <<>> <> <> <> <<>> <> <<>> <> <> <<>> <<>> <<>> <> <> <> <> <> <> <> Lock: TYPE = {read, write}; <> <> <> <> <> FileInfo: PROC [name: ROPE, wantedCreatedTime: BasicTime.GMT _ BasicTime.nullGMT, remoteCheck: BOOLEAN _ TRUE, wDir: ROPE _ NIL] RETURNS [fullFName, attachedTo: ROPE, keep: CARDINAL, bytes: INT, created: BasicTime.GMT]; <<>> <> <<>> <> <<>> <> <<>> <> <<>> <> <> <<>> <<>> <> <<>> <<>> <> <> <<>> InfoProc: TYPE = PROC [fullFName, attachedTo: ROPE, created: BasicTime.GMT, bytes: INT, keep: CARDINAL] RETURNS [continue: BOOLEAN]; EnumerateForInfo: PROC [pattern: ROPE, proc: InfoProc, wDir: ROPE _ NIL]; <<>> <<"proc" is called for each FName selected by the pattern. Returning "continue" as FALSE stops the enumeration. "fullFName" reports the complete FName including version part of each name encountered. The keep, byte length, and created date of a local or global file are reported. When an LName attached to a GName is encountered, "fullFName" is the LName and "attachedTo" is the GName. In this case, the "keep" reported is that of the LName but the "bytes" and "created" are that of the GName. If any FS.Error's are encountered when trying to determine the byte count of an attachment, they are suppressed and "bytes" is reported as -1. Whenever a valid byte count for an attachment is reported then the version part in an "attachedTo" name is the true version number that corresponds to the created-time for the attachment; otherwise this version part will be whatever was recorded by FS.Copy when the attachment was made.>> <<>> <> <> <<>> NameProc: TYPE = PROC [fullFName: ROPE] RETURNS [continue: BOOLEAN]; EnumerateForNames: PROC [pattern: ROPE, proc: NameProc, wDir: ROPE _ NIL]; <<>> <> <<>> <> <> << >> <<>> <> <> <<>> <> OpenFile: TYPE = RECORD [REF]; nullOpenFile: OpenFile = [NIL]; <<>> Open: PROC [name: ROPE, lock: Lock _ $read, wantedCreatedTime: BasicTime.GMT _ BasicTime.nullGMT, remoteCheck: BOOLEAN _ TRUE, wDir: ROPE _ NIL] RETURNS [OpenFile]; <> <<>> <> <> Create: PROC [name: ROPE, setPages: BOOLEAN _ TRUE, pages: INT _ 0, setKeep: BOOLEAN _ FALSE, keep: CARDINAL _ 1, wDir: ROPE _ NIL] RETURNS [OpenFile]; <> <<>> <> <> OpenOrCreate: PROC [name: ROPE, keep: CARDINAL _ 1, pages: INT _ 5, wDir: ROPE _ NIL] RETURNS [OpenFile]; <> <<>> <> <> <<>> <> <<>> GetClass: PROC [file: OpenFile] RETURNS [ATOM]; <> <<>> <> <> <<>> SameFile: PROC [file1, file2: OpenFile] RETURNS [BOOLEAN]; <> <<>> <> <> GetName: PROC [file: OpenFile] RETURNS [fullFName, attachedTo: ROPE]; <> <<>> <> <> GetInfo: PROC [file: OpenFile] RETURNS [keep: CARDINAL, pages, bytes: INT, created: BasicTime.GMT, lock: Lock]; <> <<>> <> <> <<>> SetPageCount: PROC [file: OpenFile, pages: INT]; <> <<>> <> <> <<>> SetByteCountAndCreatedTime: PROC [file: OpenFile, bytes: INT _ -1, created: BasicTime.GMT _ BasicTime.nullGMT]; <> <<>> <> <> <<>> Read: UNSAFE PROC [file: OpenFile, from, nPages: INT, to: LONG POINTER]; <> <<>> <> <> Write: PROC [file: OpenFile, to: INT, nPages: INT, from: LONG POINTER]; <> <<>> <> <> Close: PROC [file: OpenFile]; <> <<>> <> <> <<>> <<>> <> <<>> <<>> <> <<>> <> <<>> <> <<>> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> < fileLen. Set streamIndex _ index.>> <> <> <> <> <<>> <> <<>> <> <<>> <> <<>> <> <<>> <> <<>> <> <<>> <<>> <<>> <> StreamOptions: TYPE = PACKED ARRAY StreamOption OF FalseBool; FalseBool: TYPE = BOOL _ FALSE; StreamOption: TYPE = { tiogaRead, -- if accessOptions = $read and file is in Tioga format, read only plain text portion of the file (ignore "looks" and nodes with the comment property). If accessOptions # $read and file is in Tioga format, raise FS.Error[$cantUpdateTiogaFile]. commitAndReopenTransOnFlush, -- each IO.Flush call "checkpoints" the transaction being used by the stream. truncatePagesOnClose, -- each IO.Close call causes extra pages of the file to be freed. finishTransOnClose, -- each IO.Close call causes the transaction to be committed or aborted, according to the abort parameter to IO.Close. closeFSOpenFileOnClose -- each IO.Close call performs FS.Close on the underlying FS.OpenFile. }; defaultStreamOptions: StreamOptions = ALL[TRUE]; StreamBufferParms: TYPE = RECORD [vmPagesPerBuffer: INT [1 .. 128], nBuffers: INT [1 .. 4]]; defaultStreamBufferParms: StreamBufferParms = [vmPagesPerBuffer: 16, nBuffers: 2]; minimumStreamBufferParms: StreamBufferParms = [vmPagesPerBuffer: 1, nBuffers: 1]; <> ByteCount: TYPE = INT; ExtendFileProc: TYPE = PROC [--current--ByteCount] RETURNS [--new--ByteCount]; <> AccessOptions: TYPE = {read, create, append, write}; StreamOpen: PROC [fileName: ROPE, accessOptions: AccessOptions _ $read, streamOptions: StreamOptions _ defaultStreamOptions, keep: CARDINAL _ 1, createByteCount: ByteCount _ 2560, streamBufferParms: StreamBufferParms _ defaultStreamBufferParms, extendFileProc: ExtendFileProc _ NIL] RETURNS [STREAM]; <<>> <> <<>> <<(1) If accessOptions = $read, perform FS.Open[name: fileName]. If accessOptions = $create, perform FS.Create[name: fileName, keep: keep, pages: FS.PagesForBytes[createByteCount]]. If accessOptions = $append, perform FS.OpenOrCreate[name: fileName, keep: keep, pages: FS.PagesForBytes[createByteCount]]. If accessOptions = $write, perform FS.Open[name: fileName, lock: $write, keep: keep, pages: FS.PagesForBytes[createByteCount]]. Any FS.Error raised by a call to FS.Open, FS.Create, or FS.OpenOrCreate will propogate through FS.StreamOpen.>> <<>> <<(2) Perform FS.StreamFromOpenFile[ ... , streamOptions, streamBufferParms, extendFileProc] on the resulting FS.OpenFile. The value of accessOptions determines the set of operations allowed on the stream (disallowed operations raise IO.Error[$NotImplementedForThisStream, stream] when called), and the initial streamIndex, as follows:>> <> <> <> <> <<>> <> <> InitialPosition: TYPE = {start, end}; StreamFromOpenFile: PROC [openFile: OpenFile, accessRights: Lock _ $read, initialPosition: InitialPosition _ $start, streamOptions: StreamOptions _ defaultStreamOptions, streamBufferParms: StreamBufferParms _ defaultStreamBufferParms, extendFileProc: ExtendFileProc _ NIL] RETURNS [STREAM]; <> <<>> <> <> OpenFileFromStream: PROC [self: STREAM] RETURNS [OpenFile]; <> ErrorFromStream: PROC [self: STREAM] RETURNS [ErrorDesc]; <> <> <<>> <> <<>> Copy: PROC [from, to: ROPE, setKeep: BOOLEAN _ FALSE, keep: CARDINAL _ 1, wantedCreatedTime: BasicTime.GMT _ BasicTime.nullGMT, remoteCheck: BOOLEAN _ TRUE, attach: BOOLEAN _ FALSE, wDir: ROPE _ NIL]; <<>> <> <<>> <> <<>> <> <<>> <> <<>> <> <<>> <> <<>> <> <> <<>> Delete: PROC [name: ROPE, wantedCreatedTime: BasicTime.GMT _ BasicTime.nullGMT, wDir: ROPE _ NIL]; <<>> <> <<>> <> <> Rename: PROC [from, to: ROPE, setKeep: BOOLEAN _ FALSE, keep: CARDINAL _ 1, wantedCreatedTime: BasicTime.GMT _ BasicTime.nullGMT, wDir: ROPE _ NIL]; <> <<>> <> <> <<>> <<>> SetKeep: PROC [name: ROPE, keep: CARDINAL _ 1, wDir: ROPE _ NIL]; <> <<>> <> <> <> <<>> <<>> <> <<>> <> <<$inconsistent -- a local volume's permanent data structures are inconsistent>> <<$software -- label check encountered while reading or writing pages on the local volume>> <<$badFP -- File.FP from directory/cache doesn't correspond to a file on a local volume>> <<>> <> <<$wentOffline -- local volume is no longer accessible>> <<$hardware -- hard error while reading or writing pages on a local volume>> <<$volumeFull -- no more free pages on a local volume>> <<$fragmented -- file required too many non-contiguous areas on a local volume>> <<$noMoreVersions -- next version number would be too big>> <<$serverInaccessible -- couldn't get a response from a remote server>> <<$connectionRejected -- remote server rejected the connection attempt>> <<$connectionTimedOut -- connection to a remote server timed out>> <<$badCredentials -- remote server rejected the user name or password>> <<$accessDenied -- remote server access controls succeeded>> <<$quotaExceeded -- disk space quota on remote server exceeded>> <<$invalidPropertyPage -- unrecognized property page format for a file on a local volume>> <<$badBTree -- directory/cache BTree is malformed and cannot be opened>> <<>> <> <<$lockConflict -- required lock cannot be obtained>> <<$fileBusy -- remote file currently being used in an incompatible way>> <<>> <> <<$noCache -- couldn't operate on global file because there is no system volume or cache>> <<$wrongLock -- operation requires a write lock and only a read lock is held>> <<$globalWriteLock -- tried to open a GName with a write lock>> <<$zeroKeep -- keep of 0 was specified>> <<$badByteCount -- tried to set a byte count that is beyond end of file or negative>> <<$unknownPage -- tried to read or write a page that is beyond end of the file>> <<$invalidOpenFile -- FS.OpenFile is closed, is FS.nullOpenFile, or is an unrecognized TYPE>> <<$notImplemented -- called procedure not provided for this FS.OpenFile>> <<>> <> <<$nonCedarVolume -- named volume is not a cedar volume>> <<$unknownServer -- couldn't get the network address for the named server>> <<$unknownVolume -- named local volume cannot be found>> <<$unknownFile -- FName not in the implied directory>> <<$unknownCreatedTime -- no version of the given FName had the specified created-time >> <<$illegalName -- file name, directory name or pattern has illegal syntax or characters, or is too long, >> <<$patternNotAllowed -- name presented contained a "*" and procedure doesn't allow patterns>> <<$versionSpecified -- tried to create an FName with a specific version>> <<$globalCreation -- tried to create a GName>> <<$badWorkingDir -- default working directory specified is global or has no volume part>> <<$noKeeps -- tried to set the keep on a server that does not implement keeps>> <<$cantUpdateTiogaFile -- tried open a file stream to write on a .tioga file>> END....