update
This commit is contained in:
+136
-7
@@ -3,6 +3,63 @@ 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
|
||||
@@ -30,23 +87,95 @@ async function run(ctx, argv) {
|
||||
for (const t of targets) {
|
||||
if (targets.length > 1) ctx.console.log(t + ':')
|
||||
let names
|
||||
/** @type {string | null} */
|
||||
let singleEntryPath = null
|
||||
try {
|
||||
names = await vfs.readdir(t)
|
||||
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
|
||||
}
|
||||
// POSIX: hide dotfiles unless -a (. and .. are dot-prefixed too).
|
||||
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 = t === '.' || t === './' ? n : t.replace(/\/$/, '') + '/' + n
|
||||
const st = await vfs.stat(sub)
|
||||
const tag = st ? (st.type === 'directory' ? 'd' : '-') : '?'
|
||||
const sz = st && st.size != null ? String(st.size) : '0'
|
||||
ctx.console.log(tag + 'rwxr-xr-x 1 user user ' + sz + ' ' + n)
|
||||
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
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user