Signed-off-by: John Howard <jhoward@microsoft.com>
| ... | ... |
@@ -1,6 +1,6 @@ |
| 1 | 1 |
# the following lines are in sorted order, FYI |
| 2 | 2 |
github.com/Azure/go-ansiterm 388960b655244e76e24c75f48631564eaefade62 |
| 3 |
-github.com/Microsoft/hcsshim v0.5.13 |
|
| 3 |
+github.com/Microsoft/hcsshim v0.5.17 |
|
| 4 | 4 |
github.com/Microsoft/go-winio v0.3.9 |
| 5 | 5 |
github.com/Sirupsen/logrus v0.11.0 |
| 6 | 6 |
github.com/davecgh/go-spew 346938d642f2ec3594ed81d874461961cd0faa76 |
| ... | ... |
@@ -18,5 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| 18 | 18 |
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| 19 | 19 |
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| 20 | 20 |
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
| 21 |
-SOFTWARE. |
|
| 22 |
- |
|
| 21 |
+SOFTWARE. |
|
| 23 | 22 |
\ No newline at end of file |
| ... | ... |
@@ -4,7 +4,6 @@ import ( |
| 4 | 4 |
"encoding/json" |
| 5 | 5 |
"fmt" |
| 6 | 6 |
"os" |
| 7 |
- "runtime" |
|
| 8 | 7 |
"sync" |
| 9 | 8 |
"syscall" |
| 10 | 9 |
"time" |
| ... | ... |
@@ -105,6 +104,27 @@ type ProcessListItem struct {
|
| 105 | 105 |
UserTime100ns uint64 `json:",omitempty"` |
| 106 | 106 |
} |
| 107 | 107 |
|
| 108 |
+// Type of Request Support in ModifySystem |
|
| 109 |
+type RequestType string |
|
| 110 |
+ |
|
| 111 |
+// Type of Resource Support in ModifySystem |
|
| 112 |
+type ResourceType string |
|
| 113 |
+ |
|
| 114 |
+// RequestType const |
|
| 115 |
+const ( |
|
| 116 |
+ Add RequestType = "Add" |
|
| 117 |
+ Remove RequestType = "Remove" |
|
| 118 |
+ Network ResourceType = "Network" |
|
| 119 |
+) |
|
| 120 |
+ |
|
| 121 |
+// ResourceModificationRequestResponse is the structure used to send request to the container to modify the system |
|
| 122 |
+// Supported resource types are Network and Request Types are Add/Remove |
|
| 123 |
+type ResourceModificationRequestResponse struct {
|
|
| 124 |
+ Resource ResourceType `json:"ResourceType"` |
|
| 125 |
+ Data string `json:"Settings"` |
|
| 126 |
+ Request RequestType `json:"RequestType,omitempty"` |
|
| 127 |
+} |
|
| 128 |
+ |
|
| 108 | 129 |
// createContainerAdditionalJSON is read from the environment at initialisation |
| 109 | 130 |
// time. It allows an environment variable to define additional JSON which |
| 110 | 131 |
// is merged in the CreateContainer call to HCS. |
| ... | ... |
@@ -185,7 +205,6 @@ func createContainerWithJSON(id string, c *ContainerConfig, additionalJSON strin |
| 185 | 185 |
} |
| 186 | 186 |
|
| 187 | 187 |
logrus.Debugf(title+" succeeded id=%s handle=%d", id, container.handle) |
| 188 |
- runtime.SetFinalizer(container, closeContainer) |
|
| 189 | 188 |
return container, nil |
| 190 | 189 |
} |
| 191 | 190 |
|
| ... | ... |
@@ -243,7 +262,6 @@ func OpenContainer(id string) (Container, error) {
|
| 243 | 243 |
} |
| 244 | 244 |
|
| 245 | 245 |
logrus.Debugf(title+" succeeded id=%s handle=%d", id, handle) |
| 246 |
- runtime.SetFinalizer(container, closeContainer) |
|
| 247 | 246 |
return container, nil |
| 248 | 247 |
} |
| 249 | 248 |
|
| ... | ... |
@@ -568,7 +586,6 @@ func (container *container) CreateProcess(c *ProcessConfig) (Process, error) {
|
| 568 | 568 |
} |
| 569 | 569 |
|
| 570 | 570 |
logrus.Debugf(title+" succeeded id=%s processid=%s", container.id, process.processID) |
| 571 |
- runtime.SetFinalizer(process, closeProcess) |
|
| 572 | 571 |
return process, nil |
| 573 | 572 |
} |
| 574 | 573 |
|
| ... | ... |
@@ -605,7 +622,6 @@ func (container *container) OpenProcess(pid int) (Process, error) {
|
| 605 | 605 |
} |
| 606 | 606 |
|
| 607 | 607 |
logrus.Debugf(title+" succeeded id=%s processid=%s", container.id, process.processID) |
| 608 |
- runtime.SetFinalizer(process, closeProcess) |
|
| 609 | 608 |
return process, nil |
| 610 | 609 |
} |
| 611 | 610 |
|
| ... | ... |
@@ -631,17 +647,11 @@ func (container *container) Close() error {
|
| 631 | 631 |
} |
| 632 | 632 |
|
| 633 | 633 |
container.handle = 0 |
| 634 |
- runtime.SetFinalizer(container, nil) |
|
| 635 | 634 |
|
| 636 | 635 |
logrus.Debugf(title+" succeeded id=%s", container.id) |
| 637 | 636 |
return nil |
| 638 | 637 |
} |
| 639 | 638 |
|
| 640 |
-// closeContainer wraps container.Close for use by a finalizer |
|
| 641 |
-func closeContainer(container *container) {
|
|
| 642 |
- container.Close() |
|
| 643 |
-} |
|
| 644 |
- |
|
| 645 | 639 |
func (container *container) registerCallback() error {
|
| 646 | 640 |
context := ¬ifcationWatcherContext{
|
| 647 | 641 |
channels: newChannels(), |
| ... | ... |
@@ -698,3 +708,32 @@ func (container *container) unregisterCallback() error {
|
| 698 | 698 |
|
| 699 | 699 |
return nil |
| 700 | 700 |
} |
| 701 |
+ |
|
| 702 |
+// Modifies the System by sending a request to HCS |
|
| 703 |
+func (container *container) Modify(config *ResourceModificationRequestResponse) error {
|
|
| 704 |
+ container.handleLock.RLock() |
|
| 705 |
+ defer container.handleLock.RUnlock() |
|
| 706 |
+ operation := "Modify" |
|
| 707 |
+ title := "HCSShim::Container::" + operation |
|
| 708 |
+ |
|
| 709 |
+ if container.handle == 0 {
|
|
| 710 |
+ return makeContainerError(container, operation, "", ErrAlreadyClosed) |
|
| 711 |
+ } |
|
| 712 |
+ |
|
| 713 |
+ requestJSON, err := json.Marshal(config) |
|
| 714 |
+ if err != nil {
|
|
| 715 |
+ return err |
|
| 716 |
+ } |
|
| 717 |
+ |
|
| 718 |
+ requestString := string(requestJSON) |
|
| 719 |
+ logrus.Debugf(title+" id=%s request=%s", container.id, requestString) |
|
| 720 |
+ |
|
| 721 |
+ var resultp *uint16 |
|
| 722 |
+ err = hcsModifyComputeSystem(container.handle, requestString, &resultp) |
|
| 723 |
+ err = processHcsResult(err, resultp) |
|
| 724 |
+ if err != nil {
|
|
| 725 |
+ return makeContainerError(container, operation, "", err) |
|
| 726 |
+ } |
|
| 727 |
+ logrus.Debugf(title+" succeeded id=%s", container.id) |
|
| 728 |
+ return nil |
|
| 729 |
+} |
| ... | ... |
@@ -13,6 +13,13 @@ var ( |
| 13 | 13 |
// ErrElementNotFound is an error encountered when the object being referenced does not exist |
| 14 | 14 |
ErrElementNotFound = syscall.Errno(0x490) |
| 15 | 15 |
|
| 16 |
+ // ErrElementNotFound is an error encountered when the object being referenced does not exist |
|
| 17 |
+ ErrNotSupported = syscall.Errno(0x32) |
|
| 18 |
+ |
|
| 19 |
+ // ErrInvalidData is an error encountered when the request being sent to hcs is invalid/unsupported |
|
| 20 |
+ // decimal -2147024883 / hex 0x8007000d |
|
| 21 |
+ ErrInvalidData = syscall.Errno(0xd) |
|
| 22 |
+ |
|
| 16 | 23 |
// ErrHandleClose is an error encountered when the handle generating the notification being waited on has been closed |
| 17 | 24 |
ErrHandleClose = errors.New("hcsshim: the handle generating this notification has been closed")
|
| 18 | 25 |
|
| ... | ... |
@@ -54,6 +61,15 @@ var ( |
| 54 | 54 |
// ErrVmcomputeOperationAccessIsDenied is an error which can be encountered when enumerating compute systems in RS1/RS2 |
| 55 | 55 |
// builds when the underlying silo might be in the process of terminating. HCS was fixed in RS3. |
| 56 | 56 |
ErrVmcomputeOperationAccessIsDenied = syscall.Errno(0x5) |
| 57 |
+ |
|
| 58 |
+ // ErrVmcomputeInvalidJSON is an error encountered when the compute system does not support/understand the messages sent by management |
|
| 59 |
+ ErrVmcomputeInvalidJSON = syscall.Errno(0xc037010d) |
|
| 60 |
+ |
|
| 61 |
+ // ErrVmcomputeUnknownMessage is an error encountered guest compute system doesn't support the message |
|
| 62 |
+ ErrVmcomputeUnknownMessage = syscall.Errno(0xc037010b) |
|
| 63 |
+ |
|
| 64 |
+ // ErrNotSupported is an error encountered when hcs doesn't support the request |
|
| 65 |
+ ErrPlatformNotSupported = errors.New("unsupported platform request")
|
|
| 57 | 66 |
) |
| 58 | 67 |
|
| 59 | 68 |
// ProcessError is an error encountered in HCS during an operation on a Process object |
| ... | ... |
@@ -196,6 +212,20 @@ func IsAlreadyStopped(err error) bool {
|
| 196 | 196 |
err == ErrProcNotFound |
| 197 | 197 |
} |
| 198 | 198 |
|
| 199 |
+// IsNotSupported returns a boolean indicating whether the error is caused by |
|
| 200 |
+// unsupported platform requests |
|
| 201 |
+// Note: Currently Unsupported platform requests can be mean either |
|
| 202 |
+// ErrVmcomputeInvalidJSON, ErrInvalidData, ErrNotSupported or ErrVmcomputeUnknownMessage |
|
| 203 |
+// is thrown from the Platform |
|
| 204 |
+func IsNotSupported(err error) bool {
|
|
| 205 |
+ err = getInnerError(err) |
|
| 206 |
+ // If Platform doesn't recognize or support the request sent, below errors are seen |
|
| 207 |
+ return err == ErrVmcomputeInvalidJSON || |
|
| 208 |
+ err == ErrInvalidData || |
|
| 209 |
+ err == ErrNotSupported || |
|
| 210 |
+ err == ErrVmcomputeUnknownMessage |
|
| 211 |
+} |
|
| 212 |
+ |
|
| 199 | 213 |
func getInnerError(err error) error {
|
| 200 | 214 |
switch pe := err.(type) {
|
| 201 | 215 |
case nil: |
| ... | ... |
@@ -4,7 +4,6 @@ import ( |
| 4 | 4 |
"io" |
| 5 | 5 |
"io/ioutil" |
| 6 | 6 |
"os" |
| 7 |
- "runtime" |
|
| 8 | 7 |
"syscall" |
| 9 | 8 |
|
| 10 | 9 |
"github.com/Microsoft/go-winio" |
| ... | ... |
@@ -143,7 +142,6 @@ func NewLayerReader(info DriverInfo, layerID string, parentLayerPaths []string) |
| 143 | 143 |
if err != nil {
|
| 144 | 144 |
return nil, makeError(err, "ExportLayerBegin", "") |
| 145 | 145 |
} |
| 146 |
- runtime.SetFinalizer(r, func(r *FilterLayerReader) { r.Close() })
|
|
| 147 | 146 |
return r, err |
| 148 | 147 |
} |
| 149 | 148 |
|
| ... | ... |
@@ -98,6 +98,8 @@ type hnsResponse struct {
|
| 98 | 98 |
|
| 99 | 99 |
func hnsCall(method, path, request string, returnResponse interface{}) error {
|
| 100 | 100 |
var responseBuffer *uint16 |
| 101 |
+ logrus.Debugf("[%s]=>[%s] Request : %s", method, path, request)
|
|
| 102 |
+ |
|
| 101 | 103 |
err := _hnsCall(method, path, request, &responseBuffer) |
| 102 | 104 |
if err != nil {
|
| 103 | 105 |
return makeError(err, "hnsCall ", "") |
| ... | ... |
@@ -158,3 +160,112 @@ func HNSEndpointRequest(method, path, request string) (*HNSEndpoint, error) {
|
| 158 | 158 |
|
| 159 | 159 |
return endpoint, nil |
| 160 | 160 |
} |
| 161 |
+ |
|
| 162 |
+// HNSListEndpointRequest makes a HNS call to query the list of available endpoints |
|
| 163 |
+func HNSListEndpointRequest() ([]HNSEndpoint, error) {
|
|
| 164 |
+ var endpoint []HNSEndpoint |
|
| 165 |
+ err := hnsCall("GET", "/endpoints/", "", &endpoint)
|
|
| 166 |
+ if err != nil {
|
|
| 167 |
+ return nil, err |
|
| 168 |
+ } |
|
| 169 |
+ |
|
| 170 |
+ return endpoint, nil |
|
| 171 |
+} |
|
| 172 |
+ |
|
| 173 |
+// HotAttachEndpoint makes a HCS Call to attach the endpoint to the container |
|
| 174 |
+func HotAttachEndpoint(containerID string, endpointID string) error {
|
|
| 175 |
+ return modifyNetworkEndpoint(containerID, endpointID, Add) |
|
| 176 |
+} |
|
| 177 |
+ |
|
| 178 |
+// HotDetachEndpoint makes a HCS Call to detach the endpoint from the container |
|
| 179 |
+func HotDetachEndpoint(containerID string, endpointID string) error {
|
|
| 180 |
+ return modifyNetworkEndpoint(containerID, endpointID, Remove) |
|
| 181 |
+} |
|
| 182 |
+ |
|
| 183 |
+// ModifyContainer corresponding to the container id, by sending a request |
|
| 184 |
+func modifyContainer(id string, request *ResourceModificationRequestResponse) error {
|
|
| 185 |
+ container, err := OpenContainer(id) |
|
| 186 |
+ if err != nil {
|
|
| 187 |
+ if IsNotExist(err) {
|
|
| 188 |
+ return ErrComputeSystemDoesNotExist |
|
| 189 |
+ } |
|
| 190 |
+ return getInnerError(err) |
|
| 191 |
+ } |
|
| 192 |
+ defer container.Close() |
|
| 193 |
+ err = container.Modify(request) |
|
| 194 |
+ if err != nil {
|
|
| 195 |
+ if IsNotSupported(err) {
|
|
| 196 |
+ return ErrPlatformNotSupported |
|
| 197 |
+ } |
|
| 198 |
+ return getInnerError(err) |
|
| 199 |
+ } |
|
| 200 |
+ |
|
| 201 |
+ return nil |
|
| 202 |
+} |
|
| 203 |
+ |
|
| 204 |
+func modifyNetworkEndpoint(containerID string, endpointID string, request RequestType) error {
|
|
| 205 |
+ requestMessage := &ResourceModificationRequestResponse{
|
|
| 206 |
+ Resource: Network, |
|
| 207 |
+ Request: request, |
|
| 208 |
+ Data: endpointID, |
|
| 209 |
+ } |
|
| 210 |
+ err := modifyContainer(containerID, requestMessage) |
|
| 211 |
+ |
|
| 212 |
+ if err != nil {
|
|
| 213 |
+ return err |
|
| 214 |
+ } |
|
| 215 |
+ |
|
| 216 |
+ return nil |
|
| 217 |
+} |
|
| 218 |
+ |
|
| 219 |
+// GetHNSNetworkByID |
|
| 220 |
+func GetHNSNetworkByID(networkID string) (*HNSNetwork, error) {
|
|
| 221 |
+ return HNSNetworkRequest("GET", networkID, "")
|
|
| 222 |
+} |
|
| 223 |
+ |
|
| 224 |
+// GetHNSNetworkName filtered by Name |
|
| 225 |
+func GetHNSNetworkByName(networkName string) (*HNSNetwork, error) {
|
|
| 226 |
+ hsnnetworks, err := HNSListNetworkRequest("GET", "", "")
|
|
| 227 |
+ if err != nil {
|
|
| 228 |
+ return nil, err |
|
| 229 |
+ } |
|
| 230 |
+ for _, hnsnetwork := range hsnnetworks {
|
|
| 231 |
+ if hnsnetwork.Name == networkName {
|
|
| 232 |
+ return &hnsnetwork, nil |
|
| 233 |
+ } |
|
| 234 |
+ } |
|
| 235 |
+ return nil, fmt.Errorf("Network %v not found", networkName)
|
|
| 236 |
+} |
|
| 237 |
+ |
|
| 238 |
+// Create Endpoint by sending EndpointRequest to HNS. TODO: Create a separate HNS interface to place all these methods |
|
| 239 |
+func (endpoint *HNSEndpoint) Create() (*HNSEndpoint, error) {
|
|
| 240 |
+ jsonString, err := json.Marshal(endpoint) |
|
| 241 |
+ if err != nil {
|
|
| 242 |
+ return nil, err |
|
| 243 |
+ } |
|
| 244 |
+ return HNSEndpointRequest("POST", "", string(jsonString))
|
|
| 245 |
+} |
|
| 246 |
+ |
|
| 247 |
+// Create Endpoint by sending EndpointRequest to HNS |
|
| 248 |
+func (endpoint *HNSEndpoint) Delete() (*HNSEndpoint, error) {
|
|
| 249 |
+ return HNSEndpointRequest("DELETE", endpoint.Id, "")
|
|
| 250 |
+} |
|
| 251 |
+ |
|
| 252 |
+// GetHNSEndpointByID |
|
| 253 |
+func GetHNSEndpointByID(endpointID string) (*HNSEndpoint, error) {
|
|
| 254 |
+ return HNSEndpointRequest("GET", endpointID, "")
|
|
| 255 |
+} |
|
| 256 |
+ |
|
| 257 |
+// GetHNSNetworkName filtered by Name |
|
| 258 |
+func GetHNSEndpointByName(endpointName string) (*HNSEndpoint, error) {
|
|
| 259 |
+ hnsResponse, err := HNSListEndpointRequest() |
|
| 260 |
+ if err != nil {
|
|
| 261 |
+ return nil, err |
|
| 262 |
+ } |
|
| 263 |
+ for _, hnsEndpoint := range hnsResponse {
|
|
| 264 |
+ if hnsEndpoint.Name == endpointName {
|
|
| 265 |
+ return &hnsEndpoint, nil |
|
| 266 |
+ } |
|
| 267 |
+ } |
|
| 268 |
+ return nil, fmt.Errorf("Endpoint %v not found", endpointName)
|
|
| 269 |
+} |
| ... | ... |
@@ -5,7 +5,6 @@ import ( |
| 5 | 5 |
"io/ioutil" |
| 6 | 6 |
"os" |
| 7 | 7 |
"path/filepath" |
| 8 |
- "runtime" |
|
| 9 | 8 |
|
| 10 | 9 |
"github.com/Microsoft/go-winio" |
| 11 | 10 |
"github.com/Sirupsen/logrus" |
| ... | ... |
@@ -209,6 +208,5 @@ func NewLayerWriter(info DriverInfo, layerID string, parentLayerPaths []string) |
| 209 | 209 |
if err != nil {
|
| 210 | 210 |
return nil, makeError(err, "ImportLayerStart", "") |
| 211 | 211 |
} |
| 212 |
- runtime.SetFinalizer(w, func(w *FilterLayerWriter) { w.Close() })
|
|
| 213 | 212 |
return w, nil |
| 214 | 213 |
} |
| ... | ... |
@@ -117,6 +117,9 @@ type Container interface {
|
| 117 | 117 |
|
| 118 | 118 |
// Close cleans up any state associated with the container but does not terminate or wait for it. |
| 119 | 119 |
Close() error |
| 120 |
+ |
|
| 121 |
+ // Modify the System |
|
| 122 |
+ Modify(config *ResourceModificationRequestResponse) error |
|
| 120 | 123 |
} |
| 121 | 124 |
|
| 122 | 125 |
// Process represents a running or exited process. |
| ... | ... |
@@ -23,6 +23,13 @@ var mutatedUtilityVMFiles = map[string]bool{
|
| 23 | 23 |
`EFI\Microsoft\Boot\BCD.LOG2`: true, |
| 24 | 24 |
} |
| 25 | 25 |
|
| 26 |
+const ( |
|
| 27 |
+ filesPath = `Files` |
|
| 28 |
+ hivesPath = `Hives` |
|
| 29 |
+ utilityVMPath = `UtilityVM` |
|
| 30 |
+ utilityVMFilesPath = `UtilityVM\Files` |
|
| 31 |
+) |
|
| 32 |
+ |
|
| 26 | 33 |
func openFileOrDir(path string, mode uint32, createDisposition uint32) (file *os.File, err error) {
|
| 27 | 34 |
return winio.OpenForBackup(path, mode, syscall.FILE_SHARE_READ, createDisposition) |
| 28 | 35 |
} |
| ... | ... |
@@ -44,6 +51,10 @@ func makeLongAbsPath(path string) (string, error) {
|
| 44 | 44 |
return `\\?\` + path, nil |
| 45 | 45 |
} |
| 46 | 46 |
|
| 47 |
+func hasPathPrefix(p, prefix string) bool {
|
|
| 48 |
+ return strings.HasPrefix(p, prefix) && len(p) > len(prefix) && p[len(prefix)] == '\\' |
|
| 49 |
+} |
|
| 50 |
+ |
|
| 47 | 51 |
type fileEntry struct {
|
| 48 | 52 |
path string |
| 49 | 53 |
fi os.FileInfo |
| ... | ... |
@@ -83,7 +94,7 @@ func readTombstones(path string) (map[string]([]string), error) {
|
| 83 | 83 |
|
| 84 | 84 |
ts := make(map[string]([]string)) |
| 85 | 85 |
for s.Scan() {
|
| 86 |
- t := filepath.Join("Files", s.Text()[1:]) // skip leading `\`
|
|
| 86 |
+ t := filepath.Join(filesPath, s.Text()[1:]) // skip leading `\` |
|
| 87 | 87 |
dir := filepath.Dir(t) |
| 88 | 88 |
ts[dir] = append(ts[dir], t) |
| 89 | 89 |
} |
| ... | ... |
@@ -212,7 +223,7 @@ func (r *legacyLayerReader) Next() (path string, size int64, fileInfo *winio.Fil |
| 212 | 212 |
return |
| 213 | 213 |
} |
| 214 | 214 |
|
| 215 |
- if fe.fi.IsDir() && strings.HasPrefix(path, `Files\`) {
|
|
| 215 |
+ if fe.fi.IsDir() && hasPathPrefix(path, filesPath) {
|
|
| 216 | 216 |
fe.path += ".$wcidirs$" |
| 217 | 217 |
} |
| 218 | 218 |
|
| ... | ... |
@@ -231,14 +242,14 @@ func (r *legacyLayerReader) Next() (path string, size int64, fileInfo *winio.Fil |
| 231 | 231 |
return |
| 232 | 232 |
} |
| 233 | 233 |
|
| 234 |
- if !strings.HasPrefix(path, `Files\`) {
|
|
| 234 |
+ if !hasPathPrefix(path, filesPath) {
|
|
| 235 | 235 |
size = fe.fi.Size() |
| 236 | 236 |
r.backupReader = winio.NewBackupFileReader(f, false) |
| 237 |
- if path == "Hives" || path == "Files" {
|
|
| 237 |
+ if path == hivesPath || path == filesPath {
|
|
| 238 | 238 |
// The Hives directory has a non-deterministic file time because of the |
| 239 | 239 |
// nature of the import process. Use the times from System_Delta. |
| 240 | 240 |
var g *os.File |
| 241 |
- g, err = os.Open(filepath.Join(r.root, `Hives\System_Delta`)) |
|
| 241 |
+ g, err = os.Open(filepath.Join(r.root, hivesPath, `System_Delta`)) |
|
| 242 | 242 |
if err != nil {
|
| 243 | 243 |
return |
| 244 | 244 |
} |
| ... | ... |
@@ -357,7 +368,7 @@ func (w *legacyLayerWriter) init() error {
|
| 357 | 357 |
|
| 358 | 358 |
func (w *legacyLayerWriter) initUtilityVM() error {
|
| 359 | 359 |
if !w.HasUtilityVM {
|
| 360 |
- err := os.Mkdir(filepath.Join(w.destRoot, `UtilityVM`), 0) |
|
| 360 |
+ err := os.Mkdir(filepath.Join(w.destRoot, utilityVMPath), 0) |
|
| 361 | 361 |
if err != nil {
|
| 362 | 362 |
return err |
| 363 | 363 |
} |
| ... | ... |
@@ -365,7 +376,7 @@ func (w *legacyLayerWriter) initUtilityVM() error {
|
| 365 | 365 |
// clone the utility VM from the parent layer into this layer. Use hard |
| 366 | 366 |
// links to avoid unnecessary copying, since most of the files are |
| 367 | 367 |
// immutable. |
| 368 |
- err = cloneTree(filepath.Join(w.parentRoots[0], `UtilityVM\Files`), filepath.Join(w.destRoot, `UtilityVM\Files`), mutatedUtilityVMFiles) |
|
| 368 |
+ err = cloneTree(filepath.Join(w.parentRoots[0], utilityVMFilesPath), filepath.Join(w.destRoot, utilityVMFilesPath), mutatedUtilityVMFiles) |
|
| 369 | 369 |
if err != nil {
|
| 370 | 370 |
return fmt.Errorf("cloning the parent utility VM image failed: %s", err)
|
| 371 | 371 |
} |
| ... | ... |
@@ -490,15 +501,15 @@ func (w *legacyLayerWriter) Add(name string, fileInfo *winio.FileBasicInfo) erro |
| 490 | 490 |
return err |
| 491 | 491 |
} |
| 492 | 492 |
|
| 493 |
- if name == `UtilityVM` {
|
|
| 493 |
+ if name == utilityVMPath {
|
|
| 494 | 494 |
return w.initUtilityVM() |
| 495 | 495 |
} |
| 496 | 496 |
|
| 497 |
- if strings.HasPrefix(name, `UtilityVM\`) {
|
|
| 497 |
+ if hasPathPrefix(name, utilityVMPath) {
|
|
| 498 | 498 |
if !w.HasUtilityVM {
|
| 499 | 499 |
return errors.New("missing UtilityVM directory")
|
| 500 | 500 |
} |
| 501 |
- if !strings.HasPrefix(name, `UtilityVM\Files\`) && name != `UtilityVM\Files` {
|
|
| 501 |
+ if !hasPathPrefix(name, utilityVMFilesPath) && name != utilityVMFilesPath {
|
|
| 502 | 502 |
return errors.New("invalid UtilityVM layer")
|
| 503 | 503 |
} |
| 504 | 504 |
path := filepath.Join(w.destRoot, name) |
| ... | ... |
@@ -585,7 +596,7 @@ func (w *legacyLayerWriter) Add(name string, fileInfo *winio.FileBasicInfo) erro |
| 585 | 585 |
return err |
| 586 | 586 |
} |
| 587 | 587 |
|
| 588 |
- if strings.HasPrefix(name, `Hives\`) {
|
|
| 588 |
+ if hasPathPrefix(name, hivesPath) {
|
|
| 589 | 589 |
w.backupWriter = winio.NewBackupFileWriter(f, false) |
| 590 | 590 |
} else {
|
| 591 | 591 |
// The file attributes are written before the stream. |
| ... | ... |
@@ -608,22 +619,19 @@ func (w *legacyLayerWriter) AddLink(name string, target string) error {
|
| 608 | 608 |
return err |
| 609 | 609 |
} |
| 610 | 610 |
|
| 611 |
- var requiredPrefix string |
|
| 612 | 611 |
var roots []string |
| 613 |
- if prefix := `Files\`; strings.HasPrefix(name, prefix) {
|
|
| 614 |
- requiredPrefix = prefix |
|
| 612 |
+ if hasPathPrefix(target, filesPath) {
|
|
| 615 | 613 |
// Look for cross-layer hard link targets in the parent layers, since |
| 616 | 614 |
// nothing is in the destination path yet. |
| 617 | 615 |
roots = w.parentRoots |
| 618 |
- } else if prefix := `UtilityVM\Files\`; strings.HasPrefix(name, prefix) {
|
|
| 619 |
- requiredPrefix = prefix |
|
| 616 |
+ } else if hasPathPrefix(target, utilityVMFilesPath) {
|
|
| 620 | 617 |
// Since the utility VM is fully cloned into the destination path |
| 621 | 618 |
// already, look for cross-layer hard link targets directly in the |
| 622 | 619 |
// destination path. |
| 623 | 620 |
roots = []string{w.destRoot}
|
| 624 | 621 |
} |
| 625 | 622 |
|
| 626 |
- if requiredPrefix == "" || !strings.HasPrefix(target, requiredPrefix) {
|
|
| 623 |
+ if roots == nil || (!hasPathPrefix(name, filesPath) && !hasPathPrefix(name, utilityVMFilesPath)) {
|
|
| 627 | 624 |
return errors.New("invalid hard link in layer")
|
| 628 | 625 |
} |
| 629 | 626 |
|
| ... | ... |
@@ -657,9 +665,9 @@ func (w *legacyLayerWriter) AddLink(name string, target string) error {
|
| 657 | 657 |
} |
| 658 | 658 |
|
| 659 | 659 |
func (w *legacyLayerWriter) Remove(name string) error {
|
| 660 |
- if strings.HasPrefix(name, `Files\`) {
|
|
| 661 |
- w.tombstones = append(w.tombstones, name[len(`Files\`):]) |
|
| 662 |
- } else if strings.HasPrefix(name, `UtilityVM\Files\`) {
|
|
| 660 |
+ if hasPathPrefix(name, filesPath) {
|
|
| 661 |
+ w.tombstones = append(w.tombstones, name[len(filesPath)+1:]) |
|
| 662 |
+ } else if hasPathPrefix(name, utilityVMFilesPath) {
|
|
| 663 | 663 |
err := w.initUtilityVM() |
| 664 | 664 |
if err != nil {
|
| 665 | 665 |
return err |
| ... | ... |
@@ -3,7 +3,6 @@ package hcsshim |
| 3 | 3 |
import ( |
| 4 | 4 |
"encoding/json" |
| 5 | 5 |
"io" |
| 6 |
- "runtime" |
|
| 7 | 6 |
"sync" |
| 8 | 7 |
"syscall" |
| 9 | 8 |
"time" |
| ... | ... |
@@ -322,17 +321,11 @@ func (process *process) Close() error {
|
| 322 | 322 |
} |
| 323 | 323 |
|
| 324 | 324 |
process.handle = 0 |
| 325 |
- runtime.SetFinalizer(process, nil) |
|
| 326 | 325 |
|
| 327 | 326 |
logrus.Debugf(title+" succeeded processid=%d", process.processID) |
| 328 | 327 |
return nil |
| 329 | 328 |
} |
| 330 | 329 |
|
| 331 |
-// closeProcess wraps process.Close for use by a finalizer |
|
| 332 |
-func closeProcess(process *process) {
|
|
| 333 |
- process.Close() |
|
| 334 |
-} |
|
| 335 |
- |
|
| 336 | 330 |
func (process *process) registerCallback() error {
|
| 337 | 331 |
context := ¬ifcationWatcherContext{
|
| 338 | 332 |
channels: newChannels(), |