diff --git a/src/tools.ts b/src/tools.ts index c8eef98..4bc1ded 100644 --- a/src/tools.ts +++ b/src/tools.ts @@ -179,13 +179,26 @@ export async function updateFfmpeg(): Promise { } const found = await findBinaries(work, ['ffmpeg', 'ffprobe']) if (!found.ffmpeg) throw new Error('압축에서 ffmpeg 바이너리를 찾지 못했습니다.') + if (!found.ffprobe) throw new Error('압축에서 ffprobe 바이너리를 찾지 못했습니다.') + // 1) 임시 위치(*.new)로 복사 + 실행 검증. 둘 다 통과해야만 교체한다. + const staged: Array<{ name: 'ffmpeg' | 'ffprobe'; tmp: string; dest: string }> = [] for (const name of ['ffmpeg', 'ffprobe'] as const) { const src = found[name] if (!src) continue const dest = path.join(binDir, name) - await fs.copyFile(src, dest) - await fs.chmod(dest, 0o755) + const tmp = dest + '.new' + await fs.rm(tmp, { force: true }) + await fs.copyFile(src, tmp) + await fs.chmod(tmp, 0o755) + const v = spawnSync(tmp, ['-version'], { encoding: 'utf8' }) + if (v.status !== 0) { + await fs.rm(tmp, { force: true }) + throw new Error('내려받은 ' + name + ' 가 실행되지 않습니다.') + } + staged.push({ name, tmp, dest }) } + // 2) 검증을 모두 통과한 뒤에만 원자적 교체(rename). + for (const s of staged) await fs.rename(s.tmp, s.dest) } finally { await fs.rm(work, { recursive: true, force: true }) }