github.com/Cloud-Foundations/Dominator@v0.3.4/lib/filesystem/compare.go (about) 1 package filesystem 2 3 import ( 4 "bytes" 5 "fmt" 6 "io" 7 "syscall" 8 ) 9 10 type timespec struct { 11 Sec int64 12 Nsec int32 13 } 14 15 func compareFileSystems(left, right *FileSystem, logWriter io.Writer) bool { 16 if len(left.InodeTable) != len(right.InodeTable) { 17 if logWriter != nil { 18 fmt.Fprintf(logWriter, "left vs. right: %d vs. %d inodes\n", 19 len(left.InodeTable), len(right.InodeTable)) 20 } 21 return false 22 } 23 return compareDirectoryInodes(&left.DirectoryInode, &right.DirectoryInode, 24 logWriter) 25 } 26 27 func compareDirectoryInodes(left, right *DirectoryInode, 28 logWriter io.Writer) bool { 29 if left == right { 30 return true 31 } 32 if !compareDirectoriesMetadata(left, right, logWriter) { 33 return false 34 } 35 if len(left.EntryList) != len(right.EntryList) { 36 if logWriter != nil { 37 fmt.Fprintf(logWriter, "left vs. right: %d vs. %d entries\n", 38 len(left.EntryList), len(right.EntryList)) 39 } 40 return false 41 } 42 for index, leftEntry := range left.EntryList { 43 if !compareDirectoryEntries(leftEntry, right.EntryList[index], 44 logWriter) { 45 return false 46 } 47 } 48 return true 49 } 50 51 func compareDirectoriesMetadata(left, right *DirectoryInode, 52 logWriter io.Writer) bool { 53 if left.Mode != right.Mode { 54 if logWriter != nil { 55 fmt.Fprintf(logWriter, "Mode: left vs. right: %o vs. %o\n", 56 left.Mode, right.Mode) 57 } 58 return false 59 } 60 if left.Uid != right.Uid { 61 if logWriter != nil { 62 fmt.Fprintf(logWriter, "Uid: left vs. right: %d vs. %d\n", 63 left.Uid, right.Uid) 64 } 65 return false 66 } 67 if left.Gid != right.Gid { 68 if logWriter != nil { 69 fmt.Fprintf(logWriter, "Gid: left vs. right: %d vs. %d\n", 70 left.Gid, right.Gid) 71 } 72 return false 73 } 74 return true 75 } 76 77 func compareDirectoryEntries(left, right *DirectoryEntry, 78 logWriter io.Writer) bool { 79 if left == right { 80 return true 81 } 82 if left.Name != right.Name { 83 if logWriter != nil { 84 fmt.Fprintf(logWriter, "filename: left vs. right: %s vs. %s\n", 85 left.Name, right.Name) 86 } 87 return false 88 } 89 switch left := left.inode.(type) { 90 case *RegularInode: 91 if right, ok := right.inode.(*RegularInode); ok { 92 return compareRegularInodes(left, right, logWriter) 93 } 94 case *ComputedRegularInode: 95 if right, ok := right.inode.(*ComputedRegularInode); ok { 96 return compareComputedRegularInodes(left, right, logWriter) 97 } 98 case *SymlinkInode: 99 if right, ok := right.inode.(*SymlinkInode); ok { 100 return compareSymlinkInodes(left, right, logWriter) 101 } 102 case *SpecialInode: 103 if right, ok := right.inode.(*SpecialInode); ok { 104 return compareSpecialInodes(left, right, logWriter) 105 } 106 case *DirectoryInode: 107 if right, ok := right.inode.(*DirectoryInode); ok { 108 return compareDirectoryInodes(left, right, logWriter) 109 } 110 } 111 if logWriter != nil { 112 fmt.Fprintf(logWriter, "types: left vs. right: %s vs. %s\n", 113 left.Name, right.Name) 114 } 115 return false 116 } 117 118 func compareInodes(left, right GenericInode, logWriter io.Writer) ( 119 sameType, sameMetadata, sameData bool) { 120 if left == right { 121 return true, true, true 122 } 123 switch left := left.(type) { 124 case *RegularInode: 125 if right, ok := right.(*RegularInode); ok { 126 sameType = true 127 sameMetadata = compareRegularInodesMetadata(left, right, logWriter) 128 sameData = compareRegularInodesData(left, right, logWriter) 129 } 130 case *ComputedRegularInode: 131 if right, ok := right.(*ComputedRegularInode); ok { 132 sameType = true 133 sameMetadata = compareComputedRegularInodesMetadata(left, right, 134 logWriter) 135 sameData = compareComputedRegularInodesData(left, right, logWriter) 136 } 137 case *SymlinkInode: 138 if right, ok := right.(*SymlinkInode); ok { 139 sameType = true 140 sameMetadata = compareSymlinkInodesMetadata(left, right, logWriter) 141 sameData = compareSymlinkInodesData(left, right, logWriter) 142 } 143 case *SpecialInode: 144 if right, ok := right.(*SpecialInode); ok { 145 sameType = true 146 sameMetadata = compareSpecialInodesMetadata(left, right, logWriter) 147 sameData = compareSpecialInodesData(left, right, logWriter) 148 } 149 case *DirectoryInode: 150 if right, ok := right.(*DirectoryInode); ok { 151 sameType = true 152 sameMetadata = compareDirectoriesMetadata(left, right, logWriter) 153 } 154 default: 155 panic(fmt.Sprintf("Unsupported entry type: %T", left)) 156 } 157 if !sameType && logWriter != nil { 158 fmt.Fprintln(logWriter, "types: left vs. right differ") 159 } 160 return 161 } 162 163 func compareRegularInodes(left, right *RegularInode, logWriter io.Writer) bool { 164 if left == right { 165 return true 166 } 167 if !compareRegularInodesMetadata(left, right, logWriter) { 168 return false 169 } 170 return compareRegularInodesData(left, right, logWriter) 171 } 172 173 func compareRegularInodesMetadata(left, right *RegularInode, 174 logWriter io.Writer) bool { 175 if left.Mode != right.Mode { 176 if logWriter != nil { 177 fmt.Fprintf(logWriter, "Mode: left vs. right: %o vs. %o\n", 178 left.Mode, right.Mode) 179 } 180 return false 181 } 182 if left.Uid != right.Uid { 183 if logWriter != nil { 184 fmt.Fprintf(logWriter, "Uid: left vs. right: %d vs. %d\n", 185 left.Uid, right.Uid) 186 } 187 return false 188 } 189 if left.Gid != right.Gid { 190 if logWriter != nil { 191 fmt.Fprintf(logWriter, "Gid: left vs. right: %d vs. %d\n", 192 left.Gid, right.Gid) 193 } 194 return false 195 } 196 var leftMtime, rightMtime timespec 197 leftMtime.Sec = left.MtimeSeconds 198 leftMtime.Nsec = left.MtimeNanoSeconds 199 rightMtime.Sec = right.MtimeSeconds 200 rightMtime.Nsec = right.MtimeNanoSeconds 201 if leftMtime != rightMtime { 202 if logWriter != nil { 203 fmt.Fprintf(logWriter, "Mtime: left vs. right: %v vs. %v\n", 204 leftMtime, rightMtime) 205 } 206 return false 207 } 208 return true 209 } 210 211 func compareRegularInodesData(left, right *RegularInode, 212 logWriter io.Writer) bool { 213 if left.Size != right.Size { 214 if logWriter != nil { 215 fmt.Fprintf(logWriter, "Size: left vs. right: %d vs. %d\n", 216 left.Size, right.Size) 217 } 218 return false 219 } 220 if left.Size > 0 { 221 if bytes.Compare(left.Hash[:], right.Hash[:]) != 0 { 222 if logWriter != nil { 223 fmt.Fprintf(logWriter, "hash: left vs. right: %x vs. %x\n", 224 left.Hash, right.Hash) 225 } 226 return false 227 } 228 } 229 return true 230 } 231 232 func compareComputedRegularInodes(left, right *ComputedRegularInode, 233 logWriter io.Writer) bool { 234 if left == right { 235 return true 236 } 237 if !compareComputedRegularInodesMetadata(left, right, logWriter) { 238 return false 239 } 240 return compareComputedRegularInodesData(left, right, logWriter) 241 } 242 243 func compareComputedRegularInodesMetadata(left, right *ComputedRegularInode, 244 logWriter io.Writer) bool { 245 if left.Mode != right.Mode { 246 if logWriter != nil { 247 fmt.Fprintf(logWriter, "Mode: left vs. right: %o vs. %o\n", 248 left.Mode, right.Mode) 249 } 250 return false 251 } 252 if left.Uid != right.Uid { 253 if logWriter != nil { 254 fmt.Fprintf(logWriter, "Uid: left vs. right: %d vs. %d\n", 255 left.Uid, right.Uid) 256 } 257 return false 258 } 259 if left.Gid != right.Gid { 260 if logWriter != nil { 261 fmt.Fprintf(logWriter, "Gid: left vs. right: %d vs. %d\n", 262 left.Gid, right.Gid) 263 } 264 return false 265 } 266 if left.Source != right.Source { 267 if logWriter != nil { 268 fmt.Fprintf(logWriter, "Gid: left vs. right: %s vs. %s\n", 269 left.Source, right.Source) 270 } 271 return false 272 } 273 return true 274 } 275 276 func compareComputedRegularInodesData(left, right *ComputedRegularInode, 277 logWriter io.Writer) bool { 278 if left.Source != right.Source { 279 if logWriter != nil { 280 fmt.Fprintf(logWriter, "data source: left vs. right: %s vs. %s\n", 281 left.Source, right.Source) 282 } 283 return false 284 } 285 return true 286 } 287 288 func compareSymlinkInodes(left, right *SymlinkInode, logWriter io.Writer) bool { 289 if left == right { 290 return true 291 } 292 if !compareSymlinkInodesMetadata(left, right, logWriter) { 293 return false 294 } 295 return compareSymlinkInodesData(left, right, logWriter) 296 } 297 298 func compareSymlinkInodesMetadata(left, right *SymlinkInode, 299 logWriter io.Writer) bool { 300 if left.Uid != right.Uid { 301 if logWriter != nil { 302 fmt.Fprintf(logWriter, "Uid: left vs. right: %d vs. %d\n", 303 left.Uid, right.Uid) 304 } 305 return false 306 } 307 if left.Gid != right.Gid { 308 if logWriter != nil { 309 fmt.Fprintf(logWriter, "Gid: left vs. right: %d vs. %d\n", 310 left.Gid, right.Gid) 311 } 312 return false 313 } 314 return true 315 } 316 317 func compareSymlinkInodesData(left, right *SymlinkInode, 318 logWriter io.Writer) bool { 319 if left.Symlink != right.Symlink { 320 if logWriter != nil { 321 fmt.Fprintf(logWriter, "symlink: left vs. right: %s vs. %s\n", 322 left.Symlink, right.Symlink) 323 } 324 return false 325 } 326 return true 327 } 328 329 func compareSpecialInodes(left, right *SpecialInode, logWriter io.Writer) bool { 330 if left == right { 331 return true 332 } 333 if !compareSpecialInodesMetadata(left, right, logWriter) { 334 return false 335 } 336 return compareSpecialInodesData(left, right, logWriter) 337 } 338 339 func compareSpecialInodesMetadata(left, right *SpecialInode, 340 logWriter io.Writer) bool { 341 if left == right { 342 return true 343 } 344 if left.Mode != right.Mode { 345 if logWriter != nil { 346 fmt.Fprintf(logWriter, "Mode: left vs. right: %o vs. %o\n", 347 left.Mode, right.Mode) 348 } 349 return false 350 } 351 if left.Uid != right.Uid { 352 if logWriter != nil { 353 fmt.Fprintf(logWriter, "Uid: left vs. right: %d vs. %d\n", 354 left.Uid, right.Uid) 355 } 356 return false 357 } 358 if left.Gid != right.Gid { 359 if logWriter != nil { 360 fmt.Fprintf(logWriter, "Gid: left vs. right: %d vs. %d\n", 361 left.Gid, right.Gid) 362 } 363 return false 364 } 365 var leftMtime, rightMtime timespec 366 leftMtime.Sec = left.MtimeSeconds 367 leftMtime.Nsec = left.MtimeNanoSeconds 368 rightMtime.Sec = right.MtimeSeconds 369 rightMtime.Nsec = right.MtimeNanoSeconds 370 if leftMtime != rightMtime { 371 if logWriter != nil { 372 fmt.Fprintf(logWriter, "Mtime: left vs. right: %v vs. %v\n", 373 leftMtime, rightMtime) 374 } 375 return false 376 } 377 return true 378 } 379 380 func compareSpecialInodesData(left, right *SpecialInode, 381 logWriter io.Writer) bool { 382 if left.Mode&syscall.S_IFMT == syscall.S_IFBLK || 383 left.Mode&syscall.S_IFMT == syscall.S_IFCHR { 384 if left.Rdev != right.Rdev { 385 if logWriter != nil { 386 fmt.Fprintf(logWriter, "Rdev: left vs. right: %#x vs. %#x\n", 387 left.Rdev, right.Rdev) 388 } 389 return false 390 } 391 } 392 return true 393 }