git-lfs/git/pkt_line_reader.go
brian m. carlson b0d669c05b
filter-process: avoid hang when using git hash-object --stdin
When we use git hash-object --stdin with the --path option, Git applies
filters to the object, so Git LFS is invoked.  However, if the object
provided is less than 1024 bytes in size, we would hang.  This occurred
because of our packet reader didn't quite implement the io.Reader
interface completely: if it returned a non-zero value and io.EOF, the
next call to Read would not return 0 and io.EOF.  Instead, it would try
to read from stdin, which would not be sending us more data until we
provided a response, so we would hang.

To solve this, keep track of the EOF and always return it on subsequent
Read calls.  In addition, don't process the callback to write the file
in this case, since we don't actually want to write into the working
tree.
2019-11-04 19:55:45 +00:00

67 lines
1.3 KiB
Go

package git
import (
"io"
"github.com/git-lfs/git-lfs/tools"
)
type pktlineReader struct {
pl *pktline
buf []byte
eof bool
}
var _ io.Reader = new(pktlineReader)
func (r *pktlineReader) Read(p []byte) (int, error) {
var n int
if r.eof {
return 0, io.EOF
}
if len(r.buf) > 0 {
// If there is data in the buffer, shift as much out of it and
// into the given "p" as we can.
n = tools.MinInt(len(p), len(r.buf))
copy(p, r.buf[:n])
r.buf = r.buf[n:]
}
// Loop and grab as many packets as we can in a given "run", until we
// have either, a) overfilled the given buffer "p", or we have started
// to internally buffer in "r.buf".
for len(r.buf) == 0 {
chunk, err := r.pl.readPacket()
if err != nil {
return n, err
}
if len(chunk) == 0 {
// If we got an empty chunk, then we know that we have
// reached the end of processing for this particular
// packet, so let's terminate.
r.eof = true
return n, io.EOF
}
// Figure out how much of the packet we can read into "p".
nn := tools.MinInt(len(chunk), len(p[n:]))
// Move that amount into "p", from where we left off.
copy(p[n:], chunk[:nn])
// And move the rest into the buffer.
r.buf = append(r.buf, chunk[nn:]...)
// Mark that we have read "nn" bytes into "p"
n += nn
}
return n, nil
}