1
16
17 package fstest
18
19 import (
20 "bytes"
21 "fmt"
22
23 "github.com/containerd/continuity"
24 )
25
26 type resourceUpdate struct {
27 Original continuity.Resource
28 Updated continuity.Resource
29 }
30
31 func (u resourceUpdate) String() string {
32 return fmt.Sprintf("%s(mode: %o, uid: %d, gid: %d) -> %s(mode: %o, uid: %d, gid: %d)",
33 u.Original.Path(), u.Original.Mode(), u.Original.UID(), u.Original.GID(),
34 u.Updated.Path(), u.Updated.Mode(), u.Updated.UID(), u.Updated.GID(),
35 )
36 }
37
38 type resourceListDifference struct {
39 Additions []continuity.Resource
40 Deletions []continuity.Resource
41 Updates []resourceUpdate
42 }
43
44 func (l resourceListDifference) HasDiff() bool {
45 if len(l.Deletions) > 0 || len(l.Updates) > 0 || (len(metadataFiles) == 0 && len(l.Additions) > 0) {
46 return true
47 }
48
49 for _, add := range l.Additions {
50 if ok := metadataFiles[add.Path()]; !ok {
51 return true
52 }
53 }
54
55 return false
56 }
57
58 func (l resourceListDifference) String() string {
59 buf := bytes.NewBuffer(nil)
60 for _, add := range l.Additions {
61 fmt.Fprintf(buf, "+ %s\n", add.Path())
62 }
63 for _, del := range l.Deletions {
64 fmt.Fprintf(buf, "- %s\n", del.Path())
65 }
66 for _, upt := range l.Updates {
67 fmt.Fprintf(buf, "~ %s\n", upt.String())
68 }
69 return buf.String()
70 }
71
72
73
74
75 func diffResourceList(r1, r2 []continuity.Resource) resourceListDifference {
76 i1 := 0
77 i2 := 0
78 var d resourceListDifference
79
80 for i1 < len(r1) && i2 < len(r2) {
81 p1 := r1[i1].Path()
82 p2 := r2[i2].Path()
83 switch {
84 case p1 < p2:
85 d.Deletions = append(d.Deletions, r1[i1])
86 i1++
87 case p1 == p2:
88 if !compareResource(r1[i1], r2[i2]) {
89 d.Updates = append(d.Updates, resourceUpdate{
90 Original: r1[i1],
91 Updated: r2[i2],
92 })
93 }
94 i1++
95 i2++
96 case p1 > p2:
97 d.Additions = append(d.Additions, r2[i2])
98 i2++
99 }
100 }
101
102 for i1 < len(r1) {
103 d.Deletions = append(d.Deletions, r1[i1])
104 i1++
105
106 }
107 for i2 < len(r2) {
108 d.Additions = append(d.Additions, r2[i2])
109 i2++
110 }
111
112 return d
113 }
114
115 func compareResource(r1, r2 continuity.Resource) bool {
116 if r1.Path() != r2.Path() {
117 return false
118 }
119 if r1.Mode() != r2.Mode() {
120 return false
121 }
122 if r1.UID() != r2.UID() {
123 return false
124 }
125 if r1.GID() != r2.GID() {
126 return false
127 }
128
129
130
131 return compareResourceTypes(r1, r2)
132 }
133
134 func compareResourceTypes(r1, r2 continuity.Resource) bool {
135 switch t1 := r1.(type) {
136 case continuity.RegularFile:
137 t2, ok := r2.(continuity.RegularFile)
138 if !ok {
139 return false
140 }
141 return compareRegularFile(t1, t2)
142 case continuity.Directory:
143 t2, ok := r2.(continuity.Directory)
144 if !ok {
145 return false
146 }
147 return compareDirectory(t1, t2)
148 case continuity.SymLink:
149 t2, ok := r2.(continuity.SymLink)
150 if !ok {
151 return false
152 }
153 return compareSymLink(t1, t2)
154 case continuity.NamedPipe:
155 t2, ok := r2.(continuity.NamedPipe)
156 if !ok {
157 return false
158 }
159 return compareNamedPipe(t1, t2)
160 case continuity.Device:
161 t2, ok := r2.(continuity.Device)
162 if !ok {
163 return false
164 }
165 return compareDevice(t1, t2)
166 default:
167
168 return r1 == r2
169 }
170 }
171
172 func compareRegularFile(r1, r2 continuity.RegularFile) bool {
173 if r1.Size() != r2.Size() {
174 return false
175 }
176 p1 := r1.Paths()
177 p2 := r2.Paths()
178 if len(p1) != len(p2) {
179 return false
180 }
181 for i := range p1 {
182 if p1[i] != p2[i] {
183 return false
184 }
185 }
186 d1 := r1.Digests()
187 d2 := r2.Digests()
188 if len(d1) != len(d2) {
189 return false
190 }
191 for i := range d1 {
192 if d1[i] != d2[i] {
193 return false
194 }
195 }
196
197 return true
198 }
199
200 func compareSymLink(r1, r2 continuity.SymLink) bool {
201 return r1.Target() == r2.Target()
202 }
203
204 func compareDirectory(r1, r2 continuity.Directory) bool {
205 return true
206 }
207
208 func compareNamedPipe(r1, r2 continuity.NamedPipe) bool {
209 return true
210 }
211
212 func compareDevice(r1, r2 continuity.Device) bool {
213 return r1.Major() == r2.Major() && r1.Minor() == r2.Minor()
214 }
215
View as plain text