ref: 73744b9f4896c513d4d7c40ef4ce1d24703810e9
parent: f188f2f0738b4888130f9f07181f4cc367afb2d1
author: cinap_lenrek <[email protected]>
date: Wed Nov 21 10:34:12 EST 2012
derp: handle file type changes handle cases when files become directories or directories become files.
--- a/sys/man/1/derp
+++ b/sys/man/1/derp
@@ -22,8 +22,10 @@
.I oldfile
as reference. The changes found are printed
to standard output, one per line, with the file
-status describing either side followed by tabulator
-and the relative file path.
+status describing either sides actions followed
+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
The possible status codes:
.TP
--- a/sys/src/cmd/derp.c
+++ b/sys/src/cmd/derp.c
@@ -31,6 +31,18 @@
#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 {
BUFSIZE = 8*1024,
};
@@ -146,16 +158,33 @@
d = dirstat(path);
if(d == nil)
error("can't stat %s: %r", path);
- else
- d->name = strdup(path);
+ else {
+ d->name = emalloc(strlen(path)+1);
+ strcpy(d->name, path);
+ }
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*
absdir(Dir *d, char *path)
{
if(d != nil)
- d->name = smprint("%s/%s", path, d->name);
+ d->name = pjoin(path, d->name);
return d;
}
@@ -252,7 +281,7 @@
od = nil;
if(t < 0){
- sp = smprint("%s/%s", path, ld[i].name);
+ sp = pjoin(path, ld[i].name);
if(ap == lp)
od = &ld[i];
else while(k < o){
@@ -270,7 +299,7 @@
od = nil;
i++;
} else {
- sp = smprint("%s/%s", path, rd[j].name);
+ sp = pjoin(path, rd[j].name);
if(ap == rp)
od = &rd[j];
else while(k < o){
@@ -310,12 +339,9 @@
void
diffgen(Dir *ld, Dir *rd, Dir *ad, char *path)
{
- char *p;
-
if(dcmp(ld, rd) == 0)
return;
- p = nil;
if(ld == nil || rd == nil){
/* one side doesnt exit anymore */
if(ad != nil){
@@ -322,10 +348,14 @@
/* existed before, is deletion */
if(ld != nil && (ad->qid.type & QTDIR) && (ld->qid.type & QTDIR)){
/* 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)){
/* 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){
/* local deleted file, local newer */
print("dn\t%s\n", path);
@@ -333,11 +363,23 @@
/* remote deleted file, remote newer */
print("nd\t%s\n", path);
} 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 */
print("md!\t%s\n", path);
+ return;
} 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 */
print("dm!\t%s\n", path);
+ return;
}
} else {
/* didnt exist before, is addition */
@@ -355,14 +397,39 @@
if((ad->qid.type & QTDIR) && (ld->qid.type & QTDIR) && (rd->qid.type & QTDIR)){
/* all still directories, no problem */
} 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 */
print("mn\t%s\n", path);
} 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 */
print("nm\t%s\n", path);
} else {
- /* local and remote modified, conflict */
- print("mm!\t%s\n", path);
+ if((ld->qid.type & QTDIR) != (ad->qid.type & QTDIR) &&
+ (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 {
/* didnt exist before, is addition from both */
@@ -369,18 +436,14 @@
if((ld->qid.type & QTDIR) && (rd->qid.type & QTDIR)){
/* local and remote added directories, no problem */
} else {
- /* local and remote added files, conflict */
+ /* local and remote added diverging files, conflict */
print("aa!\t%s\n", path);
+ return;
}
}
}
diffdir(ld, rd, ad, path);
-
- if(p != nil){
- print("%s", p);
- free(p);
- }
}
void
@@ -387,38 +450,27 @@
diff3(char *lp, char *ap, char *rp)
{
Dir *ld, *rd, *ad;
- char *name;
- rd = ad = nil;
- if((ld = statdir(lp)) == nil)
+ ad = nil;
+ ld = statdir(lp);
+ rd = statdir(rp);
+ if(ld == nil && rd == nil)
goto Out;
- if((rd = statdir(rp)) == nil)
- goto Out;
-
- if(strcmp(ap, lp) == 0)
+ else if(strcmp(ap, lp) == 0)
ad = ld;
else if(strcmp(ap, rp) == 0)
ad = rd;
- else if((ad = statdir(ap)) == nil)
- goto Out;
- else if(samefile(ad, ld)){
- freedir(ad);
- ad = ld;
+ else if((ad = statdir(ap)) != nil){
+ if(ld != nil && samefile(ad, ld)){
+ freedir(ad);
+ ad = ld;
+ }
+ else if(rd != nil && samefile(ad, rd)){
+ freedir(ad);
+ ad = rd;
+ }
}
- else if(samefile(ad, rd)){
- freedir(ad);
- ad = rd;
- }
-
- if(ld->qid.type & QTDIR)
- name = ".";
- else {
- if(name = strrchr(lp, '/'))
- name++;
- else
- name = lp;
- }
- diffgen(ld, rd, ad, name);
+ diffgen(ld, rd, ad, "");
Out:
freedir(ld);
freedir(rd);