Files
root-at-skicandClaude Opus 5.5 22815a9940 Archify Diagram Viewer 0.1.0
VS Code extension that previews Archify diagrams from their JSON sources
(live, as you type) and opens rendered Archify HTML in a viewer tab.
Bundles the Archify 3.0.1 renderer and runs it on VS Code's Node runtime.
Adds validation diagnostics, JSON schema help, source-link navigation,
export saving, render-to-file and open-in-browser commands.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-30 12:44:15 +03:00

1983 lines
69 KiB
JavaScript

import { createHash, randomBytes } from 'node:crypto';
import fs from 'node:fs';
import path from 'node:path';
import { canonicalFuturePath } from './output-path.mjs';
function relation(status, code, details = {}) {
return { status, reason: { code, ...details } };
}
function filesystemFailure(code, error, details = {}) {
return relation('unknown', code, {
...details,
...(typeof error?.code === 'string' ? { systemCode: error.code } : {}),
...(typeof error?.message === 'string' ? { message: error.message } : {}),
});
}
function entryType(metadata) {
if (metadata.isFile()) return 'file';
if (metadata.isSymbolicLink()) return 'symbolic-link';
if (metadata.isDirectory()) return 'directory';
if (metadata.isFIFO()) return 'fifo';
if (metadata.isSocket()) return 'socket';
if (metadata.isBlockDevice()) return 'block-device';
if (metadata.isCharacterDevice()) return 'character-device';
return 'other';
}
// Windows lstat can fall back to directory enumeration when a file handle
// cannot be opened, and that fallback reports a synthetic link count of one.
// Treat handle-backed fstat as authoritative and fail closed when it cannot be
// reconciled with the no-follow path snapshots on either side of the open.
function captureRegularFileHandle(filePath, initial, subject) {
const pathKey = subject === 'target'
? 'commitPath'
: subject === 'requested-entry'
? 'requestedPath'
: 'candidatePath';
if (initial.ino === 0n) {
return relation('unknown', `${subject}-identity-unavailable`, { [pathKey]: filePath });
}
let descriptor;
let handle;
let current;
let closeError;
try {
const noFollow = process.platform === 'win32' ? 0 : (fs.constants.O_NOFOLLOW || 0);
const nonBlock = fs.constants.O_NONBLOCK || 0;
descriptor = fs.openSync(filePath, fs.constants.O_RDONLY | noFollow | nonBlock);
handle = fs.fstatSync(descriptor, { bigint: true });
current = fs.lstatSync(filePath, { bigint: true });
} catch (error) {
return filesystemFailure(`${subject}-handle-inspection-failed`, error, {
[pathKey]: filePath,
});
} finally {
if (descriptor !== undefined) {
try {
fs.closeSync(descriptor);
} catch (error) {
closeError = error;
}
}
}
if (closeError) {
return filesystemFailure(`${subject}-handle-close-failed`, closeError, {
[pathKey]: filePath,
});
}
if (!handle.isFile() || !current.isFile()
|| handle.ino === 0n || current.ino === 0n
|| handle.dev !== initial.dev || handle.ino !== initial.ino
|| current.dev !== handle.dev || current.ino !== handle.ino) {
return relation('unknown', `${subject}-changed-during-inspection`, {
[pathKey]: filePath,
});
}
if (handle.nlink === 0n) {
return relation('unknown', `${subject}-link-count-unavailable`, {
[pathKey]: filePath,
});
}
if (handle.nlink !== 1n) {
return relation('unsupported', `${subject}-hardlinked`, {
[pathKey]: filePath,
links: handle.nlink.toString(),
});
}
return { status: 'captured', metadata: handle };
}
const regularFileBindings = new WeakMap();
const regularFileBindingGroups = new Map();
const digestChunkBytes = 64 * 1024;
const removalCleanupSignal = new Int32Array(new SharedArrayBuffer(4));
const removalCleanupAttempts = 10;
const publicationRecoveryRecordName = 'publication-recovery-v1.json';
const publicationRecoveryRecordVersion = 1;
const publicationRecoveryRecordMaxBytes = 16 * 1024;
export function removeEmptyDirectoryWithRetry(directory, { retry = true } = {}) {
const attempts = retry ? removalCleanupAttempts : 1;
let failure;
for (let attempt = 0; attempt < attempts; attempt += 1) {
try {
fs.rmdirSync(directory);
return;
} catch (error) {
failure = error;
// SMB can acknowledge unlink before a following directory removal sees
// the deleted entry disappear. Retrying rmdir is claimant-safe: a real
// entry keeps the directory non-empty and is never removed recursively.
if (error?.code !== 'ENOTEMPTY' || attempt === attempts - 1) break;
Atomics.wait(
removalCleanupSignal,
0,
0,
Math.min(5 * (2 ** attempt), 250),
);
}
}
throw failure;
}
function validExpectedLinks(value) {
return Number.isSafeInteger(value) && value > 0;
}
function validateBindingExpectations(options) {
const hasSha256 = options.expectedSha256 !== undefined;
const hasBytes = options.expectedBytes !== undefined;
const expectedIdentity = options.expectedIdentity;
if (hasSha256 !== hasBytes
|| (hasSha256 && !/^[a-f\d]{64}$/i.test(options.expectedSha256))
|| (hasBytes && (!Number.isSafeInteger(options.expectedBytes) || options.expectedBytes < 0))
|| (options.expectedMode !== undefined
&& (!Number.isSafeInteger(options.expectedMode)
|| options.expectedMode < 0
|| options.expectedMode > 0o777))
|| (expectedIdentity !== undefined
&& (typeof expectedIdentity?.device !== 'bigint'
|| typeof expectedIdentity?.inode !== 'bigint'
|| expectedIdentity.inode === 0n))
|| typeof options.includeContent !== 'boolean'
|| !validExpectedLinks(options.expectedLinks)) {
return relation('unknown', 'invalid-regular-file-binding-expectation');
}
return null;
}
function descriptorDigest(descriptor, expectedSize, subject, filePath, includeContent) {
if (expectedSize < 0n || expectedSize > BigInt(Number.MAX_SAFE_INTEGER)) {
return relation('unknown', `${subject}-size-unavailable`, { filePath });
}
const expectedBytes = Number(expectedSize);
const digest = createHash('sha256');
let capturedContent;
let chunk;
try {
capturedContent = includeContent ? Buffer.allocUnsafe(expectedBytes) : null;
chunk = capturedContent
|| Buffer.allocUnsafe(Math.min(digestChunkBytes, Math.max(1, expectedBytes)));
} catch (error) {
return filesystemFailure(`${subject}-content-inspection-failed`, error, { filePath });
}
let bytes = 0;
try {
while (bytes < expectedBytes) {
const offset = includeContent ? bytes : 0;
const read = fs.readSync(
descriptor,
chunk,
offset,
Math.min(digestChunkBytes, chunk.byteLength - offset, expectedBytes - bytes),
bytes,
);
if (read === 0) break;
digest.update(chunk.subarray(offset, offset + read));
bytes += read;
}
} catch (error) {
return filesystemFailure(`${subject}-content-inspection-failed`, error, { filePath });
}
return {
status: 'inspected',
sha256: digest.digest('hex'),
bytes,
...(includeContent ? { buffer: capturedContent.subarray(0, bytes) } : {}),
};
}
function sameHandleState(left, right) {
return left.dev === right.dev
&& left.ino === right.ino
&& left.nlink === right.nlink
&& left.mode === right.mode
&& left.size === right.size
&& left.mtimeNs === right.mtimeNs
&& left.ctimeNs === right.ctimeNs;
}
function inspectRegularFileDescriptor({
descriptor,
filePath,
identity,
subject,
expectedLinks,
phase,
includeContent = false,
}) {
let beforeHandle;
let beforePath;
let afterHandle;
let afterPath;
let content;
try {
beforeHandle = fs.fstatSync(descriptor, { bigint: true });
beforePath = fs.lstatSync(filePath, { bigint: true });
} catch (error) {
return filesystemFailure(`${subject}-handle-${phase}-failed`, error, { filePath });
}
if (!beforeHandle.isFile() || !beforePath.isFile()) {
return relation('unsupported', `${subject}-not-regular-file`, {
filePath,
entryType: entryType(beforePath),
});
}
if (beforeHandle.ino === 0n || beforePath.ino === 0n) {
return relation('unknown', `${subject}-identity-unavailable`, { filePath });
}
if (beforeHandle.dev !== identity.device
|| beforeHandle.ino !== identity.inode
|| beforePath.dev !== beforeHandle.dev
|| beforePath.ino !== beforeHandle.ino) {
return relation(phase === 'inspection' ? 'unknown' : 'different',
`${subject}-${phase === 'inspection' ? 'changed-during-inspection' : 'identity-changed'}`,
{ filePath });
}
if (beforeHandle.nlink === 0n) {
return relation('unknown', `${subject}-link-count-unavailable`, { filePath });
}
if (beforeHandle.nlink !== BigInt(expectedLinks)) {
if (beforeHandle.nlink > BigInt(expectedLinks)) {
return relation('unsupported', `${subject}-hardlinked`, {
filePath,
links: beforeHandle.nlink.toString(),
});
}
return relation('different', `${subject}-link-count-changed`, {
filePath,
expectedLinks,
currentLinks: beforeHandle.nlink.toString(),
});
}
content = descriptorDigest(
descriptor,
beforeHandle.size,
subject,
filePath,
includeContent,
);
if (content.status !== 'inspected') return content;
try {
afterHandle = fs.fstatSync(descriptor, { bigint: true });
afterPath = fs.lstatSync(filePath, { bigint: true });
} catch (error) {
return filesystemFailure(`${subject}-handle-${phase}-failed`, error, { filePath });
}
if (!afterHandle.isFile() || !afterPath.isFile()
|| afterHandle.ino === 0n || afterPath.ino === 0n
|| afterHandle.dev !== identity.device || afterHandle.ino !== identity.inode
|| afterPath.dev !== afterHandle.dev || afterPath.ino !== afterHandle.ino) {
return relation(phase === 'inspection' ? 'unknown' : 'different',
`${subject}-${phase === 'inspection' ? 'changed-during-inspection' : 'identity-changed'}`,
{ filePath });
}
if (!sameHandleState(beforeHandle, afterHandle)) {
return relation('unknown', `${subject}-changed-during-${phase}`, { filePath });
}
if (content.bytes !== Number(afterHandle.size)) {
return relation('unknown', `${subject}-changed-during-${phase}`, { filePath });
}
return { status: 'inspected', metadata: afterHandle, content };
}
function closeCapturedDescriptor(descriptor, subject, filePath) {
try {
fs.closeSync(descriptor);
return null;
} catch (error) {
return filesystemFailure(`${subject}-handle-close-failed`, error, { filePath });
}
}
/**
* Capture a regular file through an open descriptor. The opaque binding keeps
* the descriptor alive so callers can prove that the same inode, mode and
* bytes are still named by either the original path or a deliberate hard-link
* publication path. Callers must release every successfully captured binding.
*/
export function captureRegularFileBinding(filePath, {
subject = 'file',
expectedSha256,
expectedBytes,
expectedMode,
expectedIdentity,
expectedLinks = 1,
includeContent = false,
} = {}) {
const options = {
expectedSha256,
expectedBytes,
expectedMode,
expectedIdentity,
expectedLinks,
includeContent,
};
const invalid = validateBindingExpectations(options);
if (invalid) return invalid;
const resolvedPath = path.resolve(filePath);
let initial;
try {
initial = fs.lstatSync(resolvedPath, { bigint: true });
} catch (error) {
return filesystemFailure(`${subject}-inspection-failed`, error, { filePath: resolvedPath });
}
const type = entryType(initial);
if (type !== 'file') {
return relation('unsupported', `${subject}-not-regular-file`, {
filePath: resolvedPath,
entryType: type,
});
}
if (initial.ino === 0n) {
return relation('unknown', `${subject}-identity-unavailable`, { filePath: resolvedPath });
}
let descriptor;
try {
const noFollow = process.platform === 'win32' ? 0 : (fs.constants.O_NOFOLLOW || 0);
const nonBlock = fs.constants.O_NONBLOCK || 0;
descriptor = fs.openSync(resolvedPath, fs.constants.O_RDONLY | noFollow | nonBlock);
} catch (error) {
return filesystemFailure(`${subject}-handle-inspection-failed`, error, { filePath: resolvedPath });
}
const identity = { device: initial.dev, inode: initial.ino };
if (expectedIdentity !== undefined
&& (identity.device !== expectedIdentity.device
|| identity.inode !== expectedIdentity.inode)) {
const closeFailure = closeCapturedDescriptor(descriptor, subject, resolvedPath);
return closeFailure || relation('different', `${subject}-identity-changed`, {
filePath: resolvedPath,
});
}
const inspected = inspectRegularFileDescriptor({
descriptor,
filePath: resolvedPath,
identity,
subject,
expectedLinks,
phase: 'inspection',
includeContent,
});
if (inspected.status !== 'inspected') {
const closeFailure = closeCapturedDescriptor(descriptor, subject, resolvedPath);
return closeFailure || inspected;
}
const mode = Number(inspected.metadata.mode & 0o777n);
if (expectedMode !== undefined && mode !== expectedMode) {
const closeFailure = closeCapturedDescriptor(descriptor, subject, resolvedPath);
return closeFailure || relation('different', `${subject}-mode-changed`, {
filePath: resolvedPath,
expectedMode,
currentMode: mode,
});
}
if (expectedSha256 !== undefined
&& (inspected.content.sha256.toLowerCase() !== expectedSha256.toLowerCase()
|| inspected.content.bytes !== expectedBytes)) {
const closeFailure = closeCapturedDescriptor(descriptor, subject, resolvedPath);
return closeFailure || relation('different', `${subject}-content-changed`, {
filePath: resolvedPath,
expectedSha256,
currentSha256: inspected.content.sha256,
expectedBytes,
currentBytes: inspected.content.bytes,
});
}
const identityKey = `${identity.device}:${identity.inode}`;
let cleanupGroup = regularFileBindingGroups.get(identityKey);
if (!cleanupGroup) {
cleanupGroup = { identityKey, bindings: 0, deferredCleanupDirectories: new Set() };
regularFileBindingGroups.set(identityKey, cleanupGroup);
}
cleanupGroup.bindings += 1;
const binding = Object.freeze({});
regularFileBindings.set(binding, {
descriptor,
filePath: resolvedPath,
subject,
expectedLinks,
cleanupGroup,
identity,
mode,
sha256: inspected.content.sha256,
bytes: inspected.content.bytes,
});
return {
status: 'captured',
binding,
identity: { ...identity, mode, links: inspected.metadata.nlink },
content: {
sha256: inspected.content.sha256,
bytes: inspected.content.bytes,
...(includeContent ? { buffer: inspected.content.buffer } : {}),
},
mode,
};
}
/** Verify a captured descriptor against its original or an alternate linked path. */
export function verifyRegularFileBinding(binding, { filePath, expectedLinks } = {}) {
const captured = regularFileBindings.get(binding);
if (!captured) return relation('unknown', 'regular-file-binding-unavailable');
const links = expectedLinks ?? captured.expectedLinks;
if (!validExpectedLinks(links)) {
return relation('unknown', 'invalid-regular-file-binding-expectation');
}
const verificationPath = path.resolve(filePath ?? captured.filePath);
const inspected = inspectRegularFileDescriptor({
descriptor: captured.descriptor,
filePath: verificationPath,
identity: captured.identity,
subject: captured.subject,
expectedLinks: links,
phase: 'verification',
});
if (inspected.status !== 'inspected') return inspected;
const mode = Number(inspected.metadata.mode & 0o777n);
if (mode !== captured.mode) {
return relation('different', `${captured.subject}-mode-changed`, {
filePath: verificationPath,
previousMode: captured.mode,
currentMode: mode,
});
}
if (inspected.content.sha256 !== captured.sha256
|| inspected.content.bytes !== captured.bytes) {
return relation('different', `${captured.subject}-content-changed`, {
filePath: verificationPath,
previousSha256: captured.sha256,
currentSha256: inspected.content.sha256,
previousBytes: captured.bytes,
currentBytes: inspected.content.bytes,
});
}
return relation('match', `${captured.subject}-binding-match`, {
filePath: verificationPath,
links,
});
}
/** Close and invalidate a captured regular-file binding. */
export function releaseRegularFileBinding(binding) {
const captured = regularFileBindings.get(binding);
if (!captured) return relation('unknown', 'regular-file-binding-unavailable');
regularFileBindings.delete(binding);
const failure = closeCapturedDescriptor(
captured.descriptor,
captured.subject,
captured.filePath,
);
const { cleanupGroup } = captured;
cleanupGroup.bindings -= 1;
let cleanupFailure;
if (cleanupGroup.bindings === 0) {
regularFileBindingGroups.delete(cleanupGroup.identityKey);
// A staging registry and its publication transaction can bind the same
// inode independently. SMB may keep a retired name visible until every
// descriptor closes, so cleanup belongs to the inode's last binding.
for (const directory of cleanupGroup.deferredCleanupDirectories) {
const cleanup = removeEmptyQuarantine(directory, { retry: true });
cleanupFailure ||= cleanup;
}
}
if (failure || cleanupFailure) return failure || cleanupFailure;
return relation('released', `${captured.subject}-binding-released`, {
filePath: captured.filePath,
});
}
function createRemovalQuarantine(parentPath) {
for (let attempt = 0; attempt < 8; attempt += 1) {
const directory = path.join(
parentPath,
`.archify-remove-${randomBytes(16).toString('hex')}`,
);
try {
fs.mkdirSync(directory, { mode: 0o700 });
return { status: 'created', directory };
} catch (error) {
if (error?.code !== 'EEXIST') {
return filesystemFailure('removal-quarantine-create-failed', error, {
parentPath,
});
}
}
}
return relation('unknown', 'removal-quarantine-name-exhausted', { parentPath });
}
function removeEmptyQuarantine(directory, { retry = false } = {}) {
let failure;
try {
removeEmptyDirectoryWithRetry(directory, { retry });
return null;
} catch (error) {
failure = error;
}
return filesystemFailure('removal-quarantine-cleanup-failed', failure, {
recoveryDirectory: directory,
});
}
function deferEmptyQuarantineCleanup(binding, cleanup) {
if (cleanup?.reason?.code !== 'removal-quarantine-cleanup-failed'
|| cleanup.reason.systemCode !== 'ENOTEMPTY') return false;
const captured = regularFileBindings.get(binding);
if (!captured) return false;
captured.cleanupGroup.deferredCleanupDirectories.add(cleanup.reason.recoveryDirectory);
return true;
}
function removalRecovery(subject, code, filePath, quarantineDirectory, quarantineFile, error) {
return {
status: 'recovery-required',
reason: {
code: `${subject}-${code}`,
filePath,
...(typeof error?.code === 'string' ? { systemCode: error.code } : {}),
...(error?.message ? { message: error.message } : {}),
},
recoveryDirectory: quarantineDirectory,
recoveryFile: quarantineFile,
target: filePath,
};
}
function decimal(value) {
return value.toString();
}
function parseDecimal(value) {
if (typeof value !== 'string' || !/^(?:0|[1-9]\d*)$/.test(value)) return null;
try {
return BigInt(value);
} catch {
return null;
}
}
function parseSafeInteger(value) {
return Number.isSafeInteger(value) && value >= 0 ? value : null;
}
function serializeRequestedEntry(entry) {
if (entry?.kind === 'absent') return { kind: 'absent' };
if (entry?.kind !== 'existing' || typeof entry.entryType !== 'string'
|| typeof entry.device !== 'bigint' || typeof entry.inode !== 'bigint') {
return null;
}
return {
kind: 'existing',
entryType: entry.entryType,
device: decimal(entry.device),
inode: decimal(entry.inode),
...(entry.entryType === 'symbolic-link' ? {
changedAtNs: decimal(entry.changedAtNs),
createdAtNs: decimal(entry.createdAtNs),
} : {}),
};
}
function createPublicationRecoveryRecord(directory, snapshot, previous) {
const requestedEntry = serializeRequestedEntry(snapshot?.requestedEntry);
const slot = snapshot?.slot;
if (!requestedEntry || !slot || typeof snapshot?.requestedPath !== 'string'
|| typeof snapshot?.requestedEntryPolicy !== 'string'
|| typeof slot.commitPath !== 'string' || typeof slot.parentPath !== 'string'
|| typeof slot.name !== 'string' || typeof slot.parentDevice !== 'bigint'
|| typeof slot.parentInode !== 'bigint' || !previous?.identity
|| !previous?.content || !Number.isSafeInteger(previous.mode)) {
return relation('unknown', 'publication-recovery-record-input-invalid');
}
const recordPath = path.join(directory, publicationRecoveryRecordName);
let directoryMetadata;
let parentMetadata;
try {
directoryMetadata = fs.lstatSync(directory, { bigint: true });
parentMetadata = fs.statSync(path.dirname(directory), { bigint: true });
} catch (error) {
return filesystemFailure('publication-recovery-directory-inspection-failed', error, {
recoveryDirectory: directory,
});
}
if (!directoryMetadata.isDirectory() || directoryMetadata.ino === 0n
|| !parentMetadata.isDirectory()
|| parentMetadata.dev !== slot.parentDevice || parentMetadata.ino !== slot.parentInode
|| !/^\.archify-remove-[a-f\d]{32}$/.test(path.basename(directory))) {
return relation('unknown', 'publication-recovery-directory-invalid', {
recoveryDirectory: directory,
});
}
const record = {
version: publicationRecoveryRecordVersion,
kind: 'archify-retired-output-recovery',
backup: {
name: 'previous',
sha256: previous.content.sha256,
bytes: previous.content.bytes,
mode: previous.mode,
device: decimal(previous.identity.device),
inode: decimal(previous.identity.inode),
},
recovery: {
name: path.basename(directory),
device: decimal(directoryMetadata.dev),
inode: decimal(directoryMetadata.ino),
},
target: {
requestedPath: snapshot.requestedPath,
requestedEntryPolicy: snapshot.requestedEntryPolicy,
requestedEntry,
commitPath: slot.commitPath,
parentPath: slot.parentPath,
parentDevice: decimal(slot.parentDevice),
parentInode: decimal(slot.parentInode),
name: slot.name,
},
};
const bytes = Buffer.from(`${JSON.stringify(record)}\n`);
let descriptor;
let writeFailure;
try {
descriptor = fs.openSync(
recordPath,
fs.constants.O_WRONLY | fs.constants.O_CREAT | fs.constants.O_EXCL,
0o600,
);
let offset = 0;
while (offset < bytes.byteLength) {
const wrote = fs.writeSync(descriptor, bytes, offset, bytes.byteLength - offset);
if (wrote <= 0) throw Object.assign(new Error('short recovery record write'), { code: 'EIO' });
offset += wrote;
}
fs.fsyncSync(descriptor);
} catch (error) {
writeFailure = error;
} finally {
if (descriptor !== undefined) {
try {
fs.closeSync(descriptor);
} catch (error) {
writeFailure ||= error;
}
}
}
if (writeFailure) {
return filesystemFailure('publication-recovery-record-write-failed', writeFailure, {
recoveryDirectory: directory,
recoveryFile: recordPath,
});
}
// POSIX requires the parent directory entry to be synced separately. Do not
// claim a kill-recovery record is durable where the platform cannot do that.
if (process.platform !== 'win32') {
let directoryDescriptor;
let directoryFailure;
try {
directoryDescriptor = fs.openSync(directory, fs.constants.O_RDONLY);
fs.fsyncSync(directoryDescriptor);
} catch (error) {
directoryFailure = error;
} finally {
if (directoryDescriptor !== undefined) {
try {
fs.closeSync(directoryDescriptor);
} catch (error) {
directoryFailure ||= error;
}
}
}
if (directoryFailure) {
return filesystemFailure('publication-recovery-record-directory-sync-failed', directoryFailure, {
recoveryDirectory: directory,
recoveryFile: recordPath,
});
}
}
const captured = captureRegularFileBinding(recordPath, {
subject: 'publication-recovery-record',
expectedSha256: createHash('sha256').update(bytes).digest('hex'),
expectedBytes: bytes.byteLength,
// Windows reports a synthetic POSIX mode whose read bits cannot represent
// the private ACL established by the exclusive create above.
expectedMode: process.platform === 'win32' ? undefined : 0o600,
expectedLinks: 1,
});
if (captured.status !== 'captured') {
return {
...captured,
recoveryDirectory: directory,
recoveryFile: recordPath,
};
}
return {
status: 'created',
recordPath,
binding: captured.binding,
};
}
function discardPublicationRecoveryRecord(record) {
if (!record?.binding || typeof record.recordPath !== 'string') return null;
let removed;
let released;
try {
removed = quarantineRemoveRegularFileBinding(record.binding, record.recordPath, {
subject: 'publication-recovery-record',
expectedLinks: 1,
});
} finally {
released = releaseRegularFileBinding(record.binding);
}
if (released.status !== 'released') return released;
return removed.status === 'removed' ? null : removed;
}
function releasePublicationRecoveryRecord(record) {
if (!record?.binding) return null;
const released = releaseRegularFileBinding(record.binding);
return released.status === 'released' ? null : released;
}
/**
* Remove a public regular-file name without a verify-to-unlink race. The
* public entry is first moved into an unpredictable private directory and is
* deleted only after the caller's still-open binding proves that the moved
* inode, mode and bytes are the owned entry. If the move captured a successor,
* restore it with a no-clobber hard link or retain it as recovery material.
* The caller retains ownership of `binding` and must release it separately.
*/
export function quarantineRemoveRegularFileBinding(binding, filePath, {
subject = 'public-entry',
expectedLinks = 1,
} = {}) {
if (!validExpectedLinks(expectedLinks)) {
return relation('unknown', 'invalid-regular-file-binding-expectation');
}
const resolvedPath = path.resolve(filePath);
const beforeMove = verifyRegularFileBinding(binding, {
filePath: resolvedPath,
expectedLinks,
});
if (beforeMove.status !== 'match') return beforeMove;
const quarantine = createRemovalQuarantine(path.dirname(resolvedPath));
if (quarantine.status !== 'created') return quarantine;
const quarantineFile = path.join(quarantine.directory, path.basename(resolvedPath));
const removeEmpty = () => removeEmptyQuarantine(quarantine.directory);
const removeEmptyAfterFileRemoval = () => {
const cleanup = removeEmpty();
return cleanup && deferEmptyQuarantineCleanup(binding, cleanup) ? null : cleanup;
};
try {
fs.renameSync(resolvedPath, quarantineFile);
} catch (error) {
const cleanup = removeEmpty();
return cleanup || filesystemFailure(`${subject}-quarantine-move-failed`, error, {
filePath: resolvedPath,
});
}
const moved = verifyRegularFileBinding(binding, {
filePath: quarantineFile,
expectedLinks,
});
if (moved.status === 'match') {
try {
fs.unlinkSync(quarantineFile);
} catch (error) {
return removalRecovery(
subject,
'quarantine-cleanup-failed',
resolvedPath,
quarantine.directory,
quarantineFile,
error,
);
}
const cleanup = removeEmptyAfterFileRemoval();
return cleanup || relation('removed', `${subject}-removed`, { filePath: resolvedPath });
}
let displaced;
try {
displaced = fs.lstatSync(quarantineFile, { bigint: true });
} catch (error) {
return removalRecovery(
subject,
'replacement-inspection-failed',
resolvedPath,
quarantine.directory,
quarantineFile,
error,
);
}
if (displaced.ino === 0n || displaced.nlink === 0n) {
return removalRecovery(
subject,
'replacement-identity-unavailable',
resolvedPath,
quarantine.directory,
quarantineFile,
);
}
try {
fs.linkSync(quarantineFile, resolvedPath);
} catch (error) {
return removalRecovery(
subject,
error?.code === 'EEXIST' ? 'replacement-restore-blocked' : 'replacement-restore-failed',
resolvedPath,
quarantine.directory,
quarantineFile,
error,
);
}
let restored;
let retained;
try {
restored = fs.lstatSync(resolvedPath, { bigint: true });
retained = fs.lstatSync(quarantineFile, { bigint: true });
} catch (error) {
return removalRecovery(
subject,
'replacement-restore-verification-failed',
resolvedPath,
quarantine.directory,
quarantineFile,
error,
);
}
if (restored.dev !== displaced.dev || restored.ino !== displaced.ino
|| retained.dev !== displaced.dev || retained.ino !== displaced.ino
|| restored.nlink !== displaced.nlink + 1n
|| retained.nlink !== displaced.nlink + 1n) {
return removalRecovery(
subject,
'replacement-restore-identity-changed',
resolvedPath,
quarantine.directory,
quarantineFile,
);
}
try {
fs.unlinkSync(quarantineFile);
} catch (error) {
return removalRecovery(
subject,
'replacement-quarantine-cleanup-failed',
resolvedPath,
quarantine.directory,
quarantineFile,
error,
);
}
try {
restored = fs.lstatSync(resolvedPath, { bigint: true });
} catch (error) {
const cleanup = removeEmptyAfterFileRemoval();
return cleanup || filesystemFailure(
`${subject}-replacement-final-verification-failed`,
error,
{ filePath: resolvedPath },
);
}
if (restored.dev !== displaced.dev || restored.ino !== displaced.ino
|| restored.nlink !== displaced.nlink) {
const cleanup = removeEmptyAfterFileRemoval();
return cleanup || relation('different', `${subject}-replacement-final-identity-changed`, {
filePath: resolvedPath,
});
}
const cleanup = removeEmptyAfterFileRemoval();
return cleanup || relation('preserved', `${subject}-replacement-restored`, {
filePath: resolvedPath,
priorState: moved.reason,
});
}
/**
* Create a no-clobber hard-link backup of a bound public file, then remove the
* public name through the quarantine protocol above. The backup is reported as
* verified only after both names have been reconciled with the open binding.
*/
export function backupPublicRegularFileBinding(binding, filePath, backupPath, {
subject = 'public-entry',
} = {}) {
const resolvedPath = path.resolve(filePath);
const resolvedBackup = path.resolve(backupPath);
const beforeLink = verifyRegularFileBinding(binding, {
filePath: resolvedPath,
expectedLinks: 1,
});
if (beforeLink.status !== 'match') {
return { ...beforeLink, backupCreated: false, backupVerified: false };
}
try {
fs.linkSync(resolvedPath, resolvedBackup);
} catch (error) {
return {
...filesystemFailure(`${subject}-backup-link-failed`, error, {
filePath: resolvedPath,
backupPath: resolvedBackup,
}),
backupCreated: false,
backupVerified: false,
};
}
for (const linkedPath of [resolvedPath, resolvedBackup]) {
const linked = verifyRegularFileBinding(binding, {
filePath: linkedPath,
expectedLinks: 2,
});
if (linked.status !== 'match') {
return {
status: 'recovery-required',
reason: {
code: `${subject}-backup-binding-mismatch`,
filePath: resolvedPath,
backupPath: resolvedBackup,
linkedState: linked.reason,
},
recoveryDirectory: path.dirname(resolvedBackup),
recoveryFile: resolvedBackup,
target: resolvedPath,
backupCreated: true,
backupVerified: false,
};
}
}
const removed = quarantineRemoveRegularFileBinding(binding, resolvedPath, {
subject,
expectedLinks: 2,
});
if (removed.status !== 'removed') {
return {
...removed,
backupPath: resolvedBackup,
backupCreated: true,
backupVerified: true,
};
}
const finalized = verifyRegularFileBinding(binding, {
filePath: resolvedBackup,
expectedLinks: 1,
});
if (finalized.status !== 'match') {
return {
status: 'recovery-required',
reason: {
code: `${subject}-backup-finalization-failed`,
filePath: resolvedPath,
backupPath: resolvedBackup,
backupState: finalized.reason,
},
recoveryDirectory: path.dirname(resolvedBackup),
recoveryFile: resolvedBackup,
target: resolvedPath,
backupCreated: true,
backupVerified: false,
};
}
return {
status: 'backed-up',
reason: {
code: `${subject}-backed-up`,
filePath: resolvedPath,
backupPath: resolvedBackup,
},
backupPath: resolvedBackup,
backupCreated: true,
backupVerified: true,
};
}
/**
* Remove a hard-link name that this process just introduced while preserving
* the source claimant. This is the rollback path when a staged pathname was
* swapped after its expected binding was verified but before `linkSync` used
* that pathname.
*/
export function quarantineRemoveLinkedRegularFileAlias(sourcePath, aliasPath, {
subject = 'linked-claimant',
} = {}) {
const source = path.resolve(sourcePath);
const alias = path.resolve(aliasPath);
const captured = captureRegularFileBinding(source, {
subject,
expectedLinks: 2,
});
if (captured.status !== 'captured') return captured;
let result;
let released;
try {
const aliasMatches = verifyRegularFileBinding(captured.binding, {
filePath: alias,
expectedLinks: 2,
});
if (aliasMatches.status !== 'match') {
result = aliasMatches;
} else {
const removal = quarantineRemoveRegularFileBinding(captured.binding, alias, {
subject,
expectedLinks: 2,
});
if (removal.status !== 'removed') {
result = removal;
} else {
const sourceRemains = verifyRegularFileBinding(captured.binding, {
filePath: source,
expectedLinks: 1,
});
result = sourceRemains.status === 'match' ? removal : sourceRemains;
}
}
} finally {
released = releaseRegularFileBinding(captured.binding);
}
if (released.status !== 'released') {
return {
...released,
removalStatus: result?.status,
...(result?.recoveryDirectory ? {
recoveryDirectory: result.recoveryDirectory,
recoveryFile: result.recoveryFile,
target: result.target,
} : {}),
};
}
return result;
}
function removePublishedBindingName(binding, filePath, subject) {
for (const expectedLinks of [2, 1]) {
const matches = verifyRegularFileBinding(binding, { filePath, expectedLinks });
if (matches.status === 'match') {
return quarantineRemoveRegularFileBinding(binding, filePath, {
subject,
expectedLinks,
});
}
}
return relation('preserved', `${subject}-identity-changed`, { filePath });
}
function restorePublicationBackup(binding, backupPath, commitPath, subject) {
const backupMatches = verifyRegularFileBinding(binding, {
filePath: backupPath,
expectedLinks: 1,
});
if (backupMatches.status !== 'match') return backupMatches;
try {
fs.linkSync(backupPath, commitPath);
} catch (error) {
return filesystemFailure(
error?.code === 'EEXIST'
? `${subject}-restore-blocked`
: `${subject}-restore-failed`,
error,
{ backupPath, commitPath },
);
}
for (const linkedPath of [backupPath, commitPath]) {
const linked = verifyRegularFileBinding(binding, {
filePath: linkedPath,
expectedLinks: 2,
});
if (linked.status !== 'match') return linked;
}
const retired = quarantineRemoveRegularFileBinding(binding, backupPath, {
subject: `${subject}-backup`,
expectedLinks: 2,
});
if (retired.status !== 'removed') return retired;
return verifyRegularFileBinding(binding, {
filePath: commitPath,
expectedLinks: 1,
});
}
/**
* Publish a captured candidate without ever replacing an unverified public
* entry. Existing output is retained through a bound private backup; the new
* name is created with a no-clobber hard link while the candidate descriptor
* remains open. Both the staged and public names are then verified through
* that descriptor before the staged name is retired via quarantine.
* Replacing an existing entry is recoverable but not crash-atomic: the public
* name is absent between retiring the verified previous name and linking the
* candidate. Portable Node.js exposes no replacement compare-and-swap that
* also preserves a late claimant.
*
* The caller owns `binding` and must release it after this function returns.
*/
export function publishRegularFileBinding(binding, candidatePath, snapshot, {
subject = 'candidate',
} = {}) {
const candidate = path.resolve(candidatePath);
const commitPath = snapshot?.slot?.commitPath;
if (typeof commitPath !== 'string') {
return relation('unknown', `${subject}-publication-snapshot-unavailable`);
}
const beforePublish = verifyAtomicOutput(snapshot);
if (beforePublish.status !== 'match') return beforePublish;
const candidateMatches = verifyRegularFileBinding(binding, {
filePath: candidate,
expectedLinks: 1,
});
if (candidateMatches.status !== 'match') return candidateMatches;
let previousBinding;
let recoveryDirectory;
let backupPath;
let recoveryRecord;
let previousBackedUp = false;
const finishPrevious = () => {
if (!previousBinding) return null;
const released = releaseRegularFileBinding(previousBinding);
previousBinding = undefined;
return released.status === 'released' ? null : released;
};
const cleanupRecoveryDirectory = () => {
if (!recoveryDirectory) return null;
const cleanup = removeEmptyQuarantine(recoveryDirectory);
if (!cleanup) recoveryDirectory = undefined;
return cleanup;
};
const restorePrevious = () => {
if (!previousBinding || !previousBackedUp) return null;
return restorePublicationBackup(
previousBinding,
backupPath,
commitPath,
'previous-output',
);
};
const rollback = (failure) => {
let publicRemoval = removePublishedBindingName(
binding,
commitPath,
`${subject}-publication`,
);
if (publicRemoval.status === 'preserved') {
const claimantRemoval = quarantineRemoveLinkedRegularFileAlias(
candidate,
commitPath,
{ subject: `${subject}-publication-claimant` },
);
if (claimantRemoval.status === 'removed') publicRemoval = claimantRemoval;
}
const restored = restorePrevious();
const recordCleanup = restored?.status === 'match'
? discardPublicationRecoveryRecord(recoveryRecord)
: releasePublicationRecoveryRecord(recoveryRecord);
recoveryRecord = undefined;
const released = finishPrevious();
const directoryCleanup = cleanupRecoveryDirectory();
return {
...failure,
...(publicRemoval.status !== 'removed' && publicRemoval.status !== 'absent'
? { publicState: publicRemoval.reason } : {}),
...(restored && restored.status !== 'match' ? { restoreState: restored.reason } : {}),
...(recordCleanup ? { recoveryRecordState: recordCleanup.reason } : {}),
...(released ? { releaseState: released.reason } : {}),
...(directoryCleanup ? {
recoveryDirectory: directoryCleanup.reason?.recoveryDirectory || recoveryDirectory,
} : {}),
...((restored && restored.status !== 'match') || recordCleanup || directoryCleanup
? { recoveryFile: backupPath } : {}),
};
};
if (snapshot.target.kind === 'file') {
const previous = captureRegularFileBinding(commitPath, {
subject: 'previous-output',
expectedIdentity: {
device: snapshot.target.device,
inode: snapshot.target.inode,
},
expectedMode: snapshot.target.mode,
expectedLinks: 1,
});
if (previous.status !== 'captured') return previous;
previousBinding = previous.binding;
const quarantine = createRemovalQuarantine(path.dirname(commitPath));
if (quarantine.status !== 'created') {
const released = finishPrevious();
return released || quarantine;
}
recoveryDirectory = quarantine.directory;
backupPath = path.join(recoveryDirectory, 'previous');
const recovery = createPublicationRecoveryRecord(recoveryDirectory, snapshot, previous);
if (recovery.status !== 'created') {
const released = finishPrevious();
const directoryCleanup = cleanupRecoveryDirectory();
return {
...recovery,
...(recoveryDirectory ? { recoveryDirectory } : {}),
...(released ? { releaseState: released.reason } : {}),
...(directoryCleanup ? { directoryCleanupState: directoryCleanup.reason } : {}),
};
}
recoveryRecord = recovery;
const backup = backupPublicRegularFileBinding(
previousBinding,
commitPath,
backupPath,
{ subject: 'previous-output' },
);
previousBackedUp = backup.status === 'backed-up';
if (!previousBackedUp) {
const recordCleanup = backup.backupCreated
? releasePublicationRecoveryRecord(recoveryRecord)
: discardPublicationRecoveryRecord(recoveryRecord);
recoveryRecord = undefined;
const released = finishPrevious();
const directoryCleanup = backup.backupCreated ? null : cleanupRecoveryDirectory();
return {
...backup,
...(recordCleanup ? { recoveryRecordState: recordCleanup.reason } : {}),
...(released ? { releaseState: released.reason } : {}),
...(directoryCleanup ? { directoryCleanupState: directoryCleanup.reason } : {}),
};
}
}
try {
fs.linkSync(candidate, commitPath);
} catch (error) {
return rollback(filesystemFailure(
error?.code === 'EEXIST'
? 'target-created-during-commit'
: `${subject}-publication-link-failed`,
error,
{ candidatePath: candidate, commitPath },
));
}
const published = verifyRegularFileBinding(binding, {
filePath: commitPath,
expectedLinks: 2,
});
const staged = verifyRegularFileBinding(binding, {
filePath: candidate,
expectedLinks: 2,
});
if (published.status !== 'match' || staged.status !== 'match') {
return rollback(relation('different', `${subject}-identity-changed`, {
candidatePath: candidate,
commitPath,
publishedState: published.reason,
stagedState: staged.reason,
}));
}
const retired = quarantineRemoveRegularFileBinding(binding, candidate, {
subject: `${subject}-staging`,
expectedLinks: 2,
});
if (retired.status !== 'removed' && retired.status !== 'preserved') {
return rollback(retired);
}
const final = verifyRegularFileBinding(binding, {
filePath: commitPath,
expectedLinks: 1,
});
if (final.status !== 'match') return rollback(final);
let cleanupWarning = retired.status === 'preserved' ? retired : undefined;
if (previousBinding) {
const backupRemoval = quarantineRemoveRegularFileBinding(
previousBinding,
backupPath,
{ subject: 'previous-output-backup', expectedLinks: 1 },
);
if (backupRemoval.status !== 'removed') cleanupWarning = backupRemoval;
const recordCleanup = backupRemoval.status === 'removed'
? discardPublicationRecoveryRecord(recoveryRecord)
: releasePublicationRecoveryRecord(recoveryRecord);
recoveryRecord = undefined;
cleanupWarning ||= recordCleanup;
}
const released = finishPrevious();
const directoryCleanup = cleanupRecoveryDirectory();
cleanupWarning ||= released || directoryCleanup;
const recoveryFile = cleanupWarning?.recoveryFile
|| (retired.status === 'preserved' ? candidate : undefined)
|| (recoveryDirectory ? backupPath : undefined);
return {
status: cleanupWarning ? 'committed-with-warning' : 'committed',
reason: {
code: `${subject}-published`,
candidatePath: candidate,
commitPath,
...(retired.status === 'preserved' ? { stagedSuccessorPreserved: true } : {}),
},
...(cleanupWarning ? {
cleanupState: cleanupWarning.reason,
...(recoveryDirectory ? { recoveryDirectory } : {}),
...(recoveryFile ? { recoveryFile } : {}),
} : {}),
};
}
/** Remove only the directory entry that still names a caller-owned inode. */
export function removeOwnedRegularFile(filePath, identity, { subject = 'candidate' } = {}) {
const resolvedPath = path.resolve(filePath);
let expectedLinks = 1;
let captured = captureRegularFileBinding(resolvedPath, {
subject,
expectedIdentity: identity,
expectedLinks,
});
const reportedLinks = Number(captured.reason?.links);
if (captured.status === 'unsupported'
&& captured.reason?.code === `${subject}-hardlinked`
&& Number.isSafeInteger(reportedLinks)
&& reportedLinks > 1) {
expectedLinks = reportedLinks;
captured = captureRegularFileBinding(resolvedPath, {
subject,
expectedIdentity: identity,
expectedLinks,
});
}
if (captured.status !== 'captured') {
if (captured.reason?.systemCode === 'ENOENT') {
return relation('absent', `${subject}-already-absent`, { filePath: resolvedPath });
}
if (captured.status === 'different' || captured.status === 'unsupported') {
return relation('preserved', `${subject}-identity-changed`, {
filePath: resolvedPath,
priorState: captured.reason,
});
}
return captured;
}
let removal;
let released;
try {
removal = quarantineRemoveRegularFileBinding(captured.binding, resolvedPath, {
subject,
expectedLinks,
});
} finally {
released = releaseRegularFileBinding(captured.binding);
}
if (released.status !== 'released') {
return {
...released,
removalStatus: removal?.status,
...(removal?.recoveryDirectory ? {
recoveryDirectory: removal.recoveryDirectory,
recoveryFile: removal.recoveryFile,
target: removal.target,
} : {}),
};
}
return removal;
}
function captureWriteSlot(requestedPath) {
let commitPath;
try {
commitPath = canonicalFuturePath(requestedPath);
} catch (error) {
const diagnostic = error?.archifyDiagnostics?.[0];
return relation('unknown', 'canonicalization-failed', {
...(diagnostic?.code ? { diagnosticCode: diagnostic.code } : {}),
...(diagnostic?.evidence?.relation ? { relation: diagnostic.evidence.relation } : {}),
});
}
const parentPath = path.dirname(commitPath);
let parent;
try {
parent = fs.statSync(parentPath, { bigint: true });
} catch (error) {
return filesystemFailure('parent-inspection-failed', error, { commitPath, parentPath });
}
if (!parent.isDirectory()) {
return relation('unknown', 'parent-not-directory', { commitPath, parentPath });
}
if (parent.ino === 0n) {
return relation('unknown', 'parent-identity-unavailable', { commitPath, parentPath });
}
return {
status: 'captured',
slot: {
commitPath,
parentPath,
name: path.basename(commitPath),
parentDevice: parent.dev,
parentInode: parent.ino,
},
};
}
function captureTarget(commitPath) {
let metadata;
try {
// The canonical commit path names the directory entry that rename will
// replace. Never follow a link introduced after canonicalization.
metadata = fs.lstatSync(commitPath, { bigint: true });
} catch (error) {
if (error.code === 'ENOENT') {
return { status: 'captured', target: { kind: 'absent' }, mode: null };
}
return filesystemFailure('target-inspection-failed', error, { commitPath });
}
const type = entryType(metadata);
if (type !== 'file') {
return relation('unsupported', 'target-not-regular-file', { commitPath, entryType: type });
}
const inspected = captureRegularFileHandle(commitPath, metadata, 'target');
if (inspected.status !== 'captured') return inspected;
metadata = inspected.metadata;
return {
status: 'captured',
target: {
kind: 'file',
device: metadata.dev,
inode: metadata.ino,
mode: Number(metadata.mode & 0o777n),
},
mode: Number(metadata.mode & 0o777n),
};
}
function captureRequestedEntry(requestedPath, policy) {
let metadata;
try {
metadata = fs.lstatSync(requestedPath, { bigint: true });
} catch (error) {
if (error.code === 'ENOENT') {
return { status: 'captured', entry: { kind: 'absent' } };
}
return filesystemFailure('requested-entry-inspection-failed', error, { requestedPath });
}
const type = entryType(metadata);
if (policy === 'regular-or-absent' && type !== 'file') {
return relation('unsupported', type === 'symbolic-link'
? 'requested-entry-symbolic-link'
: 'requested-entry-not-regular-file', {
requestedPath,
entryType: type,
});
}
if (metadata.ino === 0n) {
return relation('unknown', 'requested-entry-identity-unavailable', { requestedPath });
}
if (policy === 'regular-or-absent') {
const inspected = captureRegularFileHandle(requestedPath, metadata, 'requested-entry');
if (inspected.status !== 'captured') return inspected;
metadata = inspected.metadata;
}
return {
status: 'captured',
entry: {
kind: 'existing',
entryType: type,
device: metadata.dev,
inode: metadata.ino,
// An unlinked symlink's inode can be reused immediately. Its target can
// stay the same while the requested directory entry is a new object.
// Reading the link only changes atime, so these no-follow timestamps
// distinguish that replacement without tracking target-file writes.
...(type === 'symbolic-link' ? {
changedAtNs: metadata.ctimeNs,
createdAtNs: metadata.birthtimeNs,
} : {}),
},
};
}
function requestedEntryMatches(left, right) {
if (left.kind !== right.kind) return false;
return left.kind === 'absent'
|| (left.entryType === right.entryType
&& left.device === right.device
&& left.inode === right.inode
&& (left.entryType !== 'symbolic-link'
|| (left.changedAtNs === right.changedAtNs
&& left.createdAtNs === right.createdAtNs)));
}
/**
* Capture the physical directory-entry slot and target identity used by a
* verified publication. Hard links are intentionally unsupported: replacing
* one name cannot safely update its unknown sibling names.
* `regular-or-absent` additionally rejects requested-entry symlinks and special
* nodes for sidecars whose public name itself must never be followed.
*/
export function captureAtomicOutput(outputPath, { requestedEntryPolicy = 'followable-alias' } = {}) {
if (!['followable-alias', 'regular-or-absent'].includes(requestedEntryPolicy)) {
return relation('unknown', 'invalid-requested-entry-policy', { requestedEntryPolicy });
}
const requestedPath = path.resolve(outputPath);
const requestedEntry = captureRequestedEntry(requestedPath, requestedEntryPolicy);
if (requestedEntry.status !== 'captured') return requestedEntry;
const slot = captureWriteSlot(requestedPath);
if (slot.status !== 'captured') return slot;
const target = captureTarget(slot.slot.commitPath);
if (target.status !== 'captured') return target;
const confirmedRequestedEntry = captureRequestedEntry(requestedPath, requestedEntryPolicy);
if (confirmedRequestedEntry.status !== 'captured') return confirmedRequestedEntry;
if (!requestedEntryMatches(confirmedRequestedEntry.entry, requestedEntry.entry)) {
return relation('unknown', 'requested-entry-changed-during-inspection', { requestedPath });
}
return {
status: 'captured',
commitPath: slot.slot.commitPath,
mode: target.mode,
snapshot: {
requestedPath,
requestedEntryPolicy,
requestedEntry: requestedEntry.entry,
slot: slot.slot,
target: target.target,
},
};
}
/** Re-resolve and verify the exact write slot plus its absent/file identity. */
export function verifyAtomicOutput(snapshot) {
const currentRequestedEntry = captureRequestedEntry(
snapshot.requestedPath,
snapshot.requestedEntryPolicy || 'followable-alias',
);
if (currentRequestedEntry.status !== 'captured') return currentRequestedEntry;
if (!requestedEntryMatches(currentRequestedEntry.entry, snapshot.requestedEntry)) {
return relation('different', 'requested-entry-changed', {
requestedPath: snapshot.requestedPath,
previousKind: snapshot.requestedEntry.kind === 'absent'
? 'absent'
: snapshot.requestedEntry.entryType,
currentKind: currentRequestedEntry.entry.kind === 'absent'
? 'absent'
: currentRequestedEntry.entry.entryType,
});
}
const currentSlot = captureWriteSlot(snapshot.requestedPath);
if (currentSlot.status !== 'captured') return currentSlot;
const previousSlot = snapshot.slot;
if (currentSlot.slot.parentDevice !== previousSlot.parentDevice
|| currentSlot.slot.parentInode !== previousSlot.parentInode
|| currentSlot.slot.name !== previousSlot.name) {
return relation('different', 'write-slot-changed', {
previousCommitPath: previousSlot.commitPath,
currentCommitPath: currentSlot.slot.commitPath,
});
}
const currentTarget = captureTarget(previousSlot.commitPath);
if (currentTarget.status !== 'captured') return currentTarget;
const previousTarget = snapshot.target;
if (currentTarget.target.kind !== previousTarget.kind) {
return relation('different', 'target-existence-changed', {
commitPath: previousSlot.commitPath,
previousKind: previousTarget.kind,
currentKind: currentTarget.target.kind,
});
}
if (previousTarget.kind === 'file'
&& (currentTarget.target.device !== previousTarget.device
|| currentTarget.target.inode !== previousTarget.inode)) {
return relation('different', 'target-identity-changed', {
commitPath: previousSlot.commitPath,
});
}
if (previousTarget.kind === 'file'
&& currentTarget.target.mode !== previousTarget.mode) {
return relation('different', 'target-mode-changed', {
commitPath: previousSlot.commitPath,
previousMode: previousTarget.mode,
currentMode: currentTarget.target.mode,
});
}
return relation('match', 'atomic-output-match', { commitPath: previousSlot.commitPath });
}
function parsePublicationRecoveryRecord(buffer) {
if (!Buffer.isBuffer(buffer) || buffer.byteLength > publicationRecoveryRecordMaxBytes) {
return relation('unknown', 'publication-recovery-record-too-large');
}
let parsed;
try {
parsed = JSON.parse(buffer.toString('utf8'));
} catch (error) {
return filesystemFailure('publication-recovery-record-invalid-json', error);
}
const backup = parsed?.backup;
const recovery = parsed?.recovery;
const target = parsed?.target;
const requestedEntry = target?.requestedEntry;
const validEntry = requestedEntry?.kind === 'absent'
|| (requestedEntry?.kind === 'existing'
&& typeof requestedEntry.entryType === 'string'
&& parseDecimal(requestedEntry.device) !== null
&& parseDecimal(requestedEntry.inode) !== null
&& (requestedEntry.entryType !== 'symbolic-link'
|| (parseDecimal(requestedEntry.changedAtNs) !== null
&& parseDecimal(requestedEntry.createdAtNs) !== null)));
const valid = parsed?.version === publicationRecoveryRecordVersion
&& parsed?.kind === 'archify-retired-output-recovery'
&& backup?.name === 'previous'
&& typeof backup.sha256 === 'string' && /^[a-f\d]{64}$/i.test(backup.sha256)
&& parseSafeInteger(backup.bytes) !== null
&& Number.isSafeInteger(backup.mode) && backup.mode >= 0 && backup.mode <= 0o777
&& parseDecimal(backup.device) !== null && parseDecimal(backup.inode) !== null
&& typeof recovery?.name === 'string' && /^\.archify-remove-[a-f\d]{32}$/.test(recovery.name)
&& parseDecimal(recovery.device) !== null
&& parseDecimal(recovery.inode) !== null
&& typeof target?.requestedPath === 'string' && path.isAbsolute(target.requestedPath)
&& typeof target.requestedEntryPolicy === 'string'
&& ['followable-alias', 'regular-or-absent'].includes(target.requestedEntryPolicy)
&& validEntry
&& typeof target.commitPath === 'string' && path.isAbsolute(target.commitPath)
&& typeof target.parentPath === 'string' && path.isAbsolute(target.parentPath)
// path-contract-allow: lexical-capability -- A record must exactly decompose the captured canonical target spelling.
&& typeof target.name === 'string' && target.name === path.basename(target.commitPath)
// path-contract-allow: lexical-capability -- A record must exactly decompose the captured canonical target spelling.
&& target.parentPath === path.dirname(target.commitPath)
&& parseDecimal(target.parentDevice) !== null && parseDecimal(target.parentInode) !== null;
if (!valid) return relation('unknown', 'publication-recovery-record-invalid');
return {
status: 'parsed',
record: {
backup: {
...backup,
device: parseDecimal(backup.device),
inode: parseDecimal(backup.inode),
},
recovery: {
...recovery,
device: parseDecimal(recovery.device),
inode: parseDecimal(recovery.inode),
},
target: {
...target,
parentDevice: parseDecimal(target.parentDevice),
parentInode: parseDecimal(target.parentInode),
requestedEntry: requestedEntry.kind === 'absent' ? requestedEntry : {
...requestedEntry,
device: parseDecimal(requestedEntry.device),
inode: parseDecimal(requestedEntry.inode),
...(requestedEntry.entryType === 'symbolic-link' ? {
changedAtNs: parseDecimal(requestedEntry.changedAtNs),
createdAtNs: parseDecimal(requestedEntry.createdAtNs),
} : {}),
},
},
},
};
}
function verifyPublicationRecoveryDirectory(directory, metadata, record) {
let parentMetadata;
try {
parentMetadata = fs.statSync(path.dirname(directory), { bigint: true });
} catch (error) {
return filesystemFailure('publication-recovery-parent-inspection-failed', error, {
recoveryDirectory: directory,
});
}
// path-contract-allow: lexical-capability -- The generated private-directory component is an exact record-bound capability.
if (path.basename(directory) !== record.recovery.name
|| !parentMetadata.isDirectory()
|| parentMetadata.dev !== record.target.parentDevice
|| parentMetadata.ino !== record.target.parentInode) {
return relation('different', 'publication-recovery-directory-not-target-child', {
recoveryDirectory: directory,
expectedParentPath: record.target.parentPath,
});
}
if (metadata.dev !== record.recovery.device || metadata.ino !== record.recovery.inode) {
return relation('different', 'publication-recovery-directory-identity-changed', {
recoveryDirectory: directory,
});
}
return relation('match', 'publication-recovery-directory-match', {
recoveryDirectory: directory,
});
}
function verifyRetiredPublicationSlot(record) {
const { target } = record;
const slot = captureWriteSlot(target.requestedPath);
if (slot.status !== 'captured') return slot;
// path-contract-allow: lexical-capability -- The recaptured canonical commit spelling must exactly match the recorded capability.
const commitPathChanged = slot.slot.commitPath !== target.commitPath;
// path-contract-allow: lexical-capability -- The recaptured canonical parent spelling must exactly match the recorded capability.
const parentPathChanged = slot.slot.parentPath !== target.parentPath;
if (commitPathChanged
|| parentPathChanged
|| slot.slot.name !== target.name
|| slot.slot.parentDevice !== target.parentDevice
|| slot.slot.parentInode !== target.parentInode) {
return relation('different', 'publication-recovery-slot-changed', {
requestedPath: target.requestedPath,
commitPath: target.commitPath,
});
}
try {
fs.lstatSync(target.commitPath, { bigint: true });
return relation('preserved', 'publication-recovery-target-present', {
commitPath: target.commitPath,
});
} catch (error) {
if (error?.code !== 'ENOENT') {
return filesystemFailure('publication-recovery-target-inspection-failed', error, {
commitPath: target.commitPath,
});
}
}
let requested;
try {
requested = fs.lstatSync(target.requestedPath, { bigint: true });
} catch (error) {
if (error?.code !== 'ENOENT') {
return filesystemFailure('publication-recovery-requested-entry-inspection-failed', error, {
requestedPath: target.requestedPath,
});
}
}
if (target.requestedEntry.kind === 'existing'
&& target.requestedEntry.entryType === 'symbolic-link') {
if (!requested?.isSymbolicLink()
|| requested.dev !== target.requestedEntry.device
|| requested.ino !== target.requestedEntry.inode
|| requested.ctimeNs !== target.requestedEntry.changedAtNs
|| requested.birthtimeNs !== target.requestedEntry.createdAtNs) {
return relation('different', 'publication-recovery-requested-alias-changed', {
requestedPath: target.requestedPath,
});
}
} else if (requested) {
return relation('different', 'publication-recovery-requested-entry-reclaimed', {
requestedPath: target.requestedPath,
});
}
return relation('match', 'publication-recovery-slot-match', {
commitPath: target.commitPath,
});
}
function releaseRecoveryBindings(result, recordBinding, backupBinding) {
const failures = [];
if (backupBinding) {
const released = releaseRegularFileBinding(backupBinding);
if (released.status !== 'released') failures.push(released.reason);
}
if (recordBinding) {
const released = releaseRegularFileBinding(recordBinding);
if (released.status !== 'released') failures.push(released.reason);
}
if (failures.length === 0) return result;
return {
...result,
status: 'recovery-required',
releaseState: failures,
};
}
/**
* Explicitly restore one retired output after a process crash. This is not a
* directory scanner: callers must name the private recovery directory they
* intend to recover. A record is only a claim; the restored byte stream must
* still match its recorded inode, mode, SHA-256 and size, the original parent
* slot and aliases must still resolve identically, and the public name must be
* absent. `linkSync` is deliberately no-clobber, so a later claimant wins.
*/
export function recoverRetiredPublication(recoveryDirectory) {
const directory = path.resolve(recoveryDirectory);
let directoryMetadata;
try {
directoryMetadata = fs.lstatSync(directory, { bigint: true });
} catch (error) {
if (error?.code === 'ENOENT') {
return relation('absent', 'publication-recovery-already-complete', { recoveryDirectory: directory });
}
return filesystemFailure('publication-recovery-directory-inspection-failed', error, {
recoveryDirectory: directory,
});
}
if (!directoryMetadata.isDirectory()) {
return relation('unsupported', 'publication-recovery-directory-not-directory', {
recoveryDirectory: directory,
entryType: entryType(directoryMetadata),
});
}
if (process.platform !== 'win32' && Number(directoryMetadata.mode & 0o077n) !== 0) {
return relation('unsupported', 'publication-recovery-directory-not-private', {
recoveryDirectory: directory,
});
}
const recordPath = path.join(directory, publicationRecoveryRecordName);
let recordMetadata;
try {
recordMetadata = fs.lstatSync(recordPath, { bigint: true });
} catch (error) {
return filesystemFailure('publication-recovery-record-inspection-failed', error, {
recoveryDirectory: directory,
recoveryFile: recordPath,
});
}
if (!recordMetadata.isFile() || recordMetadata.nlink !== 1n
|| recordMetadata.size > BigInt(publicationRecoveryRecordMaxBytes)) {
return relation('unsupported', 'publication-recovery-record-not-private-regular-file', {
recoveryDirectory: directory,
recoveryFile: recordPath,
});
}
const capturedRecord = captureRegularFileBinding(recordPath, {
subject: 'publication-recovery-record',
expectedLinks: 1,
includeContent: true,
});
if (capturedRecord.status !== 'captured') return capturedRecord;
const parsed = parsePublicationRecoveryRecord(capturedRecord.content.buffer);
if (parsed.status !== 'parsed') {
return releaseRecoveryBindings(parsed, capturedRecord.binding);
}
const recoveryDirectoryState = verifyPublicationRecoveryDirectory(
directory,
directoryMetadata,
parsed.record,
);
if (recoveryDirectoryState.status !== 'match') {
return releaseRecoveryBindings({
...recoveryDirectoryState,
recoveryDirectory: directory,
recoveryFile: recordPath,
}, capturedRecord.binding);
}
const slot = verifyRetiredPublicationSlot(parsed.record);
if (slot.status !== 'match') {
return releaseRecoveryBindings({
...slot,
recoveryDirectory: directory,
recoveryFile: recordPath,
}, capturedRecord.binding);
}
const backupPath = path.join(directory, parsed.record.backup.name);
const capturedBackup = captureRegularFileBinding(backupPath, {
subject: 'publication-recovery-backup',
expectedSha256: parsed.record.backup.sha256,
expectedBytes: parsed.record.backup.bytes,
expectedMode: parsed.record.backup.mode,
expectedIdentity: {
device: parsed.record.backup.device,
inode: parsed.record.backup.inode,
},
expectedLinks: 1,
});
if (capturedBackup.status !== 'captured') {
return releaseRecoveryBindings({
...capturedBackup,
recoveryDirectory: directory,
recoveryFile: backupPath,
}, capturedRecord.binding);
}
// This second check narrows the remaining path-based link window. It cannot
// make `linkSync` descriptor-bound, but it avoids linking after an ordinary
// observed parent, alias, target, or backup change.
const beforeLinkSlot = verifyRetiredPublicationSlot(parsed.record);
const beforeLinkBackup = verifyRegularFileBinding(capturedBackup.binding, {
filePath: backupPath,
expectedLinks: 1,
});
if (beforeLinkSlot.status !== 'match' || beforeLinkBackup.status !== 'match') {
return releaseRecoveryBindings({
status: beforeLinkSlot.status === 'match' ? beforeLinkBackup.status : beforeLinkSlot.status,
reason: {
code: 'publication-recovery-pre-link-verification-failed',
slotState: beforeLinkSlot.reason,
backupState: beforeLinkBackup.reason,
},
recoveryDirectory: directory,
recoveryFile: backupPath,
}, capturedRecord.binding, capturedBackup.binding);
}
try {
fs.linkSync(backupPath, parsed.record.target.commitPath);
} catch (error) {
return releaseRecoveryBindings(relation(
error?.code === 'EEXIST' ? 'preserved' : 'unknown',
error?.code === 'EEXIST'
? 'publication-recovery-target-created'
: 'publication-recovery-link-failed',
{
recoveryDirectory: directory,
recoveryFile: backupPath,
commitPath: parsed.record.target.commitPath,
...(typeof error?.code === 'string' ? { systemCode: error.code } : {}),
},
), capturedRecord.binding, capturedBackup.binding);
}
const publicState = verifyRegularFileBinding(capturedBackup.binding, {
filePath: parsed.record.target.commitPath,
expectedLinks: 2,
});
const backupState = verifyRegularFileBinding(capturedBackup.binding, {
filePath: backupPath,
expectedLinks: 2,
});
if (publicState.status !== 'match' || backupState.status !== 'match') {
// We may have introduced an alias to a pathname that was swapped after the
// pre-link checks. Remove only that alias when it is still a verified
// two-link pair; otherwise preserve every uncertain name for inspection.
const linkedAliasCleanup = quarantineRemoveLinkedRegularFileAlias(
backupPath,
parsed.record.target.commitPath,
{ subject: 'publication-recovery-unverified-link' },
);
return releaseRecoveryBindings(relation('recovery-required', 'publication-recovery-link-verification-failed', {
recoveryDirectory: directory,
recoveryFile: backupPath,
commitPath: parsed.record.target.commitPath,
publicState: publicState.reason,
backupState: backupState.reason,
linkedAliasCleanup: linkedAliasCleanup.reason,
}), capturedRecord.binding, capturedBackup.binding);
}
const backupRemoval = quarantineRemoveRegularFileBinding(capturedBackup.binding, backupPath, {
subject: 'publication-recovery-backup',
expectedLinks: 2,
});
if (backupRemoval.status !== 'removed') {
return releaseRecoveryBindings({
...backupRemoval,
status: 'recovered-with-warning',
recoveryDirectory: directory,
recoveryFile: backupPath,
target: parsed.record.target.commitPath,
}, capturedRecord.binding, capturedBackup.binding);
}
const recordCleanup = discardPublicationRecoveryRecord({
recordPath,
binding: capturedRecord.binding,
});
const directoryCleanup = removeEmptyQuarantine(directory);
const result = {
status: recordCleanup || directoryCleanup ? 'recovered-with-warning' : 'recovered',
reason: {
code: 'publication-recovery-restored',
recoveryDirectory: directory,
commitPath: parsed.record.target.commitPath,
},
...(recordCleanup ? { recoveryRecordState: recordCleanup.reason } : {}),
...(directoryCleanup ? { directoryCleanupState: directoryCleanup.reason } : {}),
};
return releaseRecoveryBindings(result, undefined, capturedBackup.binding);
}