Skip to content

Commit

Permalink
Add directory parameter to Rmdir and Mkdir rclone#100 rclone#831
Browse files Browse the repository at this point in the history
This will enable rclone to manage directories properly in the future.
  • Loading branch information
ncw committed Nov 26, 2016
1 parent c41b67e commit aaa1370
Show file tree
Hide file tree
Showing 34 changed files with 220 additions and 89 deletions.
28 changes: 18 additions & 10 deletions amazonclouddrive/amazonclouddrive.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"io"
"log"
"net/http"
"path"
"regexp"
"strings"
"sync/atomic"
Expand Down Expand Up @@ -607,8 +608,15 @@ func (f *Fs) Put(in io.Reader, src fs.ObjectInfo) (fs.Object, error) {
}

// Mkdir creates the container if it doesn't exist
func (f *Fs) Mkdir() error {
return f.dirCache.FindRoot(true)
func (f *Fs) Mkdir(dir string) error {
err := f.dirCache.FindRoot(true)
if err != nil {
return err
}
if dir != "" {
_, err = f.dirCache.FindDir(dir, true)
}
return err
}

// Move src to this remote using server side move operations.
Expand Down Expand Up @@ -685,16 +693,16 @@ func (f *Fs) DirMove(src fs.Fs) (err error) {

// purgeCheck remotes the root directory, if check is set then it
// refuses to do so if it has anything in
func (f *Fs) purgeCheck(check bool) error {
if f.root == "" {
func (f *Fs) purgeCheck(dir string, check bool) error {
root := path.Join(f.root, dir)
if root == "" {
return errors.New("can't purge root directory")
}
dc := f.dirCache
err := dc.FindRoot(false)
rootID, err := dc.FindDir(dir, false)
if err != nil {
return err
}
rootID := dc.RootID()

if check {
// check directory is empty
Expand Down Expand Up @@ -730,7 +738,7 @@ func (f *Fs) purgeCheck(check bool) error {
return err
}

f.dirCache.ResetRoot()
f.dirCache.FlushDir(dir)
if err != nil {
return err
}
Expand All @@ -740,8 +748,8 @@ func (f *Fs) purgeCheck(check bool) error {
// Rmdir deletes the root folder
//
// Returns an error if it isn't empty
func (f *Fs) Rmdir() error {
return f.purgeCheck(true)
func (f *Fs) Rmdir(dir string) error {
return f.purgeCheck(dir, true)
}

// Precision return the precision of this Fs
Expand Down Expand Up @@ -783,7 +791,7 @@ func (f *Fs) Hashes() fs.HashSet {
// deleting all the files quicker than just running Remove() on the
// result of List()
func (f *Fs) Purge() error {
return f.purgeCheck(false)
return f.purgeCheck("", false)
}

// ------------------------------------------------------------
Expand Down
1 change: 1 addition & 0 deletions amazonclouddrive/amazonclouddrive_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ func TestFsString(t *testing.T) { fstests.TestFsString(t) }
func TestFsRmdirEmpty(t *testing.T) { fstests.TestFsRmdirEmpty(t) }
func TestFsRmdirNotFound(t *testing.T) { fstests.TestFsRmdirNotFound(t) }
func TestFsMkdir(t *testing.T) { fstests.TestFsMkdir(t) }
func TestFsMkdirRmdirSubdir(t *testing.T) { fstests.TestFsMkdirRmdirSubdir(t) }
func TestFsListEmpty(t *testing.T) { fstests.TestFsListEmpty(t) }
func TestFsListDirEmpty(t *testing.T) { fstests.TestFsListDirEmpty(t) }
func TestFsNewObjectNotFound(t *testing.T) { fstests.TestFsNewObjectNotFound(t) }
Expand Down
12 changes: 8 additions & 4 deletions b2/b2.go
Original file line number Diff line number Diff line change
Expand Up @@ -745,7 +745,11 @@ func (f *Fs) Put(in io.Reader, src fs.ObjectInfo) (fs.Object, error) {
}

// Mkdir creates the bucket if it doesn't exist
func (f *Fs) Mkdir() error {
func (f *Fs) Mkdir(dir string) error {
// Can't create subdirs
if dir != "" {
return nil
}
opts := rest.Opts{
Method: "POST",
Path: "/b2_create_bucket",
Expand Down Expand Up @@ -784,8 +788,8 @@ func (f *Fs) Mkdir() error {
// Rmdir deletes the bucket if the fs is at the root
//
// Returns an error if it isn't empty
func (f *Fs) Rmdir() error {
if f.root != "" {
func (f *Fs) Rmdir(dir string) error {
if f.root != "" || dir != "" {
return nil
}
opts := rest.Opts{
Expand Down Expand Up @@ -896,7 +900,7 @@ func (f *Fs) purge(oldOnly bool) error {
wg.Wait()

if !oldOnly {
checkErr(f.Rmdir())
checkErr(f.Rmdir(""))
}
return errReturn
}
Expand Down
1 change: 1 addition & 0 deletions b2/b2_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ func TestFsString(t *testing.T) { fstests.TestFsString(t) }
func TestFsRmdirEmpty(t *testing.T) { fstests.TestFsRmdirEmpty(t) }
func TestFsRmdirNotFound(t *testing.T) { fstests.TestFsRmdirNotFound(t) }
func TestFsMkdir(t *testing.T) { fstests.TestFsMkdir(t) }
func TestFsMkdirRmdirSubdir(t *testing.T) { fstests.TestFsMkdirRmdirSubdir(t) }
func TestFsListEmpty(t *testing.T) { fstests.TestFsListEmpty(t) }
func TestFsListDirEmpty(t *testing.T) { fstests.TestFsListDirEmpty(t) }
func TestFsNewObjectNotFound(t *testing.T) { fstests.TestFsNewObjectNotFound(t) }
Expand Down
2 changes: 1 addition & 1 deletion cmd/mkdir/mkdir.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ var mkdirCmd = &cobra.Command{
cmd.CheckArgs(1, 1, command, args)
fdst := cmd.NewFsDst(args)
cmd.Run(true, command, func() error {
return fs.Mkdir(fdst)
return fs.Mkdir(fdst, "")
})
},
}
2 changes: 1 addition & 1 deletion cmd/mount/fs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ func newRun() *Run {
log.Fatalf("Failed to open remote %q: %v", *RemoteName, err)
}

err = r.fremote.Mkdir()
err = r.fremote.Mkdir("")
if err != nil {
log.Fatalf("Failed to open mkdir %q: %v", *RemoteName, err)
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/rmdir/rmdir.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ objects in it, use purge for that.`,
cmd.CheckArgs(1, 1, command, args)
fdst := cmd.NewFsDst(args)
cmd.Run(true, command, func() error {
return fs.Rmdir(fdst)
return fs.Rmdir(fdst, "")
})
},
}
1 change: 1 addition & 0 deletions crypt/crypt2_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ func TestFsString2(t *testing.T) { fstests.TestFsString(t) }
func TestFsRmdirEmpty2(t *testing.T) { fstests.TestFsRmdirEmpty(t) }
func TestFsRmdirNotFound2(t *testing.T) { fstests.TestFsRmdirNotFound(t) }
func TestFsMkdir2(t *testing.T) { fstests.TestFsMkdir(t) }
func TestFsMkdirRmdirSubdir2(t *testing.T) { fstests.TestFsMkdirRmdirSubdir(t) }
func TestFsListEmpty2(t *testing.T) { fstests.TestFsListEmpty(t) }
func TestFsListDirEmpty2(t *testing.T) { fstests.TestFsListDirEmpty(t) }
func TestFsNewObjectNotFound2(t *testing.T) { fstests.TestFsNewObjectNotFound(t) }
Expand Down
1 change: 1 addition & 0 deletions crypt/crypt_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ func TestFsString(t *testing.T) { fstests.TestFsString(t) }
func TestFsRmdirEmpty(t *testing.T) { fstests.TestFsRmdirEmpty(t) }
func TestFsRmdirNotFound(t *testing.T) { fstests.TestFsRmdirNotFound(t) }
func TestFsMkdir(t *testing.T) { fstests.TestFsMkdir(t) }
func TestFsMkdirRmdirSubdir(t *testing.T) { fstests.TestFsMkdirRmdirSubdir(t) }
func TestFsListEmpty(t *testing.T) { fstests.TestFsListEmpty(t) }
func TestFsListDirEmpty(t *testing.T) { fstests.TestFsListDirEmpty(t) }
func TestFsNewObjectNotFound(t *testing.T) { fstests.TestFsNewObjectNotFound(t) }
Expand Down
29 changes: 29 additions & 0 deletions dircache/dircache.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,35 @@ func (dc *DirCache) Flush() {
dc.cacheMu.Unlock()
}

// FlushDir flushes the map of all data starting with dir
//
// If dir is empty then this is equivalent to calling ResetRoot
func (dc *DirCache) FlushDir(dir string) {
if dir == "" {
dc.ResetRoot()
return
}
dc.cacheMu.Lock()

// Delete the root dir
ID, ok := dc.cache[dir]
if ok {
delete(dc.cache, dir)
delete(dc.invCache, ID)
}

// And any sub directories
dir += "/"
for key, ID := range dc.cache {
if strings.HasPrefix(key, dir) {
delete(dc.cache, key)
delete(dc.invCache, ID)
}
}

dc.cacheMu.Unlock()
}

// SplitPath splits a path into directory, leaf
//
// Path shouldn't start or end with a /
Expand Down
31 changes: 22 additions & 9 deletions drive/drive.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"io"
"log"
"net/http"
"path"
"strings"
"time"

Expand Down Expand Up @@ -592,21 +593,30 @@ func (f *Fs) PutUnchecked(in io.Reader, src fs.ObjectInfo) (fs.Object, error) {
}

// Mkdir creates the container if it doesn't exist
func (f *Fs) Mkdir() error {
return f.dirCache.FindRoot(true)
func (f *Fs) Mkdir(dir string) error {
err := f.dirCache.FindRoot(true)
if err != nil {
return err
}
if dir != "" {
_, err = f.dirCache.FindDir(dir, true)
}
return err
}

// Rmdir deletes the container
//
// Returns an error if it isn't empty
func (f *Fs) Rmdir() error {
err := f.dirCache.FindRoot(false)
func (f *Fs) Rmdir(dir string) error {
root := path.Join(f.root, dir)
dc := f.dirCache
rootID, err := dc.FindDir(dir, false)
if err != nil {
return err
}
var children *drive.ChildList
err = f.pacer.Call(func() (bool, error) {
children, err = f.svc.Children.List(f.dirCache.RootID()).MaxResults(10).Do()
children, err = f.svc.Children.List(rootID).MaxResults(10).Do()
return shouldRetry(err)
})
if err != nil {
Expand All @@ -616,20 +626,23 @@ func (f *Fs) Rmdir() error {
return errors.Errorf("directory not empty: %#v", children.Items)
}
// Delete the directory if it isn't the root
if f.root != "" {
if root != "" {
err = f.pacer.Call(func() (bool, error) {
if *driveUseTrash {
_, err = f.svc.Files.Trash(f.dirCache.RootID()).Do()
_, err = f.svc.Files.Trash(rootID).Do()
} else {
err = f.svc.Files.Delete(f.dirCache.RootID()).Do()
err = f.svc.Files.Delete(rootID).Do()
}
return shouldRetry(err)
})
if err != nil {
return err
}
}
f.dirCache.ResetRoot()
f.dirCache.FlushDir(dir)
if err != nil {
return err
}
return nil
}

Expand Down
1 change: 1 addition & 0 deletions drive/drive_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ func TestFsString(t *testing.T) { fstests.TestFsString(t) }
func TestFsRmdirEmpty(t *testing.T) { fstests.TestFsRmdirEmpty(t) }
func TestFsRmdirNotFound(t *testing.T) { fstests.TestFsRmdirNotFound(t) }
func TestFsMkdir(t *testing.T) { fstests.TestFsMkdir(t) }
func TestFsMkdirRmdirSubdir(t *testing.T) { fstests.TestFsMkdirRmdirSubdir(t) }
func TestFsListEmpty(t *testing.T) { fstests.TestFsListEmpty(t) }
func TestFsListDirEmpty(t *testing.T) { fstests.TestFsListDirEmpty(t) }
func TestFsNewObjectNotFound(t *testing.T) { fstests.TestFsNewObjectNotFound(t) }
Expand Down
15 changes: 9 additions & 6 deletions dropbox/dropbox.go
Original file line number Diff line number Diff line change
Expand Up @@ -448,30 +448,33 @@ func (f *Fs) Put(in io.Reader, src fs.ObjectInfo) (fs.Object, error) {
}

// Mkdir creates the container if it doesn't exist
func (f *Fs) Mkdir() error {
entry, err := f.db.Metadata(f.slashRoot, false, false, "", "", metadataLimit)
func (f *Fs) Mkdir(dir string) error {
root := path.Join(f.slashRoot, dir)
entry, err := f.db.Metadata(root, false, false, "", "", metadataLimit)
if err == nil {
if entry.IsDir {
return nil
}
return errors.Errorf("%q already exists as file", f.root)
}
_, err = f.db.CreateFolder(f.slashRoot)
_, err = f.db.CreateFolder(root)
return err
}

// Rmdir deletes the container
//
// Returns an error if it isn't empty
func (f *Fs) Rmdir() error {
entry, err := f.db.Metadata(f.slashRoot, true, false, "", "", 16)
func (f *Fs) Rmdir(dir string) error {
root := path.Join(f.slashRoot, dir)
entry, err := f.db.Metadata(root, true, false, "", "", 16)
if err != nil {
return err
}
if len(entry.Contents) != 0 {
return errors.New("directory not empty")
}
return f.Purge()
_, err = f.db.Delete(root)
return err
}

// Precision returns the precision
Expand Down
1 change: 1 addition & 0 deletions dropbox/dropbox_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ func TestFsString(t *testing.T) { fstests.TestFsString(t) }
func TestFsRmdirEmpty(t *testing.T) { fstests.TestFsRmdirEmpty(t) }
func TestFsRmdirNotFound(t *testing.T) { fstests.TestFsRmdirNotFound(t) }
func TestFsMkdir(t *testing.T) { fstests.TestFsMkdir(t) }
func TestFsMkdirRmdirSubdir(t *testing.T) { fstests.TestFsMkdirRmdirSubdir(t) }
func TestFsListEmpty(t *testing.T) { fstests.TestFsListEmpty(t) }
func TestFsListDirEmpty(t *testing.T) { fstests.TestFsListDirEmpty(t) }
func TestFsNewObjectNotFound(t *testing.T) { fstests.TestFsNewObjectNotFound(t) }
Expand Down
4 changes: 2 additions & 2 deletions fs/fs.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,12 +135,12 @@ type Fs interface {
// Mkdir makes the directory (container, bucket)
//
// Shouldn't return an error if it already exists
Mkdir() error
Mkdir(dir string) error

// Rmdir removes the directory (container, bucket) if empty
//
// Return an error if it doesn't exist or isn't empty
Rmdir() error
Rmdir(dir string) error
}

// Info provides an interface to reading information about a filesystem.
Expand Down
14 changes: 7 additions & 7 deletions fs/operations.go
Original file line number Diff line number Diff line change
Expand Up @@ -707,12 +707,12 @@ func ListDir(f Fs, w io.Writer) error {
}

// Mkdir makes a destination directory or container
func Mkdir(f Fs) error {
func Mkdir(f Fs, dir string) error {
if Config.DryRun {
Log(f, "Not making directory as dry run is set")
return nil
}
err := f.Mkdir()
err := f.Mkdir(dir)
if err != nil {
Stats.Error()
return err
Expand All @@ -722,17 +722,17 @@ func Mkdir(f Fs) error {

// TryRmdir removes a container but not if not empty. It doesn't
// count errors but may return one.
func TryRmdir(f Fs) error {
func TryRmdir(f Fs, dir string) error {
if Config.DryRun {
Log(f, "Not deleting as dry run is set")
return nil
}
return f.Rmdir()
return f.Rmdir(dir)
}

// Rmdir removes a container but not if not empty
func Rmdir(f Fs) error {
err := TryRmdir(f)
func Rmdir(f Fs, dir string) error {
err := TryRmdir(f, dir)
if err != nil {
Stats.Error()
return err
Expand Down Expand Up @@ -764,7 +764,7 @@ func Purge(f Fs) error {
if err != nil {
return err
}
err = Rmdir(f)
err = Rmdir(f, "")
}
if err != nil {
Stats.Error()
Expand Down
Loading

0 comments on commit aaa1370

Please sign in to comment.