Skip to content

Commit

Permalink
feat: Added some methods for sanitizing path on different platforms
Browse files Browse the repository at this point in the history
Signed-off-by: zongz <[email protected]>
  • Loading branch information
zong-zhe committed Mar 15, 2024
1 parent 116d6e4 commit 18abd37
Show file tree
Hide file tree
Showing 5 changed files with 145 additions and 1 deletion.
2 changes: 1 addition & 1 deletion pkg/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -1037,7 +1037,7 @@ func (c *KpmClient) PullFromOci(localPath, source, tag string) error {
}

// Untar the tar file.
storagePath := ociOpts.AddStoragePathSuffix(localPath)
storagePath := ociOpts.SanitizePathWithSuffix(localPath)
err = utils.UnTarDir(matches[0], storagePath)
if err != nil {
return reporter.NewErrorEvent(
Expand Down
6 changes: 6 additions & 0 deletions pkg/opt/opt.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/hashicorp/go-version"
"kcl-lang.io/kcl-go/pkg/kcl"
"kcl-lang.io/kpm/pkg/errors"
"kcl-lang.io/kpm/pkg/path"
"kcl-lang.io/kpm/pkg/reporter"
"oras.land/oras-go/v2"
)
Expand Down Expand Up @@ -278,6 +279,11 @@ func (oci *OciOptions) AddStoragePathSuffix(pathPrefix string) string {
return filepath.Join(filepath.Join(filepath.Join(pathPrefix, oci.Reg), oci.Repo), oci.Tag)
}

// SanitizePathSuffix will take 'Registry/Repo/Tag' as a path suffix and sanitize it.
func (oci *OciOptions) SanitizePathWithSuffix(pathPrefix string) string {
return path.SanitizePath(filepath.Join(filepath.Join(filepath.Join(pathPrefix, oci.Reg), oci.Repo), oci.Tag))
}

type OciManifestOptions struct {
Annotations map[string]string
}
Expand Down
46 changes: 46 additions & 0 deletions pkg/path/path_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package path

import (
"runtime"
"testing"
)

func TestSanitizePath(t *testing.T) {
tests := []struct {
name string
input string
expected string
}{
{
name: "Path with null character",
input: "test\x00file",
expected: "test_file",
},
{
name: "Path without invalid characters",
input: "/usr/local/bin/test",
expected: "/usr/local/bin/test",
},
}

if runtime.GOOS == "windows" {
tests = append(tests, struct {
name string
input string
expected string
}{
name: "Windows style path",
input: "C:\\Program Files\\Test<:>*|",
expected: "C:\\Program Files\\Test______",
})
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
output := SanitizePath(tt.input)
if output != tt.expected {
t.Errorf("expected %s, got %s", tt.expected, output)
}
})
}
}
44 changes: 44 additions & 0 deletions pkg/path/path_unix.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
//go:build !windows
// +build !windows

package path

import (
"path/filepath"
"strings"
)

var NeedToSanitize map[rune]bool

func init() {
NeedToSanitize = map[rune]bool{
'\x00': true,
}
}

// sanitizePath cleans a path string by removing or replacing invalid Windows file name characters.
func sanitizePath(path string, sanitize sanitizer, toSanitize map[rune]bool) string {
// replace all slashes with backslashes
path = filepath.FromSlash(path)

// replace all invalid characters
return strings.Map(func(r rune) rune {
if _, isInvalid := toSanitize[r]; isInvalid {
return sanitize(r, toSanitize)
}
return r
}, path)
}

// sanitizer defined how to handle and replace invalid file name characters.
type sanitizer func(rune, map[rune]bool) rune

// SanitizePath replaces invalid characters in a Windows path with a placeholder.
func SanitizePath(path string) string {
return sanitizePath(path, func(r rune, invalidChars map[rune]bool) rune {
if _, ok := invalidChars[r]; ok {
return '_'
}
return r
}, NeedToSanitize)
}
48 changes: 48 additions & 0 deletions pkg/path/path_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
//go:build windows
// +build windows

package path

import (
"path/filepath"
"strings"
)

var NeedToSanitize map[rune]bool

func init() {
NeedToSanitize = map[rune]bool{
'<': true, '>': true, ':': true, '"': true,
'/': true, '\\': true, '|': true, '?': true, '*': true,
}
}

// sanitizePath cleans a path string by removing or replacing invalid Windows file name characters.
func sanitizePath(path string, sanitize sanitizer, toSanitize map[rune]bool) string {
// replace all slashes with backslashes
path = filepath.FromSlash(path)

// replace all invalid characters
return strings.Map(func(r rune) rune {
if _, isInvalid := toSanitize[r]; isInvalid {
return sanitize(r, toSanitize)
}
return r
}, path)
}

// sanitizer defined how to handle and replace invalid file name characters.
type sanitizer func(rune, map[rune]bool) rune

// SanitizePath replaces invalid characters in a Windows path with a placeholder.
func SanitizePath(path string) string {
volumeName := filepath.VolumeName(path)
// Only sanitize the part of the path after the volume name
sanitized := sanitizePath(path[len(volumeName):], func(r rune, invalidChars map[rune]bool) rune {
if _, ok := invalidChars[r]; ok {
return '_'
}
return r
}, NeedToSanitize)
return volumeName + sanitized
}

0 comments on commit 18abd37

Please sign in to comment.