2017-05-15 17:13:34 -04:00
|
|
|
package filesync
|
|
|
|
|
|
|
|
import (
|
2018-06-08 05:26:10 -04:00
|
|
|
"bufio"
|
|
|
|
io "io"
|
2017-09-29 06:32:26 -04:00
|
|
|
"os"
|
2017-05-15 17:13:34 -04:00
|
|
|
"time"
|
|
|
|
|
2018-06-08 05:26:10 -04:00
|
|
|
"github.com/pkg/errors"
|
2017-08-07 05:52:40 -04:00
|
|
|
"github.com/sirupsen/logrus"
|
2017-05-15 17:13:34 -04:00
|
|
|
"github.com/tonistiigi/fsutil"
|
2018-10-05 05:05:42 -04:00
|
|
|
fstypes "github.com/tonistiigi/fsutil/types"
|
2017-09-29 06:32:26 -04:00
|
|
|
"google.golang.org/grpc"
|
2017-05-15 17:13:34 -04:00
|
|
|
)
|
|
|
|
|
2018-08-11 15:04:13 -04:00
|
|
|
func sendDiffCopy(stream grpc.Stream, fs fsutil.FS, progress progressCb) error {
|
2019-09-20 20:42:32 -04:00
|
|
|
return errors.WithStack(fsutil.Send(stream.Context(), stream, fs, progress))
|
2017-05-15 17:13:34 -04:00
|
|
|
}
|
|
|
|
|
2018-06-08 05:26:10 -04:00
|
|
|
func newStreamWriter(stream grpc.ClientStream) io.WriteCloser {
|
|
|
|
wc := &streamWriterCloser{ClientStream: stream}
|
|
|
|
return &bufferedWriteCloser{Writer: bufio.NewWriter(wc), Closer: wc}
|
|
|
|
}
|
|
|
|
|
|
|
|
type bufferedWriteCloser struct {
|
|
|
|
*bufio.Writer
|
|
|
|
io.Closer
|
|
|
|
}
|
|
|
|
|
|
|
|
func (bwc *bufferedWriteCloser) Close() error {
|
|
|
|
if err := bwc.Writer.Flush(); err != nil {
|
2019-09-20 20:42:32 -04:00
|
|
|
return errors.WithStack(err)
|
2018-06-08 05:26:10 -04:00
|
|
|
}
|
|
|
|
return bwc.Closer.Close()
|
|
|
|
}
|
|
|
|
|
|
|
|
type streamWriterCloser struct {
|
|
|
|
grpc.ClientStream
|
|
|
|
}
|
|
|
|
|
|
|
|
func (wc *streamWriterCloser) Write(dt []byte) (int, error) {
|
|
|
|
if err := wc.ClientStream.SendMsg(&BytesMessage{Data: dt}); err != nil {
|
2019-09-20 20:42:32 -04:00
|
|
|
// SendMsg return EOF on remote errors
|
2020-07-20 09:49:37 -04:00
|
|
|
if errors.Is(err, io.EOF) {
|
2019-09-20 20:42:32 -04:00
|
|
|
if err := errors.WithStack(wc.ClientStream.RecvMsg(struct{}{})); err != nil {
|
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0, errors.WithStack(err)
|
2018-06-08 05:26:10 -04:00
|
|
|
}
|
|
|
|
return len(dt), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (wc *streamWriterCloser) Close() error {
|
|
|
|
if err := wc.ClientStream.CloseSend(); err != nil {
|
2019-09-20 20:42:32 -04:00
|
|
|
return errors.WithStack(err)
|
2018-06-08 05:26:10 -04:00
|
|
|
}
|
|
|
|
// block until receiver is done
|
|
|
|
var bm BytesMessage
|
|
|
|
if err := wc.ClientStream.RecvMsg(&bm); err != io.EOF {
|
2019-09-20 20:42:32 -04:00
|
|
|
return errors.WithStack(err)
|
2018-06-08 05:26:10 -04:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-04-03 02:23:23 -04:00
|
|
|
func recvDiffCopy(ds grpc.Stream, dest string, cu CacheUpdater, progress progressCb, filter func(string, *fstypes.Stat) bool) error {
|
2017-05-15 17:13:34 -04:00
|
|
|
st := time.Now()
|
|
|
|
defer func() {
|
|
|
|
logrus.Debugf("diffcopy took: %v", time.Since(st))
|
|
|
|
}()
|
|
|
|
var cf fsutil.ChangeFunc
|
2017-09-29 06:32:26 -04:00
|
|
|
var ch fsutil.ContentHasher
|
2017-05-15 17:13:34 -04:00
|
|
|
if cu != nil {
|
|
|
|
cu.MarkSupported(true)
|
|
|
|
cf = cu.HandleChange
|
2017-09-29 06:32:26 -04:00
|
|
|
ch = cu.ContentHasher()
|
2017-05-15 17:13:34 -04:00
|
|
|
}
|
2019-09-20 20:42:32 -04:00
|
|
|
return errors.WithStack(fsutil.Receive(ds.Context(), ds, dest, fsutil.ReceiveOpt{
|
2017-09-29 06:32:26 -04:00
|
|
|
NotifyHashed: cf,
|
|
|
|
ContentHasher: ch,
|
|
|
|
ProgressCb: progress,
|
2019-04-03 02:23:23 -04:00
|
|
|
Filter: fsutil.FilterFunc(filter),
|
2019-09-20 20:42:32 -04:00
|
|
|
}))
|
2017-09-29 06:32:26 -04:00
|
|
|
}
|
2017-05-15 17:13:34 -04:00
|
|
|
|
2017-09-29 06:32:26 -04:00
|
|
|
func syncTargetDiffCopy(ds grpc.Stream, dest string) error {
|
|
|
|
if err := os.MkdirAll(dest, 0700); err != nil {
|
2019-09-20 20:42:32 -04:00
|
|
|
return errors.Wrapf(err, "failed to create synctarget dest dir %s", dest)
|
2017-09-29 06:32:26 -04:00
|
|
|
}
|
2019-09-20 20:42:32 -04:00
|
|
|
return errors.WithStack(fsutil.Receive(ds.Context(), ds, dest, fsutil.ReceiveOpt{
|
2017-09-29 06:32:26 -04:00
|
|
|
Merge: true,
|
2019-04-03 02:23:23 -04:00
|
|
|
Filter: func() func(string, *fstypes.Stat) bool {
|
2017-09-29 06:32:26 -04:00
|
|
|
uid := os.Getuid()
|
|
|
|
gid := os.Getgid()
|
2019-04-03 02:23:23 -04:00
|
|
|
return func(p string, st *fstypes.Stat) bool {
|
2017-09-29 06:32:26 -04:00
|
|
|
st.Uid = uint32(uid)
|
|
|
|
st.Gid = uint32(gid)
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}(),
|
2019-09-20 20:42:32 -04:00
|
|
|
}))
|
2017-05-15 17:13:34 -04:00
|
|
|
}
|
2018-06-08 05:26:10 -04:00
|
|
|
|
|
|
|
func writeTargetFile(ds grpc.Stream, wc io.WriteCloser) error {
|
|
|
|
for {
|
|
|
|
bm := BytesMessage{}
|
|
|
|
if err := ds.RecvMsg(&bm); err != nil {
|
2020-07-20 09:49:37 -04:00
|
|
|
if errors.Is(err, io.EOF) {
|
2018-06-08 05:26:10 -04:00
|
|
|
return nil
|
|
|
|
}
|
2019-09-20 20:42:32 -04:00
|
|
|
return errors.WithStack(err)
|
2018-06-08 05:26:10 -04:00
|
|
|
}
|
|
|
|
if _, err := wc.Write(bm.Data); err != nil {
|
2019-09-20 20:42:32 -04:00
|
|
|
return errors.WithStack(err)
|
2018-06-08 05:26:10 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|