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  }