path type inode size modified perm ver dev uid gid links suid sgid stky
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
. dir 1 0 2026-02-28T21:20:27.000Z rwxrwxr-x 8.1 0.0 0 0 0 0 0 0
dev dir 2 0 2026-02-28T21:20:27.000Z rwxrwxr-x 8.1 0.0 0 0 0 0 0 0
dev/null chr 3 0 2026-02-28T21:20:27.000Z rw-rw-r-- 8.1 1.3 0 0 0 0 0 0
dev/zero chr 4 0 2026-02-28T21:20:27.000Z rw-rw-r-- 8.1 1.5 0 0 0 0 0 0
dev/pts dir 5 0 2026-02-28T21:20:27.000Z rwxrwxr-x 8.1 0.0 0 0 0 0 0 0
dev/vda blk 6 0 2026-02-28T21:20:27.000Z rw-r--r-- 8.1 254.0 0 0 0 0 0 0
dev/ptp0 chr 7 0 2026-02-28T21:20:27.000Z rw-rw-r-- 8.1 246.0 0 0 0 0 0 0
dev/urandom chr 8 0 2026-02-28T21:20:27.000Z rw-rw-r-- 8.1 1.9 0 0 0 0 0 0
dev/tty0 chr 9 0 2026-02-28T21:20:27.000Z rw-rw-r-- 8.1 4.0 0 0 0 0 0 0
dev/tty1 chr 10 0 2026-02-28T21:20:27.000Z rw-rw-r-- 8.1 4.1 0 0 0 0 0 0
dev/tty2 chr 11 0 2026-02-28T21:20:27.000Z rw-rw-r-- 8.1 4.2 0 0 0 0 0 0
dev/tty3 chr 12 0 2026-02-28T21:20:27.000Z rw-rw-r-- 8.1 4.3 0 0 0 0 0 0
dev/tty4 chr 13 0 2026-02-28T21:20:27.000Z rw-rw-r-- 8.1 4.4 0 0 0 0 0 0
dev/tty chr 14 0 2026-02-28T21:20:27.000Z rw-rw-r-- 8.1 5.0 0 0 0 0 0 0
dev/console chr 15 0 2026-02-28T21:20:27.000Z rw-rw-r-- 8.1 5.1 0 0 0 0 0 0
dev/ptmx chr 16 0 2026-02-28T21:20:27.000Z rw-rw-r-- 8.1 5.2 0 0 0 0 0 0
dev/mem chr 17 0 2026-02-28T21:20:27.000Z rw-rw-r-- 8.1 1.1 0 0 0 0 0 0
dev/ttyS0 chr 18 0 2026-02-28T21:20:27.000Z rw-rw-r-- 8.1 4.5 0 0 0 0 0 0
sys dir 19 0 2026-02-28T21:20:27.000Z rwxrwxr-x 8.1 0.0 0 0 0 0 0 0
bin dir 20 0 2026-02-28T21:20:27.000Z rwxrwxr-x 8.1 0.0 0 0 0 0 0 0
bin/busybox reg 21 2160224 2026-02-28T21:20:27.000Z rwxrwxr-x 8.1 0.0 0 0 0 0 0 0
proc dir 22 0 2026-02-28T21:20:27.000Z rwxrwxr-x 8.1 0.0 0 0 0 0 0 0
etc dir 23 0 2026-02-28T21:20:27.000Z rwxrwxr-x 8.1 0.0 0 0 0 0 0 0
etc/shadow reg 24 24 2026-02-28T21:20:27.000Z rw-r--r-- 8.1 0.0 0 0 0 0 0 0
etc/hosts reg 25 0 2026-02-28T21:20:27.000Z rw-r--r-- 8.1 0.0 0 0 0 0 0 0
etc/resolv.conf reg 26 19 2026-02-28T21:20:27.000Z rw-r--r-- 8.1 0.0 0 0 0 0 0 0
etc/profile reg 27 85 2026-02-28T21:20:27.000Z rw-r--r-- 8.1 0.0 0 0 0 0 0 0
etc/passwd reg 28 41 2026-02-28T21:20:27.000Z rw-r--r-- 8.1 0.0 0 0 0 0 0 0
etc/dropbear dir 29 0 2026-02-28T21:20:27.000Z rwxrwxr-x 8.1 0.0 0 0 0 0 0 0
etc/dropbear/dropbear_ed25519_host_key reg 30 83 2026-02-28T21:20:27.000Z rw-r--r-- 8.1 0.0 0 0 0 0 0 0
etc/ssl dir 31 0 2026-02-28T21:20:27.000Z rwxrwxr-x 8.1 0.0 0 0 0 0 0 0
etc/ssl/certs dir 32 0 2026-02-28T21:20:27.000Z rwxrwxr-x 8.1 0.0 0 0 0 0 0 0
etc/ssl/certs/ca-certificates.crt reg 33 220302 2026-02-28T21:20:27.000Z rw-r--r-- 8.1 0.0 0 0 0 0 0 0
init reg 34 836216 2026-02-28T21:20:27.000Z rwxrwxr-x 8.1 0.0 0 0 0 0 0 0
tmp dir 35 0 2026-02-28T21:20:27.000Z rwxrwxr-x 8.1 0.0 0 0 0 0 0 0
total: 3216994
node_v24.13.1 cpio parse time 1867 rate 53545 rate/core 53015 ns/iter 18675.93 rss 71397376 usr 101.00 sys 0.00 tot 101.00 thru 170.78 GBps
node_v24.13.1 cpio parse time 1849 rate 54081 rate/core 54081 ns/iter 18490.87 rss 71528448 usr 100.00 sys 0.00 tot 100.00 thru 174.21 GBps
node_v24.13.1 cpio parse time 1806 rate 55352 rate/core 55352 ns/iter 18066.48 rss 79917056 usr 100.00 sys 0.00 tot 100.00 thru 178.31 GBps
node_v24.13.1 cpio parse time 1796 rate 55675 rate/core 56237 ns/iter 17961.59 rss 79917056 usr 99.00 sys 0.00 tot 99.00 thru 181.16 GBps
node_v24.13.1 cpio parse time 1797 rate 55648 rate/core 55648 ns/iter 17970.17 rss 79917056 usr 100.00 sys 0.00 tot 100.00 thru 179.26 GBps
node_v24.13.1 cpio parse time 1808 rate 55294 rate/core 55294 ns/iter 18085.28 rss 79917056 usr 100.00 sys 0.00 tot 100.00 thru 178.12 GBps
$ bun bench-cpio.js
path type inode size modified perm ver dev uid gid links suid sgid stky
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
. dir 1 0 2026-02-28T21:20:27.000Z rwxrwxr-x 8.1 0.0 0 0 0 0 0 0
dev dir 2 0 2026-02-28T21:20:27.000Z rwxrwxr-x 8.1 0.0 0 0 0 0 0 0
dev/null chr 3 0 2026-02-28T21:20:27.000Z rw-rw-r-- 8.1 1.3 0 0 0 0 0 0
dev/zero chr 4 0 2026-02-28T21:20:27.000Z rw-rw-r-- 8.1 1.5 0 0 0 0 0 0
dev/pts dir 5 0 2026-02-28T21:20:27.000Z rwxrwxr-x 8.1 0.0 0 0 0 0 0 0
dev/vda blk 6 0 2026-02-28T21:20:27.000Z rw-r--r-- 8.1 254.0 0 0 0 0 0 0
dev/ptp0 chr 7 0 2026-02-28T21:20:27.000Z rw-rw-r-- 8.1 246.0 0 0 0 0 0 0
dev/urandom chr 8 0 2026-02-28T21:20:27.000Z rw-rw-r-- 8.1 1.9 0 0 0 0 0 0
dev/tty0 chr 9 0 2026-02-28T21:20:27.000Z rw-rw-r-- 8.1 4.0 0 0 0 0 0 0
dev/tty1 chr 10 0 2026-02-28T21:20:27.000Z rw-rw-r-- 8.1 4.1 0 0 0 0 0 0
dev/tty2 chr 11 0 2026-02-28T21:20:27.000Z rw-rw-r-- 8.1 4.2 0 0 0 0 0 0
dev/tty3 chr 12 0 2026-02-28T21:20:27.000Z rw-rw-r-- 8.1 4.3 0 0 0 0 0 0
dev/tty4 chr 13 0 2026-02-28T21:20:27.000Z rw-rw-r-- 8.1 4.4 0 0 0 0 0 0
dev/tty chr 14 0 2026-02-28T21:20:27.000Z rw-rw-r-- 8.1 5.0 0 0 0 0 0 0
dev/console chr 15 0 2026-02-28T21:20:27.000Z rw-rw-r-- 8.1 5.1 0 0 0 0 0 0
dev/ptmx chr 16 0 2026-02-28T21:20:27.000Z rw-rw-r-- 8.1 5.2 0 0 0 0 0 0
dev/mem chr 17 0 2026-02-28T21:20:27.000Z rw-rw-r-- 8.1 1.1 0 0 0 0 0 0
dev/ttyS0 chr 18 0 2026-02-28T21:20:27.000Z rw-rw-r-- 8.1 4.5 0 0 0 0 0 0
sys dir 19 0 2026-02-28T21:20:27.000Z rwxrwxr-x 8.1 0.0 0 0 0 0 0 0
bin dir 20 0 2026-02-28T21:20:27.000Z rwxrwxr-x 8.1 0.0 0 0 0 0 0 0
bin/busybox reg 21 2160224 2026-02-28T21:20:27.000Z rwxrwxr-x 8.1 0.0 0 0 0 0 0 0
proc dir 22 0 2026-02-28T21:20:27.000Z rwxrwxr-x 8.1 0.0 0 0 0 0 0 0
etc dir 23 0 2026-02-28T21:20:27.000Z rwxrwxr-x 8.1 0.0 0 0 0 0 0 0
etc/shadow reg 24 24 2026-02-28T21:20:27.000Z rw-r--r-- 8.1 0.0 0 0 0 0 0 0
etc/hosts reg 25 0 2026-02-28T21:20:27.000Z rw-r--r-- 8.1 0.0 0 0 0 0 0 0
etc/resolv.conf reg 26 19 2026-02-28T21:20:27.000Z rw-r--r-- 8.1 0.0 0 0 0 0 0 0
etc/profile reg 27 85 2026-02-28T21:20:27.000Z rw-r--r-- 8.1 0.0 0 0 0 0 0 0
etc/passwd reg 28 41 2026-02-28T21:20:27.000Z rw-r--r-- 8.1 0.0 0 0 0 0 0 0
etc/dropbear dir 29 0 2026-02-28T21:20:27.000Z rwxrwxr-x 8.1 0.0 0 0 0 0 0 0
etc/dropbear/dropbear_ed25519_host_key reg 30 83 2026-02-28T21:20:27.000Z rw-r--r-- 8.1 0.0 0 0 0 0 0 0
etc/ssl dir 31 0 2026-02-28T21:20:27.000Z rwxrwxr-x 8.1 0.0 0 0 0 0 0 0
etc/ssl/certs dir 32 0 2026-02-28T21:20:27.000Z rwxrwxr-x 8.1 0.0 0 0 0 0 0 0
etc/ssl/certs/ca-certificates.crt reg 33 220302 2026-02-28T21:20:27.000Z rw-r--r-- 8.1 0.0 0 0 0 0 0 0
init reg 34 836216 2026-02-28T21:20:27.000Z rwxrwxr-x 8.1 0.0 0 0 0 0 0 0
tmp dir 35 0 2026-02-28T21:20:27.000Z rwxrwxr-x 8.1 0.0 0 0 0 0 0 0
total: 3216994
bun_1.3.9 cpio parse time 1998 rate 50035 rate/core 48578 ns/iter 19986.07 rss 109740032 usr 102.00 sys 1.00 tot 103.00 thru 156.48 GBps
bun_1.3.9 cpio parse time 1979 rate 50527 rate/core 49536 ns/iter 19791.54 rss 104263680 usr 100.00 sys 2.00 tot 102.00 thru 159.57 GBps
bun_1.3.9 cpio parse time 2026 rate 49339 rate/core 48850 ns/iter 20268.35 rss 105050112 usr 100.00 sys 1.00 tot 101.00 thru 157.36 GBps
bun_1.3.9 cpio parse time 1995 rate 50125 rate/core 49629 ns/iter 19950.15 rss 105500672 usr 100.00 sys 1.00 tot 101.00 thru 159.87 GBps
bun_1.3.9 cpio parse time 1970 rate 50744 rate/core 50744 ns/iter 19706.87 rss 105709568 usr 100.00 sys 0.00 tot 100.00 thru 163.46 GBps
bun_1.3.9 cpio parse time 1994 rate 50128 rate/core 49145 ns/iter 19949.04 rss 105218048 usr 100.00 sys 2.00 tot 102.00 thru 158.31 GBps
bun_1.3.9 cpio parse time 1974 rate 50655 rate/core 50154 ns/iter 19741.50 rss 105742336 usr 100.00 sys 1.00 tot 101.00 thru 161.56 GBps
bun_1.3.9 cpio parse time 2005 rate 49874 rate/core 49380 ns/iter 20050.69 rss 106397696 usr 100.00 sys 1.00 tot 101.00 thru 159.07 GBps
$ deno -A bench-cpio.js
path type inode size modified perm ver dev uid gid links suid sgid stky
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
. dir 1 0 2026-02-28T21:20:27.000Z rwxrwxr-x 8.1 0.0 0 0 0 0 0 0
dev dir 2 0 2026-02-28T21:20:27.000Z rwxrwxr-x 8.1 0.0 0 0 0 0 0 0
dev/null chr 3 0 2026-02-28T21:20:27.000Z rw-rw-r-- 8.1 1.3 0 0 0 0 0 0
dev/zero chr 4 0 2026-02-28T21:20:27.000Z rw-rw-r-- 8.1 1.5 0 0 0 0 0 0
dev/pts dir 5 0 2026-02-28T21:20:27.000Z rwxrwxr-x 8.1 0.0 0 0 0 0 0 0
dev/vda blk 6 0 2026-02-28T21:20:27.000Z rw-r--r-- 8.1 254.0 0 0 0 0 0 0
dev/ptp0 chr 7 0 2026-02-28T21:20:27.000Z rw-rw-r-- 8.1 246.0 0 0 0 0 0 0
dev/urandom chr 8 0 2026-02-28T21:20:27.000Z rw-rw-r-- 8.1 1.9 0 0 0 0 0 0
dev/tty0 chr 9 0 2026-02-28T21:20:27.000Z rw-rw-r-- 8.1 4.0 0 0 0 0 0 0
dev/tty1 chr 10 0 2026-02-28T21:20:27.000Z rw-rw-r-- 8.1 4.1 0 0 0 0 0 0
dev/tty2 chr 11 0 2026-02-28T21:20:27.000Z rw-rw-r-- 8.1 4.2 0 0 0 0 0 0
dev/tty3 chr 12 0 2026-02-28T21:20:27.000Z rw-rw-r-- 8.1 4.3 0 0 0 0 0 0
dev/tty4 chr 13 0 2026-02-28T21:20:27.000Z rw-rw-r-- 8.1 4.4 0 0 0 0 0 0
dev/tty chr 14 0 2026-02-28T21:20:27.000Z rw-rw-r-- 8.1 5.0 0 0 0 0 0 0
dev/console chr 15 0 2026-02-28T21:20:27.000Z rw-rw-r-- 8.1 5.1 0 0 0 0 0 0
dev/ptmx chr 16 0 2026-02-28T21:20:27.000Z rw-rw-r-- 8.1 5.2 0 0 0 0 0 0
dev/mem chr 17 0 2026-02-28T21:20:27.000Z rw-rw-r-- 8.1 1.1 0 0 0 0 0 0
dev/ttyS0 chr 18 0 2026-02-28T21:20:27.000Z rw-rw-r-- 8.1 4.5 0 0 0 0 0 0
sys dir 19 0 2026-02-28T21:20:27.000Z rwxrwxr-x 8.1 0.0 0 0 0 0 0 0
bin dir 20 0 2026-02-28T21:20:27.000Z rwxrwxr-x 8.1 0.0 0 0 0 0 0 0
bin/busybox reg 21 2160224 2026-02-28T21:20:27.000Z rwxrwxr-x 8.1 0.0 0 0 0 0 0 0
proc dir 22 0 2026-02-28T21:20:27.000Z rwxrwxr-x 8.1 0.0 0 0 0 0 0 0
etc dir 23 0 2026-02-28T21:20:27.000Z rwxrwxr-x 8.1 0.0 0 0 0 0 0 0
etc/shadow reg 24 24 2026-02-28T21:20:27.000Z rw-r--r-- 8.1 0.0 0 0 0 0 0 0
etc/hosts reg 25 0 2026-02-28T21:20:27.000Z rw-r--r-- 8.1 0.0 0 0 0 0 0 0
etc/resolv.conf reg 26 19 2026-02-28T21:20:27.000Z rw-r--r-- 8.1 0.0 0 0 0 0 0 0
etc/profile reg 27 85 2026-02-28T21:20:27.000Z rw-r--r-- 8.1 0.0 0 0 0 0 0 0
etc/passwd reg 28 41 2026-02-28T21:20:27.000Z rw-r--r-- 8.1 0.0 0 0 0 0 0 0
etc/dropbear dir 29 0 2026-02-28T21:20:27.000Z rwxrwxr-x 8.1 0.0 0 0 0 0 0 0
etc/dropbear/dropbear_ed25519_host_key reg 30 83 2026-02-28T21:20:27.000Z rw-r--r-- 8.1 0.0 0 0 0 0 0 0
etc/ssl dir 31 0 2026-02-28T21:20:27.000Z rwxrwxr-x 8.1 0.0 0 0 0 0 0 0
etc/ssl/certs dir 32 0 2026-02-28T21:20:27.000Z rwxrwxr-x 8.1 0.0 0 0 0 0 0 0
etc/ssl/certs/ca-certificates.crt reg 33 220302 2026-02-28T21:20:27.000Z rw-r--r-- 8.1 0.0 0 0 0 0 0 0
init reg 34 836216 2026-02-28T21:20:27.000Z rwxrwxr-x 8.1 0.0 0 0 0 0 0 0
tmp dir 35 0 2026-02-28T21:20:27.000Z rwxrwxr-x 8.1 0.0 0 0 0 0 0 0
total: 3216994
deno_2.6.9 cpio parse time 2197 rate 45499 rate/core 45499 ns/iter 21978.54 rss 83365888 usr 100.00 sys 0.00 tot 100.00 thru 146.56 GBps
deno_2.6.9 cpio parse time 2110 rate 47373 rate/core 47852 ns/iter 21109.17 rss 91754496 usr 99.00 sys 0.00 tot 99.00 thru 154.14 GBps
deno_2.6.9 cpio parse time 2024 rate 49383 rate/core 49882 ns/iter 20249.93 rss 92016640 usr 99.00 sys 0.00 tot 99.00 thru 160.68 GBps
deno_2.6.9 cpio parse time 2021 rate 49464 rate/core 49464 ns/iter 20217.07 rss 92016640 usr 100.00 sys 0.00 tot 100.00 thru 159.34 GBps
deno_2.6.9 cpio parse time 2019 rate 49513 rate/core 49513 ns/iter 20197.03 rss 92278784 usr 100.00 sys 0.00 tot 100.00 thru 159.50 GBps
deno_2.6.9 cpio parse time 2027 rate 49317 rate/core 49815 ns/iter 20277.23 rss 92278784 usr 99.00 sys 0.00 tot 99.00 thru 160.47 GBps
$ lo bench-cpio.js
path type inode size modified perm ver dev uid gid links suid sgid stky
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
. dir 1 0 2026-02-28T21:20:27.000Z rwxrwxr-x 8.1 0.0 0 0 0 0 0 0
dev dir 2 0 2026-02-28T21:20:27.000Z rwxrwxr-x 8.1 0.0 0 0 0 0 0 0
dev/null chr 3 0 2026-02-28T21:20:27.000Z rw-rw-r-- 8.1 1.3 0 0 0 0 0 0
dev/zero chr 4 0 2026-02-28T21:20:27.000Z rw-rw-r-- 8.1 1.5 0 0 0 0 0 0
dev/pts dir 5 0 2026-02-28T21:20:27.000Z rwxrwxr-x 8.1 0.0 0 0 0 0 0 0
dev/vda blk 6 0 2026-02-28T21:20:27.000Z rw-r--r-- 8.1 254.0 0 0 0 0 0 0
dev/ptp0 chr 7 0 2026-02-28T21:20:27.000Z rw-rw-r-- 8.1 246.0 0 0 0 0 0 0
dev/urandom chr 8 0 2026-02-28T21:20:27.000Z rw-rw-r-- 8.1 1.9 0 0 0 0 0 0
dev/tty0 chr 9 0 2026-02-28T21:20:27.000Z rw-rw-r-- 8.1 4.0 0 0 0 0 0 0
dev/tty1 chr 10 0 2026-02-28T21:20:27.000Z rw-rw-r-- 8.1 4.1 0 0 0 0 0 0
dev/tty2 chr 11 0 2026-02-28T21:20:27.000Z rw-rw-r-- 8.1 4.2 0 0 0 0 0 0
dev/tty3 chr 12 0 2026-02-28T21:20:27.000Z rw-rw-r-- 8.1 4.3 0 0 0 0 0 0
dev/tty4 chr 13 0 2026-02-28T21:20:27.000Z rw-rw-r-- 8.1 4.4 0 0 0 0 0 0
dev/tty chr 14 0 2026-02-28T21:20:27.000Z rw-rw-r-- 8.1 5.0 0 0 0 0 0 0
dev/console chr 15 0 2026-02-28T21:20:27.000Z rw-rw-r-- 8.1 5.1 0 0 0 0 0 0
dev/ptmx chr 16 0 2026-02-28T21:20:27.000Z rw-rw-r-- 8.1 5.2 0 0 0 0 0 0
dev/mem chr 17 0 2026-02-28T21:20:27.000Z rw-rw-r-- 8.1 1.1 0 0 0 0 0 0
dev/ttyS0 chr 18 0 2026-02-28T21:20:27.000Z rw-rw-r-- 8.1 4.5 0 0 0 0 0 0
sys dir 19 0 2026-02-28T21:20:27.000Z rwxrwxr-x 8.1 0.0 0 0 0 0 0 0
bin dir 20 0 2026-02-28T21:20:27.000Z rwxrwxr-x 8.1 0.0 0 0 0 0 0 0
bin/busybox reg 21 2160224 2026-02-28T21:20:27.000Z rwxrwxr-x 8.1 0.0 0 0 0 0 0 0
proc dir 22 0 2026-02-28T21:20:27.000Z rwxrwxr-x 8.1 0.0 0 0 0 0 0 0
etc dir 23 0 2026-02-28T21:20:27.000Z rwxrwxr-x 8.1 0.0 0 0 0 0 0 0
etc/shadow reg 24 24 2026-02-28T21:20:27.000Z rw-r--r-- 8.1 0.0 0 0 0 0 0 0
etc/hosts reg 25 0 2026-02-28T21:20:27.000Z rw-r--r-- 8.1 0.0 0 0 0 0 0 0
etc/resolv.conf reg 26 19 2026-02-28T21:20:27.000Z rw-r--r-- 8.1 0.0 0 0 0 0 0 0
etc/profile reg 27 85 2026-02-28T21:20:27.000Z rw-r--r-- 8.1 0.0 0 0 0 0 0 0
etc/passwd reg 28 41 2026-02-28T21:20:27.000Z rw-r--r-- 8.1 0.0 0 0 0 0 0 0
etc/dropbear dir 29 0 2026-02-28T21:20:27.000Z rwxrwxr-x 8.1 0.0 0 0 0 0 0 0
etc/dropbear/dropbear_ed25519_host_key reg 30 83 2026-02-28T21:20:27.000Z rw-r--r-- 8.1 0.0 0 0 0 0 0 0
etc/ssl dir 31 0 2026-02-28T21:20:27.000Z rwxrwxr-x 8.1 0.0 0 0 0 0 0 0
etc/ssl/certs dir 32 0 2026-02-28T21:20:27.000Z rwxrwxr-x 8.1 0.0 0 0 0 0 0 0
etc/ssl/certs/ca-certificates.crt reg 33 220302 2026-02-28T21:20:27.000Z rw-r--r-- 8.1 0.0 0 0 0 0 0 0
init reg 34 836216 2026-02-28T21:20:27.000Z rwxrwxr-x 8.1 0.0 0 0 0 0 0 0
tmp dir 35 0 2026-02-28T21:20:27.000Z rwxrwxr-x 8.1 0.0 0 0 0 0 0 0
total: 3216994
lo_0.0.23-pre cpio parse time 1267 rate 78895 rate/core 77074 ns/iter 12675.18 rss 42426368 usr 101.57 sys 0.79 tot 102.36 thru 248.28 GBps
lo_0.0.23-pre cpio parse time 1276 rate 78350 rate/core 77145 ns/iter 12763.24 rss 43343872 usr 100.78 sys 0.78 tot 101.56 thru 248.51 GBps
lo_0.0.23-pre cpio parse time 1288 rate 77614 rate/core 77614 ns/iter 12884.34 rss 46096384 usr 100.00 sys 0.00 tot 100.00 thru 250.02 GBps
lo_0.0.23-pre cpio parse time 1246 rate 80247 rate/core 78973 ns/iter 12461.64 rss 46489600 usr 101.61 sys 0.00 tot 101.61 thru 254.40 GBps
lo_0.0.23-pre cpio parse time 1244 rate 80356 rate/core 79718 ns/iter 12444.70 rss 46882816 usr 100.00 sys 0.80 tot 100.80 thru 256.80 GBps
lo_0.0.23-pre cpio parse time 1254 rate 79701 rate/core 79701 ns/iter 12546.92 rss 47276032 usr 100.00 sys 0.00 tot 100.00 thru 256.74 GBps
lo_0.0.23-pre cpio parse time 1237 rate 80827 rate/core 80180 ns/iter 12372.18 rss 51863552 usr 100.00 sys 0.81 tot 100.81 thru 258.29 GBps
lo_0.0.23-pre cpio parse time 1237 rate 80810 rate/core 80810 ns/iter 12374.79 rss 52125696 usr 100.00 sys 0.00 tot 100.00 thru 260.32 GBps
Last active
February 28, 2026 23:52
-
-
Save billywhizz/35e2d6d2fa0862fb2925e4f5bc761bf4 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import { Bench } from './bench.js' | |
| import { parse_cpio, dump_cpio } from './cpio.js' | |
| const bench = new Bench() | |
| const iter = 5 | |
| const path = './initrd.cpio' | |
| const buf = readFileSync(path) | |
| const files = parse_cpio(buf) | |
| const num_entries = files.length | |
| dump_cpio(path) | |
| while (1) { | |
| { | |
| const runs = 100000 | |
| for (let i = 0; i < iter; i++) { | |
| bench.start('cpio parse') | |
| for (let j = 0; j < runs; j++) { | |
| assert(parse_cpio(buf).length === num_entries) | |
| } | |
| bench.end(runs, buf.length) | |
| } | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| this runs on bun/lo/deno/node on macos and linux | |
| need to test on windows | |
| */ | |
| function is_a_tty(fd = 1) { | |
| if (globalThis.Deno) return Deno.isatty(fd); | |
| if (globalThis.lo) return lo.core.isatty(fd); | |
| if (fd === 1) return process.stdout.isTTY; | |
| if (fd === 2) return process.stderr.isTTY; | |
| return process.stdin.isTTY; | |
| } | |
| const isatty = is_a_tty(); | |
| const AD = isatty ? "\u001b[0m" : ""; // ANSI Default | |
| const A0 = isatty ? "\u001b[30m" : ""; // ANSI Black | |
| const AR = isatty ? "\u001b[31m" : ""; // ANSI Red | |
| const AG = isatty ? "\u001b[32m" : ""; // ANSI Green | |
| const AY = isatty ? "\u001b[33m" : ""; // ANSI Yellow | |
| const AB = isatty ? "\u001b[34m" : ""; // ANSI Blue | |
| const AM = isatty ? "\u001b[35m" : ""; // ANSI Magenta | |
| const AC = isatty ? "\u001b[36m" : ""; // ANSI Cyan | |
| const AW = isatty ? "\u001b[37m" : ""; // ANSI White | |
| const colors = { AD, AG, AY, AM, AD, AR, AB, AC, AW, A0 }; | |
| const decoder = new TextDecoder(); | |
| const encoder = new TextEncoder(); | |
| class Stats { | |
| recv = 0; | |
| send = 0; | |
| conn = 0; | |
| rps = 0; | |
| log() { | |
| const { send, recv, conn, rps } = this; | |
| const [usr, sys] = cputime(); | |
| const rps_per_core = Math.floor(rps / ((usr + sys) / 100)) | |
| console.log( | |
| `${AC}send${AD} ${to_size_string(send)} ${AC}recv${AD} ${to_size_string(recv)} ${AC}rps${AD} ${rps.toString().padStart(10, ' ')} ${AM}rps/core${AD} ${rps_per_core.toString().padStart(10, ' ')} ${AC}rss${AD} ${mem().toString().padStart(12, ' ')} ${AC}con${AD} ${conn} ${AY}usr${AD} ${usr.toString().padStart(3, " ")} ${AY}sys${AD} ${sys.toString().padStart(3, " ")} ${AY}tot${AD} ${(usr + sys).toString().padStart(3, " ")}`, | |
| ); | |
| this.send = this.recv = this.rps = 0; | |
| } | |
| get runtime() { | |
| return lo.hrtime() - lo.start; | |
| } | |
| } | |
| function pad(v, size, precision = 0) { | |
| return v.toFixed(precision).padStart(size, " "); | |
| } | |
| function memory_usage(buf) { | |
| return Math.floor(Number(decoder.decode(buf).split(" ")[23]) * 4096); | |
| } | |
| let lastusr = 0; | |
| let lastsys = 0; | |
| let last_time = Date.now(); | |
| function cpu_usage(bytes) { | |
| const str = decoder.decode(bytes); | |
| const parts = str.split(" ");`` | |
| const elapsed = Date.now() - last_time; | |
| const usr = Number(parts[13]); | |
| const sys = Number(parts[14]); | |
| const res = [(((usr - lastusr) * 10) / elapsed) * 100, (((sys - lastsys) * 10) / elapsed) * 100].map(v => Math.floor(v)) | |
| lastusr = usr; | |
| lastsys = sys; | |
| last_time = Date.now(); | |
| return res; | |
| } | |
| async function wrap_mem_usage() { | |
| if (globalThis.Deno) { | |
| if (Deno.build.os === "linux") { | |
| const mem = () => memory_usage(Deno.readFileSync("/proc/self/stat")); | |
| const cputime = () => cpu_usage(Deno.readFileSync("/proc/self/stat")); | |
| cputime(); | |
| return { mem, cputime }; | |
| } | |
| const mem = () => Deno.memoryUsage().rss; | |
| const _SC_CLK_TCK = 3; | |
| const api = Deno.dlopen("libc.dylib", { | |
| sysconf: { parameters: ["i32"], result: "i32" }, | |
| times: { parameters: ["buffer"], result: "i32" }, | |
| }).symbols; | |
| const { sysconf, times } = api; | |
| const clock_ticks_per_second = sysconf(_SC_CLK_TCK); | |
| const last = new Int32Array(5); | |
| const current = new Int32Array(6); | |
| current[5] = clock_ticks_per_second; | |
| const time32 = new Uint32Array(9); | |
| const _cputime = () => { | |
| time32[4] = times(time32); | |
| for (let i = 0; i < 5; i++) { | |
| current[i] = time32[i] - last[i]; | |
| last[i] = time32[i]; | |
| } | |
| return current; | |
| }; | |
| _cputime(); | |
| return { | |
| mem, | |
| cputime: () => { | |
| const time = _cputime(); | |
| const usr = time[0] / (time[4] / time[5]); | |
| const sys = time[2] / (time[4] / time[5]); | |
| return [usr, sys]; | |
| }, | |
| }; | |
| } | |
| if (globalThis.process && !globalThis.lo) { | |
| const os = await import("os"); | |
| if (os.platform() === "linux") { | |
| const fs = await import("fs"); | |
| const mem = () => memory_usage(fs.readFileSync("/proc/self/stat")); | |
| const cputime = () => cpu_usage(fs.readFileSync("/proc/self/stat")); | |
| cputime(); | |
| return { mem, cputime }; | |
| } | |
| let prev = process.cpuUsage(); | |
| let since = Date.now(); | |
| return { | |
| mem: () => process.memoryUsage().rss, | |
| cputime: () => { | |
| const now = Date.now(); | |
| const elapsed_ms = now - since; | |
| const cpu = process.cpuUsage(); | |
| const user = cpu.user - prev.user; | |
| const system = cpu.system - prev.system; | |
| prev = cpu; | |
| const usr = (user / 1000 / elapsed_ms) * 100; | |
| const sys = (system / 1000 / elapsed_ms) * 100; | |
| since = Date.now(); | |
| return [usr, sys]; | |
| }, | |
| }; | |
| } | |
| if (globalThis.lo) { | |
| const proc = await import("lib/proc.js"); | |
| proc.cputime(); | |
| const cputime = () => { | |
| const time = proc.cputime(); | |
| const usr = time[0] / (time[4] / time[5]); | |
| const sys = time[2] / (time[4] / time[5]); | |
| return [usr, sys]; | |
| }; | |
| return { mem: proc.mem, cputime }; | |
| } | |
| } | |
| function to_size_string(bytes) { | |
| if (bytes < 1000) { | |
| return `${bytes.toFixed(2).padStart(8, " ")} ${AY} Bps${AD}`; | |
| } else if (bytes < 1000 * 1000) { | |
| return `${(Math.floor((bytes / 1000) * 100) / 100).toFixed(2).padStart(8, " ")} ${AY}KBps${AD}`; | |
| } else if (bytes < 1000 * 1000 * 1000) { | |
| return `${(Math.floor((bytes / (1000 * 1000)) * 100) / 100).toFixed(2).padStart(8, " ")} ${AY}MBps${AD}`; | |
| } | |
| return `${(Math.floor((bytes / (1000 * 1000 * 1000)) * 100) / 100).toFixed(2).padStart(8, " ")} ${AY}GBps${AD}`; | |
| } | |
| function formatNanos(nanos) { | |
| if (nanos >= 1000000000) return `${AY}sec/iter${AD} ${pad(nanos / 1000000000, 10, 2)}`; | |
| if (nanos >= 1000000) return `${AY}ms/iter${AD} ${pad(nanos / 1000000, 10, 2)}`; | |
| if (nanos >= 1000) return `${AY}μs/iter${AD} ${pad(nanos / 1000, 10, 2)}`; | |
| return `${AY}ns/iter${AD} ${pad(nanos, 10, 2)}`; | |
| } | |
| function bench(name, fn, count, after = noop) { | |
| const start = performance.now(); | |
| for (let i = 0; i < count; i++) fn(); | |
| const elapsed = performance.now() - start; | |
| const rate = Math.floor(count / (elapsed / 1000)); | |
| const nanos = 1000000000 / rate; | |
| const rss = mem(); | |
| console.log( | |
| `${name.slice(0, 32).padEnd(17, " ")} ${pad(Math.floor(elapsed), 6)} ms ${AG}rate${AD} ${pad(rate, 10)} ${formatNanos(nanos)} ${AG}rss${AD} ${rss}`, | |
| ); | |
| after(); | |
| return { name, count, elapsed, rate, nanos, rss, runtime }; | |
| } | |
| async function benchAsync(name, fn, count, after = noop) { | |
| const start = performance.now(); | |
| for (let i = 0; i < count; i++) await fn(); | |
| const elapsed = performance.now() - start; | |
| const rate = Math.floor((count / (elapsed / 1000)) * 100) / 100; | |
| const nanos = 1000000000 / rate; | |
| const rss = mem(); | |
| console.log( | |
| `${name.slice(0, 32).padEnd(17, " ")} ${pad(Math.floor(elapsed), 6)} ms ${AG}rate${AD} ${pad(rate, 10)} ${formatNanos(nanos)} ${AG}rss${AD} ${rss}`, | |
| ); | |
| after(); | |
| return { name, count, elapsed, rate, nanos, rss, runtime }; | |
| } | |
| const runAsync = async (name, fn, count, repeat = 10, after = () => {}) => { | |
| const runs = []; | |
| for (let i = 0; i < repeat; i++) { | |
| runs.push(await benchAsync(name, fn, count, after)); | |
| } | |
| return runs; | |
| }; | |
| const run = (name, fn, count, repeat = 10, after = () => {}) => { | |
| const runs = []; | |
| for (let i = 0; i < repeat; i++) { | |
| runs.push(bench(name, fn, count, after)); | |
| } | |
| return runs; | |
| }; | |
| function arrayEquals(a, b) { | |
| return Array.isArray(a) && Array.isArray(b) && a.length === b.length && a.every((val, index) => val === b[index]); | |
| } | |
| class Bench { | |
| #start = 0; | |
| #end = 0; | |
| #name = "bench"; | |
| #display = true; | |
| #name_width = 20; | |
| #runtime = ""; | |
| constructor(display = true) { | |
| this.#display = display; | |
| this.#runtime = `${runtime.name}_${runtime.version}` | |
| } | |
| set name_width(len) { | |
| this.#name_width = len; | |
| } | |
| start(name = "bench") { | |
| this.#name = name.slice(0, 32).padEnd(32, " "); | |
| this.#start = performance.now(); | |
| } | |
| end(count = 0, size = 0) { | |
| this.#end = performance.now(); | |
| const elapsed = this.#end - this.#start; | |
| const nanos = Math.floor(elapsed * 1000000); | |
| const seconds = nanos / 1000000000; | |
| let rate = count / seconds; | |
| const rss = mem(); | |
| const [usr, sys] = cputime(); | |
| const total = usr + sys; | |
| const rate_pc_f = rate / (total / 100); | |
| const rate_pc = rate_pc_f > 100 ? Math.ceil(rate_pc_f) : Math.ceil(rate_pc_f * 100) / 100; | |
| const ns_iter = Math.floor((nanos / count) * 100) / 100; | |
| rate = rate > 100 ? Math.ceil(rate) : Math.ceil(rate * 100) / 100; | |
| if (this.#display) { | |
| if (size) { | |
| console.log( | |
| `${AC}${this.#runtime.padEnd(16, " ")}${AD} ${AM}${this.#name.trim().padEnd(this.#name_width, " ")}${AD} ${AY}time${AD} ${Math.floor(elapsed).toString().padStart(8, " ")} ${AY}rate${AD} ${rate.toString().padStart(12, " ")} ${AM}rate/core${AD} ${rate_pc.toString().padStart(12, " ")} ${AG}ns/iter${AD} ${ns_iter.toFixed(2).padStart(12, " ")} ${AG}rss${AD} ${rss.toString().padStart(12, " ")} ${AG}usr${AD} ${usr.toFixed(2).padStart(6, " ")} ${AR}sys${AD} ${sys.toFixed(2).padStart(6, " ")} ${AY}tot${AD} ${total.toFixed(2).padStart(6, " ")} ${AG}thru${AD} ${to_size_string(rate_pc * size).padStart(12, " ")}`, | |
| ); | |
| } else { | |
| console.log( | |
| `${AC}${this.#runtime.padEnd(16, " ")}${AD} ${AM}${this.#name.trim().padEnd(this.#name_width, " ")}${AD} ${AY}time${AD} ${Math.floor(elapsed).toString().padStart(8, " ")} ${AY}rate${AD} ${rate.toString().padStart(12, " ")} ${AM}rate/core${AD} ${rate_pc.toString().padStart(12, " ")} ${AG}ns/iter${AD} ${ns_iter.toFixed(2).padStart(12, " ")} ${AG}rss${AD} ${rss.toString().padStart(12, " ")} ${AG}usr${AD} ${usr.toFixed(2).padStart(6, " ")} ${AR}sys${AD} ${sys.toFixed(2).padStart(6, " ")} ${AY}tot${AD} ${total.toFixed(2).padStart(6, " ")}`, | |
| ); | |
| } | |
| } | |
| return { name: this.#name.trim(), count, elapsed, rate, nanos, rss, runtime, usr, sys, rate_pc, ns_iter, seconds }; | |
| } | |
| } | |
| const runtime = { name: "", version: "" }; | |
| if (globalThis.Deno) { | |
| globalThis.args = Deno.args; | |
| runtime.name = "deno"; | |
| runtime.version = Deno.version.deno; | |
| runtime.v8 = Deno.version.v8; | |
| globalThis.readFileAsText = async fn => decoder.decode(Deno.readFileSync(fn)); | |
| globalThis.readFileAsBytes = async fn => Deno.readFileSync(fn); | |
| globalThis.writeFileAsText = async (fn, str) => Deno.writeFileSync(fn, encoder.encode(str)); | |
| globalThis.writeFileAsBytes = async (fn, u8) => Deno.writeFileSync(fn, u8); | |
| const fs = await import("node:fs"); | |
| globalThis.openSync = fs.openSync; | |
| globalThis.readSync = fs.readSync; | |
| globalThis.closeSync = fs.closeSync; | |
| globalThis.readFileSync = fs.readFileSync; | |
| globalThis.process = await import('node:process') | |
| const { Buffer } = await import('node:buffer') | |
| globalThis.Buffer = Buffer | |
| } else if (globalThis.lo) { | |
| globalThis.performance = { now: () => lo.hrtime() / 1000000 }; | |
| globalThis.assert = lo.assert; | |
| globalThis.args = lo.args.slice(2); | |
| runtime.name = "lo"; | |
| runtime.version = lo.version.lo; | |
| runtime.v8 = lo.version.v8; | |
| const { readFile, writeFile } = lo.core; | |
| const { close, open, read, O_RDONLY } = lo.core; | |
| globalThis.readFileAsText = async fn => decoder.decode(readFile(fn)); | |
| globalThis.readFileAsBytes = async fn => readFile(fn); | |
| globalThis.writeFileAsText = async (fn, str) => writeFile(fn, encoder.encode(str)); | |
| globalThis.writeFileAsBytes = async (fn, u8) => writeFile(fn, u8); | |
| globalThis.openSync = file_name => open(file_name, O_RDONLY); | |
| globalThis.readSync = (fd, buf) => read(fd, buf, buf.length); | |
| globalThis.closeSync = fd => close(fd); | |
| globalThis.readFileSync = readFile; | |
| globalThis.process = { argv: lo.args } | |
| } else if (globalThis.Bun) { | |
| globalThis.args = Bun.argv.slice(2); | |
| runtime.name = "bun"; | |
| runtime.version = Bun.version; | |
| globalThis.readFileAsText = async fn => await Bun.file(fn).text(); | |
| globalThis.readFileAsBytes = async fn => await Bun.file(fn).bytes(); | |
| globalThis.writeFileAsText = async (fn, str) => Bun.write(fn, str); | |
| globalThis.writeFileAsBytes = async (fn, u8) => Bun.write(fn, u8); | |
| const fs = await import("node:fs"); | |
| globalThis.openSync = fs.openSync; | |
| globalThis.readSync = fs.readSync; | |
| globalThis.closeSync = fs.closeSync; | |
| globalThis.readFileSync = fs.readFileSync; | |
| } else if (globalThis.process) { | |
| globalThis.args = process.argv.slice(2); | |
| runtime.name = "node"; | |
| runtime.version = process.version; | |
| runtime.v8 = process.versions.v8; | |
| const fs = await import("fs"); | |
| globalThis.readFileAsText = async fn => decoder.decode(fs.readFileSync(fn)); | |
| globalThis.readFileAsBytes = async fn => fs.readFileSync(fn); | |
| globalThis.writeFileAsText = async (fn, str) => fs.writeFileSync(fn, encoder.encode(str)); | |
| globalThis.writeFileAsBytes = async (fn, u8) => fs.writeFileSync(fn, u8); | |
| globalThis.openSync = fs.openSync; | |
| globalThis.readSync = fs.readSync; | |
| globalThis.closeSync = fs.closeSync; | |
| globalThis.readFileSync = fs.readFileSync; | |
| } | |
| globalThis.colors = colors; | |
| globalThis.arrayEquals = arrayEquals; | |
| const noop = () => {}; | |
| const { mem, cputime } = await wrap_mem_usage(); | |
| if (!globalThis.assert) { | |
| function fix_stack (err) { | |
| err.stack = err.stack.split('\n') | |
| .filter(line => !line.match(/\s+at assert \(main\.js.+/)) | |
| .join('\n') | |
| } | |
| function assert (condition, message, ErrorType = Error) { | |
| if (!condition) { | |
| if (message && message.constructor.name === 'Function') { | |
| const err = new ErrorType(message(condition)) | |
| fix_stack(err) | |
| throw(err) | |
| } | |
| const err = new ErrorType(message || "Assertion failed") | |
| fix_stack(err) | |
| throw(err) | |
| } | |
| return condition | |
| } | |
| globalThis.assert = assert; | |
| } | |
| const measure = { | |
| start: (name = 'bench') => { | |
| cputime(); | |
| let start = performance.now(); | |
| function end (count) { | |
| const now = performance.now() | |
| const nanos = Math.floor((now - start) * 1000000); | |
| const elapsed = nanos / 1000000; | |
| const seconds = nanos / 1000000000; | |
| let rate = count / seconds; | |
| const rss = mem(); | |
| const [usr, sys] = cputime(); | |
| const total = usr + sys; | |
| const rate_pc_f = rate / (total / 100); | |
| const rate_pc = rate_pc_f > 100 ? Math.ceil(rate_pc_f) : Math.ceil(rate_pc_f * 100) / 100; | |
| const ns_iter = Math.floor((nanos / count) * 100) / 100; | |
| rate = rate > 100 ? Math.ceil(rate) : Math.ceil(rate * 100) / 100; | |
| start = now | |
| return { rss, usr, sys, total, elapsed, rate, rate_pc, ns_iter } | |
| } | |
| function log (count, size = 0) { | |
| const { rss, usr, sys, total, elapsed, rate, rate_pc, ns_iter } = end(count) | |
| if (size) { | |
| console.log(`${AG}${runtime.name.padEnd(10, ' ')}${AD} ${AM}${name.slice(0, 24).padEnd(20, ' ')}${AD} ${AY}${size.toString().padStart(8, ' ')}${AD} ${AY}time${AD} ${Math.floor(elapsed).toString().padStart(8, " ")} ${AY}rate${AD} ${rate.toString().padStart(12, " ")} ${AM}rate/core${AD} ${rate_pc.toString().padStart(12, " ")} ${AG}ns/iter${AD} ${ns_iter.toFixed(2).padStart(12, " ")} ${AG}rss${AD} ${rss.toString().padStart(12, " ")} ${AG}usr${AD} ${usr.toFixed(2).padStart(6, " ")} ${AR}sys${AD} ${sys.toFixed(2).padStart(6, " ")} ${AY}tot${AD} ${total.toFixed(2).padStart(6, " ")} ${AG}thru${AD} ${to_size_string(rate_pc * size).padStart(12, " ")}`,) | |
| } else { | |
| console.log(`${AG}${runtime.name.padEnd(10, ' ')}${AD} ${AM}${name.slice(0, 24).padEnd(20, ' ')}${AD} ${AY}${size.toString().padStart(8, ' ')}${AD} ${AY}time${AD} ${Math.floor(elapsed).toString().padStart(8, " ")} ${AY}rate${AD} ${rate.toString().padStart(12, " ")} ${AM}rate/core${AD} ${rate_pc.toString().padStart(12, " ")} ${AG}ns/iter${AD} ${ns_iter.toFixed(2).padStart(12, " ")} ${AG}rss${AD} ${rss.toString().padStart(12, " ")} ${AG}usr${AD} ${usr.toFixed(2).padStart(6, " ")} ${AR}sys${AD} ${sys.toFixed(2).padStart(6, " ")} ${AY}tot${AD} ${total.toFixed(2).padStart(6, " ")}`,) | |
| } | |
| } | |
| return { end, log } | |
| } | |
| }; | |
| export { | |
| pad, | |
| formatNanos, | |
| colors, | |
| run, | |
| runAsync, | |
| Bench, | |
| mem, | |
| runtime, | |
| to_size_string, | |
| Stats, | |
| cputime, | |
| measure, | |
| is_a_tty, | |
| cpu_usage, | |
| memory_usage, | |
| }; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // COMPAT | |
| let constants = {} | |
| let stat | |
| let decode_latin1 | |
| let decode_utf8 | |
| const encoder = new TextEncoder() | |
| const decoder = new TextDecoder() | |
| const AD = "\u001b[0m" // ANSI Default | |
| const AG = "\u001b[32m" // ANSI Green | |
| const AY = "\u001b[33m" // ANSI Yellow | |
| const AC = "\u001b[36m" // ANSI Cyan | |
| if (globalThis.lo) { | |
| const { utf8_decode, latin1_decode, ptr } = lo | |
| globalThis.readFileSync = lo.core.read_file | |
| const { file_stat } = await import('lib/fs.js') | |
| stat = file_stat | |
| globalThis.args = lo.args.slice(2) | |
| constants.S_IFBLK = lo.core.S_IFBLK | |
| constants.S_IFCHR = lo.core.S_IFCHR | |
| constants.S_IFIFO = lo.core.S_IFIFO | |
| constants.S_IFMT = lo.core.S_IFMT | |
| constants.S_IFDIR = lo.core.S_IFDIR | |
| constants.S_IFREG = lo.core.S_IFREG | |
| constants.S_IRUSR = lo.core.S_IRUSR | |
| constants.S_IWUSR = lo.core.S_IWUSR | |
| constants.S_IXUSR = lo.core.S_IXUSR | |
| constants.S_IRGRP = lo.core.S_IRGRP | |
| constants.S_IWGRP = lo.core.S_IWGRP | |
| constants.S_IXGRP = lo.core.S_IXGRP | |
| constants.S_IROTH = lo.core.S_IROTH | |
| constants.S_IWOTH = lo.core.S_IWOTH | |
| constants.S_IXOTH = lo.core.S_IXOTH | |
| constants.S_IRWXU = lo.core.S_IRWXU | |
| constants.S_IRWXG = lo.core.S_IRWXG | |
| constants.S_IRWXO = lo.core.S_IRWXO | |
| constants.O_WRONLY = lo.core.O_WRONLY | |
| constants.O_RDONLY = lo.core.O_RDONLY | |
| constants.O_RDWR = lo.core.O_RDWR | |
| constants.O_CREAT = lo.core.O_CREAT | |
| constants.O_TRUNC = lo.core.O_TRUNC | |
| decode_utf8 = (bytes, off, sz) => { | |
| if (!bytes.ptr) ptr(bytes) | |
| if (off + sz > bytes.length) throw new Error('OOB') | |
| return utf8_decode(bytes.ptr + off, sz) | |
| } | |
| decode_latin1 = (bytes, off, sz) => { | |
| if (!bytes.ptr) ptr(bytes) | |
| if (off + sz > bytes.length) throw new Error('OOB') | |
| return latin1_decode(bytes.ptr + off, sz) | |
| } | |
| } else { | |
| const fs = await import('node:fs') | |
| stat = fs.statSync | |
| globalThis.readFileSync = fs.readFileSync | |
| globalThis.args = process.argv.slice(2) | |
| constants.S_IFBLK = fs.constants.S_IFBLK | |
| constants.S_IFCHR = fs.constants.S_IFCHR | |
| constants.S_IFIFO = fs.constants.S_IFIFO | |
| constants.S_IFMT = fs.constants.S_IFMT | |
| constants.S_IFDIR = fs.constants.S_IFDIR | |
| constants.S_IFREG = fs.constants.S_IFREG | |
| constants.S_IRUSR = fs.constants.S_IRUSR | |
| constants.S_IWUSR = fs.constants.S_IWUSR | |
| constants.S_IXUSR = fs.constants.S_IXUSR | |
| constants.S_IRGRP = fs.constants.S_IRGRP | |
| constants.S_IWGRP = fs.constants.S_IWGRP | |
| constants.S_IXGRP = fs.constants.S_IXGRP | |
| constants.S_IROTH = fs.constants.S_IROTH | |
| constants.S_IWOTH = fs.constants.S_IWOTH | |
| constants.S_IXOTH = fs.constants.S_IXOTH | |
| constants.S_IRWXU = fs.constants.S_IRWXU | |
| constants.S_IRWXG = fs.constants.S_IRWXG | |
| constants.S_IRWXO = fs.constants.S_IRWXO | |
| constants.O_WRONLY = fs.constants.O_WRONLY | |
| constants.O_RDONLY = fs.constants.O_RDONLY | |
| constants.O_RDWR = fs.constants.O_RDWR | |
| constants.O_CREAT = fs.constants.O_CREAT | |
| constants.O_TRUNC = fs.constants.O_TRUNC | |
| decode_utf8 = (bytes, off, sz) => { | |
| return decoder.decode(bytes.subarray(off, off + sz)) | |
| } | |
| decode_latin1 = (bytes, off, sz) => { | |
| return decoder.decode(bytes.subarray(off, off + sz)) | |
| } | |
| } | |
| const { | |
| S_IFBLK, | |
| S_IFCHR, | |
| S_IFIFO, | |
| S_IFMT , | |
| S_IFDIR, | |
| S_IFREG, | |
| S_IRUSR, | |
| S_IWUSR, | |
| S_IXUSR, | |
| S_IRGRP, | |
| S_IWGRP, | |
| S_IXGRP, | |
| S_IROTH, | |
| S_IWOTH, | |
| S_IXOTH, | |
| S_IRWXU, | |
| S_IRWXG, | |
| S_IRWXO, | |
| O_WRONLY, | |
| O_RDONLY, | |
| O_RDWR, | |
| O_CREAT, | |
| O_TRUNC | |
| } = constants | |
| // END OF COMPAT | |
| // SRV4 ASCII CPIO Format | |
| // https://github.com/libyal/dtformats/blob/main/documentation/Copy%20in%20and%20out%20(CPIO)%20archive%20format.asciidoc#5-mode-permissions-and-type | |
| /* | |
| 0170000 This masks the file type bits. | |
| 0140000 File type value for sockets. | |
| 0120000 File type value for symbolic links. For symbolic links, | |
| the link body is stored as file data. | |
| 0100000 File type value for regular files. | |
| 0060000 File type value for block special devices. | |
| 0040000 File type value for directories. | |
| 0020000 File type value for character special devices. | |
| 0010000 File type value for named pipes or FIFOs. | |
| 0004000 SUID bit. | |
| 0002000 SGID bit. | |
| 0001000 Sticky bit. On some systems, this modifies the behavior | |
| of executables and/or directories. | |
| 0000777 The lower 9 bits specify read/write/execute permissions | |
| for world, group, and user following standard POSIX con- | |
| ventions. | |
| */ | |
| function get_file_type (val) { | |
| const type = val & IF_TYPE | |
| if (type === IF_SOCK) return 'sck' | |
| if (type === IF_LINK) return 'sym' | |
| if (type === IF_REG) return 'reg' | |
| if (type === IF_BLK) return 'blk' | |
| if (type === IF_DIR) return 'dir' | |
| if (type === IF_CHR) return 'chr' | |
| if (type === IF_PIPE) return 'pip' | |
| return '' | |
| } | |
| const bits = new Uint8Array(3) | |
| function get_bits (val) { | |
| bits[0] = val & IF_SUID | |
| bits[1] = val & IF_SGID | |
| bits[2] = val & IF_STICKY | |
| return bits | |
| } | |
| function perms (p) { | |
| const { r, w, x } = mode | |
| return `${(p & r) === r ? 'r' : '-'}${(p & w) === w ? 'w' : '-'}${(p & x) === x ? 'x' : '-'}` | |
| } | |
| function get_perms (perm) { | |
| const u = perm >> 6 | |
| const g = (perm >> 3) & 0x07 | |
| const w = perm & 0x07 | |
| return [u, g, w].map(perms) | |
| } | |
| // https://lemire.me/blog/2019/04/17/parsing-short-hexadecimal-strings-efficiently/ | |
| const H = new Int8Array([ | |
| -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | |
| -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | |
| -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | |
| 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, | |
| -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, | |
| -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | |
| -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, | |
| -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | |
| -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | |
| -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | |
| -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | |
| -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | |
| -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | |
| -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | |
| -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | |
| -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 | |
| ]) | |
| function parse_cpio (bytes) { | |
| function octal6 () { | |
| off += 6 | |
| return ((bytes[off - 6] - 48) << 15 | |
| | (bytes[off - 5] - 48) << 12 | |
| | (bytes[off - 4] - 48) << 9 | |
| | (bytes[off - 3] - 48) << 6 | |
| | (bytes[off - 2] - 48) << 3 | |
| | (bytes[off - 1] - 48)) | |
| } | |
| function hex8 () { | |
| off += 8 | |
| return (H[bytes[off - 8]] << 28 | |
| | H[bytes[off - 7]] << 24 | |
| | H[bytes[off - 6]] << 20 | |
| | H[bytes[off - 5]] << 16 | |
| | H[bytes[off - 4]] << 12 | |
| | H[bytes[off - 3]] << 8 | |
| | H[bytes[off - 2]] << 4 | |
| | H[bytes[off - 1]]) | |
| } | |
| function string (sz) { | |
| off += sz + 1 | |
| return decode_latin1(bytes, off - sz - 1, sz) | |
| } | |
| function align () { | |
| const over = off % 4 | |
| if (over === 0) return | |
| off += 4 - over | |
| } | |
| function buffer (sz) { | |
| off += sz | |
| return bytes.subarray(off - sz, off) | |
| } | |
| let off = 0 | |
| const files = [] | |
| while (off < bytes.length) { | |
| // can be "070701" (no checksums) or "070702" (with checksums) | |
| const id = octal6() | |
| if (id !== 29121 && id !== 29122) throw new Error('Unrecognized file id') | |
| const inode = hex8() | |
| const mode = hex8() | |
| const type = get_file_type(mode) | |
| const perms = mode & IF_PERM | |
| const [ suid, sgid, sticky ] = get_bits(mode) | |
| const uid = hex8() | |
| const gid = hex8() | |
| const links = hex8() | |
| const mod = hex8() * 1000 | |
| const size = hex8() | |
| const major = hex8() | |
| const minor = hex8() | |
| const dev_major = hex8() | |
| const dev_minor = hex8() | |
| const path_size = hex8() | |
| const checksum = hex8() // will only be set if id is "070702" | |
| const path = string(path_size - 1) | |
| if (path === 'TRAILER!!!') break | |
| const file = { | |
| id, inode, mode, uid, gid, links, mod, size, major, minor, dev_major, | |
| dev_minor, path_size, checksum, path, type, perms, | |
| suid, sgid, sticky | |
| } | |
| align() | |
| if (type === 'link') { | |
| file.link_path = string(size) | |
| } else { | |
| file.data = buffer(size) | |
| } | |
| align() | |
| files.push(file) | |
| } | |
| return files | |
| } | |
| function build_cpio (entries) { | |
| function octal (n, sz) { | |
| const str = n.toString(8).padStart(sz, '0') | |
| off += sz | |
| return str | |
| } | |
| function hex (n, sz) { | |
| const str = n.toString(16).padStart(sz, '0') | |
| off += sz | |
| return str | |
| } | |
| function string (s) { | |
| const str = `${s}\0` | |
| off += str.length // TODO - UTF8 | |
| return str | |
| } | |
| function align () { | |
| const over = off % 4 | |
| if (over === 0) return | |
| off += 4 - over | |
| } | |
| function buffer (b) { | |
| off += b.length | |
| return b | |
| } | |
| function get_type (entry) { | |
| const { type } = entry | |
| if (type === 'reg') return S_IFREG | |
| if (type === 'dir') return S_IFDIR | |
| if (type === 'blk') return S_IFBLK | |
| if (type === 'chr') return S_IFCHR | |
| return S_IFREG | |
| } | |
| function get_perms (entry) { | |
| const { type, exe } = entry | |
| if (type === 'reg') { | |
| if (exe) return S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IXOTH | |
| return S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH | |
| } | |
| if (type === 'dir') return S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH | |
| if (type === 'blk') return S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH | |
| if (type === 'chr') return S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | |
| return 0 | |
| } | |
| function get_size (entry) { | |
| const { type } = entry | |
| if (type === 'reg') { | |
| const st = stat(entry.source) | |
| return st.size | |
| } | |
| return 0 | |
| } | |
| function get_dev (entry) { | |
| if (entry.type !== 'chr' && entry.type !== 'blk') return { major: 0, minor: 0 } | |
| const [ major, minor ] = entry.dev.split('.').map(v => parseInt(v, 10)) | |
| return { major, minor } | |
| } | |
| function create_entry (entry) { | |
| off = 0 | |
| const id = octal(29121, 6) | |
| const inode = hex(next_inode++, 8) | |
| const mode = hex(get_perms(entry) | get_type(entry), 8) | |
| const uid = hex(0, 8) | |
| const gid = hex(0, 8) | |
| const links = hex(0, 8) | |
| const mod = hex(Math.floor(Date.now() / 1000), 8) | |
| const size = hex(get_size(entry), 8) | |
| const dev = get_dev(entry) | |
| const major = hex(8, 8) | |
| const minor = hex(1, 8) | |
| const dev_major = hex(dev.major, 8) | |
| const dev_minor = hex(dev.minor, 8) | |
| const path_size = hex(entry.path.length + 1, 8) | |
| const checksum = hex(0, 8) | |
| const path = string(entry.path) | |
| let payload | |
| align() | |
| if (entry.type === 'link') { | |
| payload = encoder.encode(string(entry.link_path)) | |
| } else if (entry.type === 'reg') { | |
| payload = buffer(readFileSync(entry.source)) | |
| } | |
| align() | |
| const dest = new Uint8Array(off) | |
| const text = `${id}${inode}${mode}${uid}${gid}${links}${mod}${size}${major}${minor}${dev_major}${dev_minor}${path_size}${checksum}${path}` | |
| const { written } = encoder.encodeInto(text, dest) | |
| off = written | |
| align() | |
| if (payload) dest.set(payload, off) | |
| return dest | |
| } | |
| const sections = [] | |
| let off = 0 | |
| let next_inode = 1 | |
| for (const entry of entries) { | |
| sections.push(create_entry(entry)) | |
| } | |
| sections.push(create_entry({ path: 'TRAILER!!!' })) | |
| return sections | |
| } | |
| function col (type, perms) { | |
| if (type === 'reg') { | |
| if (perms) { | |
| const executable = perms.map(p => p.split('')[2]).includes('x') | |
| if (executable) return AG | |
| } | |
| return AD | |
| } | |
| if (type === 'dir') return AC | |
| if (type === 'link') return AG | |
| if (type === 'sock') return AG | |
| if (type === 'chr') return AY | |
| return AY | |
| } | |
| function header () { | |
| const fields = [] | |
| fields.push('path'.padEnd(40, ' ')) | |
| fields.push('type'.padEnd(6, ' ')) | |
| fields.push('inode'.padEnd(10, ' ')) | |
| fields.push('size'.padStart(20, ' ')) | |
| fields.push('modified'.padStart(30, ' ')) | |
| fields.push('perm'.padStart(10, ' ')) | |
| fields.push('ver'.padStart(6, ' ')) | |
| fields.push('dev'.padStart(6, ' ')) | |
| fields.push('uid'.padStart(8, ' ')) | |
| fields.push('gid'.padStart(8, ' ')) | |
| fields.push('links'.padStart(6, ' ')) | |
| fields.push('suid'.padStart(4, ' ')) | |
| fields.push('sgid'.padStart(4, ' ')) | |
| fields.push('stky'.padStart(4, ' ')) | |
| return `${AG}${fields.join(' ')}${AD}\n${'-'.repeat(175)}` | |
| } | |
| function dump_file (file) { | |
| const { | |
| path, inode, type, size, mod, major, minor, dev_major, dev_minor, uid, gid, links, | |
| suid, sgid, sticky | |
| } = file | |
| const fields = [] | |
| const perms = get_perms(file.perms) | |
| fields.push(`${col(type, perms)}${path.padEnd(40, ' ')}${AD}`) | |
| fields.push(`${type.padEnd(6, ' ')}`) | |
| fields.push(`${inode.toString().padEnd(10, ' ')}`) | |
| fields.push(`${size.toString().padStart(20, ' ')}`) | |
| fields.push(`${AY}${(new Date(mod)).toISOString().padStart(30, ' ')}${AD}`) | |
| fields.push(`${perms.join('').padStart(10, ' ')}`) | |
| fields.push(`${(major + "." + minor).padStart(6, ' ')}`) | |
| fields.push(`${(dev_major + "." + dev_minor).padStart(6, ' ')}`) | |
| fields.push(`${uid.toString().padStart(8, ' ')}`) | |
| fields.push(`${gid.toString().padStart(8, ' ')}`) | |
| fields.push(`${links.toString().padStart(6, ' ')}`) | |
| fields.push(`${suid.toString().padStart(4, ' ')}`) | |
| fields.push(`${sgid.toString().padStart(4, ' ')}`) | |
| fields.push(`${sticky.toString().padStart(4, ' ')}`) | |
| return fields.join(' ') | |
| } | |
| const mode = { x: 1, w: 2, r: 4 } | |
| const IF_TYPE = 0o170000 | |
| const IF_SOCK = 0o140000 | |
| const IF_LINK = 0o120000 | |
| const IF_REG = 0o100000 | |
| const IF_BLK = 0o060000 | |
| const IF_DIR = 0o040000 | |
| const IF_CHR = 0o020000 | |
| const IF_PIPE = 0o010000 | |
| const IF_SUID = 0o004000 | |
| const IF_SGID = 0o002000 | |
| const IF_STICKY = 0o001000 | |
| const IF_PERM = 0o000777 | |
| function dump_cpio (path) { | |
| const files = parse_cpio(readFileSync(path)) | |
| dump_parsed(files) | |
| } | |
| function dump_parsed (files) { | |
| let total = 0 | |
| console.log(header()) | |
| for (const file of files) { | |
| console.log(dump_file(file)) | |
| total += file.size | |
| } | |
| console.log(`\ntotal: ${total}`) | |
| } | |
| export { parse_cpio, build_cpio, dump_cpio, dump_parsed } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment