Further Cleanup
This commit is contained in:
@@ -33,6 +33,10 @@ import { bareOsSeederHyperswarmOptsFromEnv } from './lib/swarm-opts.js'
|
||||
import { parseSeedDhtBootstrapJson } from './lib/dht-bootstrap-validate.js'
|
||||
import { seedLog } from './lib/host-logger.mjs'
|
||||
import { bareOsCorestoreConstructOpts } from './lib/corestore-opts.js'
|
||||
import {
|
||||
applyHostFlagsFromArgv,
|
||||
hostArgv
|
||||
} from '../../lib/bare-os-host-flags.mjs'
|
||||
|
||||
const _pkg = packageRootDir(import.meta.url)
|
||||
|
||||
@@ -101,27 +105,7 @@ async function maybeBuildBareLibsFromSource() {
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const hostArgv = (() => {
|
||||
if (typeof globalThis.Bare !== 'undefined' && Array.isArray(globalThis.Bare.argv)) {
|
||||
const a0 = String(globalThis.Bare.argv[0] || '')
|
||||
const base = a0.split(/[/\\]/).pop() || ''
|
||||
return globalThis.Bare.argv.slice(base === 'bare' ? 2 : 1)
|
||||
}
|
||||
return globalThis.process?.argv?.slice(2) || []
|
||||
})()
|
||||
for (let i = 0; i < hostArgv.length; i++) {
|
||||
const a = hostArgv[i]
|
||||
let datadir = null
|
||||
if (a === '--datadir' || a === '--data-dir') datadir = hostArgv[++i]
|
||||
else if (a.startsWith('--datadir=')) datadir = a.slice('--datadir='.length)
|
||||
else if (a.startsWith('--data-dir=')) datadir = a.slice('--data-dir='.length)
|
||||
if (datadir != null && String(datadir).trim()) {
|
||||
if (!globalThis.process) globalThis.process = { env: {} }
|
||||
if (!globalThis.process.env) globalThis.process.env = {}
|
||||
globalThis.process.env.BARE_OS_HOST_DATA = path.resolve(String(datadir).trim())
|
||||
break
|
||||
}
|
||||
}
|
||||
applyHostFlagsFromArgv(hostArgv())
|
||||
|
||||
console.clear?.()
|
||||
seedLog('info', 'bare-os-seeder (Hyperdrive + MBR) start')
|
||||
|
||||
@@ -312,10 +312,87 @@ function bareOsHexEncode(u8) {
|
||||
}
|
||||
|
||||
/**
|
||||
* chgrp — change file group (Hyperdrive metadata on writable paths).
|
||||
* Shared GNU-style checksum FILE / stdin loop used by *sum commands.
|
||||
* @param {Record<string, unknown>} ctx
|
||||
* @param {string[]} argv
|
||||
* @param {{
|
||||
* cmd: string,
|
||||
* help?: string,
|
||||
* digest: (u8: Uint8Array) => string | Promise<string>
|
||||
* }} opts
|
||||
*/
|
||||
async function bareChecksumRun(ctx, argv, opts) {
|
||||
const cmd = String(opts.cmd || 'checksum')
|
||||
const help =
|
||||
opts.help ||
|
||||
'usage: ' +
|
||||
cmd +
|
||||
' [FILE]...\nWith no FILE, or when FILE is -, read standard input.'
|
||||
const digest = opts.digest
|
||||
const paths = []
|
||||
for (let i = 1; i < argv.length; i++) {
|
||||
const a = argv[i]
|
||||
if (a === '-h' || a === '--help') {
|
||||
ctx.console.log(help)
|
||||
ctx.exitCode = 0
|
||||
return
|
||||
}
|
||||
if (a.startsWith('-') && a !== '-') {
|
||||
ctx.console.error(cmd + ': unsupported option ' + a)
|
||||
ctx.exitCode = 1
|
||||
return
|
||||
}
|
||||
paths.push(a)
|
||||
}
|
||||
const b4 = ctx.b4a
|
||||
async function one(name, buf) {
|
||||
const u8 = buf instanceof Uint8Array ? buf : new Uint8Array(buf)
|
||||
try {
|
||||
const hex = await digest(u8)
|
||||
ctx.console.log(hex + ' ' + name)
|
||||
} catch (e) {
|
||||
ctx.console.error(cmd + ': ' + (e.message || e))
|
||||
ctx.exitCode = 1
|
||||
}
|
||||
}
|
||||
if (!paths.length || (paths.length === 1 && paths[0] === '-')) {
|
||||
await one('-', b4.from(bareStdin(ctx)))
|
||||
return
|
||||
}
|
||||
for (const p of paths) {
|
||||
if (p === '-') {
|
||||
await one('-', b4.from(bareStdin(ctx)))
|
||||
continue
|
||||
}
|
||||
const b = await ctx.vfs.readFile(p)
|
||||
if (!b) {
|
||||
ctx.console.error(cmd + ': ' + p + ': No such file')
|
||||
ctx.exitCode = 1
|
||||
continue
|
||||
}
|
||||
await one(p, b)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* WebCrypto hex digest; throws the same missing-subtle message as the old *sum files.
|
||||
* @param {string} algo
|
||||
* @param {string} missingMsg
|
||||
* @returns {(u8: Uint8Array) => Promise<string>}
|
||||
*/
|
||||
function bareSubtleHexDigest(algo, missingMsg) {
|
||||
return async function (u8) {
|
||||
const subtle = globalThis.crypto?.subtle
|
||||
if (!subtle || typeof subtle.digest !== 'function') {
|
||||
throw new Error(missingMsg)
|
||||
}
|
||||
const hash = await subtle.digest(algo, u8)
|
||||
return bareOsHexEncode(new Uint8Array(hash))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Owner/group name → uid/gid used by chown / chgrp.
|
||||
* @param {string} spec
|
||||
* @param {Record<string, string>} env
|
||||
* @returns {number | null}
|
||||
@@ -337,6 +414,33 @@ function parseGroupSpec(spec, env) {
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* User name / numeric uid used by chown.
|
||||
* @param {string} spec
|
||||
* @param {Record<string, string>} env
|
||||
* @returns {{ uid: number | null, gid: number | null }}
|
||||
*/
|
||||
function parseIdSpec(spec, env) {
|
||||
const s = String(spec).trim()
|
||||
if (!s) return { uid: null, gid: null }
|
||||
if (/^\d+$/.test(s)) {
|
||||
const n = Number.parseInt(s, 10)
|
||||
return { uid: Number.isFinite(n) ? n : null, gid: null }
|
||||
}
|
||||
const u = (env.USER || env.LOGNAME || '').trim()
|
||||
if (s === 'root') return { uid: 0, gid: null }
|
||||
if (s === 'guest' || s === 'nobody') return { uid: 65534, gid: null }
|
||||
if (u && s === u) {
|
||||
const uid = Number.parseInt(String(env.UID ?? '65534'), 10)
|
||||
return { uid: Number.isFinite(uid) ? uid : 65534, gid: null }
|
||||
}
|
||||
return { uid: null, gid: null }
|
||||
}
|
||||
|
||||
/**
|
||||
* chgrp — change file group (Hyperdrive metadata on writable paths).
|
||||
*/
|
||||
|
||||
async function run(ctx, argv) {
|
||||
let i = 1
|
||||
const files = []
|
||||
|
||||
@@ -312,10 +312,110 @@ function bareOsHexEncode(u8) {
|
||||
}
|
||||
|
||||
/**
|
||||
* chown — change file owner and group (Hyperdrive metadata on writable paths).
|
||||
* Shared GNU-style checksum FILE / stdin loop used by *sum commands.
|
||||
* @param {Record<string, unknown>} ctx
|
||||
* @param {string[]} argv
|
||||
* @param {{
|
||||
* cmd: string,
|
||||
* help?: string,
|
||||
* digest: (u8: Uint8Array) => string | Promise<string>
|
||||
* }} opts
|
||||
*/
|
||||
async function bareChecksumRun(ctx, argv, opts) {
|
||||
const cmd = String(opts.cmd || 'checksum')
|
||||
const help =
|
||||
opts.help ||
|
||||
'usage: ' +
|
||||
cmd +
|
||||
' [FILE]...\nWith no FILE, or when FILE is -, read standard input.'
|
||||
const digest = opts.digest
|
||||
const paths = []
|
||||
for (let i = 1; i < argv.length; i++) {
|
||||
const a = argv[i]
|
||||
if (a === '-h' || a === '--help') {
|
||||
ctx.console.log(help)
|
||||
ctx.exitCode = 0
|
||||
return
|
||||
}
|
||||
if (a.startsWith('-') && a !== '-') {
|
||||
ctx.console.error(cmd + ': unsupported option ' + a)
|
||||
ctx.exitCode = 1
|
||||
return
|
||||
}
|
||||
paths.push(a)
|
||||
}
|
||||
const b4 = ctx.b4a
|
||||
async function one(name, buf) {
|
||||
const u8 = buf instanceof Uint8Array ? buf : new Uint8Array(buf)
|
||||
try {
|
||||
const hex = await digest(u8)
|
||||
ctx.console.log(hex + ' ' + name)
|
||||
} catch (e) {
|
||||
ctx.console.error(cmd + ': ' + (e.message || e))
|
||||
ctx.exitCode = 1
|
||||
}
|
||||
}
|
||||
if (!paths.length || (paths.length === 1 && paths[0] === '-')) {
|
||||
await one('-', b4.from(bareStdin(ctx)))
|
||||
return
|
||||
}
|
||||
for (const p of paths) {
|
||||
if (p === '-') {
|
||||
await one('-', b4.from(bareStdin(ctx)))
|
||||
continue
|
||||
}
|
||||
const b = await ctx.vfs.readFile(p)
|
||||
if (!b) {
|
||||
ctx.console.error(cmd + ': ' + p + ': No such file')
|
||||
ctx.exitCode = 1
|
||||
continue
|
||||
}
|
||||
await one(p, b)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* WebCrypto hex digest; throws the same missing-subtle message as the old *sum files.
|
||||
* @param {string} algo
|
||||
* @param {string} missingMsg
|
||||
* @returns {(u8: Uint8Array) => Promise<string>}
|
||||
*/
|
||||
function bareSubtleHexDigest(algo, missingMsg) {
|
||||
return async function (u8) {
|
||||
const subtle = globalThis.crypto?.subtle
|
||||
if (!subtle || typeof subtle.digest !== 'function') {
|
||||
throw new Error(missingMsg)
|
||||
}
|
||||
const hash = await subtle.digest(algo, u8)
|
||||
return bareOsHexEncode(new Uint8Array(hash))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Owner/group name → uid/gid used by chown / chgrp.
|
||||
* @param {string} spec
|
||||
* @param {Record<string, string>} env
|
||||
* @returns {number | null}
|
||||
*/
|
||||
function parseGroupSpec(spec, env) {
|
||||
const s = String(spec).trim()
|
||||
if (!s) return null
|
||||
if (/^\d+$/.test(s)) {
|
||||
const n = Number.parseInt(s, 10)
|
||||
return Number.isFinite(n) ? n : null
|
||||
}
|
||||
const g = (env.GROUP || env.USER || 'guest').trim()
|
||||
if (s === 'root') return 0
|
||||
if (s === 'guest' || s === 'nobody') return 65534
|
||||
if (g && s === g) {
|
||||
const gid = Number.parseInt(String(env.GID ?? '65534'), 10)
|
||||
return Number.isFinite(gid) ? gid : 65534
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* User name / numeric uid used by chown.
|
||||
* @param {string} spec
|
||||
* @param {Record<string, string>} env
|
||||
* @returns {{ uid: number | null, gid: number | null }}
|
||||
@@ -338,26 +438,8 @@ function parseIdSpec(spec, env) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} spec
|
||||
* @param {Record<string, string>} env
|
||||
* @returns {number | null}
|
||||
* chown — change file owner and group (Hyperdrive metadata on writable paths).
|
||||
*/
|
||||
function parseGroupSpec(spec, env) {
|
||||
const s = String(spec).trim()
|
||||
if (!s) return null
|
||||
if (/^\d+$/.test(s)) {
|
||||
const n = Number.parseInt(s, 10)
|
||||
return Number.isFinite(n) ? n : null
|
||||
}
|
||||
const g = (env.GROUP || env.USER || 'guest').trim()
|
||||
if (s === 'root') return 0
|
||||
if (s === 'guest' || s === 'nobody') return 65534
|
||||
if (g && s === g) {
|
||||
const gid = Number.parseInt(String(env.GID ?? '65534'), 10)
|
||||
return Number.isFinite(gid) ? gid : 65534
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
async function run(ctx, argv) {
|
||||
let i = 1
|
||||
|
||||
@@ -311,6 +311,132 @@ function bareOsHexEncode(u8) {
|
||||
return s
|
||||
}
|
||||
|
||||
/**
|
||||
* Shared GNU-style checksum FILE / stdin loop used by *sum commands.
|
||||
* @param {Record<string, unknown>} ctx
|
||||
* @param {string[]} argv
|
||||
* @param {{
|
||||
* cmd: string,
|
||||
* help?: string,
|
||||
* digest: (u8: Uint8Array) => string | Promise<string>
|
||||
* }} opts
|
||||
*/
|
||||
async function bareChecksumRun(ctx, argv, opts) {
|
||||
const cmd = String(opts.cmd || 'checksum')
|
||||
const help =
|
||||
opts.help ||
|
||||
'usage: ' +
|
||||
cmd +
|
||||
' [FILE]...\nWith no FILE, or when FILE is -, read standard input.'
|
||||
const digest = opts.digest
|
||||
const paths = []
|
||||
for (let i = 1; i < argv.length; i++) {
|
||||
const a = argv[i]
|
||||
if (a === '-h' || a === '--help') {
|
||||
ctx.console.log(help)
|
||||
ctx.exitCode = 0
|
||||
return
|
||||
}
|
||||
if (a.startsWith('-') && a !== '-') {
|
||||
ctx.console.error(cmd + ': unsupported option ' + a)
|
||||
ctx.exitCode = 1
|
||||
return
|
||||
}
|
||||
paths.push(a)
|
||||
}
|
||||
const b4 = ctx.b4a
|
||||
async function one(name, buf) {
|
||||
const u8 = buf instanceof Uint8Array ? buf : new Uint8Array(buf)
|
||||
try {
|
||||
const hex = await digest(u8)
|
||||
ctx.console.log(hex + ' ' + name)
|
||||
} catch (e) {
|
||||
ctx.console.error(cmd + ': ' + (e.message || e))
|
||||
ctx.exitCode = 1
|
||||
}
|
||||
}
|
||||
if (!paths.length || (paths.length === 1 && paths[0] === '-')) {
|
||||
await one('-', b4.from(bareStdin(ctx)))
|
||||
return
|
||||
}
|
||||
for (const p of paths) {
|
||||
if (p === '-') {
|
||||
await one('-', b4.from(bareStdin(ctx)))
|
||||
continue
|
||||
}
|
||||
const b = await ctx.vfs.readFile(p)
|
||||
if (!b) {
|
||||
ctx.console.error(cmd + ': ' + p + ': No such file')
|
||||
ctx.exitCode = 1
|
||||
continue
|
||||
}
|
||||
await one(p, b)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* WebCrypto hex digest; throws the same missing-subtle message as the old *sum files.
|
||||
* @param {string} algo
|
||||
* @param {string} missingMsg
|
||||
* @returns {(u8: Uint8Array) => Promise<string>}
|
||||
*/
|
||||
function bareSubtleHexDigest(algo, missingMsg) {
|
||||
return async function (u8) {
|
||||
const subtle = globalThis.crypto?.subtle
|
||||
if (!subtle || typeof subtle.digest !== 'function') {
|
||||
throw new Error(missingMsg)
|
||||
}
|
||||
const hash = await subtle.digest(algo, u8)
|
||||
return bareOsHexEncode(new Uint8Array(hash))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Owner/group name → uid/gid used by chown / chgrp.
|
||||
* @param {string} spec
|
||||
* @param {Record<string, string>} env
|
||||
* @returns {number | null}
|
||||
*/
|
||||
function parseGroupSpec(spec, env) {
|
||||
const s = String(spec).trim()
|
||||
if (!s) return null
|
||||
if (/^\d+$/.test(s)) {
|
||||
const n = Number.parseInt(s, 10)
|
||||
return Number.isFinite(n) ? n : null
|
||||
}
|
||||
const g = (env.GROUP || env.USER || 'guest').trim()
|
||||
if (s === 'root') return 0
|
||||
if (s === 'guest' || s === 'nobody') return 65534
|
||||
if (g && s === g) {
|
||||
const gid = Number.parseInt(String(env.GID ?? '65534'), 10)
|
||||
return Number.isFinite(gid) ? gid : 65534
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* User name / numeric uid used by chown.
|
||||
* @param {string} spec
|
||||
* @param {Record<string, string>} env
|
||||
* @returns {{ uid: number | null, gid: number | null }}
|
||||
*/
|
||||
function parseIdSpec(spec, env) {
|
||||
const s = String(spec).trim()
|
||||
if (!s) return { uid: null, gid: null }
|
||||
if (/^\d+$/.test(s)) {
|
||||
const n = Number.parseInt(s, 10)
|
||||
return { uid: Number.isFinite(n) ? n : null, gid: null }
|
||||
}
|
||||
const u = (env.USER || env.LOGNAME || '').trim()
|
||||
if (s === 'root') return { uid: 0, gid: null }
|
||||
if (s === 'guest' || s === 'nobody') return { uid: 65534, gid: null }
|
||||
if (u && s === u) {
|
||||
const uid = Number.parseInt(String(env.UID ?? '65534'), 10)
|
||||
return { uid: Number.isFinite(uid) ? uid : 65534, gid: null }
|
||||
}
|
||||
return { uid: null, gid: null }
|
||||
}
|
||||
|
||||
/** RFC 1321 MD5 — no Web Crypto; used by md5sum. */
|
||||
function bareMd5DigestBytes(u8) {
|
||||
const n = u8.length
|
||||
@@ -382,50 +508,11 @@ function bareMd5DigestBytes(u8) {
|
||||
}
|
||||
|
||||
async function run(ctx, argv) {
|
||||
const paths = []
|
||||
for (let i = 1; i < argv.length; i++) {
|
||||
const a = argv[i]
|
||||
if (a === '-h' || a === '--help') {
|
||||
ctx.console.log(
|
||||
'usage: md5sum [FILE]...\n' +
|
||||
'With no FILE, or when FILE is -, read standard input. Uses bundled MD5 (no Web Crypto MD5).'
|
||||
)
|
||||
ctx.exitCode = 0
|
||||
return
|
||||
}
|
||||
if (a.startsWith('-') && a !== '-') {
|
||||
ctx.console.error('md5sum: unsupported option ' + a)
|
||||
ctx.exitCode = 1
|
||||
return
|
||||
}
|
||||
paths.push(a)
|
||||
}
|
||||
const b4 = ctx.b4a
|
||||
function one(name, buf) {
|
||||
const u8 = buf instanceof Uint8Array ? buf : new Uint8Array(buf)
|
||||
try {
|
||||
const hex = bareMd5DigestBytes(u8)
|
||||
ctx.console.log(hex + ' ' + name)
|
||||
} catch (e) {
|
||||
ctx.console.error('md5sum: ' + (e.message || e))
|
||||
ctx.exitCode = 1
|
||||
}
|
||||
}
|
||||
if (!paths.length || (paths.length === 1 && paths[0] === '-')) {
|
||||
one('-', b4.from(bareStdin(ctx)))
|
||||
return
|
||||
}
|
||||
for (const p of paths) {
|
||||
if (p === '-') {
|
||||
one('-', b4.from(bareStdin(ctx)))
|
||||
continue
|
||||
}
|
||||
const b = await ctx.vfs.readFile(p)
|
||||
if (!b) {
|
||||
ctx.console.error('md5sum: ' + p + ': No such file')
|
||||
ctx.exitCode = 1
|
||||
continue
|
||||
}
|
||||
one(p, b)
|
||||
}
|
||||
await bareChecksumRun(ctx, argv, {
|
||||
cmd: 'md5sum',
|
||||
help:
|
||||
'usage: md5sum [FILE]...\n' +
|
||||
'With no FILE, or when FILE is -, read standard input. Uses bundled MD5 (no Web Crypto MD5).',
|
||||
digest: (u8) => bareMd5DigestBytes(u8)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -311,31 +311,34 @@ function bareOsHexEncode(u8) {
|
||||
return s
|
||||
}
|
||||
|
||||
async function sha1Hex(u8) {
|
||||
const subtle = globalThis.crypto?.subtle
|
||||
if (!subtle || typeof subtle.digest !== 'function') {
|
||||
throw new Error('crypto.subtle.digest (SHA-1) is not available')
|
||||
}
|
||||
const hash = await subtle.digest('SHA-1', u8)
|
||||
return [...new Uint8Array(hash)]
|
||||
.map((b) => b.toString(16).padStart(2, '0'))
|
||||
.join('')
|
||||
}
|
||||
|
||||
async function run(ctx, argv) {
|
||||
/**
|
||||
* Shared GNU-style checksum FILE / stdin loop used by *sum commands.
|
||||
* @param {Record<string, unknown>} ctx
|
||||
* @param {string[]} argv
|
||||
* @param {{
|
||||
* cmd: string,
|
||||
* help?: string,
|
||||
* digest: (u8: Uint8Array) => string | Promise<string>
|
||||
* }} opts
|
||||
*/
|
||||
async function bareChecksumRun(ctx, argv, opts) {
|
||||
const cmd = String(opts.cmd || 'checksum')
|
||||
const help =
|
||||
opts.help ||
|
||||
'usage: ' +
|
||||
cmd +
|
||||
' [FILE]...\nWith no FILE, or when FILE is -, read standard input.'
|
||||
const digest = opts.digest
|
||||
const paths = []
|
||||
for (let i = 1; i < argv.length; i++) {
|
||||
const a = argv[i]
|
||||
if (a === '-h' || a === '--help') {
|
||||
ctx.console.log(
|
||||
'usage: sha1sum [FILE]...\n' +
|
||||
'With no FILE, or when FILE is -, read standard input.'
|
||||
)
|
||||
ctx.console.log(help)
|
||||
ctx.exitCode = 0
|
||||
return
|
||||
}
|
||||
if (a.startsWith('-') && a !== '-') {
|
||||
ctx.console.error('sha1sum: unsupported option ' + a)
|
||||
ctx.console.error(cmd + ': unsupported option ' + a)
|
||||
ctx.exitCode = 1
|
||||
return
|
||||
}
|
||||
@@ -345,10 +348,10 @@ async function run(ctx, argv) {
|
||||
async function one(name, buf) {
|
||||
const u8 = buf instanceof Uint8Array ? buf : new Uint8Array(buf)
|
||||
try {
|
||||
const hex = await sha1Hex(u8)
|
||||
const hex = await digest(u8)
|
||||
ctx.console.log(hex + ' ' + name)
|
||||
} catch (e) {
|
||||
ctx.console.error('sha1sum: ' + (e.message || e))
|
||||
ctx.console.error(cmd + ': ' + (e.message || e))
|
||||
ctx.exitCode = 1
|
||||
}
|
||||
}
|
||||
@@ -363,10 +366,83 @@ async function run(ctx, argv) {
|
||||
}
|
||||
const b = await ctx.vfs.readFile(p)
|
||||
if (!b) {
|
||||
ctx.console.error('sha1sum: ' + p + ': No such file')
|
||||
ctx.console.error(cmd + ': ' + p + ': No such file')
|
||||
ctx.exitCode = 1
|
||||
continue
|
||||
}
|
||||
await one(p, b)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* WebCrypto hex digest; throws the same missing-subtle message as the old *sum files.
|
||||
* @param {string} algo
|
||||
* @param {string} missingMsg
|
||||
* @returns {(u8: Uint8Array) => Promise<string>}
|
||||
*/
|
||||
function bareSubtleHexDigest(algo, missingMsg) {
|
||||
return async function (u8) {
|
||||
const subtle = globalThis.crypto?.subtle
|
||||
if (!subtle || typeof subtle.digest !== 'function') {
|
||||
throw new Error(missingMsg)
|
||||
}
|
||||
const hash = await subtle.digest(algo, u8)
|
||||
return bareOsHexEncode(new Uint8Array(hash))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Owner/group name → uid/gid used by chown / chgrp.
|
||||
* @param {string} spec
|
||||
* @param {Record<string, string>} env
|
||||
* @returns {number | null}
|
||||
*/
|
||||
function parseGroupSpec(spec, env) {
|
||||
const s = String(spec).trim()
|
||||
if (!s) return null
|
||||
if (/^\d+$/.test(s)) {
|
||||
const n = Number.parseInt(s, 10)
|
||||
return Number.isFinite(n) ? n : null
|
||||
}
|
||||
const g = (env.GROUP || env.USER || 'guest').trim()
|
||||
if (s === 'root') return 0
|
||||
if (s === 'guest' || s === 'nobody') return 65534
|
||||
if (g && s === g) {
|
||||
const gid = Number.parseInt(String(env.GID ?? '65534'), 10)
|
||||
return Number.isFinite(gid) ? gid : 65534
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* User name / numeric uid used by chown.
|
||||
* @param {string} spec
|
||||
* @param {Record<string, string>} env
|
||||
* @returns {{ uid: number | null, gid: number | null }}
|
||||
*/
|
||||
function parseIdSpec(spec, env) {
|
||||
const s = String(spec).trim()
|
||||
if (!s) return { uid: null, gid: null }
|
||||
if (/^\d+$/.test(s)) {
|
||||
const n = Number.parseInt(s, 10)
|
||||
return { uid: Number.isFinite(n) ? n : null, gid: null }
|
||||
}
|
||||
const u = (env.USER || env.LOGNAME || '').trim()
|
||||
if (s === 'root') return { uid: 0, gid: null }
|
||||
if (s === 'guest' || s === 'nobody') return { uid: 65534, gid: null }
|
||||
if (u && s === u) {
|
||||
const uid = Number.parseInt(String(env.UID ?? '65534'), 10)
|
||||
return { uid: Number.isFinite(uid) ? uid : 65534, gid: null }
|
||||
}
|
||||
return { uid: null, gid: null }
|
||||
}
|
||||
|
||||
async function run(ctx, argv) {
|
||||
await bareChecksumRun(ctx, argv, {
|
||||
cmd: 'sha1sum',
|
||||
digest: bareSubtleHexDigest(
|
||||
'SHA-1',
|
||||
'crypto.subtle.digest (SHA-1) is not available'
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -311,6 +311,132 @@ function bareOsHexEncode(u8) {
|
||||
return s
|
||||
}
|
||||
|
||||
/**
|
||||
* Shared GNU-style checksum FILE / stdin loop used by *sum commands.
|
||||
* @param {Record<string, unknown>} ctx
|
||||
* @param {string[]} argv
|
||||
* @param {{
|
||||
* cmd: string,
|
||||
* help?: string,
|
||||
* digest: (u8: Uint8Array) => string | Promise<string>
|
||||
* }} opts
|
||||
*/
|
||||
async function bareChecksumRun(ctx, argv, opts) {
|
||||
const cmd = String(opts.cmd || 'checksum')
|
||||
const help =
|
||||
opts.help ||
|
||||
'usage: ' +
|
||||
cmd +
|
||||
' [FILE]...\nWith no FILE, or when FILE is -, read standard input.'
|
||||
const digest = opts.digest
|
||||
const paths = []
|
||||
for (let i = 1; i < argv.length; i++) {
|
||||
const a = argv[i]
|
||||
if (a === '-h' || a === '--help') {
|
||||
ctx.console.log(help)
|
||||
ctx.exitCode = 0
|
||||
return
|
||||
}
|
||||
if (a.startsWith('-') && a !== '-') {
|
||||
ctx.console.error(cmd + ': unsupported option ' + a)
|
||||
ctx.exitCode = 1
|
||||
return
|
||||
}
|
||||
paths.push(a)
|
||||
}
|
||||
const b4 = ctx.b4a
|
||||
async function one(name, buf) {
|
||||
const u8 = buf instanceof Uint8Array ? buf : new Uint8Array(buf)
|
||||
try {
|
||||
const hex = await digest(u8)
|
||||
ctx.console.log(hex + ' ' + name)
|
||||
} catch (e) {
|
||||
ctx.console.error(cmd + ': ' + (e.message || e))
|
||||
ctx.exitCode = 1
|
||||
}
|
||||
}
|
||||
if (!paths.length || (paths.length === 1 && paths[0] === '-')) {
|
||||
await one('-', b4.from(bareStdin(ctx)))
|
||||
return
|
||||
}
|
||||
for (const p of paths) {
|
||||
if (p === '-') {
|
||||
await one('-', b4.from(bareStdin(ctx)))
|
||||
continue
|
||||
}
|
||||
const b = await ctx.vfs.readFile(p)
|
||||
if (!b) {
|
||||
ctx.console.error(cmd + ': ' + p + ': No such file')
|
||||
ctx.exitCode = 1
|
||||
continue
|
||||
}
|
||||
await one(p, b)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* WebCrypto hex digest; throws the same missing-subtle message as the old *sum files.
|
||||
* @param {string} algo
|
||||
* @param {string} missingMsg
|
||||
* @returns {(u8: Uint8Array) => Promise<string>}
|
||||
*/
|
||||
function bareSubtleHexDigest(algo, missingMsg) {
|
||||
return async function (u8) {
|
||||
const subtle = globalThis.crypto?.subtle
|
||||
if (!subtle || typeof subtle.digest !== 'function') {
|
||||
throw new Error(missingMsg)
|
||||
}
|
||||
const hash = await subtle.digest(algo, u8)
|
||||
return bareOsHexEncode(new Uint8Array(hash))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Owner/group name → uid/gid used by chown / chgrp.
|
||||
* @param {string} spec
|
||||
* @param {Record<string, string>} env
|
||||
* @returns {number | null}
|
||||
*/
|
||||
function parseGroupSpec(spec, env) {
|
||||
const s = String(spec).trim()
|
||||
if (!s) return null
|
||||
if (/^\d+$/.test(s)) {
|
||||
const n = Number.parseInt(s, 10)
|
||||
return Number.isFinite(n) ? n : null
|
||||
}
|
||||
const g = (env.GROUP || env.USER || 'guest').trim()
|
||||
if (s === 'root') return 0
|
||||
if (s === 'guest' || s === 'nobody') return 65534
|
||||
if (g && s === g) {
|
||||
const gid = Number.parseInt(String(env.GID ?? '65534'), 10)
|
||||
return Number.isFinite(gid) ? gid : 65534
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* User name / numeric uid used by chown.
|
||||
* @param {string} spec
|
||||
* @param {Record<string, string>} env
|
||||
* @returns {{ uid: number | null, gid: number | null }}
|
||||
*/
|
||||
function parseIdSpec(spec, env) {
|
||||
const s = String(spec).trim()
|
||||
if (!s) return { uid: null, gid: null }
|
||||
if (/^\d+$/.test(s)) {
|
||||
const n = Number.parseInt(s, 10)
|
||||
return { uid: Number.isFinite(n) ? n : null, gid: null }
|
||||
}
|
||||
const u = (env.USER || env.LOGNAME || '').trim()
|
||||
if (s === 'root') return { uid: 0, gid: null }
|
||||
if (s === 'guest' || s === 'nobody') return { uid: 65534, gid: null }
|
||||
if (u && s === u) {
|
||||
const uid = Number.parseInt(String(env.UID ?? '65534'), 10)
|
||||
return { uid: Number.isFinite(uid) ? uid : 65534, gid: null }
|
||||
}
|
||||
return { uid: null, gid: null }
|
||||
}
|
||||
|
||||
/**
|
||||
* SHA-224 (FIPS 180-4) — same compression as SHA-256, distinct IV, output first 224 bits.
|
||||
* Bundled because many runtimes (incl. Node Web Crypto) omit SHA-224 in subtle.digest.
|
||||
@@ -410,50 +536,8 @@ function bareSha224DigestBytes(u8) {
|
||||
* Uses bundled SHA-224 (many runtimes omit SHA-224 in crypto.subtle.digest).
|
||||
*/
|
||||
async function run(ctx, argv) {
|
||||
const paths = []
|
||||
for (let i = 1; i < argv.length; i++) {
|
||||
const a = argv[i]
|
||||
if (a === '-h' || a === '--help') {
|
||||
ctx.console.log(
|
||||
'usage: sha224sum [FILE]...\n' +
|
||||
'With no FILE, or when FILE is -, read standard input.'
|
||||
)
|
||||
ctx.exitCode = 0
|
||||
return
|
||||
}
|
||||
if (a.startsWith('-') && a !== '-') {
|
||||
ctx.console.error('sha224sum: unsupported option ' + a)
|
||||
ctx.exitCode = 1
|
||||
return
|
||||
}
|
||||
paths.push(a)
|
||||
}
|
||||
const b4 = ctx.b4a
|
||||
function one(name, buf) {
|
||||
const u8 = buf instanceof Uint8Array ? buf : new Uint8Array(buf)
|
||||
try {
|
||||
const hex = bareSha224DigestBytes(u8)
|
||||
ctx.console.log(hex + ' ' + name)
|
||||
} catch (e) {
|
||||
ctx.console.error('sha224sum: ' + (e.message || e))
|
||||
ctx.exitCode = 1
|
||||
}
|
||||
}
|
||||
if (!paths.length || (paths.length === 1 && paths[0] === '-')) {
|
||||
one('-', b4.from(bareStdin(ctx)))
|
||||
return
|
||||
}
|
||||
for (const p of paths) {
|
||||
if (p === '-') {
|
||||
one('-', b4.from(bareStdin(ctx)))
|
||||
continue
|
||||
}
|
||||
const b = await ctx.vfs.readFile(p)
|
||||
if (!b) {
|
||||
ctx.console.error('sha224sum: ' + p + ': No such file')
|
||||
ctx.exitCode = 1
|
||||
continue
|
||||
}
|
||||
one(p, b)
|
||||
}
|
||||
await bareChecksumRun(ctx, argv, {
|
||||
cmd: 'sha224sum',
|
||||
digest: (u8) => bareSha224DigestBytes(u8)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -312,33 +312,33 @@ function bareOsHexEncode(u8) {
|
||||
}
|
||||
|
||||
/**
|
||||
* sha256sum — compute SHA-256 checksums (hex), GNU-like output line.
|
||||
* Shared GNU-style checksum FILE / stdin loop used by *sum commands.
|
||||
* @param {Record<string, unknown>} ctx
|
||||
* @param {string[]} argv
|
||||
* @param {{
|
||||
* cmd: string,
|
||||
* help?: string,
|
||||
* digest: (u8: Uint8Array) => string | Promise<string>
|
||||
* }} opts
|
||||
*/
|
||||
async function sha256Hex(u8) {
|
||||
const subtle = globalThis.crypto?.subtle
|
||||
if (!subtle || typeof subtle.digest !== 'function') {
|
||||
throw new Error('crypto.subtle.digest (SHA-256) is not available')
|
||||
}
|
||||
const hash = await subtle.digest('SHA-256', u8)
|
||||
return [...new Uint8Array(hash)]
|
||||
.map((b) => b.toString(16).padStart(2, '0'))
|
||||
.join('')
|
||||
}
|
||||
|
||||
async function run(ctx, argv) {
|
||||
async function bareChecksumRun(ctx, argv, opts) {
|
||||
const cmd = String(opts.cmd || 'checksum')
|
||||
const help =
|
||||
opts.help ||
|
||||
'usage: ' +
|
||||
cmd +
|
||||
' [FILE]...\nWith no FILE, or when FILE is -, read standard input.'
|
||||
const digest = opts.digest
|
||||
const paths = []
|
||||
for (let i = 1; i < argv.length; i++) {
|
||||
const a = argv[i]
|
||||
if (a === '-h' || a === '--help') {
|
||||
ctx.console.log(
|
||||
'usage: sha256sum [FILE]...\n' +
|
||||
'With no FILE, or when FILE is -, read standard input.'
|
||||
)
|
||||
ctx.console.log(help)
|
||||
ctx.exitCode = 0
|
||||
return
|
||||
}
|
||||
if (a.startsWith('-') && a !== '-') {
|
||||
ctx.console.error('sha256sum: unsupported option ' + a)
|
||||
ctx.console.error(cmd + ': unsupported option ' + a)
|
||||
ctx.exitCode = 1
|
||||
return
|
||||
}
|
||||
@@ -348,16 +348,15 @@ async function run(ctx, argv) {
|
||||
async function one(name, buf) {
|
||||
const u8 = buf instanceof Uint8Array ? buf : new Uint8Array(buf)
|
||||
try {
|
||||
const hex = await sha256Hex(u8)
|
||||
const hex = await digest(u8)
|
||||
ctx.console.log(hex + ' ' + name)
|
||||
} catch (e) {
|
||||
ctx.console.error('sha256sum: ' + (e.message || e))
|
||||
ctx.console.error(cmd + ': ' + (e.message || e))
|
||||
ctx.exitCode = 1
|
||||
}
|
||||
}
|
||||
if (!paths.length || (paths.length === 1 && paths[0] === '-')) {
|
||||
const buf = b4.from(bareStdin(ctx))
|
||||
await one('-', buf)
|
||||
await one('-', b4.from(bareStdin(ctx)))
|
||||
return
|
||||
}
|
||||
for (const p of paths) {
|
||||
@@ -367,10 +366,86 @@ async function run(ctx, argv) {
|
||||
}
|
||||
const b = await ctx.vfs.readFile(p)
|
||||
if (!b) {
|
||||
ctx.console.error('sha256sum: ' + p + ': No such file')
|
||||
ctx.console.error(cmd + ': ' + p + ': No such file')
|
||||
ctx.exitCode = 1
|
||||
continue
|
||||
}
|
||||
await one(p, b)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* WebCrypto hex digest; throws the same missing-subtle message as the old *sum files.
|
||||
* @param {string} algo
|
||||
* @param {string} missingMsg
|
||||
* @returns {(u8: Uint8Array) => Promise<string>}
|
||||
*/
|
||||
function bareSubtleHexDigest(algo, missingMsg) {
|
||||
return async function (u8) {
|
||||
const subtle = globalThis.crypto?.subtle
|
||||
if (!subtle || typeof subtle.digest !== 'function') {
|
||||
throw new Error(missingMsg)
|
||||
}
|
||||
const hash = await subtle.digest(algo, u8)
|
||||
return bareOsHexEncode(new Uint8Array(hash))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Owner/group name → uid/gid used by chown / chgrp.
|
||||
* @param {string} spec
|
||||
* @param {Record<string, string>} env
|
||||
* @returns {number | null}
|
||||
*/
|
||||
function parseGroupSpec(spec, env) {
|
||||
const s = String(spec).trim()
|
||||
if (!s) return null
|
||||
if (/^\d+$/.test(s)) {
|
||||
const n = Number.parseInt(s, 10)
|
||||
return Number.isFinite(n) ? n : null
|
||||
}
|
||||
const g = (env.GROUP || env.USER || 'guest').trim()
|
||||
if (s === 'root') return 0
|
||||
if (s === 'guest' || s === 'nobody') return 65534
|
||||
if (g && s === g) {
|
||||
const gid = Number.parseInt(String(env.GID ?? '65534'), 10)
|
||||
return Number.isFinite(gid) ? gid : 65534
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* User name / numeric uid used by chown.
|
||||
* @param {string} spec
|
||||
* @param {Record<string, string>} env
|
||||
* @returns {{ uid: number | null, gid: number | null }}
|
||||
*/
|
||||
function parseIdSpec(spec, env) {
|
||||
const s = String(spec).trim()
|
||||
if (!s) return { uid: null, gid: null }
|
||||
if (/^\d+$/.test(s)) {
|
||||
const n = Number.parseInt(s, 10)
|
||||
return { uid: Number.isFinite(n) ? n : null, gid: null }
|
||||
}
|
||||
const u = (env.USER || env.LOGNAME || '').trim()
|
||||
if (s === 'root') return { uid: 0, gid: null }
|
||||
if (s === 'guest' || s === 'nobody') return { uid: 65534, gid: null }
|
||||
if (u && s === u) {
|
||||
const uid = Number.parseInt(String(env.UID ?? '65534'), 10)
|
||||
return { uid: Number.isFinite(uid) ? uid : 65534, gid: null }
|
||||
}
|
||||
return { uid: null, gid: null }
|
||||
}
|
||||
|
||||
/**
|
||||
* sha256sum — compute SHA-256 checksums (hex), GNU-like output line.
|
||||
*/
|
||||
async function run(ctx, argv) {
|
||||
await bareChecksumRun(ctx, argv, {
|
||||
cmd: 'sha256sum',
|
||||
digest: bareSubtleHexDigest(
|
||||
'SHA-256',
|
||||
'crypto.subtle.digest (SHA-256) is not available'
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -311,31 +311,34 @@ function bareOsHexEncode(u8) {
|
||||
return s
|
||||
}
|
||||
|
||||
async function sha384Hex(u8) {
|
||||
const subtle = globalThis.crypto?.subtle
|
||||
if (!subtle || typeof subtle.digest !== 'function') {
|
||||
throw new Error('crypto.subtle.digest (SHA-384) is not available')
|
||||
}
|
||||
const hash = await subtle.digest('SHA-384', u8)
|
||||
return [...new Uint8Array(hash)]
|
||||
.map((b) => b.toString(16).padStart(2, '0'))
|
||||
.join('')
|
||||
}
|
||||
|
||||
async function run(ctx, argv) {
|
||||
/**
|
||||
* Shared GNU-style checksum FILE / stdin loop used by *sum commands.
|
||||
* @param {Record<string, unknown>} ctx
|
||||
* @param {string[]} argv
|
||||
* @param {{
|
||||
* cmd: string,
|
||||
* help?: string,
|
||||
* digest: (u8: Uint8Array) => string | Promise<string>
|
||||
* }} opts
|
||||
*/
|
||||
async function bareChecksumRun(ctx, argv, opts) {
|
||||
const cmd = String(opts.cmd || 'checksum')
|
||||
const help =
|
||||
opts.help ||
|
||||
'usage: ' +
|
||||
cmd +
|
||||
' [FILE]...\nWith no FILE, or when FILE is -, read standard input.'
|
||||
const digest = opts.digest
|
||||
const paths = []
|
||||
for (let i = 1; i < argv.length; i++) {
|
||||
const a = argv[i]
|
||||
if (a === '-h' || a === '--help') {
|
||||
ctx.console.log(
|
||||
'usage: sha384sum [FILE]...\n' +
|
||||
'With no FILE, or when FILE is -, read standard input.'
|
||||
)
|
||||
ctx.console.log(help)
|
||||
ctx.exitCode = 0
|
||||
return
|
||||
}
|
||||
if (a.startsWith('-') && a !== '-') {
|
||||
ctx.console.error('sha384sum: unsupported option ' + a)
|
||||
ctx.console.error(cmd + ': unsupported option ' + a)
|
||||
ctx.exitCode = 1
|
||||
return
|
||||
}
|
||||
@@ -345,10 +348,10 @@ async function run(ctx, argv) {
|
||||
async function one(name, buf) {
|
||||
const u8 = buf instanceof Uint8Array ? buf : new Uint8Array(buf)
|
||||
try {
|
||||
const hex = await sha384Hex(u8)
|
||||
const hex = await digest(u8)
|
||||
ctx.console.log(hex + ' ' + name)
|
||||
} catch (e) {
|
||||
ctx.console.error('sha384sum: ' + (e.message || e))
|
||||
ctx.console.error(cmd + ': ' + (e.message || e))
|
||||
ctx.exitCode = 1
|
||||
}
|
||||
}
|
||||
@@ -363,10 +366,83 @@ async function run(ctx, argv) {
|
||||
}
|
||||
const b = await ctx.vfs.readFile(p)
|
||||
if (!b) {
|
||||
ctx.console.error('sha384sum: ' + p + ': No such file')
|
||||
ctx.console.error(cmd + ': ' + p + ': No such file')
|
||||
ctx.exitCode = 1
|
||||
continue
|
||||
}
|
||||
await one(p, b)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* WebCrypto hex digest; throws the same missing-subtle message as the old *sum files.
|
||||
* @param {string} algo
|
||||
* @param {string} missingMsg
|
||||
* @returns {(u8: Uint8Array) => Promise<string>}
|
||||
*/
|
||||
function bareSubtleHexDigest(algo, missingMsg) {
|
||||
return async function (u8) {
|
||||
const subtle = globalThis.crypto?.subtle
|
||||
if (!subtle || typeof subtle.digest !== 'function') {
|
||||
throw new Error(missingMsg)
|
||||
}
|
||||
const hash = await subtle.digest(algo, u8)
|
||||
return bareOsHexEncode(new Uint8Array(hash))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Owner/group name → uid/gid used by chown / chgrp.
|
||||
* @param {string} spec
|
||||
* @param {Record<string, string>} env
|
||||
* @returns {number | null}
|
||||
*/
|
||||
function parseGroupSpec(spec, env) {
|
||||
const s = String(spec).trim()
|
||||
if (!s) return null
|
||||
if (/^\d+$/.test(s)) {
|
||||
const n = Number.parseInt(s, 10)
|
||||
return Number.isFinite(n) ? n : null
|
||||
}
|
||||
const g = (env.GROUP || env.USER || 'guest').trim()
|
||||
if (s === 'root') return 0
|
||||
if (s === 'guest' || s === 'nobody') return 65534
|
||||
if (g && s === g) {
|
||||
const gid = Number.parseInt(String(env.GID ?? '65534'), 10)
|
||||
return Number.isFinite(gid) ? gid : 65534
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* User name / numeric uid used by chown.
|
||||
* @param {string} spec
|
||||
* @param {Record<string, string>} env
|
||||
* @returns {{ uid: number | null, gid: number | null }}
|
||||
*/
|
||||
function parseIdSpec(spec, env) {
|
||||
const s = String(spec).trim()
|
||||
if (!s) return { uid: null, gid: null }
|
||||
if (/^\d+$/.test(s)) {
|
||||
const n = Number.parseInt(s, 10)
|
||||
return { uid: Number.isFinite(n) ? n : null, gid: null }
|
||||
}
|
||||
const u = (env.USER || env.LOGNAME || '').trim()
|
||||
if (s === 'root') return { uid: 0, gid: null }
|
||||
if (s === 'guest' || s === 'nobody') return { uid: 65534, gid: null }
|
||||
if (u && s === u) {
|
||||
const uid = Number.parseInt(String(env.UID ?? '65534'), 10)
|
||||
return { uid: Number.isFinite(uid) ? uid : 65534, gid: null }
|
||||
}
|
||||
return { uid: null, gid: null }
|
||||
}
|
||||
|
||||
async function run(ctx, argv) {
|
||||
await bareChecksumRun(ctx, argv, {
|
||||
cmd: 'sha384sum',
|
||||
digest: bareSubtleHexDigest(
|
||||
'SHA-384',
|
||||
'crypto.subtle.digest (SHA-384) is not available'
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -311,31 +311,34 @@ function bareOsHexEncode(u8) {
|
||||
return s
|
||||
}
|
||||
|
||||
async function sha512Hex(u8) {
|
||||
const subtle = globalThis.crypto?.subtle
|
||||
if (!subtle || typeof subtle.digest !== 'function') {
|
||||
throw new Error('crypto.subtle.digest (SHA-512) is not available')
|
||||
}
|
||||
const hash = await subtle.digest('SHA-512', u8)
|
||||
return [...new Uint8Array(hash)]
|
||||
.map((b) => b.toString(16).padStart(2, '0'))
|
||||
.join('')
|
||||
}
|
||||
|
||||
async function run(ctx, argv) {
|
||||
/**
|
||||
* Shared GNU-style checksum FILE / stdin loop used by *sum commands.
|
||||
* @param {Record<string, unknown>} ctx
|
||||
* @param {string[]} argv
|
||||
* @param {{
|
||||
* cmd: string,
|
||||
* help?: string,
|
||||
* digest: (u8: Uint8Array) => string | Promise<string>
|
||||
* }} opts
|
||||
*/
|
||||
async function bareChecksumRun(ctx, argv, opts) {
|
||||
const cmd = String(opts.cmd || 'checksum')
|
||||
const help =
|
||||
opts.help ||
|
||||
'usage: ' +
|
||||
cmd +
|
||||
' [FILE]...\nWith no FILE, or when FILE is -, read standard input.'
|
||||
const digest = opts.digest
|
||||
const paths = []
|
||||
for (let i = 1; i < argv.length; i++) {
|
||||
const a = argv[i]
|
||||
if (a === '-h' || a === '--help') {
|
||||
ctx.console.log(
|
||||
'usage: sha512sum [FILE]...\n' +
|
||||
'With no FILE, or when FILE is -, read standard input.'
|
||||
)
|
||||
ctx.console.log(help)
|
||||
ctx.exitCode = 0
|
||||
return
|
||||
}
|
||||
if (a.startsWith('-') && a !== '-') {
|
||||
ctx.console.error('sha512sum: unsupported option ' + a)
|
||||
ctx.console.error(cmd + ': unsupported option ' + a)
|
||||
ctx.exitCode = 1
|
||||
return
|
||||
}
|
||||
@@ -345,10 +348,10 @@ async function run(ctx, argv) {
|
||||
async function one(name, buf) {
|
||||
const u8 = buf instanceof Uint8Array ? buf : new Uint8Array(buf)
|
||||
try {
|
||||
const hex = await sha512Hex(u8)
|
||||
const hex = await digest(u8)
|
||||
ctx.console.log(hex + ' ' + name)
|
||||
} catch (e) {
|
||||
ctx.console.error('sha512sum: ' + (e.message || e))
|
||||
ctx.console.error(cmd + ': ' + (e.message || e))
|
||||
ctx.exitCode = 1
|
||||
}
|
||||
}
|
||||
@@ -363,10 +366,83 @@ async function run(ctx, argv) {
|
||||
}
|
||||
const b = await ctx.vfs.readFile(p)
|
||||
if (!b) {
|
||||
ctx.console.error('sha512sum: ' + p + ': No such file')
|
||||
ctx.console.error(cmd + ': ' + p + ': No such file')
|
||||
ctx.exitCode = 1
|
||||
continue
|
||||
}
|
||||
await one(p, b)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* WebCrypto hex digest; throws the same missing-subtle message as the old *sum files.
|
||||
* @param {string} algo
|
||||
* @param {string} missingMsg
|
||||
* @returns {(u8: Uint8Array) => Promise<string>}
|
||||
*/
|
||||
function bareSubtleHexDigest(algo, missingMsg) {
|
||||
return async function (u8) {
|
||||
const subtle = globalThis.crypto?.subtle
|
||||
if (!subtle || typeof subtle.digest !== 'function') {
|
||||
throw new Error(missingMsg)
|
||||
}
|
||||
const hash = await subtle.digest(algo, u8)
|
||||
return bareOsHexEncode(new Uint8Array(hash))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Owner/group name → uid/gid used by chown / chgrp.
|
||||
* @param {string} spec
|
||||
* @param {Record<string, string>} env
|
||||
* @returns {number | null}
|
||||
*/
|
||||
function parseGroupSpec(spec, env) {
|
||||
const s = String(spec).trim()
|
||||
if (!s) return null
|
||||
if (/^\d+$/.test(s)) {
|
||||
const n = Number.parseInt(s, 10)
|
||||
return Number.isFinite(n) ? n : null
|
||||
}
|
||||
const g = (env.GROUP || env.USER || 'guest').trim()
|
||||
if (s === 'root') return 0
|
||||
if (s === 'guest' || s === 'nobody') return 65534
|
||||
if (g && s === g) {
|
||||
const gid = Number.parseInt(String(env.GID ?? '65534'), 10)
|
||||
return Number.isFinite(gid) ? gid : 65534
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* User name / numeric uid used by chown.
|
||||
* @param {string} spec
|
||||
* @param {Record<string, string>} env
|
||||
* @returns {{ uid: number | null, gid: number | null }}
|
||||
*/
|
||||
function parseIdSpec(spec, env) {
|
||||
const s = String(spec).trim()
|
||||
if (!s) return { uid: null, gid: null }
|
||||
if (/^\d+$/.test(s)) {
|
||||
const n = Number.parseInt(s, 10)
|
||||
return { uid: Number.isFinite(n) ? n : null, gid: null }
|
||||
}
|
||||
const u = (env.USER || env.LOGNAME || '').trim()
|
||||
if (s === 'root') return { uid: 0, gid: null }
|
||||
if (s === 'guest' || s === 'nobody') return { uid: 65534, gid: null }
|
||||
if (u && s === u) {
|
||||
const uid = Number.parseInt(String(env.UID ?? '65534'), 10)
|
||||
return { uid: Number.isFinite(uid) ? uid : 65534, gid: null }
|
||||
}
|
||||
return { uid: null, gid: null }
|
||||
}
|
||||
|
||||
async function run(ctx, argv) {
|
||||
await bareChecksumRun(ctx, argv, {
|
||||
cmd: 'sha512sum',
|
||||
digest: bareSubtleHexDigest(
|
||||
'SHA-512',
|
||||
'crypto.subtle.digest (SHA-512) is not available'
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -311,6 +311,132 @@ function bareOsHexEncode(u8) {
|
||||
return s
|
||||
}
|
||||
|
||||
/**
|
||||
* Shared GNU-style checksum FILE / stdin loop used by *sum commands.
|
||||
* @param {Record<string, unknown>} ctx
|
||||
* @param {string[]} argv
|
||||
* @param {{
|
||||
* cmd: string,
|
||||
* help?: string,
|
||||
* digest: (u8: Uint8Array) => string | Promise<string>
|
||||
* }} opts
|
||||
*/
|
||||
async function bareChecksumRun(ctx, argv, opts) {
|
||||
const cmd = String(opts.cmd || 'checksum')
|
||||
const help =
|
||||
opts.help ||
|
||||
'usage: ' +
|
||||
cmd +
|
||||
' [FILE]...\nWith no FILE, or when FILE is -, read standard input.'
|
||||
const digest = opts.digest
|
||||
const paths = []
|
||||
for (let i = 1; i < argv.length; i++) {
|
||||
const a = argv[i]
|
||||
if (a === '-h' || a === '--help') {
|
||||
ctx.console.log(help)
|
||||
ctx.exitCode = 0
|
||||
return
|
||||
}
|
||||
if (a.startsWith('-') && a !== '-') {
|
||||
ctx.console.error(cmd + ': unsupported option ' + a)
|
||||
ctx.exitCode = 1
|
||||
return
|
||||
}
|
||||
paths.push(a)
|
||||
}
|
||||
const b4 = ctx.b4a
|
||||
async function one(name, buf) {
|
||||
const u8 = buf instanceof Uint8Array ? buf : new Uint8Array(buf)
|
||||
try {
|
||||
const hex = await digest(u8)
|
||||
ctx.console.log(hex + ' ' + name)
|
||||
} catch (e) {
|
||||
ctx.console.error(cmd + ': ' + (e.message || e))
|
||||
ctx.exitCode = 1
|
||||
}
|
||||
}
|
||||
if (!paths.length || (paths.length === 1 && paths[0] === '-')) {
|
||||
await one('-', b4.from(bareStdin(ctx)))
|
||||
return
|
||||
}
|
||||
for (const p of paths) {
|
||||
if (p === '-') {
|
||||
await one('-', b4.from(bareStdin(ctx)))
|
||||
continue
|
||||
}
|
||||
const b = await ctx.vfs.readFile(p)
|
||||
if (!b) {
|
||||
ctx.console.error(cmd + ': ' + p + ': No such file')
|
||||
ctx.exitCode = 1
|
||||
continue
|
||||
}
|
||||
await one(p, b)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* WebCrypto hex digest; throws the same missing-subtle message as the old *sum files.
|
||||
* @param {string} algo
|
||||
* @param {string} missingMsg
|
||||
* @returns {(u8: Uint8Array) => Promise<string>}
|
||||
*/
|
||||
function bareSubtleHexDigest(algo, missingMsg) {
|
||||
return async function (u8) {
|
||||
const subtle = globalThis.crypto?.subtle
|
||||
if (!subtle || typeof subtle.digest !== 'function') {
|
||||
throw new Error(missingMsg)
|
||||
}
|
||||
const hash = await subtle.digest(algo, u8)
|
||||
return bareOsHexEncode(new Uint8Array(hash))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Owner/group name → uid/gid used by chown / chgrp.
|
||||
* @param {string} spec
|
||||
* @param {Record<string, string>} env
|
||||
* @returns {number | null}
|
||||
*/
|
||||
function parseGroupSpec(spec, env) {
|
||||
const s = String(spec).trim()
|
||||
if (!s) return null
|
||||
if (/^\d+$/.test(s)) {
|
||||
const n = Number.parseInt(s, 10)
|
||||
return Number.isFinite(n) ? n : null
|
||||
}
|
||||
const g = (env.GROUP || env.USER || 'guest').trim()
|
||||
if (s === 'root') return 0
|
||||
if (s === 'guest' || s === 'nobody') return 65534
|
||||
if (g && s === g) {
|
||||
const gid = Number.parseInt(String(env.GID ?? '65534'), 10)
|
||||
return Number.isFinite(gid) ? gid : 65534
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* User name / numeric uid used by chown.
|
||||
* @param {string} spec
|
||||
* @param {Record<string, string>} env
|
||||
* @returns {{ uid: number | null, gid: number | null }}
|
||||
*/
|
||||
function parseIdSpec(spec, env) {
|
||||
const s = String(spec).trim()
|
||||
if (!s) return { uid: null, gid: null }
|
||||
if (/^\d+$/.test(s)) {
|
||||
const n = Number.parseInt(s, 10)
|
||||
return { uid: Number.isFinite(n) ? n : null, gid: null }
|
||||
}
|
||||
const u = (env.USER || env.LOGNAME || '').trim()
|
||||
if (s === 'root') return { uid: 0, gid: null }
|
||||
if (s === 'guest' || s === 'nobody') return { uid: 65534, gid: null }
|
||||
if (u && s === u) {
|
||||
const uid = Number.parseInt(String(env.UID ?? '65534'), 10)
|
||||
return { uid: Number.isFinite(uid) ? uid : 65534, gid: null }
|
||||
}
|
||||
return { uid: null, gid: null }
|
||||
}
|
||||
|
||||
async function run(ctx, argv) {
|
||||
for (let i = 1; i < argv.length; i++) {
|
||||
if (argv[i] === '-h' || argv[i] === '--help') {
|
||||
@@ -323,3 +449,4 @@ async function run(ctx, argv) {
|
||||
const msg = argv.slice(1).join(' ') || 'y'
|
||||
const cap = bareOsEnvInt(ctx, 'BARE_OS_YES_MAX_LINES', 50000, 1, 200000)
|
||||
for (let n = 0; n < cap; n++) ctx.console.log(msg)
|
||||
}
|
||||
|
||||
@@ -1,15 +1,7 @@
|
||||
/**
|
||||
* Corestore 7.11+ constructor extras used by the seeder host store.
|
||||
* `treeCache` forwards to Hypercore default storage (proof/tree node cache).
|
||||
* Re-export shared Corestore ctor extras (single source: repo `lib/`).
|
||||
*/
|
||||
export const BARE_OS_CORESTORE_TREE_CACHE = { maxSize: 8192 }
|
||||
|
||||
/**
|
||||
* @param {Record<string, unknown>} [extra]
|
||||
*/
|
||||
export function bareOsCorestoreConstructOpts(extra) {
|
||||
return {
|
||||
treeCache: BARE_OS_CORESTORE_TREE_CACHE,
|
||||
...(extra && typeof extra === 'object' ? extra : {})
|
||||
}
|
||||
}
|
||||
export {
|
||||
BARE_OS_CORESTORE_TREE_CACHE,
|
||||
bareOsCorestoreConstructOpts
|
||||
} from '../../../lib/bare-os-corestore-opts.mjs'
|
||||
|
||||
Reference in New Issue
Block a user