derp: handle file type changes

handle cases when files become directories or directories
become files.
This commit is contained in:
cinap_lenrek 2012-11-21 15:34:12 +01:00
parent f188f2f073
commit 73744b9f48
2 changed files with 100 additions and 46 deletions

View file

@ -22,8 +22,10 @@ using a third common backup directory
.I oldfile .I oldfile
as reference. The changes found are printed as reference. The changes found are printed
to standard output, one per line, with the file to standard output, one per line, with the file
status describing either side followed by tabulator status describing either sides actions followed
and the relative file path. by tabulator and the relative file path which might
be empty in case when the changed files refers to the
ones given at program arguments.
.LP .LP
The possible status codes: The possible status codes:
.TP .TP

View file

@ -31,6 +31,18 @@ error(char *fmt, ...)
#pragma varargck argpos error 1 #pragma varargck argpos error 1
void*
emalloc(int n)
{
void *v;
if((v = malloc(n)) == nil){
noerror = 0;
error("out of memory");
}
return v;
}
enum { enum {
BUFSIZE = 8*1024, BUFSIZE = 8*1024,
}; };
@ -146,16 +158,33 @@ statdir(char *path)
d = dirstat(path); d = dirstat(path);
if(d == nil) if(d == nil)
error("can't stat %s: %r", path); error("can't stat %s: %r", path);
else else {
d->name = strdup(path); d->name = emalloc(strlen(path)+1);
strcpy(d->name, path);
}
return d; return d;
} }
char*
pjoin(char *path, char *name)
{
char *s;
int n;
n = strlen(path);
s = emalloc(n+strlen(name)+2);
strcpy(s, path);
if(path[0] != '\0' && path[n-1] != '/')
s[n++] = '/';
strcpy(s+n, name);
return s;
}
Dir* Dir*
absdir(Dir *d, char *path) absdir(Dir *d, char *path)
{ {
if(d != nil) if(d != nil)
d->name = smprint("%s/%s", path, d->name); d->name = pjoin(path, d->name);
return d; return d;
} }
@ -252,7 +281,7 @@ diffdir(Dir *ld, Dir *rd, Dir *ad, char *path)
od = nil; od = nil;
if(t < 0){ if(t < 0){
sp = smprint("%s/%s", path, ld[i].name); sp = pjoin(path, ld[i].name);
if(ap == lp) if(ap == lp)
od = &ld[i]; od = &ld[i];
else while(k < o){ else while(k < o){
@ -270,7 +299,7 @@ diffdir(Dir *ld, Dir *rd, Dir *ad, char *path)
od = nil; od = nil;
i++; i++;
} else { } else {
sp = smprint("%s/%s", path, rd[j].name); sp = pjoin(path, rd[j].name);
if(ap == rp) if(ap == rp)
od = &rd[j]; od = &rd[j];
else while(k < o){ else while(k < o){
@ -310,22 +339,23 @@ diffdir(Dir *ld, Dir *rd, Dir *ad, char *path)
void void
diffgen(Dir *ld, Dir *rd, Dir *ad, char *path) diffgen(Dir *ld, Dir *rd, Dir *ad, char *path)
{ {
char *p;
if(dcmp(ld, rd) == 0) if(dcmp(ld, rd) == 0)
return; return;
p = nil;
if(ld == nil || rd == nil){ if(ld == nil || rd == nil){
/* one side doesnt exit anymore */ /* one side doesnt exit anymore */
if(ad != nil){ if(ad != nil){
/* existed before, is deletion */ /* existed before, is deletion */
if(ld != nil && (ad->qid.type & QTDIR) && (ld->qid.type & QTDIR)){ if(ld != nil && (ad->qid.type & QTDIR) && (ld->qid.type & QTDIR)){
/* remote deleted direcotry, remote newer */ /* remote deleted direcotry, remote newer */
p = smprint("nd\t%s\n", path); diffdir(ld, nil, ad, path);
print("nd\t%s\n", path);
return;
} else if(rd != nil && (ad->qid.type & QTDIR) && (rd->qid.type & QTDIR)){ } else if(rd != nil && (ad->qid.type & QTDIR) && (rd->qid.type & QTDIR)){
/* local deleted direcotry, local newer */ /* local deleted direcotry, local newer */
p = smprint("dn\t%s\n", path); diffdir(nil, rd, ad, path);
print("dn\t%s\n", path);
return;
} else if(dcmp(rd, ad) == 0){ } else if(dcmp(rd, ad) == 0){
/* local deleted file, local newer */ /* local deleted file, local newer */
print("dn\t%s\n", path); print("dn\t%s\n", path);
@ -333,11 +363,23 @@ diffgen(Dir *ld, Dir *rd, Dir *ad, char *path)
/* remote deleted file, remote newer */ /* remote deleted file, remote newer */
print("nd\t%s\n", path); print("nd\t%s\n", path);
} else if(ld != nil){ } else if(ld != nil){
if((ld->qid.type ^ ad->qid.type) & QTDIR){
/* local file type change, remote deleted, no conflict */
diffgen(ld, nil, nil, path);
return;
}
/* local modified, remote deleted, conflict */ /* local modified, remote deleted, conflict */
print("md!\t%s\n", path); print("md!\t%s\n", path);
return;
} else { } else {
if((rd->qid.type ^ ad->qid.type) & QTDIR){
/* remote file type change, local deleted, no conflict */
diffgen(nil, rd, nil, path);
return;
}
/* remote modified, local deleted, conflict */ /* remote modified, local deleted, conflict */
print("dm!\t%s\n", path); print("dm!\t%s\n", path);
return;
} }
} else { } else {
/* didnt exist before, is addition */ /* didnt exist before, is addition */
@ -355,70 +397,80 @@ diffgen(Dir *ld, Dir *rd, Dir *ad, char *path)
if((ad->qid.type & QTDIR) && (ld->qid.type & QTDIR) && (rd->qid.type & QTDIR)){ if((ad->qid.type & QTDIR) && (ld->qid.type & QTDIR) && (rd->qid.type & QTDIR)){
/* all still directories, no problem */ /* all still directories, no problem */
} else if(dcmp(rd, ad) == 0){ } else if(dcmp(rd, ad) == 0){
if((ld->qid.type ^ ad->qid.type) & QTDIR){
/* local file type change */
diffgen(nil, ad, ad, path);
diffgen(ld, nil, nil, path);
return;
}
/* local modified file, local newer */ /* local modified file, local newer */
print("mn\t%s\n", path); print("mn\t%s\n", path);
} else if(dcmp(ld, ad) == 0){ } else if(dcmp(ld, ad) == 0){
if((rd->qid.type ^ ad->qid.type) & QTDIR){
/* remote file type change */
diffgen(ad, nil, ad, path);
diffgen(nil, rd, nil, path);
return;
}
/* remote modified file, remote newer */ /* remote modified file, remote newer */
print("nm\t%s\n", path); print("nm\t%s\n", path);
} else { } else {
/* local and remote modified, conflict */ if((ld->qid.type & QTDIR) != (ad->qid.type & QTDIR) &&
print("mm!\t%s\n", path); (rd->qid.type & QTDIR) != (ad->qid.type & QTDIR) &&
(ld->qid.type & QTDIR) == (rd->qid.type & QTDIR)){
if((ad->qid.type & QTDIR) == 0){
/* local and remote became directories, was file before */
diffdir(ld, rd, nil, path);
} else {
/* local and remote became diverging files, conflict */
print("aa!\t%s\n", path);
}
} else {
/* local and remote modified, conflict */
print("mm!\t%s\n", path);
}
return;
} }
} else { } else {
/* didnt exist before, is addition from both */ /* didnt exist before, is addition from both */
if((ld->qid.type & QTDIR) && (rd->qid.type & QTDIR)){ if((ld->qid.type & QTDIR) && (rd->qid.type & QTDIR)){
/* local and remote added directories, no problem */ /* local and remote added directories, no problem */
} else { } else {
/* local and remote added files, conflict */ /* local and remote added diverging files, conflict */
print("aa!\t%s\n", path); print("aa!\t%s\n", path);
return;
} }
} }
} }
diffdir(ld, rd, ad, path); diffdir(ld, rd, ad, path);
if(p != nil){
print("%s", p);
free(p);
}
} }
void void
diff3(char *lp, char *ap, char *rp) diff3(char *lp, char *ap, char *rp)
{ {
Dir *ld, *rd, *ad; Dir *ld, *rd, *ad;
char *name;
rd = ad = nil; ad = nil;
if((ld = statdir(lp)) == nil) ld = statdir(lp);
rd = statdir(rp);
if(ld == nil && rd == nil)
goto Out; goto Out;
if((rd = statdir(rp)) == nil) else if(strcmp(ap, lp) == 0)
goto Out;
if(strcmp(ap, lp) == 0)
ad = ld; ad = ld;
else if(strcmp(ap, rp) == 0) else if(strcmp(ap, rp) == 0)
ad = rd; ad = rd;
else if((ad = statdir(ap)) == nil) else if((ad = statdir(ap)) != nil){
goto Out; if(ld != nil && samefile(ad, ld)){
else if(samefile(ad, ld)){ freedir(ad);
freedir(ad); ad = ld;
ad = ld; }
else if(rd != nil && samefile(ad, rd)){
freedir(ad);
ad = rd;
}
} }
else if(samefile(ad, rd)){ diffgen(ld, rd, ad, "");
freedir(ad);
ad = rd;
}
if(ld->qid.type & QTDIR)
name = ".";
else {
if(name = strrchr(lp, '/'))
name++;
else
name = lp;
}
diffgen(ld, rd, ad, name);
Out: Out:
freedir(ld); freedir(ld);
freedir(rd); freedir(rd);