acme: use buffered i/o to write file

Bakul Shah has observed corrupted files being written
when acme writes over osxfuse to sshfs to a remote file system.
In one example we examined, acme is writing an 0xf03-byte
file in two system calls, first an 0x806-byte write and then a 0x6fd-byte
write. (0x806 is BUFSIZE/sizeof(Rune); this file has no multibyte UTF-8.)

What actually ends up happening is that an 0x806-byte file is written:

        0x000-0x6fd contains what should be 0x806-0xf03
        0x6fd-0x7fa contains zeros
        0x7fa-0x806 contains what should be 0x7fa-0x806 (correct!)

The theory is that fuse or sshfs or perhaps the remote file server is
mishandling the unaligned writes. acme does not seem to be at fault.

Using bio here will make the writes align to 8K boundaries,
avoiding the bugs in whatever underlying piece is broken.

TBR=r
https://codereview.appspot.com/89550043
diff --git a/src/cmd/acme/exec.c b/src/cmd/acme/exec.c
index 59ae228..0ef6684 100644
--- a/src/cmd/acme/exec.c
+++ b/src/cmd/acme/exec.c
@@ -1,5 +1,6 @@
 #include <u.h>
 #include <libc.h>
+#include <bio.h>
 #include <draw.h>
 #include <thread.h>
 #include <cursor.h>
@@ -633,6 +634,7 @@
 {
 	uint n, m;
 	Rune *r;
+	Biobuf *b;
 	char *s, *name;
 	int i, fd, q;
 	Dir *d, *d1;
@@ -660,6 +662,8 @@
 		warning(nil, "can't create file %s: %r\n", name);
 		goto Rescue1;
 	}
+	b = emalloc(sizeof *b);
+	Binit(b, fd, OWRITE);
 	r = fbufalloc();
 	s = fbufalloc();
 	free(d);
@@ -676,11 +680,18 @@
 			n = BUFSIZE/UTFmax;
 		bufread(&f->b, q, r, n);
 		m = snprint(s, BUFSIZE+1, "%.*S", n, r);
-		if(write(fd, s, m) != m){
+		if(Bwrite(b, s, m) != m){
 			warning(nil, "can't write file %s: %r\n", name);
 			goto Rescue2;
 		}
 	}
+	if(Bflush(b) < 0) {
+		warning(nil, "can't write file %s: %r\n", name);
+		goto Rescue2;
+	}
+	Bterm(b);
+	free(b);
+	b = nil;
 	if(runeeq(namer, nname, f->name, f->nname)){
 		if(q0!=0 || q1!=f->b.nc){
 			f->mod = TRUE;
@@ -727,6 +738,10 @@
 	return;
 
     Rescue2:
+	if(b != nil) {
+		Bterm(b);
+		free(b);
+	}
 	fbuffree(s);
 	fbuffree(r);
 	close(fd);