From 35a64369837f76280ac02df882d19bfc69614891 Mon Sep 17 00:00:00 2001
From: Nick Craig-Wood <nick@craig-wood.com>
Date: Fri, 6 Jan 2017 11:24:22 +0000
Subject: [PATCH] mount: implement proper directory handling (mkdir, rmdir)

Before this change mount only simulated rmdir & mkdir, now it actually
runs mkdir & rmdir on the underlying remote, using the new parmaeters
to fs.Mkdir and fs.Rmdir.

Fixes #956
---
 cmd/mount/dir.go   | 28 ++++++++++++++++++++++------
 cmd/mount/mount.go | 18 +++++++++---------
 2 files changed, 31 insertions(+), 15 deletions(-)

diff --git a/cmd/mount/dir.go b/cmd/mount/dir.go
index 4e9761376..e94253ef1 100644
--- a/cmd/mount/dir.go
+++ b/cmd/mount/dir.go
@@ -273,10 +273,13 @@ var _ fusefs.NodeMkdirer = (*Dir)(nil)
 
 // Mkdir creates a new directory
 func (d *Dir) Mkdir(ctx context.Context, req *fuse.MkdirRequest) (fusefs.Node, error) {
-	// We just pretend to have created the directory - rclone will
-	// actually create the directory if we write files into it
 	path := path.Join(d.path, req.Name)
 	fs.Debug(path, "Dir.Mkdir")
+	err := d.f.Mkdir(path)
+	if err != nil {
+		fs.ErrorLog(path, "Dir.Mkdir failed to create directory: %v", err)
+		return nil, err
+	}
 	fsDir := &fs.Dir{
 		Name: path,
 		When: time.Now(),
@@ -308,10 +311,7 @@ func (d *Dir) Remove(ctx context.Context, req *fuse.RemoveRequest) error {
 			return err
 		}
 	case *fs.Dir:
-		// Do nothing for deleting directory - rclone can't
-		// currently remote a random directory
-		//
-		// Check directory is empty first though
+		// Check directory is empty first
 		dir := item.node.(*Dir)
 		empty, err := dir.isEmpty()
 		if err != nil {
@@ -323,6 +323,12 @@ func (d *Dir) Remove(ctx context.Context, req *fuse.RemoveRequest) error {
 			fs.ErrorLog(path, "Dir.Remove not empty")
 			return fuse.EEXIST
 		}
+		// remove directory
+		err = d.f.Rmdir(path)
+		if err != nil {
+			fs.ErrorLog(path, "Dir.Remove failed to remove directory: %v", err)
+			return err
+		}
 	default:
 		fs.ErrorLog(path, "Dir.Remove unknown type %T", item)
 		return errors.Errorf("unknown type %T", item)
@@ -380,6 +386,16 @@ func (d *Dir) Rename(ctx context.Context, req *fuse.RenameRequest, newDir fusefs
 			fs.ErrorLog(oldPath, "Dir.Rename can't rename non empty directory")
 			return fuse.EEXIST
 		}
+		err = d.f.Rmdir(oldPath)
+		if err != nil {
+			fs.ErrorLog(oldPath, "Dir.Rename failed to remove directory: %v", err)
+			return err
+		}
+		err = d.f.Mkdir(newPath)
+		if err != nil {
+			fs.ErrorLog(newPath, "Dir.Rename failed to create directory: %v", err)
+			return err
+		}
 		newObj = &fs.Dir{
 			Name: newPath,
 			When: time.Now(),
diff --git a/cmd/mount/mount.go b/cmd/mount/mount.go
index 1fb0337e2..88c177836 100644
--- a/cmd/mount/mount.go
+++ b/cmd/mount/mount.go
@@ -88,16 +88,16 @@ Or with OS X
 ### Limitations ###
 
 This can only write files seqentially, it can only seek when reading.
+This means that many applications won't work with their files on an
+rclone mount.
 
-Rclone mount inherits rclone's directory handling.  In rclone's world
-directories don't really exist.  This means that empty directories
-will have a tendency to disappear once they fall out of the directory
-cache.
-
-The bucket based FSes (eg swift, s3, google compute storage, b2) won't
-work from the root - you will need to specify a bucket, or a path
-within the bucket.  So ` + "`swift:`" + ` won't work whereas ` + "`swift:bucket`" + ` will
-as will ` + "`swift:bucket/path`" + `.
+The bucket based remotes (eg Swift, S3, Google Compute Storage, B2,
+Hubic) won't work from the root - you will need to specify a bucket,
+or a path within the bucket.  So ` + "`swift:`" + ` won't work whereas
+` + "`swift:bucket`" + ` will as will ` + "`swift:bucket/path`" + `.
+None of these support the concept of directories, so empty
+directories will have a tendency to disappear once they fall out of
+the directory cache.
 
 Only supported on Linux, FreeBSD and OS X at the moment.