diff --git a/packages/node_modules/@node-red/runtime/lib/nodes/context/localfilesystem.js b/packages/node_modules/@node-red/runtime/lib/nodes/context/localfilesystem.js index 10b4349b8..0f83573e8 100644 --- a/packages/node_modules/@node-red/runtime/lib/nodes/context/localfilesystem.js +++ b/packages/node_modules/@node-red/runtime/lib/nodes/context/localfilesystem.js @@ -137,6 +137,16 @@ function stringify(value) { return { json: result, circular: hasCircular }; } + +function writeFileAtomic(storagePath, content) { + // To protect against file corruption, write to a tmp file first and then + // rename to the destination file + let finalFile = storagePath + ".json"; + let tmpFile = finalFile + "."+Date.now()+".tmp"; + return fs.outputFile(tmpFile, content, "utf8").then(function() { + return fs.rename(tmpFile,finalFile); + }) +} function LocalFileSystem(config){ this.config = config; this.storageBaseDir = getBasePath(this.config); @@ -202,7 +212,7 @@ LocalFileSystem.prototype.open = function(){ delete self.knownCircularRefs[scope]; } log.debug("Flushing localfilesystem context scope "+scope); - promises.push(fs.outputFile(storagePath + ".json", stringifiedContext.json, "utf8")); + promises.push(writeFileAtomic(storagePath, stringifiedContext.json)) }); delete self._pendingWriteTimeout; return Promise.all(promises); @@ -319,7 +329,7 @@ LocalFileSystem.prototype.set = function(scope, key, value, callback) { } else { delete self.knownCircularRefs[scope]; } - return fs.outputFile(storagePath + ".json", stringifiedContext.json, "utf8"); + return writeFileAtomic(storagePath, stringifiedContext.json); }).then(function(){ if(typeof callback === "function"){ callback(null);