github.com/demonoid81/moby@v0.0.0-20200517203328-62dd8e17c460/daemon/graphdriver/lcow/remotefs_file.go (about) 1 // +build windows 2 3 package lcow // import "github.com/demonoid81/moby/daemon/graphdriver/lcow" 4 5 import ( 6 "bytes" 7 "encoding/binary" 8 "encoding/json" 9 "fmt" 10 "io" 11 "os" 12 "strconv" 13 14 "github.com/Microsoft/hcsshim" 15 "github.com/Microsoft/opengcs/service/gcsutils/remotefs" 16 "github.com/containerd/continuity/driver" 17 ) 18 19 type lcowfile struct { 20 process hcsshim.Process 21 stdin io.WriteCloser 22 stdout io.ReadCloser 23 stderr io.ReadCloser 24 fs *lcowfs 25 guestPath string 26 } 27 28 func (l *lcowfs) Open(path string) (driver.File, error) { 29 return l.OpenFile(path, os.O_RDONLY, 0) 30 } 31 32 func (l *lcowfs) OpenFile(path string, flag int, perm os.FileMode) (_ driver.File, err error) { 33 flagStr := strconv.FormatInt(int64(flag), 10) 34 permStr := strconv.FormatUint(uint64(perm), 8) 35 36 commandLine := fmt.Sprintf("%s %s %s %s %s", remotefs.RemotefsCmd, remotefs.OpenFileCmd, path, flagStr, permStr) 37 env := make(map[string]string) 38 env["PATH"] = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:" 39 processConfig := &hcsshim.ProcessConfig{ 40 EmulateConsole: false, 41 CreateStdInPipe: true, 42 CreateStdOutPipe: true, 43 CreateStdErrPipe: true, 44 CreateInUtilityVm: true, 45 WorkingDirectory: "/bin", 46 Environment: env, 47 CommandLine: commandLine, 48 } 49 50 process, err := l.currentSVM.config.Uvm.CreateProcess(processConfig) 51 if err != nil { 52 return nil, fmt.Errorf("failed to open file %s: %s", path, err) 53 } 54 55 stdin, stdout, stderr, err := process.Stdio() 56 if err != nil { 57 process.Kill() 58 process.Close() 59 return nil, fmt.Errorf("failed to open file pipes %s: %s", path, err) 60 } 61 62 lf := &lcowfile{ 63 process: process, 64 stdin: stdin, 65 stdout: stdout, 66 stderr: stderr, 67 fs: l, 68 guestPath: path, 69 } 70 71 if _, err := lf.getResponse(); err != nil { 72 return nil, fmt.Errorf("failed to open file %s: %s", path, err) 73 } 74 return lf, nil 75 } 76 77 func (l *lcowfile) Read(b []byte) (int, error) { 78 hdr := &remotefs.FileHeader{ 79 Cmd: remotefs.Read, 80 Size: uint64(len(b)), 81 } 82 83 if err := remotefs.WriteFileHeader(l.stdin, hdr, nil); err != nil { 84 return 0, err 85 } 86 87 buf, err := l.getResponse() 88 if err != nil { 89 return 0, err 90 } 91 92 n := copy(b, buf) 93 return n, nil 94 } 95 96 func (l *lcowfile) Write(b []byte) (int, error) { 97 hdr := &remotefs.FileHeader{ 98 Cmd: remotefs.Write, 99 Size: uint64(len(b)), 100 } 101 102 if err := remotefs.WriteFileHeader(l.stdin, hdr, b); err != nil { 103 return 0, err 104 } 105 106 _, err := l.getResponse() 107 if err != nil { 108 return 0, err 109 } 110 111 return len(b), nil 112 } 113 114 func (l *lcowfile) Seek(offset int64, whence int) (int64, error) { 115 seekHdr := &remotefs.SeekHeader{ 116 Offset: offset, 117 Whence: int32(whence), 118 } 119 120 buf := &bytes.Buffer{} 121 if err := binary.Write(buf, binary.BigEndian, seekHdr); err != nil { 122 return 0, err 123 } 124 125 hdr := &remotefs.FileHeader{ 126 Cmd: remotefs.Write, 127 Size: uint64(buf.Len()), 128 } 129 if err := remotefs.WriteFileHeader(l.stdin, hdr, buf.Bytes()); err != nil { 130 return 0, err 131 } 132 133 resBuf, err := l.getResponse() 134 if err != nil { 135 return 0, err 136 } 137 138 var res int64 139 if err := binary.Read(bytes.NewBuffer(resBuf), binary.BigEndian, &res); err != nil { 140 return 0, err 141 } 142 return res, nil 143 } 144 145 func (l *lcowfile) Close() error { 146 hdr := &remotefs.FileHeader{ 147 Cmd: remotefs.Close, 148 Size: 0, 149 } 150 151 if err := remotefs.WriteFileHeader(l.stdin, hdr, nil); err != nil { 152 return err 153 } 154 155 _, err := l.getResponse() 156 return err 157 } 158 159 func (l *lcowfile) Readdir(n int) ([]os.FileInfo, error) { 160 nStr := strconv.FormatInt(int64(n), 10) 161 162 // Unlike the other File functions, this one can just be run without maintaining state, 163 // so just do the normal runRemoteFSProcess way. 164 buf := &bytes.Buffer{} 165 if err := l.fs.runRemoteFSProcess(nil, buf, remotefs.ReadDirCmd, l.guestPath, nStr); err != nil { 166 return nil, err 167 } 168 169 var info []remotefs.FileInfo 170 if err := json.Unmarshal(buf.Bytes(), &info); err != nil { 171 return nil, err 172 } 173 174 osInfo := make([]os.FileInfo, len(info)) 175 for i := range info { 176 osInfo[i] = &info[i] 177 } 178 return osInfo, nil 179 } 180 181 func (l *lcowfile) getResponse() ([]byte, error) { 182 hdr, err := remotefs.ReadFileHeader(l.stdout) 183 if err != nil { 184 return nil, err 185 } 186 187 if hdr.Cmd != remotefs.CmdOK { 188 // Something went wrong during the openfile in the server. 189 // Parse stderr and return that as an error 190 eerr, err := remotefs.ReadError(l.stderr) 191 if eerr != nil { 192 return nil, remotefs.ExportedToError(eerr) 193 } 194 195 // Maybe the parsing went wrong? 196 if err != nil { 197 return nil, err 198 } 199 200 // At this point, we know something went wrong in the remotefs program, but 201 // we we don't know why. 202 return nil, fmt.Errorf("unknown error") 203 } 204 205 // Successful command, we might have some data to read (for Read + Seek) 206 buf := make([]byte, hdr.Size, hdr.Size) 207 if _, err := io.ReadFull(l.stdout, buf); err != nil { 208 return nil, err 209 } 210 return buf, nil 211 }