2016-10-28 20:57:43 +00:00
|
|
|
package git
|
|
|
|
|
|
|
|
import (
|
|
|
|
"io"
|
2016-11-03 20:26:19 +00:00
|
|
|
|
2016-11-15 17:01:18 +00:00
|
|
|
"github.com/git-lfs/git-lfs/tools"
|
2016-10-28 20:57:43 +00:00
|
|
|
)
|
|
|
|
|
2016-11-09 01:49:19 +00:00
|
|
|
// PktlineWriter is an implementation of `io.Writer` which writes data buffers
|
|
|
|
// "p" to an underlying pkt-line stream for use with the Git pkt-line format.
|
|
|
|
type PktlineWriter struct {
|
2016-11-07 22:35:01 +00:00
|
|
|
// buf is an internal buffer used to store data until enough has been
|
|
|
|
// collected to write a full packet, or the buffer was instructed to
|
|
|
|
// flush.
|
2016-10-28 20:57:43 +00:00
|
|
|
buf []byte
|
2016-11-08 20:45:38 +00:00
|
|
|
// pl is the place where packets get written.
|
|
|
|
pl *pktline
|
2016-10-28 20:57:43 +00:00
|
|
|
}
|
|
|
|
|
2016-11-09 01:49:19 +00:00
|
|
|
var _ io.Writer = new(PktlineWriter)
|
2016-10-28 20:57:43 +00:00
|
|
|
|
2016-11-09 01:49:19 +00:00
|
|
|
// NewPktlineWriter returns a new *PktlineWriter, which will write to the
|
2016-11-04 21:15:18 +00:00
|
|
|
// underlying data stream "w". The internal buffer is initialized with the given
|
|
|
|
// capacity, "c".
|
2016-10-28 21:04:23 +00:00
|
|
|
//
|
2016-11-09 01:49:19 +00:00
|
|
|
// If "w" is already a `*PktlineWriter`, it will be returned as-is.
|
|
|
|
func NewPktlineWriter(w io.Writer, c int) *PktlineWriter {
|
|
|
|
if pw, ok := w.(*PktlineWriter); ok {
|
2016-10-28 21:04:23 +00:00
|
|
|
return pw
|
|
|
|
}
|
|
|
|
|
2016-11-09 01:49:19 +00:00
|
|
|
return &PktlineWriter{
|
2016-11-08 20:45:38 +00:00
|
|
|
buf: make([]byte, 0, c),
|
|
|
|
pl: newPktline(nil, w),
|
2016-11-04 21:15:18 +00:00
|
|
|
}
|
2016-10-28 21:04:23 +00:00
|
|
|
}
|
|
|
|
|
2016-10-28 20:57:43 +00:00
|
|
|
// Write implements the io.Writer interface's `Write` method by providing a
|
|
|
|
// packet-based backend to the given buffer "p".
|
|
|
|
//
|
|
|
|
// As many bytes are removed from "p" as possible and stored in an internal
|
|
|
|
// buffer until the amount of data in the internal buffer is enough to write a
|
|
|
|
// single packet. Once the internal buffer is full, a packet is written to the
|
|
|
|
// underlying stream of data, and the process repeats.
|
|
|
|
//
|
|
|
|
// When the caller has no more data to write in the given chunk of packets, a
|
2016-11-11 19:53:40 +00:00
|
|
|
// subsequent call to `Flush()` SHOULD be made in order to signify that the
|
|
|
|
// current pkt sequence has terminated, and a new one can begin.
|
2016-10-28 20:57:43 +00:00
|
|
|
//
|
2016-11-07 21:06:44 +00:00
|
|
|
// Write returns the number of bytes in "p" accepted into the writer, which
|
|
|
|
// _MAY_ be written to the underlying protocol stream, or may be written into
|
|
|
|
// the internal buffer.
|
|
|
|
//
|
|
|
|
// If any error was encountered while either buffering or writing, that
|
2016-10-28 20:57:43 +00:00
|
|
|
// error is returned, along with the number of bytes written to the underlying
|
|
|
|
// protocol stream, as described above.
|
2016-11-09 01:49:19 +00:00
|
|
|
func (w *PktlineWriter) Write(p []byte) (int, error) {
|
2016-10-28 20:57:43 +00:00
|
|
|
var n int
|
|
|
|
|
2016-11-10 22:25:28 +00:00
|
|
|
for len(p[n:]) > 0 {
|
2016-10-28 20:57:43 +00:00
|
|
|
// While there is still data left to process in "p", grab as
|
|
|
|
// much of it as we can while not allowing the internal buffer
|
|
|
|
// to exceed the MaxPacketLength const.
|
2016-11-10 22:25:28 +00:00
|
|
|
m := tools.MinInt(len(p[n:]), MaxPacketLength-len(w.buf))
|
2016-10-28 20:57:43 +00:00
|
|
|
|
|
|
|
// Append on all of the data that we could into the internal
|
|
|
|
// buffer.
|
2016-11-10 22:25:28 +00:00
|
|
|
w.buf = append(w.buf, p[n:n+m]...)
|
2016-10-28 20:57:43 +00:00
|
|
|
|
2016-11-10 19:20:11 +00:00
|
|
|
n += m
|
2016-11-07 21:06:44 +00:00
|
|
|
|
2016-10-28 20:57:43 +00:00
|
|
|
if len(w.buf) == MaxPacketLength {
|
|
|
|
// If we were able to grab an entire packet's worth of
|
|
|
|
// data, flush the buffer.
|
|
|
|
|
2016-11-07 21:06:44 +00:00
|
|
|
if _, err := w.flush(); err != nil {
|
2016-10-28 20:57:43 +00:00
|
|
|
return n, err
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return n, nil
|
|
|
|
}
|
|
|
|
|
2016-11-08 17:19:23 +00:00
|
|
|
// Flush empties the internal buffer used to store data temporarily and then
|
|
|
|
// writes the pkt-line's FLUSH packet, to signal that it is done writing this
|
|
|
|
// chunk of data.
|
2016-11-09 01:49:19 +00:00
|
|
|
func (w *PktlineWriter) Flush() error {
|
2016-11-08 17:19:23 +00:00
|
|
|
if _, err := w.flush(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2016-11-08 20:45:38 +00:00
|
|
|
if err := w.pl.writeFlush(); err != nil {
|
2016-11-08 17:19:23 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2016-10-28 20:57:43 +00:00
|
|
|
// flush writes any data in the internal buffer out to the underlying protocol
|
|
|
|
// stream. If the amount of data in the internal buffer exceeds the
|
|
|
|
// MaxPacketLength, the data will be written in multiple packets to accommodate.
|
|
|
|
//
|
|
|
|
// flush returns the number of bytes written to the underlying packet stream,
|
|
|
|
// and any error that it encountered along the way.
|
2016-11-09 01:49:19 +00:00
|
|
|
func (w *PktlineWriter) flush() (int, error) {
|
2016-10-28 20:57:43 +00:00
|
|
|
var n int
|
|
|
|
|
|
|
|
for len(w.buf) > 0 {
|
2016-11-08 20:45:38 +00:00
|
|
|
if err := w.pl.writePacket(w.buf); err != nil {
|
2016-10-28 20:57:43 +00:00
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
|
2016-11-03 20:26:19 +00:00
|
|
|
m := tools.MinInt(len(w.buf), MaxPacketLength)
|
2016-10-28 20:57:43 +00:00
|
|
|
|
|
|
|
w.buf = w.buf[m:]
|
|
|
|
|
|
|
|
n = n + m
|
|
|
|
}
|
|
|
|
|
|
|
|
return n, nil
|
|
|
|
}
|