Rewrite history: 9front was first

History was built using a heuristic where a file not present in
the dump in 30 days was considered as a deleted file, without
being important if those days had an actual dump. Having the file
server off 30 days made all the files to be deleted from the
history point of view. This new version is rewriten from scratch
in rc and it does not try to detect deleted files since it can
be derived only with fragile assumptions.
This commit is contained in:
Roberto E. Vargas Caballero 2022-08-08 16:56:11 +00:00
parent 6d99af6f34
commit e55b6a5aff
3 changed files with 76 additions and 369 deletions

73
rc/bin/history Normal file
View file

@ -0,0 +1,73 @@
#!/bin/rc
rfork e
nl='
'
fn prfile {
echo -n `{date $flagu -f 'MMM DD hh:mm:ss ZZZ YYYY' `{walk -e m $1}}
walk -e psM $1 | awk '{printf " %s %lld [%s]\n", $1,$2,$3,$4}'
}
fn diffflags {
t=()
for(f in a b c e m n w) {
flagname=flag$f
if(~ $$flagname 1)
t=(-$f $t)
}
echo $t
}
fn ysearch {
if(~ $1 /*)
file=$1
if not
file=`{pwd}^/$1
if(test -f $file)
prfile $file
if not
echo history: warning: $file does not exist >[1=2]
old=()
ls -qr /n/$dump/*/*/$file >[2] /dev/null |
sed 's/\(([^ ]*) *([^ ]*) *([^ ]*)\)/\1\2\3/p' |
awk '"/n/'$dump/$since'" <= $2 {next}
$1 != qid {
qid=$1
gsub($1, "")
print}' |
while(new=`$nl{read}){
prfile $new
if (~ $flagD 1 && ~ $#old 1)
diff `{diffflags} $new $old
old=$new
}
}
flagfmt='D,a,b,f,c,e,m,n,w,u,d:dump,s since'
args='[ -Dabcemnw ] [ -uf ] [ -d dumpfilesystem ] [ -s yyyymmdd ] files ...'
if(! ifs=() eval `{aux/getflags $*} ||
~ $#* 0 ||
! ~ $#dump 0 && ! ~ $#dump 1 ||
! ~ $#flags 0 && ! ~ $#flags 1) {
aux/usage
exit usage
}
if(~ $#dump 0)
dump=dump
if(~ $#flags 0)
flags=`{date -f 'YYYYMMDD'}
if(~ $#flagu 1)
flagu=-u
since=`{date -f 'YYYY\/MMDD' `{seconds -f 'YYYYMMDD' $flags}}
9fs $dump
for(arg in $*)
ysearch $arg

View file

@ -6,7 +6,7 @@ history \- print file names from the dump
[
.B -Dabcemnw
] [
.B -fuv
.B -fu
] [
.B -d
.I dumpfilesystem
@ -38,18 +38,6 @@ May 10 16:40:51 EDT 2001 /n/dump/2001/0511/adm/users 10476 [adm]
...
.EE
.PP
When presented with a path of the form
.BI /n/ fs / path \fR,
.I history
will use
.IB fs dump
as the name of the dump file system, and will print a history of
.IR path .
.PP
The
.B -v
option enables verbose debugging printout.
.PP
The
.B -D
option causes
@ -78,9 +66,8 @@ option selects some other dump file system such as
.PP
The
.B -f
option forces the search to continue even when the
file in question does not exist (useful for files that only
exist intermittently).
option is accepted
but ignored by compatibilty with other history implementations.
.PP
Finally, the
.B -s

View file

@ -1,353 +0,0 @@
#include <u.h>
#include <libc.h>
#define MINUTE(x) ((long)(x)*60L)
#define HOUR(x) (MINUTE(x)*60L)
#define YEAR(x) (HOUR(x)*24L*360L)
int verb;
int uflag;
int force;
int diff;
char* sflag;
char* dargv[20] = {
"diff",
};
int ndargv = 1;
void usage(void);
void ysearch(char*, char*);
long starttime(char*);
void lastbefore(ulong, char*, char*, char*);
char* prtime(ulong);
void darg(char*);
void
main(int argc, char *argv[])
{
int i;
char *ndump;
ndump = nil;
ARGBEGIN {
default:
usage();
case 'a':
darg("-a");
break;
case 'b':
darg("-b");
break;
case 'c':
darg("-c");
break;
case 'e':
darg("-e");
break;
case 'm':
darg("-m");
break;
case 'n':
darg("-n");
break;
case 'w':
darg("-w");
break;
case 'D':
diff = 1;
break;
case 'd':
ndump = ARGF();
break;
case 'f':
force = 1;
break;
case 's':
sflag = ARGF();
break;
case 'u':
uflag = 1;
break;
case 'v':
verb = 1;
break;
} ARGEND
if(argc == 0)
usage();
for(i=0; i<argc; i++)
ysearch(argv[i], ndump);
exits(0);
}
void
darg(char* a)
{
if(ndargv >= nelem(dargv)-3)
return;
dargv[ndargv++] = a;
}
void
usage(void)
{
fprint(2, "usage: history [-bDfuv] [-d dumpfilesystem] [-s yyyymmdd] files\n");
exits("usage");
}
void
ysearch(char *file, char *ndump)
{
char fil[400], buf[500], nbuf[100], pair[2][500], *p;
Tm *tm;
Waitmsg *w;
Dir *dir, *d;
ulong otime, dt;
int toggle, started, missing;
fil[0] = 0;
if(file[0] != '/') {
getwd(strchr(fil, 0), 100);
strcat(fil, "/");
}
strcat(fil, file);
if(memcmp(fil, "/n/", 3) == 0){
p = strchr(fil+3, '/');
if(p == nil)
p = fil+strlen(fil);
if(ndump == nil){
if(p-fil >= sizeof nbuf-10){
fprint(2, "%s: dump name too long", fil);
return;
}
memmove(nbuf, fil+3, p-(fil+3));
nbuf[p-(fil+3)] = 0;
strcat(nbuf, "dump");
ndump = nbuf;
}
memmove(fil, p, strlen(p)+1);
}
if(ndump == nil)
ndump = "dump";
tm = localtime(time(0));
snprint(buf, sizeof buf, "/n/%s/%.4d/", ndump, tm->year+1900);
if(access(buf, AREAD) < 0) {
if(verb)
print("mounting dump %s\n", ndump);
if(rfork(RFFDG|RFPROC) == 0) {
execl("/bin/rc", "rc", "9fs", ndump, nil);
exits(0);
}
w = wait();
if(w == nil){
fprint(2, "history: wait error: %r\n");
exits("wait");
}
if(w->msg[0] != '\0'){
fprint(2, "9fs failed: %s\n", w->msg);
exits(w->msg);
}
free(w);
}
started = 0;
dir = dirstat(file);
if(dir == nil)
fprint(2, "history: warning: %s does not exist\n", file);
else{
print("%s %s %lld [%s]\n", prtime(dir->mtime), file, dir->length, dir->muid);
started = 1;
strecpy(pair[1], pair[1]+sizeof pair[1], file);
}
free(dir);
otime = starttime(sflag);
toggle = 0;
for(;;) {
lastbefore(otime, fil, buf, ndump);
dir = dirstat(buf);
if(dir == nil) {
if(!force)
return;
dir = malloc(sizeof(Dir));
nulldir(dir);
dir->mtime = otime + 1;
}
dt = HOUR(12);
missing = 0;
while(otime <= dir->mtime){
if(verb)
print("backup %ld, %ld\n", dir->mtime, otime-dt);
lastbefore(otime-dt, fil, buf, ndump);
d = dirstat(buf);
if(d == nil){
if(!force)
return;
if(!missing)
print("removed %s\n", buf);
missing = 1;
}else{
free(dir);
dir = d;
}
dt += HOUR(12);
}
strcpy(pair[toggle], buf);
if(diff && started){
switch(rfork(RFFDG|RFPROC)){
case 0:
dargv[ndargv] = pair[toggle];
dargv[ndargv+1] = pair[toggle ^ 1];
exec("/bin/diff", dargv);
fprint(2, "can't exec diff: %r\n");
exits(0);
case -1:
fprint(2, "can't fork diff: %r\n");
break;
default:
while(waitpid() != -1)
;
break;
}
}
print("%s %s %lld [%s]\n", prtime(dir->mtime), buf, dir->length, dir->muid);
toggle ^= 1;
started = 1;
otime = dir->mtime;
free(dir);
}
}
void
lastbefore(ulong t, char *f, char *b, char *ndump)
{
Tm *tm;
Dir *dir;
int vers, try;
ulong t0, mtime;
int i, n, fd;
t0 = t;
if(verb)
print("%ld lastbefore %s\n", t0, f);
mtime = 0;
for(try=0; try<30; try++) {
tm = localtime(t);
sprint(b, "/n/%s/%.4d/%.2d%.2d", ndump,
tm->year+1900, tm->mon+1, tm->mday);
dir = dirstat(b);
if(dir){
mtime = dir->mtime;
free(dir);
}
if(dir==nil || mtime > t0) {
if(verb)
print("%ld earlier %s\n", mtime, b);
t -= HOUR(24);
continue;
}
if(strstr(ndump, "snap")){
fd = open(b, OREAD);
if(fd < 0)
continue;
n = dirreadall(fd, &dir);
close(fd);
if(n == 0)
continue;
for(i = n-1; i > 0; i--){
if(dir[i].mtime > t0)
break;
}
sprint(b, "/n/%s/%.4d/%.2d%.2d/%s%s", ndump,
tm->year+1900, tm->mon+1, tm->mday, dir[i].name, f);
free(dir);
} else {
for(vers=0;; vers++) {
sprint(b, "/n/%s/%.4d/%.2d%.2d%d", ndump,
tm->year+1900, tm->mon+1, tm->mday, vers+1);
dir = dirstat(b);
if(dir){
mtime = dir->mtime;
free(dir);
}
if(dir==nil || mtime > t0)
break;
if(verb)
print("%ld later %s\n", mtime, b);
}
sprint(b, "/n/%s/%.4d/%.2d%.2d%s", ndump,
tm->year+1900, tm->mon+1, tm->mday, f);
if(vers)
sprint(b, "/n/%s/%.4d/%.2d%.2d%d%s", ndump,
tm->year+1900, tm->mon+1, tm->mday, vers, f);
}
return;
}
strcpy(b, "XXX"); /* error */
}
char*
prtime(ulong t)
{
static char buf[100];
char *b;
Tm *tm;
if(uflag)
tm = gmtime(t);
else
tm = localtime(t);
b = asctime(tm);
memcpy(buf, b+4, 24);
buf[24] = 0;
return buf;
}
long
starttime(char *s)
{
Tm *tm;
long t, dt;
int i, yr, mo, da;
t = time(0);
if(s == 0)
return t;
for(i=0; s[i]; i++)
if(s[i] < '0' || s[i] > '9') {
fprint(2, "bad start time: %s\n", s);
return t;
}
if(strlen(s)==6){
yr = (s[0]-'0')*10 + s[1]-'0';
mo = (s[2]-'0')*10 + s[3]-'0' - 1;
da = (s[4]-'0')*10 + s[5]-'0';
if(yr < 70)
yr += 100;
}else if(strlen(s)==8){
yr = (((s[0]-'0')*10 + s[1]-'0')*10 + s[2]-'0')*10 + s[3]-'0';
yr -= 1900;
mo = (s[4]-'0')*10 + s[5]-'0' - 1;
da = (s[6]-'0')*10 + s[7]-'0';
}else{
fprint(2, "bad start time: %s\n", s);
return t;
}
t = 0;
dt = YEAR(10);
for(i=0; i<50; i++) {
tm = localtime(t+dt);
if(yr > tm->year ||
(yr == tm->year && mo > tm->mon) ||
(yr == tm->year && mo == tm->mon) && da > tm->mday) {
t += dt;
continue;
}
dt /= 2;
if(dt == 0)
break;
}
t += HOUR(12); /* .5 day to get to noon of argument */
return t;
}