Update util.writeFile to write to tmp file before rename

This commit is contained in:
Nick O'Leary 2020-08-13 17:17:40 +01:00
parent bcd85b11a1
commit b0b2c32654
No known key found for this signature in database
GPG Key ID: 4F2157149161A6C9
1 changed files with 36 additions and 18 deletions

View File

@ -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