1
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
20 type Plan9Share struct {
21
22 vm *UtilityVM
23 name, uvmPath string
24 }
25
26
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
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
52
53 const (
54 shareFlagsReadOnly int32 = 0x00000001
55 shareFlagsLinuxMetadata int32 = 0x00000004
56 shareFlagsCaseSensitive int32 = 0x00000008
57 shareFlagsRestrictFileAccess int32 = 0x00000080
58 )
59
60
61
62
63 flags := shareFlagsLinuxMetadata
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
112
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