184 lines
4.8 KiB
Plaintext
184 lines
4.8 KiB
Plaintext
/* BARE_OS_BIN_API 1.0.0 — bump when staged /bin script semantics change (see developer guide). */
|
|
/** Shared helpers for drive-resident /bin scripts (prepended before each command). */
|
|
function bareStdin(ctx) {
|
|
return typeof ctx.shellStdin === 'string' ? ctx.shellStdin : ''
|
|
}
|
|
|
|
/** @param {number} mode @param {'file' | 'directory' | 'symlink'} type */
|
|
function bareFormatModeString(mode, type) {
|
|
const typeChar =
|
|
type === 'directory' ? 'd' : type === 'symlink' ? 'l' : '-'
|
|
const perm = mode & 0o777
|
|
const r = (bit) => (perm & bit ? 'r' : '-')
|
|
const w = (bit) => (perm & bit ? 'w' : '-')
|
|
const x = (bit) => (perm & bit ? 'x' : '-')
|
|
return (
|
|
typeChar +
|
|
r(0o400) +
|
|
w(0o200) +
|
|
x(0o100) +
|
|
r(0o040) +
|
|
w(0o020) +
|
|
x(0o010) +
|
|
r(0o004) +
|
|
w(0o002) +
|
|
x(0o001)
|
|
)
|
|
}
|
|
|
|
/** @param {number} mtimeMs @param {number} [nowMs] */
|
|
function bareFormatLsMtime(mtimeMs, nowMs) {
|
|
const now = nowMs != null ? nowMs : Date.now()
|
|
const d = new Date(mtimeMs)
|
|
const months = [
|
|
'Jan',
|
|
'Feb',
|
|
'Mar',
|
|
'Apr',
|
|
'May',
|
|
'Jun',
|
|
'Jul',
|
|
'Aug',
|
|
'Sep',
|
|
'Oct',
|
|
'Nov',
|
|
'Dec'
|
|
]
|
|
const mon = months[d.getMonth()]
|
|
const day = String(d.getDate()).padStart(2, ' ')
|
|
const sixMo = 180 * 24 * 3600 * 1000
|
|
if (Math.abs(now - mtimeMs) > sixMo) {
|
|
const yr = String(d.getFullYear()).padStart(4, ' ')
|
|
return mon + ' ' + day + ' ' + yr
|
|
}
|
|
const hh = String(d.getHours()).padStart(2, '0')
|
|
const mm = String(d.getMinutes()).padStart(2, '0')
|
|
return mon + ' ' + day + ' ' + hh + ':' + mm
|
|
}
|
|
|
|
/** @param {number} size */
|
|
function barePosixBlocks(size) {
|
|
return Math.ceil(Number(size) / 512) || 0
|
|
}
|
|
|
|
async function run(ctx, argv) {
|
|
const vfs = ctx.vfs
|
|
let showAll = false
|
|
let longFmt = false
|
|
const paths = []
|
|
for (let i = 1; i < argv.length; i++) {
|
|
const a = argv[i]
|
|
if (a === '--') {
|
|
paths.push(...argv.slice(i + 1))
|
|
break
|
|
}
|
|
if (a.startsWith('-') && a.length > 1) {
|
|
for (let j = 1; j < a.length; j++) {
|
|
const c = a[j]
|
|
if (c === 'a') showAll = true
|
|
else if (c === 'l') longFmt = true
|
|
else if (c === '1') longFmt = false
|
|
}
|
|
continue
|
|
}
|
|
paths.push(a)
|
|
}
|
|
const targets = paths.length ? paths : ['.']
|
|
|
|
for (const t of targets) {
|
|
if (targets.length > 1) ctx.console.log(t + ':')
|
|
let names
|
|
/** @type {string | null} */
|
|
let singleEntryPath = null
|
|
try {
|
|
const stT = await vfs.lstat(t)
|
|
if (stT && stT.type !== 'directory') {
|
|
const leaf = t
|
|
.replace(/\/+$/, '')
|
|
.split('/')
|
|
.filter(Boolean)
|
|
.pop()
|
|
names = [leaf || t]
|
|
singleEntryPath = t
|
|
} else {
|
|
names = await vfs.readdir(t)
|
|
}
|
|
} catch (e) {
|
|
ctx.console.error('ls: cannot access ' + t + ': ' + (e.message || e))
|
|
continue
|
|
}
|
|
if (!showAll) names = names.filter((n) => !n.startsWith('.'))
|
|
if (!longFmt) {
|
|
ctx.console.log(names.join(' '))
|
|
} else {
|
|
let totalBlocks = 0
|
|
const rows = []
|
|
for (const n of names) {
|
|
const sub =
|
|
singleEntryPath != null
|
|
? singleEntryPath
|
|
: t === '.' || t === './'
|
|
? n
|
|
: t.replace(/\/$/, '') + '/' + n
|
|
const st = await vfs.lstat(sub)
|
|
if (!st) {
|
|
rows.push({
|
|
modeStr: '?---------',
|
|
nlink: '?',
|
|
user: '?',
|
|
group: '?',
|
|
size: 0,
|
|
mtimeStr: '?',
|
|
name: n,
|
|
arrow: ''
|
|
})
|
|
continue
|
|
}
|
|
const blocks = barePosixBlocks(st.size || 0)
|
|
totalBlocks += blocks
|
|
const modeStr = bareFormatModeString(st.mode, st.type)
|
|
const nlink = st.nlink != null ? String(st.nlink) : '1'
|
|
const user = st.user != null ? st.user : String(st.uid ?? 0)
|
|
const group = st.group != null ? st.group : String(st.gid ?? 0)
|
|
const size = st.size != null ? String(st.size) : '0'
|
|
const mtimeStr = bareFormatLsMtime(
|
|
typeof st.mtimeMs === 'number' ? st.mtimeMs : Date.now()
|
|
)
|
|
let arrow = ''
|
|
if (st.type === 'symlink' && st.linkname != null) {
|
|
arrow = ' -> ' + st.linkname
|
|
}
|
|
rows.push({
|
|
modeStr,
|
|
nlink,
|
|
user,
|
|
group,
|
|
size,
|
|
mtimeStr,
|
|
name: n,
|
|
arrow
|
|
})
|
|
}
|
|
if (singleEntryPath == null) ctx.console.log('total ' + totalBlocks)
|
|
for (const r of rows) {
|
|
ctx.console.log(
|
|
r.modeStr +
|
|
' ' +
|
|
r.nlink +
|
|
' ' +
|
|
r.user +
|
|
' ' +
|
|
r.group +
|
|
' ' +
|
|
r.size +
|
|
' ' +
|
|
r.mtimeStr +
|
|
' ' +
|
|
r.name +
|
|
r.arrow
|
|
)
|
|
}
|
|
}
|
|
}
|
|
}
|