Skip to content
This repository has been archived by the owner on Mar 29, 2023. It is now read-only.

Commit

Permalink
Merge pull request #21 from ipfs/fix/11
Browse files Browse the repository at this point in the history
serialfile: fix handling of hidden paths on windows
  • Loading branch information
Stebalien committed Aug 16, 2019
2 parents 20be69d + f0180f2 commit 6d2d295
Show file tree
Hide file tree
Showing 6 changed files with 176 additions and 28 deletions.
3 changes: 3 additions & 0 deletions filewriter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ func TestWriteTo(t *testing.T) {
"5/a": "foobar",
}
err = filepath.Walk(path, func(cpath string, info os.FileInfo, err error) error {
if err != nil {
return err
}
rpath, err := filepath.Rel(path, cpath)
if err != nil {
return err
Expand Down
19 changes: 9 additions & 10 deletions is_hidden.go
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
// +build !windows
//+build !windows

package files

import (
"path/filepath"
"strings"
"os"
)

func IsHidden(name string, f Node) bool {
fName := filepath.Base(name)

if strings.HasPrefix(fName, ".") && len(fName) > 1 {
return true
func isHidden(fi os.FileInfo) bool {
fName := fi.Name()
switch fName {
case "", ".", "..":
return false
default:
return fName[0] == '.'
}

return false
}
27 changes: 10 additions & 17 deletions is_hidden_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,33 +3,26 @@
package files

import (
"path/filepath"
"strings"
"os"

windows "golang.org/x/sys/windows"
)

func IsHidden(name string, f Node) bool {

fName := filepath.Base(name)
func isHidden(fi os.FileInfo) bool {
fName := fi.Name()
switch fName {
case "", ".", "..":
return false
}

if strings.HasPrefix(fName, ".") && len(fName) > 1 {
if fName[0] == '.' {
return true
}

fi, ok := f.(FileInfo)
wi, ok := fi.Sys().(*windows.Win32FileAttributeData)
if !ok {
return false
}

p, e := windows.UTF16PtrFromString(fi.AbsPath())
if e != nil {
return false
}

attrs, e := windows.GetFileAttributes(p)
if e != nil {
return false
}
return attrs&windows.FILE_ATTRIBUTE_HIDDEN != 0
return wi.FileAttributes&windows.FILE_ATTRIBUTE_HIDDEN != 0
}
2 changes: 1 addition & 1 deletion serialfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ func (it *serialIterator) Next() bool {

stat := it.files[0]
it.files = it.files[1:]
for !it.handleHiddenFiles && strings.HasPrefix(stat.Name(), ".") {
for !it.handleHiddenFiles && isHidden(stat) {
if len(it.files) == 0 {
return false
}
Expand Down
126 changes: 126 additions & 0 deletions serialfile_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
package files

import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strings"
"testing"
)

func isPathHidden(p string) bool {
return strings.HasPrefix(p, ".") || strings.Contains(p, "/.")
}

func TestSerialFile(t *testing.T) {
t.Run("Hidden", func(t *testing.T) { testSerialFile(t, true) })
t.Run("NotHidden", func(t *testing.T) { testSerialFile(t, false) })
}

func testSerialFile(t *testing.T, hidden bool) {
tmppath, err := ioutil.TempDir("", "files-test")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmppath)

expected := map[string]string{
"1": "Some text!\n",
"2": "beep",
"3": "",
"4": "boop",
"5": "",
"5/a": "foobar",
".6": "thing",
"7": "",
"7/.foo": "bla",
".8": "",
".8/foo": "bla",
}

for p, c := range expected {
path := filepath.Join(tmppath, p)
if c != "" {
continue
}
if err := os.MkdirAll(path, 0777); err != nil {
t.Fatal(err)
}
}

for p, c := range expected {
path := filepath.Join(tmppath, p)
if c == "" {
continue
}
if err := ioutil.WriteFile(path, []byte(c), 0666); err != nil {
t.Fatal(err)
}
}

stat, err := os.Stat(tmppath)
if err != nil {
t.Fatal(err)
}

sf, err := NewSerialFile(tmppath, hidden, stat)
if err != nil {
t.Fatal(err)
}
defer sf.Close()

rootFound := false
err = Walk(sf, func(path string, nd Node) error {
defer nd.Close()

// root node.
if path == "" {
if rootFound {
return fmt.Errorf("found root twice")
}
if sf != nd {
return fmt.Errorf("wrong root")
}
rootFound = true
return nil
}

if !hidden && isPathHidden(path) {
return fmt.Errorf("found a hidden file")
}

data, ok := expected[path]
if !ok {
return fmt.Errorf("expected something at %q", path)
}
delete(expected, path)

switch nd := nd.(type) {
case *Symlink:
return fmt.Errorf("didn't expect a symlink")
case Directory:
if data != "" {
return fmt.Errorf("expected a directory at %q", path)
}
case File:
actual, err := ioutil.ReadAll(nd)
if err != nil {
return err
}
if string(actual) != data {
return fmt.Errorf("expected %q, got %q", data, string(actual))
}
}
return nil
})
if !rootFound {
t.Fatal("didn't find the root")
}
for p := range expected {
if !hidden && isPathHidden(p) {
continue
}
t.Errorf("missed %q", p)
}
}
27 changes: 27 additions & 0 deletions walk.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package files

import (
"path/filepath"
)

// Walk walks a file tree, like `os.Walk`.
func Walk(nd Node, cb func(fpath string, nd Node) error) error {
var helper func(string, Node) error
helper = func(path string, nd Node) error {
if err := cb(path, nd); err != nil {
return err
}
dir, ok := nd.(Directory)
if !ok {
return nil
}
iter := dir.Entries()
for iter.Next() {
if err := helper(filepath.Join(path, iter.Name()), iter.Node()); err != nil {
return err
}
}
return iter.Err()
}
return helper("", nd)
}

0 comments on commit 6d2d295

Please sign in to comment.