github.com/docker/docker@v299999999.0.0-20200612211812-aaf470eca7b5+incompatible/daemon/graphdriver/lcow/remotefs_file.go (about)

     1  // +build windows
     2  
     3  package lcow // import "github.com/docker/docker/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  }