diff --git a/backend/src/workspaces/workspace-lock-root-lease.ts b/backend/src/workspaces/workspace-lock-root-lease.ts index da5344c1..8200e5d4 100644 --- a/backend/src/workspaces/workspace-lock-root-lease.ts +++ b/backend/src/workspaces/workspace-lock-root-lease.ts @@ -4,7 +4,7 @@ export interface WorkspaceLockRootIdentityV1 { readonly schemaVersion:1; readonl export class CanonicalWorkspaceLockRootInput { private constructor(readonly workspaceId:CanonicalWorkspaceId, readonly owner:symbol){} static make(id:CanonicalWorkspaceId,owner:symbol){return new CanonicalWorkspaceLockRootInput(id,owner);} } export class BorrowedVerifiedWorkspaceLockRootLease { private constructor(readonly identity:WorkspaceLockRootIdentityV1, private readonly check:()=>void){} static make(i:WorkspaceLockRootIdentityV1,c:()=>void){return new BorrowedVerifiedWorkspaceLockRootLease(i,c);} assertLive(){this.check();} } function conflict(message="preprocessing conflict"):Error { const e=new Error(message); e.name="PreprocessingConflictError"; return e; } -function exactStat(stat:WorkspaceFsAtStatV1,uid:number):boolean { return (stat.mode&0o170000)===0o040000 && (stat.mode&0o777)===0o700 && stat.uid===uid && stat.nlink===1n; } +function exactStat(stat:WorkspaceFsAtStatV1,uid:number):boolean { return (stat.mode&0o170000)===0o040000 && (stat.mode&0o777)===0o700 && stat.uid===uid && stat.nlink>=2n; } export class WorkspaceSessionReadersLockLease { private live=true; private constructor(private readonly lock:OwnedWorkspaceFsAtRegularFile, private readonly root:OwnedWorkspaceFsAtDirectory, readonly rootIdentity:WorkspaceLockRootIdentityV1){} static make(lock:OwnedWorkspaceFsAtRegularFile,root:OwnedWorkspaceFsAtDirectory,id:WorkspaceLockRootIdentityV1){return new WorkspaceSessionReadersLockLease(lock,root,id);}