vfs: read directory and check for a file before mkdir

Before this change when doing Mkdir the VFS layer could add the new
item to an unread directory which caused confusion.

It could also do mkdir on a file when run on a bucket based remote
which would temporarily overwrite the file with a directory.

Fixes #2993
This commit is contained in:
Nick Craig-Wood 2019-02-27 16:38:32 +00:00
parent e3bceb9083
commit 173dfbd051
2 changed files with 44 additions and 2 deletions

View File

@ -458,8 +458,23 @@ func (d *Dir) Mkdir(name string) (*Dir, error) {
return nil, EROFS return nil, EROFS
} }
path := path.Join(d.path, name) path := path.Join(d.path, name)
node, err := d.stat(name)
switch err {
case ENOENT:
// not found, carry on
case nil:
// found so check what it is
if node.IsDir() {
return node.(*Dir), err
}
return nil, EEXIST
default:
// a different error - report
fs.Errorf(d, "Dir.Mkdir failed to read directory: %v", err)
return nil, err
}
// fs.Debugf(path, "Dir.Mkdir") // fs.Debugf(path, "Dir.Mkdir")
err := d.f.Mkdir(path) err = d.f.Mkdir(path)
if err != nil { if err != nil {
fs.Errorf(d, "Dir.Mkdir failed to create directory: %v", err) fs.Errorf(d, "Dir.Mkdir failed to create directory: %v", err)
return nil, err return nil, err
@ -600,7 +615,7 @@ func (d *Dir) Rename(oldName, newName string, destDir *Dir) error {
} }
default: default:
err = errors.Errorf("unknown type %T", oldNode) err = errors.Errorf("unknown type %T", oldNode)
fs.Errorf(d.path, "Dir.ReadDirAll error: %v", err) fs.Errorf(d.path, "Dir.Rename error: %v", err)
return err return err
} }

View File

@ -353,6 +353,33 @@ func TestDirMkdir(t *testing.T) {
assert.Equal(t, EROFS, err) assert.Equal(t, EROFS, err)
} }
func TestDirMkdirSub(t *testing.T) {
r := fstest.NewRun(t)
defer r.Finalise()
vfs, dir, file1 := dirCreate(t, r)
_, err := dir.Mkdir("file1")
assert.Error(t, err)
sub, err := dir.Mkdir("sub")
assert.NoError(t, err)
subsub, err := sub.Mkdir("subsub")
assert.NoError(t, err)
// check the vfs
checkListing(t, dir, []string{"file1,14,false", "sub,0,true"})
checkListing(t, sub, []string{"subsub,0,true"})
checkListing(t, subsub, []string(nil))
// check the underlying r.Fremote
fstest.CheckListingWithPrecision(t, r.Fremote, []fstest.Item{file1}, []string{"dir", "dir/sub", "dir/sub/subsub"}, r.Fremote.Precision())
vfs.Opt.ReadOnly = true
_, err = dir.Mkdir("sausage")
assert.Equal(t, EROFS, err)
}
func TestDirRemove(t *testing.T) { func TestDirRemove(t *testing.T) {
r := fstest.NewRun(t) r := fstest.NewRun(t)
defer r.Finalise() defer r.Finalise()