golang 내부 코드를 까보면서 어떻게 동작하는지 공부해보기 위해 작성하게 되었습니다.
// An FS provides access to a hierarchical file system.
//
// The FS interface is the minimum implementation required of the file system.
// A file system may implement additional interfaces,
// such as ReadFileFS, to provide additional or optimized functionality.
type FS interface {
// Open opens the named file.
//
// When Open returns an error, it should be of type *PathError
// with the Op field set to "open", the Path field set to name,
// and the Err field describing the problem.
//
// Open should reject attempts to open names that do not satisfy
// ValidPath(name), returning a *PathError with Err set to
// ErrInvalid or ErrNotExist.
Open(name string) (File, error)
}
주석을 해석해보니 FS 인터페이스는 파일 시스템에 접근을 제공해주는 것으로 보입니다.
Open이라는 함수는 ValidPath함수를 만족하지 못할 경우, ErrInvaild, ErrNotExist 등을 리턴해줍니다.
// ValidPath reports whether the given path name
// is valid for use in a call to Open.
//
// Path names passed to open are UTF-8-encoded,
// unrooted, slash-separated sequences of path elements, like “x/y/z”.
// Path names must not contain an element that is “.” or “..” or the empty string,
// except for the special case that the root directory is named “.”.
// Paths must not start or end with a slash: “/x” and “x/” are invalid.
//
// Note that paths are slash-separated on all systems, even Windows.
// Paths containing other characters such as backslash and colon
// are accepted as valid, but those characters must never be
// interpreted by an FS implementation as path element separators.
func ValidPath(name string) bool {
if !utf8.ValidString(name) {
return false
}
if name == "." {
// special case
return true
}
// Iterate over elements in name, checking each.
for {
i := 0
for i < len(name) && name[i] != '/' {
i++
}
elem := name[:i]
if elem == "" || elem == "." || elem == ".." {
return false
}
if i == len(name) {
return true // reached clean ending
}
name = name[i+1:]
}
}
ValidPath는 주어진 경로가 Open할 수 있는지에 대해 식별해줍니다.
Path는 utf-8로 인코딩 되어 있어야 하며 slash기반으로 경로를 구분해주어야 합니다.
또한, .은 기준이 되는 루트 폴더에만 붙일 수 있고 slash는 처음과 끝에 붙으면 안됩니다.
아래 테스트 코드를 보시면 이해할 수 있습니다.
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package fs_test
import (
. "io/fs"
"testing"
)
var isValidPathTests = []struct {
name string
ok bool
}{
{".", true},
{"x", true},
{"x/y", true},
{"", false},
{"..", false},
{"/", false},
{"x/", false},
{"/x", false},
{"x/y/", false},
{"/x/y", false},
{"./", false},
{"./x", false},
{"x/.", false},
{"x/./y", false},
{"../", false},
{"../x", false},
{"x/..", false},
{"x/../y", false},
{"x//y", false},
{`x\`, true},
{`x\y`, true},
{`x:y`, true},
{`\x`, true},
}
func TestValidPath(t *testing.T) {
for _, tt := range isValidPathTests {
ok := ValidPath(tt.name)
if ok != tt.ok {
t.Errorf("ValidPath(%q) = %v, want %v", tt.name, ok, tt.ok)
}
}
}