87 lines
2.4 KiB
Go
87 lines
2.4 KiB
Go
package adb
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"time"
|
|
|
|
"github.com/timoxa0/goadb/internal/errors"
|
|
"github.com/timoxa0/goadb/wire"
|
|
)
|
|
|
|
// syncFileWriter wraps a SyncConn that has requested to send a file.
|
|
type syncFileWriter struct {
|
|
// The modification time to write in the footer.
|
|
// If 0, use the current time.
|
|
mtime time.Time
|
|
|
|
// Reader used to read data from the adb connection.
|
|
sender wire.SyncSender
|
|
}
|
|
|
|
var _ io.WriteCloser = &syncFileWriter{}
|
|
|
|
func newSyncFileWriter(s wire.SyncSender, mtime time.Time) io.WriteCloser {
|
|
return &syncFileWriter{
|
|
mtime: mtime,
|
|
sender: s,
|
|
}
|
|
}
|
|
|
|
/*
|
|
encodePathAndMode encodes a path and file mode as required for starting a send file stream.
|
|
|
|
From https://android.googlesource.com/platform/system/core/+/master/adb/SYNC.TXT:
|
|
The remote file name is split into two parts separated by the last
|
|
comma (","). The first part is the actual path, while the second is a decimal
|
|
encoded file mode containing the permissions of the file on device.
|
|
*/
|
|
func encodePathAndMode(path string, mode os.FileMode) []byte {
|
|
return []byte(fmt.Sprintf("%s,%d", path, uint32(mode.Perm())))
|
|
}
|
|
|
|
// Write writes the min of (len(buf), 64k).
|
|
func (w *syncFileWriter) Write(buf []byte) (n int, err error) {
|
|
written := 0
|
|
|
|
// If buf > 64k we'll have to send multiple chunks.
|
|
// TODO Refactor this into something that can coalesce smaller writes into a single chukn.
|
|
for len(buf) > 0 {
|
|
// Writes < 64k have a one-to-one mapping to chunks.
|
|
// If buffer is larger than the max, we'll return the max size and leave it up to the
|
|
// caller to handle correctly.
|
|
partialBuf := buf
|
|
if len(partialBuf) > wire.SyncMaxChunkSize {
|
|
partialBuf = partialBuf[:wire.SyncMaxChunkSize]
|
|
}
|
|
|
|
if err := w.sender.SendOctetString(wire.StatusSyncData); err != nil {
|
|
return written, err
|
|
}
|
|
if err := w.sender.SendBytes(partialBuf); err != nil {
|
|
return written, err
|
|
}
|
|
|
|
written += len(partialBuf)
|
|
buf = buf[len(partialBuf):]
|
|
}
|
|
|
|
return written, nil
|
|
}
|
|
|
|
func (w *syncFileWriter) Close() error {
|
|
if w.mtime.IsZero() {
|
|
w.mtime = time.Now()
|
|
}
|
|
|
|
if err := w.sender.SendOctetString(wire.StatusSyncDone); err != nil {
|
|
return errors.WrapErrf(err, "error sending done chunk to close stream")
|
|
}
|
|
if err := w.sender.SendTime(w.mtime); err != nil {
|
|
return errors.WrapErrf(err, "error writing file modification time")
|
|
}
|
|
|
|
return errors.WrapErrf(w.sender.Close(), "error closing FileWriter")
|
|
}
|