fileName: Rope.ROPE; -- gets the name from nameOwnerProperties
fileOwner: Rope.ROPE; -- gets the owner from nameOwnerProperties
BEGIN
ENABLE {
-- Extra nesting so above variables accessible in
ENABLE and
EXITS clauses
PossiblyDamaged => NULL;
UNWIND, AccessFailed, OperationFailed, StaticallyInvalid, Unknown => {
IF stage>=fileLocked THEN FileLock.ReleaseFileLock[fileInstance];
IF stage>=handleRegistered THEN OpenFileMap.Unregister[openFile];
stage ← nothing;
}};
BEGIN -- More extra nesting so ENABLE in force during EXITS clause
IF access NOT IN AccessRights OR lock.mode NOT IN AlpineEnvironment.LockMode OR recoveryOption NOT IN RecoveryOption OR referencePattern NOT IN ReferencePattern THEN ERROR StaticallyInvalid;
[openFile, openFileID] ← OpenFileMap.Register[conversation: conversation, trans: trans, volumeID: universalFile.volumeID, fileID: universalFile.fileID];
stage ← handleRegistered;
fileInstance ← OpenFileMap.GetFileInstanceHandle[openFile];
file ← FileInstance.GetFileHandle[fileInstance];
Ensure that volumeID identifies an actual volume (as opposed to a volume group), and read-lock the volume group as a side-effect. (Read-locking the volume group is required before several of the AccessControl operations that can be performed on open files, though it is not required during Open itself.)
[volumeID: actualVolumeID] ← VolumeGroup.Identify[volID: universalFile.volumeID, trans: trans, lock: [read, lock.ifConflict] !
VolumeGroup.Failed => GOTO unknownVolumeID];
IF universalFile.volumeID#actualVolumeID THEN GOTO unknownVolumeID;
Acquire file lock before calling AccessControl, because it must be able to read the leader page via this OpenFileID. Also this ensures that the file won't disappear out from under us once we have determined that it in fact exists.
FileLock.AcquireFileLock[fileInstance: fileInstance, requested: lock, minimum: intendRead];
stage ← fileLocked;
description ← LogMap.DescribeFile[file, trans];
IF description.registered AND ~description.exists THEN GOTO unknownFileID;
OpenFileMap.SetAccessRights[openFile, readOnly];
LeaderPage.Validate[fileInstance !
LeaderPage.Error => GOTO damagedLeaderPage];
IF ~AccessControl.PermissionToAccessFile[conversation: conversation, transHandle: trans, openFileID: openFileID, requestedAccess: access, lockOption: lock]
THEN
ERROR AccessFailed[IF access=readOnly THEN fileRead ELSE fileModify];
OpenFileMap.SetAccessRights[openFile, access];
OpenFileMap.SetRecoveryOption[openFile, recoveryOption];
OpenFileMap.SetReferencePattern[openFile, referencePattern];
Record the file's human-legible name. We can't do this when we register the FileMap.Handle (the information isn't available then), so we might as well wait until we can use GetPropertyList. If the stringName is NIL, then we record the owner name to get some grasp of what the file is.
nameOwnerPropertyList[owner] ← nameOwnerPropertyList[stringName] ← TRUE;
nameOwnerProperties ← LeaderPage.GetPropertyList[fileInstance: fileInstance, desiredProperties: nameOwnerPropertyList];
WHILE nameOwnerProperties #
NIL
DO
WITH nameOwnerProperties.first
SELECT
FROM
stringName => fileName ← stringName;
owner => fileOwner ← owner;
ENDCASE => ERROR;
nameOwnerProperties ← nameOwnerProperties.rest;
ENDLOOP;
IF fileName = NIL THEN fileName ← Rope.Cat["(unnamed file owned by ", fileOwner, ")"];
FileMap.SetName[file, fileName];
Must log the setting of the lock, since opening a file does not give rise to any log records which would cause the lock to be set during recovery. Note: do not do this until all possibility of error has passed.
IF lock.mode
IN [update..write]
THEN
FileLog.LogFileLock[fileInstance: fileInstance];
fileID ← universalFile.fileID;
EXITS
damagedLeaderPage => {
logProc: PROC [SkiPatrolLog.OpFailureInfo];
IF (logProc ← SkiPatrolLog.notice.operationFailed) #
NIL
THEN
logProc[[
what: damagedLeaderPage,
transID: transID,
where: "FileActionsImpl.Open",
message: ""
]];
ERROR OperationFailed[damagedLeaderPage];
};
unknownFileID => ERROR Unknown[fileID];
unknownVolumeID => ERROR Unknown[volumeID];
END;
END;