| 106 | } |
| 107 | |
| 108 | func compareFileContents(a, b fs.FS, name string) error { |
| 109 | af, err := a.Open(name) |
| 110 | if err != nil { |
| 111 | return err |
| 112 | } |
| 113 | defer func() { _ = af.Close() }() |
| 114 | |
| 115 | bf, err := b.Open(name) |
| 116 | if err != nil { |
| 117 | return err |
| 118 | } |
| 119 | defer func() { _ = bf.Close() }() |
| 120 | |
| 121 | const bufSize = 32 * 1024 |
| 122 | bufA := make([]byte, bufSize) |
| 123 | bufB := make([]byte, bufSize) |
| 124 | |
| 125 | for { |
| 126 | na, ea := af.Read(bufA) |
| 127 | nb, eb := bf.Read(bufB) |
| 128 | |
| 129 | if na != nb || !bytes.Equal(bufA[:na], bufB[:nb]) { |
| 130 | return fmt.Errorf("content mismatch at %q", path.Clean(name)) |
| 131 | } |
| 132 | |
| 133 | if ea == io.EOF && eb == io.EOF { |
| 134 | return nil |
| 135 | } |
| 136 | if ea != nil && ea != io.EOF { |
| 137 | return ea |
| 138 | } |
| 139 | if eb != nil && eb != io.EOF { |
| 140 | return eb |
| 141 | } |
| 142 | } |
| 143 | } |
| 144 | |
| 145 | // LimitedWriter writes to W but limits the total amount of data written to N bytes. |
| 146 | // Each call to Write updates N to reflect the new amount remaining. |