diff options
| author | Damien Neil <dneil@google.com> | 2023-09-30 10:38:01 -0700 |
|---|---|---|
| committer | Damien Neil <dneil@google.com> | 2024-02-26 18:08:14 +0000 |
| commit | e596e8831885ad057a7f1db1391fddfd53f06431 (patch) | |
| tree | 0e5893682f270732c95e823e3623c49ae87d98ec /src/path/filepath | |
| parent | 7b583fd1a1aeda98daa5a9d485b35786c031e941 (diff) | |
| download | go-e596e8831885ad057a7f1db1391fddfd53f06431.tar.xz | |
path/filepath: add Localize
Add the Localize function, which takes an io/fs slash-separated path
and returns an operating system path.
Localize returns an error if the path cannot be represented on
the current platform.
Replace internal/safefile.FromFS with Localize,
which serves the same purpose as this function.
The internal/safefile package remains separate from path/filepath
to avoid a dependency cycle with the os package.
Fixes #57151
Change-Id: I75c88047ddea17808276761da07bf79172c4f6fc
Reviewed-on: https://go-review.googlesource.com/c/go/+/531677
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Ian Lance Taylor <iant@google.com>
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{ |
