...
1
20
21 package sympath
22
23 import (
24 "log"
25 "os"
26 "path/filepath"
27 "sort"
28
29 "github.com/pkg/errors"
30 )
31
32
33
34
35
36
37 func Walk(root string, walkFn filepath.WalkFunc) error {
38 info, err := os.Lstat(root)
39 if err != nil {
40 err = walkFn(root, nil, err)
41 } else {
42 err = symwalk(root, info, walkFn)
43 }
44 if err == filepath.SkipDir {
45 return nil
46 }
47 return err
48 }
49
50
51
52 func readDirNames(dirname string) ([]string, error) {
53 f, err := os.Open(dirname)
54 if err != nil {
55 return nil, err
56 }
57 names, err := f.Readdirnames(-1)
58 f.Close()
59 if err != nil {
60 return nil, err
61 }
62 sort.Strings(names)
63 return names, nil
64 }
65
66
67 func symwalk(path string, info os.FileInfo, walkFn filepath.WalkFunc) error {
68
69 if IsSymlink(info) {
70 resolved, err := filepath.EvalSymlinks(path)
71 if err != nil {
72 return errors.Wrapf(err, "error evaluating symlink %s", path)
73 }
74 log.Printf("found symbolic link in path: %s resolves to %s. Contents of linked file included and used", path, resolved)
75 if info, err = os.Lstat(resolved); err != nil {
76 return err
77 }
78 if err := symwalk(path, info, walkFn); err != nil && err != filepath.SkipDir {
79 return err
80 }
81 return nil
82 }
83
84 if err := walkFn(path, info, nil); err != nil {
85 return err
86 }
87
88 if !info.IsDir() {
89 return nil
90 }
91
92 names, err := readDirNames(path)
93 if err != nil {
94 return walkFn(path, info, err)
95 }
96
97 for _, name := range names {
98 filename := filepath.Join(path, name)
99 fileInfo, err := os.Lstat(filename)
100 if err != nil {
101 if err := walkFn(filename, fileInfo, err); err != nil && err != filepath.SkipDir {
102 return err
103 }
104 } else {
105 err = symwalk(filename, fileInfo, walkFn)
106 if err != nil {
107 if (!fileInfo.IsDir() && !IsSymlink(fileInfo)) || err != filepath.SkipDir {
108 return err
109 }
110 }
111 }
112 }
113 return nil
114 }
115
116
117 func IsSymlink(fi os.FileInfo) bool {
118 return fi.Mode()&os.ModeSymlink != 0
119 }
120
View as plain text