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