From 6b9c8bced66853ed36379204a70b30ac5be223d2 Mon Sep 17 00:00:00 2001 From: Jakob Ackermann Date: Mon, 17 May 2021 14:18:07 +0100 Subject: [PATCH] [ContentCacheManager] write streams to disk atomically Use an intermediate file for writing to disk, then rename to the target. --- services/clsi/app/js/ContentCacheManager.js | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/services/clsi/app/js/ContentCacheManager.js b/services/clsi/app/js/ContentCacheManager.js index 94ed9ebc00..a32a952ca5 100644 --- a/services/clsi/app/js/ContentCacheManager.js +++ b/services/clsi/app/js/ContentCacheManager.js @@ -100,17 +100,27 @@ async function writePdfStream(dir, hash, buffers) { // ETags used for client side caching via browser internals. return false } catch (e) {} - const file = await fs.promises.open(filename, 'w') + const atomicWriteFilename = filename + '~' + const file = await fs.promises.open(atomicWriteFilename, 'w') if (Settings.enablePdfCachingDark) { // Write an empty file in dark mode. buffers = [] } try { - for (const buffer of buffers) { - await file.write(buffer) + try { + for (const buffer of buffers) { + await file.write(buffer) + } + } finally { + await file.close() + } + await fs.promises.rename(atomicWriteFilename, filename) + } catch (err) { + try { + await fs.promises.unlink(atomicWriteFilename) + } catch (_) { + throw err } - } finally { - await file.close() } return true }