github.com/iqoqo/nomad@v0.11.3-0.20200911112621-d7021c74d101/client/lib/fifo/fifo_windows.go (about) 1 package fifo 2 3 import ( 4 "fmt" 5 "io" 6 "net" 7 "os" 8 "sync" 9 "time" 10 11 winio "github.com/Microsoft/go-winio" 12 ) 13 14 // PipeBufferSize is the size of the input and output buffers for the windows 15 // named pipe 16 const PipeBufferSize = int32(^uint16(0)) 17 18 type winFIFO struct { 19 listener net.Listener 20 conn net.Conn 21 connLock sync.Mutex 22 } 23 24 func (f *winFIFO) ensureConn() (net.Conn, error) { 25 f.connLock.Lock() 26 defer f.connLock.Unlock() 27 if f.conn == nil { 28 c, err := f.listener.Accept() 29 if err != nil { 30 return nil, err 31 } 32 f.conn = c 33 } 34 35 return f.conn, nil 36 } 37 38 func (f *winFIFO) Read(p []byte) (n int, err error) { 39 conn, err := f.ensureConn() 40 if err != nil { 41 return 0, err 42 } 43 44 // If the connection is closed then we need to close the listener 45 // to emulate unix fifo behavior 46 n, err = conn.Read(p) 47 if err == io.EOF { 48 f.listener.Close() 49 } 50 return n, err 51 } 52 53 func (f *winFIFO) Write(p []byte) (n int, err error) { 54 conn, err := f.ensureConn() 55 if err != nil { 56 return 0, err 57 } 58 59 // If the connection is closed then we need to close the listener 60 // to emulate unix fifo behavior 61 n, err = conn.Write(p) 62 if err == io.EOF { 63 conn.Close() 64 f.listener.Close() 65 } 66 return n, err 67 68 } 69 70 func (f *winFIFO) Close() error { 71 f.connLock.Lock() 72 if f.conn != nil { 73 f.conn.Close() 74 } 75 f.connLock.Unlock() 76 return f.listener.Close() 77 } 78 79 // CreateAndRead creates a fifo at the given path and returns an io.ReadCloser open for it. 80 // The fifo must not already exist 81 func CreateAndRead(path string) (func() (io.ReadCloser, error), error) { 82 l, err := winio.ListenPipe(path, &winio.PipeConfig{ 83 InputBufferSize: PipeBufferSize, 84 OutputBufferSize: PipeBufferSize, 85 }) 86 if err != nil { 87 return nil, fmt.Errorf("failed to create fifo: %v", err) 88 } 89 90 return func() (io.ReadCloser, error) { 91 return &winFIFO{ 92 listener: l, 93 }, nil 94 }, nil 95 } 96 97 func OpenReader(path string) (io.ReadCloser, error) { 98 l, err := winio.ListenOnlyPipe(path, nil) 99 if err != nil { 100 return nil, fmt.Errorf("failed to open fifo listener: %v", err) 101 } 102 103 return &winFIFO{listener: l}, nil 104 } 105 106 // OpenWriter opens a fifo that already exists and returns an io.WriteCloser for it 107 func OpenWriter(path string) (io.WriteCloser, error) { 108 return winio.DialPipe(path, nil) 109 } 110 111 // Remove a fifo that already exists at a given path 112 func Remove(path string) error { 113 dur := 500 * time.Millisecond 114 conn, err := winio.DialPipe(path, &dur) 115 if err == nil { 116 return conn.Close() 117 } 118 119 os.Remove(path) 120 return nil 121 } 122 123 func IsClosedErr(err error) bool { 124 return err == winio.ErrFileClosed 125 }