Skip to content

Commit 663fd00

Browse files
authored
Merge pull request #1885 from rumpl/fix/use-os-remove-instead-of-syscall-rmdir
Replace syscall.Rmdir with golang.org/x/sys for cross-platform directory removal
2 parents 87c3c68 + b91c896 commit 663fd00

File tree

4 files changed

+28
-7
lines changed

4 files changed

+28
-7
lines changed

pkg/tools/builtin/filesystem.go

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package builtin
33
import (
44
"context"
55
"encoding/json"
6-
"errors"
76
"fmt"
87
"io/fs"
98
"log/slog"
@@ -13,7 +12,6 @@ import (
1312
"regexp"
1413
"strings"
1514
"sync"
16-
"syscall"
1715

1816
"github.com/docker/cagent/pkg/fsx"
1917
"github.com/docker/cagent/pkg/tools"
@@ -756,10 +754,7 @@ func (t *FilesystemTool) handleRemoveDirectory(_ context.Context, args RemoveDir
756754
for _, path := range args.Paths {
757755
resolvedPath := t.resolvePath(path)
758756

759-
if err := syscall.Rmdir(resolvedPath); err != nil {
760-
if errors.Is(err, syscall.ENOTDIR) {
761-
return tools.ResultError(fmt.Sprintf("Error: %s is not a directory", path)), nil
762-
}
757+
if err := rmdir(resolvedPath); err != nil {
763758
return tools.ResultError(fmt.Sprintf("Error removing directory %s: %s", path, err)), nil
764759
}
765760
results = append(results, fmt.Sprintf("Directory removed successfully: %s", path))

pkg/tools/builtin/filesystem_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -738,7 +738,7 @@ func TestFilesystemTool_RemoveDirectory_IsFile(t *testing.T) {
738738
})
739739
require.NoError(t, err)
740740
assert.True(t, result.IsError)
741-
assert.Contains(t, result.Output, "is not a directory")
741+
assert.Contains(t, result.Output, "not a directory")
742742
}
743743

744744
func TestFilesystemTool_RemoveDirectory_MultipleStopsOnError(t *testing.T) {

pkg/tools/builtin/rmdir_unix.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
2+
3+
package builtin
4+
5+
import "golang.org/x/sys/unix"
6+
7+
// rmdir removes an empty directory. It returns an error if the path is not
8+
// a directory (e.g. ENOTDIR) without the TOCTOU race that a stat-then-remove
9+
// sequence would have, because unix.Rmdir is a single atomic syscall.
10+
func rmdir(path string) error {
11+
return unix.Rmdir(path)
12+
}

pkg/tools/builtin/rmdir_windows.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package builtin
2+
3+
import "golang.org/x/sys/windows"
4+
5+
// rmdir removes an empty directory. It returns an error if the path is not
6+
// a directory without the TOCTOU race that a stat-then-remove sequence would
7+
// have, because windows.RemoveDirectory is a single atomic syscall.
8+
func rmdir(path string) error {
9+
p, err := windows.UTF16PtrFromString(path)
10+
if err != nil {
11+
return err
12+
}
13+
return windows.RemoveDirectory(p)
14+
}

0 commit comments

Comments
 (0)