1package continuity 2 3type resourceUpdate struct { 4 Original Resource 5 Updated Resource 6} 7 8type resourceListDifference struct { 9 Additions []Resource 10 Deletions []Resource 11 Updates []resourceUpdate 12} 13 14func (l resourceListDifference) HasDiff() bool { 15 return len(l.Additions) > 0 || len(l.Deletions) > 0 || len(l.Updates) > 0 16} 17 18// diffManifest compares two resource lists and returns the list 19// of adds updates and deletes, resource lists are not reordered 20// before doing difference. 21func diffResourceList(r1, r2 []Resource) resourceListDifference { 22 i1 := 0 23 i2 := 0 24 var d resourceListDifference 25 26 for i1 < len(r1) && i2 < len(r2) { 27 p1 := r1[i1].Path() 28 p2 := r2[i2].Path() 29 switch { 30 case p1 < p2: 31 d.Deletions = append(d.Deletions, r1[i1]) 32 i1++ 33 case p1 == p2: 34 if !compareResource(r1[i1], r2[i2]) { 35 d.Updates = append(d.Updates, resourceUpdate{ 36 Original: r1[i1], 37 Updated: r2[i2], 38 }) 39 } 40 i1++ 41 i2++ 42 case p1 > p2: 43 d.Additions = append(d.Additions, r2[i2]) 44 i2++ 45 } 46 } 47 48 for i1 < len(r1) { 49 d.Deletions = append(d.Deletions, r1[i1]) 50 i1++ 51 52 } 53 for i2 < len(r2) { 54 d.Additions = append(d.Additions, r2[i2]) 55 i2++ 56 } 57 58 return d 59} 60 61func compareResource(r1, r2 Resource) bool { 62 if r1.Path() != r2.Path() { 63 return false 64 } 65 if r1.Mode() != r2.Mode() { 66 return false 67 } 68 if r1.UID() != r2.UID() { 69 return false 70 } 71 if r1.GID() != r2.GID() { 72 return false 73 } 74 75 // TODO(dmcgowan): Check if is XAttrer 76 77 switch t1 := r1.(type) { 78 case RegularFile: 79 t2, ok := r2.(RegularFile) 80 if !ok { 81 return false 82 } 83 return compareRegularFile(t1, t2) 84 case Directory: 85 t2, ok := r2.(Directory) 86 if !ok { 87 return false 88 } 89 return compareDirectory(t1, t2) 90 case SymLink: 91 t2, ok := r2.(SymLink) 92 if !ok { 93 return false 94 } 95 return compareSymLink(t1, t2) 96 case NamedPipe: 97 t2, ok := r2.(NamedPipe) 98 if !ok { 99 return false 100 } 101 return compareNamedPipe(t1, t2) 102 case Device: 103 t2, ok := r2.(Device) 104 if !ok { 105 return false 106 } 107 return compareDevice(t1, t2) 108 default: 109 // TODO(dmcgowan): Should this panic? 110 return r1 == r2 111 } 112} 113 114func compareRegularFile(r1, r2 RegularFile) bool { 115 if r1.Size() != r2.Size() { 116 return false 117 } 118 p1 := r1.Paths() 119 p2 := r2.Paths() 120 if len(p1) != len(p2) { 121 return false 122 } 123 for i := range p1 { 124 if p1[i] != p2[i] { 125 return false 126 } 127 } 128 d1 := r1.Digests() 129 d2 := r2.Digests() 130 if len(d1) != len(d2) { 131 return false 132 } 133 for i := range d1 { 134 if d1[i] != d2[i] { 135 return false 136 } 137 } 138 139 return true 140} 141 142func compareSymLink(r1, r2 SymLink) bool { 143 return r1.Target() == r2.Target() 144} 145 146func compareDirectory(r1, r2 Directory) bool { 147 return true 148} 149 150func compareNamedPipe(r1, r2 NamedPipe) bool { 151 return true 152} 153 154func compareDevice(r1, r2 Device) bool { 155 return r1.Major() == r2.Major() && r1.Minor() == r2.Minor() 156} 157