Updated kernel-runner delegate deny path to emit on stderr in packages/bare-os-booter/lib/kernel-runner.js. Added structured errno metadata (err.code) via vfsErr(...) and applied it to key VFS traversal/permission throws in packages/bare-os-booter/lib/vfs.js (ENOENT/EACCES paths). Critical command exit-code fixes: packages/bare-os-coreutils/src/ls.js Tracks access/stat failures and sets nonzero exit when any operand fails. packages/bare-os-coreutils/src/grep.js Recursive walker now reports traversal/stat errors back to main flow so fatal status becomes 2. packages/bare-os-coreutils/src/rm.js -f only suppresses not-found style errors; permission/deny failures stay nonzero. packages/bare-os-coreutils/src/chmod.js Treats falsy/no-op backend chmod result as failure (nonzero). packages/bare-os-coreutils/src/find.js Added root-path preflight so missing root now reports explicit error + nonzero. Minor quirks: packages/bare-os-coreutils/src/xargs.js -P0 now maps to bounded parallel cap (env/default cap), not forced serial. packages/bare-os-coreutils/src/ulimit.js -f with value now returns explicit unsupported-setter diagnostic + nonzero. -f alone reports unlimited. Regression tests: Added packages/bare-os-coreutils/test/error-propagation.test.mjs covering: grep missing file => exit 2 rm -f permission error => nonzero find missing root => nonzero + diagnostic ulimit -f 1M => explicit unsupported + nonzero xargs -P0 bounded behavior
6538 lines
226 KiB
JavaScript
6538 lines
226 KiB
JavaScript
import unixPathResolve from 'unix-path-resolve'
|
|
import b4a from 'b4a'
|
|
import { raceWithAbortAndTimeout } from './bare-os-abort.js'
|
|
import { bareOsIpcLogicalToActualFifoName } from './bare-os-ipc-namespace.js'
|
|
import { listBareInitdJournalUnits } from './bare-initd-journal.js'
|
|
import { bareOsVfsAclDeniesDriveOp } from './bare-os-vfs-acl-enforce.js'
|
|
import { bareOsVfsPathCapabilityDeniesDriveRead } from './bare-os-path-capability.js'
|
|
import {
|
|
extractBareOs,
|
|
identityNames,
|
|
isPersonalRoute,
|
|
isVirtualMountPoint,
|
|
mergeBareOsOnWrite,
|
|
mergeEntryMetadata,
|
|
modeAllows,
|
|
newBareOsForSymlink,
|
|
parseUidGid,
|
|
statFromBareOs,
|
|
synthesizeStat,
|
|
S_IFDIR,
|
|
S_IFLNK,
|
|
S_IFREG
|
|
} from './vfs-posix-meta.js'
|
|
import { bareOsKernelMetricInc } from './bare-os-kernel-metrics.js'
|
|
|
|
/**
|
|
* Policy-oriented path class for VFS routing (system vs personal vs pseudo vs mount vs volatile).
|
|
* Used by operator tooling and future policy engines; routing itself stays in `createVfs`.
|
|
* @param {string} p
|
|
* @returns {'system' | 'personal' | 'pseudo' | 'mount' | 'volatile' | 'snapshot' | 'unknown'}
|
|
*/
|
|
export function classifyBareOsVfsPathClass(p) {
|
|
const path = String(p || '').replace(/\\/g, '/')
|
|
if (!path.startsWith('/')) return 'unknown'
|
|
if (path === '/snapshots' || path.startsWith('/snapshots/')) return 'snapshot'
|
|
if (path.startsWith('/proc/') || path === '/proc') return 'pseudo'
|
|
if (path.startsWith('/sys/') || path === '/sys') return 'pseudo'
|
|
if (path.startsWith('/dev/') || path === '/dev') return 'pseudo'
|
|
if (path.startsWith('/run/') || path === '/run') return 'volatile'
|
|
if (
|
|
path.startsWith('/mnt/') ||
|
|
path.startsWith('/media/') ||
|
|
path.startsWith('/mount/')
|
|
)
|
|
return 'mount'
|
|
if (path.startsWith('/home/')) return 'personal'
|
|
if (path === '/root' || path.startsWith('/root/')) return 'personal'
|
|
if (path.startsWith('/tmp/') || path === '/tmp') return 'volatile'
|
|
if (
|
|
path.startsWith('/boot/') ||
|
|
path.startsWith('/bin/') ||
|
|
path.startsWith('/lib/') ||
|
|
path.startsWith('/etc/') ||
|
|
path === '/etc' ||
|
|
path.startsWith('/usr/') ||
|
|
path.startsWith('/var/')
|
|
)
|
|
return 'system'
|
|
return 'system'
|
|
}
|
|
|
|
/**
|
|
* Declarative policy evaluation over {@link classifyBareOsVfsPathClass} (allow/deny/audit rule stack).
|
|
* Later rules override earlier allow/deny; **`audit`** matches are recorded but do not change verdict.
|
|
* @param {string} p
|
|
* @param {{ id?: string, effect: 'allow' | 'deny' | 'audit', pathClass?: string, prefix?: string }[]} [rules]
|
|
* @returns {{ path: string, pathClass: string, matched: { id?: string, effect: 'allow' | 'deny' | 'audit' }[], verdict: 'neutral' | 'allow' | 'deny', auditHits: number, metrics: { rulesEvaluated: number, matchCount: number } }}
|
|
*/
|
|
export function evaluateBareOsVfsPathPolicy(p, rules = []) {
|
|
const path = String(p || '').replace(/\\/g, '/')
|
|
const pathClass = classifyBareOsVfsPathClass(path)
|
|
/** @type {{ id?: string, effect: 'allow' | 'deny' | 'audit' }[]} */
|
|
const matched = []
|
|
let verdict = 'neutral'
|
|
let auditHits = 0
|
|
let rulesEvaluated = 0
|
|
for (const r of rules) {
|
|
rulesEvaluated++
|
|
if (
|
|
!r ||
|
|
(r.effect !== 'allow' && r.effect !== 'deny' && r.effect !== 'audit')
|
|
)
|
|
continue
|
|
if (r.pathClass && r.pathClass !== pathClass) continue
|
|
if (r.prefix && !path.startsWith(String(r.prefix))) continue
|
|
matched.push({ id: r.id, effect: r.effect })
|
|
if (r.effect === 'audit') {
|
|
auditHits++
|
|
continue
|
|
}
|
|
verdict = r.effect
|
|
}
|
|
return {
|
|
path,
|
|
pathClass,
|
|
matched,
|
|
verdict,
|
|
auditHits,
|
|
metrics: { rulesEvaluated, matchCount: matched.length }
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Parse optional **`BARE_OS_VFS_POLICY_RULES_JSON`** env: `{ "rules": [ ... ] }`.
|
|
* @param {Record<string, unknown> | null | undefined} env
|
|
*/
|
|
export function parseBareOsVfsPolicyRulesFromEnv(env) {
|
|
const raw = env && env.BARE_OS_VFS_POLICY_RULES_JSON
|
|
if (raw == null || raw === '') return []
|
|
try {
|
|
const j = JSON.parse(String(raw))
|
|
if (j && typeof j === 'object' && Array.isArray(j.rules)) return j.rules
|
|
} catch {
|
|
/* ignore */
|
|
}
|
|
return []
|
|
}
|
|
|
|
/**
|
|
* Batch put helper: uses Hyperdrive `batch()` when present, else sequential `put`.
|
|
* @param {{ put?: Function, batch?: () => { put: Function, flush?: () => Promise<void> } }} drive
|
|
* @param {{ path: string, buf: Uint8Array | ArrayBuffer, opts?: Record<string, unknown> }[]} puts
|
|
*/
|
|
export async function bareOsVfsBatchPut(drive, puts) {
|
|
if (!drive || typeof drive.put !== 'function') {
|
|
throw new Error('bareOsVfsBatchPut: drive.put required')
|
|
}
|
|
if (!Array.isArray(puts) || !puts.length) return
|
|
if (typeof drive.batch === 'function') {
|
|
const b = drive.batch()
|
|
for (const row of puts) {
|
|
const p = String(row.path || '').trim()
|
|
if (!p) continue
|
|
await b.put(p, row.buf, row.opts)
|
|
}
|
|
if (typeof b.flush === 'function') await b.flush()
|
|
return
|
|
}
|
|
for (const row of puts) {
|
|
const p = String(row.path || '').trim()
|
|
if (!p) continue
|
|
await drive.put(p, row.buf, row.opts)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Collect diff entries when the drive exposes `diff` (signature varies by Hyperdrive version).
|
|
* @param {{ diff?: (...args: unknown[]) => AsyncIterable<unknown> | Iterable<unknown> }} drive
|
|
* @param {unknown} a
|
|
* @param {unknown} b
|
|
* @param {{ maxEntries?: number, diffOpts?: Record<string, unknown> }} [opts]
|
|
*/
|
|
export async function bareOsHyperdriveDiffCollect(drive, a, b, opts = {}) {
|
|
if (!drive || typeof drive.diff !== 'function') {
|
|
return { ok: false, error: 'diff-unavailable' }
|
|
}
|
|
const max = opts.maxEntries ?? 5000
|
|
/** @type {unknown[]} */
|
|
const entries = []
|
|
try {
|
|
const raw = drive.diff(a, b, opts.diffOpts)
|
|
if (raw && Symbol.asyncIterator in raw) {
|
|
for await (const ent of /** @type {AsyncIterable<unknown>} */ (raw)) {
|
|
entries.push(ent)
|
|
if (entries.length >= max) break
|
|
}
|
|
} else if (raw && Symbol.iterator in raw) {
|
|
for (const ent of /** @type {Iterable<unknown>} */ (raw)) {
|
|
entries.push(ent)
|
|
if (entries.length >= max) break
|
|
}
|
|
} else {
|
|
return { ok: false, error: 'diff-not-iterable' }
|
|
}
|
|
return {
|
|
ok: true,
|
|
entries,
|
|
truncated: entries.length >= max
|
|
}
|
|
} catch (e) {
|
|
return { ok: false, error: (e && e.message) || String(e) }
|
|
}
|
|
}
|
|
|
|
/** Empty-directory marker (must match {@link ./git-fs-adapter.js}). */
|
|
const DIR_MARKER = '.bareos_empty'
|
|
|
|
/** Capability word 6 `/proc` pseudo files → {@link ./bare-os-proc-replication-operator-surface.js} ids. */
|
|
export const BARE_OS_PROC_FILE_TO_ID_REPLICATION_OPERATOR_SURFACE = Object.freeze({
|
|
bare_os_udx_extended: 'udx_extended',
|
|
bare_os_dht_status: 'dht_status',
|
|
bare_os_replication_backpressure: 'replication_backpressure',
|
|
bare_os_ipc_backpressure: 'ipc_backpressure',
|
|
bare_os_delegate_red: 'delegate_red',
|
|
bare_os_build_attestation_pointer: 'build_attestation_pointer',
|
|
bare_os_pear_ipc_health: 'pear_ipc_health',
|
|
bare_os_hypercore_lengths: 'hypercore_lengths',
|
|
bare_os_slo_hints: 'slo_hints',
|
|
bare_os_locale: 'locale',
|
|
bare_os_worker_budget: 'worker_budget',
|
|
bare_os_sandbox_profile: 'sandbox_profile',
|
|
bare_os_dns_map_active: 'dns_map_active',
|
|
bare_os_git_delegate_stats: 'git_delegate_stats',
|
|
bare_os_replication_operator_panel: 'replication_operator_panel'
|
|
})
|
|
|
|
/** Capability word 7 `/proc` pseudo files → {@link ./bare-os-proc-pear-corestore-hrpc.js} ids. */
|
|
export const BARE_OS_PROC_FILE_TO_ID_PEAR_CORESTORE_HRPC = Object.freeze({
|
|
bare_os_async_hooks_lag: 'async_hooks_lag',
|
|
bare_os_autopass_session_sketch: 'autopass_session_sketch',
|
|
bare_os_bare_diagnostics_channel: 'diagnostics_channel',
|
|
bare_os_bare_net_interfaces: 'bare_net_interfaces',
|
|
bare_os_bare_thread_pool: 'thread_pool',
|
|
bare_os_blind_relay_router: 'blind_relay_router',
|
|
bare_os_compact_encoding_profile: 'compact_encoding_profile',
|
|
bare_os_corestore_gc_hint: 'corestore_gc_hint',
|
|
bare_os_git_lfs_pointer_stats: 'git_lfs_pointer_stats',
|
|
bare_os_hrpc_bridge_health: 'hrpc_bridge_health',
|
|
bare_os_hyperdb_readonly_index: 'hyperdb_readonly_index',
|
|
bare_os_pear_build_fingerprint: 'pear_build_fingerprint',
|
|
bare_os_pear_runtime_channel: 'pear_runtime_channel',
|
|
bare_os_protomux_channels: 'protomux_channels',
|
|
bare_os_security_context: 'security_context',
|
|
bare_os_updater_download_state: 'updater_download_state'
|
|
})
|
|
|
|
/** Capability word 8 `/proc` pseudo files → {@link ./bare-os-proc-bare-runtime-proto-mux.js} ids. */
|
|
export const BARE_OS_PROC_FILE_TO_ID_BARE_RUNTIME_PROTO_MUX = Object.freeze({
|
|
bare_os_bare_kit_bridge: 'bare_kit_bridge',
|
|
bare_os_brittle_snapshot_ci: 'brittle_snapshot_ci',
|
|
bare_os_cellery_sidecar_hint: 'cellery_sidecar_hint',
|
|
bare_os_form_data_delegate_limits: 'form_data_delegate_limits',
|
|
bare_os_gip_transport_sketch: 'gip_transport_sketch',
|
|
bare_os_http_dht_proxy_route: 'http_dht_proxy_route',
|
|
bare_os_hyper_multisig_trust_pointer: 'hyper_multisig_trust_pointer',
|
|
bare_os_hypercore_signing_status: 'hypercore_signing_status',
|
|
bare_os_hypermininet_topology: 'hypermininet_topology',
|
|
bare_os_libmqjs_queue_depth: 'libmqjs_queue_depth',
|
|
bare_os_oidc_publishing_pointer: 'oidc_publishing_pointer',
|
|
bare_os_pear_sidecar_bundle_index: 'pear_sidecar_bundle_index',
|
|
bare_os_protomux_rpc_pool_health: 'protomux_rpc_pool_health',
|
|
bare_os_react_native_bare_kit: 'react_native_bare_kit',
|
|
bare_os_rocksdb_pointer: 'rocksdb_pointer',
|
|
bare_os_safe_sodium_buffer_policy: 'safe_sodium_buffer_policy',
|
|
bare_os_sandbox_worker_queue: 'sandbox_worker_queue',
|
|
bare_os_structured_clone_profile: 'structured_clone_profile'
|
|
})
|
|
|
|
/** Capability word 9 `/proc` pseudo files → {@link ./bare-os-proc-bare-module-crypto-staging.js} ids. */
|
|
export const BARE_OS_PROC_FILE_TO_ID_BARE_MODULE_CRYPTO_STAGING = Object.freeze({
|
|
bare_os_pear_stage_pointer: 'pear_stage_pointer',
|
|
bare_os_pear_updater_state: 'pear_updater_state',
|
|
bare_os_pear_appling_manifest: 'pear_appling_manifest',
|
|
bare_os_drive_resolve_cache: 'drive_resolve_cache',
|
|
bare_os_bare_module_resolution: 'bare_module_resolution',
|
|
bare_os_bare_crypto_policy: 'bare_crypto_policy',
|
|
bare_os_bare_ipc_bridge: 'bare_ipc_bridge',
|
|
bare_os_bare_vm_sandbox_sketch: 'bare_vm_sandbox_sketch',
|
|
bare_os_bare_daemon_hooks: 'bare_daemon_hooks',
|
|
bare_os_bare_storage_quota: 'bare_storage_quota',
|
|
bare_os_bare_worker_pool: 'bare_worker_pool',
|
|
bare_os_pear_wakeups_schedule: 'pear_wakeups_schedule',
|
|
bare_os_pear_drop_events: 'pear_drop_events',
|
|
bare_os_pear_radio_state: 'pear_radio_state',
|
|
bare_os_hypercore_repair_hint: 'hypercore_repair_hint',
|
|
bare_os_hyperdrive_sparse_index: 'hyperdrive_sparse_index',
|
|
bare_os_protomux_channel_alias_v2: 'protomux_channel_alias_v2',
|
|
bare_os_structured_clone_budget_v2: 'structured_clone_budget_v2',
|
|
bare_os_form_data_delegate_limits_v2: 'form_data_delegate_limits_v2'
|
|
})
|
|
|
|
/** Capability word 10 `/proc` pseudo files → {@link ./bare-os-proc-pear-inspect-logger-tls.js} ids. */
|
|
export const BARE_OS_PROC_FILE_TO_ID_PEAR_INSPECT_LOGGER_TLS = Object.freeze({
|
|
bare_os_activity_queue_depth: 'activity_queue_depth',
|
|
bare_os_autobase_writer_hint: 'autobase_writer_hint',
|
|
bare_os_bare_boot_phase_map: 'bare_boot_phase_map',
|
|
bare_os_bare_inspect_policy: 'bare_inspect_policy',
|
|
bare_os_bare_logger_policy: 'bare_logger_policy',
|
|
bare_os_bare_performance_counters: 'bare_performance_counters',
|
|
bare_os_bare_rpc_registry_sketch: 'bare_rpc_registry_sketch',
|
|
bare_os_bare_signals_mask: 'bare_signals_mask',
|
|
bare_os_bare_stream_backpressure: 'bare_stream_backpressure',
|
|
bare_os_bare_timers_budget: 'bare_timers_budget',
|
|
bare_os_bare_tls_session_hint: 'bare_tls_session_hint',
|
|
bare_os_bare_ws_gateway_sketch: 'bare_ws_gateway_sketch',
|
|
bare_os_blind_pairing_sketch: 'blind_pairing_sketch',
|
|
bare_os_broadcast_encryption_hint: 'broadcast_encryption_hint',
|
|
bare_os_pear_api_allowlist_sketch: 'pear_api_allowlist_sketch',
|
|
bare_os_pear_doctor_state: 'pear_doctor_state',
|
|
bare_os_pear_rti_pointer: 'pear_rti_pointer',
|
|
bare_os_pear_user_dirs_map: 'pear_user_dirs_map',
|
|
bare_os_pear_workshop_flags: 'pear_workshop_flags'
|
|
})
|
|
|
|
/** Capability word 11 `/proc` pseudo files → {@link ./bare-os-proc-hypercore-pack-hrpc-lifecycle.js} ids. */
|
|
export const BARE_OS_PROC_FILE_TO_ID_HYPERCORE_PACK_HRPC_LIFECYCLE = Object.freeze({
|
|
bare_os_autopass_rotation_sketch: 'autopass_rotation_sketch',
|
|
bare_os_bare_addon_policy: 'bare_addon_policy',
|
|
bare_os_bare_pack_cache: 'bare_pack_cache',
|
|
bare_os_bare_signals_profile: 'bare_signals_profile',
|
|
bare_os_bare_timers_histogram: 'bare_timers_histogram',
|
|
bare_os_bundle_preload_hint: 'bundle_preload_hint',
|
|
bare_os_drive_version_graph: 'drive_version_graph',
|
|
bare_os_git_lfs_budget: 'git_lfs_budget',
|
|
bare_os_hrpc_allowlist_sketch: 'hrpc_allowlist_sketch',
|
|
bare_os_hypercore_replicate_budget: 'hypercore_replicate_budget',
|
|
bare_os_indexer_catchup: 'indexer_catchup',
|
|
bare_os_multisig_quorum_pointer: 'multisig_quorum_pointer',
|
|
bare_os_net_qos_class: 'net_qos_class',
|
|
bare_os_pear_runtime_matrix: 'pear_runtime_matrix',
|
|
bare_os_protomux_backpressure: 'protomux_backpressure',
|
|
bare_os_relay_geo_hint: 'relay_geo_hint',
|
|
bare_os_sidecar_resource_cap: 'sidecar_resource_cap',
|
|
bare_os_storage_tier_hint: 'storage_tier_hint',
|
|
bare_os_wave11_operator_slo_v2: 'wave11_operator_slo_v2',
|
|
bare_os_wave11_peer_qos_sketch: 'wave11_peer_qos_sketch',
|
|
bare_os_kernel_program: 'kernel_program',
|
|
bare_os_giant_phase_program: 'giant_phase_program'
|
|
})
|
|
|
|
/**
|
|
* Unified path view: system Hyperdrive for OS paths, personal Hyperdrive under $HOME,
|
|
* optional HDMS mounts under /mnt/<label>/…, virtual /var with writable /var/log/…
|
|
* on the personal drive under /.bare-os/var/log/<home-seg>/… (session-isolated).
|
|
* Read-only pseudo `proc`, `sys`, `run`, `dev` under `/` (including vfs-backed **`/proc/cpuinfo`**, **`/proc/loadavg`**, **`/proc/self/exe`**, and **`/dev/urandom`** — urandom is bounded and **not** crypto-grade unless `secureRandomBytes` is wired); session `tmp` maps to `/.bare-os/tmp/<seg>/` on the personal drive.
|
|
* @param {import('hyperdrive').default} systemDrive
|
|
* @param {import('hyperdrive').default} personalDrive
|
|
* @param {Record<string, string>} env
|
|
* @param {{ getMounts?: () => Map<string, { drive: import('hyperdrive').default, writable: boolean }> } | null} [mntRef]
|
|
* @param {{
|
|
* procSnapshot?: { version?: string, cmdline?: string },
|
|
* bootStartedMs?: number,
|
|
* initdRunText?: () => string,
|
|
* bootProfileText?: () => string,
|
|
* sessionText?: () => string,
|
|
* sessionStatsText?: () => string,
|
|
* bootReadyMarkerText?: () => string,
|
|
* bootReadyJsonText?: () => string,
|
|
* buildIdText?: () => string,
|
|
* secureRandomBytes?: (n: number) => Uint8Array,
|
|
* bareOsIpc?: ReturnType<import('./bare-os-ipc.js').createBareOsIpc> | null,
|
|
* procNetDevText?: () => string,
|
|
* procDiskstatsText?: () => string,
|
|
* procBareOsQuotasText?: () => string,
|
|
* procBareOsResourcesText?: () => string,
|
|
* procBareOsFeaturesText?: () => string,
|
|
* procBareOsSwarmText?: () => string,
|
|
* procBareOsSwarmHealthText?: () => string,
|
|
* procBareOsSwarmSubsystemStatusJsonText?: (fileKey: string) => string,
|
|
* procBareOsReplicationText?: () => string,
|
|
* procBareOsCapabilitiesText?: () => string,
|
|
* procBareOsCapabilitiesJsonText?: () => string,
|
|
* procBareOsBootstrapText?: () => string,
|
|
* procBareOsUnionText?: () => string,
|
|
* procBareOsSeedHandshakeText?: () => string,
|
|
* procBareOsManifestHintsText?: () => string,
|
|
* procBareOsPeerHealthText?: () => string,
|
|
* procBareOsStagingSlotText?: () => string,
|
|
* procBareOsSnapshotHintsText?: () => string,
|
|
* procBareOsProvenanceText?: () => string,
|
|
* procBareOsPearIpcRegistryText?: () => string,
|
|
* procBareOsInitdDagText?: () => string,
|
|
* procBareOsInitdReadinessText?: () => string,
|
|
* procBareOsBootGraphJsonText?: () => string,
|
|
* procBareOsBootBudgetSummaryText?: () => string,
|
|
* procBareOsMetricsLiveText?: () => string,
|
|
* procBareOsChatText?: () => string,
|
|
* procBareOsMeshdropText?: () => string,
|
|
* procBareOsPeerDetailsText?: () => string,
|
|
* procBareOsDhtScanText?: () => string,
|
|
* procBareOsSwarmDoctorText?: () => string,
|
|
* procBareOsRouteSummaryText?: () => string,
|
|
* procBareOsHolepunchSummaryText?: () => string,
|
|
* procBareOsProcessTableText?: () => string,
|
|
* procBareOsProcessIoText?: () => string,
|
|
* procBareOsProcessThreadsText?: () => string,
|
|
* procBareOsProcessMapsText?: () => string,
|
|
* procBareOsSyscallsText?: () => string,
|
|
* procBareOsMetricsPromText?: () => string,
|
|
* procBareOsProtomuxWireText?: () => string,
|
|
* procBareOsProtomuxExtensionsText?: () => string,
|
|
* procBareOsNetSummaryText?: () => string,
|
|
* procBareOsExtensionsText?: () => string,
|
|
* procBareOsHdmsHintsText?: () => string,
|
|
* procBareOsPearTrustText?: () => string,
|
|
* procBareOsSecurityPostureText?: () => string,
|
|
* procBareOsRlimitsText?: () => string,
|
|
* procBareOsSelfLimitsText?: () => string,
|
|
* procBareOsHdmsHealthText?: () => string,
|
|
* procBareOsVirtualRegistryText?: () => string,
|
|
* procBareOsHostOsText?: () => string,
|
|
* procBareOsSyncWindowText?: () => string,
|
|
* procBareOsClockText?: () => string,
|
|
* procBareOsOpensshText?: () => string,
|
|
* procBareOsDebugText?: () => string,
|
|
* procBareOsReplicationOperatorSurfaceJsonText?: (replicationOperatorSurfaceProcId: string) => string,
|
|
* procBareOsPearCorestoreHrpcJsonText?: (pearCorestoreHrpcProcId: string) => string,
|
|
* procBareOsBareRuntimeProtoMuxJsonText?: (bareRuntimeProtoMuxProcId: string) => string,
|
|
* procBareOsBareModuleCryptoStagingJsonText?: (bareModuleCryptoStagingProcId: string) => string,
|
|
* procBareOsPearInspectLoggerTlsJsonText?: (pearInspectLoggerTlsProcId: string) => string,
|
|
* procBareOsHypercorePackHrpcLifecycleJsonText?: (hypercorePackHrpcLifecycleProcId: string) => string,
|
|
* getUnitJournalNdjson?: (unit: string) => string,
|
|
* getVirtualReaders?: () => Map<string, unknown>,
|
|
* unionReadPrefixes?: readonly string[],
|
|
* unionWriteDenyPrefixes?: readonly string[],
|
|
* sysClassNetLoText?: () => string,
|
|
* hostProcStatsRef?: { stats?: unknown } | null,
|
|
* ipcFifoLogicalToActual?: (logicalName: string) => string,
|
|
* getProcSelfExtraFds?: () => { fdNum: string, target: string }[],
|
|
* getProcSyntheticLinuxCompat?: () => { sessionId: string, swarmPeerCount: number, peerIds: string[] } | null | undefined,
|
|
* getAuxiliaryMountLines?: () => (string | null | undefined)[],
|
|
* getAuxiliaryDrives?: () => unknown[] | null | undefined,
|
|
* warmReadCacheStatsRef?: { current: Record<string, unknown> | null },
|
|
* bareOsIdentityVfsRef?: { session: 'guest' | 'unlocked' }
|
|
* }} [vfsOptions]
|
|
*/
|
|
export function createVfs(
|
|
systemDrive,
|
|
personalDrive,
|
|
env,
|
|
mntRef = null,
|
|
vfsOptions = {}
|
|
) {
|
|
/** When `BARE_OS_HIDE_PROC_HYPERCORE_PACK_HRPC_LIFECYCLE` is `0` / `false` / `off`, hide Capability word 11 `/proc` JSON nodes (flat + `/proc/bare_os/*` + index entries). */
|
|
const omitHypercorePackHrpcLifecycleProc =
|
|
env &&
|
|
(env.BARE_OS_HIDE_PROC_HYPERCORE_PACK_HRPC_LIFECYCLE === '0' ||
|
|
env.BARE_OS_HIDE_PROC_HYPERCORE_PACK_HRPC_LIFECYCLE === 'false' ||
|
|
env.BARE_OS_HIDE_PROC_HYPERCORE_PACK_HRPC_LIFECYCLE === 'off')
|
|
const hypercorePackHrpcLifecycleBareOsRelNames = new Set(
|
|
Object.keys(BARE_OS_PROC_FILE_TO_ID_HYPERCORE_PACK_HRPC_LIFECYCLE).map((k) => {
|
|
const base = k.startsWith('bare_os_') ? k.slice('bare_os_'.length) : k
|
|
return base.endsWith('.json') ? base : base + '.json'
|
|
})
|
|
)
|
|
const hypercorePackHrpcLifecycleFlatProcNames = new Set(
|
|
Object.keys(BARE_OS_PROC_FILE_TO_ID_HYPERCORE_PACK_HRPC_LIFECYCLE).map((k) =>
|
|
k.endsWith('.json') ? k : k + '.json'
|
|
)
|
|
)
|
|
/** @param {string[]} names */
|
|
function stripHypercorePackHrpcLifecycleFlat(names) {
|
|
if (!omitHypercorePackHrpcLifecycleProc) return names
|
|
return names.filter((n) => !hypercorePackHrpcLifecycleFlatProcNames.has(n))
|
|
}
|
|
/** @param {string[]} names */
|
|
function stripHypercorePackHrpcLifecycleBareOs(names) {
|
|
if (!omitHypercorePackHrpcLifecycleProc) return names
|
|
return names.filter((n) => !hypercorePackHrpcLifecycleBareOsRelNames.has(n))
|
|
}
|
|
const procSnapshot = vfsOptions.procSnapshot || null
|
|
const bootStartedMs =
|
|
typeof vfsOptions.bootStartedMs === 'number'
|
|
? vfsOptions.bootStartedMs
|
|
: null
|
|
const initdRunText =
|
|
typeof vfsOptions.initdRunText === 'function'
|
|
? vfsOptions.initdRunText
|
|
: null
|
|
const bootProfileText =
|
|
typeof vfsOptions.bootProfileText === 'function'
|
|
? vfsOptions.bootProfileText
|
|
: null
|
|
const sessionText =
|
|
typeof vfsOptions.sessionText === 'function' ? vfsOptions.sessionText : null
|
|
const sessionStatsText =
|
|
typeof vfsOptions.sessionStatsText === 'function'
|
|
? vfsOptions.sessionStatsText
|
|
: null
|
|
const bootReadyMarkerText =
|
|
typeof vfsOptions.bootReadyMarkerText === 'function'
|
|
? vfsOptions.bootReadyMarkerText
|
|
: null
|
|
const bootReadyJsonText =
|
|
typeof vfsOptions.bootReadyJsonText === 'function'
|
|
? vfsOptions.bootReadyJsonText
|
|
: null
|
|
const buildIdText =
|
|
typeof vfsOptions.buildIdText === 'function' ? vfsOptions.buildIdText : null
|
|
const secureRandomBytes =
|
|
typeof vfsOptions.secureRandomBytes === 'function'
|
|
? vfsOptions.secureRandomBytes
|
|
: null
|
|
const bareOsIpc = vfsOptions.bareOsIpc ?? null
|
|
const vfsReadMetricsOn =
|
|
env &&
|
|
(env.BARE_OS_VFS_READ_METRICS === '1' ||
|
|
env.BARE_OS_VFS_READ_METRICS === 'true')
|
|
/** In-memory POSIX-like named segments (not shared across hosts). */
|
|
const bareOsDevShm = new Map()
|
|
const bareOsDevShmMaxBytes = Math.max(
|
|
0,
|
|
Math.floor(Number(env?.BARE_OS_SHM_MAX_BYTES) || 0)
|
|
)
|
|
/** TTL memo for `readdir` under `/.bare/**` on the personal drive (see `BARE_OS_PERSONAL_VAULT_INDEX_CACHE_MS`). */
|
|
const personalBareReaddirCache = new Map()
|
|
const procNetDevText =
|
|
typeof vfsOptions.procNetDevText === 'function'
|
|
? vfsOptions.procNetDevText
|
|
: null
|
|
const procDiskstatsText =
|
|
typeof vfsOptions.procDiskstatsText === 'function'
|
|
? vfsOptions.procDiskstatsText
|
|
: null
|
|
const procBareOsQuotasText =
|
|
typeof vfsOptions.procBareOsQuotasText === 'function'
|
|
? vfsOptions.procBareOsQuotasText
|
|
: null
|
|
const procBareOsResourcesText =
|
|
typeof vfsOptions.procBareOsResourcesText === 'function'
|
|
? vfsOptions.procBareOsResourcesText
|
|
: null
|
|
const procBareOsFeaturesText =
|
|
typeof vfsOptions.procBareOsFeaturesText === 'function'
|
|
? vfsOptions.procBareOsFeaturesText
|
|
: null
|
|
const procBareOsSwarmText =
|
|
typeof vfsOptions.procBareOsSwarmText === 'function'
|
|
? vfsOptions.procBareOsSwarmText
|
|
: null
|
|
const procBareOsSwarmHealthText =
|
|
typeof vfsOptions.procBareOsSwarmHealthText === 'function'
|
|
? vfsOptions.procBareOsSwarmHealthText
|
|
: null
|
|
const procBareOsSwarmSubsystemStatusJsonText =
|
|
typeof vfsOptions.procBareOsSwarmSubsystemStatusJsonText === 'function'
|
|
? vfsOptions.procBareOsSwarmSubsystemStatusJsonText
|
|
: null
|
|
const procBareOsReplicationText =
|
|
typeof vfsOptions.procBareOsReplicationText === 'function'
|
|
? vfsOptions.procBareOsReplicationText
|
|
: null
|
|
const procBareOsCapabilitiesText =
|
|
typeof vfsOptions.procBareOsCapabilitiesText === 'function'
|
|
? vfsOptions.procBareOsCapabilitiesText
|
|
: null
|
|
const procBareOsCapabilitiesJsonText =
|
|
typeof vfsOptions.procBareOsCapabilitiesJsonText === 'function'
|
|
? vfsOptions.procBareOsCapabilitiesJsonText
|
|
: null
|
|
const procBareOsBootstrapText =
|
|
typeof vfsOptions.procBareOsBootstrapText === 'function'
|
|
? vfsOptions.procBareOsBootstrapText
|
|
: null
|
|
const procBareOsUnionText =
|
|
typeof vfsOptions.procBareOsUnionText === 'function'
|
|
? vfsOptions.procBareOsUnionText
|
|
: null
|
|
const procBareOsSeedHandshakeText =
|
|
typeof vfsOptions.procBareOsSeedHandshakeText === 'function'
|
|
? vfsOptions.procBareOsSeedHandshakeText
|
|
: null
|
|
const procBareOsManifestHintsText =
|
|
typeof vfsOptions.procBareOsManifestHintsText === 'function'
|
|
? vfsOptions.procBareOsManifestHintsText
|
|
: null
|
|
const procBareOsPeerHealthText =
|
|
typeof vfsOptions.procBareOsPeerHealthText === 'function'
|
|
? vfsOptions.procBareOsPeerHealthText
|
|
: null
|
|
const procBareOsStagingSlotText =
|
|
typeof vfsOptions.procBareOsStagingSlotText === 'function'
|
|
? vfsOptions.procBareOsStagingSlotText
|
|
: null
|
|
const procBareOsSnapshotHintsText =
|
|
typeof vfsOptions.procBareOsSnapshotHintsText === 'function'
|
|
? vfsOptions.procBareOsSnapshotHintsText
|
|
: null
|
|
const procBareOsProvenanceText =
|
|
typeof vfsOptions.procBareOsProvenanceText === 'function'
|
|
? vfsOptions.procBareOsProvenanceText
|
|
: null
|
|
const procBareOsPearIpcRegistryText =
|
|
typeof vfsOptions.procBareOsPearIpcRegistryText === 'function'
|
|
? vfsOptions.procBareOsPearIpcRegistryText
|
|
: null
|
|
const procBareOsInitdDagText =
|
|
typeof vfsOptions.procBareOsInitdDagText === 'function'
|
|
? vfsOptions.procBareOsInitdDagText
|
|
: null
|
|
const procBareOsInitdReadinessText =
|
|
typeof vfsOptions.procBareOsInitdReadinessText === 'function'
|
|
? vfsOptions.procBareOsInitdReadinessText
|
|
: null
|
|
const procBareOsBootGraphJsonText =
|
|
typeof vfsOptions.procBareOsBootGraphJsonText === 'function'
|
|
? vfsOptions.procBareOsBootGraphJsonText
|
|
: null
|
|
const procBareOsBootBudgetSummaryText =
|
|
typeof vfsOptions.procBareOsBootBudgetSummaryText === 'function'
|
|
? vfsOptions.procBareOsBootBudgetSummaryText
|
|
: null
|
|
const procBareOsMetricsLiveText =
|
|
typeof vfsOptions.procBareOsMetricsLiveText === 'function'
|
|
? vfsOptions.procBareOsMetricsLiveText
|
|
: null
|
|
const procBareOsChatText =
|
|
typeof vfsOptions.procBareOsChatText === 'function'
|
|
? vfsOptions.procBareOsChatText
|
|
: null
|
|
const procBareOsMeshdropText =
|
|
typeof vfsOptions.procBareOsMeshdropText === 'function'
|
|
? vfsOptions.procBareOsMeshdropText
|
|
: null
|
|
const procBareOsPeerDetailsText =
|
|
typeof vfsOptions.procBareOsPeerDetailsText === 'function'
|
|
? vfsOptions.procBareOsPeerDetailsText
|
|
: null
|
|
const procBareOsDhtScanText =
|
|
typeof vfsOptions.procBareOsDhtScanText === 'function'
|
|
? vfsOptions.procBareOsDhtScanText
|
|
: null
|
|
const procBareOsSwarmDoctorText =
|
|
typeof vfsOptions.procBareOsSwarmDoctorText === 'function'
|
|
? vfsOptions.procBareOsSwarmDoctorText
|
|
: null
|
|
const procBareOsRouteSummaryText =
|
|
typeof vfsOptions.procBareOsRouteSummaryText === 'function'
|
|
? vfsOptions.procBareOsRouteSummaryText
|
|
: null
|
|
const procBareOsHolepunchSummaryText =
|
|
typeof vfsOptions.procBareOsHolepunchSummaryText === 'function'
|
|
? vfsOptions.procBareOsHolepunchSummaryText
|
|
: null
|
|
const procBareOsProcessTableText =
|
|
typeof vfsOptions.procBareOsProcessTableText === 'function'
|
|
? vfsOptions.procBareOsProcessTableText
|
|
: null
|
|
const procBareOsProcessIoText =
|
|
typeof vfsOptions.procBareOsProcessIoText === 'function'
|
|
? vfsOptions.procBareOsProcessIoText
|
|
: null
|
|
const procBareOsProcessThreadsText =
|
|
typeof vfsOptions.procBareOsProcessThreadsText === 'function'
|
|
? vfsOptions.procBareOsProcessThreadsText
|
|
: null
|
|
const procBareOsProcessMapsText =
|
|
typeof vfsOptions.procBareOsProcessMapsText === 'function'
|
|
? vfsOptions.procBareOsProcessMapsText
|
|
: null
|
|
const procBareOsSyscallsText =
|
|
typeof vfsOptions.procBareOsSyscallsText === 'function'
|
|
? vfsOptions.procBareOsSyscallsText
|
|
: null
|
|
const procBareOsMetricsPromText =
|
|
typeof vfsOptions.procBareOsMetricsPromText === 'function'
|
|
? vfsOptions.procBareOsMetricsPromText
|
|
: null
|
|
const procBareOsProtomuxWireText =
|
|
typeof vfsOptions.procBareOsProtomuxWireText === 'function'
|
|
? vfsOptions.procBareOsProtomuxWireText
|
|
: null
|
|
const procBareOsProtomuxExtensionsText =
|
|
typeof vfsOptions.procBareOsProtomuxExtensionsText === 'function'
|
|
? vfsOptions.procBareOsProtomuxExtensionsText
|
|
: null
|
|
const procBareOsNetSummaryText =
|
|
typeof vfsOptions.procBareOsNetSummaryText === 'function'
|
|
? vfsOptions.procBareOsNetSummaryText
|
|
: null
|
|
const procBareOsExtensionsText =
|
|
typeof vfsOptions.procBareOsExtensionsText === 'function'
|
|
? vfsOptions.procBareOsExtensionsText
|
|
: null
|
|
const procBareOsHdmsHintsText =
|
|
typeof vfsOptions.procBareOsHdmsHintsText === 'function'
|
|
? vfsOptions.procBareOsHdmsHintsText
|
|
: null
|
|
const procBareOsPearTrustText =
|
|
typeof vfsOptions.procBareOsPearTrustText === 'function'
|
|
? vfsOptions.procBareOsPearTrustText
|
|
: null
|
|
const procBareOsSecurityPostureText =
|
|
typeof vfsOptions.procBareOsSecurityPostureText === 'function'
|
|
? vfsOptions.procBareOsSecurityPostureText
|
|
: null
|
|
const procBareOsRlimitsText =
|
|
typeof vfsOptions.procBareOsRlimitsText === 'function'
|
|
? vfsOptions.procBareOsRlimitsText
|
|
: null
|
|
const procBareOsSelfLimitsText =
|
|
typeof vfsOptions.procBareOsSelfLimitsText === 'function'
|
|
? vfsOptions.procBareOsSelfLimitsText
|
|
: null
|
|
const procBareOsHdmsHealthText =
|
|
typeof vfsOptions.procBareOsHdmsHealthText === 'function'
|
|
? vfsOptions.procBareOsHdmsHealthText
|
|
: null
|
|
const procBareOsVirtualRegistryText =
|
|
typeof vfsOptions.procBareOsVirtualRegistryText === 'function'
|
|
? vfsOptions.procBareOsVirtualRegistryText
|
|
: null
|
|
const procBareOsHostOsText =
|
|
typeof vfsOptions.procBareOsHostOsText === 'function'
|
|
? vfsOptions.procBareOsHostOsText
|
|
: null
|
|
const procBareOsSyncWindowText =
|
|
typeof vfsOptions.procBareOsSyncWindowText === 'function'
|
|
? vfsOptions.procBareOsSyncWindowText
|
|
: null
|
|
const procBareOsClockText =
|
|
typeof vfsOptions.procBareOsClockText === 'function'
|
|
? vfsOptions.procBareOsClockText
|
|
: null
|
|
const procBareOsOpensshText =
|
|
typeof vfsOptions.procBareOsOpensshText === 'function'
|
|
? vfsOptions.procBareOsOpensshText
|
|
: null
|
|
const procBareOsDebugText =
|
|
typeof vfsOptions.procBareOsDebugText === 'function'
|
|
? vfsOptions.procBareOsDebugText
|
|
: null
|
|
const procBareOsReplicationOperatorSurfaceJsonText =
|
|
typeof vfsOptions.procBareOsReplicationOperatorSurfaceJsonText === 'function'
|
|
? vfsOptions.procBareOsReplicationOperatorSurfaceJsonText
|
|
: null
|
|
const procBareOsPearCorestoreHrpcJsonText =
|
|
typeof vfsOptions.procBareOsPearCorestoreHrpcJsonText === 'function'
|
|
? vfsOptions.procBareOsPearCorestoreHrpcJsonText
|
|
: null
|
|
const procBareOsBareRuntimeProtoMuxJsonText =
|
|
typeof vfsOptions.procBareOsBareRuntimeProtoMuxJsonText === 'function'
|
|
? vfsOptions.procBareOsBareRuntimeProtoMuxJsonText
|
|
: null
|
|
const procBareOsBareModuleCryptoStagingJsonText =
|
|
typeof vfsOptions.procBareOsBareModuleCryptoStagingJsonText === 'function'
|
|
? vfsOptions.procBareOsBareModuleCryptoStagingJsonText
|
|
: null
|
|
const procBareOsPearInspectLoggerTlsJsonText =
|
|
typeof vfsOptions.procBareOsPearInspectLoggerTlsJsonText === 'function'
|
|
? vfsOptions.procBareOsPearInspectLoggerTlsJsonText
|
|
: null
|
|
const procBareOsHypercorePackHrpcLifecycleJsonText =
|
|
typeof vfsOptions.procBareOsHypercorePackHrpcLifecycleJsonText === 'function'
|
|
? vfsOptions.procBareOsHypercorePackHrpcLifecycleJsonText
|
|
: null
|
|
const getUnitJournalNdjson =
|
|
typeof vfsOptions.getUnitJournalNdjson === 'function'
|
|
? vfsOptions.getUnitJournalNdjson
|
|
: null
|
|
const getVirtualReaders =
|
|
typeof vfsOptions.getVirtualReaders === 'function'
|
|
? vfsOptions.getVirtualReaders
|
|
: null
|
|
const getProcSyntheticLinuxCompat =
|
|
typeof vfsOptions.getProcSyntheticLinuxCompat === 'function'
|
|
? vfsOptions.getProcSyntheticLinuxCompat
|
|
: null
|
|
const getAuxiliaryMountLines =
|
|
typeof vfsOptions.getAuxiliaryMountLines === 'function'
|
|
? vfsOptions.getAuxiliaryMountLines
|
|
: null
|
|
const getAuxiliaryDrives =
|
|
typeof vfsOptions.getAuxiliaryDrives === 'function'
|
|
? vfsOptions.getAuxiliaryDrives
|
|
: null
|
|
const unionReadPrefixes = Array.isArray(vfsOptions.unionReadPrefixes)
|
|
? vfsOptions.unionReadPrefixes.filter(
|
|
(s) => typeof s === 'string' && s.startsWith('/')
|
|
)
|
|
: []
|
|
const unionWriteDenyPrefixes = Array.isArray(
|
|
vfsOptions.unionWriteDenyPrefixes
|
|
)
|
|
? vfsOptions.unionWriteDenyPrefixes.filter(
|
|
(s) => typeof s === 'string' && s.startsWith('/')
|
|
)
|
|
: []
|
|
/** Optional read-only view of the **system** drive under a second prefix (snapshot/version workflows). */
|
|
const systemRoAliasNorm =
|
|
env && String(env.BARE_OS_VFS_SYSTEM_RO_ALIAS || '').trim()
|
|
? String(env.BARE_OS_VFS_SYSTEM_RO_ALIAS).trim().replace(/\/+$/, '')
|
|
: ''
|
|
|
|
/**
|
|
* Deny writes under union overlay read paths when `BARE_OS_VFS_UNION_WRITE_DENY` applies.
|
|
* @param {string} abs logical absolute path
|
|
*/
|
|
function assertUnionWriteNotDenied(abs) {
|
|
if (!unionReadPrefixes.length || !unionWriteDenyPrefixes.length) return
|
|
const underUnion = unionReadPrefixes.some(
|
|
(pre) => abs === pre || abs.startsWith(pre + '/')
|
|
)
|
|
if (!underUnion) return
|
|
for (const d of unionWriteDenyPrefixes) {
|
|
if (abs === d || abs.startsWith(d + '/')) {
|
|
throw new Error(
|
|
'EACCES: union write denied (BARE_OS_VFS_UNION_WRITE_DENY): ' + abs
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
/** Comma-separated absolute prefixes from `boot.policy` v3 (`denyVfsPrefixes`). */
|
|
function assertNotBootPolicyDenyVfs(abs, op) {
|
|
const raw = env.BARE_OS_BOOT_POLICY_DENY_VFS || ''
|
|
if (!raw.trim()) return
|
|
for (const p of raw.split(',')) {
|
|
const pre = p.trim()
|
|
if (!pre.startsWith('/')) continue
|
|
if (abs === pre || abs.startsWith(pre + '/')) {
|
|
throw new Error(`EACCES: boot policy denies ${op} (${pre}): ` + abs)
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Warm read-cache invalidation (decision matrix — operator + maintainer reference):
|
|
* | Trigger | Mechanism | Notes |
|
|
* | --- | --- | --- |
|
|
* | Full flush | `bareOsClearWarmReadCaches` | Clears `/bin` + `/lib/bare` maps; syscall proc cache reset in booter. |
|
|
* | Replication core growth | `BARE_OS_VFS_WARM_CACHE_INVALIDATE_ON_REPLICATION` + swarm hints | Prefix eviction via `bareOsInvalidateWarmReadCachesForReplicationPrefixes`. |
|
|
* | Batch `ctx.bareOsVfsBatchWrite` | `bareOsVfsBatchWrite` | Clears on `bin/` / `lib/bare/` puts. |
|
|
* | Manifest-only bundle rows | `bareOsEvictLibBareBundlesFromManifest` + `ctx.bareOsInvalidateWarmReadCachesFromBareManifestJson` | Targeted `/lib/bare/bundles/<ctxKey>.js` + manifest path. |
|
|
* | Parse errors on manifest JSON | `bareOsEvictLibBareBundlesFromManifest` | Falls back to **full** clear. |
|
|
*/
|
|
const binCacheEnabled =
|
|
env.BARE_OS_VFS_BIN_CACHE === '1' || env.BARE_OS_VFS_BIN_CACHE === 'true'
|
|
const binCacheBlake2b =
|
|
binCacheEnabled &&
|
|
(env.BARE_OS_VFS_BIN_CACHE_BLAKE2B === '1' ||
|
|
env.BARE_OS_VFS_BIN_CACHE_BLAKE2B === 'true')
|
|
/** @type {Map<string, Uint8Array> | null} */
|
|
const binReadCache = binCacheEnabled && !binCacheBlake2b ? new Map() : null
|
|
/** @type {Map<string, Uint8Array> | null} digest hex → bytes */
|
|
const binDigestCache = binCacheBlake2b ? new Map() : null
|
|
/** @type {Map<string, string> | null} logical path → digest */
|
|
const binPathToBlakeDigest = binCacheBlake2b ? new Map() : null
|
|
/** @type {Map<string, number> | null} digest refcount */
|
|
const binDigestRefcount = binCacheBlake2b ? new Map() : null
|
|
/** @type {string[] | null} */
|
|
const binBlake2bLruPaths = binCacheBlake2b ? [] : null
|
|
const BIN_READ_CACHE_MAX = 64
|
|
const libBareWarmCache =
|
|
binCacheEnabled &&
|
|
(env.BARE_OS_VFS_LIB_BARE_CACHE === '1' ||
|
|
env.BARE_OS_VFS_LIB_BARE_CACHE === 'true')
|
|
|
|
const warmReadCacheStats =
|
|
binReadCache || binDigestCache
|
|
? {
|
|
schema: 2,
|
|
hits: 0,
|
|
misses: 0,
|
|
binHits: 0,
|
|
libBareHits: 0,
|
|
libBareCacheEnabled: !!libBareWarmCache,
|
|
/** Last selective invalidation driven by replication core-length hints (metrics_live). */
|
|
replicationPrefixEviction: /** @type {{ atMs: number, pathsEvicted: number, prefixes: string[] } | null} */ (
|
|
null
|
|
)
|
|
}
|
|
: null
|
|
if (vfsOptions.warmReadCacheStatsRef && warmReadCacheStats) {
|
|
vfsOptions.warmReadCacheStatsRef.current = warmReadCacheStats
|
|
}
|
|
|
|
/** @param {string} abs */
|
|
function bumpWarmReadCacheHit(absFollowed) {
|
|
if (!warmReadCacheStats) return
|
|
warmReadCacheStats.hits++
|
|
if (absFollowed.startsWith('/lib/bare/')) warmReadCacheStats.libBareHits++
|
|
else warmReadCacheStats.binHits++
|
|
}
|
|
|
|
/** @param {string} abs */
|
|
function isWarmReadCachePath(abs) {
|
|
if (abs.startsWith('/bin/')) return true
|
|
return !!(libBareWarmCache && abs.startsWith('/lib/bare/'))
|
|
}
|
|
|
|
function touchBinBlake2bLru(p) {
|
|
if (!binBlake2bLruPaths || !binPathToBlakeDigest) return
|
|
const i = binBlake2bLruPaths.indexOf(p)
|
|
if (i >= 0) binBlake2bLruPaths.splice(i, 1)
|
|
binBlake2bLruPaths.push(p)
|
|
while (binBlake2bLruPaths.length > BIN_READ_CACHE_MAX) {
|
|
const victim = binBlake2bLruPaths.shift()
|
|
if (!victim) continue
|
|
const hex = binPathToBlakeDigest.get(victim)
|
|
if (!hex) continue
|
|
binPathToBlakeDigest.delete(victim)
|
|
const n = (binDigestRefcount.get(hex) || 1) - 1
|
|
if (n <= 0) {
|
|
binDigestRefcount.delete(hex)
|
|
binDigestCache.delete(hex)
|
|
} else {
|
|
binDigestRefcount.set(hex, n)
|
|
}
|
|
}
|
|
}
|
|
|
|
/** Drop `/bin` and `/lib/bare` warm read caches (replication / OTA safety). */
|
|
function bareOsClearWarmReadCaches() {
|
|
if (binReadCache) binReadCache.clear()
|
|
if (binDigestCache) binDigestCache.clear()
|
|
if (binPathToBlakeDigest) binPathToBlakeDigest.clear()
|
|
if (binDigestRefcount) binDigestRefcount.clear()
|
|
if (binBlake2bLruPaths) binBlake2bLruPaths.length = 0
|
|
if (warmReadCacheStats) {
|
|
warmReadCacheStats.hits = 0
|
|
warmReadCacheStats.misses = 0
|
|
warmReadCacheStats.binHits = 0
|
|
warmReadCacheStats.libBareHits = 0
|
|
warmReadCacheStats.replicationPrefixEviction = null
|
|
}
|
|
bareOsKernelMetricInc('vfs.warm_read_cache_clear')
|
|
}
|
|
|
|
/**
|
|
* Evict warm-cache rows whose logical paths start with one of the prefixes (replication / OTA).
|
|
* @param {string[]} prefixes
|
|
* @returns {number} paths evicted
|
|
*/
|
|
function bareOsEvictWarmReadPrefixes(prefixes) {
|
|
if (!binReadCache && !binDigestCache) return 0
|
|
const ps = (Array.isArray(prefixes) ? prefixes : [])
|
|
.map((p) => String(p || '').replace(/\\/g, '/'))
|
|
.filter((p) => p.startsWith('/'))
|
|
if (!ps.length) return 0
|
|
/** @type {string[]} */
|
|
const victims = []
|
|
const collect = (k) => {
|
|
if (!isWarmReadCachePath(k)) return
|
|
if (!ps.some((p) => k.startsWith(p))) return
|
|
victims.push(k)
|
|
}
|
|
if (binReadCache) {
|
|
for (const k of binReadCache.keys()) collect(k)
|
|
}
|
|
if (binPathToBlakeDigest) {
|
|
for (const k of binPathToBlakeDigest.keys()) collect(k)
|
|
}
|
|
for (const k of victims) bareOsEvictSingleWarmReadPath(k)
|
|
const n = victims.length
|
|
if (n > 0 && warmReadCacheStats) {
|
|
warmReadCacheStats.replicationPrefixEviction = {
|
|
atMs: Date.now(),
|
|
pathsEvicted: n,
|
|
prefixes: ps.slice(0, 16)
|
|
}
|
|
bareOsKernelMetricInc('vfs.warm_read_cache_invalidate_prefix')
|
|
}
|
|
return n
|
|
}
|
|
|
|
/** @param {string} absFollowed */
|
|
function bareOsEvictSingleWarmReadPath(absFollowed) {
|
|
if (!isWarmReadCachePath(absFollowed)) return
|
|
if (binReadCache) binReadCache.delete(absFollowed)
|
|
if (binDigestCache && binPathToBlakeDigest && binDigestRefcount) {
|
|
const oldHex = binPathToBlakeDigest.get(absFollowed)
|
|
if (oldHex) {
|
|
binPathToBlakeDigest.delete(absFollowed)
|
|
const n0 = (binDigestRefcount.get(oldHex) || 1) - 1
|
|
if (n0 <= 0) {
|
|
binDigestRefcount.delete(oldHex)
|
|
binDigestCache.delete(oldHex)
|
|
} else {
|
|
binDigestRefcount.set(oldHex, n0)
|
|
}
|
|
}
|
|
}
|
|
if (binBlake2bLruPaths) {
|
|
const i = binBlake2bLruPaths.indexOf(absFollowed)
|
|
if (i >= 0) binBlake2bLruPaths.splice(i, 1)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Invalidate warm-cache entries for `bare-module-manifest.json` and bundled
|
|
* `/lib/bare/bundles/<ctxKey>.js` rows (parse errors fall back to full clear).
|
|
* @param {Uint8Array | ArrayBuffer} buf
|
|
*/
|
|
function bareOsEvictLibBareBundlesFromManifest(buf) {
|
|
const u8 =
|
|
buf instanceof Uint8Array ? buf : new Uint8Array(/** @type {ArrayBuffer} */ (buf))
|
|
let text
|
|
try {
|
|
text = new TextDecoder().decode(u8)
|
|
} catch {
|
|
bareOsClearWarmReadCaches()
|
|
return
|
|
}
|
|
/** @type {unknown} */
|
|
let o
|
|
try {
|
|
o = JSON.parse(text)
|
|
} catch {
|
|
bareOsClearWarmReadCaches()
|
|
return
|
|
}
|
|
if (
|
|
!o ||
|
|
typeof o !== 'object' ||
|
|
!Array.isArray(/** @type {{ entries?: unknown }} */ (o).entries)
|
|
) {
|
|
bareOsClearWarmReadCaches()
|
|
return
|
|
}
|
|
bareOsEvictSingleWarmReadPath('/lib/bare/bare-module-manifest.json')
|
|
for (const e of /** @type {{ entries: unknown[] }} */ (o).entries) {
|
|
if (!e || typeof e !== 'object') continue
|
|
const ent = /** @type {{ bundle?: boolean, ctxKey?: string }} */ (e)
|
|
if (ent.bundle !== true) continue
|
|
const ck = String(ent.ctxKey || '').trim()
|
|
if (!ck) continue
|
|
bareOsEvictSingleWarmReadPath(`/lib/bare/bundles/${ck}.js`)
|
|
}
|
|
bareOsKernelMetricInc('vfs.warm_read_cache_evict_manifest')
|
|
}
|
|
|
|
const sysClassNetLoText =
|
|
typeof vfsOptions.sysClassNetLoText === 'function'
|
|
? vfsOptions.sysClassNetLoText
|
|
: null
|
|
const hostProcStatsRef =
|
|
vfsOptions.hostProcStatsRef &&
|
|
typeof vfsOptions.hostProcStatsRef === 'object'
|
|
? vfsOptions.hostProcStatsRef
|
|
: null
|
|
const ipcFifoLogicalToActual =
|
|
typeof vfsOptions.ipcFifoLogicalToActual === 'function'
|
|
? vfsOptions.ipcFifoLogicalToActual
|
|
: (/** @type {string} */ n) => bareOsIpcLogicalToActualFifoName(n, env)
|
|
const getProcSelfExtraFds =
|
|
typeof vfsOptions.getProcSelfExtraFds === 'function'
|
|
? vfsOptions.getProcSelfExtraFds
|
|
: null
|
|
const HOME = () => env.HOME || '/home/guest'
|
|
let cwd = env.PWD || HOME()
|
|
|
|
const injectedIdentityRef = vfsOptions.bareOsIdentityVfsRef
|
|
/** @type {{ session: 'guest' | 'unlocked' }} */
|
|
const bareOsIdentityVfsRef =
|
|
injectedIdentityRef &&
|
|
typeof injectedIdentityRef === 'object' &&
|
|
(injectedIdentityRef.session === 'guest' ||
|
|
injectedIdentityRef.session === 'unlocked')
|
|
? injectedIdentityRef
|
|
: { session: 'guest' }
|
|
|
|
function usePersonalAcctPrefix() {
|
|
return (
|
|
env &&
|
|
(env.BARE_OS_PERSONAL_ACCT_PREFIX === '1' ||
|
|
env.BARE_OS_PERSONAL_ACCT_PREFIX === 'true')
|
|
)
|
|
}
|
|
|
|
function personalAcctLayoutSubpath() {
|
|
if (!usePersonalAcctPrefix()) return ''
|
|
const seg = activeHomeBasename()
|
|
if (!seg) return 'acct/_nosession'
|
|
if (seg === 'guest') return 'acct/_guest'
|
|
const uid = String(env.UID || '').trim()
|
|
if (uid && uid !== '65534') return `acct/u${uid}`
|
|
return `acct/h${seg}`
|
|
}
|
|
|
|
/** `/.bare-os` or `/.bare-os/acct/…` when {@link usePersonalAcctPrefix}. */
|
|
function personalLayoutRootAbs() {
|
|
const rel = personalAcctLayoutSubpath()
|
|
return rel ? `/.bare-os/${rel}` : '/.bare-os'
|
|
}
|
|
|
|
function normalizeHome() {
|
|
const h = HOME()
|
|
return h.length > 1 && h.endsWith('/') ? h.slice(0, -1) : h
|
|
}
|
|
|
|
/** First path segment under /home for $HOME (e.g. guest, eeb18de988e9); null if HOME is not /home/… */
|
|
function activeHomeBasename() {
|
|
const h = normalizeHome()
|
|
if (!h.startsWith('/home/')) return null
|
|
const seg = h.slice('/home/'.length).split('/')[0]
|
|
return seg || null
|
|
}
|
|
|
|
/** Session home tree on the personal drive (isolates guest vs unlocked users). */
|
|
function personalHomeStorageRoot() {
|
|
const seg = activeHomeBasename()
|
|
const homeRel = seg ? `home/${seg}` : 'home/_nosession'
|
|
return `${personalLayoutRootAbs()}/${homeRel}`
|
|
}
|
|
|
|
/** Personal-drive backing for logical `/var/log/…` (per session segment). */
|
|
function varLogStorageRoot() {
|
|
const seg = activeHomeBasename()
|
|
const sub = seg ? `var/log/${seg}` : 'var/log/_nosession'
|
|
return `${personalLayoutRootAbs()}/${sub}`
|
|
}
|
|
|
|
/** Session-isolated writable `/tmp` on the personal drive. */
|
|
function tmpStorageRoot() {
|
|
const seg = activeHomeBasename()
|
|
const sub = seg ? `tmp/${seg}` : 'tmp/_nosession'
|
|
return `${personalLayoutRootAbs()}/${sub}`
|
|
}
|
|
|
|
/**
|
|
* Guest cannot read sealed identity material on the personal drive (override with BARE_OS_GUEST_BARE_READ_ALL=1).
|
|
* @param {string} personalPath absolute on personal Hyperdrive
|
|
*/
|
|
function bareOsGuestSensitivePersonalDenied(personalPath) {
|
|
if (
|
|
env &&
|
|
(env.BARE_OS_GUEST_BARE_READ_ALL === '1' ||
|
|
env.BARE_OS_GUEST_BARE_READ_ALL === 'true')
|
|
) {
|
|
return false
|
|
}
|
|
if (bareOsIdentityVfsRef.session === 'unlocked') return false
|
|
const norm = String(personalPath || '').replace(/\/+$/, '') || '/'
|
|
if (/\/\.bare\/account(\/|$)/.test(norm)) return true
|
|
if (/\/\.bare\/vault(\/|$)/.test(norm)) return true
|
|
if (norm.endsWith('/.bare/vault-rotation-audit.ndjson')) return true
|
|
return false
|
|
}
|
|
|
|
/**
|
|
* @param {unknown} drive
|
|
* @param {string} personalPath
|
|
* @param {string} op
|
|
* @param {string} logicalAbs
|
|
*/
|
|
function assertGuestSensitivePersonalOp(drive, personalPath, op, logicalAbs) {
|
|
if (drive !== personalDrive) return
|
|
if (!bareOsGuestSensitivePersonalDenied(personalPath)) return
|
|
throw new Error(
|
|
`EACCES: ${op} denied for guest on sensitive /.bare path: ` + logicalAbs
|
|
)
|
|
}
|
|
|
|
const ENV_SECRET_HINT = new RegExp(
|
|
'PASSWORD|SECRET|TOKEN|AUTH|KEY|VAULT|PRIVATE|CREDENTIAL|PASSPHRASE',
|
|
'i'
|
|
)
|
|
|
|
const ENV_PUBLIC_KEYS = new Set([
|
|
'HOME',
|
|
'USER',
|
|
'LOGNAME',
|
|
'PATH',
|
|
'PWD',
|
|
'SHELL',
|
|
'HOSTNAME',
|
|
'UID',
|
|
'GID',
|
|
'GROUP',
|
|
'TERM',
|
|
'LANG',
|
|
'LC_ALL',
|
|
'EDITOR',
|
|
'BARE_OS_EXIT_STATUS',
|
|
'BARE_OS_IDENTITY',
|
|
'BARE_OS_CTX_API_VERSION',
|
|
'BARE_OS_SESSION_ID'
|
|
])
|
|
|
|
function environKeyAllowed(k) {
|
|
if (ENV_SECRET_HINT.test(k)) return false
|
|
if (ENV_PUBLIC_KEYS.has(k)) return true
|
|
if (k.startsWith('BARE_OS_')) return true
|
|
return false
|
|
}
|
|
|
|
function pseudoVersionText() {
|
|
const v = procSnapshot?.version ?? env.BARE_OS_CTX_API_VERSION ?? 'unknown'
|
|
let out = `Bare OS\nbare_os_ctx_api_version=${v}\n`
|
|
const tty = String(env.BARE_OS_PEAR_TTY_FLAGS_JSON || '').trim()
|
|
if (tty) {
|
|
out += `pear_tty_flags_json=${tty.slice(0, 512)}\n`
|
|
}
|
|
return out
|
|
}
|
|
|
|
function pseudoCmdlineText() {
|
|
return `${procSnapshot?.cmdline ?? 'bare-os'}\n`
|
|
}
|
|
|
|
/** UTF-8 bytes; Bare may not define global TextEncoder (see curl-cli utf8Encode). */
|
|
function utf8Encode(str) {
|
|
return b4a.from(String(str), 'utf8')
|
|
}
|
|
|
|
function listProcSelfFdDirNames() {
|
|
const names = new Set(['0', '1', '2'])
|
|
const extra = getProcSelfExtraFds ? getProcSelfExtraFds() : []
|
|
for (const e of extra) {
|
|
if (e && e.fdNum && /^[0-9]+$/.test(String(e.fdNum))) {
|
|
names.add(String(e.fdNum))
|
|
}
|
|
}
|
|
return [...names].sort((a, b) => Number(a) - Number(b))
|
|
}
|
|
|
|
function encodeProcSelfFdSymlink(fdNumRaw) {
|
|
const n = String(fdNumRaw ?? '0')
|
|
if (n === '0' || n === '1' || n === '2') {
|
|
return utf8Encode(
|
|
`/proc/self/fd/${n} -> (bare-os stdio pseudo inode)\n`
|
|
)
|
|
}
|
|
const extra = getProcSelfExtraFds ? getProcSelfExtraFds() : []
|
|
const hit = extra.find((e) => e && String(e.fdNum) === n)
|
|
if (hit && hit.target) {
|
|
return utf8Encode(`/proc/self/fd/${n} -> ${hit.target}\n`)
|
|
}
|
|
return utf8Encode(`/proc/self/fd/${n} -> (not open)\n`)
|
|
}
|
|
|
|
function pseudoEnvironBytes() {
|
|
const parts = []
|
|
for (const k of Object.keys(env).sort()) {
|
|
if (!environKeyAllowed(k)) continue
|
|
const v = env[k]
|
|
if (typeof v !== 'string') continue
|
|
parts.push(`${k}=${v}\0`)
|
|
}
|
|
return utf8Encode(parts.join(''))
|
|
}
|
|
|
|
function pseudoUptimeText() {
|
|
const start = bootStartedMs != null ? bootStartedMs : Date.now()
|
|
const up = Math.max(0, (Date.now() - start) / 1000)
|
|
return `${up.toFixed(2)} ${up.toFixed(2)}\n`
|
|
}
|
|
|
|
function pseudoMeminfoText() {
|
|
const snap = hostProcStatsRef?.stats
|
|
const mu =
|
|
snap &&
|
|
typeof snap === 'object' &&
|
|
snap !== null &&
|
|
/** @type {{ memoryUsage?: () => unknown }} */ (snap).memoryUsage
|
|
? /** @type {{ memoryUsage: () => { rss?: number, heapTotal?: number, heapUsed?: number, external?: number } }} */ (
|
|
snap
|
|
).memoryUsage()
|
|
: null
|
|
if (mu && typeof mu === 'object') {
|
|
const rss = Number(mu.rss) || 0
|
|
const heap = Number(mu.heapUsed) || 0
|
|
const total = Math.max(rss, heap, 1)
|
|
const kb = (n) => Math.max(0, Math.floor(n / 1024))
|
|
return [
|
|
`MemTotal: ${kb(total * 2)} kB`,
|
|
`MemFree: ${kb(Math.max(0, total - heap))} kB`,
|
|
`MemAvailable: ${kb(Math.max(0, total - heap))} kB`,
|
|
'SwapTotal: 0 kB',
|
|
'SwapFree: 0 kB',
|
|
'BogoSource: bare-os host memoryUsage snapshot',
|
|
''
|
|
].join('\n')
|
|
}
|
|
return [
|
|
'MemTotal: 524288 kB',
|
|
'MemFree: 262144 kB',
|
|
'MemAvailable: 262144 kB',
|
|
'SwapTotal: 0 kB',
|
|
'SwapFree: 0 kB',
|
|
''
|
|
].join('\n')
|
|
}
|
|
|
|
function pseudoCpuinfoText() {
|
|
const snap = hostProcStatsRef?.stats
|
|
const cpus =
|
|
snap &&
|
|
typeof snap === 'object' &&
|
|
snap !== null &&
|
|
typeof (/** @type {{ cpus?: () => unknown[] }} */ (snap).cpus) ===
|
|
'function'
|
|
? /** @type {{ cpus: () => unknown[] }} */ (snap).cpus()
|
|
: null
|
|
if (Array.isArray(cpus) && cpus.length > 0) {
|
|
const lines = []
|
|
let i = 0
|
|
for (const c of cpus) {
|
|
const m =
|
|
c && typeof c === 'object' && 'model' in c
|
|
? String(/** @type {{ model?: string }} */ (c).model || '')
|
|
: ''
|
|
const sp =
|
|
c && typeof c === 'object' && 'speed' in c
|
|
? Number(/** @type {{ speed?: number }} */ (c).speed) || 0
|
|
: 0
|
|
lines.push(`processor\t: ${i}`)
|
|
lines.push(`vendor_id\t: host`)
|
|
lines.push(`model name\t: ${m || 'host CPU (bare-os snapshot)'}`)
|
|
lines.push(`cpu MHz\t\t: ${sp}`)
|
|
lines.push(`flags\t: bare_os_host_stats`)
|
|
lines.push('')
|
|
i++
|
|
}
|
|
return lines.join('\n')
|
|
}
|
|
return [
|
|
'processor\t: 0',
|
|
'vendor_id\t: BareOS',
|
|
'model name\t: Bare OS pseudo CPU (vfs-backed)',
|
|
'flags\t: bare_os',
|
|
''
|
|
].join('\n')
|
|
}
|
|
|
|
function pseudoLoadavgText() {
|
|
return '0.05 0.04 0.02 1/64 1\n'
|
|
}
|
|
|
|
function pseudoSelfExeText() {
|
|
return '/bin/sh (bare-os pseudo inode; no backing host file)\n'
|
|
}
|
|
|
|
function bareOsSanitizeCgroupSegment(s) {
|
|
return String(s || 'unknown')
|
|
.replace(/[^a-zA-Z0-9._-]/g, '_')
|
|
.slice(0, 128)
|
|
}
|
|
|
|
/** @returns {{ sessionId: string, swarmPeerCount: number, peerIds: string[] }} */
|
|
function readProcSyntheticLinuxCompat() {
|
|
let sessionId = String(env.BARE_OS_SESSION_ID || env.BARE_OS_TRACE_ID || '')
|
|
.trim()
|
|
let swarmPeerCount = 0
|
|
let peerIds = []
|
|
try {
|
|
const h = getProcSyntheticLinuxCompat ? getProcSyntheticLinuxCompat() : null
|
|
if (h && typeof h === 'object') {
|
|
if (h.sessionId != null && String(h.sessionId).trim())
|
|
sessionId = String(h.sessionId).trim()
|
|
const n = Number(h.swarmPeerCount)
|
|
if (Number.isFinite(n) && n >= 0) swarmPeerCount = Math.min(4096, n | 0)
|
|
if (Array.isArray(h.peerIds))
|
|
peerIds = h.peerIds.map((x) => String(x || '')).filter(Boolean)
|
|
}
|
|
} catch {
|
|
/* ignore */
|
|
}
|
|
if (!sessionId) sessionId = 'session'
|
|
return { sessionId, swarmPeerCount, peerIds }
|
|
}
|
|
|
|
/**
|
|
* Linux cgroup v2 single-column lines, scoped to the guest session (not host cgroups).
|
|
*/
|
|
function pseudoSelfCgroupsText() {
|
|
const { sessionId } = readProcSyntheticLinuxCompat()
|
|
const sid = bareOsSanitizeCgroupSegment(sessionId)
|
|
return [
|
|
'# bare_os synthetic cgroup v2 view (guest session + swarm scope; not the host cgroup hierarchy)',
|
|
'0::/bare-os.scope',
|
|
`0::/bare-os.session/${sid}/init`,
|
|
`0::/bare-os.session/${sid}/swarm`,
|
|
''
|
|
].join('\n')
|
|
}
|
|
|
|
/** IPv4:port as in /proc/net/tcp (little-endian quad hex + port hex). */
|
|
function bareOsProcNetIpv4PortHex(ip, port) {
|
|
const parts = String(ip || '0.0.0.0').split('.')
|
|
const a = Number(parts[0]) || 0
|
|
const b = Number(parts[1]) || 0
|
|
const c = Number(parts[2]) || 0
|
|
const d = Number(parts[3]) || 0
|
|
const addr = (a | (b << 8) | (c << 16) | (d << 24)) >>> 0
|
|
const p = port & 0xffff
|
|
return (
|
|
addr.toString(16).padStart(8, '0') +
|
|
':' +
|
|
p.toString(16).padStart(4, '0')
|
|
)
|
|
}
|
|
|
|
/**
|
|
* Logical Hyperswarm / replication streams as Linux-shaped /proc/net/tcp rows (inode encodes slot).
|
|
*/
|
|
function pseudoNetTcpText() {
|
|
const { swarmPeerCount, peerIds } = readProcSyntheticLinuxCompat()
|
|
const nPeers = Math.max(swarmPeerCount, peerIds.length)
|
|
const lines = [
|
|
' sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode',
|
|
'# bare_os: logical swarm/replication endpoints (not host TCP); st 0A=LISTEN 01=ESTABLISHED'
|
|
]
|
|
lines.push(
|
|
` 0: ${bareOsProcNetIpv4PortHex('127.0.0.1', 57800)} 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 800000`
|
|
)
|
|
let inode = 800001
|
|
for (let i = 0; i < nPeers; i++) {
|
|
const id = peerIds[i] || '0'.repeat(64)
|
|
const h = id.slice(0, 8) || '00000000'
|
|
const v = Number.parseInt(h, 16) || 0
|
|
const o1 = v & 255
|
|
const o2 = (v >>> 8) & 255
|
|
const o3 = (v >>> 16) & 255
|
|
const o4 = (v >>> 24) & 255
|
|
const remIp = `${o1}.${o2}.${o3}.${o4}`
|
|
lines.push(
|
|
` ${i + 1}: ${bareOsProcNetIpv4PortHex('127.0.0.1', 58000 + i)} ${bareOsProcNetIpv4PortHex(remIp, 57900 + i)} 01 00000000:00000000 00:00000000 00000000 0 0 ${inode}`
|
|
)
|
|
inode++
|
|
}
|
|
lines.push('')
|
|
return lines.join('\n')
|
|
}
|
|
|
|
function pseudoNetUdpText() {
|
|
const { swarmPeerCount } = readProcSyntheticLinuxCompat()
|
|
const lines = [
|
|
' sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode ref',
|
|
'# bare_os: logical UDP-shaped discovery/datagram hints (not host UDP)'
|
|
]
|
|
lines.push(
|
|
` 0: ${bareOsProcNetIpv4PortHex('0.0.0.0', 49721)} 00000000:0000 07 00000000:00000000 00:00000000 00000000 0 0 810000 2`
|
|
)
|
|
if (swarmPeerCount > 0) {
|
|
lines.push(
|
|
` 1: ${bareOsProcNetIpv4PortHex('127.0.0.1', 49722)} 00000000:0000 07 00000000:00000000 00:00000000 00000000 0 0 810001 2`
|
|
)
|
|
}
|
|
lines.push('')
|
|
return lines.join('\n')
|
|
}
|
|
|
|
/**
|
|
* When the booter supplies `secureRandomBytes` (e.g. bare-crypto), reads are suitable
|
|
* for cryptographic use; otherwise falls back to Math.random (not crypto-grade).
|
|
*/
|
|
function pseudoUrandomBytes() {
|
|
const n = 4096
|
|
if (secureRandomBytes) {
|
|
try {
|
|
return secureRandomBytes(n)
|
|
} catch {
|
|
/* fall through */
|
|
}
|
|
}
|
|
const u = new Uint8Array(n)
|
|
for (let i = 0; i < n; i++) u[i] = Math.floor(Math.random() * 256)
|
|
return u
|
|
}
|
|
|
|
function pseudoFileBytes(routePseudo) {
|
|
const f = routePseudo.file
|
|
const k = routePseudo.kind
|
|
if (f === 'version' && (k === 'proc' || k === 'sys')) {
|
|
return utf8Encode(pseudoVersionText())
|
|
}
|
|
if (k === 'sys' && f === 'build_id') {
|
|
const t = buildIdText ? buildIdText() : 'unknown\n'
|
|
return utf8Encode(t)
|
|
}
|
|
if (k === 'proc') {
|
|
if (f === 'cmdline') return utf8Encode(pseudoCmdlineText())
|
|
if (f === 'environ') return pseudoEnvironBytes()
|
|
if (f === 'uptime') return utf8Encode(pseudoUptimeText())
|
|
if (f === 'meminfo') return utf8Encode(pseudoMeminfoText())
|
|
if (f === 'cpuinfo') return utf8Encode(pseudoCpuinfoText())
|
|
if (f === 'loadavg') return utf8Encode(pseudoLoadavgText())
|
|
if (f === 'exe') return utf8Encode(pseudoSelfExeText())
|
|
if (f === 'self_cgroups') return utf8Encode(pseudoSelfCgroupsText())
|
|
if (f === 'self_limits') {
|
|
const t = procBareOsSelfLimitsText
|
|
? procBareOsSelfLimitsText()
|
|
: 'Limit Soft Limit Hard Limit Units\n'
|
|
return utf8Encode(t)
|
|
}
|
|
if (f === 'mounts') return utf8Encode(pseudoMountsText())
|
|
if (f === 'bare_os_session_stats') {
|
|
const t = sessionStatsText ? sessionStatsText() : '{}\n'
|
|
return utf8Encode(t)
|
|
}
|
|
if (f === 'diskstats') {
|
|
const t = procDiskstatsText
|
|
? procDiskstatsText()
|
|
: '# bare-os diskstats (no procDiskstatsText provider)\n'
|
|
return utf8Encode(t)
|
|
}
|
|
if (f === 'bare_os_quotas') {
|
|
const t = procBareOsQuotasText ? procBareOsQuotasText() : '{}\n'
|
|
return utf8Encode(t)
|
|
}
|
|
if (f === 'bare_os_resources') {
|
|
const t = procBareOsResourcesText ? procBareOsResourcesText() : '{}\n'
|
|
return utf8Encode(t)
|
|
}
|
|
if (f === 'bare_os_features') {
|
|
const t = procBareOsFeaturesText ? procBareOsFeaturesText() : '{}\n'
|
|
return utf8Encode(t)
|
|
}
|
|
if (f === 'bare_os_swarm') {
|
|
const t = procBareOsSwarmText ? procBareOsSwarmText() : '{}\n'
|
|
return utf8Encode(t)
|
|
}
|
|
if (f === 'bare_os_swarm_health') {
|
|
const t = procBareOsSwarmHealthText
|
|
? procBareOsSwarmHealthText()
|
|
: '{}\n'
|
|
return utf8Encode(t)
|
|
}
|
|
if (
|
|
f.startsWith('bare_os_swarm_') &&
|
|
f.endsWith('_status') &&
|
|
f !== 'bare_os_swarm_health'
|
|
) {
|
|
const t =
|
|
procBareOsSwarmSubsystemStatusJsonText &&
|
|
procBareOsSwarmSubsystemStatusJsonText(f)
|
|
return utf8Encode(
|
|
t && typeof t === 'string' && t.length
|
|
? t
|
|
: JSON.stringify({
|
|
schema: 1,
|
|
file: f,
|
|
status: 'unavailable',
|
|
note:
|
|
'procBareOsSwarmSubsystemStatusJsonText missing or returned empty'
|
|
}) + '\n'
|
|
)
|
|
}
|
|
if (f === 'bare_os_replication') {
|
|
const t = procBareOsReplicationText
|
|
? procBareOsReplicationText()
|
|
: '{}\n'
|
|
return utf8Encode(t)
|
|
}
|
|
if (f === 'bare_os_capabilities') {
|
|
const t = procBareOsCapabilitiesText
|
|
? procBareOsCapabilitiesText()
|
|
: '(no snapshot)\n'
|
|
return utf8Encode(t)
|
|
}
|
|
if (f === 'bare_os_capabilities_json') {
|
|
const t = procBareOsCapabilitiesJsonText
|
|
? procBareOsCapabilitiesJsonText()
|
|
: '{}\n'
|
|
return utf8Encode(t)
|
|
}
|
|
if (f === 'bare_os_bootstrap') {
|
|
const t = procBareOsBootstrapText ? procBareOsBootstrapText() : '{}\n'
|
|
return utf8Encode(t)
|
|
}
|
|
if (f === 'bare_os_union') {
|
|
const t = procBareOsUnionText ? procBareOsUnionText() : '{}\n'
|
|
return utf8Encode(t)
|
|
}
|
|
if (f === 'bare_os_seed_handshake') {
|
|
const t = procBareOsSeedHandshakeText
|
|
? procBareOsSeedHandshakeText()
|
|
: '{}\n'
|
|
return utf8Encode(t)
|
|
}
|
|
if (f === 'bare_os_manifest_hints') {
|
|
const t = procBareOsManifestHintsText
|
|
? procBareOsManifestHintsText()
|
|
: 'null\n'
|
|
return utf8Encode(t)
|
|
}
|
|
if (f === 'bare_os_peer_health') {
|
|
const t = procBareOsPeerHealthText
|
|
? procBareOsPeerHealthText()
|
|
: 'null\n'
|
|
return utf8Encode(t)
|
|
}
|
|
if (f === 'bare_os_staging_slot') {
|
|
const t = procBareOsStagingSlotText
|
|
? procBareOsStagingSlotText()
|
|
: 'null\n'
|
|
return utf8Encode(t)
|
|
}
|
|
if (f === 'bare_os_snapshot_hints') {
|
|
const t = procBareOsSnapshotHintsText
|
|
? procBareOsSnapshotHintsText()
|
|
: 'null\n'
|
|
return utf8Encode(t)
|
|
}
|
|
if (f === 'bare_os_provenance') {
|
|
const t = procBareOsProvenanceText ? procBareOsProvenanceText() : '{}\n'
|
|
return utf8Encode(t)
|
|
}
|
|
if (f === 'bare_os_pear_ipc_registry') {
|
|
const t = procBareOsPearIpcRegistryText
|
|
? procBareOsPearIpcRegistryText()
|
|
: '{}\n'
|
|
return utf8Encode(t)
|
|
}
|
|
if (f === 'bare_os_initd_dag') {
|
|
const t = procBareOsInitdDagText ? procBareOsInitdDagText() : 'null\n'
|
|
return utf8Encode(t)
|
|
}
|
|
if (f === 'bare_os_initd_readiness') {
|
|
const t = procBareOsInitdReadinessText
|
|
? procBareOsInitdReadinessText()
|
|
: '{"schema":2,"units":[],"note":"initd readiness provider missing","atMs":0}\n'
|
|
return utf8Encode(t)
|
|
}
|
|
if (f === 'bare_os_boot_graph') {
|
|
const t = procBareOsBootGraphJsonText
|
|
? procBareOsBootGraphJsonText()
|
|
: `${JSON.stringify({
|
|
schema: 1,
|
|
note: 'boot graph provider missing',
|
|
nodes: [],
|
|
edges: []
|
|
})}\n`
|
|
return utf8Encode(t)
|
|
}
|
|
if (f === 'bare_os_boot_budget_summary') {
|
|
const t = procBareOsBootBudgetSummaryText
|
|
? procBareOsBootBudgetSummaryText()
|
|
: '{"schema":1,"note":"boot_budget_summary_provider_missing"}\n'
|
|
return utf8Encode(t)
|
|
}
|
|
if (f === 'bare_os_metrics_live') {
|
|
const t = procBareOsMetricsLiveText
|
|
? procBareOsMetricsLiveText()
|
|
: '{}\n'
|
|
return utf8Encode(t)
|
|
}
|
|
if (f === 'bare_os_chat') {
|
|
const t = procBareOsChatText ? procBareOsChatText() : '{}\n'
|
|
return utf8Encode(t)
|
|
}
|
|
if (f === 'bare_os_meshdrop') {
|
|
const t = procBareOsMeshdropText ? procBareOsMeshdropText() : '{}\n'
|
|
return utf8Encode(t)
|
|
}
|
|
if (f === 'bare_os_peer_details') {
|
|
const t = procBareOsPeerDetailsText ? procBareOsPeerDetailsText() : '{}\n'
|
|
return utf8Encode(t)
|
|
}
|
|
if (f === 'bare_os_dht_scan') {
|
|
const t = procBareOsDhtScanText ? procBareOsDhtScanText() : '{}\n'
|
|
return utf8Encode(t)
|
|
}
|
|
if (f === 'bare_os_swarm_doctor') {
|
|
const t = procBareOsSwarmDoctorText ? procBareOsSwarmDoctorText() : '{}\n'
|
|
return utf8Encode(t)
|
|
}
|
|
if (f === 'bare_os_route_summary') {
|
|
const t = procBareOsRouteSummaryText ? procBareOsRouteSummaryText() : '{}\n'
|
|
return utf8Encode(t)
|
|
}
|
|
if (f === 'bare_os_holepunch_summary') {
|
|
const t = procBareOsHolepunchSummaryText
|
|
? procBareOsHolepunchSummaryText()
|
|
: '{}\n'
|
|
return utf8Encode(t)
|
|
}
|
|
if (f === 'bare_os_process_table') {
|
|
const t = procBareOsProcessTableText
|
|
? procBareOsProcessTableText()
|
|
: '{"schema":1,"processes":[]}\n'
|
|
return utf8Encode(t)
|
|
}
|
|
if (f === 'bare_os_process_io') {
|
|
const t = procBareOsProcessIoText
|
|
? procBareOsProcessIoText()
|
|
: '{"schema":1,"byPid":[]}\n'
|
|
return utf8Encode(t)
|
|
}
|
|
if (f === 'bare_os_process_threads') {
|
|
const t = procBareOsProcessThreadsText
|
|
? procBareOsProcessThreadsText()
|
|
: '{"schema":1,"byPid":[]}\n'
|
|
return utf8Encode(t)
|
|
}
|
|
if (f === 'bare_os_process_maps') {
|
|
const t = procBareOsProcessMapsText
|
|
? procBareOsProcessMapsText()
|
|
: '{"schema":1,"regions":[]}\n'
|
|
return utf8Encode(t)
|
|
}
|
|
if (f === 'bare_os_syscalls') {
|
|
const t = procBareOsSyscallsText
|
|
? procBareOsSyscallsText()
|
|
: '{"schemaVersion":5,"ops":[],"errnoHints":{},"fdModel":{"schema":1},"signalModel":{"schema":1,"names":[]}}\n'
|
|
return utf8Encode(t)
|
|
}
|
|
if (f === 'bare_os_metrics_prom') {
|
|
const t = procBareOsMetricsPromText
|
|
? procBareOsMetricsPromText()
|
|
: '# TYPE bare_os_kernel_counters counter\n'
|
|
return utf8Encode(t)
|
|
}
|
|
if (f === 'bare_os_protomux_wire') {
|
|
const t = procBareOsProtomuxWireText
|
|
? procBareOsProtomuxWireText()
|
|
: '{"schemaVersion":1,"aliases":{}}\n'
|
|
return utf8Encode(t)
|
|
}
|
|
if (f === 'bare_os_protomux_extensions') {
|
|
const t = procBareOsProtomuxExtensionsText
|
|
? procBareOsProtomuxExtensionsText()
|
|
: '{"schema":1,"exposed":false}\n'
|
|
return utf8Encode(t)
|
|
}
|
|
if (f === 'bare_os_net_summary') {
|
|
const t = procBareOsNetSummaryText
|
|
? procBareOsNetSummaryText()
|
|
: '{}\n'
|
|
return utf8Encode(t)
|
|
}
|
|
if (f === 'bare_os_extensions') {
|
|
const t = procBareOsExtensionsText
|
|
? procBareOsExtensionsText()
|
|
: '{"schema":1,"entries":[]}\n'
|
|
return utf8Encode(t)
|
|
}
|
|
if (f === 'bare_os_hdms_hints') {
|
|
const t = procBareOsHdmsHintsText ? procBareOsHdmsHintsText() : '{}\n'
|
|
return utf8Encode(t)
|
|
}
|
|
if (f === 'bare_os_pear_trust') {
|
|
const t = procBareOsPearTrustText ? procBareOsPearTrustText() : '{}\n'
|
|
return utf8Encode(t)
|
|
}
|
|
if (f === 'bare_os_security_posture') {
|
|
const t = procBareOsSecurityPostureText
|
|
? procBareOsSecurityPostureText()
|
|
: '{}\n'
|
|
return utf8Encode(t)
|
|
}
|
|
if (f === 'bare_os_rlimits') {
|
|
const t = procBareOsRlimitsText ? procBareOsRlimitsText() : '{}\n'
|
|
return utf8Encode(t)
|
|
}
|
|
if (f === 'bare_os_hdms_health') {
|
|
const t = procBareOsHdmsHealthText ? procBareOsHdmsHealthText() : '{}\n'
|
|
return utf8Encode(t)
|
|
}
|
|
if (f === 'bare_os_initd_graph') {
|
|
const t = procBareOsInitdDagText ? procBareOsInitdDagText() : 'null\n'
|
|
return utf8Encode(t)
|
|
}
|
|
if (f === 'net_tcp') {
|
|
return utf8Encode(pseudoNetTcpText())
|
|
}
|
|
if (f === 'net_udp') {
|
|
return utf8Encode(pseudoNetUdpText())
|
|
}
|
|
if (f === 'bare_os_virtual_registry') {
|
|
const t = procBareOsVirtualRegistryText
|
|
? procBareOsVirtualRegistryText()
|
|
: '[]\n'
|
|
return utf8Encode(t)
|
|
}
|
|
if (f === 'bare_os_host_os') {
|
|
const t = procBareOsHostOsText ? procBareOsHostOsText() : '{}\n'
|
|
return utf8Encode(t)
|
|
}
|
|
if (f === 'bare_os_sync_window') {
|
|
const t = procBareOsSyncWindowText ? procBareOsSyncWindowText() : '{}\n'
|
|
return utf8Encode(t)
|
|
}
|
|
if (f === 'bare_os_clock') {
|
|
const t = procBareOsClockText ? procBareOsClockText() : '{}\n'
|
|
return utf8Encode(t)
|
|
}
|
|
if (f === 'bare_os_openssh') {
|
|
const t = procBareOsOpensshText ? procBareOsOpensshText() : '{}\n'
|
|
return utf8Encode(t)
|
|
}
|
|
if (f === 'bare_os_debug') {
|
|
const t = procBareOsDebugText ? procBareOsDebugText() : '{}\n'
|
|
return utf8Encode(t)
|
|
}
|
|
{
|
|
const wid = BARE_OS_PROC_FILE_TO_ID_REPLICATION_OPERATOR_SURFACE[f]
|
|
if (wid) {
|
|
const t = procBareOsReplicationOperatorSurfaceJsonText
|
|
? procBareOsReplicationOperatorSurfaceJsonText(wid)
|
|
: `${JSON.stringify({
|
|
schema: 1,
|
|
note: 'wave6 proc provider missing'
|
|
})}\n`
|
|
return utf8Encode(t)
|
|
}
|
|
}
|
|
{
|
|
const pearCorestoreHrpcWid = BARE_OS_PROC_FILE_TO_ID_PEAR_CORESTORE_HRPC[f]
|
|
if (pearCorestoreHrpcWid) {
|
|
const t = procBareOsPearCorestoreHrpcJsonText
|
|
? procBareOsPearCorestoreHrpcJsonText(pearCorestoreHrpcWid)
|
|
: `${JSON.stringify({
|
|
schema: 1,
|
|
note: 'wave7 proc provider missing'
|
|
})}\n`
|
|
return utf8Encode(t)
|
|
}
|
|
}
|
|
{
|
|
const bareRuntimeProtoMuxWid = BARE_OS_PROC_FILE_TO_ID_BARE_RUNTIME_PROTO_MUX[f]
|
|
if (bareRuntimeProtoMuxWid) {
|
|
const t = procBareOsBareRuntimeProtoMuxJsonText
|
|
? procBareOsBareRuntimeProtoMuxJsonText(bareRuntimeProtoMuxWid)
|
|
: `${JSON.stringify({
|
|
schema: 1,
|
|
note: 'wave8 proc provider missing'
|
|
})}\n`
|
|
return utf8Encode(t)
|
|
}
|
|
}
|
|
{
|
|
const bareModuleCryptoStagingWid = BARE_OS_PROC_FILE_TO_ID_BARE_MODULE_CRYPTO_STAGING[f]
|
|
if (bareModuleCryptoStagingWid) {
|
|
const t = procBareOsBareModuleCryptoStagingJsonText
|
|
? procBareOsBareModuleCryptoStagingJsonText(bareModuleCryptoStagingWid)
|
|
: `${JSON.stringify({
|
|
schema: 1,
|
|
note: 'wave9 proc provider missing'
|
|
})}\n`
|
|
return utf8Encode(t)
|
|
}
|
|
}
|
|
{
|
|
const pearInspectLoggerTlsWid = BARE_OS_PROC_FILE_TO_ID_PEAR_INSPECT_LOGGER_TLS[f]
|
|
if (pearInspectLoggerTlsWid) {
|
|
const t = procBareOsPearInspectLoggerTlsJsonText
|
|
? procBareOsPearInspectLoggerTlsJsonText(pearInspectLoggerTlsWid)
|
|
: `${JSON.stringify({
|
|
schema: 1,
|
|
note: 'wave10 proc provider missing'
|
|
})}\n`
|
|
return utf8Encode(t)
|
|
}
|
|
}
|
|
{
|
|
const hypercorePackHrpcLifecycleWid = BARE_OS_PROC_FILE_TO_ID_HYPERCORE_PACK_HRPC_LIFECYCLE[f]
|
|
if (hypercorePackHrpcLifecycleWid && !omitHypercorePackHrpcLifecycleProc) {
|
|
const t = procBareOsHypercorePackHrpcLifecycleJsonText
|
|
? procBareOsHypercorePackHrpcLifecycleJsonText(hypercorePackHrpcLifecycleWid)
|
|
: `${JSON.stringify({
|
|
schema: 1,
|
|
note: 'hypercore pack hrpc lifecycle proc provider missing'
|
|
})}\n`
|
|
return utf8Encode(t)
|
|
}
|
|
}
|
|
if (f === 'bare_os_proc_index') {
|
|
const idx = {
|
|
schema: 10,
|
|
description:
|
|
'Stable aliases under /proc/bare_os/ (same payloads as flat /proc/bare_os_* files).',
|
|
entries: [
|
|
{ name: 'index.json', path: '/proc/bare_os/index.json' },
|
|
{ name: 'features', path: '/proc/bare_os/features' },
|
|
{ name: 'features.json', path: '/proc/bare_os/features.json' },
|
|
{ name: 'swarm', path: '/proc/bare_os/swarm' },
|
|
{ name: 'swarm.json', path: '/proc/bare_os/swarm.json' },
|
|
{
|
|
name: 'swarm_health.json',
|
|
path: '/proc/bare_os/swarm_health.json'
|
|
},
|
|
{
|
|
name: 'swarm_status.json',
|
|
path: '/proc/bare_os/swarm_status.json'
|
|
},
|
|
{
|
|
name: 'swarm_replication_status.json',
|
|
path: '/proc/bare_os/swarm_replication_status.json'
|
|
},
|
|
{
|
|
name: 'swarm_relay_status.json',
|
|
path: '/proc/bare_os/swarm_relay_status.json'
|
|
},
|
|
{
|
|
name: 'swarm_datagrams_status.json',
|
|
path: '/proc/bare_os/swarm_datagrams_status.json'
|
|
},
|
|
{
|
|
name: 'swarm_connection_manager_status.json',
|
|
path: '/proc/bare_os/swarm_connection_manager_status.json'
|
|
},
|
|
{
|
|
name: 'swarm_key_broker_status.json',
|
|
path: '/proc/bare_os/swarm_key_broker_status.json'
|
|
},
|
|
{
|
|
name: 'swarm_holepunch_status.json',
|
|
path: '/proc/bare_os/swarm_holepunch_status.json'
|
|
},
|
|
{
|
|
name: 'swarm_datagram_replication_status.json',
|
|
path: '/proc/bare_os/swarm_datagram_replication_status.json'
|
|
},
|
|
{ name: 'replication', path: '/proc/bare_os/replication' },
|
|
{ name: 'resources', path: '/proc/bare_os/resources' },
|
|
{ name: 'quotas', path: '/proc/bare_os/quotas' },
|
|
{ name: 'capabilities', path: '/proc/bare_os/capabilities' },
|
|
{
|
|
name: 'capabilities.json',
|
|
path: '/proc/bare_os/capabilities.json'
|
|
},
|
|
{ name: 'seed_handshake', path: '/proc/bare_os/seed_handshake' },
|
|
{
|
|
name: 'virtual_registry',
|
|
path: '/proc/bare_os/virtual_registry'
|
|
},
|
|
{ name: 'session_stats', path: '/proc/bare_os/session_stats' },
|
|
{ name: 'union', path: '/proc/bare_os/union' },
|
|
{ name: 'bootstrap', path: '/proc/bare_os/bootstrap' },
|
|
{ name: 'version', path: '/proc/bare_os/version' },
|
|
{
|
|
name: 'manifest_hints',
|
|
path: '/proc/bare_os/manifest_hints'
|
|
},
|
|
{ name: 'peer_health', path: '/proc/bare_os/peer_health' },
|
|
{ name: 'staging_slot', path: '/proc/bare_os/staging_slot' },
|
|
{
|
|
name: 'snapshot_hints.json',
|
|
path: '/proc/bare_os/snapshot_hints.json'
|
|
},
|
|
{ name: 'provenance', path: '/proc/bare_os/provenance' },
|
|
{
|
|
name: 'pear_ipc.json',
|
|
path: '/proc/bare_os/pear_ipc.json'
|
|
},
|
|
{
|
|
name: 'initd_dag.json',
|
|
path: '/proc/bare_os/initd_dag.json'
|
|
},
|
|
{
|
|
name: 'initd_readiness.json',
|
|
path: '/proc/bare_os/initd_readiness.json'
|
|
},
|
|
{
|
|
name: 'boot_graph.json',
|
|
path: '/proc/bare_os/boot_graph.json'
|
|
},
|
|
{
|
|
name: 'boot_budget_summary.json',
|
|
path: '/proc/bare_os/boot_budget_summary.json'
|
|
},
|
|
{
|
|
name: 'metrics_live.json',
|
|
path: '/proc/bare_os/metrics_live.json'
|
|
},
|
|
{ name: 'chat.json', path: '/proc/bare_os/chat.json' },
|
|
{ name: 'meshdrop.json', path: '/proc/bare_os/meshdrop.json' },
|
|
{ name: 'peer_details.json', path: '/proc/bare_os/peer_details.json' },
|
|
{ name: 'dht_scan.json', path: '/proc/bare_os/dht_scan.json' },
|
|
{ name: 'swarm_doctor.json', path: '/proc/bare_os/swarm_doctor.json' },
|
|
{ name: 'route_summary.json', path: '/proc/bare_os/route_summary.json' },
|
|
{
|
|
name: 'holepunch_summary.json',
|
|
path: '/proc/bare_os/holepunch_summary.json'
|
|
},
|
|
{
|
|
name: 'process_table.json',
|
|
path: '/proc/bare_os/process_table.json'
|
|
},
|
|
{
|
|
name: 'process_io.json',
|
|
path: '/proc/bare_os/process_io.json'
|
|
},
|
|
{
|
|
name: 'process_threads.json',
|
|
path: '/proc/bare_os/process_threads.json'
|
|
},
|
|
{
|
|
name: 'process_maps.json',
|
|
path: '/proc/bare_os/process_maps.json'
|
|
},
|
|
{
|
|
name: 'syscalls.json',
|
|
path: '/proc/bare_os/syscalls.json'
|
|
},
|
|
{
|
|
name: 'metrics.prom',
|
|
path: '/proc/bare_os/metrics.prom'
|
|
},
|
|
{
|
|
name: 'protomux.json',
|
|
path: '/proc/bare_os/protomux.json'
|
|
},
|
|
{
|
|
name: 'protomux_extensions.json',
|
|
path: '/proc/bare_os/protomux_extensions.json'
|
|
},
|
|
{
|
|
name: 'net_summary.json',
|
|
path: '/proc/bare_os/net_summary.json'
|
|
},
|
|
{
|
|
name: 'host_os.json',
|
|
path: '/proc/bare_os/host_os.json'
|
|
},
|
|
{
|
|
name: 'sync_window.json',
|
|
path: '/proc/bare_os/sync_window.json'
|
|
},
|
|
{
|
|
name: 'clock.json',
|
|
path: '/proc/bare_os/clock.json'
|
|
},
|
|
{
|
|
name: 'openssh.json',
|
|
path: '/proc/bare_os/openssh.json'
|
|
},
|
|
{
|
|
name: 'debug.json',
|
|
path: '/proc/bare_os/debug.json'
|
|
},
|
|
{
|
|
name: 'extensions.json',
|
|
path: '/proc/bare_os/extensions.json'
|
|
},
|
|
{
|
|
name: 'hdms_hints.json',
|
|
path: '/proc/bare_os/hdms_hints.json'
|
|
},
|
|
{
|
|
name: 'pear_trust.json',
|
|
path: '/proc/bare_os/pear_trust.json'
|
|
},
|
|
{
|
|
name: 'security_posture.json',
|
|
path: '/proc/bare_os/security_posture.json'
|
|
},
|
|
{
|
|
name: 'rlimits.json',
|
|
path: '/proc/bare_os/rlimits.json'
|
|
},
|
|
{
|
|
name: 'hdms_health.json',
|
|
path: '/proc/bare_os/hdms_health.json'
|
|
},
|
|
{
|
|
name: 'initd_graph.json',
|
|
path: '/proc/bare_os/initd_graph.json'
|
|
},
|
|
{
|
|
name: 'udx_extended.json',
|
|
path: '/proc/bare_os/udx_extended.json'
|
|
},
|
|
{
|
|
name: 'dht_status.json',
|
|
path: '/proc/bare_os/dht_status.json'
|
|
},
|
|
{
|
|
name: 'replication_backpressure.json',
|
|
path: '/proc/bare_os/replication_backpressure.json'
|
|
},
|
|
{
|
|
name: 'ipc_backpressure.json',
|
|
path: '/proc/bare_os/ipc_backpressure.json'
|
|
},
|
|
{
|
|
name: 'delegate_red.json',
|
|
path: '/proc/bare_os/delegate_red.json'
|
|
},
|
|
{
|
|
name: 'build_attestation_pointer.json',
|
|
path: '/proc/bare_os/build_attestation_pointer.json'
|
|
},
|
|
{
|
|
name: 'pear_ipc_health.json',
|
|
path: '/proc/bare_os/pear_ipc_health.json'
|
|
},
|
|
{
|
|
name: 'hypercore_lengths.json',
|
|
path: '/proc/bare_os/hypercore_lengths.json'
|
|
},
|
|
{
|
|
name: 'slo_hints.json',
|
|
path: '/proc/bare_os/slo_hints.json'
|
|
},
|
|
{
|
|
name: 'locale.json',
|
|
path: '/proc/bare_os/locale.json'
|
|
},
|
|
{
|
|
name: 'worker_budget.json',
|
|
path: '/proc/bare_os/worker_budget.json'
|
|
},
|
|
{
|
|
name: 'sandbox_profile.json',
|
|
path: '/proc/bare_os/sandbox_profile.json'
|
|
},
|
|
{
|
|
name: 'dns_map_active.json',
|
|
path: '/proc/bare_os/dns_map_active.json'
|
|
},
|
|
{
|
|
name: 'git_delegate_stats.json',
|
|
path: '/proc/bare_os/git_delegate_stats.json'
|
|
},
|
|
{
|
|
name: 'replication_operator_panel.json',
|
|
path: '/proc/bare_os/replication_operator_panel.json'
|
|
},
|
|
{
|
|
name: 'async_hooks_lag.json',
|
|
path: '/proc/bare_os/async_hooks_lag.json'
|
|
},
|
|
{
|
|
name: 'autopass_session_sketch.json',
|
|
path: '/proc/bare_os/autopass_session_sketch.json'
|
|
},
|
|
{
|
|
name: 'bare_diagnostics_channel.json',
|
|
path: '/proc/bare_os/bare_diagnostics_channel.json'
|
|
},
|
|
{
|
|
name: 'bare_net_interfaces.json',
|
|
path: '/proc/bare_os/bare_net_interfaces.json'
|
|
},
|
|
{
|
|
name: 'bare_thread_pool.json',
|
|
path: '/proc/bare_os/bare_thread_pool.json'
|
|
},
|
|
{
|
|
name: 'blind_relay_router.json',
|
|
path: '/proc/bare_os/blind_relay_router.json'
|
|
},
|
|
{
|
|
name: 'compact_encoding_profile.json',
|
|
path: '/proc/bare_os/compact_encoding_profile.json'
|
|
},
|
|
{
|
|
name: 'corestore_gc_hint.json',
|
|
path: '/proc/bare_os/corestore_gc_hint.json'
|
|
},
|
|
{
|
|
name: 'git_lfs_pointer_stats.json',
|
|
path: '/proc/bare_os/git_lfs_pointer_stats.json'
|
|
},
|
|
{
|
|
name: 'hrpc_bridge_health.json',
|
|
path: '/proc/bare_os/hrpc_bridge_health.json'
|
|
},
|
|
{
|
|
name: 'hyperdb_readonly_index.json',
|
|
path: '/proc/bare_os/hyperdb_readonly_index.json'
|
|
},
|
|
{
|
|
name: 'pear_build_fingerprint.json',
|
|
path: '/proc/bare_os/pear_build_fingerprint.json'
|
|
},
|
|
{
|
|
name: 'pear_runtime_channel.json',
|
|
path: '/proc/bare_os/pear_runtime_channel.json'
|
|
},
|
|
{
|
|
name: 'protomux_channels.json',
|
|
path: '/proc/bare_os/protomux_channels.json'
|
|
},
|
|
{
|
|
name: 'security_context.json',
|
|
path: '/proc/bare_os/security_context.json'
|
|
},
|
|
{
|
|
name: 'updater_download_state.json',
|
|
path: '/proc/bare_os/updater_download_state.json'
|
|
},
|
|
{
|
|
name: 'bare_kit_bridge.json',
|
|
path: '/proc/bare_os/bare_kit_bridge.json'
|
|
},
|
|
{
|
|
name: 'brittle_snapshot_ci.json',
|
|
path: '/proc/bare_os/brittle_snapshot_ci.json'
|
|
},
|
|
{
|
|
name: 'cellery_sidecar_hint.json',
|
|
path: '/proc/bare_os/cellery_sidecar_hint.json'
|
|
},
|
|
{
|
|
name: 'form_data_delegate_limits.json',
|
|
path: '/proc/bare_os/form_data_delegate_limits.json'
|
|
},
|
|
{
|
|
name: 'gip_transport_sketch.json',
|
|
path: '/proc/bare_os/gip_transport_sketch.json'
|
|
},
|
|
{
|
|
name: 'http_dht_proxy_route.json',
|
|
path: '/proc/bare_os/http_dht_proxy_route.json'
|
|
},
|
|
{
|
|
name: 'hyper_multisig_trust_pointer.json',
|
|
path: '/proc/bare_os/hyper_multisig_trust_pointer.json'
|
|
},
|
|
{
|
|
name: 'hypercore_signing_status.json',
|
|
path: '/proc/bare_os/hypercore_signing_status.json'
|
|
},
|
|
{
|
|
name: 'hypermininet_topology.json',
|
|
path: '/proc/bare_os/hypermininet_topology.json'
|
|
},
|
|
{
|
|
name: 'libmqjs_queue_depth.json',
|
|
path: '/proc/bare_os/libmqjs_queue_depth.json'
|
|
},
|
|
{
|
|
name: 'oidc_publishing_pointer.json',
|
|
path: '/proc/bare_os/oidc_publishing_pointer.json'
|
|
},
|
|
{
|
|
name: 'pear_sidecar_bundle_index.json',
|
|
path: '/proc/bare_os/pear_sidecar_bundle_index.json'
|
|
},
|
|
{
|
|
name: 'protomux_rpc_pool_health.json',
|
|
path: '/proc/bare_os/protomux_rpc_pool_health.json'
|
|
},
|
|
{
|
|
name: 'react_native_bare_kit.json',
|
|
path: '/proc/bare_os/react_native_bare_kit.json'
|
|
},
|
|
{
|
|
name: 'rocksdb_pointer.json',
|
|
path: '/proc/bare_os/rocksdb_pointer.json'
|
|
},
|
|
{
|
|
name: 'safe_sodium_buffer_policy.json',
|
|
path: '/proc/bare_os/safe_sodium_buffer_policy.json'
|
|
},
|
|
{
|
|
name: 'sandbox_worker_queue.json',
|
|
path: '/proc/bare_os/sandbox_worker_queue.json'
|
|
},
|
|
{
|
|
name: 'structured_clone_profile.json',
|
|
path: '/proc/bare_os/structured_clone_profile.json'
|
|
},
|
|
{
|
|
name: 'pear_stage_pointer.json',
|
|
path: '/proc/bare_os/pear_stage_pointer.json'
|
|
},
|
|
{
|
|
name: 'pear_updater_state.json',
|
|
path: '/proc/bare_os/pear_updater_state.json'
|
|
},
|
|
{
|
|
name: 'pear_appling_manifest.json',
|
|
path: '/proc/bare_os/pear_appling_manifest.json'
|
|
},
|
|
{
|
|
name: 'drive_resolve_cache.json',
|
|
path: '/proc/bare_os/drive_resolve_cache.json'
|
|
},
|
|
{
|
|
name: 'bare_module_resolution.json',
|
|
path: '/proc/bare_os/bare_module_resolution.json'
|
|
},
|
|
{
|
|
name: 'bare_crypto_policy.json',
|
|
path: '/proc/bare_os/bare_crypto_policy.json'
|
|
},
|
|
{
|
|
name: 'bare_ipc_bridge.json',
|
|
path: '/proc/bare_os/bare_ipc_bridge.json'
|
|
},
|
|
{
|
|
name: 'bare_vm_sandbox_sketch.json',
|
|
path: '/proc/bare_os/bare_vm_sandbox_sketch.json'
|
|
},
|
|
{
|
|
name: 'bare_daemon_hooks.json',
|
|
path: '/proc/bare_os/bare_daemon_hooks.json'
|
|
},
|
|
{
|
|
name: 'bare_storage_quota.json',
|
|
path: '/proc/bare_os/bare_storage_quota.json'
|
|
},
|
|
{
|
|
name: 'bare_worker_pool.json',
|
|
path: '/proc/bare_os/bare_worker_pool.json'
|
|
},
|
|
{
|
|
name: 'pear_wakeups_schedule.json',
|
|
path: '/proc/bare_os/pear_wakeups_schedule.json'
|
|
},
|
|
{
|
|
name: 'pear_drop_events.json',
|
|
path: '/proc/bare_os/pear_drop_events.json'
|
|
},
|
|
{
|
|
name: 'pear_radio_state.json',
|
|
path: '/proc/bare_os/pear_radio_state.json'
|
|
},
|
|
{
|
|
name: 'hypercore_repair_hint.json',
|
|
path: '/proc/bare_os/hypercore_repair_hint.json'
|
|
},
|
|
{
|
|
name: 'hyperdrive_sparse_index.json',
|
|
path: '/proc/bare_os/hyperdrive_sparse_index.json'
|
|
},
|
|
{
|
|
name: 'protomux_channel_alias_v2.json',
|
|
path: '/proc/bare_os/protomux_channel_alias_v2.json'
|
|
},
|
|
{
|
|
name: 'structured_clone_budget_v2.json',
|
|
path: '/proc/bare_os/structured_clone_budget_v2.json'
|
|
},
|
|
{
|
|
name: 'form_data_delegate_limits_v2.json',
|
|
path: '/proc/bare_os/form_data_delegate_limits_v2.json'
|
|
},
|
|
{
|
|
name: 'activity_queue_depth.json',
|
|
path: '/proc/bare_os/activity_queue_depth.json'
|
|
},
|
|
{
|
|
name: 'autobase_writer_hint.json',
|
|
path: '/proc/bare_os/autobase_writer_hint.json'
|
|
},
|
|
{
|
|
name: 'bare_boot_phase_map.json',
|
|
path: '/proc/bare_os/bare_boot_phase_map.json'
|
|
},
|
|
{
|
|
name: 'bare_inspect_policy.json',
|
|
path: '/proc/bare_os/bare_inspect_policy.json'
|
|
},
|
|
{
|
|
name: 'bare_logger_policy.json',
|
|
path: '/proc/bare_os/bare_logger_policy.json'
|
|
},
|
|
{
|
|
name: 'bare_performance_counters.json',
|
|
path: '/proc/bare_os/bare_performance_counters.json'
|
|
},
|
|
{
|
|
name: 'bare_rpc_registry_sketch.json',
|
|
path: '/proc/bare_os/bare_rpc_registry_sketch.json'
|
|
},
|
|
{
|
|
name: 'bare_signals_mask.json',
|
|
path: '/proc/bare_os/bare_signals_mask.json'
|
|
},
|
|
{
|
|
name: 'bare_stream_backpressure.json',
|
|
path: '/proc/bare_os/bare_stream_backpressure.json'
|
|
},
|
|
{
|
|
name: 'bare_timers_budget.json',
|
|
path: '/proc/bare_os/bare_timers_budget.json'
|
|
},
|
|
{
|
|
name: 'bare_tls_session_hint.json',
|
|
path: '/proc/bare_os/bare_tls_session_hint.json'
|
|
},
|
|
{
|
|
name: 'bare_ws_gateway_sketch.json',
|
|
path: '/proc/bare_os/bare_ws_gateway_sketch.json'
|
|
},
|
|
{
|
|
name: 'blind_pairing_sketch.json',
|
|
path: '/proc/bare_os/blind_pairing_sketch.json'
|
|
},
|
|
{
|
|
name: 'broadcast_encryption_hint.json',
|
|
path: '/proc/bare_os/broadcast_encryption_hint.json'
|
|
},
|
|
{
|
|
name: 'pear_api_allowlist_sketch.json',
|
|
path: '/proc/bare_os/pear_api_allowlist_sketch.json'
|
|
},
|
|
{
|
|
name: 'pear_doctor_state.json',
|
|
path: '/proc/bare_os/pear_doctor_state.json'
|
|
},
|
|
{
|
|
name: 'pear_rti_pointer.json',
|
|
path: '/proc/bare_os/pear_rti_pointer.json'
|
|
},
|
|
{
|
|
name: 'pear_user_dirs_map.json',
|
|
path: '/proc/bare_os/pear_user_dirs_map.json'
|
|
},
|
|
{
|
|
name: 'pear_workshop_flags.json',
|
|
path: '/proc/bare_os/pear_workshop_flags.json'
|
|
},
|
|
{
|
|
name: 'hypercore_replicate_budget.json',
|
|
path: '/proc/bare_os/hypercore_replicate_budget.json'
|
|
},
|
|
{
|
|
name: 'drive_version_graph.json',
|
|
path: '/proc/bare_os/drive_version_graph.json'
|
|
},
|
|
{
|
|
name: 'protomux_backpressure.json',
|
|
path: '/proc/bare_os/protomux_backpressure.json'
|
|
},
|
|
{
|
|
name: 'pear_runtime_matrix.json',
|
|
path: '/proc/bare_os/pear_runtime_matrix.json'
|
|
},
|
|
{
|
|
name: 'bundle_preload_hint.json',
|
|
path: '/proc/bare_os/bundle_preload_hint.json'
|
|
},
|
|
{
|
|
name: 'autopass_rotation_sketch.json',
|
|
path: '/proc/bare_os/autopass_rotation_sketch.json'
|
|
},
|
|
{
|
|
name: 'hrpc_allowlist_sketch.json',
|
|
path: '/proc/bare_os/hrpc_allowlist_sketch.json'
|
|
},
|
|
{
|
|
name: 'sidecar_resource_cap.json',
|
|
path: '/proc/bare_os/sidecar_resource_cap.json'
|
|
},
|
|
{
|
|
name: 'git_lfs_budget.json',
|
|
path: '/proc/bare_os/git_lfs_budget.json'
|
|
},
|
|
{
|
|
name: 'kernel_program.json',
|
|
path: '/proc/bare_os/kernel_program.json'
|
|
},
|
|
{
|
|
name: 'giant_phase_program.json',
|
|
path: '/proc/bare_os/giant_phase_program.json'
|
|
},
|
|
{
|
|
name: 'net_qos_class.json',
|
|
path: '/proc/bare_os/net_qos_class.json'
|
|
},
|
|
{
|
|
name: 'storage_tier_hint.json',
|
|
path: '/proc/bare_os/storage_tier_hint.json'
|
|
},
|
|
{
|
|
name: 'indexer_catchup.json',
|
|
path: '/proc/bare_os/indexer_catchup.json'
|
|
},
|
|
{
|
|
name: 'multisig_quorum_pointer.json',
|
|
path: '/proc/bare_os/multisig_quorum_pointer.json'
|
|
},
|
|
{
|
|
name: 'relay_geo_hint.json',
|
|
path: '/proc/bare_os/relay_geo_hint.json'
|
|
},
|
|
{
|
|
name: 'bare_pack_cache.json',
|
|
path: '/proc/bare_os/bare_pack_cache.json'
|
|
},
|
|
{
|
|
name: 'bare_addon_policy.json',
|
|
path: '/proc/bare_os/bare_addon_policy.json'
|
|
},
|
|
{
|
|
name: 'bare_signals_profile.json',
|
|
path: '/proc/bare_os/bare_signals_profile.json'
|
|
},
|
|
{
|
|
name: 'bare_timers_histogram.json',
|
|
path: '/proc/bare_os/bare_timers_histogram.json'
|
|
},
|
|
{
|
|
name: 'wave11_peer_qos_sketch.json',
|
|
path: '/proc/bare_os/wave11_peer_qos_sketch.json'
|
|
},
|
|
{
|
|
name: 'wave11_operator_slo_v2.json',
|
|
path: '/proc/bare_os/wave11_operator_slo_v2.json'
|
|
}
|
|
]
|
|
}
|
|
if (omitHypercorePackHrpcLifecycleProc) {
|
|
idx.entries = idx.entries.filter(
|
|
(e) =>
|
|
!(
|
|
typeof e.name === 'string' &&
|
|
hypercorePackHrpcLifecycleBareOsRelNames.has(e.name)
|
|
)
|
|
)
|
|
}
|
|
idx.entries.sort((a, b) =>
|
|
String(a?.name || '').localeCompare(String(b?.name || ''))
|
|
)
|
|
return utf8Encode(JSON.stringify(idx, null, 2) + '\n')
|
|
}
|
|
if (f === 'self_fd') {
|
|
const n = /** @type {{ fdNum?: string }} */ (routePseudo).fdNum ?? '0'
|
|
return encodeProcSelfFdSymlink(n)
|
|
}
|
|
if (f === 'net_dev') {
|
|
const t = procNetDevText
|
|
? procNetDevText()
|
|
: 'Inter-|Receive: packets errs\ntun0: 0 0 0\n'
|
|
return utf8Encode(t)
|
|
}
|
|
}
|
|
if (k === 'sys' && f === 'class_net_lo') {
|
|
const t = sysClassNetLoText ? sysClassNetLoText() : 'operstate unknown\n'
|
|
return utf8Encode(t)
|
|
}
|
|
if (k === 'run' && f === 'units') {
|
|
const t = initdRunText
|
|
? initdRunText()
|
|
: '# bare-initd: no snapshot provider\n'
|
|
return utf8Encode(t)
|
|
}
|
|
if (k === 'run' && f === 'unit_journal' && getUnitJournalNdjson) {
|
|
const u =
|
|
/** @type {{ unitJournalName?: string }} */ (routePseudo)
|
|
.unitJournalName || ''
|
|
const t = getUnitJournalNdjson(u)
|
|
return utf8Encode(t || '')
|
|
}
|
|
if (k === 'run' && f === 'boot_profile') {
|
|
const t = bootProfileText ? bootProfileText() : '\n'
|
|
return utf8Encode(t)
|
|
}
|
|
if (k === 'run' && f === 'session') {
|
|
const t = sessionText ? sessionText() : '\n'
|
|
return utf8Encode(t)
|
|
}
|
|
if (k === 'run' && f === 'ready') {
|
|
const t = bootReadyMarkerText ? bootReadyMarkerText() : '0\n'
|
|
return utf8Encode(t)
|
|
}
|
|
if (k === 'run' && f === 'boot_json') {
|
|
const t = bootReadyJsonText ? bootReadyJsonText() : '{}\n'
|
|
return utf8Encode(t)
|
|
}
|
|
if (k === 'dev' && f === 'null') return utf8Encode('')
|
|
if (k === 'dev' && f === 'zero') return new Uint8Array(65536)
|
|
if (k === 'dev' && f === 'urandom') return pseudoUrandomBytes()
|
|
if (k === 'dev' && f === 'shm') {
|
|
const nm = String(
|
|
/** @type {{ shmName?: string }} */ (routePseudo).shmName || ''
|
|
).trim()
|
|
if (!nm) return new Uint8Array(0)
|
|
const got = bareOsDevShm.get(nm)
|
|
return got ? b4a.from(got) : new Uint8Array(0)
|
|
}
|
|
return utf8Encode('')
|
|
}
|
|
|
|
/**
|
|
* @param {string} absPath
|
|
* @returns {null | Record<string, unknown>}
|
|
*/
|
|
function classifyPseudoAbs(absPath) {
|
|
const n = absPath.replace(/\/+$/, '') || '/'
|
|
if (n === '/proc' || n.startsWith('/proc/')) {
|
|
if (n === '/proc') {
|
|
return { virtualPseudo: true, kind: 'proc', node: 'root' }
|
|
}
|
|
const sub = n.slice(6)
|
|
if (sub === 'version' || sub === 'bare_os_version') {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: 'version'
|
|
}
|
|
}
|
|
if (sub === 'self') {
|
|
return { virtualPseudo: true, kind: 'proc', node: 'dir', dir: 'self' }
|
|
}
|
|
if (sub === 'self/environ') {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: 'environ'
|
|
}
|
|
}
|
|
if (sub === 'self/cmdline') {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: 'cmdline'
|
|
}
|
|
}
|
|
if (sub === 'self/cgroups') {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: 'self_cgroups'
|
|
}
|
|
}
|
|
if (sub === 'uptime') {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: 'uptime'
|
|
}
|
|
}
|
|
if (sub === 'meminfo') {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: 'meminfo'
|
|
}
|
|
}
|
|
if (sub === 'cpuinfo') {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: 'cpuinfo'
|
|
}
|
|
}
|
|
if (sub === 'loadavg') {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: 'loadavg'
|
|
}
|
|
}
|
|
if (sub === 'self/exe') {
|
|
return { virtualPseudo: true, kind: 'proc', node: 'file', file: 'exe' }
|
|
}
|
|
if (sub === 'self/limits') {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: 'self_limits'
|
|
}
|
|
}
|
|
if (sub === 'mounts') {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: 'mounts'
|
|
}
|
|
}
|
|
if (sub === 'bare_os' || sub === 'bare_os/') {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'dir',
|
|
dir: 'bare_os_proc'
|
|
}
|
|
}
|
|
if (sub.startsWith('bare_os/')) {
|
|
const rest = sub.slice('bare_os/'.length).replace(/\/+$/, '')
|
|
if (rest === 'index.json') {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: 'bare_os_proc_index'
|
|
}
|
|
}
|
|
const alias = {
|
|
features: 'bare_os_features',
|
|
'features.json': 'bare_os_features',
|
|
swarm: 'bare_os_swarm',
|
|
'swarm.json': 'bare_os_swarm',
|
|
swarm_health: 'bare_os_swarm_health',
|
|
'swarm_health.json': 'bare_os_swarm_health',
|
|
'swarm_status.json': 'bare_os_swarm_health',
|
|
'swarm_replication_status.json': 'bare_os_swarm_replication_status',
|
|
'swarm_relay_status.json': 'bare_os_swarm_relay_status',
|
|
'swarm_datagrams_status.json': 'bare_os_swarm_datagrams_status',
|
|
'swarm_connection_manager_status.json':
|
|
'bare_os_swarm_connection_manager_status',
|
|
'swarm_key_broker_status.json': 'bare_os_swarm_key_broker_status',
|
|
'swarm_holepunch_status.json': 'bare_os_swarm_holepunch_status',
|
|
'swarm_datagram_replication_status.json':
|
|
'bare_os_swarm_datagram_replication_status',
|
|
replication: 'bare_os_replication',
|
|
resources: 'bare_os_resources',
|
|
quotas: 'bare_os_quotas',
|
|
capabilities: 'bare_os_capabilities',
|
|
'capabilities.json': 'bare_os_capabilities_json',
|
|
seed_handshake: 'bare_os_seed_handshake',
|
|
virtual_registry: 'bare_os_virtual_registry',
|
|
session_stats: 'bare_os_session_stats',
|
|
union: 'bare_os_union',
|
|
bootstrap: 'bare_os_bootstrap',
|
|
version: 'version',
|
|
manifest_hints: 'bare_os_manifest_hints',
|
|
peer_health: 'bare_os_peer_health',
|
|
staging_slot: 'bare_os_staging_slot',
|
|
snapshot_hints: 'bare_os_snapshot_hints',
|
|
'snapshot_hints.json': 'bare_os_snapshot_hints',
|
|
provenance: 'bare_os_provenance',
|
|
'pear_ipc.json': 'bare_os_pear_ipc_registry',
|
|
'initd_dag.json': 'bare_os_initd_dag',
|
|
'initd_readiness.json': 'bare_os_initd_readiness',
|
|
'boot_graph.json': 'bare_os_boot_graph',
|
|
'boot_budget_summary.json': 'bare_os_boot_budget_summary',
|
|
metrics_live: 'bare_os_metrics_live',
|
|
'metrics_live.json': 'bare_os_metrics_live',
|
|
chat: 'bare_os_chat',
|
|
'chat.json': 'bare_os_chat',
|
|
meshdrop: 'bare_os_meshdrop',
|
|
'meshdrop.json': 'bare_os_meshdrop',
|
|
peer_details: 'bare_os_peer_details',
|
|
'peer_details.json': 'bare_os_peer_details',
|
|
dht_scan: 'bare_os_dht_scan',
|
|
'dht_scan.json': 'bare_os_dht_scan',
|
|
swarm_doctor: 'bare_os_swarm_doctor',
|
|
'swarm_doctor.json': 'bare_os_swarm_doctor',
|
|
route_summary: 'bare_os_route_summary',
|
|
'route_summary.json': 'bare_os_route_summary',
|
|
holepunch_summary: 'bare_os_holepunch_summary',
|
|
'holepunch_summary.json': 'bare_os_holepunch_summary',
|
|
process_table: 'bare_os_process_table',
|
|
'process_table.json': 'bare_os_process_table',
|
|
process_io: 'bare_os_process_io',
|
|
'process_io.json': 'bare_os_process_io',
|
|
process_threads: 'bare_os_process_threads',
|
|
'process_threads.json': 'bare_os_process_threads',
|
|
process_maps: 'bare_os_process_maps',
|
|
'process_maps.json': 'bare_os_process_maps',
|
|
syscalls: 'bare_os_syscalls',
|
|
'syscalls.json': 'bare_os_syscalls',
|
|
'metrics.prom': 'bare_os_metrics_prom',
|
|
protomux: 'bare_os_protomux_wire',
|
|
'protomux.json': 'bare_os_protomux_wire',
|
|
protomux_extensions: 'bare_os_protomux_extensions',
|
|
'protomux_extensions.json': 'bare_os_protomux_extensions',
|
|
net_summary: 'bare_os_net_summary',
|
|
'net_summary.json': 'bare_os_net_summary',
|
|
host_os: 'bare_os_host_os',
|
|
'host_os.json': 'bare_os_host_os',
|
|
sync_window: 'bare_os_sync_window',
|
|
'sync_window.json': 'bare_os_sync_window',
|
|
clock: 'bare_os_clock',
|
|
'clock.json': 'bare_os_clock',
|
|
openssh: 'bare_os_openssh',
|
|
'openssh.json': 'bare_os_openssh',
|
|
debug: 'bare_os_debug',
|
|
'debug.json': 'bare_os_debug',
|
|
udx_extended: 'bare_os_udx_extended',
|
|
'udx_extended.json': 'bare_os_udx_extended',
|
|
dht_status: 'bare_os_dht_status',
|
|
'dht_status.json': 'bare_os_dht_status',
|
|
replication_backpressure: 'bare_os_replication_backpressure',
|
|
'replication_backpressure.json': 'bare_os_replication_backpressure',
|
|
ipc_backpressure: 'bare_os_ipc_backpressure',
|
|
'ipc_backpressure.json': 'bare_os_ipc_backpressure',
|
|
delegate_red: 'bare_os_delegate_red',
|
|
'delegate_red.json': 'bare_os_delegate_red',
|
|
build_attestation_pointer: 'bare_os_build_attestation_pointer',
|
|
'build_attestation_pointer.json': 'bare_os_build_attestation_pointer',
|
|
pear_ipc_health: 'bare_os_pear_ipc_health',
|
|
'pear_ipc_health.json': 'bare_os_pear_ipc_health',
|
|
hypercore_lengths: 'bare_os_hypercore_lengths',
|
|
'hypercore_lengths.json': 'bare_os_hypercore_lengths',
|
|
slo_hints: 'bare_os_slo_hints',
|
|
'slo_hints.json': 'bare_os_slo_hints',
|
|
locale: 'bare_os_locale',
|
|
'locale.json': 'bare_os_locale',
|
|
worker_budget: 'bare_os_worker_budget',
|
|
'worker_budget.json': 'bare_os_worker_budget',
|
|
sandbox_profile: 'bare_os_sandbox_profile',
|
|
'sandbox_profile.json': 'bare_os_sandbox_profile',
|
|
dns_map_active: 'bare_os_dns_map_active',
|
|
'dns_map_active.json': 'bare_os_dns_map_active',
|
|
git_delegate_stats: 'bare_os_git_delegate_stats',
|
|
'git_delegate_stats.json': 'bare_os_git_delegate_stats',
|
|
replication_operator_panel: 'bare_os_replication_operator_panel',
|
|
'replication_operator_panel.json':
|
|
'bare_os_replication_operator_panel',
|
|
async_hooks_lag: 'bare_os_async_hooks_lag',
|
|
'async_hooks_lag.json': 'bare_os_async_hooks_lag',
|
|
autopass_session_sketch: 'bare_os_autopass_session_sketch',
|
|
'autopass_session_sketch.json': 'bare_os_autopass_session_sketch',
|
|
bare_diagnostics_channel: 'bare_os_bare_diagnostics_channel',
|
|
'bare_diagnostics_channel.json': 'bare_os_bare_diagnostics_channel',
|
|
bare_net_interfaces: 'bare_os_bare_net_interfaces',
|
|
'bare_net_interfaces.json': 'bare_os_bare_net_interfaces',
|
|
bare_thread_pool: 'bare_os_bare_thread_pool',
|
|
'bare_thread_pool.json': 'bare_os_bare_thread_pool',
|
|
blind_relay_router: 'bare_os_blind_relay_router',
|
|
'blind_relay_router.json': 'bare_os_blind_relay_router',
|
|
compact_encoding_profile: 'bare_os_compact_encoding_profile',
|
|
'compact_encoding_profile.json': 'bare_os_compact_encoding_profile',
|
|
corestore_gc_hint: 'bare_os_corestore_gc_hint',
|
|
'corestore_gc_hint.json': 'bare_os_corestore_gc_hint',
|
|
git_lfs_pointer_stats: 'bare_os_git_lfs_pointer_stats',
|
|
'git_lfs_pointer_stats.json': 'bare_os_git_lfs_pointer_stats',
|
|
hrpc_bridge_health: 'bare_os_hrpc_bridge_health',
|
|
'hrpc_bridge_health.json': 'bare_os_hrpc_bridge_health',
|
|
hyperdb_readonly_index: 'bare_os_hyperdb_readonly_index',
|
|
'hyperdb_readonly_index.json': 'bare_os_hyperdb_readonly_index',
|
|
pear_build_fingerprint: 'bare_os_pear_build_fingerprint',
|
|
'pear_build_fingerprint.json': 'bare_os_pear_build_fingerprint',
|
|
pear_runtime_channel: 'bare_os_pear_runtime_channel',
|
|
'pear_runtime_channel.json': 'bare_os_pear_runtime_channel',
|
|
protomux_channels: 'bare_os_protomux_channels',
|
|
'protomux_channels.json': 'bare_os_protomux_channels',
|
|
security_context: 'bare_os_security_context',
|
|
'security_context.json': 'bare_os_security_context',
|
|
updater_download_state: 'bare_os_updater_download_state',
|
|
'updater_download_state.json': 'bare_os_updater_download_state',
|
|
bare_kit_bridge: 'bare_os_bare_kit_bridge',
|
|
'bare_kit_bridge.json': 'bare_os_bare_kit_bridge',
|
|
brittle_snapshot_ci: 'bare_os_brittle_snapshot_ci',
|
|
'brittle_snapshot_ci.json': 'bare_os_brittle_snapshot_ci',
|
|
cellery_sidecar_hint: 'bare_os_cellery_sidecar_hint',
|
|
'cellery_sidecar_hint.json': 'bare_os_cellery_sidecar_hint',
|
|
form_data_delegate_limits: 'bare_os_form_data_delegate_limits',
|
|
'form_data_delegate_limits.json': 'bare_os_form_data_delegate_limits',
|
|
gip_transport_sketch: 'bare_os_gip_transport_sketch',
|
|
'gip_transport_sketch.json': 'bare_os_gip_transport_sketch',
|
|
http_dht_proxy_route: 'bare_os_http_dht_proxy_route',
|
|
'http_dht_proxy_route.json': 'bare_os_http_dht_proxy_route',
|
|
hyper_multisig_trust_pointer: 'bare_os_hyper_multisig_trust_pointer',
|
|
'hyper_multisig_trust_pointer.json':
|
|
'bare_os_hyper_multisig_trust_pointer',
|
|
hypercore_signing_status: 'bare_os_hypercore_signing_status',
|
|
'hypercore_signing_status.json': 'bare_os_hypercore_signing_status',
|
|
hypermininet_topology: 'bare_os_hypermininet_topology',
|
|
'hypermininet_topology.json': 'bare_os_hypermininet_topology',
|
|
libmqjs_queue_depth: 'bare_os_libmqjs_queue_depth',
|
|
'libmqjs_queue_depth.json': 'bare_os_libmqjs_queue_depth',
|
|
oidc_publishing_pointer: 'bare_os_oidc_publishing_pointer',
|
|
'oidc_publishing_pointer.json': 'bare_os_oidc_publishing_pointer',
|
|
pear_sidecar_bundle_index: 'bare_os_pear_sidecar_bundle_index',
|
|
'pear_sidecar_bundle_index.json': 'bare_os_pear_sidecar_bundle_index',
|
|
protomux_rpc_pool_health: 'bare_os_protomux_rpc_pool_health',
|
|
'protomux_rpc_pool_health.json': 'bare_os_protomux_rpc_pool_health',
|
|
react_native_bare_kit: 'bare_os_react_native_bare_kit',
|
|
'react_native_bare_kit.json': 'bare_os_react_native_bare_kit',
|
|
rocksdb_pointer: 'bare_os_rocksdb_pointer',
|
|
'rocksdb_pointer.json': 'bare_os_rocksdb_pointer',
|
|
safe_sodium_buffer_policy: 'bare_os_safe_sodium_buffer_policy',
|
|
'safe_sodium_buffer_policy.json': 'bare_os_safe_sodium_buffer_policy',
|
|
sandbox_worker_queue: 'bare_os_sandbox_worker_queue',
|
|
'sandbox_worker_queue.json': 'bare_os_sandbox_worker_queue',
|
|
structured_clone_profile: 'bare_os_structured_clone_profile',
|
|
'structured_clone_profile.json': 'bare_os_structured_clone_profile',
|
|
pear_stage_pointer: 'bare_os_pear_stage_pointer',
|
|
'pear_stage_pointer.json': 'bare_os_pear_stage_pointer',
|
|
pear_updater_state: 'bare_os_pear_updater_state',
|
|
'pear_updater_state.json': 'bare_os_pear_updater_state',
|
|
pear_appling_manifest: 'bare_os_pear_appling_manifest',
|
|
'pear_appling_manifest.json': 'bare_os_pear_appling_manifest',
|
|
drive_resolve_cache: 'bare_os_drive_resolve_cache',
|
|
'drive_resolve_cache.json': 'bare_os_drive_resolve_cache',
|
|
bare_module_resolution: 'bare_os_bare_module_resolution',
|
|
'bare_module_resolution.json': 'bare_os_bare_module_resolution',
|
|
bare_crypto_policy: 'bare_os_bare_crypto_policy',
|
|
'bare_crypto_policy.json': 'bare_os_bare_crypto_policy',
|
|
bare_ipc_bridge: 'bare_os_bare_ipc_bridge',
|
|
'bare_ipc_bridge.json': 'bare_os_bare_ipc_bridge',
|
|
bare_vm_sandbox_sketch: 'bare_os_bare_vm_sandbox_sketch',
|
|
'bare_vm_sandbox_sketch.json': 'bare_os_bare_vm_sandbox_sketch',
|
|
bare_daemon_hooks: 'bare_os_bare_daemon_hooks',
|
|
'bare_daemon_hooks.json': 'bare_os_bare_daemon_hooks',
|
|
bare_storage_quota: 'bare_os_bare_storage_quota',
|
|
'bare_storage_quota.json': 'bare_os_bare_storage_quota',
|
|
bare_worker_pool: 'bare_os_bare_worker_pool',
|
|
'bare_worker_pool.json': 'bare_os_bare_worker_pool',
|
|
pear_wakeups_schedule: 'bare_os_pear_wakeups_schedule',
|
|
'pear_wakeups_schedule.json': 'bare_os_pear_wakeups_schedule',
|
|
pear_drop_events: 'bare_os_pear_drop_events',
|
|
'pear_drop_events.json': 'bare_os_pear_drop_events',
|
|
pear_radio_state: 'bare_os_pear_radio_state',
|
|
'pear_radio_state.json': 'bare_os_pear_radio_state',
|
|
hypercore_repair_hint: 'bare_os_hypercore_repair_hint',
|
|
'hypercore_repair_hint.json': 'bare_os_hypercore_repair_hint',
|
|
hyperdrive_sparse_index: 'bare_os_hyperdrive_sparse_index',
|
|
'hyperdrive_sparse_index.json': 'bare_os_hyperdrive_sparse_index',
|
|
protomux_channel_alias_v2: 'bare_os_protomux_channel_alias_v2',
|
|
'protomux_channel_alias_v2.json':
|
|
'bare_os_protomux_channel_alias_v2',
|
|
structured_clone_budget_v2: 'bare_os_structured_clone_budget_v2',
|
|
'structured_clone_budget_v2.json':
|
|
'bare_os_structured_clone_budget_v2',
|
|
form_data_delegate_limits_v2: 'bare_os_form_data_delegate_limits_v2',
|
|
'form_data_delegate_limits_v2.json':
|
|
'bare_os_form_data_delegate_limits_v2',
|
|
extensions: 'bare_os_extensions',
|
|
'extensions.json': 'bare_os_extensions',
|
|
hdms_hints: 'bare_os_hdms_hints',
|
|
'hdms_hints.json': 'bare_os_hdms_hints',
|
|
pear_trust: 'bare_os_pear_trust',
|
|
'pear_trust.json': 'bare_os_pear_trust',
|
|
security_posture: 'bare_os_security_posture',
|
|
'security_posture.json': 'bare_os_security_posture',
|
|
rlimits: 'bare_os_rlimits',
|
|
'rlimits.json': 'bare_os_rlimits',
|
|
hdms_health: 'bare_os_hdms_health',
|
|
'hdms_health.json': 'bare_os_hdms_health',
|
|
activity_queue_depth: 'bare_os_activity_queue_depth',
|
|
'activity_queue_depth.json': 'bare_os_activity_queue_depth',
|
|
autobase_writer_hint: 'bare_os_autobase_writer_hint',
|
|
'autobase_writer_hint.json': 'bare_os_autobase_writer_hint',
|
|
bare_boot_phase_map: 'bare_os_bare_boot_phase_map',
|
|
'bare_boot_phase_map.json': 'bare_os_bare_boot_phase_map',
|
|
bare_inspect_policy: 'bare_os_bare_inspect_policy',
|
|
'bare_inspect_policy.json': 'bare_os_bare_inspect_policy',
|
|
bare_logger_policy: 'bare_os_bare_logger_policy',
|
|
'bare_logger_policy.json': 'bare_os_bare_logger_policy',
|
|
bare_performance_counters: 'bare_os_bare_performance_counters',
|
|
'bare_performance_counters.json': 'bare_os_bare_performance_counters',
|
|
bare_rpc_registry_sketch: 'bare_os_bare_rpc_registry_sketch',
|
|
'bare_rpc_registry_sketch.json': 'bare_os_bare_rpc_registry_sketch',
|
|
bare_signals_mask: 'bare_os_bare_signals_mask',
|
|
'bare_signals_mask.json': 'bare_os_bare_signals_mask',
|
|
bare_stream_backpressure: 'bare_os_bare_stream_backpressure',
|
|
'bare_stream_backpressure.json': 'bare_os_bare_stream_backpressure',
|
|
bare_timers_budget: 'bare_os_bare_timers_budget',
|
|
'bare_timers_budget.json': 'bare_os_bare_timers_budget',
|
|
bare_tls_session_hint: 'bare_os_bare_tls_session_hint',
|
|
'bare_tls_session_hint.json': 'bare_os_bare_tls_session_hint',
|
|
bare_ws_gateway_sketch: 'bare_os_bare_ws_gateway_sketch',
|
|
'bare_ws_gateway_sketch.json': 'bare_os_bare_ws_gateway_sketch',
|
|
blind_pairing_sketch: 'bare_os_blind_pairing_sketch',
|
|
'blind_pairing_sketch.json': 'bare_os_blind_pairing_sketch',
|
|
broadcast_encryption_hint: 'bare_os_broadcast_encryption_hint',
|
|
'broadcast_encryption_hint.json': 'bare_os_broadcast_encryption_hint',
|
|
pear_api_allowlist_sketch: 'bare_os_pear_api_allowlist_sketch',
|
|
'pear_api_allowlist_sketch.json': 'bare_os_pear_api_allowlist_sketch',
|
|
pear_doctor_state: 'bare_os_pear_doctor_state',
|
|
'pear_doctor_state.json': 'bare_os_pear_doctor_state',
|
|
pear_rti_pointer: 'bare_os_pear_rti_pointer',
|
|
'pear_rti_pointer.json': 'bare_os_pear_rti_pointer',
|
|
pear_user_dirs_map: 'bare_os_pear_user_dirs_map',
|
|
'pear_user_dirs_map.json': 'bare_os_pear_user_dirs_map',
|
|
pear_workshop_flags: 'bare_os_pear_workshop_flags',
|
|
'pear_workshop_flags.json': 'bare_os_pear_workshop_flags',
|
|
hypercore_replicate_budget: 'bare_os_hypercore_replicate_budget',
|
|
'hypercore_replicate_budget.json':
|
|
'bare_os_hypercore_replicate_budget',
|
|
drive_version_graph: 'bare_os_drive_version_graph',
|
|
'drive_version_graph.json': 'bare_os_drive_version_graph',
|
|
protomux_backpressure: 'bare_os_protomux_backpressure',
|
|
'protomux_backpressure.json': 'bare_os_protomux_backpressure',
|
|
pear_runtime_matrix: 'bare_os_pear_runtime_matrix',
|
|
'pear_runtime_matrix.json': 'bare_os_pear_runtime_matrix',
|
|
bundle_preload_hint: 'bare_os_bundle_preload_hint',
|
|
'bundle_preload_hint.json': 'bare_os_bundle_preload_hint',
|
|
autopass_rotation_sketch: 'bare_os_autopass_rotation_sketch',
|
|
'autopass_rotation_sketch.json':
|
|
'bare_os_autopass_rotation_sketch',
|
|
hrpc_allowlist_sketch: 'bare_os_hrpc_allowlist_sketch',
|
|
'hrpc_allowlist_sketch.json': 'bare_os_hrpc_allowlist_sketch',
|
|
sidecar_resource_cap: 'bare_os_sidecar_resource_cap',
|
|
'sidecar_resource_cap.json': 'bare_os_sidecar_resource_cap',
|
|
git_lfs_budget: 'bare_os_git_lfs_budget',
|
|
'git_lfs_budget.json': 'bare_os_git_lfs_budget',
|
|
net_qos_class: 'bare_os_net_qos_class',
|
|
'net_qos_class.json': 'bare_os_net_qos_class',
|
|
storage_tier_hint: 'bare_os_storage_tier_hint',
|
|
'storage_tier_hint.json': 'bare_os_storage_tier_hint',
|
|
indexer_catchup: 'bare_os_indexer_catchup',
|
|
'indexer_catchup.json': 'bare_os_indexer_catchup',
|
|
multisig_quorum_pointer: 'bare_os_multisig_quorum_pointer',
|
|
'multisig_quorum_pointer.json':
|
|
'bare_os_multisig_quorum_pointer',
|
|
relay_geo_hint: 'bare_os_relay_geo_hint',
|
|
'relay_geo_hint.json': 'bare_os_relay_geo_hint',
|
|
bare_pack_cache: 'bare_os_bare_pack_cache',
|
|
'bare_pack_cache.json': 'bare_os_bare_pack_cache',
|
|
bare_addon_policy: 'bare_os_bare_addon_policy',
|
|
'bare_addon_policy.json': 'bare_os_bare_addon_policy',
|
|
bare_signals_profile: 'bare_os_bare_signals_profile',
|
|
'bare_signals_profile.json': 'bare_os_bare_signals_profile',
|
|
bare_timers_histogram: 'bare_os_bare_timers_histogram',
|
|
'bare_timers_histogram.json': 'bare_os_bare_timers_histogram',
|
|
wave11_peer_qos_sketch: 'bare_os_wave11_peer_qos_sketch',
|
|
'wave11_peer_qos_sketch.json': 'bare_os_wave11_peer_qos_sketch',
|
|
wave11_operator_slo_v2: 'bare_os_wave11_operator_slo_v2',
|
|
'wave11_operator_slo_v2.json': 'bare_os_wave11_operator_slo_v2',
|
|
kernel_program: 'bare_os_kernel_program',
|
|
'kernel_program.json': 'bare_os_kernel_program',
|
|
giant_phase_program: 'bare_os_giant_phase_program',
|
|
'giant_phase_program.json': 'bare_os_giant_phase_program',
|
|
'initd_graph.json': 'bare_os_initd_graph'
|
|
}[rest]
|
|
if (alias) {
|
|
if (
|
|
omitHypercorePackHrpcLifecycleProc &&
|
|
/** @type {Record<string, string>} */ (BARE_OS_PROC_FILE_TO_ID_HYPERCORE_PACK_HRPC_LIFECYCLE)[
|
|
alias
|
|
]
|
|
) {
|
|
return { virtualPseudo: true, kind: 'proc', node: 'enoent' }
|
|
}
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: alias
|
|
}
|
|
}
|
|
return { virtualPseudo: true, kind: 'proc', node: 'enoent' }
|
|
}
|
|
if (sub === 'bare_os_session_stats') {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: 'bare_os_session_stats'
|
|
}
|
|
}
|
|
if (sub === 'diskstats') {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: 'diskstats'
|
|
}
|
|
}
|
|
if (sub === 'bare_os_quotas') {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: 'bare_os_quotas'
|
|
}
|
|
}
|
|
if (sub === 'bare_os_resources') {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: 'bare_os_resources'
|
|
}
|
|
}
|
|
if (sub === 'bare_os_features') {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: 'bare_os_features'
|
|
}
|
|
}
|
|
if (sub === 'bare_os_features.json') {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: 'bare_os_features'
|
|
}
|
|
}
|
|
if (sub === 'bare_os_swarm') {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: 'bare_os_swarm'
|
|
}
|
|
}
|
|
if (sub === 'bare_os_swarm.json') {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: 'bare_os_swarm'
|
|
}
|
|
}
|
|
if (sub === 'bare_os_swarm_health') {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: 'bare_os_swarm_health'
|
|
}
|
|
}
|
|
if (
|
|
sub === 'bare_os_swarm_health.json' ||
|
|
sub === 'bare_os_swarm_status.json'
|
|
) {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: 'bare_os_swarm_health'
|
|
}
|
|
}
|
|
if (sub === 'bare_os_swarm_replication_status.json') {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: 'bare_os_swarm_replication_status'
|
|
}
|
|
}
|
|
if (sub === 'bare_os_swarm_relay_status.json') {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: 'bare_os_swarm_relay_status'
|
|
}
|
|
}
|
|
if (sub === 'bare_os_swarm_datagrams_status.json') {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: 'bare_os_swarm_datagrams_status'
|
|
}
|
|
}
|
|
if (sub === 'bare_os_swarm_connection_manager_status.json') {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: 'bare_os_swarm_connection_manager_status'
|
|
}
|
|
}
|
|
if (sub === 'bare_os_swarm_key_broker_status.json') {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: 'bare_os_swarm_key_broker_status'
|
|
}
|
|
}
|
|
if (sub === 'bare_os_swarm_holepunch_status.json') {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: 'bare_os_swarm_holepunch_status'
|
|
}
|
|
}
|
|
if (sub === 'bare_os_swarm_datagram_replication_status.json') {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: 'bare_os_swarm_datagram_replication_status'
|
|
}
|
|
}
|
|
if (sub === 'bare_os_replication') {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: 'bare_os_replication'
|
|
}
|
|
}
|
|
if (sub === 'bare_os_capabilities') {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: 'bare_os_capabilities'
|
|
}
|
|
}
|
|
if (sub === 'bare_os_capabilities.json') {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: 'bare_os_capabilities_json'
|
|
}
|
|
}
|
|
if (sub === 'bare_os_bootstrap') {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: 'bare_os_bootstrap'
|
|
}
|
|
}
|
|
if (sub === 'bare_os_union') {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: 'bare_os_union'
|
|
}
|
|
}
|
|
if (sub === 'bare_os_seed_handshake') {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: 'bare_os_seed_handshake'
|
|
}
|
|
}
|
|
if (sub === 'bare_os_virtual_registry') {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: 'bare_os_virtual_registry'
|
|
}
|
|
}
|
|
if (sub === 'bare_os_manifest_hints') {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: 'bare_os_manifest_hints'
|
|
}
|
|
}
|
|
if (sub === 'bare_os_peer_health') {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: 'bare_os_peer_health'
|
|
}
|
|
}
|
|
if (sub === 'bare_os_staging_slot') {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: 'bare_os_staging_slot'
|
|
}
|
|
}
|
|
if (
|
|
sub === 'bare_os_snapshot_hints' ||
|
|
sub === 'bare_os_snapshot_hints.json'
|
|
) {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: 'bare_os_snapshot_hints'
|
|
}
|
|
}
|
|
if (sub === 'bare_os_provenance') {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: 'bare_os_provenance'
|
|
}
|
|
}
|
|
if (sub === 'bare_os_initd_dag.json') {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: 'bare_os_initd_dag'
|
|
}
|
|
}
|
|
if (sub === 'bare_os_initd_readiness.json') {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: 'bare_os_initd_readiness'
|
|
}
|
|
}
|
|
if (sub === 'bare_os_boot_graph.json') {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: 'bare_os_boot_graph'
|
|
}
|
|
}
|
|
if (sub === 'bare_os_boot_budget_summary.json') {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: 'bare_os_boot_budget_summary'
|
|
}
|
|
}
|
|
if (
|
|
sub === 'bare_os_metrics_live' ||
|
|
sub === 'bare_os_metrics_live.json'
|
|
) {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: 'bare_os_metrics_live'
|
|
}
|
|
}
|
|
if (sub === 'bare_os_chat' || sub === 'bare_os_chat.json') {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: 'bare_os_chat'
|
|
}
|
|
}
|
|
if (sub === 'bare_os_meshdrop' || sub === 'bare_os_meshdrop.json') {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: 'bare_os_meshdrop'
|
|
}
|
|
}
|
|
if (
|
|
sub === 'bare_os_peer_details' ||
|
|
sub === 'bare_os_peer_details.json'
|
|
) {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: 'bare_os_peer_details'
|
|
}
|
|
}
|
|
if (sub === 'bare_os_dht_scan' || sub === 'bare_os_dht_scan.json') {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: 'bare_os_dht_scan'
|
|
}
|
|
}
|
|
if (
|
|
sub === 'bare_os_swarm_doctor' ||
|
|
sub === 'bare_os_swarm_doctor.json'
|
|
) {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: 'bare_os_swarm_doctor'
|
|
}
|
|
}
|
|
if (
|
|
sub === 'bare_os_route_summary' ||
|
|
sub === 'bare_os_route_summary.json'
|
|
) {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: 'bare_os_route_summary'
|
|
}
|
|
}
|
|
if (
|
|
sub === 'bare_os_holepunch_summary' ||
|
|
sub === 'bare_os_holepunch_summary.json'
|
|
) {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: 'bare_os_holepunch_summary'
|
|
}
|
|
}
|
|
if (
|
|
sub === 'bare_os_metrics_prom' ||
|
|
sub === 'bare_os_metrics_prom.json'
|
|
) {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: 'bare_os_metrics_prom'
|
|
}
|
|
}
|
|
if (
|
|
sub === 'bare_os_protomux_wire' ||
|
|
sub === 'bare_os_protomux_wire.json'
|
|
) {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: 'bare_os_protomux_wire'
|
|
}
|
|
}
|
|
if (
|
|
sub === 'bare_os_protomux_extensions' ||
|
|
sub === 'bare_os_protomux_extensions.json'
|
|
) {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: 'bare_os_protomux_extensions'
|
|
}
|
|
}
|
|
if (
|
|
sub === 'bare_os_net_summary' ||
|
|
sub === 'bare_os_net_summary.json'
|
|
) {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: 'bare_os_net_summary'
|
|
}
|
|
}
|
|
if (
|
|
sub === 'bare_os_host_os' ||
|
|
sub === 'bare_os_host_os.json'
|
|
) {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: 'bare_os_host_os'
|
|
}
|
|
}
|
|
if (
|
|
sub === 'bare_os_sync_window' ||
|
|
sub === 'bare_os_sync_window.json'
|
|
) {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: 'bare_os_sync_window'
|
|
}
|
|
}
|
|
if (sub === 'bare_os_clock' || sub === 'bare_os_clock.json') {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: 'bare_os_clock'
|
|
}
|
|
}
|
|
if (sub === 'bare_os_openssh' || sub === 'bare_os_openssh.json') {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: 'bare_os_openssh'
|
|
}
|
|
}
|
|
if (sub === 'bare_os_debug' || sub === 'bare_os_debug.json') {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: 'bare_os_debug'
|
|
}
|
|
}
|
|
if (sub === 'bare_os_extensions.json') {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: 'bare_os_extensions'
|
|
}
|
|
}
|
|
if (sub === 'bare_os_hdms_hints.json') {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: 'bare_os_hdms_hints'
|
|
}
|
|
}
|
|
if (sub === 'bare_os_pear_trust.json') {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: 'bare_os_pear_trust'
|
|
}
|
|
}
|
|
if (sub === 'bare_os_security_posture.json') {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: 'bare_os_security_posture'
|
|
}
|
|
}
|
|
if (sub === 'bare_os_rlimits.json') {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: 'bare_os_rlimits'
|
|
}
|
|
}
|
|
if (sub === 'bare_os_hdms_health.json') {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: 'bare_os_hdms_health'
|
|
}
|
|
}
|
|
if (sub === 'bare_os_initd_graph.json') {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: 'bare_os_initd_graph'
|
|
}
|
|
}
|
|
if (sub === 'self/fd' || sub === 'self/fd/') {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'dir',
|
|
dir: 'self_fd'
|
|
}
|
|
}
|
|
if (sub.startsWith('self/fd/')) {
|
|
const fd = sub.slice('self/fd/'.length).replace(/\/+$/, '')
|
|
if (/^[0-9]+$/.test(fd)) {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: 'self_fd',
|
|
fdNum: fd
|
|
}
|
|
}
|
|
}
|
|
if (sub === 'net' || sub === 'net/') {
|
|
return { virtualPseudo: true, kind: 'proc', node: 'dir', dir: 'net' }
|
|
}
|
|
if (sub === 'net/dev') {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: 'net_dev'
|
|
}
|
|
}
|
|
if (sub === 'net/tcp') {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: 'net_tcp'
|
|
}
|
|
}
|
|
if (sub === 'net/udp') {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: 'net_udp'
|
|
}
|
|
}
|
|
if (sub.startsWith('bare_os_')) {
|
|
const stripped = sub.replace(/\.json$/i, '')
|
|
if (BARE_OS_PROC_FILE_TO_ID_REPLICATION_OPERATOR_SURFACE[stripped]) {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: stripped
|
|
}
|
|
}
|
|
if (BARE_OS_PROC_FILE_TO_ID_PEAR_CORESTORE_HRPC[stripped]) {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: stripped
|
|
}
|
|
}
|
|
if (BARE_OS_PROC_FILE_TO_ID_BARE_RUNTIME_PROTO_MUX[stripped]) {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: stripped
|
|
}
|
|
}
|
|
if (BARE_OS_PROC_FILE_TO_ID_BARE_MODULE_CRYPTO_STAGING[stripped]) {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: stripped
|
|
}
|
|
}
|
|
if (BARE_OS_PROC_FILE_TO_ID_PEAR_INSPECT_LOGGER_TLS[stripped]) {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: stripped
|
|
}
|
|
}
|
|
if (
|
|
!omitHypercorePackHrpcLifecycleProc &&
|
|
BARE_OS_PROC_FILE_TO_ID_HYPERCORE_PACK_HRPC_LIFECYCLE[stripped]
|
|
) {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'proc',
|
|
node: 'file',
|
|
file: stripped
|
|
}
|
|
}
|
|
}
|
|
return { virtualPseudo: true, kind: 'proc', node: 'enoent' }
|
|
}
|
|
if (n === '/run' || n.startsWith('/run/')) {
|
|
if (n === '/run') {
|
|
return { virtualPseudo: true, kind: 'run', node: 'root' }
|
|
}
|
|
if (n === '/run/bare-os') {
|
|
return { virtualPseudo: true, kind: 'run', node: 'dir', dir: 'bare_os' }
|
|
}
|
|
if (n === '/run/bare-os/units') {
|
|
return { virtualPseudo: true, kind: 'run', node: 'file', file: 'units' }
|
|
}
|
|
if (
|
|
n === '/run/bare-os/unit-journal' ||
|
|
n === '/run/bare-os/unit-journal/'
|
|
) {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'run',
|
|
node: 'dir',
|
|
dir: 'unit_journal_root'
|
|
}
|
|
}
|
|
{
|
|
const uj = '/run/bare-os/unit-journal/'
|
|
if (n.startsWith(uj)) {
|
|
const seg = n.slice(uj.length).replace(/\/+$/, '')
|
|
if (/^[a-zA-Z0-9._-]+\.ndjson$/.test(seg)) {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'run',
|
|
node: 'file',
|
|
file: 'unit_journal',
|
|
unitJournalName: seg.replace(/\.ndjson$/, '')
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (n === '/run/bare-os/boot_profile') {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'run',
|
|
node: 'file',
|
|
file: 'boot_profile'
|
|
}
|
|
}
|
|
if (n === '/run/bare-os/session') {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'run',
|
|
node: 'file',
|
|
file: 'session'
|
|
}
|
|
}
|
|
if (n === '/run/bare-os/ready') {
|
|
return { virtualPseudo: true, kind: 'run', node: 'file', file: 'ready' }
|
|
}
|
|
if (n === '/run/bare-os/boot.json') {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'run',
|
|
node: 'file',
|
|
file: 'boot_json'
|
|
}
|
|
}
|
|
if (n === '/run/bare-os/virtual' || n === '/run/bare-os/virtual/') {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'run',
|
|
node: 'dir',
|
|
dir: 'virtual_root'
|
|
}
|
|
}
|
|
{
|
|
const vpref = '/run/bare-os/virtual/'
|
|
if (n.startsWith(vpref)) {
|
|
const seg = n.slice(vpref.length).replace(/\/+$/, '')
|
|
if (seg && !seg.includes('/')) {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'run',
|
|
node: 'file',
|
|
file: 'virtual_plugin',
|
|
virtualName: seg
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (n === '/run/bare-os/ipc') {
|
|
if (!bareOsIpc) {
|
|
return { virtualPseudo: true, kind: 'run', node: 'enoent' }
|
|
}
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'run',
|
|
node: 'dir',
|
|
dir: 'bare_ipc'
|
|
}
|
|
}
|
|
const ipcPref = '/run/bare-os/ipc/'
|
|
if (n.startsWith(ipcPref)) {
|
|
if (!bareOsIpc) {
|
|
return { virtualPseudo: true, kind: 'run', node: 'enoent' }
|
|
}
|
|
const seg = n.slice(ipcPref.length).replace(/\/+$/, '')
|
|
if (!seg || seg.includes('/')) {
|
|
return { virtualPseudo: true, kind: 'run', node: 'enoent' }
|
|
}
|
|
const ipcActual = ipcFifoLogicalToActual(seg)
|
|
if (!bareOsIpc.has(ipcActual)) {
|
|
return { virtualPseudo: true, kind: 'run', node: 'enoent' }
|
|
}
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'run',
|
|
node: 'file',
|
|
file: 'ipc',
|
|
ipcName: ipcActual
|
|
}
|
|
}
|
|
return { virtualPseudo: true, kind: 'run', node: 'enoent' }
|
|
}
|
|
if (n === '/dev' || n.startsWith('/dev/')) {
|
|
if (n === '/dev') {
|
|
return { virtualPseudo: true, kind: 'dev', node: 'root' }
|
|
}
|
|
if (n === '/dev/null') {
|
|
return { virtualPseudo: true, kind: 'dev', node: 'file', file: 'null' }
|
|
}
|
|
if (n === '/dev/zero') {
|
|
return { virtualPseudo: true, kind: 'dev', node: 'file', file: 'zero' }
|
|
}
|
|
if (n === '/dev/urandom') {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'dev',
|
|
node: 'file',
|
|
file: 'urandom'
|
|
}
|
|
}
|
|
if (n === '/dev/shm' || n === '/dev/shm/') {
|
|
return { virtualPseudo: true, kind: 'dev', node: 'dir', dir: 'shm' }
|
|
}
|
|
if (n.startsWith('/dev/shm/')) {
|
|
const seg = n.slice('/dev/shm/'.length).replace(/\/+$/, '')
|
|
if (
|
|
!seg ||
|
|
seg.includes('/') ||
|
|
!/^[a-zA-Z0-9._-]{1,128}$/.test(seg)
|
|
) {
|
|
return { virtualPseudo: true, kind: 'dev', node: 'enoent' }
|
|
}
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'dev',
|
|
node: 'file',
|
|
file: 'shm',
|
|
shmName: seg
|
|
}
|
|
}
|
|
return { virtualPseudo: true, kind: 'dev', node: 'enoent' }
|
|
}
|
|
if (n === '/sys' || n.startsWith('/sys/')) {
|
|
if (n === '/sys') {
|
|
return { virtualPseudo: true, kind: 'sys', node: 'root' }
|
|
}
|
|
if (n === '/sys/fs') {
|
|
return { virtualPseudo: true, kind: 'sys', node: 'dir', dir: 'fs' }
|
|
}
|
|
if (n === '/sys/fs/bare_os') {
|
|
return { virtualPseudo: true, kind: 'sys', node: 'dir', dir: 'bare_os' }
|
|
}
|
|
if (n === '/sys/fs/bare_os/version') {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'sys',
|
|
node: 'file',
|
|
file: 'version'
|
|
}
|
|
}
|
|
if (n === '/sys/fs/bare_os/build_id') {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'sys',
|
|
node: 'file',
|
|
file: 'build_id'
|
|
}
|
|
}
|
|
if (n === '/sys/class' || n === '/sys/class/') {
|
|
return { virtualPseudo: true, kind: 'sys', node: 'dir', dir: 'class' }
|
|
}
|
|
if (n === '/sys/class/net' || n === '/sys/class/net/') {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'sys',
|
|
node: 'dir',
|
|
dir: 'class_net'
|
|
}
|
|
}
|
|
if (n === '/sys/class/net/lo') {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'sys',
|
|
node: 'file',
|
|
file: 'class_net_lo'
|
|
}
|
|
}
|
|
if (n === '/sys/devices' || n === '/sys/devices/') {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'sys',
|
|
node: 'dir',
|
|
dir: 'devices'
|
|
}
|
|
}
|
|
if (n === '/sys/devices/virtual' || n === '/sys/devices/virtual/') {
|
|
return {
|
|
virtualPseudo: true,
|
|
kind: 'sys',
|
|
node: 'dir',
|
|
dir: 'devices_virtual'
|
|
}
|
|
}
|
|
return { virtualPseudo: true, kind: 'sys', node: 'enoent' }
|
|
}
|
|
return null
|
|
}
|
|
|
|
function lstatVirtualPseudo(abs, r) {
|
|
if (!r.virtualPseudo) return null
|
|
if (r.node === 'enoent') return null
|
|
if (r.node === 'root' || r.node === 'dir') {
|
|
const personalDir =
|
|
r.kind === 'run' && r.node === 'dir' && r.dir === 'bare_ipc'
|
|
return {
|
|
...synthesizeStat(abs, personalDir, env, 'directory'),
|
|
path: abs
|
|
}
|
|
}
|
|
if (r.file === 'ipc') {
|
|
const st = { ...synthesizeStat(abs, true, env, 'file'), path: abs }
|
|
st.size = 0
|
|
return st
|
|
}
|
|
const body = pseudoFileBytes(r)
|
|
const st = { ...synthesizeStat(abs, false, env, 'file'), path: abs }
|
|
st.size = body.byteLength
|
|
return st
|
|
}
|
|
|
|
/**
|
|
* `cd ~`, `touch ~/x`, etc. must map to $HOME — otherwise `unix-path-resolve(cwd, '~')`
|
|
* becomes `/~` on the system drive (read-only).
|
|
*/
|
|
function expandTilde(userPath) {
|
|
const h = normalizeHome()
|
|
if (userPath === '~') return h
|
|
if (userPath.startsWith('~/')) {
|
|
const rest = userPath.slice(2)
|
|
return rest ? unixPathResolve(h, rest) : h
|
|
}
|
|
return userPath
|
|
}
|
|
|
|
/** Logical absolute path from cwd + user path */
|
|
function resolveLogical(userPath) {
|
|
const expanded = expandTilde(userPath)
|
|
return unixPathResolve(cwd, expanded)
|
|
}
|
|
|
|
function getMntMap() {
|
|
if (mntRef && typeof mntRef.getMounts === 'function')
|
|
return mntRef.getMounts()
|
|
return new Map()
|
|
}
|
|
|
|
/** Linux-shaped mount table: root + HDMS `/mnt/<label>` rows (best-effort). */
|
|
function pseudoMountsText() {
|
|
const lines = ['bare-os-root / hyperdrive ro 0 0']
|
|
if (systemRoAliasNorm)
|
|
lines.push(
|
|
`bare-os-system-ro-alias ${systemRoAliasNorm} hyperdrive ro 0 0`
|
|
)
|
|
const map = getMntMap()
|
|
const keys = [...map.keys()].sort((a, b) => a.localeCompare(b))
|
|
for (const label of keys) {
|
|
const ent = map.get(label)
|
|
if (!ent) continue
|
|
const rw = ent.writable ? 'rw' : 'ro'
|
|
lines.push(`bare-os-${label} /mnt/${label} hyperdrive ${rw} 0 0`)
|
|
}
|
|
try {
|
|
const extra = getAuxiliaryMountLines ? getAuxiliaryMountLines() : []
|
|
if (Array.isArray(extra)) {
|
|
for (const row of extra) {
|
|
if (typeof row === 'string' && row.trim()) lines.push(row.trim())
|
|
}
|
|
}
|
|
} catch {
|
|
/* ignore */
|
|
}
|
|
return lines.join('\n') + '\n'
|
|
}
|
|
|
|
/**
|
|
* Optional read-only auxiliary Hyperdrives under `/mirror/aux0`, `/mirror/aux1`, …
|
|
* @returns {null | Record<string, unknown>}
|
|
*/
|
|
function routeMirror(absPath) {
|
|
const aux = getAuxiliaryDrives ? getAuxiliaryDrives() : null
|
|
if (!Array.isArray(aux) || aux.length === 0) return null
|
|
if (absPath === '/mirror' || absPath === '/mirror/') {
|
|
return { virtualMirrorRoot: true }
|
|
}
|
|
if (!absPath.startsWith('/mirror/')) return null
|
|
const rest = absPath.slice('/mirror/'.length)
|
|
const slash = rest.indexOf('/')
|
|
const seg = slash === -1 ? rest : rest.slice(0, slash)
|
|
const tail = slash === -1 ? '' : rest.slice(slash + 1)
|
|
if (!seg) return { virtualMirrorRoot: true }
|
|
const m = /^aux(\d+)$/.exec(seg)
|
|
if (!m) {
|
|
return { drive: systemDrive, path: absPath }
|
|
}
|
|
const idx = Number(m[1])
|
|
const drive = /** @type {unknown} */ (aux[idx])
|
|
if (
|
|
!drive ||
|
|
typeof (/** @type {{ get?: unknown }} */ (drive).get) !== 'function'
|
|
) {
|
|
return { drive: systemDrive, path: absPath }
|
|
}
|
|
const sub = tail ? '/' + tail.replace(/^\/+/, '') : '/'
|
|
const p = unixPathResolve('/', sub)
|
|
return {
|
|
drive: /** @type {import('hyperdrive').default} */ (drive),
|
|
path: p,
|
|
mntReadOnly: true
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @returns {null | Record<string, unknown>}
|
|
*/
|
|
function routeMnt(absPath) {
|
|
if (absPath === '/mnt' || absPath === '/mnt/') {
|
|
return { virtualMntRoot: true }
|
|
}
|
|
if (!absPath.startsWith('/mnt/')) return null
|
|
const rest = absPath.slice(5)
|
|
const slash = rest.indexOf('/')
|
|
const label = slash === -1 ? rest : rest.slice(0, slash)
|
|
const tail = slash === -1 ? '' : rest.slice(slash + 1)
|
|
if (!label) return { virtualMntRoot: true }
|
|
const mounts = getMntMap()
|
|
const ent = mounts.get(label)
|
|
if (!ent) {
|
|
return { drive: systemDrive, path: absPath }
|
|
}
|
|
const sub = tail ? '/' + tail.replace(/^\/+/, '') : '/'
|
|
const p = unixPathResolve('/', sub)
|
|
return { drive: ent.drive, path: p, mntReadOnly: !ent.writable }
|
|
}
|
|
|
|
/**
|
|
* Map logical absolute path to { drive, path } for Hyperdrive ops.
|
|
* Virtual /home lists only the active session dir; /home/<active>/… is the personal drive.
|
|
*/
|
|
function routeSystemRoAlias(absPath) {
|
|
if (!systemRoAliasNorm || !systemRoAliasNorm.startsWith('/')) return null
|
|
const norm = absPath.replace(/\/+$/, '') || '/'
|
|
if (
|
|
norm !== systemRoAliasNorm &&
|
|
!absPath.startsWith(systemRoAliasNorm + '/')
|
|
)
|
|
return null
|
|
let tail = '/'
|
|
if (norm !== systemRoAliasNorm) {
|
|
tail = absPath.slice(systemRoAliasNorm.length) || '/'
|
|
}
|
|
const p = tail.startsWith('/') ? tail : '/' + tail
|
|
const resolved = unixPathResolve('/', p.replace(/^\/+/, '') || '/')
|
|
return {
|
|
drive: systemDrive,
|
|
path: resolved,
|
|
mntReadOnly: true
|
|
}
|
|
}
|
|
|
|
/**
|
|
* When HDMS (or other) mounts label `www` at `/mnt/www`, expose it at `$HOME/.www`.
|
|
* @param {string} relFromHomeRoot path under the session home root (e.g. `.www`, `.www/a`)
|
|
* @returns {{ drive: import('hyperdrive').default, path: string, mntReadOnly: boolean } | null}
|
|
*/
|
|
function routeHomeWwwAlias(relFromHomeRoot) {
|
|
const rel = String(relFromHomeRoot || '').replace(/^\/+/, '')
|
|
if (rel !== '.www' && !rel.startsWith('.www/')) return null
|
|
const mounts = getMntMap()
|
|
const ent = mounts.get('www')
|
|
if (!ent) return null
|
|
const wwwPrefix = '.www/'
|
|
const tail =
|
|
rel === '.www'
|
|
? ''
|
|
: rel.startsWith(wwwPrefix)
|
|
? rel.slice(wwwPrefix.length)
|
|
: null
|
|
if (tail === null && rel !== '.www') return null
|
|
const sub = tail ? '/' + tail.replace(/^\/+/, '') : '/'
|
|
const p = unixPathResolve('/', sub)
|
|
return {
|
|
drive: ent.drive,
|
|
path: p,
|
|
mntReadOnly: !ent.writable
|
|
}
|
|
}
|
|
|
|
function route(absPath) {
|
|
const aliasR = routeSystemRoAlias(absPath)
|
|
if (aliasR) return aliasR
|
|
const mirR = routeMirror(absPath)
|
|
if (mirR) return mirR
|
|
const mntR = routeMnt(absPath)
|
|
if (mntR) return mntR
|
|
|
|
const pseudo = classifyPseudoAbs(absPath)
|
|
if (pseudo) return pseudo
|
|
|
|
const tmpRoot = tmpStorageRoot()
|
|
const tmpNorm = absPath.replace(/\/+$/, '') || '/'
|
|
if (tmpNorm === '/tmp') {
|
|
return { drive: personalDrive, path: tmpRoot }
|
|
}
|
|
if (absPath.startsWith('/tmp/')) {
|
|
const rel = absPath.slice(5).replace(/^\/+/, '')
|
|
const p = rel ? unixPathResolve(tmpRoot, rel) : tmpRoot
|
|
return { drive: personalDrive, path: p }
|
|
}
|
|
|
|
const varNorm = absPath.replace(/\/+$/, '') || '/'
|
|
if (varNorm === '/var') {
|
|
return { virtualVarRoot: true }
|
|
}
|
|
const varLogRoot = varLogStorageRoot()
|
|
if (varNorm === '/var/log' || absPath === '/var/log/') {
|
|
return { drive: personalDrive, path: varLogRoot }
|
|
}
|
|
if (absPath.startsWith('/var/log/')) {
|
|
const rel = absPath.slice('/var/log/'.length).replace(/^\/+/, '')
|
|
const p = rel ? unixPathResolve(varLogRoot, rel) : varLogRoot
|
|
return { drive: personalDrive, path: p }
|
|
}
|
|
if (absPath.startsWith('/var/')) {
|
|
return { drive: systemDrive, path: absPath }
|
|
}
|
|
|
|
const h = normalizeHome()
|
|
const activeSeg = activeHomeBasename()
|
|
const homeRoot = personalHomeStorageRoot()
|
|
|
|
if (activeSeg && absPath === '/home') {
|
|
return { virtualHomeDir: true }
|
|
}
|
|
|
|
if (activeSeg && absPath.startsWith('/home/')) {
|
|
const after = absPath.slice('/home/'.length)
|
|
const slash = after.indexOf('/')
|
|
const seg = slash === -1 ? after : after.slice(0, slash)
|
|
const rest = slash === -1 ? '' : after.slice(slash + 1)
|
|
if (seg === activeSeg) {
|
|
if (!rest) {
|
|
return { drive: personalDrive, path: homeRoot }
|
|
}
|
|
const rel = rest.replace(/^\/+/, '')
|
|
const wwwR = routeHomeWwwAlias(rel)
|
|
if (wwwR) return wwwR
|
|
const p = unixPathResolve(homeRoot, rel)
|
|
return { drive: personalDrive, path: p }
|
|
}
|
|
return { drive: systemDrive, path: absPath }
|
|
}
|
|
|
|
if (absPath === h || absPath.startsWith(h + '/')) {
|
|
if (absPath === h) {
|
|
return { drive: personalDrive, path: homeRoot }
|
|
}
|
|
const rel = absPath.slice(h.length + 1).replace(/^\/+/, '')
|
|
const wwwR = routeHomeWwwAlias(rel)
|
|
if (wwwR) return wwwR
|
|
const p = unixPathResolve(homeRoot, rel)
|
|
return { drive: personalDrive, path: p }
|
|
}
|
|
|
|
const unionNorm = absPath.replace(/\/+$/, '') || '/'
|
|
if (
|
|
unionNorm === '/.bare-os/union' ||
|
|
absPath.startsWith('/.bare-os/union/')
|
|
) {
|
|
const p = unionNorm === '/.bare-os/union' ? '/.bare-os/union' : unionNorm
|
|
return { drive: personalDrive, path: p }
|
|
}
|
|
|
|
const snapsOn =
|
|
env &&
|
|
(env.BARE_OS_VFS_SNAPSHOTS === '1' || env.BARE_OS_VFS_SNAPSHOTS === 'true')
|
|
if (
|
|
snapsOn &&
|
|
systemDrive &&
|
|
typeof systemDrive.checkout === 'function'
|
|
) {
|
|
const snapNorm = absPath.replace(/\/+$/, '') || '/'
|
|
if (snapNorm === '/snapshots') {
|
|
return { virtualSnapshotRoot: true }
|
|
}
|
|
if (snapNorm === '/snapshots/system') {
|
|
return { virtualSnapshotSystem: true }
|
|
}
|
|
const m = /^\/snapshots\/system\/([0-9]+)(\/.*)?$/.exec(absPath)
|
|
if (m) {
|
|
const ver = Number.parseInt(m[1], 10)
|
|
const tail = m[2] || '/'
|
|
const sub =
|
|
tail === '/' ? '/' : unixPathResolve('/', tail.replace(/^\/+/, ''))
|
|
try {
|
|
const chk = systemDrive.checkout(ver)
|
|
if (chk)
|
|
return { drive: chk, path: sub, snapshotReadOnly: true }
|
|
} catch {
|
|
/* fall through to system path */
|
|
}
|
|
}
|
|
}
|
|
|
|
const bareTop = absPath.replace(/\/+$/, '') || '/'
|
|
if (
|
|
personalDrive &&
|
|
(bareTop === '/.bare' || absPath.startsWith('/.bare/'))
|
|
) {
|
|
const p =
|
|
bareTop === '/.bare'
|
|
? '/.bare'
|
|
: absPath.replace(/\/+$/, '') || absPath
|
|
if (usePersonalAcctPrefix()) {
|
|
const tail = bareTop === '/.bare' ? '' : p.slice('/.bare'.length)
|
|
// Managed Holesail persistence: keep `/.bare/holesail/**` on the personal drive root so
|
|
// guest vs unlocked sessions share one `state.json` (not under per-session `acct/…` layout).
|
|
if (tail === '/holesail' || tail.startsWith('/holesail/')) {
|
|
return { drive: personalDrive, path: p }
|
|
}
|
|
const layoutRoot = personalLayoutRootAbs()
|
|
const physical = layoutRoot + '/.bare' + tail
|
|
return { drive: personalDrive, path: physical }
|
|
}
|
|
return { drive: personalDrive, path: p }
|
|
}
|
|
|
|
return { drive: systemDrive, path: absPath }
|
|
}
|
|
|
|
function personalVaultReaddirCacheTtlMs() {
|
|
const raw = env && env.BARE_OS_PERSONAL_VAULT_INDEX_CACHE_MS
|
|
if (raw == null || raw === '' || raw === '0' || raw === 'false') return 0
|
|
const n = Number(raw)
|
|
if (!Number.isFinite(n) || n <= 0) return 0
|
|
return Math.min(Math.floor(n), 3_600_000)
|
|
}
|
|
|
|
/**
|
|
* entry/get/exists use std(name, false), which throws for name === '/'.
|
|
* readdir('/') is OK (std with removeSlash). Treat drive root separately.
|
|
*/
|
|
function isHyperdriveRootPath(p) {
|
|
return p === '/'
|
|
}
|
|
|
|
async function entryOn(drive, p, opts) {
|
|
return drive.entry(p, opts)
|
|
}
|
|
|
|
async function isRegularFile(absPath) {
|
|
if (absPath === '/') return false
|
|
const r = route(absPath)
|
|
if (r.virtualPseudo && r.node === 'file') return true
|
|
if (
|
|
r.virtualHomeDir ||
|
|
r.virtualMntRoot ||
|
|
r.virtualMirrorRoot ||
|
|
r.virtualVarRoot ||
|
|
r.virtualPseudo
|
|
) {
|
|
return false
|
|
}
|
|
const { drive, path: p } = r
|
|
if (isHyperdriveRootPath(p)) return false
|
|
const e = await entryOn(drive, p, { follow: true })
|
|
return !!(e && e.value && e.value.blob)
|
|
}
|
|
|
|
function joinLogical(base, name) {
|
|
if (base === '/') return '/' + name.replace(/^\/+/, '')
|
|
return unixPathResolve(base, name)
|
|
}
|
|
|
|
function dirnameAbs(abs) {
|
|
if (!abs || abs === '/') return '/'
|
|
const t = abs.replace(/\/$/, '')
|
|
const i = t.lastIndexOf('/')
|
|
if (i <= 0) return '/'
|
|
return t.slice(0, i) || '/'
|
|
}
|
|
|
|
/** @param {string} abs */
|
|
function pathPrefixes(abs) {
|
|
if (abs === '/') return ['/']
|
|
const t = abs.replace(/\/$/, '') || '/'
|
|
if (t === '/') return ['/']
|
|
const parts = t.split('/').filter(Boolean)
|
|
const out = ['/']
|
|
let acc = ''
|
|
for (const p of parts) {
|
|
acc += '/' + p
|
|
out.push(acc)
|
|
}
|
|
return out
|
|
}
|
|
|
|
/**
|
|
* Create errno-shaped errors with a stable `code` field.
|
|
* @param {string} code
|
|
* @param {string} message
|
|
*/
|
|
function vfsErr(code, message) {
|
|
const e = new Error(`${code}: ${message}`)
|
|
const errObj = /** @type {{ code?: string }} */ (e)
|
|
errObj.code = code
|
|
return e
|
|
}
|
|
|
|
/**
|
|
* @param {string} abs
|
|
* @param {Awaited<ReturnType<typeof route>>} r
|
|
* @param {boolean} personal
|
|
* @param {Awaited<ReturnType<typeof entryOn>>} e
|
|
*/
|
|
function statFromEntryValue(abs, r, personal, e) {
|
|
const v = e && e.value
|
|
if (!v) return null
|
|
if (v.linkname) {
|
|
const linkname = v.linkname
|
|
const size = utf8Encode(String(linkname)).length
|
|
const bo = extractBareOs(v)
|
|
if (bo) return statFromBareOs(bo, 'symlink', size, abs, linkname)
|
|
return synthesizeStat(abs, personal, env, 'symlink', { linkname })
|
|
}
|
|
if (v.blob) {
|
|
const bl = v.blob
|
|
const len =
|
|
typeof bl.byteLength === 'number'
|
|
? bl.byteLength
|
|
: (bl.blockLength ?? 0)
|
|
const bo = extractBareOs(v)
|
|
const ex = !!v.executable
|
|
if (bo) return statFromBareOs(bo, 'file', len, abs)
|
|
const s = synthesizeStat(abs, personal, env, 'file', { executable: ex })
|
|
s.size = len
|
|
return s
|
|
}
|
|
return null
|
|
}
|
|
|
|
async function lstatFromAbs(abs) {
|
|
if (abs === '/mirror' || abs === '/mirror/') {
|
|
return { ...synthesizeStat(abs, false, env, 'directory'), path: abs }
|
|
}
|
|
if (abs === '/mnt' || abs === '/mnt/') {
|
|
return { ...synthesizeStat(abs, false, env, 'directory'), path: abs }
|
|
}
|
|
const activeSeg = activeHomeBasename()
|
|
if (activeSeg && abs === '/home') {
|
|
return { ...synthesizeStat(abs, false, env, 'directory'), path: abs }
|
|
}
|
|
if (abs === '/') {
|
|
return { ...synthesizeStat(abs, false, env, 'directory'), path: abs }
|
|
}
|
|
const r = route(abs)
|
|
if (r.virtualMntRoot || r.virtualMirrorRoot) {
|
|
return { ...synthesizeStat(abs, false, env, 'directory'), path: abs }
|
|
}
|
|
if (r.virtualVarRoot) {
|
|
return { ...synthesizeStat(abs, true, env, 'directory'), path: abs }
|
|
}
|
|
if (r.virtualSnapshotRoot || r.virtualSnapshotSystem) {
|
|
return { ...synthesizeStat(abs, false, env, 'directory'), path: abs }
|
|
}
|
|
if (r.virtualPseudo) {
|
|
return lstatVirtualPseudo(abs, r)
|
|
}
|
|
const { drive, path: p } = r
|
|
if (
|
|
drive === personalDrive &&
|
|
bareOsGuestSensitivePersonalDenied(p) &&
|
|
bareOsIdentityVfsRef.session !== 'unlocked' &&
|
|
!(
|
|
env?.BARE_OS_GUEST_BARE_READ_ALL === '1' ||
|
|
env?.BARE_OS_GUEST_BARE_READ_ALL === 'true'
|
|
)
|
|
) {
|
|
return null
|
|
}
|
|
const personal = isPersonalRoute(personalDrive, r)
|
|
if (isHyperdriveRootPath(p)) {
|
|
// Writable HDMS mounts are user-owned space; a synthetic root dir must not
|
|
// look like root:root 0755 or mkdir/touch at /mnt/<label>/… gets EACCES.
|
|
const treatAsPersonal = personal || r.mntReadOnly === false
|
|
return {
|
|
...synthesizeStat(abs, treatAsPersonal, env, 'directory'),
|
|
path: abs
|
|
}
|
|
}
|
|
const e = await entryOn(drive, p, { follow: false })
|
|
const fromVal = statFromEntryValue(abs, r, personal, e)
|
|
if (fromVal) return fromVal
|
|
const names = await (async () => {
|
|
const out = []
|
|
try {
|
|
const stream = drive.readdir(p === '/' ? '/' : p)
|
|
for await (const n of stream) out.push(n)
|
|
} catch {
|
|
/* missing */
|
|
}
|
|
return out
|
|
})()
|
|
if (names.length) {
|
|
if (names.includes(DIR_MARKER)) {
|
|
const mLogical = joinLogical(abs, DIR_MARKER)
|
|
const mr = route(mLogical)
|
|
const { drive: md, path: mp } = mr
|
|
if (md && mp && !isHyperdriveRootPath(mp)) {
|
|
const me = await entryOn(md, mp, { follow: false })
|
|
const mv = me?.value
|
|
if (mv?.blob) {
|
|
const bo = extractBareOs(mv)
|
|
if (bo) {
|
|
let perm = bo.mode & 0o777
|
|
if (perm & 0o400) perm |= 0o100
|
|
if (perm & 0o040) perm |= 0o010
|
|
if (perm & 0o004) perm |= 0o001
|
|
return statFromBareOs(
|
|
{ ...bo, mode: S_IFDIR | perm },
|
|
'directory',
|
|
0,
|
|
abs
|
|
)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return { ...synthesizeStat(abs, personal, env, 'directory'), path: abs }
|
|
}
|
|
if (e)
|
|
return { ...synthesizeStat(abs, personal, env, 'directory'), path: abs }
|
|
const normLog = abs.replace(/\/+$/, '') || '/'
|
|
if (
|
|
normLog === '/var/log' &&
|
|
r.drive === personalDrive &&
|
|
p === varLogStorageRoot()
|
|
) {
|
|
return { ...synthesizeStat(abs, true, env, 'directory'), path: abs }
|
|
}
|
|
const normTmp = abs.replace(/\/+$/, '') || '/'
|
|
if (
|
|
normTmp === '/tmp' &&
|
|
r.drive === personalDrive &&
|
|
p === tmpStorageRoot()
|
|
) {
|
|
return { ...synthesizeStat(abs, true, env, 'directory'), path: abs }
|
|
}
|
|
const h = normalizeHome()
|
|
const homeNorm = h.replace(/\/+$/, '') || h
|
|
const absNorm = abs.replace(/\/+$/, '') || abs
|
|
if (activeSeg && absNorm === homeNorm) {
|
|
return { ...synthesizeStat(absNorm, true, env, 'directory'), path: abs }
|
|
}
|
|
return null
|
|
}
|
|
|
|
/**
|
|
* Walk final symlink components on logical paths (POSIX-style relative targets).
|
|
* Hyperdrive `get(..., { follow: true })` does not apply this to VFS layout.
|
|
* @param {string} abs
|
|
* @returns {Promise<string>}
|
|
*/
|
|
async function resolveSymlinksOnLogicalAbs(abs) {
|
|
const normVar = abs.replace(/\/+$/, '') || '/'
|
|
const normTmp = abs.replace(/\/+$/, '') || '/'
|
|
if (
|
|
abs === '/mnt' ||
|
|
abs === '/mnt/' ||
|
|
abs === '/mirror' ||
|
|
abs === '/mirror/' ||
|
|
abs === '/home' ||
|
|
abs === '/' ||
|
|
normVar === '/var' ||
|
|
normVar === '/var/log' ||
|
|
normTmp === '/tmp' ||
|
|
(activeHomeBasename() && abs === '/home')
|
|
) {
|
|
return abs
|
|
}
|
|
const r0 = route(abs)
|
|
if (
|
|
r0.virtualMntRoot ||
|
|
r0.virtualMirrorRoot ||
|
|
r0.virtualVarRoot ||
|
|
r0.virtualPseudo ||
|
|
r0.virtualSnapshotRoot ||
|
|
r0.virtualSnapshotSystem
|
|
) {
|
|
return abs
|
|
}
|
|
let cur = abs
|
|
/** @type {Set<string>} */
|
|
const seen = new Set()
|
|
for (let depth = 0; depth < 64; depth++) {
|
|
const curNorm = cur.replace(/\/+$/, '') || '/'
|
|
if (seen.has(curNorm)) {
|
|
throw new Error('ELOOP: symbolic link cycle')
|
|
}
|
|
seen.add(curNorm)
|
|
if (
|
|
cur === '/' ||
|
|
cur === '/home' ||
|
|
cur === '/mnt' ||
|
|
cur === '/mirror' ||
|
|
curNorm === '/var' ||
|
|
curNorm === '/var/log' ||
|
|
curNorm === '/tmp'
|
|
) {
|
|
return cur
|
|
}
|
|
const r = route(cur)
|
|
if (
|
|
r.virtualMntRoot ||
|
|
r.virtualMirrorRoot ||
|
|
r.virtualVarRoot ||
|
|
r.virtualPseudo
|
|
) {
|
|
return cur
|
|
}
|
|
const { drive, path: p } = r
|
|
if (isHyperdriveRootPath(p)) return cur
|
|
const e = await entryOn(drive, p, { follow: false })
|
|
if (!e || !e.value) return cur
|
|
if (e.value.linkname) {
|
|
const parent = dirnameAbs(cur)
|
|
cur = unixPathResolve(parent, e.value.linkname)
|
|
continue
|
|
}
|
|
return cur
|
|
}
|
|
throw new Error('ELOOP: too many symlink levels')
|
|
}
|
|
|
|
async function statFromAbs(abs) {
|
|
const cur = await resolveSymlinksOnLogicalAbs(abs)
|
|
return lstatFromAbs(cur)
|
|
}
|
|
|
|
async function assertTraverseTo(abs, finalOp) {
|
|
const { uid: euid, gid: egid } = parseUidGid(env)
|
|
const rTr = route(abs)
|
|
if (
|
|
personalDrive &&
|
|
rTr.drive === personalDrive &&
|
|
typeof rTr.path === 'string'
|
|
) {
|
|
const rp = rTr.path.replace(/\/+$/, '') || '/'
|
|
if (rp === '/.bare/holesail' || rp.startsWith('/.bare/holesail/')) {
|
|
const phys = rTr.path.replace(/\/+$/, '') || rTr.path
|
|
const physPrefixes = pathPrefixes(phys)
|
|
for (let i = 0; i < physPrefixes.length; i++) {
|
|
const ppre = physPrefixes[i]
|
|
const isLast = i === physPrefixes.length - 1
|
|
if (ppre === '/') continue
|
|
const st = await lstatPersonalDrivePhysicalAny(ppre)
|
|
if (!isLast) {
|
|
if (!st) throw vfsErr('ENOENT', abs)
|
|
if (st.type !== 'directory') {
|
|
throw new Error('Not a directory: ' + ppre)
|
|
}
|
|
if (!modeAllows(st, euid, egid, 'x', 'directory')) {
|
|
throw vfsErr('EACCES', 'cannot traverse ' + ppre)
|
|
}
|
|
continue
|
|
}
|
|
if (!st) {
|
|
if (finalOp === 'read') return
|
|
throw vfsErr('ENOENT', abs)
|
|
}
|
|
if (st.type === 'directory') {
|
|
if (finalOp === 'readdir') {
|
|
if (!modeAllows(st, euid, egid, 'r', 'directory')) {
|
|
throw vfsErr('EACCES', 'cannot read directory ' + ppre)
|
|
}
|
|
if (!modeAllows(st, euid, egid, 'x', 'directory')) {
|
|
throw vfsErr('EACCES', 'cannot access directory ' + ppre)
|
|
}
|
|
} else if (finalOp === 'chdir') {
|
|
if (!modeAllows(st, euid, egid, 'x', 'directory')) {
|
|
throw vfsErr('EACCES', 'permission denied: ' + ppre)
|
|
}
|
|
}
|
|
} else if (st.type === 'file' || st.type === 'symlink') {
|
|
if (finalOp === 'read') {
|
|
if (!modeAllows(st, euid, egid, 'r', 'file')) {
|
|
throw vfsErr('EACCES', 'cannot read ' + ppre)
|
|
}
|
|
} else if (finalOp === 'write') {
|
|
if (!modeAllows(st, euid, egid, 'w', 'file')) {
|
|
throw vfsErr('EACCES', 'cannot write ' + ppre)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return
|
|
}
|
|
}
|
|
const prefixes = pathPrefixes(abs)
|
|
for (let i = 0; i < prefixes.length; i++) {
|
|
const pre = prefixes[i]
|
|
const isLast = i === prefixes.length - 1
|
|
if (isVirtualMountPoint(pre)) continue
|
|
const st = await lstatFromAbs(pre)
|
|
if (!isLast) {
|
|
if (!st) throw vfsErr('ENOENT', abs)
|
|
if (st.type !== 'directory') {
|
|
throw new Error('Not a directory: ' + pre)
|
|
}
|
|
if (!modeAllows(st, euid, egid, 'x', 'directory')) {
|
|
throw vfsErr('EACCES', 'cannot traverse ' + pre)
|
|
}
|
|
continue
|
|
}
|
|
// Final path component
|
|
if (!st) {
|
|
// open(2) on a missing path: callers like touch read then write; readFile returns null.
|
|
if (finalOp === 'read') return
|
|
throw vfsErr('ENOENT', abs)
|
|
}
|
|
if (st.type === 'directory') {
|
|
if (finalOp === 'readdir') {
|
|
if (!modeAllows(st, euid, egid, 'r', 'directory')) {
|
|
throw vfsErr('EACCES', 'cannot read directory ' + pre)
|
|
}
|
|
if (!modeAllows(st, euid, egid, 'x', 'directory')) {
|
|
throw vfsErr('EACCES', 'cannot access directory ' + pre)
|
|
}
|
|
} else if (finalOp === 'chdir') {
|
|
if (!modeAllows(st, euid, egid, 'x', 'directory')) {
|
|
throw vfsErr('EACCES', 'permission denied: ' + pre)
|
|
}
|
|
}
|
|
} else if (st.type === 'file' || st.type === 'symlink') {
|
|
if (finalOp === 'read') {
|
|
if (!modeAllows(st, euid, egid, 'r', 'file')) {
|
|
throw vfsErr('EACCES', 'cannot read ' + pre)
|
|
}
|
|
} else if (finalOp === 'write') {
|
|
if (!modeAllows(st, euid, egid, 'w', 'file')) {
|
|
throw vfsErr('EACCES', 'cannot write ' + pre)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
async function assertUnlink(abs) {
|
|
const parent = dirnameAbs(abs)
|
|
const { uid: euid, gid: egid } = parseUidGid(env)
|
|
const prefixes = pathPrefixes(parent)
|
|
for (let i = 0; i < prefixes.length; i++) {
|
|
const pre = prefixes[i]
|
|
const isLast = i === prefixes.length - 1
|
|
if (isVirtualMountPoint(pre)) continue
|
|
const st = await lstatFromAbs(pre)
|
|
if (!st) throw vfsErr('ENOENT', abs)
|
|
if (st.type !== 'directory') throw new Error('Not a directory: ' + pre)
|
|
if (!modeAllows(st, euid, egid, 'x', 'directory')) {
|
|
throw vfsErr('EACCES', 'cannot traverse ' + pre)
|
|
}
|
|
if (isLast) {
|
|
if (!modeAllows(st, euid, egid, 'w', 'directory')) {
|
|
throw new Error('EACCES: cannot unlink in ' + pre)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* `/.bare/holesail/**` on the personal drive: parent checks and traverse must walk **physical**
|
|
* paths on that drive — logical `/.bare` may map to a different backing path under
|
|
* {@link usePersonalAcctPrefix}, and `/` is skipped as a virtual mount point.
|
|
*/
|
|
async function lstatPersonalDrivePhysicalDir(physPath) {
|
|
if (!personalDrive) return null
|
|
const pnorm = String(physPath || '').replace(/\/+$/, '') || '/'
|
|
if (pnorm === '/') {
|
|
return { ...synthesizeStat('/', true, env, 'directory'), path: pnorm }
|
|
}
|
|
const e = await entryOn(personalDrive, pnorm, { follow: false })
|
|
const fromVal = statFromEntryValue(
|
|
pnorm,
|
|
{ drive: personalDrive, path: pnorm },
|
|
true,
|
|
e
|
|
)
|
|
if (fromVal) return { ...fromVal, path: pnorm }
|
|
const names = []
|
|
try {
|
|
const stream = personalDrive.readdir(pnorm)
|
|
for await (const n of stream) names.push(n)
|
|
} catch {
|
|
/* missing parent */
|
|
}
|
|
if (names.length) {
|
|
if (names.includes(DIR_MARKER)) {
|
|
const mPath = `${pnorm}/${DIR_MARKER}`.replace(/\/{2,}/g, '/')
|
|
const me = await entryOn(personalDrive, mPath, { follow: false })
|
|
const mv = me?.value
|
|
if (mv?.blob) {
|
|
const bo = extractBareOs(mv)
|
|
if (bo) {
|
|
let perm = bo.mode & 0o777
|
|
if (perm & 0o400) perm |= 0o100
|
|
if (perm & 0o040) perm |= 0o010
|
|
if (perm & 0o004) perm |= 0o001
|
|
return statFromBareOs(
|
|
{ ...bo, mode: S_IFDIR | perm },
|
|
'directory',
|
|
0,
|
|
pnorm
|
|
)
|
|
}
|
|
}
|
|
}
|
|
return { ...synthesizeStat(pnorm, true, env, 'directory'), path: pnorm }
|
|
}
|
|
if (e) return { ...synthesizeStat(pnorm, true, env, 'directory'), path: pnorm }
|
|
return null
|
|
}
|
|
|
|
/** Directory or regular file (or symlink) on the personal drive by absolute path on that drive. */
|
|
async function lstatPersonalDrivePhysicalAny(physPath) {
|
|
if (!personalDrive) return null
|
|
const pnorm = String(physPath || '').replace(/\/+$/, '') || '/'
|
|
if (pnorm === '/') {
|
|
return { ...synthesizeStat('/', true, env, 'directory'), path: pnorm }
|
|
}
|
|
const e = await entryOn(personalDrive, pnorm, { follow: false })
|
|
const rf = statFromEntryValue(
|
|
pnorm,
|
|
{ drive: personalDrive, path: pnorm },
|
|
true,
|
|
e
|
|
)
|
|
if (rf) return rf
|
|
return await lstatPersonalDrivePhysicalDir(pnorm)
|
|
}
|
|
|
|
async function assertPersonalDriveAncestorWritableForCreate(physPath) {
|
|
if (!personalDrive) {
|
|
throw new Error('ENOENT: ' + String(physPath || ''))
|
|
}
|
|
const { uid: euid, gid: egid } = parseUidGid(env)
|
|
const norm = String(physPath || '').replace(/\/+$/, '') || '/'
|
|
let probe = dirnameAbs(norm)
|
|
/** @type {{ pre: string, st: Awaited<ReturnType<typeof lstatFromAbs>> } | null} */
|
|
let deepest = null
|
|
while (probe && probe !== '/') {
|
|
const st = await lstatPersonalDrivePhysicalDir(probe)
|
|
if (st && st.type === 'directory') {
|
|
deepest = { pre: probe, st }
|
|
break
|
|
}
|
|
probe = dirnameAbs(probe)
|
|
}
|
|
if (!deepest) {
|
|
deepest = {
|
|
pre: '/',
|
|
st: await lstatPersonalDrivePhysicalDir('/')
|
|
}
|
|
}
|
|
if (!deepest.st || !modeAllows(deepest.st, euid, egid, 'w', 'directory')) {
|
|
throw new Error('EACCES: cannot create in ' + String(deepest?.pre ?? ''))
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param {string} logicalAbs policy / guest messaging
|
|
* @param {string} physPath path on {@link personalDrive}
|
|
*/
|
|
async function putPersonalDrivePhysical(logicalAbs, physPath, buf, opts = {}) {
|
|
assertNotBootPolicyDenyVfs(logicalAbs, 'write')
|
|
assertUnionWriteNotDenied(logicalAbs)
|
|
if (!personalDrive) {
|
|
throw new Error('Read-only path (not under $HOME): ' + logicalAbs)
|
|
}
|
|
if (await bareOsVfsAclDeniesDriveOp(env, personalDrive, physPath, 'write')) {
|
|
throw new Error('EACCES: ACL enforces deny write: ' + logicalAbs)
|
|
}
|
|
assertGuestSensitivePersonalOp(personalDrive, physPath, 'write', logicalAbs)
|
|
const existing = await entryOn(personalDrive, physPath, { follow: false })
|
|
const hadBlob = !!existing?.value?.blob
|
|
if (!hadBlob) await assertPersonalDriveAncestorWritableForCreate(physPath)
|
|
const value = existing?.value
|
|
const prevBare = extractBareOs(value)
|
|
const bareOs = mergeBareOsOnWrite(prevBare, env, {
|
|
executable: opts.executable,
|
|
bumpMtime: opts.bumpMtime !== false,
|
|
touchCtime: opts.touchCtime === true,
|
|
legacyExecutable: !!value?.executable,
|
|
mtimeMs: opts.mtimeMs,
|
|
ctimeMs: opts.ctimeMs,
|
|
posixModeBits: opts.posixModeBits
|
|
})
|
|
const executable =
|
|
opts.executable !== undefined ? !!opts.executable : !!value?.executable
|
|
const metadata = mergeEntryMetadata(value?.metadata, bareOs)
|
|
return personalDrive.put(physPath, buf, { executable, metadata })
|
|
}
|
|
|
|
/**
|
|
* Ensure `/.bare` and `/.bare/holesail` DIR_MARKER entries exist on the personal drive for stable
|
|
* Holesail paths (needed when `/` is skipped as a virtual mount point in parent checks, and when
|
|
* `/.bare` is not the same backing path as `/.bare/holesail/**` under {@link usePersonalAcctPrefix}).
|
|
*/
|
|
async function ensureBareHolesailStablePersonalDirTree(physPath, logicalAbs) {
|
|
if (!personalDrive) return
|
|
const norm = String(physPath || '').replace(/\/+$/, '') || '/'
|
|
const d = dirnameAbs(norm)
|
|
if (d === '/' || d === '') return
|
|
const physPrefs = pathPrefixes(d)
|
|
const empty = new Uint8Array(0)
|
|
for (let i = 1; i < physPrefs.length; i++) {
|
|
const physPre = physPrefs[i]
|
|
const st = await lstatPersonalDrivePhysicalDir(physPre)
|
|
if (st) continue
|
|
const markerPath =
|
|
physPre === '/' ? `/${DIR_MARKER}` : `${physPre}/${DIR_MARKER}`
|
|
await putPersonalDrivePhysical(logicalAbs, markerPath, empty, {})
|
|
}
|
|
}
|
|
|
|
async function assertParentWritableForCreate(abs) {
|
|
const parent = dirnameAbs(abs)
|
|
if (parent === abs) return
|
|
const rH = route(abs)
|
|
if (
|
|
personalDrive &&
|
|
rH.drive === personalDrive &&
|
|
typeof rH.path === 'string'
|
|
) {
|
|
const rp = rH.path.replace(/\/+$/, '') || '/'
|
|
if (rp === '/.bare/holesail' || rp.startsWith('/.bare/holesail/')) {
|
|
const physPath = rH.path.replace(/\/+$/, '') || rH.path
|
|
await assertPersonalDriveAncestorWritableForCreate(physPath)
|
|
return
|
|
}
|
|
}
|
|
const { uid: euid, gid: egid } = parseUidGid(env)
|
|
const prefixes = pathPrefixes(parent)
|
|
/** @type {{ pre: string, st: Awaited<ReturnType<typeof lstatFromAbs>> } | null} */
|
|
let deepest = null
|
|
for (const pre of prefixes) {
|
|
if (isVirtualMountPoint(pre)) continue
|
|
const st = await lstatFromAbs(pre)
|
|
if (!st) continue
|
|
if (st.type !== 'directory') {
|
|
throw new Error('Not a directory: ' + pre)
|
|
}
|
|
if (!modeAllows(st, euid, egid, 'x', 'directory')) {
|
|
throw new Error('EACCES: cannot traverse ' + pre)
|
|
}
|
|
deepest = { pre, st }
|
|
}
|
|
if (!deepest) {
|
|
throw new Error('ENOENT: ' + parent)
|
|
}
|
|
if (!modeAllows(deepest.st, euid, egid, 'w', 'directory')) {
|
|
throw new Error('EACCES: cannot create in ' + deepest.pre)
|
|
}
|
|
}
|
|
|
|
async function readdirFromAbs(abs) {
|
|
if (abs === '/mnt' || abs === '/mnt/') {
|
|
return [...getMntMap().keys()].sort()
|
|
}
|
|
const activeSeg = activeHomeBasename()
|
|
if (activeSeg && abs === '/home') {
|
|
return [activeSeg].sort()
|
|
}
|
|
if (abs === '/var' || abs === '/var/') {
|
|
const names = new Set()
|
|
try {
|
|
const stream = systemDrive.readdir('/var')
|
|
for await (const n of stream) names.add(n)
|
|
} catch {
|
|
/* no /var on system image */
|
|
}
|
|
names.add('log')
|
|
return [...names].sort()
|
|
}
|
|
const pr = route(abs)
|
|
if (pr.virtualPseudo) {
|
|
if (pr.node === 'enoent') {
|
|
throw new Error('ENOENT: ' + abs)
|
|
}
|
|
if (pr.node === 'file') {
|
|
throw new Error('Not a directory: ' + abs)
|
|
}
|
|
if (pr.kind === 'proc' && pr.node === 'root') {
|
|
return stripHypercorePackHrpcLifecycleFlat([
|
|
'bare_os',
|
|
'bare_os_activity_queue_depth.json',
|
|
'bare_os_async_hooks_lag.json',
|
|
'bare_os_autobase_writer_hint.json',
|
|
'bare_os_autopass_session_sketch.json',
|
|
'bare_os_autopass_rotation_sketch.json',
|
|
'bare_os_bare_addon_policy.json',
|
|
'bare_os_bare_boot_phase_map.json',
|
|
'bare_os_bare_crypto_policy.json',
|
|
'bare_os_bare_daemon_hooks.json',
|
|
'bare_os_bare_diagnostics_channel.json',
|
|
'bare_os_bare_inspect_policy.json',
|
|
'bare_os_bare_ipc_bridge.json',
|
|
'bare_os_bare_kit_bridge.json',
|
|
'bare_os_bare_logger_policy.json',
|
|
'bare_os_bare_module_resolution.json',
|
|
'bare_os_bare_net_interfaces.json',
|
|
'bare_os_bare_pack_cache.json',
|
|
'bare_os_bare_performance_counters.json',
|
|
'bare_os_bare_rpc_registry_sketch.json',
|
|
'bare_os_bare_signals_mask.json',
|
|
'bare_os_bare_signals_profile.json',
|
|
'bare_os_bare_storage_quota.json',
|
|
'bare_os_bare_stream_backpressure.json',
|
|
'bare_os_bare_thread_pool.json',
|
|
'bare_os_bare_timers_budget.json',
|
|
'bare_os_bare_timers_histogram.json',
|
|
'bare_os_bare_tls_session_hint.json',
|
|
'bare_os_bare_vm_sandbox_sketch.json',
|
|
'bare_os_bare_worker_pool.json',
|
|
'bare_os_bare_ws_gateway_sketch.json',
|
|
'bare_os_blind_pairing_sketch.json',
|
|
'bare_os_blind_relay_router.json',
|
|
'bare_os_bootstrap',
|
|
'bare_os_brittle_snapshot_ci.json',
|
|
'bare_os_broadcast_encryption_hint.json',
|
|
'bare_os_bundle_preload_hint.json',
|
|
'bare_os_build_attestation_pointer.json',
|
|
'bare_os_capabilities',
|
|
'bare_os_capabilities.json',
|
|
'bare_os_cellery_sidecar_hint.json',
|
|
'bare_os_compact_encoding_profile.json',
|
|
'bare_os_corestore_gc_hint.json',
|
|
'bare_os_debug.json',
|
|
'bare_os_delegate_red.json',
|
|
'bare_os_dht_status.json',
|
|
'bare_os_dns_map_active.json',
|
|
'bare_os_drive_resolve_cache.json',
|
|
'bare_os_drive_version_graph.json',
|
|
'bare_os_extensions.json',
|
|
'bare_os_features',
|
|
'bare_os_features.json',
|
|
'bare_os_form_data_delegate_limits.json',
|
|
'bare_os_form_data_delegate_limits_v2.json',
|
|
'bare_os_giant_phase_program.json',
|
|
'bare_os_gip_transport_sketch.json',
|
|
'bare_os_git_delegate_stats.json',
|
|
'bare_os_git_lfs_budget.json',
|
|
'bare_os_git_lfs_pointer_stats.json',
|
|
'bare_os_hdms_health.json',
|
|
'bare_os_hdms_hints.json',
|
|
'bare_os_host_os.json',
|
|
'bare_os_hrpc_bridge_health.json',
|
|
'bare_os_hrpc_allowlist_sketch.json',
|
|
'bare_os_http_dht_proxy_route.json',
|
|
'bare_os_hyper_multisig_trust_pointer.json',
|
|
'bare_os_hypercore_lengths.json',
|
|
'bare_os_hypercore_repair_hint.json',
|
|
'bare_os_hypercore_replicate_budget.json',
|
|
'bare_os_hypercore_signing_status.json',
|
|
'bare_os_hyperdb_readonly_index.json',
|
|
'bare_os_hyperdrive_sparse_index.json',
|
|
'bare_os_hypermininet_topology.json',
|
|
'bare_os_indexer_catchup.json',
|
|
'bare_os_multisig_quorum_pointer.json',
|
|
'bare_os_initd_dag.json',
|
|
'bare_os_initd_readiness.json',
|
|
'bare_os_boot_graph.json',
|
|
'bare_os_boot_budget_summary.json',
|
|
'bare_os_chat.json',
|
|
'bare_os_meshdrop.json',
|
|
'bare_os_peer_details.json',
|
|
'bare_os_dht_scan.json',
|
|
'bare_os_swarm_doctor.json',
|
|
'bare_os_route_summary.json',
|
|
'bare_os_holepunch_summary.json',
|
|
'bare_os_initd_graph.json',
|
|
'bare_os_ipc_backpressure.json',
|
|
'bare_os_kernel_program.json',
|
|
'bare_os_libmqjs_queue_depth.json',
|
|
'bare_os_locale.json',
|
|
'bare_os_manifest_hints',
|
|
'bare_os_metrics_live.json',
|
|
'bare_os_metrics_prom.json',
|
|
'bare_os_net_summary.json',
|
|
'bare_os_net_qos_class.json',
|
|
'bare_os_oidc_publishing_pointer.json',
|
|
'bare_os_pear_api_allowlist_sketch.json',
|
|
'bare_os_pear_appling_manifest.json',
|
|
'bare_os_pear_build_fingerprint.json',
|
|
'bare_os_pear_runtime_channel.json',
|
|
'bare_os_pear_doctor_state.json',
|
|
'bare_os_pear_drop_events.json',
|
|
'bare_os_pear_ipc_health.json',
|
|
'bare_os_pear_radio_state.json',
|
|
'bare_os_pear_runtime_matrix.json',
|
|
'bare_os_pear_rti_pointer.json',
|
|
'bare_os_pear_sidecar_bundle_index.json',
|
|
'bare_os_pear_stage_pointer.json',
|
|
'bare_os_pear_trust.json',
|
|
'bare_os_pear_updater_state.json',
|
|
'bare_os_pear_user_dirs_map.json',
|
|
'bare_os_pear_wakeups_schedule.json',
|
|
'bare_os_pear_workshop_flags.json',
|
|
'bare_os_peer_health',
|
|
'bare_os_protomux_backpressure.json',
|
|
'bare_os_protomux_channel_alias_v2.json',
|
|
'bare_os_protomux_channels.json',
|
|
'bare_os_protomux_rpc_pool_health.json',
|
|
'bare_os_protomux_wire.json',
|
|
'bare_os_protomux_extensions.json',
|
|
'bare_os_provenance',
|
|
'bare_os_quotas',
|
|
'bare_os_react_native_bare_kit.json',
|
|
'bare_os_replication',
|
|
'bare_os_replication_backpressure.json',
|
|
'bare_os_replication_operator_panel.json',
|
|
'bare_os_relay_geo_hint.json',
|
|
'bare_os_resources',
|
|
'bare_os_rlimits.json',
|
|
'bare_os_rocksdb_pointer.json',
|
|
'bare_os_safe_sodium_buffer_policy.json',
|
|
'bare_os_sandbox_profile.json',
|
|
'bare_os_sandbox_worker_queue.json',
|
|
'bare_os_security_context.json',
|
|
'bare_os_security_posture.json',
|
|
'bare_os_sidecar_resource_cap.json',
|
|
'bare_os_seed_handshake',
|
|
'bare_os_session_stats',
|
|
'bare_os_slo_hints.json',
|
|
'bare_os_storage_tier_hint.json',
|
|
'bare_os_snapshot_hints',
|
|
'bare_os_snapshot_hints.json',
|
|
'bare_os_staging_slot',
|
|
'bare_os_structured_clone_budget_v2.json',
|
|
'bare_os_structured_clone_profile.json',
|
|
'bare_os_swarm',
|
|
'bare_os_swarm.json',
|
|
'bare_os_swarm_connection_manager_status.json',
|
|
'bare_os_swarm_datagram_replication_status.json',
|
|
'bare_os_swarm_datagrams_status.json',
|
|
'bare_os_swarm_health.json',
|
|
'bare_os_swarm_holepunch_status.json',
|
|
'bare_os_swarm_key_broker_status.json',
|
|
'bare_os_swarm_relay_status.json',
|
|
'bare_os_swarm_replication_status.json',
|
|
'bare_os_swarm_status.json',
|
|
'bare_os_sync_window.json',
|
|
'bare_os_clock.json',
|
|
'bare_os_openssh.json',
|
|
'bare_os_syscalls',
|
|
'bare_os_syscalls.json',
|
|
'bare_os_udx_extended.json',
|
|
'bare_os_union',
|
|
'bare_os_updater_download_state.json',
|
|
'bare_os_version',
|
|
'bare_os_virtual_registry',
|
|
'bare_os_worker_budget.json',
|
|
'bare_os_wave11_operator_slo_v2.json',
|
|
'bare_os_wave11_peer_qos_sketch.json',
|
|
'cpuinfo',
|
|
'diskstats',
|
|
'loadavg',
|
|
'meminfo',
|
|
'mounts',
|
|
'net',
|
|
'self',
|
|
'uptime',
|
|
'version'
|
|
])
|
|
}
|
|
if (
|
|
pr.kind === 'proc' &&
|
|
pr.node === 'dir' &&
|
|
pr.dir === 'bare_os_proc'
|
|
) {
|
|
return stripHypercorePackHrpcLifecycleBareOs([
|
|
'activity_queue_depth.json',
|
|
'async_hooks_lag.json',
|
|
'autobase_writer_hint.json',
|
|
'autopass_session_sketch.json',
|
|
'autopass_rotation_sketch.json',
|
|
'bare_addon_policy.json',
|
|
'bare_boot_phase_map.json',
|
|
'bare_crypto_policy.json',
|
|
'bare_daemon_hooks.json',
|
|
'bare_diagnostics_channel.json',
|
|
'bare_inspect_policy.json',
|
|
'bare_ipc_bridge.json',
|
|
'bare_kit_bridge.json',
|
|
'bare_logger_policy.json',
|
|
'bare_module_resolution.json',
|
|
'bare_net_interfaces.json',
|
|
'bare_pack_cache.json',
|
|
'bare_performance_counters.json',
|
|
'bare_rpc_registry_sketch.json',
|
|
'bare_signals_mask.json',
|
|
'bare_signals_profile.json',
|
|
'bare_storage_quota.json',
|
|
'bare_stream_backpressure.json',
|
|
'bare_thread_pool.json',
|
|
'bare_timers_budget.json',
|
|
'bare_timers_histogram.json',
|
|
'bare_tls_session_hint.json',
|
|
'bare_vm_sandbox_sketch.json',
|
|
'bare_worker_pool.json',
|
|
'bare_ws_gateway_sketch.json',
|
|
'blind_pairing_sketch.json',
|
|
'blind_relay_router.json',
|
|
'bootstrap',
|
|
'brittle_snapshot_ci.json',
|
|
'clock.json',
|
|
'openssh.json',
|
|
'broadcast_encryption_hint.json',
|
|
'bundle_preload_hint.json',
|
|
'build_attestation_pointer.json',
|
|
'capabilities',
|
|
'capabilities.json',
|
|
'cellery_sidecar_hint.json',
|
|
'compact_encoding_profile.json',
|
|
'corestore_gc_hint.json',
|
|
'debug.json',
|
|
'delegate_red.json',
|
|
'dht_status.json',
|
|
'dns_map_active.json',
|
|
'drive_resolve_cache.json',
|
|
'drive_version_graph.json',
|
|
'extensions.json',
|
|
'features',
|
|
'features.json',
|
|
'form_data_delegate_limits.json',
|
|
'form_data_delegate_limits_v2.json',
|
|
'gip_transport_sketch.json',
|
|
'git_delegate_stats.json',
|
|
'git_lfs_pointer_stats.json',
|
|
'git_lfs_budget.json',
|
|
'giant_phase_program.json',
|
|
'hdms_health.json',
|
|
'hdms_hints.json',
|
|
'host_os.json',
|
|
'hrpc_bridge_health.json',
|
|
'hrpc_allowlist_sketch.json',
|
|
'http_dht_proxy_route.json',
|
|
'hyper_multisig_trust_pointer.json',
|
|
'hypercore_lengths.json',
|
|
'hypercore_repair_hint.json',
|
|
'hypercore_replicate_budget.json',
|
|
'hypercore_signing_status.json',
|
|
'hyperdb_readonly_index.json',
|
|
'hyperdrive_sparse_index.json',
|
|
'hypermininet_topology.json',
|
|
'index.json',
|
|
'initd_dag.json',
|
|
'initd_readiness.json',
|
|
'boot_graph.json',
|
|
'boot_budget_summary.json',
|
|
'initd_graph.json',
|
|
'indexer_catchup.json',
|
|
'ipc_backpressure.json',
|
|
'kernel_program.json',
|
|
'libmqjs_queue_depth.json',
|
|
'locale.json',
|
|
'manifest_hints',
|
|
'metrics_live.json',
|
|
'metrics.prom',
|
|
'multisig_quorum_pointer.json',
|
|
'net_qos_class.json',
|
|
'net_summary.json',
|
|
'oidc_publishing_pointer.json',
|
|
'pear_api_allowlist_sketch.json',
|
|
'pear_appling_manifest.json',
|
|
'pear_build_fingerprint.json',
|
|
'pear_runtime_channel.json',
|
|
'pear_doctor_state.json',
|
|
'pear_drop_events.json',
|
|
'pear_ipc.json',
|
|
'pear_ipc_health.json',
|
|
'pear_radio_state.json',
|
|
'pear_runtime_matrix.json',
|
|
'pear_rti_pointer.json',
|
|
'pear_sidecar_bundle_index.json',
|
|
'pear_stage_pointer.json',
|
|
'pear_trust.json',
|
|
'security_posture.json',
|
|
'pear_updater_state.json',
|
|
'pear_user_dirs_map.json',
|
|
'pear_wakeups_schedule.json',
|
|
'pear_workshop_flags.json',
|
|
'peer_health',
|
|
'process_table.json',
|
|
'protomux_backpressure.json',
|
|
'protomux_channel_alias_v2.json',
|
|
'protomux_channels.json',
|
|
'protomux_rpc_pool_health.json',
|
|
'protomux.json',
|
|
'protomux_extensions.json',
|
|
'provenance',
|
|
'quotas',
|
|
'react_native_bare_kit.json',
|
|
'replication',
|
|
'replication_backpressure.json',
|
|
'replication_operator_panel.json',
|
|
'relay_geo_hint.json',
|
|
'resources',
|
|
'rlimits.json',
|
|
'rocksdb_pointer.json',
|
|
'safe_sodium_buffer_policy.json',
|
|
'sandbox_profile.json',
|
|
'sandbox_worker_queue.json',
|
|
'security_context.json',
|
|
'sidecar_resource_cap.json',
|
|
'seed_handshake',
|
|
'session_stats',
|
|
'slo_hints.json',
|
|
'storage_tier_hint.json',
|
|
'snapshot_hints',
|
|
'snapshot_hints.json',
|
|
'staging_slot',
|
|
'structured_clone_budget_v2.json',
|
|
'structured_clone_profile.json',
|
|
'swarm',
|
|
'swarm.json',
|
|
'swarm_connection_manager_status.json',
|
|
'swarm_datagram_replication_status.json',
|
|
'swarm_datagrams_status.json',
|
|
'swarm_health.json',
|
|
'swarm_holepunch_status.json',
|
|
'swarm_key_broker_status.json',
|
|
'swarm_relay_status.json',
|
|
'swarm_replication_status.json',
|
|
'swarm_status.json',
|
|
'sync_window.json',
|
|
'syscalls.json',
|
|
'udx_extended.json',
|
|
'union',
|
|
'updater_download_state.json',
|
|
'version',
|
|
'virtual_registry',
|
|
'worker_budget.json',
|
|
'wave11_operator_slo_v2.json',
|
|
'wave11_peer_qos_sketch.json'
|
|
|
|
])
|
|
}
|
|
if (pr.kind === 'proc' && pr.node === 'dir' && pr.dir === 'net') {
|
|
return ['dev', 'tcp', 'udp']
|
|
}
|
|
if (pr.kind === 'proc' && pr.node === 'dir' && pr.dir === 'self') {
|
|
return ['cgroups', 'cmdline', 'environ', 'exe', 'fd', 'limits']
|
|
}
|
|
if (pr.kind === 'proc' && pr.node === 'dir' && pr.dir === 'self_fd') {
|
|
return listProcSelfFdDirNames()
|
|
}
|
|
if (pr.kind === 'sys' && pr.node === 'root') {
|
|
return ['class', 'devices', 'fs']
|
|
}
|
|
if (pr.kind === 'sys' && pr.node === 'dir' && pr.dir === 'devices') {
|
|
return ['virtual']
|
|
}
|
|
if (
|
|
pr.kind === 'sys' &&
|
|
pr.node === 'dir' &&
|
|
pr.dir === 'devices_virtual'
|
|
) {
|
|
return []
|
|
}
|
|
if (pr.kind === 'sys' && pr.node === 'dir' && pr.dir === 'class') {
|
|
return ['net']
|
|
}
|
|
if (pr.kind === 'sys' && pr.node === 'dir' && pr.dir === 'class_net') {
|
|
return ['lo']
|
|
}
|
|
if (pr.kind === 'sys' && pr.node === 'dir' && pr.dir === 'fs') {
|
|
return ['bare_os']
|
|
}
|
|
if (pr.kind === 'sys' && pr.node === 'dir' && pr.dir === 'bare_os') {
|
|
return ['build_id', 'version']
|
|
}
|
|
if (pr.kind === 'run' && pr.node === 'root') {
|
|
return ['bare-os']
|
|
}
|
|
if (pr.kind === 'run' && pr.node === 'dir' && pr.dir === 'bare_os') {
|
|
const base = [
|
|
'boot.json',
|
|
'boot_profile',
|
|
'ipc',
|
|
'ready',
|
|
'session',
|
|
'unit-journal',
|
|
'units',
|
|
'virtual'
|
|
]
|
|
return bareOsIpc ? base : base.filter((x) => x !== 'ipc')
|
|
}
|
|
if (
|
|
pr.kind === 'run' &&
|
|
pr.node === 'dir' &&
|
|
pr.dir === 'unit_journal_root' &&
|
|
getUnitJournalNdjson
|
|
) {
|
|
return listBareInitdJournalUnits().map((u) => `${u}.ndjson`)
|
|
}
|
|
if (
|
|
pr.kind === 'run' &&
|
|
pr.node === 'dir' &&
|
|
pr.dir === 'virtual_root' &&
|
|
getVirtualReaders
|
|
) {
|
|
const m = getVirtualReaders()
|
|
return m && typeof m.keys === 'function' ? [...m.keys()].sort() : []
|
|
}
|
|
if (
|
|
pr.kind === 'run' &&
|
|
pr.node === 'dir' &&
|
|
pr.dir === 'bare_ipc' &&
|
|
bareOsIpc
|
|
) {
|
|
return bareOsIpc.list()
|
|
}
|
|
if (pr.kind === 'dev' && pr.node === 'root') {
|
|
return ['null', 'shm', 'urandom', 'zero']
|
|
}
|
|
if (pr.kind === 'dev' && pr.node === 'dir' && pr.dir === 'shm') {
|
|
return [...bareOsDevShm.keys()].sort()
|
|
}
|
|
}
|
|
const r = route(abs)
|
|
if (r.virtualMirrorRoot) {
|
|
const aux = getAuxiliaryDrives ? getAuxiliaryDrives() : []
|
|
return Array.isArray(aux)
|
|
? aux.map((_, i) => 'aux' + i).sort()
|
|
: []
|
|
}
|
|
if (r.virtualMntRoot) {
|
|
return [...getMntMap().keys()].sort()
|
|
}
|
|
if (r.virtualSnapshotRoot) return ['system']
|
|
if (r.virtualSnapshotSystem) return []
|
|
const { drive, path: p } = r
|
|
const folder = p === '/' ? '/' : p
|
|
const bareAbsNorm = abs.replace(/\/+$/, '') || '/'
|
|
const bareCacheable =
|
|
drive === personalDrive &&
|
|
(bareAbsNorm === '/.bare' || bareAbsNorm.startsWith('/.bare/'))
|
|
const bareTtl = bareCacheable ? personalVaultReaddirCacheTtlMs() : 0
|
|
if (bareCacheable && bareTtl > 0) {
|
|
const hit = personalBareReaddirCache.get(bareAbsNorm)
|
|
const now = Date.now()
|
|
if (hit && now - hit.at < bareTtl) {
|
|
return [...hit.names].sort()
|
|
}
|
|
}
|
|
const names = []
|
|
assertGuestSensitivePersonalOp(drive, folder, 'readdir', abs)
|
|
const stream = drive.readdir(folder)
|
|
for await (const name of stream) {
|
|
names.push(name)
|
|
}
|
|
if (
|
|
drive === personalDrive &&
|
|
bareOsIdentityVfsRef.session !== 'unlocked' &&
|
|
!(
|
|
env?.BARE_OS_GUEST_BARE_READ_ALL === '1' ||
|
|
env?.BARE_OS_GUEST_BARE_READ_ALL === 'true'
|
|
) &&
|
|
bareAbsNorm === '/.bare'
|
|
) {
|
|
const hide = new Set(['account', 'vault'])
|
|
for (let i = names.length - 1; i >= 0; i--) {
|
|
const n = names[i]
|
|
if (
|
|
hide.has(n) ||
|
|
(typeof n === 'string' && n.startsWith('vault-rotation-audit'))
|
|
) {
|
|
names.splice(i, 1)
|
|
}
|
|
}
|
|
}
|
|
if (activeSeg && abs === '/' && !names.includes('home')) {
|
|
names.push('home')
|
|
}
|
|
if (abs === '/' && !names.includes('mnt')) {
|
|
names.push('mnt')
|
|
}
|
|
if (abs === '/' && !names.includes('mirror')) {
|
|
const aux = getAuxiliaryDrives ? getAuxiliaryDrives() : []
|
|
if (Array.isArray(aux) && aux.length) names.push('mirror')
|
|
}
|
|
if (abs === '/' && !names.includes('var')) {
|
|
names.push('var')
|
|
}
|
|
if (abs === '/' && !names.includes('proc')) {
|
|
names.push('proc')
|
|
}
|
|
if (abs === '/' && !names.includes('sys')) {
|
|
names.push('sys')
|
|
}
|
|
if (abs === '/' && !names.includes('tmp')) {
|
|
names.push('tmp')
|
|
}
|
|
if (abs === '/' && !names.includes('run')) {
|
|
names.push('run')
|
|
}
|
|
if (abs === '/' && !names.includes('dev')) {
|
|
names.push('dev')
|
|
}
|
|
const snapsOnRoot =
|
|
env &&
|
|
(env.BARE_OS_VFS_SNAPSHOTS === '1' || env.BARE_OS_VFS_SNAPSHOTS === 'true')
|
|
if (
|
|
abs === '/' &&
|
|
snapsOnRoot &&
|
|
systemDrive &&
|
|
typeof systemDrive.checkout === 'function' &&
|
|
!names.includes('snapshots')
|
|
) {
|
|
names.push('snapshots')
|
|
}
|
|
if (bareCacheable && bareTtl > 0) {
|
|
personalBareReaddirCache.set(bareAbsNorm, {
|
|
at: Date.now(),
|
|
names: [...names]
|
|
})
|
|
}
|
|
return names.sort()
|
|
}
|
|
|
|
async function delFromAbs(abs) {
|
|
const r = route(abs)
|
|
if (r.snapshotReadOnly) {
|
|
throw new Error('EROFS: snapshot checkout is read-only: ' + abs)
|
|
}
|
|
if (
|
|
r.virtualPseudo &&
|
|
r.kind === 'dev' &&
|
|
r.node === 'file' &&
|
|
r.file === 'shm' &&
|
|
r.shmName
|
|
) {
|
|
bareOsDevShm.delete(String(r.shmName))
|
|
return
|
|
}
|
|
if (
|
|
r.virtualHomeDir ||
|
|
r.virtualMntRoot ||
|
|
r.virtualMirrorRoot ||
|
|
r.virtualVarRoot ||
|
|
r.virtualPseudo
|
|
) {
|
|
throw new Error('Read-only path (not under $HOME): ' + abs)
|
|
}
|
|
if (r.mntReadOnly === true) {
|
|
throw new Error('Read-only mount: ' + abs)
|
|
}
|
|
const { drive, path: p } = r
|
|
if (r.mntReadOnly === false) {
|
|
if (isHyperdriveRootPath(p)) {
|
|
throw new Error('Cannot unlink directory root')
|
|
}
|
|
assertGuestSensitivePersonalOp(drive, p, 'unlink', abs)
|
|
return drive.del(p)
|
|
}
|
|
if (drive !== personalDrive) {
|
|
throw new Error('Read-only path (not under $HOME): ' + abs)
|
|
}
|
|
if (isHyperdriveRootPath(p)) {
|
|
throw new Error('Cannot unlink directory root')
|
|
}
|
|
assertGuestSensitivePersonalOp(drive, p, 'unlink', abs)
|
|
return drive.del(p)
|
|
}
|
|
|
|
/**
|
|
* Recursive remove: Hyperdrive `del` is one entry; directories need a tree walk.
|
|
*/
|
|
async function rmFromAbs(abs, { recursive = false, force = false } = {}) {
|
|
assertNotBootPolicyDenyVfs(abs, 'unlink')
|
|
const r = route(abs)
|
|
if (r.snapshotReadOnly) {
|
|
if (force) return
|
|
throw new Error('EROFS: snapshot checkout is read-only: ' + abs)
|
|
}
|
|
if (
|
|
r.virtualPseudo &&
|
|
r.kind === 'dev' &&
|
|
r.node === 'file' &&
|
|
r.file === 'shm' &&
|
|
r.shmName
|
|
) {
|
|
await assertUnlink(abs)
|
|
return delFromAbs(abs)
|
|
}
|
|
if (
|
|
r.virtualHomeDir ||
|
|
r.virtualMntRoot ||
|
|
r.virtualMirrorRoot ||
|
|
r.virtualVarRoot ||
|
|
r.virtualPseudo
|
|
) {
|
|
if (force) return
|
|
throw new Error('Read-only path (not under $HOME): ' + abs)
|
|
}
|
|
if (r.mntReadOnly === true) {
|
|
if (force) return
|
|
throw new Error('Read-only mount: ' + abs)
|
|
}
|
|
const st = await lstatFromAbs(abs)
|
|
if (!st) {
|
|
if (force) return
|
|
throw new Error('ENOENT: no such file or directory')
|
|
}
|
|
if (st.type === 'symlink' || st.type === 'file') {
|
|
await assertUnlink(abs)
|
|
return delFromAbs(abs)
|
|
}
|
|
if (st.type === 'directory') {
|
|
if (!recursive) {
|
|
throw new Error('Is a directory')
|
|
}
|
|
const names = await readdirFromAbs(abs)
|
|
for (const n of names) {
|
|
await rmFromAbs(joinLogical(abs, n), { recursive: true, force: true })
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param {string} abs logical absolute path
|
|
* @param {Uint8Array | ArrayBuffer} buf
|
|
*/
|
|
async function writeFileAtAbs(abs, buf, opts = {}) {
|
|
assertNotBootPolicyDenyVfs(abs, 'write')
|
|
assertUnionWriteNotDenied(abs)
|
|
const allowSystemImageWrite =
|
|
env &&
|
|
(env.BARE_OS_VFS_SYSTEM_IMAGE_WRITE === '1' ||
|
|
env.BARE_OS_VFS_SYSTEM_IMAGE_WRITE === 'true')
|
|
const r = route(abs)
|
|
if (r.snapshotReadOnly) {
|
|
throw new Error('EROFS: snapshot checkout is read-only: ' + abs)
|
|
}
|
|
if (
|
|
r.virtualPseudo &&
|
|
r.kind === 'dev' &&
|
|
r.node === 'file' &&
|
|
(r.file === 'null' || r.file === 'zero')
|
|
) {
|
|
return
|
|
}
|
|
if (
|
|
r.virtualPseudo &&
|
|
r.kind === 'dev' &&
|
|
r.node === 'file' &&
|
|
r.file === 'shm' &&
|
|
r.shmName
|
|
) {
|
|
await assertTraverseTo(abs, 'write')
|
|
const u8 = buf instanceof Uint8Array ? buf : new Uint8Array(buf)
|
|
const shmName = String(r.shmName)
|
|
if (bareOsDevShmMaxBytes > 0) {
|
|
let used = 0
|
|
for (const v of bareOsDevShm.values()) used += v.byteLength
|
|
const prev = bareOsDevShm.get(shmName)
|
|
const nextTotal = used - (prev ? prev.byteLength : 0) + u8.byteLength
|
|
if (nextTotal > bareOsDevShmMaxBytes) {
|
|
throw new Error(
|
|
`ENOSPC: /dev/shm quota exceeded (${nextTotal}/${bareOsDevShmMaxBytes})`
|
|
)
|
|
}
|
|
}
|
|
bareOsDevShm.set(shmName, b4a.from(u8))
|
|
return
|
|
}
|
|
if (
|
|
r.virtualPseudo &&
|
|
r.kind === 'run' &&
|
|
r.node === 'file' &&
|
|
r.file === 'ipc' &&
|
|
bareOsIpc
|
|
) {
|
|
await assertTraverseTo(abs, 'write')
|
|
bareOsIpc.push(r.ipcName, buf)
|
|
return
|
|
}
|
|
if (
|
|
r.virtualHomeDir ||
|
|
r.virtualMntRoot ||
|
|
r.virtualMirrorRoot ||
|
|
r.virtualVarRoot ||
|
|
r.virtualPseudo
|
|
) {
|
|
throw new Error('Read-only path (not under $HOME): ' + abs)
|
|
}
|
|
if (r.mntReadOnly === true) {
|
|
throw new Error('Read-only mount: ' + abs)
|
|
}
|
|
const { drive, path: p } = r
|
|
if (r.mntReadOnly === false) {
|
|
if (isHyperdriveRootPath(p)) {
|
|
throw new Error('Cannot write directory: ' + abs)
|
|
}
|
|
} else if (drive !== personalDrive) {
|
|
if (!allowSystemImageWrite) {
|
|
throw new Error('Read-only path (not under $HOME): ' + abs)
|
|
}
|
|
}
|
|
if (isHyperdriveRootPath(p)) {
|
|
throw new Error('Cannot write directory: ' + abs)
|
|
}
|
|
if (await bareOsVfsAclDeniesDriveOp(env, drive, p, 'write')) {
|
|
throw new Error('EACCES: ACL enforces deny write: ' + abs)
|
|
}
|
|
assertGuestSensitivePersonalOp(drive, p, 'write', abs)
|
|
const existing = await entryOn(drive, p, { follow: false })
|
|
const hadBlob = !!existing?.value?.blob
|
|
if (hadBlob) {
|
|
const skipModeTraverse =
|
|
allowSystemImageWrite &&
|
|
drive === systemDrive &&
|
|
isWarmReadCachePath(abs)
|
|
if (!skipModeTraverse) await assertTraverseTo(abs, 'write')
|
|
} else {
|
|
await assertParentWritableForCreate(abs)
|
|
if (personalDrive && drive === personalDrive && typeof p === 'string') {
|
|
const rp = p.replace(/\/+$/, '') || '/'
|
|
if (rp === '/.bare/holesail' || rp.startsWith('/.bare/holesail/')) {
|
|
const phys = p.replace(/\/+$/, '') || p
|
|
await ensureBareHolesailStablePersonalDirTree(phys, abs)
|
|
}
|
|
}
|
|
}
|
|
const value = existing?.value
|
|
const prevBare = extractBareOs(value)
|
|
const bareOs = mergeBareOsOnWrite(prevBare, env, {
|
|
executable: opts.executable,
|
|
bumpMtime: opts.bumpMtime !== false,
|
|
touchCtime: opts.touchCtime === true,
|
|
legacyExecutable: !!value?.executable,
|
|
mtimeMs: opts.mtimeMs,
|
|
ctimeMs: opts.ctimeMs,
|
|
posixModeBits: opts.posixModeBits
|
|
})
|
|
const executable =
|
|
opts.executable !== undefined ? !!opts.executable : !!value?.executable
|
|
const metadata = mergeEntryMetadata(value?.metadata, bareOs)
|
|
const putRes = await drive.put(p, buf, { executable, metadata })
|
|
if (drive === systemDrive && (binReadCache || binDigestCache)) {
|
|
if (abs === '/lib/bare/bare-module-manifest.json') {
|
|
const u8 =
|
|
buf instanceof Uint8Array ? buf : new Uint8Array(/** @type {ArrayBuffer} */ (buf))
|
|
bareOsEvictLibBareBundlesFromManifest(u8)
|
|
} else if (isWarmReadCachePath(abs)) {
|
|
bareOsEvictSingleWarmReadPath(abs)
|
|
bareOsKernelMetricInc('vfs.warm_read_cache_invalidate_writeFile')
|
|
}
|
|
}
|
|
return putRes
|
|
}
|
|
|
|
return {
|
|
get home() {
|
|
return normalizeHome()
|
|
},
|
|
|
|
getcwd() {
|
|
return cwd
|
|
},
|
|
|
|
resolveLogical,
|
|
|
|
route,
|
|
|
|
env,
|
|
|
|
get bareOsIdentitySession() {
|
|
return bareOsIdentityVfsRef.session
|
|
},
|
|
set bareOsIdentitySession(v) {
|
|
bareOsIdentityVfsRef.session = v === 'unlocked' ? 'unlocked' : 'guest'
|
|
},
|
|
|
|
/**
|
|
* New VFS over the same drives with a copied env and separate cwd/cache state.
|
|
* Duplicates in-memory scaffolding (warm caches, dev/shm, etc.); intended for a
|
|
* small number of concurrent SSH-like sessions. Shares {@link bareOsIdentityVfsRef}
|
|
* with the parent so guest/unlocked policy stays aligned.
|
|
* @param {Record<string, string | undefined>} [extraEnv]
|
|
*/
|
|
bareOsForkShellEnv(extraEnv = {}) {
|
|
const forkEnv = Object.assign({}, env, extraEnv)
|
|
return createVfs(systemDrive, personalDrive, forkEnv, mntRef, {
|
|
...vfsOptions,
|
|
bareOsIdentityVfsRef: bareOsIdentityVfsRef
|
|
})
|
|
},
|
|
|
|
bareOsClearWarmReadCaches,
|
|
bareOsEvictLibBareBundlesFromManifest,
|
|
bareOsEvictWarmReadPrefixes,
|
|
|
|
/**
|
|
* Evict one logical absolute path from `/bin` / `/lib/bare` warm caches (OTA batch tuning).
|
|
* @param {string} userPath
|
|
*/
|
|
bareOsEvictWarmReadLogicalPath(userPath) {
|
|
const abs = resolveLogical(String(userPath || ''))
|
|
bareOsEvictSingleWarmReadPath(abs)
|
|
},
|
|
|
|
async chdir(userPath) {
|
|
const abs = resolveLogical(userPath)
|
|
assertNotBootPolicyDenyVfs(abs, 'chdir')
|
|
if (await isRegularFile(abs)) {
|
|
throw new Error('Not a directory: ' + userPath)
|
|
}
|
|
await assertTraverseTo(abs, 'chdir')
|
|
cwd = abs
|
|
env.PWD = cwd
|
|
},
|
|
|
|
/**
|
|
* @param {string} userPath
|
|
* @param {import('./bare-os-abort.js').BareOsAbortOpts} [abortOpts]
|
|
*/
|
|
async readFile(userPath, abortOpts) {
|
|
return raceWithAbortAndTimeout(
|
|
(async () => {
|
|
if (vfsReadMetricsOn) bareOsKernelMetricInc('vfs.readfile.samples')
|
|
const abs = resolveLogical(userPath)
|
|
assertNotBootPolicyDenyVfs(abs, 'read')
|
|
const r = route(abs)
|
|
if (r.virtualPseudo) {
|
|
if (r.node === 'enoent') {
|
|
await assertTraverseTo(abs, 'read')
|
|
return null
|
|
}
|
|
if (
|
|
r.node === 'file' &&
|
|
r.file === 'virtual_plugin' &&
|
|
getVirtualReaders
|
|
) {
|
|
await assertTraverseTo(abs, 'read')
|
|
const m = getVirtualReaders()
|
|
const ent =
|
|
r.virtualName && m && typeof m.get === 'function'
|
|
? m.get(r.virtualName)
|
|
: null
|
|
const fn =
|
|
typeof ent === 'function'
|
|
? ent
|
|
: ent &&
|
|
typeof ent === 'object' &&
|
|
ent !== null &&
|
|
typeof (/** @type {{ read?: unknown }} */ (ent).read) ===
|
|
'function'
|
|
? /** @type {{ read: () => unknown }} */ (ent).read
|
|
: null
|
|
if (typeof fn !== 'function') return null
|
|
const out = await Promise.resolve(fn())
|
|
if (typeof out === 'string') return utf8Encode(out)
|
|
return out instanceof Uint8Array ? out : new Uint8Array(out)
|
|
}
|
|
if (r.node === 'file' && r.file === 'ipc' && bareOsIpc) {
|
|
await assertTraverseTo(abs, 'read')
|
|
return bareOsIpc.take(r.ipcName)
|
|
}
|
|
if (r.node === 'file') {
|
|
await assertTraverseTo(abs, 'read')
|
|
return pseudoFileBytes(r)
|
|
}
|
|
return null
|
|
}
|
|
if (
|
|
r.virtualHomeDir ||
|
|
r.virtualMntRoot ||
|
|
r.virtualMirrorRoot ||
|
|
r.virtualVarRoot
|
|
)
|
|
return null
|
|
await assertTraverseTo(abs, 'read')
|
|
const absFollowed = await resolveSymlinksOnLogicalAbs(abs)
|
|
const r2 = route(absFollowed)
|
|
if (
|
|
r2.virtualHomeDir ||
|
|
r2.virtualMntRoot ||
|
|
r2.virtualMirrorRoot ||
|
|
r2.virtualVarRoot
|
|
)
|
|
return null
|
|
if (r2.virtualPseudo) {
|
|
await assertTraverseTo(absFollowed, 'read')
|
|
if (r2.node === 'enoent') {
|
|
return null
|
|
}
|
|
if (
|
|
r2.node === 'file' &&
|
|
r2.file === 'virtual_plugin' &&
|
|
getVirtualReaders
|
|
) {
|
|
const m = getVirtualReaders()
|
|
const ent =
|
|
r2.virtualName && m && typeof m.get === 'function'
|
|
? m.get(r2.virtualName)
|
|
: null
|
|
const fn =
|
|
typeof ent === 'function'
|
|
? ent
|
|
: ent &&
|
|
typeof ent === 'object' &&
|
|
ent !== null &&
|
|
typeof (/** @type {{ read?: unknown }} */ (ent).read) ===
|
|
'function'
|
|
? /** @type {{ read: () => unknown }} */ (ent).read
|
|
: null
|
|
if (typeof fn !== 'function') return null
|
|
const out = await Promise.resolve(fn())
|
|
if (typeof out === 'string') return utf8Encode(out)
|
|
return out instanceof Uint8Array ? out : new Uint8Array(out)
|
|
}
|
|
if (r2.node === 'file' && r2.file === 'ipc' && bareOsIpc) {
|
|
return bareOsIpc.take(r2.ipcName)
|
|
}
|
|
if (r2.node === 'file') {
|
|
return pseudoFileBytes(r2)
|
|
}
|
|
return null
|
|
}
|
|
await assertTraverseTo(absFollowed, 'read')
|
|
const { drive, path: p } = r2
|
|
if (isHyperdriveRootPath(p)) return null
|
|
if (unionReadPrefixes.length && drive === systemDrive) {
|
|
for (const pre of unionReadPrefixes) {
|
|
if (absFollowed === pre || absFollowed.startsWith(pre + '/')) {
|
|
const ol =
|
|
'/.bare-os/union' +
|
|
(absFollowed === '/' ? '' : absFollowed)
|
|
const ur = route(ol)
|
|
if (
|
|
!ur.virtualPseudo &&
|
|
ur.drive === personalDrive &&
|
|
!isHyperdriveRootPath(ur.path)
|
|
) {
|
|
try {
|
|
assertGuestSensitivePersonalOp(
|
|
ur.drive,
|
|
ur.path,
|
|
'read',
|
|
absFollowed
|
|
)
|
|
const ubuf = await ur.drive.get(ur.path, { follow: true })
|
|
if (ubuf) return ubuf
|
|
} catch {
|
|
/* fall through to system */
|
|
}
|
|
}
|
|
break
|
|
}
|
|
}
|
|
}
|
|
if (
|
|
binDigestCache &&
|
|
drive === systemDrive &&
|
|
isWarmReadCachePath(absFollowed)
|
|
) {
|
|
const dh = binPathToBlakeDigest.get(absFollowed)
|
|
if (dh) {
|
|
const hit = binDigestCache.get(dh)
|
|
if (hit) {
|
|
bumpWarmReadCacheHit(absFollowed)
|
|
return new Uint8Array(hit)
|
|
}
|
|
}
|
|
}
|
|
if (
|
|
binReadCache &&
|
|
drive === systemDrive &&
|
|
isWarmReadCachePath(absFollowed)
|
|
) {
|
|
const hit = binReadCache.get(absFollowed)
|
|
if (hit) {
|
|
bumpWarmReadCacheHit(absFollowed)
|
|
return new Uint8Array(hit)
|
|
}
|
|
}
|
|
if (
|
|
drive === personalDrive &&
|
|
(await bareOsVfsPathCapabilityDeniesDriveRead(
|
|
env,
|
|
drive,
|
|
p,
|
|
absFollowed
|
|
))
|
|
) {
|
|
throw new Error(
|
|
'EACCES: path capability enforces deny read: ' + absFollowed
|
|
)
|
|
}
|
|
if (await bareOsVfsAclDeniesDriveOp(env, drive, p, 'read')) {
|
|
throw new Error('EACCES: ACL enforces deny read: ' + absFollowed)
|
|
}
|
|
assertGuestSensitivePersonalOp(drive, p, 'read', absFollowed)
|
|
if (
|
|
warmReadCacheStats &&
|
|
drive === systemDrive &&
|
|
isWarmReadCachePath(absFollowed)
|
|
) {
|
|
warmReadCacheStats.misses++
|
|
}
|
|
const got = await drive.get(p, { follow: false })
|
|
if (got && drive === systemDrive && isWarmReadCachePath(absFollowed)) {
|
|
if (
|
|
binDigestCache &&
|
|
binPathToBlakeDigest &&
|
|
binDigestRefcount &&
|
|
binBlake2bLruPaths
|
|
) {
|
|
try {
|
|
const { createHash: ch } = await import('bare-crypto')
|
|
if (typeof ch !== 'function') throw new Error('no createHash')
|
|
const u8 = got instanceof Uint8Array ? got : new Uint8Array(got)
|
|
const h = ch('blake2b')
|
|
h.update(u8)
|
|
const dig = String(h.digest('hex'))
|
|
const oldHex = binPathToBlakeDigest.get(absFollowed)
|
|
if (oldHex === dig) {
|
|
touchBinBlake2bLru(absFollowed)
|
|
} else {
|
|
if (oldHex) {
|
|
const n0 = (binDigestRefcount.get(oldHex) || 1) - 1
|
|
if (n0 <= 0) {
|
|
binDigestRefcount.delete(oldHex)
|
|
binDigestCache.delete(oldHex)
|
|
} else {
|
|
binDigestRefcount.set(oldHex, n0)
|
|
}
|
|
}
|
|
binPathToBlakeDigest.set(absFollowed, dig)
|
|
if (!binDigestCache.has(dig)) {
|
|
binDigestCache.set(dig, new Uint8Array(u8))
|
|
}
|
|
binDigestRefcount.set(
|
|
dig,
|
|
(binDigestRefcount.get(dig) || 0) + 1
|
|
)
|
|
touchBinBlake2bLru(absFollowed)
|
|
}
|
|
} catch {
|
|
/* ignore blake2b cache failures */
|
|
}
|
|
} else if (binReadCache) {
|
|
if (binReadCache.size >= BIN_READ_CACHE_MAX) {
|
|
const first = binReadCache.keys().next().value
|
|
binReadCache.delete(first)
|
|
}
|
|
binReadCache.set(absFollowed, new Uint8Array(got))
|
|
}
|
|
}
|
|
return got
|
|
})(),
|
|
abortOpts,
|
|
'vfs.readFile'
|
|
)
|
|
},
|
|
|
|
/**
|
|
* @param {string} userPath
|
|
* @param {Uint8Array} buf
|
|
* @param {{
|
|
* executable?: boolean,
|
|
* signal?: AbortSignal,
|
|
* timeoutMs?: number,
|
|
* bumpMtime?: boolean,
|
|
* touchCtime?: boolean,
|
|
* mtimeMs?: number,
|
|
* ctimeMs?: number,
|
|
* posixModeBits?: number
|
|
* }} [opts]
|
|
*/
|
|
async writeFile(userPath, buf, opts = {}) {
|
|
const hyperDedup =
|
|
env &&
|
|
(env.BARE_OS_VFS_HYPERBLOBS_DEDUP === '1' ||
|
|
env.BARE_OS_VFS_HYPERBLOBS_DEDUP === 'true')
|
|
if (hyperDedup) bareOsKernelMetricInc('vfs.hyperblobs_dedup_hint_writes')
|
|
const { signal, timeoutMs, ...rest } = opts
|
|
const abortOpts =
|
|
signal || timeoutMs != null ? { signal, timeoutMs } : undefined
|
|
try {
|
|
return await raceWithAbortAndTimeout(
|
|
writeFileAtAbs(resolveLogical(userPath), buf, rest),
|
|
abortOpts,
|
|
'vfs.writeFile'
|
|
)
|
|
} catch (e) {
|
|
if (hyperDedup) bareOsKernelMetricInc('vfs.hyperblobs_dedup_write_abort')
|
|
throw e
|
|
}
|
|
},
|
|
|
|
async unlink(userPath) {
|
|
const abs = resolveLogical(userPath)
|
|
const r = route(abs)
|
|
if (r.snapshotReadOnly) {
|
|
throw new Error('EROFS: snapshot checkout is read-only: ' + userPath)
|
|
}
|
|
if (
|
|
r.virtualPseudo &&
|
|
r.kind === 'run' &&
|
|
r.node === 'file' &&
|
|
r.file === 'ipc' &&
|
|
bareOsIpc
|
|
) {
|
|
await assertTraverseTo(abs, 'write')
|
|
bareOsIpc.remove(r.ipcName)
|
|
return
|
|
}
|
|
if (
|
|
r.virtualPseudo &&
|
|
r.kind === 'dev' &&
|
|
r.node === 'file' &&
|
|
r.file === 'shm' &&
|
|
r.shmName
|
|
) {
|
|
await assertTraverseTo(abs, 'write')
|
|
bareOsDevShm.delete(String(r.shmName))
|
|
return
|
|
}
|
|
if (
|
|
r.virtualHomeDir ||
|
|
r.virtualMntRoot ||
|
|
r.virtualMirrorRoot ||
|
|
r.virtualVarRoot ||
|
|
r.virtualPseudo
|
|
) {
|
|
throw new Error('Read-only path (not under $HOME): ' + userPath)
|
|
}
|
|
if (r.mntReadOnly === true) {
|
|
throw new Error('Read-only mount: ' + userPath)
|
|
}
|
|
const { drive, path: p } = r
|
|
if (r.mntReadOnly === false) {
|
|
if (isHyperdriveRootPath(p)) {
|
|
throw new Error('Cannot unlink directory root')
|
|
}
|
|
await assertUnlink(abs)
|
|
assertGuestSensitivePersonalOp(drive, p, 'unlink', abs)
|
|
return drive.del(p)
|
|
}
|
|
if (drive !== personalDrive) {
|
|
throw new Error('Read-only path (not under $HOME): ' + userPath)
|
|
}
|
|
if (isHyperdriveRootPath(p)) {
|
|
throw new Error('Cannot unlink directory root')
|
|
}
|
|
await assertUnlink(abs)
|
|
assertGuestSensitivePersonalOp(drive, p, 'unlink', abs)
|
|
return drive.del(p)
|
|
},
|
|
|
|
/**
|
|
* Remove file, symlink, or directory tree (with recursive). Single-key `del` is not enough for dirs.
|
|
* @param {string} userPath
|
|
* @param {{ recursive?: boolean, force?: boolean }} [opts]
|
|
*/
|
|
async rm(userPath, opts = {}) {
|
|
const abs = resolveLogical(userPath)
|
|
return rmFromAbs(abs, {
|
|
recursive: Boolean(opts.recursive),
|
|
force: Boolean(opts.force)
|
|
})
|
|
},
|
|
|
|
async exists(userPath) {
|
|
const abs = resolveLogical(userPath)
|
|
assertNotBootPolicyDenyVfs(abs, 'stat')
|
|
const r = route(abs)
|
|
if (r.virtualPseudo) {
|
|
if (r.node === 'enoent') return false
|
|
return true
|
|
}
|
|
if (
|
|
r.virtualHomeDir ||
|
|
r.virtualMntRoot ||
|
|
r.virtualMirrorRoot ||
|
|
r.virtualVarRoot
|
|
)
|
|
return true
|
|
const { drive, path: p } = r
|
|
if (isHyperdriveRootPath(p)) return true
|
|
if (
|
|
drive === personalDrive &&
|
|
bareOsGuestSensitivePersonalDenied(p) &&
|
|
bareOsIdentityVfsRef.session !== 'unlocked' &&
|
|
!(
|
|
env?.BARE_OS_GUEST_BARE_READ_ALL === '1' ||
|
|
env?.BARE_OS_GUEST_BARE_READ_ALL === 'true'
|
|
)
|
|
) {
|
|
return false
|
|
}
|
|
return drive.exists(p)
|
|
},
|
|
|
|
/** @returns {Promise<string[]>} */
|
|
async readdir(userPath) {
|
|
const abs = resolveLogical(userPath)
|
|
assertNotBootPolicyDenyVfs(abs, 'readdir')
|
|
await assertTraverseTo(abs, 'readdir')
|
|
return readdirFromAbs(abs)
|
|
},
|
|
|
|
async stat(userPath) {
|
|
const abs = resolveLogical(userPath)
|
|
assertNotBootPolicyDenyVfs(abs, 'stat')
|
|
return statFromAbs(abs)
|
|
},
|
|
|
|
/**
|
|
* Octal mode (e.g. 0o644); applies to files and symlinks with a drive entry.
|
|
* @param {string} userPath
|
|
* @param {number} modeOctal permission bits + optional type bits (masked)
|
|
*/
|
|
async chmod(userPath, modeOctal) {
|
|
const abs = resolveLogical(userPath)
|
|
assertUnionWriteNotDenied(abs)
|
|
const r = route(abs)
|
|
if (
|
|
r.virtualHomeDir ||
|
|
r.virtualMntRoot ||
|
|
r.virtualMirrorRoot ||
|
|
r.virtualVarRoot ||
|
|
r.virtualPseudo
|
|
) {
|
|
throw new Error('chmod: ' + userPath + ': Operation not supported')
|
|
}
|
|
if (r.mntReadOnly === true) {
|
|
throw new Error('Read-only mount: ' + userPath)
|
|
}
|
|
const { drive, path: p } = r
|
|
if (drive !== personalDrive) {
|
|
throw new Error('chmod: read-only system path: ' + userPath)
|
|
}
|
|
if (isHyperdriveRootPath(p)) {
|
|
throw new Error('chmod: invalid path')
|
|
}
|
|
assertGuestSensitivePersonalOp(drive, p, 'chmod', abs)
|
|
const st = await lstatFromAbs(abs)
|
|
if (!st) throw new Error('chmod: ' + userPath + ': No such file')
|
|
const { uid: euid } = parseUidGid(env)
|
|
if (euid !== 0 && euid !== st.uid) {
|
|
throw new Error('chmod: ' + userPath + ': Operation not permitted')
|
|
}
|
|
const e = await entryOn(drive, p, { follow: false })
|
|
if (!e?.value) {
|
|
throw new Error('chmod: cannot change inferred directory: ' + userPath)
|
|
}
|
|
const v = e.value
|
|
const perm = modeOctal & 0o777
|
|
let typeBits = S_IFREG
|
|
if (v.linkname) typeBits = S_IFLNK
|
|
else if (!v.blob) typeBits = S_IFDIR
|
|
const newMode = typeBits | perm
|
|
const prevBare = extractBareOs(v)
|
|
const bo = prevBare
|
|
? {
|
|
...prevBare,
|
|
mode: newMode,
|
|
mtimeMs: prevBare.mtimeMs,
|
|
ctimeMs: prevBare.ctimeMs
|
|
}
|
|
: {
|
|
mode: newMode,
|
|
uid: st.uid,
|
|
gid: st.gid,
|
|
uname: st.user,
|
|
gname: st.group,
|
|
mtimeMs: st.mtimeMs,
|
|
ctimeMs: st.ctimeMs
|
|
}
|
|
const executable = !!(v.blob && newMode & 0o111)
|
|
await drive.putEntry(p, {
|
|
executable,
|
|
linkname: v.linkname ?? null,
|
|
blob: v.blob ?? null,
|
|
metadata: mergeEntryMetadata(v.metadata, bo)
|
|
})
|
|
},
|
|
|
|
/**
|
|
* Update stored ownership on the personal drive (same writable scope as chmod). Root (euid 0)
|
|
* may set any uid/gid; non-root may only change the group of files they own.
|
|
* @param {string} userPath
|
|
* @param {{ uid: number, gid: number, uname?: string, gname?: string }} next
|
|
*/
|
|
async chown(userPath, next) {
|
|
const abs = resolveLogical(userPath)
|
|
assertUnionWriteNotDenied(abs)
|
|
const r = route(abs)
|
|
if (
|
|
r.virtualHomeDir ||
|
|
r.virtualMntRoot ||
|
|
r.virtualMirrorRoot ||
|
|
r.virtualVarRoot ||
|
|
r.virtualPseudo
|
|
) {
|
|
throw new Error('chown: ' + userPath + ': Operation not supported')
|
|
}
|
|
if (r.mntReadOnly === true) {
|
|
throw new Error('Read-only mount: ' + userPath)
|
|
}
|
|
const { drive, path: p } = r
|
|
if (drive !== personalDrive) {
|
|
throw new Error('chown: read-only system path: ' + userPath)
|
|
}
|
|
if (isHyperdriveRootPath(p)) {
|
|
throw new Error('chown: invalid path')
|
|
}
|
|
const st = await lstatFromAbs(abs)
|
|
if (!st) throw new Error('chown: ' + userPath + ': No such file')
|
|
const { uid: euid } = parseUidGid(env)
|
|
const nu = Number(next.uid)
|
|
const ng = Number(next.gid)
|
|
if (!Number.isFinite(nu) || !Number.isFinite(ng)) {
|
|
throw new Error('chown: invalid uid/gid')
|
|
}
|
|
if (euid !== 0) {
|
|
if (euid !== st.uid) {
|
|
throw new Error('chown: ' + userPath + ': Operation not permitted')
|
|
}
|
|
if (nu !== st.uid) {
|
|
throw new Error('chown: ' + userPath + ': Operation not permitted')
|
|
}
|
|
}
|
|
const { user: defU, group: defG } = identityNames(env)
|
|
const uname =
|
|
typeof next.uname === 'string' && next.uname.trim()
|
|
? next.uname.trim()
|
|
: defU
|
|
const gname =
|
|
typeof next.gname === 'string' && next.gname.trim()
|
|
? next.gname.trim()
|
|
: defG
|
|
const e = await entryOn(drive, p, { follow: false })
|
|
if (!e?.value) {
|
|
throw new Error('chown: cannot change inferred directory: ' + userPath)
|
|
}
|
|
const v = e.value
|
|
const prevBare = extractBareOs(v)
|
|
const now = Date.now()
|
|
const bo = prevBare
|
|
? {
|
|
...prevBare,
|
|
uid: nu,
|
|
gid: ng,
|
|
uname,
|
|
gname,
|
|
mtimeMs: prevBare.mtimeMs,
|
|
ctimeMs: now
|
|
}
|
|
: {
|
|
mode: S_IFREG | 0o644,
|
|
uid: nu,
|
|
gid: ng,
|
|
uname,
|
|
gname,
|
|
mtimeMs: st.mtimeMs,
|
|
ctimeMs: now
|
|
}
|
|
const executable = !!(v.blob && bo.mode & 0o111)
|
|
await drive.putEntry(p, {
|
|
executable,
|
|
linkname: v.linkname ?? null,
|
|
blob: v.blob ?? null,
|
|
metadata: mergeEntryMetadata(v.metadata, bo)
|
|
})
|
|
},
|
|
|
|
/**
|
|
* Like stat but do not follow symlinks at the final path (for isomorphic-git lstat).
|
|
*/
|
|
async lstat(userPath) {
|
|
return lstatFromAbs(resolveLogical(userPath))
|
|
},
|
|
|
|
/**
|
|
* Create a directory using a hidden marker file (Hyperdrive has no empty dirs).
|
|
* @param {string} userPath
|
|
* @param {{ recursive?: boolean, mode?: number }} [opts]
|
|
* `mode`: permission bits (e.g. 0o755) stored on `.bareos_empty`; directory `lstat` reports **`S_IFDIR`** with those bits.
|
|
*/
|
|
async mkdir(userPath, opts = {}) {
|
|
const recursive = Boolean(opts.recursive)
|
|
const modeBits =
|
|
typeof opts.mode === 'number' && Number.isFinite(opts.mode)
|
|
? opts.mode & 0o777
|
|
: null
|
|
const markerPutOpts = modeBits != null ? { posixModeBits: modeBits } : {}
|
|
let abs = resolveLogical(userPath)
|
|
if (abs !== '/' && abs.endsWith('/')) {
|
|
abs = abs.replace(/\/+$/, '') || '/'
|
|
}
|
|
if (abs === '/') {
|
|
throw new Error('mkdir: cannot create /')
|
|
}
|
|
const existing = await lstatFromAbs(abs)
|
|
if (existing) {
|
|
if (existing.type === 'directory') return
|
|
throw new Error('mkdir: File exists')
|
|
}
|
|
const empty = new Uint8Array(0)
|
|
if (!recursive) {
|
|
const parent = dirnameAbs(abs)
|
|
const pst = await lstatFromAbs(parent)
|
|
if (!pst || pst.type !== 'directory') {
|
|
throw new Error('mkdir: No such file or directory')
|
|
}
|
|
await writeFileAtAbs(joinLogical(abs, DIR_MARKER), empty, markerPutOpts)
|
|
return
|
|
}
|
|
const rMk = route(abs)
|
|
if (
|
|
recursive &&
|
|
personalDrive &&
|
|
rMk.drive === personalDrive &&
|
|
typeof rMk.path === 'string'
|
|
) {
|
|
const rp = rMk.path.replace(/\/+$/, '') || '/'
|
|
if (rp === '/.bare/holesail' || rp.startsWith('/.bare/holesail/')) {
|
|
const norm = rMk.path.replace(/\/+$/, '') || rMk.path
|
|
const physPrefs = pathPrefixes(norm)
|
|
for (let i = 1; i < physPrefs.length; i++) {
|
|
const physPre = physPrefs[i]
|
|
const st = await lstatPersonalDrivePhysicalDir(physPre)
|
|
if (st) {
|
|
if (st.type === 'directory') continue
|
|
throw new Error('mkdir: File exists')
|
|
}
|
|
const markerPath =
|
|
physPre === '/' ? `/${DIR_MARKER}` : `${physPre}/${DIR_MARKER}`
|
|
await putPersonalDrivePhysical(abs, markerPath, empty, markerPutOpts)
|
|
}
|
|
return
|
|
}
|
|
}
|
|
const prefs = pathPrefixes(abs)
|
|
for (let i = 1; i < prefs.length; i++) {
|
|
const pre = prefs[i]
|
|
const st = await lstatFromAbs(pre)
|
|
if (st) {
|
|
if (st.type === 'directory') continue
|
|
throw new Error('mkdir: File exists')
|
|
}
|
|
const markerAbs = joinLogical(pre, DIR_MARKER)
|
|
await writeFileAtAbs(markerAbs, empty, markerPutOpts)
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Remove an empty directory (only the marker file may remain besides hidden marker).
|
|
*/
|
|
async rmdir(userPath) {
|
|
const abs = resolveLogical(userPath)
|
|
const st = await lstatFromAbs(abs)
|
|
if (!st) {
|
|
throw new Error('rmdir: No such file or directory')
|
|
}
|
|
if (st.type !== 'directory') {
|
|
throw new Error('rmdir: Not a directory')
|
|
}
|
|
const names = await readdirFromAbs(abs)
|
|
const rest = names.filter((n) => n !== DIR_MARKER)
|
|
if (rest.length) {
|
|
throw new Error('rmdir: Directory not empty')
|
|
}
|
|
if (names.includes(DIR_MARKER)) {
|
|
const mabs = joinLogical(abs, DIR_MARKER)
|
|
await assertUnlink(mabs)
|
|
await delFromAbs(mabs)
|
|
}
|
|
},
|
|
|
|
async readlink(userPath) {
|
|
const abs = resolveLogical(userPath)
|
|
const r = route(abs)
|
|
if (
|
|
r.virtualHomeDir ||
|
|
r.virtualMntRoot ||
|
|
r.virtualMirrorRoot ||
|
|
r.virtualVarRoot ||
|
|
r.virtualPseudo
|
|
) {
|
|
throw new Error('EINVAL readlink')
|
|
}
|
|
if (r.mntReadOnly === true) {
|
|
throw new Error('Read-only mount: ' + userPath)
|
|
}
|
|
const { drive, path: p } = r
|
|
if (isHyperdriveRootPath(p)) throw new Error('EINVAL readlink')
|
|
if (unionReadPrefixes.length && drive === systemDrive) {
|
|
for (const pre of unionReadPrefixes) {
|
|
if (abs === pre || abs.startsWith(pre + '/')) {
|
|
const ol = '/.bare-os/union' + (abs === '/' ? '' : abs)
|
|
const ur = route(ol)
|
|
if (
|
|
!ur.virtualPseudo &&
|
|
ur.drive === personalDrive &&
|
|
!isHyperdriveRootPath(ur.path)
|
|
) {
|
|
try {
|
|
const ue = await entryOn(ur.drive, ur.path, { follow: false })
|
|
if (ue && ue.value && ue.value.linkname) return ue.value.linkname
|
|
} catch {
|
|
/* fall through to system */
|
|
}
|
|
}
|
|
break
|
|
}
|
|
}
|
|
}
|
|
const e = await entryOn(drive, p, { follow: false })
|
|
if (e && e.value && e.value.linkname) return e.value.linkname
|
|
throw new Error('EINVAL not a symlink')
|
|
},
|
|
|
|
/**
|
|
* @param {string} target link text (stored as-is)
|
|
* @param {string} userPath new symlink path
|
|
*/
|
|
async symlink(target, userPath) {
|
|
const abs = resolveLogical(userPath)
|
|
assertUnionWriteNotDenied(abs)
|
|
const r = route(abs)
|
|
if (
|
|
r.virtualHomeDir ||
|
|
r.virtualMntRoot ||
|
|
r.virtualMirrorRoot ||
|
|
r.virtualVarRoot ||
|
|
r.virtualPseudo
|
|
) {
|
|
throw new Error('Read-only path (not under $HOME): ' + userPath)
|
|
}
|
|
if (r.mntReadOnly === true) {
|
|
throw new Error('Read-only mount: ' + userPath)
|
|
}
|
|
const { drive, path: p } = r
|
|
if (r.mntReadOnly === false) {
|
|
if (isHyperdriveRootPath(p)) {
|
|
throw new Error('Cannot symlink at directory root')
|
|
}
|
|
return drive.symlink(p, target, {
|
|
metadata: mergeEntryMetadata(null, newBareOsForSymlink(env))
|
|
})
|
|
}
|
|
if (drive !== personalDrive) {
|
|
throw new Error('Read-only path (not under $HOME): ' + userPath)
|
|
}
|
|
if (isHyperdriveRootPath(p)) {
|
|
throw new Error('Cannot symlink at directory root')
|
|
}
|
|
return drive.symlink(p, target, {
|
|
metadata: mergeEntryMetadata(null, newBareOsForSymlink(env))
|
|
})
|
|
},
|
|
|
|
/**
|
|
* POSIX fsync analog: Hyperdrive has no per-path flush; returns immediately.
|
|
* @param {string} userPath
|
|
*/
|
|
async fsync(userPath) {
|
|
void resolveLogical(userPath)
|
|
return undefined
|
|
},
|
|
|
|
/**
|
|
* Hyperdrive-backed path watch (not pseudo paths). Yields `[current, previous]` snapshots.
|
|
* Call `await watcher.ready()` then iterate; `await watcher.destroy()` when done.
|
|
* @param {string} userPath
|
|
*/
|
|
async watch(userPath) {
|
|
const abs = resolveLogical(userPath)
|
|
const absNorm = abs.replace(/\/+$/, '') || '/'
|
|
const pseudoWatchOn =
|
|
env.BARE_OS_VFS_WATCH_PSEUDO === '1' ||
|
|
env.BARE_OS_VFS_WATCH_PSEUDO === 'true'
|
|
const swarmWatchOn =
|
|
env.BARE_OS_VFS_WATCH_SWARM === '1' ||
|
|
env.BARE_OS_VFS_WATCH_SWARM === 'true'
|
|
if (pseudoWatchOn || swarmWatchOn) {
|
|
const allowPseudoMetrics =
|
|
pseudoWatchOn &&
|
|
(absNorm === '/proc/bare_os/metrics_live.json' ||
|
|
absNorm === '/proc/bare_os/metrics_live' ||
|
|
absNorm === '/proc/bare_os_metrics_live' ||
|
|
absNorm === '/proc/bare_os_metrics_live.json' ||
|
|
absNorm === '/proc/bare_os/metrics.prom' ||
|
|
absNorm === '/proc/bare_os_metrics_prom' ||
|
|
absNorm === '/proc/bare_os_metrics_prom.json')
|
|
const swarmLike =
|
|
absNorm === '/proc/bare_os/swarm' ||
|
|
absNorm === '/proc/bare_os_swarm' ||
|
|
absNorm === '/proc/bare_os/swarm_health.json' ||
|
|
absNorm === '/proc/bare_os_swarm_health' ||
|
|
absNorm === '/proc/bare_os_swarm_health.json' ||
|
|
absNorm === '/proc/bare_os/replication' ||
|
|
absNorm === '/proc/bare_os_replication'
|
|
const allowSwarm = swarmWatchOn && swarmLike
|
|
if (allowPseudoMetrics || allowSwarm) {
|
|
const pm = Number.parseInt(env.BARE_OS_PROC_POLL_MS || '1000', 10)
|
|
const pollMs = Number.isFinite(pm)
|
|
? Math.min(60000, Math.max(250, pm))
|
|
: 1000
|
|
let destroyed = false
|
|
const gen = (async function* () {
|
|
let last = ''
|
|
while (!destroyed) {
|
|
await new Promise((r) => setTimeout(r, pollMs))
|
|
if (destroyed) break
|
|
const cur = allowSwarm
|
|
? absNorm === '/proc/bare_os/replication' ||
|
|
absNorm === '/proc/bare_os_replication'
|
|
? procBareOsReplicationText
|
|
? procBareOsReplicationText()
|
|
: '{}\n'
|
|
: absNorm === '/proc/bare_os/swarm_health.json' ||
|
|
absNorm === '/proc/bare_os_swarm_health' ||
|
|
absNorm === '/proc/bare_os_swarm_health.json'
|
|
? procBareOsSwarmHealthText
|
|
? procBareOsSwarmHealthText()
|
|
: '{}\n'
|
|
: procBareOsSwarmText
|
|
? procBareOsSwarmText()
|
|
: '{}\n'
|
|
: absNorm === '/proc/bare_os/metrics.prom' ||
|
|
absNorm === '/proc/bare_os_metrics_prom' ||
|
|
absNorm === '/proc/bare_os_metrics_prom.json'
|
|
? procBareOsMetricsPromText
|
|
? procBareOsMetricsPromText()
|
|
: '# TYPE bare_os_kernel_counters counter\n'
|
|
: procBareOsMetricsLiveText
|
|
? procBareOsMetricsLiveText()
|
|
: '{}\n'
|
|
yield [cur, last]
|
|
last = cur
|
|
}
|
|
})()
|
|
const watcher = {
|
|
async ready() {},
|
|
async destroy() {
|
|
destroyed = true
|
|
},
|
|
[Symbol.asyncIterator]() {
|
|
return gen
|
|
}
|
|
}
|
|
await watcher.ready()
|
|
return {
|
|
logicalAbs: abs,
|
|
driveFolder: '',
|
|
watcher,
|
|
watchConsistencyClass: 'poll',
|
|
destroy: () => {
|
|
destroyed = true
|
|
}
|
|
}
|
|
}
|
|
}
|
|
const r = route(abs)
|
|
if (r.virtualPseudo) {
|
|
throw new Error('watch: pseudo filesystem path not supported')
|
|
}
|
|
if (
|
|
r.virtualHomeDir ||
|
|
r.virtualVarRoot ||
|
|
r.virtualMntRoot ||
|
|
r.virtualMirrorRoot ||
|
|
r.virtualSnapshotRoot ||
|
|
r.virtualSnapshotSystem
|
|
) {
|
|
throw new Error('watch: virtual directory path not supported')
|
|
}
|
|
const { drive, path: p } = r
|
|
await drive.ready()
|
|
const e = await entryOn(drive, p, { follow: true })
|
|
let folder = '/'
|
|
const norm = p === '/' ? '/' : p.replace(/\/+$/, '') || '/'
|
|
if (norm !== '/') {
|
|
if (e && e.value && e.value.blob) {
|
|
const i = norm.lastIndexOf('/')
|
|
folder = i <= 0 ? '/' : norm.slice(0, i) || '/'
|
|
} else {
|
|
folder = norm
|
|
}
|
|
}
|
|
const watcher = drive.watch(folder)
|
|
await watcher.ready()
|
|
const wcRaw = String(env.BARE_OS_VFS_WATCH_CONSISTENCY || 'edge')
|
|
.trim()
|
|
.toLowerCase()
|
|
const watchConsistencyClass =
|
|
wcRaw === 'coalesced' || wcRaw === 'poll' || wcRaw === 'edge'
|
|
? wcRaw
|
|
: 'edge'
|
|
return {
|
|
logicalAbs: abs,
|
|
driveFolder: folder,
|
|
watcher,
|
|
watchConsistencyClass,
|
|
destroy: () => watcher.destroy()
|
|
}
|
|
}
|
|
}
|
|
}
|