improve native isolation

This commit is contained in:
olcxja 2026-10-07 08:26:57 +02:00
commit 9748b98163
15 changed files with 341 additions and 95 deletions

View file

@ -199,6 +199,49 @@ async function chmodTree(root) {
return { files, dirs }
}
// One file, streamed, with byte progress: copyFile says nothing until a
// multi-gigabyte copy is over. The bytes land on a .part name and are renamed
// at the end, so nothing can ever read a half-written document.
async function copyFileProgress(src, dst, onProgress) {
const stat = await fsp.stat(src)
if (!stat.isFile()) throw new Error('not a file: ' + src)
const gate = onProgress ? progressGate(onProgress) : null
await fsp.mkdir(path.dirname(dst), { recursive: true })
const part = dst + '.part'
let bytes = 0
try {
await new Promise((resolve, reject) => {
const input = fs.createReadStream(src)
const output = fs.createWriteStream(part)
const fail = err => {
input.destroy()
output.destroy()
reject(err)
}
input.on('error', fail)
output.on('error', fail)
input.on('data', chunk => {
bytes += chunk.length
if (gate) gate({ done: 0, bytes }, false)
})
output.on('finish', resolve)
input.pipe(output)
})
await fsp.chmod(part, stat.mode & 0o777)
await fsp.rename(part, dst)
} catch (err) {
try {
await fsp.rm(part, { force: true })
} catch {}
throw err
}
if (gate) {
gate({ done: 1, bytes: stat.size }, true)
gate.done()
}
return { files: 1, bytes: stat.size }
}
// Delete deepest-first with progress through onProgress; symlinks are
// unlinked, never followed.
async function removeTree(root, onProgress) {
@ -266,5 +309,5 @@ async function removeTree(root, onProgress) {
return { files, dirs, bytes }
}
module.exports = { pathExists, dedupeDir, copyTree, treeSize, removeTree, chmodTree, progressGate, mapLimit }
module.exports = { pathExists, dedupeDir, copyTree, copyFileProgress, treeSize, removeTree, chmodTree, progressGate, mapLimit }