diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..42ea61e --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module github.com/myml/ar + +go 1.14 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..e69de29 diff --git a/reader.go b/reader.go index 4b82493..db05f24 100644 --- a/reader.go +++ b/reader.go @@ -22,6 +22,7 @@ THE SOFTWARE. package ar import ( + "bytes" "io" "io/ioutil" "os" @@ -84,8 +85,12 @@ func (rd *Reader) octal(b []byte) int64 { for i > 0 && b[i] == 32 { i-- } - - n, _ := strconv.ParseInt(string(b[3:i+1]), 8, 64) + start := 3 + // ar command tool mode no hava '100' prefix + if bytes.IndexByte(b, ' ') == 3 { + start = 0 + } + n, _ := strconv.ParseInt(string(b[start:i+1]), 8, 64) return n } diff --git a/writer.go b/writer.go index 680f5cb..bd623ac 100644 --- a/writer.go +++ b/writer.go @@ -1,4 +1,4 @@ -/* +/* Copyright (c) 2013 Blake Smith Permission is hereby granted, free of charge, to any person obtaining a copy @@ -28,7 +28,7 @@ import ( ) var ( - ErrWriteTooLong = errors.New("ar: write too long") + ErrWriteTooLong = errors.New("ar: write too long") ) // Writer provides sequential writing of an ar archive. @@ -45,7 +45,7 @@ var ( // } // io.Copy(archive, data) type Writer struct { - w io.Writer + w io.Writer nb int64 // number of unwritten bytes for the current file entry } @@ -92,7 +92,7 @@ func (aw *Writer) Write(b []byte) (n int, err error) { if len(b)%2 == 1 { // data size must be aligned to an even byte n2, _ := aw.w.Write([]byte{'\n'}) - return n+n2, err + return n + n2, err } return @@ -122,3 +122,18 @@ func (aw *Writer) WriteHeader(hdr *Header) error { return err } + +var _ io.ReaderFrom = &Writer{} + +// ReadFrom prevent returns io.ErrShortWrite when using io.Copy. This is to make io.Copy() to work correctly. +func (aw *Writer) ReadFrom(r io.Reader) (written int64, err error) { + written, err = io.Copy(aw.w, r) + if err != nil { + return written, err + } + if written%2 == 1 { // data size must be aligned to an even byte + n2, err := aw.w.Write([]byte{'\n'}) + return written + int64(n2), err + } + return written, err +} diff --git a/writer_test.go b/writer_test.go index 36b576a..4a38d41 100644 --- a/writer_test.go +++ b/writer_test.go @@ -1,4 +1,4 @@ -/* +/* Copyright (c) 2013 Blake Smith Permission is hereby granted, free of charge, to any person obtaining a copy @@ -23,8 +23,10 @@ package ar import ( "bytes" + "io" "io/ioutil" "os" + "strings" "testing" "time" ) @@ -90,3 +92,39 @@ func TestWriteTooLong(t *testing.T) { t.Errorf("Error should have been: %s", ErrWriteTooLong) } } + +// Use odd byte check error +func TestShortWrite(t *testing.T) { + body := strings.NewReader("Hello world!\n") + + hdr := new(Header) + hdr.Size = body.Size() + + var buf bytes.Buffer + writer := NewWriter(&buf) + writer.WriteHeader(hdr) + // Hide io.WriteTo interface and io.ReadFrom interface + _, err := io.Copy(io.MultiWriter(writer), io.MultiReader(body)) + if err != io.ErrShortWrite { + t.Errorf("Error should have been: %s", io.ErrShortWrite) + } +} + +func TestWriteCopy(t *testing.T) { + body := strings.NewReader("Hello world!\n") + + hdr := new(Header) + hdr.Size = body.Size() + + var buf bytes.Buffer + writer := NewWriter(&buf) + writer.WriteHeader(hdr) + // Only hide io.WriteTo interface + wn, err := io.Copy(writer, io.MultiReader(body)) + if err != nil { + t.Fatal(err) + } + if wn != hdr.Size+1 { + t.Errorf("Expected %d to equal %d", wn, hdr.Size+1) + } +}