shithub: riscv

Download patch

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);