返回 DeepSeek-Reasonix
matcher.go
根目录 / internal / pathidentity / matcher.go
1 package pathidentity
2
3 import "os"
4
5 // Matcher compares paths under one Options, resolving and statting each
6 // distinct path once. Identity can change between passes (a directory's case
7 // flag, a relinked junction), so a Matcher must not outlive the pass using it.
8 type Matcher struct {
9 options Options
10 resolve func(string, Options) (Identity, error)
11 seen map[string]matchedPath
12 }
13
14 type matchedPath struct {
15 identity Identity
16 err error
17 info os.FileInfo
18 statErr error
19 }
20
21 // NewMatcher uses resolve in place of Resolve when it is non-nil.
22 func NewMatcher(options Options, resolve func(string, Options) (Identity, error)) *Matcher {
23 if resolve == nil {
24 resolve = Resolve
25 }
26 return &Matcher{options: options, resolve: resolve, seen: map[string]matchedPath{}}
27 }
28
29 func (m *Matcher) lookup(path string) matchedPath {
30 if found, ok := m.seen[path]; ok {
31 return found
32 }
33 var entry matchedPath
34 entry.identity, entry.err = m.resolve(path, m.options)
35 if entry.err == nil {
36 entry.info, entry.statErr = statForMode(entry.identity.AccessPath, m.options.FollowLeaf)
37 }
38 m.seen[path] = entry
39 return entry
40 }
41
42 func (m *Matcher) Same(a, b string) (bool, error) {
43 left := m.lookup(a)
44 if left.err != nil {
45 return false, left.err
46 }
47 right := m.lookup(b)
48 if right.err != nil {
49 return false, right.err
50 }
51 if left.statErr == nil && right.statErr == nil && os.SameFile(left.info, right.info) {
52 return true, nil
53 }
54 for _, statErr := range []error{left.statErr, right.statErr} {
55 if statErr != nil && !os.IsNotExist(statErr) {
56 return false, classify("verify", "", statErr)
57 }
58 }
59 return left.identity.Key == right.identity.Key, nil
60 }
61
61 lines GO