diff --git a/pkg/config/error.go b/pkg/config/error.go index 01be115..f6ce154 100644 --- a/pkg/config/error.go +++ b/pkg/config/error.go @@ -43,5 +43,6 @@ var ( ErrWriteCacheTypeUnsupported = errors.New("write cache type unsupported") ErrWriteCacheTypeUnknown = errors.New("write cache type unknown") - ErrNoRootDirectory = errors.New("root directory could not be found") + ErrNoRootDirectory = errors.New("root directory could not be found") + ErrDirectoryNotEmpty = errors.New("directory not empty") ) diff --git a/pkg/fs/filesystem.go b/pkg/fs/filesystem.go index 9e4dfbe..79c11d8 100644 --- a/pkg/fs/filesystem.go +++ b/pkg/fs/filesystem.go @@ -446,6 +446,40 @@ func (f *STFS) Remove(name string) error { f.ioLock.Lock() defer f.ioLock.Unlock() + hdr, err := inventory.Stat( + f.metadata, + + name, + false, + + f.onHeader, + ) + if err != nil { + if err == sql.ErrNoRows { + return os.ErrNotExist + } + + return err + } + + if hdr.Typeflag == tar.TypeDir { + hdrs, err := inventory.List( + f.metadata, + + name, + -1, + + f.onHeader, + ) + if err != nil { + return err + } + + if len(hdrs) > 0 { + return config.ErrDirectoryNotEmpty + } + } + return f.writeOps.Delete(name) } diff --git a/pkg/fs/filesystem_test.go b/pkg/fs/filesystem_test.go index ffa73b5..53a9ace 100644 --- a/pkg/fs/filesystem_test.go +++ b/pkg/fs/filesystem_test.go @@ -1372,27 +1372,82 @@ var removeTests = []struct { }, false, }, - // FIXME: STFS can delete directories using `Remove` even if it isn't empty - // { - // "Can not remove /mydir if it is a directory and not empty", - // removeArgs{"/mydir"}, - // true, - // func(f afero.Fs) error { - // if err := f.Mkdir("/mydir", os.ModePerm); err != nil { - // return err - // } + { + "Can not remove /mydir if it is a directory and not empty", + removeArgs{"/mydir"}, + true, + func(f afero.Fs) error { + if err := f.Mkdir("/mydir", os.ModePerm); err != nil { + return err + } - // if _, err := f.Create("/mydir/test.txt"); err != nil { - // return err - // } + if _, err := f.Create("/mydir/test.txt"); err != nil { + return err + } - // return nil - // }, - // func(f afero.Fs) error { - // return nil - // }, - // false, - // }, + return nil + }, + func(f afero.Fs) error { + return nil + }, + false, + }, + { + "Can not remove /mydir/subdir if it is a directory and not empty", + removeArgs{"/mydir/subdir"}, + true, + func(f afero.Fs) error { + if err := f.Mkdir("/mydir", os.ModePerm); err != nil { + return err + } + + if err := f.Mkdir("/mydir/subdir", os.ModePerm); err != nil { + return err + } + + if _, err := f.Create("/mydir/subdir/test.txt"); err != nil { + return err + } + + return nil + }, + func(f afero.Fs) error { + if _, err := f.Stat("/mydir/subdir/test.txt"); !errors.Is(err, os.ErrNotExist) { + return err + } + + if _, err := f.Stat("/mydir/subdir"); !errors.Is(err, os.ErrNotExist) { + return err + } + + return nil + }, + false, + }, + { + "Can remove /mydir/subdir if it is a directory and empty", + removeArgs{"/mydir/subdir"}, + false, + func(f afero.Fs) error { + if err := f.Mkdir("/mydir", os.ModePerm); err != nil { + return err + } + + if err := f.Mkdir("/mydir/subdir", os.ModePerm); err != nil { + return err + } + + return nil + }, + func(f afero.Fs) error { + if _, err := f.Stat("/mydir/subdir"); !errors.Is(err, os.ErrNotExist) { + return err + } + + return nil + }, + false, + }, } func TestSTFS_Remove(t *testing.T) {