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

Commit 6d2d295

Browse files
authored
Merge pull request #21 from ipfs/fix/11
serialfile: fix handling of hidden paths on windows
2 parents 20be69d + f0180f2 commit 6d2d295

6 files changed

+176
-28
lines changed

filewriter_test.go

+3
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ func TestWriteTo(t *testing.T) {
4040
"5/a": "foobar",
4141
}
4242
err = filepath.Walk(path, func(cpath string, info os.FileInfo, err error) error {
43+
if err != nil {
44+
return err
45+
}
4346
rpath, err := filepath.Rel(path, cpath)
4447
if err != nil {
4548
return err

is_hidden.go

+9-10
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,17 @@
1-
// +build !windows
1+
//+build !windows
22

33
package files
44

55
import (
6-
"path/filepath"
7-
"strings"
6+
"os"
87
)
98

10-
func IsHidden(name string, f Node) bool {
11-
fName := filepath.Base(name)
12-
13-
if strings.HasPrefix(fName, ".") && len(fName) > 1 {
14-
return true
9+
func isHidden(fi os.FileInfo) bool {
10+
fName := fi.Name()
11+
switch fName {
12+
case "", ".", "..":
13+
return false
14+
default:
15+
return fName[0] == '.'
1516
}
16-
17-
return false
1817
}

is_hidden_windows.go

+10-17
Original file line numberDiff line numberDiff line change
@@ -3,33 +3,26 @@
33
package files
44

55
import (
6-
"path/filepath"
7-
"strings"
6+
"os"
87

98
windows "golang.org/x/sys/windows"
109
)
1110

12-
func IsHidden(name string, f Node) bool {
13-
14-
fName := filepath.Base(name)
11+
func isHidden(fi os.FileInfo) bool {
12+
fName := fi.Name()
13+
switch fName {
14+
case "", ".", "..":
15+
return false
16+
}
1517

16-
if strings.HasPrefix(fName, ".") && len(fName) > 1 {
18+
if fName[0] == '.' {
1719
return true
1820
}
1921

20-
fi, ok := f.(FileInfo)
22+
wi, ok := fi.Sys().(*windows.Win32FileAttributeData)
2123
if !ok {
2224
return false
2325
}
2426

25-
p, e := windows.UTF16PtrFromString(fi.AbsPath())
26-
if e != nil {
27-
return false
28-
}
29-
30-
attrs, e := windows.GetFileAttributes(p)
31-
if e != nil {
32-
return false
33-
}
34-
return attrs&windows.FILE_ATTRIBUTE_HIDDEN != 0
27+
return wi.FileAttributes&windows.FILE_ATTRIBUTE_HIDDEN != 0
3528
}

serialfile.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ func (it *serialIterator) Next() bool {
7575

7676
stat := it.files[0]
7777
it.files = it.files[1:]
78-
for !it.handleHiddenFiles && strings.HasPrefix(stat.Name(), ".") {
78+
for !it.handleHiddenFiles && isHidden(stat) {
7979
if len(it.files) == 0 {
8080
return false
8181
}

serialfile_test.go

+126
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
package files
2+
3+
import (
4+
"fmt"
5+
"io/ioutil"
6+
"os"
7+
"path/filepath"
8+
"strings"
9+
"testing"
10+
)
11+
12+
func isPathHidden(p string) bool {
13+
return strings.HasPrefix(p, ".") || strings.Contains(p, "/.")
14+
}
15+
16+
func TestSerialFile(t *testing.T) {
17+
t.Run("Hidden", func(t *testing.T) { testSerialFile(t, true) })
18+
t.Run("NotHidden", func(t *testing.T) { testSerialFile(t, false) })
19+
}
20+
21+
func testSerialFile(t *testing.T, hidden bool) {
22+
tmppath, err := ioutil.TempDir("", "files-test")
23+
if err != nil {
24+
t.Fatal(err)
25+
}
26+
defer os.RemoveAll(tmppath)
27+
28+
expected := map[string]string{
29+
"1": "Some text!\n",
30+
"2": "beep",
31+
"3": "",
32+
"4": "boop",
33+
"5": "",
34+
"5/a": "foobar",
35+
".6": "thing",
36+
"7": "",
37+
"7/.foo": "bla",
38+
".8": "",
39+
".8/foo": "bla",
40+
}
41+
42+
for p, c := range expected {
43+
path := filepath.Join(tmppath, p)
44+
if c != "" {
45+
continue
46+
}
47+
if err := os.MkdirAll(path, 0777); err != nil {
48+
t.Fatal(err)
49+
}
50+
}
51+
52+
for p, c := range expected {
53+
path := filepath.Join(tmppath, p)
54+
if c == "" {
55+
continue
56+
}
57+
if err := ioutil.WriteFile(path, []byte(c), 0666); err != nil {
58+
t.Fatal(err)
59+
}
60+
}
61+
62+
stat, err := os.Stat(tmppath)
63+
if err != nil {
64+
t.Fatal(err)
65+
}
66+
67+
sf, err := NewSerialFile(tmppath, hidden, stat)
68+
if err != nil {
69+
t.Fatal(err)
70+
}
71+
defer sf.Close()
72+
73+
rootFound := false
74+
err = Walk(sf, func(path string, nd Node) error {
75+
defer nd.Close()
76+
77+
// root node.
78+
if path == "" {
79+
if rootFound {
80+
return fmt.Errorf("found root twice")
81+
}
82+
if sf != nd {
83+
return fmt.Errorf("wrong root")
84+
}
85+
rootFound = true
86+
return nil
87+
}
88+
89+
if !hidden && isPathHidden(path) {
90+
return fmt.Errorf("found a hidden file")
91+
}
92+
93+
data, ok := expected[path]
94+
if !ok {
95+
return fmt.Errorf("expected something at %q", path)
96+
}
97+
delete(expected, path)
98+
99+
switch nd := nd.(type) {
100+
case *Symlink:
101+
return fmt.Errorf("didn't expect a symlink")
102+
case Directory:
103+
if data != "" {
104+
return fmt.Errorf("expected a directory at %q", path)
105+
}
106+
case File:
107+
actual, err := ioutil.ReadAll(nd)
108+
if err != nil {
109+
return err
110+
}
111+
if string(actual) != data {
112+
return fmt.Errorf("expected %q, got %q", data, string(actual))
113+
}
114+
}
115+
return nil
116+
})
117+
if !rootFound {
118+
t.Fatal("didn't find the root")
119+
}
120+
for p := range expected {
121+
if !hidden && isPathHidden(p) {
122+
continue
123+
}
124+
t.Errorf("missed %q", p)
125+
}
126+
}

walk.go

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package files
2+
3+
import (
4+
"path/filepath"
5+
)
6+
7+
// Walk walks a file tree, like `os.Walk`.
8+
func Walk(nd Node, cb func(fpath string, nd Node) error) error {
9+
var helper func(string, Node) error
10+
helper = func(path string, nd Node) error {
11+
if err := cb(path, nd); err != nil {
12+
return err
13+
}
14+
dir, ok := nd.(Directory)
15+
if !ok {
16+
return nil
17+
}
18+
iter := dir.Entries()
19+
for iter.Next() {
20+
if err := helper(filepath.Join(path, iter.Name()), iter.Node()); err != nil {
21+
return err
22+
}
23+
}
24+
return iter.Err()
25+
}
26+
return helper("", nd)
27+
}

0 commit comments

Comments
 (0)