pax_global_header 0000666 0000000 0000000 00000000064 12744050656 0014523 g ustar 00root root 0000000 0000000 52 comment=3035450ff8b987ec4373f65c40767f096b35f2d2
binarydist-3035450ff8b987ec4373f65c40767f096b35f2d2/ 0000775 0000000 0000000 00000000000 12744050656 0020420 5 ustar 00root root 0000000 0000000 binarydist-3035450ff8b987ec4373f65c40767f096b35f2d2/.gitignore 0000664 0000000 0000000 00000000007 12744050656 0022405 0 ustar 00root root 0000000 0000000 test.*
binarydist-3035450ff8b987ec4373f65c40767f096b35f2d2/License 0000664 0000000 0000000 00000002034 12744050656 0021724 0 ustar 00root root 0000000 0000000 Copyright 2012 Keith Rarick
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
binarydist-3035450ff8b987ec4373f65c40767f096b35f2d2/Readme.md 0000664 0000000 0000000 00000000366 12744050656 0022144 0 ustar 00root root 0000000 0000000 # binarydist
Package binarydist implements binary diff and patch as described on
. It reads and writes files
compatible with the tools there.
Documentation at .
binarydist-3035450ff8b987ec4373f65c40767f096b35f2d2/bzip2.go 0000664 0000000 0000000 00000001271 12744050656 0021776 0 ustar 00root root 0000000 0000000 package binarydist
import (
"io"
"os/exec"
)
type bzip2Writer struct {
c *exec.Cmd
w io.WriteCloser
}
func (w bzip2Writer) Write(b []byte) (int, error) {
return w.w.Write(b)
}
func (w bzip2Writer) Close() error {
if err := w.w.Close(); err != nil {
return err
}
return w.c.Wait()
}
// Package compress/bzip2 implements only decompression,
// so we'll fake it by running bzip2 in another process.
func newBzip2Writer(w io.Writer) (wc io.WriteCloser, err error) {
var bw bzip2Writer
bw.c = exec.Command("bzip2", "-c")
bw.c.Stdout = w
if bw.w, err = bw.c.StdinPipe(); err != nil {
return nil, err
}
if err = bw.c.Start(); err != nil {
return nil, err
}
return bw, nil
}
binarydist-3035450ff8b987ec4373f65c40767f096b35f2d2/common_test.go 0000664 0000000 0000000 00000002206 12744050656 0023276 0 ustar 00root root 0000000 0000000 package binarydist
import (
"io"
"io/ioutil"
"math/rand"
"os"
)
func mustOpen(path string) *os.File {
f, err := os.Open(path)
if err != nil {
panic(err)
}
return f
}
func mustReadAll(r io.Reader) []byte {
b, err := ioutil.ReadAll(r)
if err != nil {
panic(err)
}
return b
}
func fileCmp(a, b *os.File) int64 {
sa, err := a.Seek(0, 2)
if err != nil {
panic(err)
}
sb, err := b.Seek(0, 2)
if err != nil {
panic(err)
}
if sa != sb {
return sa
}
_, err = a.Seek(0, 0)
if err != nil {
panic(err)
}
_, err = b.Seek(0, 0)
if err != nil {
panic(err)
}
pa, err := ioutil.ReadAll(a)
if err != nil {
panic(err)
}
pb, err := ioutil.ReadAll(b)
if err != nil {
panic(err)
}
for i := range pa {
if pa[i] != pb[i] {
return int64(i)
}
}
return -1
}
func mustWriteRandFile(path string, size int, seed int64) *os.File {
p := make([]byte, size)
rand.Seed(seed)
_, err := rand.Read(p)
if err != nil {
panic(err)
}
f, err := os.Create(path)
if err != nil {
panic(err)
}
_, err = f.Write(p)
if err != nil {
panic(err)
}
_, err = f.Seek(0, 0)
if err != nil {
panic(err)
}
return f
}
binarydist-3035450ff8b987ec4373f65c40767f096b35f2d2/diff.go 0000664 0000000 0000000 00000015756 12744050656 0021675 0 ustar 00root root 0000000 0000000 package binarydist
import (
"bytes"
"encoding/binary"
"io"
"io/ioutil"
)
func swap(a []int, i, j int) { a[i], a[j] = a[j], a[i] }
func split(I, V []int, start, length, h int) {
var i, j, k, x, jj, kk int
if length < 16 {
for k = start; k < start+length; k += j {
j = 1
x = V[I[k]+h]
for i = 1; k+i < start+length; i++ {
if V[I[k+i]+h] < x {
x = V[I[k+i]+h]
j = 0
}
if V[I[k+i]+h] == x {
swap(I, k+i, k+j)
j++
}
}
for i = 0; i < j; i++ {
V[I[k+i]] = k + j - 1
}
if j == 1 {
I[k] = -1
}
}
return
}
x = V[I[start+length/2]+h]
jj = 0
kk = 0
for i = start; i < start+length; i++ {
if V[I[i]+h] < x {
jj++
}
if V[I[i]+h] == x {
kk++
}
}
jj += start
kk += jj
i = start
j = 0
k = 0
for i < jj {
if V[I[i]+h] < x {
i++
} else if V[I[i]+h] == x {
swap(I, i, jj+j)
j++
} else {
swap(I, i, kk+k)
k++
}
}
for jj+j < kk {
if V[I[jj+j]+h] == x {
j++
} else {
swap(I, jj+j, kk+k)
k++
}
}
if jj > start {
split(I, V, start, jj-start, h)
}
for i = 0; i < kk-jj; i++ {
V[I[jj+i]] = kk - 1
}
if jj == kk-1 {
I[jj] = -1
}
if start+length > kk {
split(I, V, kk, start+length-kk, h)
}
}
func qsufsort(obuf []byte) []int {
var buckets [256]int
var i, h int
I := make([]int, len(obuf)+1)
V := make([]int, len(obuf)+1)
for _, c := range obuf {
buckets[c]++
}
for i = 1; i < 256; i++ {
buckets[i] += buckets[i-1]
}
copy(buckets[1:], buckets[:])
buckets[0] = 0
for i, c := range obuf {
buckets[c]++
I[buckets[c]] = i
}
I[0] = len(obuf)
for i, c := range obuf {
V[i] = buckets[c]
}
V[len(obuf)] = 0
for i = 1; i < 256; i++ {
if buckets[i] == buckets[i-1]+1 {
I[buckets[i]] = -1
}
}
I[0] = -1
for h = 1; I[0] != -(len(obuf) + 1); h += h {
var n int
for i = 0; i < len(obuf)+1; {
if I[i] < 0 {
n -= I[i]
i -= I[i]
} else {
if n != 0 {
I[i-n] = -n
}
n = V[I[i]] + 1 - i
split(I, V, i, n, h)
i += n
n = 0
}
}
if n != 0 {
I[i-n] = -n
}
}
for i = 0; i < len(obuf)+1; i++ {
I[V[i]] = i
}
return I
}
func matchlen(a, b []byte) (i int) {
for i < len(a) && i < len(b) && a[i] == b[i] {
i++
}
return i
}
func search(I []int, obuf, nbuf []byte, st, en int) (pos, n int) {
if en-st < 2 {
x := matchlen(obuf[I[st]:], nbuf)
y := matchlen(obuf[I[en]:], nbuf)
if x > y {
return I[st], x
} else {
return I[en], y
}
}
x := st + (en-st)/2
if bytes.Compare(obuf[I[x]:], nbuf) < 0 {
return search(I, obuf, nbuf, x, en)
} else {
return search(I, obuf, nbuf, st, x)
}
panic("unreached")
}
// Diff computes the difference between old and new, according to the bsdiff
// algorithm, and writes the result to patch.
func Diff(old, new io.Reader, patch io.Writer) error {
obuf, err := ioutil.ReadAll(old)
if err != nil {
return err
}
nbuf, err := ioutil.ReadAll(new)
if err != nil {
return err
}
pbuf, err := diffBytes(obuf, nbuf)
if err != nil {
return err
}
_, err = patch.Write(pbuf)
return err
}
func diffBytes(obuf, nbuf []byte) ([]byte, error) {
var patch seekBuffer
err := diff(obuf, nbuf, &patch)
if err != nil {
return nil, err
}
return patch.buf, nil
}
func diff(obuf, nbuf []byte, patch io.WriteSeeker) error {
var lenf int
I := qsufsort(obuf)
db := make([]byte, len(nbuf))
eb := make([]byte, len(nbuf))
var dblen, eblen int
var hdr header
hdr.Magic = magic
hdr.NewSize = int64(len(nbuf))
err := binary.Write(patch, signMagLittleEndian{}, &hdr)
if err != nil {
return err
}
// Compute the differences, writing ctrl as we go
pfbz2, err := newBzip2Writer(patch)
if err != nil {
return err
}
var scan, pos, length int
var lastscan, lastpos, lastoffset int
for scan < len(nbuf) {
var oldscore int
scan += length
for scsc := scan; scan < len(nbuf); scan++ {
pos, length = search(I, obuf, nbuf[scan:], 0, len(obuf))
for ; scsc < scan+length; scsc++ {
if scsc+lastoffset < len(obuf) &&
obuf[scsc+lastoffset] == nbuf[scsc] {
oldscore++
}
}
if (length == oldscore && length != 0) || length > oldscore+8 {
break
}
if scan+lastoffset < len(obuf) && obuf[scan+lastoffset] == nbuf[scan] {
oldscore--
}
}
if length != oldscore || scan == len(nbuf) {
var s, Sf int
lenf = 0
for i := 0; lastscan+i < scan && lastpos+i < len(obuf); {
if obuf[lastpos+i] == nbuf[lastscan+i] {
s++
}
i++
if s*2-i > Sf*2-lenf {
Sf = s
lenf = i
}
}
lenb := 0
if scan < len(nbuf) {
var s, Sb int
for i := 1; (scan >= lastscan+i) && (pos >= i); i++ {
if obuf[pos-i] == nbuf[scan-i] {
s++
}
if s*2-i > Sb*2-lenb {
Sb = s
lenb = i
}
}
}
if lastscan+lenf > scan-lenb {
overlap := (lastscan + lenf) - (scan - lenb)
s := 0
Ss := 0
lens := 0
for i := 0; i < overlap; i++ {
if nbuf[lastscan+lenf-overlap+i] == obuf[lastpos+lenf-overlap+i] {
s++
}
if nbuf[scan-lenb+i] == obuf[pos-lenb+i] {
s--
}
if s > Ss {
Ss = s
lens = i + 1
}
}
lenf += lens - overlap
lenb -= lens
}
for i := 0; i < lenf; i++ {
db[dblen+i] = nbuf[lastscan+i] - obuf[lastpos+i]
}
for i := 0; i < (scan-lenb)-(lastscan+lenf); i++ {
eb[eblen+i] = nbuf[lastscan+lenf+i]
}
dblen += lenf
eblen += (scan - lenb) - (lastscan + lenf)
err = binary.Write(pfbz2, signMagLittleEndian{}, int64(lenf))
if err != nil {
pfbz2.Close()
return err
}
val := (scan - lenb) - (lastscan + lenf)
err = binary.Write(pfbz2, signMagLittleEndian{}, int64(val))
if err != nil {
pfbz2.Close()
return err
}
val = (pos - lenb) - (lastpos + lenf)
err = binary.Write(pfbz2, signMagLittleEndian{}, int64(val))
if err != nil {
pfbz2.Close()
return err
}
lastscan = scan - lenb
lastpos = pos - lenb
lastoffset = pos - scan
}
}
err = pfbz2.Close()
if err != nil {
return err
}
// Compute size of compressed ctrl data
l64, err := patch.Seek(0, 1)
if err != nil {
return err
}
hdr.CtrlLen = int64(l64 - 32)
// Write compressed diff data
pfbz2, err = newBzip2Writer(patch)
if err != nil {
return err
}
n, err := pfbz2.Write(db[:dblen])
if err != nil {
pfbz2.Close()
return err
}
if n != dblen {
pfbz2.Close()
return io.ErrShortWrite
}
err = pfbz2.Close()
if err != nil {
return err
}
// Compute size of compressed diff data
n64, err := patch.Seek(0, 1)
if err != nil {
return err
}
hdr.DiffLen = n64 - l64
// Write compressed extra data
pfbz2, err = newBzip2Writer(patch)
if err != nil {
return err
}
n, err = pfbz2.Write(eb[:eblen])
if err != nil {
pfbz2.Close()
return err
}
if n != eblen {
pfbz2.Close()
return io.ErrShortWrite
}
err = pfbz2.Close()
if err != nil {
return err
}
// Seek to the beginning, write the header, and close the file
_, err = patch.Seek(0, 0)
if err != nil {
return err
}
err = binary.Write(patch, signMagLittleEndian{}, &hdr)
if err != nil {
return err
}
return nil
}
binarydist-3035450ff8b987ec4373f65c40767f096b35f2d2/diff_test.go 0000664 0000000 0000000 00000002415 12744050656 0022720 0 ustar 00root root 0000000 0000000 package binarydist
import (
"bytes"
"io/ioutil"
"os"
"os/exec"
"testing"
)
var diffT = []struct {
old *os.File
new *os.File
}{
{
old: mustWriteRandFile("test.old", 1e3, 1),
new: mustWriteRandFile("test.new", 1e3, 2),
},
{
old: mustOpen("testdata/sample.old"),
new: mustOpen("testdata/sample.new"),
},
}
func TestDiff(t *testing.T) {
for _, s := range diffT {
got, err := ioutil.TempFile("/tmp", "bspatch.")
if err != nil {
panic(err)
}
os.Remove(got.Name())
exp, err := ioutil.TempFile("/tmp", "bspatch.")
if err != nil {
panic(err)
}
cmd := exec.Command("bsdiff", s.old.Name(), s.new.Name(), exp.Name())
cmd.Stdout = os.Stdout
err = cmd.Run()
os.Remove(exp.Name())
if err != nil {
panic(err)
}
err = Diff(s.old, s.new, got)
if err != nil {
t.Fatal("err", err)
}
_, err = got.Seek(0, 0)
if err != nil {
panic(err)
}
gotBuf := mustReadAll(got)
expBuf := mustReadAll(exp)
if !bytes.Equal(gotBuf, expBuf) {
t.Fail()
t.Logf("diff %s %s", s.old.Name(), s.new.Name())
t.Logf("%s: len(got) = %d", got.Name(), len(gotBuf))
t.Logf("%s: len(exp) = %d", exp.Name(), len(expBuf))
i := matchlen(gotBuf, expBuf)
t.Logf("produced different output at pos %d; %d != %d", i, gotBuf[i], expBuf[i])
}
}
}
binarydist-3035450ff8b987ec4373f65c40767f096b35f2d2/doc.go 0000664 0000000 0000000 00000001371 12744050656 0021516 0 ustar 00root root 0000000 0000000 // Package binarydist implements binary diff and patch as described on
// http://www.daemonology.net/bsdiff/. It reads and writes files
// compatible with the tools there.
package binarydist
var magic = [8]byte{'B', 'S', 'D', 'I', 'F', 'F', '4', '0'}
// File format:
// 0 8 "BSDIFF40"
// 8 8 X
// 16 8 Y
// 24 8 sizeof(newfile)
// 32 X bzip2(control block)
// 32+X Y bzip2(diff block)
// 32+X+Y ??? bzip2(extra block)
// with control block a set of triples (x,y,z) meaning "add x bytes
// from oldfile to x bytes from the diff block; copy y bytes from the
// extra block; seek forwards in oldfile by z bytes".
type header struct {
Magic [8]byte
CtrlLen int64
DiffLen int64
NewSize int64
}
binarydist-3035450ff8b987ec4373f65c40767f096b35f2d2/encoding.go 0000664 0000000 0000000 00000002377 12744050656 0022546 0 ustar 00root root 0000000 0000000 package binarydist
// SignMagLittleEndian is the numeric encoding used by the bsdiff tools.
// It implements binary.ByteOrder using a sign-magnitude format
// and little-endian byte order. Only methods Uint64 and String
// have been written; the rest panic.
type signMagLittleEndian struct{}
func (signMagLittleEndian) Uint16(b []byte) uint16 { panic("unimplemented") }
func (signMagLittleEndian) PutUint16(b []byte, v uint16) { panic("unimplemented") }
func (signMagLittleEndian) Uint32(b []byte) uint32 { panic("unimplemented") }
func (signMagLittleEndian) PutUint32(b []byte, v uint32) { panic("unimplemented") }
func (signMagLittleEndian) Uint64(b []byte) uint64 {
y := int64(b[0]) |
int64(b[1])<<8 |
int64(b[2])<<16 |
int64(b[3])<<24 |
int64(b[4])<<32 |
int64(b[5])<<40 |
int64(b[6])<<48 |
int64(b[7]&0x7f)<<56
if b[7]&0x80 != 0 {
y = -y
}
return uint64(y)
}
func (signMagLittleEndian) PutUint64(b []byte, v uint64) {
x := int64(v)
neg := x < 0
if neg {
x = -x
}
b[0] = byte(x)
b[1] = byte(x >> 8)
b[2] = byte(x >> 16)
b[3] = byte(x >> 24)
b[4] = byte(x >> 32)
b[5] = byte(x >> 40)
b[6] = byte(x >> 48)
b[7] = byte(x >> 56)
if neg {
b[7] |= 0x80
}
}
func (signMagLittleEndian) String() string { return "signMagLittleEndian" }
binarydist-3035450ff8b987ec4373f65c40767f096b35f2d2/patch.go 0000664 0000000 0000000 00000004127 12744050656 0022052 0 ustar 00root root 0000000 0000000 package binarydist
import (
"bytes"
"compress/bzip2"
"encoding/binary"
"errors"
"io"
"io/ioutil"
)
var ErrCorrupt = errors.New("corrupt patch")
// Patch applies patch to old, according to the bspatch algorithm,
// and writes the result to new.
func Patch(old io.Reader, new io.Writer, patch io.Reader) error {
var hdr header
err := binary.Read(patch, signMagLittleEndian{}, &hdr)
if err != nil {
return err
}
if hdr.Magic != magic {
return ErrCorrupt
}
if hdr.CtrlLen < 0 || hdr.DiffLen < 0 || hdr.NewSize < 0 {
return ErrCorrupt
}
ctrlbuf := make([]byte, hdr.CtrlLen)
_, err = io.ReadFull(patch, ctrlbuf)
if err != nil {
return err
}
cpfbz2 := bzip2.NewReader(bytes.NewReader(ctrlbuf))
diffbuf := make([]byte, hdr.DiffLen)
_, err = io.ReadFull(patch, diffbuf)
if err != nil {
return err
}
dpfbz2 := bzip2.NewReader(bytes.NewReader(diffbuf))
// The entire rest of the file is the extra block.
epfbz2 := bzip2.NewReader(patch)
obuf, err := ioutil.ReadAll(old)
if err != nil {
return err
}
nbuf := make([]byte, hdr.NewSize)
var oldpos, newpos int64
for newpos < hdr.NewSize {
var ctrl struct{ Add, Copy, Seek int64 }
err = binary.Read(cpfbz2, signMagLittleEndian{}, &ctrl)
if err != nil {
return err
}
// Sanity-check
if newpos+ctrl.Add > hdr.NewSize {
return ErrCorrupt
}
// Read diff string
_, err = io.ReadFull(dpfbz2, nbuf[newpos:newpos+ctrl.Add])
if err != nil {
return ErrCorrupt
}
// Add old data to diff string
for i := int64(0); i < ctrl.Add; i++ {
if oldpos+i >= 0 && oldpos+i < int64(len(obuf)) {
nbuf[newpos+i] += obuf[oldpos+i]
}
}
// Adjust pointers
newpos += ctrl.Add
oldpos += ctrl.Add
// Sanity-check
if newpos+ctrl.Copy > hdr.NewSize {
return ErrCorrupt
}
// Read extra string
_, err = io.ReadFull(epfbz2, nbuf[newpos:newpos+ctrl.Copy])
if err != nil {
return ErrCorrupt
}
// Adjust pointers
newpos += ctrl.Copy
oldpos += ctrl.Seek
}
// Write the new file
for len(nbuf) > 0 {
n, err := new.Write(nbuf)
if err != nil {
return err
}
nbuf = nbuf[n:]
}
return nil
}
binarydist-3035450ff8b987ec4373f65c40767f096b35f2d2/patch_test.go 0000664 0000000 0000000 00000002246 12744050656 0023111 0 ustar 00root root 0000000 0000000 package binarydist
import (
"io/ioutil"
"os"
"os/exec"
"testing"
)
func TestPatch(t *testing.T) {
mustWriteRandFile("test.old", 1e3, 1)
mustWriteRandFile("test.new", 1e3, 2)
got, err := ioutil.TempFile("/tmp", "bspatch.")
if err != nil {
panic(err)
}
os.Remove(got.Name())
err = exec.Command("bsdiff", "test.old", "test.new", "test.patch").Run()
if err != nil {
panic(err)
}
err = Patch(mustOpen("test.old"), got, mustOpen("test.patch"))
if err != nil {
t.Fatal("err", err)
}
ref, err := got.Seek(0, 2)
if err != nil {
panic(err)
}
t.Logf("got %d bytes", ref)
if n := fileCmp(got, mustOpen("test.new")); n > -1 {
t.Fatalf("produced different output at pos %d", n)
}
}
func TestPatchHk(t *testing.T) {
got, err := ioutil.TempFile("/tmp", "bspatch.")
if err != nil {
panic(err)
}
os.Remove(got.Name())
err = Patch(mustOpen("testdata/sample.old"), got, mustOpen("testdata/sample.patch"))
if err != nil {
t.Fatal("err", err)
}
ref, err := got.Seek(0, 2)
if err != nil {
panic(err)
}
t.Logf("got %d bytes", ref)
if n := fileCmp(got, mustOpen("testdata/sample.new")); n > -1 {
t.Fatalf("produced different output at pos %d", n)
}
}
binarydist-3035450ff8b987ec4373f65c40767f096b35f2d2/seek.go 0000664 0000000 0000000 00000001406 12744050656 0021677 0 ustar 00root root 0000000 0000000 package binarydist
import (
"errors"
)
type seekBuffer struct {
buf []byte
pos int
}
func (b *seekBuffer) Write(p []byte) (n int, err error) {
n = copy(b.buf[b.pos:], p)
if n == len(p) {
b.pos += n
return n, nil
}
b.buf = append(b.buf, p[n:]...)
b.pos += len(p)
return len(p), nil
}
func (b *seekBuffer) Seek(offset int64, whence int) (ret int64, err error) {
var abs int64
switch whence {
case 0:
abs = offset
case 1:
abs = int64(b.pos) + offset
case 2:
abs = int64(len(b.buf)) + offset
default:
return 0, errors.New("binarydist: invalid whence")
}
if abs < 0 {
return 0, errors.New("binarydist: negative position")
}
if abs >= 1<<31 {
return 0, errors.New("binarydist: position out of range")
}
b.pos = int(abs)
return abs, nil
}
binarydist-3035450ff8b987ec4373f65c40767f096b35f2d2/sort_test.go 0000664 0000000 0000000 00000000776 12744050656 0023007 0 ustar 00root root 0000000 0000000 package binarydist
import (
"bytes"
"crypto/rand"
"testing"
)
var sortT = [][]byte{
mustRandBytes(1000),
mustReadAll(mustOpen("test.old")),
[]byte("abcdefabcdef"),
}
func TestQsufsort(t *testing.T) {
for _, s := range sortT {
I := qsufsort(s)
for i := 1; i < len(I); i++ {
if bytes.Compare(s[I[i-1]:], s[I[i]:]) > 0 {
t.Fatalf("unsorted at %d", i)
}
}
}
}
func mustRandBytes(n int) []byte {
b := make([]byte, n)
_, err := rand.Read(b)
if err != nil {
panic(err)
}
return b
}
binarydist-3035450ff8b987ec4373f65c40767f096b35f2d2/testdata/ 0000775 0000000 0000000 00000000000 12744050656 0022231 5 ustar 00root root 0000000 0000000 binarydist-3035450ff8b987ec4373f65c40767f096b35f2d2/testdata/sample.new 0000664 0000000 0000000 00000023420 12744050656 0024226 0 ustar 00root root 0000000 0000000 H __PAGEZERO __TEXT @/ @/ __text __TEXT __symbol_stub1 __TEXT 8 __DATA P/ @ @/ Q __data __DATA P/ P @/ __nl_symbol_ptr __DATA 0 0 __bss __DATA 0 0 H __LINKEDIT `2 ? __DWARF 0 ul __debug_abbrev __DWARF 0 __debug_line __DWARF ̠0 __debug_frame __DWARF E l2 __debug_info __DWARF C 4 __debug_pubnames__DWARF FM
<