feat(backups-cli): dont report compressed XVAs as broken (#4642)

Detect compressed XVAs and don't try to validate them with tar heuristic.
This commit is contained in:
Julien Fontanet
2019-11-04 14:33:50 +01:00
committed by GitHub
parent 1c767b709f
commit 7f26aea585

View File

@@ -44,43 +44,62 @@ const asyncMap = curryRight((iterable, fn) =>
const filter = (...args) => thisArg => thisArg.filter(...args)
// TODO: better check?
const isGzipFile = async fd => {
// https://tools.ietf.org/html/rfc1952.html#page-5
const magicNumber = Buffer.allocUnsafe(2)
assert.strictEqual(
await fs.read(fd, magicNumber, 0, magicNumber.length, 0),
magicNumber.length
)
return magicNumber[0] === 31 && magicNumber[1] === 139
}
// TODO: better check?
//
// our heuristic is not good enough, there has been some false positives
// (detected as invalid by us but valid by `tar` and imported with success),
// either:
// either THOUGH THEY MAY HAVE BEEN COMPRESSED FILES:
// - these files were normal but the check is incorrect
// - these files were invalid but without data loss
// - these files were invalid but with silent data loss
//
// FIXME: the heuristic does not work if the XVA is compressed, we need to
// implement a specific test for it
//
// maybe reading the end of the file looking for a file named
// /^Ref:\d+/\d+\.checksum$/ and then validating the tar structure from it
//
// https://github.com/npm/node-tar/issues/234#issuecomment-538190295
const isValidTar = async path => {
const isValidTar = async (size, fd) => {
if (size <= 1024 || size % 512 !== 0) {
return false
}
const buf = Buffer.allocUnsafe(1024)
assert.strictEqual(
await fs.read(fd, buf, 0, buf.length, size - buf.length),
buf.length
)
return buf.every(_ => _ === 0)
}
// TODO: find an heuristic for compressed files
const isValidXva = async path => {
try {
const fd = await fs.open(path, 'r')
try {
const { size } = await fs.fstat(fd)
if (size <= 1024 || size % 512 !== 0) {
if (size < 20) {
// neither a valid gzip not tar
return false
}
const buf = Buffer.allocUnsafe(1024)
assert.strictEqual(
await fs.read(fd, buf, 0, buf.length, size - buf.length),
buf.length
)
return buf.every(_ => _ === 0)
return (await isGzipFile(fd))
? true // gzip files cannot be validated at this time
: await isValidTar(size, fd)
} finally {
fs.close(fd).catch(noop)
}
} catch (error) {
// never throw, log and report as valid to avoid side effects
console.error('isValidTar', path, error)
console.error('isValidXva', path, error)
return true
}
}
@@ -245,7 +264,7 @@ async function handleVm(vmDir) {
await asyncMap(xvas, async path => {
// check is not good enough to delete the file, the best we can do is report
// it
if (!(await isValidTar(path))) {
if (!(await isValidXva(path))) {
console.warn('Potential broken XVA', path)
console.warn('')
}