utils: Add function to allow copying with detach
@@ -79,3 +79,63 @@ func newProp(name string, units interface{}) systemdDbus.Property {
Value: dbus.MakeVariant(units),
}
}
+
+// DetachError is special error which returned in case of container detach.
+type DetachError struct{}
+
+func (DetachError) Error() string {
+ return "detached from container"
+}
+
+// CopyDetachable is similar to io.Copy but support a detach key sequence to break out.
+func CopyDetachable(dst io.Writer, src io.Reader, keys []byte) (written int64, err error) {
+ if len(keys) == 0 {
+ // Default keys : ctrl-p ctrl-q
+ keys = []byte{16, 17}
+ }
+
+ buf := make([]byte, 32*1024)
+ for {
+ nr, er := src.Read(buf)
+ if nr > 0 {
+ preservBuf := []byte{}
+ for i, key := range keys {
+ preservBuf = append(preservBuf, buf[0:nr]...)
+ if nr != 1 || buf[0] != key {
+ break
+ }
+ if i == len(keys)-1 {
+ // src.Close()
+ return 0, DetachError{}
+ }
+ nr, er = src.Read(buf)
+ }
+ var nw int
+ var ew error
+ if len(preservBuf) > 0 {
+ nw, ew = dst.Write(preservBuf)
+ nr = len(preservBuf)
+ } else {
+ nw, ew = dst.Write(buf[0:nr])
+ }
+ if nw > 0 {
+ written += int64(nw)
+ }
+ if ew != nil {
+ err = ew
+ break
+ }
+ if nr != nw {
+ err = io.ErrShortWrite
+ break
+ }
+ }
+ if er != nil {
+ if er != io.EOF {
+ err = er
+ }
+ break
+ }
+ }
+ return written, err
+}
