Skip to content

Commit

Permalink
os: add DirFS
Browse files Browse the repository at this point in the history
  • Loading branch information
dkegel-fastly committed Jan 23, 2022
1 parent cd39edf commit 57e9d46
Show file tree
Hide file tree
Showing 2 changed files with 118 additions and 1 deletion.
50 changes: 49 additions & 1 deletion src/os/file_go_116.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,64 @@ package os
import (
"io"
"io/fs"
"runtime"
)

type (
FileMode = fs.FileMode
FileInfo = fs.FileInfo
)

// The followings are copied from Go 1.16 official implementation:
// The followings are copied from Go 1.16 or 1.17 official implementation:
// https://github.com/golang/go/blob/go1.16/src/os/file.go

// DirFS returns a file system (an fs.FS) for the tree of files rooted at the directory dir.
//
// Note that DirFS("/prefix") only guarantees that the Open calls it makes to the
// operating system will begin with "/prefix": DirFS("/prefix").Open("file") is the
// same as os.Open("/prefix/file"). So if /prefix/file is a symbolic link pointing outside
// the /prefix tree, then using DirFS does not stop the access any more than using
// os.Open does. DirFS is therefore not a general substitute for a chroot-style security
// mechanism when the directory tree contains arbitrary content.
func DirFS(dir string) fs.FS {
return dirFS(dir)
}

func containsAny(s, chars string) bool {
for i := 0; i < len(s); i++ {
for j := 0; j < len(chars); j++ {
if s[i] == chars[j] {
return true
}
}
}
return false
}

type dirFS string

func (dir dirFS) Open(name string) (fs.File, error) {
if !fs.ValidPath(name) || runtime.GOOS == "windows" && containsAny(name, `\:`) {
return nil, &PathError{Op: "open", Path: name, Err: ErrInvalid}
}
f, err := Open(string(dir) + "/" + name)
if err != nil {
return nil, err // nil fs.File
}
return f, nil
}

func (dir dirFS) Stat(name string) (fs.FileInfo, error) {
if !fs.ValidPath(name) || runtime.GOOS == "windows" && containsAny(name, `\:`) {
return nil, &PathError{Op: "stat", Path: name, Err: ErrInvalid}
}
f, err := Stat(string(dir) + "/" + name)
if err != nil {
return nil, err
}
return f, nil
}

// ReadFile reads the named file and returns the contents.
// A successful call returns err == nil, not err == EOF.
// Because ReadFile reads the whole file, it does not treat an EOF from Read
Expand Down
69 changes: 69 additions & 0 deletions src/os/file_go_116_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// Copyright 2009 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.

// +build go1.16,!baremetal,!js,!wasi

package os_test

import (
"io/fs"
"os"
. "os"
"path/filepath"
"runtime"
"testing"
"testing/fstest"
)

func TestDirFS(t *testing.T) {
if runtime.GOOS == "windows" {
t.Log("TODO: implement Readdir for Windows")
return
}
if err := fstest.TestFS(DirFS("./testdata/dirfs"), "a", "b", "dir/x"); err != nil {
t.Fatal(err)
}

// Test that Open does not accept backslash as separator.
d := DirFS(".")
_, err := d.Open(`testdata\dirfs`)
if err == nil {
t.Fatalf(`Open testdata\dirfs succeeded`)
}
}

func TestDirFSPathsValid(t *testing.T) {
if runtime.GOOS == "windows" {
t.Log("skipping on Windows")
return
}

// TODO: switch back to t.TempDir once it's implemented
d, err := MkdirTemp("", "TestDirFSPathsValid")
if err != nil {
t.Fatal(err)
}
defer Remove(d)
if err := os.WriteFile(filepath.Join(d, "control.txt"), []byte(string("Hello, world!")), 0644); err != nil {
t.Fatal(err)
}
defer Remove(filepath.Join(d, "control.txt"))
if err := os.WriteFile(filepath.Join(d, `e:xperi\ment.txt`), []byte(string("Hello, colon and backslash!")), 0644); err != nil {
t.Fatal(err)
}
defer Remove(filepath.Join(d, `e:xperi\ment.txt`))

fsys := os.DirFS(d)
err = fs.WalkDir(fsys, ".", func(path string, e fs.DirEntry, err error) error {
if fs.ValidPath(e.Name()) {
t.Logf("%q ok", e.Name())
} else {
t.Errorf("%q INVALID", e.Name())
}
return nil
})
if err != nil {
t.Fatal(err)
}
}

0 comments on commit 57e9d46

Please sign in to comment.