github.com/containerd/Containerd@v1.4.13/cio/io_windows.go (about) 1 /* 2 Copyright The containerd Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package cio 18 19 import ( 20 "context" 21 "fmt" 22 "io" 23 "net" 24 25 winio "github.com/Microsoft/go-winio" 26 "github.com/containerd/containerd/log" 27 "github.com/pkg/errors" 28 ) 29 30 const pipeRoot = `\\.\pipe` 31 32 // NewFIFOSetInDir returns a new set of fifos for the task 33 func NewFIFOSetInDir(_, id string, terminal bool) (*FIFOSet, error) { 34 stderrPipe := "" 35 if !terminal { 36 stderrPipe = fmt.Sprintf(`%s\ctr-%s-stderr`, pipeRoot, id) 37 } 38 return NewFIFOSet(Config{ 39 Terminal: terminal, 40 Stdin: fmt.Sprintf(`%s\ctr-%s-stdin`, pipeRoot, id), 41 Stdout: fmt.Sprintf(`%s\ctr-%s-stdout`, pipeRoot, id), 42 Stderr: stderrPipe, 43 }, nil), nil 44 } 45 46 func copyIO(fifos *FIFOSet, ioset *Streams) (*cio, error) { 47 var ( 48 set []io.Closer 49 ) 50 51 if fifos.Stdin != "" { 52 l, err := winio.ListenPipe(fifos.Stdin, nil) 53 if err != nil { 54 return nil, errors.Wrapf(err, "failed to create stdin pipe %s", fifos.Stdin) 55 } 56 defer func(l net.Listener) { 57 if err != nil { 58 l.Close() 59 } 60 }(l) 61 set = append(set, l) 62 63 go func() { 64 c, err := l.Accept() 65 if err != nil { 66 log.L.WithError(err).Errorf("failed to accept stdin connection on %s", fifos.Stdin) 67 return 68 } 69 70 p := bufPool.Get().(*[]byte) 71 defer bufPool.Put(p) 72 73 io.CopyBuffer(c, ioset.Stdin, *p) 74 c.Close() 75 l.Close() 76 }() 77 } 78 79 if fifos.Stdout != "" { 80 l, err := winio.ListenPipe(fifos.Stdout, nil) 81 if err != nil { 82 return nil, errors.Wrapf(err, "failed to create stdout pipe %s", fifos.Stdout) 83 } 84 defer func(l net.Listener) { 85 if err != nil { 86 l.Close() 87 } 88 }(l) 89 set = append(set, l) 90 91 go func() { 92 c, err := l.Accept() 93 if err != nil { 94 log.L.WithError(err).Errorf("failed to accept stdout connection on %s", fifos.Stdout) 95 return 96 } 97 98 p := bufPool.Get().(*[]byte) 99 defer bufPool.Put(p) 100 101 io.CopyBuffer(ioset.Stdout, c, *p) 102 c.Close() 103 l.Close() 104 }() 105 } 106 107 if fifos.Stderr != "" { 108 l, err := winio.ListenPipe(fifos.Stderr, nil) 109 if err != nil { 110 return nil, errors.Wrapf(err, "failed to create stderr pipe %s", fifos.Stderr) 111 } 112 defer func(l net.Listener) { 113 if err != nil { 114 l.Close() 115 } 116 }(l) 117 set = append(set, l) 118 119 go func() { 120 c, err := l.Accept() 121 if err != nil { 122 log.L.WithError(err).Errorf("failed to accept stderr connection on %s", fifos.Stderr) 123 return 124 } 125 126 p := bufPool.Get().(*[]byte) 127 defer bufPool.Put(p) 128 129 io.CopyBuffer(ioset.Stderr, c, *p) 130 c.Close() 131 l.Close() 132 }() 133 } 134 135 return &cio{config: fifos.Config, closers: set}, nil 136 } 137 138 // NewDirectIO returns an IO implementation that exposes the IO streams as io.ReadCloser 139 // and io.WriteCloser. 140 func NewDirectIO(stdin io.WriteCloser, stdout, stderr io.ReadCloser, terminal bool) *DirectIO { 141 return &DirectIO{ 142 pipes: pipes{ 143 Stdin: stdin, 144 Stdout: stdout, 145 Stderr: stderr, 146 }, 147 cio: cio{ 148 config: Config{Terminal: terminal}, 149 }, 150 } 151 } 152 153 // NewDirectIOFromFIFOSet returns an IO implementation that exposes the IO streams as io.ReadCloser 154 // and io.WriteCloser. 155 func NewDirectIOFromFIFOSet(ctx context.Context, stdin io.WriteCloser, stdout, stderr io.ReadCloser, fifos *FIFOSet) *DirectIO { 156 _, cancel := context.WithCancel(ctx) 157 pipes := pipes{ 158 Stdin: stdin, 159 Stdout: stdout, 160 Stderr: stderr, 161 } 162 return &DirectIO{ 163 pipes: pipes, 164 cio: cio{ 165 config: fifos.Config, 166 closers: append(pipes.closers(), fifos), 167 cancel: cancel, 168 }, 169 } 170 }