Fixed a panic when reading an empty file.
This commit is contained in:
parent
3e1d948164
commit
d2cac01b63
|
@ -1,7 +1,6 @@
|
|||
package goadb
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/zach-klippenstein/goadb/util"
|
||||
|
@ -15,6 +14,9 @@ type syncFileReader struct {
|
|||
|
||||
// Reader for the current chunk only.
|
||||
chunkReader io.Reader
|
||||
|
||||
// False until the DONE chunk is encountered.
|
||||
eof bool
|
||||
}
|
||||
|
||||
var _ io.ReadCloser = &syncFileReader{}
|
||||
|
@ -26,18 +28,30 @@ func newSyncFileReader(s wire.SyncScanner) (r io.ReadCloser, err error) {
|
|||
|
||||
// Read the header for the first chunk to consume any errors.
|
||||
if _, err = r.Read([]byte{}); err != nil {
|
||||
if err == io.EOF {
|
||||
// EOF means the file was empty. This still means the file was opened successfully,
|
||||
// and the next time the caller does a read they'll get the EOF and handle it themselves.
|
||||
err = nil
|
||||
} else {
|
||||
r.Close()
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (r *syncFileReader) Read(buf []byte) (n int, err error) {
|
||||
if r.eof {
|
||||
return 0, io.EOF
|
||||
}
|
||||
|
||||
if r.chunkReader == nil {
|
||||
chunkReader, err := readNextChunk(r.scanner)
|
||||
if err != nil {
|
||||
// If this is EOF, we've read the last chunk.
|
||||
// Either way, we want to pass it up to the caller.
|
||||
if err == io.EOF {
|
||||
// We just read the last chunk, set our flag before passing it up.
|
||||
r.eof = true
|
||||
}
|
||||
return 0, err
|
||||
}
|
||||
r.chunkReader = chunkReader
|
||||
|
@ -82,7 +96,7 @@ func readNextChunk(r wire.SyncScanner) (io.Reader, error) {
|
|||
case wire.StatusSyncDone:
|
||||
return nil, io.EOF
|
||||
default:
|
||||
return nil, fmt.Errorf("expected chunk id '%s' or '%s', but got '%s'",
|
||||
return nil, util.Errorf(util.AssertionError, "expected chunk id '%s' or '%s', but got '%s'",
|
||||
wire.StatusSyncData, wire.StatusSyncDone, []byte(status))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"github.com/stretchr/testify/assert"
|
||||
"github.com/zach-klippenstein/goadb/util"
|
||||
"github.com/zach-klippenstein/goadb/wire"
|
||||
"io/ioutil"
|
||||
)
|
||||
|
||||
func TestReadNextChunk(t *testing.T) {
|
||||
|
@ -44,7 +45,7 @@ func TestReadNextChunkInvalidChunkId(t *testing.T) {
|
|||
|
||||
// Read 1st chunk
|
||||
_, err := readNextChunk(s)
|
||||
assert.EqualError(t, err, "expected chunk id 'DATA' or 'DONE', but got 'ATAD'")
|
||||
assert.EqualError(t, err, "AssertionError: expected chunk id 'DATA' or 'DONE', but got 'ATAD'")
|
||||
}
|
||||
|
||||
func TestReadMultipleCalls(t *testing.T) {
|
||||
|
@ -91,6 +92,20 @@ func TestReadError(t *testing.T) {
|
|||
assert.EqualError(t, err, "AdbError: server error for read-chunk request: fail ({Request:read-chunk ServerMsg:fail})")
|
||||
}
|
||||
|
||||
func TestReadEmpty(t *testing.T) {
|
||||
s := wire.NewSyncScanner(strings.NewReader(
|
||||
"DONE"))
|
||||
r, err := newSyncFileReader(s)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Multiple read calls that return EOF is a valid case.
|
||||
for i := 0; i < 5; i++ {
|
||||
data, err := ioutil.ReadAll(r)
|
||||
assert.NoError(t, err)
|
||||
assert.Empty(t, data)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReadErrorNotFound(t *testing.T) {
|
||||
s := wire.NewSyncScanner(strings.NewReader(
|
||||
"FAIL\031\000\000\000No such file or directory"))
|
||||
|
|
2
util.go
2
util.go
|
@ -26,7 +26,7 @@ func wrapClientError(err error, client interface{}, operation string, args ...in
|
|||
return nil
|
||||
}
|
||||
if _, ok := err.(*util.Err); !ok {
|
||||
panic("err is not a *util.Err")
|
||||
panic("err is not a *util.Err: " + err.Error())
|
||||
}
|
||||
|
||||
clientType := reflect.TypeOf(client)
|
||||
|
|
|
@ -68,8 +68,7 @@ func (s *realSyncSender) SendBytes(data []byte) error {
|
|||
if err := s.SendInt32(int32(length)); err != nil {
|
||||
return util.WrapErrorf(err, util.NetworkError, "error sending data length on sync sender")
|
||||
}
|
||||
return util.WrapErrorf(writeFully(s.Writer, data),
|
||||
util.NetworkError, "error sending data on sync sender")
|
||||
return writeFully(s.Writer, data)
|
||||
}
|
||||
|
||||
func (s *realSyncSender) Close() error {
|
||||
|
|
Loading…
Reference in a new issue