...

Source file src/github.com/Microsoft/hcsshim/internal/uvm/plan9.go

Documentation: github.com/Microsoft/hcsshim/internal/uvm

     1  //go:build windows
     2  
     3  package uvm
     4  
     5  import (
     6  	"context"
     7  	"errors"
     8  	"fmt"
     9  	"strconv"
    10  
    11  	"github.com/Microsoft/hcsshim/internal/hcs"
    12  	"github.com/Microsoft/hcsshim/internal/hcs/resourcepaths"
    13  	hcsschema "github.com/Microsoft/hcsshim/internal/hcs/schema2"
    14  	"github.com/Microsoft/hcsshim/internal/protocol/guestrequest"
    15  	"github.com/Microsoft/hcsshim/internal/protocol/guestresource"
    16  	"github.com/Microsoft/hcsshim/osversion"
    17  )
    18  
    19  // Plan9Share is a struct containing host paths for the UVM
    20  type Plan9Share struct {
    21  	// UVM resource belongs to
    22  	vm            *UtilityVM
    23  	name, uvmPath string
    24  }
    25  
    26  // Release frees the resources of the corresponding Plan9 share
    27  func (p9 *Plan9Share) Release(ctx context.Context) error {
    28  	if err := p9.vm.RemovePlan9(ctx, p9); err != nil {
    29  		return fmt.Errorf("failed to remove plan9 share: %s", err)
    30  	}
    31  	return nil
    32  }
    33  
    34  const plan9Port = 564
    35  
    36  // AddPlan9 adds a Plan9 share to a utility VM.
    37  func (uvm *UtilityVM) AddPlan9(ctx context.Context, hostPath string, uvmPath string, readOnly bool, restrict bool, allowedNames []string) (*Plan9Share, error) {
    38  	if uvm.operatingSystem != "linux" {
    39  		return nil, errNotSupported
    40  	}
    41  	if restrict && osversion.Build() < osversion.V19H1 {
    42  		return nil, errors.New("single-file mappings are not supported on this build of Windows")
    43  	}
    44  	if uvmPath == "" {
    45  		return nil, fmt.Errorf("uvmPath must be passed to AddPlan9")
    46  	}
    47  	if !readOnly && uvm.NoWritableFileShares() {
    48  		return nil, fmt.Errorf("adding writable shares is denied: %w", hcs.ErrOperationDenied)
    49  	}
    50  
    51  	// TODO: JTERRY75 - These are marked private in the schema. For now use them
    52  	// but when there are public variants we need to switch to them.
    53  	const (
    54  		shareFlagsReadOnly           int32 = 0x00000001
    55  		shareFlagsLinuxMetadata      int32 = 0x00000004
    56  		shareFlagsCaseSensitive      int32 = 0x00000008
    57  		shareFlagsRestrictFileAccess int32 = 0x00000080
    58  	)
    59  
    60  	// TODO: JTERRY75 - `shareFlagsCaseSensitive` only works if the Windows
    61  	// `hostPath` supports case sensitivity. We need to detect this case before
    62  	// forwarding this flag in all cases.
    63  	flags := shareFlagsLinuxMetadata // | shareFlagsCaseSensitive
    64  	if readOnly {
    65  		flags |= shareFlagsReadOnly
    66  	}
    67  	if restrict {
    68  		flags |= shareFlagsRestrictFileAccess
    69  	}
    70  
    71  	uvm.m.Lock()
    72  	index := uvm.plan9Counter
    73  	uvm.plan9Counter++
    74  	uvm.m.Unlock()
    75  	name := strconv.FormatUint(index, 10)
    76  
    77  	modification := &hcsschema.ModifySettingRequest{
    78  		RequestType: guestrequest.RequestTypeAdd,
    79  		Settings: hcsschema.Plan9Share{
    80  			Name:         name,
    81  			AccessName:   name,
    82  			Path:         hostPath,
    83  			Port:         plan9Port,
    84  			Flags:        flags,
    85  			AllowedFiles: allowedNames,
    86  		},
    87  		ResourcePath: resourcepaths.Plan9ShareResourcePath,
    88  		GuestRequest: guestrequest.ModificationRequest{
    89  			ResourceType: guestresource.ResourceTypeMappedDirectory,
    90  			RequestType:  guestrequest.RequestTypeAdd,
    91  			Settings: guestresource.LCOWMappedDirectory{
    92  				MountPath: uvmPath,
    93  				ShareName: name,
    94  				Port:      plan9Port,
    95  				ReadOnly:  readOnly,
    96  			},
    97  		},
    98  	}
    99  
   100  	if err := uvm.modify(ctx, modification); err != nil {
   101  		return nil, err
   102  	}
   103  
   104  	return &Plan9Share{
   105  		vm:      uvm,
   106  		name:    name,
   107  		uvmPath: uvmPath,
   108  	}, nil
   109  }
   110  
   111  // RemovePlan9 removes a Plan9 share from a utility VM. Each Plan9 share is ref-counted
   112  // and only actually removed when the ref-count drops to zero.
   113  func (uvm *UtilityVM) RemovePlan9(ctx context.Context, share *Plan9Share) error {
   114  	if uvm.operatingSystem != "linux" {
   115  		return errNotSupported
   116  	}
   117  
   118  	modification := &hcsschema.ModifySettingRequest{
   119  		RequestType: guestrequest.RequestTypeRemove,
   120  		Settings: hcsschema.Plan9Share{
   121  			Name:       share.name,
   122  			AccessName: share.name,
   123  			Port:       plan9Port,
   124  		},
   125  		ResourcePath: resourcepaths.Plan9ShareResourcePath,
   126  		GuestRequest: guestrequest.ModificationRequest{
   127  			ResourceType: guestresource.ResourceTypeMappedDirectory,
   128  			RequestType:  guestrequest.RequestTypeRemove,
   129  			Settings: guestresource.LCOWMappedDirectory{
   130  				MountPath: share.uvmPath,
   131  				ShareName: share.name,
   132  				Port:      plan9Port,
   133  			},
   134  		},
   135  	}
   136  	if err := uvm.modify(ctx, modification); err != nil {
   137  		return fmt.Errorf("failed to remove plan9 share %s from %s: %+v: %s", share.name, uvm.id, modification, err)
   138  	}
   139  	return nil
   140  }
   141  

View as plain text