gtfs: Support intra-directory rename

9p can handle it.  This actually has a couple benefits apart from passing a
Go test:
- No needless copies for large files
- Atomic rename for intra-directory files, which is a common pattern for
  updating a file atomically.

Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
diff --git a/kern/drivers/dev/gtfs.c b/kern/drivers/dev/gtfs.c
index 6a596ea..a7284ba 100644
--- a/kern/drivers/dev/gtfs.c
+++ b/kern/drivers/dev/gtfs.c
@@ -517,6 +517,15 @@
 	poperror();
 }
 
+static void gtfs_wstat_rename(struct fs_file *f, const char *name)
+{
+	struct dir dir;
+
+	init_empty_dir(&dir);
+	dir.name = (char*)name;
+	wstat_dir(f, &dir);
+}
+
 static void gtfs_tf_rename(struct tree_file *tf, struct tree_file *old_parent,
                            struct tree_file *new_parent, const char *name,
                            int flags)
@@ -524,9 +533,16 @@
 	struct chan *tf_c = tf_to_gtfs_priv(tf)->be_walk;
 	struct chan *np_c = tf_to_gtfs_priv(new_parent)->be_walk;
 
-	if (!devtab[tf_c->type].rename)
+	if (!devtab[tf_c->type].rename) {
+		/* 9p can handle intra-directory renames, though some Akaros #devices
+		 * might throw. */
+		if (old_parent == new_parent) {
+			gtfs_wstat_rename(&tf->file, name);
+			return;
+		}
 		error(EXDEV, "%s: %s doesn't support rename", devname(),
 		      devtab[tf_c->type].name);
+	}
 	devtab[tf_c->type].rename(tf_c, np_c, name, flags);
 }
 
@@ -858,6 +874,7 @@
 	.write = tree_chan_write,
 	.bwrite = devbwrite,
 	.remove = gtfs_remove,
+	.rename = tree_chan_rename,
 	.wstat = gtfs_wstat,
 	.power = devpower,
 	.chaninfo = devchaninfo,