Created
April 20, 2022 10:03
-
-
Save ZReC/36bdac682b0780fe3ece425c1da372c9 to your computer and use it in GitHub Desktop.
It compares directories and outputs homonymous files bytes that aren't equal
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* The program compares same name files of different directories and | |
* outputs differences. Stops comparing if there's no bytes left in any file | |
*/ | |
import { join, resolve } from "https://deno.land/std@0.134.0/path/mod.ts"; | |
const szCHUNK = 512; | |
if (Deno.args.length < 2) { | |
throw new Error("you should provide at least two paths"); | |
} | |
interface File { | |
path: string, | |
descriptor: Deno.FsFile | |
} | |
const fnames: { [fname: string]: File[] } = {}; | |
for (const path of Deno.args) { | |
for await (const entry of Deno.readDir(path)) { | |
if (entry.isFile) { | |
const val: File = { path: resolve(path), descriptor: await Deno.open(join(path, entry.name)) }; | |
fnames[entry.name] | |
? fnames[entry.name].push(val) | |
: fnames[entry.name] = new Array(val); | |
} | |
} | |
} | |
for (const fname in fnames) { | |
if (fnames[fname].length > 1) { | |
const paths: Map<File, { buff: Uint8Array, byteLength: number }> = new Map(); | |
for (const v of fnames[fname]) { | |
paths.set(v, { buff: new Uint8Array(szCHUNK), byteLength: 0 }); | |
} | |
const diffArr: Array<[number, number | null]> = []; | |
const pointers: Set<number> = new Set(); | |
let chunk_offset = 0; | |
while (paths.size > 0) { | |
// await chunks | |
await Promise.all( | |
(() => { | |
const promises = []; | |
for (const path of paths) { | |
promises.push(path[0].descriptor.read(path[1].buff).then(v => { | |
if (v == null) { | |
paths.delete(path[0]); | |
} else { | |
path[1].byteLength = v; | |
} | |
})); | |
} | |
return promises; | |
})() | |
); | |
const pathsCopy = new Map(paths); | |
for (let i = 0; i < szCHUNK; i++) { | |
const entries = pathsCopy.entries(); | |
for (let [a, b] = entries; b != undefined; [b] = entries) { | |
if (i < a[1].byteLength && i < b[1].byteLength) { | |
if (a[1].buff[i] != b[1].buff[i]) { | |
const offset = i + chunk_offset * szCHUNK; | |
pointers.add(offset); | |
if (pointers.delete(offset - 1)) { | |
diffArr[diffArr.length - 1][1] = offset; | |
} else { | |
diffArr[diffArr.length] = [offset, null]; | |
} | |
break; | |
} | |
} | |
} | |
} | |
chunk_offset++; | |
} | |
if (diffArr.length > 0) { | |
const files = fnames[fname].map(v => v.descriptor); | |
console.log(`'${fname}' [${fnames[fname].map(v => v.path).join(', ')}]`); | |
for (const v of diffArr) { | |
const byteLength = 1 + (v[1] || v[0]) - v[0], pos = v[0].toString(16); | |
console.log(` $${pos.length & 1 ? '0' + pos : pos}`); | |
for (const f of files) { | |
const buffer = new Uint8Array(byteLength); | |
await f.seek(v[0], Deno.SeekMode.Start); | |
await f.read(buffer); | |
let str = ' '; | |
for (let i = 0; i < buffer.byteLength; i++) { | |
str += buffer[i].toString(16).padStart(2, '0') + (i % 32 == 31 ? '\n ' : ' '); | |
} | |
console.log(`${str.slice(0, -1)}\n`); | |
} | |
} | |
} | |
} | |
delete fnames[fname]; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment