diff options
Diffstat (limited to 'src/path/filepath')
| -rw-r--r-- | src/path/filepath/path.go | 16 | ||||
| -rw-r--r-- | src/path/filepath/path_test.go | 67 |
2 files changed, 83 insertions, 0 deletions
diff --git a/src/path/filepath/path.go b/src/path/filepath/path.go index 2af0f5b04c..6c8a0aa8b3 100644 --- a/src/path/filepath/path.go +++ b/src/path/filepath/path.go @@ -13,6 +13,7 @@ package filepath import ( "errors" + "internal/safefilepath" "io/fs" "os" "slices" @@ -211,6 +212,18 @@ func unixIsLocal(path string) bool { return true } +// Localize converts a slash-separated path into an operating system path. +// The input path must be a valid path as reported by [io/fs.ValidPath]. +// +// Localize returns an error if the path cannot be represented by the operating system. +// For example, the path a\b is rejected on Windows, on which \ is a separator +// character and cannot be part of a filename. +// +// The path returned by Localize will always be local, as reported by IsLocal. +func Localize(path string) (string, error) { + return safefilepath.Localize(path) +} + // ToSlash returns the result of replacing each separator character // in path with a slash ('/') character. Multiple separators are // replaced by multiple slashes. @@ -224,6 +237,9 @@ func ToSlash(path string) string { // FromSlash returns the result of replacing each slash ('/') character // in path with a separator character. Multiple slashes are replaced // by multiple separators. +// +// See also the Localize function, which converts a slash-separated path +// as used by the io/fs package to an operating system path. func FromSlash(path string) string { if Separator == '/' { return path diff --git a/src/path/filepath/path_test.go b/src/path/filepath/path_test.go index c96a758c69..1b2a66bc6d 100644 --- a/src/path/filepath/path_test.go +++ b/src/path/filepath/path_test.go @@ -237,6 +237,73 @@ func TestIsLocal(t *testing.T) { } } +type LocalizeTest struct { + path string + want string +} + +var localizetests = []LocalizeTest{ + {"", ""}, + {".", "."}, + {"..", ""}, + {"a/..", ""}, + {"/", ""}, + {"/a", ""}, + {"a\xffb", ""}, + {"a/", ""}, + {"a/./b", ""}, + {"\x00", ""}, + {"a", "a"}, + {"a/b/c", "a/b/c"}, +} + +var plan9localizetests = []LocalizeTest{ + {"#a", ""}, + {`a\b:c`, `a\b:c`}, +} + +var unixlocalizetests = []LocalizeTest{ + {"#a", "#a"}, + {`a\b:c`, `a\b:c`}, +} + +var winlocalizetests = []LocalizeTest{ + {"#a", "#a"}, + {"c:", ""}, + {`a\b`, ""}, + {`a:b`, ""}, + {`a/b:c`, ""}, + {`NUL`, ""}, + {`a/NUL`, ""}, + {`./com1`, ""}, + {`a/nul/b`, ""}, +} + +func TestLocalize(t *testing.T) { + tests := localizetests + switch runtime.GOOS { + case "plan9": + tests = append(tests, plan9localizetests...) + case "windows": + tests = append(tests, winlocalizetests...) + for i := range tests { + tests[i].want = filepath.FromSlash(tests[i].want) + } + default: + tests = append(tests, unixlocalizetests...) + } + for _, test := range tests { + got, err := filepath.Localize(test.path) + wantErr := "<nil>" + if test.want == "" { + wantErr = "error" + } + if got != test.want || ((err == nil) != (test.want != "")) { + t.Errorf("IsLocal(%q) = %q, %v want %q, %v", test.path, got, err, test.want, wantErr) + } + } +} + const sep = filepath.Separator var slashtests = []PathTest{ |
