From b0b2c3265401e5fb97cb4e582d593e04ba8a16d3 Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Thu, 13 Aug 2020 17:17:40 +0100 Subject: [PATCH] Update util.writeFile to write to tmp file before rename --- .../lib/storage/localfilesystem/util.js | 54 ++++++++++++------- 1 file changed, 36 insertions(+), 18 deletions(-) diff --git a/packages/node_modules/@node-red/runtime/lib/storage/localfilesystem/util.js b/packages/node_modules/@node-red/runtime/lib/storage/localfilesystem/util.js index b18c80643..d07d40868 100644 --- a/packages/node_modules/@node-red/runtime/lib/storage/localfilesystem/util.js +++ b/packages/node_modules/@node-red/runtime/lib/storage/localfilesystem/util.js @@ -17,7 +17,6 @@ var fs = require('fs-extra'); var fspath = require('path'); var when = require('when'); -var nodeFn = require('when/node/function'); var log = require("@node-red/util").log; // TODO: separate module @@ -75,39 +74,58 @@ function readFile(path,backupPath,emptyResponse,type) { module.exports = { /** - * Write content to a file using UTF8 encoding. - * This forces a fsync before completing to ensure - * the write hits disk. - */ - writeFile: function(path,content,backupPath) { + * Write content to a file using UTF8 encoding. + * This forces a fsync before completing to ensure + * the write hits disk. + */ + writeFile: function(path,content,backupPath) { + var backupPromise; if (backupPath) { - if (fs.existsSync(path)) { - fs.renameSync(path,backupPath); - } + backupPromise = fs.copy(path,backupPath); + } else { + backupPromise = Promise.resolve(); } - return when.promise(function(resolve,reject) { - fs.ensureDir(fspath.dirname(path), (err)=>{ - if (err) { - reject(err); - return; - } - var stream = fs.createWriteStream(path); + + const dirname = fspath.dirname(path); + const tempFile = `${path}.$$$`; + + return backupPromise.then(() => { + if (backupPath) { + log.trace(`utils.writeFile - copied ${path} TO ${backupPath}`) + } + return fs.ensureDir(dirname) + }).then(() => { + return new Promise(function(resolve,reject) { + var stream = fs.createWriteStream(tempFile); stream.on('open',function(fd) { stream.write(content,'utf8',function() { fs.fsync(fd,function(err) { if (err) { - log.warn(log._("storage.localfilesystem.fsync-fail",{path: path, message: err.toString()})); + log.warn(log._("storage.localfilesystem.fsync-fail",{path: tempFile, message: err.toString()})); } stream.end(resolve); }); }); }); stream.on('error',function(err) { + log.warn(log._("storage.localfilesystem.fsync-fail",{path: tempFile, message: err.toString()})); reject(err); }); }); + }).then(() => { + log.trace(`utils.writeFile - written content to ${tempFile}`) + return new Promise(function(resolve,reject) { + fs.rename(tempFile,path,err => { + if (err) { + log.warn(log._("storage.localfilesystem.fsync-fail",{path: path, message: err.toString()})); + return reject(err); + } + log.trace(`utils.writeFile - renamed ${tempFile} to ${path}`) + resolve(); + }) + }); }); - }, + }, readFile: readFile, parseJSON: parseJSON