diff --git a/components/engine/libcontainerd/client_windows.go b/components/engine/libcontainerd/client_windows.go index fac9a35683..ddf8543e33 100644 --- a/components/engine/libcontainerd/client_windows.go +++ b/components/engine/libcontainerd/client_windows.go @@ -291,6 +291,9 @@ func (clnt *client) AddProcess(containerID, processFriendlyName string, procToAd return err } + // TEMP: Work around Windows BS/DEL behavior. + iopipe.Stdin = fixStdinBackspaceBehavior(iopipe.Stdin, procToAdd.Terminal) + // Convert io.ReadClosers to io.Readers if stdout != nil { iopipe.Stdout = openReaderFromPipe(stdout) diff --git a/components/engine/libcontainerd/container_windows.go b/components/engine/libcontainerd/container_windows.go index ec35746b5c..e1f64a1704 100644 --- a/components/engine/libcontainerd/container_windows.go +++ b/components/engine/libcontainerd/container_windows.go @@ -102,6 +102,9 @@ func (ctr *container) start() error { } ctr.startedAt = time.Now() + // TEMP: Work around Windows BS/DEL behavior. + iopipe.Stdin = fixStdinBackspaceBehavior(iopipe.Stdin, ctr.ociSpec.Process.Terminal) + // Convert io.ReadClosers to io.Readers if stdout != nil { iopipe.Stdout = openReaderFromPipe(stdout) diff --git a/components/engine/libcontainerd/process_windows.go b/components/engine/libcontainerd/process_windows.go index 0371aec91f..12593bba67 100644 --- a/components/engine/libcontainerd/process_windows.go +++ b/components/engine/libcontainerd/process_windows.go @@ -2,6 +2,8 @@ package libcontainerd import ( "io" + + "github.com/docker/docker/pkg/system" ) // process keeps the state for both main container process and exec process. @@ -25,3 +27,33 @@ func openReaderFromPipe(p io.ReadCloser) io.Reader { }() return r } + +// fixStdinBackspaceBehavior works around a bug in Windows before build 14350 +// where it interpreted DEL as VK_DELETE instead of as VK_BACK. This replaces +// DEL with BS to work around this. +func fixStdinBackspaceBehavior(w io.WriteCloser, tty bool) io.WriteCloser { + if !tty || system.GetOSVersion().Build >= 14350 { + return w + } + return &delToBsWriter{w} +} + +type delToBsWriter struct { + io.WriteCloser +} + +func (w *delToBsWriter) Write(b []byte) (int, error) { + const ( + backspace = 0x8 + del = 0x7f + ) + bc := make([]byte, len(b)) + for i, c := range b { + if c == del { + bc[i] = backspace + } else { + bc[i] = c + } + } + return w.WriteCloser.Write(bc) +}