remotefs_file.go 4.6 KB

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