iobroker.backitup
Version:
ioBroker.backitup allows you to backup and restore your ioBroker installation and other systems, such as databases, Zigbee, scripts and many more.
137 lines (121 loc) • 4.73 kB
JavaScript
const copyFile = require('../tools').copyFile;
const path = require('node:path');
const fs = require('node:fs');
function copyFiles(dir, fileNames, log, errors, callback) {
if (!fileNames || !fileNames.length) {
callback && callback();
} else {
let fileName = fileNames.shift();
fileName = fileName.replace(/\\/g, '/');
const onlyFileName = fileName.split('/').pop();
try {
log.debug(`Copy ${onlyFileName}...`);
copyFile(fileName, path.join(dir, onlyFileName), err => {
if (err) {
errors.cifs = err;
log.error(err);
}
setImmediate(copyFiles, dir, fileNames, log, errors, callback);
});
} catch (e) {
log.error(e);
errors.cifs = e;
setImmediate(copyFiles, dir, fileNames, log, errors, callback);
}
}
}
function deleteFiles(files, log, errors) {
try {
for (let f = 0; f < files.length; f++) {
log.debug(`delete ${files[f]}`);
fs.unlinkSync(files[f]);
}
return true;
} catch (e) {
errors.cifs = errors.cifs || e;
log.error(e);
}
}
function cleanFiles(dir, options, names, num, log, errors) {
if (!num) {
return;
}
try {
if (dir[dir.length - 1] !== '/') {
dir += '/';
}
let result = fs.readdirSync(dir);
if (result && result.length) {
const files = [];
names.forEach(name => {
const subResult = result.filter(a => a.startsWith(name));
let numDel = num;
if (name === 'influxDB' && options.influxDBMulti) numDel = num * options.influxDBEvents.length;
if (name === 'mysql' && options.mySqlMulti) numDel = num * options.mySqlEvents.length;
if (name === 'pgsql' && options.pgSqlMulti) numDel = num * options.pgSqlEvents.length;
if (name === 'homematic' && options.ccuMulti) numDel = num * options.ccuEvents.length;
if (subResult.length > numDel) {
// delete oldest files
subResult.sort((a, b) => {
const at = fs.statSync(dir + a).ctime;
const bt = fs.statSync(dir + b).ctime;
if (at > bt) return -1;
if (at < bt) return 1;
return 0;
});
for (let i = numDel; i < subResult.length; i++) {
files.push(path.join(dir, subResult[i]));
}
}
});
deleteFiles(files, log, errors);
}
} catch (e) {
errors.cifs = errors.cifs || e;
}
}
function command(options, log, callback) {
if (options.dir && options.context && options.context.fileNames && options.context.fileNames.length) {
const fileNames = JSON.parse(JSON.stringify(options.context.fileNames));
let dir = options.dir.replace(/\\/g, '/');
if (dir[0] !== '/' && !dir.match(/\w:/)) {
dir = `/${dir || ''}`;
}
log.debug(`used copy path: ${dir}`);
if (fs.existsSync(dir)) {
if (dir === options.backupDir) {
callback && callback(`The storage path "${dir}" for copying is not configured correctly`);
} else {
copyFiles(dir, fileNames, log, options.context.errors, err => {
if (err) {
log.error(err);
options.context.errors.cifs = options.context.errors.cifs || err;
}
if (options.deleteOldBackup === true) {
// todo: function cleanFiles returns nothing
if (cleanFiles(dir, options, options.context.types, options.deleteBackupAfter, log, options.context.errors)) {
!options.context.errors.cifs && options.context.done.push('cifs');
}
} else {
!options.context.errors.cifs && options.context.done.push('cifs');
}
if (callback) {
callback(err);
callback = null;
}
});
}
} else if (options.mountType === 'Copy') {
callback && callback(`Path "${dir}" not found`);
} else {
callback && callback();
}
} else {
callback && callback();
}
}
module.exports = {
command,
ignoreErrors: true
};
;