Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion command/rm.go
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,9 @@ func validateRMCommand(c *cli.Context) error {
)
for i, srcurl := range srcurls {
// we don't operate on S3 prefixes for copy and delete operations.
if srcurl.IsBucket() || srcurl.IsPrefix() {
// When --raw is set the user explicitly targets a real object key that
// happens to end with "/", so skip the prefix guard in that case.
if srcurl.IsBucket() || (srcurl.IsPrefix() && !srcurl.IsRaw()) {
return fmt.Errorf("s3 bucket/prefix cannot be used for delete operations (forgot wildcard character?)")
}

Expand Down
45 changes: 45 additions & 0 deletions command/rm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,51 @@ import (
"github.com/urfave/cli/v2"
)

// TestRemoveCommand_DirobjKeyWithRawFlag verifies that a key ending with "/"
// (a directory-marker object, "DIROBJ") can be targeted when --raw is set.
// Without --raw the prefix guard correctly rejects such keys; with --raw the
// user has explicitly opted out of prefix treatment and the key must pass
// validation so that the actual S3 DeleteObject call can proceed.
func TestRemoveCommand_DirobjKeyWithRawFlag(t *testing.T) {
t.Parallel()

// Build a flagset that mirrors what NewDeleteCommand registers.
cmd := NewDeleteCommand()
set := flagSet(t, cmd.Name, cmd.Flags)

// Simulate: s5cmd rm --raw s3://bucket/dirobj/
if err := set.Set("raw", "true"); err != nil {
t.Fatalf("setting --raw flag: %v", err)
}
if err := set.Parse([]string{"s3://bucket/dirobj/"}); err != nil {
t.Fatalf("parsing args: %v", err)
}

ctx := cli.NewContext(nil, set, nil)
if err := validateRMCommand(ctx); err != nil {
t.Errorf("expected no error with --raw for a key ending in '/'; got: %v", err)
}
}

// TestRemoveCommand_PrefixWithoutRawFlag verifies that the prefix guard still
// rejects keys ending with "/" when --raw is not set.
func TestRemoveCommand_PrefixWithoutRawFlag(t *testing.T) {
t.Parallel()

cmd := NewDeleteCommand()
set := flagSet(t, cmd.Name, cmd.Flags)

if err := set.Parse([]string{"s3://bucket/prefix/"}); err != nil {
t.Fatalf("parsing args: %v", err)
}

ctx := cli.NewContext(nil, set, nil)
err := validateRMCommand(ctx)
if err == nil {
t.Error("expected error for prefix key without --raw; got nil")
}
}

func TestValidateRMCommand(t *testing.T) {
t.Parallel()

Expand Down
Loading