#!/usr/bin/nesla
/*
* This script makes a summary report of all files in a directory (recursive).
* It records the date, time, size, and a cryptographic hash (md5 or sha1)
* of the contents of each file. Directories themselves are mostly ignored.
*
* If a previous summary exists, a detailed comparison can be made of the
* differences, including files with modified contents, deleted files, and
* also new files.
*
* Creating a new report from a script;
* nesla -e "global newlist=1;include('/utils/scripts/dirhash.ns');" > hashlist.txt
*
* Comparing an old report with the current status from a script;
* nesla -e "global hashlist='hashlist.txt';include('/utils/scripts/dirhash.ns');"
* or just
* nesla -f dirhash.ns
*
*/
global hashtype='sha1';
//global hashtype='md5';
if (newlist!=null) {
global noise=2;
} else {
global noise=1;
}
global totalfiles=0;
global totalsize=0;
global newtab={};
function printcommas(n) {
if ((n=math.floor(n))>=1000) {
printcommas(n/1000);
print(","+string.sub(tostring(n), -3));
} else {
print(tostring(n));
}
}
function dirsub(pwd) {
_d=dirlist(pwd);
for (i=0;;i++) {
var x=iname(_d, i);
if (typeof(_d[x])!='table') break;
if (string.cmp(x, '.')==0) continue;
if (string.cmp(x, '..')==0) continue;
fullname=pwd+"/"+x;
if (_d[x].type=='dir') {
dirsub(fullname);
} else if (_d[x].type=='file') {
if (hashtype=='sha1') h=file.sha1(fullname);
else /* default md5 *//* default md5 */ h=file.md5(fullname);
l=h+"|"+string.sub(tostring(_d[x].size)+" ",0,9)+"|"+_d[x].mtime+"|"+fullname;
newtab[totalfiles]={ date=_d[x].mtime, hash=h, name=fullname, size=_d[x].size };
if (noise>1) print(l+"\n"); else if (noise==1) print(".");
global totalsize+=_d[x].size;
totalfiles++;
io.flush();
}
}
return;
}
function dircmp() {
io.flush();
if (hashlist==null) global hashlist="hashlist.txt";
if (typeof(file.stat(hashlist))!='table') return;
global oldtab=string.split(file.read(hashlist), '\n');
s1=sizeof(newtab);
s2=sizeof(oldtab);
for (i=0;i<s1;i++) {
if (typeof(newtab[i])!='table') continue;
if (sizeof(newtab[i])!=4) continue;
for (j=0;j<s2;j++) {
if (typeof(oldtab[j])=='string') {
if (string.sub(oldtab[j], -1)=='\r') {
oldtab[j]=string.sub(oldtab[j], 0, sizeof(oldtab[j])-1);
}
t=string.split(oldtab[j], '|');
if (sizeof(t)!=4) { oldtab[j]=null; continue; }
oldtab[j]={ date=tonumber(t[2]), hash=t[0], name=t[3], size=tonumber(t[1]) };
}
if (typeof(oldtab[j])!='table') continue;
if (sizeof(oldtab[j])!=4) continue;
if (newtab[i].name==oldtab[j].name) {
/* name match */
if (newtab[i].hash!=oldtab[j].hash) {
print("\nhash mismatch ["+newtab[i].name+"]");
if (noise>0) print("\n");
} else if (newtab[i].size!=oldtab[j].size) {
print("\nsize mismatch ["+newtab[i].name+"]");
if (noise>0) print("\n");
} else if (newtab[i].date!=oldtab[j].date) {
print("\ndate mismatch ["+newtab[i].name+"]");
if (noise>0) print("\n");
}
newtab[i]=null;
oldtab[j]=null;
}
}
if (noise>0) print(".");
io.flush();
}
print("\n");
for (i=0;i<sizeof(oldtab);i++) {
var x=iname(oldtab, i);
print("\ndeleted file [",oldtab[x].name,"] ");
}
for (i=0;i<sizeof(newtab);i++) {
var x=iname(newtab, i);
print("\nnew file [",newtab[x].name,"] ");
}
return;
}
dirsub(".");
if (newlist==null) {
print("\n"+totalfiles+" files ");
printcommas(totalsize);
print(" bytes\n");
dircmp();
}